From 933558521062191e854c45a25bc3cbc11350fcc7 Mon Sep 17 00:00:00 2001 From: Lei Zhang Date: Tue, 29 Aug 2023 20:54:06 +0800 Subject: [PATCH] fix: V2EX Route Exclude Duplicate Posts (#13144) * update: V2EX Route Exclude Duplicate Posts * use ctx.query.limit * refactor: migrate to v2 --------- Co-authored-by: pull[bot] <39814207+pull[bot]@users.noreply.github.com> --- lib/router.js | 6 ++--- lib/routes/v2ex/post.js | 39 ------------------------------- lib/v2/v2ex/maintainer.js | 5 ++++ lib/v2/v2ex/post.js | 35 +++++++++++++++++++++++++++ lib/v2/v2ex/radar.js | 35 +++++++++++++++++++++++++++ lib/v2/v2ex/router.js | 5 ++++ lib/{routes => v2}/v2ex/tab.js | 38 ++++++++++++++---------------- lib/{routes => v2}/v2ex/topics.js | 2 +- 8 files changed, 101 insertions(+), 64 deletions(-) delete mode 100644 lib/routes/v2ex/post.js create mode 100644 lib/v2/v2ex/maintainer.js create mode 100644 lib/v2/v2ex/post.js create mode 100644 lib/v2/v2ex/radar.js create mode 100644 lib/v2/v2ex/router.js rename lib/{routes => v2}/v2ex/tab.js (62%) rename lib/{routes => v2}/v2ex/topics.js (96%) diff --git a/lib/router.js b/lib/router.js index 8f859a2b69d801..e61ec26abce1bc 100644 --- a/lib/router.js +++ b/lib/router.js @@ -77,9 +77,9 @@ router.get('/huya/live/:id', lazyloadRouteHandler('./routes/huya/live')); router.get('/showroom/room/:id', lazyloadRouteHandler('./routes/showroom/room')); // v2ex -router.get('/v2ex/topics/:type', lazyloadRouteHandler('./routes/v2ex/topics')); -router.get('/v2ex/post/:postid', lazyloadRouteHandler('./routes/v2ex/post')); -router.get('/v2ex/tab/:tabid', lazyloadRouteHandler('./routes/v2ex/tab')); +// router.get('/v2ex/topics/:type', lazyloadRouteHandler('./routes/v2ex/topics')); +// router.get('/v2ex/post/:postid', lazyloadRouteHandler('./routes/v2ex/post')); +// router.get('/v2ex/tab/:tabid', lazyloadRouteHandler('./routes/v2ex/tab')); // f-droid router.get('/fdroid/apprelease/:app', lazyloadRouteHandler('./routes/fdroid/apprelease')); diff --git a/lib/routes/v2ex/post.js b/lib/routes/v2ex/post.js deleted file mode 100644 index 5b4d26c4d723af..00000000000000 --- a/lib/routes/v2ex/post.js +++ /dev/null @@ -1,39 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const { parseDate } = require('@/utils/parse-date'); - -module.exports = async (ctx) => { - const postid = ctx.params.postid; - const pageUrl = `https://www.v2ex.com/t/${postid}`; - - const response = await got({ - method: 'get', - url: pageUrl, - }); - - const $ = cheerio.load(response.data); - const list = $('[id^="r_"]').get(); - - ctx.state.data = { - title: `V2EX-${$('.header h1').text()}`, - link: pageUrl, - description: $('.topic_content').text(), - item: list - .map((item) => { - const post = $(item); - const reply_content = post.find('.reply_content').first(); - const no = post.find('.no').first(); - - return { - title: `#${no.text()} ${reply_content.text()}`, - description: reply_content.html(), - guid: post.attr('id'), - link: `${pageUrl}#${post.attr('id')}`, - author: post.find('.dark').first().text(), - pubDate: parseDate(post.find('.ago').attr('title')), - }; - }) - .reverse(), - allowEmpty: true, - }; -}; diff --git a/lib/v2/v2ex/maintainer.js b/lib/v2/v2ex/maintainer.js new file mode 100644 index 00000000000000..01c685653ac57d --- /dev/null +++ b/lib/v2/v2ex/maintainer.js @@ -0,0 +1,5 @@ +module.exports = { + '/post/:postid': ['kt286'], + '/tab/:tabid': ['liyefox'], + '/topics/:type': ['WhiteWorld'], +}; diff --git a/lib/v2/v2ex/post.js b/lib/v2/v2ex/post.js new file mode 100644 index 00000000000000..b933692cfbf113 --- /dev/null +++ b/lib/v2/v2ex/post.js @@ -0,0 +1,35 @@ +const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); + +module.exports = async (ctx) => { + const { postid } = ctx.params; + const pageUrl = `https://www.v2ex.com/t/${postid}`; + + const { data: topicResponse } = await got('https://www.v2ex.com/api/topics/show.json', { + searchParams: { + id: postid, + }, + }); + + const { data: replies } = await got('https://www.v2ex.com/api/replies/show.json', { + searchParams: { + topic_id: postid, + }, + }); + + const topic = topicResponse[0]; + + ctx.state.data = { + title: `V2EX-${topic.title}`, + link: pageUrl, + description: topic.content, + item: replies.map((item, index) => ({ + title: `#${index + 1} ${item.content}`, + description: item.content_rendered, + link: `${pageUrl}#r_${item.id}`, + author: item.member.username, + pubDate: parseDate(item.created, 'X'), + })), + allowEmpty: true, + }; +}; diff --git a/lib/v2/v2ex/radar.js b/lib/v2/v2ex/radar.js new file mode 100644 index 00000000000000..f3a9d43bbfcdf6 --- /dev/null +++ b/lib/v2/v2ex/radar.js @@ -0,0 +1,35 @@ +module.exports = { + 'v2ex.com': { + _name: 'V2EX', + '.': [ + { + title: '最热 / 最新主题', + docs: 'https://docs.rsshub.app/routes/v2ex', + source: ['/'], + target: (_, url) => { + const { searchParams } = new URL(url); + if (searchParams.get('tab') === 'all' || searchParams.get('tab') === 'hot') { + return `/v2ex/topics/${searchParams.get('tab')?.replace('all', 'latest')}`; + } + }, + }, + { + title: '帖子', + docs: 'https://docs.rsshub.app/routes/v2ex', + source: ['/t/:postid'], + target: '/v2ex/post/:postid', + }, + { + title: '标签', + docs: 'https://docs.rsshub.app/routes/v2ex', + source: ['/'], + target: (_, url) => { + const { searchParams } = new URL(url); + if (searchParams.get('tab') && searchParams.get('tab') !== 'all' && searchParams.get('tab') !== 'hot') { + return `/v2ex/tab/${searchParams.get('tab')}`; + } + }, + }, + ], + }, +}; diff --git a/lib/v2/v2ex/router.js b/lib/v2/v2ex/router.js new file mode 100644 index 00000000000000..c17828c761aec2 --- /dev/null +++ b/lib/v2/v2ex/router.js @@ -0,0 +1,5 @@ +module.exports = (router) => { + router.get('/post/:postid', require('./post')); + router.get('/tab/:tabid', require('./tab')); + router.get('/topics/:type', require('./topics')); +}; diff --git a/lib/routes/v2ex/tab.js b/lib/v2/v2ex/tab.js similarity index 62% rename from lib/routes/v2ex/tab.js rename to lib/v2/v2ex/tab.js index 140eca922d4750..71e141dc32eabe 100644 --- a/lib/routes/v2ex/tab.js +++ b/lib/v2/v2ex/tab.js @@ -13,24 +13,21 @@ module.exports = async (ctx) => { const $ = cheerio.load(response.data); const links = $('span.item_title > a') - .map((i, link) => `${host}${$(link).attr('href')}`) - .slice(0, 10) - .get(); + .toArray() + .slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 10) + .map((link) => `${host}${$(link).attr('href').replace(/#.*$/, '')}`); + const items = await Promise.all( - links.map(async (pageUrl) => { - const cacheKey = `v2ex-${pageUrl}`; - const cacheValue = await ctx.cache.get(cacheKey); - let post = {}; - if (cacheValue) { - post = cacheValue; - } else { + links.map((link) => + ctx.cache.tryGet(`v2ex-${link}`, async () => { const response = await got({ method: 'get', - url: pageUrl, + url: link, }); + const $ = cheerio.load(response.data); - const list = $('[id^="r_"]').get(); - const reply_content = list + const list = $('[id^="r_"]').toArray(); + const replyContent = list .map((item) => { const post = $(item); const content = post.find('.reply_content').html(); @@ -39,18 +36,17 @@ module.exports = async (ctx) => { return `

#${no}: ${author}
${content}

`; }) .join(''); - post = { + + return { title: $('.header h1').text(), - link: pageUrl, - guid: pageUrl, - description: $('div.topic_content').html() + `
${reply_content}
`, + link, + description: `${$('div.topic_content').html()}
${replyContent}
`, author: $('div.header > small > a').text(), }; - ctx.cache.set(cacheKey, post); - } - return Promise.resolve(post); - }) + }) + ) ); + ctx.state.data = { title: `V2EX-${tabid}`, link: pageUrl, diff --git a/lib/routes/v2ex/topics.js b/lib/v2/v2ex/topics.js similarity index 96% rename from lib/routes/v2ex/topics.js rename to lib/v2/v2ex/topics.js index db3097d9c15531..28062030b8d85f 100644 --- a/lib/routes/v2ex/topics.js +++ b/lib/v2/v2ex/topics.js @@ -2,7 +2,7 @@ const got = require('@/utils/got'); const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { - const type = ctx.params.type; + const { type } = ctx.params; const { data } = await got(`https://www.v2ex.com/api/topics/${type}.json`);