From 2bd8e4842a7c45f615f2183b83fe1fc48bd810d7 Mon Sep 17 00:00:00 2001 From: Junk_Chen <38450642+monologconnor@users.noreply.github.com> Date: Mon, 15 May 2023 23:04:59 +0800 Subject: [PATCH] =?UTF-8?q?feat(route):=20=E5=BE=AE=E5=8D=9A=E8=87=AA?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=88=86=E7=BB=84(=E4=BD=BF=E7=94=A8Cookie)?= =?UTF-8?q?=20(#12514)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * change route 'weibo/user' to fit api could be opened with Share(third-party android weibo clent) * update weibo group route using cookies approach * fix typo * code optimization for /weibo/group; docs for /weibo/group * try fix ESLint error * fix typo and code optimization * fix missing ',' * '/weibo/group' throw error when the cookie is not set --- .gitignore | 2 + docs/install/README.md | 8 +++ docs/social-media.md | 16 ++++++ lib/config.js | 1 + lib/v2/weibo/group.js | 99 ++++++++++++++++++++++++++++++++++++++ lib/v2/weibo/maintainer.js | 1 + lib/v2/weibo/router.js | 1 + lib/v2/weibo/user.js | 2 +- 8 files changed, 129 insertions(+), 1 deletion(-) create mode 100644 lib/v2/weibo/group.js diff --git a/.gitignore b/.gitignore index 472cbac3a64575..0f1bcc4871414c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ .vercel .vscode .yarn +.yarnrc.yml +.pnp* *.swp *.iml diff --git a/docs/install/README.md b/docs/install/README.md index 029d0626ef96d7..ed8fc474efb4f8 100644 --- a/docs/install/README.md +++ b/docs/install/README.md @@ -943,6 +943,14 @@ RSSHub 支持使用访问密钥 / 码,白名单和黑名单三种方式进行 - `WEIBO_APP_SECRET`: 微博 App Secret - `WEIBO_REDIRECT_URL`: 微博登录授权回调地址,默认为 `RSSHub 地址/weibo/timeline/0`,自定义回调地址请确保最后可以转跳到 `RSSHub 地址/weibo/timeline/0?code=xxx` +- 微博 自定义分组 + + - `WEIBO_COOKIES`: 用户访问网页微博时所使用的cookie, 获取方式: + 1. 打开并登录 (确保打开页面为手机版, 如果强制跳转电脑端可尝试使用可更改UserAgent的浏览器插件) + 2. 按下`F12`打开控制台,切换至`Network(网络)`面板 + 3. 在该网页切换至任意关注分组, 并在面板打开最先捕获到的请求(该情形下捕获到的请求路径应包含`/feed/group`) + 4. 查看该请求的`Headers(请求头)`, 找到`Cookie`字段并复制内容 + - 小宇宙:需要 App 登陆后抓包获取相应数据。 - `XIAOYUZHOU_ID`: 即数据包中的 `x-jike-device-id`。 diff --git a/docs/social-media.md b/docs/social-media.md index e0c98f3d7357f3..21967e202d058c 100644 --- a/docs/social-media.md +++ b/docs/social-media.md @@ -1574,6 +1574,22 @@ rule +### 自定义分组 + + + +::: warning 注意 + +由于微博官方未提供自定义分组相关api, 此方案必须使用用户`Cookie`进行抓取 + +因微博cookies的过期与更新方案未经验证, 部署一次Cookie的有效时长未知 + +微博用户Cookie的配置可参照部署文档 + +::: + + + ## 微博绿洲 ### 用户 diff --git a/lib/config.js b/lib/config.js index 2b693bcbc5a9f3..ce8131acd7984b 100644 --- a/lib/config.js +++ b/lib/config.js @@ -277,6 +277,7 @@ const calculateValue = () => { weibo: { app_key: envs.WEIBO_APP_KEY, app_secret: envs.WEIBO_APP_SECRET, + cookies: envs.WEIBO_COOKIES, redirect_url: envs.WEIBO_REDIRECT_URL, }, wenku8: { diff --git a/lib/v2/weibo/group.js b/lib/v2/weibo/group.js new file mode 100644 index 00000000000000..71977d4fc8961d --- /dev/null +++ b/lib/v2/weibo/group.js @@ -0,0 +1,99 @@ +const querystring = require('querystring'); +const got = require('@/utils/got'); +const config = require('@/config').value; +const weiboUtils = require('./utils'); +const { fallback, queryToBoolean } = require('@/utils/readable-social'); + +module.exports = async (ctx) => { + if (!config.weibo_cookies) { + throw 'Weibo Group Timeline is not available due to the absense of [Weibo Cookies]. Check relevant config tutorial'; + } + + const gid = ctx.params.gid; + const groupName = ctx.params.gname || '微博分组'; + let displayVideo = '1'; + let displayArticle = '0'; + let displayComments = '0'; + if (ctx.params.routeParams) { + if (ctx.params.routeParams === '1' || ctx.params.routeParams === '0') { + displayVideo = ctx.params.routeParams; + } else { + const routeParams = querystring.parse(ctx.params.routeParams); + displayVideo = fallback(undefined, queryToBoolean(routeParams.displayVideo), true) ? '1' : '0'; + displayArticle = fallback(undefined, queryToBoolean(routeParams.displayArticle), false) ? '1' : '0'; + displayComments = fallback(undefined, queryToBoolean(routeParams.displayComments), false) ? '1' : '0'; + } + } + + const responseData = await ctx.cache.tryGet( + `weibo:group:index:${gid}`, + async() => { + const _r = await got({ + method: 'get', + url: `https://m.weibo.cn/feed/group?gid=${gid}`, + headers: { + Referer: `https://m.weibo.cn/`, + 'MWeibo-Pwa': 1, + 'X-Requested-With': 'XMLHttpRequest', + 'Cookie': config.weibo.cookies, + } + }); + return _r.data.data; + }, + config.cache.routeExpire, + false + ); + + const resultItems = await Promise.all( + responseData.statuses.map(async (item) => { + const retweet = item.retweeted_status; + if (retweet && retweet.isLongText) { + const retweetData = await ctx.cache.tryGet(`weibo:retweeted:${retweet.user.id}:${retweet.bid}`, () => weiboUtils.getShowData(retweet.user.id, retweet.bid)); + if (retweetData !== undefined && retweetData.text) { + item.retweeted_status.text = retweetData.text; + } + } + + const link = `https://m.weibo.cn/status/${item.bid}`; + const formatExtended = weiboUtils.formatExtended(ctx, item); + let description = formatExtended.description; + const title = formatExtended.title; + const pubDate = item.created_at; + + if (displayVideo === '1') { + if (item.retweeted_status) { + description = weiboUtils.formatVideo(description, item.retweeted_status); + } else { + description = weiboUtils.formatVideo(description, item); + } + } + + if (displayComments === '1') { + description = await weiboUtils.formatComments(ctx, description, item); + } + + if (displayArticle === '1') { + if (item.retweeted_status) { + description = await weiboUtils.formatArticle(ctx, description, item.retweeted_status); + } else { + description = await weiboUtils.formatArticle(ctx, description, item); + } + } + + return { + title, + description, + link, + pubDate, + author: item.user.screen_name + }; + }) + ); + + ctx.state.data = weiboUtils.sinaimgTvax({ + title: groupName, + link: `https://weibo.com/mygroups?gid=${gid}`, + description: '微博自定义分组', + item: resultItems, + }); +}; diff --git a/lib/v2/weibo/maintainer.js b/lib/v2/weibo/maintainer.js index 1d7d2a244ba961..afbc9f9a982533 100644 --- a/lib/v2/weibo/maintainer.js +++ b/lib/v2/weibo/maintainer.js @@ -1,4 +1,5 @@ module.exports = { + '/group/:gid/:gname?/:routeParams?': ['monologconnor'], '/keyword/:keyword/:routeParams?': ['DIYgod'], '/oasis/user/:userid': ['kt286'], '/search/hot': ['xyqfer'], diff --git a/lib/v2/weibo/router.js b/lib/v2/weibo/router.js index 2936afe92a727a..ec4a2dc8601f3d 100644 --- a/lib/v2/weibo/router.js +++ b/lib/v2/weibo/router.js @@ -1,4 +1,5 @@ module.exports = (router) => { + router.get('/group/:gid/:gname?/:routeParams?', require('./group')); router.get('/keyword/:keyword/:routeParams?', require('./keyword')); router.get('/oasis/user/:userid', require('./oasis/user')); router.get('/search/hot', require('./search/hot')); diff --git a/lib/v2/weibo/user.js b/lib/v2/weibo/user.js index 9b3edd945e23cf..dead03f4887dca 100644 --- a/lib/v2/weibo/user.js +++ b/lib/v2/weibo/user.js @@ -94,7 +94,7 @@ module.exports = async (ctx) => { } } - const link = `https://weibo.com/${uid}/${item.mblog.bid}`; + const link = `https://m.weibo.cn/status/${item.mblog.bid}`; const formatExtended = weiboUtils.formatExtended(ctx, item.mblog); let description = formatExtended.description; const title = formatExtended.title;