rsshub 1.0.0-master.ff3a9ce → 1.0.0-master.ff3ea5a

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.

Potentially problematic release.


This version of rsshub might be problematic. Click here for more details.

Files changed (388) hide show
  1. package/lib/config.ts +38 -0
  2. package/lib/errors/index.tsx +3 -2
  3. package/lib/middleware/debug.ts +6 -4
  4. package/lib/middleware/header.ts +4 -2
  5. package/lib/registry.test.ts +24 -1
  6. package/lib/registry.ts +40 -11
  7. package/lib/router.js +1 -1
  8. package/lib/routes/121/namespace.ts +9 -0
  9. package/lib/routes/121/templates/description.art +17 -0
  10. package/lib/routes/121/weather-live.ts +104 -0
  11. package/lib/routes/141jav/index.ts +3 -0
  12. package/lib/routes/141ppv/index.ts +3 -0
  13. package/lib/routes/163/news/rank.ts +1 -1
  14. package/lib/routes/18comic/album.ts +59 -64
  15. package/lib/routes/18comic/index.ts +1 -0
  16. package/lib/routes/18comic/search.ts +53 -4
  17. package/lib/routes/18comic/utils.ts +70 -1
  18. package/lib/routes/2048/index.ts +1 -0
  19. package/lib/routes/30secondsofcode/utils.ts +0 -1
  20. package/lib/routes/6park/index.ts +1 -1
  21. package/lib/routes/7mmtv/index.ts +1 -0
  22. package/lib/routes/91porn/index.ts +1 -0
  23. package/lib/routes/95mm/tab.ts +1 -0
  24. package/lib/routes/agefans/detail.ts +1 -1
  25. package/lib/routes/aliyun/database-month.ts +1 -1
  26. package/lib/routes/anthropic/research.ts +112 -0
  27. package/lib/routes/apnews/topics.ts +2 -1
  28. package/lib/routes/apnews/utils.ts +1 -1
  29. package/lib/routes/apple/design.ts +54 -0
  30. package/lib/routes/apple/namespace.ts +1 -1
  31. package/lib/routes/aqara/post.ts +1 -1
  32. package/lib/routes/augmentcode/blog.ts +161 -0
  33. package/lib/routes/augmentcode/namespace.ts +9 -0
  34. package/lib/routes/augmentcode/templates/description.art +17 -0
  35. package/lib/routes/azul/namespace.ts +9 -0
  36. package/lib/routes/azul/packages.ts +105 -0
  37. package/lib/routes/banshujiang/index.ts +763 -0
  38. package/lib/routes/banshujiang/namespace.ts +9 -0
  39. package/lib/routes/banshujiang/templates/description.art +17 -0
  40. package/lib/routes/bfl/announcements.ts +1 -1
  41. package/lib/routes/bilibili/cache.ts +78 -0
  42. package/lib/routes/bilibili/danmaku.ts +1 -1
  43. package/lib/routes/bilibili/dynamic.ts +8 -2
  44. package/lib/routes/bilibili/video.ts +31 -73
  45. package/lib/routes/biquge/index.ts +1 -1
  46. package/lib/routes/bsky/keyword.ts +15 -10
  47. package/lib/routes/capitalmind/insights.ts +40 -0
  48. package/lib/routes/capitalmind/namespace.ts +8 -0
  49. package/lib/routes/capitalmind/podcasts.ts +41 -0
  50. package/lib/routes/capitalmind/utils.ts +122 -0
  51. package/lib/routes/cartoonmad/comic.ts +1 -1
  52. package/lib/routes/chikubi/index.ts +1 -0
  53. package/lib/routes/chikubi/tag.ts +1 -0
  54. package/lib/routes/chocolatey/namespace.ts +9 -0
  55. package/lib/routes/chocolatey/packages.ts +122 -0
  56. package/lib/routes/cmde/index.ts +1 -1
  57. package/lib/routes/cockroachlabs/blog.ts +113 -0
  58. package/lib/routes/cockroachlabs/namespace.ts +7 -0
  59. package/lib/routes/cool18/index.ts +4 -1
  60. package/lib/routes/coomer/index.ts +12 -6
  61. package/lib/routes/coomer/namespace.ts +1 -1
  62. package/lib/routes/copymanga/comic.ts +7 -9
  63. package/lib/routes/css-tricks/articles.ts +48 -0
  64. package/lib/routes/css-tricks/collections.ts +62 -0
  65. package/lib/routes/css-tricks/namespace.ts +8 -0
  66. package/lib/routes/css-tricks/popular.ts +39 -0
  67. package/lib/routes/css-tricks/utils.ts +103 -0
  68. package/lib/routes/cursor/changelog.ts +26 -17
  69. package/lib/routes/cursor/namespace.ts +1 -1
  70. package/lib/routes/cw/utils.ts +6 -13
  71. package/lib/routes/dealstreetasia/home.ts +1 -1
  72. package/lib/routes/dedao/index.ts +3 -3
  73. package/lib/routes/deepl/blog.ts +422 -0
  74. package/lib/routes/deepl/namespace.ts +9 -0
  75. package/lib/routes/deepl/templates/description.art +21 -0
  76. package/lib/routes/deeplearning/the-batch.ts +1 -1
  77. package/lib/routes/dev.to/guides.ts +100 -0
  78. package/lib/routes/dev.to/namespace.ts +8 -0
  79. package/lib/routes/dev.to/top.ts +105 -0
  80. package/lib/routes/dgut/jwb.ts +73 -0
  81. package/lib/routes/dgut/namespace.ts +9 -0
  82. package/lib/routes/digitalpolicyalert/activity-tracker.ts +135 -0
  83. package/lib/routes/digitalpolicyalert/namespace.ts +9 -0
  84. package/lib/routes/dnaindia/common.ts +26 -8
  85. package/lib/routes/douban/other/list.ts +3 -3
  86. package/lib/routes/e-hentai/index.ts +4 -1
  87. package/lib/routes/ehentai/tag.ts +1 -0
  88. package/lib/routes/englishhome/index.ts +55 -0
  89. package/lib/routes/englishhome/namespace.ts +6 -0
  90. package/lib/routes/epicgames/index.ts +2 -2
  91. package/lib/routes/espn/news.ts +1 -1
  92. package/lib/routes/expats/czech-news.ts +272 -0
  93. package/lib/routes/expats/namespace.ts +9 -0
  94. package/lib/routes/fanbox/index.ts +1 -0
  95. package/lib/routes/fanbox/utils.ts +1 -1
  96. package/lib/routes/fansly/tag.ts +1 -0
  97. package/lib/routes/fantia/search.ts +1 -1
  98. package/lib/routes/fantube/creator.ts +69 -0
  99. package/lib/routes/fantube/namespace.ts +7 -0
  100. package/lib/routes/fantube/templates/post.art +17 -0
  101. package/lib/routes/fantube/types.ts +100 -0
  102. package/lib/routes/fantube/utils.ts +268 -0
  103. package/lib/routes/follow/profile.ts +1 -1
  104. package/lib/routes/followin/news.ts +1 -1
  105. package/lib/routes/foresightnews/util.ts +1 -1
  106. package/lib/routes/freexcomic/book.ts +4 -1
  107. package/lib/routes/gamer/hot.ts +5 -5
  108. package/lib/routes/gaoyu/blog.ts +145 -0
  109. package/lib/routes/gaoyu/namespace.ts +9 -0
  110. package/lib/routes/gaoyu/templates/description.art +7 -0
  111. package/lib/routes/geocaching/blogs.ts +2 -2
  112. package/lib/routes/github/namespace.ts +1 -1
  113. package/lib/routes/github/private-feed.ts +229 -0
  114. package/lib/routes/github/star.ts +1 -1
  115. package/lib/routes/google/extension.ts +9 -10
  116. package/lib/routes/gov/beijing/bphc/index.ts +1 -1
  117. package/lib/routes/gov/ccdi/index.ts +1 -1
  118. package/lib/routes/gov/chongqing/sydwgkzp.ts +22 -6
  119. package/lib/routes/gov/customs/list.ts +1 -1
  120. package/lib/routes/gov/general/general.ts +1 -1
  121. package/lib/routes/gov/hangzhou/zwfw.ts +1 -1
  122. package/lib/routes/gov/pbc/goutongjiaoliu.ts +1 -1
  123. package/lib/routes/gov/shenzhen/szlh/index.ts +77 -0
  124. package/lib/routes/gov/shenzhen/szlh/namespace.ts +8 -0
  125. package/lib/routes/grist/utils.ts +5 -4
  126. package/lib/routes/hanime1/search.ts +4 -2
  127. package/lib/routes/hellogithub/report.ts +1 -1
  128. package/lib/routes/hit/hitgs.ts +240 -54
  129. package/lib/routes/hit/templates/description.art +7 -0
  130. package/lib/routes/hlju/namespace.ts +8 -0
  131. package/lib/routes/hlju/news.ts +141 -0
  132. package/lib/routes/hostmonit/cloudflareyes.ts +1 -1
  133. package/lib/routes/hotukdeals/index.ts +1 -1
  134. package/lib/routes/hyperdash/namespace.ts +7 -0
  135. package/lib/routes/hyperdash/templates/description.art +34 -0
  136. package/lib/routes/hyperdash/top-traders.ts +84 -0
  137. package/lib/routes/hyperdash/utils.ts +49 -0
  138. package/lib/routes/hypergryph/arknights/announce.ts +1 -1
  139. package/lib/routes/ielts/index.ts +1 -1
  140. package/lib/routes/infoq/topic.ts +16 -13
  141. package/lib/routes/instagram/web-api/index.ts +17 -13
  142. package/lib/routes/instagram/web-api/utils.ts +46 -63
  143. package/lib/routes/jamesclear/book-summaries.ts +40 -0
  144. package/lib/routes/jamesclear/great-speeches.ts +40 -0
  145. package/lib/routes/jamesclear/namespace.ts +8 -0
  146. package/lib/routes/jamesclear/quotes.ts +40 -0
  147. package/lib/routes/jamesclear/three-two-one.ts +41 -0
  148. package/lib/routes/jamesclear/utils.ts +22 -0
  149. package/lib/routes/japanpost/utils.ts +2 -2
  150. package/lib/routes/javbus/index.ts +3 -0
  151. package/lib/routes/javdb/tags.ts +1 -0
  152. package/lib/routes/javlibrary/star.ts +1 -0
  153. package/lib/routes/javtiful/actress.ts +3 -0
  154. package/lib/routes/javtiful/channel.ts +3 -0
  155. package/lib/routes/javtrailers/casts.ts +3 -0
  156. package/lib/routes/jetbrains/comments.ts +99 -0
  157. package/lib/routes/jetbrains/namespace.ts +8 -0
  158. package/lib/routes/jimmyspa/books.ts +1 -1
  159. package/lib/routes/jimmyspa/news.ts +1 -1
  160. package/lib/routes/jpxgmn/tab.ts +3 -0
  161. package/lib/routes/kakuyomu/works.ts +3 -0
  162. package/lib/routes/kaopu/news.ts +1 -1
  163. package/lib/routes/kemono/const.ts +1 -1
  164. package/lib/routes/kemono/index.ts +12 -11
  165. package/lib/routes/kemono/namespace.ts +1 -1
  166. package/lib/routes/kiro/blog.ts +131 -0
  167. package/lib/routes/kiro/changelog.ts +128 -0
  168. package/lib/routes/kiro/namespace.ts +9 -0
  169. package/lib/routes/konachan/post.ts +3 -0
  170. package/lib/routes/kovidgoyal/kitty/changelog.ts +83 -0
  171. package/lib/routes/kovidgoyal/namespace.ts +7 -0
  172. package/lib/routes/kunchengblog/essay.ts +1 -1
  173. package/lib/routes/landiannews/category.ts +1 -1
  174. package/lib/routes/landiannews/index.ts +1 -1
  175. package/lib/routes/landiannews/tag.ts +1 -1
  176. package/lib/routes/line/utils.ts +1 -1
  177. package/lib/routes/lineageos/changes.ts +79 -0
  178. package/lib/routes/lineageos/namespace.ts +9 -0
  179. package/lib/routes/linkedin/cn/renderer.ts +1 -1
  180. package/lib/routes/liquipedia/cs-matches.ts +42 -14
  181. package/lib/routes/literotica/new.ts +1 -0
  182. package/lib/routes/lofter/tag.ts +27 -3
  183. package/lib/routes/makerworld/contest.ts +51 -0
  184. package/lib/routes/makerworld/namespace.ts +7 -0
  185. package/lib/routes/makerworld/trending.ts +45 -0
  186. package/lib/routes/makerworld/user-upload.ts +54 -0
  187. package/lib/routes/makerworld/utils.ts +18 -0
  188. package/lib/routes/manhuagui/comic.ts +1 -1
  189. package/lib/routes/manus/blog.ts +77 -0
  190. package/lib/routes/manus/namespace.ts +7 -0
  191. package/lib/routes/mastodon/tag.ts +48 -0
  192. package/lib/routes/mathpix/blog.ts +155 -0
  193. package/lib/routes/mathpix/namespace.ts +9 -0
  194. package/lib/routes/mathpix/templates/description.art +21 -0
  195. package/lib/routes/mckinsey/cn/category-map.ts +9 -15
  196. package/lib/routes/mckinsey/cn/index.ts +77 -40
  197. package/lib/routes/melonbooks/search.ts +1 -0
  198. package/lib/routes/metacritic/index.ts +2 -2
  199. package/lib/routes/meteoblue/namespace.ts +8 -0
  200. package/lib/routes/meteoblue/weathernews.ts +75 -0
  201. package/lib/routes/meteor/index.ts +1 -1
  202. package/lib/routes/microsoft/addon.ts +7 -9
  203. package/lib/routes/mihoyo/zzz/news.ts +106 -0
  204. package/lib/routes/missav/new.ts +2 -1
  205. package/lib/routes/mit/hanlab.ts +61 -0
  206. package/lib/routes/mit/namespace.ts +6 -0
  207. package/lib/routes/mittrchina/index.ts +3 -3
  208. package/lib/routes/mixcloud/config.ts +129 -0
  209. package/lib/routes/mixcloud/index.ts +163 -107
  210. package/lib/routes/mixcloud/user-playlist.ts +31 -0
  211. package/lib/routes/mixi2/community.ts +72 -0
  212. package/lib/routes/mixi2/discovery.ts +52 -0
  213. package/lib/routes/mixi2/home.ts +51 -0
  214. package/lib/routes/mixi2/namespace.ts +8 -0
  215. package/lib/routes/mixi2/user.ts +77 -0
  216. package/lib/routes/mixi2/utils.ts +56 -0
  217. package/lib/routes/modelscope/learn.ts +94 -0
  218. package/lib/routes/moodysmismicrosite/report.ts +1 -1
  219. package/lib/routes/musify/index.ts +130 -0
  220. package/lib/routes/musify/namespace.ts +9 -0
  221. package/lib/routes/musikguru/namespace.ts +9 -0
  222. package/lib/routes/musikguru/news.ts +146 -0
  223. package/lib/routes/musikguru/templates/description.art +21 -0
  224. package/lib/routes/myfans/post.ts +1 -0
  225. package/lib/routes/nankai/cc-notice.ts +114 -0
  226. package/lib/routes/nankai/jwc.ts +131 -0
  227. package/lib/routes/nankai/namespace.ts +7 -0
  228. package/lib/routes/nankai/notice.ts +84 -0
  229. package/lib/routes/nankai/yzb.ts +97 -0
  230. package/lib/routes/neu/yz.ts +172 -0
  231. package/lib/routes/newslaundry/explainer.ts +30 -0
  232. package/lib/routes/newslaundry/namespace.ts +8 -0
  233. package/lib/routes/newslaundry/nl-cheatsheet.ts +30 -0
  234. package/lib/routes/newslaundry/nl-collaborations.ts +30 -0
  235. package/lib/routes/newslaundry/podcast.ts +61 -0
  236. package/lib/routes/newslaundry/reports.ts +30 -0
  237. package/lib/routes/newslaundry/shot.ts +30 -0
  238. package/lib/routes/newslaundry/subscriber-only.ts +30 -0
  239. package/lib/routes/newslaundry/templates/description.art +28 -0
  240. package/lib/routes/newslaundry/utils.ts +108 -0
  241. package/lib/routes/newswav/latest.ts +100 -0
  242. package/lib/routes/newswav/namespace.ts +7 -0
  243. package/lib/routes/nhentai/index.ts +1 -0
  244. package/lib/routes/nifd/research.ts +16 -0
  245. package/lib/routes/nio/namespace.ts +9 -0
  246. package/lib/routes/nio/nioradio.ts +75 -0
  247. package/lib/routes/njust/cs.ts +58 -0
  248. package/lib/routes/njust/utils.ts +1 -1
  249. package/lib/routes/ntdm/video.ts +1 -1
  250. package/lib/routes/nuaa/utils/pypasswaf.ts +1 -1
  251. package/lib/routes/oilchem/index.ts +1 -1
  252. package/lib/routes/oncc/money18.ts +1 -1
  253. package/lib/routes/openai/cookbook.ts +1 -1
  254. package/lib/routes/paulgraham/article.ts +2 -2
  255. package/lib/routes/picuki/profile.ts +4 -0
  256. package/lib/routes/pixiv/bookmarks.ts +1 -1
  257. package/lib/routes/pixiv/novel-api/series/sfw.ts +1 -1
  258. package/lib/routes/pixiv/novels.ts +2 -2
  259. package/lib/routes/pixiv/user.ts +1 -1
  260. package/lib/routes/playno1/av.ts +1 -0
  261. package/lib/routes/pornhub/model.ts +3 -7
  262. package/lib/routes/pornhub/pornstar.ts +2 -7
  263. package/lib/routes/pornhub/users.ts +2 -7
  264. package/lib/routes/pornhub/utils.ts +12 -1
  265. package/lib/routes/qingting/podcast.ts +2 -1
  266. package/lib/routes/qipamaijia/index.ts +1 -0
  267. package/lib/routes/questmobile/report.ts +1 -1
  268. package/lib/routes/railway/index.ts +73 -0
  269. package/lib/routes/railway/namespace.ts +8 -0
  270. package/lib/routes/reuters/common.ts +0 -3
  271. package/lib/routes/rockthejvm/articles.ts +167 -0
  272. package/lib/routes/rockthejvm/namespace.ts +9 -0
  273. package/lib/routes/rockthejvm/templates/description.art +7 -0
  274. package/lib/routes/samrdprc/namespace.ts +7 -0
  275. package/lib/routes/samrdprc/news.ts +79 -0
  276. package/lib/routes/sankei/namespace.ts +7 -0
  277. package/lib/routes/sankei/news.ts +68 -0
  278. package/lib/routes/sankei/topics.ts +71 -0
  279. package/lib/routes/sciencenet/user.ts +1 -1
  280. package/lib/routes/scoop/apps.ts +188 -0
  281. package/lib/routes/scoop/namespace.ts +9 -0
  282. package/lib/routes/scoop/templates/description.art +56 -0
  283. package/lib/routes/scpta/namespace.ts +8 -0
  284. package/lib/routes/scpta/news.ts +101 -0
  285. package/lib/routes/seekingalpha/index.ts +1 -1
  286. package/lib/routes/sehuatang/index.ts +29 -31
  287. package/lib/routes/setn/index.ts +11 -2
  288. package/lib/routes/seu/cyber/index.ts +78 -0
  289. package/lib/routes/sicau/jiaowu.ts +42 -34
  290. package/lib/routes/sis001/forum.ts +1 -0
  291. package/lib/routes/sjtu/seiee/icisee.ts +67 -0
  292. package/lib/routes/sketis/isabelle-dev/blog/index.ts +1 -1
  293. package/lib/routes/smartlink/index.ts +13 -3
  294. package/lib/routes/sohu/mp.ts +17 -6
  295. package/lib/routes/sotwe/namespace.ts +1 -0
  296. package/lib/routes/sotwe/user.ts +98 -0
  297. package/lib/routes/spankbang/new-videos.ts +1 -0
  298. package/lib/routes/spglobal/ratings.ts +1 -1
  299. package/lib/routes/stanford/blog.ts +77 -0
  300. package/lib/routes/stanford/namespace.ts +7 -0
  301. package/lib/routes/syosetu/index.ts +1 -1
  302. package/lib/routes/t66y/index.ts +1 -0
  303. package/lib/routes/taobao/mysql.ts +157 -0
  304. package/lib/routes/taobao/namespace.ts +2 -2
  305. package/lib/routes/techcrunch/category.ts +48 -0
  306. package/lib/routes/telegram/channel.ts +2 -2
  307. package/lib/routes/tesla/cx.ts +1 -1
  308. package/lib/routes/test/index.ts +1 -1
  309. package/lib/routes/themoviedb/episodes.ts +1 -1
  310. package/lib/routes/thewirehindi/category.ts +78 -0
  311. package/lib/routes/thewirehindi/index.ts +43 -0
  312. package/lib/routes/thewirehindi/namespace.ts +7 -0
  313. package/lib/routes/thewirehindi/templates/description.art +9 -0
  314. package/lib/routes/thewirehindi/utils.ts +33 -0
  315. package/lib/routes/threads/utils.ts +2 -2
  316. package/lib/routes/tidb/blog.ts +314 -0
  317. package/lib/routes/tidb/namespace.ts +9 -0
  318. package/lib/routes/tumblr/namespace.ts +17 -0
  319. package/lib/routes/tumblr/posts.ts +74 -0
  320. package/lib/routes/tumblr/utils.ts +110 -0
  321. package/lib/routes/tver/namespace.ts +7 -0
  322. package/lib/routes/tver/series.ts +98 -0
  323. package/lib/routes/twitter/api/web-api/login.ts +1 -3
  324. package/lib/routes/twitter/api/web-api/utils.ts +23 -1
  325. package/lib/routes/twitter/utils.ts +21 -21
  326. package/lib/routes/udn/breaking-news.ts +2 -2
  327. package/lib/routes/uestc/auto.ts +1 -1
  328. package/lib/routes/uestc/cqe.ts +1 -1
  329. package/lib/routes/uestc/scse.ts +1 -1
  330. package/lib/routes/uestc/sice.ts +1 -1
  331. package/lib/routes/uestc/sise.ts +1 -1
  332. package/lib/routes/upc/jwc.ts +32 -46
  333. package/lib/routes/uptimerobot/rss.ts +1 -1
  334. package/lib/routes/visionias/daily-news-summary.ts +65 -0
  335. package/lib/routes/visionias/monthly-magazine.ts +68 -0
  336. package/lib/routes/visionias/news-today.ts +3 -13
  337. package/lib/routes/visionias/utils.ts +5 -5
  338. package/lib/routes/visionias/weekly-focus.ts +2 -2
  339. package/lib/routes/wdfxw/bookfree.ts +528 -0
  340. package/lib/routes/wdfxw/namespace.ts +8 -0
  341. package/lib/routes/wdfxw/templates/description.art +13 -0
  342. package/lib/routes/whu/swrh.ts +1 -1
  343. package/lib/routes/windsurf/blog.ts +118 -0
  344. package/lib/routes/windsurf/changelog.ts +100 -0
  345. package/lib/routes/windsurf/namespace.ts +9 -0
  346. package/lib/routes/windsurf/templates/description.art +21 -0
  347. package/lib/routes/x6d/index.ts +1 -1
  348. package/lib/routes/xbookcn/blog.ts +1 -0
  349. package/lib/routes/xiaohongshu/util.ts +1 -3
  350. package/lib/routes/xiaoyuzhou/pickup.ts +1 -1
  351. package/lib/routes/ximalaya/album.ts +32 -70
  352. package/lib/routes/ximalaya/types.ts +48 -0
  353. package/lib/routes/ximalaya/utils.ts +9 -7
  354. package/lib/routes/xmanhua/index.ts +1 -0
  355. package/lib/routes/xueqiu/cookies.ts +1 -1
  356. package/lib/routes/xueqiu/user.ts +1 -1
  357. package/lib/routes/xwenming/index.ts +184 -0
  358. package/lib/routes/xwenming/namespace.ts +9 -0
  359. package/lib/routes/yahoo/news/utils.ts +1 -1
  360. package/lib/routes/yande/post.ts +3 -0
  361. package/lib/routes/ymgal/game.ts +1 -0
  362. package/lib/routes/youtube/api/google.ts +27 -0
  363. package/lib/routes/youtube/api/youtubei.ts +70 -20
  364. package/lib/routes/youtube/community.ts +3 -1
  365. package/lib/routes/youtube/utils.ts +16 -14
  366. package/lib/routes/zaobao/util.ts +8 -5
  367. package/lib/routes/zhihu/activities.ts +3 -0
  368. package/lib/routes/zhihu/execlib/x-zse-96-v3.ts +5 -5
  369. package/lib/routes/zhizhuan100/namespace.ts +7 -0
  370. package/lib/routes/zhizhuan100/report.ts +79 -0
  371. package/lib/routes/zimuxia/portfolio.ts +1 -1
  372. package/lib/routes/zju/sis/index.ts +161 -0
  373. package/lib/server.ts +5 -0
  374. package/lib/types.ts +58 -54
  375. package/lib/utils/helpers.ts +1 -1
  376. package/lib/utils/logger.ts +1 -1
  377. package/lib/utils/proxy/index.ts +102 -18
  378. package/lib/utils/proxy/multi-proxy.ts +139 -0
  379. package/lib/utils/proxy/unify-proxy.ts +3 -1
  380. package/lib/utils/puppeteer-utils.test.ts +1 -1
  381. package/lib/utils/puppeteer.test.ts +14 -27
  382. package/lib/utils/puppeteer.ts +51 -37
  383. package/lib/utils/readable-social.test.ts +65 -0
  384. package/lib/utils/readable-social.ts +15 -1
  385. package/lib/utils/request-rewriter/fetch.ts +42 -4
  386. package/package.json +54 -56
  387. package/lib/routes/mixcloud/queries.ts +0 -2274
  388. package/lib/routes-deprecated/dev.to/top.js +0 -40
@@ -0,0 +1,9 @@
1
+ import type { Namespace } from '@/types';
2
+
3
+ export const namespace: Namespace = {
4
+ name: '未知文明',
5
+ url: 'xwenming.com',
6
+ categories: ['new-media'],
7
+ description: '',
8
+ lang: 'zh-CN',
9
+ };
@@ -84,7 +84,7 @@ const parseItem = (item, tryGet) =>
84
84
 
85
85
  const ldJson = JSON.parse($('script[type="application/ld+json"]').first().text());
86
86
  const author = `${$('span.caas-author-byline-collapse').text()} @${$('span.caas-attr-provider').text()}`;
87
- const body = $('.caas-body');
87
+ const body = $('.atoms');
88
88
 
89
89
  body.find('noscript').remove();
90
90
  // remove padding
@@ -30,6 +30,9 @@ export const route: Route = {
30
30
  | ------- | -------- | ------- | -------- |
31
31
  | 1d | 1w | 1m | 1y |`,
32
32
  handler,
33
+ features: {
34
+ nsfw: true,
35
+ },
33
36
  };
34
37
 
35
38
  async function handler(ctx) {
@@ -23,6 +23,7 @@ export const route: Route = {
23
23
  supportBT: false,
24
24
  supportPodcast: false,
25
25
  supportScihub: false,
26
+ nsfw: true,
26
27
  },
27
28
  radar: [
28
29
  {
@@ -8,6 +8,9 @@ import ofetch from '@/utils/ofetch';
8
8
  import * as cheerio from 'cheerio';
9
9
  import NotFoundError from '@/errors/types/not-found';
10
10
  import { Data } from '@/types';
11
+ import dayjs from 'dayjs';
12
+ import duration from 'dayjs/plugin/duration.js';
13
+ dayjs.extend(duration);
11
14
 
12
15
  let count = 0;
13
16
  const youtube = {};
@@ -102,6 +105,8 @@ export const getDataByUsername = async ({ username, embed, filterShorts }: { use
102
105
  if (!playlistItems) {
103
106
  throw new NotFoundError("This channel doesn't have any content.");
104
107
  }
108
+ const videoIds = playlistItems.data.items.map((item) => item.snippet.resourceId.videoId).join(',');
109
+ const videoDetails = await utils.getVideos(videoIds, 'contentDetails', cache);
105
110
 
106
111
  return {
107
112
  title: `${userHandleData?.channelName || username} - YouTube`,
@@ -114,6 +119,7 @@ export const getDataByUsername = async ({ username, embed, filterShorts }: { use
114
119
  const snippet = item.snippet;
115
120
  const videoId = snippet.resourceId.videoId;
116
121
  const img = utils.getThumbnail(snippet.thumbnails);
122
+ const detail = videoDetails?.data.items.find((d) => d.id === videoId);
117
123
  return {
118
124
  title: snippet.title,
119
125
  description: utils.renderDescription(embed, videoId, img, utils.formatDescription(snippet.description)),
@@ -125,6 +131,7 @@ export const getDataByUsername = async ({ username, embed, filterShorts }: { use
125
131
  {
126
132
  url: getVideoUrl(videoId),
127
133
  mime_type: 'text/html',
134
+ duration_in_seconds: detail?.contentDetails.duration ? dayjs.duration(detail.contentDetails.duration).asSeconds() : undefined,
128
135
  },
129
136
  ],
130
137
  };
@@ -140,6 +147,8 @@ export const getDataByChannelId = async ({ channelId, embed, filterShorts }: { c
140
147
  const playlistId = filterShorts ? utils.getPlaylistWithShortsFilter(channelId) : originalPlaylistId;
141
148
 
142
149
  const data = (await utils.getPlaylistItems(playlistId, 'snippet', cache)).data.items;
150
+ const videoIds = data.map((item) => item.snippet.resourceId.videoId).join(',');
151
+ const videoDetails = await utils.getVideos(videoIds, 'contentDetails', cache);
143
152
 
144
153
  return {
145
154
  title: `${data[0].snippet.channelTitle} - YouTube`,
@@ -151,6 +160,7 @@ export const getDataByChannelId = async ({ channelId, embed, filterShorts }: { c
151
160
  const snippet = item.snippet;
152
161
  const videoId = snippet.resourceId.videoId;
153
162
  const img = utils.getThumbnail(snippet.thumbnails);
163
+ const detail = videoDetails?.data.items.find((d) => d.id === videoId);
154
164
  return {
155
165
  title: snippet.title,
156
166
  description: utils.renderDescription(embed, videoId, img, utils.formatDescription(snippet.description)),
@@ -158,6 +168,13 @@ export const getDataByChannelId = async ({ channelId, embed, filterShorts }: { c
158
168
  link: `https://www.youtube.com/watch?v=${videoId}`,
159
169
  author: snippet.videoOwnerChannelTitle,
160
170
  image: img.url,
171
+ attachments: [
172
+ {
173
+ url: getVideoUrl(videoId),
174
+ mime_type: 'text/html',
175
+ duration_in_seconds: detail?.contentDetails.duration ? dayjs.duration(detail.contentDetails.duration).asSeconds() : undefined,
176
+ },
177
+ ],
161
178
  };
162
179
  }),
163
180
  };
@@ -167,6 +184,8 @@ export const getDataByPlaylistId = async ({ playlistId, embed }: { playlistId: s
167
184
  const playlistTitle = (await utils.getPlaylist(playlistId, 'snippet', cache)).data.items[0].snippet.title;
168
185
 
169
186
  const data = (await utils.getPlaylistItems(playlistId, 'snippet', cache)).data.items.filter((d) => d.snippet.title !== 'Private video' && d.snippet.title !== 'Deleted video');
187
+ const videoIds = data.map((item) => item.snippet.resourceId.videoId).join(',');
188
+ const videoDetails = await utils.getVideos(videoIds, 'contentDetails', cache);
170
189
 
171
190
  return {
172
191
  title: `${playlistTitle} by ${data[0].snippet.channelTitle} - YouTube`,
@@ -176,6 +195,7 @@ export const getDataByPlaylistId = async ({ playlistId, embed }: { playlistId: s
176
195
  const snippet = item.snippet;
177
196
  const videoId = snippet.resourceId.videoId;
178
197
  const img = utils.getThumbnail(snippet.thumbnails);
198
+ const detail = videoDetails?.data.items.find((d) => d.id === videoId);
179
199
  return {
180
200
  title: snippet.title,
181
201
  description: utils.renderDescription(embed, videoId, img, utils.formatDescription(snippet.description)),
@@ -183,6 +203,13 @@ export const getDataByPlaylistId = async ({ playlistId, embed }: { playlistId: s
183
203
  link: `https://www.youtube.com/watch?v=${videoId}`,
184
204
  author: snippet.videoOwnerChannelTitle,
185
205
  image: img.url,
206
+ attachments: [
207
+ {
208
+ url: getVideoUrl(videoId),
209
+ mime_type: 'text/html',
210
+ duration_in_seconds: detail?.contentDetails.duration ? dayjs.duration(detail.contentDetails.duration).asSeconds() : undefined,
211
+ },
212
+ ],
186
213
  };
187
214
  }),
188
215
  };
@@ -1,3 +1,4 @@
1
+ import { getSubtitles } from 'youtube-caption-extractor';
1
2
  import cache from '@/utils/cache';
2
3
  import { Innertube } from 'youtubei.js';
3
4
  import utils, { getVideoUrl } from '../utils';
@@ -6,6 +7,38 @@ import { parseRelativeDate } from '@/utils/parse-date';
6
7
 
7
8
  const innertubePromise = Innertube.create();
8
9
 
10
+ function pad(n: number, width: number = 2) {
11
+ return String(n).padStart(width, '0');
12
+ }
13
+
14
+ function toSrtTime(seconds: number): string {
15
+ const totalMs = Math.floor(seconds * 1000);
16
+ const hours = Math.floor(totalMs / 3_600_000);
17
+ const minutes = Math.floor((totalMs % 3_600_000) / 60000);
18
+ const secs = Math.floor((totalMs % 60000) / 1000);
19
+ const millis = totalMs % 1000;
20
+ return `${pad(hours)}:${pad(minutes)}:${pad(secs)},${pad(millis, 3)}`;
21
+ }
22
+
23
+ type Subtitle = {
24
+ start: string;
25
+ dur: string;
26
+ text: string;
27
+ };
28
+
29
+ function convertToSrt(segments: Subtitle[]): string {
30
+ return segments
31
+ .map((seg, index) => {
32
+ const start = Number.parseFloat(seg.start);
33
+ const end = start + Number.parseFloat(seg.dur);
34
+ return `${index + 1}
35
+ ${toSrtTime(start)} --> ${toSrtTime(end)}
36
+ ${seg.text}
37
+ `;
38
+ })
39
+ .join('\n');
40
+ }
41
+
9
42
  export const getChannelIdByUsername = (username: string) =>
10
43
  cache.tryGet(`youtube:getChannelIdByUsername:${username}`, async () => {
11
44
  const innertube = await innertubePromise;
@@ -18,6 +51,13 @@ export const getDataByUsername = async ({ username, embed, filterShorts }: { use
18
51
  return getDataByChannelId({ channelId, embed, filterShorts });
19
52
  };
20
53
 
54
+ const getSubtitlesByVideoId = (videoId: string) =>
55
+ cache.tryGet(`youtube:getSubtitlesByVideoId:${videoId}`, async () => {
56
+ const subtitles = await getSubtitles({ videoID: videoId });
57
+ const srt = convertToSrt(subtitles);
58
+ return srt;
59
+ });
60
+
21
61
  export const getDataByChannelId = async ({ channelId, embed }: { channelId: string; embed: boolean; filterShorts: boolean }): Promise<Data> => {
22
62
  const innertube = await innertubePromise;
23
63
  const channel = await innertube.getChannel(channelId);
@@ -29,27 +69,37 @@ export const getDataByChannelId = async ({ channelId, embed }: { channelId: stri
29
69
  image: channel.metadata.avatar?.[0].url,
30
70
  description: channel.metadata.description,
31
71
 
32
- item: videos.videos
33
- .filter((video) => 'video_id' in video)
34
- .map((video) => {
35
- const img = 'best_thumbnail' in video ? video.best_thumbnail?.url : ('thumbnails' in video ? video.thumbnails?.[0]?.url : undefined);
72
+ item: await Promise.all(
73
+ videos.videos
74
+ .filter((video) => 'video_id' in video)
75
+ .map(async (video) => {
76
+ const srt = await getSubtitlesByVideoId(video.video_id);
77
+ const dataUrl = `data:text/plain;charset=utf-8,${encodeURIComponent(srt)}`;
36
78
 
37
- return {
38
- title: video.title.text || `YouTube Video ${video.video_id}`,
39
- description: 'description_snippet' in video ? utils.renderDescription(embed, video.video_id, img, utils.formatDescription(video.description_snippet?.toHTML())) : null,
40
- link: `https://www.youtube.com/watch?v=${video.video_id}`,
41
- author: typeof video.author === 'string' ? video.author : (video.author.name === 'N/A' ? undefined : video.author.name),
42
- image: img,
43
- pubDate: 'published' in video && video.published?.text ? parseRelativeDate(video.published.text) : undefined,
44
- attachments: [
45
- {
46
- url: getVideoUrl(video.video_id),
47
- mime_type: 'text/html',
48
- duration_in_seconds: video.duration && 'seconds' in video.duration ? video.duration.seconds : undefined,
49
- },
50
- ],
51
- };
52
- }),
79
+ const img = 'best_thumbnail' in video ? video.best_thumbnail?.url : 'thumbnails' in video ? video.thumbnails?.[0]?.url : undefined;
80
+
81
+ return {
82
+ title: video.title.text || `YouTube Video ${video.video_id}`,
83
+ description: 'description_snippet' in video ? utils.renderDescription(embed, video.video_id, img, utils.formatDescription(video.description_snippet?.toHTML())) : null,
84
+ link: `https://www.youtube.com/watch?v=${video.video_id}`,
85
+ author: typeof video.author === 'string' ? video.author : video.author.name === 'N/A' ? undefined : video.author.name,
86
+ image: img,
87
+ pubDate: 'published' in video && video.published?.text ? parseRelativeDate(video.published.text) : undefined,
88
+ attachments: [
89
+ {
90
+ url: getVideoUrl(video.video_id),
91
+ mime_type: 'text/html',
92
+ duration_in_seconds: video.duration && 'seconds' in video.duration ? video.duration.seconds : undefined,
93
+ },
94
+ {
95
+ url: dataUrl,
96
+ mime_type: 'text/srt',
97
+ title: 'Subtitles',
98
+ },
99
+ ],
100
+ };
101
+ })
102
+ ),
53
103
  };
54
104
  };
55
105
 
@@ -35,7 +35,9 @@ async function handler(ctx) {
35
35
 
36
36
  const channelMetadata = ytInitialData.metadata.channelMetadataRenderer;
37
37
  const username = channelMetadata.title;
38
- const communityTab = ytInitialData.contents.twoColumnBrowseResultsRenderer.tabs.find((tab) => tab.tabRenderer.endpoint.commandMetadata.webCommandMetadata.url.endsWith('/community'));
38
+ const communityTab = ytInitialData.contents.twoColumnBrowseResultsRenderer.tabs.find(
39
+ (tab) => tab.tabRenderer.endpoint.commandMetadata.webCommandMetadata.url.endsWith('/posts') || tab.tabRenderer.endpoint.commandMetadata.webCommandMetadata.url.endsWith('/community')
40
+ );
39
41
  const list = communityTab.tabRenderer.content.sectionListRenderer.contents[0].itemSectionRenderer.contents;
40
42
 
41
43
  if (list[0].messageRenderer) {
@@ -50,18 +50,18 @@ export const getChannelWithUsername = (username, part, cache) =>
50
50
  );
51
51
  return res;
52
52
  });
53
- // not in use
54
- // export const getVideoAuthor = async (id, part) => {
55
- // const res = await exec((youtube) =>
56
- // youtube.videos.list({
57
- // part,
58
- // id,
59
- // })
60
- // );
61
- // return res;
62
- // }
53
+ export const getVideos = (id, part, cache) =>
54
+ cache.tryGet(`youtube:getVideos:${id}`, async () => {
55
+ const res = await exec((youtube) =>
56
+ youtube.videos.list({
57
+ part,
58
+ id,
59
+ })
60
+ );
61
+ return res;
62
+ });
63
63
  export const getThumbnail = (thumbnails) => thumbnails.maxres || thumbnails.standard || thumbnails.high || thumbnails.medium || thumbnails.default;
64
- export const formatDescription = (description) => description.replaceAll(/\r\n|\r|\n/g, '<br>');
64
+ export const formatDescription = (description) => description?.replaceAll(/\r\n|\r|\n/g, '<br>');
65
65
  export const renderDescription = (embed, videoId, img, description) =>
66
66
  art(path.join(__dirname, 'templates/description.art'), {
67
67
  embed,
@@ -93,7 +93,9 @@ export async function getSubscriptionsRecusive(part, nextPageToken?) {
93
93
  // recursively get next page
94
94
  if (res.data.nextPageToken) {
95
95
  const next = await getSubscriptionsRecusive(part, res.data.nextPageToken);
96
- res.data.items = [...res.data.items, ...next.data.items];
96
+ if (next.data.items) {
97
+ res.data.items = [...(res.data.items || []), ...next.data.items];
98
+ }
97
99
  }
98
100
  return res;
99
101
  }
@@ -140,11 +142,12 @@ export const callApi = async <T>({ googleApi, youtubeiApi, params }: { googleApi
140
142
  return await youtubeiApi(params);
141
143
  };
142
144
 
143
- const youtubeUtils = {
145
+ export default {
144
146
  getPlaylistItems,
145
147
  getPlaylist,
146
148
  getChannelWithId,
147
149
  getChannelWithUsername,
150
+ getVideos,
148
151
  getThumbnail,
149
152
  formatDescription,
150
153
  renderDescription,
@@ -155,4 +158,3 @@ const youtubeUtils = {
155
158
  getVideoUrl,
156
159
  getPlaylistWithShortsFilter,
157
160
  };
158
- export default youtubeUtils;
@@ -35,10 +35,10 @@ const parseList = async (
35
35
  }> => {
36
36
  const response = await got_ins.get(baseUrl + sectionUrl);
37
37
  const $ = load(response.data);
38
- let data = $('.card-listing .card');
38
+ let data = $('.card-listing .card .content-header a');
39
39
  if (data.length === 0) {
40
40
  // for HK version
41
- data = $('.clearfix').find('.list-block');
41
+ data = $('[data-testid="article-list"] article a.article-link');
42
42
  }
43
43
 
44
44
  const title = $('meta[property="og:title"]').attr('content');
@@ -47,7 +47,7 @@ const parseList = async (
47
47
  data.toArray().map((item) => {
48
48
  const $item = $(item);
49
49
  // addBack: for HK version
50
- let link = $item.find('a').addBack('a')[0].attribs.href;
50
+ let link = $item.attr('href');
51
51
 
52
52
  if (link[0] !== '/') {
53
53
  // https://www.zaobao.com/interactive-graphics
@@ -88,7 +88,7 @@ const parseList = async (
88
88
  // HK
89
89
  title = $1('h1.article-title').text();
90
90
  const jsonText = $1("head script[type='application/ld+json']")
91
- .eq(1)
91
+ .eq(0)
92
92
  .text()
93
93
  .replaceAll(/[\u0000-\u001F\u007F-\u009F]/g, '');
94
94
  time = new Date(JSON.parse(jsonText)?.datePublished);
@@ -106,11 +106,14 @@ const parseList = async (
106
106
  $1('#video-freemium-player').remove();
107
107
  $1('script').remove();
108
108
  $1('.bff-google-ad').remove();
109
+ $1('.bff-recommend-article').remove();
109
110
 
110
111
  let articleBodyNode = $1('.articleBody');
111
112
  if (articleBodyNode.length === 0) {
112
113
  // for HK version
113
- orderContent($1('.article-body'));
114
+ $1('.read-on-app-cover').remove();
115
+ $1('astro-island').remove();
116
+ $1('.further-reading').remove();
114
117
  articleBodyNode = $1('.article-body');
115
118
  }
116
119
 
@@ -103,6 +103,9 @@ async function handler(ctx) {
103
103
  src="${contentItem.playlist[1].url}"></video></p>`;
104
104
 
105
105
  break;
106
+ case 'link_card':
107
+ link = `<p><a href="${contentItem.url.split('?')[0]}" target="_blank"></a></p>`;
108
+ break;
106
109
 
107
110
  default:
108
111
  throw new Error(`Unknown type: ${contentItem.type}`);
@@ -5,7 +5,7 @@
5
5
  /* eslint-disable @typescript-eslint/no-unused-expressions */
6
6
 
7
7
  function i(e, t, n) {
8
- (t[n] = 255 & (e >>> 24)), (t[n + 1] = 255 & (e >>> 16)), (t[n + 2] = 255 & (e >>> 8)), (t[n + 3] = 255 & e);
8
+ ((t[n] = 255 & (e >>> 24)), (t[n + 1] = 255 & (e >>> 16)), (t[n + 2] = 255 & (e >>> 8)), (t[n + 3] = 255 & e));
9
9
  }
10
10
  function B(e, t) {
11
11
  return ((255 & e[t]) << 24) | ((255 & e[t + 1]) << 16) | ((255 & e[t + 2]) << 8) | (255 & e[t + 3]);
@@ -16,7 +16,7 @@ function Q(e, t) {
16
16
  function G(e) {
17
17
  const t = Array.from({ length: 4 });
18
18
  const n = Array.from({ length: 4 });
19
- i(e, t, 0), (n[0] = h.zb[255 & t[0]]), (n[1] = h.zb[255 & t[1]]), (n[2] = h.zb[255 & t[2]]), (n[3] = h.zb[255 & t[3]]);
19
+ (i(e, t, 0), (n[0] = h.zb[255 & t[0]]), (n[1] = h.zb[255 & t[1]]), (n[2] = h.zb[255 & t[2]]), (n[3] = h.zb[255 & t[3]]));
20
20
  const r = B(n, 0);
21
21
  return r ^ Q(r, 2) ^ Q(r, 10) ^ Q(r, 18) ^ Q(r, 24);
22
22
  }
@@ -29,19 +29,19 @@ const __g = {
29
29
  a[c] = o[c] ^ t[c];
30
30
  }
31
31
  // eslint-disable-next-line unicorn/prefer-spread
32
- (t = __g.r(a)), (n = n.concat(t)), i++;
32
+ ((t = __g.r(a)), (n = n.concat(t)), i++);
33
33
  }
34
34
  return n;
35
35
  },
36
36
  r(e) {
37
37
  const t = Array.from({ length: 16 });
38
38
  const n = Array.from({ length: 36 });
39
- (n[0] = B(e, 0)), (n[1] = B(e, 4)), (n[2] = B(e, 8)), (n[3] = B(e, 12));
39
+ ((n[0] = B(e, 0)), (n[1] = B(e, 4)), (n[2] = B(e, 8)), (n[3] = B(e, 12)));
40
40
  for (let r = 0; r < 32; r++) {
41
41
  const o = G(n[r + 1] ^ n[r + 2] ^ n[r + 3] ^ h.zk[r]);
42
42
  n[r + 4] = n[r] ^ o;
43
43
  }
44
- return i(n[35], t, 0), i(n[34], t, 4), i(n[33], t, 8), i(n[32], t, 12), t;
44
+ return (i(n[35], t, 0), i(n[34], t, 4), i(n[33], t, 8), i(n[32], t, 12), t);
45
45
  },
46
46
  };
47
47
  const h = {
@@ -0,0 +1,7 @@
1
+ import type { Namespace } from '@/types';
2
+
3
+ export const namespace: Namespace = {
4
+ name: '智篆商业',
5
+ url: 'www.zhizhuan100.com.cn',
6
+ lang: 'zh-CN',
7
+ };
@@ -0,0 +1,79 @@
1
+ import { Route, ViewType } from '@/types';
2
+ import { parseRelativeDate } from '@/utils/parse-date';
3
+ import ofetch from '@/utils/ofetch';
4
+ import * as cheerio from 'cheerio';
5
+
6
+ export const route: Route = {
7
+ path: '/analytic',
8
+ categories: ['finance'],
9
+ view: ViewType.Articles,
10
+ example: '/zhizhuan100/analytic',
11
+ radar: [
12
+ {
13
+ source: ['www.zhizhuan100.com.cn/analysis'],
14
+ },
15
+ ],
16
+ name: 'analytic',
17
+ maintainers: ['Cedaric'],
18
+ handler,
19
+ };
20
+
21
+ async function handler() {
22
+ const urlData = await ofetch('https://www.zhizhuan100.com.cn/analysis');
23
+
24
+ const $ = cheerio.load(urlData);
25
+
26
+ const bodyJsUrl: string | undefined = $('script[src*="Body.js"]').attr('src');
27
+
28
+ if (!bodyJsUrl) {
29
+ throw new Error('无法找到 Body.js 脚本文件');
30
+ }
31
+
32
+ const responseData = await ofetch(bodyJsUrl, {
33
+ parseResponse: (txt) => txt,
34
+ });
35
+
36
+ const htmlMatch = responseData.match(/document\.write\('(.*)'\);/s);
37
+ if (!htmlMatch) {
38
+ throw new Error('无法找到HTML内容');
39
+ }
40
+
41
+ const htmlContent = JSON.parse(`"${htmlMatch[1]}"`);
42
+ const $content = cheerio.load(htmlContent);
43
+
44
+ const listItems = $content('.w-list-item');
45
+
46
+ const items = listItems
47
+ .toArray()
48
+ .map((item) => {
49
+ const $item = $content(item);
50
+ const titleElement = $item.find('.w-list-title');
51
+ const dateElement = $item.find('.w-list-date');
52
+ const linkElement = $item.find('.w-list-link');
53
+ const imgElement = $item.find('.w-listpic-in');
54
+
55
+ const title = titleElement.text().trim() || '';
56
+ const dateText = dateElement.text().trim() || '';
57
+ const href = linkElement.attr('href') || '';
58
+ const imgSrc = imgElement.attr('src') || '';
59
+
60
+ const idMatch = href.match(/\/productinfo\/(\d+)\.html/);
61
+ const id = idMatch ? idMatch[1] : '';
62
+
63
+ return {
64
+ title,
65
+ pubDate: parseRelativeDate(dateText),
66
+ link: href.startsWith('http') ? href : `https://www.zhizhuan100.com.cn${href}`,
67
+ description: `<img src="${imgSrc.startsWith('//') ? 'https:' + imgSrc : imgSrc}" alt="${title}">`,
68
+ guid: id,
69
+ };
70
+ })
71
+ .filter((item) => item.title);
72
+
73
+ return {
74
+ title: '智篆商业-消费报告',
75
+ link: 'https://www.zhizhuan100.com.cn/analysis',
76
+ allowEmpty: true,
77
+ item: items,
78
+ };
79
+ }
@@ -69,7 +69,7 @@ async function handler(ctx) {
69
69
  guid: `${currentUrl}#${title}`,
70
70
  };
71
71
  })
72
- .reverse();
72
+ .toReversed();
73
73
 
74
74
  return {
75
75
  title: `${$('.content-page-title').text()} - FIX字幕侠`,