rsshub
Version:
Make RSS Great Again!
124 lines (116 loc) • 5.49 kB
text/typescript
import { Route } from '@/types';
import got from '@/utils/got';
import path from 'node:path';
import { art } from '@/utils/render';
import { fallback, queryToInteger, queryToFloat } from '@/utils/readable-social';
export const route: Route = {
path: '/list/:type?/:routeParams?',
categories: ['social-media'],
example: '/douban/list/subject_real_time_hotest',
parameters: { type: '榜单类型,见下表。默认为实时热门书影音', routeParams: '额外参数;请参阅以下说明和表格' },
features: {
requireConfig: false,
requirePuppeteer: false,
antiCrawler: false,
supportBT: false,
supportPodcast: false,
supportScihub: false,
},
radar: [
{
source: ['www.douban.com/subject_collection/:type'],
target: '/list/:type',
},
],
name: '豆瓣榜单与集合',
maintainers: ['5upernova-heng', 'honue'],
handler,
description: `| 榜单 / 集合 | 路由 |
| ------------------ | ----------------------------- |
| 实时热门书影音 | subject\_real\_time\_hotest |
| 影院热映 | movie\_showing |
| 实时热门电影 | movie\_real\_time\_hotest |
| 实时热门电视 | tv\_real\_time\_hotest |
| 一周口碑电影榜 | movie\_weekly\_best |
| 华语口碑剧集榜 | tv\_chinese\_best\_weekly |
| 全球口碑剧集榜 | tv\_global\_best\_weekly |
| 国内口碑综艺榜 | show\_chinese\_best\_weekly |
| 国外口碑综艺榜 | show\_global\_best\_weekly |
| 热播新剧国产剧 | tv\_domestic |
| 热播新剧欧美剧 | tv\_american |
| 热播新剧日剧 | tv\_japanese |
| 热播新剧韩剧 | tv\_korean |
| 热播新剧动画 | tv\_animation |
| 虚构类小说热门榜 | book\_fiction\_hot\_weekly |
| 非虚构类小说热门榜 | book\_nonfiction\_hot\_weekly |
| 热门单曲榜 | music\_single |
| 华语新碟榜 | music\_chinese |
| ... | ... |
| 额外参数 | 含义 | 接受的值 | 默认值 |
| -------- | ---------------------- | -------- | ------ |
| playable | 仅看有可播放片源的影片 | 0/1 | 0 |
| score | 筛选评分 | 0.0-10.0 | 0 |
用例:\`/douban/list/tv_korean/playable=1&score=8\`
> 上面的榜单 / 集合并没有列举完整。
>
> 如何找到榜单对应的路由参数:
> 在豆瓣手机 APP 中,对应地榜单页面右上角,点击分享链接。链接路径 \`subject_collection\` 后的路径就是路由参数 \`type\`。
> 如:小说热门榜的分享链接为:\`https://m.douban.com/subject_collection/ECDIHUN4A\`,其对应本 RSS 路由的 \`type\` 为 \`ECDIHUN4A\`,对应的订阅链接路由:[\`/douban/list/ECDIHUN4A\`](https://rsshub.app/douban/list/ECDIHUN4A)`,
};
async function handler(ctx) {
const type = ctx.req.param('type') || 'subject_real_time_hotest';
const routeParams = Object.fromEntries(new URLSearchParams(ctx.req.param('routeParams')));
const playable = fallback(undefined, queryToInteger(routeParams.playable), 0);
const score = fallback(undefined, queryToFloat(routeParams.score), 0);
let start = 0;
const count = 50;
let items = [];
let title = '';
let description = '';
let total = null;
while (total === null || start < total) {
const url = `https://m.douban.com/rexxar/api/v2/subject_collection/${type}/items?playable=${playable}&start=${start}&count=${count}`;
// eslint-disable-next-line no-await-in-loop
const response = await got({
method: 'get',
url,
headers: {
Referer: `https://m.douban.com/subject_collection/${type}`,
},
});
title = response.data.subject_collection.name;
description = response.data.subject_collection.description;
total = response.data.total;
const newItems = response.data.subject_collection_items
.filter((item) => {
const rate = item.rating ? item.rating.value : 0;
return rate >= score; // 保留rate大于等于score的项and过滤无评分项
})
.map((item) => {
const title = item.title;
const link = item.url;
const description = art(path.join(__dirname, '../templates/list_description.art'), {
ranking_value: item.ranking_value,
title,
original_title: item.original_title,
rate: item.rating ? item.rating.value : null,
card_subtitle: item.card_subtitle,
description: item.cards ? item.cards[0].content : item.abstract,
cover: item.cover_url || item.cover?.url,
});
return {
title,
link,
description,
};
});
items = [...items, ...newItems];
start += count;
}
return {
title: `豆瓣 - ${title}`,
link: `https://m.douban.com/subject_collection/${type}`,
item: items,
description,
};
}