From 43b08ccd6877477bc163e6f528f08b65cd10eafa Mon Sep 17 00:00:00 2001 From: damii Date: Wed, 27 Nov 2024 18:52:18 +1100 Subject: [PATCH 1/6] Features: Add multiple widgets per service --- docs/configs/service-widgets.md | 24 +- docs/widgets/index.md | 13 +- src/components/services/item.jsx | 4 +- src/components/services/widget.jsx | 10 +- src/pages/api/services/proxy.js | 4 +- src/utils/config/service-helpers.js | 591 ++++++++++++----------- src/utils/proxy/api-helpers.js | 1 + src/utils/proxy/handlers/credentialed.js | 4 +- src/utils/proxy/handlers/generic.js | 4 +- src/utils/proxy/handlers/jsonrpc.js | 4 +- src/utils/proxy/handlers/synology.js | 4 +- 11 files changed, 351 insertions(+), 312 deletions(-) diff --git a/docs/configs/service-widgets.md b/docs/configs/service-widgets.md index 9c54964ec22..8397e7c97ac 100644 --- a/docs/configs/service-widgets.md +++ b/docs/configs/service-widgets.md @@ -5,7 +5,7 @@ description: Service Widget Configuration Unless otherwise noted, URLs should not end with a `/` or other API path. Each widget will handle the path on its own. -Each service can have one widget attached to it (often matching the service type, but that's not forced). +Each service can have widgets attached to it (often matching the service type, but that's not forced). In addition to the href of the service, you can also specify the target location in which to open that link. See [Link Target](settings.md#link-target) for more details. @@ -22,6 +22,28 @@ Using Emby as an example, this is how you would attach the Emby service widget. key: apikeyapikeyapikeyapikeyapikey ``` +## Multiple Widgets + +Each service can have multiple widgets attached to it. Each widget needs a unique name. + +Using Emby as an example, here is how you would attack the Emby service widget alongside an uptime widget. + +```yaml +- Emby: + icon: emby.png + href: http://emby.host.or.ip/ + description: Movies & TV Shows + widgets: + - Emby: + type: emby + url: http://emby.host.or.ip + key: apikeyapikeyapikeyapikeyapikey + - Uptime: + type: uptimekuma + url: http://uptimekuma.host.or.ip:port + slug: statuspageslug +``` + ## Field Visibility Each widget can optionally provide a list of which fields should be visible via the `fields` widget property. If no fields are specified, then all fields will be displayed. The `fields` property must be a valid YAML array of strings. As an example, here is the entry for Sonarr showing only a couple of fields. diff --git a/docs/widgets/index.md b/docs/widgets/index.md index 8b81ee4027a..faa30975cec 100644 --- a/docs/widgets/index.md +++ b/docs/widgets/index.md @@ -19,10 +19,15 @@ Service widgets are used to display the status of a service, often a web service description: Watch movies and TV shows. server: localhost container: plex - widget: - type: tautulli - url: http://172.16.1.1:8181 - key: aabbccddeeffgghhiijjkkllmmnnoo + widgets: + - Tautulli: + type: tautulli + url: http://172.16.1.1:8181 + key: aabbccddeeffgghhiijjkkllmmnnoo + - UptimeKuma: + type: uptimekuma + url: http://172.16.1.2:8080 + slug: aaaaaaabbbbb ``` ## Info Widgets diff --git a/src/components/services/item.jsx b/src/components/services/item.jsx index a38dfaa3a37..09e744251b2 100644 --- a/src/components/services/item.jsx +++ b/src/components/services/item.jsx @@ -154,7 +154,9 @@ export default function Item({ service, group, useEqualHeights }) { )} - {service.widget && } + {service.widgets.map((widget) => ( + + ))} ); diff --git a/src/components/services/widget.jsx b/src/components/services/widget.jsx index 292b2b1c50b..628ff8c25b3 100644 --- a/src/components/services/widget.jsx +++ b/src/components/services/widget.jsx @@ -3,22 +3,24 @@ import { useTranslation } from "next-i18next"; import ErrorBoundary from "components/errorboundry"; import components from "widgets/components"; -export default function Widget({ service }) { +export default function Widget({ widget, service }) { const { t } = useTranslation("common"); - const ServiceWidget = components[service.widget.type]; + const ServiceWidget = components[widget.type]; + const fullService = service; + fullService.widget = widget; if (ServiceWidget) { return ( - + ); } return (
-
{t("widget.missing_type", { type: service.widget.type })}
+
{t("widget.missing_type", { type: widget.type })}
); } diff --git a/src/pages/api/services/proxy.js b/src/pages/api/services/proxy.js index 90280c3ddde..e7439ced520 100644 --- a/src/pages/api/services/proxy.js +++ b/src/pages/api/services/proxy.js @@ -9,8 +9,8 @@ const logger = createLogger("servicesProxy"); export default async function handler(req, res) { try { - const { service, group } = req.query; - const serviceWidget = await getServiceWidget(group, service); + const { service, group, name } = req.query; + const serviceWidget = await getServiceWidget(group, service, name); let type = serviceWidget?.type; // exceptions diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index ea82c7352cb..77e17aa75f7 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -354,311 +354,315 @@ export function cleanServiceGroups(groups) { if (typeof cleanedService.weight !== "number") { cleanedService.weight = 0; } + cleanedService.widgets = cleanedService.widgets ? cleanedService.widgets : []; + if (cleanedService.widget != undefined) cleanedService.widgets.push(cleanedService.widget); + if (cleanedService.widgets != []) { + cleanedService.widgets = cleanedService.widgets.map((widget) => { + // whitelisted set of keys to pass to the frontend + // alphabetical, grouped by widget(s) + const { + // all widgets + fields, + hideErrors, + type, + + // azuredevops + repositoryId, + userEmail, + + // beszel + systemId, + + // calendar + firstDayInWeek, + integrations, + maxEvents, + showTime, + previousDays, + view, + timezone, + + // coinmarketcap + currency, + defaultinterval, + slugs, + symbols, + + // customapi + mappings, + display, + + // diskstation + volume, + + // docker + container, + server, + + // emby, jellyfin + enableBlocks, + enableNowPlaying, + + // emby, jellyfin, tautulli + enableUser, + expandOneStreamToTwoRows, + showEpisodeNumber, + + // frigate + enableRecentEvents, + + // glances, immich, mealie, pihole, pfsense + version, + + // glances + chart, + metric, + pointsLimit, + diskUnits, + + // glances, customapi, iframe, prometheusmetric + refreshInterval, + + // hdhomerun + tuner, + + // healthchecks + uuid, + + // iframe + allowFullscreen, + allowPolicy, + allowScrolling, + classes, + loadingStrategy, + referrerPolicy, + src, + + // kopia + snapshotHost, + snapshotPath, + + // kubernetes + app, + namespace, + podSelector, + + // lubelogger + vehicleID, + + // mjpeg + fit, + stream, + + // openmediavault + method, + + // openwrt + interfaceName, + + // opnsense, pfsense + wan, + + // prometheusmetric + metrics, - if (cleanedService.widget) { - // whitelisted set of keys to pass to the frontend - // alphabetical, grouped by widget(s) - const { - // all widgets - fields, - hideErrors, - type, - - // azuredevops - repositoryId, - userEmail, - - // beszel - systemId, - - // calendar - firstDayInWeek, - integrations, - maxEvents, - showTime, - previousDays, - view, - timezone, - - // coinmarketcap - currency, - defaultinterval, - slugs, - symbols, - - // customapi - mappings, - display, + // proxmox + node, - // diskstation - volume, + // speedtest + bitratePrecision, - // docker - container, - server, + // sonarr, radarr + enableQueue, + + // stocks + watchlist, + showUSMarketStatus, - // emby, jellyfin - enableBlocks, - enableNowPlaying, + // truenas + enablePools, + nasType, - // emby, jellyfin, tautulli - enableUser, - expandOneStreamToTwoRows, - showEpisodeNumber, + // unifi + site, - // frigate - enableRecentEvents, + // vikunja + enableTaskList, - // glances, immich, mealie, pihole, pfsense - version, + // wgeasy + threshold, - // glances - chart, - metric, - pointsLimit, - diskUnits, + // technitium + range, - // glances, customapi, iframe, prometheusmetric - refreshInterval, + // spoolman + spoolIds, + } = Object.keys(widget)[0] != "type" ? widget[Object.keys(widget)[0]] : widget; - // hdhomerun - tuner, - - // healthchecks - uuid, - - // iframe - allowFullscreen, - allowPolicy, - allowScrolling, - classes, - loadingStrategy, - referrerPolicy, - src, - - // kopia - snapshotHost, - snapshotPath, - - // kubernetes - app, - namespace, - podSelector, - - // lubelogger - vehicleID, - - // mjpeg - fit, - stream, - - // openmediavault - method, - - // openwrt - interfaceName, - - // opnsense, pfsense - wan, - - // prometheusmetric - metrics, - - // proxmox - node, - - // speedtest - bitratePrecision, - - // sonarr, radarr - enableQueue, - - // stocks - watchlist, - showUSMarketStatus, - - // truenas - enablePools, - nasType, - - // unifi - site, - - // vikunja - enableTaskList, - - // wgeasy - threshold, - - // technitium - range, - - // spoolman - spoolIds, - } = cleanedService.widget; - - let fieldsList = fields; - if (typeof fields === "string") { - try { - fieldsList = JSON.parse(fields); - } catch (e) { - logger.error("Invalid fields list detected in config for service '%s'", service.name); - fieldsList = null; + let fieldsList = fields; + if (typeof fields === "string") { + try { + fieldsList = JSON.parse(fields); + } catch (e) { + logger.error("Invalid fields list detected in config for service '%s'", service.name); + fieldsList = null; + } } - } - - cleanedService.widget = { - type, - fields: fieldsList || null, - hide_errors: hideErrors || false, - service_name: service.name, - service_group: serviceGroup.name, - }; - if (type === "azuredevops") { - if (userEmail) cleanedService.widget.userEmail = userEmail; - if (repositoryId) cleanedService.widget.repositoryId = repositoryId; - } + widget = { + type, + fields: fieldsList || null, + hide_errors: hideErrors || false, + service_name: service.name, + service_group: serviceGroup.name, + widget_name: Object.keys(widget)[0] != "type" ? Object.keys(widget)[0] : "", + }; + + if (type === "azuredevops") { + if (userEmail) widget.userEmail = userEmail; + if (repositoryId) widget.repositoryId = repositoryId; + } - if (type === "beszel") { - if (systemId) cleanedService.widget.systemId = systemId; - } + if (type === "beszel") { + if (systemId) widget.systemId = systemId; + } - if (type === "coinmarketcap") { - if (currency) cleanedService.widget.currency = currency; - if (symbols) cleanedService.widget.symbols = symbols; - if (slugs) cleanedService.widget.slugs = slugs; - if (defaultinterval) cleanedService.widget.defaultinterval = defaultinterval; - } + if (type === "coinmarketcap") { + if (currency) widget.currency = currency; + if (symbols) widget.symbols = symbols; + if (slugs) widget.slugs = slugs; + if (defaultinterval) widget.defaultinterval = defaultinterval; + } - if (type === "docker") { - if (server) cleanedService.widget.server = server; - if (container) cleanedService.widget.container = container; - } - if (type === "unifi") { - if (site) cleanedService.widget.site = site; - } - if (type === "proxmox") { - if (node) cleanedService.widget.node = node; - } - if (type === "kubernetes") { - if (namespace) cleanedService.widget.namespace = namespace; - if (app) cleanedService.widget.app = app; - if (podSelector) cleanedService.widget.podSelector = podSelector; - } - if (type === "iframe") { - if (src) cleanedService.widget.src = src; - if (classes) cleanedService.widget.classes = classes; - if (referrerPolicy) cleanedService.widget.referrerPolicy = referrerPolicy; - if (allowPolicy) cleanedService.widget.allowPolicy = allowPolicy; - if (allowFullscreen) cleanedService.widget.allowFullscreen = allowFullscreen; - if (loadingStrategy) cleanedService.widget.loadingStrategy = loadingStrategy; - if (allowScrolling) cleanedService.widget.allowScrolling = allowScrolling; - if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval; - } - if (["opnsense", "pfsense"].includes(type)) { - if (wan) cleanedService.widget.wan = wan; - } - if (["emby", "jellyfin"].includes(type)) { - if (enableBlocks !== undefined) cleanedService.widget.enableBlocks = JSON.parse(enableBlocks); - if (enableNowPlaying !== undefined) cleanedService.widget.enableNowPlaying = JSON.parse(enableNowPlaying); - } - if (["emby", "jellyfin", "tautulli"].includes(type)) { - if (expandOneStreamToTwoRows !== undefined) - cleanedService.widget.expandOneStreamToTwoRows = !!JSON.parse(expandOneStreamToTwoRows); - if (showEpisodeNumber !== undefined) - cleanedService.widget.showEpisodeNumber = !!JSON.parse(showEpisodeNumber); - if (enableUser !== undefined) cleanedService.widget.enableUser = !!JSON.parse(enableUser); - } - if (["sonarr", "radarr"].includes(type)) { - if (enableQueue !== undefined) cleanedService.widget.enableQueue = JSON.parse(enableQueue); - } - if (type === "truenas") { - if (enablePools !== undefined) cleanedService.widget.enablePools = JSON.parse(enablePools); - if (nasType !== undefined) cleanedService.widget.nasType = nasType; - } - if (["diskstation", "qnap"].includes(type)) { - if (volume) cleanedService.widget.volume = volume; - } - if (type === "kopia") { - if (snapshotHost) cleanedService.widget.snapshotHost = snapshotHost; - if (snapshotPath) cleanedService.widget.snapshotPath = snapshotPath; - } - if (["glances", "immich", "mealie", "pfsense", "pihole"].includes(type)) { - if (version) cleanedService.widget.version = parseInt(version, 10); - } - if (type === "glances") { - if (metric) cleanedService.widget.metric = metric; - if (chart !== undefined) { - cleanedService.widget.chart = chart; - } else { - cleanedService.widget.chart = true; - } - if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval; - if (pointsLimit) cleanedService.widget.pointsLimit = pointsLimit; - if (diskUnits) cleanedService.widget.diskUnits = diskUnits; - } - if (type === "mjpeg") { - if (stream) cleanedService.widget.stream = stream; - if (fit) cleanedService.widget.fit = fit; - } - if (type === "openmediavault") { - if (method) cleanedService.widget.method = method; - } - if (type === "openwrt") { - if (interfaceName) cleanedService.widget.interfaceName = interfaceName; - } - if (type === "customapi") { - if (mappings) cleanedService.widget.mappings = mappings; - if (display) cleanedService.widget.display = display; - if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval; - } - if (type === "calendar") { - if (integrations) cleanedService.widget.integrations = integrations; - if (firstDayInWeek) cleanedService.widget.firstDayInWeek = firstDayInWeek; - if (view) cleanedService.widget.view = view; - if (maxEvents) cleanedService.widget.maxEvents = maxEvents; - if (previousDays) cleanedService.widget.previousDays = previousDays; - if (showTime) cleanedService.widget.showTime = showTime; - if (timezone) cleanedService.widget.timezone = timezone; - } - if (type === "hdhomerun") { - if (tuner !== undefined) cleanedService.widget.tuner = tuner; - } - if (type === "healthchecks") { - if (uuid !== undefined) cleanedService.widget.uuid = uuid; - } - if (type === "speedtest") { - if (bitratePrecision !== undefined) { - cleanedService.widget.bitratePrecision = parseInt(bitratePrecision, 10); + if (type === "docker") { + if (server) widget.server = server; + if (container) widget.container = container; } - } - if (type === "stocks") { - if (watchlist) cleanedService.widget.watchlist = watchlist; - if (showUSMarketStatus) cleanedService.widget.showUSMarketStatus = showUSMarketStatus; - } - if (type === "wgeasy") { - if (threshold !== undefined) cleanedService.widget.threshold = parseInt(threshold, 10); - } - if (type === "frigate") { - if (enableRecentEvents !== undefined) cleanedService.widget.enableRecentEvents = enableRecentEvents; - } - if (type === "technitium") { - if (range !== undefined) cleanedService.widget.range = range; - } - if (type === "lubelogger") { - if (vehicleID !== undefined) cleanedService.widget.vehicleID = parseInt(vehicleID, 10); - } - if (type === "vikunja") { - if (enableTaskList !== undefined) cleanedService.widget.enableTaskList = !!enableTaskList; - } - if (type === "prometheusmetric") { - if (metrics) cleanedService.widget.metrics = metrics; - if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval; - } - if (type === "spoolman") { - if (spoolIds !== undefined) cleanedService.widget.spoolIds = spoolIds; - } + if (type === "unifi") { + if (site) widget.site = site; + } + if (type === "proxmox") { + if (node) widget.node = node; + } + if (type === "kubernetes") { + if (namespace) widget.namespace = namespace; + if (app) widget.app = app; + if (podSelector) widget.podSelector = podSelector; + } + if (type === "iframe") { + if (src) widget.src = src; + if (classes) widget.classes = classes; + if (referrerPolicy) widget.referrerPolicy = referrerPolicy; + if (allowPolicy) widget.allowPolicy = allowPolicy; + if (allowFullscreen) widget.allowFullscreen = allowFullscreen; + if (loadingStrategy) widget.loadingStrategy = loadingStrategy; + if (allowScrolling) widget.allowScrolling = allowScrolling; + if (refreshInterval) widget.refreshInterval = refreshInterval; + } + if (["opnsense", "pfsense"].includes(type)) { + if (wan) widget.wan = wan; + } + if (["emby", "jellyfin"].includes(type)) { + if (enableBlocks !== undefined) widget.enableBlocks = JSON.parse(enableBlocks); + if (enableNowPlaying !== undefined) widget.enableNowPlaying = JSON.parse(enableNowPlaying); + } + if (["emby", "jellyfin", "tautulli"].includes(type)) { + if (expandOneStreamToTwoRows !== undefined) + widget.expandOneStreamToTwoRows = !!JSON.parse(expandOneStreamToTwoRows); + if (showEpisodeNumber !== undefined) widget.showEpisodeNumber = !!JSON.parse(showEpisodeNumber); + if (enableUser !== undefined) widget.enableUser = !!JSON.parse(enableUser); + } + if (["sonarr", "radarr"].includes(type)) { + if (enableQueue !== undefined) widget.enableQueue = JSON.parse(enableQueue); + } + if (type === "truenas") { + if (enablePools !== undefined) widget.enablePools = JSON.parse(enablePools); + if (nasType !== undefined) widget.nasType = nasType; + } + if (["diskstation", "qnap"].includes(type)) { + if (volume) widget.volume = volume; + } + if (type === "kopia") { + if (snapshotHost) widget.snapshotHost = snapshotHost; + if (snapshotPath) widget.snapshotPath = snapshotPath; + } + if (["glances", "immich", "mealie", "pfsense", "pihole"].includes(type)) { + if (version) widget.version = parseInt(version, 10); + } + if (type === "glances") { + if (metric) widget.metric = metric; + if (chart !== undefined) { + widget.chart = chart; + } else { + widget.chart = true; + } + if (refreshInterval) widget.refreshInterval = refreshInterval; + if (pointsLimit) widget.pointsLimit = pointsLimit; + if (diskUnits) widget.diskUnits = diskUnits; + } + if (type === "mjpeg") { + if (stream) widget.stream = stream; + if (fit) widget.fit = fit; + } + if (type === "openmediavault") { + if (method) widget.method = method; + } + if (type === "openwrt") { + if (interfaceName) widget.interfaceName = interfaceName; + } + if (type === "customapi") { + if (mappings) widget.mappings = mappings; + if (display) widget.display = display; + if (refreshInterval) widget.refreshInterval = refreshInterval; + } + if (type === "calendar") { + if (integrations) widget.integrations = integrations; + if (firstDayInWeek) widget.firstDayInWeek = firstDayInWeek; + if (view) widget.view = view; + if (maxEvents) widget.maxEvents = maxEvents; + if (previousDays) widget.previousDays = previousDays; + if (showTime) widget.showTime = showTime; + if (timezone) widget.timezone = timezone; + } + if (type === "hdhomerun") { + if (tuner !== undefined) widget.tuner = tuner; + } + if (type === "healthchecks") { + if (uuid !== undefined) widget.uuid = uuid; + } + if (type === "speedtest") { + if (bitratePrecision !== undefined) { + widget.bitratePrecision = parseInt(bitratePrecision, 10); + } + } + if (type === "stocks") { + if (watchlist) widget.watchlist = watchlist; + if (showUSMarketStatus) widget.showUSMarketStatus = showUSMarketStatus; + } + if (type === "wgeasy") { + if (threshold !== undefined) widget.threshold = parseInt(threshold, 10); + } + if (type === "frigate") { + if (enableRecentEvents !== undefined) widget.enableRecentEvents = enableRecentEvents; + } + if (type === "technitium") { + if (range !== undefined) widget.range = range; + } + if (type === "lubelogger") { + if (vehicleID !== undefined) widget.vehicleID = parseInt(vehicleID, 10); + } + if (type === "vikunja") { + if (enableTaskList !== undefined) widget.enableTaskList = !!enableTaskList; + } + if (type === "prometheusmetric") { + if (metrics) widget.metrics = metrics; + if (refreshInterval) widget.refreshInterval = refreshInterval; + } + if (type === "spoolman") { + if (spoolIds !== undefined) widget.spoolIds = spoolIds; + } + return widget; + }); } return cleanedService; @@ -693,12 +697,15 @@ export async function getServiceItem(group, service) { return false; } -export default async function getServiceWidget(group, service) { +export default async function getServiceWidget(group, service, name = null) { const serviceItem = await getServiceItem(group, service); - if (serviceItem) { + if (serviceItem && (name == null || name === "undefined")) { const { widget } = serviceItem; return widget; } - + if (serviceItem && name != null && name !== "undefined") { + const { widgets } = serviceItem; + return widgets.filter((widget) => Object.keys(widget)[0] == name)[0][name]; + } return false; } diff --git a/src/utils/proxy/api-helpers.js b/src/utils/proxy/api-helpers.js index 8e0682dbc89..c762d0ba691 100644 --- a/src/utils/proxy/api-helpers.js +++ b/src/utils/proxy/api-helpers.js @@ -12,6 +12,7 @@ export function getURLSearchParams(widget, endpoint) { const params = new URLSearchParams({ group: widget.service_group, service: widget.service_name, + ...(widget.widget_name != "" && { name: widget.widget_name }), }); if (endpoint) { params.append("endpoint", endpoint); diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js index cbe0422ae00..416e38fc418 100644 --- a/src/utils/proxy/handlers/credentialed.js +++ b/src/utils/proxy/handlers/credentialed.js @@ -9,10 +9,10 @@ import widgets from "widgets/widgets"; const logger = createLogger("credentialedProxyHandler"); export default async function credentialedProxyHandler(req, res, map) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widgets?.[widget.type]?.api) { return res.status(403).json({ error: "Service does not support API calls" }); diff --git a/src/utils/proxy/handlers/generic.js b/src/utils/proxy/handlers/generic.js index c6b9236b3f5..7dc7fb5373c 100644 --- a/src/utils/proxy/handlers/generic.js +++ b/src/utils/proxy/handlers/generic.js @@ -8,10 +8,10 @@ import widgets from "widgets/widgets"; const logger = createLogger("genericProxyHandler"); export default async function genericProxyHandler(req, res, map) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widgets?.[widget.type]?.api) { return res.status(403).json({ error: "Service does not support API calls" }); diff --git a/src/utils/proxy/handlers/jsonrpc.js b/src/utils/proxy/handlers/jsonrpc.js index 3974dbdc33d..e95264bda11 100644 --- a/src/utils/proxy/handlers/jsonrpc.js +++ b/src/utils/proxy/handlers/jsonrpc.js @@ -65,10 +65,10 @@ export async function sendJsonRpcRequest(url, method, params, widget) { } export default async function jsonrpcProxyHandler(req, res) { - const { group, service, endpoint: method } = req.query; + const { group, service, endpoint: method, name } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); const api = widgets?.[widget.type]?.api; const [, mapping] = Object.entries(widgets?.[widget.type]?.mappings).find(([, value]) => value.endpoint === method); diff --git a/src/utils/proxy/handlers/synology.js b/src/utils/proxy/handlers/synology.js index be44e810ad3..e711db7ee97 100644 --- a/src/utils/proxy/handlers/synology.js +++ b/src/utils/proxy/handlers/synology.js @@ -131,13 +131,13 @@ function toError(url, synologyError) { } export default async function synologyProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (!group || !service) { return res.status(400).json({ error: "Invalid proxy service type" }); } - const serviceWidget = await getServiceWidget(group, service); + const serviceWidget = await getServiceWidget(group, service, name ? name : null); const widget = widgets?.[serviceWidget.type]; const mapping = widget?.mappings?.[endpoint]; if (!widget.api || !mapping) { From b225d3850e8e64dd090ac409acd6447772026e4b Mon Sep 17 00:00:00 2001 From: damii Date: Wed, 27 Nov 2024 19:29:34 +1100 Subject: [PATCH 2/6] Clean old widget value before sending to client --- src/utils/config/service-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index 77e17aa75f7..2d7090656fe 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -664,7 +664,7 @@ export function cleanServiceGroups(groups) { return widget; }); } - + cleanedService.widget = null; return cleanedService; }), })); From 43e8010375e7f5f4d67ad11c590e50560d116760 Mon Sep 17 00:00:00 2001 From: damii Date: Wed, 27 Nov 2024 19:53:07 +1100 Subject: [PATCH 3/6] Add support for multiple widgets in widgets with custom proxies --- src/widgets/audiobookshelf/proxy.js | 4 ++-- src/widgets/beszel/proxy.js | 4 ++-- src/widgets/calendar/proxy.js | 4 ++-- src/widgets/crowdsec/proxy.js | 4 ++-- src/widgets/deluge/proxy.js | 4 ++-- src/widgets/flood/proxy.js | 4 ++-- src/widgets/freshrss/proxy.js | 4 ++-- src/widgets/fritzbox/proxy.js | 4 ++-- src/widgets/gamedig/proxy.js | 4 ++-- src/widgets/homeassistant/proxy.js | 4 ++-- src/widgets/homebox/proxy.js | 4 ++-- src/widgets/homebridge/proxy.js | 4 ++-- src/widgets/jackett/proxy.js | 4 ++-- src/widgets/jdownloader/proxy.js | 4 ++-- src/widgets/kavita/proxy.js | 4 ++-- src/widgets/minecraft/proxy.js | 4 ++-- src/widgets/npm/proxy.js | 4 ++-- src/widgets/omada/proxy.js | 4 ++-- src/widgets/openmediavault/proxy.js | 4 ++-- src/widgets/openwrt/proxy.js | 4 ++-- src/widgets/photoprism/proxy.js | 4 ++-- src/widgets/pihole/proxy.js | 4 ++-- src/widgets/plex/proxy.js | 4 ++-- src/widgets/pyload/proxy.js | 4 ++-- src/widgets/qbittorrent/proxy.js | 4 ++-- src/widgets/qnap/proxy.js | 4 ++-- src/widgets/rutorrent/proxy.js | 4 ++-- src/widgets/suwayomi/proxy.js | 4 ++-- src/widgets/tdarr/proxy.js | 4 ++-- src/widgets/transmission/proxy.js | 4 ++-- src/widgets/unifi/proxy.js | 4 ++-- src/widgets/urbackup/proxy.js | 4 ++-- src/widgets/watchtower/proxy.js | 4 ++-- src/widgets/xteve/proxy.js | 4 ++-- 34 files changed, 68 insertions(+), 68 deletions(-) diff --git a/src/widgets/audiobookshelf/proxy.js b/src/widgets/audiobookshelf/proxy.js index 9701c1feb3d..3c40ffd10ad 100644 --- a/src/widgets/audiobookshelf/proxy.js +++ b/src/widgets/audiobookshelf/proxy.js @@ -23,14 +23,14 @@ async function retrieveFromAPI(url, key) { } export default async function audiobookshelfProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/beszel/proxy.js b/src/widgets/beszel/proxy.js index 04083e4209a..f25e63846fe 100644 --- a/src/widgets/beszel/proxy.js +++ b/src/widgets/beszel/proxy.js @@ -34,10 +34,10 @@ async function login(loginUrl, username, password, service) { } export default async function beszelProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widgets?.[widget.type]?.api) { return res.status(403).json({ error: "Service does not support API calls" }); diff --git a/src/widgets/calendar/proxy.js b/src/widgets/calendar/proxy.js index cf754424f4a..568edb656d8 100644 --- a/src/widgets/calendar/proxy.js +++ b/src/widgets/calendar/proxy.js @@ -5,10 +5,10 @@ import createLogger from "utils/logger"; const logger = createLogger("calendarProxyHandler"); export default async function calendarProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); const integration = widget.integrations?.find((i) => i.name === endpoint); if (integration) { diff --git a/src/widgets/crowdsec/proxy.js b/src/widgets/crowdsec/proxy.js index e78fbc5ef00..cc481064569 100644 --- a/src/widgets/crowdsec/proxy.js +++ b/src/widgets/crowdsec/proxy.js @@ -35,14 +35,14 @@ async function login(widget, service) { } export default async function crowdsecProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (!group || !service) { logger.error("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget || !widgets[widget.type].api) { logger.error("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid widget configuration" }); diff --git a/src/widgets/deluge/proxy.js b/src/widgets/deluge/proxy.js index b86873a897d..aa4ccb05d3e 100644 --- a/src/widgets/deluge/proxy.js +++ b/src/widgets/deluge/proxy.js @@ -40,14 +40,14 @@ function login(url, password) { } export default async function delugeProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/flood/proxy.js b/src/widgets/flood/proxy.js index 3345ad7b2b6..d0e34430930 100644 --- a/src/widgets/flood/proxy.js +++ b/src/widgets/flood/proxy.js @@ -28,14 +28,14 @@ async function login(widget) { } export default async function floodProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/freshrss/proxy.js b/src/widgets/freshrss/proxy.js index c08e5c87170..5ce98f346bf 100644 --- a/src/widgets/freshrss/proxy.js +++ b/src/widgets/freshrss/proxy.js @@ -74,14 +74,14 @@ async function apiCall(widget, endpoint, service) { } export default async function freshrssProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); diff --git a/src/widgets/fritzbox/proxy.js b/src/widgets/fritzbox/proxy.js index a0a22d8b5f7..3599229b1f0 100644 --- a/src/widgets/fritzbox/proxy.js +++ b/src/widgets/fritzbox/proxy.js @@ -46,8 +46,8 @@ async function requestEndpoint(apiBaseUrl, service, action) { } export default async function fritzboxProxyHandler(req, res) { - const { group, service } = req.query; - const serviceWidget = await getServiceWidget(group, service); + const { group, service, name } = req.query; + const serviceWidget = await getServiceWidget(group, service, name ? name : null); if (!serviceWidget) { res.status(500).json({ error: { message: "Service widget not found" } }); diff --git a/src/widgets/gamedig/proxy.js b/src/widgets/gamedig/proxy.js index 05fa615c102..819cd13d68a 100644 --- a/src/widgets/gamedig/proxy.js +++ b/src/widgets/gamedig/proxy.js @@ -7,8 +7,8 @@ const proxyName = "gamedigProxyHandler"; const logger = createLogger(proxyName); export default async function gamedigProxyHandler(req, res) { - const { group, service } = req.query; - const serviceWidget = await getServiceWidget(group, service); + const { group, service, name } = req.query; + const serviceWidget = await getServiceWidget(group, service, name ? name : null); const url = new URL(serviceWidget.url); try { diff --git a/src/widgets/homeassistant/proxy.js b/src/widgets/homeassistant/proxy.js index fe488f86b39..7719b13e3c3 100644 --- a/src/widgets/homeassistant/proxy.js +++ b/src/widgets/homeassistant/proxy.js @@ -62,14 +62,14 @@ async function getQuery(query, { url, key }) { } export default async function homeassistantProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); diff --git a/src/widgets/homebox/proxy.js b/src/widgets/homebox/proxy.js index 0d6fdf13c66..0f6d6e7e14e 100644 --- a/src/widgets/homebox/proxy.js +++ b/src/widgets/homebox/proxy.js @@ -68,14 +68,14 @@ async function apiCall(widget, endpoint, service) { } export default async function homeboxProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); diff --git a/src/widgets/homebridge/proxy.js b/src/widgets/homebridge/proxy.js index 17dc8635c71..0985b2696cb 100644 --- a/src/widgets/homebridge/proxy.js +++ b/src/widgets/homebridge/proxy.js @@ -71,14 +71,14 @@ async function apiCall(widget, endpoint, service) { } export default async function homebridgeProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/jackett/proxy.js b/src/widgets/jackett/proxy.js index 5292695fc9e..4c3b02fbe35 100644 --- a/src/widgets/jackett/proxy.js +++ b/src/widgets/jackett/proxy.js @@ -25,14 +25,14 @@ async function fetchJackettCookie(widget, loginURL) { } export default async function jackettProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (!group || !service) { logger.error("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget || !widgets[widget.type].api) { logger.error("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid widget configuration" }); diff --git a/src/widgets/jdownloader/proxy.js b/src/widgets/jdownloader/proxy.js index 88a92d95d72..77a7a65ffc2 100644 --- a/src/widgets/jdownloader/proxy.js +++ b/src/widgets/jdownloader/proxy.js @@ -12,12 +12,12 @@ const proxyName = "jdownloaderProxyHandler"; const logger = createLogger(proxyName); async function getWidget(req) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return null; } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return null; diff --git a/src/widgets/kavita/proxy.js b/src/widgets/kavita/proxy.js index b8e9813f8aa..ef991037fd4 100644 --- a/src/widgets/kavita/proxy.js +++ b/src/widgets/kavita/proxy.js @@ -70,14 +70,14 @@ async function apiCall(widget, endpoint, service) { } export default async function KavitaProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); diff --git a/src/widgets/minecraft/proxy.js b/src/widgets/minecraft/proxy.js index f7bac9d4593..17d845ef553 100644 --- a/src/widgets/minecraft/proxy.js +++ b/src/widgets/minecraft/proxy.js @@ -7,8 +7,8 @@ const proxyName = "minecraftProxyHandler"; const logger = createLogger(proxyName); export default async function minecraftProxyHandler(req, res) { - const { group, service } = req.query; - const serviceWidget = await getServiceWidget(group, service); + const { group, service, name } = req.query; + const serviceWidget = await getServiceWidget(group, service, name ? name : null); const url = new URL(serviceWidget.url); try { const pingResponse = await pingWithPromise(url.hostname, url.port || 25565); diff --git a/src/widgets/npm/proxy.js b/src/widgets/npm/proxy.js index 978254f815c..d672b35f65b 100644 --- a/src/widgets/npm/proxy.js +++ b/src/widgets/npm/proxy.js @@ -36,10 +36,10 @@ async function login(loginUrl, username, password, service) { } export default async function npmProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widgets?.[widget.type]?.api) { return res.status(403).json({ error: "Service does not support API calls" }); diff --git a/src/widgets/omada/proxy.js b/src/widgets/omada/proxy.js index 8e8994a5ba3..5d9110d9c93 100644 --- a/src/widgets/omada/proxy.js +++ b/src/widgets/omada/proxy.js @@ -33,10 +33,10 @@ async function login(loginUrl, username, password, controllerVersionMajor) { } export default async function omadaProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (widget) { const { url } = widget; diff --git a/src/widgets/openmediavault/proxy.js b/src/widgets/openmediavault/proxy.js index e1f97a56e5c..9463ffce994 100644 --- a/src/widgets/openmediavault/proxy.js +++ b/src/widgets/openmediavault/proxy.js @@ -12,14 +12,14 @@ const BG_POLL_PERIOD = 500; const logger = createLogger(PROXY_NAME); async function getWidget(req) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return null; } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/openwrt/proxy.js b/src/widgets/openwrt/proxy.js index 977db8ca9dd..197b43965a9 100644 --- a/src/widgets/openwrt/proxy.js +++ b/src/widgets/openwrt/proxy.js @@ -17,14 +17,14 @@ const PARAMS = { }; async function getWidget(req) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return null; } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/photoprism/proxy.js b/src/widgets/photoprism/proxy.js index 509bfa0c75b..1d849e4b589 100644 --- a/src/widgets/photoprism/proxy.js +++ b/src/widgets/photoprism/proxy.js @@ -6,14 +6,14 @@ import createLogger from "utils/logger"; const logger = createLogger("photoprismProxyHandler"); export default async function photoprismProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/pihole/proxy.js b/src/widgets/pihole/proxy.js index 35873fa92ca..bf1172353f1 100644 --- a/src/widgets/pihole/proxy.js +++ b/src/widgets/pihole/proxy.js @@ -33,7 +33,7 @@ async function login(widget, service) { } export default async function piholeProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; let endpoint = "stats/summary"; if (!group || !service) { @@ -41,7 +41,7 @@ export default async function piholeProxyHandler(req, res) { return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.error("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid widget configuration" }); diff --git a/src/widgets/plex/proxy.js b/src/widgets/plex/proxy.js index d803306546f..e93e8709c5f 100644 --- a/src/widgets/plex/proxy.js +++ b/src/widgets/plex/proxy.js @@ -16,14 +16,14 @@ const tvCacheKey = `${proxyName}__tv`; const logger = createLogger(proxyName); async function getWidget(req) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return null; } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/pyload/proxy.js b/src/widgets/pyload/proxy.js index d9469d1cb0f..23809ebe55b 100644 --- a/src/widgets/pyload/proxy.js +++ b/src/widgets/pyload/proxy.js @@ -67,11 +67,11 @@ async function login(loginUrl, service, username, password = "") { } export default async function pyloadProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; try { if (group && service) { - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (widget) { const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); diff --git a/src/widgets/qbittorrent/proxy.js b/src/widgets/qbittorrent/proxy.js index e1a0f0552cb..36ebe419294 100644 --- a/src/widgets/qbittorrent/proxy.js +++ b/src/widgets/qbittorrent/proxy.js @@ -21,14 +21,14 @@ async function login(widget) { } export default async function qbittorrentProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/qnap/proxy.js b/src/widgets/qnap/proxy.js index 508c8a46ff1..4e6474872ce 100644 --- a/src/widgets/qnap/proxy.js +++ b/src/widgets/qnap/proxy.js @@ -77,14 +77,14 @@ async function apiCall(widget, endpoint, service) { } export default async function qnapProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); diff --git a/src/widgets/rutorrent/proxy.js b/src/widgets/rutorrent/proxy.js index 47c761916b3..d371d2ba8e8 100644 --- a/src/widgets/rutorrent/proxy.js +++ b/src/widgets/rutorrent/proxy.js @@ -45,10 +45,10 @@ const getTorrentInfo = (data) => ({ }); export default async function rutorrentProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (widget) { const api = widgets?.[widget.type]?.api; diff --git a/src/widgets/suwayomi/proxy.js b/src/widgets/suwayomi/proxy.js index d4d7167520b..082a5d6afd9 100644 --- a/src/widgets/suwayomi/proxy.js +++ b/src/widgets/suwayomi/proxy.js @@ -114,14 +114,14 @@ function extractCounts(responseJSON, fields) { } export default async function suwayomiProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/tdarr/proxy.js b/src/widgets/tdarr/proxy.js index 9e26fdc0697..04b5c04de2c 100644 --- a/src/widgets/tdarr/proxy.js +++ b/src/widgets/tdarr/proxy.js @@ -8,14 +8,14 @@ const proxyName = "tdarrProxyHandler"; const logger = createLogger(proxyName); export default async function tdarrProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/transmission/proxy.js b/src/widgets/transmission/proxy.js index 823def0545f..ce8d138ab42 100644 --- a/src/widgets/transmission/proxy.js +++ b/src/widgets/transmission/proxy.js @@ -11,14 +11,14 @@ const headerCacheKey = `${proxyName}__headers`; const logger = createLogger(proxyName); export default async function transmissionProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/unifi/proxy.js b/src/widgets/unifi/proxy.js index 98c98f37755..bef6f3403e6 100644 --- a/src/widgets/unifi/proxy.js +++ b/src/widgets/unifi/proxy.js @@ -14,7 +14,7 @@ const prefixCacheKey = `${proxyName}__prefix`; const logger = createLogger(proxyName); async function getWidget(req) { - const { group, service } = req.query; + const { group, service, name } = req.query; let widget = null; if (group === "unifi_console" && service === "unifi_console") { @@ -32,7 +32,7 @@ async function getWidget(req) { return null; } - widget = await getServiceWidget(group, service); + widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/urbackup/proxy.js b/src/widgets/urbackup/proxy.js index 94b8eeff6fe..09e8814abc2 100644 --- a/src/widgets/urbackup/proxy.js +++ b/src/widgets/urbackup/proxy.js @@ -3,8 +3,8 @@ import { UrbackupServer } from "urbackup-server-api"; import getServiceWidget from "utils/config/service-helpers"; export default async function urbackupProxyHandler(req, res) { - const { group, service } = req.query; - const serviceWidget = await getServiceWidget(group, service); + const { group, service, name } = req.query; + const serviceWidget = await getServiceWidget(group, service, name ? name : null); const server = new UrbackupServer({ url: serviceWidget.url, diff --git a/src/widgets/watchtower/proxy.js b/src/widgets/watchtower/proxy.js index b3155a1e937..71b787f7d9e 100644 --- a/src/widgets/watchtower/proxy.js +++ b/src/widgets/watchtower/proxy.js @@ -8,14 +8,14 @@ const proxyName = "watchtowerProxyHandler"; const logger = createLogger(proxyName); export default async function watchtowerProxyHandler(req, res) { - const { group, service, endpoint } = req.query; + const { group, service, endpoint, name } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/xteve/proxy.js b/src/widgets/xteve/proxy.js index 421f2b4999c..73487b98168 100644 --- a/src/widgets/xteve/proxy.js +++ b/src/widgets/xteve/proxy.js @@ -7,13 +7,13 @@ import getServiceWidget from "utils/config/service-helpers"; const logger = createLogger("xteveProxyHandler"); export default async function xteveProxyHandler(req, res) { - const { group, service } = req.query; + const { group, service, name } = req.query; if (!group || !service) { return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service); + const widget = await getServiceWidget(group, service, name ? name : null); const api = widgets?.[widget.type]?.api; if (!api) { return res.status(403).json({ error: "Service does not support API calls" }); From ec383d60bb5d9e2f8bcc7b3b0fb9942a1db52d78 Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 27 Nov 2024 02:04:47 -0800 Subject: [PATCH 4/6] Use index instead of name, lots of code cleanup --- docs/widgets/index.md | 14 +- src/components/services/item.jsx | 2 +- src/components/services/widget.jsx | 2 +- src/pages/api/services/proxy.js | 6 +- src/utils/config/service-helpers.js | 602 +++++++++++------------ src/utils/proxy/api-helpers.js | 2 +- src/utils/proxy/handlers/credentialed.js | 4 +- src/utils/proxy/handlers/generic.js | 4 +- src/utils/proxy/handlers/jsonrpc.js | 4 +- src/utils/proxy/handlers/synology.js | 4 +- src/widgets/audiobookshelf/proxy.js | 4 +- src/widgets/beszel/proxy.js | 4 +- src/widgets/calendar/proxy.js | 4 +- src/widgets/crowdsec/proxy.js | 4 +- src/widgets/deluge/proxy.js | 4 +- src/widgets/flood/proxy.js | 4 +- src/widgets/freshrss/proxy.js | 4 +- src/widgets/fritzbox/proxy.js | 4 +- src/widgets/gamedig/proxy.js | 4 +- src/widgets/homeassistant/proxy.js | 4 +- src/widgets/homebox/proxy.js | 4 +- src/widgets/homebridge/proxy.js | 4 +- src/widgets/jackett/proxy.js | 4 +- src/widgets/jdownloader/proxy.js | 4 +- src/widgets/kavita/proxy.js | 4 +- src/widgets/minecraft/proxy.js | 4 +- src/widgets/npm/proxy.js | 4 +- src/widgets/omada/proxy.js | 4 +- src/widgets/openmediavault/proxy.js | 4 +- src/widgets/openwrt/proxy.js | 4 +- src/widgets/photoprism/proxy.js | 4 +- src/widgets/pihole/proxy.js | 4 +- src/widgets/plex/proxy.js | 4 +- src/widgets/pyload/proxy.js | 4 +- src/widgets/qbittorrent/proxy.js | 4 +- src/widgets/qnap/proxy.js | 4 +- src/widgets/rutorrent/proxy.js | 4 +- src/widgets/suwayomi/proxy.js | 4 +- src/widgets/tdarr/proxy.js | 4 +- src/widgets/transmission/proxy.js | 4 +- src/widgets/unifi/proxy.js | 8 +- src/widgets/urbackup/proxy.js | 4 +- src/widgets/watchtower/proxy.js | 4 +- src/widgets/xteve/proxy.js | 4 +- 44 files changed, 389 insertions(+), 395 deletions(-) diff --git a/docs/widgets/index.md b/docs/widgets/index.md index faa30975cec..4bd45af712e 100644 --- a/docs/widgets/index.md +++ b/docs/widgets/index.md @@ -20,14 +20,12 @@ Service widgets are used to display the status of a service, often a web service server: localhost container: plex widgets: - - Tautulli: - type: tautulli - url: http://172.16.1.1:8181 - key: aabbccddeeffgghhiijjkkllmmnnoo - - UptimeKuma: - type: uptimekuma - url: http://172.16.1.2:8080 - slug: aaaaaaabbbbb + - type: tautulli + url: http://172.16.1.1:8181 + key: aabbccddeeffgghhiijjkkllmmnnoo + - type: uptimekuma + url: http://172.16.1.2:8080 + slug: aaaaaaabbbbb ``` ## Info Widgets diff --git a/src/components/services/item.jsx b/src/components/services/item.jsx index 09e744251b2..54560d6f250 100644 --- a/src/components/services/item.jsx +++ b/src/components/services/item.jsx @@ -155,7 +155,7 @@ export default function Item({ service, group, useEqualHeights }) { )} {service.widgets.map((widget) => ( - + ))} diff --git a/src/components/services/widget.jsx b/src/components/services/widget.jsx index 628ff8c25b3..61a21a6639a 100644 --- a/src/components/services/widget.jsx +++ b/src/components/services/widget.jsx @@ -8,7 +8,7 @@ export default function Widget({ widget, service }) { const ServiceWidget = components[widget.type]; - const fullService = service; + const fullService = Object.apply({}, service); fullService.widget = widget; if (ServiceWidget) { return ( diff --git a/src/pages/api/services/proxy.js b/src/pages/api/services/proxy.js index e7439ced520..3f8adc883b7 100644 --- a/src/pages/api/services/proxy.js +++ b/src/pages/api/services/proxy.js @@ -9,8 +9,8 @@ const logger = createLogger("servicesProxy"); export default async function handler(req, res) { try { - const { service, group, name } = req.query; - const serviceWidget = await getServiceWidget(group, service, name); + const { service, group, index } = req.query; + const serviceWidget = await getServiceWidget(group, service, index); let type = serviceWidget?.type; // exceptions @@ -41,7 +41,7 @@ export default async function handler(req, res) { const endpoint = mapping?.endpoint; const endpointProxy = mapping?.proxyHandler || serviceProxyHandler; - if (mapping.method && mapping.method !== req.method) { + if (mapping?.method && mapping.method !== req.method) { logger.debug("Unsupported method: %s", req.method); return res.status(403).json({ error: "Unsupported method" }); } diff --git a/src/utils/config/service-helpers.js b/src/utils/config/service-helpers.js index 2d7090656fe..e6ef6173e9d 100644 --- a/src/utils/config/service-helpers.js +++ b/src/utils/config/service-helpers.js @@ -354,317 +354,317 @@ export function cleanServiceGroups(groups) { if (typeof cleanedService.weight !== "number") { cleanedService.weight = 0; } - cleanedService.widgets = cleanedService.widgets ? cleanedService.widgets : []; - if (cleanedService.widget != undefined) cleanedService.widgets.push(cleanedService.widget); - if (cleanedService.widgets != []) { - cleanedService.widgets = cleanedService.widgets.map((widget) => { - // whitelisted set of keys to pass to the frontend - // alphabetical, grouped by widget(s) - const { - // all widgets - fields, - hideErrors, - type, - - // azuredevops - repositoryId, - userEmail, - - // beszel - systemId, - - // calendar - firstDayInWeek, - integrations, - maxEvents, - showTime, - previousDays, - view, - timezone, - - // coinmarketcap - currency, - defaultinterval, - slugs, - symbols, - - // customapi - mappings, - display, - - // diskstation - volume, - - // docker - container, - server, - - // emby, jellyfin - enableBlocks, - enableNowPlaying, - - // emby, jellyfin, tautulli - enableUser, - expandOneStreamToTwoRows, - showEpisodeNumber, - - // frigate - enableRecentEvents, - - // glances, immich, mealie, pihole, pfsense - version, - - // glances - chart, - metric, - pointsLimit, - diskUnits, - - // glances, customapi, iframe, prometheusmetric - refreshInterval, - - // hdhomerun - tuner, - - // healthchecks - uuid, - - // iframe - allowFullscreen, - allowPolicy, - allowScrolling, - classes, - loadingStrategy, - referrerPolicy, - src, - - // kopia - snapshotHost, - snapshotPath, - - // kubernetes - app, - namespace, - podSelector, - - // lubelogger - vehicleID, - - // mjpeg - fit, - stream, - - // openmediavault - method, - - // openwrt - interfaceName, - - // opnsense, pfsense - wan, - - // prometheusmetric - metrics, + if (!cleanedService.widgets) cleanedService.widgets = []; + if (cleanedService.widget) { + cleanedService.widgets.push(cleanedService.widget); + delete cleanedService.widget; + } + cleanedService.widgets = cleanedService.widgets.map((widgetData, index) => { + // whitelisted set of keys to pass to the frontend + // alphabetical, grouped by widget(s) + const { + // all widgets + fields, + hideErrors, + type, + + // azuredevops + repositoryId, + userEmail, + + // beszel + systemId, + + // calendar + firstDayInWeek, + integrations, + maxEvents, + showTime, + previousDays, + view, + timezone, + + // coinmarketcap + currency, + defaultinterval, + slugs, + symbols, + + // customapi + mappings, + display, - // proxmox - node, + // diskstation + volume, - // speedtest - bitratePrecision, + // docker + container, + server, - // sonarr, radarr - enableQueue, - - // stocks - watchlist, - showUSMarketStatus, + // emby, jellyfin + enableBlocks, + enableNowPlaying, + + // emby, jellyfin, tautulli + enableUser, + expandOneStreamToTwoRows, + showEpisodeNumber, + + // frigate + enableRecentEvents, + + // glances, immich, mealie, pihole, pfsense + version, + + // glances + chart, + metric, + pointsLimit, + diskUnits, + + // glances, customapi, iframe, prometheusmetric + refreshInterval, + + // hdhomerun + tuner, + + // healthchecks + uuid, + + // iframe + allowFullscreen, + allowPolicy, + allowScrolling, + classes, + loadingStrategy, + referrerPolicy, + src, + + // kopia + snapshotHost, + snapshotPath, + + // kubernetes + app, + namespace, + podSelector, + + // lubelogger + vehicleID, + + // mjpeg + fit, + stream, + + // openmediavault + method, + + // openwrt + interfaceName, + + // opnsense, pfsense + wan, - // truenas - enablePools, - nasType, + // prometheusmetric + metrics, - // unifi - site, + // proxmox + node, - // vikunja - enableTaskList, + // speedtest + bitratePrecision, - // wgeasy - threshold, + // sonarr, radarr + enableQueue, - // technitium - range, + // stocks + watchlist, + showUSMarketStatus, - // spoolman - spoolIds, - } = Object.keys(widget)[0] != "type" ? widget[Object.keys(widget)[0]] : widget; + // truenas + enablePools, + nasType, - let fieldsList = fields; - if (typeof fields === "string") { - try { - fieldsList = JSON.parse(fields); - } catch (e) { - logger.error("Invalid fields list detected in config for service '%s'", service.name); - fieldsList = null; - } - } + // unifi + site, - widget = { - type, - fields: fieldsList || null, - hide_errors: hideErrors || false, - service_name: service.name, - service_group: serviceGroup.name, - widget_name: Object.keys(widget)[0] != "type" ? Object.keys(widget)[0] : "", - }; - - if (type === "azuredevops") { - if (userEmail) widget.userEmail = userEmail; - if (repositoryId) widget.repositoryId = repositoryId; - } + // vikunja + enableTaskList, - if (type === "beszel") { - if (systemId) widget.systemId = systemId; - } + // wgeasy + threshold, - if (type === "coinmarketcap") { - if (currency) widget.currency = currency; - if (symbols) widget.symbols = symbols; - if (slugs) widget.slugs = slugs; - if (defaultinterval) widget.defaultinterval = defaultinterval; - } + // technitium + range, - if (type === "docker") { - if (server) widget.server = server; - if (container) widget.container = container; - } - if (type === "unifi") { - if (site) widget.site = site; - } - if (type === "proxmox") { - if (node) widget.node = node; - } - if (type === "kubernetes") { - if (namespace) widget.namespace = namespace; - if (app) widget.app = app; - if (podSelector) widget.podSelector = podSelector; - } - if (type === "iframe") { - if (src) widget.src = src; - if (classes) widget.classes = classes; - if (referrerPolicy) widget.referrerPolicy = referrerPolicy; - if (allowPolicy) widget.allowPolicy = allowPolicy; - if (allowFullscreen) widget.allowFullscreen = allowFullscreen; - if (loadingStrategy) widget.loadingStrategy = loadingStrategy; - if (allowScrolling) widget.allowScrolling = allowScrolling; - if (refreshInterval) widget.refreshInterval = refreshInterval; - } - if (["opnsense", "pfsense"].includes(type)) { - if (wan) widget.wan = wan; - } - if (["emby", "jellyfin"].includes(type)) { - if (enableBlocks !== undefined) widget.enableBlocks = JSON.parse(enableBlocks); - if (enableNowPlaying !== undefined) widget.enableNowPlaying = JSON.parse(enableNowPlaying); - } - if (["emby", "jellyfin", "tautulli"].includes(type)) { - if (expandOneStreamToTwoRows !== undefined) - widget.expandOneStreamToTwoRows = !!JSON.parse(expandOneStreamToTwoRows); - if (showEpisodeNumber !== undefined) widget.showEpisodeNumber = !!JSON.parse(showEpisodeNumber); - if (enableUser !== undefined) widget.enableUser = !!JSON.parse(enableUser); - } - if (["sonarr", "radarr"].includes(type)) { - if (enableQueue !== undefined) widget.enableQueue = JSON.parse(enableQueue); - } - if (type === "truenas") { - if (enablePools !== undefined) widget.enablePools = JSON.parse(enablePools); - if (nasType !== undefined) widget.nasType = nasType; - } - if (["diskstation", "qnap"].includes(type)) { - if (volume) widget.volume = volume; - } - if (type === "kopia") { - if (snapshotHost) widget.snapshotHost = snapshotHost; - if (snapshotPath) widget.snapshotPath = snapshotPath; - } - if (["glances", "immich", "mealie", "pfsense", "pihole"].includes(type)) { - if (version) widget.version = parseInt(version, 10); - } - if (type === "glances") { - if (metric) widget.metric = metric; - if (chart !== undefined) { - widget.chart = chart; - } else { - widget.chart = true; - } - if (refreshInterval) widget.refreshInterval = refreshInterval; - if (pointsLimit) widget.pointsLimit = pointsLimit; - if (diskUnits) widget.diskUnits = diskUnits; - } - if (type === "mjpeg") { - if (stream) widget.stream = stream; - if (fit) widget.fit = fit; - } - if (type === "openmediavault") { - if (method) widget.method = method; - } - if (type === "openwrt") { - if (interfaceName) widget.interfaceName = interfaceName; - } - if (type === "customapi") { - if (mappings) widget.mappings = mappings; - if (display) widget.display = display; - if (refreshInterval) widget.refreshInterval = refreshInterval; - } - if (type === "calendar") { - if (integrations) widget.integrations = integrations; - if (firstDayInWeek) widget.firstDayInWeek = firstDayInWeek; - if (view) widget.view = view; - if (maxEvents) widget.maxEvents = maxEvents; - if (previousDays) widget.previousDays = previousDays; - if (showTime) widget.showTime = showTime; - if (timezone) widget.timezone = timezone; - } - if (type === "hdhomerun") { - if (tuner !== undefined) widget.tuner = tuner; - } - if (type === "healthchecks") { - if (uuid !== undefined) widget.uuid = uuid; - } - if (type === "speedtest") { - if (bitratePrecision !== undefined) { - widget.bitratePrecision = parseInt(bitratePrecision, 10); - } - } - if (type === "stocks") { - if (watchlist) widget.watchlist = watchlist; - if (showUSMarketStatus) widget.showUSMarketStatus = showUSMarketStatus; - } - if (type === "wgeasy") { - if (threshold !== undefined) widget.threshold = parseInt(threshold, 10); - } - if (type === "frigate") { - if (enableRecentEvents !== undefined) widget.enableRecentEvents = enableRecentEvents; - } - if (type === "technitium") { - if (range !== undefined) widget.range = range; - } - if (type === "lubelogger") { - if (vehicleID !== undefined) widget.vehicleID = parseInt(vehicleID, 10); - } - if (type === "vikunja") { - if (enableTaskList !== undefined) widget.enableTaskList = !!enableTaskList; - } - if (type === "prometheusmetric") { - if (metrics) widget.metrics = metrics; - if (refreshInterval) widget.refreshInterval = refreshInterval; + // spoolman + spoolIds, + } = widgetData; + + let fieldsList = fields; + if (typeof fields === "string") { + try { + fieldsList = JSON.parse(fields); + } catch (e) { + logger.error("Invalid fields list detected in config for service '%s'", service.name); + fieldsList = null; } - if (type === "spoolman") { - if (spoolIds !== undefined) widget.spoolIds = spoolIds; + } + + const widget = { + type, + fields: fieldsList || null, + hide_errors: hideErrors || false, + service_name: service.name, + service_group: serviceGroup.name, + index, + }; + + if (type === "azuredevops") { + if (userEmail) widget.userEmail = userEmail; + if (repositoryId) widget.repositoryId = repositoryId; + } + + if (type === "beszel") { + if (systemId) widget.systemId = systemId; + } + + if (type === "coinmarketcap") { + if (currency) widget.currency = currency; + if (symbols) widget.symbols = symbols; + if (slugs) widget.slugs = slugs; + if (defaultinterval) widget.defaultinterval = defaultinterval; + } + + if (type === "docker") { + if (server) widget.server = server; + if (container) widget.container = container; + } + if (type === "unifi") { + if (site) widget.site = site; + } + if (type === "proxmox") { + if (node) widget.node = node; + } + if (type === "kubernetes") { + if (namespace) widget.namespace = namespace; + if (app) widget.app = app; + if (podSelector) widget.podSelector = podSelector; + } + if (type === "iframe") { + if (src) widget.src = src; + if (classes) widget.classes = classes; + if (referrerPolicy) widget.referrerPolicy = referrerPolicy; + if (allowPolicy) widget.allowPolicy = allowPolicy; + if (allowFullscreen) widget.allowFullscreen = allowFullscreen; + if (loadingStrategy) widget.loadingStrategy = loadingStrategy; + if (allowScrolling) widget.allowScrolling = allowScrolling; + if (refreshInterval) widget.refreshInterval = refreshInterval; + } + if (["opnsense", "pfsense"].includes(type)) { + if (wan) widget.wan = wan; + } + if (["emby", "jellyfin"].includes(type)) { + if (enableBlocks !== undefined) widget.enableBlocks = JSON.parse(enableBlocks); + if (enableNowPlaying !== undefined) widget.enableNowPlaying = JSON.parse(enableNowPlaying); + } + if (["emby", "jellyfin", "tautulli"].includes(type)) { + if (expandOneStreamToTwoRows !== undefined) + widget.expandOneStreamToTwoRows = !!JSON.parse(expandOneStreamToTwoRows); + if (showEpisodeNumber !== undefined) widget.showEpisodeNumber = !!JSON.parse(showEpisodeNumber); + if (enableUser !== undefined) widget.enableUser = !!JSON.parse(enableUser); + } + if (["sonarr", "radarr"].includes(type)) { + if (enableQueue !== undefined) widget.enableQueue = JSON.parse(enableQueue); + } + if (type === "truenas") { + if (enablePools !== undefined) widget.enablePools = JSON.parse(enablePools); + if (nasType !== undefined) widget.nasType = nasType; + } + if (["diskstation", "qnap"].includes(type)) { + if (volume) widget.volume = volume; + } + if (type === "kopia") { + if (snapshotHost) widget.snapshotHost = snapshotHost; + if (snapshotPath) widget.snapshotPath = snapshotPath; + } + if (["glances", "immich", "mealie", "pfsense", "pihole"].includes(type)) { + if (version) widget.version = parseInt(version, 10); + } + if (type === "glances") { + if (metric) widget.metric = metric; + if (chart !== undefined) { + widget.chart = chart; + } else { + widget.chart = true; + } + if (refreshInterval) widget.refreshInterval = refreshInterval; + if (pointsLimit) widget.pointsLimit = pointsLimit; + if (diskUnits) widget.diskUnits = diskUnits; + } + if (type === "mjpeg") { + if (stream) widget.stream = stream; + if (fit) widget.fit = fit; + } + if (type === "openmediavault") { + if (method) widget.method = method; + } + if (type === "openwrt") { + if (interfaceName) widget.interfaceName = interfaceName; + } + if (type === "customapi") { + if (mappings) widget.mappings = mappings; + if (display) widget.display = display; + if (refreshInterval) widget.refreshInterval = refreshInterval; + } + if (type === "calendar") { + if (integrations) widget.integrations = integrations; + if (firstDayInWeek) widget.firstDayInWeek = firstDayInWeek; + if (view) widget.view = view; + if (maxEvents) widget.maxEvents = maxEvents; + if (previousDays) widget.previousDays = previousDays; + if (showTime) widget.showTime = showTime; + if (timezone) widget.timezone = timezone; + } + if (type === "hdhomerun") { + if (tuner !== undefined) widget.tuner = tuner; + } + if (type === "healthchecks") { + if (uuid !== undefined) widget.uuid = uuid; + } + if (type === "speedtest") { + if (bitratePrecision !== undefined) { + widget.bitratePrecision = parseInt(bitratePrecision, 10); } - return widget; - }); - } - cleanedService.widget = null; + } + if (type === "stocks") { + if (watchlist) widget.watchlist = watchlist; + if (showUSMarketStatus) widget.showUSMarketStatus = showUSMarketStatus; + } + if (type === "wgeasy") { + if (threshold !== undefined) widget.threshold = parseInt(threshold, 10); + } + if (type === "frigate") { + if (enableRecentEvents !== undefined) widget.enableRecentEvents = enableRecentEvents; + } + if (type === "technitium") { + if (range !== undefined) widget.range = range; + } + if (type === "lubelogger") { + if (vehicleID !== undefined) widget.vehicleID = parseInt(vehicleID, 10); + } + if (type === "vikunja") { + if (enableTaskList !== undefined) widget.enableTaskList = !!enableTaskList; + } + if (type === "prometheusmetric") { + if (metrics) widget.metrics = metrics; + if (refreshInterval) widget.refreshInterval = refreshInterval; + } + if (type === "spoolman") { + if (spoolIds !== undefined) widget.spoolIds = spoolIds; + } + return widget; + }); return cleanedService; }), })); @@ -697,15 +697,11 @@ export async function getServiceItem(group, service) { return false; } -export default async function getServiceWidget(group, service, name = null) { +export default async function getServiceWidget(group, service, index) { const serviceItem = await getServiceItem(group, service); - if (serviceItem && (name == null || name === "undefined")) { - const { widget } = serviceItem; - return widget; - } - if (serviceItem && name != null && name !== "undefined") { - const { widgets } = serviceItem; - return widgets.filter((widget) => Object.keys(widget)[0] == name)[0][name]; + if (serviceItem) { + const { widget, widgets } = serviceItem; + return index > -1 && widgets ? widgets[index] : widget; } return false; } diff --git a/src/utils/proxy/api-helpers.js b/src/utils/proxy/api-helpers.js index c762d0ba691..a02ea623399 100644 --- a/src/utils/proxy/api-helpers.js +++ b/src/utils/proxy/api-helpers.js @@ -12,7 +12,7 @@ export function getURLSearchParams(widget, endpoint) { const params = new URLSearchParams({ group: widget.service_group, service: widget.service_name, - ...(widget.widget_name != "" && { name: widget.widget_name }), + index: widget.index, }); if (endpoint) { params.append("endpoint", endpoint); diff --git a/src/utils/proxy/handlers/credentialed.js b/src/utils/proxy/handlers/credentialed.js index 416e38fc418..cea95196a2d 100644 --- a/src/utils/proxy/handlers/credentialed.js +++ b/src/utils/proxy/handlers/credentialed.js @@ -9,10 +9,10 @@ import widgets from "widgets/widgets"; const logger = createLogger("credentialedProxyHandler"); export default async function credentialedProxyHandler(req, res, map) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widgets?.[widget.type]?.api) { return res.status(403).json({ error: "Service does not support API calls" }); diff --git a/src/utils/proxy/handlers/generic.js b/src/utils/proxy/handlers/generic.js index 7dc7fb5373c..2e788a98c37 100644 --- a/src/utils/proxy/handlers/generic.js +++ b/src/utils/proxy/handlers/generic.js @@ -8,10 +8,10 @@ import widgets from "widgets/widgets"; const logger = createLogger("genericProxyHandler"); export default async function genericProxyHandler(req, res, map) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widgets?.[widget.type]?.api) { return res.status(403).json({ error: "Service does not support API calls" }); diff --git a/src/utils/proxy/handlers/jsonrpc.js b/src/utils/proxy/handlers/jsonrpc.js index e95264bda11..f9fb1883270 100644 --- a/src/utils/proxy/handlers/jsonrpc.js +++ b/src/utils/proxy/handlers/jsonrpc.js @@ -65,10 +65,10 @@ export async function sendJsonRpcRequest(url, method, params, widget) { } export default async function jsonrpcProxyHandler(req, res) { - const { group, service, endpoint: method, name } = req.query; + const { group, service, endpoint: method, index } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); const api = widgets?.[widget.type]?.api; const [, mapping] = Object.entries(widgets?.[widget.type]?.mappings).find(([, value]) => value.endpoint === method); diff --git a/src/utils/proxy/handlers/synology.js b/src/utils/proxy/handlers/synology.js index e711db7ee97..030e53bad53 100644 --- a/src/utils/proxy/handlers/synology.js +++ b/src/utils/proxy/handlers/synology.js @@ -131,13 +131,13 @@ function toError(url, synologyError) { } export default async function synologyProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (!group || !service) { return res.status(400).json({ error: "Invalid proxy service type" }); } - const serviceWidget = await getServiceWidget(group, service, name ? name : null); + const serviceWidget = await getServiceWidget(group, service, index); const widget = widgets?.[serviceWidget.type]; const mapping = widget?.mappings?.[endpoint]; if (!widget.api || !mapping) { diff --git a/src/widgets/audiobookshelf/proxy.js b/src/widgets/audiobookshelf/proxy.js index 3c40ffd10ad..1a89736b149 100644 --- a/src/widgets/audiobookshelf/proxy.js +++ b/src/widgets/audiobookshelf/proxy.js @@ -23,14 +23,14 @@ async function retrieveFromAPI(url, key) { } export default async function audiobookshelfProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/beszel/proxy.js b/src/widgets/beszel/proxy.js index f25e63846fe..61bc969b421 100644 --- a/src/widgets/beszel/proxy.js +++ b/src/widgets/beszel/proxy.js @@ -34,10 +34,10 @@ async function login(loginUrl, username, password, service) { } export default async function beszelProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widgets?.[widget.type]?.api) { return res.status(403).json({ error: "Service does not support API calls" }); diff --git a/src/widgets/calendar/proxy.js b/src/widgets/calendar/proxy.js index 568edb656d8..d36f30c9092 100644 --- a/src/widgets/calendar/proxy.js +++ b/src/widgets/calendar/proxy.js @@ -5,10 +5,10 @@ import createLogger from "utils/logger"; const logger = createLogger("calendarProxyHandler"); export default async function calendarProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); const integration = widget.integrations?.find((i) => i.name === endpoint); if (integration) { diff --git a/src/widgets/crowdsec/proxy.js b/src/widgets/crowdsec/proxy.js index cc481064569..85803845b6c 100644 --- a/src/widgets/crowdsec/proxy.js +++ b/src/widgets/crowdsec/proxy.js @@ -35,14 +35,14 @@ async function login(widget, service) { } export default async function crowdsecProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (!group || !service) { logger.error("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget || !widgets[widget.type].api) { logger.error("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid widget configuration" }); diff --git a/src/widgets/deluge/proxy.js b/src/widgets/deluge/proxy.js index aa4ccb05d3e..6132969786f 100644 --- a/src/widgets/deluge/proxy.js +++ b/src/widgets/deluge/proxy.js @@ -40,14 +40,14 @@ function login(url, password) { } export default async function delugeProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/flood/proxy.js b/src/widgets/flood/proxy.js index d0e34430930..e0c101731d9 100644 --- a/src/widgets/flood/proxy.js +++ b/src/widgets/flood/proxy.js @@ -28,14 +28,14 @@ async function login(widget) { } export default async function floodProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/freshrss/proxy.js b/src/widgets/freshrss/proxy.js index 5ce98f346bf..881094bd720 100644 --- a/src/widgets/freshrss/proxy.js +++ b/src/widgets/freshrss/proxy.js @@ -74,14 +74,14 @@ async function apiCall(widget, endpoint, service) { } export default async function freshrssProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); diff --git a/src/widgets/fritzbox/proxy.js b/src/widgets/fritzbox/proxy.js index 3599229b1f0..d1a66d9794f 100644 --- a/src/widgets/fritzbox/proxy.js +++ b/src/widgets/fritzbox/proxy.js @@ -46,8 +46,8 @@ async function requestEndpoint(apiBaseUrl, service, action) { } export default async function fritzboxProxyHandler(req, res) { - const { group, service, name } = req.query; - const serviceWidget = await getServiceWidget(group, service, name ? name : null); + const { group, service, index } = req.query; + const serviceWidget = await getServiceWidget(group, service, index); if (!serviceWidget) { res.status(500).json({ error: { message: "Service widget not found" } }); diff --git a/src/widgets/gamedig/proxy.js b/src/widgets/gamedig/proxy.js index 819cd13d68a..ecf6e4c68e8 100644 --- a/src/widgets/gamedig/proxy.js +++ b/src/widgets/gamedig/proxy.js @@ -7,8 +7,8 @@ const proxyName = "gamedigProxyHandler"; const logger = createLogger(proxyName); export default async function gamedigProxyHandler(req, res) { - const { group, service, name } = req.query; - const serviceWidget = await getServiceWidget(group, service, name ? name : null); + const { group, service, index } = req.query; + const serviceWidget = await getServiceWidget(group, service, index); const url = new URL(serviceWidget.url); try { diff --git a/src/widgets/homeassistant/proxy.js b/src/widgets/homeassistant/proxy.js index 7719b13e3c3..e1f02ddbb8e 100644 --- a/src/widgets/homeassistant/proxy.js +++ b/src/widgets/homeassistant/proxy.js @@ -62,14 +62,14 @@ async function getQuery(query, { url, key }) { } export default async function homeassistantProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); diff --git a/src/widgets/homebox/proxy.js b/src/widgets/homebox/proxy.js index 0f6d6e7e14e..c91ce5528cd 100644 --- a/src/widgets/homebox/proxy.js +++ b/src/widgets/homebox/proxy.js @@ -68,14 +68,14 @@ async function apiCall(widget, endpoint, service) { } export default async function homeboxProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); diff --git a/src/widgets/homebridge/proxy.js b/src/widgets/homebridge/proxy.js index 0985b2696cb..4da9197b00e 100644 --- a/src/widgets/homebridge/proxy.js +++ b/src/widgets/homebridge/proxy.js @@ -71,14 +71,14 @@ async function apiCall(widget, endpoint, service) { } export default async function homebridgeProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/jackett/proxy.js b/src/widgets/jackett/proxy.js index 4c3b02fbe35..035309b3632 100644 --- a/src/widgets/jackett/proxy.js +++ b/src/widgets/jackett/proxy.js @@ -25,14 +25,14 @@ async function fetchJackettCookie(widget, loginURL) { } export default async function jackettProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (!group || !service) { logger.error("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget || !widgets[widget.type].api) { logger.error("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid widget configuration" }); diff --git a/src/widgets/jdownloader/proxy.js b/src/widgets/jdownloader/proxy.js index 77a7a65ffc2..ae8c845ca41 100644 --- a/src/widgets/jdownloader/proxy.js +++ b/src/widgets/jdownloader/proxy.js @@ -12,12 +12,12 @@ const proxyName = "jdownloaderProxyHandler"; const logger = createLogger(proxyName); async function getWidget(req) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return null; } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return null; diff --git a/src/widgets/kavita/proxy.js b/src/widgets/kavita/proxy.js index ef991037fd4..1c41c45f1dc 100644 --- a/src/widgets/kavita/proxy.js +++ b/src/widgets/kavita/proxy.js @@ -70,14 +70,14 @@ async function apiCall(widget, endpoint, service) { } export default async function KavitaProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); diff --git a/src/widgets/minecraft/proxy.js b/src/widgets/minecraft/proxy.js index 17d845ef553..98d1be88c72 100644 --- a/src/widgets/minecraft/proxy.js +++ b/src/widgets/minecraft/proxy.js @@ -7,8 +7,8 @@ const proxyName = "minecraftProxyHandler"; const logger = createLogger(proxyName); export default async function minecraftProxyHandler(req, res) { - const { group, service, name } = req.query; - const serviceWidget = await getServiceWidget(group, service, name ? name : null); + const { group, service, index } = req.query; + const serviceWidget = await getServiceWidget(group, service, index); const url = new URL(serviceWidget.url); try { const pingResponse = await pingWithPromise(url.hostname, url.port || 25565); diff --git a/src/widgets/npm/proxy.js b/src/widgets/npm/proxy.js index d672b35f65b..6c7ba09ef36 100644 --- a/src/widgets/npm/proxy.js +++ b/src/widgets/npm/proxy.js @@ -36,10 +36,10 @@ async function login(loginUrl, username, password, service) { } export default async function npmProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widgets?.[widget.type]?.api) { return res.status(403).json({ error: "Service does not support API calls" }); diff --git a/src/widgets/omada/proxy.js b/src/widgets/omada/proxy.js index 5d9110d9c93..f4da129360a 100644 --- a/src/widgets/omada/proxy.js +++ b/src/widgets/omada/proxy.js @@ -33,10 +33,10 @@ async function login(loginUrl, username, password, controllerVersionMajor) { } export default async function omadaProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (widget) { const { url } = widget; diff --git a/src/widgets/openmediavault/proxy.js b/src/widgets/openmediavault/proxy.js index 9463ffce994..9cda42e867e 100644 --- a/src/widgets/openmediavault/proxy.js +++ b/src/widgets/openmediavault/proxy.js @@ -12,14 +12,14 @@ const BG_POLL_PERIOD = 500; const logger = createLogger(PROXY_NAME); async function getWidget(req) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return null; } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/openwrt/proxy.js b/src/widgets/openwrt/proxy.js index 197b43965a9..0a0da3ff572 100644 --- a/src/widgets/openwrt/proxy.js +++ b/src/widgets/openwrt/proxy.js @@ -17,14 +17,14 @@ const PARAMS = { }; async function getWidget(req) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return null; } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/photoprism/proxy.js b/src/widgets/photoprism/proxy.js index 1d849e4b589..fe5096b3a7f 100644 --- a/src/widgets/photoprism/proxy.js +++ b/src/widgets/photoprism/proxy.js @@ -6,14 +6,14 @@ import createLogger from "utils/logger"; const logger = createLogger("photoprismProxyHandler"); export default async function photoprismProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/pihole/proxy.js b/src/widgets/pihole/proxy.js index bf1172353f1..bf24624d4a3 100644 --- a/src/widgets/pihole/proxy.js +++ b/src/widgets/pihole/proxy.js @@ -33,7 +33,7 @@ async function login(widget, service) { } export default async function piholeProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; let endpoint = "stats/summary"; if (!group || !service) { @@ -41,7 +41,7 @@ export default async function piholeProxyHandler(req, res) { return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.error("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid widget configuration" }); diff --git a/src/widgets/plex/proxy.js b/src/widgets/plex/proxy.js index e93e8709c5f..2956f28094a 100644 --- a/src/widgets/plex/proxy.js +++ b/src/widgets/plex/proxy.js @@ -16,14 +16,14 @@ const tvCacheKey = `${proxyName}__tv`; const logger = createLogger(proxyName); async function getWidget(req) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return null; } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/pyload/proxy.js b/src/widgets/pyload/proxy.js index 23809ebe55b..a380c865d6b 100644 --- a/src/widgets/pyload/proxy.js +++ b/src/widgets/pyload/proxy.js @@ -67,11 +67,11 @@ async function login(loginUrl, service, username, password = "") { } export default async function pyloadProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; try { if (group && service) { - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (widget) { const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); diff --git a/src/widgets/qbittorrent/proxy.js b/src/widgets/qbittorrent/proxy.js index 36ebe419294..aead7582002 100644 --- a/src/widgets/qbittorrent/proxy.js +++ b/src/widgets/qbittorrent/proxy.js @@ -21,14 +21,14 @@ async function login(widget) { } export default async function qbittorrentProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/qnap/proxy.js b/src/widgets/qnap/proxy.js index 4e6474872ce..07917d28c63 100644 --- a/src/widgets/qnap/proxy.js +++ b/src/widgets/qnap/proxy.js @@ -77,14 +77,14 @@ async function apiCall(widget, endpoint, service) { } export default async function qnapProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); diff --git a/src/widgets/rutorrent/proxy.js b/src/widgets/rutorrent/proxy.js index d371d2ba8e8..e0ae44fec63 100644 --- a/src/widgets/rutorrent/proxy.js +++ b/src/widgets/rutorrent/proxy.js @@ -45,10 +45,10 @@ const getTorrentInfo = (data) => ({ }); export default async function rutorrentProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (group && service) { - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (widget) { const api = widgets?.[widget.type]?.api; diff --git a/src/widgets/suwayomi/proxy.js b/src/widgets/suwayomi/proxy.js index 082a5d6afd9..def811ccf9d 100644 --- a/src/widgets/suwayomi/proxy.js +++ b/src/widgets/suwayomi/proxy.js @@ -114,14 +114,14 @@ function extractCounts(responseJSON, fields) { } export default async function suwayomiProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/tdarr/proxy.js b/src/widgets/tdarr/proxy.js index 04b5c04de2c..88da30fdf99 100644 --- a/src/widgets/tdarr/proxy.js +++ b/src/widgets/tdarr/proxy.js @@ -8,14 +8,14 @@ const proxyName = "tdarrProxyHandler"; const logger = createLogger(proxyName); export default async function tdarrProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/transmission/proxy.js b/src/widgets/transmission/proxy.js index ce8d138ab42..8b8049bc870 100644 --- a/src/widgets/transmission/proxy.js +++ b/src/widgets/transmission/proxy.js @@ -11,14 +11,14 @@ const headerCacheKey = `${proxyName}__headers`; const logger = createLogger(proxyName); export default async function transmissionProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/unifi/proxy.js b/src/widgets/unifi/proxy.js index bef6f3403e6..559065e3313 100644 --- a/src/widgets/unifi/proxy.js +++ b/src/widgets/unifi/proxy.js @@ -14,13 +14,13 @@ const prefixCacheKey = `${proxyName}__prefix`; const logger = createLogger(proxyName); async function getWidget(req) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; let widget = null; if (group === "unifi_console" && service === "unifi_console") { // info widget - const index = req.query?.query ? JSON.parse(req.query.query).index : undefined; - widget = await getPrivateWidgetOptions("unifi_console", index); + const infowidgetIndex = req.query?.query ? JSON.parse(req.query.query).index : undefined; + widget = await getPrivateWidgetOptions("unifi_console", infowidgetIndex); if (!widget) { logger.debug("Error retrieving settings for this Unifi widget"); return null; @@ -32,7 +32,7 @@ async function getWidget(req) { return null; } - widget = await getServiceWidget(group, service, name ? name : null); + widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/urbackup/proxy.js b/src/widgets/urbackup/proxy.js index 09e8814abc2..4e7a0a8d57a 100644 --- a/src/widgets/urbackup/proxy.js +++ b/src/widgets/urbackup/proxy.js @@ -3,8 +3,8 @@ import { UrbackupServer } from "urbackup-server-api"; import getServiceWidget from "utils/config/service-helpers"; export default async function urbackupProxyHandler(req, res) { - const { group, service, name } = req.query; - const serviceWidget = await getServiceWidget(group, service, name ? name : null); + const { group, service, index } = req.query; + const serviceWidget = await getServiceWidget(group, service, index); const server = new UrbackupServer({ url: serviceWidget.url, diff --git a/src/widgets/watchtower/proxy.js b/src/widgets/watchtower/proxy.js index 71b787f7d9e..588d08ee049 100644 --- a/src/widgets/watchtower/proxy.js +++ b/src/widgets/watchtower/proxy.js @@ -8,14 +8,14 @@ const proxyName = "watchtowerProxyHandler"; const logger = createLogger(proxyName); export default async function watchtowerProxyHandler(req, res) { - const { group, service, endpoint, name } = req.query; + const { group, service, endpoint, index } = req.query; if (!group || !service) { logger.debug("Invalid or missing service '%s' or group '%s'", service, group); return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); if (!widget) { logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group); diff --git a/src/widgets/xteve/proxy.js b/src/widgets/xteve/proxy.js index 73487b98168..453e364569f 100644 --- a/src/widgets/xteve/proxy.js +++ b/src/widgets/xteve/proxy.js @@ -7,13 +7,13 @@ import getServiceWidget from "utils/config/service-helpers"; const logger = createLogger("xteveProxyHandler"); export default async function xteveProxyHandler(req, res) { - const { group, service, name } = req.query; + const { group, service, index } = req.query; if (!group || !service) { return res.status(400).json({ error: "Invalid proxy service type" }); } - const widget = await getServiceWidget(group, service, name ? name : null); + const widget = await getServiceWidget(group, service, index); const api = widgets?.[widget.type]?.api; if (!api) { return res.status(403).json({ error: "Service does not support API calls" }); From 9dad64985de816f1002294eecc7bdd0e45f1796b Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 27 Nov 2024 02:07:42 -0800 Subject: [PATCH 5/6] Update service-widgets.md --- docs/configs/service-widgets.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/configs/service-widgets.md b/docs/configs/service-widgets.md index 8397e7c97ac..df696f618d6 100644 --- a/docs/configs/service-widgets.md +++ b/docs/configs/service-widgets.md @@ -24,9 +24,7 @@ Using Emby as an example, this is how you would attach the Emby service widget. ## Multiple Widgets -Each service can have multiple widgets attached to it. Each widget needs a unique name. - -Using Emby as an example, here is how you would attack the Emby service widget alongside an uptime widget. +Each service can have multiple widgets attached to it, for example: ```yaml - Emby: @@ -34,14 +32,12 @@ Using Emby as an example, here is how you would attack the Emby service widget a href: http://emby.host.or.ip/ description: Movies & TV Shows widgets: - - Emby: - type: emby - url: http://emby.host.or.ip - key: apikeyapikeyapikeyapikeyapikey - - Uptime: - type: uptimekuma - url: http://uptimekuma.host.or.ip:port - slug: statuspageslug + - type: emby + url: http://emby.host.or.ip + key: apikeyapikeyapikeyapikeyapikey + - type: uptimekuma + url: http://uptimekuma.host.or.ip:port + slug: statuspageslug ``` ## Field Visibility From 0ad0616325efdeeca2819b132bd8581b0762e4cf Mon Sep 17 00:00:00 2001 From: shamoon <4887959+shamoon@users.noreply.github.com> Date: Wed, 27 Nov 2024 02:23:09 -0800 Subject: [PATCH 6/6] Add docker info for multiple widgets --- docs/configs/docker.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/configs/docker.md b/docs/configs/docker.md index 51f6b523807..7cea1fdce9b 100644 --- a/docs/configs/docker.md +++ b/docs/configs/docker.md @@ -153,6 +153,18 @@ labels: - homepage.widget.fields=["field1","field2"] # optional ``` +Multiple widgets can be specified by incrementing the index, e.g. + +```yaml +labels: ... + - homepage.widget[0].type=emby + - homepage.widget[0].url=http://emby.home + - homepage.widget[0].key=yourembyapikeyhere + - homepage.widget[1].type=uptimekuma + - homepage.widget[1].url=http://uptimekuma.home + - homepage.widget[1].slug=youreventslughere +``` + You can add specify fields for e.g. the [CustomAPI](../widgets/services/customapi.md) widget by using array-style dot notation: ```yaml