diff --git a/package.json b/package.json
index f4f46180..a08072df 100644
--- a/package.json
+++ b/package.json
@@ -17,6 +17,7 @@
"dockerode": "^3.3.4",
"follow-redirects": "^1.15.2",
"i18next": "^21.9.2",
+ "jdownloader-client": "^1.0.0",
"js-yaml": "^4.1.0",
"json-rpc-2.0": "^1.4.1",
"memory-cache": "^0.2.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 86188aa5..8eec7883 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -22,6 +22,9 @@ dependencies:
i18next:
specifier: ^21.9.2
version: 21.10.0
+ jdownloader-client:
+ specifier: ^1.0.0
+ version: 1.0.0
js-yaml:
specifier: ^4.1.0
version: 4.1.0
@@ -681,6 +684,16 @@ packages:
engines: {node: '>=4'}
dev: true
+ /axios@0.17.1:
+ resolution: {integrity: sha512-mZzWRyJeJ0rtK7e1/6iYBUzmeXjzei+1h1IvbedyU0sB52++tU5AU6r6TLXpwNVR0ebXIpvTVW+9CpWNyc1n8w==}
+ deprecated: Critical security vulnerability fixed in v0.21.1. For more information, see https://github.com/axios/axios/pull/3410
+ dependencies:
+ follow-redirects: 1.15.2
+ is-buffer: 1.1.6
+ transitivePeerDependencies:
+ - debug
+ dev: false
+
/axobject-query@3.1.1:
resolution: {integrity: sha512-goKlv8DZrK9hUh975fnHzhNIO4jUnFCfv/dszV5VwUGDFjI6vQ2VwoyjYjYNEbBE8AH87TduWP5uyDR1D+Iteg==}
dependencies:
@@ -1963,6 +1976,10 @@ packages:
has-tostringtag: 1.0.0
dev: true
+ /is-buffer@1.1.6:
+ resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==}
+ dev: false
+
/is-callable@1.2.7:
resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==}
engines: {node: '>= 0.4'}
@@ -2106,6 +2123,14 @@ packages:
resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==}
dev: false
+ /jdownloader-client@1.0.0:
+ resolution: {integrity: sha512-3aksD+UE6xDXGmRIWUUVnVcJQBvNwff2HfrkBIo/Ptxaru4dDO5WCb93vP+wNrTVKdw8QQZ9sE4Y3jBvrKVaXQ==}
+ dependencies:
+ axios: 0.17.1
+ transitivePeerDependencies:
+ - debug
+ dev: false
+
/jiti@1.18.2:
resolution: {integrity: sha512-QAdOptna2NYiSSpv0O/BwoHBSmz4YhpzJHyi+fnMRTXFjp7B8i/YG5Z8IfusxB1ufjcD2Sre1F3R+nX3fvy7gg==}
dev: true
diff --git a/src/widgets/components.js b/src/widgets/components.js
index bb8171d0..08345654 100644
--- a/src/widgets/components.js
+++ b/src/widgets/components.js
@@ -32,6 +32,7 @@ const components = {
immich: dynamic(() => import("./immich/component")),
jackett: dynamic(() => import("./jackett/component")),
jdrssdownloader: dynamic(() => import("./jdrssdownloader/component")),
+ jdownloader: dynamic(() => import("./jdownloader/component")),
jellyfin: dynamic(() => import("./emby/component")),
jellyseerr: dynamic(() => import("./jellyseerr/component")),
komga: dynamic(() => import("./komga/component")),
diff --git a/src/widgets/jdownloader/component.jsx b/src/widgets/jdownloader/component.jsx
new file mode 100644
index 00000000..d8fea9ca
--- /dev/null
+++ b/src/widgets/jdownloader/component.jsx
@@ -0,0 +1,37 @@
+import { useTranslation } from "next-i18next";
+
+import Block from "components/services/widget/block";
+import Container from "components/services/widget/container";
+import useWidgetAPI from "utils/proxy/use-widget-api";
+
+export default function Component({ service }) {
+ const { t } = useTranslation();
+
+ const { widget } = service;
+
+ const { data: jdownloaderData, error: jdownloaderAPIError } = useWidgetAPI(widget, "unified", {
+ refreshInterval: 30000,
+ });
+
+ if (jdownloaderAPIError) {
+ return ;
+ }
+
+ if (!jdownloaderData) {
+ return (
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/widgets/jdownloader/proxy.js b/src/widgets/jdownloader/proxy.js
new file mode 100644
index 00000000..3e6fcce2
--- /dev/null
+++ b/src/widgets/jdownloader/proxy.js
@@ -0,0 +1,71 @@
+/* eslint-disable no-underscore-dangle */
+import { JDownloaderClient } from 'jdownloader-client';
+
+import getServiceWidget from "utils/config/service-helpers";
+import createLogger from "utils/logger";
+
+
+const proxyName = "jdownloaderProxyHandler";
+
+const logger = createLogger(proxyName);
+
+async function getWidget(req) {
+ const { group, service } = req.query;
+ if (!group || !service) {
+ logger.debug("Invalid or missing service '%s' or group '%s'", service, group);
+ return null;
+ }
+ const widget = await getServiceWidget(group, service);
+ if (!widget) {
+ logger.debug("Invalid or missing widget for service '%s' in group '%s'", service, group);
+ return null;
+ }
+
+ return widget;
+}
+
+export default async function jdownloaderProxyHandler(req, res) {
+ const widget = await getWidget(req);
+
+ if (!widget) {
+ return res.status(400).json({ error: "Invalid proxy service type" });
+ }
+ logger.debug("Getting data from JDRss API");
+ const client = new JDownloaderClient(widget.username, widget.password)
+ await client.connect()
+ const devices = await client.listDevices()
+ const packageStatus = await client.downloadsQueryPackages(devices[0].id, {
+ "bytesLoaded": false,
+ "bytesTotal": true,
+ "comment": false,
+ "enabled": true,
+ "eta": false,
+ "priority": false,
+ "finished": true,
+ "running": true,
+ "speed": true,
+ "status": true,
+ "childCount": false,
+ "hosts": false,
+ "saveTo": false,
+ "maxResults": -1,
+ "startAt": 0,
+ })
+ let totalBytes = 0;
+ let totalSpeed = 0;
+ packageStatus.forEach(file => {
+ totalBytes += file.bytesTotal;
+ if (file.speed) {
+ totalSpeed += file.speed;
+ }
+ });
+
+ const data = {
+ downloadCount: packageStatus.length,
+ totalBytes,
+ totalSpeed
+ };
+
+ return res.send(data);
+
+}
diff --git a/src/widgets/jdownloader/widget.js b/src/widgets/jdownloader/widget.js
new file mode 100644
index 00000000..2685b571
--- /dev/null
+++ b/src/widgets/jdownloader/widget.js
@@ -0,0 +1,14 @@
+import jdownloaderProxyHandler from "./proxy";
+
+const widget = {
+ api: "{url}/api/{endpoint}",
+ proxyHandler: jdownloaderProxyHandler,
+
+ mappings: {
+ unified: {
+ endpoint: "/",
+ },
+ },
+};
+
+export default widget;
diff --git a/src/widgets/widgets.js b/src/widgets/widgets.js
index 36b06c2e..4642bb36 100644
--- a/src/widgets/widgets.js
+++ b/src/widgets/widgets.js
@@ -86,6 +86,7 @@ import whatsupdocker from "./whatsupdocker/widget";
import wgeasy from "./wgeasy/widget";
import xteve from "./xteve/widget";
import jdrssdownloader from "./jdrssdownloader/widget";
+import jdownloader from "./jdownloader/widget";
const widgets = {
adguard,
@@ -118,6 +119,7 @@ const widgets = {
jackett,
jellyfin: emby,
jdrssdownloader,
+ jdownloader,
jellyseerr,
komga,
kopia,