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.
Files changed (88) hide show
  1. package/lib/api/index.ts +1 -6
  2. package/lib/routes/2048/index.ts +24 -23
  3. package/lib/routes/anthropic/news.ts +27 -13
  4. package/lib/routes/asianfanfics/namespace.ts +7 -0
  5. package/lib/routes/asianfanfics/tag.ts +89 -0
  6. package/lib/routes/asianfanfics/text-search.ts +68 -0
  7. package/lib/routes/blockworks/index.ts +128 -0
  8. package/lib/routes/blockworks/namespace.ts +7 -0
  9. package/lib/routes/cmu/andypavlo/blog.ts +55 -0
  10. package/lib/routes/cmu/namespace.ts +7 -0
  11. package/lib/routes/coindesk/{index.ts → consensus-magazine.ts} +17 -21
  12. package/lib/routes/coindesk/namespace.ts +2 -1
  13. package/lib/routes/coindesk/news.ts +47 -0
  14. package/lib/routes/coindesk/utils.ts +26 -0
  15. package/lib/routes/cointelegraph/index.ts +106 -0
  16. package/lib/routes/cointelegraph/namespace.ts +7 -0
  17. package/lib/routes/collabo-cafe/category.ts +37 -0
  18. package/lib/routes/collabo-cafe/index.ts +35 -0
  19. package/lib/routes/collabo-cafe/namespace.ts +9 -0
  20. package/lib/routes/collabo-cafe/parser.ts +29 -0
  21. package/lib/routes/collabo-cafe/tag.ts +37 -0
  22. package/lib/routes/cryptoslate/index.ts +98 -0
  23. package/lib/routes/cryptoslate/namespace.ts +7 -0
  24. package/lib/routes/decrypt/index.ts +115 -0
  25. package/lib/routes/decrypt/namespace.ts +7 -0
  26. package/lib/routes/discuz/discuz.ts +7 -9
  27. package/lib/routes/fangchan/list.ts +224 -0
  28. package/lib/routes/fangchan/namespace.ts +9 -0
  29. package/lib/routes/fangchan/templates/description.art +7 -0
  30. package/lib/routes/foreignaffairs/namespace.ts +7 -0
  31. package/lib/routes/foreignaffairs/rss.ts +55 -0
  32. package/lib/routes/forklog/index.ts +72 -0
  33. package/lib/routes/forklog/namespace.ts +7 -0
  34. package/lib/routes/gcores/categories.ts +129 -0
  35. package/lib/routes/gcores/collections.ts +129 -0
  36. package/lib/routes/gcores/topics.ts +63 -0
  37. package/lib/routes/gov/moa/gjs.ts +210 -0
  38. package/lib/routes/gov/tianjin/tjftz.ts +53 -0
  39. package/lib/routes/gov/tianjin/tjrcgzw.ts +51 -0
  40. package/lib/routes/grainoil/category.ts +207 -0
  41. package/lib/routes/grainoil/namespace.ts +9 -0
  42. package/lib/routes/huxiu/util.ts +11 -9
  43. package/lib/routes/ifanr/category.ts +7 -2
  44. package/lib/routes/ifanr/digest.ts +1 -1
  45. package/lib/routes/ifanr/index.ts +1 -1
  46. package/lib/routes/instructables/projects.ts +20 -15
  47. package/lib/routes/juejin/collections.ts +1 -1
  48. package/lib/routes/komiic/comic.ts +88 -0
  49. package/lib/routes/komiic/namespace.ts +7 -0
  50. package/lib/routes/leagueoflegends/namespace.ts +8 -0
  51. package/lib/routes/leagueoflegends/patch-notes.ts +76 -0
  52. package/lib/routes/likeshop/index.ts +43 -0
  53. package/lib/routes/likeshop/namespace.ts +7 -0
  54. package/lib/routes/ltaaa/article.ts +180 -0
  55. package/lib/routes/ltaaa/namespace.ts +9 -0
  56. package/lib/routes/ltaaa/templates/description.art +7 -0
  57. package/lib/routes/mashiro/index.ts +1 -0
  58. package/lib/routes/nhentai/util.ts +4 -1
  59. package/lib/routes/pinterest/user.ts +9 -0
  60. package/lib/routes/sohu/mp.ts +3 -2
  61. package/lib/routes/spotify/show.ts +1 -1
  62. package/lib/routes/stcn/index.ts +241 -136
  63. package/lib/routes/stcn/kx.ts +144 -0
  64. package/lib/routes/swjtu/namespace.ts +1 -1
  65. package/lib/routes/swjtu/{scai/bks.ts → scai.ts} +34 -20
  66. package/lib/routes/swjtu/sports.ts +77 -0
  67. package/lib/routes/theblock/index.ts +142 -0
  68. package/lib/routes/theblock/namespace.ts +7 -0
  69. package/lib/routes/theverge/index.ts +73 -62
  70. package/lib/routes/theverge/templates/header.art +19 -0
  71. package/lib/routes/threads/index.ts +73 -54
  72. package/lib/routes/threads/utils.ts +60 -78
  73. package/lib/routes/tmtpost/column.ts +298 -0
  74. package/lib/routes/tmtpost/new.ts +4 -199
  75. package/lib/routes/tmtpost/util.ts +207 -0
  76. package/lib/routes/toranoana/namespace.ts +7 -0
  77. package/lib/routes/toranoana/news.ts +110 -0
  78. package/lib/routes/wainao/templates/description.art +9 -0
  79. package/lib/routes/wainao/topics.ts +214 -0
  80. package/lib/routes/xiaoyuzhou/podcast.ts +27 -27
  81. package/lib/routes/xjtu/yz.ts +74 -0
  82. package/lib/routes/youmemark/index.ts +6 -6
  83. package/lib/routes/zaobao/util.ts +11 -3
  84. package/lib/routes/zhihu/answers.ts +26 -54
  85. package/package.json +36 -35
  86. package/lib/routes/gcores/category.ts +0 -171
  87. package/lib/routes/gcores/collection.ts +0 -161
  88. 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.f6cb490",
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.18.4",
39
- "@notionhq/client": "2.2.16",
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.5.174",
50
- "@sentry/node": "7.119.1",
51
- "@tonyrl/rand-user-agent": "2.0.81",
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": "144.0.0",
69
- "hono": "4.7.2",
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.181",
74
+ "imapflow": "1.0.184",
75
75
  "instagram-private-api": "1.46.1",
76
- "ioredis": "5.5.0",
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.5",
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.6",
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": "5.0.5",
100
- "re2js": "1.0.1",
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.77",
111
+ "tldts": "6.1.84",
111
112
  "tosource": "2.0.0-alpha.3",
112
- "tough-cookie": "5.1.1",
113
+ "tough-cookie": "5.1.2",
113
114
  "tsx": "4.19.3",
114
- "twitter-api-v2": "1.20.1",
115
+ "twitter-api-v2": "1.20.2",
115
116
  "ufo": "1.5.4",
116
- "undici": "6.21.1",
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.2.0",
127
- "@eslint/js": "9.20.0",
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.1",
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.19",
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.4",
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.24.1",
153
- "@typescript-eslint/parser": "8.24.1",
154
- "@vercel/nft": "0.29.1",
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.20.1",
158
- "eslint-config-prettier": "10.0.1",
158
+ "eslint": "9.22.0",
159
+ "eslint-config-prettier": "10.1.1",
159
160
  "eslint-nibble": "8.1.0",
160
- "eslint-plugin-n": "17.15.1",
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": "15.15.0",
166
+ "globals": "16.0.0",
166
167
  "got": "14.4.6",
167
168
  "husky": "9.1.7",
168
- "js-beautify": "1.15.3",
169
- "lint-staged": "15.4.3",
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.1",
174
+ "prettier": "3.5.3",
174
175
  "remark-parse": "11.0.0",
175
176
  "supertest": "7.0.0",
176
- "typescript": "5.7.3",
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.2.3"
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
- };