Aria2 Service Widget

This commit is contained in:
hapylestat 2024-12-16 14:01:38 +00:00
parent 9aa46e4fdd
commit 3b207f3250
7 changed files with 137 additions and 0 deletions

View File

@ -0,0 +1,18 @@
---
title: Aria2
description: Aria2 Widget Configuration
---
Learn more about [Aria2](https://github.com/aria2/aria2).
Find your API key in aria2c configuration file `aria2c.conf`: `rpc-secret`.
To make it work, JSON RPC in Aria2 should be enabled.
Optionally, `jsonrpc` endpoint path could be adjusted via `endpoint` widget config.
```yaml
widget:
type: aria2c
url: http://aria2c.host.or.ip
key: apikey
```

View File

@ -1007,5 +1007,11 @@
"issues": "Issues",
"merges": "Merge Requests",
"projects": "Projects"
},
"aria2c": {
"active": "Active",
"waiting": "Waiting",
"download": "↓",
"upload": "↑"
}
}

View File

@ -0,0 +1,37 @@
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: aria2cData, error: aria2cError } = useWidgetAPI(widget);
if (aria2cError) {
return <Container service={service} error={aria2cError} />;
}
if (!aria2cData) {
return (
<Container service={service}>
<Block label="aria2c.active" />
<Block label="aria2c.waiting" />
<Block label="aria2c.download" />
<Block label="aria2c.upload" />
</Container>
);
}
return (
<Container service={service}>
<Block label="aria2c.active" value={t("common.number", { value: aria2cData.numActive })} />
<Block label="aria2c.waiting" value={t("common.number", { value: aria2cData.numWaiting })} />
<Block label="aria2c.download" value={t("common.byterate", { value: parseInt(aria2cData.downloadSpeed, 10) })} />
<Block label="aria2c.upload" value={t("common.byterate", { value: parseInt(aria2cData.uploadSpeed, 10) })} />
</Container>
);
}

View File

@ -0,0 +1,65 @@
import getServiceWidget from "utils/config/service-helpers";
import { httpProxy } from "utils/proxy/http";
import widgets from "widgets/widgets";
import { formatApiCall } from "utils/proxy/api-helpers";
import createLogger from "utils/logger";
const logger = createLogger("ariaProxyHandler");
export default async function ariaProxyHandler(req, res) {
const { group, service, index } = req.query;
if (group && service) {
const widget = await getServiceWidget(group, service, index);
if (widget) {
if (widget.endpoint === undefined) {
widget.endpoint = 'jsonrpc'
}
const api = widgets?.[widget.type]?.api;
const url = new URL(formatApiCall(api, { ...widget }));
const headers = {
"content-type": "application/json",
accept: "application/json",
};
if (widget.username) {
headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`;
}
const rpcRequestBody = {
id: "homepage",
jsonrpc: "2.0",
method: "aria2.getGlobalStat",
params: []
}
if (widget.token !== undefined) {
rpcRequestBody.params.push(`token:${widget.token}`)
}
const [status, , data] = await httpProxy(url, {
method: "POST",
headers,
body: JSON.stringify(rpcRequestBody),
});
if (status !== 200) {
logger.error("HTTP Error %d calling %s", status, url.toString());
return res.status(status).json({ error: { message: "HTTP Error", url, data } });
}
try {
const rawData = JSON.parse(data);
return res.status(200).send(rawData.result);
} catch (e) {
return res.status(500).json({ error: { message: e?.toString() ?? "Error parsing aria2c rpc data", url, data } });
}
}
}
return res.status(500).json({ error: "Invalid proxy service type" });
}

View File

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

View File

@ -3,6 +3,7 @@ import dynamic from "next/dynamic";
const components = {
adguard: dynamic(() => import("./adguard/component")),
argocd: dynamic(() => import("./argocd/component")),
aria2c: dynamic(() => import("./aria2c/component")),
atsumeru: dynamic(() => import("./atsumeru/component")),
audiobookshelf: dynamic(() => import("./audiobookshelf/component")),
authentik: dynamic(() => import("./authentik/component")),

View File

@ -1,5 +1,6 @@
import adguard from "./adguard/widget";
import argocd from "./argocd/widget";
import aria2c from "./aria2c/widget";
import atsumeru from "./atsumeru/widget";
import audiobookshelf from "./audiobookshelf/widget";
import authentik from "./authentik/widget";
@ -134,6 +135,7 @@ import zabbix from "./zabbix/widget";
const widgets = {
adguard,
argocd,
aria2c,
atsumeru,
audiobookshelf,
authentik,