Feature: fireshare widget
This commit is contained in:
parent
97d7ae21e4
commit
f57368519f
16
docs/widgets/services/fireshare.md
Normal file
16
docs/widgets/services/fireshare.md
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
---
|
||||||
|
title: Fireshare
|
||||||
|
description: Fireshare Widget Configuration
|
||||||
|
---
|
||||||
|
|
||||||
|
Learn more about [Fireshare](https://github.com/ShaneIsrael/fireshare).
|
||||||
|
|
||||||
|
Allowed fields: `["total", "categories", "views"]`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
widget:
|
||||||
|
type: fireshare
|
||||||
|
url: http://fireshare.host.or.ip
|
||||||
|
username: username
|
||||||
|
password: password
|
||||||
|
```
|
||||||
@ -882,5 +882,10 @@
|
|||||||
"enabled": "Enabled",
|
"enabled": "Enabled",
|
||||||
"disabled": "Disabled",
|
"disabled": "Disabled",
|
||||||
"total": "Total"
|
"total": "Total"
|
||||||
|
},
|
||||||
|
"fireshare": {
|
||||||
|
"total": "Total",
|
||||||
|
"categories": "Categories",
|
||||||
|
"views": "Views"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -27,6 +27,7 @@ const components = {
|
|||||||
esphome: dynamic(() => import("./esphome/component")),
|
esphome: dynamic(() => import("./esphome/component")),
|
||||||
evcc: dynamic(() => import("./evcc/component")),
|
evcc: dynamic(() => import("./evcc/component")),
|
||||||
fileflows: dynamic(() => import("./fileflows/component")),
|
fileflows: dynamic(() => import("./fileflows/component")),
|
||||||
|
fireshare: dynamic(() => import("./fireshare/component")),
|
||||||
flood: dynamic(() => import("./flood/component")),
|
flood: dynamic(() => import("./flood/component")),
|
||||||
freshrss: dynamic(() => import("./freshrss/component")),
|
freshrss: dynamic(() => import("./freshrss/component")),
|
||||||
fritzbox: dynamic(() => import("./fritzbox/component")),
|
fritzbox: dynamic(() => import("./fritzbox/component")),
|
||||||
|
|||||||
44
src/widgets/fireshare/component.jsx
Normal file
44
src/widgets/fireshare/component.jsx
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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 { widget } = service;
|
||||||
|
|
||||||
|
const { data: infoData, error: infoError } = useWidgetAPI(widget);
|
||||||
|
|
||||||
|
if (!widget.fields) {
|
||||||
|
widget.fields = ["total", "categories", "views"];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (infoError) {
|
||||||
|
return <Container service={service} error={infoError} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!infoData) {
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
<Block label="fireshare.total" />
|
||||||
|
<Block label="fireshare.categories" />
|
||||||
|
<Block label="fireshare.views" />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const total = infoData.videos.length;
|
||||||
|
const categoriesSet = new Set();
|
||||||
|
infoData.videos.forEach(video => {
|
||||||
|
const category = video.path.split('/')[0];
|
||||||
|
categoriesSet.add(category);
|
||||||
|
});
|
||||||
|
const categoriesCount = categoriesSet.size;
|
||||||
|
const totalViews = infoData.videos.reduce((acc, video) => acc + video.view_count, 0);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Container service={service}>
|
||||||
|
<Block label="fireshare.total" value={total} />
|
||||||
|
<Block label="fireshare.categories" value={categoriesCount} />
|
||||||
|
<Block label="fireshare.views" value={totalViews} />
|
||||||
|
</Container>
|
||||||
|
);
|
||||||
|
}
|
||||||
74
src/widgets/fireshare/proxy.js
Normal file
74
src/widgets/fireshare/proxy.js
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import cache from "memory-cache";
|
||||||
|
|
||||||
|
import getServiceWidget from "utils/config/service-helpers";
|
||||||
|
import { formatApiCall } from "utils/proxy/api-helpers";
|
||||||
|
import { httpProxy } from "utils/proxy/http";
|
||||||
|
import widgets from "widgets/widgets";
|
||||||
|
import createLogger from "utils/logger";
|
||||||
|
|
||||||
|
const proxyName = "fireshareProxyHandler";
|
||||||
|
const logger = createLogger(proxyName);
|
||||||
|
const sessionTokenCacheKey = `${proxyName}__sessionToken`;
|
||||||
|
|
||||||
|
async function login(widget, service) {
|
||||||
|
const url = formatApiCall(widgets[widget.type].api, { ...widget, endpoint: "login" });
|
||||||
|
logger.info(`url: ${url}`);
|
||||||
|
logger.info(`username: ${widget.username}, password: ${widget.password}`);
|
||||||
|
const [, , , responseHeaders] = await httpProxy(url, {
|
||||||
|
method: "POST",
|
||||||
|
body: JSON.stringify({ username: widget.username, password: widget.password }),
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
logger.info(responseHeaders);
|
||||||
|
const rememberTokenCookie = responseHeaders["set-cookie"]
|
||||||
|
.find((cookie) => cookie.startsWith("remember_token="))
|
||||||
|
.split(";")[0]
|
||||||
|
.replace("remember_token=", "");
|
||||||
|
logger.info(`remember_token: ${rememberTokenCookie}`);
|
||||||
|
cache.put(`${sessionTokenCacheKey}.${service}`, rememberTokenCookie);
|
||||||
|
return rememberTokenCookie;
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Error retrieving 'remember_token' cookie for service: ${service}`);
|
||||||
|
cache.del(`${sessionTokenCacheKey}.${service}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function fireshareProxyHandler(req, res) {
|
||||||
|
const { group, service } = 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) {
|
||||||
|
let token = cache.get(`${sessionTokenCacheKey}.${service}`);
|
||||||
|
if (!token) {
|
||||||
|
token = await login(widget, service);
|
||||||
|
if (!token) {
|
||||||
|
return res.status(500).json({ error: "Failed to authenticate with Fireshare" });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const [, , data] = await httpProxy(
|
||||||
|
formatApiCall(widgets[widget.type].api, { ...widget, endpoint: "videos?sort=updated_at+desc" }),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
Cookie: `remember_token=${token}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return res.json(JSON.parse(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.status(400).json({ error: "Invalid proxy service type" });
|
||||||
|
}
|
||||||
8
src/widgets/fireshare/widget.js
Normal file
8
src/widgets/fireshare/widget.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import fireshareProxyHandler from "./proxy";
|
||||||
|
|
||||||
|
const widget = {
|
||||||
|
api: "{url}/api/{endpoint}",
|
||||||
|
proxyHandler: fireshareProxyHandler,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default widget;
|
||||||
@ -21,6 +21,7 @@ import emby from "./emby/widget";
|
|||||||
import esphome from "./esphome/widget";
|
import esphome from "./esphome/widget";
|
||||||
import evcc from "./evcc/widget";
|
import evcc from "./evcc/widget";
|
||||||
import fileflows from "./fileflows/widget";
|
import fileflows from "./fileflows/widget";
|
||||||
|
import fireshare from "./fireshare/widget";
|
||||||
import flood from "./flood/widget";
|
import flood from "./flood/widget";
|
||||||
import freshrss from "./freshrss/widget";
|
import freshrss from "./freshrss/widget";
|
||||||
import fritzbox from "./fritzbox/widget";
|
import fritzbox from "./fritzbox/widget";
|
||||||
@ -136,6 +137,7 @@ const widgets = {
|
|||||||
esphome,
|
esphome,
|
||||||
evcc,
|
evcc,
|
||||||
fileflows,
|
fileflows,
|
||||||
|
fireshare,
|
||||||
flood,
|
flood,
|
||||||
freshrss,
|
freshrss,
|
||||||
fritzbox,
|
fritzbox,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user