From 950bfa61ed00b885271df30bef4eec96f8d31f43 Mon Sep 17 00:00:00 2001 From: CancerGary <12206312+CancerGary@users.noreply.github.com> Date: Fri, 20 May 2022 01:55:18 +0800 Subject: [PATCH] feat(route): add juejin news (#7969) * feat(route): add juejin news * feat(route): add juejin news * fix(route): juejin news pubDate * fix: fix utility * refactor: migrate to v2 * fix: typo Co-authored-by: TonyRL --- assets/radar-rules.js | 16 ------- docs/programming.md | 28 ++++++++---- lib/radar-rules.js | 41 ----------------- lib/router.js | 23 +++++----- lib/{routes => v2}/juejin/books.js | 3 +- lib/{routes => v2}/juejin/category.js | 2 +- lib/{routes => v2}/juejin/collection.js | 0 lib/{routes => v2}/juejin/column.js | 0 lib/{routes => v2}/juejin/favorites.js | 0 lib/v2/juejin/maintainer.js | 13 ++++++ lib/v2/juejin/news.js | 25 ++++++++++ lib/{routes => v2}/juejin/pins.js | 5 +- lib/{routes => v2}/juejin/posts.js | 0 lib/v2/juejin/radar.js | 61 +++++++++++++++++++++++++ lib/v2/juejin/router.js | 13 ++++++ lib/{routes => v2}/juejin/shares.js | 0 lib/{routes => v2}/juejin/tag.js | 0 lib/{routes => v2}/juejin/trending.js | 0 lib/{routes => v2}/juejin/utils.js | 22 ++++++--- 19 files changed, 163 insertions(+), 89 deletions(-) rename lib/{routes => v2}/juejin/books.js (89%) rename lib/{routes => v2}/juejin/category.js (95%) rename lib/{routes => v2}/juejin/collection.js (100%) rename lib/{routes => v2}/juejin/column.js (100%) rename lib/{routes => v2}/juejin/favorites.js (100%) create mode 100644 lib/v2/juejin/maintainer.js create mode 100644 lib/v2/juejin/news.js rename lib/{routes => v2}/juejin/pins.js (91%) rename lib/{routes => v2}/juejin/posts.js (100%) create mode 100644 lib/v2/juejin/radar.js create mode 100644 lib/v2/juejin/router.js rename lib/{routes => v2}/juejin/shares.js (100%) rename lib/{routes => v2}/juejin/tag.js (100%) rename lib/{routes => v2}/juejin/trending.js (100%) rename lib/{routes => v2}/juejin/utils.js (54%) diff --git a/assets/radar-rules.js b/assets/radar-rules.js index 5228681a2..cb6e43829 100644 --- a/assets/radar-rules.js +++ b/assets/radar-rules.js @@ -151,22 +151,6 @@ }, 'algocasts.io': { _name: 'AlgoCasts', '.': [{ title: '视频更新', docs: 'https://docs.rsshub.app/programming.html#algocasts', source: '/episodes', target: '/algocasts' }] }, 'soulapp.cn': { _name: 'Soul', '.': [{ title: '瞬间更新', docs: 'https://docs.rsshub.app/social-media.html#soul' }] }, - 'juejin.cn': { - _name: '掘金', - '.': [ - { title: '标签', docs: 'https://docs.rsshub.app/programming.html#jue-jin-biao-qian', source: '/tag/:tag', target: '/juejin/tag/:tag' }, - { title: '小册', docs: 'https://docs.rsshub.app/programming.html#jue-jin-xiao-ce', source: '/books', target: '/juejin/books' }, - { - title: '沸点', - docs: 'https://docs.rsshub.app/programming.html#jue-jin-fei-dian', - source: ['/pins/:type', '/pins/topic/:type'], - target: (params) => (params.type !== 'recommended' ? '/juejin/pins/:type' : '/juejin/pins'), - }, - { title: '专栏', docs: 'https://docs.rsshub.app/programming.html#jue-jin-zhuan-lan', source: ['/user/:id', '/user/:id/posts'], target: '/juejin/posts/:id' }, - { title: '收藏集', docs: 'https://docs.rsshub.app/programming.html#jue-jin-shou-cang-ji', source: ['/user/:id', '/user/:id/collections'], target: '/juejin/collections/:id' }, - { title: '单个收藏夹', docs: 'https://docs.rsshub.app/programming.html#jue-jin-dan-ge-shou-cang-jia', source: '/collection/:collectionId', target: '/juejin/collection/:collectionId' }, - ], - }, 'anime1.me': { _name: 'Anime1', '.': [ diff --git a/docs/programming.md b/docs/programming.md index 1e88e5e12..57c544708 100644 --- a/docs/programming.md +++ b/docs/programming.md @@ -701,7 +701,7 @@ GitHub 官方也提供了一些 RSS: ### 分类 - + | 后端 | 前端 | Android | iOS | 人工智能 | 开发工具 | 代码人生 | 阅读 | | ------- | -------- | ------- | --- | ---- | ------- | ------ | ------- | @@ -711,11 +711,11 @@ GitHub 官方也提供了一些 RSS: ### 标签 - + ### 热门 - + | category | 标签 | | -------- | ------- | @@ -741,13 +741,13 @@ GitHub 官方也提供了一些 RSS: ### 小册 - + > 掘金小册需要付费订阅,RSS 仅做更新提醒,不含付费内容. ### 沸点 - + | 推荐 | 热门 | 上班摸鱼 | 内推招聘 | 一图胜千言 | 今天学到了 | 每天一道算法题 | 开发工具推荐 | 树洞一下 | | --------- | --- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | ------------------- | @@ -755,21 +755,29 @@ GitHub 官方也提供了一些 RSS: -### 专栏 +### 用户专栏 - + ### 收藏集 - + ### 单个收藏夹 - + ### 分享 - + + +### 专栏 + + + +### 资讯 + + ## 开源中国 diff --git a/lib/radar-rules.js b/lib/radar-rules.js index a19259b15..08c3f1017 100644 --- a/lib/radar-rules.js +++ b/lib/radar-rules.js @@ -207,47 +207,6 @@ module.exports = { }, ], }, - 'juejin.cn': { - _name: '掘金', - '.': [ - { - title: '标签', - docs: 'https://docs.rsshub.app/programming.html#jue-jin-biao-qian', - source: '/tag/:tag', - target: '/juejin/tag/:tag', - }, - { - title: '小册', - docs: 'https://docs.rsshub.app/programming.html#jue-jin-xiao-ce', - source: '/books', - target: '/juejin/books', - }, - { - title: '沸点', - docs: 'https://docs.rsshub.app/programming.html#jue-jin-fei-dian', - source: ['/pins/:type', '/pins/topic/:type'], - target: (params) => (params.type !== 'recommended' ? '/juejin/pins/:type' : '/juejin/pins'), - }, - { - title: '专栏', - docs: 'https://docs.rsshub.app/programming.html#jue-jin-zhuan-lan', - source: ['/user/:id', '/user/:id/posts'], - target: '/juejin/posts/:id', - }, - { - title: '收藏集', - docs: 'https://docs.rsshub.app/programming.html#jue-jin-shou-cang-ji', - source: ['/user/:id', '/user/:id/collections'], - target: '/juejin/collections/:id', - }, - { - title: '单个收藏夹', - docs: 'https://docs.rsshub.app/programming.html#jue-jin-dan-ge-shou-cang-jia', - source: '/collection/:collectionId', - target: '/juejin/collection/:collectionId', - }, - ], - }, 'anime1.me': { _name: 'Anime1', '.': [ diff --git a/lib/router.js b/lib/router.js index 3b3703c2e..f31b1fcfc 100644 --- a/lib/router.js +++ b/lib/router.js @@ -68,17 +68,18 @@ router.get('/ncm/artist/:id', lazyloadRouteHandler('./routes/ncm/artist')); router.get('/ncm/djradio/:id', lazyloadRouteHandler('./routes/ncm/djradio')); router.get('/ncm/user/playrecords/:uid/:type?', lazyloadRouteHandler('./routes/ncm/userplayrecords')); -// 掘金 -router.get('/juejin/category/:category', lazyloadRouteHandler('./routes/juejin/category')); -router.get('/juejin/tag/:tag', lazyloadRouteHandler('./routes/juejin/tag')); -router.get('/juejin/trending/:category/:type', lazyloadRouteHandler('./routes/juejin/trending')); -router.get('/juejin/books', lazyloadRouteHandler('./routes/juejin/books')); -router.get('/juejin/pins/:type?', lazyloadRouteHandler('./routes/juejin/pins')); -router.get('/juejin/posts/:id', lazyloadRouteHandler('./routes/juejin/posts')); -router.get('/juejin/collections/:userId', lazyloadRouteHandler('./routes/juejin/favorites')); -router.get('/juejin/collection/:collectionId', lazyloadRouteHandler('./routes/juejin/collection')); -router.get('/juejin/shares/:userId', lazyloadRouteHandler('./routes/juejin/shares')); -router.get('/juejin/column/:id', lazyloadRouteHandler('./routes/juejin/column')); +// 掘金 migrated to v2 +// router.get('/juejin/category/:category', lazyloadRouteHandler('./routes/juejin/category')); +// router.get('/juejin/tag/:tag', lazyloadRouteHandler('./routes/juejin/tag')); +// router.get('/juejin/trending/:category/:type', lazyloadRouteHandler('./routes/juejin/trending')); +// router.get('/juejin/books', lazyloadRouteHandler('./routes/juejin/books')); +// router.get('/juejin/pins/:type?', lazyloadRouteHandler('./routes/juejin/pins')); +// router.get('/juejin/posts/:id', lazyloadRouteHandler('./routes/juejin/posts')); +// router.get('/juejin/news/:id', lazyloadRouteHandler('./routes/juejin/news')); +// router.get('/juejin/collections/:userId', lazyloadRouteHandler('./routes/juejin/favorites')); +// router.get('/juejin/collection/:collectionId', lazyloadRouteHandler('./routes/juejin/collection')); +// router.get('/juejin/shares/:userId', lazyloadRouteHandler('./routes/juejin/shares')); +// router.get('/juejin/column/:id', lazyloadRouteHandler('./routes/juejin/column')); // 自如 router.get('/ziroom/room/:city/:iswhole/:room/:keyword', lazyloadRouteHandler('./routes/ziroom/room')); diff --git a/lib/routes/juejin/books.js b/lib/v2/juejin/books.js similarity index 89% rename from lib/routes/juejin/books.js rename to lib/v2/juejin/books.js index a414643d7..29120e0eb 100644 --- a/lib/routes/juejin/books.js +++ b/lib/v2/juejin/books.js @@ -1,4 +1,5 @@ const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { const response = await got({ @@ -17,7 +18,7 @@ module.exports = async (ctx) => { ${base_info.summary}
价格: ${base_info.price / 100}元 `, - pubDate: new Date(base_info.ctime * 1000).toUTCString(), + pubDate: parseDate(base_info.ctime * 1000), guid: base_info.booklet_id, })); diff --git a/lib/routes/juejin/category.js b/lib/v2/juejin/category.js similarity index 95% rename from lib/routes/juejin/category.js rename to lib/v2/juejin/category.js index 3a5e46d69..f3d3b6be3 100644 --- a/lib/routes/juejin/category.js +++ b/lib/v2/juejin/category.js @@ -26,7 +26,7 @@ module.exports = async (ctx) => { let originalData = []; if (response.data.data) { - originalData = response.data.data.slice(0, 5); + originalData = response.data.data; } const resultItems = await util.ProcessFeed(originalData, ctx.cache); diff --git a/lib/routes/juejin/collection.js b/lib/v2/juejin/collection.js similarity index 100% rename from lib/routes/juejin/collection.js rename to lib/v2/juejin/collection.js diff --git a/lib/routes/juejin/column.js b/lib/v2/juejin/column.js similarity index 100% rename from lib/routes/juejin/column.js rename to lib/v2/juejin/column.js diff --git a/lib/routes/juejin/favorites.js b/lib/v2/juejin/favorites.js similarity index 100% rename from lib/routes/juejin/favorites.js rename to lib/v2/juejin/favorites.js diff --git a/lib/v2/juejin/maintainer.js b/lib/v2/juejin/maintainer.js new file mode 100644 index 000000000..8121cf2f1 --- /dev/null +++ b/lib/v2/juejin/maintainer.js @@ -0,0 +1,13 @@ +module.exports = { + '/books': ['xyqfer'], + '/category/:category': ['DIYgod'], + '/collection/:collectionId': ['isQ'], + '/collections/:userId': ['isQ'], + '/column/:id': ['xiangzy1'], + '/news/:id': ['CancerGary'], + '/pins/:type?': ['xyqfer', 'laampui'], + '/posts/:id': ['Maecenas'], + '/shares/:userId': ['qiwihui'], + '/tag/:tag': ['isheng5'], + '/trending/:category/:type': ['moaix'], +}; diff --git a/lib/v2/juejin/news.js b/lib/v2/juejin/news.js new file mode 100644 index 000000000..494660f53 --- /dev/null +++ b/lib/v2/juejin/news.js @@ -0,0 +1,25 @@ +const got = require('@/utils/got'); +const util = require('./utils'); + +module.exports = async (ctx) => { + const { id } = ctx.params; + + const response = await got({ + method: 'post', + url: 'https://api.juejin.cn/content_api/v1/news/list_user', + json: { + user_id: id, + sort_type: 2, + }, + }); + const { data } = response.data; + const username = data[0] && data[0].author_user_info && data[0].author_user_info.user_name; + const resultItems = await util.ProcessFeed(data, ctx.cache); + + ctx.state.data = { + title: `掘金资讯-${username}`, + link: `https://juejin.cn/user/${id}/news`, + description: `掘金资讯-${username}`, + item: resultItems, + }; +}; diff --git a/lib/routes/juejin/pins.js b/lib/v2/juejin/pins.js similarity index 91% rename from lib/routes/juejin/pins.js rename to lib/v2/juejin/pins.js index 06cf39117..7c149dd1b 100644 --- a/lib/routes/juejin/pins.js +++ b/lib/v2/juejin/pins.js @@ -1,7 +1,8 @@ const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { - const type = ctx.params.type || 'recommend'; + const type = ctx.params.type ?? 'recommend'; const title = { recommend: '推荐', hot: '热门', @@ -35,7 +36,7 @@ module.exports = async (ctx) => { const title = content; const guid = item.msg_id; const link = `https://juejin.cn/pin/${guid}`; - const pubDate = new Date(parseInt(item.msg_Info.ctime) * 1000).toUTCString(); + const pubDate = parseDate(item.msg_Info.ctime * 1000); const author = item.author_user_info.user_name; const imgs = item.msg_Info.pic_list.reduce((imgs, item) => { imgs += ` diff --git a/lib/routes/juejin/posts.js b/lib/v2/juejin/posts.js similarity index 100% rename from lib/routes/juejin/posts.js rename to lib/v2/juejin/posts.js diff --git a/lib/v2/juejin/radar.js b/lib/v2/juejin/radar.js new file mode 100644 index 000000000..c86595dc6 --- /dev/null +++ b/lib/v2/juejin/radar.js @@ -0,0 +1,61 @@ +module.exports = { + 'juejin.cn': { + _name: '掘金', + '.': [ + { + title: '标签', + docs: 'https://docs.rsshub.app/programming.html#jue-jin-biao-qian', + source: '/tag/:tag', + target: '/juejin/tag/:tag', + }, + { + title: '小册', + docs: 'https://docs.rsshub.app/programming.html#jue-jin-xiao-ce', + source: '/books', + target: '/juejin/books', + }, + { + title: '沸点', + docs: 'https://docs.rsshub.app/programming.html#jue-jin-fei-dian', + source: ['/pins/:type', '/pins/topic/:type'], + target: (params) => (params.type !== 'recommended' ? '/juejin/pins/:type' : '/juejin/pins'), + }, + { + title: '用户专栏', + docs: 'https://docs.rsshub.app/programming.html#jue-jin-zhuan-lan', + source: ['/user/:id', '/user/:id/posts'], + target: '/juejin/posts/:id', + }, + { + title: '收藏集', + docs: 'https://docs.rsshub.app/programming.html#jue-jin-shou-cang-ji', + source: ['/user/:id', '/user/:id/collections'], + target: '/juejin/collections/:id', + }, + { + title: '单个收藏夹', + docs: 'https://docs.rsshub.app/programming.html#jue-jin-dan-ge-shou-cang-jia', + source: '/collection/:collectionId', + target: '/juejin/collection/:collectionId', + }, + { + title: '分享', + docs: 'https://docs.rsshub.app/programming.html#jue-jin', + source: ['/user/:userId', '/user/:userId/shares'], + target: '/juejin/shares/:userId', + }, + { + title: '专栏', + docs: 'https://docs.rsshub.app/programming.html#jue-jin', + source: '/column/:id', + target: '/juejin/column/:id', + }, + { + title: '资讯', + docs: 'https://docs.rsshub.app/programming.html#jue-jin', + source: ['/user/:id', '/user/:id/news'], + target: '/juejin/news/:userId', + }, + ], + }, +}; diff --git a/lib/v2/juejin/router.js b/lib/v2/juejin/router.js new file mode 100644 index 000000000..a3f4a2ea1 --- /dev/null +++ b/lib/v2/juejin/router.js @@ -0,0 +1,13 @@ +module.exports = (router) => { + router.get('/books', require('./books')); + router.get('/category/:category', require('./category')); + router.get('/collection/:collectionId', require('./collection')); + router.get('/collections/:userId', require('./favorites')); + router.get('/column/:id', require('./column')); + router.get('/news/:id', require('./news')); + router.get('/pins/:type?', require('./pins')); + router.get('/posts/:id', require('./posts')); + router.get('/shares/:userId', require('./shares')); + router.get('/tag/:tag', require('./tag')); + router.get('/trending/:category/:type', require('./trending')); +}; diff --git a/lib/routes/juejin/shares.js b/lib/v2/juejin/shares.js similarity index 100% rename from lib/routes/juejin/shares.js rename to lib/v2/juejin/shares.js diff --git a/lib/routes/juejin/tag.js b/lib/v2/juejin/tag.js similarity index 100% rename from lib/routes/juejin/tag.js rename to lib/v2/juejin/tag.js diff --git a/lib/routes/juejin/trending.js b/lib/v2/juejin/trending.js similarity index 100% rename from lib/routes/juejin/trending.js rename to lib/v2/juejin/trending.js diff --git a/lib/routes/juejin/utils.js b/lib/v2/juejin/utils.js similarity index 54% rename from lib/routes/juejin/utils.js rename to lib/v2/juejin/utils.js index b62591cd0..50a9faafe 100644 --- a/lib/routes/juejin/utils.js +++ b/lib/v2/juejin/utils.js @@ -1,6 +1,6 @@ const got = require('@/utils/got'); +const cheerio = require('cheerio'); const { parseDate } = require('@/utils/parse-date'); -const timezone = require('@/utils/timezone'); const md = require('markdown-it')({ html: true, }); @@ -15,21 +15,29 @@ async function load(id) { }); let description; if (response.data.data) { - description = md.render(response.data.data.article_info.mark_content); + description = md.render(response.data.data.article_info.mark_content) || response.data.data.article_info.content; } return { description }; } +const loadNews = async (link) => { + const response = await got(link); + const $ = cheerio.load(response.data); + $('h1.title, .main-box .message').remove(); + return { description: $('.main-box .article').html() }; +}; + const ProcessFeed = (list, caches) => Promise.all( list.map(async (item) => { - const pubDate = timezone(parseDate(parseInt(item.article_info.ctime) * 1000), +8); - const link = `https://juejin.cn/post/${item.article_id}`; + const isArticle = !!item.article_info; + const pubDate = parseDate((isArticle ? item.article_info.ctime : item.content_info.ctime) * 1000); + const link = `https://juejin.cn${isArticle ? '/post/' + item.article_id : '/news/' + item.content_id}`; // 列表上提取到的信息 const single = { - title: item.article_info.title, - description: (item.article_info.brief_content || '无描述').replace(/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]/g, ''), + title: isArticle ? item.article_info.title : item.content_info.title, + description: ((isArticle ? item.article_info.brief_content : item.content_info.brief) || '无描述').replace(/[\x00-\x08\x0b-\x0c\x0e-\x1f\x7f]/g, ''), pubDate, author: item.author_user_info.user_name, link, @@ -37,7 +45,7 @@ const ProcessFeed = (list, caches) => // 使用tryGet方法从缓存获取内容。 // 当缓存中无法获取到链接内容的时候,则使用load方法加载文章内容。 - const other = await caches.tryGet(link, () => load(item.article_id)); + const other = await caches.tryGet(link, () => (isArticle ? load(item.article_id) : loadNews(link))); // 合并解析后的结果集作为该篇文章最终的输出结果 return { ...single, ...other }; })