diff --git a/docs/widgets/services/index.md b/docs/widgets/services/index.md index 15caadc2e..beb6d4917 100644 --- a/docs/widgets/services/index.md +++ b/docs/widgets/services/index.md @@ -117,6 +117,7 @@ You can also find a list of all available service widgets in the sidebar navigat - [ruTorrent](rutorrent.md) - [SABnzbd](sabnzbd.md) - [Scrutiny](scrutiny.md) +- [Slskd](slskd.md) - [Sonarr](sonarr.md) - [Speedtest Tracker](speedtest-tracker.md) - [Stash](stash.md) diff --git a/docs/widgets/services/slskd.md b/docs/widgets/services/slskd.md new file mode 100644 index 000000000..7afb07605 --- /dev/null +++ b/docs/widgets/services/slskd.md @@ -0,0 +1,25 @@ +--- +title: Slskd +description: Slskd Widget Configuration +--- + +Learn more about [Slskd](https://github.com/slskd/slskd). + +Generate an API key for slskd with `openssl rand -base64 48`. +Add it to your `path/to/config/slskd.yml` in `web > authentication > api_keys`: + +```yaml +homepage_widget: + key: + role: readonly + cidr: +``` + +Allowed fields: `["slskStatus", "updateStatus", "downloads", "uploads", "sharedFiles"]` (maximum of 4). + +```yaml +widget: + type: slskd + url: http[s]://slskd.host.or.ip[:5030] + key: generatedapikey +``` diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 2bc4cf9c0..0535cd6ee 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -1030,5 +1030,16 @@ "highlights": "Highlights", "lists": "Lists", "tags": "Tags" + }, + "slskd": { + "slskStatus": "Network", + "connected": "Connected", + "disconnected": "Disconnected", + "updateStatus": "Update", + "update_yes": "Available", + "update_no": "Up to Date", + "downloads": "Downloads", + "uploads": "Uploads", + "sharedFiles": "Files" } } diff --git a/src/widgets/components.js b/src/widgets/components.js index 6c12d8235..148a626bd 100644 --- a/src/widgets/components.js +++ b/src/widgets/components.js @@ -113,6 +113,7 @@ const components = { rutorrent: dynamic(() => import("./rutorrent/component")), sabnzbd: dynamic(() => import("./sabnzbd/component")), scrutiny: dynamic(() => import("./scrutiny/component")), + slskd: dynamic(() => import("./slskd/component")), sonarr: dynamic(() => import("./sonarr/component")), speedtest: dynamic(() => import("./speedtest/component")), spoolman: dynamic(() => import("./spoolman/component")), diff --git a/src/widgets/slskd/component.jsx b/src/widgets/slskd/component.jsx new file mode 100644 index 000000000..8c26d4e48 --- /dev/null +++ b/src/widgets/slskd/component.jsx @@ -0,0 +1,55 @@ +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"; + +const slskdDefaultFields = ["slskStatus", "downloads", "uploads", "sharedFiles"]; +const MAX_ALLOWED_FIELDS = 4; + +export default function Component({ service }) { + const { t } = useTranslation(); + const { widget } = service; + + const { data: appData, error: appError } = useWidgetAPI(widget, "application"); + const { data: downData, error: downError } = useWidgetAPI(widget, "downloads"); + const { data: upData, error: upError } = useWidgetAPI(widget, "uploads"); + + if (appError || downError || upError) { + return ; + } + + if (!widget.fields || widget.fields.length === 0) { + widget.fields = slskdDefaultFields; + } else if (widget.fields?.length > MAX_ALLOWED_FIELDS) { + widget.fields = widget.fields.slice(0, MAX_ALLOWED_FIELDS); + } + + if (!appData || !downData || !upData) { + return ( + + + + + + + + ); + } + + return ( + + + + + + + + ); +} diff --git a/src/widgets/slskd/widget.js b/src/widgets/slskd/widget.js new file mode 100644 index 000000000..fdea77387 --- /dev/null +++ b/src/widgets/slskd/widget.js @@ -0,0 +1,21 @@ +import credentialedProxyHandler from "utils/proxy/handlers/credentialed"; +import { asJson } from "utils/proxy/api-helpers"; + +const widget = { + api: `{url}/api/v0/{endpoint}`, + proxyHandler: credentialedProxyHandler, + + mappings: { + application: { + endpoint: "application", + }, + downloads: { + endpoint: "transfers/downloads", + }, + uploads: { + endpoint: "transfers/uploads", + }, + }, +}; + +export default widget; diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js index 1537301c2..21cff92b1 100644 --- a/src/widgets/widgets.js +++ b/src/widgets/widgets.js @@ -104,6 +104,7 @@ import readarr from "./readarr/widget"; import rutorrent from "./rutorrent/widget"; import sabnzbd from "./sabnzbd/widget"; import scrutiny from "./scrutiny/widget"; +import slskd from "./slskd/widget"; import sonarr from "./sonarr/widget"; import speedtest from "./speedtest/widget"; import spoolman from "./spoolman/widget"; @@ -244,6 +245,7 @@ const widgets = { rutorrent, sabnzbd, scrutiny, + slskd, sonarr, speedtest, spoolman,