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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rsshub",
|
|
3
|
-
"version": "1.0.0-master.
|
|
3
|
+
"version": "1.0.0-master.f6f0273",
|
|
4
4
|
"description": "Make RSS Great Again!",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"RSS"
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"@bbob/html": "4.2.0",
|
|
36
36
|
"@bbob/preset-html5": "4.2.0",
|
|
37
37
|
"@hono/node-server": "1.13.8",
|
|
38
|
-
"@hono/zod-openapi": "0.
|
|
39
|
-
"@notionhq/client": "2.
|
|
38
|
+
"@hono/zod-openapi": "0.19.2",
|
|
39
|
+
"@notionhq/client": "2.3.0",
|
|
40
40
|
"@opentelemetry/api": "1.9.0",
|
|
41
41
|
"@opentelemetry/exporter-prometheus": "0.57.2",
|
|
42
42
|
"@opentelemetry/exporter-trace-otlp-http": "0.57.2",
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
"@opentelemetry/semantic-conventions": "1.30.0",
|
|
47
47
|
"@postlight/parser": "2.2.3",
|
|
48
48
|
"@rss3/sdk": "0.0.25",
|
|
49
|
-
"@scalar/hono-api-reference": "0.
|
|
50
|
-
"@sentry/node": "
|
|
51
|
-
"@tonyrl/rand-user-agent": "2.0.
|
|
49
|
+
"@scalar/hono-api-reference": "0.6.0",
|
|
50
|
+
"@sentry/node": "9.5.0",
|
|
51
|
+
"@tonyrl/rand-user-agent": "2.0.83",
|
|
52
52
|
"aes-js": "3.1.2",
|
|
53
53
|
"art-template": "4.13.2",
|
|
54
54
|
"cheerio": "1.0.0",
|
|
@@ -65,18 +65,19 @@
|
|
|
65
65
|
"etag": "1.8.1",
|
|
66
66
|
"fanfou-sdk": "5.0.0",
|
|
67
67
|
"form-data": "4.0.2",
|
|
68
|
-
"googleapis": "
|
|
69
|
-
"hono": "4.7.
|
|
68
|
+
"googleapis": "146.0.0",
|
|
69
|
+
"hono": "4.7.4",
|
|
70
70
|
"html-to-text": "9.0.5",
|
|
71
71
|
"http-cookie-agent": "6.0.8",
|
|
72
72
|
"https-proxy-agent": "7.0.6",
|
|
73
73
|
"iconv-lite": "0.6.3",
|
|
74
|
-
"imapflow": "1.0.
|
|
74
|
+
"imapflow": "1.0.184",
|
|
75
75
|
"instagram-private-api": "1.46.1",
|
|
76
|
-
"ioredis": "5.
|
|
76
|
+
"ioredis": "5.6.0",
|
|
77
77
|
"ip-regex": "5.0.0",
|
|
78
78
|
"jsdom": "26.0.0",
|
|
79
79
|
"json-bigint": "1.0.0",
|
|
80
|
+
"jsonpath-plus": "10.3.0",
|
|
80
81
|
"jsrsasign": "10.9.0",
|
|
81
82
|
"lru-cache": "11.0.2",
|
|
82
83
|
"lz-string": "1.5.0",
|
|
@@ -84,20 +85,20 @@
|
|
|
84
85
|
"markdown-it": "14.1.0",
|
|
85
86
|
"module-alias": "2.2.3",
|
|
86
87
|
"narou": "1.1.0",
|
|
87
|
-
"notion-to-md": "3.1.
|
|
88
|
+
"notion-to-md": "3.1.7",
|
|
88
89
|
"oauth-1.0a": "2.2.6",
|
|
89
90
|
"ofetch": "1.4.1",
|
|
90
91
|
"otplib": "12.0.1",
|
|
91
92
|
"pac-proxy-agent": "7.2.0",
|
|
92
|
-
"proxy-chain": "2.5.
|
|
93
|
+
"proxy-chain": "2.5.7",
|
|
93
94
|
"puppeteer": "22.6.2",
|
|
94
95
|
"puppeteer-extra": "3.3.6",
|
|
95
96
|
"puppeteer-extra-plugin-stealth": "2.11.2",
|
|
96
97
|
"puppeteer-extra-plugin-user-data-dir": "2.4.1",
|
|
97
98
|
"puppeteer-extra-plugin-user-preferences": "2.4.1",
|
|
98
99
|
"query-string": "9.1.1",
|
|
99
|
-
"rate-limiter-flexible": "
|
|
100
|
-
"re2js": "1.0
|
|
100
|
+
"rate-limiter-flexible": "6.1.0",
|
|
101
|
+
"re2js": "1.1.0",
|
|
101
102
|
"rfc4648": "1.5.4",
|
|
102
103
|
"rss-parser": "3.13.0",
|
|
103
104
|
"sanitize-html": "2.14.0",
|
|
@@ -107,13 +108,13 @@
|
|
|
107
108
|
"telegram": "2.26.22",
|
|
108
109
|
"tiny-async-pool": "2.1.0",
|
|
109
110
|
"title": "4.0.1",
|
|
110
|
-
"tldts": "6.1.
|
|
111
|
+
"tldts": "6.1.84",
|
|
111
112
|
"tosource": "2.0.0-alpha.3",
|
|
112
|
-
"tough-cookie": "5.1.
|
|
113
|
+
"tough-cookie": "5.1.2",
|
|
113
114
|
"tsx": "4.19.3",
|
|
114
|
-
"twitter-api-v2": "1.20.
|
|
115
|
+
"twitter-api-v2": "1.20.2",
|
|
115
116
|
"ufo": "1.5.4",
|
|
116
|
-
"undici": "6.21.
|
|
117
|
+
"undici": "6.21.2",
|
|
117
118
|
"uuid": "11.1.0",
|
|
118
119
|
"winston": "3.17.0",
|
|
119
120
|
"xxhash-wasm": "1.1.0",
|
|
@@ -123,10 +124,10 @@
|
|
|
123
124
|
"@babel/preset-env": "7.26.9",
|
|
124
125
|
"@babel/preset-typescript": "7.26.0",
|
|
125
126
|
"@bbob/types": "4.2.0",
|
|
126
|
-
"@eslint/eslintrc": "3.
|
|
127
|
-
"@eslint/js": "9.
|
|
127
|
+
"@eslint/eslintrc": "3.3.0",
|
|
128
|
+
"@eslint/js": "9.22.0",
|
|
128
129
|
"@microsoft/eslint-formatter-sarif": "3.1.0",
|
|
129
|
-
"@stylistic/eslint-plugin": "4.0
|
|
130
|
+
"@stylistic/eslint-plugin": "4.2.0",
|
|
130
131
|
"@types/aes-js": "3.1.4",
|
|
131
132
|
"@types/babel__preset-env": "7.10.0",
|
|
132
133
|
"@types/crypto-js": "4.2.2",
|
|
@@ -134,7 +135,7 @@
|
|
|
134
135
|
"@types/etag": "1.8.3",
|
|
135
136
|
"@types/fs-extra": "11.0.4",
|
|
136
137
|
"@types/html-to-text": "9.0.4",
|
|
137
|
-
"@types/imapflow": "1.0.
|
|
138
|
+
"@types/imapflow": "1.0.20",
|
|
138
139
|
"@types/js-beautify": "1.14.3",
|
|
139
140
|
"@types/jsdom": "21.1.7",
|
|
140
141
|
"@types/json-bigint": "1.0.4",
|
|
@@ -143,41 +144,41 @@
|
|
|
143
144
|
"@types/mailparser": "3.4.5",
|
|
144
145
|
"@types/markdown-it": "14.1.2",
|
|
145
146
|
"@types/module-alias": "2.0.4",
|
|
146
|
-
"@types/node": "22.13.
|
|
147
|
+
"@types/node": "22.13.10",
|
|
147
148
|
"@types/sanitize-html": "2.13.0",
|
|
148
149
|
"@types/supertest": "6.0.2",
|
|
149
150
|
"@types/tiny-async-pool": "2.0.3",
|
|
150
151
|
"@types/title": "3.4.3",
|
|
151
152
|
"@types/uuid": "10.0.0",
|
|
152
|
-
"@typescript-eslint/eslint-plugin": "8.
|
|
153
|
-
"@typescript-eslint/parser": "8.
|
|
154
|
-
"@vercel/nft": "0.29.
|
|
153
|
+
"@typescript-eslint/eslint-plugin": "8.26.1",
|
|
154
|
+
"@typescript-eslint/parser": "8.26.1",
|
|
155
|
+
"@vercel/nft": "0.29.2",
|
|
155
156
|
"@vitest/coverage-v8": "2.1.9",
|
|
156
157
|
"discord-api-types": "0.37.119",
|
|
157
|
-
"eslint": "9.
|
|
158
|
-
"eslint-config-prettier": "10.
|
|
158
|
+
"eslint": "9.22.0",
|
|
159
|
+
"eslint-config-prettier": "10.1.1",
|
|
159
160
|
"eslint-nibble": "8.1.0",
|
|
160
|
-
"eslint-plugin-n": "17.
|
|
161
|
+
"eslint-plugin-n": "17.16.2",
|
|
161
162
|
"eslint-plugin-prettier": "5.2.3",
|
|
162
163
|
"eslint-plugin-unicorn": "57.0.0",
|
|
163
164
|
"eslint-plugin-yml": "1.17.0",
|
|
164
165
|
"fs-extra": "11.3.0",
|
|
165
|
-
"globals": "
|
|
166
|
+
"globals": "16.0.0",
|
|
166
167
|
"got": "14.4.6",
|
|
167
168
|
"husky": "9.1.7",
|
|
168
|
-
"js-beautify": "1.15.
|
|
169
|
-
"lint-staged": "15.
|
|
169
|
+
"js-beautify": "1.15.4",
|
|
170
|
+
"lint-staged": "15.5.0",
|
|
170
171
|
"mockdate": "3.0.5",
|
|
171
172
|
"msw": "2.4.3",
|
|
172
173
|
"node-network-devtools": "1.0.25",
|
|
173
|
-
"prettier": "3.5.
|
|
174
|
+
"prettier": "3.5.3",
|
|
174
175
|
"remark-parse": "11.0.0",
|
|
175
176
|
"supertest": "7.0.0",
|
|
176
|
-
"typescript": "5.
|
|
177
|
+
"typescript": "5.8.2",
|
|
177
178
|
"unified": "11.0.5",
|
|
178
179
|
"vite-tsconfig-paths": "5.1.4",
|
|
179
180
|
"vitest": "2.1.9",
|
|
180
|
-
"yaml-eslint-parser": "1.
|
|
181
|
+
"yaml-eslint-parser": "1.3.0"
|
|
181
182
|
},
|
|
182
183
|
"engines": {
|
|
183
184
|
"node": ">=22"
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
import InvalidParameterError from '@/errors/types/invalid-parameter';
|
|
2
|
-
import { Route } from '@/types';
|
|
3
|
-
import cache from '@/utils/cache';
|
|
4
|
-
import got from '@/utils/got';
|
|
5
|
-
import { load } from 'cheerio';
|
|
6
|
-
|
|
7
|
-
export const route: Route = {
|
|
8
|
-
path: '/category/:category',
|
|
9
|
-
categories: ['new-media', 'popular'],
|
|
10
|
-
example: '/gcores/category/news',
|
|
11
|
-
parameters: { category: '分类名' },
|
|
12
|
-
features: {
|
|
13
|
-
requireConfig: false,
|
|
14
|
-
requirePuppeteer: false,
|
|
15
|
-
antiCrawler: false,
|
|
16
|
-
supportBT: false,
|
|
17
|
-
supportPodcast: false,
|
|
18
|
-
supportScihub: false,
|
|
19
|
-
},
|
|
20
|
-
radar: [
|
|
21
|
-
{
|
|
22
|
-
source: ['gcores.com/:category'],
|
|
23
|
-
},
|
|
24
|
-
],
|
|
25
|
-
name: '分类',
|
|
26
|
-
maintainers: ['MoguCloud', 'StevenRCE0'],
|
|
27
|
-
handler,
|
|
28
|
-
description: `| 资讯 | 视频 | 电台 | 文章 |
|
|
29
|
-
| ---- | ------ | ------ | -------- |
|
|
30
|
-
| news | videos | radios | articles |`,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
async function handler(ctx) {
|
|
34
|
-
const category = ctx.req.param('category');
|
|
35
|
-
const url = `https://www.gcores.com/${category}`;
|
|
36
|
-
const res = await got({
|
|
37
|
-
method: 'get',
|
|
38
|
-
url,
|
|
39
|
-
});
|
|
40
|
-
const data = res.data;
|
|
41
|
-
const $ = load(data);
|
|
42
|
-
const feedTitle = $('title').text();
|
|
43
|
-
|
|
44
|
-
let list =
|
|
45
|
-
category === 'news'
|
|
46
|
-
? $('a.news').map(function () {
|
|
47
|
-
const item = {
|
|
48
|
-
url: $(this).attr('href'),
|
|
49
|
-
title: $(this).find('.news_content>h3').text(),
|
|
50
|
-
};
|
|
51
|
-
return item;
|
|
52
|
-
})
|
|
53
|
-
: $('.original.am_card.original-normal').map(function () {
|
|
54
|
-
const item = {
|
|
55
|
-
url: $(this).find('.am_card_inner>a').attr('href'),
|
|
56
|
-
title: $(this).find('h3.am_card_title').text(),
|
|
57
|
-
category: $(this).find('span.original_category>a').text(),
|
|
58
|
-
};
|
|
59
|
-
return item;
|
|
60
|
-
});
|
|
61
|
-
list = list.get();
|
|
62
|
-
|
|
63
|
-
if (list.length > 0 && list.every((item) => item.url === undefined)) {
|
|
64
|
-
throw new InvalidParameterError('Article URL not found! Please submit an issue on GitHub.');
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
const out = await Promise.all(
|
|
68
|
-
list.map((item) => {
|
|
69
|
-
const articleUrl = `https://www.gcores.com${item.url}`;
|
|
70
|
-
|
|
71
|
-
return cache.tryGet(articleUrl, async () => {
|
|
72
|
-
const itemRes = await got({
|
|
73
|
-
method: 'get',
|
|
74
|
-
url: articleUrl,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const itemPage = itemRes.data;
|
|
78
|
-
const $ = load(itemPage);
|
|
79
|
-
|
|
80
|
-
const articleRaw = await got(`https://www.gcores.com/gapi/v1${item.url}?include=media,category,user`);
|
|
81
|
-
const articleData = articleRaw.data.data;
|
|
82
|
-
const articleMeta = articleRaw.data.included.find((i) => i.type === 'users' && i.id === articleData.relationships.user.data.id);
|
|
83
|
-
const author = articleMeta.attributes.nickname;
|
|
84
|
-
|
|
85
|
-
let cover;
|
|
86
|
-
if (articleData.attributes.cover) {
|
|
87
|
-
cover = `<img src="https://image.gcores.com/${articleData.attributes.cover}" />`;
|
|
88
|
-
} else if (articleData.attributes.thumb) {
|
|
89
|
-
cover = `<img src="https://image.gcores.com/${articleData.attributes.thumb}" />`;
|
|
90
|
-
} else {
|
|
91
|
-
cover = '';
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// replace figure with img
|
|
95
|
-
const articleContent = JSON.parse(articleData.attributes.content);
|
|
96
|
-
const entityRangeMap = {};
|
|
97
|
-
for (const block of articleContent.blocks || []) {
|
|
98
|
-
if (block.entityRanges.length) {
|
|
99
|
-
entityRangeMap[block.key] = block.entityRanges;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
$('figure').each((i, elem) => {
|
|
104
|
-
const keyAttr = elem.attribs['data-offset-key'];
|
|
105
|
-
const keyMatch = /^(\w+)-(\d+)-(\d)$/.exec(keyAttr);
|
|
106
|
-
let actualContent = '';
|
|
107
|
-
if (keyMatch) {
|
|
108
|
-
const [, key, index] = keyMatch;
|
|
109
|
-
if (entityRangeMap[key] && entityRangeMap[key][index]) {
|
|
110
|
-
const entityKey = entityRangeMap[key] && entityRangeMap[key][index].key;
|
|
111
|
-
const entity = articleContent.entityMap[entityKey];
|
|
112
|
-
actualContent = convertEntityToContent(entity);
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
if (actualContent) {
|
|
117
|
-
$(elem).replaceWith(actualContent);
|
|
118
|
-
}
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
// remove editor toolbar img
|
|
122
|
-
$('.md-editor-toolbar').replaceWith('');
|
|
123
|
-
// remove hidden tip block
|
|
124
|
-
$('.story_hidden').replaceWith('');
|
|
125
|
-
|
|
126
|
-
const content = $('.story.story-show').html();
|
|
127
|
-
const basicItem = {
|
|
128
|
-
title: item.title,
|
|
129
|
-
description: cover + content,
|
|
130
|
-
link: articleUrl,
|
|
131
|
-
guid: articleUrl,
|
|
132
|
-
author,
|
|
133
|
-
pubDate: new Date(articleData.attributes['published-at']),
|
|
134
|
-
};
|
|
135
|
-
return category === 'news' ? basicItem : { ...basicItem, category: item.category };
|
|
136
|
-
});
|
|
137
|
-
})
|
|
138
|
-
);
|
|
139
|
-
return {
|
|
140
|
-
title: feedTitle,
|
|
141
|
-
link: url,
|
|
142
|
-
item: out,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
function convertEntityToContent(entity) {
|
|
147
|
-
const { type, data } = entity;
|
|
148
|
-
switch (type) {
|
|
149
|
-
case 'IMAGE':
|
|
150
|
-
return `
|
|
151
|
-
<figure>
|
|
152
|
-
<img src="https://image.gcores.com/${data.path}" alt="${data.caption || ''}">
|
|
153
|
-
${data.caption ? `<figcaption>${data.caption}</figcaption>` : ''}
|
|
154
|
-
</figure>`;
|
|
155
|
-
|
|
156
|
-
case 'GALLERY':
|
|
157
|
-
return data.images
|
|
158
|
-
.map(
|
|
159
|
-
(image, i, arr) => `
|
|
160
|
-
<figure>
|
|
161
|
-
<img src="https://image.gcores.com/${image.path}" alt="${image.caption || ''}">
|
|
162
|
-
<figcaption>${data.caption || ''} (${i + 1}/${arr.length}) ${image.caption || ''}</figcaption>
|
|
163
|
-
</figure>
|
|
164
|
-
`
|
|
165
|
-
)
|
|
166
|
-
.join('');
|
|
167
|
-
|
|
168
|
-
default:
|
|
169
|
-
return '';
|
|
170
|
-
}
|
|
171
|
-
}
|
|
@@ -1,161 +0,0 @@
|
|
|
1
|
-
import { Route } from '@/types';
|
|
2
|
-
import cache from '@/utils/cache';
|
|
3
|
-
/* refer to: ./tag.js (author: @StevenREC0) */
|
|
4
|
-
import got from '@/utils/got';
|
|
5
|
-
|
|
6
|
-
export const route: Route = {
|
|
7
|
-
path: '/collections/:collection',
|
|
8
|
-
categories: ['new-media', 'popular'],
|
|
9
|
-
example: '/gcores/collections/64',
|
|
10
|
-
parameters: { collection: '专题id,可在专题页面的 URL 中找到,如 游戏开发设计心得分享 -- 64' },
|
|
11
|
-
features: {
|
|
12
|
-
requireConfig: false,
|
|
13
|
-
requirePuppeteer: false,
|
|
14
|
-
antiCrawler: true,
|
|
15
|
-
supportBT: false,
|
|
16
|
-
supportPodcast: false,
|
|
17
|
-
supportScihub: false,
|
|
18
|
-
},
|
|
19
|
-
radar: [
|
|
20
|
-
{
|
|
21
|
-
source: ['gcores.com/collections/:collection'],
|
|
22
|
-
},
|
|
23
|
-
],
|
|
24
|
-
name: '专题文章',
|
|
25
|
-
maintainers: ['kudryavka1013'],
|
|
26
|
-
handler,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
async function handler(ctx) {
|
|
30
|
-
// get params
|
|
31
|
-
const collection = ctx.req.param('collection');
|
|
32
|
-
|
|
33
|
-
// feed info
|
|
34
|
-
const baseUrl = `https://www.gcores.com/gapi/v1/collections/${collection}`;
|
|
35
|
-
const baseRes = await got(baseUrl);
|
|
36
|
-
const feedTitle = baseRes.data.data.attributes.title;
|
|
37
|
-
const feedUrl = `https://www.gcores.com/collections/${collection}`;
|
|
38
|
-
|
|
39
|
-
// resolve articles
|
|
40
|
-
const dataUrl = `${baseUrl}/articles?sort=-published-at`;
|
|
41
|
-
const res = await got(dataUrl);
|
|
42
|
-
const list = res.data.data;
|
|
43
|
-
|
|
44
|
-
function wrapInlineTag(strArr, startIdx, endIdx, preString, sufString) {
|
|
45
|
-
if (startIdx === endIdx - 1) {
|
|
46
|
-
strArr[startIdx] = `${preString}${strArr[startIdx]}${sufString}`;
|
|
47
|
-
} else {
|
|
48
|
-
strArr[startIdx] = `${preString}${strArr[startIdx]}`;
|
|
49
|
-
strArr[endIdx - 1] = `${strArr[endIdx - 1]}${sufString}`;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
const items = list.map((item) => {
|
|
54
|
-
const articleUrl = `https://www.gcores.com/${item.type}/${item.id}`;
|
|
55
|
-
return cache.tryGet(articleUrl, () => {
|
|
56
|
-
let cover = '';
|
|
57
|
-
if (item.attributes.cover) {
|
|
58
|
-
cover = `<img src="https://image.gcores.com/${item.attributes.cover}" />`;
|
|
59
|
-
} else if (item.attributes.thumb) {
|
|
60
|
-
cover = `<img src="https://image.gcores.com/${item.attributes.thumb}" />`;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const contentBlocks = JSON.parse(item.attributes.content);
|
|
64
|
-
const { blocks, entityMap } = contentBlocks;
|
|
65
|
-
|
|
66
|
-
function convertBlockToContent(block) {
|
|
67
|
-
const { type, text, entityRanges, inlineStyleRanges } = block;
|
|
68
|
-
let formattedText = text;
|
|
69
|
-
if (entityRanges.length || inlineStyleRanges.length) {
|
|
70
|
-
// split string and insert HTML tag
|
|
71
|
-
const strArr = [...text];
|
|
72
|
-
let isMedia = false;
|
|
73
|
-
if (entityRanges.length) {
|
|
74
|
-
for (const entityRange of entityRanges) {
|
|
75
|
-
const { key, offset, length } = entityRange;
|
|
76
|
-
const startIdx = offset,
|
|
77
|
-
endIdx = offset + length;
|
|
78
|
-
const { data, type } = entityMap[key];
|
|
79
|
-
switch (type) {
|
|
80
|
-
case 'LINK':
|
|
81
|
-
wrapInlineTag(strArr, startIdx, endIdx, `<a href="${data.url || data.href}" target="${data.target || '_blank'}">`, `</a>`);
|
|
82
|
-
break;
|
|
83
|
-
case 'IMAGE':
|
|
84
|
-
formattedText = `<figure><img src="https://image.gcores.com/${data.path}" width="${data.width}" height="${data.height}"/>${data.caption ? `<figcaption>${data.caption}</figcaption>` : ''}</figure>`;
|
|
85
|
-
isMedia = true;
|
|
86
|
-
break;
|
|
87
|
-
case 'EMBED':
|
|
88
|
-
formattedText = `<figure>${data.content}${data.caption ? `<figcaption>${data.caption}</figcaption>` : ''}</figure>`;
|
|
89
|
-
isMedia = true;
|
|
90
|
-
break;
|
|
91
|
-
case 'GALLERY':
|
|
92
|
-
formattedText = `<figure>${data.images.map((image) => `<div><img src="https://image.gcores.com/${image.path}" width="${image.width}" height="${image.height}"/></div>`).join('')}</figure>`;
|
|
93
|
-
isMedia = true;
|
|
94
|
-
break;
|
|
95
|
-
default:
|
|
96
|
-
break;
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (inlineStyleRanges.length) {
|
|
101
|
-
for (const inlineStyleRange of inlineStyleRanges) {
|
|
102
|
-
const { style, offset, length } = inlineStyleRange;
|
|
103
|
-
const startIdx = offset,
|
|
104
|
-
endIdx = offset + length;
|
|
105
|
-
switch (style) {
|
|
106
|
-
case 'BOLD':
|
|
107
|
-
wrapInlineTag(strArr, startIdx, endIdx, `<b>`, `</b>`);
|
|
108
|
-
break;
|
|
109
|
-
case 'UNDERLINE':
|
|
110
|
-
wrapInlineTag(strArr, startIdx, endIdx, `<span style="text-decoration:underline">`, `</span>`);
|
|
111
|
-
break;
|
|
112
|
-
case 'ITALIC':
|
|
113
|
-
wrapInlineTag(strArr, startIdx, endIdx, `<i>`, `</i>`);
|
|
114
|
-
break;
|
|
115
|
-
default:
|
|
116
|
-
break;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
formattedText = isMedia ? formattedText : strArr.join('');
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
/* 未兼容列表,仅展示为段落,有兴趣可以补全:unordered-list-item、ordered-list-item */
|
|
124
|
-
switch (type) {
|
|
125
|
-
case 'unstyled':
|
|
126
|
-
return `<p>${formattedText}</p>`;
|
|
127
|
-
case 'header-one':
|
|
128
|
-
return `<h1>${formattedText}</h1>`;
|
|
129
|
-
case 'header-two':
|
|
130
|
-
return `<h2>${formattedText}</h2>`;
|
|
131
|
-
case 'header-three':
|
|
132
|
-
return `<h3>${formattedText}</h3>`;
|
|
133
|
-
case 'header-four':
|
|
134
|
-
return `<h4>${formattedText}</h4>`;
|
|
135
|
-
case 'header-five':
|
|
136
|
-
return `<h5>${formattedText}</h5>`;
|
|
137
|
-
case 'header-six':
|
|
138
|
-
return `<h6>${formattedText}</h6>`;
|
|
139
|
-
case 'atomic':
|
|
140
|
-
return formattedText;
|
|
141
|
-
default:
|
|
142
|
-
return `<p>${formattedText}</p>`;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
const content = blocks.map((block) => convertBlockToContent(block));
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
title: item.attributes.title,
|
|
149
|
-
description: cover + content.join(''),
|
|
150
|
-
link: articleUrl,
|
|
151
|
-
};
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
// return data
|
|
156
|
-
return {
|
|
157
|
-
title: feedTitle,
|
|
158
|
-
link: feedUrl,
|
|
159
|
-
item: items,
|
|
160
|
-
};
|
|
161
|
-
}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
const got = require('@/utils/got');
|
|
2
|
-
const cheerio = require('cheerio');
|
|
3
|
-
const timezone = require('@/utils/timezone');
|
|
4
|
-
const { parseDate } = require('@/utils/parse-date');
|
|
5
|
-
|
|
6
|
-
module.exports = async (ctx) => {
|
|
7
|
-
const category = ctx.params.category || 'latest';
|
|
8
|
-
|
|
9
|
-
const rootUrl = 'http://www.ltaaa.cn';
|
|
10
|
-
const currentUrl = `${rootUrl}/${category === 'picture' ? category : `article${category === 'latest' ? '' : `/${category}`}`}`;
|
|
11
|
-
|
|
12
|
-
const response = await got({
|
|
13
|
-
method: 'get',
|
|
14
|
-
url: currentUrl,
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
const $ = cheerio.load(response.data);
|
|
18
|
-
|
|
19
|
-
const list = $(category === 'picture' || category === 'curiosities' ? 'dd .title' : '.li-title a')
|
|
20
|
-
.slice(0, 10)
|
|
21
|
-
.map((_, item) => {
|
|
22
|
-
item = $(item);
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
title: item.text(),
|
|
26
|
-
link: `${rootUrl}${item.attr('href')}`,
|
|
27
|
-
};
|
|
28
|
-
})
|
|
29
|
-
.get();
|
|
30
|
-
|
|
31
|
-
const items = await Promise.all(
|
|
32
|
-
list.map((item) =>
|
|
33
|
-
ctx.cache.tryGet(item.link, async () => {
|
|
34
|
-
const detailResponse = await got({
|
|
35
|
-
method: 'get',
|
|
36
|
-
url: item.link,
|
|
37
|
-
});
|
|
38
|
-
const content = cheerio.load(detailResponse.data);
|
|
39
|
-
|
|
40
|
-
if (category === 'picture') {
|
|
41
|
-
item.description = '';
|
|
42
|
-
content('.show li').each(function () {
|
|
43
|
-
item.description += content(this).find('a').html() + (content(this).find('.pic-p').html() || '');
|
|
44
|
-
});
|
|
45
|
-
item.pubDate = parseDate(
|
|
46
|
-
content('.view a img')
|
|
47
|
-
.attr('src')
|
|
48
|
-
.match(/http:\/\/img\.ltaaa\.cn\/uploadfile\/(.*)\/\d+\.jpg/)[1],
|
|
49
|
-
'YYYY/MM/DD'
|
|
50
|
-
);
|
|
51
|
-
} else {
|
|
52
|
-
content('.post-param').find('a, span').remove();
|
|
53
|
-
item.pubDate = timezone(new Date(content('.post-param').text().trim()), +8);
|
|
54
|
-
|
|
55
|
-
content('.post-title, .post-param, .post-keywords, .like-post, .clear, .hook').remove();
|
|
56
|
-
item.description = content('.post-body').html();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
return item;
|
|
60
|
-
})
|
|
61
|
-
)
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
ctx.state.data = {
|
|
65
|
-
title: $('title').text(),
|
|
66
|
-
link: currentUrl,
|
|
67
|
-
item: items,
|
|
68
|
-
};
|
|
69
|
-
};
|