diff --git a/docs/reading.md b/docs/reading.md index ec0f6895b..e69390e4b 100644 --- a/docs/reading.md +++ b/docs/reading.md @@ -180,11 +180,11 @@ For instance, when doing search at and you get url + -### 排行榜 +### 排行 - + | 文章点击排行 | 最近更新文章 | 文章推荐排行 | | ------------ | ------------ | ------------ | @@ -194,11 +194,10 @@ For instance, when doing search at and you get url + -| 论文 | 时评 | 随笔 | 演讲 | 访谈 | 著作 | 读书 | 史论 | 译作 | 诗歌 | 书信 | 科学 | -| ---- | ---- | ----- | ---- | ----- | ------ | ----- | ------ | ----- | ----- | ------ | ----- | -| lunw | ship | shuib | yanj | fangt | zhuanz | dushu | shilun | yizuo | shige | shuxin | kexue | +| 论文 | 时评 | 随笔 | 演讲 | 访谈 | 著作 | 读书 | 史论 | 译作 | 诗歌 | 书信 | 科学 | +| ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | diff --git a/lib/router.js b/lib/router.js index f4d8021c6..bac7a8344 100644 --- a/lib/router.js +++ b/lib/router.js @@ -1297,9 +1297,9 @@ router.get('/whalegogo/home', lazyloadRouteHandler('./routes/whalegogo/home')); router.get('/whalegogo/portal/:type_id/:tagid?', lazyloadRouteHandler('./routes/whalegogo/portal')); // 爱思想 -router.get('/aisixiang/column/:id', lazyloadRouteHandler('./routes/aisixiang/column')); -router.get('/aisixiang/ranking/:type?/:range?', lazyloadRouteHandler('./routes/aisixiang/ranking')); -router.get('/aisixiang/thinktank/:name/:type?', lazyloadRouteHandler('./routes/aisixiang/thinktank')); +// router.get('/aisixiang/column/:id', lazyloadRouteHandler('./routes/aisixiang/column')); +// router.get('/aisixiang/ranking/:type?/:range?', lazyloadRouteHandler('./routes/aisixiang/ranking')); +// router.get('/aisixiang/thinktank/:name/:type?', lazyloadRouteHandler('./routes/aisixiang/thinktank')); // Hacker News // router.get('/hackernews/:section/:type?', lazyloadRouteHandler('./routes/hackernews/story')); diff --git a/lib/routes/aisixiang/column.js b/lib/routes/aisixiang/column.js deleted file mode 100644 index c864cbb78..000000000 --- a/lib/routes/aisixiang/column.js +++ /dev/null @@ -1,37 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const iconv = require('iconv-lite'); - -const util = require('./utils'); - -module.exports = async (ctx) => { - const { id } = ctx.params; - - const host = `http://www.aisixiang.com/data/search.php?lanmu=${id}`; - - const response = await got.get(host, { - responseType: 'buffer', - }); - - response.data = iconv.decode(response.data, 'gbk'); - - const $ = cheerio.load(response.data); - - const list = $('.search_list > ul > li > a:nth-child(2)').slice(0, 10).get(); - - const columnName = $('.search_list > ul > li:nth-child(1) > a:nth-child(1)').text(); - - const items = await Promise.all( - list.map((e) => { - const link = $(e).attr('href'); - return ctx.cache.tryGet(link, () => util.ProcessFeed(link)); - }) - ); - - ctx.state.data = { - title: `爱思想栏目 - ${columnName}`, - link: host, - description: `爱思想栏目 - ${columnName}`, - item: items, - }; -}; diff --git a/lib/routes/aisixiang/ranking.js b/lib/routes/aisixiang/ranking.js deleted file mode 100644 index 53341401b..000000000 --- a/lib/routes/aisixiang/ranking.js +++ /dev/null @@ -1,37 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const iconv = require('iconv-lite'); - -const util = require('./utils'); - -module.exports = async (ctx) => { - const { type = 1, range = 1 } = ctx.params; - - const host = `http://www.aisixiang.com/toplist/index.php?id=${type}&period=${range}`; - - const response = await got.get(host, { - responseType: 'buffer', - }); - - response.data = iconv.decode(response.data, 'gbk'); - - const $ = cheerio.load(response.data); - - const list = $('.tops_list > .tips > a').slice(0, 10).get(); - - const columnName = $('.tops_text > h3')[0].firstChild.nodeValue; - - const items = await Promise.all( - list.map((e) => { - const link = $(e).attr('href'); - return ctx.cache.tryGet(link, () => util.ProcessFeed(link)); - }) - ); - - ctx.state.data = { - title: `爱思想 - ${columnName}`, - link: host, - description: `爱思想 - ${columnName}`, - item: items, - }; -}; diff --git a/lib/routes/aisixiang/thinktank.js b/lib/routes/aisixiang/thinktank.js deleted file mode 100644 index 85bb36f04..000000000 --- a/lib/routes/aisixiang/thinktank.js +++ /dev/null @@ -1,40 +0,0 @@ -const got = require('@/utils/got'); -const cheerio = require('cheerio'); -const iconv = require('iconv-lite'); -const util = require('./utils'); - -module.exports = async (ctx) => { - const { name, type = 'lunw' } = ctx.params; - - const host = `http://www.aisixiang.com/thinktank/${name}.html`; - - const response = await got.get(host, { - responseType: 'buffer', - }); - response.data = iconv.decode(response.data, 'gbk'); - - const $ = cheerio.load(response.data); - - const tds = $('td > img').filter(function () { - return $(this).attr('src') === `images/${type}.gif`; - }); - if (tds.length === 0) { - throw `Type Not Found - ${type}`; - } - - const list = tds.parent().next().find('a').slice(0, 5).get(); - - const items = await Promise.all( - list.map((e) => { - const link = $(e).attr('href'); - return ctx.cache.tryGet(link, () => util.ProcessFeed(link)); - }) - ); - - ctx.state.data = { - title: $('title').text(), - link: host, - description: $('meta[name="description"]').attr('content'), - item: items, - }; -}; diff --git a/lib/routes/aisixiang/utils.js b/lib/routes/aisixiang/utils.js deleted file mode 100644 index 5f87240f2..000000000 --- a/lib/routes/aisixiang/utils.js +++ /dev/null @@ -1,39 +0,0 @@ -const cheerio = require('cheerio'); -const iconv = require('iconv-lite'); -const got = require('@/utils/got'); -const date = require('@/utils/date'); - -const ProcessFeed = async (link) => { - const id = link.split('/').pop().split('.')[0]; - - let response; - response = await got.get(`http://www.aisixiang.com/data/view_json.php?id=${id}`, { - responseType: 'json', - }); - const description = response.data.content; - - link = `http://www.aisixiang.com${link}`; - response = await got.get(link, { - responseType: 'buffer', - }); - - response.data = iconv.decode(response.data, 'gbk'); - - const $ = cheerio.load(response.data); - - const title = $('.show_text > h3').text(); - - const pubDate = date($('.show_text > .info').text().split(':').pop(), 8); - - return { - title: title.split(':')[1] || title, - author: title.split(':')[0] || '', - description, - pubDate, - link, - }; -}; - -module.exports = { - ProcessFeed, -}; diff --git a/lib/v2/aisixiang/column.js b/lib/v2/aisixiang/column.js new file mode 100644 index 000000000..863ce1ccd --- /dev/null +++ b/lib/v2/aisixiang/column.js @@ -0,0 +1,36 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { rootUrl, ProcessFeed } = require('./utils'); + +module.exports = async (ctx) => { + const id = ctx.params.id; + const limit = ctx.query.limit ? parseInt(ctx.query.limit) : 30; + + const currentUrl = `${rootUrl}/data/search?column=${id}`; + + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const $ = cheerio.load(response.data); + + const title = $('div.article-title a').first().text().replace(/\[|\]/g, ''); + + const items = $('div.search_list a[title]') + .toArray() + .map((item) => { + item = $(item); + + return { + title: item.text().split(':').pop(), + link: new URL(item.attr('href'), rootUrl).href, + }; + }); + + ctx.state.data = { + title: `爱思想 - ${title}`, + link: currentUrl, + item: await ProcessFeed(limit, ctx.cache.tryGet, items), + }; +}; diff --git a/lib/v2/aisixiang/maintainer.js b/lib/v2/aisixiang/maintainer.js new file mode 100644 index 000000000..1b6175522 --- /dev/null +++ b/lib/v2/aisixiang/maintainer.js @@ -0,0 +1,6 @@ +module.exports = { + '/column/:id': ['HenryQW', 'nczitzk'], + '/ranking/:id?/:period?': ['HenryQW', 'nczitzk'], + '/toplist/:id?/:period?': ['nczitzk'], + '/thinktank/:id/:type?': ['hoilc', 'nczitzk'], +}; diff --git a/lib/v2/aisixiang/radar.js b/lib/v2/aisixiang/radar.js new file mode 100644 index 000000000..0e1b9306f --- /dev/null +++ b/lib/v2/aisixiang/radar.js @@ -0,0 +1,29 @@ +module.exports = { + 'aisixiang.com': { + _name: '爱思想', + '.': [ + { + title: '栏目', + docs: 'https://docs.rsshub.app/reading.html#ai-si-xiang', + source: ['/data/search', '/'], + target: (params, url) => `/aisixiang/column/${new URL(url).searchParams.get('column')}`, + }, + { + title: '排行', + docs: 'https://docs.rsshub.app/reading.html#ai-si-xiang', + source: ['/toplist', '/'], + target: (params, url) => { + const id = new URL(url).searchParams.get('id'); + const period = new URL(url).searchParams.get('period'); + return `/aisixiang/toplist${id ? `/${id}${(id === '1' || !id) && period ? `/${period}` : ''}` : ''}`; + }, + }, + { + title: '思想库(专栏)', + docs: 'https://docs.rsshub.app/reading.html#ai-si-xiang', + source: ['/thinktank', '/'], + target: (params, url) => `/aisixiang/thinktank/${new URL(url).href.match(/thinktank\/(.*)\.html/)[1]}`, + }, + ], + }, +}; diff --git a/lib/v2/aisixiang/router.js b/lib/v2/aisixiang/router.js new file mode 100644 index 000000000..8cbf64048 --- /dev/null +++ b/lib/v2/aisixiang/router.js @@ -0,0 +1,6 @@ +module.exports = function (router) { + router.get('/column/:id', require('./column')); + router.get('/ranking/:id?/:period?', require('./toplist')); + router.get('/toplist/:id?/:period?', require('./toplist')); + router.get('/thinktank/:id/:type?', require('./thinktank')); +}; diff --git a/lib/v2/aisixiang/thinktank.js b/lib/v2/aisixiang/thinktank.js new file mode 100644 index 000000000..38732a250 --- /dev/null +++ b/lib/v2/aisixiang/thinktank.js @@ -0,0 +1,49 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { rootUrl, ProcessFeed } = require('./utils'); + +module.exports = async (ctx) => { + const id = ctx.params.id; + const type = ctx.params.type ?? ''; + const limit = ctx.query.limit ? parseInt(ctx.query.limit) : 30; + + const currentUrl = `${rootUrl}/thinktank/${id}.html`; + + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const $ = cheerio.load(response.data); + + const title = `${$('h2').first().text().trim()}${type}`; + + let items = []; + + const targetList = $('h3') + .toArray() + .filter((h) => (type ? $(h).text() === type : true)); + if (!targetList) { + throw `Not found ${type} in ${id}: ${currentUrl}`; + } + + for (const l of targetList) { + items = [...items, ...$(l).parent().find('ul li a').toArray()]; + } + + items = items.map((item) => { + item = $(item); + + return { + title: item.text().split(':').pop(), + link: new URL(item.attr('href'), rootUrl).href, + }; + }); + + ctx.state.data = { + title: `爱思想 - ${title}`, + link: currentUrl, + item: await ProcessFeed(limit, ctx.cache.tryGet, items), + description: $('div.thinktank-author-description-box p').text(), + }; +}; diff --git a/lib/v2/aisixiang/toplist.js b/lib/v2/aisixiang/toplist.js new file mode 100644 index 000000000..2d855e702 --- /dev/null +++ b/lib/v2/aisixiang/toplist.js @@ -0,0 +1,37 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { rootUrl, ProcessFeed } = require('./utils'); + +module.exports = async (ctx) => { + const id = ctx.params.id ?? '1'; + const period = ctx.params.period ?? '1'; + const limit = ctx.query.limit ? parseInt(ctx.query.limit) : 30; + + const currentUrl = `${rootUrl}/toplist${id ? `?id=${id}${id === '1' ? `&period=${period}` : ''}` : ''}`; + + const response = await got({ + method: 'get', + url: currentUrl, + }); + + const $ = cheerio.load(response.data); + + const title = `${$('.hl').text() || ''}${$('title').text().split('_')[0]}`; + + const items = $('div.tips a') + .toArray() + .map((item) => { + item = $(item); + + return { + title: item.text().split(':').pop(), + link: new URL(item.attr('href'), rootUrl).href, + }; + }); + + ctx.state.data = { + title: `爱思想 - ${title}`, + link: currentUrl, + item: await ProcessFeed(limit, ctx.cache.tryGet, items), + }; +}; diff --git a/lib/v2/aisixiang/utils.js b/lib/v2/aisixiang/utils.js new file mode 100644 index 000000000..48fca95c7 --- /dev/null +++ b/lib/v2/aisixiang/utils.js @@ -0,0 +1,37 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const timezone = require('@/utils/timezone'); +const { parseDate } = require('@/utils/parse-date'); + +const rootUrl = 'http://www.aisixiang.com'; + +const ProcessFeed = (limit, tryGet, items) => + Promise.all( + items.slice(0, limit).map((item) => + tryGet(item.link, async () => { + const detailResponse = await got({ + method: 'get', + url: item.link, + }); + + const content = cheerio.load(detailResponse.data); + + item.author = content('strong').first().text(); + item.description = content('.article-content').html(); + item.pubDate = timezone(parseDate(content('.info').text().split('时间:').pop()), +8); + item.category = content('u') + .first() + .parent() + .find('u') + .toArray() + .map((a) => content(a).text()); + + return item; + }) + ) + ); + +module.exports = { + rootUrl, + ProcessFeed, +};