mirror of
https://github.com/DIYgod/RSSHub.git
synced 2025-12-09 23:00:48 +08:00
feat(route): 微博自定义分组(使用Cookie) (#12514)
* 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
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -7,6 +7,8 @@
|
|||||||
.vercel
|
.vercel
|
||||||
.vscode
|
.vscode
|
||||||
.yarn
|
.yarn
|
||||||
|
.yarnrc.yml
|
||||||
|
.pnp*
|
||||||
|
|
||||||
*.swp
|
*.swp
|
||||||
*.iml
|
*.iml
|
||||||
|
|||||||
@@ -943,6 +943,14 @@ RSSHub 支持使用访问密钥 / 码,白名单和黑名单三种方式进行
|
|||||||
- `WEIBO_APP_SECRET`: 微博 App Secret
|
- `WEIBO_APP_SECRET`: 微博 App Secret
|
||||||
- `WEIBO_REDIRECT_URL`: 微博登录授权回调地址,默认为 `RSSHub 地址/weibo/timeline/0`,自定义回调地址请确保最后可以转跳到 `RSSHub 地址/weibo/timeline/0?code=xxx`
|
- `WEIBO_REDIRECT_URL`: 微博登录授权回调地址,默认为 `RSSHub 地址/weibo/timeline/0`,自定义回调地址请确保最后可以转跳到 `RSSHub 地址/weibo/timeline/0?code=xxx`
|
||||||
|
|
||||||
|
- 微博 自定义分组
|
||||||
|
|
||||||
|
- `WEIBO_COOKIES`: 用户访问网页微博时所使用的cookie, 获取方式:
|
||||||
|
1. 打开并登录 <https://m.weibo.cn> (确保打开页面为手机版, 如果强制跳转电脑端可尝试使用可更改UserAgent的浏览器插件)
|
||||||
|
2. 按下`F12`打开控制台,切换至`Network(网络)`面板
|
||||||
|
3. 在该网页切换至任意关注分组, 并在面板打开最先捕获到的请求(该情形下捕获到的请求路径应包含`/feed/group`)
|
||||||
|
4. 查看该请求的`Headers(请求头)`, 找到`Cookie`字段并复制内容
|
||||||
|
|
||||||
- 小宇宙:需要 App 登陆后抓包获取相应数据。
|
- 小宇宙:需要 App 登陆后抓包获取相应数据。
|
||||||
|
|
||||||
- `XIAOYUZHOU_ID`: 即数据包中的 `x-jike-device-id`。
|
- `XIAOYUZHOU_ID`: 即数据包中的 `x-jike-device-id`。
|
||||||
|
|||||||
@@ -1574,6 +1574,22 @@ rule
|
|||||||
|
|
||||||
</Route>
|
</Route>
|
||||||
|
|
||||||
|
### 自定义分组
|
||||||
|
|
||||||
|
<Route author="monologconnor" example="/weibo/group/4541216424989965/微博分组/:routeParams?" path="/weibo/group/:gid/:gname?/:routeParams?" :paramsDesc="['分组id, 在网页版分组地址栏末尾`?gid=`处获取', '分组显示名称; 默认为: `微博分组`', '额外参数;请参阅上面的说明和表格']" anticrawler="1" selfhost="1">
|
||||||
|
|
||||||
|
::: warning 注意
|
||||||
|
|
||||||
|
由于微博官方未提供自定义分组相关api, 此方案必须使用用户`Cookie`进行抓取
|
||||||
|
|
||||||
|
因微博cookies的过期与更新方案未经验证, 部署一次Cookie的有效时长未知
|
||||||
|
|
||||||
|
微博用户Cookie的配置可参照部署文档
|
||||||
|
|
||||||
|
:::
|
||||||
|
|
||||||
|
</Route>
|
||||||
|
|
||||||
## 微博绿洲
|
## 微博绿洲
|
||||||
|
|
||||||
### 用户
|
### 用户
|
||||||
|
|||||||
@@ -277,6 +277,7 @@ const calculateValue = () => {
|
|||||||
weibo: {
|
weibo: {
|
||||||
app_key: envs.WEIBO_APP_KEY,
|
app_key: envs.WEIBO_APP_KEY,
|
||||||
app_secret: envs.WEIBO_APP_SECRET,
|
app_secret: envs.WEIBO_APP_SECRET,
|
||||||
|
cookies: envs.WEIBO_COOKIES,
|
||||||
redirect_url: envs.WEIBO_REDIRECT_URL,
|
redirect_url: envs.WEIBO_REDIRECT_URL,
|
||||||
},
|
},
|
||||||
wenku8: {
|
wenku8: {
|
||||||
|
|||||||
99
lib/v2/weibo/group.js
Normal file
99
lib/v2/weibo/group.js
Normal file
@@ -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 <a href="https://docs.rsshub.app/install/#pei-zhi-bu-fen-rss-mo-kuai-pei-zhi">relevant config tutorial</a>';
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
};
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
|
'/group/:gid/:gname?/:routeParams?': ['monologconnor'],
|
||||||
'/keyword/:keyword/:routeParams?': ['DIYgod'],
|
'/keyword/:keyword/:routeParams?': ['DIYgod'],
|
||||||
'/oasis/user/:userid': ['kt286'],
|
'/oasis/user/:userid': ['kt286'],
|
||||||
'/search/hot': ['xyqfer'],
|
'/search/hot': ['xyqfer'],
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
module.exports = (router) => {
|
module.exports = (router) => {
|
||||||
|
router.get('/group/:gid/:gname?/:routeParams?', require('./group'));
|
||||||
router.get('/keyword/:keyword/:routeParams?', require('./keyword'));
|
router.get('/keyword/:keyword/:routeParams?', require('./keyword'));
|
||||||
router.get('/oasis/user/:userid', require('./oasis/user'));
|
router.get('/oasis/user/:userid', require('./oasis/user'));
|
||||||
router.get('/search/hot', require('./search/hot'));
|
router.get('/search/hot', require('./search/hot'));
|
||||||
|
|||||||
@@ -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);
|
const formatExtended = weiboUtils.formatExtended(ctx, item.mblog);
|
||||||
let description = formatExtended.description;
|
let description = formatExtended.description;
|
||||||
const title = formatExtended.title;
|
const title = formatExtended.title;
|
||||||
|
|||||||
Reference in New Issue
Block a user