mirror of
				https://github.com/karl0ss/homepage.git
				synced 2025-10-31 14:34:00 +00:00 
			
		
		
		
	Merge pull request #496 from stuffinator/pyload_widget
Add Pyload widget
This commit is contained in:
		
						commit
						b719a9f6a0
					
				| @ -319,5 +319,11 @@ | |||||||
|         "uptime": "Uptime", |         "uptime": "Uptime", | ||||||
|         "alerts": "Alerts", |         "alerts": "Alerts", | ||||||
|         "time": "{{value, number(style: unit; unitDisplay: long;)}}" |         "time": "{{value, number(style: unit; unitDisplay: long;)}}" | ||||||
|  |     }, | ||||||
|  |     "pyload": { | ||||||
|  |         "speed": "Speed", | ||||||
|  |         "active": "Active", | ||||||
|  |         "queue": "Queue", | ||||||
|  |         "total": "Total" | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ const components = { | |||||||
|   portainer: dynamic(() => import("./portainer/component")), |   portainer: dynamic(() => import("./portainer/component")), | ||||||
|   prowlarr: dynamic(() => import("./prowlarr/component")), |   prowlarr: dynamic(() => import("./prowlarr/component")), | ||||||
|   proxmox: dynamic(() => import("./proxmox/component")), |   proxmox: dynamic(() => import("./proxmox/component")), | ||||||
|  |   pyload: dynamic(() => import("./pyload/component")), | ||||||
|   qbittorrent: dynamic(() => import("./qbittorrent/component")), |   qbittorrent: dynamic(() => import("./qbittorrent/component")), | ||||||
|   radarr: dynamic(() => import("./radarr/component")), |   radarr: dynamic(() => import("./radarr/component")), | ||||||
|   readarr: dynamic(() => import("./readarr/component")), |   readarr: dynamic(() => import("./readarr/component")), | ||||||
|  | |||||||
							
								
								
									
										35
									
								
								src/widgets/pyload/component.jsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/widgets/pyload/component.jsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | import { useTranslation } from 'next-i18next' | ||||||
|  | 
 | ||||||
|  | import Container from "components/services/widget/container"; | ||||||
|  | import Block from "components/services/widget/block"; | ||||||
|  | import useWidgetAPI from "utils/proxy/use-widget-api"; | ||||||
|  | 
 | ||||||
|  | export default function Component({ service }) { | ||||||
|  |   const { t } = useTranslation(); | ||||||
|  |   const { widget } = service; | ||||||
|  |   const { data: pyloadData, error: pyloadError } = useWidgetAPI(widget, "status"); | ||||||
|  | 
 | ||||||
|  |   if (pyloadError || pyloadData?.error) { | ||||||
|  |     return <Container error={t("widget.api_error")} />; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (!pyloadData) { | ||||||
|  |     return ( | ||||||
|  |       <Container service={service}> | ||||||
|  |         <Block label="pyload.speed" /> | ||||||
|  |         <Block label="pyload.active" /> | ||||||
|  |         <Block label="pyload.queue" /> | ||||||
|  |         <Block label="pyload.total" /> | ||||||
|  |       </Container> | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return ( | ||||||
|  |     <Container service={service}> | ||||||
|  |       <Block label="pyload.speed" value={t("common.bitrate", { value: pyloadData.speed })} /> | ||||||
|  |       <Block label="pyload.active" value={t("common.number", { value: pyloadData.active })} /> | ||||||
|  |       <Block label="pyload.queue" value={t("common.number", { value: pyloadData.queue })} /> | ||||||
|  |       <Block label="pyload.total" value={t("common.number", { value: pyloadData.total })} /> | ||||||
|  |     </Container> | ||||||
|  |   ); | ||||||
|  | } | ||||||
							
								
								
									
										75
									
								
								src/widgets/pyload/proxy.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										75
									
								
								src/widgets/pyload/proxy.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,75 @@ | |||||||
|  | import cache from 'memory-cache'; | ||||||
|  | 
 | ||||||
|  | import getServiceWidget from 'utils/config/service-helpers'; | ||||||
|  | import { formatApiCall } from 'utils/proxy/api-helpers'; | ||||||
|  | import widgets from 'widgets/widgets'; | ||||||
|  | import createLogger from 'utils/logger'; | ||||||
|  | import { httpProxy } from 'utils/proxy/http'; | ||||||
|  | 
 | ||||||
|  | const proxyName = 'pyloadProxyHandler'; | ||||||
|  | const logger = createLogger(proxyName); | ||||||
|  | const sessionCacheKey = `${proxyName}__sessionId`; | ||||||
|  | 
 | ||||||
|  | async function fetchFromPyloadAPI(url, sessionId, params) { | ||||||
|  |   const options = { | ||||||
|  |     body: params | ||||||
|  |       ? Object.keys(params) | ||||||
|  |           .map((prop) => `${prop}=${params[prop]}`) | ||||||
|  |           .join('&') | ||||||
|  |       : `session=${sessionId}`, | ||||||
|  |     method: 'POST', | ||||||
|  |     headers: { | ||||||
|  |       'Content-Type': 'application/x-www-form-urlencoded', | ||||||
|  |     }, | ||||||
|  |   }; | ||||||
|  | 
 | ||||||
|  |   // eslint-disable-next-line no-unused-vars
 | ||||||
|  |   const [status, contentType, data] = await httpProxy(url, options); | ||||||
|  |   return [status, JSON.parse(Buffer.from(data).toString())]; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | async function login(loginUrl, username, password = '') { | ||||||
|  |   const [status, sessionId] = await fetchFromPyloadAPI(loginUrl, null, { username, password }); | ||||||
|  |   if (status !== 200) { | ||||||
|  |     throw new Error(`HTTP error ${status} logging into Pyload API, returned: ${sessionId}`); | ||||||
|  |   } else { | ||||||
|  |     cache.put(sessionCacheKey, sessionId); | ||||||
|  |     return sessionId; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export default async function pyloadProxyHandler(req, res) { | ||||||
|  |   const { group, service, endpoint } = req.query; | ||||||
|  | 
 | ||||||
|  |   try { | ||||||
|  |     if (group && service) { | ||||||
|  |       const widget = await getServiceWidget(group, service); | ||||||
|  | 
 | ||||||
|  |       if (widget) { | ||||||
|  |         const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget })); | ||||||
|  |         const loginUrl = `${widget.url}/api/login`; | ||||||
|  | 
 | ||||||
|  |         let sessionId = cache.get(sessionCacheKey) ?? await login(loginUrl, widget.username, widget.password); | ||||||
|  |         let [status, data] = await fetchFromPyloadAPI(url, sessionId); | ||||||
|  | 
 | ||||||
|  |         if (status === 403) { | ||||||
|  |           logger.debug('Failed to retrieve data from Pyload API, login and re-try'); | ||||||
|  |           cache.del(sessionCacheKey); | ||||||
|  |           sessionId = await login(loginUrl, widget.username, widget.password); | ||||||
|  |           [status, data] = await fetchFromPyloadAPI(url, sessionId); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (data?.error || status !== 200) { | ||||||
|  |           return res.status(500).send(Buffer.from(data).toString()); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         return res.json(data); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } catch (e) { | ||||||
|  |     logger.error(e); | ||||||
|  |     return res.status(500).send(e.toString()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   return res.status(400).json({ error: 'Invalid proxy service type' }); | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								src/widgets/pyload/widget.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/widgets/pyload/widget.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,14 @@ | |||||||
|  | import pyloadProxyHandler from "./proxy"; | ||||||
|  | 
 | ||||||
|  | const widget = { | ||||||
|  |   api: "{url}/api/{endpoint}", | ||||||
|  |   proxyHandler: pyloadProxyHandler, | ||||||
|  | 
 | ||||||
|  |   mappings: { | ||||||
|  |     "status": { | ||||||
|  |       endpoint: "statusServer", | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export default widget; | ||||||
| @ -21,6 +21,7 @@ import plex from "./plex/widget"; | |||||||
| import portainer from "./portainer/widget"; | import portainer from "./portainer/widget"; | ||||||
| import prowlarr from "./prowlarr/widget"; | import prowlarr from "./prowlarr/widget"; | ||||||
| import proxmox from "./proxmox/widget"; | import proxmox from "./proxmox/widget"; | ||||||
|  | import pyload from "./pyload/widget"; | ||||||
| import qbittorrent from "./qbittorrent/widget"; | import qbittorrent from "./qbittorrent/widget"; | ||||||
| import radarr from "./radarr/widget"; | import radarr from "./radarr/widget"; | ||||||
| import readarr from "./readarr/widget"; | import readarr from "./readarr/widget"; | ||||||
| @ -62,6 +63,7 @@ const widgets = { | |||||||
|   portainer, |   portainer, | ||||||
|   prowlarr, |   prowlarr, | ||||||
|   proxmox, |   proxmox, | ||||||
|  |   pyload, | ||||||
|   qbittorrent, |   qbittorrent, | ||||||
|   radarr, |   radarr, | ||||||
|   readarr, |   readarr, | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 shamoon
						shamoon