resolve review issues
This commit is contained in:
parent
a1f86a4470
commit
04a9be5c93
@ -5,28 +5,16 @@ description: Suwayomi Widget Configuration
|
||||
|
||||
Learn more about [Suwayomi](https://github.com/Suwayomi/Suwayomi-Server).
|
||||
|
||||
all supported fields shown in example yaml, though a max of 4 will show at one time.
|
||||
The default fields are download, nondownload, read and unread.
|
||||
category defaults to "all" if left unset or set to not a number.
|
||||
The category ID can be obtained from the url when navigating to it, `?tab={categoryID}`.
|
||||
username and password are available if you have basic auth setup for Suwayomi.
|
||||
Allowed fields:["download", "nondownload", "read", "unread", "downloadedread", "downloadedunread", "nondownloadedread", "nondownloadedunread"]
|
||||
|
||||
The widget defaults to the first four above. If more than four fields are provided, only the first 4 are displayed.
|
||||
Category IDs can be obtained from the url when navigating to it, `?tab={categoryID}`.
|
||||
|
||||
```yaml
|
||||
widget:
|
||||
icon: https://raw.githubusercontent.com/Suwayomi/Suwayomi-Server/refs/heads/master/server/src/main/resources/icon/faviconlogo-128.png
|
||||
widget:
|
||||
type: suwayomi
|
||||
url: http://suwayomi.host.or.ip
|
||||
username: username
|
||||
password: password
|
||||
category: 0
|
||||
fields:
|
||||
- download
|
||||
- nondownload
|
||||
- read
|
||||
- unread
|
||||
- downloadedRead
|
||||
- downloadedunread
|
||||
- nondownloadedread
|
||||
- nondownloadedunread
|
||||
type: suwayomi
|
||||
url: http://suwayomi.host.or.ip
|
||||
username: username #optional
|
||||
password: password #optional
|
||||
category: 0 #optional, defaults to all categories
|
||||
```
|
||||
|
||||
@ -4,43 +4,11 @@ import Container from "components/services/widget/container";
|
||||
import Block from "components/services/widget/block";
|
||||
import useWidgetAPI from "utils/proxy/use-widget-api";
|
||||
|
||||
/**
|
||||
* @param {string[]|null} Fields
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function makeFields(Fields = []) {
|
||||
let fields = Fields ?? [];
|
||||
if (fields.length === 0) {
|
||||
fields = ["download", "nonDownload", "read", "unRead"];
|
||||
}
|
||||
if (fields.length > 4) {
|
||||
fields.length = 4;
|
||||
}
|
||||
fields = fields.map((field) => field.toLowerCase());
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
export default function Component({ service }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
/**
|
||||
* @type {{
|
||||
* widget: {
|
||||
* fields: string[]|null
|
||||
* }
|
||||
* }}
|
||||
*/
|
||||
const { widget } = service;
|
||||
|
||||
/**
|
||||
* @type {{
|
||||
* error: unknown
|
||||
* data: ({
|
||||
* label: string, count: number
|
||||
* }[]),
|
||||
* }}
|
||||
*/
|
||||
const { data: suwayomiData, error: suwayomiError } = useWidgetAPI(widget);
|
||||
|
||||
if (suwayomiError) {
|
||||
@ -48,10 +16,15 @@ export default function Component({ service }) {
|
||||
}
|
||||
|
||||
if (!suwayomiData) {
|
||||
const fields = makeFields(widget.fields);
|
||||
if (!widget.fields || widget.fields.length === 0) {
|
||||
widget.fields = ["download", "nondownload", "read", "unread"];
|
||||
} else if (widget.fields.length > 4) {
|
||||
widget.fields = widget.fields.slice(0, 4);
|
||||
widget.fields = widget.fields.map((field) => field.toLowerCase());
|
||||
}
|
||||
return (
|
||||
<Container service={service}>
|
||||
{fields.map((field) => (
|
||||
{widget.fields.map((field) => (
|
||||
<Block key={field} label={`suwayomi.${field}`} />
|
||||
))}
|
||||
</Container>
|
||||
|
||||
@ -7,69 +7,6 @@ import widgets from "widgets/widgets";
|
||||
const proxyName = "suwayomiProxyHandler";
|
||||
const logger = createLogger(proxyName);
|
||||
|
||||
/**
|
||||
* @typedef {object} countsToExtractItem
|
||||
* @property {(chapter: chapter) => boolean} condition
|
||||
* @property {string} gqlCondition
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef totalCount
|
||||
* @type {object}
|
||||
* @property {string} totalCount - count
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef ResponseJSON
|
||||
* @type {{
|
||||
* data: {
|
||||
* download: totalCount,
|
||||
* nondownload: totalCount,
|
||||
* read: totalCount,
|
||||
* unread: totalCount,
|
||||
* downloadedRead: totalCount,
|
||||
* downloadedunread: totalCount,
|
||||
* nondownloadedread: totalCount,
|
||||
* nondownloadedunread: totalCount,
|
||||
* }
|
||||
* }}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef chapter
|
||||
* @type {{
|
||||
* isRead: boolean,
|
||||
* isDownloaded: boolean
|
||||
* }}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef ResponseJSONcategory
|
||||
* @type {{
|
||||
* data: {
|
||||
* category: {
|
||||
* mangas: {
|
||||
* nodes: {
|
||||
* chapters: {
|
||||
* nodes: chapter[]
|
||||
* }
|
||||
* }[]
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }}
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {object} widget
|
||||
* @property {string} username
|
||||
* @property {string} password
|
||||
* @property {string[]|null} fields
|
||||
* @property {string|number|undefined} category
|
||||
* @property {keyof typeof widgets} type
|
||||
*/
|
||||
|
||||
/** @type {Record<string, countsToExtractItem>} */
|
||||
const countsToExtract = {
|
||||
download: {
|
||||
condition: (c) => c.isDownloaded,
|
||||
@ -79,9 +16,18 @@ const countsToExtract = {
|
||||
condition: (c) => !c.isDownloaded,
|
||||
gqlCondition: "isDownloaded: false",
|
||||
},
|
||||
read: { condition: (c) => c.isRead, gqlCondition: "isRead: true" },
|
||||
unread: { condition: (c) => !c.isRead, gqlCondition: "isRead: false" },
|
||||
downloadedread: { condition: (c) => c.isDownloaded && c.isRead, gqlCondition: "isDownloaded: true, isRead: true" },
|
||||
read: {
|
||||
condition: (c) => c.isRead,
|
||||
gqlCondition: "isRead: true",
|
||||
},
|
||||
unread: {
|
||||
condition: (c) => !c.isRead,
|
||||
gqlCondition: "isRead: false",
|
||||
},
|
||||
downloadedread: {
|
||||
condition: (c) => c.isDownloaded && c.isRead,
|
||||
gqlCondition: "isDownloaded: true, isRead: true",
|
||||
},
|
||||
downloadedunread: {
|
||||
condition: (c) => c.isDownloaded && !c.isRead,
|
||||
gqlCondition: "isDownloaded: true, isRead: false",
|
||||
@ -96,13 +42,6 @@ const countsToExtract = {
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Makes a GraphQL query body based on the provided fieldsSet and category.
|
||||
*
|
||||
* @param {string[]} fields - Array of field names.
|
||||
* @param {string|number|undefined} [category="all"] - Category ID or "all" for general counts.
|
||||
* @returns {string} - The JSON stringified query body.
|
||||
*/
|
||||
function makeBody(fields, category = "all") {
|
||||
if (Number.isNaN(Number(category))) {
|
||||
let query = "";
|
||||
@ -148,13 +87,6 @@ function makeBody(fields, category = "all") {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the counts from the response JSON object based on the provided fields.
|
||||
*
|
||||
* @param {ResponseJSON|ResponseJSONcategory} responseJSON - The response JSON object.
|
||||
* @param {string[]} fields - Array of field names.
|
||||
* @returns
|
||||
*/
|
||||
function extractCounts(responseJSON, fields) {
|
||||
if (!("category" in responseJSON.data)) {
|
||||
return fields.map((field) => ({
|
||||
@ -181,38 +113,6 @@ function extractCounts(responseJSON, fields) {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string[]|null} Fields
|
||||
* @returns {string[]}
|
||||
*/
|
||||
function makeFields(Fields = []) {
|
||||
let fields = Fields ?? [];
|
||||
if (fields.length === 0) {
|
||||
fields = ["download", "nonDownload", "read", "unRead"];
|
||||
}
|
||||
if (fields.length > 4) {
|
||||
fields.length = 4;
|
||||
}
|
||||
fields = fields.map((f) => f.toLowerCase());
|
||||
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {widget} widget
|
||||
* @returns {{ "Content-Type": string, Authorization?: string }}
|
||||
*/
|
||||
function makeHeaders(widget) {
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
if (widget.username && widget.password) {
|
||||
headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`;
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
export default async function suwayomiProxyHandler(req, res) {
|
||||
const { group, service, endpoint } = req.query;
|
||||
|
||||
@ -221,7 +121,6 @@ export default async function suwayomiProxyHandler(req, res) {
|
||||
return res.status(400).json({ error: "Invalid proxy service type" });
|
||||
}
|
||||
|
||||
/** @type {widget} */
|
||||
const widget = await getServiceWidget(group, service);
|
||||
|
||||
if (!widget) {
|
||||
@ -229,13 +128,24 @@ export default async function suwayomiProxyHandler(req, res) {
|
||||
return res.status(400).json({ error: "Invalid proxy service type" });
|
||||
}
|
||||
|
||||
const fields = makeFields(widget.fields);
|
||||
if (!widget.fields || widget.fields.length === 0) {
|
||||
widget.fields = ["download", "nondownload", "read", "unread"];
|
||||
} else if (widget.fields.length > 4) {
|
||||
widget.fields = widget.fields.slice(0, 4);
|
||||
widget.fields = widget.fields.map((field) => field.toLowerCase());
|
||||
}
|
||||
|
||||
const url = new URL(formatApiCall(widgets[widget.type].api, { endpoint, ...widget }));
|
||||
|
||||
const body = makeBody(fields, widget.category);
|
||||
const body = makeBody(widget.fields, widget.category);
|
||||
|
||||
const headers = makeHeaders(widget);
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
if (widget.username && widget.password) {
|
||||
headers.Authorization = `Basic ${Buffer.from(`${widget.username}:${widget.password}`).toString("base64")}`;
|
||||
}
|
||||
|
||||
const [status, contentType, data] = await httpProxy(url, {
|
||||
method: "POST",
|
||||
@ -259,10 +169,9 @@ export default async function suwayomiProxyHandler(req, res) {
|
||||
return res.status(status).send({ error: { message: "Error getting data. body: %s, data: %s", body, data } });
|
||||
}
|
||||
|
||||
/** @type {ResponseJSON|ResponseJSONcategory} */
|
||||
const responseJSON = JSON.parse(data);
|
||||
|
||||
const returnData = extractCounts(responseJSON, fields);
|
||||
const returnData = extractCounts(responseJSON, widget.fields);
|
||||
|
||||
if (contentType) res.setHeader("Content-Type", contentType);
|
||||
return res.status(status).send(returnData);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user