diff --git a/docs/reading.md b/docs/reading.md index 673b00a60..068d00eb9 100644 --- a/docs/reading.md +++ b/docs/reading.md @@ -303,6 +303,10 @@ count 的取值范围为 1-12,为防止请求次数过多,推荐设置为 5 +### 最新卷 + + + ## 生物帮 ### 所有栏目 diff --git a/lib/router.js b/lib/router.js index ba6427815..40e8b50b9 100644 --- a/lib/router.js +++ b/lib/router.js @@ -1433,6 +1433,7 @@ router.get('/gaoqing/latest', lazyloadRouteHandler('./routes/gaoqing/latest')); // 轻小说文库 router.get('/wenku8/chapter/:id', lazyloadRouteHandler('./routes/wenku8/chapter')); +router.get('/wenku8/volume/:id', lazyloadRouteHandler('./routes/wenku8/volume')); // 鲸跃汽车 router.get('/whalegogo/home', lazyloadRouteHandler('./routes/whalegogo/home')); diff --git a/lib/routes/wenku8/volume.js b/lib/routes/wenku8/volume.js new file mode 100644 index 000000000..d9e09b622 --- /dev/null +++ b/lib/routes/wenku8/volume.js @@ -0,0 +1,52 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const iconv = require('iconv-lite'); + +module.exports = async (ctx) => { + const aid = ctx.params.id; + const novel_url = `https://www.wenku8.net/novel/${parseInt(aid / 1000)}/${aid}/index.htm`; + const $ = cheerio.load(await get(novel_url)); + + const novel_name = $('#title').text(); + + const volume_list = $('.vcss'); + const last_volume = $(volume_list[volume_list.length - 1]); + const vid = last_volume.parent().next().find('a')[0].attribs.href.replace('.htm', ''); + + const volume_url = `https://dl.wenku8.com/packtxt.php?aid=${aid}&vid=${vid}&charset=gbk`; + const item_list = await ctx.cache.tryGet(volume_url, async () => { + const result = await get(volume_url); + const chapter_list = [...result.matchAll(/ {2}(\S.*)\r\n([\S\s]+?)\r\n\r\n/g)]; + return chapter_list + .filter((chapter) => chapter[2].trim()) + .reverse() + .map((chapter) => ({ + title: chapter[1], + description: format_description(chapter[2]), + guid: Buffer.from(`${vid}${chapter[1]}`).toString('base64'), + })); + }); + + ctx.state.data = { + title: `轻小说文库 ${novel_name} 最新卷`, + link: novel_url, + item: item_list, + }; +}; + +const get = async (url) => { + const response = await got({ + method: 'get', + url, + responseType: 'buffer', + }); + + return iconv.decode(response.data, 'gbk'); +}; + +const format_description = (str) => + str + .split('\r\n') + .filter((line) => line.trim()) + .map((line) => `

${line.trim()}

`) + .join('');