133 lines
4.6 KiB
TypeScript
133 lines
4.6 KiB
TypeScript
import { Route } from '@/types';
|
||
import cache from '@/utils/cache';
|
||
import got from '@/utils/got';
|
||
import { load } from 'cheerio';
|
||
import { parseDate } from '@/utils/parse-date';
|
||
import InvalidParameterError from '@/errors/types/invalid-parameter';
|
||
|
||
const baseUrl = 'https://www.acfun.cn';
|
||
const categoryMap = {
|
||
184: {
|
||
title: '二次元画师',
|
||
realmId: 'realmId=18' + '&realmId=14' + '&realmId=51',
|
||
},
|
||
110: {
|
||
title: '综合',
|
||
realmId: 'realmId=5' + '&realmId=22' + '&realmId=28' + '&realmId=3' + '&realmId=4',
|
||
},
|
||
73: {
|
||
title: '生活情感',
|
||
realmId: 'realmId=50' + '&realmId=25' + '&realmId=34' + '&realmId=7' + '&realmId=6' + '&realmId=17' + '&realmId=1' + '&realmId=2' + '&realmId=49',
|
||
},
|
||
164: {
|
||
title: '游戏',
|
||
realmId: 'realmId=8' + '&realmId=53' + '&realmId=52' + '&realmId=11' + '&realmId=43' + '&realmId=44' + '&realmId=45' + '&realmId=46' + '&realmId=47',
|
||
},
|
||
74: {
|
||
title: '动漫文化',
|
||
realmId: 'realmId=13' + '&realmId=31' + '&realmId=48',
|
||
},
|
||
75: {
|
||
title: '漫画文学',
|
||
realmId: 'realmId=15' + '&realmId=23' + '&realmId=16',
|
||
},
|
||
};
|
||
const sortTypeEnum = new Set(['createTime', 'lastCommentTime', 'hotScore']);
|
||
const timeRangeEnum = new Set(['all', 'oneDay', 'threeDay', 'oneWeek', 'oneMonth']);
|
||
|
||
export const route: Route = {
|
||
path: '/article/:categoryId/:sortType?/:timeRange?',
|
||
categories: ['anime'],
|
||
example: '/acfun/article/110',
|
||
parameters: { categoryId: '分区 ID,见下表', sortType: '排序,见下表,默认为 `createTime`', timeRange: '时间范围,见下表,仅在排序是 `hotScore` 有效,默认为 `all`' },
|
||
features: {
|
||
requireConfig: false,
|
||
requirePuppeteer: false,
|
||
antiCrawler: false,
|
||
supportBT: false,
|
||
supportPodcast: false,
|
||
supportScihub: false,
|
||
},
|
||
name: '文章',
|
||
maintainers: ['TonyRL'],
|
||
handler,
|
||
description: `| 二次元画师 | 综合 | 生活情感 | 游戏 | 动漫文化 | 漫画文学 |
|
||
| ---------- | ---- | -------- | ---- | -------- | -------- |
|
||
| 184 | 110 | 73 | 164 | 74 | 75 |
|
||
|
||
| 最新发表 | 最新动态 | 最热文章 |
|
||
| ---------- | --------------- | -------- |
|
||
| createTime | lastCommentTime | hotScore |
|
||
|
||
| 时间不限 | 24 小时 | 三天 | 一周 | 一个月 |
|
||
| -------- | ------- | -------- | ------- | -------- |
|
||
| all | oneDay | threeDay | oneWeek | oneMonth |`,
|
||
};
|
||
|
||
async function handler(ctx) {
|
||
const { categoryId, sortType = 'createTime', timeRange = 'all' } = ctx.req.param();
|
||
if (!categoryMap[categoryId]) {
|
||
throw new InvalidParameterError(`Invalid category Id: ${categoryId}`);
|
||
}
|
||
if (!sortTypeEnum.has(sortType)) {
|
||
throw new InvalidParameterError(`Invalid sort type: ${sortType}`);
|
||
}
|
||
if (!timeRangeEnum.has(timeRange)) {
|
||
throw new InvalidParameterError(`Invalid time range: ${timeRange}`);
|
||
}
|
||
|
||
const url = `${baseUrl}/v/list${categoryId}/index.htm`;
|
||
const response = await got.post(
|
||
`${baseUrl}/rest/pc-direct/article/feed` +
|
||
'?cursor=first_page' +
|
||
'&onlyOriginal=false' +
|
||
'&limit=10' +
|
||
`&sortType=${sortType}` +
|
||
`&timeRange=${sortType === 'hotScore' ? timeRange : 'all'}` +
|
||
`&${categoryMap[categoryId].realmId}`,
|
||
{
|
||
headers: {
|
||
referer: url,
|
||
},
|
||
}
|
||
);
|
||
|
||
const list = response.data.data.map((item) => ({
|
||
title: item.title,
|
||
link: `${baseUrl}/a/ac${item.articleId}`,
|
||
author: item.userName,
|
||
pubDate: parseDate(item.createTime, 'x'),
|
||
category: item.realmName,
|
||
}));
|
||
|
||
const items = await Promise.all(
|
||
list.map((item) =>
|
||
cache.tryGet(item.link, async () => {
|
||
const response = await got(item.link, {
|
||
headers: {
|
||
referer: url,
|
||
},
|
||
});
|
||
const $ = load(response.data);
|
||
const articleInfo = $('.main script')
|
||
.text()
|
||
.match(/window.articleInfo = (.*);\n\s*window.likeDomain/)[1];
|
||
const data = JSON.parse(articleInfo);
|
||
|
||
item.description = data.parts[0].content;
|
||
if (data.tagList) {
|
||
item.category = [item.category, ...data.tagList.map((tag) => tag.name)];
|
||
}
|
||
|
||
return item;
|
||
})
|
||
)
|
||
);
|
||
|
||
return {
|
||
title: categoryMap[categoryId].title,
|
||
link: url,
|
||
item: items,
|
||
};
|
||
}
|