From 35576d5b2165921154e12637e4f1a9c322954244 Mon Sep 17 00:00:00 2001 From: lyqluis <39592732+lyqluis@users.noreply.github.com> Date: Thu, 21 Mar 2024 22:35:31 +0800 Subject: [PATCH 1/4] fix(route): douban/book/latest, add route optional params, replace cheerio with mobile api (#14897) --- lib/routes/douban/book/latest.ts | 66 ++++++++++++++++++++++++++ lib/routes/douban/other/latest-book.ts | 38 --------------- 2 files changed, 66 insertions(+), 38 deletions(-) create mode 100644 lib/routes/douban/book/latest.ts delete mode 100644 lib/routes/douban/other/latest-book.ts diff --git a/lib/routes/douban/book/latest.ts b/lib/routes/douban/book/latest.ts new file mode 100644 index 00000000000000..778791afbc704f --- /dev/null +++ b/lib/routes/douban/book/latest.ts @@ -0,0 +1,66 @@ +import { Route } from '@/types'; +import got from '@/utils/got'; + +const linkUrl = 'https://book.douban.com/latest'; +const baseUrl = 'https://m.douban.com/rexxar/api/v2/subject_collection'; +const params = 'items?start=0&count=10&mode=collection&for_mobile=1'; + +export const route: Route = { + path: '/book/latest/:type?', + categories: ['social-media'], + example: '/douban/book/latest/fiction', + parameters: { type: '专题分类,可选,默认为 `all`' }, + features: { + requireConfig: false, + requirePuppeteer: false, + antiCrawler: false, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, + name: '新书速递', + maintainers: ['fengkx', 'lyqluis'], + description: ` + | 文学 | 小说 | 历史文化 | 社会纪实 | 科学新知 | 艺术设计 | 商业经管 | 绘本漫画 | + | ------------ | ------- | -------- | --------- | -------- | -------- | -------- | -------- | + | prose_poetry | fiction | history | biography | science | art | business | comics |`, + handler, +}; + +const SUBCATS = { + all: '全部', + prose_poetry: '文学', + fiction: '小说', + history: '历史文化', + biography: '社会纪实', + science: '科学新知', + art: '艺术设计', + business: '商业经管', + comics: '绘本漫画', +}; + +async function handler(ctx) { + const type = ctx.req.param('type') ?? 'all'; + const subUrl = `new_book_${type}`; + const url = `${baseUrl}/${subUrl}/${params}`; + + const res = await got.get(url); + const items = res.data.items; + + return { + title: `豆瓣新书速递${type === 'all' ? '' : '-' + SUBCATS[type]}`, + link: `${linkUrl}${type === 'all' ? '' : '?subcat=' + SUBCATS[type]}`, + item: items.map(({ title, url, card_subtitle, cards, pic, rating, null_rating_reason }) => { + const rate = rating.value ? `${rating.value}分` : null_rating_reason; + const img = ``; + const info = card_subtitle; + const description = `${img}
${title}

${info}

${cards[0]?.content ?? ''}

${rate}`; + + return { + title, + description, + link: url, + }; + }), + }; +} diff --git a/lib/routes/douban/other/latest-book.ts b/lib/routes/douban/other/latest-book.ts deleted file mode 100644 index 70b16692f4b22c..00000000000000 --- a/lib/routes/douban/other/latest-book.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Route } from '@/types'; -import got from '@/utils/got'; -import { load } from 'cheerio'; - -const url = 'https://book.douban.com/latest'; - -export const route: Route = { - path: '/book/latest', - categories: ['social-media'], - example: '/douban/book/latest', - parameters: {}, - features: { - requireConfig: false, - requirePuppeteer: false, - antiCrawler: false, - supportBT: false, - supportPodcast: false, - supportScihub: false, - }, - name: '新书速递', - maintainers: ['fengkx'], - handler, -}; - -async function handler() { - const res = await got.get(url); - const $ = load(res.data); - const list = $('#content').find('li').get(); - return { - title: '豆瓣新书速递', - link: url, - item: list.map((item, index) => ({ - title: `${index < 20 ? '[虚构类]' : '[非虚构类]'}${$(item).find('h2').text().trim()}`, - link: $(item).find('a').first().attr('href'), - description: $(item).html(), - })), - }; -} From 7d1448bd00f6806b418afe1ca6fbbbb12d2b207a Mon Sep 17 00:00:00 2001 From: Mg Pig Date: Thu, 21 Mar 2024 22:58:54 +0800 Subject: [PATCH 2/4] =?UTF-8?q?feat(route):=20Add=20yxxc(=E6=B8=B8?= =?UTF-8?q?=E6=88=8F=E6=98=9F=E8=BE=B0)=20(#14870)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat(route): Add yxxc(游戏星辰) * feat(route): Move route yxxc to 2023game --- lib/routes/2023game/index.ts | 69 ++++++++++++++++++++++++++++++++ lib/routes/2023game/namespace.ts | 6 +++ 2 files changed, 75 insertions(+) create mode 100644 lib/routes/2023game/index.ts create mode 100644 lib/routes/2023game/namespace.ts diff --git a/lib/routes/2023game/index.ts b/lib/routes/2023game/index.ts new file mode 100644 index 00000000000000..03ae687a08ca97 --- /dev/null +++ b/lib/routes/2023game/index.ts @@ -0,0 +1,69 @@ +import { Data, DataItem, Route } from '@/types'; +import got from '@/utils/got'; +import { parseDate } from '@/utils/parse-date'; +import { load } from 'cheerio'; +import { Context } from 'hono'; + +export const route: Route = { + path: '/:category?/:tab?', + categories: ['game'], + example: '/2023game/sgame/topicList', + parameters: { + category: '分类,见下表', + tab: '标签, 所有:all;最新:topicList;热门:jhcpb', + }, + features: { + requireConfig: false, + requirePuppeteer: false, + antiCrawler: false, + supportBT: false, + supportPodcast: false, + supportScihub: false, + }, + name: '游戏星辰', + maintainers: ['xzzpig'], + handler, + url: 'www.2023game.com/', + description: `分类 + + | PS4游戏 | switch游戏 | 3DS游戏 | PSV游戏 | Xbox360 | PS3游戏 | 世嘉MD/SS | PSP游戏 | PC周边 | 怀旧掌机 | 怀旧主机 | PS4教程 | PS4金手指 | switch金手指 | switch教程 | switch补丁 | switch主题 | switch存档 | + | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | -------- | + | ps4 | sgame | 3ds | psv | jiaocheng | ps3yx | zhuji.md | zhangji.psp | pcgame | zhangji | zhuji | ps4.psjc | ps41.ps4pkg | nsaita.cundang | nsaita.pojie | nsaita.buding | nsaita.zhutie | nsaita.zhuti |`, +}; + +async function handler(ctx?: Context): Promise { + const category = (ctx!.req.param('category') ?? 'sgame').replaceAll('.', '/'); + const tab = ctx?.req.param('tab') ?? 'all'; + + const currentUrl = `https://www.2023game.com/${category}/`; + + const response = await got(currentUrl); + const $ = load(response.data as any); + + let selector = `.news`; + if (tab !== 'all') { + selector = `#${tab} > ${selector}`; + } + + const items: DataItem[] = $(selector) + .toArray() + .map((item) => { + const $item = $(item); + const href = $item.find('a').attr('href'); + return { + title: $item.text().trim(), + guid: `2023game:${href}`, + link: href!, + pubDate: parseDate($item.find('.time_box').text().trim()), + description: $item.html() ?? '', + }; + }); + + return { + title: $('title').text(), + link: currentUrl, + allowEmpty: true, + image: 'https://www.2023game.com/resources/img/logo.png', + item: items, + }; +} diff --git a/lib/routes/2023game/namespace.ts b/lib/routes/2023game/namespace.ts new file mode 100644 index 00000000000000..0405df7cc98a7b --- /dev/null +++ b/lib/routes/2023game/namespace.ts @@ -0,0 +1,6 @@ +import type { Namespace } from '@/types'; + +export const namespace: Namespace = { + name: '游戏星辰', + url: 'www.2023game.com', +}; From fe798966156bc57ec9fcd89d5a3685c8c3008002 Mon Sep 17 00:00:00 2001 From: frankcwl <45101942+frankcwl@users.noreply.github.com> Date: Thu, 21 Mar 2024 23:32:31 +0800 Subject: [PATCH 3/4] fix(route): fix priconne-redive and remove deprecated route (#14893) * fix(route): fix priconne-redive and remove deprecated route * remove entries in router.js --- lib/router.js | 5 --- lib/routes-deprecated/pcr/news-cn.js | 28 ------------ lib/routes-deprecated/pcr/news-tw.js | 67 ---------------------------- lib/routes/priconne-redive/news.ts | 25 +++++++---- 4 files changed, 17 insertions(+), 108 deletions(-) delete mode 100644 lib/routes-deprecated/pcr/news-cn.js delete mode 100644 lib/routes-deprecated/pcr/news-tw.js diff --git a/lib/router.js b/lib/router.js index ccc3a1bf365839..0661dad1386599 100644 --- a/lib/router.js +++ b/lib/router.js @@ -992,11 +992,6 @@ router.get('/ddrk/index', lazyloadRouteHandler('./routes/ddrk/list')); router.get('/avgle/videos/:order?/:time?/:top?', lazyloadRouteHandler('./routes/avgle/videos.js')); router.get('/avgle/search/:keyword/:order?/:time?/:top?', lazyloadRouteHandler('./routes/avgle/videos.js')); -// 公主链接公告 -// router.get('/pcr/news', lazyloadRouteHandler('./routes/pcr/news')); -router.get('/pcr/news-tw', lazyloadRouteHandler('./routes/pcr/news-tw')); -router.get('/pcr/news-cn', lazyloadRouteHandler('./routes/pcr/news-cn')); - // project-zero issues router.get('/project-zero-issues', lazyloadRouteHandler('./routes/project-zero-issues/index')); diff --git a/lib/routes-deprecated/pcr/news-cn.js b/lib/routes-deprecated/pcr/news-cn.js deleted file mode 100644 index 55986a9d1775cc..00000000000000 --- a/lib/routes-deprecated/pcr/news-cn.js +++ /dev/null @@ -1,28 +0,0 @@ -const got = require('@/utils/got'); - -module.exports = async (ctx) => { - const response = await got({ - method: 'get', - url: `https://api.biligame.com/news/list?gameExtensionId=267&positionId=2&typeId=&pageNum=1&pageSize=5`, - }); - const data = response.data; - ctx.state.data = { - title: '公主链接国服-最新公告', - link: 'https://game.bilibili.com/pcr/news.html', - item: data - ? await Promise.all( - data.data.map(async (item) => ({ - title: item.title, - description: await ctx.cache.tryGet(`pcrcn_${item.id}`, async () => { - const resp = await got({ method: 'get', url: `https://api.biligame.com/news/${item.id}` }); - return resp.data.data.content; - }), - link: `https://game.bilibili.com/pcr/news.html#detail=${item.id}`, - pubDate: item.ctime ?? item.createTime, - })) - ) - : { - title: '获取失败!', - }, - }; -}; diff --git a/lib/routes-deprecated/pcr/news-tw.js b/lib/routes-deprecated/pcr/news-tw.js deleted file mode 100644 index 327cbfbc2b5236..00000000000000 --- a/lib/routes-deprecated/pcr/news-tw.js +++ /dev/null @@ -1,67 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); - -const base = 'http://www.princessconnect.so-net.tw'; - -module.exports = async (ctx) => { - const url = `${base}/news`; - - const list_response = await got.get(url); - const $ = cheerio.load(list_response.data); - - const list = $('.news_con dl dd').get(); - - const parseContent = (htmlString) => { - const $ = cheerio.load(htmlString); - - $('.news_con h2 > span').remove(); - const time = $('.news_con h2').text().trim(); - $('.news_con section h4').first().remove(); - const content = $('.news_con section'); - - return { - description: content.html(), - pubDate: new Date(time), - }; - }; - - const out = await Promise.all( - list.map(async (item) => { - const $ = cheerio.load(item); - - const title = $('a'); - const path = title.attr('href'); - - const link = base + path; - - const cache = await ctx.cache.get(link); - if (cache) { - return JSON.parse(cache); - } - - const rssitem = { - title: title.text().trim(), - link, - }; - - try { - const response = await got.get(link); - const result = parseContent(response.data); - - rssitem.author = '《超異域公主連結☆Re:Dive》營運團隊'; - rssitem.description = result.description; - rssitem.pubDate = result.pubDate; - } catch { - return ''; - } - ctx.cache.set(link, JSON.stringify(rssitem)); - return rssitem; - }) - ); - - ctx.state.data = { - title: '公主连结 - 台服公告', - link: url, - item: out.filter((item) => item !== ''), - }; -}; diff --git a/lib/routes/priconne-redive/news.ts b/lib/routes/priconne-redive/news.ts index 5c6fe734907a35..278885b8231459 100644 --- a/lib/routes/priconne-redive/news.ts +++ b/lib/routes/priconne-redive/news.ts @@ -5,10 +5,10 @@ import cache from '@/utils/cache'; import { load } from 'cheerio'; export const route: Route = { - path: '/news/:location?', + path: '/news/:server?', categories: ['game'], example: '/priconne-redive/news', - parameters: { location: '区域,默认日服' }, + parameters: { server: '服务器,默认日服' }, features: { requireConfig: false, requirePuppeteer: false, @@ -20,23 +20,32 @@ export const route: Route = { radar: [ { source: ['priconne-redive.jp/news'], + target: '/news/jp', + }, + { + source: ['princessconnect.so-net.tw/news'], + target: '/news/zh-tw', + }, + { + source: ['game.bilibili.com/pcr/news.html'], + target: '/news/zh-cn', }, ], name: '最新公告', maintainers: ['SayaSS', 'frankcwl'], handler, url: 'priconne-redive.jp/news', - description: `location + description: `服务器 - | 国服 | 台服 | 日服 | - | ----- | ----- | ---- | - | zh-cn | zh-tw | jp |`, + | 国服 | 台服 | 日服 | + | ----- | ----- | ---- | + | zh-cn | zh-tw | jp |`, }; async function handler(ctx) { - const { location = 'jp' } = ctx.req.param(); + const { server = 'jp' } = ctx.req.param(); - switch (location) { + switch (server) { case 'jp': { const parseContent = (htmlString) => { const $ = load(htmlString); From 3351e51f3cf7085a7c8ca79136e7ac0677b847f2 Mon Sep 17 00:00:00 2001 From: karasu Date: Thu, 21 Mar 2024 23:45:34 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix(route):=20=E5=8D=97=E6=96=B9=E5=91=A8?= =?UTF-8?q?=E6=9C=AB=20(#14886)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix(route): 南方周末 * update image * update radar rules * remove the deprecated content * Update lib/routes/infzm/index.ts Co-authored-by: Tony * Update lib/routes/infzm/index.ts Co-authored-by: Tony * use cache.tryGet --------- --- lib/router.js | 3 -- lib/routes-deprecated/infzm/news.js | 62 ------------------------ lib/routes/infzm/index.ts | 75 +++++++++++++++++++++++++++++ lib/routes/infzm/types.ts | 17 +++++++ 4 files changed, 92 insertions(+), 65 deletions(-) delete mode 100644 lib/routes-deprecated/infzm/news.js create mode 100644 lib/routes/infzm/index.ts create mode 100644 lib/routes/infzm/types.ts diff --git a/lib/router.js b/lib/router.js index 0661dad1386599..0c89d215ed33c4 100644 --- a/lib/router.js +++ b/lib/router.js @@ -34,9 +34,6 @@ router.get('/disqus/posts/:forum', lazyloadRouteHandler('./routes/disqus/posts') // 极客时间 router.get('/geektime/column/:cid', lazyloadRouteHandler('./routes/geektime/column')); -// 南方周末 -router.get('/infzm/:id', lazyloadRouteHandler('./routes/infzm/news')); - // Dribbble // router.get('/dribbble/popular/:timeframe?', lazyloadRouteHandler('./routes/dribbble/popular')); // router.get('/dribbble/user/:name', lazyloadRouteHandler('./routes/dribbble/user')); diff --git a/lib/routes-deprecated/infzm/news.js b/lib/routes-deprecated/infzm/news.js deleted file mode 100644 index 44662081afa7f9..00000000000000 --- a/lib/routes-deprecated/infzm/news.js +++ /dev/null @@ -1,62 +0,0 @@ -const config = require('@/config').value; -const got = require('@/utils/got'); -const timezone = require('@/utils/timezone'); -const cheerio = require('cheerio'); - -const baseUrl = 'http://www.infzm.com/contents'; - -module.exports = async (ctx) => { - const { id } = ctx.params; - const link = `${baseUrl}?term_id=${id}`; - const response = await got({ - method: 'get', - url: `http://www.infzm.com/contents?term_id=${id}&page=1&format=json`, - headers: { - Referer: link, - }, - }); - const data = response.data.data; - const resultItem = await Promise.all( - data.contents.map(async ({ id, subject, author, publish_time }) => { - // the timezone is GMT+8 - const date = timezone(publish_time, +8); - const link = `http://www.infzm.com/contents/${id}`; - let description = ''; - - const key = `infzm: ${link}`; - const value = await ctx.cache.get(key); - - if (value) { - description = value; - } else { - const cookie = config.infzm.cookie; - const response = await got({ - method: 'get', - url: `http://www.infzm.com/content/${id}`, - headers: { - Referer: link, - Cookie: cookie || `passport_session=${Math.floor(Math.random() * 100)};`, - }, - }); - const $ = cheerio.load(response.data); - description = $('div.nfzm-content__content').html(); - - ctx.cache.set(key, description); - } - - return { - title: subject, - description, - pubDate: date.toUTCString(), - link, - author, - }; - }) - ); - - ctx.state.data = { - title: `南方周末-${data.current_term.title}`, - link, - item: resultItem, - }; -}; diff --git a/lib/routes/infzm/index.ts b/lib/routes/infzm/index.ts new file mode 100644 index 00000000000000..2b98371ec62fd1 --- /dev/null +++ b/lib/routes/infzm/index.ts @@ -0,0 +1,75 @@ +import type { Data, DataItem, Route } from '@/types'; +import type { ContentsResponse } from './types'; +import { config } from '@/config'; +import got from '@/utils/got'; +import { load } from 'cheerio'; +import timezone from '@/utils/timezone'; +import cache from '@/utils/cache'; + +export const route: Route = { + path: '/:id', + parameters: { id: '南方周末频道 id, 可在该频道的 URL 中找到(即 https://www.infzm.com/contents?term_id=:id)' }, + categories: ['traditional-media'], + example: '/infzm/1', + radar: [ + { + source: ['infzm.com/contents'], + target: (_, url) => (url ? `/infzm/${url.match(/contents\?term_id=(\d*)/)?.[1]}` : ''), + }, + ], + name: '频道', + maintainers: ['KarasuShin', 'ranpox', 'xyqfer'], + handler, + description: `下面给出部分参考: + + | 推荐 | 新闻 | 观点 | 文化 | 人物 | 影像 | 专题 | 生活 | 视频 | + | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | + | 1 | 2 | 3 | 4 | 7 | 8 | 6 | 5 | 131 |`, +}; + +const baseUrl = 'https://www.infzm.com/contents'; + +async function handler(ctx): Promise { + const id = ctx.req.param('id'); + const link = `${baseUrl}?term_id=${id}`; + const { data } = await got({ + method: 'get', + url: `${baseUrl}?term_id=${id}&page=1&format=json`, + headers: { + Referer: link, + }, + }); + + const resultItem = await Promise.all( + data.data.contents.map(({ id, subject, author, publish_time }) => { + const link = `${baseUrl}/${id}`; + + return cache.tryGet(link, async () => { + const cookie = config.infzm.cookie; + const response = await got.get({ + method: 'get', + url: link, + headers: { + Referer: link, + Cookie: cookie || `passport_session=${Math.floor(Math.random() * 100)};`, + }, + }); + const $ = load(response.data); + return { + title: subject, + description: $('div.nfzm-content__content').html() ?? '', + pubDate: timezone(publish_time, +8).toUTCString(), + link, + author, + }; + }); + }) + ); + + return { + title: `南方周末-${data.data.current_term.title}`, + link, + image: 'https://www.infzm.com/favicon.ico', + item: resultItem as DataItem[], + }; +} diff --git a/lib/routes/infzm/types.ts b/lib/routes/infzm/types.ts new file mode 100644 index 00000000000000..1f6ba32da0bf51 --- /dev/null +++ b/lib/routes/infzm/types.ts @@ -0,0 +1,17 @@ +export interface ContentsResponse { + code: number; + msg: string; + data: { + contents: { + id: number; + subject: string; + author: string; + publish_time: string; + }[]; + current_term: { + id: number; + title: string; + type: string; + }; + }; +}