diff --git a/lib/router.js b/lib/router.js index 8bf1ee589..955ae25df 100644 --- a/lib/router.js +++ b/lib/router.js @@ -429,10 +429,6 @@ router.get('/testerhome/newest', lazyloadRouteHandler('./routes/testerhome/newes // 玩物志 router.get('/coolbuy/newest', lazyloadRouteHandler('./routes/coolbuy/newest')); -// MiniFlux -router.get('/miniflux/subscription/:parameters?', lazyloadRouteHandler('./routes/miniflux/get-feeds')); -router.get('/miniflux/:feeds/:parameters?', lazyloadRouteHandler('./routes/miniflux/get-entries')); - // 動畫瘋 // router.get('/anigamer/new_anime', lazyloadRouteHandler('./routes/anigamer/new-anime')); // router.get('/anigamer/anime/:sn', lazyloadRouteHandler('./routes/anigamer/anime')); diff --git a/lib/routes-deprecated/miniflux/get-entries.js b/lib/routes/miniflux/entry.ts similarity index 61% rename from lib/routes-deprecated/miniflux/get-entries.js rename to lib/routes/miniflux/entry.ts index bbd363de8..e24a07794 100644 --- a/lib/routes-deprecated/miniflux/get-entries.js +++ b/lib/routes/miniflux/entry.ts @@ -1,18 +1,64 @@ -const got = require('@/utils/got'); -const config = require('@/config').value; +import { Route, Data } from '@/types'; +import got from '@/utils/got'; +import { config } from '@/config'; -// Unchanged entries status after fetching. -// mark = unchanged | read | removed | unread -let mark = 'unchanged'; -// Return shared link as default behavior -// link = shared | original -// let link = 'shared'; -// Add feed's name to each article, default is off. -let addFeedName = 0; -// Here we use `limit` to temporarily store the limit number. -let limit = 0; +export const route: Route = { + path: '/entry/:feeds/:parameters?', + description: ` +1. Support to get all content: You can obtain the content of all subscription sources by using keywords such as \`/miniflux/all\` or \`/miniflux/default\`. +2. Support to get the subscription content of a specific subscription source by its ID. Please obtain the subscription source ID on the page where it is located under \`Sources\` (shortcut keys \`g\` \`f\`). The URL for each category (or subscription source) displays its ID information. There are several format options available: + 1. Support \`/miniflux/feed=[feed_id]\`, please replace \`[feed_id]\` with the actual ID of the subscribed feed (note that it should be just a number without brackets). + 2. Support subscribing to multiple feeds using \`/miniflux/feed=[feed1_id]&feed=[feed2_id]\` or \`/miniflux/feeds=[feed1_id]&[feed2_id]\`. + 3. Additionally, you can use shorthand notation by directly using feed IDs: \`/miniflux/[feed1_id]&[feed2_id]\`. +3. Further customization options are available based on your needs: + 1. All parameters/options provided by MiniFlux are supported ([link](https://miniflux.app/docs/api.html#endpoint-get-feed-entries)). As noted in their documentation, multiple filtering options should be connected with \`&\`. Except for \`status\`, only the first occurrence of duplicate filter options will be considered. + 2. Specifically, this route defaults to sorting entries from new to old (\`direction=desc\`). + 3. Moreover, this route supports additional options including: + - Using the \`feed_name\` parameter to control title formatting; setting \`feed_name=1\` will display each title as "Article Title | Feed Name," while default is set at \`0\`, showing only article titles. + - Utilizing the \`mark\` parameter to specify actions after fetching subscriptions in RSSHub, such as maintaining unchanged state (\`unchanged\`, default), marking as read (\`read\`), removing (\`removed\`) or marking as unread (\`unread\`). Note that marking as read should not simply be understood as a means for implementing synchronization services; rather, it functions more like an aid for MiniFlux's automatic cleaning feature. + - Future support may include utilizing the \`link\` parameter to control output URLs (this functionality requires corresponding interfaces from MiniFlux). It could involve generating URLs through MiniFlux entity sharing features or original content links. + - The output content quantity can be controlled via the 'limit' parameter; although all matching contents are typically outputted by default, **it is recommended that users set this parameter**. + `, + categories: ['other'], + example: '/miniflux/feeds=1&2&3/mark=read&limit=7&status=unread', + parameters: { + feeds: 'Subscribe source ID or get all.', + parameters: 'Filter and set parameters, use `&` to connect multiple.', + }, + features: { + requireConfig: [ + { + name: 'MINIFLUX_INSTANCE', + description: 'The instance used by the user, by default, is the official MiniFlux [paid service address](https://reader.miniflux.app)', + }, + { + name: 'MINIFLUX_TOKEN', + description: "User's API key, please log in to the instance used and go to `Settings` -> `API Key` -> `Create a new API key` to obtain.", + }, + ], + requirePuppeteer: false, + antiCrawler: false, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, + name: 'Subscriptions', + maintainers: ['emdoe', 'DIYgod'], + handler, +}; + +async function handler(ctx) { + // Unchanged entries status after fetching. + // mark = unchanged | read | removed | unread + let mark = 'unchanged'; + // Return shared link as default behavior + // link = shared | original + // let link = 'shared'; + // Add feed's name to each article, default is off. + let addFeedName = 0; + // Here we use `limit` to temporarily store the limit number. + let limit = 0; -module.exports = async (ctx) => { const instance = config.miniflux.instance; const token = config.miniflux.token; @@ -94,9 +140,9 @@ module.exports = async (ctx) => { const setMark = []; const setFeedName = []; - const feeds = ctx.params.feeds; + const feeds = ctx.req.param('feeds'); - let parameters = ctx.params.parameters; + let parameters = ctx.req.param('parameters'); // Set default direction if (parameters.search('direction=') === -1) { parameters += '&direction=desc'; @@ -108,32 +154,34 @@ module.exports = async (ctx) => { .filter(Boolean) .join('&'); + let queryLimit = ctx.req.query('limit'); + let result: Data; if (feeds.search(/feeds?=/g) !== -1 || !isNaN(Number.parseInt(feeds.split('&').join('')))) { const feedsID = feeds.replaceAll(/feeds?=/g, ''); const feedsList = [feedsID.split('&')].flat(); - if (limit && ctx.query.limit) { - if (limit < ctx.query.limit) { - ctx.query.limit = limit * feedsList.length; + if (limit && queryLimit) { + if (limit < queryLimit) { + queryLimit = limit * feedsList.length; } else { - const eachLimit = Number.parseInt(ctx.query.limit / feedsList.length); + const eachLimit = Number.parseInt(queryLimit / feedsList.length); if (eachLimit) { limit = eachLimit; } else { limit = 1; - ctx.query.limit = feedsList.length; + queryLimit = feedsList.length; } } parameters += `&limit=${limit}`; } else if (limit) { parameters += `&limit=${limit}`; - } else if (ctx.query.limit) { - const eachLimit = Number.parseInt(ctx.query.limit / feedsList.length); + } else if (queryLimit) { + const eachLimit = Number.parseInt(queryLimit / feedsList.length); if (eachLimit) { limit = eachLimit; } else { limit = 1; - ctx.query.limit = feedsList.length; + queryLimit = feedsList.length; } parameters += `&limit=${limit}`; } @@ -193,7 +241,7 @@ module.exports = async (ctx) => { agInfo = 'An aggregator powered by MiniFlux and RSSHub ' + 'with empty content. If this is not your intention, ' + `please double-check your setting for parameters.`; } - ctx.state.data = { + result = { title: agTitle, link: instance, description: agInfo, @@ -201,14 +249,14 @@ module.exports = async (ctx) => { allowEmpty: true, }; } else { - if (limit && ctx.query.limit) { - if (limit < ctx.query.limit) { - ctx.query.limit = limit; + if (limit && queryLimit) { + if (limit < queryLimit) { + queryLimit = limit; } // Here we could add a '&' since parameter(s) list must not empty. - parameters += `&limit=${ctx.query.limit}`; - } else if (ctx.query.limit) { - parameters += `&limit=${ctx.query.limit}`; + parameters += `&limit=${queryLimit}`; + } else if (queryLimit) { + parameters += `&limit=${queryLimit}`; } else if (limit) { parameters += `&limit=${limit}`; } @@ -238,7 +286,7 @@ module.exports = async (ctx) => { }); } - ctx.state.data = { + result = { title: `MiniFlux | All`, link: instance, description: `All feeds on ${instance} powered by MiniFlux`, @@ -261,4 +309,6 @@ module.exports = async (ctx) => { }, }); } -}; + + return result; +} diff --git a/lib/routes/miniflux/namespace.ts b/lib/routes/miniflux/namespace.ts new file mode 100644 index 000000000..e3ed1d00b --- /dev/null +++ b/lib/routes/miniflux/namespace.ts @@ -0,0 +1,6 @@ +import type { Namespace } from '@/types'; + +export const namespace: Namespace = { + name: 'MiniFlux', + url: 'miniflux.app', +}; diff --git a/lib/routes-deprecated/miniflux/get-feeds.js b/lib/routes/miniflux/subscription.ts similarity index 52% rename from lib/routes-deprecated/miniflux/get-feeds.js rename to lib/routes/miniflux/subscription.ts index 7b8b3d98d..0aa91c42a 100644 --- a/lib/routes-deprecated/miniflux/get-feeds.js +++ b/lib/routes/miniflux/subscription.ts @@ -1,7 +1,44 @@ -const got = require('@/utils/got'); -const config = require('@/config').value; +import { Route } from '@/types'; +import got from '@/utils/got'; +import { config } from '@/config'; -module.exports = async (ctx) => { +export const route: Route = { + path: '/subscription/:parameters?', + description: ` +1. If no specific parameters are specified, all subscription sources will be output by default. +2. Please obtain the Category ID or Subscription Source ID on the \`Category\` (shortcut \`g\` \`c\`) or \`Source\` (shortcut \`g\` \`f\`) page. The URL of each category (or subscription source) will display its ID information. +3. Support for category names and category IDs, to output multiple categories, please repeat entering \`category=\` and connect with \`&\`, or directly use **English** commas between different category names. For example, you can subscribe through \`/miniflux/subscription/category=technology&category=1\` or \`/miniflux/subscription/categories=technology,1\`. +4. Support specifying the subscription source name or subscription source ID, similar to setting categories. For example, you can subscribe through \`/miniflux/subscription/feed=1&feed=Archdaily\` or \`/miniflux/subscription/feeds=1,Archdaily\`. +5. Support simultaneously specifying subscription source information and category information; it will output subscription sources that meet the selected categories' criteria. Consider an example: by using \`/miniflux/subscription/feeds=1,archdaily&category=art,7\`, if the Subscription Source ID is 1 or the Subscription Source Name is ArchDaily indeed falls under Category 'art' or has a Category ID of 7, then output that subscription source information. + `, + categories: ['other'], + example: '/miniflux/subscription/categories=test', + parameters: { + parameters: 'Category name or category ID or/and subscription source name or subscription source ID', + }, + features: { + requireConfig: [ + { + name: 'MINIFLUX_INSTANCE', + description: 'The instance used by the user, by default, is the official MiniFlux [paid service address](https://reader.miniflux.app)', + }, + { + name: 'MINIFLUX_TOKEN', + description: "User's API key, please log in to the instance used and go to `Settings` -> `API Key` -> `Create a new API key` to obtain.", + }, + ], + requirePuppeteer: false, + antiCrawler: false, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, + name: 'Subscriptions', + maintainers: ['emdoe', 'DIYgod'], + handler, +}; + +async function handler(ctx) { const instance = config.miniflux.instance; const token = config.miniflux.token; @@ -45,7 +82,8 @@ module.exports = async (ctx) => { const feeds = []; const feedsList = response.data; - const parameters = ctx.params.parameters + const parameters = ctx.req + .param('parameters') ?.split('&') .map((parameter) => set(parameter)) .join(''); @@ -80,11 +118,11 @@ module.exports = async (ctx) => { } } - ctx.state.data = { + return { title: `MiniFlux | Subscription List`, link: instance, description: `A subscription tracking feed.`, item: subscription, allowEmpty: true, }; -}; +}