diff --git a/README.md b/README.md index 5167f9bc3..ae2ecf0f9 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ * Service Integration - Currently supports Sonarr, Radarr, Ombi, Emby, Jellyfin, Tautulli (Plex), Overseerr, Jellyseerr ([ilusi0n](https://github.com/benphelps/homepage/pull/34)), NZBGet, ruTorrent - Portainer, Traefik, Speedtest Tracker, PiHole, Nginx Proxy Manager ([aidenpwnz](https://github.com/benphelps/homepage/pull/45)) + - Readarr, SABnzbd ([JazzFisch]()) * Information & Utility Widgets - System Stats (Disk, CPU, Memory) - Weather via WeatherAPI.com or OpenWeatherMap ([AlexFullmoon](https://github.com/benphelps/homepage/pull/25)) diff --git a/public/locales/de/common.json b/public/locales/de/common.json index d7152f68a..94eff1692 100644 --- a/public/locales/de/common.json +++ b/public/locales/de/common.json @@ -36,6 +36,11 @@ "remaining": "Verblieben", "downloaded": "Heruntergeladen" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "rutorrent": { "active": "Aktiv", "upload": "Hochladen", @@ -51,6 +56,11 @@ "queued": "In Warteschlange", "movies": "Filme" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "Ausstehend", "approved": "Genehmigt", diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 72c0e02ad..a92ee97aa 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -53,6 +53,11 @@ "remaining": "Remaining", "downloaded": "Downloaded" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "rutorrent": { "active": "Active", "upload": "Upload", @@ -68,6 +73,11 @@ "queued": "Queued", "movies": "Movies" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "Pending", "approved": "Approved", diff --git a/public/locales/es/common.json b/public/locales/es/common.json index f80a0a2b4..66299c8e2 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -36,6 +36,11 @@ "remaining": "Restante", "downloaded": "Descargado" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "rutorrent": { "active": "Activo", "upload": "Subir", @@ -51,6 +56,11 @@ "queued": "Puesto en cola", "movies": "Películas" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "Pendiente", "approved": "Aprobado", diff --git a/public/locales/fr/common.json b/public/locales/fr/common.json index 333a9e025..21fc296cf 100644 --- a/public/locales/fr/common.json +++ b/public/locales/fr/common.json @@ -36,6 +36,11 @@ "remaining": "Restante", "downloaded": "Téléchargé" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "rutorrent": { "active": "Active", "upload": "Téléverser", @@ -51,6 +56,11 @@ "queued": "En queue", "movies": "Films" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "En attente", "approved": "Approuvée", diff --git a/public/locales/it/common.json b/public/locales/it/common.json index e582a7a93..316161f6e 100644 --- a/public/locales/it/common.json +++ b/public/locales/it/common.json @@ -51,6 +51,11 @@ "remaining": "Remaining", "downloaded": "Downloaded" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "rutorrent": { "active": "Active", "upload": "Upload", @@ -66,6 +71,11 @@ "queued": "Queued", "movies": "Movies" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "Pending", "approved": "Approved", diff --git a/public/locales/nb-NO/common.json b/public/locales/nb-NO/common.json index a174a82dd..e605c8a28 100644 --- a/public/locales/nb-NO/common.json +++ b/public/locales/nb-NO/common.json @@ -36,6 +36,11 @@ "remaining": "Gjenstående", "downloaded": "Nedlastet" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "rutorrent": { "active": "Aktiv", "upload": "Opplasting", @@ -51,6 +56,11 @@ "queued": "I kø", "movies": "Filmer" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "Venter", "approved": "Godkjent", diff --git a/public/locales/nl/common.json b/public/locales/nl/common.json index ada7e08fa..8ad0fc6b4 100644 --- a/public/locales/nl/common.json +++ b/public/locales/nl/common.json @@ -21,6 +21,11 @@ "remaining": "Overgebleven", "downloaded": "Gedownload" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "speedtest": { "upload": "Upload", "download": "Download", @@ -67,6 +72,11 @@ "wanted": "Gezocht", "queued": "In de wachtrij" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "In afwachting", "approved": "Goedgekeurd", diff --git a/public/locales/pt/common.json b/public/locales/pt/common.json index 8b4688df7..a1749b5b4 100644 --- a/public/locales/pt/common.json +++ b/public/locales/pt/common.json @@ -36,6 +36,11 @@ "remaining": "Em falta", "downloaded": "Baixada" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "rutorrent": { "active": "Ativa", "upload": "Envio", @@ -51,6 +56,11 @@ "queued": "Enfileiradas", "movies": "Filmes" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "Pendente", "approved": "Aprovada", diff --git a/public/locales/ru/common.json b/public/locales/ru/common.json index dd424d8dc..780b033b7 100644 --- a/public/locales/ru/common.json +++ b/public/locales/ru/common.json @@ -36,6 +36,11 @@ "remaining": "Осталось", "downloaded": "Загружено" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "rutorrent": { "active": "Активный", "upload": "Загрузить", @@ -51,6 +56,11 @@ "queued": "В очереди", "movies": "Фильмы" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "Ожидание", "approved": "Одобрено", diff --git a/public/locales/vi/common.json b/public/locales/vi/common.json index 21fc74f65..bd2fdb78e 100644 --- a/public/locales/vi/common.json +++ b/public/locales/vi/common.json @@ -36,6 +36,11 @@ "remaining": "Còn lại", "downloaded": "Đã tải" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "rutorrent": { "active": "Hoạt động", "upload": "Tải lên", @@ -51,6 +56,11 @@ "queued": "Queued", "movies": "Movies" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "Pending", "approved": "Approved", diff --git a/public/locales/zh-CN/common.json b/public/locales/zh-CN/common.json index 2deff5bf8..44c9d85a9 100644 --- a/public/locales/zh-CN/common.json +++ b/public/locales/zh-CN/common.json @@ -36,6 +36,11 @@ "remaining": "其余的", "downloaded": "下载" }, + "sabnzbd": { + "rate": "Rate", + "queue": "Queue", + "timeleft": "Time Left" + }, "rutorrent": { "active": "积极的", "upload": "上传", @@ -51,6 +56,11 @@ "queued": "排队", "movies": "电影" }, + "readarr": { + "wanted": "Wanted", + "queued": "Queued", + "books": "Books" + }, "ombi": { "pending": "待办的", "approved": "得到正式认可的", diff --git a/src/components/services/widget.jsx b/src/components/services/widget.jsx index 41257a5c9..41942eadd 100644 --- a/src/components/services/widget.jsx +++ b/src/components/services/widget.jsx @@ -2,10 +2,12 @@ import { useTranslation } from "react-i18next"; import Sonarr from "./widgets/service/sonarr"; import Radarr from "./widgets/service/radarr"; +import Readarr from "./widgets/service/readarr"; import Ombi from "./widgets/service/ombi"; import Portainer from "./widgets/service/portainer"; import Emby from "./widgets/service/emby"; import Nzbget from "./widgets/service/nzbget"; +import SABnzbd from "./widgets/service/sabnzbd"; import Docker from "./widgets/service/docker"; import Pihole from "./widgets/service/pihole"; import Rutorrent from "./widgets/service/rutorrent"; @@ -21,11 +23,13 @@ const widgetMappings = { docker: Docker, sonarr: Sonarr, radarr: Radarr, + readarr: Readarr, ombi: Ombi, portainer: Portainer, emby: Emby, jellyfin: Jellyfin, nzbget: Nzbget, + sabnzbd: SABnzbd, pihole: Pihole, rutorrent: Rutorrent, speedtest: Speedtest, diff --git a/src/components/services/widgets/service/readarr.jsx b/src/components/services/widgets/service/readarr.jsx new file mode 100644 index 000000000..5aa0cba4d --- /dev/null +++ b/src/components/services/widgets/service/readarr.jsx @@ -0,0 +1,41 @@ +import useSWR from "swr"; +import { useTranslation } from "react-i18next"; + +import Widget from "../widget"; +import Block from "../block"; + +import { formatApiUrl } from "utils/api-helpers"; + +export default function Readarr({ service }) { + const { t } = useTranslation(); + + const config = service.widget; + + const { data: booksData, error: booksError } = useSWR(formatApiUrl(config, "book")); + const { data: wantedData, error: wantedError } = useSWR(formatApiUrl(config, "wanted/missing")); + const { data: queueData, error: queueError } = useSWR(formatApiUrl(config, "queue/status")); + + if (booksError || wantedError || queueError) { + return ; + } + + if (!booksData || !wantedData || !queueData) { + return ( + + + + + + ); + } + + const have = booksData.filter((book) => book.statistics.bookFileCount > 0); + + return ( + + + + + + ); +} diff --git a/src/components/services/widgets/service/sabnzbd.jsx b/src/components/services/widgets/service/sabnzbd.jsx new file mode 100644 index 000000000..d1a08a27e --- /dev/null +++ b/src/components/services/widgets/service/sabnzbd.jsx @@ -0,0 +1,37 @@ +import useSWR from "swr"; +import { useTranslation } from "react-i18next"; + +import Widget from "../widget"; +import Block from "../block"; + +import { formatApiUrl } from "utils/api-helpers"; + +export default function SABnzbd({ service }) { + const { t } = useTranslation(); + + const config = service.widget; + + const { data: queueData, error: queueError } = useSWR(formatApiUrl(config, "queue")); + + if (queueError) { + return ; + } + + if (!queueData) { + return ( + + + + + + ); + } + + return ( + + + + + + ); +} diff --git a/src/pages/api/services/proxy.js b/src/pages/api/services/proxy.js index c4ef2b3bc..985d64b83 100644 --- a/src/pages/api/services/proxy.js +++ b/src/pages/api/services/proxy.js @@ -11,9 +11,11 @@ const serviceProxyHandlers = { pihole: genericProxyHandler, radarr: genericProxyHandler, sonarr: genericProxyHandler, + readarr: genericProxyHandler, speedtest: genericProxyHandler, tautulli: genericProxyHandler, traefik: genericProxyHandler, + sabnzbd: genericProxyHandler, // uses X-API-Key header auth portainer: credentialedProxyHandler, jellyseerr: credentialedProxyHandler, diff --git a/src/utils/api-helpers.js b/src/utils/api-helpers.js index c8953a825..69cd60a28 100644 --- a/src/utils/api-helpers.js +++ b/src/utils/api-helpers.js @@ -13,6 +13,8 @@ const formats = { overseerr: `{url}/api/v1/{endpoint}`, ombi: `{url}/api/v1/{endpoint}`, npm: `{url}/api/{endpoint}`, + readarr: `{url}/api/v1/{endpoint}?apikey={key}`, + sabnzbd: `{url}/api/?apikey={key}&output=json&mode={endpoint}`, }; export function formatApiCall(api, args) {