UNPKG

rsshub

Version:
148 lines (131 loc) 4.08 kB
import { Context } from 'hono'; import { load } from 'cheerio'; import { Data, Route, DataItem } from '@/types'; import { parseDate } from '@/utils/parse-date'; import cache from '@/utils/cache'; import ofetch from '@/utils/ofetch'; export const route: Route = { path: '/:category?', categories: ['game'], example: '/chuapp/daily', parameters: { category: '栏目分类,见下表', }, description: ` | \`category\` | 栏目分类 | | ------------ | ------- | | \`daily\` | 每日聚焦 | | \`pcz\` | 最好玩 | | \`night\` | 触乐夜话 | | \`news\` | 动态资讯 | `, features: { requireConfig: false, requirePuppeteer: false, antiCrawler: false, supportBT: false, supportPodcast: false, supportScihub: false, }, name: '分类', maintainers: ['dousha'], radar: [ { source: ['chuapp.com/category/:category'], target: '/:category', }, { source: ['chuapp.com/tag/index/id/20369.html'], target: '/night', }, ], handler, }; const baseUrl = 'https://www.chuapp.com'; const pathLut: Record<string, { title: string; suffix: string }> = { daily: { title: '每日聚焦', suffix: '/category/daily', }, pcz: { title: '最好玩', suffix: '/category/pcz', }, night: { title: '触乐夜话', suffix: '/tag/index/id/20369.html', }, news: { // route from the old implementation title: '动态资讯', suffix: '/category/zsyx', }, zsyx: { // route for radar title: '动态资讯', suffix: '/category/zsyx', }, }; type InvalidArticle = { title?: string; link?: string; }; type ValidArticle = { title: string; link: string; }; type RawArticle = InvalidArticle | ValidArticle; function isValidArticle(article: RawArticle): article is ValidArticle { return 'title' in article && 'link' in article && article.title !== null && article.link !== null; } function toJavaScriptTimestamp(x: string | number | null | undefined): number { return x ? Number(x) * 1000 : 0; } async function handler(ctx: Context): Promise<Data | null> { const { category = 'night' } = ctx.req.param(); const subpath = pathLut[category]; if (!subpath) { return null; } const targetUrl = `${baseUrl}${subpath.suffix}`; const response = await ofetch(targetUrl); const $ = load(response); const articles: RawArticle[] = $('a.fn-clear') .toArray() .map((element) => ({ title: $(element).attr('title'), link: $(element).attr('href'), })); const processedItems: Promise<DataItem>[] = articles .filter((article: RawArticle): article is ValidArticle => isValidArticle(article)) .map((article: ValidArticle) => { if (article.link.startsWith('/')) { return article; } return { title: article.title, link: `/${article.link}`, }; }) .map((article: ValidArticle) => { const fullArticleUrl = `${baseUrl}${article.link}`; return cache.tryGet(fullArticleUrl, async () => { const res = await ofetch(fullArticleUrl); const s = load(res); const item: DataItem = { title: article.title, link: article.link, description: s('.content .the-content').html() || '', pubDate: parseDate(toJavaScriptTimestamp(s('.friendly_time').attr('data-time'))), author: s('.author-time .fn-left').text() || '', }; return item; }) as Promise<DataItem>; }); const items = await Promise.all(processedItems); return { title: `触乐 - ${subpath.title}`, link: targetUrl, item: items, }; }