mirror of
				https://github.com/karl0ss/homepage.git
				synced 2025-10-31 06:24:02 +00:00 
			
		
		
		
	Enhancement: multiple widgets per service (#4338)
This commit is contained in:
		
							parent
							
								
									385511f773
								
							
						
					
					
						commit
						907abee1aa
					
				| @ -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 | ||||
|  | ||||
| @ -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. | ||||
|  | ||||
| @ -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 | ||||
|  | ||||
| @ -154,7 +154,9 @@ export default function Item({ service, group, useEqualHeights }) { | ||||
|           </div> | ||||
|         )} | ||||
| 
 | ||||
|         {service.widget && <Widget service={service} />} | ||||
|         {service.widgets.map((widget) => ( | ||||
|           <Widget widget={widget} service={service} key={widget.index} /> | ||||
|         ))} | ||||
|       </div> | ||||
|     </li> | ||||
|   ); | ||||
|  | ||||
| @ -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 ( | ||||
|       <ErrorBoundary> | ||||
|         <ServiceWidget service={service} /> | ||||
|         <ServiceWidget service={fullService} /> | ||||
|       </ErrorBoundary> | ||||
|     ); | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <div className="bg-theme-200/50 dark:bg-theme-900/20 rounded m-1 flex-1 flex flex-col items-center justify-center p-1 service-missing"> | ||||
|       <div className="font-thin text-sm">{t("widget.missing_type", { type: service.widget.type })}</div> | ||||
|       <div className="font-thin text-sm">{t("widget.missing_type", { type: widget.type })}</div> | ||||
|     </div> | ||||
|   ); | ||||
| } | ||||
|  | ||||
| @ -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" }); | ||||
|         } | ||||
|  | ||||
| @ -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; | ||||
| } | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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) { | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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" } }); | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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 })); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
| @ -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; | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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, | ||||
|  | ||||
| @ -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); | ||||
|  | ||||
| @ -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" }); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 shamoon
						shamoon