rsshub 1.0.0-master.f3315cd → 1.0.0-master.f378dab

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 (388) hide show
  1. package/README.md +13 -48
  2. package/lib/api/radar/rules/all.ts +3 -6
  3. package/lib/api/radar/rules/one.ts +3 -6
  4. package/lib/config.ts +30 -22
  5. package/lib/errors/index.test.ts +1 -1
  6. package/lib/errors/index.tsx +2 -2
  7. package/lib/index.ts +1 -1
  8. package/lib/middleware/anti-hotlink.test.ts +191 -6
  9. package/lib/middleware/anti-hotlink.ts +28 -0
  10. package/lib/middleware/logger.ts +2 -2
  11. package/lib/middleware/parameter.test.ts +22 -5
  12. package/lib/middleware/parameter.ts +47 -17
  13. package/lib/registry.test.ts +8 -0
  14. package/lib/registry.ts +2 -0
  15. package/lib/router.js +1 -4
  16. package/lib/routes/141jav/index.ts +25 -21
  17. package/lib/routes/141ppv/index.ts +24 -20
  18. package/lib/routes/51cto/recommend.ts +45 -7
  19. package/lib/routes/51read/article.ts +82 -0
  20. package/lib/routes/51read/namespace.ts +6 -0
  21. package/lib/routes/5eplay/utils.ts +5 -3
  22. package/lib/routes/abc/index.ts +2 -2
  23. package/lib/routes/agri/index.ts +307 -0
  24. package/lib/routes/agri/namespace.ts +8 -0
  25. package/lib/routes/agri/templates/description.art +21 -0
  26. package/lib/routes/aljazeera/index.ts +2 -2
  27. package/lib/routes/anime1/anime.ts +63 -0
  28. package/lib/routes/anime1/namespace.ts +6 -0
  29. package/lib/routes/anime1/search.ts +57 -0
  30. package/lib/routes/apnews/api.ts +62 -0
  31. package/lib/routes/apnews/rss.ts +1 -1
  32. package/lib/routes/apnews/sitemap.ts +99 -0
  33. package/lib/routes/apnews/topics.ts +2 -2
  34. package/lib/routes/apnews/utils.ts +7 -5
  35. package/lib/routes/asus/bios.ts +88 -21
  36. package/lib/routes/asus/templates/bios.art +13 -6
  37. package/lib/routes/autocentre/index.ts +29 -0
  38. package/lib/routes/autocentre/namespace.ts +7 -0
  39. package/lib/routes/bestblogs/feeds.ts +107 -0
  40. package/lib/routes/bestblogs/namespace.ts +6 -0
  41. package/lib/routes/bilibili/api-interface.d.ts +1 -0
  42. package/lib/routes/bilibili/bilibili-recommend.ts +42 -0
  43. package/lib/routes/bilibili/cache.ts +25 -1
  44. package/lib/routes/bilibili/dynamic.ts +103 -101
  45. package/lib/routes/bilibili/followings-video.ts +9 -3
  46. package/lib/routes/bilibili/utils.ts +5 -0
  47. package/lib/routes/bilibili/video.ts +2 -1
  48. package/lib/routes/binance/announcement.ts +168 -0
  49. package/lib/routes/binance/types.ts +26 -0
  50. package/lib/routes/bing/daily-wallpaper.ts +1 -1
  51. package/lib/routes/bitget/announcement.ts +200 -0
  52. package/lib/routes/bitget/namespace.ts +6 -0
  53. package/lib/routes/bitget/type.ts +26 -0
  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/bjp/apod.ts +4 -2
  59. package/lib/routes/bjx/fd.ts +35 -26
  60. package/lib/routes/buaa/jiaowu.ts +1 -1
  61. package/lib/routes/buaa/lib/space/newbook.ts +171 -0
  62. package/lib/routes/buaa/lib/space/templates/newbook.art +44 -0
  63. package/lib/routes/bupt/jwc.ts +130 -0
  64. package/lib/routes/cccfna/index.ts +2 -2
  65. package/lib/routes/ccfa/index.ts +216 -0
  66. package/lib/routes/ccfa/namespace.ts +8 -0
  67. package/lib/routes/ccfa/templates/description.art +7 -0
  68. package/lib/routes/cctv/category.ts +16 -12
  69. package/lib/routes/cctv/xwlb.ts +32 -10
  70. package/lib/routes/cdu/jwgg.ts +79 -0
  71. package/lib/routes/cdu/namespace.ts +6 -0
  72. package/lib/routes/cffex/announcement.ts +73 -0
  73. package/lib/routes/cffex/namespace.ts +6 -0
  74. package/lib/routes/chikubi/index.ts +75 -0
  75. package/lib/routes/chikubi/namespace.ts +6 -0
  76. package/lib/routes/chikubi/utils.ts +82 -0
  77. package/lib/routes/chlinlearn/daily-blog.ts +55 -0
  78. package/lib/routes/chlinlearn/namespcae.ts +6 -0
  79. package/lib/routes/cls/subject.ts +153 -0
  80. package/lib/routes/cls/templates/description.art +21 -0
  81. package/lib/routes/copymanga/comic.ts +3 -1
  82. package/lib/routes/deeplearning/thebatch.ts +30 -18
  83. package/lib/routes/devolverdigital/blog.ts +59 -42
  84. package/lib/routes/devtrium/namespace.ts +6 -0
  85. package/lib/routes/devtrium/posts.ts +55 -0
  86. package/lib/routes/digitalcameraworld/news.ts +1 -1
  87. package/lib/routes/discord/channel.ts +10 -10
  88. package/lib/routes/discord/discord-api.ts +27 -32
  89. package/lib/routes/discord/templates/message.art +15 -0
  90. package/lib/routes/discourse/notifications.ts +2 -1
  91. package/lib/routes/discourse/official.ts +55 -0
  92. package/lib/routes/dockerhub/utils.ts +4 -3
  93. package/lib/routes/dongqiudi/result.ts +1 -1
  94. package/lib/routes/douban/movie/coming.ts +68 -0
  95. package/lib/routes/douban/templates/movie_coming.art +27 -0
  96. package/lib/routes/eastmoney/report/index.ts +63 -15
  97. package/lib/routes/eastmoney/templates/stock_description.art +36 -0
  98. package/lib/routes/eastmoney/utils.ts +35 -0
  99. package/lib/routes/easynomad/joblist.ts +56 -0
  100. package/lib/routes/easynomad/namespace.ts +6 -0
  101. package/lib/routes/espn/namespace.ts +6 -0
  102. package/lib/routes/espn/news.ts +120 -0
  103. package/lib/routes/espn/templates/media.art +19 -0
  104. package/lib/routes/fediverse/timeline.ts +35 -18
  105. package/lib/routes/flashcat/blog.ts +61 -0
  106. package/lib/routes/flashcat/namespace.ts +6 -0
  107. package/lib/routes/follow/namespace.ts +6 -0
  108. package/lib/routes/follow/profile.ts +69 -0
  109. package/lib/routes/follow/types.ts +38 -0
  110. package/lib/routes/ftm/index.ts +60 -0
  111. package/lib/routes/ftm/namespace.ts +6 -0
  112. package/lib/routes/galxe/index.ts +94 -0
  113. package/lib/routes/galxe/namespace.ts +9 -0
  114. package/lib/routes/gamersky/ent.ts +57 -0
  115. package/lib/routes/gamersky/namespace.ts +10 -0
  116. package/lib/routes/gamersky/news.ts +91 -0
  117. package/lib/routes/gamersky/review.ts +80 -0
  118. package/lib/routes/gamersky/utils.ts +94 -0
  119. package/lib/routes/gdut/oa-news.ts +12 -17
  120. package/lib/routes/geekpark/index.ts +219 -0
  121. package/lib/routes/geekpark/namespace.ts +8 -0
  122. package/lib/routes/geekpark/templates/description.art +21 -0
  123. package/lib/routes/gisreportsonline/index.ts +60 -0
  124. package/lib/routes/gisreportsonline/namespace.ts +6 -0
  125. package/lib/routes/github/activity.ts +4 -3
  126. package/lib/routes/github/comments.ts +32 -30
  127. package/lib/routes/github/search.ts +20 -18
  128. package/lib/routes/go/mhlw/pdf.ts +87 -0
  129. package/lib/routes/go/namespace.ts +8 -0
  130. package/lib/routes/go/niid/idwr-dl.ts +104 -0
  131. package/lib/routes/google/research.ts +45 -0
  132. package/lib/routes/gov/cbirc/index.ts +371 -0
  133. package/lib/routes/gov/chongqing/sydwgkzp.ts +4 -4
  134. package/lib/routes/gov/cn/namespace.ts +8 -0
  135. package/lib/routes/gov/{news → cn/news}/index.ts +11 -7
  136. package/lib/routes/gov/lswz/index.ts +289 -0
  137. package/lib/routes/gov/ndrc/fggz.ts +637 -2
  138. package/lib/routes/gov/ndrc/namespace.ts +8 -0
  139. package/lib/routes/gov/ndrc/xwdt.ts +28 -8
  140. package/lib/routes/gov/ndrc/zfxxgk/articles.ts +73 -0
  141. package/lib/routes/gov/zj/ningbogzw-notice.ts +50 -0
  142. package/lib/routes/gov/zj/ningborsjnotice.ts +50 -0
  143. package/lib/routes/gq/news.ts +1 -1
  144. package/lib/routes/gs/developer/blog.ts +58 -0
  145. package/lib/routes/gs/namespace.ts +9 -0
  146. package/lib/routes/healthz.ts +8 -0
  147. package/lib/routes/hket/index.ts +80 -76
  148. package/lib/routes/hottoys/index.ts +63 -0
  149. package/lib/routes/hottoys/namespace.ts +6 -0
  150. package/lib/routes/hpoi/all.ts +3 -2
  151. package/lib/routes/hpoi/character.ts +3 -2
  152. package/lib/routes/hpoi/work.ts +3 -2
  153. package/lib/routes/hust/gs.ts +281 -0
  154. package/lib/routes/hust/namespace.ts +1 -1
  155. package/lib/routes/imhcg/blog.ts +47 -0
  156. package/lib/routes/imhcg/namespace.ts +7 -0
  157. package/lib/routes/imop/namespace.ts +10 -0
  158. package/lib/routes/imop/tianshu.ts +53 -0
  159. package/lib/routes/infzm/hot.ts +39 -0
  160. package/lib/routes/infzm/index.ts +3 -30
  161. package/lib/routes/infzm/utils.ts +34 -0
  162. package/lib/routes/inspirehep/author.ts +46 -0
  163. package/lib/routes/inspirehep/literature.ts +42 -0
  164. package/lib/routes/inspirehep/namespace.ts +7 -0
  165. package/lib/routes/inspirehep/types.ts +210 -0
  166. package/lib/routes/inspirehep/utils.ts +15 -0
  167. package/lib/routes/iwara/subscriptions.ts +1 -1
  168. package/lib/routes/javdb/actors.ts +6 -2
  169. package/lib/routes/jjwxc/book.ts +18 -14
  170. package/lib/routes/joins/chinese.ts +218 -0
  171. package/lib/routes/joins/namespace.ts +8 -0
  172. package/lib/routes/joins/templates/description.art +17 -0
  173. package/lib/routes/juejin/dynamic.ts +114 -0
  174. package/lib/routes/kakuyomu/namespace.ts +6 -0
  175. package/lib/routes/kakuyomu/types.ts +6 -0
  176. package/lib/routes/kakuyomu/works.ts +73 -0
  177. package/lib/routes/kaopu/news.ts +3 -3
  178. package/lib/routes/kemono/index.ts +21 -0
  179. package/lib/routes/keylol/index.ts +56 -11
  180. package/lib/routes/kurogames/namespace.ts +7 -0
  181. package/lib/routes/kurogames/wutheringwaves/news.ts +59 -0
  182. package/lib/routes/link3/events.ts +86 -0
  183. package/lib/routes/link3/namespace.ts +6 -0
  184. package/lib/routes/link3/profile.ts +143 -0
  185. package/lib/routes/linkedin/cn/renderer.ts +1 -1
  186. package/lib/routes/lmu/jobs.ts +96 -0
  187. package/lib/routes/lmu/namespace.ts +17 -0
  188. package/lib/routes/lmu/templates/jobPosting.art +11 -0
  189. package/lib/routes/lofter/collection.ts +87 -0
  190. package/lib/routes/lofter/user.ts +1 -1
  191. package/lib/routes/luma/index.ts +92 -0
  192. package/lib/routes/luma/namespace.ts +6 -0
  193. package/lib/routes/malaysiakini/index.ts +179 -0
  194. package/lib/routes/malaysiakini/namespace.ts +11 -0
  195. package/lib/routes/mastodon/acct.ts +4 -3
  196. package/lib/routes/mastodon/timeline-local.ts +3 -2
  197. package/lib/routes/mastodon/timeline-remote.ts +3 -2
  198. package/lib/routes/mcmod/index.ts +105 -0
  199. package/lib/routes/mcmod/namespace.ts +6 -0
  200. package/lib/routes/mcmod/templates/mod.art +13 -0
  201. package/lib/routes/meishichina/index.ts +1997 -0
  202. package/lib/routes/meishichina/namespace.ts +8 -0
  203. package/lib/routes/misskey/user-timeline.ts +42 -0
  204. package/lib/routes/misskey/utils.ts +41 -1
  205. package/lib/routes/nationalgeographic/latest-stories.ts +1 -1
  206. package/lib/routes/nationalgeographic/templates/stories.art +1 -1
  207. package/lib/routes/newyorker/news.ts +24 -17
  208. package/lib/routes/nicovideo/namespace.ts +7 -0
  209. package/lib/routes/nicovideo/templates/video.art +7 -0
  210. package/lib/routes/nicovideo/types.ts +54 -0
  211. package/lib/routes/nicovideo/utils.ts +37 -0
  212. package/lib/routes/nicovideo/video.ts +47 -0
  213. package/lib/routes/oct0pu5/namespace.ts +10 -0
  214. package/lib/routes/oct0pu5/rss.ts +48 -0
  215. package/lib/routes/oschina/news.ts +2 -0
  216. package/lib/routes/pconline/focus.ts +143 -0
  217. package/lib/routes/pconline/namespace.ts +10 -0
  218. package/lib/routes/people/index.ts +8 -2
  219. package/lib/routes/picnob/user.ts +11 -3
  220. package/lib/routes/pixiv/search.ts +20 -1
  221. package/lib/routes/pixiv/utils.ts +3 -3
  222. package/lib/routes/pixivision/index.ts +84 -0
  223. package/lib/routes/pixivision/namespace.ts +6 -0
  224. package/lib/routes/pixivision/utils.ts +86 -0
  225. package/lib/routes/pku/bbs/hot.ts +1 -1
  226. package/lib/routes/pornhub/category.ts +3 -2
  227. package/lib/routes/pornhub/model.ts +4 -3
  228. package/lib/routes/pornhub/pornstar.ts +20 -8
  229. package/lib/routes/pornhub/search.ts +3 -2
  230. package/lib/routes/psyche/topic.ts +1 -1
  231. package/lib/routes/psyche/type.ts +1 -1
  232. package/lib/routes/psyche/utils.ts +1 -1
  233. package/lib/routes/qiche365/namespace.ts +5 -0
  234. package/lib/routes/qiche365/recall.ts +53 -0
  235. package/lib/routes/questn/community.ts +76 -0
  236. package/lib/routes/questn/events.ts +101 -0
  237. package/lib/routes/questn/namespace.ts +6 -0
  238. package/lib/routes/questn/util.ts +16 -0
  239. package/lib/routes/rebase/geekdaily.ts +35 -0
  240. package/lib/routes/rebase/namespace.ts +6 -0
  241. package/lib/routes/rss3/index.ts +22 -13
  242. package/lib/routes/rss3/interfaces/metadata.ts +67 -0
  243. package/lib/routes/rsshub/routes.ts +18 -12
  244. package/lib/routes/samd/news.ts +2 -2
  245. package/lib/routes/sara/index.ts +1 -1
  246. package/lib/routes/scut/gzic/media.ts +71 -0
  247. package/lib/routes/scut/gzic/news.ts +65 -0
  248. package/lib/routes/scut/gzic/notice.ts +88 -0
  249. package/lib/routes/sdu/{cs.ts → cs/index.ts} +46 -12
  250. package/lib/routes/sdu/cs/yjsgz.ts +85 -0
  251. package/lib/routes/sdu/gjsw.ts +80 -0
  252. package/lib/routes/sdu/namespace.ts +2 -2
  253. package/lib/routes/sdu/qd/xszxqd.ts +98 -0
  254. package/lib/routes/sdu/qd/xyb.ts +82 -0
  255. package/lib/routes/sdu/ygb.ts +90 -0
  256. package/lib/routes/shiep/config.ts +4 -10
  257. package/lib/routes/shiep/index.ts +9 -9
  258. package/lib/routes/showstart/artist.ts +5 -4
  259. package/lib/routes/showstart/brand.ts +5 -4
  260. package/lib/routes/showstart/event.ts +8 -7
  261. package/lib/routes/showstart/search.ts +43 -9
  262. package/lib/routes/showstart/service.ts +81 -53
  263. package/lib/routes/showstart/site.ts +41 -0
  264. package/lib/routes/showstart/utils.ts +9 -8
  265. package/lib/routes/sis001/author.ts +52 -0
  266. package/lib/routes/sis001/common.ts +38 -0
  267. package/lib/routes/sis001/forum.ts +2 -29
  268. package/lib/routes/sjtu/jwc.ts +4 -1
  269. package/lib/routes/sjtu/namespace.ts +1 -1
  270. package/lib/routes/sjtu/seiee/index.ts +97 -0
  271. package/lib/routes/smzdm/product.ts +86 -0
  272. package/lib/routes/soundon/namespace.ts +6 -0
  273. package/lib/routes/soundon/podcast.ts +80 -0
  274. package/lib/routes/soundon/types.ts +67 -0
  275. package/lib/routes/spotify/show.ts +1 -1
  276. package/lib/routes/springer/journal.ts +10 -12
  277. package/lib/routes/sse/sselawsrules.ts +370 -0
  278. package/lib/routes/sspai/author.ts +1 -1
  279. package/lib/routes/sspai/column.ts +1 -1
  280. package/lib/routes/sspai/index.ts +3 -3
  281. package/lib/routes/sspai/matrix.ts +1 -1
  282. package/lib/routes/sspai/series-update.ts +1 -1
  283. package/lib/routes/sspai/tag.ts +1 -1
  284. package/lib/routes/sspai/topic.ts +1 -1
  285. package/lib/routes/sustainabilitymag/articles.ts +2 -0
  286. package/lib/routes/swjtu/scai/bks.ts +80 -0
  287. package/lib/routes/szse/rule.ts +315 -42
  288. package/lib/routes/t66y/index.ts +29 -7
  289. package/lib/routes/taoguba/blog.ts +1 -1
  290. package/lib/routes/taoguba/index.ts +1 -1
  291. package/lib/routes/techcrunch/news.ts +20 -29
  292. package/lib/routes/techcrunch/templates/description.art +7 -0
  293. package/lib/routes/telegram/blog.ts +3 -2
  294. package/lib/routes/telegram/channel.ts +34 -1
  295. package/lib/routes/telegram/stickerpack.ts +3 -2
  296. package/lib/routes/tencent/news/author.ts +2 -1
  297. package/lib/routes/test/index.ts +50 -43
  298. package/lib/routes/the/index.ts +214 -0
  299. package/lib/routes/the/namespace.ts +8 -0
  300. package/lib/routes/the/templates/description.art +27 -0
  301. package/lib/routes/the/util.ts +307 -0
  302. package/lib/routes/theblockbeats/index.ts +10 -5
  303. package/lib/routes/theinitium/app.ts +137 -0
  304. package/lib/routes/theinitium/templates/description.art +17 -0
  305. package/lib/routes/threads/index.ts +26 -20
  306. package/lib/routes/tju/cic/index.ts +2 -2
  307. package/lib/routes/tju/news/index.ts +2 -2
  308. package/lib/routes/tju/oaa/index.ts +2 -2
  309. package/lib/routes/towardsdatascience/latest.ts +67 -0
  310. package/lib/routes/towardsdatascience/namespace.ts +6 -0
  311. package/lib/routes/tvb/news.ts +1 -0
  312. package/lib/routes/twitch/live.ts +3 -2
  313. package/lib/routes/twitch/video.ts +3 -2
  314. package/lib/routes/twitter/api/index.ts +2 -0
  315. package/lib/routes/twitter/api/mobile-api/login.ts +1 -1
  316. package/lib/routes/twitter/api/web-api/api.ts +18 -0
  317. package/lib/routes/twitter/api/web-api/constants.ts +17 -14
  318. package/lib/routes/twitter/api/web-api/login.ts +68 -0
  319. package/lib/routes/twitter/api/web-api/utils.ts +57 -32
  320. package/lib/routes/twitter/home-latest.ts +60 -0
  321. package/lib/routes/twitter/home.ts +1 -1
  322. package/lib/routes/twitter/list.ts +5 -2
  323. package/lib/routes/twitter/tweet.ts +1 -0
  324. package/lib/routes/twitter/user.ts +1 -1
  325. package/lib/routes/twitter/utils.ts +4 -1
  326. package/lib/routes/uber/blog.ts +1 -1
  327. package/lib/routes/ustc/scms.ts +97 -0
  328. package/lib/routes/v2ex/xna.ts +55 -0
  329. package/lib/routes/wchscu/namespace.ts +6 -0
  330. package/lib/routes/wchscu/recruit.ts +73 -0
  331. package/lib/routes/weibo/namespace.ts +1 -0
  332. package/lib/routes/weibo/oasis/user.ts +1 -1
  333. package/lib/routes/weibo/super-index.ts +23 -11
  334. package/lib/routes/weibo/user.ts +13 -2
  335. package/lib/routes/weibo/utils.ts +20 -4
  336. package/lib/routes/whu/cs.ts +11 -3
  337. package/lib/routes/whu/gs/index.ts +2 -1
  338. package/lib/routes/whu/news.ts +27 -2
  339. package/lib/routes/withgoogle/explorables.ts +54 -0
  340. package/lib/routes/withgoogle/namespace.ts +6 -0
  341. package/lib/routes/xiaohongshu/notes.ts +10 -2
  342. package/lib/routes/xiaohongshu/user.ts +27 -5
  343. package/lib/routes/xiaohongshu/util.ts +3 -1
  344. package/lib/routes/xidian/cs.ts +143 -0
  345. package/lib/routes/xidian/gr.ts +289 -0
  346. package/lib/routes/xidian/jwc.ts +1 -0
  347. package/lib/routes/xidian/namespace.ts +1 -1
  348. package/lib/routes/xueqiu/cookies.ts +14 -1
  349. package/lib/routes/xueqiu/favorite.ts +16 -2
  350. package/lib/routes/yahoo/news/index.ts +1 -0
  351. package/lib/routes/yahoo/news/listid.ts +67 -0
  352. package/lib/routes/yahoo/news/utils.ts +8 -2
  353. package/lib/routes/yicai/carousel.ts +48 -0
  354. package/lib/routes/yicai/utils.ts +23 -17
  355. package/lib/routes/yilinzazhi/index.ts +58 -0
  356. package/lib/routes/yilinzazhi/latest.ts +103 -0
  357. package/lib/routes/yilinzazhi/namespace.ts +8 -0
  358. package/lib/routes/youtube/subscriptions.ts +1 -0
  359. package/lib/routes/yystv/docs.ts +28 -19
  360. package/lib/routes/zaobao/util.ts +1 -1
  361. package/lib/routes/zhihu/answers.ts +5 -1
  362. package/lib/routes/zhihu/execlib/x-zse-96-v3.ts +2 -0
  363. package/lib/routes/zhihu/namespace.ts +3 -0
  364. package/lib/routes/zhihu/utils.ts +21 -4
  365. package/lib/routes/zhihu/zhuanlan.ts +8 -7
  366. package/lib/routes/zsxq/types.ts +9 -0
  367. package/lib/routes/zsxq/utils.ts +4 -3
  368. package/lib/routes.test.ts +11 -5
  369. package/lib/setup.test.ts +1 -1
  370. package/lib/types.ts +6 -0
  371. package/lib/utils/cache/index.ts +8 -0
  372. package/lib/utils/camelcase-keys.spec.ts +127 -0
  373. package/lib/utils/camelcase-keys.ts +27 -0
  374. package/lib/utils/common-utils.ts +1 -0
  375. package/lib/utils/otel/metric.ts +3 -2
  376. package/lib/views/error.tsx +3 -3
  377. package/lib/views/index.tsx +7 -9
  378. package/lib/views/json.ts +1 -1
  379. package/lib/views/layout.tsx +1 -1
  380. package/lib/views/rss.tsx +7 -0
  381. package/package.json +50 -48
  382. package/lib/routes/sse/lawandrules.ts +0 -68
  383. package/lib/routes-deprecated/anime1/anime.js +0 -25
  384. package/lib/routes-deprecated/anime1/search.js +0 -25
  385. package/lib/routes-deprecated/bjnews/news.js +0 -44
  386. package/lib/routes-deprecated/gamersky/ent.js +0 -89
  387. package/lib/routes-deprecated/gamersky/news.js +0 -34
  388. package/lib/routes-deprecated/geekpark/breakingnews.js +0 -25
package/README.md CHANGED
@@ -12,29 +12,15 @@
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
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)
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
+ [![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) [![X (Twitter)](https://img.shields.io/badge/any_text-Follow-blue?color=2CA5E0&label=Twitter&logo=X&cacheSeconds=3600&style=flat-square)](https://x.com/intent/follow?screen_name=_RSSHub)
16
16
 
17
17
  ## Introduction
18
18
 
19
- RSSHub is an open source, easy to use, and extensible RSS feed generator. It's capable of generating RSS feeds from pretty much everything.
19
+ RSSHub is the world's largest RSS network, consisting of over 5,000 global instances.
20
20
 
21
21
  RSSHub delivers millions of contents aggregated from all kinds of sources, our vibrant open source community is ensuring the deliver of RSSHub's new routes, new features and bug fixes.
22
22
 
23
- RSSHub can be used with browser extension [RSSHub Radar](https://github.com/DIYgod/RSSHub-Radar) and mobile auxiliary app [RSSBud](https://github.com/Cay-Zhang/RSSBud) (iOS) and [RSSAid](https://github.com/LeetaoGoooo/RSSAid) (Android)
24
-
25
- [English docs](https://docs.rsshub.app) | [Telegram Group](https://t.me/rsshub) | [Telegram Channel](https://t.me/awesomeRSSHub) | [Twitter](https://x.com/intent/follow?screen_name=_RSSHub) | [中文文档](https://docs.rsshub.app/zh/)
26
-
27
- ## Special Thanks
28
-
29
- ### Contributors
30
-
31
- [![](https://opencollective.com/RSSHub/contributors.svg?width=890)](https://github.com/DIYgod/RSSHub/graphs/contributors)
32
-
33
- Logo designer [sheldonrrr](https://dribbble.com/sheldonrrr)
34
-
35
- ### Backers
36
-
37
- <a href="https://www.cloudflare.com" target="_blank"><img height="50px" src="https://i.imgur.com/7Ph27Fq.png"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://www.netlify.com" target="_blank"><img height="40px" src="https://i.imgur.com/cU01915.png"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://1password.com" target="_blank"><img height="40px" src="https://i.imgur.com/a2XjflO.png"></a>
23
+ [Documentation](https://docs.rsshub.app) | [Telegram Group](https://t.me/rsshub) | [Telegram Channel](https://t.me/awesomeRSSHub) | [X (Twitter)](https://x.com/intent/follow?screen_name=_RSSHub)
38
24
 
39
25
  ## Related Projects
40
26
 
@@ -43,53 +29,32 @@ Logo designer [sheldonrrr](https://dribbble.com/sheldonrrr)
43
29
  - [RSSAid](https://github.com/LeetaoGoooo/RSSAid) | RSSHub Radar for Android platform built with Flutter.
44
30
  - [DocSearch](https://github.com/Fatpandac/DocSearch) | Link RSSHub DocSearch into Raycast
45
31
 
46
- ## Join Us
32
+ ## Contribute
47
33
 
48
34
  We welcome all pull requests. Suggestions and feedback are also welcomed [here](https://github.com/DIYgod/RSSHub/issues).
49
35
 
50
- Refer to [Join Us](https://docs.rsshub.app/joinus/)
36
+ Refer to [Quick Start](https://docs.rsshub.app/joinus/)
51
37
 
52
38
  ## Deployment
53
39
 
54
40
  Refer to [Deployment](https://docs.rsshub.app/deploy/)
55
41
 
56
- ## Support RSSHub
57
-
58
- Refer to [Support RSSHub](https://docs.rsshub.app/sponsor/)
59
-
60
- RSSHub is open source and completely free under the MIT license. However, just like any other open source project, as the project grows, the hosting, development and maintenance requires funding support.
61
-
62
- You can support RSSHub via donations.
63
-
64
- ### Recurring Donation
65
-
66
- Recurring donors will be rewarded via express issue response, or even have your name displayed on our GitHub page and website.
67
-
68
- - Become a Sponser on [GitHub](https://github.com/sponsors/DIYgod)
69
- - Become a Sponser on [Patreon](https://www.patreon.com/DIYgod)
70
- - Become a Sponser on [Open Collective](https://opencollective.com/RSSHub)
71
- - Become a Sponser on [爱发电](https://afdian.net/@diygod)
72
- - Contact us directly: <i@diygod.me>
42
+ ## Special Thanks
73
43
 
74
- ### One-time Donation
44
+ <div align="center">
75
45
 
76
- We accept donations via the following ways:
46
+ [![](https://opencollective.com/RSSHub/contributors.svg?width=890)](https://github.com/DIYgod/RSSHub/graphs/contributors)
77
47
 
78
- - [WeChat Pay](https://archive.diygod.me/images/wx.jpg)
79
- - [Alipay](https://archive.diygod.me/images/zfb.jpg)
80
- - [Paypal](https://www.paypal.me/DIYgod)
48
+ Logo designer [sheldonrrr](https://dribbble.com/sheldonrrr)
81
49
 
82
- Open source is a very expensive thing. RSSHub would not be possible without the help of these individuals and organizations.
50
+ [![](https://raw.githubusercontent.com/DIYgod/sponsors/main/sponsors.simple.svg)](https://github.com/DIYgod/sponsors)
83
51
 
84
- <p align="center">
85
- <a href="https://github.com/DIYgod/sponsors">
86
- <img src="https://raw.githubusercontent.com/DIYgod/sponsors/main/sponsors.wide.svg" />
87
- </a>
88
- </p>
52
+ <a href="https://www.cloudflare.com" target="_blank"><img height="50px" src="https://i.imgur.com/7Ph27Fq.png"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://www.netlify.com" target="_blank"><img height="40px" src="https://i.imgur.com/cU01915.png"></a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://1password.com" target="_blank"><img height="40px" src="https://i.imgur.com/a2XjflO.png"></a>
53
+ </div>
89
54
 
90
55
  ## Author
91
56
 
92
57
  **RSSHub** © [DIYgod](https://github.com/DIYgod), Released under the [MIT](./LICENSE) License.<br>
93
58
  Authored and maintained by DIYgod with help from contributors ([list](https://github.com/DIYgod/RSSHub/contributors)).
94
59
 
95
- > Blog [@DIYgod](https://diygod.cc) · GitHub [@DIYgod](https://github.com/DIYgod) · Twitter [@DIYgod](https://x.com/DIYgod) · Telegram Channel [@awesomeDIYgod](https://t.me/awesomeDIYgod)
60
+ > Blog [@DIYgod](https://diygod.cc) · GitHub [@DIYgod](https://github.com/DIYgod) · X (Twitter) [@DIYgod](https://x.com/DIYgod) · Telegram Channel [@awesomeDIYgod](https://t.me/awesomeDIYgod)
@@ -1,13 +1,10 @@
1
1
  import { namespaces } from '@/registry';
2
2
  import { parse } from 'tldts';
3
- import { RadarItem } from '@/types';
3
+ import { RadarDomain } from '@/types';
4
4
  import { createRoute, RouteHandler } from '@hono/zod-openapi';
5
5
 
6
6
  const radar: {
7
- [domain: string]: {
8
- _name: string;
9
- [subdomain: string]: RadarItem[] | string;
10
- };
7
+ [domain: string]: RadarDomain;
11
8
  } = {};
12
9
 
13
10
  for (const namespace in namespaces) {
@@ -23,7 +20,7 @@ for (const namespace in namespaces) {
23
20
  if (!radar[domain]) {
24
21
  radar[domain] = {
25
22
  _name: namespaces[namespace].name,
26
- };
23
+ } as RadarDomain;
27
24
  }
28
25
  if (!radar[domain][subdomain]) {
29
26
  radar[domain][subdomain] = [];
@@ -1,13 +1,10 @@
1
1
  import { namespaces } from '@/registry';
2
2
  import { parse } from 'tldts';
3
- import { RadarItem } from '@/types';
3
+ import { RadarDomain } from '@/types';
4
4
  import { z, createRoute, RouteHandler } from '@hono/zod-openapi';
5
5
 
6
6
  const radar: {
7
- [domain: string]: {
8
- _name: string;
9
- [subdomain: string]: RadarItem[] | string;
10
- };
7
+ [domain: string]: RadarDomain;
11
8
  } = {};
12
9
 
13
10
  for (const namespace in namespaces) {
@@ -23,7 +20,7 @@ for (const namespace in namespaces) {
23
20
  if (!radar[domain]) {
24
21
  radar[domain] = {
25
22
  _name: namespaces[namespace].name,
26
- };
23
+ } as RadarDomain;
27
24
  }
28
25
  if (!radar[domain][subdomain]) {
29
26
  radar[domain][subdomain] = [];
package/lib/config.ts CHANGED
@@ -47,6 +47,10 @@ export type Config = {
47
47
  debugInfo: string;
48
48
  loggerLevel: string;
49
49
  noLogfiles?: boolean;
50
+ otel: {
51
+ seconds_bucket?: string;
52
+ milliseconds_bucket?: string;
53
+ };
50
54
  showLoggerTimestamp?: boolean;
51
55
  sentry: {
52
56
  dsn?: string;
@@ -70,7 +74,9 @@ export type Config = {
70
74
  temperature?: number;
71
75
  maxTokens?: number;
72
76
  endpoint: string;
73
- prompt?: string;
77
+ inputOption: string;
78
+ promptTitle: string;
79
+ promptDescription: string;
74
80
  };
75
81
  bilibili: {
76
82
  cookies: Record<string, string | undefined>;
@@ -168,12 +174,20 @@ export type Config = {
168
174
  javdb: {
169
175
  session?: string;
170
176
  };
177
+ keylol: {
178
+ cookie?: string;
179
+ };
171
180
  lastfm: {
172
181
  api_key?: string;
173
182
  };
174
183
  lightnovel: {
175
184
  cookie?: string;
176
185
  };
186
+ malaysiakini: {
187
+ email?: string;
188
+ password?: string;
189
+ refreshToken?: string;
190
+ };
177
191
  manhuagui: {
178
192
  cookie?: string;
179
193
  };
@@ -409,6 +423,10 @@ const calculateValue = () => {
409
423
  debugInfo: envs.DEBUG_INFO || 'true',
410
424
  loggerLevel: envs.LOGGER_LEVEL || 'info',
411
425
  noLogfiles: toBoolean(envs.NO_LOGFILES, false),
426
+ otel: {
427
+ seconds_bucket: envs.OTEL_SECONDS_BUCKET || '0.01,0.1,1,2,5,15,30,60',
428
+ milliseconds_bucket: envs.OTEL_MILLISECONDS_BUCKET || '10,20,50,100,250,500,1000,5000,15000',
429
+ },
412
430
  showLoggerTimestamp: toBoolean(envs.SHOW_LOGGER_TIMESTAMP, false),
413
431
  sentry: {
414
432
  dsn: envs.SENTRY,
@@ -433,7 +451,9 @@ const calculateValue = () => {
433
451
  temperature: toInt(envs.OPENAI_TEMPERATURE, 0.2),
434
452
  maxTokens: toInt(envs.OPENAI_MAX_TOKENS, 0) || undefined,
435
453
  endpoint: envs.OPENAI_API_ENDPOINT || 'https://api.openai.com/v1',
436
- prompt: envs.OPENAI_PROMPT || 'Please summarize the following article and reply with markdown format.',
454
+ inputOption: envs.OPENAI_INPUT_OPTION || 'description',
455
+ promptDescription: envs.OPENAI_PROMPT || 'Please summarize the following article and reply with markdown format.',
456
+ promptTitle: envs.OPENAI_PROMPT_TITLE || 'Please translate the following title into Simplified Chinese and reply only translated text.',
437
457
  },
438
458
 
439
459
  // Route-specific Configurations
@@ -534,12 +554,20 @@ const calculateValue = () => {
534
554
  javdb: {
535
555
  session: envs.JAVDB_SESSION,
536
556
  },
557
+ keylol: {
558
+ cookie: envs.KEYLOL_COOKIE,
559
+ },
537
560
  lastfm: {
538
561
  api_key: envs.LASTFM_API_KEY,
539
562
  },
540
563
  lightnovel: {
541
564
  cookie: envs.SECURITY_KEY,
542
565
  },
566
+ malaysiakini: {
567
+ email: envs.MALAYSIAKINI_EMAIL,
568
+ password: envs.MALAYSIAKINI_PASSWORD,
569
+ refreshToken: envs.MALAYSIAKINI_REFRESHTOKEN,
570
+ },
543
571
  manhuagui: {
544
572
  cookie: envs.MHGUI_COOKIE,
545
573
  },
@@ -713,26 +741,6 @@ calculateValue();
713
741
  logger.error('Remote config load failed.', error);
714
742
  }
715
743
  }
716
-
717
- if (!envs.DISABLE_UMAMI && envs.NODE_ENV === 'production') {
718
- ofetch(`https://umami.rss3.io/api/send`, {
719
- method: 'POST',
720
- headers: {
721
- 'content-type': 'application/json',
722
- 'user-agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36',
723
- },
724
- body: JSON.stringify({
725
- payload: {
726
- hostname: 'rsshub.app',
727
- language: 'en-US',
728
- referrer: 'rsshub.app',
729
- url: 'rsshub.app',
730
- website: '239067cd-231f-4a3f-a478-cced11a84876',
731
- },
732
- type: 'event',
733
- }),
734
- });
735
- }
736
744
  })();
737
745
 
738
746
  // @ts-expect-error value is set
@@ -22,7 +22,7 @@ describe('httperror', () => {
22
22
  it(`httperror`, async () => {
23
23
  const response = await request.get('/test/httperror');
24
24
  expect(response.status).toBe(503);
25
- expect(response.text).toMatch('FetchError: [GET] &quot;https://httpbingo.org/status/404&quot;: 404 Not Found');
25
+ expect(response.text).toContain('FetchError: [GET] &quot;https://httpbingo.org/status/404&quot;: 404 Not Found');
26
26
  }, 20000);
27
27
  });
28
28
 
@@ -67,9 +67,9 @@ export const errorHandler: ErrorHandler = (error, ctx) => {
67
67
  const message = `${error.name}: ${errorMessage}`;
68
68
 
69
69
  logger.error(`Error in ${requestPath}: ${message}`);
70
- requestMetric.error({ path: requestPath, method: ctx.req.method, status: ctx.res.status });
70
+ requestMetric.error({ path: matchedRoute, method: ctx.req.method, status: ctx.res.status });
71
71
 
72
- return config.isPackage
72
+ return config.isPackage || ctx.req.query('format') === 'json'
73
73
  ? ctx.json({
74
74
  error: {
75
75
  message: error.message ?? error,
package/lib/index.ts CHANGED
@@ -18,7 +18,7 @@ if (config.listenInaddrAny) {
18
18
 
19
19
  const server = serve({
20
20
  fetch: app.fetch,
21
- hostname: config.listenInaddrAny ? undefined : '127.0.0.1',
21
+ hostname: config.listenInaddrAny ? '::' : '127.0.0.1',
22
22
  port,
23
23
  });
24
24
 
@@ -116,6 +116,148 @@ const expects = {
116
116
  desc: '<video src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
117
117
  },
118
118
  },
119
+ extraComplicated: {
120
+ origin: {
121
+ items: [
122
+ {
123
+ content:
124
+ '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n\n<a href="http://mock.com/DIYgod/RSSHub"></a>\n<img src="https://mock.com/DIYgod/RSSHub.jpg" data-src="/DIYgod/RSSHub0.jpg" referrerpolicy="no-referrer">\n<img data-src="/DIYgod/RSSHub.jpg" src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img data-mock="/DIYgod/RSSHub.png" src="https://mock.com/DIYgod/RSSHub.png" referrerpolicy="no-referrer">\n<img mock="/DIYgod/RSSHub.gif" src="https://mock.com/DIYgod/RSSHub.gif" referrerpolicy="no-referrer">\n<img src="http://mock.com/DIYgod/DIYgod/RSSHub" referrerpolicy="no-referrer">\n<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
125
+ itunes: {},
126
+ },
127
+ {
128
+ content: '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">',
129
+ itunes: {},
130
+ },
131
+ {
132
+ content:
133
+ '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
134
+ enclosure: {
135
+ url: 'https://mock.com/DIYgod/RSSHub.png',
136
+ type: 'image/png',
137
+ },
138
+ itunes: {
139
+ image: 'https://mock.com/DIYgod/RSSHub.gif',
140
+ },
141
+ },
142
+ ],
143
+ image: {
144
+ link: 'https://github.com/DIYgod/RSSHub',
145
+ url: 'https://mock.com/DIYgod/RSSHub.png',
146
+ title: 'Test complicated',
147
+ },
148
+ description: '<img src="http://mock.com/DIYgod/DIYgod/RSSHub"> - Powered by RSSHub',
149
+ },
150
+ processed: {
151
+ items: [
152
+ {
153
+ content:
154
+ '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n\n<a href="http://mock.com/DIYgod/RSSHub"></a>\n<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" data-src="/DIYgod/RSSHub0.jpg" referrerpolicy="no-referrer">\n<img data-src="/DIYgod/RSSHub.jpg" src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img data-mock="/DIYgod/RSSHub.png" src="https://i3.wp.com/mock.com/DIYgod/RSSHub.png" referrerpolicy="no-referrer">\n<img mock="/DIYgod/RSSHub.gif" src="https://i3.wp.com/mock.com/DIYgod/RSSHub.gif" referrerpolicy="no-referrer">\n<img src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub" referrerpolicy="no-referrer">\n<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
155
+ itunes: {},
156
+ },
157
+ {
158
+ content: '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">',
159
+ itunes: {},
160
+ },
161
+ {
162
+ content:
163
+ '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
164
+ enclosure: {
165
+ url: 'https://i3.wp.com/mock.com/DIYgod/RSSHub.png',
166
+ type: 'image/png',
167
+ },
168
+ itunes: {
169
+ image: 'https://i3.wp.com/mock.com/DIYgod/RSSHub.gif',
170
+ },
171
+ },
172
+ ],
173
+ image: {
174
+ link: 'https://github.com/DIYgod/RSSHub',
175
+ url: 'https://i3.wp.com/mock.com/DIYgod/RSSHub.png',
176
+ title: 'Test complicated',
177
+ },
178
+ description: '<img src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"> - Powered by RSSHub',
179
+ },
180
+ urlencoded: {
181
+ items: [
182
+ {
183
+ content:
184
+ '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">\n\n<a href="http://mock.com/DIYgod/RSSHub"></a>\n<img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" data-src="/DIYgod/RSSHub0.jpg" referrerpolicy="no-referrer">\n<img data-src="/DIYgod/RSSHub.jpg" src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">\n<img data-mock="/DIYgod/RSSHub.png" src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.png" referrerpolicy="no-referrer">\n<img mock="/DIYgod/RSSHub.gif" src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.gif" referrerpolicy="no-referrer">\n<img src="https://images.weserv.nl?url=http%3A%2F%2Fmock.com%2FDIYgod%2FDIYgod%2FRSSHub" referrerpolicy="no-referrer">\n<img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
185
+ itunes: {},
186
+ },
187
+ {
188
+ content: '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">',
189
+ itunes: {},
190
+ },
191
+ {
192
+ content:
193
+ '<a href="https://mock.com/DIYgod/RSSHub"></a>\n<img src="https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.jpg" referrerpolicy="no-referrer">\n<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" referrerpolicy="no-referrer">',
194
+ enclosure: {
195
+ url: 'https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.png',
196
+ type: 'image/png',
197
+ },
198
+ itunes: {
199
+ image: 'https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.gif',
200
+ },
201
+ },
202
+ ],
203
+ image: {
204
+ link: 'https://github.com/DIYgod/RSSHub',
205
+ url: 'https://images.weserv.nl?url=https%3A%2F%2Fmock.com%2FDIYgod%2FRSSHub.png',
206
+ title: 'Test complicated',
207
+ },
208
+ description: '<img src="https://images.weserv.nl?url=http%3A%2F%2Fmock.com%2FDIYgod%2FDIYgod%2FRSSHub"> - Powered by RSSHub',
209
+ },
210
+ },
211
+ extraMultimedia: {
212
+ origin: {
213
+ items: [
214
+ {
215
+ content:
216
+ '<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://mock.com/DIYgod/RSSHub.mp4"></video>\n<video poster="https://mock.com/DIYgod/RSSHub.jpg">\n<source src="https://mock.com/DIYgod/RSSHub.mp4" type="video/mp4">\n<source src="https://mock.com/DIYgod/RSSHub.webm" type="video/webm">\n</video>\n<audio src="https://mock.com/DIYgod/RSSHub.mp3"></audio>\n<iframe src="https://mock.com/DIYgod/RSSHub.html" referrerpolicy="no-referrer"></iframe>',
217
+ },
218
+ {
219
+ content: '<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://mock.com/DIYgod/RSSHub.mp4"></video>',
220
+ enclosure: {
221
+ url: 'https://mock.com/DIYgod/RSSHub.mp4',
222
+ type: 'video/mp4',
223
+ },
224
+ },
225
+ ],
226
+ description: '<video src="http://mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
227
+ },
228
+ relayed: {
229
+ items: [
230
+ {
231
+ content:
232
+ '<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4"></video>\n<video poster="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg">\n<source src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4" type="video/mp4">\n<source src="https://i3.wp.com/mock.com/DIYgod/RSSHub.webm" type="video/webm">\n</video>\n<audio src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp3"></audio>\n<iframe src="https://mock.com/DIYgod/RSSHub.html" referrerpolicy="no-referrer"></iframe>',
233
+ },
234
+ {
235
+ content: '<img src="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4"></video>',
236
+ enclosure: {
237
+ url: 'https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4',
238
+ type: 'video/mp4',
239
+ },
240
+ },
241
+ ],
242
+ description: '<video src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
243
+ },
244
+ partlyRelayed: {
245
+ items: [
246
+ {
247
+ content:
248
+ '<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4"></video>\n<video poster="https://i3.wp.com/mock.com/DIYgod/RSSHub.jpg">\n<source src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4" type="video/mp4">\n<source src="https://i3.wp.com/mock.com/DIYgod/RSSHub.webm" type="video/webm">\n</video>\n<audio src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp3"></audio>\n<iframe src="https://mock.com/DIYgod/RSSHub.html" referrerpolicy="no-referrer"></iframe>',
249
+ },
250
+ {
251
+ content: '<img src="https://mock.com/DIYgod/RSSHub.jpg" referrerpolicy="no-referrer">\n<video src="https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4"></video>',
252
+ enclosure: {
253
+ url: 'https://i3.wp.com/mock.com/DIYgod/RSSHub.mp4',
254
+ type: 'video/mp4',
255
+ },
256
+ },
257
+ ],
258
+ description: '<video src="https://i3.wp.com/mock.com/DIYgod/DIYgod/RSSHub"></video> - Powered by RSSHub',
259
+ },
260
+ },
119
261
  };
120
262
 
121
263
  const testAntiHotlink = async (path, expectObj, query?: string | Record<string, any>) => {
@@ -142,12 +284,55 @@ const testAntiHotlink = async (path, expectObj, query?: string | Record<string,
142
284
  return parsed;
143
285
  };
144
286
 
145
- const expectImgOrigin = (query?: string | Record<string, any>) => testAntiHotlink('/test/complicated', expects.complicated.origin, query);
146
- const expectImgProcessed = (query?: string | Record<string, any>) => testAntiHotlink('/test/complicated', expects.complicated.processed, query);
147
- const expectImgUrlencoded = (query?: string | Record<string, any>) => testAntiHotlink('/test/complicated', expects.complicated.urlencoded, query);
148
- const expectMultimediaOrigin = (query?: string | Record<string, any>) => testAntiHotlink('/test/multimedia', expects.multimedia.origin, query);
149
- const expectMultimediaRelayed = (query?: string | Record<string, any>) => testAntiHotlink('/test/multimedia', expects.multimedia.relayed, query);
150
- const expectMultimediaPartlyRelayed = (query?: string | Record<string, any>) => testAntiHotlink('/test/multimedia', expects.multimedia.partlyRelayed, query);
287
+ const testAntiHotlinkExtra = async (path, expectObj, query?: string | Record<string, any>) => {
288
+ const app = (await import('@/app')).default;
289
+
290
+ path += query ? `?${new URLSearchParams(query).toString()}` : '';
291
+
292
+ const response = await app.request(path);
293
+ const parsed = await parser.parseString(await response.text());
294
+ const obj = {
295
+ description: parsed.description,
296
+ image: parsed.image,
297
+ items: parsed.items.slice(0, expectObj.items.length).map((e) => ({
298
+ content: e.content,
299
+ enclosure: e.enclosure,
300
+ itunes: e.itunes,
301
+ })),
302
+ };
303
+ expect(obj).toEqual(expectObj);
304
+
305
+ return parsed;
306
+ };
307
+
308
+ const expectImgOrigin = async (query?: string | Record<string, any>) => {
309
+ await testAntiHotlink('/test/complicated', expects.complicated.origin, query);
310
+ await testAntiHotlinkExtra('/test/complicated', expects.extraComplicated.origin, query);
311
+ };
312
+ const expectImgProcessed = async (query?: string | Record<string, any>) => {
313
+ await testAntiHotlink('/test/complicated', expects.complicated.processed, query);
314
+ await testAntiHotlinkExtra('/test/complicated', expects.extraComplicated.processed, query);
315
+ };
316
+
317
+ const expectImgUrlencoded = async (query?: string | Record<string, any>) => {
318
+ await testAntiHotlink('/test/complicated', expects.complicated.urlencoded, query);
319
+ await testAntiHotlinkExtra('/test/complicated', expects.extraComplicated.urlencoded, query);
320
+ };
321
+
322
+ const expectMultimediaOrigin = async (query?: string | Record<string, any>) => {
323
+ await testAntiHotlink('/test/multimedia', expects.multimedia.origin, query);
324
+ await testAntiHotlinkExtra('/test/multimedia', expects.extraMultimedia.origin, query);
325
+ };
326
+
327
+ const expectMultimediaRelayed = async (query?: string | Record<string, any>) => {
328
+ await testAntiHotlink('/test/multimedia', expects.multimedia.relayed, query);
329
+ await testAntiHotlinkExtra('/test/multimedia', expects.extraMultimedia.relayed, query);
330
+ };
331
+
332
+ const expectMultimediaPartlyRelayed = async (query?: string | Record<string, any>) => {
333
+ await testAntiHotlink('/test/multimedia', expects.multimedia.partlyRelayed, query);
334
+ await testAntiHotlinkExtra('/test/multimedia', expects.extraMultimedia.partlyRelayed, query);
335
+ };
151
336
 
152
337
  describe('anti-hotlink', () => {
153
338
  it('template-legacy', async () => {
@@ -44,6 +44,18 @@ const parseUrl = (str: string) => {
44
44
 
45
45
  return url;
46
46
  };
47
+
48
+ const replaceUrl = (template?: string, url?: string) => {
49
+ if (!template || !url) {
50
+ return url;
51
+ }
52
+ const oldUrl = parseUrl(url);
53
+ if (oldUrl && oldUrl.protocol !== 'data:') {
54
+ return interpolate(template, oldUrl);
55
+ }
56
+ return url;
57
+ };
58
+
47
59
  const replaceUrls = ($: CheerioAPI, selector: string, template: string, attribute = 'src') => {
48
60
  $(selector).each(function () {
49
61
  const oldSrc = $(this).attr(attribute);
@@ -120,6 +132,9 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
120
132
  // image link
121
133
  const data: Data = ctx.get('data');
122
134
  if (data) {
135
+ if (data.image) {
136
+ data.image = replaceUrl(imageHotlinkTemplate, data.image);
137
+ }
123
138
  if (data.description) {
124
139
  data.description = process(data.description, imageHotlinkTemplate, multimediaHotlinkTemplate);
125
140
  }
@@ -129,6 +144,19 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
129
144
  if (item.description) {
130
145
  item.description = process(item.description, imageHotlinkTemplate, multimediaHotlinkTemplate);
131
146
  }
147
+ if (item.enclosure_url && item.enclosure_type) {
148
+ if (item.enclosure_type.startsWith('image/')) {
149
+ item.enclosure_url = replaceUrl(imageHotlinkTemplate, item.enclosure_url);
150
+ } else if (/^(video|audio)\//.test(item.enclosure_type)) {
151
+ item.enclosure_url = replaceUrl(multimediaHotlinkTemplate, item.enclosure_url);
152
+ }
153
+ }
154
+ if (item.image) {
155
+ item.image = replaceUrl(imageHotlinkTemplate, item.image);
156
+ }
157
+ if (item.itunes_item_image) {
158
+ item.itunes_item_image = replaceUrl(imageHotlinkTemplate, item.itunes_item_image);
159
+ }
132
160
  }
133
161
  }
134
162
 
@@ -26,7 +26,7 @@ const colorStatus = (status: number) => {
26
26
  };
27
27
 
28
28
  const middleware: MiddlewareHandler = async (ctx, next) => {
29
- const { method, raw } = ctx.req;
29
+ const { method, raw, routePath } = ctx.req;
30
30
  const path = getPath(raw);
31
31
 
32
32
  logger.info(`${LogPrefix.Incoming} ${method} ${path}`);
@@ -38,7 +38,7 @@ const middleware: MiddlewareHandler = async (ctx, next) => {
38
38
  const status = ctx.res.status;
39
39
 
40
40
  logger.info(`${LogPrefix.Outgoing} ${method} ${path} ${colorStatus(status)} ${time(start)}`);
41
- requestMetric.success(Date.now() - start, { path, method, status });
41
+ requestMetric.success(Date.now() - start, { path: routePath, method, status });
42
42
  };
43
43
 
44
44
  export default middleware;
@@ -427,7 +427,8 @@ describe('multi parameter', () => {
427
427
  });
428
428
 
429
429
  describe('openai', () => {
430
- it(`chatgpt`, async () => {
430
+ it('processes both title and description', async () => {
431
+ config.openai.inputOption = 'both';
431
432
  const responseWithGpt = await app.request('/test/gpt?chatgpt=true');
432
433
  const responseNormal = await app.request('/test/gpt');
433
434
 
@@ -437,9 +438,25 @@ describe('openai', () => {
437
438
  const parsedGpt = await parser.parseString(await responseWithGpt.text());
438
439
  const parsedNormal = await parser.parseString(await responseNormal.text());
439
440
 
440
- expect(parsedGpt.items[0].content).not.toBe(undefined);
441
- expect(parsedGpt.items[0].content).toBe(parsedNormal.items[0].content);
442
- expect(parsedGpt.items[1].content).not.toBe(undefined);
443
- expect(parsedGpt.items[1].content).not.toBe(parsedNormal.items[1].content);
441
+ expect(parsedGpt.items[0].title).not.toBe(parsedNormal.items[0].title);
442
+ expect(parsedGpt.items[0].title).toContain('AI processed content.');
443
+ expect(parsedGpt.items[0].content).not.toBe(parsedNormal.items[0].content);
444
+ expect(parsedGpt.items[0].content).toContain('AI processed content.');
445
+ });
446
+
447
+ it('processes title or description', async () => {
448
+ // test title
449
+ config.openai.inputOption = 'title';
450
+ const responseTitleOnly = await app.request('/test/gpt?chatgpt=true');
451
+ const parsedTitleOnly = await parser.parseString(await responseTitleOnly.text());
452
+ expect(parsedTitleOnly.items[0].title).toContain('AI processed content.');
453
+ expect(parsedTitleOnly.items[0].content).not.toContain('AI processed content.');
454
+
455
+ // test description
456
+ config.openai.inputOption = 'description';
457
+ const responseDescriptionOnly = await app.request('/test/gpt?chatgpt=true');
458
+ const parsedDescriptionOnly = await parser.parseString(await responseDescriptionOnly.text());
459
+ expect(parsedDescriptionOnly.items[0].title).not.toContain('AI processed content.');
460
+ expect(parsedDescriptionOnly.items[0].content).toContain('AI processed content.');
444
461
  });
445
462
  });