/
article.ts
132 lines (121 loc) · 4.6 KB
/
article.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
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,
};
}