widget refactoring and cleanup

This commit is contained in:
Ben Phelps 2022-09-26 02:23:02 +03:00
parent 808e79e2ac
commit 47bc073fb4
39 changed files with 92 additions and 1410 deletions

View file

@ -10,15 +10,20 @@ const components = {
jackett: dynamic(() => import("./jackett/component")),
jellyfin: dynamic(() => import("./emby/component")),
jellyseerr: dynamic(() => import("./jellyseerr/component")),
mastodon: dynamic(() => import("./mastodon/component")),
npm: dynamic(() => import("./npm/component")),
nzbget: dynamic(() => import("./nzbget/component")),
ombi: dynamic(() => import("./ombi/component")),
overseerr: dynamic(() => import("./overseerr/component")),
pihole: dynamic(() => import("./pihole/component")),
portainer: dynamic(() => import("./portainer/component")),
prowlarr: dynamic(() => import("./prowlarr/component")),
qbittorrent: dynamic(() => import("./qbittorrent/component")),
radarr: dynamic(() => import("./radarr/component")),
sonarr: dynamic(() => import("./sonarr/component")),
readarr: dynamic(() => import("./readarr/component")),
rutorrent: dynamic(() => import("./rutorrent/component")),
sabnzbd: dynamic(() => import("./sabnzbd/component")),
sonarr: dynamic(() => import("./sonarr/component")),
speedtest: dynamic(() => import("./speedtest/component")),
strelaysrv: dynamic(() => import("./strelaysrv/component")),
tautulli: dynamic(() => import("./tautulli/component")),

View file

@ -0,0 +1,36 @@
import useSWR from "swr";
import { useTranslation } from "next-i18next";
import Widget from "components/services/widgets/widget";
import Block from "components/services/widgets/block";
import { formatProxyUrl } from "utils/api-helpers";
export default function Component({ service }) {
const { t } = useTranslation();
const config = service.widget;
const { data: statsData, error: statsError } = useSWR(formatProxyUrl(config, `instance`));
if (statsError) {
return <Widget error={t("widget.api_error")} />;
}
if (!statsData) {
return (
<Widget>
<Block label={t("mastodon.user_count")} />
<Block label={t("mastodon.status_count")} />
<Block label={t("mastodon.domain_count")} />
</Widget>
);
}
return (
<Widget>
<Block label={t("mastodon.user_count")} value={t("common.number", { value: statsData.stats.user_count })} />
<Block label={t("mastodon.status_count")} value={t("common.number", { value: statsData.stats.status_count })} />
<Block label={t("mastodon.domain_count")} value={t("common.number", { value: statsData.stats.domain_count })} />
</Widget>
);
}

View file

@ -0,0 +1,14 @@
import genericProxyHandler from "utils/proxies/generic";
const widget = {
api: "{url}/api/v1/{endpoint}",
proxyHandler: genericProxyHandler,
mappings: {
instance: {
endpoint: "instance",
},
},
};
export default widget;

View file

@ -0,0 +1,40 @@
import useSWR from "swr";
import { useTranslation } from "next-i18next";
import Widget from "components/services/widgets/widget";
import Block from "components/services/widgets/block";
import { formatProxyUrl } from "utils/api-helpers";
export default function Component({ service }) {
const { t } = useTranslation();
const config = service.widget;
const { data: infoData, error: infoError } = useSWR(formatProxyUrl(config, "nginx/proxy-hosts"));
if (infoError) {
return <Widget error={t("widget.api_error")} />;
}
if (!infoData) {
return (
<Widget>
<Block label={t("npm.enabled")} />
<Block label={t("npm.disabled")} />
<Block label={t("npm.total")} />
</Widget>
);
}
const enabled = infoData.filter((c) => c.enabled === 1).length;
const disabled = infoData.filter((c) => c.enabled === 0).length;
const total = infoData.length;
return (
<Widget>
<Block label={t("npm.enabled")} value={enabled} />
<Block label={t("npm.disabled")} value={disabled} />
<Block label={t("npm.total")} value={total} />
</Widget>
);
}

42
src/widgets/npm/proxy.js Normal file
View file

@ -0,0 +1,42 @@
import getServiceWidget from "utils/service-helpers";
import { formatApiCall } from "utils/api-helpers";
import widgets from "widgets/widgets";
export default async function npmProxyHandler(req, res) {
const { group, service, endpoint } = req.query;
if (group && service) {
const widget = await getServiceWidget(group, service);
if (!widgets?.[widget.type]?.api) {
return res.status(403).json({ error: "Service does not support API calls" });
}
if (widget) {
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
const loginUrl = `${widget.url}/api/tokens`;
const body = { identity: widget.username, secret: widget.password };
const authResponse = await fetch(loginUrl, {
method: "POST",
body: JSON.stringify(body),
headers: {
"Content-Type": "application/json",
},
}).then((response) => response.json());
const apiResponse = await fetch(url, {
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${authResponse.token}`,
},
}).then((response) => response.json());
return res.send(apiResponse);
}
}
return res.status(400).json({ error: "Invalid proxy service type" });
}

View file

@ -0,0 +1,8 @@
import npmProxyHandler from "./proxy";
const widget = {
api: "{url}/api/{endpoint}",
proxyHandler: npmProxyHandler,
};
export default widget;

View file

@ -0,0 +1,42 @@
import useSWR from "swr";
import { useTranslation } from "next-i18next";
import Widget from "components/services/widgets/widget";
import Block from "components/services/widgets/block";
import { formatProxyUrl } from "utils/api-helpers";
export default function Component({ service }) {
const { t } = useTranslation("common");
const config = service.widget;
const { data: statusData, error: statusError } = useSWR(formatProxyUrl(config, "status"));
if (statusError) {
return <Widget error={t("widget.api_error")} />;
}
if (!statusData) {
return (
<Widget>
<Block label={t("nzbget.rate")} />
<Block label={t("nzbget.remaining")} />
<Block label={t("nzbget.downloaded")} />
</Widget>
);
}
return (
<Widget>
<Block label={t("nzbget.rate")} value={t("common.bitrate", { value: statusData.DownloadRate })} />
<Block
label={t("nzbget.remaining")}
value={t("common.bytes", { value: statusData.RemainingSizeMB * 1024 * 1024 })}
/>
<Block
label={t("nzbget.downloaded")}
value={t("common.bytes", { value: statusData.DownloadedSizeMB * 1024 * 1024 })}
/>
</Widget>
);
}

View file

@ -0,0 +1,40 @@
import { JSONRPCClient } from "json-rpc-2.0";
import getServiceWidget from "utils/service-helpers";
export default async function nzbgetProxyHandler(req, res) {
const { group, service, endpoint } = req.query;
if (group && service) {
const widget = await getServiceWidget(group, service);
if (widget) {
const constructedUrl = new URL(widget.url);
constructedUrl.pathname = "jsonrpc";
const authorization = Buffer.from(`${widget.username}:${widget.password}`).toString("base64");
const client = new JSONRPCClient((jsonRPCRequest) =>
fetch(constructedUrl.toString(), {
method: "POST",
headers: {
"content-type": "application/json",
authorization: `Basic ${authorization}`,
},
body: JSON.stringify(jsonRPCRequest),
}).then(async (response) => {
if (response.status === 200) {
const jsonRPCResponse = await response.json();
return client.receive(jsonRPCResponse);
}
return Promise.reject(new Error(response.statusText));
})
);
return res.send(await client.request(endpoint));
}
}
return res.status(400).json({ error: "Invalid proxy service type" });
}

View file

@ -0,0 +1,7 @@
import nzbgetProxyHandler from "./proxy";
const widget = {
proxyHandler: nzbgetProxyHandler,
};
export default widget;

View file

@ -0,0 +1,36 @@
import useSWR from "swr";
import { useTranslation } from "next-i18next";
import Widget from "components/services/widgets/widget";
import Block from "components/services/widgets/block";
import { formatProxyUrl } from "utils/api-helpers";
export default function Component({ service }) {
const { t } = useTranslation();
const config = service.widget;
const { data: statsData, error: statsError } = useSWR(formatProxyUrl(config, `Request/count`));
if (statsError) {
return <Widget error={t("widget.api_error")} />;
}
if (!statsData) {
return (
<Widget>
<Block label={t("ombi.pending")} />
<Block label={t("ombi.approved")} />
<Block label={t("ombi.available")} />
</Widget>
);
}
return (
<Widget>
<Block label={t("ombi.pending")} value={statsData.pending} />
<Block label={t("ombi.approved")} value={statsData.approved} />
<Block label={t("ombi.available")} value={statsData.available} />
</Widget>
);
}

View file

@ -0,0 +1,14 @@
import credentialedProxyHandler from "utils/proxies/credentialed";
const widget = {
api: "{url}/api/v1/{endpoint}",
proxyHandler: credentialedProxyHandler,
mappings: {
"Request/count": {
endpoint: "Request/count",
},
},
};
export default widget;

View file

@ -0,0 +1,36 @@
import useSWR from "swr";
import { useTranslation } from "next-i18next";
import Widget from "components/services/widgets/widget";
import Block from "components/services/widgets/block";
import { formatProxyUrl } from "utils/api-helpers";
export default function Component({ service }) {
const { t } = useTranslation();
const config = service.widget;
const { data: piholeData, error: piholeError } = useSWR(formatProxyUrl(config, "api.php"));
if (piholeError) {
return <Widget error={t("widget.api_error")} />;
}
if (!piholeData) {
return (
<Widget>
<Block label={t("pihole.queries")} />
<Block label={t("pihole.blocked")} />
<Block label={t("pihole.gravity")} />
</Widget>
);
}
return (
<Widget>
<Block label={t("pihole.queries")} value={t("common.number", { value: piholeData.dns_queries_today })} />
<Block label={t("pihole.blocked")} value={t("common.number", { value: piholeData.ads_blocked_today })} />
<Block label={t("pihole.gravity")} value={t("common.number", { value: piholeData.domains_being_blocked })} />
</Widget>
);
}

View file

@ -0,0 +1,14 @@
import genericProxyHandler from "utils/proxies/generic";
const widget = {
api: "{url}/admin/{endpoint}",
proxyHandler: genericProxyHandler,
mappings: {
"api.php": {
endpoint: "api.php",
},
},
};
export default widget;

View file

@ -5,15 +5,20 @@ import emby from "./emby/widget";
import gotify from "./gotify/widget";
import jackett from "./jackett/widget";
import jellyseerr from "./jellyseerr/widget";
import mastodon from "./mastodon/widget";
import npm from "./npm/widget";
import nzbget from "./nzbget/widget";
import ombi from "./ombi/widget";
import overseerr from "./overseerr/widget";
import pihole from "./pihole/widget";
import portainer from "./portainer/widget";
import prowlarr from "./prowlarr/widget";
import qbittorrent from "./qbittorrent/widget";
import radarr from "./radarr/widget";
import sonarr from "./sonarr/widget";
import readarr from "./readarr/widget";
import rutorrent from "./rutorrent/widget";
import sabnzbd from "./sabnzbd/widget";
import sonarr from "./sonarr/widget";
import speedtest from "./speedtest/widget";
import strelaysrv from "./strelaysrv/widget";
import tautulli from "./tautulli/widget";
@ -29,15 +34,20 @@ const widgets = {
jackett,
jellyfin: emby,
jellyseerr,
mastodon,
npm,
nzbget,
ombi,
overseerr,
pihole,
portainer,
prowlarr,
qbittorrent,
radarr,
sonarr,
readarr,
rutorrent,
sabnzbd,
sonarr,
speedtest,
strelaysrv,
tautulli,