rsshub 1.0.0-master.f6cb490 → 1.0.0-master.f6f0273
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api/index.ts +1 -6
- package/lib/routes/2048/index.ts +24 -23
- package/lib/routes/anthropic/news.ts +27 -13
- package/lib/routes/asianfanfics/namespace.ts +7 -0
- package/lib/routes/asianfanfics/tag.ts +89 -0
- package/lib/routes/asianfanfics/text-search.ts +68 -0
- package/lib/routes/blockworks/index.ts +128 -0
- package/lib/routes/blockworks/namespace.ts +7 -0
- package/lib/routes/cmu/andypavlo/blog.ts +55 -0
- package/lib/routes/cmu/namespace.ts +7 -0
- package/lib/routes/coindesk/{index.ts → consensus-magazine.ts} +17 -21
- package/lib/routes/coindesk/namespace.ts +2 -1
- package/lib/routes/coindesk/news.ts +47 -0
- package/lib/routes/coindesk/utils.ts +26 -0
- package/lib/routes/cointelegraph/index.ts +106 -0
- package/lib/routes/cointelegraph/namespace.ts +7 -0
- package/lib/routes/collabo-cafe/category.ts +37 -0
- package/lib/routes/collabo-cafe/index.ts +35 -0
- package/lib/routes/collabo-cafe/namespace.ts +9 -0
- package/lib/routes/collabo-cafe/parser.ts +29 -0
- package/lib/routes/collabo-cafe/tag.ts +37 -0
- package/lib/routes/cryptoslate/index.ts +98 -0
- package/lib/routes/cryptoslate/namespace.ts +7 -0
- package/lib/routes/decrypt/index.ts +115 -0
- package/lib/routes/decrypt/namespace.ts +7 -0
- package/lib/routes/discuz/discuz.ts +7 -9
- package/lib/routes/fangchan/list.ts +224 -0
- package/lib/routes/fangchan/namespace.ts +9 -0
- package/lib/routes/fangchan/templates/description.art +7 -0
- package/lib/routes/foreignaffairs/namespace.ts +7 -0
- package/lib/routes/foreignaffairs/rss.ts +55 -0
- package/lib/routes/forklog/index.ts +72 -0
- package/lib/routes/forklog/namespace.ts +7 -0
- package/lib/routes/gcores/categories.ts +129 -0
- package/lib/routes/gcores/collections.ts +129 -0
- package/lib/routes/gcores/topics.ts +63 -0
- package/lib/routes/gov/moa/gjs.ts +210 -0
- package/lib/routes/gov/tianjin/tjftz.ts +53 -0
- package/lib/routes/gov/tianjin/tjrcgzw.ts +51 -0
- package/lib/routes/grainoil/category.ts +207 -0
- package/lib/routes/grainoil/namespace.ts +9 -0
- package/lib/routes/huxiu/util.ts +11 -9
- package/lib/routes/ifanr/category.ts +7 -2
- package/lib/routes/ifanr/digest.ts +1 -1
- package/lib/routes/ifanr/index.ts +1 -1
- package/lib/routes/instructables/projects.ts +20 -15
- package/lib/routes/juejin/collections.ts +1 -1
- package/lib/routes/komiic/comic.ts +88 -0
- package/lib/routes/komiic/namespace.ts +7 -0
- package/lib/routes/leagueoflegends/namespace.ts +8 -0
- package/lib/routes/leagueoflegends/patch-notes.ts +76 -0
- package/lib/routes/likeshop/index.ts +43 -0
- package/lib/routes/likeshop/namespace.ts +7 -0
- package/lib/routes/ltaaa/article.ts +180 -0
- package/lib/routes/ltaaa/namespace.ts +9 -0
- package/lib/routes/ltaaa/templates/description.art +7 -0
- package/lib/routes/mashiro/index.ts +1 -0
- package/lib/routes/nhentai/util.ts +4 -1
- package/lib/routes/pinterest/user.ts +9 -0
- package/lib/routes/sohu/mp.ts +3 -2
- package/lib/routes/spotify/show.ts +1 -1
- package/lib/routes/stcn/index.ts +241 -136
- package/lib/routes/stcn/kx.ts +144 -0
- package/lib/routes/swjtu/namespace.ts +1 -1
- package/lib/routes/swjtu/{scai/bks.ts → scai.ts} +34 -20
- package/lib/routes/swjtu/sports.ts +77 -0
- package/lib/routes/theblock/index.ts +142 -0
- package/lib/routes/theblock/namespace.ts +7 -0
- package/lib/routes/theverge/index.ts +73 -62
- package/lib/routes/theverge/templates/header.art +19 -0
- package/lib/routes/threads/index.ts +73 -54
- package/lib/routes/threads/utils.ts +60 -78
- package/lib/routes/tmtpost/column.ts +298 -0
- package/lib/routes/tmtpost/new.ts +4 -199
- package/lib/routes/tmtpost/util.ts +207 -0
- package/lib/routes/toranoana/namespace.ts +7 -0
- package/lib/routes/toranoana/news.ts +110 -0
- package/lib/routes/wainao/templates/description.art +9 -0
- package/lib/routes/wainao/topics.ts +214 -0
- package/lib/routes/xiaoyuzhou/podcast.ts +27 -27
- package/lib/routes/xjtu/yz.ts +74 -0
- package/lib/routes/youmemark/index.ts +6 -6
- package/lib/routes/zaobao/util.ts +11 -3
- package/lib/routes/zhihu/answers.ts +26 -54
- package/package.json +36 -35
- package/lib/routes/gcores/category.ts +0 -171
- package/lib/routes/gcores/collection.ts +0 -161
- package/lib/routes-deprecated/ltaaa/index.js +0 -69
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { type Data, type DataItem, type Route, ViewType } from '@/types';
|
|
2
|
+
|
|
3
|
+
import { art } from '@/utils/render';
|
|
4
|
+
import { getCurrentPath } from '@/utils/helpers';
|
|
5
|
+
import ofetch from '@/utils/ofetch';
|
|
6
|
+
import { parseDate } from '@/utils/parse-date';
|
|
7
|
+
|
|
8
|
+
import { type CheerioAPI, load } from 'cheerio';
|
|
9
|
+
import { type Context } from 'hono';
|
|
10
|
+
import path from 'node:path';
|
|
11
|
+
|
|
12
|
+
const __dirname = getCurrentPath(import.meta.url);
|
|
13
|
+
|
|
14
|
+
export const handler = async (ctx: Context): Promise<Data> => {
|
|
15
|
+
const { id = 'hotspot' } = ctx.req.param();
|
|
16
|
+
const limit: number = Number.parseInt(ctx.req.query('limit') ?? '30', 10);
|
|
17
|
+
|
|
18
|
+
const baseUrl: string = 'https://www.wainao.me';
|
|
19
|
+
const targetUrl: string = new URL(`topics/${id}`, baseUrl).href;
|
|
20
|
+
const apiUrl: string = new URL('pf/api/v3/content/fetch/story-feed-sections', baseUrl).href;
|
|
21
|
+
|
|
22
|
+
const response = await ofetch(apiUrl, {
|
|
23
|
+
query: {
|
|
24
|
+
query: JSON.stringify({
|
|
25
|
+
feedOffset: 0,
|
|
26
|
+
feedSize: limit,
|
|
27
|
+
includeSections: `/topics/${id}`,
|
|
28
|
+
}),
|
|
29
|
+
d: 81,
|
|
30
|
+
_website: 'wainao',
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const targetResponse = await ofetch(targetUrl);
|
|
35
|
+
const $: CheerioAPI = load(targetResponse);
|
|
36
|
+
const language = $('html').attr('lang') ?? 'zh-CN';
|
|
37
|
+
|
|
38
|
+
let items: DataItem[] = [];
|
|
39
|
+
|
|
40
|
+
items = response.content_elements
|
|
41
|
+
.slice(0, limit)
|
|
42
|
+
.map((item): DataItem => {
|
|
43
|
+
const title: string = item.headlines.basic;
|
|
44
|
+
const description: string = art(path.join(__dirname, 'templates/description.art'), {
|
|
45
|
+
elements: item.content_elements,
|
|
46
|
+
});
|
|
47
|
+
const pubDate: number | string = item.publish_date;
|
|
48
|
+
const linkUrl: string | undefined = item.website_url;
|
|
49
|
+
const categories: string[] = [item.taxonomy?.primary_section?.name].filter(Boolean);
|
|
50
|
+
const authors: DataItem['author'] =
|
|
51
|
+
item.credits?.by?.map((author) => ({
|
|
52
|
+
name: author.name,
|
|
53
|
+
})) ?? [];
|
|
54
|
+
const guid: string = item.website_url;
|
|
55
|
+
const image: string | undefined = item.promo_items.basic.url;
|
|
56
|
+
const updated: number | string = item.last_updated_date;
|
|
57
|
+
|
|
58
|
+
const processedItem: DataItem = {
|
|
59
|
+
title,
|
|
60
|
+
description,
|
|
61
|
+
pubDate: pubDate ? parseDate(pubDate) : undefined,
|
|
62
|
+
link: linkUrl ? new URL(linkUrl, baseUrl).href : undefined,
|
|
63
|
+
category: categories,
|
|
64
|
+
author: authors,
|
|
65
|
+
guid,
|
|
66
|
+
id: guid,
|
|
67
|
+
content: {
|
|
68
|
+
html: description,
|
|
69
|
+
text: description,
|
|
70
|
+
},
|
|
71
|
+
image,
|
|
72
|
+
banner: image,
|
|
73
|
+
updated: updated ? parseDate(updated) : undefined,
|
|
74
|
+
language,
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return processedItem;
|
|
78
|
+
})
|
|
79
|
+
.filter((_): _ is DataItem => true);
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
title: $('title').text(),
|
|
83
|
+
description: $('meta[property="og:title"]').attr('content'),
|
|
84
|
+
link: targetUrl,
|
|
85
|
+
item: items,
|
|
86
|
+
allowEmpty: true,
|
|
87
|
+
image: $('meta[property="og:image"]').attr('content'),
|
|
88
|
+
author: $('meta[property="og:site_name"]').attr('content'),
|
|
89
|
+
language,
|
|
90
|
+
id: targetUrl,
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
export const route: Route = {
|
|
95
|
+
path: '/topics/:id?',
|
|
96
|
+
name: '主题',
|
|
97
|
+
url: 'wainao.me',
|
|
98
|
+
maintainers: ['nczitzk'],
|
|
99
|
+
handler,
|
|
100
|
+
example: '/wainao/topics/hotspot',
|
|
101
|
+
parameters: {
|
|
102
|
+
id: {
|
|
103
|
+
description: '主题 id,默认为 `hotspot`,即热点,可在对应主题页 URL 中找到',
|
|
104
|
+
options: [
|
|
105
|
+
{
|
|
106
|
+
label: '热点',
|
|
107
|
+
value: 'hotspot',
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
label: '人物',
|
|
111
|
+
value: 'people',
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
label: '身份',
|
|
115
|
+
value: 'identity',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
label: '政治',
|
|
119
|
+
value: 'politics',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
label: '社会',
|
|
123
|
+
value: 'society',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
label: '文化',
|
|
127
|
+
value: 'culture',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
label: '经济',
|
|
131
|
+
value: 'economics',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
label: '环境',
|
|
135
|
+
value: 'environment',
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
label: 'FUN',
|
|
139
|
+
value: 'fun',
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
description: `:::tip
|
|
145
|
+
若订阅 [人物](https://www.wainao.me/topics/people),网址为 \`https://www.wainao.me/topics/people\`,请截取 \`https://www.wainao.me/topics/\` 到末尾的部分 \`people\` 作为 \`id\` 参数填入,此时目标路由为 [\`/wainao/topics/people\`](https://rsshub.app/wainao/topics/people)。
|
|
146
|
+
:::
|
|
147
|
+
|
|
148
|
+
| [热点](https://www.wainao.me/topics/hotspot) | [人物](https://www.wainao.me/topics/people) | [身份](https://www.wainao.me/topics/identity) | [政治](https://www.wainao.me/topics/politics) | [社会](https://www.wainao.me/topics/society) | [文化](https://www.wainao.me/topics/culture) | [经济](https://www.wainao.me/topics/economics) | [环境](https://www.wainao.me/topics/environment) | [FUN](https://www.wainao.me/topics/fun) |
|
|
149
|
+
| --------------------------------------------------- | ------------------------------------------------- | ----------------------------------------------------- | ----------------------------------------------------- | --------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------- | ----------------------------------------------------------- | ------------------------------------------- |
|
|
150
|
+
| [hotspot](https://rsshub.app/wainao/topics/hotspot) | [people](https://rsshub.app/wainao/topics/people) | [identity](https://rsshub.app/wainao/topics/identity) | [politics](https://rsshub.app/wainao/topics/politics) | [society](https://rsshub.app/wainao/topics/society) | [culture](https://rsshub.app/wainao/topics/culture) | [economics](https://rsshub.app/wainao/topics/economics) | [environment](https://rsshub.app/wainao/topics/environment) | [fun](https://rsshub.app/wainao/topics/fun) |
|
|
151
|
+
`,
|
|
152
|
+
categories: ['new-media'],
|
|
153
|
+
features: {
|
|
154
|
+
requireConfig: false,
|
|
155
|
+
requirePuppeteer: false,
|
|
156
|
+
antiCrawler: false,
|
|
157
|
+
supportRadar: true,
|
|
158
|
+
supportBT: false,
|
|
159
|
+
supportPodcast: false,
|
|
160
|
+
supportScihub: false,
|
|
161
|
+
},
|
|
162
|
+
radar: [
|
|
163
|
+
{
|
|
164
|
+
source: ['www.wainao.me/topics/:id'],
|
|
165
|
+
target: '/topics/:id',
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
title: '热点',
|
|
169
|
+
source: ['www.wainao.me/topics/hotspot'],
|
|
170
|
+
target: '/topics/hotspot',
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
title: '人物',
|
|
174
|
+
source: ['www.wainao.me/topics/people'],
|
|
175
|
+
target: '/topics/people',
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
title: '身份',
|
|
179
|
+
source: ['www.wainao.me/topics/identity'],
|
|
180
|
+
target: '/topics/identity',
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
title: '政治',
|
|
184
|
+
source: ['www.wainao.me/topics/politics'],
|
|
185
|
+
target: '/topics/politics',
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
title: '社会',
|
|
189
|
+
source: ['www.wainao.me/topics/society'],
|
|
190
|
+
target: '/topics/society',
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
title: '文化',
|
|
194
|
+
source: ['www.wainao.me/topics/culture'],
|
|
195
|
+
target: '/topics/culture',
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
title: '经济',
|
|
199
|
+
source: ['www.wainao.me/topics/economics'],
|
|
200
|
+
target: '/topics/economics',
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
title: '环境',
|
|
204
|
+
source: ['www.wainao.me/topics/environment'],
|
|
205
|
+
target: '/topics/environment',
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
title: 'FUN',
|
|
209
|
+
source: ['www.wainao.me/topics/fun'],
|
|
210
|
+
target: '/topics/fun',
|
|
211
|
+
},
|
|
212
|
+
],
|
|
213
|
+
view: ViewType.Articles,
|
|
214
|
+
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Route, ViewType } from '@/types';
|
|
2
|
-
import
|
|
2
|
+
import ofetch from '@/utils/ofetch';
|
|
3
3
|
import { load } from 'cheerio';
|
|
4
4
|
import { parseDate } from '@/utils/parse-date';
|
|
5
5
|
|
|
@@ -30,43 +30,43 @@ export const route: Route = {
|
|
|
30
30
|
|
|
31
31
|
async function handler(ctx) {
|
|
32
32
|
const id = ctx.req.param('id');
|
|
33
|
-
let link
|
|
34
|
-
let response
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
33
|
+
let link;
|
|
34
|
+
let response;
|
|
35
|
+
let $;
|
|
36
|
+
let page_data;
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
// First try podcast URL, if that fails try episode URL
|
|
39
|
+
try {
|
|
40
|
+
link = `https://www.xiaoyuzhoufm.com/podcast/${id}`;
|
|
41
|
+
response = await ofetch(link);
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
43
|
+
$ = load(response);
|
|
44
|
+
const nextDataElement = $('#__NEXT_DATA__').get(0);
|
|
45
|
+
page_data = JSON.parse(nextDataElement.children[0].data);
|
|
46
|
+
|
|
47
|
+
// If no episodes found, we should try episode URL
|
|
48
|
+
if (!page_data.props.pageProps.podcast?.episodes) {
|
|
49
|
+
throw new Error('No episodes found in podcast data');
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
// Try as episode instead
|
|
45
53
|
link = `https://www.xiaoyuzhoufm.com/episode/${id}`;
|
|
46
|
-
response = await
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
54
|
+
response = await ofetch(link);
|
|
55
|
+
|
|
56
|
+
$ = load(response);
|
|
57
|
+
const podcastLink = $('a[href^="/podcast/"].name').attr('href');
|
|
50
58
|
|
|
51
|
-
$ = load(response.data);
|
|
52
|
-
const podcastLink = $('.jsx-605929003.podcast-title .jsx-605929003.name').attr('href');
|
|
53
59
|
if (podcastLink) {
|
|
54
60
|
const podcastId = podcastLink.split('/').pop();
|
|
55
61
|
link = `https://www.xiaoyuzhoufm.com/podcast/${podcastId}`;
|
|
56
|
-
response = await
|
|
57
|
-
method: 'get',
|
|
58
|
-
url: link,
|
|
59
|
-
});
|
|
62
|
+
response = await ofetch(link);
|
|
60
63
|
|
|
61
|
-
$ = load(response
|
|
62
|
-
|
|
64
|
+
$ = load(response);
|
|
65
|
+
const nextDataElement = $('#__NEXT_DATA__').get(0);
|
|
66
|
+
page_data = JSON.parse(nextDataElement.children[0].data);
|
|
63
67
|
}
|
|
64
68
|
}
|
|
65
69
|
|
|
66
|
-
if (!page_data.props.pageProps.podcast?.episodes) {
|
|
67
|
-
throw new Error('Failed to fetch podcast episodes');
|
|
68
|
-
}
|
|
69
|
-
|
|
70
70
|
const episodes = page_data.props.pageProps.podcast.episodes.map((item) => ({
|
|
71
71
|
title: item.title,
|
|
72
72
|
enclosure_url: item.enclosure.url,
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import type { Data, DataItem, Route } from '@/types';
|
|
2
|
+
import ofetch from '@/utils/ofetch';
|
|
3
|
+
import { load } from 'cheerio';
|
|
4
|
+
import { parseDate } from '@/utils/parse-date';
|
|
5
|
+
import cache from '@/utils/cache';
|
|
6
|
+
import logger from '@/utils/logger';
|
|
7
|
+
import timezone from '@/utils/timezone';
|
|
8
|
+
|
|
9
|
+
export const route: Route = {
|
|
10
|
+
path: '/yz/:category?',
|
|
11
|
+
categories: ['university'],
|
|
12
|
+
example: '/xjtu/yz/zsdt',
|
|
13
|
+
parameters: { category: '栏目类型,默认请求`zsdt`,详见下方表格' },
|
|
14
|
+
features: {
|
|
15
|
+
requireConfig: false,
|
|
16
|
+
requirePuppeteer: false,
|
|
17
|
+
antiCrawler: false,
|
|
18
|
+
supportBT: false,
|
|
19
|
+
supportPodcast: false,
|
|
20
|
+
supportScihub: false,
|
|
21
|
+
},
|
|
22
|
+
radar: [
|
|
23
|
+
{
|
|
24
|
+
source: ['yz.xjtu.edu.cn/index/:category.htm'],
|
|
25
|
+
target: '/yz/:category',
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
name: '研究生招生信息网',
|
|
29
|
+
maintainers: ['YoghurtGuy'],
|
|
30
|
+
handler,
|
|
31
|
+
description: `栏目类型
|
|
32
|
+
|
|
33
|
+
| 招生动态 | 通知公告 | 政策法规 | 招生统计 | 历年复试线 | 博士招生 | 硕士招生 | 推免生 | 其他招生 |
|
|
34
|
+
| -------- | -------- | -------- | -------- | ---------- | -------- | -------- | ------ | -------- |
|
|
35
|
+
| zsdt | tzgg | zcfg | zstj | lnfsx | bszs | sszs | tms | qtzs |`,
|
|
36
|
+
};
|
|
37
|
+
async function handler(ctx) {
|
|
38
|
+
const { category = 'zsdt' } = ctx.req.param();
|
|
39
|
+
const baseUrl = 'https://yz.xjtu.edu.cn';
|
|
40
|
+
|
|
41
|
+
const response = await ofetch(`${baseUrl}/index/${category}.htm`);
|
|
42
|
+
const $ = load(response);
|
|
43
|
+
const list = $('div.list-con ul li')
|
|
44
|
+
.toArray()
|
|
45
|
+
.map((item_) => {
|
|
46
|
+
const item = $(item_);
|
|
47
|
+
const a = item.find('a');
|
|
48
|
+
return {
|
|
49
|
+
title: a.attr('title'),
|
|
50
|
+
link: new URL(a.attr('href')!, baseUrl).href,
|
|
51
|
+
pubDate: timezone(parseDate(item.find('span.date.fr').text()), +8),
|
|
52
|
+
} as DataItem;
|
|
53
|
+
});
|
|
54
|
+
const items = await Promise.all(
|
|
55
|
+
list.map((item) =>
|
|
56
|
+
cache.tryGet(item.link!, async () => {
|
|
57
|
+
try {
|
|
58
|
+
const res = await ofetch(item.link!);
|
|
59
|
+
const content = load(res);
|
|
60
|
+
item.description = content('#vsb_content').html()! + (content('form ul').length > 0 ? content('form ul').html() : '');
|
|
61
|
+
return item;
|
|
62
|
+
} catch (error) {
|
|
63
|
+
logger.error(`Fetch failed for ${item.link}:`, error);
|
|
64
|
+
return item;
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
)
|
|
68
|
+
);
|
|
69
|
+
return {
|
|
70
|
+
title: '西安交通大学研究生招生信息网',
|
|
71
|
+
link: 'https://yz.xjtu.edu.cn',
|
|
72
|
+
item: items,
|
|
73
|
+
} as Data;
|
|
74
|
+
}
|
|
@@ -44,13 +44,13 @@ async function handler(ctx): Promise<Data> {
|
|
|
44
44
|
const $ = load(response);
|
|
45
45
|
|
|
46
46
|
const name = $('h2.font-bold').text().trim();
|
|
47
|
-
const avatar = $('span.relative.flex img').attr('src');
|
|
48
|
-
const intro = $('.text-center .prose p').first().text().trim();
|
|
47
|
+
const avatar = $('span.relative.flex img, span.relative.flex.shrink-0 img').attr('src');
|
|
48
|
+
const intro = $('.text-center .prose p, .text-sm.text-gray-500.text-center .prose p').first().text().trim();
|
|
49
49
|
|
|
50
50
|
const items: Data['item'] = [];
|
|
51
51
|
$('h2:contains("收集箱")')
|
|
52
|
-
.
|
|
53
|
-
.find('
|
|
52
|
+
.parent()
|
|
53
|
+
.find('.rounded-lg.space-y-2')
|
|
54
54
|
.each((_, element) => {
|
|
55
55
|
const $item = $(element);
|
|
56
56
|
|
|
@@ -60,10 +60,10 @@ async function handler(ctx): Promise<Data> {
|
|
|
60
60
|
const domain = $link.find('span').last().text().trim().replaceAll(/[()]/g, '').trim();
|
|
61
61
|
const link = $link.attr('href');
|
|
62
62
|
|
|
63
|
-
const $contentDiv = $linkDiv.find('> div')
|
|
63
|
+
const $contentDiv = $linkDiv.find('> div.text-sm.text-gray-500');
|
|
64
64
|
const content = $contentDiv.find('p').text().trim();
|
|
65
65
|
|
|
66
|
-
const dateStr = $item.
|
|
66
|
+
const dateStr = $item.find('.text-xs.text-gray-500 span').text().trim();
|
|
67
67
|
|
|
68
68
|
if (link && title && dateStr) {
|
|
69
69
|
items.push({
|
|
@@ -90,11 +90,19 @@ const parseList = async (
|
|
|
90
90
|
if ($1('#seo-article-page').text() === '') {
|
|
91
91
|
// HK
|
|
92
92
|
title = $1('h1.article-title').text();
|
|
93
|
-
|
|
93
|
+
const jsonText = $1("head script[type='application/ld+json']")
|
|
94
|
+
.eq(1)
|
|
95
|
+
.text()
|
|
96
|
+
.replaceAll(/[\u0000-\u001F\u007F-\u009F]/g, '');
|
|
97
|
+
time = new Date(JSON.parse(jsonText)?.datePublished);
|
|
94
98
|
} else {
|
|
95
99
|
// SG
|
|
96
|
-
|
|
97
|
-
|
|
100
|
+
const jsonText = $1('#seo-article-page')
|
|
101
|
+
.text()
|
|
102
|
+
.replaceAll(/[\u0000-\u001F\u007F-\u009F]/g, '');
|
|
103
|
+
const json = JSON.parse(jsonText);
|
|
104
|
+
title = json['@graph'][0]?.headline;
|
|
105
|
+
time = new Date(json['@graph'][0]?.datePublished);
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
$1('.overlay-microtransaction').remove();
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { Route } from '@/types';
|
|
2
|
-
import cache from '@/utils/cache';
|
|
3
2
|
import got from '@/utils/got';
|
|
4
|
-
import {
|
|
3
|
+
import { header, getSignedHeader } from './utils';
|
|
5
4
|
import { parseDate } from '@/utils/parse-date';
|
|
6
5
|
|
|
7
6
|
export const route: Route = {
|
|
@@ -30,66 +29,39 @@ export const route: Route = {
|
|
|
30
29
|
async function handler(ctx) {
|
|
31
30
|
const id = ctx.req.param('id');
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
// second: get real data from zhihu
|
|
33
|
+
const apiPath = `/api/v4/members/${id}/answers?limit=7&include=data[*].is_normal,content`;
|
|
34
34
|
|
|
35
|
-
const
|
|
36
|
-
'User-Agent': 'ZhihuHybrid com.zhihu.android/Futureve/6.59.0 Mozilla/5.0 (Linux; Android 10; GM1900 Build/QKQ1.190716.003; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/85.0.4183.127 Mobile Safari/537.36',
|
|
37
|
-
Referer: `https://www.zhihu.com/people/${id}/answers`,
|
|
38
|
-
Cookie: zc0 ? `z_c0=${zc0}` : '',
|
|
39
|
-
};
|
|
35
|
+
const signedHeader = await getSignedHeader(`https://www.zhihu.com/people/${id}`, apiPath);
|
|
40
36
|
|
|
41
|
-
const response = await got({
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
37
|
+
const response = await got(`https://www.zhihu.com${apiPath}`, {
|
|
38
|
+
headers: {
|
|
39
|
+
...header,
|
|
40
|
+
...signedHeader,
|
|
41
|
+
Referer: `https://www.zhihu.com/people/${id}/activities`,
|
|
42
|
+
// Authorization: 'oauth c3cef7c66a1843f8b3a9e6a1e3160e20', // hard-coded in js
|
|
43
|
+
},
|
|
45
44
|
});
|
|
46
45
|
|
|
47
46
|
const data = response.data.data;
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
const
|
|
52
|
-
|
|
47
|
+
const items = data.map((item) => {
|
|
48
|
+
const title = item.question.title;
|
|
49
|
+
// let description = processImage(detail.content);
|
|
50
|
+
const url = `https://www.zhihu.com/question/${item.question.id}/answer/${item.id}`;
|
|
51
|
+
const author = item.author.name;
|
|
52
|
+
const description = item.content;
|
|
53
53
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
return data;
|
|
63
|
-
});
|
|
64
|
-
name = userProfile.name;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const items = await Promise.all(
|
|
68
|
-
data.map(async (item) => {
|
|
69
|
-
let description;
|
|
70
|
-
const link = `https://www.zhihu.com/question/${item.question.id}/answer/${item.id}`;
|
|
71
|
-
const title = item.question.title;
|
|
72
|
-
try {
|
|
73
|
-
const detail = await got({
|
|
74
|
-
method: 'get',
|
|
75
|
-
url: `https://api.zhihu.com/appview/api/v4/answers/${item.id}?include=content&is_appview=true`,
|
|
76
|
-
headers,
|
|
77
|
-
});
|
|
78
|
-
description = processImage(detail.data.content);
|
|
79
|
-
} catch {
|
|
80
|
-
description = `<a href="${link}" target="_blank">${title}</a>`;
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
title,
|
|
84
|
-
description,
|
|
85
|
-
pubDate: parseDate(item.created_time * 1000),
|
|
86
|
-
link,
|
|
87
|
-
};
|
|
88
|
-
})
|
|
89
|
-
);
|
|
54
|
+
return {
|
|
55
|
+
title,
|
|
56
|
+
author,
|
|
57
|
+
description,
|
|
58
|
+
pubDate: parseDate(item.created_time * 1000),
|
|
59
|
+
link: url,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
90
62
|
|
|
91
63
|
return {
|
|
92
|
-
title: `${name}的知乎回答`,
|
|
64
|
+
title: `${data[0].author.name}的知乎回答`,
|
|
93
65
|
link: `https://www.zhihu.com/people/${id}/answers`,
|
|
94
66
|
item: items,
|
|
95
67
|
};
|