diff --git a/lib/v2/rsshub/maintainer.js b/lib/v2/rsshub/maintainer.js index b0ffddb838..5ab179176c 100644 --- a/lib/v2/rsshub/maintainer.js +++ b/lib/v2/rsshub/maintainer.js @@ -3,4 +3,5 @@ module.exports = { '/rsshub/sponsors': ['DIYgod'], '/transform/html/:url/:routeParams': ['ttttmr'], '/transform/json/:url/:routeParams': ['ttttmr'], + '/transform/sitemap/:url/:routeParams?': ['flrngel'], }; diff --git a/lib/v2/rsshub/router.js b/lib/v2/rsshub/router.js index 960796dbf4..2f90c082f8 100644 --- a/lib/v2/rsshub/router.js +++ b/lib/v2/rsshub/router.js @@ -3,4 +3,5 @@ module.exports = (router) => { router.get('/sponsors', require('./sponsors')); router.get('/transform/html/:url/:routeParams', require('./transform/html')); router.get('/transform/json/:url/:routeParams', require('./transform/json')); + router.get('/transform/sitemap/:url/:routeParams?', require('./transform/sitemap')); }; diff --git a/lib/v2/rsshub/transform/sitemap.js b/lib/v2/rsshub/transform/sitemap.js new file mode 100644 index 0000000000..d4f233e84c --- /dev/null +++ b/lib/v2/rsshub/transform/sitemap.js @@ -0,0 +1,52 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const config = require('@/config').value; + +module.exports = async (ctx) => { + if (!config.feature.allow_user_supply_unsafe_domain) { + ctx.throw(403, `This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`); + } + const { url } = ctx.params; + const response = await got({ + method: 'get', + url, + }); + + const routeParams = new URLSearchParams(ctx.params.routeParams); + const $ = cheerio.load(response.data, { xmlMode: true }); + + const rssTitle = routeParams.get('title') ? routeParams.get('title') : ($('urlset url').length && $('urlset url').first().find('loc').text() ? $('urlset url').first().find('loc').text() : 'Sitemap'); + + let items; + const urls = $('urlset url').toArray(); + if (urls && urls.length) { + items = urls.map((item) => { + try { + const title = $(item).find('loc').text() || ''; + const link = $(item).find('loc').text() || ''; + const description = $(item).find('loc').text() || ''; + const pubDate = $(item).find('lastmod').text() || undefined; + + return { + title, + link, + description, + pubDate, + }; + } catch (e) { + return null; + } + }) + .filter(Boolean); + } + else { + items = []; + } + + ctx.state.data = { + title: rssTitle, + link: url, + description: `Proxy ${url}`, + item: items, + }; +}; diff --git a/website/docs/routes/other.md b/website/docs/routes/other.md index 44af8528f0..7dca5e3d33 100644 --- a/website/docs/routes/other.md +++ b/website/docs/routes/other.md @@ -646,6 +646,25 @@ Parsing of `routeParams` parameter: +### Sitemap {#transformation-sitemap} + +Specify options (in the format of query string) in parameter `routeParams` parameter to extract data from Sitemap. (Follows Sitemap Protocol 0.9) + +| Key | Meaning | Accepted Values | Default | +|-----------------|----------------------------------------------------------------|-----------------|------------------------| +| `title` | The title of the RSS | `string` | Extract from `` | + +<Route author="flrngel" example="/rsshub/transform/xml/https%3A%2F%2Fwww.sitemaps.org%2Fsitemap.xml/" path="/rsshub/transform/html/:url/:routeParams?" paramsDesc={['`encodeURIComponent`ed URL address', 'Transformation rules, requires URL encode']} selfhost="1"> + +Parameters parsing in the above example: + +| Parameter | Value | +|---------------|-------------------------------------------| +| `url` | `https://www.sitemaps.org/sitemap.xml` | +| `routeParams` | `title=Example` | + +</Route> + ## TSSstatus (iOS downgrade channel) {#tssstatus-ios-downgrade-channel} ### Status {#tssstatus-ios-downgrade-channel-status}