rsshub 1.0.0-master.f71451d → 1.0.0-master.f75997f
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/config.ts +14 -0
- package/lib/errors/index.test.ts +2 -2
- package/lib/middleware/template.tsx +12 -3
- package/lib/routes/0x80/index.ts +87 -0
- package/lib/routes/0x80/namespace.ts +7 -0
- package/lib/routes/aljazeera/index.ts +17 -14
- package/lib/routes/apple/podcast.ts +64 -0
- package/lib/routes/bilibili/cache.ts +1 -1
- package/lib/routes/bing/daily-wallpaper.ts +9 -8
- package/lib/routes/byau/namespace.ts +6 -0
- package/lib/routes/byau/xinwen/index.ts +72 -0
- package/lib/routes/cpcaauto/index.ts +255 -0
- package/lib/routes/cpcaauto/namespace.ts +8 -0
- package/lib/routes/dehenglaw/index.ts +128 -0
- package/lib/routes/dehenglaw/namespace.ts +8 -0
- package/lib/routes/dehenglaw/templates/description.art +7 -0
- package/lib/routes/gov/stats/index.ts +25 -22
- package/lib/routes/gxmzu/ai.ts +1 -1
- package/lib/routes/gxmzu/lib.ts +9 -26
- package/lib/routes/gxmzu/utils/index.ts +31 -13
- package/lib/routes/gxmzu/yjs.ts +1 -1
- package/lib/routes/jou/utils/index.ts +35 -25
- package/lib/routes/lofter/tag.ts +3 -3
- package/lib/routes/lofter/user.ts +3 -3
- package/lib/routes/njxzc/utils/index.ts +31 -13
- package/lib/routes/qingting/podcast.ts +61 -39
- package/lib/routes/reuters/common.ts +2 -2
- package/lib/routes/sara/index.ts +66 -0
- package/lib/routes/sara/namespace.ts +6 -0
- package/lib/routes/tencent/news/author.ts +13 -11
- package/lib/routes/test/index.ts +11 -1
- package/lib/routes/twitter/api/mobile-api/login.ts +29 -28
- package/lib/routes/twitter/namespace.ts +2 -2
- package/lib/routes/twitter/user.ts +5 -0
- package/lib/routes/u3c3/index.ts +1 -1
- package/lib/routes/u3c3/namespace.ts +1 -1
- package/lib/routes/u9a9/index.ts +2 -2
- package/lib/routes/u9a9/namespace.ts +1 -1
- package/lib/routes/zsxq/group.ts +63 -0
- package/lib/routes/zsxq/namespace.ts +6 -0
- package/lib/routes/zsxq/types.ts +149 -0
- package/lib/routes/zsxq/user.ts +58 -0
- package/lib/routes/zsxq/utils.ts +70 -0
- package/lib/setup.test.ts +183 -12
- package/lib/utils/render.ts +1 -1
- package/lib/utils/request-rewriter/get.ts +8 -1
- package/lib/utils/wechat-mp.test.ts +411 -32
- package/lib/utils/wechat-mp.ts +447 -76
- package/lib/views/{rss3-ums.ts → rss3.ts} +2 -2
- package/package.json +14 -14
package/lib/config.ts
CHANGED
|
@@ -230,6 +230,9 @@ export type Config = {
|
|
|
230
230
|
pkubbs: {
|
|
231
231
|
cookie?: string;
|
|
232
232
|
};
|
|
233
|
+
qingting: {
|
|
234
|
+
id?: string;
|
|
235
|
+
};
|
|
233
236
|
saraba1st: {
|
|
234
237
|
cookie?: string;
|
|
235
238
|
};
|
|
@@ -258,6 +261,7 @@ export type Config = {
|
|
|
258
261
|
oauthTokenSecrets?: string[];
|
|
259
262
|
username?: string;
|
|
260
263
|
password?: string;
|
|
264
|
+
authenticationSecret?: string;
|
|
261
265
|
cookie?: string;
|
|
262
266
|
};
|
|
263
267
|
weibo: {
|
|
@@ -294,6 +298,9 @@ export type Config = {
|
|
|
294
298
|
zodgame: {
|
|
295
299
|
cookie?: string;
|
|
296
300
|
};
|
|
301
|
+
zsxq: {
|
|
302
|
+
accessToken?: string;
|
|
303
|
+
};
|
|
297
304
|
};
|
|
298
305
|
|
|
299
306
|
const value: Config | Record<string, any> = {};
|
|
@@ -575,6 +582,9 @@ const calculateValue = () => {
|
|
|
575
582
|
pkubbs: {
|
|
576
583
|
cookie: envs.PKUBBS_COOKIE,
|
|
577
584
|
},
|
|
585
|
+
qingting: {
|
|
586
|
+
id: envs.QINGTING_ID,
|
|
587
|
+
},
|
|
578
588
|
saraba1st: {
|
|
579
589
|
cookie: envs.SARABA1ST_COOKIE,
|
|
580
590
|
},
|
|
@@ -607,6 +617,7 @@ const calculateValue = () => {
|
|
|
607
617
|
oauthTokenSecrets: envs.TWITTER_OAUTH_TOKEN_SECRET?.split(','),
|
|
608
618
|
username: envs.TWITTER_USERNAME,
|
|
609
619
|
password: envs.TWITTER_PASSWORD,
|
|
620
|
+
authenticationSecret: envs.TWITTER_AUTHENTICATION_SECRET,
|
|
610
621
|
cookie: envs.TWITTER_COOKIE,
|
|
611
622
|
},
|
|
612
623
|
weibo: {
|
|
@@ -643,6 +654,9 @@ const calculateValue = () => {
|
|
|
643
654
|
zodgame: {
|
|
644
655
|
cookie: envs.ZODGAME_COOKIE,
|
|
645
656
|
},
|
|
657
|
+
zsxq: {
|
|
658
|
+
accessToken: envs.ZSXQ_ACCESS_TOKEN,
|
|
659
|
+
},
|
|
646
660
|
};
|
|
647
661
|
|
|
648
662
|
for (const name in _value) {
|
package/lib/errors/index.test.ts
CHANGED
|
@@ -66,13 +66,13 @@ describe('route throws an error', () => {
|
|
|
66
66
|
expect(value).toBe('9');
|
|
67
67
|
break;
|
|
68
68
|
case 'Hot Routes:':
|
|
69
|
-
expect(value).toBe('6 /test/:id
|
|
69
|
+
expect(value).toBe('6 /test/:id/:params?<br>');
|
|
70
70
|
break;
|
|
71
71
|
case 'Hot Paths:':
|
|
72
72
|
expect(value).toBe('2 /test/error<br>2 /test/slow<br>1 /test/httperror<br>1 /test/config-not-found-error<br>1 /test/invalid-parameter-error<br>1 /thisDoesNotExist<br>1 /<br>');
|
|
73
73
|
break;
|
|
74
74
|
case 'Hot Error Routes:':
|
|
75
|
-
expect(value).toBe('5 /test/:id
|
|
75
|
+
expect(value).toBe('5 /test/:id/:params?<br>');
|
|
76
76
|
break;
|
|
77
77
|
case 'Hot Error Paths:':
|
|
78
78
|
expect(value).toBe('2 /test/error<br>1 /test/httperror<br>1 /test/slow<br>1 /test/config-not-found-error<br>1 /test/invalid-parameter-error<br>1 /thisDoesNotExist<br>');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { rss3, json, RSS, Atom } from '@/utils/render';
|
|
2
2
|
import { config } from '@/config';
|
|
3
3
|
import { collapseWhitespace, convertDateToISO8601 } from '@/utils/common-utils';
|
|
4
4
|
import type { MiddlewareHandler } from 'hono';
|
|
@@ -48,6 +48,14 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
if (item.description) {
|
|
52
|
+
// https://stackoverflow.com/questions/2507608/error-input-is-not-proper-utf-8-indicate-encoding-using-phps-simplexml-lo/40552083#40552083
|
|
53
|
+
// https://stackoverflow.com/questions/1497885/remove-control-characters-from-php-string/1497928#1497928
|
|
54
|
+
// remove unicode control characters
|
|
55
|
+
// see #14940 #14943 #15262
|
|
56
|
+
item.description = item.description.replaceAll(/[\u0000-\u0009\u000B\u000C\u000E-\u001F\u007F]/g, '');
|
|
57
|
+
}
|
|
58
|
+
|
|
51
59
|
if (typeof item.author === 'string') {
|
|
52
60
|
item.author = collapseWhitespace(item.author) || '';
|
|
53
61
|
} else if (typeof item.author === 'object' && item.author !== null) {
|
|
@@ -86,8 +94,9 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
|
|
|
86
94
|
return ctx.json(result);
|
|
87
95
|
}
|
|
88
96
|
|
|
89
|
-
|
|
90
|
-
|
|
97
|
+
// retain .ums for backward compatibility
|
|
98
|
+
if (outputType === 'ums' || outputType === 'rss3') {
|
|
99
|
+
return ctx.json(rss3(result));
|
|
91
100
|
} else if (outputType === 'json') {
|
|
92
101
|
ctx.header('Content-Type', 'application/feed+json; charset=UTF-8');
|
|
93
102
|
return ctx.body(json(result));
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { Route } from '@/types';
|
|
2
|
+
|
|
3
|
+
import cache from '@/utils/cache';
|
|
4
|
+
import got from '@/utils/got';
|
|
5
|
+
import { load } from 'cheerio';
|
|
6
|
+
import { parseDate } from '@/utils/parse-date';
|
|
7
|
+
|
|
8
|
+
export const route: Route = {
|
|
9
|
+
path: '/blog',
|
|
10
|
+
categories: ['blog'],
|
|
11
|
+
example: '/0x80/blog',
|
|
12
|
+
url: '0x80.pl/notesen.html',
|
|
13
|
+
name: 'Articles',
|
|
14
|
+
maintainers: ['xnum'],
|
|
15
|
+
handler,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function extractDateFromURL(url: string) {
|
|
19
|
+
const regex = /\d{4}-\d{2}-\d{2}/;
|
|
20
|
+
const match = url.match(regex);
|
|
21
|
+
|
|
22
|
+
return match ? match[0] : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function handler() {
|
|
26
|
+
// The TLS cert is invalid, we are limited to use HTTP unfortunately.
|
|
27
|
+
const baseUrl = 'http://0x80.pl/';
|
|
28
|
+
const targetUrl = `${baseUrl}notesen.html`;
|
|
29
|
+
|
|
30
|
+
const response = await got({
|
|
31
|
+
method: 'get',
|
|
32
|
+
url: targetUrl,
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
const $ = load(response.data);
|
|
36
|
+
|
|
37
|
+
const alist = $('a.reference.external');
|
|
38
|
+
|
|
39
|
+
const list = alist
|
|
40
|
+
.toArray()
|
|
41
|
+
.map((item) => {
|
|
42
|
+
item = $(item);
|
|
43
|
+
|
|
44
|
+
const link = item.attr('href') || '';
|
|
45
|
+
const title = item.text() || '';
|
|
46
|
+
const pubDate = extractDateFromURL(link);
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
title,
|
|
50
|
+
link,
|
|
51
|
+
pubDate,
|
|
52
|
+
category: 'Uncategoried',
|
|
53
|
+
};
|
|
54
|
+
})
|
|
55
|
+
.filter((item) => item.link.startsWith('notesen'));
|
|
56
|
+
|
|
57
|
+
const items = await Promise.all(
|
|
58
|
+
list.map((item) =>
|
|
59
|
+
cache.tryGet(item.link, async () => {
|
|
60
|
+
const articleUrl = `${baseUrl}${item.link}`;
|
|
61
|
+
const response = await got({
|
|
62
|
+
method: 'get',
|
|
63
|
+
url: articleUrl,
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const $ = load(response.data);
|
|
67
|
+
|
|
68
|
+
const author = $('tr.author.field td.field-body').text();
|
|
69
|
+
const articlePubDate = $('tr.added-on.field td.field-body').text();
|
|
70
|
+
|
|
71
|
+
item.author = author;
|
|
72
|
+
// Some articles might be missing the added-on field.
|
|
73
|
+
// As a safeguard, if the date from url is null, fallbacks to the article one.
|
|
74
|
+
item.pubDate = parseDate(item.pubDate || articlePubDate);
|
|
75
|
+
item.description = $('div.document').first().html();
|
|
76
|
+
|
|
77
|
+
return item;
|
|
78
|
+
})
|
|
79
|
+
)
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
title: '0x80.pl articles',
|
|
84
|
+
link: targetUrl,
|
|
85
|
+
item: items,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -4,11 +4,10 @@ const __dirname = getCurrentPath(import.meta.url);
|
|
|
4
4
|
|
|
5
5
|
import { getSubPath } from '@/utils/common-utils';
|
|
6
6
|
import cache from '@/utils/cache';
|
|
7
|
-
import got from '@/utils/got';
|
|
8
7
|
import { load } from 'cheerio';
|
|
9
|
-
import { parseDate } from '@/utils/parse-date';
|
|
10
8
|
import { art } from '@/utils/render';
|
|
11
9
|
import path from 'node:path';
|
|
10
|
+
import { ofetch } from 'ofetch';
|
|
12
11
|
|
|
13
12
|
const languages = {
|
|
14
13
|
arabic: {
|
|
@@ -45,12 +44,8 @@ async function handler(ctx) {
|
|
|
45
44
|
const rootUrl = languages[language].rootUrl;
|
|
46
45
|
const currentUrl = `${rootUrl}/${isRSS ? languages[language].rssUrl : params.join('/')}`;
|
|
47
46
|
|
|
48
|
-
const response = await
|
|
49
|
-
|
|
50
|
-
url: currentUrl,
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
const $ = load(response.data);
|
|
47
|
+
const response = await ofetch(currentUrl);
|
|
48
|
+
const $ = load(response);
|
|
54
49
|
|
|
55
50
|
let items = isRSS
|
|
56
51
|
? response.data.match(new RegExp('<link>' + rootUrl + '/(.*?)</link>', 'g')).map((item) => ({
|
|
@@ -69,19 +64,27 @@ async function handler(ctx) {
|
|
|
69
64
|
items = await Promise.all(
|
|
70
65
|
items.slice(0, ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit')) : 50).map((item) =>
|
|
71
66
|
cache.tryGet(item.link, async () => {
|
|
72
|
-
const detailResponse = await
|
|
73
|
-
method: 'get',
|
|
74
|
-
url: item.link,
|
|
75
|
-
});
|
|
67
|
+
const detailResponse = await ofetch(item.link);
|
|
76
68
|
|
|
77
|
-
const content = load(detailResponse
|
|
69
|
+
const content = load(detailResponse);
|
|
78
70
|
|
|
79
71
|
content('.more-on').parent().remove();
|
|
80
72
|
content('.responsive-image img').removeAttr('srcset');
|
|
73
|
+
let pubDate;
|
|
74
|
+
|
|
75
|
+
const datePublished = detailResponse.match(/"datePublished": ?"(.*?)",/);
|
|
76
|
+
if (datePublished && datePublished.length > 1) {
|
|
77
|
+
pubDate = detailResponse.match(/"datePublished": ?"(.*?)",/)[1];
|
|
78
|
+
} else {
|
|
79
|
+
// uploadDate replaces datePublished for video articles
|
|
80
|
+
const uploadDate = detailResponse.match(/"uploadDate": ?"(.*?)",/)[1];
|
|
81
|
+
|
|
82
|
+
pubDate = uploadDate && uploadDate.length > 1 ? uploadDate : content('div.date-simple > span:nth-child(2)').text();
|
|
83
|
+
}
|
|
81
84
|
|
|
82
85
|
item.title = content('h1').first().text();
|
|
83
86
|
item.author = content('.author').text();
|
|
84
|
-
item.pubDate =
|
|
87
|
+
item.pubDate = pubDate;
|
|
85
88
|
item.description = art(path.join(__dirname, 'templates/description.art'), {
|
|
86
89
|
image: content('.article-featured-image').html(),
|
|
87
90
|
description: content('.wysiwyg').html(),
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Route } from '@/types';
|
|
2
|
+
import got from '@/utils/got';
|
|
3
|
+
import { load } from 'cheerio';
|
|
4
|
+
import { parseDate } from '@/utils/parse-date';
|
|
5
|
+
|
|
6
|
+
export const route: Route = {
|
|
7
|
+
path: '/podcast/:id',
|
|
8
|
+
categories: ['multimedia'],
|
|
9
|
+
example: '/apple/podcast/id1559695855',
|
|
10
|
+
parameters: { id: '播客id,可以在 Apple 播客app 内分享的播客的 URL 中找到' },
|
|
11
|
+
features: {
|
|
12
|
+
requireConfig: false,
|
|
13
|
+
requirePuppeteer: false,
|
|
14
|
+
antiCrawler: false,
|
|
15
|
+
supportBT: false,
|
|
16
|
+
supportPodcast: false,
|
|
17
|
+
supportScihub: false,
|
|
18
|
+
},
|
|
19
|
+
radar: [
|
|
20
|
+
{
|
|
21
|
+
source: ['podcasts.apple.com/cn/podcast/:id'],
|
|
22
|
+
},
|
|
23
|
+
],
|
|
24
|
+
name: '播客',
|
|
25
|
+
maintainers: ['Acring'],
|
|
26
|
+
handler,
|
|
27
|
+
url: 'https://www.apple.com.cn/apple-podcasts/',
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
async function handler(ctx) {
|
|
31
|
+
const link = `https://podcasts.apple.com/cn/podcast/${ctx.req.param('id')}`;
|
|
32
|
+
const response = await got({
|
|
33
|
+
method: 'get',
|
|
34
|
+
url: link,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const $ = load(response.data);
|
|
38
|
+
|
|
39
|
+
const page_data = JSON.parse($('#shoebox-media-api-cache-amp-podcasts').text());
|
|
40
|
+
|
|
41
|
+
const data = JSON.parse(page_data[Object.keys(page_data)[0]]).d[0];
|
|
42
|
+
const attributes = data.attributes;
|
|
43
|
+
|
|
44
|
+
const episodes = data.relationships.episodes.data.map((item) => {
|
|
45
|
+
const attr = item.attributes;
|
|
46
|
+
return {
|
|
47
|
+
title: attr.name,
|
|
48
|
+
enclosure_url: attr.assetUrl,
|
|
49
|
+
itunes_duration: attr.durationInMilliseconds / 1000,
|
|
50
|
+
enclosure_type: 'audio/mp4',
|
|
51
|
+
link: attr.url,
|
|
52
|
+
pubDate: parseDate(attr.releaseDateTime),
|
|
53
|
+
description: attr.description.standard.replaceAll('\n', '<br>'),
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
title: attributes.name,
|
|
59
|
+
link: attributes.url,
|
|
60
|
+
itunes_author: attributes.artistName,
|
|
61
|
+
item: episodes,
|
|
62
|
+
description: attributes.description.standard,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { Route } from '@/types';
|
|
2
|
-
import
|
|
2
|
+
import ofetch from '@/utils/ofetch';
|
|
3
|
+
import { parseDate } from '@/utils/parse-date';
|
|
4
|
+
import timezone from '@/utils/timezone';
|
|
3
5
|
|
|
4
6
|
export const route: Route = {
|
|
5
7
|
path: '/',
|
|
@@ -9,25 +11,23 @@ export const route: Route = {
|
|
|
9
11
|
target: '',
|
|
10
12
|
},
|
|
11
13
|
],
|
|
12
|
-
name: '
|
|
14
|
+
name: '每日壁纸',
|
|
13
15
|
maintainers: ['FHYunCai'],
|
|
14
16
|
handler,
|
|
15
17
|
url: 'cn.bing.com/',
|
|
16
18
|
};
|
|
17
19
|
|
|
18
20
|
async function handler(ctx) {
|
|
19
|
-
const response = await
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
url: 'HPImageArchive.aspx',
|
|
23
|
-
searchParams: {
|
|
21
|
+
const response = await ofetch('HPImageArchive.aspx', {
|
|
22
|
+
baseURL: 'https://cn.bing.com',
|
|
23
|
+
query: {
|
|
24
24
|
format: 'js',
|
|
25
25
|
idx: 0,
|
|
26
26
|
n: ctx.req.query('limit') ? Number.parseInt(ctx.req.query('limit'), 10) : 7,
|
|
27
27
|
mkt: 'zh-CN',
|
|
28
28
|
},
|
|
29
29
|
});
|
|
30
|
-
const data = response
|
|
30
|
+
const data = response;
|
|
31
31
|
return {
|
|
32
32
|
title: 'Bing每日壁纸',
|
|
33
33
|
link: 'https://cn.bing.com/',
|
|
@@ -35,6 +35,7 @@ async function handler(ctx) {
|
|
|
35
35
|
title: item.copyright,
|
|
36
36
|
description: `<img src="https://cn.bing.com${item.url}">`,
|
|
37
37
|
link: item.copyrightlink,
|
|
38
|
+
pubDate: timezone(parseDate(item.fullstartdate), 0),
|
|
38
39
|
})),
|
|
39
40
|
};
|
|
40
41
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Route } from '@/types';
|
|
2
|
+
import cache from '@/utils/cache';
|
|
3
|
+
import got from '@/utils/got';
|
|
4
|
+
import { load } from 'cheerio';
|
|
5
|
+
import { parseDate } from '@/utils/parse-date';
|
|
6
|
+
import timezone from '@/utils/timezone';
|
|
7
|
+
|
|
8
|
+
export const route: Route = {
|
|
9
|
+
path: '/news/:type_id',
|
|
10
|
+
categories: ['university'],
|
|
11
|
+
example: '/byau/news/3674',
|
|
12
|
+
parameters: { type_id: '栏目类型(从菜单栏获取对应 ID)' },
|
|
13
|
+
radar: [
|
|
14
|
+
{
|
|
15
|
+
source: ['xinwen.byau.edu.cn/:type_id/list.htm'],
|
|
16
|
+
target: '/news/:type_id',
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
name: '新闻网',
|
|
20
|
+
maintainers: ['ueiu'],
|
|
21
|
+
handler,
|
|
22
|
+
url: 'xinwen.byau.edu.cn',
|
|
23
|
+
description: `| 学校要闻 | 校园动态 |
|
|
24
|
+
| ---- | ----------- |
|
|
25
|
+
| 3674 | 3676 |`,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
async function handler(ctx) {
|
|
29
|
+
const baseUrl = 'http://xinwen.byau.edu.cn/';
|
|
30
|
+
|
|
31
|
+
const typeID = ctx.req.param('type_id');
|
|
32
|
+
const url = `${baseUrl}${typeID}/list.htm`;
|
|
33
|
+
|
|
34
|
+
const response = await got(url);
|
|
35
|
+
const $ = load(response.data);
|
|
36
|
+
|
|
37
|
+
const list = $('.news')
|
|
38
|
+
.toArray()
|
|
39
|
+
.map((item) => {
|
|
40
|
+
const $$ = load(item);
|
|
41
|
+
|
|
42
|
+
const originalItemUrl = $$('a').attr('href');
|
|
43
|
+
// 因为学校要闻的头两个像是固定了跳转专栏页面的,不能相同处理
|
|
44
|
+
const startsWithHttp = originalItemUrl.startsWith('http');
|
|
45
|
+
const itemUrl = startsWithHttp ? originalItemUrl : new URL(originalItemUrl, baseUrl).href;
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
title: $$('a').text(),
|
|
49
|
+
link: itemUrl,
|
|
50
|
+
pubDate: timezone(parseDate($$('.news_meta').text()), +8),
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const items = await Promise.all(
|
|
55
|
+
list.map((item) =>
|
|
56
|
+
cache.tryGet(item.link, async () => {
|
|
57
|
+
const response = await got(item.link);
|
|
58
|
+
const $ = load(response.data);
|
|
59
|
+
|
|
60
|
+
item.description = $('.col_news_con').html();
|
|
61
|
+
|
|
62
|
+
return item;
|
|
63
|
+
})
|
|
64
|
+
)
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
title: $('title').text(),
|
|
69
|
+
link: url,
|
|
70
|
+
item: items,
|
|
71
|
+
};
|
|
72
|
+
}
|