rsshub 1.0.0-master.f9b85f5 → 1.0.0-master.f9c381a

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 (166) hide show
  1. package/lib/config.ts +10 -0
  2. package/lib/middleware/cache.ts +4 -0
  3. package/lib/middleware/parameter.ts +1 -1
  4. package/lib/registry.ts +6 -2
  5. package/lib/routes/51cto/utils.ts +1 -1
  6. package/lib/routes/abc/index.ts +1 -1
  7. package/lib/routes/acgvinyl/namespace.ts +6 -0
  8. package/lib/routes/acgvinyl/news.ts +86 -0
  9. package/lib/routes/ally/rail.ts +1 -1
  10. package/lib/routes/anthropic/news.ts +13 -11
  11. package/lib/routes/apnews/mobile-api.ts +1 -1
  12. package/lib/routes/apnews/sitemap.ts +1 -1
  13. package/lib/routes/apple/apps.ts +2 -2
  14. package/lib/routes/apple/podcast.ts +58 -25
  15. package/lib/routes/bangumi.tv/group/reply.ts +1 -1
  16. package/lib/routes/bilibili/cache.ts +18 -2
  17. package/lib/routes/bilibili/dynamic.ts +31 -7
  18. package/lib/routes/bilibili/page.ts +1 -1
  19. package/lib/routes/bilibili/ranking.ts +23 -17
  20. package/lib/routes/bilibili/wasm-exec.ts +1 -1
  21. package/lib/routes/bilibili/weekly-recommend.ts +22 -6
  22. package/lib/routes/bjp/apod.ts +1 -1
  23. package/lib/routes/buaa/jiaowu.ts +1 -1
  24. package/lib/routes/bullionvault/gold-news.ts +3 -3
  25. package/lib/routes/cast/index.ts +1 -1
  26. package/lib/routes/coolapk/utils.ts +5 -4
  27. package/lib/routes/coolbuy/index.ts +106 -0
  28. package/lib/routes/{xinhuanet → coolbuy}/namespace.ts +3 -3
  29. package/lib/routes/coolbuy/templates/description.art +48 -0
  30. package/lib/routes/coolidge/film-guide.ts +60 -0
  31. package/lib/routes/coolidge/namespace.ts +7 -0
  32. package/lib/routes/coolidge/news.ts +65 -0
  33. package/lib/routes/coolidge/templates/description.art +4 -0
  34. package/lib/routes/copymanga/comic.ts +1 -1
  35. package/lib/routes/cpta/handler.ts +1 -1
  36. package/lib/routes/creative-comic/book.ts +1 -1
  37. package/lib/routes/daum/potplayer.ts +1 -1
  38. package/lib/routes/dockerhub/utils.ts +1 -1
  39. package/lib/routes/dora-world/article.ts +2 -2
  40. package/lib/routes/ehentai/ehapi.ts +3 -3
  41. package/lib/routes/eventbrite/events.ts +152 -0
  42. package/lib/routes/eventbrite/namespace.ts +7 -0
  43. package/lib/routes/github/activity.ts +1 -1
  44. package/lib/routes/google/jules.ts +63 -0
  45. package/lib/routes/gov/mem/namespace.ts +7 -0
  46. package/lib/routes/gov/mem/zfxxgkpt.ts +96 -0
  47. package/lib/routes/gov/mot/index.ts +158 -53
  48. package/lib/routes/hameln/chapter.ts +1 -1
  49. package/lib/routes/hpoi/banner-item.ts +28 -11
  50. package/lib/routes/hpoi/info.ts +1 -1
  51. package/lib/routes/huggingface/daily-papers.ts +1 -1
  52. package/lib/routes/hupu/index.ts +158 -74
  53. package/lib/routes/hupu/types.ts +163 -0
  54. package/lib/routes/hust/gs.ts +1 -1
  55. package/lib/routes/hust/mse.ts +1 -1
  56. package/lib/routes/huxiu/util.ts +2 -2
  57. package/lib/routes/infoq/presentations.ts +1 -1
  58. package/lib/routes/instagram/common-utils.ts +3 -3
  59. package/lib/routes/itch/devlog.ts +7 -3
  60. package/lib/routes/javbus/index.ts +1 -1
  61. package/lib/routes/javlibrary/utils.ts +1 -1
  62. package/lib/routes/jbma/namespace.ts +17 -0
  63. package/lib/routes/jbma/report.ts +473 -0
  64. package/lib/routes/jetbrains/comments.ts +1 -1
  65. package/lib/routes/jingzhengu/utils.ts +1 -1
  66. package/lib/routes/juejin/aicoding.ts +102 -0
  67. package/lib/routes/juejin/utils.ts +36 -51
  68. package/lib/routes/kakuyomu/works.ts +1 -1
  69. package/lib/routes/kemono/index.ts +2 -2
  70. package/lib/routes/komiic/comic.ts +1 -1
  71. package/lib/routes/koyso/index.ts +338 -0
  72. package/lib/routes/koyso/namespace.ts +9 -0
  73. package/lib/routes/koyso/templates/description.art +13 -0
  74. package/lib/routes/letterboxd/index.ts +65 -0
  75. package/lib/routes/letterboxd/namespace.ts +8 -0
  76. package/lib/routes/maccms/index.ts +1 -1
  77. package/lib/routes/mercari/util.ts +1 -1
  78. package/lib/routes/mingpao/index.ts +1 -1
  79. package/lib/routes/nankai/ai-notice.ts +142 -0
  80. package/lib/routes/nankai/graduate-notice.ts +162 -0
  81. package/lib/routes/natgeo/natgeo.ts +1 -0
  82. package/lib/routes/nhk/news-web-easy.ts +1 -1
  83. package/lib/routes/nicovideo/mylist.ts +39 -0
  84. package/lib/routes/nicovideo/types.ts +27 -0
  85. package/lib/routes/nicovideo/utils.ts +27 -1
  86. package/lib/routes/nikkei/cn/index.ts +1 -4
  87. package/lib/routes/now/news.ts +1 -1
  88. package/lib/routes/nytimes/index.ts +1 -1
  89. package/lib/routes/pixiv/novel-api/user-novels/sfw.ts +1 -1
  90. package/lib/routes/pixivision/utils.ts +1 -1
  91. package/lib/routes/pku/hr.ts +1 -1
  92. package/lib/routes/pku/scc/recruit.ts +1 -1
  93. package/lib/routes/producthunt/templates/description.art +2 -2
  94. package/lib/routes/producthunt/today.ts +17 -8
  95. package/lib/routes/ps/trophy.ts +1 -1
  96. package/lib/routes/pubscholar/utils.ts +14 -1
  97. package/lib/routes/qweather/3days.ts +14 -14
  98. package/lib/routes/qweather/now.ts +12 -10
  99. package/lib/routes/qweather/util.tsx +89 -0
  100. package/lib/routes/qwenlm/blog.ts +75 -0
  101. package/lib/routes/qwenlm/namespace.ts +6 -0
  102. package/lib/routes/radio-canada/latest.ts +30 -17
  103. package/lib/routes/ruc/ai.ts +1 -1
  104. package/lib/routes/ruc/hr.ts +1 -1
  105. package/lib/routes/samrdprc/index.ts +241 -0
  106. package/lib/routes/samrdprc/namespace.ts +1 -1
  107. package/lib/routes/sdo/ff14risingstones/api.ts +78 -0
  108. package/lib/routes/sdo/ff14risingstones/constant.ts +338 -0
  109. package/lib/routes/sdo/ff14risingstones/posts.ts +80 -0
  110. package/lib/routes/sdo/ff14risingstones/strats.ts +75 -0
  111. package/lib/routes/sdo/ff14risingstones/templates/duties-party.art +41 -0
  112. package/lib/routes/sdo/ff14risingstones/templates/fc-party.art +26 -0
  113. package/lib/routes/sdo/ff14risingstones/templates/novice-network-party.art +9 -0
  114. package/lib/routes/sdo/ff14risingstones/templates/rp-party.art +15 -0
  115. package/lib/routes/sdo/ff14risingstones/timeline.ts +31 -0
  116. package/lib/routes/sdo/ff14risingstones/types/dynamic.ts +50 -0
  117. package/lib/routes/sdo/ff14risingstones/types/index.ts +3 -0
  118. package/lib/routes/sdo/ff14risingstones/types/other.ts +57 -0
  119. package/lib/routes/sdo/ff14risingstones/types/party.ts +111 -0
  120. package/lib/routes/sdo/ff14risingstones/user-dynamics.ts +32 -0
  121. package/lib/routes/sdo/ff14risingstones/user-posts.ts +32 -0
  122. package/lib/routes/sdo/ff14risingstones/user-resently.ts +38 -0
  123. package/lib/routes/sdo/ff14risingstones/user-strats.ts +32 -0
  124. package/lib/routes/sdo/ff14risingstones/utils.ts +215 -0
  125. package/lib/routes/sdo/namespace.ts +7 -0
  126. package/lib/routes/showstart/utils.ts +1 -1
  127. package/lib/routes/sohu/mp.ts +1 -1
  128. package/lib/routes/sotwe/user.ts +1 -1
  129. package/lib/routes/surfshark/blog.ts +273 -77
  130. package/lib/routes/surfshark/templates/description.art +16 -4
  131. package/lib/routes/sustainabilitymag/articles.ts +1 -1
  132. package/lib/routes/syosetu/dev.ts +1 -1
  133. package/lib/routes/syosetu/ranking-isekai.ts +1 -1
  134. package/lib/routes/szse/disclosure/listed-notice.ts +44 -6
  135. package/lib/routes/telegram/channel-media.ts +249 -0
  136. package/lib/routes/telegram/channel.ts +5 -4
  137. package/lib/routes/telegram/stories.ts +130 -0
  138. package/lib/routes/telegram/tglib/channel.ts +136 -118
  139. package/lib/routes/telegram/tglib/client.ts +37 -139
  140. package/lib/routes/tesla/cx.ts +1 -1
  141. package/lib/routes/theverge/index.ts +20 -6
  142. package/lib/routes/threads/utils.ts +7 -3
  143. package/lib/routes/tidb/blog.ts +1 -1
  144. package/lib/routes/toutiao/user.ts +2 -2
  145. package/lib/routes/twitter/api/mobile-api/api.ts +1 -1
  146. package/lib/routes/txrjy/fornumtopic.ts +2 -2
  147. package/lib/routes/typst/universe.ts +1 -1
  148. package/lib/routes/uber/blog.ts +87 -46
  149. package/lib/routes/weibo/utils.ts +17 -9
  150. package/lib/routes/xiaohongshu/user.ts +1 -1
  151. package/lib/routes/xjtu/ee-jzxx.ts +1 -1
  152. package/lib/routes/yahoo/news/utils.ts +1 -1
  153. package/lib/routes/ymgal/article.ts +1 -1
  154. package/lib/routes/yoasobi-music/media.ts +1 -1
  155. package/lib/routes/youtube/api/youtubei.ts +1 -1
  156. package/lib/routes/youtube/community.ts +4 -4
  157. package/lib/routes/zaker/utils.ts +1 -1
  158. package/lib/routes/zaobao/util.tsx +1 -1
  159. package/lib/server.ts +1 -1
  160. package/lib/types.ts +1 -1
  161. package/lib/utils/puppeteer-utils.test.ts +2 -2
  162. package/lib/views/index.tsx +4 -4
  163. package/package.json +40 -40
  164. package/lib/routes/qweather/templates/3days.art +0 -22
  165. package/lib/routes/qweather/templates/now.art +0 -16
  166. package/lib/routes/xinhuanet/app.ts +0 -109
@@ -71,12 +71,12 @@ async function handler(ctx) {
71
71
  .remove()
72
72
  .end()
73
73
  .html()
74
- ?.replace(/(<img.*?) src=".*?"(.*?>)/g, '$1$2')
74
+ ?.replaceAll(/(<img.*?) src=".*?"(.*?>)/g, '$1$2')
75
75
  .replaceAll(/(<img.*?)zoomfile(.*?>)/g, '$1src$2'),
76
76
  pattl: content(item)
77
77
  .find('div.pattl')
78
78
  .html()
79
- ?.replace(/(<img.*?) src=".*?"(.*?>)/g, '$1$2')
79
+ ?.replaceAll(/(<img.*?) src=".*?"(.*?>)/g, '$1$2')
80
80
  .replaceAll(/(<img.*?)zoomfile(.*?>)/g, '$1src$2'),
81
81
  author: content(item).find('a.xw1').text().trim(),
82
82
  })
@@ -77,7 +77,7 @@ export const route: Route = {
77
77
  displayErrors: true,
78
78
  });
79
79
  const md = markdownit('commonmark');
80
- const items = context.an.exports.sort((a, b) => a.updatedAt - b.updatedAt);
80
+ const items = context.an.exports.toSorted((a, b) => a.updatedAt - b.updatedAt);
81
81
  const groups = new Map(items.map((it) => [it.name, it]));
82
82
  const pkgs = [...groups.values()].map((item) => {
83
83
  const $ = load(md.render(item.readme));
@@ -1,16 +1,17 @@
1
1
  import { Route } from '@/types';
2
2
  import cache from '@/utils/cache';
3
- import got from '@/utils/got';
3
+ import ofetch from '@/utils/ofetch';
4
+ import { load } from 'cheerio';
4
5
  import { parseDate } from '@/utils/parse-date';
5
6
 
6
7
  const rootURL = 'https://www.uber.com';
7
- const apiURL = 'https://blogapi.uber.com';
8
8
 
9
9
  export const route: Route = {
10
- path: '/blog/:maxPage?',
10
+ // `compat` is a never used parameter
11
+ // just for backward compatibility with the deprecated `:maxPage` parameter
12
+ path: '/blog/:compat?',
11
13
  categories: ['blog'],
12
14
  example: '/uber/blog',
13
- parameters: { maxPage: 'max number of pages to retrieve, default to 1 page at most' },
14
15
  features: {
15
16
  requireConfig: false,
16
17
  requirePuppeteer: false,
@@ -21,65 +22,105 @@ export const route: Route = {
21
22
  },
22
23
  radar: [
23
24
  {
24
- source: ['www.uber.com/:language/blog/engineering', 'www.uber.com/:language/blog'],
25
+ source: ['www.uber.com/:language/blog/engineering'],
25
26
  target: '/blog',
26
27
  },
27
28
  ],
28
29
  name: 'Engineering',
29
30
  maintainers: ['hulb'],
30
31
  handler,
31
- url: 'www.uber.com/blog/pittsburgh/engineering',
32
+ url: 'www.uber.com/en-HK/blog/engineering',
33
+ description:
34
+ "The English blog on any of Uber's regional sites (e.g., www.uber.com/en-JP/blog) is the same engineering blog provided by this route, so language selection is not supported. This route is not for the public news blog on specific regional sites (e.g., www.uber.com/ja-JP/blog).",
35
+ zh: {
36
+ description: 'uber的任何区域站点的英文blog(例如www.uber.com/en-JP/blog)都是相同的内容,正是本路由提供的engineering blog,因此本路由不提供语言选择;本路由不是uber在特定区域站点的公开新闻blog(例如www.uber.com/ja-JP/blog)',
37
+ },
32
38
  };
33
39
 
34
- async function handler(ctx) {
35
- let maxPage = Number(ctx.req.param('maxPage'));
36
- if (Number.isNaN(maxPage)) {
37
- maxPage = 1;
38
- }
39
-
40
- let pages = await Promise.all(
41
- [...Array.from({ length: maxPage }).keys()].map((pageIdx) =>
42
- got(`${apiURL}/wp-json/blog/v1/data`, {
43
- searchParams: {
44
- page: pageIdx + 1,
45
- parent: 'pittsburgh',
46
- slug: 'engineering',
47
- },
48
- })
49
- )
50
- );
51
- pages = pages.map((page) => page.data);
40
+ async function handler() {
41
+ const response = await ofetch(`${rootURL}/en-HK/blog/engineering/rss/`, {
42
+ // The source site is misconfigured or intentionally blocking requests without a specific accept header
43
+ // Without this header, it will return an HTTP 406 error
44
+ // Note that the accept type must be 'text/html'; 'application/xml' or similar will get HTTP 404 error
45
+ headers: {
46
+ accept: 'text/html',
47
+ },
48
+ // Without this, ofetch will parse the response as a blob instead of text, which cannot be loaded by cheerio
49
+ parseResponse: (txt) => txt,
50
+ });
51
+ const $ = load(response, { xmlMode: true });
52
52
 
53
53
  const result = await Promise.all(
54
- pages.map((page) =>
55
- Promise.all(
56
- page.posts.map((post) =>
57
- cache.tryGet(`${rootURL}${post.link}`, async () => {
58
- let { data: article } = await got(`${apiURL}/wp-json/blog/v1/data`, {
59
- searchParams: {
60
- slug: post.link.replaceAll('/', '').replace('blog', ''),
61
- },
62
- });
63
- article = article.article;
54
+ $('item')
55
+ .toArray()
56
+ .map((el) =>
57
+ cache.tryGet($(el).find('link').text(), async () => {
58
+ const detailResponse = await ofetch($(el).find('link').text(), {
59
+ headers: {
60
+ accept: 'text/html',
61
+ },
62
+ });
63
+ const detail = load(detailResponse);
64
+
65
+ const scriptText = detail('script#__REDUX_STATE__').text().trim();
66
+ // The json in the script element is over-encoded
67
+ // It needs to be decoded this way before it can be parsed by JSON.parse
68
+ const jsonText = decodeURIComponent(JSON.parse(`"${scriptText}"`));
69
+ // Traverse the JSON to find the content node, which is more robust against format changes.
70
+ const contentHtml = findNode(JSON.parse(jsonText), { idKey: 'id', idValue: 'BlogArticleContent', siblingKey: 'props', childKey: 'content' }).replaceAll(String.raw`\n`, '');
64
71
 
65
- return {
66
- link: article.link,
67
- title: article.title,
68
- description: article.content,
69
- pubDate: parseDate(article.created),
70
- author: article.author,
71
- category: article.categories.map((category) => category.category_name),
72
- };
73
- })
74
- )
72
+ return {
73
+ link: $(el).find('link').text(),
74
+ title: $(el).find('title').text(),
75
+ description: contentHtml,
76
+ pubDate: parseDate($(el).find('pubDate').text()),
77
+ category: $(el)
78
+ .find('category')
79
+ .toArray()
80
+ .map((item) => $(item).text()),
81
+ };
82
+ })
75
83
  )
76
- )
77
84
  );
78
85
 
79
86
  return {
80
87
  title: `Uber Engineering Blog`,
81
88
  link: rootURL + '/blog/engineering',
82
89
  description: 'The technology behind Uber Engineering',
83
- item: result.flat(),
90
+ item: result,
84
91
  };
85
92
  }
93
+
94
+ function findNode(
95
+ json: any,
96
+ options: {
97
+ idKey?: string;
98
+ idValue: string;
99
+ siblingKey: string;
100
+ childKey: string;
101
+ }
102
+ ): any {
103
+ const { idKey = 'id', idValue, siblingKey, childKey } = options;
104
+
105
+ if (Array.isArray(json)) {
106
+ for (const item of json) {
107
+ const result = findNode(item, options);
108
+ if (result !== undefined) {
109
+ return result;
110
+ }
111
+ }
112
+ } else if (json && typeof json === 'object') {
113
+ if (json[idKey] === idValue) {
114
+ return json[siblingKey]?.[childKey];
115
+ }
116
+
117
+ for (const key in json) {
118
+ const result = findNode(json[key], options);
119
+ if (result !== undefined) {
120
+ return result;
121
+ }
122
+ }
123
+ }
124
+
125
+ return undefined;
126
+ }
@@ -36,7 +36,7 @@ const weiboUtils = {
36
36
  widthOfPics: fallback(params.widthOfPics, queryToInteger(routeParams.widthOfPics), -1),
37
37
  heightOfPics: fallback(params.heightOfPics, queryToInteger(routeParams.heightOfPics), -1),
38
38
  sizeOfAuthorAvatar: fallback(params.sizeOfAuthorAvatar, queryToInteger(routeParams.sizeOfAuthorAvatar), 48),
39
- showEmojiInDescription: fallback(params.showEmojiInDescription, queryToInteger(routeParams.showEmojiInDescription), true),
39
+ showEmojiInDescription: fallback(params.showEmojiInDescription, queryToInteger(routeParams.showEmojiInDescription), false),
40
40
  showLinkIconInDescription: fallback(params.showLinkIconInDescription, queryToInteger(routeParams.showLinkIconInDescription), true),
41
41
  preferMobileLink: fallback(params.preferMobileLink, queryToBoolean(routeParams.preferMobileLink), false),
42
42
  };
@@ -157,15 +157,23 @@ const weiboUtils = {
157
157
  let style = '';
158
158
  html += '<img ';
159
159
  html += readable ? 'vspace="8" hspace="4"' : '';
160
- if (widthOfPics >= 0) {
161
- html += ` width="${widthOfPics}"`;
162
- style += `width: ${widthOfPics}px;`;
163
- }
164
- if (heightOfPics >= 0) {
165
- html += ` height="${heightOfPics}"`;
166
- style += `height: ${heightOfPics}px;`;
160
+ if (item.large) {
161
+ const { geo, url } = item.large;
162
+
163
+ if (geo?.width || widthOfPics >= 0) {
164
+ const width = geo?.width || widthOfPics;
165
+ html += ` width="${width}"`;
166
+ style += `width: ${width}px;`;
167
+ }
168
+
169
+ if (geo?.height || heightOfPics >= 0) {
170
+ const height = geo?.height || heightOfPics;
171
+ html += ` height="${height}"`;
172
+ style += `height: ${height}px;`;
173
+ }
174
+
175
+ html += ` style="${style}" src="${url}">`;
167
176
  }
168
- html += ` style="${style}"` + ' src="' + item.large.url + '">';
169
177
 
170
178
  if (addLinkForPics) {
171
179
  html += '</a>';
@@ -99,7 +99,7 @@ async function getUserFeeds(url: string, category: string) {
99
99
  title: noteCard.displayTitle,
100
100
  link: new URL(noteCard.noteId || id, url).toString(),
101
101
  guid: noteCard.displayTitle,
102
- description: `<img src ="${noteCard.cover.infoList.pop().url}"><br>${noteCard.displayTitle}`,
102
+ description: `<img src ="${noteCard.cover.infoList.pop().url} width="${noteCard.cover.width}" height="${noteCard.cover.height}"><br>${noteCard.displayTitle}`,
103
103
  author: noteCard.user.nickname,
104
104
  upvotes: noteCard.interactInfo.likedCount,
105
105
  }))
@@ -77,7 +77,7 @@ async function handler(ctx) {
77
77
  .find('ul li') // 定位到附件列表项
78
78
  .each(function () {
79
79
  const $li = $(this);
80
- const newText = $li.html()?.replace(/已下载[\s\S]*?<\/span>次/g, '') ?? '';
80
+ const newText = $li.html()?.replaceAll(/已下载[\s\S]*?<\/span>次/g, '') ?? '';
81
81
  $li.html(newText.replace(/<\/a>\s*$/, '</a>'));
82
82
  })
83
83
  .end()
@@ -86,7 +86,7 @@ const parseItem = (item, tryGet) =>
86
86
  const author = `${$('span.caas-author-byline-collapse').text()} @${$('span.caas-attr-provider').text()}`;
87
87
  const body = $('.atoms');
88
88
 
89
- body.find('noscript').remove();
89
+ body.find('noscript, .text-gandalf, [id^="sda-inbody-"]').remove();
90
90
  // remove padding
91
91
  body.find('.caas-figure-with-pb, .caas-img-container').each((_, ele) => {
92
92
  const $ele = $(ele);
@@ -45,7 +45,7 @@ async function handler(ctx) {
45
45
  data.push(...response.data.data);
46
46
  })
47
47
  );
48
- data = data.sort((a, b) => b.publishTime - a.publishTime).slice(0, 10);
48
+ data = data.toSorted((a, b) => b.publishTime - a.publishTime).slice(0, 10);
49
49
  } else {
50
50
  const response = await got(link);
51
51
  data = response.data.data;
@@ -42,7 +42,7 @@ async function handler() {
42
42
 
43
43
  const data = Object.values(parseJSONP(response.data).items)
44
44
  .flat()
45
- .sort((a, b) => new Date(b.date) - new Date(a.date))
45
+ .toSorted((a, b) => new Date(b.date) - new Date(a.date))
46
46
  .map((item) => ({
47
47
  date: item.date,
48
48
  weekDay: item.youbi,
@@ -74,7 +74,7 @@ export const getDataByChannelId = async ({ channelId, embed }: { channelId: stri
74
74
  .filter((video) => 'video_id' in video)
75
75
  .map(async (video) => {
76
76
  const srt = await getSubtitlesByVideoId(video.video_id);
77
- const dataUrl = `data:text/plain;charset=utf-8,${srt}`;
77
+ const dataUrl = `data:text/plain;charset=utf-8,${encodeURIComponent(srt)}`;
78
78
 
79
79
  const img = 'best_thumbnail' in video ? video.best_thumbnail?.url : 'thumbnails' in video ? video.thumbnails?.[0]?.url : undefined;
80
80
 
@@ -1,6 +1,6 @@
1
1
  import { Route } from '@/types';
2
2
 
3
- import got from '@/utils/got';
3
+ import ofetch from '@/utils/ofetch';
4
4
  import { load } from 'cheerio';
5
5
  import { parseRelativeDate } from '@/utils/parse-date';
6
6
  import { art } from '@/utils/render';
@@ -12,7 +12,7 @@ export const route: Route = {
12
12
  categories: ['social-media'],
13
13
  example: '/youtube/community/@JFlaMusic',
14
14
  parameters: { handle: 'YouTube handles or channel id' },
15
- name: 'Community',
15
+ name: 'Community Posts',
16
16
  maintainers: ['TonyRL'],
17
17
  handler,
18
18
  };
@@ -25,7 +25,7 @@ async function handler(ctx) {
25
25
  urlPath = `channel/${handle}`;
26
26
  }
27
27
 
28
- const { data: response } = await got(`https://www.youtube.com/${urlPath}/community`);
28
+ const response = await ofetch(`https://www.youtube.com/${urlPath}/posts`);
29
29
  const $ = load(response);
30
30
  const ytInitialData = JSON.parse(
31
31
  $('script')
@@ -62,7 +62,7 @@ async function handler(ctx) {
62
62
  });
63
63
 
64
64
  return {
65
- title: `${username} - Community - YouTube`,
65
+ title: `${username} - Community Posts- YouTube`,
66
66
  link: channelMetadata.channelUrl,
67
67
  description: channelMetadata.description,
68
68
  item: items,
@@ -84,7 +84,7 @@ export const getSafeLineCookieWithData = async (link): Promise<{ cookie: string;
84
84
  query: {
85
85
  once_id: onceId,
86
86
  v: '1.0.0',
87
- hints: hints.sort(() => Math.random() - 0.5).join(','),
87
+ hints: hints.toSorted(() => Math.random() - 0.5).join(','),
88
88
  },
89
89
  });
90
90
 
@@ -119,7 +119,7 @@ export const orderContent = (parent) => {
119
119
  for (const [i, e] of parent
120
120
  .children()
121
121
  .toArray()
122
- .sort((a, b) => {
122
+ .toSorted((a, b) => {
123
123
  const index = Buffer.from(base32.parse('GM======')).toString(); // substring(3)
124
124
  a = Buffer.from(
125
125
  base32.parse(
package/lib/server.ts CHANGED
@@ -2,4 +2,4 @@
2
2
 
3
3
  import '@/utils/request-rewriter';
4
4
 
5
- export default (await import('./app-bootstrap')).default;
5
+ export { default } from './app-bootstrap';
package/lib/types.ts CHANGED
@@ -281,7 +281,7 @@ interface RouteItem {
281
281
  /**
282
282
  * The handler function of the route
283
283
  */
284
- handler: (ctx: Context) => Promise<Data | null> | Data | null;
284
+ handler: (ctx: Context) => Promise<Data | null | Response> | Data | null | Response;
285
285
 
286
286
  /**
287
287
  * An example URL of the route
@@ -73,7 +73,7 @@ describe('puppeteer-utils', () => {
73
73
  await page.goto('https://httpbingo.org/cookies/set?foo=bar&baz=qux', {
74
74
  waitUntil: 'domcontentloaded',
75
75
  });
76
- expect((await getCookies(page, 'httpbingo.org')).split('; ').sort()).toEqual(['foo=bar', 'baz=qux'].sort());
76
+ expect((await getCookies(page, 'httpbingo.org')).split('; ').toSorted()).toEqual(['foo=bar', 'baz=qux'].toSorted());
77
77
  }, 45000);
78
78
 
79
79
  it('setCookies httpbingo', async () => {
@@ -96,6 +96,6 @@ describe('puppeteer-utils', () => {
96
96
  await page.goto('https://example.org', {
97
97
  waitUntil: 'domcontentloaded',
98
98
  });
99
- expect((await getCookies(page, 'example.org')).split('; ').sort()).toEqual(cookieStrAll.split('; ').sort());
99
+ expect((await getCookies(page, 'example.org')).split('; ').toSorted()).toEqual(cookieStrAll.split('; ').toSorted());
100
100
  }, 45000);
101
101
  });
@@ -78,7 +78,7 @@ const Index: FC<{ debugQuery: string | undefined }> = ({ debugQuery }) => {
78
78
  {
79
79
  name: 'Hot Routes',
80
80
  value: Object.keys(debug.routes)
81
- .sort((a, b) => debug.routes[b] - debug.routes[a])
81
+ .toSorted((a, b) => debug.routes[b] - debug.routes[a])
82
82
  .slice(0, 30)
83
83
  .map((route) => (
84
84
  <>
@@ -90,7 +90,7 @@ const Index: FC<{ debugQuery: string | undefined }> = ({ debugQuery }) => {
90
90
  {
91
91
  name: 'Hot Paths',
92
92
  value: Object.keys(debug.paths)
93
- .sort((a, b) => debug.paths[b] - debug.paths[a])
93
+ .toSorted((a, b) => debug.paths[b] - debug.paths[a])
94
94
  .slice(0, 30)
95
95
  .map((path) => (
96
96
  <>
@@ -102,7 +102,7 @@ const Index: FC<{ debugQuery: string | undefined }> = ({ debugQuery }) => {
102
102
  {
103
103
  name: 'Hot Error Routes',
104
104
  value: Object.keys(debug.errorRoutes)
105
- .sort((a, b) => debug.errorRoutes[b] - debug.errorRoutes[a])
105
+ .toSorted((a, b) => debug.errorRoutes[b] - debug.errorRoutes[a])
106
106
  .slice(0, 30)
107
107
  .map((route) => (
108
108
  <>
@@ -114,7 +114,7 @@ const Index: FC<{ debugQuery: string | undefined }> = ({ debugQuery }) => {
114
114
  {
115
115
  name: 'Hot Error Paths',
116
116
  value: Object.keys(debug.errorPaths)
117
- .sort((a, b) => debug.errorPaths[b] - debug.errorPaths[a])
117
+ .toSorted((a, b) => debug.errorPaths[b] - debug.errorPaths[a])
118
118
  .slice(0, 30)
119
119
  .map((path) => (
120
120
  <>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rsshub",
3
- "version": "1.0.0-master.f9b85f5",
3
+ "version": "1.0.0-master.f9c381a",
4
4
  "description": "Make RSS Great Again!",
5
5
  "keywords": [
6
6
  "RSS"
@@ -35,20 +35,20 @@
35
35
  "@bbob/html": "4.2.0",
36
36
  "@bbob/plugin-helper": "4.2.0",
37
37
  "@bbob/preset-html5": "4.2.0",
38
- "@hono/node-server": "1.19.0",
38
+ "@hono/node-server": "1.19.3",
39
39
  "@hono/zod-openapi": "0.19.10",
40
- "@notionhq/client": "4.0.2",
40
+ "@notionhq/client": "5.1.0",
41
41
  "@opentelemetry/api": "1.9.0",
42
- "@opentelemetry/exporter-prometheus": "0.203.0",
43
- "@opentelemetry/exporter-trace-otlp-http": "0.203.0",
44
- "@opentelemetry/resources": "2.0.1",
45
- "@opentelemetry/sdk-metrics": "2.0.1",
46
- "@opentelemetry/sdk-trace-base": "2.0.1",
47
- "@opentelemetry/semantic-conventions": "1.36.0",
42
+ "@opentelemetry/exporter-prometheus": "0.205.0",
43
+ "@opentelemetry/exporter-trace-otlp-http": "0.205.0",
44
+ "@opentelemetry/resources": "2.1.0",
45
+ "@opentelemetry/sdk-metrics": "2.1.0",
46
+ "@opentelemetry/sdk-trace-base": "2.1.0",
47
+ "@opentelemetry/semantic-conventions": "1.37.0",
48
48
  "@postlight/parser": "2.2.3",
49
49
  "@rss3/sdk": "0.0.25",
50
- "@scalar/hono-api-reference": "0.9.16",
51
- "@sentry/node": "10.7.0",
50
+ "@scalar/hono-api-reference": "0.9.18",
51
+ "@sentry/node": "10.12.0",
52
52
  "@tonyrl/rand-user-agent": "2.0.83",
53
53
  "aes-js": "3.1.2",
54
54
  "art-template": "4.13.2",
@@ -60,13 +60,13 @@
60
60
  "dayjs": "1.11.8",
61
61
  "destr": "2.0.5",
62
62
  "directory-import": "3.3.2",
63
- "dotenv": "17.2.1",
64
- "entities": "6.0.1",
63
+ "dotenv": "17.2.2",
64
+ "entities": "7.0.0",
65
65
  "etag": "1.8.1",
66
66
  "fanfou-sdk": "6.0.0",
67
67
  "form-data": "4.0.4",
68
- "googleapis": "159.0.0",
69
- "hono": "4.9.4",
68
+ "googleapis": "160.0.0",
69
+ "hono": "4.9.7",
70
70
  "html-to-text": "9.0.5",
71
71
  "http-cookie-agent": "6.0.8",
72
72
  "https-proxy-agent": "7.0.6",
@@ -75,11 +75,11 @@
75
75
  "instagram-private-api": "1.46.1",
76
76
  "ioredis": "5.7.0",
77
77
  "ip-regex": "5.0.0",
78
- "jsdom": "26.1.0",
78
+ "jsdom": "27.0.0",
79
79
  "json-bigint": "1.0.0",
80
80
  "jsonpath-plus": "10.3.0",
81
81
  "jsrsasign": "10.9.0",
82
- "lru-cache": "11.1.0",
82
+ "lru-cache": "11.2.1",
83
83
  "lz-string": "1.5.0",
84
84
  "mailparser": "3.7.4",
85
85
  "markdown-it": "14.1.0",
@@ -93,9 +93,9 @@
93
93
  "p-map": "7.0.3",
94
94
  "pac-proxy-agent": "7.2.0",
95
95
  "proxy-chain": "2.5.9",
96
- "query-string": "9.2.2",
97
- "rate-limiter-flexible": "7.2.0",
98
- "re2js": "1.1.0",
96
+ "query-string": "9.3.0",
97
+ "rate-limiter-flexible": "7.3.1",
98
+ "re2js": "1.2.0",
99
99
  "rebrowser-puppeteer": "24.8.1",
100
100
  "rfc4648": "1.5.4",
101
101
  "rss-parser": "3.13.0",
@@ -105,18 +105,18 @@
105
105
  "source-map": "0.7.6",
106
106
  "telegram": "2.26.22",
107
107
  "title": "4.0.1",
108
- "tldts": "7.0.12",
108
+ "tldts": "7.0.14",
109
109
  "tosource": "2.0.0-alpha.3",
110
110
  "tough-cookie": "5.1.2",
111
111
  "tsx": "4.20.5",
112
- "twitter-api-v2": "1.25.0",
112
+ "twitter-api-v2": "1.27.0",
113
113
  "ufo": "1.6.1",
114
114
  "undici": "6.21.3",
115
- "uuid": "11.1.0",
115
+ "uuid": "13.0.0",
116
116
  "winston": "3.17.0",
117
117
  "xxhash-wasm": "1.1.0",
118
118
  "youtube-caption-extractor": "1.9.1",
119
- "youtubei.js": "15.0.1",
119
+ "youtubei.js": "15.1.1",
120
120
  "zod": "3.25.76"
121
121
  },
122
122
  "devDependencies": {
@@ -124,9 +124,9 @@
124
124
  "@babel/preset-typescript": "7.27.1",
125
125
  "@bbob/types": "4.2.0",
126
126
  "@eslint/eslintrc": "3.3.1",
127
- "@eslint/js": "9.34.0",
127
+ "@eslint/js": "9.35.0",
128
128
  "@microsoft/eslint-formatter-sarif": "3.1.0",
129
- "@stylistic/eslint-plugin": "5.2.3",
129
+ "@stylistic/eslint-plugin": "5.3.1",
130
130
  "@types/aes-js": "3.1.4",
131
131
  "@types/babel__preset-env": "7.10.0",
132
132
  "@types/crypto-js": "4.2.2",
@@ -142,38 +142,38 @@
142
142
  "@types/mailparser": "3.4.6",
143
143
  "@types/markdown-it": "14.1.2",
144
144
  "@types/module-alias": "2.0.4",
145
- "@types/node": "24.3.0",
145
+ "@types/node": "24.5.1",
146
146
  "@types/sanitize-html": "2.16.0",
147
147
  "@types/supertest": "6.0.3",
148
148
  "@types/title": "4.0.0",
149
- "@types/uuid": "10.0.0",
150
- "@typescript-eslint/eslint-plugin": "8.41.0",
151
- "@typescript-eslint/parser": "8.41.0",
149
+ "@types/uuid": "11.0.0",
150
+ "@typescript-eslint/eslint-plugin": "8.44.0",
151
+ "@typescript-eslint/parser": "8.44.0",
152
152
  "@vercel/nft": "0.30.1",
153
153
  "@vitest/coverage-v8": "2.1.9",
154
- "discord-api-types": "0.38.21",
154
+ "discord-api-types": "0.38.25",
155
155
  "domhandler": "5.0.3",
156
- "eslint": "9.34.0",
156
+ "eslint": "9.35.0",
157
157
  "eslint-config-prettier": "10.1.8",
158
158
  "eslint-nibble": "9.0.0",
159
- "eslint-plugin-n": "17.21.3",
159
+ "eslint-plugin-n": "17.23.0",
160
160
  "eslint-plugin-prettier": "5.5.4",
161
- "eslint-plugin-unicorn": "60.0.0",
161
+ "eslint-plugin-unicorn": "61.0.2",
162
162
  "eslint-plugin-yml": "1.18.0",
163
- "fs-extra": "11.3.1",
164
- "globals": "16.3.0",
165
- "got": "14.4.7",
163
+ "fs-extra": "11.3.2",
164
+ "globals": "16.4.0",
165
+ "got": "14.4.8",
166
166
  "husky": "9.1.7",
167
167
  "js-beautify": "1.15.4",
168
- "lint-staged": "16.1.5",
169
- "magic-string": "0.30.18",
168
+ "lint-staged": "16.1.6",
169
+ "magic-string": "0.30.19",
170
170
  "mockdate": "3.0.5",
171
171
  "msw": "2.4.3",
172
172
  "node-network-devtools": "1.0.29",
173
173
  "prettier": "3.6.2",
174
174
  "remark-parse": "11.0.0",
175
175
  "supertest": "7.1.4",
176
- "tsdown": "0.14.2",
176
+ "tsdown": "0.15.2",
177
177
  "typescript": "5.9.2",
178
178
  "unified": "11.0.5",
179
179
  "vite-tsconfig-paths": "5.1.4",
@@ -1,22 +0,0 @@
1
- <text>白天:{{item.textDay}}——夜间:{{item.textNight}}</text>
2
- <br>
3
- <text>气温:{{item.tempMin}}℃~{{item.tempMax}}℃</text>
4
- <br>
5
- <text>相对湿度:{{item.humidity}}%</text>
6
- <br>
7
- <text>空气质量指数:{{item.aqi}} ({{item.aqiCategory}})</text>
8
- <br>
9
- <text>大气压强:{{item.pressure}}百帕</text>
10
- <br>
11
- <text>紫外线强度:{{item.uvIndex}}</text>
12
- <br>
13
- <text>白天风向:{{item.windDirDay}} 风力:{{item.windScaleDay}}级 风速:{{item.windSpeedDay}}公里/小时</text>
14
- <br>
15
- <text>夜间风向:{{item.windDirNight}} 风力:{{item.windScaleNight}}级 风速:{{item.windSpeedNight}}公里/小时</text>
16
- <br>
17
- <text>能见度:{{item.vis}}公里</text>
18
- <br>
19
- <text>日出:{{item.sunrise}} 日落: {{item.sunset}}</text>
20
- <br>
21
- <text>月相:{{item.moonPhase}} 月出:{{item.sunrise}} 月落:{{item.moonset}}
22
- <br>
@@ -1,16 +0,0 @@
1
- <text>天气:{{item.text}}</text>
2
- <br>
3
- <text>气温:{{item.temp}}℃</text>
4
- <br>
5
- <text>体感温度:{{item.feelsLike}}℃</text>
6
- <br>
7
- <text>风向:{{item.windDir}}</text>
8
- <br>
9
- <text>风力:{{item.windScale}}级 风速:{{item.windSpeed}}km/h</text>
10
- <br>
11
- <text>湿度:{{item.humidity}}% 大气压强:{{item.pressure}}hPa</text>
12
- <br>
13
- <text>本小时降水量:{{item.precip}}mm</text>
14
- <br>
15
- <text>能见度:{{item.vis}}km</text>
16
- <br>