${details}
${medias}
作者:${author_name}
`, description: art(path.join(__dirname, '../templates/forum.art'), { details, medias, diff --git a/lib/v2/cts/maintainer.js b/lib/v2/cts/maintainer.js new file mode 100644 index 0000000000..5c4aa089da --- /dev/null +++ b/lib/v2/cts/maintainer.js @@ -0,0 +1,3 @@ +module.exports = { + '/:category': ['miles170'], +}; diff --git a/lib/v2/cts/news.js b/lib/v2/cts/news.js new file mode 100644 index 0000000000..e77d0ae898 --- /dev/null +++ b/lib/v2/cts/news.js @@ -0,0 +1,40 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); +const asyncPool = require('tiny-async-pool'); + +module.exports = async (ctx) => { + const category = ctx.params.category; + const currentUrl = `https://news.cts.com.tw/${category}/index.html`; + const response = await got(currentUrl); + const $ = cheerio.load(response.data); + const items = []; + for await (const data of asyncPool(5, $('#newslist-top a[title]').slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 20), (item) => { + item = $(item); + const link = item.attr('href'); + return ctx.cache.tryGet(link, async () => { + const response = await got(link); + const $ = cheerio.load(response.data); + const author = $('.artical-content p:eq(0)').text().trim(); + $('.artical-content p:eq(0), .artical-content .flexbox').remove(); + + return { + title: item.attr('title'), + author, + description: $('.artical-content').html(), + category: $('meta[property="article:section"]').attr('content'), + pubDate: parseDate($('meta[property="article:published_time"]').attr('content')), + link, + }; + }); + })) { + items.push(data); + } + + ctx.state.data = { + title: $('title').text(), + link: currentUrl, + description: $('meta[name="description"]').attr('content'), + item: items, + }; +}; diff --git a/lib/v2/cts/radar.js b/lib/v2/cts/radar.js new file mode 100644 index 0000000000..6dc1db9275 --- /dev/null +++ b/lib/v2/cts/radar.js @@ -0,0 +1,13 @@ +module.exports = { + 'cts.com.tw': { + _name: '華視', + news: [ + { + title: '新聞', + docs: 'https://docs.rsshub.app/traditional-media.html#hua-shi-xin-wen', + source: '/:category/index.html', + target: '/cts/:category', + }, + ], + }, +}; diff --git a/lib/v2/cts/router.js b/lib/v2/cts/router.js new file mode 100644 index 0000000000..b9311da838 --- /dev/null +++ b/lib/v2/cts/router.js @@ -0,0 +1,3 @@ +module.exports = function (router) { + router.get('/:category', require('./news')); +}; diff --git a/lib/v2/greasyfork/maintainer.js b/lib/v2/greasyfork/maintainer.js new file mode 100644 index 0000000000..0eb4f31b83 --- /dev/null +++ b/lib/v2/greasyfork/maintainer.js @@ -0,0 +1,3 @@ +module.exports = { + '/:language/:domain?': ['imlonghao', 'miles170'], +}; diff --git a/lib/v2/greasyfork/radar.js b/lib/v2/greasyfork/radar.js new file mode 100644 index 0000000000..ee48265de2 --- /dev/null +++ b/lib/v2/greasyfork/radar.js @@ -0,0 +1,13 @@ +module.exports = { + 'greasyfork.org': { + _name: 'Greasy Fork', + '.': [ + { + title: 'User scripts', + docs: 'https://docs.rsshub.app/program-update.html#greasy-fork', + source: ['/:language', '/:language/scripts/by-site/:domain?'], + target: '/greasyfork/:language/:domain?', + }, + ], + }, +}; diff --git a/lib/v2/greasyfork/router.js b/lib/v2/greasyfork/router.js new file mode 100644 index 0000000000..32144b2830 --- /dev/null +++ b/lib/v2/greasyfork/router.js @@ -0,0 +1,3 @@ +module.exports = (router) => { + router.get('/:language/:domain?', require('./scripts')); +}; diff --git a/lib/routes/greasyfork/scripts.js b/lib/v2/greasyfork/scripts.js similarity index 86% rename from lib/routes/greasyfork/scripts.js rename to lib/v2/greasyfork/scripts.js index cee531a42e..b3d0659265 100644 --- a/lib/routes/greasyfork/scripts.js +++ b/lib/v2/greasyfork/scripts.js @@ -7,10 +7,10 @@ module.exports = async (ctx) => { const domain = ctx.params.domain; const filter_locale = ctx.params.language === 'all' ? 0 : 1; const url = domain ? `by-site/${domain}` : ''; - + const currentUrl = `https://greasyfork.org/${language}/scripts/${url}`; const res = await got({ method: 'get', - url: `https://greasyfork.org/${language}/scripts/${url}`, + url: currentUrl, searchParams: queryString.stringify({ filter_locale, sort: 'updated', @@ -21,12 +21,12 @@ module.exports = async (ctx) => { ctx.state.data = { title: $('title').first().text(), - link: `https://greasyfork.org/${language}/scripts/${url}`, + link: currentUrl, description: $('meta[name=description]').attr('content'), item: list && list - .map((index, item) => { + .map((_, item) => { item = $(item); return { title: item.find('a').text(), diff --git a/lib/v2/lovelive-anime/maintainer.js b/lib/v2/lovelive-anime/maintainer.js index 4dc741ff71..1f883a6c90 100644 --- a/lib/v2/lovelive-anime/maintainer.js +++ b/lib/v2/lovelive-anime/maintainer.js @@ -1,3 +1,4 @@ module.exports = { '/news/:option?': ['axojhf'], + '/topics/:abbr/:category?': ['axojhf'], }; diff --git a/lib/v2/lovelive-anime/radar.js b/lib/v2/lovelive-anime/radar.js index fa57df0d35..e64c194838 100644 --- a/lib/v2/lovelive-anime/radar.js +++ b/lib/v2/lovelive-anime/radar.js @@ -3,11 +3,20 @@ module.exports = { _name: 'Love Live 官网', www: [ { - title: '最新NEWS', - docs: 'https://docs.rsshub.app/anime.html#lovelive-anime', - source: ['/'], + title: '最新 NEWS', + docs: 'https://docs.rsshub.app/anime.html#lovelive-anime-love-live-guan-wang-zui-xin-news', + source: ['/', '/news'], target: '/lovelive-anime/news', }, + { + title: '分类 Topics', + docs: 'https://docs.rsshub.app/anime.html#lovelive-anime-love-live-guan-wang-fen-lei-topics', + source: ['/:abbr/topics/', '/:abbr/topics.php'], + target: (params, url) => { + const cat = url.match(/\?cat=(.*)/); + return `/lovelive-anime/topics/${params.abbr}/${null !== cat && cat.length === 2 ? cat[1] : ''}`; + }, + }, ], }, }; diff --git a/lib/v2/lovelive-anime/router.js b/lib/v2/lovelive-anime/router.js index c7bbc2e167..0734739f7b 100644 --- a/lib/v2/lovelive-anime/router.js +++ b/lib/v2/lovelive-anime/router.js @@ -1,3 +1,4 @@ module.exports = (router) => { router.get('/news/:option?', require('./news')); + router.get('/topics/:abbr/:category?/:option?', require('./topics')); }; diff --git a/lib/v2/lovelive-anime/topics.js b/lib/v2/lovelive-anime/topics.js new file mode 100644 index 0000000000..01a65f9401 --- /dev/null +++ b/lib/v2/lovelive-anime/topics.js @@ -0,0 +1,84 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const path = require('path'); +const { art } = require('@/utils/render'); +const { parseDate } = require('@/utils/parse-date'); +const renderDescription = (desc) => art(path.join(__dirname, 'templates/description.art'), desc); + +module.exports = async (ctx) => { + const abbr = ctx.params.abbr; + const rootUrl = `https://www.lovelive-anime.jp/${abbr}`; + const topicsUrlPart = 'yuigaoka' === abbr ? 'topics/' : 'topics.php'; + const baseUrl = `${rootUrl}/${'yuigaoka' === abbr ? 'topics/' : ''}`; + const abbrDetail = { + otonokizaka: 'ラブライブ!', + uranohoshi: 'サンシャイン!!', + nijigasaki: '虹ヶ咲学園', + yuigaoka: 'スーパースター!!', + }; + let url; + + if (ctx.params.hasOwnProperty('category') && ctx.params.category !== 'detail') { + url = `${rootUrl}/${topicsUrlPart}?cat=${ctx.params.category}`; + } else { + url = `${rootUrl}/${topicsUrlPart}`; + } + + const response = await got(url); + + const $ = cheerio.load(response.data); + + const categoryName = 'uranohoshi' === abbr ? $('div.llbox > p').text() : $('div.category_title > h2').text(); + + let items = $('ul.listbox > li') + .map((_, item) => { + item = $(item); + + const link = `${baseUrl}${item.find('div > a').attr('href')}`; + const pubDate = parseDate(item.find('a > p.date').text(), 'YYYY/MM/DD'); + const title = item.find('a > p.title').text(); + const category = item.find('a > p.category').text(); + const imglink = `${baseUrl}${ + item + .find('a > img') + .attr('style') + .match(/background-image:url\((.*)\)/)[1] + }`; + + return { + link, + pubDate, + title, + category, + description: renderDescription({ + title, + imglink, + }), + }; + }) + .get(); + + if (ctx.params.option === 'detail' || ctx.params.category === 'detail') { + items = await Promise.all( + items.map((item) => + ctx.cache.tryGet(item.link, async () => { + const detailResp = await got(item.link); + const $ = cheerio.load(detailResp.data); + + const content = $('div.p-page__detail.p-article'); + for (const v of content.find('img')) { + v.attribs.src = `${baseUrl}${v.attribs.src}`; + } + item.description = content.html(); + return item; + }) + ) + ); + } + + ctx.state.data = { + title: `${categoryName} - ${abbrDetail[abbr]} - Love Live Official Website Topics`, + link: url, + item: items, + }; +}; diff --git a/lib/v2/nuaa/college/cae.js b/lib/v2/nuaa/college/cae.js new file mode 100644 index 0000000000..3f2dfa6c05 --- /dev/null +++ b/lib/v2/nuaa/college/cae.js @@ -0,0 +1,79 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); +const getCookie = require('../utils/pypasswaf'); +const host = 'https://cae.nuaa.edu.cn/'; + +const map = new Map([ + ['zhxw', { title: '综合新闻 | 南京航空航天大学自动化学院', suffix: '5399/list.htm' }], + ['dwxz', { title: '党委行政 | 南京航空航天大学自动化学院', suffix: '13266/list.htm' }], + ['rshz', { title: '人事/合作 | 南京航空航天大学自动化学院', suffix: '13267/list.htm' }], + ['yjs', { title: '研究生培养 | 南京航空航天大学自动化学院', suffix: '13271/list.htm' }], + ['bks', { title: '本科生培养 | 南京航空航天大学自动化学院', suffix: '13270/list.htm' }], + ['xsgz', { title: '学生工作 | 南京航空航天大学自动化学院', suffix: '13268/list.htm' }], + ['tzgg', { title: '通知公告 | 南京航空航天大学自动化学院', suffix: '13264/list.htm' }], + ['xsxx', { title: '学术信息 | 南京航空航天大学自动化学院', suffix: '13265/list.htm' }], + ['dbgg', { title: '答辩公告 | 南京航空航天大学自动化学院', suffix: 'dbgg/list.htm' }], +]); + +module.exports = async (ctx) => { + const type = ctx.params.type; + const suffix = map.get(type).suffix; + const getDescription = Boolean(ctx.params.getDescription) || false; + const link = new URL(suffix, host).href; + const cookie = await getCookie(host); + const gotConfig = { + headers: { + cookie, + }, + }; + const response = await got(link, gotConfig); + const $ = cheerio.load(response.data); + + const list = $('#wp_news_w6 ul li') + .slice(0, 10) + .map(function () { + const info = { + title: $(this).find('a').text(), + link: $(this).find('a').attr('href'), + date: $(this).find('span').text(), + }; + return info; + }) + .get(); + + const out = await Promise.all( + list.map(async (info) => { + const title = info.title || 'tzgg'; + const date = info.date; + const itemUrl = new URL(info.link, host).href; + let description = title + '画师:${illust.user.name} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}
${images.join('')}`, link: `https://www.pixiv.net/artworks/${illust.id}`, }; diff --git a/lib/routes/pixiv/constants.js b/lib/v2/pixiv/constants.js similarity index 100% rename from lib/routes/pixiv/constants.js rename to lib/v2/pixiv/constants.js diff --git a/lib/routes/pixiv/illustfollow.js b/lib/v2/pixiv/illustfollow.js similarity index 84% rename from lib/routes/pixiv/illustfollow.js rename to lib/v2/pixiv/illustfollow.js index 0c37c0dba4..a40b73586d 100644 --- a/lib/routes/pixiv/illustfollow.js +++ b/lib/v2/pixiv/illustfollow.js @@ -1,15 +1,16 @@ -const getToken = require('./token'); +const { getToken } = require('./token'); const getIllustFollows = require('./api/getIllustFollows'); const config = require('@/config').value; const pixivUtils = require('./utils'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { if (!config.pixiv || !config.pixiv.refreshToken) { throw 'pixiv RSS is disabled due to the lack of relevant config'; } - const token = await getToken(); - if (!(await getToken())) { + const token = await getToken(ctx.cache.tryGet); + if (!token) { throw 'pixiv not login'; } @@ -24,7 +25,7 @@ module.exports = async (ctx) => { return { title: illust.title, author: illust.user.name, - pubDate: new Date(illust.create_date).toUTCString(), + pubDate: parseDate(illust.create_date), description: `画师:${illust.user.name} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}
${images.join('')}`, link: `https://www.pixiv.net/artworks/${illust.id}`, }; diff --git a/lib/v2/pixiv/maintainer.js b/lib/v2/pixiv/maintainer.js new file mode 100644 index 0000000000..c609eeb9a0 --- /dev/null +++ b/lib/v2/pixiv/maintainer.js @@ -0,0 +1,8 @@ +module.exports = { + '/ranking/:mode/:date?': ['EYHN'], + '/search/:keyword/:order?/:mode?': ['DIYgod'], + '/user/bookmarks/:id': ['EYHN'], + '/user/illustfollows': ['ClarkeCheng'], + '/user/novels/:id': ['TonyRL'], + '/user/:id': ['DIYgod'], +}; diff --git a/lib/v2/pixiv/novels.js b/lib/v2/pixiv/novels.js new file mode 100644 index 0000000000..44567f3b2c --- /dev/null +++ b/lib/v2/pixiv/novels.js @@ -0,0 +1,35 @@ +const got = require('@/utils/got'); +const { parseDate } = require('@/utils/parse-date'); +const baseUrl = 'https://www.pixiv.net'; + +module.exports = async (ctx) => { + const { id } = ctx.params; + const { data } = await got(`${baseUrl}/ajax/user/${id}/profile/all`); + + const items = [ + ...data.body.novelSeries.map((item) => ({ + title: item.title, + description: item.caption, + link: `https://www.pixiv.net/novel/series/${item.id}`, + author: item.userName, + pubDate: parseDate(item.createDate), + updated: parseDate(item.updateDate), + category: item.tags, + })), + ...data.body.pickup.map((item) => ({ + title: item.title, + description: item.description, + link: item.contentUrl, + author: item.userName, + pubDate: parseDate(item.createDate), + updated: parseDate(item.updateDate), + category: item.tags, + })), + ]; + + ctx.state.data = { + title: `${data.body.novelSeries[0].userName || data.body.pickup[0].userName} 的小说`, + link: `${baseUrl}/users/${id}/novels`, + item: items, + }; +}; diff --git a/lib/routes/pixiv/pixiv-got.js b/lib/v2/pixiv/pixiv-got.js similarity index 97% rename from lib/routes/pixiv/pixiv-got.js rename to lib/v2/pixiv/pixiv-got.js index 0fd73f9e9f..f562bc17fb 100644 --- a/lib/routes/pixiv/pixiv-got.js +++ b/lib/v2/pixiv/pixiv-got.js @@ -6,7 +6,7 @@ const pixivConfig = require('@/config').value.pixiv; async function dohResolve(name, jsonDohEndpoint) { try { - const response = await got.get(jsonDohEndpoint, { + const response = await got(jsonDohEndpoint, { searchParams: { name, type: 'A', diff --git a/lib/v2/pixiv/radar.js b/lib/v2/pixiv/radar.js new file mode 100644 index 0000000000..6b2229adbf --- /dev/null +++ b/lib/v2/pixiv/radar.js @@ -0,0 +1,43 @@ +module.exports = { + 'pixiv.net': { + _name: 'Pixiv', + www: [ + { + title: '用户收藏', + docs: 'https://docs.rsshub.app/social-media.html#pixiv', + source: '/users/:id/bookmarks/artworks', + target: '/pixiv/user/bookmarks/:id', + }, + { + title: '用户动态', + docs: 'https://docs.rsshub.app/social-media.html#pixiv', + source: '/users/:id', + target: '/pixiv/user/:id', + }, + { + title: '用户小说', + docs: 'https://docs.rsshub.app/social-media.html#pixiv', + source: '/users/:id/novels', + target: '/pixiv/user/novels/:id', + }, + { + title: '排行榜', + docs: 'https://docs.rsshub.app/social-media.html#pixiv', + source: '/ranking.php', + target: (params, url) => `/pixiv/ranking/${new URL(url).searchParams.get('mode') || 'daily'}`, + }, + { + title: '关键词', + docs: 'https://docs.rsshub.app/social-media.html#pixiv', + source: ['/tags/:keyword', '/tags/:keyword/:type?'], + target: (params, url) => `/pixiv/search/:keyword/${new URL(url).searchParams.get('order')}/${new URL(url).searchParams.get('mode')}`, + }, + { + title: '关注的新作品', + docs: 'https://docs.rsshub.app/social-media.html#pixiv', + source: '/bookmark_new_illust.php', + target: '/pixiv/user/illustfollows', + }, + ], + }, +}; diff --git a/lib/routes/pixiv/ranking.js b/lib/v2/pixiv/ranking.js similarity index 93% rename from lib/routes/pixiv/ranking.js rename to lib/v2/pixiv/ranking.js index b35b2bd592..ab1f139a70 100644 --- a/lib/routes/pixiv/ranking.js +++ b/lib/v2/pixiv/ranking.js @@ -1,7 +1,8 @@ -const getToken = require('./token'); +const { getToken } = require('./token'); const getRanking = require('./api/getRanking'); const config = require('@/config').value; const pixivUtils = require('./utils'); +const { parseDate } = require('@/utils/parse-date'); const titles = { day: 'pixiv 日排行', @@ -56,7 +57,7 @@ module.exports = async (ctx) => { const mode = alias[ctx.params.mode] ? alias[ctx.params.mode] : ctx.params.mode; const date = ctx.params.date ? new Date(ctx.params.date) : new Date(); - const token = await getToken(); + const token = await getToken(ctx.cache.tryGet); if (!token) { throw 'pixiv not login'; } @@ -75,7 +76,7 @@ module.exports = async (ctx) => { const images = pixivUtils.getImgs(illust); return { title: `#${index + 1} ${illust.title}`, - pubDate: new Date(illust.create_date).toUTCString(), + pubDate: parseDate(illust.create_date), description: `画师:${illust.user.name} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}
画师:${illust.user.name} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}
${images.join('')}`, link: `https://www.pixiv.net/artworks/${illust.id}`, }; diff --git a/lib/v2/pixiv/token.js b/lib/v2/pixiv/token.js new file mode 100644 index 0000000000..06911904ba --- /dev/null +++ b/lib/v2/pixiv/token.js @@ -0,0 +1,86 @@ +const config = require('@/config').value; +const logger = require('@/utils/logger'); +const got = require('./pixiv-got'); +const { maskHeader } = require('./constants'); + +let token = null; + +const authorizationInfo = { + client_id: 'MOBrBDS8blbauoSck0ZfDbtuzpyT', + client_secret: 'lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj', + hash_secret: '28c1fdd170a5204386cb1313c7077b34f83e4aaf4aa829ce78c231e05b0bae2c', +}; + +const refreshToken = (tryGet) => + tryGet( + 'pixiv:accessToken', + () => + got + .post('https://oauth.secure.pixiv.net/auth/token', { + form: { + ...authorizationInfo, + get_secure_url: 1, + grant_type: 'refresh_token', + refresh_token: config.pixiv.refreshToken, + }, + headers: { + ...maskHeader, + }, + responseType: 'json', + resolveBodyOnly: true, + }) + .catch((e) => { + logger.error('Pixiv refresh token failed.'); + logger.error(e); + }), + 3600, + false + ); + +async function getToken(tryGet) { + const result = await refreshToken(tryGet); + // let expireTime; + if (result && result.access_token) { + logger.debug('Pixiv refresh token success.'); + token = result.access_token; + // expireTime = result.expires_in; + } + // } else { + // expireTime = 30; + // logger.error(`Pixiv refresh token failed, retry in ${expireTime} seconds.`); + // } + // If is package, the mock server should be closed after request, needn't to refresh + // if (!config.isPackage) { + // setTimeout(tickToken, expireTime * 1000); + // } + return token; +} + +module.exports = { + getToken, +}; + +// let tickTokenStarted = false; + +// async function startTickToken(tryGet) { +// if (!tickTokenStarted) { +// // 如果tickToken没启动 +// tickTokenStarted = true; +// await tickToken(tryGet); // 启动tickToken +// } +// } + +// async function waitForToken() { +// while (!token) { +// // eslint-disable-next-line no-await-in-loop +// await new Promise((resolve) => setTimeout(resolve, 0)); +// } +// return token; +// } + +// module.exports = async (tryGet) => { +// await startTickToken(tryGet); +// return waitForToken(); +// }; + +// module.exports.tickToken = tickToken; diff --git a/lib/routes/pixiv/user.js b/lib/v2/pixiv/user.js similarity index 85% rename from lib/routes/pixiv/user.js rename to lib/v2/pixiv/user.js index e9ff62b09f..e3893ec8cf 100644 --- a/lib/routes/pixiv/user.js +++ b/lib/v2/pixiv/user.js @@ -1,7 +1,8 @@ -const getToken = require('./token'); +const { getToken } = require('./token'); const getIllusts = require('./api/getIllusts'); const config = require('@/config').value; const pixivUtils = require('./utils'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { if (!config.pixiv || !config.pixiv.refreshToken) { @@ -9,7 +10,7 @@ module.exports = async (ctx) => { } const id = ctx.params.id; - const token = await getToken(); + const token = await getToken(ctx.cache.tryGet); if (!token) { throw 'pixiv not login'; } @@ -28,7 +29,7 @@ module.exports = async (ctx) => { return { title: illust.title, author: username, - pubDate: new Date(illust.create_date).toUTCString(), + pubDate: parseDate(illust.create_date), description: `画师:${username} - 阅览数:${illust.total_view} - 收藏数:${illust.total_bookmarks}
${images.join('')}`, link: `https://www.pixiv.net/artworks/${illust.id}`, }; diff --git a/lib/routes/pixiv/utils.js b/lib/v2/pixiv/utils.js similarity index 100% rename from lib/routes/pixiv/utils.js rename to lib/v2/pixiv/utils.js diff --git a/lib/v2/qidian/author.js b/lib/v2/qidian/author.js new file mode 100644 index 0000000000..8b515f0da2 --- /dev/null +++ b/lib/v2/qidian/author.js @@ -0,0 +1,41 @@ +const got = require('@/utils/got'); +const cheerio = require('cheerio'); +const { parseDate, parseRelativeDate } = require('@/utils/parse-date'); +const { art } = require('@/utils/render'); +const path = require('path'); +const timezone = require('@/utils/timezone'); + +module.exports = async (ctx) => { + const id = ctx.params.id; + const rootUrl = 'https://my.qidian.com'; + const currentUrl = `${rootUrl}/author/${id}/`; + const response = await got(currentUrl); + const $ = cheerio.load(response.data); + const authorName = $('.header-msg h1').contents().first().text().trim(); + const items = $('.author-work .author-item') + .toArray() + .map((item) => { + item = $(item); + const messageItem = item.find('.author-item-msg'); + const updatedDate = messageItem.find('.author-item-update span').text().replace('·', '').trim(); + + return { + title: messageItem.find('.author-item-title').text().trim(), + author: authorName, + category: messageItem.find('.author-item-exp a').first().text().trim(), + description: art(path.join(__dirname, 'templates/description.art'), { + description: messageItem.find('.author-item-update a').attr('title'), + image: item.find('a img').attr('src'), + }), + pubDate: timezone(/(今|昨)/.test(updatedDate) ? parseRelativeDate(updatedDate) : parseDate(updatedDate, 'YYYY-MM-DD HH:mm'), +8), + link: messageItem.find('.author-item-update a').attr('href'), + }; + }); + + ctx.state.data = { + title: `${authorName} - 起点中文网`, + description: $('.header-msg-desc').text().trim(), + link: currentUrl, + item: items, + }; +}; diff --git a/lib/routes/qidian/chapter.js b/lib/v2/qidian/chapter.js similarity index 75% rename from lib/routes/qidian/chapter.js rename to lib/v2/qidian/chapter.js index a84cebbce9..f1f806386a 100644 --- a/lib/routes/qidian/chapter.js +++ b/lib/v2/qidian/chapter.js @@ -1,13 +1,11 @@ const got = require('@/utils/got'); const cheerio = require('cheerio'); +const { parseDate } = require('@/utils/parse-date'); module.exports = async (ctx) => { const id = ctx.params.id; - const response = await got({ - method: 'get', - url: `https://book.qidian.com/info/${id}#Catalog`, - }); + const response = await got(`https://book.qidian.com/info/${id}/#Catalog`); const $ = cheerio.load(response.data); const name = $('.book-info>h1>em').text(); @@ -15,10 +13,7 @@ module.exports = async (ctx) => { const csrfToken = response.headers['set-cookie'].find((s) => s.startsWith('_csrfToken=')).split(';')[0]; - const chapters_response = await got({ - method: 'get', - url: `https://book.qidian.com/ajax/book/category?${csrfToken}&bookId=${id}`, - }); + const chapters_response = await got(`https://book.qidian.com/ajax/book/category?${csrfToken}&bookId=${id}`); const chapter_item = []; for (let i = 0; i < chapters_response.data.data.vs.length; i++) { @@ -27,7 +22,7 @@ module.exports = async (ctx) => { const chapter = chapters[j]; chapter_item.push({ title: chapter.cN, - pubDate: new Date(chapter.uT).toUTCString(), + pubDate: parseDate(chapter.uT), link: `https://vipreader.qidian.com/chapter/${id}/${chapter.id}`, }); } diff --git a/lib/routes/qidian/forum.js b/lib/v2/qidian/forum.js similarity index 93% rename from lib/routes/qidian/forum.js rename to lib/v2/qidian/forum.js index 177119e46b..8911e247a8 100644 --- a/lib/routes/qidian/forum.js +++ b/lib/v2/qidian/forum.js @@ -7,9 +7,7 @@ module.exports = async (ctx) => { const url = `https://forum.qidian.com/NewForum/List.aspx?BookId=${id}`; - const forum_response = await got({ - method: 'get', - url, + const forum_response = await got(url, { headers: { Referer: `https://book.qidian.com/info/${id}`, }, diff --git a/lib/routes/qidian/free-next.js b/lib/v2/qidian/free-next.js similarity index 93% rename from lib/routes/qidian/free-next.js rename to lib/v2/qidian/free-next.js index cbcb1abaa4..5643035c4c 100644 --- a/lib/routes/qidian/free-next.js +++ b/lib/v2/qidian/free-next.js @@ -13,10 +13,7 @@ module.exports = async (ctx) => { title = '起点中文网'; } - const response = await got({ - method: 'get', - url: link, - }); + const response = await got(link); const $ = cheerio.load(response.data); const list = $('div.other-rec-wrap li'); diff --git a/lib/routes/qidian/free.js b/lib/v2/qidian/free.js similarity index 88% rename from lib/routes/qidian/free.js rename to lib/v2/qidian/free.js index 01fe3d0d47..33253d3dca 100644 --- a/lib/routes/qidian/free.js +++ b/lib/v2/qidian/free.js @@ -1,5 +1,6 @@ const got = require('@/utils/got'); const cheerio = require('cheerio'); +const parseDate = require('@/utils/date'); module.exports = async (ctx) => { const type = ctx.params.type; @@ -13,10 +14,7 @@ module.exports = async (ctx) => { title = '起点中文网'; } - const response = await got({ - method: 'get', - url: link, - }); + const response = await got(link); const $ = cheerio.load(response.data); const list = $('#limit-list li'); @@ -31,7 +29,7 @@ module.exports = async (ctx) => { return { title: item.find('.book-mid-info h4 a').text(), description: img + rank + update + '{{ description }}
+{{ if image }} +