feat(route): add xueqiu timeline (#15079)

* feat(route): add xueqiu timeline

* feat(xueqiu): accept review advices

* 更新 timeline.ts

Co-authored-by: Tony <TonyRL@users.noreply.github.com>

---------
This commit is contained in:
Ernest Dong 2024-04-03 23:16:15 +08:00 committed by GitHub
parent 690b06e680
commit 23c1d6b10d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 99 additions and 0 deletions

View File

@ -276,6 +276,9 @@ export type Config = {
ximalaya: {
token?: string;
};
xueqiu: {
cookies?: string;
};
youtube: {
key?: string;
clientId?: string;
@ -619,6 +622,9 @@ const calculateValue = () => {
ximalaya: {
token: envs.XIMALAYA_TOKEN,
},
xueqiu: {
cookies: envs.XUEQIU_COOKIES,
},
youtube: {
key: envs.YOUTUBE_KEY,
clientId: envs.YOUTUBE_CLIENT_ID,

View File

@ -0,0 +1,93 @@
import { DataItem, Route } from '@/types';
import got from '@/utils/got';
import { config } from '@/config';
import { parseDate } from '@/utils/parse-date';
import cache from '@/utils/cache';
const rootUrl = 'https://xueqiu.com';
export const route: Route = {
path: '/timeline/:usergroup_id?',
categories: ['finance'],
example: '/xueqiu/timeline/',
parameters: { usergroup_id: '用户组 ID-1 为全部关注用户' },
features: {
requireConfig: [
{
name: 'XUEQIU_COOKIES',
description: '',
},
],
requirePuppeteer: false,
antiCrawler: true,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
name: '用户关注时间线',
maintainers: ['ErnestDong'],
handler,
description: `:::warning
Cookie
:::
| -1 | -2 | 1 |
| ---- | -------- | ------------- |
| | | 1 |`,
};
async function handler(ctx) {
const cookie = config.xueqiu.cookies;
const limit = ctx.req.query('limit') || 15;
const usergroup_id = ctx.req.param('usergroup_id') ?? -1;
if (cookie === undefined) {
throw new Error('缺少雪球用户登录后的 Cookie 值');
}
let out: DataItem[] = [];
let max_id = -1;
async function fetchItems() {
const data = await fetchNextID(max_id, cookie as string, usergroup_id);
const items = await Promise.all(
data.home_timeline.map((item) =>
cache.tryGet(item.target, async () => {
const retweetedStatus = item.retweeted_status ? `<blockquote>${item.retweeted_status.user.screen_name}:&nbsp;${item.retweeted_status.description}</blockquote>` : '';
const description = item.description + retweetedStatus;
const result = await Promise.resolve({
title: item.title === '' ? item.user.screen_name + (item.retweeted_status ? ' 转发' : '') : item.title,
description: item.text ? item.text + retweetedStatus : description,
pubDate: parseDate(item.created_at),
link: rootUrl + item.target,
});
return result;
})
)
);
out = [...out, ...items];
max_id = data.next_max_id;
if (out.length < limit) {
await fetchItems();
}
}
await fetchItems();
return {
title: '雪球关注动态',
link: 'https://xueqiu.com/',
item: out,
};
}
async function fetchNextID(max_id: number, cookie: string, usergroup_id = -1) {
let url = `https://xueqiu.com/v4/statuses/system/home_timeline.json?source=user&usergroup_id=${usergroup_id}`;
if (max_id > 0) {
url += `&max_id=${max_id}`;
}
const response = await got({
method: 'get',
url,
headers: {
Cookie: cookie,
},
});
return response.data;
}