mirror of
https://github.com/gethomepage/homepage.git
synced 2025-12-06 21:57:48 +01:00
Compare commits
3 Commits
v1.5.0
...
1e06e93e47
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1e06e93e47 | ||
|
|
8f756d4084 | ||
|
|
02089a35ee |
@@ -16,4 +16,5 @@ widget:
|
|||||||
username: username
|
username: username
|
||||||
password: password
|
password: password
|
||||||
enableLeechProgress: true # optional, defaults to false
|
enableLeechProgress: true # optional, defaults to false
|
||||||
|
enableLeechSize: true # optional, defaults to false
|
||||||
```
|
```
|
||||||
|
|||||||
28
docs/widgets/services/yourspotify.md
Normal file
28
docs/widgets/services/yourspotify.md
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
---
|
||||||
|
title: Your Spotify
|
||||||
|
description: Your Spotify Widget Configuration
|
||||||
|
---
|
||||||
|
|
||||||
|
Learn more about [Your Spotify](https://github.com/Yooooomi/your_spotify).
|
||||||
|
|
||||||
|
Find your API key under `Settings > Account > Public token`, click `Generate` if not yet generated, copy key after
|
||||||
|
`?token=`.
|
||||||
|
|
||||||
|
Allowed fields: `["songs", "time", "artists"]`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
widget:
|
||||||
|
type: yourspotify
|
||||||
|
url: http://your-spotify-server.host.or.ip # if using lsio image, add /api/
|
||||||
|
key: apikeyapikeyapikeyapikeyapikey
|
||||||
|
interval: month # optional, defaults to week
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Interval
|
||||||
|
|
||||||
|
Allowed values for `interval`: `day`, `week`, `month`, `year`, `all`.
|
||||||
|
|
||||||
|
!!! note
|
||||||
|
|
||||||
|
`interval` is different from predefined intervals you see in `Your Spotify`'s UI.
|
||||||
|
For example, `This week` in UI means _from the start of this week_, here `week` means _past 7 days_.
|
||||||
@@ -176,6 +176,7 @@ nav:
|
|||||||
- widgets/services/wgeasy.md
|
- widgets/services/wgeasy.md
|
||||||
- widgets/services/whatsupdocker.md
|
- widgets/services/whatsupdocker.md
|
||||||
- widgets/services/xteve.md
|
- widgets/services/xteve.md
|
||||||
|
- widgets/services/yourspotify.md
|
||||||
- widgets/services/zabbix.md
|
- widgets/services/zabbix.md
|
||||||
- "Information Widgets":
|
- "Information Widgets":
|
||||||
- widgets/info/index.md
|
- widgets/info/index.md
|
||||||
|
|||||||
@@ -1114,5 +1114,10 @@
|
|||||||
"num_success_latest": "Succeeding",
|
"num_success_latest": "Succeeding",
|
||||||
"num_failure_latest": "Failing",
|
"num_failure_latest": "Failing",
|
||||||
"bytes_added_30": "Bytes Added"
|
"bytes_added_30": "Bytes Added"
|
||||||
|
},
|
||||||
|
"yourspotify": {
|
||||||
|
"songs": "Songs",
|
||||||
|
"time": "Time",
|
||||||
|
"artists": "Artists"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export default function QueueEntry({ title, activity, timeLeft, progress }) {
|
export default function QueueEntry({ title, activity, timeLeft, progress, size }) {
|
||||||
return (
|
return (
|
||||||
<div className="text-theme-700 dark:text-theme-200 relative h-5 rounded-md bg-theme-200/50 dark:bg-theme-900/20 m-1 px-1 flex">
|
<div className="text-theme-700 dark:text-theme-200 relative h-5 rounded-md bg-theme-200/50 dark:bg-theme-900/20 m-1 px-1 flex">
|
||||||
<div
|
<div
|
||||||
@@ -11,6 +11,7 @@ export default function QueueEntry({ title, activity, timeLeft, progress }) {
|
|||||||
<div className="absolute w-full whitespace-nowrap text-ellipsis overflow-hidden text-left">{title}</div>
|
<div className="absolute w-full whitespace-nowrap text-ellipsis overflow-hidden text-left">{title}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="self-center text-xs flex justify-end mr-1.5 pl-1 z-10 text-ellipsis overflow-hidden whitespace-nowrap">
|
<div className="self-center text-xs flex justify-end mr-1.5 pl-1 z-10 text-ellipsis overflow-hidden whitespace-nowrap">
|
||||||
|
{size && `${size} - `}
|
||||||
{timeLeft ? `${activity} - ${timeLeft}` : activity}
|
{timeLeft ? `${activity} - ${timeLeft}` : activity}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -417,6 +417,7 @@ function Home({ initialSettings }) {
|
|||||||
)}
|
)}
|
||||||
<meta name="msapplication-TileColor" content={themes[settings.color || "slate"][settings.theme || "dark"]} />
|
<meta name="msapplication-TileColor" content={themes[settings.color || "slate"][settings.theme || "dark"]} />
|
||||||
<meta name="theme-color" content={themes[settings.color || "slate"][settings.theme || "dark"]} />
|
<meta name="theme-color" content={themes[settings.color || "slate"][settings.theme || "dark"]} />
|
||||||
|
<meta name="color-scheme" content="dark light"></meta>
|
||||||
</Head>
|
</Head>
|
||||||
|
|
||||||
<Script src="/api/config/custom.js" />
|
<Script src="/api/config/custom.js" />
|
||||||
|
|||||||
@@ -284,6 +284,7 @@ export function cleanServiceGroups(groups) {
|
|||||||
|
|
||||||
// deluge, qbittorrent
|
// deluge, qbittorrent
|
||||||
enableLeechProgress,
|
enableLeechProgress,
|
||||||
|
enableLeechSize,
|
||||||
|
|
||||||
// diskstation
|
// diskstation
|
||||||
volume,
|
volume,
|
||||||
@@ -408,6 +409,9 @@ export function cleanServiceGroups(groups) {
|
|||||||
// wgeasy
|
// wgeasy
|
||||||
threshold,
|
threshold,
|
||||||
|
|
||||||
|
// yourspotify
|
||||||
|
interval,
|
||||||
|
|
||||||
// technitium
|
// technitium
|
||||||
range,
|
range,
|
||||||
|
|
||||||
@@ -490,6 +494,7 @@ export function cleanServiceGroups(groups) {
|
|||||||
}
|
}
|
||||||
if (["deluge", "qbittorrent"].includes(type)) {
|
if (["deluge", "qbittorrent"].includes(type)) {
|
||||||
if (enableLeechProgress !== undefined) widget.enableLeechProgress = JSON.parse(enableLeechProgress);
|
if (enableLeechProgress !== undefined) widget.enableLeechProgress = JSON.parse(enableLeechProgress);
|
||||||
|
if (enableLeechSize !== undefined) widget.enableLeechSize = JSON.parse(enableLeechSize);
|
||||||
}
|
}
|
||||||
if (["opnsense", "pfsense"].includes(type)) {
|
if (["opnsense", "pfsense"].includes(type)) {
|
||||||
if (wan) widget.wan = wan;
|
if (wan) widget.wan = wan;
|
||||||
@@ -623,6 +628,11 @@ export function cleanServiceGroups(groups) {
|
|||||||
if (pool3) widget.pool3 = pool3;
|
if (pool3) widget.pool3 = pool3;
|
||||||
if (pool4) widget.pool4 = pool4;
|
if (pool4) widget.pool4 = pool4;
|
||||||
}
|
}
|
||||||
|
if (type === "yourspotify") {
|
||||||
|
if (interval !== undefined) {
|
||||||
|
widget.interval = interval;
|
||||||
|
}
|
||||||
|
}
|
||||||
return widget;
|
return widget;
|
||||||
});
|
});
|
||||||
return cleanedService;
|
return cleanedService;
|
||||||
|
|||||||
@@ -150,6 +150,7 @@ const components = {
|
|||||||
wgeasy: dynamic(() => import("./wgeasy/component")),
|
wgeasy: dynamic(() => import("./wgeasy/component")),
|
||||||
whatsupdocker: dynamic(() => import("./whatsupdocker/component")),
|
whatsupdocker: dynamic(() => import("./whatsupdocker/component")),
|
||||||
xteve: dynamic(() => import("./xteve/component")),
|
xteve: dynamic(() => import("./xteve/component")),
|
||||||
|
yourspotify: dynamic(() => import("./yourspotify/component")),
|
||||||
zabbix: dynamic(() => import("./zabbix/component")),
|
zabbix: dynamic(() => import("./zabbix/component")),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -80,6 +80,11 @@ export default function Component({ service }) {
|
|||||||
timeLeft={t("common.duration", { value: queueEntry.eta })}
|
timeLeft={t("common.duration", { value: queueEntry.eta })}
|
||||||
title={queueEntry.name}
|
title={queueEntry.name}
|
||||||
activity={queueEntry.state}
|
activity={queueEntry.state}
|
||||||
|
size={
|
||||||
|
widget?.enableLeechSize
|
||||||
|
? t("common.bbytes", { value: queueEntry.size, maximumFractionDigits: 1 })
|
||||||
|
: undefined
|
||||||
|
}
|
||||||
key={`${queueEntry.name}-${queueEntry.amount_left}`}
|
key={`${queueEntry.name}-${queueEntry.amount_left}`}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ import watchtower from "./watchtower/widget";
|
|||||||
import wgeasy from "./wgeasy/widget";
|
import wgeasy from "./wgeasy/widget";
|
||||||
import whatsupdocker from "./whatsupdocker/widget";
|
import whatsupdocker from "./whatsupdocker/widget";
|
||||||
import xteve from "./xteve/widget";
|
import xteve from "./xteve/widget";
|
||||||
|
import yourspotify from "./yourspotify/widget";
|
||||||
import zabbix from "./zabbix/widget";
|
import zabbix from "./zabbix/widget";
|
||||||
|
|
||||||
const widgets = {
|
const widgets = {
|
||||||
@@ -291,6 +292,7 @@ const widgets = {
|
|||||||
wgeasy,
|
wgeasy,
|
||||||
whatsupdocker,
|
whatsupdocker,
|
||||||
xteve,
|
xteve,
|
||||||
|
yourspotify,
|
||||||
zabbix,
|
zabbix,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
76
src/widgets/yourspotify/component.jsx
Normal file
76
src/widgets/yourspotify/component.jsx
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
import Block from "components/services/widget/block";
|
||||||
|
import Container from "components/services/widget/container";
|
||||||
|
import { useTranslation } from "next-i18next";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
|
||||||
|
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||||
|
|
||||||
|
function getStartDate(interval) {
|
||||||
|
const d = new Date();
|
||||||
|
switch (interval) {
|
||||||
|
case "day":
|
||||||
|
d.setDate(d.getDate() - 1);
|
||||||
|
break;
|
||||||
|
case "week":
|
||||||
|
d.setDate(d.getDate() - 7);
|
||||||
|
break;
|
||||||
|
case "month":
|
||||||
|
d.setMonth(d.getMonth() - 1);
|
||||||
|
break;
|
||||||
|
case "year":
|
||||||
|
d.setFullYear(d.getFullYear() - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return d.toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Component({ service }) {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const { widget } = service;
|
||||||
|
|
||||||
|
const interval = widget?.interval || "week";
|
||||||
|
|
||||||
|
const date = useMemo(() => {
|
||||||
|
return interval === "all" ? "2006-04-23T00:00:00.000Z" : getStartDate(interval);
|
||||||
|
}, [interval]);
|
||||||
|
|
||||||
|
const params = {
|
||||||
|
timeSplit: "all",
|
||||||
|
start: date,
|
||||||
|
};
|
||||||
|
|
||||||
|
const { data: songsListened, error: songsError } = useWidgetAPI(widget, "songs", params);
|
||||||
|
const { data: timeListened, error: timeError } = useWidgetAPI(widget, "time", params);
|
||||||
|
const { data: artistsListened, error: artistsError } = useWidgetAPI(widget, "artists", params);
|
||||||
|
|
||||||
|
if (songsError || timeError || artistsError) {
|
||||||
|
return <Container service={service} error={songsError ?? timeError ?? artistsError} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isNaN(songsListened) || isNaN(timeListened) || isNaN(artistsListened)) {
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
<Block label="yourspotify.songs" />
|
||||||
|
<Block label="yourspotify.time" />
|
||||||
|
<Block label="yourspotify.artists" />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
<Block label="yourspotify.songs" value={t("common.number", { value: songsListened })} />
|
||||||
|
|
||||||
|
<Block
|
||||||
|
label="yourspotify.time"
|
||||||
|
value={t(
|
||||||
|
timeListened > 0 ? "common.duration" : "common.number", // Display 0 if duration is 0
|
||||||
|
{
|
||||||
|
value: timeListened / 1000,
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Block label="yourspotify.artists" value={t("common.number", { value: artistsListened })} />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
27
src/widgets/yourspotify/widget.js
Normal file
27
src/widgets/yourspotify/widget.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import { asJson } from "utils/proxy/api-helpers";
|
||||||
|
import genericProxyHandler from "utils/proxy/handlers/generic";
|
||||||
|
|
||||||
|
const widget = {
|
||||||
|
api: "{url}/spotify/{endpoint}?token={key}",
|
||||||
|
proxyHandler: genericProxyHandler,
|
||||||
|
|
||||||
|
mappings: {
|
||||||
|
songs: {
|
||||||
|
endpoint: "songs_per",
|
||||||
|
params: ["start", "timeSplit"],
|
||||||
|
map: (data) => asJson(data)[0]?.count || 0,
|
||||||
|
},
|
||||||
|
time: {
|
||||||
|
endpoint: "time_per",
|
||||||
|
params: ["start", "timeSplit"],
|
||||||
|
map: (data) => asJson(data)[0]?.count || 0,
|
||||||
|
},
|
||||||
|
artists: {
|
||||||
|
endpoint: "different_artists_per",
|
||||||
|
params: ["start", "timeSplit"],
|
||||||
|
map: (data) => asJson(data)[0]?.artists?.length || 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default widget;
|
||||||
Reference in New Issue
Block a user