rsshub 1.0.0-master.f9003f9 → 1.0.0-master.f917bdc

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 (532) hide show
  1. package/README.md +1 -0
  2. package/lib/api/category/one.ts +54 -0
  3. package/lib/api/index.ts +10 -4
  4. package/lib/app.tsx +2 -0
  5. package/lib/config.ts +43 -17
  6. package/lib/errors/index.test.ts +9 -5
  7. package/lib/errors/index.tsx +11 -4
  8. package/lib/index.ts +5 -2
  9. package/lib/middleware/anti-hotlink.test.ts +6 -6
  10. package/lib/middleware/cache.ts +21 -6
  11. package/lib/middleware/logger.ts +5 -1
  12. package/lib/middleware/template.tsx +15 -11
  13. package/lib/middleware/trace.ts +25 -0
  14. package/lib/registry.test.ts +8 -0
  15. package/lib/registry.ts +10 -2
  16. package/lib/router.js +0 -9
  17. package/lib/routes/141jav/index.ts +25 -21
  18. package/lib/routes/141ppv/index.ts +24 -20
  19. package/lib/routes/2048/index.ts +13 -10
  20. package/lib/routes/3dmgame/news-center.ts +1 -1
  21. package/lib/routes/51read/article.ts +82 -0
  22. package/lib/routes/51read/namespace.ts +6 -0
  23. package/lib/routes/69shu/article.ts +8 -8
  24. package/lib/routes/69shu/namespace.ts +1 -1
  25. package/lib/routes/academia/namespace.ts +6 -0
  26. package/lib/routes/academia/topics.ts +49 -0
  27. package/lib/routes/alistapart/utils.ts +2 -2
  28. package/lib/routes/aljazeera/index.ts +2 -2
  29. package/lib/routes/alpinelinux/namespace.ts +11 -0
  30. package/lib/routes/alpinelinux/pkgs.ts +104 -0
  31. package/lib/routes/apnews/rss.ts +10 -4
  32. package/lib/routes/apnews/topics.ts +11 -5
  33. package/lib/routes/apnews/utils.ts +36 -12
  34. package/lib/routes/apple/apps.ts +30 -8
  35. package/lib/routes/asmr-200/index.ts +66 -0
  36. package/lib/routes/asmr-200/namespace.ts +6 -0
  37. package/lib/routes/asmr-200/templates/work.art +7 -0
  38. package/lib/routes/asmr-200/type.ts +96 -0
  39. package/lib/routes/autocentre/index.ts +29 -0
  40. package/lib/routes/autocentre/namespace.ts +7 -0
  41. package/lib/routes/bbc/index.ts +3 -1
  42. package/lib/routes/bc3ts/list.ts +72 -0
  43. package/lib/routes/bc3ts/namespace.ts +7 -0
  44. package/lib/routes/bc3ts/templates/media.art +10 -0
  45. package/lib/routes/bc3ts/types.ts +118 -0
  46. package/lib/routes/beijingprice/index.ts +193 -0
  47. package/lib/routes/beijingprice/namespace.ts +8 -0
  48. package/lib/routes/bilibili/api-interface.d.ts +1 -0
  49. package/lib/routes/bilibili/dynamic.ts +35 -18
  50. package/lib/routes/bilibili/namespace.ts +1 -1
  51. package/lib/routes/bilibili/ranking.ts +99 -8
  52. package/lib/routes/bilibili/video.ts +3 -5
  53. package/lib/routes/bing/daily-wallpaper.ts +57 -18
  54. package/lib/routes/bjnews/cat.ts +43 -0
  55. package/lib/routes/bjnews/column.ts +43 -0
  56. package/lib/routes/bjnews/namespace.ts +6 -0
  57. package/lib/routes/bjnews/utils.ts +19 -0
  58. package/lib/routes/bjx/fd.ts +63 -0
  59. package/lib/routes/bjx/namespace.ts +1 -1
  60. package/lib/routes/bluearchive/namespace.ts +7 -0
  61. package/lib/routes/bluearchive/news.ts +88 -0
  62. package/lib/routes/bt0/mv.ts +65 -0
  63. package/lib/routes/bt0/namespace.ts +9 -0
  64. package/lib/routes/bt0/tlist.ts +67 -0
  65. package/lib/routes/bt0/util.ts +51 -0
  66. package/lib/routes/buaa/jiaowu.ts +124 -0
  67. package/lib/routes/buaa/lib/space/newbook.ts +171 -0
  68. package/lib/routes/buaa/lib/space/templates/newbook.art +44 -0
  69. package/lib/routes/buaa/news/index.ts +15 -13
  70. package/lib/routes/buaa/sme.ts +5 -3
  71. package/lib/routes/bugzilla/bug.ts +59 -0
  72. package/lib/routes/bugzilla/namespace.ts +11 -0
  73. package/lib/routes/cara/constant.ts +5 -0
  74. package/lib/routes/cara/likes.ts +56 -0
  75. package/lib/routes/cara/namespace.ts +6 -0
  76. package/lib/routes/cara/portfolio.ts +40 -0
  77. package/lib/routes/cara/templates/post.art +6 -0
  78. package/lib/routes/cara/timeline.ts +56 -0
  79. package/lib/routes/cara/types.ts +45 -0
  80. package/lib/routes/cara/utils.ts +62 -0
  81. package/lib/routes/cbaigui/utils.ts +1 -1
  82. package/lib/routes/cccfna/index.ts +82 -0
  83. package/lib/routes/cccfna/namespace.ts +6 -0
  84. package/lib/routes/cffex/announcement.ts +73 -0
  85. package/lib/routes/cffex/namespace.ts +6 -0
  86. package/lib/routes/cfr/index.ts +58 -0
  87. package/lib/routes/cfr/namespace.ts +6 -0
  88. package/lib/routes/cfr/types.ts +30 -0
  89. package/lib/routes/cfr/utils.ts +284 -0
  90. package/lib/routes/chaping/newsflash.ts +2 -2
  91. package/lib/routes/chlinlearn/daily-blog.ts +48 -0
  92. package/lib/routes/chlinlearn/namespcae.ts +6 -0
  93. package/lib/routes/cnbc/rss.ts +1 -1
  94. package/lib/routes/codeforces/contests.ts +2 -2
  95. package/lib/routes/codeforces/recent-actions.ts +2 -2
  96. package/lib/routes/copymanga/comic.ts +3 -1
  97. package/lib/routes/dangdang/namespace.ts +6 -0
  98. package/lib/routes/dangdang/notice.ts +69 -0
  99. package/lib/routes/dataguidance/index.ts +66 -0
  100. package/lib/routes/dataguidance/namespace.ts +7 -0
  101. package/lib/routes/dblp/publication.ts +4 -6
  102. package/lib/routes/deadbydaylight/index.ts +69 -0
  103. package/lib/routes/deadbydaylight/namespace.ts +12 -0
  104. package/lib/routes/devolverdigital/blog.ts +59 -42
  105. package/lib/routes/dewu/declaration.ts +86 -0
  106. package/lib/routes/dewu/namespace.ts +6 -0
  107. package/lib/routes/dhu/jiaowu/news.ts +53 -24
  108. package/lib/routes/dhu/namespace.ts +1 -1
  109. package/lib/routes/dhu/xxgk/news.ts +48 -20
  110. package/lib/routes/digitalcameraworld/news.ts +1 -1
  111. package/lib/routes/discord/channel.ts +10 -10
  112. package/lib/routes/discord/discord-api.ts +27 -32
  113. package/lib/routes/discord/templates/message.art +15 -0
  114. package/lib/routes/discourse/notifications.ts +4 -2
  115. package/lib/routes/dlnews/utils.ts +2 -2
  116. package/lib/routes/dockerhub/build.ts +11 -6
  117. package/lib/routes/domp4/detail.ts +1 -1
  118. package/lib/routes/domp4/latest-movie-bt.ts +71 -0
  119. package/lib/routes/dongqiudi/result.ts +1 -1
  120. package/lib/routes/douban/other/group.ts +24 -3
  121. package/lib/routes/duckdb/namespace.ts +6 -0
  122. package/lib/routes/duckdb/news.ts +65 -0
  123. package/lib/routes/dushu/fuzhou/index.ts +10 -11
  124. package/lib/routes/epicgames/index.ts +14 -4
  125. package/lib/routes/famitsu/category.ts +110 -43
  126. package/lib/routes/famitsu/templates/description.art +7 -0
  127. package/lib/routes/famitsu/types.ts +117 -0
  128. package/lib/routes/fanbox/namespace.ts +1 -1
  129. package/lib/routes/fanqienovel/namespace.ts +7 -0
  130. package/lib/routes/fanqienovel/page.ts +100 -0
  131. package/lib/routes/fansly/post.ts +1 -2
  132. package/lib/routes/fansly/tag.ts +1 -2
  133. package/lib/routes/fansly/utils.ts +5 -4
  134. package/lib/routes/fashionnetwork/index.ts +192 -0
  135. package/lib/routes/fashionnetwork/namespace.ts +8 -0
  136. package/lib/routes/fashionnetwork/templates/description.art +17 -0
  137. package/lib/routes/fediverse/namespace.ts +6 -0
  138. package/lib/routes/fediverse/timeline.ts +98 -0
  139. package/lib/routes/finviz/news.ts +4 -4
  140. package/lib/routes/foresightnews/util.ts +1 -1
  141. package/lib/routes/fortunechina/index.ts +24 -14
  142. package/lib/routes/freebuf/index.ts +3 -3
  143. package/lib/routes/ftchinese/channel.ts +3 -3
  144. package/lib/routes/gdut/oa-news.ts +12 -17
  145. package/lib/routes/getitfree/util.ts +1 -1
  146. package/lib/routes/github/activity.ts +55 -0
  147. package/lib/routes/github/issue.ts +26 -3
  148. package/lib/routes/github/search.ts +20 -18
  149. package/lib/routes/github/star.ts +4 -3
  150. package/lib/routes/github/trending.ts +27 -5
  151. package/lib/routes/google/citations.ts +2 -2
  152. package/lib/routes/google/research.ts +45 -0
  153. package/lib/routes/google/scholar.ts +2 -2
  154. package/lib/routes/gov/beijing/bphc/index.ts +3 -3
  155. package/lib/routes/gov/immiau/news.ts +2 -2
  156. package/lib/routes/gov/sh/fgw/index.ts +155 -0
  157. package/lib/routes/gov/sh/fgw/templates/description.art +17 -0
  158. package/lib/routes/gov/sh/namespace.ts +8 -0
  159. package/lib/routes/gov/{shanghai → sh}/rsj/ksxm.ts +2 -2
  160. package/lib/routes/gov/{shanghai → sh}/wgj/wgj.ts +3 -3
  161. package/lib/routes/gov/{shanghai → sh}/wsjkw/yqtb/index.ts +2 -2
  162. package/lib/routes/gov/{shanghai → sh}/yjj/index.ts +3 -3
  163. package/lib/routes/gov/stats/index.ts +8 -8
  164. package/lib/routes/gov/zhengce/index.ts +3 -6
  165. package/lib/routes/gov/zj/ningbogzw-notice.ts +50 -0
  166. package/lib/routes/gov/zj/ningborsjnotice.ts +50 -0
  167. package/lib/routes/gq/news.ts +1 -1
  168. package/lib/routes/grist/utils.ts +2 -2
  169. package/lib/routes/guokr/utils.ts +1 -1
  170. package/lib/routes/healthz.ts +8 -0
  171. package/lib/routes/hitcon/zeroday.ts +1 -1
  172. package/lib/routes/hket/index.ts +80 -76
  173. package/lib/routes/hrbeu/job/calendar.ts +8 -6
  174. package/lib/routes/huxiu/util.ts +2 -2
  175. package/lib/routes/hypergryph/arknights/arktca.ts +124 -0
  176. package/lib/routes/ieee/journal.ts +50 -67
  177. package/lib/routes/ieee/templates/description.art +1 -1
  178. package/lib/routes/imdb/chart.ts +61 -0
  179. package/lib/routes/imdb/namespace.ts +6 -0
  180. package/lib/routes/imdb/templates/chart.art +15 -0
  181. package/lib/routes/imdb/types.ts +103 -0
  182. package/lib/routes/imop/namespace.ts +10 -0
  183. package/lib/routes/imop/tianshu.ts +53 -0
  184. package/lib/routes/informedainews/docs.ts +78 -0
  185. package/lib/routes/informedainews/namespace.ts +18 -0
  186. package/lib/routes/inspirehep/author.ts +46 -0
  187. package/lib/routes/inspirehep/literature.ts +42 -0
  188. package/lib/routes/inspirehep/namespace.ts +7 -0
  189. package/lib/routes/inspirehep/types.ts +210 -0
  190. package/lib/routes/inspirehep/utils.ts +15 -0
  191. package/lib/routes/instagram/private-api/index.ts +28 -6
  192. package/lib/routes/investor/index.ts +213 -0
  193. package/lib/routes/investor/namespace.ts +8 -0
  194. package/lib/routes/iplaysoft/index.ts +68 -0
  195. package/lib/routes/iplaysoft/namespace.ts +6 -0
  196. package/lib/routes/j-test/namespace.ts +6 -0
  197. package/lib/routes/j-test/news.ts +64 -0
  198. package/lib/routes/japanpost/namespace.ts +7 -1
  199. package/lib/routes/japanpost/router.ts +40 -0
  200. package/lib/routes/japanpost/track.ts +1 -23
  201. package/lib/routes/javbus/index.ts +8 -1
  202. package/lib/routes/javdb/actors.ts +6 -2
  203. package/lib/routes/javdb/index.ts +4 -3
  204. package/lib/routes/javdb/series.ts +1 -1
  205. package/lib/routes/javdb/utils.ts +6 -0
  206. package/lib/routes/javdb/videocodes.ts +56 -0
  207. package/lib/routes/jike/topic.ts +1 -1
  208. package/lib/routes/jike/user.ts +1 -1
  209. package/lib/routes/jingzhengu/namespace.ts +6 -0
  210. package/lib/routes/jingzhengu/news.ts +77 -0
  211. package/lib/routes/jingzhengu/types.ts +39 -0
  212. package/lib/routes/jingzhengu/utils.ts +35 -0
  213. package/lib/routes/jinritemai/docs.ts +74 -0
  214. package/lib/routes/jinritemai/namespace.ts +6 -0
  215. package/lib/routes/jiuyangongshe/community.ts +147 -0
  216. package/lib/routes/jiuyangongshe/namespace.ts +7 -0
  217. package/lib/routes/jiuyangongshe/templates/community-description.art +4 -0
  218. package/lib/routes/jjwxc/book.ts +4 -3
  219. package/lib/routes/jlu/ccst/xwzx/index.ts +63 -0
  220. package/lib/routes/jlu/jwc.ts +55 -0
  221. package/lib/routes/jlu/namespace.ts +6 -0
  222. package/lib/routes/juejin/dynamic.ts +114 -0
  223. package/lib/routes/kadokawa/blog.ts +134 -0
  224. package/lib/routes/kadokawa/namespace.ts +8 -0
  225. package/lib/routes/kadokawa/templates/description.art +21 -0
  226. package/lib/routes/kaopu/news.ts +3 -3
  227. package/lib/routes/kelownacapnews/namespace.ts +6 -0
  228. package/lib/routes/kelownacapnews/news.ts +93 -0
  229. package/lib/routes/kemono/index.ts +21 -0
  230. package/lib/routes/keylol/index.ts +56 -11
  231. package/lib/routes/kurogames/namespace.ts +7 -0
  232. package/lib/routes/kurogames/wutheringwaves/news.ts +59 -0
  233. package/lib/routes/kyodonews/index.ts +1 -1
  234. package/lib/routes/leetcode/articles.ts +19 -21
  235. package/lib/routes/line/today.ts +1 -1
  236. package/lib/routes/linkedin/cn/renderer.ts +1 -1
  237. package/lib/routes/lmu/jobs.ts +96 -0
  238. package/lib/routes/lmu/namespace.ts +17 -0
  239. package/lib/routes/lmu/templates/jobPosting.art +11 -0
  240. package/lib/routes/lofter/user.ts +2 -1
  241. package/lib/routes/logclub/index.ts +1 -2
  242. package/lib/routes/luogu/user-blog.ts +6 -6
  243. package/lib/routes/luolei/index.ts +1 -2
  244. package/lib/routes/maccms/index.ts +72 -0
  245. package/lib/routes/maccms/namespace.ts +9 -0
  246. package/lib/routes/maccms/templates/vod.art +12 -0
  247. package/lib/routes/maccms/type.ts +102 -0
  248. package/lib/routes/mangadex/namespace.ts +1 -1
  249. package/lib/routes/manyvids/namespace.ts +7 -0
  250. package/lib/routes/manyvids/templates/video.art +3 -0
  251. package/lib/routes/manyvids/types.ts +89 -0
  252. package/lib/routes/manyvids/video.ts +51 -0
  253. package/lib/routes/matters/author.ts +63 -0
  254. package/lib/routes/matters/latest.ts +74 -0
  255. package/lib/routes/matters/namespace.ts +7 -0
  256. package/lib/routes/matters/tags.ts +85 -0
  257. package/lib/routes/matters/utils.ts +30 -0
  258. package/lib/routes/mcmod/index.ts +105 -0
  259. package/lib/routes/mcmod/namespace.ts +6 -0
  260. package/lib/routes/mcmod/templates/mod.art +13 -0
  261. package/lib/routes/meituan/namespace.ts +6 -0
  262. package/lib/routes/meituan/tech.ts +67 -0
  263. package/lib/routes/metacritic/index.ts +10 -0
  264. package/lib/routes/metrics.ts +12 -0
  265. package/lib/routes/microsoft/mcr.ts +63 -0
  266. package/lib/routes/microsoft/namespace.ts +2 -2
  267. package/lib/routes/mihoyo/bbs/img-ranking.ts +4 -4
  268. package/lib/routes/mihoyo/bbs/static-data.ts +7 -0
  269. package/lib/routes/minecraft/version.ts +1 -1
  270. package/lib/routes/mirrormedia/category.ts +101 -0
  271. package/lib/routes/mirrormedia/index.ts +43 -0
  272. package/lib/routes/mirrormedia/namespace.ts +6 -0
  273. package/lib/routes/mirrormedia/utils.ts +19 -0
  274. package/lib/routes/misskey/user-timeline.ts +42 -0
  275. package/lib/routes/misskey/utils.ts +41 -1
  276. package/lib/routes/modb/topic.ts +5 -6
  277. package/lib/routes/my-formosa/index.ts +78 -0
  278. package/lib/routes/my-formosa/namespace.ts +6 -0
  279. package/lib/routes/myfans/namespace.ts +6 -0
  280. package/lib/routes/myfans/post.ts +64 -0
  281. package/lib/routes/myfans/templates/post.art +8 -0
  282. package/lib/routes/myfans/types.ts +104 -0
  283. package/lib/routes/myfans/utils.ts +39 -0
  284. package/lib/routes/nasa/apod.ts +4 -3
  285. package/lib/routes/nasa/namespace.ts +1 -1
  286. package/lib/routes/nationalgeographic/latest-stories.ts +1 -1
  287. package/lib/routes/nationalgeographic/templates/stories.art +1 -1
  288. package/lib/routes/neea/index.ts +47 -19
  289. package/lib/routes/neea/jlpt.ts +12 -15
  290. package/lib/routes/neea/namespace.ts +2 -2
  291. package/lib/routes/newrank/utils.ts +1 -1
  292. package/lib/routes/newzmz/util.ts +1 -1
  293. package/lib/routes/nextjs/blog.ts +63 -0
  294. package/lib/routes/nextjs/namespace.ts +6 -0
  295. package/lib/routes/nga/forum.ts +3 -2
  296. package/lib/routes/nikkei/asia/index.ts +1 -10
  297. package/lib/routes/nikkei/cn/index.ts +39 -3
  298. package/lib/routes/nikkei/index.ts +5 -4
  299. package/lib/routes/nikkei/namespace.ts +1 -1
  300. package/lib/routes/nikkei/news.ts +2 -2
  301. package/lib/routes/nmc/weatheralarm.ts +1 -0
  302. package/lib/routes/notion/release.ts +81 -0
  303. package/lib/routes/npm/package.ts +15 -8
  304. package/lib/routes/nyaa/main.ts +2 -3
  305. package/lib/routes/nyaa/namespace.ts +10 -0
  306. package/lib/routes/ollama/blog.ts +39 -0
  307. package/lib/routes/ollama/models.ts +7 -4
  308. package/lib/routes/oschina/news.ts +6 -2
  309. package/lib/routes/people/index.ts +4 -2
  310. package/lib/routes/picnob/namespace.ts +1 -4
  311. package/lib/routes/picnob/user.ts +3 -2
  312. package/lib/routes/picuki/namespace.ts +1 -4
  313. package/lib/routes/picuki/profile.ts +11 -7
  314. package/lib/routes/pixiv/ranking.ts +73 -10
  315. package/lib/routes/pixiv/search.ts +58 -7
  316. package/lib/routes/pixiv/user.ts +3 -1
  317. package/lib/routes/pixiv/utils.ts +3 -3
  318. package/lib/routes/podwise/collections.ts +46 -0
  319. package/lib/routes/podwise/episodes.ts +119 -0
  320. package/lib/routes/podwise/namespace.ts +9 -0
  321. package/lib/routes/ps/monthly-games.ts +3 -2
  322. package/lib/routes/psyche/namespace.ts +6 -0
  323. package/lib/routes/psyche/templates/essay.art +3 -0
  324. package/lib/routes/psyche/templates/video.art +10 -0
  325. package/lib/routes/psyche/topic.ts +46 -0
  326. package/lib/routes/psyche/type.ts +53 -0
  327. package/lib/routes/psyche/utils.ts +107 -0
  328. package/lib/routes/pubscholar/explore.ts +62 -0
  329. package/lib/routes/pubscholar/namespace.ts +7 -0
  330. package/lib/routes/pubscholar/types.ts +41 -0
  331. package/lib/routes/pubscholar/utils.ts +44 -0
  332. package/lib/routes/pwc/sustainability.ts +53 -49
  333. package/lib/routes/qidian/chapter.ts +4 -3
  334. package/lib/routes/raycast/changelog.ts +54 -0
  335. package/lib/routes/raycast/namespace.ts +7 -0
  336. package/lib/routes/react/blog.ts +57 -0
  337. package/lib/routes/react/namespace.ts +6 -0
  338. package/lib/routes/readwise/list.ts +152 -0
  339. package/lib/routes/readwise/namespace.ts +6 -0
  340. package/lib/routes/reuters/common.ts +3 -2
  341. package/lib/routes/reuters/namespace.ts +1 -1
  342. package/lib/routes/rss3/index.ts +148 -0
  343. package/lib/routes/rss3/namespace.ts +7 -0
  344. package/lib/routes/rsshub/routes.ts +36 -14
  345. package/lib/routes/ruc/ai.ts +87 -0
  346. package/lib/routes/ruc/namespace.ts +5 -2
  347. package/lib/routes/samd/namespace.ts +6 -0
  348. package/lib/routes/samd/news.ts +74 -0
  349. package/lib/routes/sara/index.ts +1 -1
  350. package/lib/routes/sciencedirect/cf-email.ts +0 -1
  351. package/lib/routes/sehuatang/index.ts +33 -14
  352. package/lib/routes/sehuatang/user.ts +1 -1
  353. package/lib/routes/shiep/config.ts +4 -10
  354. package/lib/routes/shiep/index.ts +9 -9
  355. package/lib/routes/showstart/artist.ts +5 -4
  356. package/lib/routes/showstart/brand.ts +5 -4
  357. package/lib/routes/showstart/event.ts +8 -7
  358. package/lib/routes/showstart/search.ts +10 -8
  359. package/lib/routes/showstart/service.ts +81 -53
  360. package/lib/routes/showstart/site.ts +41 -0
  361. package/lib/routes/showstart/utils.ts +9 -8
  362. package/lib/routes/sicau/jiaowu.ts +77 -0
  363. package/lib/routes/sicau/jk.ts +210 -0
  364. package/lib/routes/sicau/namespace.ts +1 -1
  365. package/lib/routes/sjtu/jwc.ts +4 -1
  366. package/lib/routes/sjtu/yzb/zkxx.ts +36 -16
  367. package/lib/routes/smzdm/keyword.ts +3 -2
  368. package/lib/routes/smzdm/ranking.ts +180 -46
  369. package/lib/routes/spotify/artist.ts +16 -18
  370. package/lib/routes/spotify/artists-top.ts +7 -8
  371. package/lib/routes/spotify/playlist.ts +10 -10
  372. package/lib/routes/spotify/saved.ts +7 -8
  373. package/lib/routes/spotify/show.ts +8 -9
  374. package/lib/routes/spotify/tracks-top.ts +7 -8
  375. package/lib/routes/spotify/utils.ts +22 -22
  376. package/lib/routes/springer/journal.ts +10 -12
  377. package/lib/routes/sspai/author.ts +8 -2
  378. package/lib/routes/sspai/column.ts +1 -1
  379. package/lib/routes/sspai/index.ts +10 -4
  380. package/lib/routes/sspai/matrix.ts +8 -2
  381. package/lib/routes/sspai/prime-community.ts +83 -0
  382. package/lib/routes/sspai/series-update.ts +1 -1
  383. package/lib/routes/sspai/tag.ts +8 -2
  384. package/lib/routes/sspai/topic.ts +8 -2
  385. package/lib/routes/sspai/topics.ts +1 -1
  386. package/lib/routes/steam/sharefile-changelog.ts +65 -0
  387. package/lib/routes/steam/templates/workshop-search-description.art +5 -0
  388. package/lib/routes/steam/workshop-search.ts +109 -0
  389. package/lib/routes/stockedge/utils.ts +9 -11
  390. package/lib/routes/stream-capital/namespace.ts +6 -0
  391. package/lib/routes/stream-capital/search.ts +79 -0
  392. package/lib/routes/stream-capital/types.ts +44 -0
  393. package/lib/routes/stream-capital/utils.ts +18 -0
  394. package/lib/routes/sustainabilitymag/articles.ts +144 -0
  395. package/lib/routes/sustainabilitymag/namespace.ts +6 -0
  396. package/lib/routes/t66y/index.ts +29 -7
  397. package/lib/routes/techcrunch/news.ts +20 -29
  398. package/lib/routes/techcrunch/templates/description.art +7 -0
  399. package/lib/routes/telecompaper/news.ts +1 -1
  400. package/lib/routes/telegram/channel.ts +37 -31
  401. package/lib/routes/tencent/cloud/developer/column.ts +81 -0
  402. package/lib/routes/tencent/namespace.ts +2 -2
  403. package/lib/routes/tesla/cx.ts +1 -1
  404. package/lib/routes/test/index.ts +5 -1
  405. package/lib/routes/test/namespace.ts +1 -1
  406. package/lib/routes/the/index.ts +210 -0
  407. package/lib/routes/the/namespace.ts +8 -0
  408. package/lib/routes/the/templates/description.art +27 -0
  409. package/lib/routes/the/util.ts +307 -0
  410. package/lib/routes/theinitium/channel.ts +1 -1
  411. package/lib/routes/theinitium/follow.ts +1 -6
  412. package/lib/routes/theinitium/utils.ts +2 -18
  413. package/lib/routes/thoughtworks/index.ts +71 -0
  414. package/lib/routes/thoughtworks/namespace.ts +6 -0
  415. package/lib/routes/trending/all-trending.ts +2 -2
  416. package/lib/routes/tsdm39/bd.ts +101 -0
  417. package/lib/routes/tsdm39/namespace.ts +7 -0
  418. package/lib/routes/tvb/news.ts +1 -0
  419. package/lib/routes/twitter/api/index.ts +1 -1
  420. package/lib/routes/twitter/api/mobile-api/api.ts +9 -6
  421. package/lib/routes/twitter/api/mobile-api/login.ts +161 -138
  422. package/lib/routes/twitter/api/mobile-api/token.ts +16 -22
  423. package/lib/routes/twitter/api/web-api/api.ts +1 -0
  424. package/lib/routes/twitter/api/web-api/utils.ts +89 -17
  425. package/lib/routes/twitter/home.ts +2 -2
  426. package/lib/routes/twitter/keyword.ts +3 -2
  427. package/lib/routes/twitter/likes.ts +1 -1
  428. package/lib/routes/twitter/list.ts +1 -1
  429. package/lib/routes/twitter/media.ts +4 -3
  430. package/lib/routes/twitter/namespace.ts +2 -2
  431. package/lib/routes/twitter/user.ts +5 -4
  432. package/lib/routes/twitter/utils.ts +14 -5
  433. package/lib/routes/twreporter/category.ts +67 -22
  434. package/lib/routes/twreporter/fetch-article.ts +11 -5
  435. package/lib/routes/twreporter/newest.ts +2 -2
  436. package/lib/routes/typst/universe.ts +34 -8
  437. package/lib/routes/udn/breaking-news.ts +9 -0
  438. package/lib/routes/utgd/category.ts +18 -59
  439. package/lib/routes/utgd/timeline.ts +9 -45
  440. package/lib/routes/utgd/topic.ts +9 -51
  441. package/lib/routes/utgd/utils.ts +41 -0
  442. package/lib/routes/v2ex/tab.ts +3 -2
  443. package/lib/routes/v2ex/topics.ts +19 -3
  444. package/lib/routes/v2ex/xna.ts +55 -0
  445. package/lib/routes/vice/namespace.ts +6 -0
  446. package/lib/routes/vice/templates/article.art +19 -0
  447. package/lib/routes/vice/topic.ts +103 -0
  448. package/lib/routes/watasuke/blog.ts +1 -1
  449. package/lib/routes/weibo/friends.ts +1 -0
  450. package/lib/routes/weibo/group.ts +1 -0
  451. package/lib/routes/weibo/keyword.ts +3 -2
  452. package/lib/routes/weibo/namespace.ts +1 -1
  453. package/lib/routes/weibo/search/hot.ts +12 -7
  454. package/lib/routes/weibo/user-bookmarks.ts +191 -0
  455. package/lib/routes/weibo/user.ts +11 -8
  456. package/lib/routes/weibo/utils.ts +32 -2
  457. package/lib/routes/wfu/news.ts +1 -1
  458. package/lib/routes/wired/namespace.ts +7 -0
  459. package/lib/routes/wired/tag.ts +97 -0
  460. package/lib/routes/wired/types.ts +81 -0
  461. package/lib/routes/wordpress/util.ts +1 -1
  462. package/lib/routes/xiaoyuzhou/podcast.ts +2 -1
  463. package/lib/routes/ximalaya/album.ts +27 -19
  464. package/lib/routes/ximalaya/types.ts +68 -0
  465. package/lib/routes/ximalaya/utils.ts +38 -1
  466. package/lib/routes/xinhuanet/app.ts +109 -0
  467. package/lib/routes/xinhuanet/namespace.ts +8 -0
  468. package/lib/routes/xsijishe/forum.ts +23 -3
  469. package/lib/routes/xsijishe/rank.ts +23 -3
  470. package/lib/routes/yahoo/news/index.ts +149 -0
  471. package/lib/routes/yahoo/news/listid.ts +67 -0
  472. package/lib/routes/yahoo/news/{tw/provider-helper.ts → provider-helper.ts} +9 -4
  473. package/lib/routes/yahoo/news/{tw/provider.ts → provider.ts} +21 -6
  474. package/lib/routes/yahoo/news/{tw/utils.ts → utils.ts} +24 -15
  475. package/lib/routes/yicai/carousel.ts +48 -0
  476. package/lib/routes/yicai/utils.ts +23 -17
  477. package/lib/routes/ymgal/article.ts +1 -1
  478. package/lib/routes/youtube/channel.ts +1 -0
  479. package/lib/routes/youtube/custom.ts +2 -0
  480. package/lib/routes/youtube/live.ts +1 -0
  481. package/lib/routes/youtube/playlist.ts +1 -0
  482. package/lib/routes/youtube/subscriptions.ts +2 -0
  483. package/lib/routes/youtube/user.ts +16 -4
  484. package/lib/routes/zaobao/interactive.ts +2 -11
  485. package/lib/routes/zaobao/{index.ts → other.ts} +2 -10
  486. package/lib/routes/zaobao/realtime.ts +0 -8
  487. package/lib/routes/zaobao/util.ts +14 -10
  488. package/lib/routes/zcool/discover.ts +2 -1
  489. package/lib/routes/zhihu/activities.ts +2 -1
  490. package/lib/routes/zhihu/execlib/x-zse-96-v3.ts +2 -0
  491. package/lib/routes/zhihu/hot.ts +56 -7
  492. package/lib/routes/zhihu/namespace.ts +3 -0
  493. package/lib/routes/zhihu/posts.ts +20 -15
  494. package/lib/routes/zhihu/types.ts +104 -0
  495. package/lib/routes/zhihu/utils.ts +25 -4
  496. package/lib/routes/zhihu/zhuanlan.ts +8 -2
  497. package/lib/routes/zhubai/top20.ts +2 -2
  498. package/lib/routes/zhuwang/index.ts +1 -1
  499. package/lib/routes/zjgtjy/index.ts +3 -9
  500. package/lib/routes.test.ts +11 -5
  501. package/lib/types.ts +34 -2
  502. package/lib/utils/cache/index.ts +8 -0
  503. package/lib/utils/ofetch.ts +15 -1
  504. package/lib/utils/otel/index.ts +2 -0
  505. package/lib/utils/otel/metric.ts +66 -0
  506. package/lib/utils/otel/trace.ts +28 -0
  507. package/lib/utils/request-rewriter/fetch.ts +21 -2
  508. package/lib/utils/request-rewriter.test.ts +14 -0
  509. package/lib/views/atom.tsx +2 -2
  510. package/lib/views/error.tsx +4 -4
  511. package/lib/views/index.tsx +5 -4
  512. package/lib/views/json.ts +1 -1
  513. package/lib/views/layout.tsx +1 -1
  514. package/lib/views/rss.tsx +3 -2
  515. package/lib/views/rss3.test.ts +99 -0
  516. package/package.json +69 -56
  517. package/lib/routes/ieee/earlyaccess.ts +0 -100
  518. package/lib/routes/ieee/recent.ts +0 -107
  519. package/lib/routes/yahoo/news/tw/index.ts +0 -80
  520. package/lib/routes/yahoo/news/us/index.ts +0 -55
  521. package/lib/routes/zhihu/hotlist.ts +0 -72
  522. package/lib/routes-deprecated/bjnews/news.js +0 -44
  523. package/lib/routes-deprecated/iplay/home.js +0 -26
  524. package/lib/routes-deprecated/iplay/utils.js +0 -57
  525. package/lib/routes-deprecated/matters/author.js +0 -49
  526. package/lib/routes-deprecated/matters/latest.js +0 -69
  527. package/lib/routes-deprecated/matters/tags.js +0 -56
  528. /package/lib/routes/gov/{shanghai → sh}/rsj/templates/ksxm.art +0 -0
  529. /package/lib/routes/gov/{shanghai → sh}/wgj/templates/wgj.art +0 -0
  530. /package/lib/routes/hypergryph/{announce.ts → arknights/announce.ts} +0 -0
  531. /package/lib/routes/hypergryph/{japan.ts → arknights/japan.ts} +0 -0
  532. /package/lib/routes/hypergryph/{news.ts → arknights/news.ts} +0 -0
package/README.md CHANGED
@@ -10,6 +10,7 @@
10
10
  [![npm publish](https://img.shields.io/npm/dt/rsshub?label=npm%20downloads&logo=npm&style=flat-square)](https://www.npmjs.com/package/rsshub)
11
11
  [![test](https://img.shields.io/github/actions/workflow/status/DIYgod/RSSHub/test.yml?branch=master&label=test&logo=github&style=flat-square)](https://github.com/DIYgod/RSSHub/actions/workflows/test.yml?query=event%3Apush+branch%3Amaster)
12
12
  [![Test coverage](https://img.shields.io/codecov/c/github/DIYgod/RSSHub.svg?style=flat-square&logo=codecov)](https://app.codecov.io/gh/DIYgod/RSSHub/branch/master)
13
+ [![Visitors](https://hits.seeyoufarm.com/api/count/incr/badge.svg?url=https%3A%2F%2Fgithub.com%2FDIYgod%2FRSSHub&count_bg=%23FF752E&title_bg=%23555555&icon=rss.svg&icon_color=%23FF752E&title=RSS+lovers&edge_flat=true)](https://github.com/DIYgod/RSSHub)
13
14
 
14
15
  [![Telegram group](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.swo.moe%2Fstats%2Ftelegram%2Frsshub&query=count&color=2CA5E0&label=Telegram%20Group&logo=telegram&cacheSeconds=3600&style=flat-square)](https://t.me/rsshub) [![Telegram channel](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fapi.swo.moe%2Fstats%2Ftelegram%2FawesomeRSSHub&query=count&color=2CA5E0&label=Telegram%20Channel&logo=telegram&cacheSeconds=3600&style=flat-square)](https://t.me/awesomeRSSHub) [![Twitter](https://img.shields.io/badge/any_text-Follow-blue?color=2CA5E0&label=Twitter&logo=twitter&cacheSeconds=3600&style=flat-square)](https://x.com/intent/follow?screen_name=_RSSHub)
15
16
 
@@ -0,0 +1,54 @@
1
+ import { namespaces } from '@/registry';
2
+ import { z, createRoute, RouteHandler } from '@hono/zod-openapi';
3
+
4
+ const categoryList: Record<string, typeof namespaces> = {};
5
+
6
+ for (const namespace in namespaces) {
7
+ for (const path in namespaces[namespace].routes) {
8
+ if (namespaces[namespace].routes[path].categories?.length) {
9
+ for (const category of namespaces[namespace].routes[path].categories!) {
10
+ if (!categoryList[category]) {
11
+ categoryList[category] = {};
12
+ }
13
+ if (!categoryList[category][namespace]) {
14
+ categoryList[category][namespace] = {
15
+ ...namespaces[namespace],
16
+ routes: {},
17
+ };
18
+ }
19
+ categoryList[category][namespace].routes[path] = namespaces[namespace].routes[path];
20
+ }
21
+ }
22
+ }
23
+ }
24
+
25
+ const ParamsSchema = z.object({
26
+ category: z.string().openapi({
27
+ param: {
28
+ name: 'category',
29
+ in: 'path',
30
+ },
31
+ example: 'popular',
32
+ }),
33
+ });
34
+
35
+ const route = createRoute({
36
+ method: 'get',
37
+ path: '/category/{category}',
38
+ tags: ['Category'],
39
+ request: {
40
+ params: ParamsSchema,
41
+ },
42
+ responses: {
43
+ 200: {
44
+ description: 'Namespace list by category',
45
+ },
46
+ },
47
+ });
48
+
49
+ const handler: RouteHandler<typeof route> = (ctx) => {
50
+ const { category } = ctx.req.valid('param');
51
+ return ctx.json(categoryList[category]);
52
+ };
53
+
54
+ export { route, handler };
package/lib/api/index.ts CHANGED
@@ -3,8 +3,9 @@ import { route as namespaceAllRoute, handler as namespaceAllHandler } from '@/ap
3
3
  import { route as namespaceOneRoute, handler as namespaceOneHandler } from '@/api/namespace/one';
4
4
  import { route as radarRulesAllRoute, handler as radarRulesAllHandler } from '@/api/radar/rules/all';
5
5
  import { route as radarRulesOneRoute, handler as radarRulesOneHandler } from '@/api/radar/rules/one';
6
+ import { route as categoryOneRoute, handler as categoryOneHandler } from '@/api/category/one';
6
7
  import { OpenAPIHono } from '@hono/zod-openapi';
7
- import { swaggerUI } from '@hono/swagger-ui';
8
+ import { apiReference } from '@scalar/hono-api-reference';
8
9
 
9
10
  const app = new OpenAPIHono();
10
11
 
@@ -12,6 +13,7 @@ app.openapi(namespaceAllRoute, namespaceAllHandler);
12
13
  app.openapi(namespaceOneRoute, namespaceOneHandler);
13
14
  app.openapi(radarRulesAllRoute, radarRulesAllHandler);
14
15
  app.openapi(radarRulesOneRoute, radarRulesOneHandler);
16
+ app.openapi(categoryOneRoute, categoryOneHandler);
15
17
 
16
18
  const docs = app.getOpenAPI31Document({
17
19
  openapi: '3.1.0',
@@ -24,8 +26,12 @@ for (const path in docs.paths) {
24
26
  docs.paths[`/api${path}`] = docs.paths[path];
25
27
  delete docs.paths[path];
26
28
  }
27
- app.get('/docs', (ctx) => ctx.json(docs));
28
-
29
- app.get('/ui', swaggerUI({ url: '/api/docs' }));
29
+ app.get('/openapi.json', (ctx) => ctx.json(docs));
30
+ app.get(
31
+ '/reference',
32
+ apiReference({
33
+ spec: { content: docs },
34
+ })
35
+ );
30
36
 
31
37
  export default app;
package/lib/app.tsx CHANGED
@@ -12,6 +12,7 @@ import debug from '@/middleware/debug';
12
12
  import header from '@/middleware/header';
13
13
  import antiHotlink from '@/middleware/anti-hotlink';
14
14
  import parameter from '@/middleware/parameter';
15
+ import trace from '@/middleware/trace';
15
16
  import { jsxRenderer } from 'hono/jsx-renderer';
16
17
  import { trimTrailingSlash } from 'hono/trailing-slash';
17
18
 
@@ -37,6 +38,7 @@ app.use(
37
38
  })
38
39
  );
39
40
  app.use(mLogger);
41
+ app.use(trace);
40
42
  app.use(sentry);
41
43
  app.use(accessControl);
42
44
  app.use(debug);
package/lib/config.ts CHANGED
@@ -1,5 +1,5 @@
1
- import 'dotenv/config';
2
1
  import randUserAgent from '@/utils/rand-user-agent';
2
+ import 'dotenv/config';
3
3
  import { ofetch } from 'ofetch';
4
4
 
5
5
  let envs = process.env;
@@ -39,8 +39,8 @@ export type Config = {
39
39
  port?: string;
40
40
  auth?: string;
41
41
  url_regex: string;
42
+ strategy: 'on_retry' | 'all';
42
43
  };
43
- proxyStrategy: string;
44
44
  pacUri?: string;
45
45
  pacScript?: string;
46
46
  accessKey?: string;
@@ -154,7 +154,6 @@ export type Config = {
154
154
  username?: string;
155
155
  password?: string;
156
156
  bearertoken?: string;
157
- iap_receipt?: string;
158
157
  };
159
158
  instagram: {
160
159
  username?: string;
@@ -169,6 +168,9 @@ export type Config = {
169
168
  javdb: {
170
169
  session?: string;
171
170
  };
171
+ keylol: {
172
+ cookie?: string;
173
+ };
172
174
  lastfm: {
173
175
  api_key?: string;
174
176
  };
@@ -233,6 +235,9 @@ export type Config = {
233
235
  qingting: {
234
236
  id?: string;
235
237
  };
238
+ readwise: {
239
+ accessToken?: string;
240
+ };
236
241
  saraba1st: {
237
242
  cookie?: string;
238
243
  };
@@ -250,19 +255,23 @@ export type Config = {
250
255
  clientSecret?: string;
251
256
  refreshToken?: string;
252
257
  };
258
+ sspai: {
259
+ bearertoken?: string;
260
+ };
253
261
  telegram: {
254
262
  token?: string;
255
263
  };
256
264
  tophub: {
257
265
  cookie?: string;
258
266
  };
267
+ tsdm39: {
268
+ cookie: string;
269
+ };
259
270
  twitter: {
260
- oauthTokens?: string[];
261
- oauthTokenSecrets?: string[];
262
- username?: string;
263
- password?: string;
264
- authenticationSecret?: string;
265
- cookie?: string;
271
+ username?: string[];
272
+ password?: string[];
273
+ authenticationSecret?: string[];
274
+ authToken?: string[];
266
275
  };
267
276
  weibo: {
268
277
  app_key?: string;
@@ -283,6 +292,10 @@ export type Config = {
283
292
  ximalaya: {
284
293
  token?: string;
285
294
  };
295
+ xsijishe: {
296
+ cookie?: string;
297
+ userAgent?: string;
298
+ };
286
299
  xueqiu: {
287
300
  cookies?: string;
288
301
  };
@@ -388,8 +401,8 @@ const calculateValue = () => {
388
401
  port: envs.PROXY_PORT,
389
402
  auth: envs.PROXY_AUTH,
390
403
  url_regex: envs.PROXY_URL_REGEX || '.*',
404
+ strategy: envs.PROXY_STRATEGY || 'all', // all / on_retry
391
405
  },
392
- proxyStrategy: envs.PROXY_STRATEGY || 'all', // all / on_retry
393
406
  pacUri: envs.PAC_URI,
394
407
  pacScript: envs.PAC_SCRIPT,
395
408
  // access control
@@ -510,7 +523,6 @@ const calculateValue = () => {
510
523
  username: envs.INITIUM_USERNAME,
511
524
  password: envs.INITIUM_PASSWORD,
512
525
  bearertoken: envs.INITIUM_BEARER_TOKEN,
513
- iap_receipt: envs.INITIUM_IAP_RECEIPT,
514
526
  },
515
527
  instagram: {
516
528
  username: envs.IG_USERNAME,
@@ -525,6 +537,9 @@ const calculateValue = () => {
525
537
  javdb: {
526
538
  session: envs.JAVDB_SESSION,
527
539
  },
540
+ keylol: {
541
+ cookie: envs.KEYLOL_COOKIE,
542
+ },
528
543
  lastfm: {
529
544
  api_key: envs.LASTFM_API_KEY,
530
545
  },
@@ -589,6 +604,9 @@ const calculateValue = () => {
589
604
  qingting: {
590
605
  id: envs.QINGTING_ID,
591
606
  },
607
+ readwise: {
608
+ accessToken: envs.READWISE_ACCESS_TOKEN,
609
+ },
592
610
  saraba1st: {
593
611
  cookie: envs.SARABA1ST_COOKIE,
594
612
  },
@@ -606,6 +624,9 @@ const calculateValue = () => {
606
624
  clientSecret: envs.SPOTIFY_CLIENT_SECRET,
607
625
  refreshToken: envs.SPOTIFY_REFRESHTOKEN,
608
626
  },
627
+ sspai: {
628
+ bearertoken: envs.SSPAI_BEARERTOKEN,
629
+ },
609
630
  telegram: {
610
631
  token: envs.TELEGRAM_TOKEN,
611
632
  session: envs.TELEGRAM_SESSION,
@@ -616,13 +637,14 @@ const calculateValue = () => {
616
637
  tophub: {
617
638
  cookie: envs.TOPHUB_COOKIE,
618
639
  },
640
+ tsdm39: {
641
+ cookie: envs.TSDM39_COOKIES,
642
+ },
619
643
  twitter: {
620
- oauthTokens: envs.TWITTER_OAUTH_TOKEN?.split(','),
621
- oauthTokenSecrets: envs.TWITTER_OAUTH_TOKEN_SECRET?.split(','),
622
- username: envs.TWITTER_USERNAME,
623
- password: envs.TWITTER_PASSWORD,
624
- authenticationSecret: envs.TWITTER_AUTHENTICATION_SECRET,
625
- cookie: envs.TWITTER_COOKIE,
644
+ username: envs.TWITTER_USERNAME?.split(','),
645
+ password: envs.TWITTER_PASSWORD?.split(','),
646
+ authenticationSecret: envs.TWITTER_AUTHENTICATION_SECRET?.split(','),
647
+ authToken: envs.TWITTER_AUTH_TOKEN?.split(','),
626
648
  },
627
649
  weibo: {
628
650
  app_key: envs.WEIBO_APP_KEY,
@@ -643,6 +665,10 @@ const calculateValue = () => {
643
665
  ximalaya: {
644
666
  token: envs.XIMALAYA_TOKEN,
645
667
  },
668
+ xsijishe: {
669
+ cookie: envs.XSIJISHE_COOKIE,
670
+ user_agent: envs.XSIJISHE_USER_AGENT,
671
+ },
646
672
  xueqiu: {
647
673
  cookies: envs.XUEQIU_COOKIES,
648
674
  },
@@ -27,8 +27,12 @@ describe('httperror', () => {
27
27
  });
28
28
 
29
29
  describe('RequestInProgressError', () => {
30
- it(`RequestInProgressError`, async () => {
30
+ it(`RequestInProgressError with retry`, async () => {
31
31
  const responses = await Promise.all([request.get('/test/slow'), request.get('/test/slow')]);
32
+ expect(new Set(responses.map((r) => r.status))).toEqual(new Set([200, 200]));
33
+ });
34
+ it(`RequestInProgressError`, async () => {
35
+ const responses = await Promise.all([request.get('/test/slow4'), request.get('/test/slow4')]);
32
36
  expect(new Set(responses.map((r) => r.status))).toEqual(new Set([200, 503]));
33
37
  expect(new Set(responses.map((r) => r.headers['cache-control']))).toEqual(new Set([`public, max-age=${config.cache.routeExpire}`, `public, max-age=${config.requestTimeout / 1000}`]));
34
38
  expect(responses.filter((r) => r.text.includes('RequestInProgressError: This path is currently fetching, please come back later!'))).toHaveLength(1);
@@ -63,19 +67,19 @@ describe('route throws an error', () => {
63
67
  const value = $(item).find('.debug-value').html()?.trim();
64
68
  switch (key) {
65
69
  case 'Request Amount:':
66
- expect(value).toBe('9');
70
+ expect(value).toBe('11');
67
71
  break;
68
72
  case 'Hot Routes:':
69
- expect(value).toBe('6 /test/:id/:params?<br>');
73
+ expect(value).toBe('8 /test/:id/:params?<br>');
70
74
  break;
71
75
  case 'Hot Paths:':
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>');
76
+ expect(value).toBe('2 /test/error<br>2 /test/slow<br>2 /test/slow4<br>1 /test/httperror<br>1 /test/config-not-found-error<br>1 /test/invalid-parameter-error<br>1 /thisDoesNotExist<br>1 /<br>');
73
77
  break;
74
78
  case 'Hot Error Routes:':
75
79
  expect(value).toBe('5 /test/:id/:params?<br>');
76
80
  break;
77
81
  case 'Hot Error Paths:':
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>');
82
+ expect(value).toBe('2 /test/error<br>1 /test/httperror<br>1 /test/slow4<br>1 /test/config-not-found-error<br>1 /test/invalid-parameter-error<br>1 /thisDoesNotExist<br>');
79
83
  break;
80
84
  default:
81
85
  }
@@ -1,20 +1,26 @@
1
1
  import { type NotFoundHandler, type ErrorHandler } from 'hono';
2
2
  import { getDebugInfo, setDebugInfo } from '@/utils/debug-info';
3
3
  import { config } from '@/config';
4
- import Sentry from '@sentry/node';
4
+ import * as Sentry from '@sentry/node';
5
5
  import logger from '@/utils/logger';
6
6
  import Error from '@/views/error';
7
7
 
8
8
  import NotFoundError from './types/not-found';
9
9
 
10
+ import { requestMetric } from '@/utils/otel';
11
+
10
12
  export const errorHandler: ErrorHandler = (error, ctx) => {
11
13
  const requestPath = ctx.req.path;
12
14
  const matchedRoute = ctx.req.routePath;
13
15
  const hasMatchedRoute = matchedRoute !== '/*';
14
16
 
15
17
  const debug = getDebugInfo();
16
- if (ctx.res.headers.get('RSSHub-Cache-Status')) {
17
- debug.hitCache++;
18
+ try {
19
+ if (ctx.res.headers.get('RSSHub-Cache-Status')) {
20
+ debug.hitCache++;
21
+ }
22
+ } catch {
23
+ // ignore
18
24
  }
19
25
  debug.error++;
20
26
 
@@ -61,8 +67,9 @@ export const errorHandler: ErrorHandler = (error, ctx) => {
61
67
  const message = `${error.name}: ${errorMessage}`;
62
68
 
63
69
  logger.error(`Error in ${requestPath}: ${message}`);
70
+ requestMetric.error({ path: requestPath, method: ctx.req.method, status: ctx.res.status });
64
71
 
65
- return config.isPackage
72
+ return config.isPackage || ctx.req.query('format') === 'json'
66
73
  ? ctx.json({
67
74
  error: {
68
75
  message: error.message ?? error,
package/lib/index.ts CHANGED
@@ -10,12 +10,15 @@ const hostIPList = getLocalhostAddress();
10
10
  logger.info(`🎉 RSSHub is running on port ${port}! Cheers!`);
11
11
  logger.info('💖 Can you help keep this open source project alive? Please sponsor 👉 https://docs.rsshub.app/sponsor');
12
12
  logger.info(`🔗 Local: 👉 http://localhost:${port}`);
13
- for (const ip of hostIPList) {
14
- logger.info(`🔗 Network: 👉 http://${ip}:${port}`);
13
+ if (config.listenInaddrAny) {
14
+ for (const ip of hostIPList) {
15
+ logger.info(`🔗 Network: 👉 http://${ip}:${port}`);
16
+ }
15
17
  }
16
18
 
17
19
  const server = serve({
18
20
  fetch: app.fetch,
21
+ hostname: config.listenInaddrAny ? undefined : '127.0.0.1',
19
22
  port,
20
23
  });
21
24
 
@@ -36,7 +36,7 @@ const expects = {
36
36
  `<a href="https://mock.com/DIYgod/RSSHub"></a>
37
37
  <img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">`,
38
38
  ],
39
- desc: '<img src="http://mock.com/DIYgod/DIYgod/RSSHub"> - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)',
39
+ desc: '<img src="http://mock.com/DIYgod/DIYgod/RSSHub"> - Powered by RSSHub',
40
40
  },
41
41
  processed: {
42
42
  items: [
@@ -54,7 +54,7 @@ const expects = {
54
54
  `<a href="https://mock.com/DIYgod/RSSHub"></a>
55
55
  <img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">`,
56
56
  ],
57
- desc: '<img src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"> - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)',
57
+ desc: '<img src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"> - Powered by RSSHub',
58
58
  },
59
59
  urlencoded: {
60
60
  items: [
@@ -72,7 +72,7 @@ const expects = {
72
72
  `<a href="https://mock.com/DIYgod/RSSHub"></a>
73
73
  <img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">`,
74
74
  ],
75
- desc: '<img src="https://images.weserv.nl?url=http%3A%2F%2Fmock.com%2FDIYgod%2FDIYgod%2FRSSHub"> - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)',
75
+ desc: '<img src="https://images.weserv.nl?url=http%3A%2F%2Fmock.com%2FDIYgod%2FDIYgod%2FRSSHub"> - Powered by RSSHub',
76
76
  },
77
77
  },
78
78
  multimedia: {
@@ -87,7 +87,7 @@ const expects = {
87
87
  <audio src="https://mock.com/DIYgod/RSSHub.mp3"></audio>
88
88
  <iframe src="https://mock.com/DIYgod/RSSHub.html" referrerpolicy="no-referrer"></iframe>`,
89
89
  ],
90
- desc: '<video src="http://mock.com/DIYgod/DIYgod/RSSHub"></video> - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)',
90
+ desc: '<video src="http://mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
91
91
  },
92
92
  relayed: {
93
93
  items: [
@@ -100,7 +100,7 @@ const expects = {
100
100
  <audio src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp3"></audio>
101
101
  <iframe src="https://mock.com/DIYgod/RSSHub.html" referrerpolicy="no-referrer"></iframe>`,
102
102
  ],
103
- desc: '<video src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"></video> - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)',
103
+ desc: '<video src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
104
104
  },
105
105
  partlyRelayed: {
106
106
  items: [
@@ -113,7 +113,7 @@ const expects = {
113
113
  <audio src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp3"></audio>
114
114
  <iframe src="https://mock.com/DIYgod/RSSHub.html" referrerpolicy="no-referrer"></iframe>`,
115
115
  ],
116
- desc: '<video src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"></video> - Made with love by RSSHub(https://github.com/DIYgod/RSSHub)',
116
+ desc: '<video src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
117
117
  },
118
118
  },
119
119
  };
@@ -6,23 +6,38 @@ import RequestInProgressError from '@/errors/types/request-in-progress';
6
6
  import cacheModule from '@/utils/cache/index';
7
7
  import { Data } from '@/types';
8
8
 
9
+ const bypassList = new Set(['/', '/robots.txt', '/logo.png', '/favicon.ico']);
9
10
  // only give cache string, as the `!` condition tricky
10
11
  // md5 is used to shrink key size
11
12
  // plz, write these tips in comments!
12
13
  const middleware: MiddlewareHandler = async (ctx, next) => {
13
- const { h64ToString } = await xxhash();
14
- const key = 'rsshub:koa-redis-cache:' + h64ToString(ctx.req.path);
15
- const controlKey = 'rsshub:path-requested:' + h64ToString(ctx.req.path);
16
-
17
- if (!cacheModule.status.available) {
14
+ if (!cacheModule.status.available || bypassList.has(ctx.req.path)) {
18
15
  await next();
19
16
  return;
20
17
  }
21
18
 
19
+ const { h64ToString } = await xxhash();
20
+ const key = 'rsshub:koa-redis-cache:' + h64ToString(ctx.req.path);
21
+ const controlKey = 'rsshub:path-requested:' + h64ToString(ctx.req.path);
22
+
22
23
  const isRequesting = await cacheModule.globalCache.get(controlKey);
23
24
 
24
25
  if (isRequesting === '1') {
25
- throw new RequestInProgressError('This path is currently fetching, please come back later!');
26
+ let retryTimes = process.env.NODE_ENV === 'test' ? 1 : 10;
27
+ let bypass = false;
28
+ while (retryTimes > 0) {
29
+ // eslint-disable-next-line no-await-in-loop
30
+ await new Promise((resolve) => setTimeout(resolve, process.env.NODE_ENV === 'test' ? 3000 : 6000));
31
+ // eslint-disable-next-line no-await-in-loop
32
+ if ((await cacheModule.globalCache.get(controlKey)) !== '1') {
33
+ bypass = true;
34
+ break;
35
+ }
36
+ retryTimes--;
37
+ }
38
+ if (!bypass) {
39
+ throw new RequestInProgressError('This path is currently fetching, please come back later!');
40
+ }
26
41
  }
27
42
 
28
43
  const value = await cacheModule.globalCache.get(key);
@@ -1,3 +1,4 @@
1
+ import { requestMetric } from '@/utils/otel';
1
2
  import { MiddlewareHandler } from 'hono';
2
3
  import logger from '@/utils/logger';
3
4
  import { getPath, time } from '@/utils/helpers';
@@ -34,7 +35,10 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
34
35
 
35
36
  await next();
36
37
 
37
- logger.info(`${LogPrefix.Outgoing} ${method} ${path} ${colorStatus(ctx.res.status)} ${time(start)}`);
38
+ const status = ctx.res.status;
39
+
40
+ logger.info(`${LogPrefix.Outgoing} ${method} ${path} ${colorStatus(status)} ${time(start)}`);
41
+ requestMetric.success(Date.now() - start, { path, method, status });
38
42
  };
39
43
 
40
44
  export default middleware;
@@ -53,7 +53,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
53
53
  // https://stackoverflow.com/questions/1497885/remove-control-characters-from-php-string/1497928#1497928
54
54
  // remove unicode control characters
55
55
  // see #14940 #14943 #15262
56
- item.description = item.description.replaceAll(/[\u0000-\u0009\u000B\u000C\u000E-\u001F\u007F]/g, '');
56
+ item.description = item.description.replaceAll(/[\u0000-\u0009\u000B\u000C\u000E-\u001F\u007F\u200B\uFFFF]/g, '');
57
57
  }
58
58
 
59
59
  if (typeof item.author === 'string') {
@@ -94,18 +94,22 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
94
94
  return ctx.json(result);
95
95
  }
96
96
 
97
- // retain .ums for backward compatibility
98
- if (outputType === 'ums' || outputType === 'rss3') {
99
- return ctx.json(rss3(result));
100
- } else if (outputType === 'json') {
101
- ctx.header('Content-Type', 'application/feed+json; charset=UTF-8');
102
- return ctx.body(json(result));
103
- } else if (ctx.get('no-content')) {
97
+ if (ctx.get('no-content')) {
104
98
  return ctx.body(null);
105
- } else if (outputType === 'atom') {
106
- return ctx.render(<Atom data={result} />);
107
99
  } else {
108
- return ctx.render(<RSS data={result} />);
100
+ // retain .ums for backward compatibility
101
+ switch (outputType) {
102
+ case 'ums':
103
+ case 'rss3':
104
+ return ctx.json(rss3(result));
105
+ case 'json':
106
+ ctx.header('Content-Type', 'application/feed+json; charset=UTF-8');
107
+ return ctx.body(json(result));
108
+ case 'atom':
109
+ return ctx.render(<Atom data={result} />);
110
+ default:
111
+ return ctx.render(<RSS data={result} />);
112
+ }
109
113
  }
110
114
  };
111
115
 
@@ -0,0 +1,25 @@
1
+ import { MiddlewareHandler } from 'hono';
2
+ import { getPath } from '@/utils/helpers';
3
+ import { config } from '@/config';
4
+ import { tracer } from '@/utils/otel';
5
+
6
+ const middleware: MiddlewareHandler = async (ctx, next) => {
7
+ if (config.debugInfo) {
8
+ // Only enable tracing in debug mode
9
+ const { method, raw } = ctx.req;
10
+ const path = getPath(raw);
11
+
12
+ const span = tracer.startSpan(`${method} ${path}`, {
13
+ kind: 1, // server
14
+ attributes: {},
15
+ });
16
+ span.addEvent('invoking handleRequest');
17
+ await next();
18
+ span.end();
19
+ } else {
20
+ // Skip
21
+ await next();
22
+ }
23
+ };
24
+
25
+ export default middleware;
@@ -29,4 +29,12 @@ describe('registry', () => {
29
29
  const response = await app.request('/favicon.ico');
30
30
  expect(response.status).toBe(200);
31
31
  });
32
+
33
+ // healthz
34
+ it('/healthz', async () => {
35
+ const response = await app.request('/healthz');
36
+ expect(response.status).toBe(200);
37
+ expect(response.headers.get('cache-control')).toBe('no-cache');
38
+ expect(await response.text()).toBe('ok');
39
+ });
32
40
  });
package/lib/registry.ts CHANGED
@@ -4,9 +4,12 @@ import { Hono, type Handler } from 'hono';
4
4
  import path from 'node:path';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { serveStatic } from '@hono/node-server/serve-static';
7
+ import { config } from '@/config';
7
8
 
8
9
  import index from '@/routes/index';
10
+ import healthz from '@/routes/healthz';
9
11
  import robotstxt from '@/routes/robots.txt';
12
+ import metrics from '@/routes/metrics';
10
13
 
11
14
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
15
 
@@ -84,7 +87,7 @@ const app = new Hono();
84
87
  for (const namespace in namespaces) {
85
88
  const subApp = app.basePath(`/${namespace}`);
86
89
  for (const path in namespaces[namespace].routes) {
87
- const wrapedHandler: Handler = async (ctx) => {
90
+ const wrappedHandler: Handler = async (ctx) => {
88
91
  if (!ctx.get('data')) {
89
92
  if (typeof namespaces[namespace].routes[path].handler !== 'function') {
90
93
  const { route } = await import(`./routes/${namespace}/${namespaces[namespace].routes[path].location}`);
@@ -93,12 +96,17 @@ for (const namespace in namespaces) {
93
96
  ctx.set('data', await namespaces[namespace].routes[path].handler(ctx));
94
97
  }
95
98
  };
96
- subApp.get(path, wrapedHandler);
99
+ subApp.get(path, wrappedHandler);
97
100
  }
98
101
  }
99
102
 
100
103
  app.get('/', index);
104
+ app.get('/healthz', healthz);
101
105
  app.get('/robots.txt', robotstxt);
106
+ if (config.debugInfo) {
107
+ // Only enable tracing in debug mode
108
+ app.get('/metrics', metrics);
109
+ }
102
110
  app.use(
103
111
  '/*',
104
112
  serveStatic({
package/lib/router.js CHANGED
@@ -66,9 +66,6 @@ router.get('/konachan.net/post/popular_recent/:period', lazyloadRouteHandler('./
66
66
  // EZTV
67
67
  router.get('/eztv/torrents/:imdb_id', lazyloadRouteHandler('./routes/eztv/imdb'));
68
68
 
69
- // 新京报
70
- router.get('/bjnews/:cat', lazyloadRouteHandler('./routes/bjnews/news'));
71
-
72
69
  // 米哈游
73
70
  router.get('/mihoyo/bh3/:type', lazyloadRouteHandler('./routes/mihoyo/bh3'));
74
71
  router.get('/mihoyo/bh2/:type', lazyloadRouteHandler('./routes/mihoyo/bh2'));
@@ -594,12 +591,6 @@ router.get('/zucc/cssearch/latest/:webVpn/:key', lazyloadRouteHandler('./routes/
594
591
  // checkee
595
592
  router.get('/checkee/:dispdate', lazyloadRouteHandler('./routes/checkee/index'));
596
593
 
597
- // Matters
598
- router.get('/matters/latest/:type?', lazyloadRouteHandler('./routes/matters/latest'));
599
- router.redirect('/matters/hot', '/matters/latest/heat'); // Deprecated
600
- router.get('/matters/tags/:tid', lazyloadRouteHandler('./routes/matters/tags'));
601
- router.get('/matters/author/:uid', lazyloadRouteHandler('./routes/matters/author'));
602
-
603
594
  // 古诗文网
604
595
  router.get('/gushiwen/recommend/:annotation?', lazyloadRouteHandler('./routes/gushiwen/recommend'));
605
596