diff --git a/docs/bbs.md b/docs/bbs.md index 8a5f050113..e67b2d6e89 100644 --- a/docs/bbs.md +++ b/docs/bbs.md @@ -30,6 +30,16 @@ pageClass: routes +### 通用子版块-支持 Cookie + + + +| Discuz X 系列 | Discuz 7.x 系列 | +| ------------- | --------------- | +| x | 7 | + + + ## MCBBS ### 版块 diff --git a/docs/en/bbs.md b/docs/en/bbs.md index 1b6caa887e..91931aaf26 100644 --- a/docs/en/bbs.md +++ b/docs/en/bbs.md @@ -19,3 +19,13 @@ pageClass: routes | x | 7 | + +### General Subforum - Support cookie + + + +| Discuz X Series | Discuz 7.x Series | +| --------------- | ----------------- | +| x | 7 | + + diff --git a/docs/en/install/README.md b/docs/en/install/README.md index 26a498e2f7..aac07966e9 100644 --- a/docs/en/install/README.md +++ b/docs/en/install/README.md @@ -372,3 +372,7 @@ Access control includes a whitelist and a blacklist, support IP and route, use ` - `NHENTAI_USERNAME`: nhentai username or email - `NHENTAI_PASSWORD`: nhentai password + +- discuz cookies + + - `DISCUZ_COOKIE_{cid}`: Cookie of a forum powered by discuz, cid can be anything from 00 to 99. When visiting route discuz, using cid to specify this cookie. diff --git a/docs/install/README.md b/docs/install/README.md index 27ba24730f..d241e9faa2 100644 --- a/docs/install/README.md +++ b/docs/install/README.md @@ -409,3 +409,7 @@ RSSHub 支持 `memory` 和 `redis` 两种缓存方式 - `NHENTAI_USERNAME`: nhentai 用户名或邮箱 - `NHENTAI_PASSWORD`: nhentai 密码 + +- discuz cookies 设定 + + - `DISCUZ_COOKIE_{cid}`: 某 Discuz 驱动的论坛,用户注册后的 Cookie 值 , cid 可自由设定,取值范围[00, 99], 使用 discuz 通用路由时, 通过指定 cid 来调用该 cookie diff --git a/lib/config.js b/lib/config.js index fd7e96935a..71e0a32fd0 100644 --- a/lib/config.js +++ b/lib/config.js @@ -6,6 +6,7 @@ const calculateValue = () => { const bilibili_cookies = {}; const twitter_tokens = {}; const email_config = {}; + const discuz_cookies = {}; for (const name in envs) { if (name.startsWith('BILIBILI_COOKIE_')) { @@ -17,6 +18,9 @@ const calculateValue = () => { } else if (name.startsWith('EMAIL_CONFIG_')) { const id = name.slice(13); email_config[id] = envs[name]; + } else if (name.startsWith('DISCUZ_COOKIE_')) { + const cid = name.slice(14); + discuz_cookies[cid] = envs[name]; } } @@ -117,6 +121,9 @@ const calculateValue = () => { username: envs.NHENTAI_USERNAME, password: envs.NHENTAI_PASSWORD, }, + discuz: { + cookies: discuz_cookies, + }, }; }; calculateValue(); diff --git a/lib/router.js b/lib/router.js index 7bd7e9177e..1f0d4052ed 100644 --- a/lib/router.js +++ b/lib/router.js @@ -2166,6 +2166,7 @@ router.get('/gbcc/trust', require('./routes/gbcc/trust')); router.get('/apnews/topics/:topic', require('./routes/apnews/topics')); // discuz +router.get('/discuz/:ver([7|x])/:cid([0-9]{2})/:link(.*)', require('./routes/discuz/discuz')); router.get('/discuz/:ver([7|x])/:link(.*)', require('./routes/discuz/discuz')); router.get('/discuz/:link(.*)', require('./routes/discuz/discuz')); diff --git a/lib/routes/discuz/discuz.js b/lib/routes/discuz/discuz.js index a14ec0c9a1..23a421d1fc 100644 --- a/lib/routes/discuz/discuz.js +++ b/lib/routes/discuz/discuz.js @@ -2,9 +2,10 @@ const got = require('@/utils/got'); const cheerio = require('cheerio'); const iconv = require('iconv-lite'); const dateUtil = require('@/utils/date'); +const config = require('@/config').value; // discuz 7.x 与 discuz x系列 通用文章内容抓取 -async function load(baseUrl, itemLink, ctx, charset) { +async function load(baseUrl, itemLink, ctx, charset, header) { // 处理相对链接 if (itemLink) { if (baseUrl && !baseUrl.match(/^https?:\/\//)) { @@ -25,9 +26,25 @@ async function load(baseUrl, itemLink, ctx, charset) { // 处理编码问题 let responseData; if (charset === 'utf-8') { - responseData = (await got.get(itemLink)).data; + responseData = ( + await got({ + method: 'get', + url: itemLink, + headers: header, + }) + ).data; } else { - responseData = iconv.decode((await got.get({ url: itemLink, responseType: 'buffer' })).data, charset); + responseData = iconv.decode( + ( + await got({ + method: 'get', + url: itemLink, + responseType: 'buffer', + headers: header, + }) + ).data, + charset + ); } if (!responseData) { const description = '获取详细内容失败'; @@ -45,9 +62,21 @@ async function load(baseUrl, itemLink, ctx, charset) { module.exports = async (ctx) => { let link = ctx.params.link; const ver = ctx.params.ver ? ctx.params.ver.toUpperCase() : undefined; + const cid = ctx.params.cid; link = link.replace(/:\/\//, ':/').replace(/:\//, '://'); - - const response = await got.get(link); + const cookie = cid === undefined ? '' : config.discuz.cookies[cid]; + if (cookie === undefined) { + throw Error('缺少对应论坛的cookie.'); + } + const header = { + Cookie: cookie, + Referer: link, + }; + const response = await got({ + method: 'get', + url: link, + headers: header, + }); const contentType = response.headers['content-type'] || ''; // 若没有指定编码,则默认utf-8 let charset = 'utf-8'; @@ -59,7 +88,22 @@ module.exports = async (ctx) => { .toLowerCase(); } } - const responseData = charset === 'utf-8' ? response.data : iconv.decode((await got.get({ url: link, responseType: 'buffer' })).data, charset); + const responseData = + charset === 'utf-8' + ? response.data + : iconv.decode( + ( + await got({ + method: 'get', + url: link, + responseType: 'buffer', + headers: { + Cookie: cookie, + }, + }) + ).data, + charset + ); const $ = cheerio.load(responseData); const title = $('head > title').text(); const version = ver ? 'DISCUZ! ' + ver : $('head > meta[name=generator]').attr('content'); @@ -67,7 +111,7 @@ module.exports = async (ctx) => { if (version.toUpperCase().startsWith('DISCUZ! 7')) { // discuz 7.x 系列 // 支持全文抓取,限制抓取页面5个 - const list = $('tbody[id^="normalthread"] tr') + const list = $('tbody[id^="normalthread"] > tr') .slice(0, 5) .get(); process = await Promise.all( @@ -79,14 +123,14 @@ module.exports = async (ctx) => { link: itemLink, pubDate: dateUtil(item.find('td.author em').text()), }; - const detail = await load(link, itemLink, ctx, charset); + const detail = await load(link, itemLink, ctx, charset, header); return Promise.resolve(Object.assign({}, single, detail)); }) ); } else if (version.toUpperCase().startsWith('DISCUZ! X')) { // discuz X 系列 // 支持全文抓取,限制抓取页面5个 - const list = $('tbody[id^="normalthread"] tr') + const list = $('tbody[id^="normalthread"] > tr') .slice(0, 5) .get(); process = await Promise.all( @@ -103,7 +147,7 @@ module.exports = async (ctx) => { .text() ), }; - const detail = await load(link, itemLink, ctx, charset); + const detail = await load(link, itemLink, ctx, charset, header); return Promise.resolve(Object.assign({}, single, detail)); }) );