From b1f206fcdffb86edf4597306c22fc6a99da9229f Mon Sep 17 00:00:00 2001 From: Ethan Shen <42264778+nczitzk@users.noreply.github.com> Date: Fri, 20 Oct 2023 04:51:34 +0800 Subject: [PATCH] fix(route): Readhub (#13567) * fix(route): Readhub * fix docs --- lib/v2/readhub/index.js | 181 ++++++++++++----------- lib/v2/readhub/maintainer.js | 2 +- lib/v2/readhub/radar.js | 8 +- lib/v2/readhub/router.js | 5 +- lib/v2/readhub/templates/description.art | 40 +++++ website/docs/routes/new-media.md | 8 +- 6 files changed, 147 insertions(+), 97 deletions(-) create mode 100644 lib/v2/readhub/templates/description.art diff --git a/lib/v2/readhub/index.js b/lib/v2/readhub/index.js index 20f5281fe6..2f79c9700f 100644 --- a/lib/v2/readhub/index.js +++ b/lib/v2/readhub/index.js @@ -1,106 +1,115 @@ const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const timezone = require('@/utils/timezone'); const { parseDate } = require('@/utils/parse-date'); - -const titles = { - topic: '热门话题', - news: '科技动态', - tech: '技术资讯', - technews: '技术资讯', - blockchain: '区块链快讯', - daily: '每日早报', -}; +const { art } = require('@/utils/render'); +const path = require('path'); +const dayjs = require('dayjs'); module.exports = async (ctx) => { - let category = 'topic'; - let overview = false; - if (titles[ctx.params.category]) { - category = ctx.params.category; - overview = !!ctx.params.overview; - category = category === 'tech' ? 'technews' : category; - } else if (ctx.params.category) { - overview = true; - } + const { category } = ctx.params; + const limit = ctx.query.limit ? parseInt(ctx.query.limit, 10) : 20; - const rootUrl = 'https://readhub.cn'; - const apiRootUrl = 'https://api.readhub.cn'; - const currentUrl = `${rootUrl}/topic/${category}`; - const apiUrl = `${apiRootUrl}/${category === 'daily' ? 'topic/daily' : category}`; + const domain = 'readhub.cn'; + const rootUrl = `https://${domain}`; + const apiRootUrl = `https://api.${domain}`; + const currentUrl = new URL(category ?? '', rootUrl).href; - const response = await got({ - method: 'get', - url: apiUrl, + const isCategory = !category || category === 'daily'; + + const formatDate = (date, format) => dayjs(date).format(format); + const toTopicUrl = (id) => new URL(`topic/${id}`, rootUrl).href; + + art.defaults.imports = { + ...art.defaults.imports, + ...{ + formatDate, + toTopicUrl, + }, + }; + + const { data: currentResponse } = await got(currentUrl); + + const buildId = currentResponse.match(/"buildId":"(\w+)"/)[1]; + + const apiUrl = new URL(category ? (category === 'daily' ? `_next/data/${buildId}/daily.json` : 'news/list') : 'topic/list', category === 'daily' ? rootUrl : apiRootUrl).href; + + const { data: response } = await got(apiUrl, { + searchParams: { + ...(isCategory + ? {} + : { + type: currentResponse.match(/"query":\{"type":"(\d+)"\}/)[1], + }), + ...{ + page: 1, + size: limit, + }, + }, }); - const list = response.data.data.map((item) => ({ - id: item.id, + let items = (response.data?.items ?? response.pageProps.daily).slice(0, limit).map((item) => ({ title: item.title, - pubDate: parseDate(item.publishDate), - description: item.summaryAuto || item.summary || '', - link: item.url || item.mobileUrl || `${rootUrl}/topic/${item.id}`, - author: item.authorName || item.siteName || '', - hasInstantView: item.hasInstantView || false, + link: item.url ?? new URL(`topic/${item.uid}`, rootUrl).href, + description: art(path.join(__dirname, 'templates/description.art'), { + description: item.summary, + news: item.newsAggList, + timeline: item.timeline, + }), + author: item.siteNameDisplay, + category: item.tagList?.map((c) => c.name) ?? [], + guid: isCategory ? item.uid : `readhub-${item.guid}`, + pubDate: timezone(parseDate(item.publishDate), +8), })); - const items = await Promise.all( - list.map((item) => - ctx.cache.tryGet(item.id + overview, async () => { - if (item.hasInstantView || category === 'daily') { - const { data } = await got({ - method: 'get', - url: `${apiRootUrl}/topic/instantview?topicId=${item.id}`, + if (isCategory) { + items = await Promise.all( + items.map((item) => + ctx.cache.tryGet(`readhub-${item.guid}`, async () => { + const { data: detailResponse } = await got(new URL(`_next/data/${buildId}/topic/${item.guid}.json`, rootUrl).href); + + const data = detailResponse.pageProps.topic; + + item.title = data.title; + item.link = data.url ?? new URL(`topic/${data.uid}`, rootUrl).href; + item.description = art(path.join(__dirname, 'templates/description.art'), { + description: data.summary, + news: data.newsAggList, + timeline: data.timeline, }); + item.author = data.entityList.map((a) => a.name).join('/'); + item.category = data.tagList.map((c) => c.name); + item.guid = `readhub-${data.uid}`; + item.pubDate = timezone(parseDate(data.publishDate), +8); - item.description = `访问原网址
${!overview ? data.content : ''}`; - } + return item; + }) + ) + ); + } - if (isNaN(item.id)) { - const { data } = await got({ - method: 'get', - url: `${apiRootUrl}/topic/${item.id}`, - }); + const $ = cheerio.load(currentResponse); - if (data.summary && overview) { - item.description += `${data.summary}
`; - } - - if (data.newsArray) { - item.description += '
媒体报道'; - } - - if (data.timeline && data.timeline.topics) { - const hasTimeline = data.timeline.commonEntities && data.timeline.commonEntities.length > 0; - - item.description += `
${hasTimeline ? '事件追踪' : '相关事件'}'; - } - } - delete item.id; - delete item.hasInstantView; - - return item; - }) - ) - ); + const author = $('meta[property="og:site_name"]').prop('content'); + const subtitle = $( + $('nav div a') + .toArray() + .filter((a) => /style_active.*/.test($(a).prop('class'))) + .pop() + ).text(); + const icon = new URL($('link[rel="apple-touch-icon"]').prop('href'), rootUrl).href; ctx.state.data = { - title: `Readhub - ${titles[category]}`, - link: currentUrl, item: items, + title: `${author} - ${subtitle}`, + link: currentUrl, + description: $('meta[property="og:description"]').prop('content'), + language: $('html').prop('lang'), + image: $('meta[property="og:image"]').prop('content'), + icon, + logo: icon, + subtitle, + author, + allowEmpty: true, }; }; diff --git a/lib/v2/readhub/maintainer.js b/lib/v2/readhub/maintainer.js index 4c09355e31..2f5f4854c3 100644 --- a/lib/v2/readhub/maintainer.js +++ b/lib/v2/readhub/maintainer.js @@ -1,3 +1,3 @@ module.exports = { - '/:category?/:overview?': ['WhiteWorld', 'nczitzk', 'Fatpandac'], + '/:category?': ['WhiteWorld', 'nczitzk', 'Fatpandac'], }; diff --git a/lib/v2/readhub/radar.js b/lib/v2/readhub/radar.js index 4df725e962..6b3e480b7d 100644 --- a/lib/v2/readhub/radar.js +++ b/lib/v2/readhub/radar.js @@ -4,9 +4,13 @@ module.exports = { '.': [ { title: '分类', - docs: 'https://docs.rsshub.app/routes/new-media#readhub', + docs: 'https://docs.rsshub.app/routes/new-media#readhub-fen-lei', source: ['/', '/:category'], - target: (params) => `/readhub/${params.category ? params.category : ''}`, + target: (params) => { + const category = params.category; + + return `/readhub${category ? `/${category}` : ''}`; + }, }, ], }, diff --git a/lib/v2/readhub/router.js b/lib/v2/readhub/router.js index da527b1da3..19b84c05d3 100644 --- a/lib/v2/readhub/router.js +++ b/lib/v2/readhub/router.js @@ -1,6 +1,3 @@ module.exports = (router) => { - // deprecated - router.get('/category/:category?/:overview?', require('./index')); - - router.get('/:category?/:overview?', require('./index')); + router.get('/:category?', require('./')); }; diff --git a/lib/v2/readhub/templates/description.art b/lib/v2/readhub/templates/description.art new file mode 100644 index 0000000000..a7570ea87c --- /dev/null +++ b/lib/v2/readhub/templates/description.art @@ -0,0 +1,40 @@ +{{ if description }} +

{{ description }}

+{{ /if }} + +{{ if news }} +

媒体报道

+ + + {{ each news n }} + + + + + {{ /each }} + +
+ {{ n.title }} + + {{ n.siteNameDisplay }} +
+{{ /if }} + +{{ if timeline }} +

事件追踪

+ + + {{ set topics = timeline.topics }} + {{ each topics t }} + + + + + {{ /each }} + +
+ {{ t.publishDate | formatDate 'YYYY-MM-DD HH:mm:ss' }} + + {{ t.title }} +
+{{ /if }} \ No newline at end of file diff --git a/website/docs/routes/new-media.md b/website/docs/routes/new-media.md index 2382f2cdf1..96e00354ab 100644 --- a/website/docs/routes/new-media.md +++ b/website/docs/routes/new-media.md @@ -1708,11 +1708,11 @@ Compared to the official one, this feed: ### 分类 {#readhub-fen-lei} - + -| 热门话题 | 科技动态 | 技术资讯 | 区块链快讯 | 每日早报 | -| -------- | -------- | -------- | ---------- | -------- | -| topic | news | tech | blockchain | daily | +| 热门话题 | 每日早报 | 科技动态 | 医疗产业 | +| -------- | -------- | -------- | -------- | +| | daily | news | medical |