From 04a9be5c93682d1e6f9cbe24f975585c0758221b Mon Sep 17 00:00:00 2001 From: Robonau <30987265+Robonau@users.noreply.github> Date: Tue, 12 Nov 2024 01:33:45 +0000 Subject: [PATCH] resolve review issues --- docs/widgets/services/suwayomi.md | 30 ++---- src/widgets/suwayomi/component.jsx | 41 ++------ src/widgets/suwayomi/proxy.js | 145 ++++++----------------------- 3 files changed, 43 insertions(+), 173 deletions(-) diff --git a/docs/widgets/services/suwayomi.md b/docs/widgets/services/suwayomi.md index 52753474..c4a7b416 100644 --- a/docs/widgets/services/suwayomi.md +++ b/docs/widgets/services/suwayomi.md @@ -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 ``` diff --git a/src/widgets/suwayomi/component.jsx b/src/widgets/suwayomi/component.jsx index 28bfc951..fa753917 100644 --- a/src/widgets/suwayomi/component.jsx +++ b/src/widgets/suwayomi/component.jsx @@ -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 ( - {fields.map((field) => ( + {widget.fields.map((field) => ( ))} diff --git a/src/widgets/suwayomi/proxy.js b/src/widgets/suwayomi/proxy.js index 324ae291..eb19f388 100644 --- a/src/widgets/suwayomi/proxy.js +++ b/src/widgets/suwayomi/proxy.js @@ -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} */ 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);