UNPKG

rsshub

Version:
234 lines (219 loc) 9.58 kB
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, })), }; }