diff --git a/docs/configs/docker.md b/docs/configs/docker.md
index 51f6b523..7cea1fdc 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
diff --git a/docs/configs/service-widgets.md b/docs/configs/service-widgets.md
index 9c54964e..df696f61 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,24 @@ 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, for example:
+
+```yaml
+- Emby:
+ icon: emby.png
+ href: http://emby.host.or.ip/
+ description: Movies & TV Shows
+ widgets:
+ - type: emby
+ url: http://emby.host.or.ip
+ key: apikeyapikeyapikeyapikeyapikey
+ - 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 8b81ee40..4bd45af7 100644
--- a/docs/widgets/index.md
+++ b/docs/widgets/index.md
@@ -19,10 +19,13 @@ 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:
+ - 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 a38dfaa3..54560d6f 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 292b2b1c..61a21a66 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 = Object.apply({}, 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 90280c3d..3f8adc88 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, 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 ea82c735..e6ef6173 100644
--- a/src/utils/config/service-helpers.js
+++ b/src/utils/config/service-helpers.js
@@ -354,8 +354,12 @@ export function cleanServiceGroups(groups) {
if (typeof cleanedService.weight !== "number") {
cleanedService.weight = 0;
}
-
+ 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 {
@@ -495,7 +499,7 @@ export function cleanServiceGroups(groups) {
// spoolman
spoolIds,
- } = cleanedService.widget;
+ } = widgetData;
let fieldsList = fields;
if (typeof fields === "string") {
@@ -507,160 +511,160 @@ export function cleanServiceGroups(groups) {
}
}
- cleanedService.widget = {
+ const widget = {
type,
fields: fieldsList || null,
hide_errors: hideErrors || false,
service_name: service.name,
service_group: serviceGroup.name,
+ index,
};
if (type === "azuredevops") {
- if (userEmail) cleanedService.widget.userEmail = userEmail;
- if (repositoryId) cleanedService.widget.repositoryId = repositoryId;
+ if (userEmail) widget.userEmail = userEmail;
+ if (repositoryId) widget.repositoryId = repositoryId;
}
if (type === "beszel") {
- if (systemId) cleanedService.widget.systemId = systemId;
+ 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 (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 (server) widget.server = server;
+ if (container) widget.container = container;
}
if (type === "unifi") {
- if (site) cleanedService.widget.site = site;
+ if (site) widget.site = site;
}
if (type === "proxmox") {
- if (node) cleanedService.widget.node = node;
+ if (node) 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 (namespace) widget.namespace = namespace;
+ if (app) widget.app = app;
+ if (podSelector) 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 (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) cleanedService.widget.wan = wan;
+ if (wan) 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 (enableBlocks !== undefined) widget.enableBlocks = JSON.parse(enableBlocks);
+ if (enableNowPlaying !== undefined) 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);
+ 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) cleanedService.widget.enableQueue = JSON.parse(enableQueue);
+ if (enableQueue !== undefined) 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 (enablePools !== undefined) widget.enablePools = JSON.parse(enablePools);
+ if (nasType !== undefined) widget.nasType = nasType;
}
if (["diskstation", "qnap"].includes(type)) {
- if (volume) cleanedService.widget.volume = volume;
+ if (volume) widget.volume = volume;
}
if (type === "kopia") {
- if (snapshotHost) cleanedService.widget.snapshotHost = snapshotHost;
- if (snapshotPath) cleanedService.widget.snapshotPath = snapshotPath;
+ if (snapshotHost) widget.snapshotHost = snapshotHost;
+ if (snapshotPath) widget.snapshotPath = snapshotPath;
}
if (["glances", "immich", "mealie", "pfsense", "pihole"].includes(type)) {
- if (version) cleanedService.widget.version = parseInt(version, 10);
+ if (version) widget.version = parseInt(version, 10);
}
if (type === "glances") {
- if (metric) cleanedService.widget.metric = metric;
+ if (metric) widget.metric = metric;
if (chart !== undefined) {
- cleanedService.widget.chart = chart;
+ widget.chart = chart;
} else {
- cleanedService.widget.chart = true;
+ widget.chart = true;
}
- if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval;
- if (pointsLimit) cleanedService.widget.pointsLimit = pointsLimit;
- if (diskUnits) cleanedService.widget.diskUnits = diskUnits;
+ if (refreshInterval) widget.refreshInterval = refreshInterval;
+ if (pointsLimit) widget.pointsLimit = pointsLimit;
+ if (diskUnits) widget.diskUnits = diskUnits;
}
if (type === "mjpeg") {
- if (stream) cleanedService.widget.stream = stream;
- if (fit) cleanedService.widget.fit = fit;
+ if (stream) widget.stream = stream;
+ if (fit) widget.fit = fit;
}
if (type === "openmediavault") {
- if (method) cleanedService.widget.method = method;
+ if (method) widget.method = method;
}
if (type === "openwrt") {
- if (interfaceName) cleanedService.widget.interfaceName = interfaceName;
+ if (interfaceName) 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 (mappings) widget.mappings = mappings;
+ if (display) widget.display = display;
+ if (refreshInterval) 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 (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) cleanedService.widget.tuner = tuner;
+ if (tuner !== undefined) widget.tuner = tuner;
}
if (type === "healthchecks") {
- if (uuid !== undefined) cleanedService.widget.uuid = uuid;
+ if (uuid !== undefined) widget.uuid = uuid;
}
if (type === "speedtest") {
if (bitratePrecision !== undefined) {
- cleanedService.widget.bitratePrecision = parseInt(bitratePrecision, 10);
+ widget.bitratePrecision = parseInt(bitratePrecision, 10);
}
}
if (type === "stocks") {
- if (watchlist) cleanedService.widget.watchlist = watchlist;
- if (showUSMarketStatus) cleanedService.widget.showUSMarketStatus = showUSMarketStatus;
+ if (watchlist) widget.watchlist = watchlist;
+ if (showUSMarketStatus) widget.showUSMarketStatus = showUSMarketStatus;
}
if (type === "wgeasy") {
- if (threshold !== undefined) cleanedService.widget.threshold = parseInt(threshold, 10);
+ if (threshold !== undefined) widget.threshold = parseInt(threshold, 10);
}
if (type === "frigate") {
- if (enableRecentEvents !== undefined) cleanedService.widget.enableRecentEvents = enableRecentEvents;
+ if (enableRecentEvents !== undefined) widget.enableRecentEvents = enableRecentEvents;
}
if (type === "technitium") {
- if (range !== undefined) cleanedService.widget.range = range;
+ if (range !== undefined) widget.range = range;
}
if (type === "lubelogger") {
- if (vehicleID !== undefined) cleanedService.widget.vehicleID = parseInt(vehicleID, 10);
+ if (vehicleID !== undefined) widget.vehicleID = parseInt(vehicleID, 10);
}
if (type === "vikunja") {
- if (enableTaskList !== undefined) cleanedService.widget.enableTaskList = !!enableTaskList;
+ if (enableTaskList !== undefined) widget.enableTaskList = !!enableTaskList;
}
if (type === "prometheusmetric") {
- if (metrics) cleanedService.widget.metrics = metrics;
- if (refreshInterval) cleanedService.widget.refreshInterval = refreshInterval;
+ if (metrics) widget.metrics = metrics;
+ if (refreshInterval) widget.refreshInterval = refreshInterval;
}
if (type === "spoolman") {
- if (spoolIds !== undefined) cleanedService.widget.spoolIds = spoolIds;
+ if (spoolIds !== undefined) widget.spoolIds = spoolIds;
}
- }
-
+ return widget;
+ });
return cleanedService;
}),
}));
@@ -693,12 +697,11 @@ export async function getServiceItem(group, service) {
return false;
}
-export default async function getServiceWidget(group, service) {
+export default async function getServiceWidget(group, service, index) {
const serviceItem = await getServiceItem(group, service);
if (serviceItem) {
- const { widget } = serviceItem;
- return widget;
+ 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 8e0682db..a02ea623 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,
+ 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 cbe0422a..cea95196 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, index } = req.query;
if (group && service) {
- const widget = await getServiceWidget(group, service);
+ 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 c6b9236b..2e788a98 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, index } = req.query;
if (group && service) {
- const widget = await getServiceWidget(group, service);
+ 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 3974dbdc..f9fb1883 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, index } = req.query;
if (group && service) {
- const widget = await getServiceWidget(group, service);
+ 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 be44e810..030e53ba 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, index } = 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, 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 9701c1fe..1a89736b 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, 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);
+ 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 04083e42..61bc969b 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, index } = req.query;
if (group && service) {
- const widget = await getServiceWidget(group, service);
+ 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 cf754424..d36f30c9 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, index } = req.query;
if (group && service) {
- const widget = await getServiceWidget(group, service);
+ 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 e78fbc5e..85803845 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, 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);
+ 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 b86873a8..61329697 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, 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);
+ 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 3345ad7b..e0c10173 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, 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);
+ 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 c08e5c87..881094bd 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, 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);
+ 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 a0a22d8b..d1a66d97 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, 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 05fa615c..ecf6e4c6 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, 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 fe488f86..e1f02ddb 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, 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);
+ 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 0d6fdf13..c91ce552 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, 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);
+ 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 17dc8635..4da9197b 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, 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);
+ 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 5292695f..035309b3 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, 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);
+ 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 88a92d95..ae8c845c 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, 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);
+ 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 b8e9813f..1c41c45f 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, 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);
+ 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 f7bac9d4..98d1be88 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, 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 978254f8..6c7ba09e 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, index } = req.query;
if (group && service) {
- const widget = await getServiceWidget(group, service);
+ 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 8e8994a5..f4da1293 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, index } = req.query;
if (group && service) {
- const widget = await getServiceWidget(group, service);
+ 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 e1f97a56..9cda42e8 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, 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);
+ 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 977db8ca..0a0da3ff 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, 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);
+ 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 509bfa0c..fe5096b3 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, 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);
+ 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 35873fa9..bf24624d 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, 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);
+ 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 d8033065..2956f280 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, 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);
+ 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 d9469d1c..a380c865 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, index } = req.query;
try {
if (group && service) {
- const widget = await getServiceWidget(group, service);
+ 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 e1a0f055..aead7582 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, 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);
+ 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 508c8a46..07917d28 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, 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);
+ 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 47c76191..e0ae44fe 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, index } = req.query;
if (group && service) {
- const widget = await getServiceWidget(group, service);
+ 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 d4d71675..def811cc 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, 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);
+ 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 9e26fdc0..88da30fd 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, 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);
+ 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 823def05..8b8049bc 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, 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);
+ 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 98c98f37..559065e3 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 } = 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);
+ 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 94b8eeff..4e7a0a8d 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, 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 b3155a1e..588d08ee 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, 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);
+ 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 421f2b49..453e3645 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, index } = 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, index);
const api = widgets?.[widget.type]?.api;
if (!api) {
return res.status(403).json({ error: "Service does not support API calls" });