Files
RSSHub/lib/routes/rsshub/transform/json.ts
2024-03-12 00:29:52 +08:00

108 lines
4.4 KiB
TypeScript

import { Route } from '@/types';
import got from '@/utils/got';
import { load } from 'cheerio';
import { config } from '@/config';
function jsonGet(obj, attr) {
if (typeof attr !== 'string') {
return obj;
}
// a.b.c
// a.b[0].c => a.b.0.c
for (const key of attr.split('.')) {
obj = obj[key];
}
return obj;
}
export const route: Route = {
path: '/transform/json/:url/:routeParams',
categories: ['other'],
example: '/rsshub/transform/json/https%3A%2F%2Fapi.github.com%2Frepos%2Fginuerzh%2Fgost%2Freleases/title=Gost%20releases&itemTitle=tag_name&itemLink=html_url&itemDesc=body',
parameters: { url: '`encodeURIComponent`ed URL address', routeParams: 'Transformation rules, requires URL encode' },
features: {
requireConfig: ['ALLOW_USER_SUPPLY_UNSAFE_DOMAIN'],
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: 'Transformation - JSON',
maintainers: ['ttttmr'],
handler,
description: `Specify options (in the format of query string) in parameter \`routeParams\` parameter to extract data from JSON.
| Key | Meaning | Accepted Values | Default |
| ------------- | ---------------------------------------- | --------------- | ------------------------------------------ |
| \`title\` | The title of the RSS | \`string\` | Extracted from home page of current domain |
| \`item\` | The JSON Path as \`item\` element | \`string\` | Entire JSON response |
| \`itemTitle\` | The JSON Path as \`title\` in \`item\` | \`string\` | None |
| \`itemLink\` | The JSON Path as \`link\` in \`item\` | \`string\` | None |
| \`itemDesc\` | The JSON Path as \`description\` in \`item\` | \`string\` | None |
| \`itemPubDate\` | The JSON Path as \`pubDate\` in \`item\` | \`string\` | None |
:::tip
JSON Path only supports format like \`a.b.c\`. if you need to access arrays, like \`a[0].b\`, you can write it as \`a.0.b\`.
:::
Parameters parsing in the above example:
| Parameter | Value |
| ------------- | ------------------------------------------------------------------------ |
| \`url\` | \`https://api.github.com/repos/ginuerzh/gost/releases\` |
| \`routeParams\` | \`title=Gost releases&itemTitle=tag_name&itemLink=html_url&itemDesc=body\` |
Parsing of \`routeParams\` parameter:
| Parameter | Value |
| ----------- | --------------- |
| \`title\` | \`Gost releases\` |
| \`itemTitle\` | \`tag_name\` |
| \`itemLink\` | \`html_url\` |
| \`itemDesc\` | \`body\` |`,
};
async function handler(ctx) {
if (!config.feature.allow_user_supply_unsafe_domain) {
throw new Error(`This RSS is disabled unless 'ALLOW_USER_SUPPLY_UNSAFE_DOMAIN' is set to 'true'.`);
}
const url = ctx.req.param('url');
const response = await got({
method: 'get',
url,
});
const routeParams = new URLSearchParams(ctx.req.param('routeParams'));
let rssTitle = routeParams.get('title');
if (!rssTitle) {
const resp = await got({
method: 'get',
url: new URL(url).origin,
});
const $ = load(resp.data);
rssTitle = $('title').text();
}
const items = jsonGet(response.data, routeParams.get('item')).map((item) => {
let link = jsonGet(item, routeParams.get('itemLink')).trim();
// 补全绝对链接
if (link && !link.startsWith('http')) {
link = `${new URL(url).origin}${link}`;
}
return {
title: jsonGet(item, routeParams.get('itemTitle')),
link,
description: routeParams.get('itemDesc') ? jsonGet(item, routeParams.get('itemDesc')) : '',
pubDate: routeParams.get('itemPubDate') ? jsonGet(item, routeParams.get('itemPubDate')) : '',
};
});
return {
title: rssTitle,
link: url,
description: `Proxy ${url}`,
item: items,
};
}