Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions docs/widgets/services/jellystat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
title: Jellystat
description: Jellystat Widget Configuration
---

Learn more about [Jellystat](https://github.com/CyferShepard/Jellystat). The widget supports (at least) Jellystat version 1.1.6

You can create an API key from inside Jellystat at `Settings > API Key`.

Allowed fields: `["songs", "movies", "episodes", "other"]`.

```yaml
widget:
type: jellystat
url: http://jellystat.host.or.ip
key: apikeyapikeyapikeyapikeyapikey
days: 30 # optional, defaults to 30
```
6 changes: 6 additions & 0 deletions public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -1042,5 +1042,11 @@
"downloads": "Downloads",
"uploads": "Uploads",
"sharedFiles": "Files"
},
"jellystat": {
"songs": "Songs",
"movies": "Movies",
"episodes": "Episodes",
"other": "Other"
}
}
6 changes: 6 additions & 0 deletions src/utils/config/service-helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -331,6 +331,9 @@ export function cleanServiceGroups(groups) {
referrerPolicy,
src,

// jellystat
days,

// kopia
snapshotHost,
snapshotPath,
Expand Down Expand Up @@ -563,6 +566,9 @@ export function cleanServiceGroups(groups) {
if (type === "spoolman") {
if (spoolIds !== undefined) widget.spoolIds = spoolIds;
}
if (type === "jellystat") {
if (days !== undefined) widget.days = parseInt(days, 10);
}
return widget;
});
return cleanedService;
Expand Down
2 changes: 1 addition & 1 deletion src/utils/proxy/handlers/credentialed.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export default async function credentialedProxyHandler(req, res, map) {
} else if (widget.type === "proxmoxbackupserver") {
delete headers["Content-Type"];
headers.Authorization = `PBSAPIToken=${widget.username}:${widget.password}`;
} else if (widget.type === "autobrr") {
} else if (["autobrr", "jellystat"].includes(widget.type)) {
headers["X-API-Token"] = `${widget.key}`;
} else if (widget.type === "tubearchivist") {
headers.Authorization = `Token ${widget.key}`;
Expand Down
1 change: 1 addition & 0 deletions src/widgets/components.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const components = {
jdownloader: dynamic(() => import("./jdownloader/component")),
jellyfin: dynamic(() => import("./emby/component")),
jellyseerr: dynamic(() => import("./jellyseerr/component")),
jellystat: dynamic(() => import("./jellystat/component")),
kavita: dynamic(() => import("./kavita/component")),
komga: dynamic(() => import("./komga/component")),
kopia: dynamic(() => import("./kopia/component")),
Expand Down
38 changes: 38 additions & 0 deletions src/widgets/jellystat/component.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
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 { widget } = service;

// Days validation
if (!(Number.isInteger(widget.days) && 0 < widget.days)) widget.days = 30;

const { data: viewsData, error: viewsError } = useWidgetAPI(widget, "getViewsByLibraryType", { days: widget.days });

const error = viewsError || viewsData?.message;
if (error) {
return <Container service={service} error={error} />;
}

if (!viewsData) {
return (
<Container service={service}>
<Block label="jellystat.songs" />
<Block label="jellystat.movies" />
<Block label="jellystat.episodes" />
<Block label="jellystat.other" />
</Container>
);
}

return (
<Container service={service}>
<Block label="jellystat.songs" value={viewsData.Audio} />
<Block label="jellystat.movies" value={viewsData.Movie} />
<Block label="jellystat.episodes" value={viewsData.Series} />
<Block label="jellystat.other" value={viewsData.Other} />
</Container>
);
}
15 changes: 15 additions & 0 deletions src/widgets/jellystat/widget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import credentialedProxyHandler from "utils/proxy/handlers/credentialed";

const widget = {
api: "{url}/{endpoint}",
proxyHandler: credentialedProxyHandler,

mappings: {
getViewsByLibraryType: {
endpoint: "stats/getViewsByLibraryType",
params: ["days"],
},
},
};

export default widget;
2 changes: 2 additions & 0 deletions src/widgets/widgets.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import immich from "./immich/widget";
import jackett from "./jackett/widget";
import jdownloader from "./jdownloader/widget";
import jellyseerr from "./jellyseerr/widget";
import jellystat from "./jellystat/widget";
import karakeep from "./karakeep/widget";
import kavita from "./kavita/widget";
import komga from "./komga/widget";
Expand Down Expand Up @@ -190,6 +191,7 @@ const widgets = {
jdownloader,
jellyfin: emby,
jellyseerr,
jellystat,
kavita,
komga,
kopia,
Expand Down
Loading