diff --git a/lib/v2/toodaylab/index.js b/lib/v2/toodaylab/index.js new file mode 100644 index 000000000..fda14bfec --- /dev/null +++ b/lib/v2/toodaylab/index.js @@ -0,0 +1,99 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const timezone = require('@/utils/timezone'); +const { parseDate, parseRelativeDate } = require('@/utils/parse-date'); + +module.exports = async (ctx) => { + const { params = 'posts' } = ctx.params; + const limit = ctx.query.limit ? parseInt(ctx.query.limit, 10) : 30; + + const isHot = params === 'hot'; + + const rootUrl = 'https://www.toodaylab.com'; + const currentUrl = new URL(isHot ? 'posts' : params, rootUrl).href; + + const { data: response } = await got(currentUrl); + + const $ = cheerio.load(response); + + let items = isHot + ? $('div.hot-list a') + .slice(0, limit) + .toArray() + .map((item) => { + item = $(item); + + return { + title: item.find('div.hot-item p').text(), + link: new URL(item.prop('href'), rootUrl).href, + }; + }) + : $('div.single-post') + .slice(0, limit) + .toArray() + .map((item) => { + item = $(item); + + const a = item.find('p.title a'); + + const pubDate = item + .find('div.left-infos p') + .text() + .trim() + .split(/\/\/\s/) + .pop(); + + return { + title: a.text(), + link: new URL(a.prop('href'), rootUrl).href, + description: item.find('p.excerpt').html(), + author: item.find('div.left-infos p a').text().trim(), + pubDate: timezone(/年|月|日/.test(pubDate) ? parseDate(pubDate, ['YYYY年M月D日 HH:mm', 'M月D日 HH:mm']) : parseRelativeDate(pubDate), +8), + }; + }); + + items = await Promise.all( + items.map((item) => + ctx.cache.tryGet(item.link, async () => { + const { data: detailResponse } = await got(item.link); + + const content = cheerio.load(detailResponse); + + const pubDate = content('div.left-infos p') + .text() + .trim() + .split(/\/\/\s/) + .pop(); + + item.title = content('h1').text() || item.title; + item.description = content('div.post-content').html() ?? item.description; + item.author = content('div.left-infos p a').text().trim() ?? item.author; + item.category = content('div.right-infos a') + .slice(1) + .toArray() + .map((c) => content(c).text().replace(/#/, '')); + item.pubDate = item.pubDate ?? timezone(/年|月|日/.test(pubDate) ? parseDate(pubDate, ['YYYY年M月D日 HH:mm', 'M月D日 HH:mm']) : parseRelativeDate(pubDate), +8); + item.upvotes = content('#like_count').text() ? parseInt(content('#like_count').text(), 10) : 0; + item.comments = parseInt(content('div.right-infos a').first().text(), 10) || 0; + + return item; + }) + ) + ); + + const title = $('title').text().split(/\s-/)[0]; + const icon = $('link[rel="apple-touch-icon"]').last().prop('href'); + + ctx.state.data = { + item: items, + title: isHot ? title.replace(/[^|]+/, '最热 ') : title, + link: currentUrl, + description: $('meta[name="description"]').prop('content'), + language: $('html').prop('lang'), + image: $('h3.logo a img').prop('src'), + icon, + logo: icon, + subtitle: $('meta[name="keywords"]').prop('content'), + author: $('h3.logo a img').prop('alt'), + }; +}; diff --git a/lib/v2/toodaylab/maintainer.js b/lib/v2/toodaylab/maintainer.js new file mode 100644 index 000000000..f7e886857 --- /dev/null +++ b/lib/v2/toodaylab/maintainer.js @@ -0,0 +1,7 @@ +module.exports = { + '/column/:id': ['nczitzk'], + '/field/:id': ['nczitzk'], + '/hot': ['nczitzk'], + '/posts': ['nczitzk'], + '/topic/:id': ['nczitzk'], +}; diff --git a/lib/v2/toodaylab/radar.js b/lib/v2/toodaylab/radar.js new file mode 100644 index 000000000..80a45f2b7 --- /dev/null +++ b/lib/v2/toodaylab/radar.js @@ -0,0 +1,37 @@ +module.exports = { + 'toodaylab.com': { + _name: '理想生活实验室', + '.': [ + { + title: '滚动', + docs: 'https://docs.rsshub.app/routes/new-media#li-xiang-sheng-huo-shi-yan-shi-gun-dong', + source: ['/posts'], + target: '/toodaylab/posts', + }, + { + title: '最热', + docs: 'https://docs.rsshub.app/routes/new-media#li-xiang-sheng-huo-shi-yan-shi-zui-re', + source: ['/posts'], + target: '/toodaylab/hot', + }, + { + title: '专栏', + docs: 'https://docs.rsshub.app/routes/new-media#li-xiang-sheng-huo-shi-yan-shi-zhuan-lan', + source: ['/column/:id'], + target: '/toodaylab/column/:id', + }, + { + title: '领域', + docs: 'https://docs.rsshub.app/routes/new-media#li-xiang-sheng-huo-shi-yan-shi-ling-yu', + source: ['/field/:id'], + target: '/toodaylab/field/:id', + }, + { + title: '话题', + docs: 'https://docs.rsshub.app/routes/new-media#li-xiang-sheng-huo-shi-yan-shi-hua-ti', + source: ['/topic/:id'], + target: '/toodaylab/topic/:id', + }, + ], + }, +}; diff --git a/lib/v2/toodaylab/router.js b/lib/v2/toodaylab/router.js new file mode 100644 index 000000000..a8cead003 --- /dev/null +++ b/lib/v2/toodaylab/router.js @@ -0,0 +1,3 @@ +module.exports = (router) => { + router.get('/:params*', require('./')); +}; diff --git a/website/docs/routes/new-media.md b/website/docs/routes/new-media.md index 059223fdc..45d7fb7a0 100644 --- a/website/docs/routes/new-media.md +++ b/website/docs/routes/new-media.md @@ -3384,6 +3384,46 @@ column 为 third 时可选的 category: +## 理想生活实验室 {#li-xiang-sheng-huo-shi-yan-shi} + +### 滚动 {#li-xiang-sheng-huo-shi-yan-shi-gun-dong} + + + +### 最热 {#li-xiang-sheng-huo-shi-yan-shi-zui-re} + + + +### 专栏 {#li-xiang-sheng-huo-shi-yan-shi-zhuan-lan} + + + +| 专题 | 攻略 | +| ---- | ---- | +| 299 | 300 | + + + +### 领域 {#li-xiang-sheng-huo-shi-yan-shi-ling-yu} + + + +| 快消 | 时尚 | 智能 | 娱乐 | 运动 | 生活 | 设计 | 出行 | +| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | +| 308 | 307 | 306 | 305 | 304 | 303 | 302 | 301 | + + + +### 话题 {#li-xiang-sheng-huo-shi-yan-shi-hua-ti} + + + +| 今日消费资讯 | 实验室带你过周末 | 实验室带你过假期 | 每日一图 | 每周一书 | 实验室数字 | 新鲜社会人 | 实验室TV | +| ------------ | ---------------- | ---------------- | -------- | -------- | ---------- | ---------- | -------- | +| 309 | 37 | 40 | 32 | 33 | 310 | 316 | 476 | + + + ## 链捕手 ChainCatcher {#lian-bu-shou-chaincatcher} ### 首页 {#lian-bu-shou-chaincatcher-shou-ye}