rsshub
Version:
Make RSS Great Again!
234 lines (219 loc) • 9.58 kB
text/typescript
import { Route, ViewType } from '@/types';
import got from '@/utils/got';
import utils, { getVideoUrl } from './utils';
import { parseDuration } from '@/utils/helpers';
// https://www.bilibili.com/v/popular/rank/all
// 0 all https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=all&web_location=333.934&w_rid=d4e0c1b83157e3d36836eb3c4258ef61&wts=1731320484
// 1 bangumi https://api.bilibili.com/pgc/web/rank/list?day=3&season_type=1&web_location=333.934&w_rid=2d46eff2d363c4960bc875e63e24df6c&wts=1731320507
// 2 guochan https://api.bilibili.com/pgc/season/rank/web/list?day=3&season_type=4&web_location=333.934&w_rid=b26195dc9ee2f925bc196da68df341a5&wts=1731320523
// 3 guochuang https://api.bilibili.com/x/web-interface/ranking/v2?rid=168&type=all&web_location=333.934&w_rid=f99e5982b011eb24643a2daffb7baf00&wts=1731320537
// 4 documentary https://api.bilibili.com/pgc/season/rank/web/list?day=3&season_type=3&web_location=333.934&w_rid=2067f7277cf49cbea4c5e5630eeb929a&wts=1731320556
// 5 douga https://api.bilibili.com/x/web-interface/ranking/v2?rid=1&type=all&web_location=333.934&w_rid=14bf53ce651e8d575d5982b24e1cebdf&wts=1731320579
// 6 music https://api.bilibili.com/x/web-interface/ranking/v2?rid=3&type=all&web_location=333.934&w_rid=70f4c870f860b9334ebe6e9fe835d3fe&wts=1731320595
// 7 dance https://api.bilibili.com/x/web-interface/ranking/v2?rid=129&type=all&web_location=333.934&w_rid=691f713f7fc6d3cc08174affcc59f97c&wts=1731321260
// 8 game https://api.bilibili.com/x/web-interface/ranking/v2?rid=4&type=all&web_location=333.934&w_rid=cac9f26f49da223cb8ab6f189250ec23&wts=1731320726
// 9 knowledge https://api.bilibili.com/x/web-interface/ranking/v2?rid=36&type=all&web_location=333.934&w_rid=79c274d74e90d93ac7adfd2df968288e&wts=1731320750
// 10 tech https://api.bilibili.com/x/web-interface/ranking/v2?rid=188&type=all&web_location=333.934&w_rid=115d9e69c48bf958622c4cc0ee861b57&wts=1731320766
// 11 sports https://api.bilibili.com/x/web-interface/ranking/v2?rid=234&type=all&web_location=333.934&w_rid=c618d12f36e2379bda0c9a2754cd71e0&wts=1731320783
// 12 car https://api.bilibili.com/x/web-interface/ranking/v2?rid=223&type=all&web_location=333.934&w_rid=753bc1395718051aa53aedaa3cd04d76&wts=1731320797
// 13 life https://api.bilibili.com/x/web-interface/ranking/v2?rid=160&type=all&web_location=333.934&w_rid=3e8895d4749e905173886dd387f657e9&wts=1731320823
// 14 food https://api.bilibili.com/x/web-interface/ranking/v2?rid=211&type=all&web_location=333.934&w_rid=9ec93cab672a98ea972dfb9cb7ed6368&wts=1731320838
// 15 animal https://api.bilibili.com/x/web-interface/ranking/v2?rid=217&type=all&web_location=333.934&w_rid=794e69434ec4a818f4d589e5306e9a21&wts=1731320852
// 16 kichiku https://api.bilibili.com/x/web-interface/ranking/v2?rid=119&type=all&web_location=333.934&w_rid=c5e35f3f247bc9294557ab90e0be166a&wts=1731320865
// 17 fashion https://api.bilibili.com/x/web-interface/ranking/v2?rid=155&type=all&web_location=333.934&w_rid=f3711c888057a8fef1f47da9cf4bcd86&wts=1731320878
// 18 ent https://api.bilibili.com/x/web-interface/ranking/v2?rid=5&type=all&web_location=333.934&w_rid=5ca1b2da22de1c9e818ac619d309fed2&wts=1731320889
// 19 cinephile https://api.bilibili.com/x/web-interface/ranking/v2?rid=181&type=all&web_location=333.934&w_rid=8f5cae08b232025f93b74feaefdc95d9&wts=1731320903
// 20 movie https://api.bilibili.com/pgc/season/rank/web/list?day=3&season_type=2&web_location=333.934&w_rid=ccd42543ab1c4330e9f81fb52b098a9c&wts=1731320916
// 21 tv https://api.bilibili.com/pgc/season/rank/web/list?day=3&season_type=5&web_location=333.934&w_rid=10fae974e8d30dd6bba11527fe17e551&wts=1731320934
// 22 variety https://api.bilibili.com/pgc/season/rank/web/list?day=3&season_type=7&web_location=333.934&w_rid=c3105fd0dac70dcdf4f08ca6b5cbdb8f&wts=1731320948
// 23 origin https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=origin&web_location=333.934&w_rid=53100b7aeeca012399f4f8f3746bcbdb&wts=1731320960
// 24 rookie https://api.bilibili.com/x/web-interface/ranking/v2?rid=0&type=rookie&web_location=333.934&w_rid=b8adda7447e2f115b2ed36495e436934&wts=1731320971
const ridNumberList = ['0', '1', '4', '168', '3', '1', '3', '129', '4', '36', '188', '234', '223', '160', '211', '217', '119', '155', '5', '181', '2', '5', '7', '0', '0'];
const ridChineseList = [
'全站',
'番剧',
'国产动画',
'国创相关',
'纪录片',
'动画',
'音乐',
'舞蹈',
'游戏',
'知识',
'科技',
'运动',
'汽车',
'生活',
'美食',
'动物圈',
'鬼畜',
'时尚',
'娱乐',
'影视',
'电影',
'电视剧',
'综艺',
'原创',
'新人',
];
const ridEnglishList = [
'all',
'bangumi',
'guochan',
'guochuang',
'documentary',
'douga',
'music',
'dance',
'game',
'knowledge',
'tech',
'sports',
'car',
'life',
'food',
'animal',
'kichiku',
'fashion',
'ent',
'cinephile',
'movie',
'tv',
'variety',
'origin',
'rookie',
];
const ridTypeList = [
'x/rid',
'pgc/web',
'pgc/season',
'x/rid',
'pgc/season',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'x/rid',
'pgc/season',
'pgc/season',
'pgc/season',
'x/type',
'x/type',
];
export const route: Route = {
path: '/ranking/:rid_index?/:embed?/:redirect1?/:redirect2?',
name: '排行榜',
maintainers: ['DIYgod', 'hyoban'],
categories: ['social-media'],
view: ViewType.Videos,
example: '/bilibili/ranking/0',
parameters: {
rid_index: {
description: '排行榜分区 id 序号',
default: '0',
options: Array.from({ length: ridNumberList.length }, (_, i) => ({
value: String(i),
label: ridChineseList[i],
})).filter((_, i) => !ridTypeList[i].startsWith('pgc/')),
},
embed: '默认为开启内嵌视频, 任意值为关闭',
redirect1: '留空,用于兼容之前的路由',
redirect2: '留空,用于兼容之前的路由',
},
handler,
};
function getRidIndexByRid(rid: string): number {
const index = ridNumberList.indexOf(rid);
if (index === -1) {
throw new Error('Invalid rid');
}
return index;
}
function getAPI(ridIndex: number) {
if (ridIndex < 0 || ridIndex >= ridNumberList.length) {
throw new Error('Invalid rid index');
}
const rid = ridNumberList[ridIndex];
const ridType = ridTypeList[ridIndex];
const ridChinese = ridChineseList[ridIndex];
const ridEnglish = ridEnglishList[ridIndex];
let apiURL = '';
switch (ridType) {
case 'x/rid':
apiURL = `https://api.bilibili.com/x/web-interface/ranking?rid=${rid}&type=all`;
break;
case 'pgc/web':
apiURL = `https://api.bilibili.com/pgc/web/rank/list?day=3&season_type=${rid}`;
break;
case 'pgc/season':
apiURL = `https://api.bilibili.com/pgc/season/rank/web/list?day=3&season_type=${rid}`;
break;
case 'x/type':
apiURL = `https://api.bilibili.com/x/web-interface/ranking?rid=0&type=${ridEnglish}`;
break;
default:
throw new Error('Invalid rid type');
}
return {
apiURL,
referer: `https://www.bilibili.com/v/popular/rank/${ridEnglish}`,
ridChinese,
ridType,
link: `https://www.bilibili.com/v/popular/rank/${ridEnglish}`,
};
}
async function handler(ctx) {
const args = ctx.req.param();
if (args.redirect1 || args.redirect2) {
// redirect old routes like /bilibili/ranking/0/3/1 or /bilibili/ranking/0/3/1/xxx
const embedArg = args.redirect2 ? '/' + args.redirect2 : '';
ctx.set('redirect', `/bilibili/ranking/${getRidIndexByRid(args.rid_index)}${embedArg}`);
return null;
}
const ridIndex = ctx.req.param('rid_index') || '0';
const embed = !ctx.req.param('embed');
const { apiURL, referer, ridChinese, link, ridType } = getAPI(Number(ridIndex));
if (ridType.startsWith('pgc/')) {
throw new Error('This type of ranking is not supported yet');
}
const response = await got({
method: 'get',
url: apiURL,
headers: {
Referer: referer,
},
});
const data = response.data.data || response.data.result;
const list = data.list || [];
return {
title: `bilibili 排行榜-${ridChinese}`,
link,
item: list.map((item) => ({
title: item.title,
description: utils.renderUGCDescription(embed, item.pic, item.description || item.title, item.aid, undefined, item.bvid),
pubDate: item.create && new Date(item.create).toUTCString(),
author: item.author,
link: !item.create || (new Date(item.create).getTime() / 1000 > utils.bvidTime && item.bvid) ? `https://www.bilibili.com/video/${item.bvid}` : `https://www.bilibili.com/video/av${item.aid}`,
image: item.pic,
attachments: item.bvid
? [
{
url: getVideoUrl(item.bvid),
mime_type: 'text/html',
duration_in_seconds: parseDuration(item.duration),
},
]
: undefined,
})),
};
}