rsshub 1.0.0-master.f9ec483 → 1.0.0-master.fa1dcc5

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 (334) hide show
  1. package/lib/config.ts +42 -1
  2. package/lib/middleware/access-control.ts +3 -3
  3. package/lib/middleware/cache.ts +5 -3
  4. package/lib/middleware/template.test.ts +6 -0
  5. package/lib/middleware/template.tsx +3 -1
  6. package/lib/router.js +0 -6
  7. package/lib/routes/141jav/index.ts +1 -1
  8. package/lib/routes/141ppv/index.ts +1 -1
  9. package/lib/routes/36kr/hot-list.ts +1 -1
  10. package/lib/routes/36kr/index.ts +1 -1
  11. package/lib/routes/78dm/index.ts +429 -43
  12. package/lib/routes/78dm/namespace.ts +2 -0
  13. package/lib/routes/78dm/templates/description.art +17 -0
  14. package/lib/routes/abc/index.ts +10 -9
  15. package/lib/routes/aeon/category.ts +1 -1
  16. package/lib/routes/aeon/type.ts +1 -1
  17. package/lib/routes/afr/latest.ts +69 -0
  18. package/lib/routes/afr/namespace.ts +7 -0
  19. package/lib/routes/afr/navigation.ts +75 -0
  20. package/lib/routes/afr/query.ts +349 -0
  21. package/lib/routes/afr/utils.ts +80 -0
  22. package/lib/routes/aibase/discover.ts +1 -1
  23. package/lib/routes/aibase/news.ts +1 -1
  24. package/lib/routes/aibase/topic.ts +1 -1
  25. package/lib/routes/air-level/index.ts +49 -0
  26. package/lib/routes/air-level/levelrank.ts +65 -0
  27. package/lib/routes/air-level/namespace.ts +12 -0
  28. package/lib/routes/ajcass/namespace.ts +11 -0
  29. package/lib/routes/ajcass/shxyj.ts +73 -0
  30. package/lib/routes/alpinelinux/pkgs.ts +2 -2
  31. package/lib/routes/anime1/anime.ts +1 -1
  32. package/lib/routes/apnews/utils.ts +6 -2
  33. package/lib/routes/appleinsider/index.ts +1 -1
  34. package/lib/routes/aqara/region.ts +1 -1
  35. package/lib/routes/asus/bios.ts +0 -1
  36. package/lib/routes/baoyu/index.ts +57 -0
  37. package/lib/routes/baoyu/namespace.ts +8 -0
  38. package/lib/routes/bilibili/article.ts +37 -14
  39. package/lib/routes/bilibili/dynamic.ts +15 -7
  40. package/lib/routes/bilibili/followings-dynamic.ts +2 -2
  41. package/lib/routes/bilibili/manga-update.ts +3 -0
  42. package/lib/routes/bilibili/ranking.ts +188 -117
  43. package/lib/routes/bilibili/reply.ts +2 -0
  44. package/lib/routes/bilibili/templates/description.art +2 -0
  45. package/lib/routes/bing/daily-wallpaper.ts +5 -1
  46. package/lib/routes/bsky/posts.ts +0 -1
  47. package/lib/routes/bsky/templates/post.art +8 -1
  48. package/lib/routes/buaa/lib/space/newbook.ts +1 -1
  49. package/lib/routes/c114/namespace.ts +2 -0
  50. package/lib/routes/c114/roll.ts +71 -42
  51. package/lib/routes/cags/edu/index.ts +84 -0
  52. package/lib/routes/cags/namespace.ts +9 -0
  53. package/lib/routes/caixin/article.ts +1 -1
  54. package/lib/routes/caixin/blog.ts +2 -3
  55. package/lib/routes/caixin/category.ts +1 -1
  56. package/lib/routes/caixin/latest.ts +12 -16
  57. package/lib/routes/caixin/namespace.ts +1 -1
  58. package/lib/routes/caixin/utils-fulltext.ts +51 -0
  59. package/lib/routes/caixin/utils.ts +37 -37
  60. package/lib/routes/cara/likes.ts +1 -1
  61. package/lib/routes/cara/portfolio.ts +1 -1
  62. package/lib/routes/cara/timeline.ts +1 -1
  63. package/lib/routes/ccfa/index.ts +11 -11
  64. package/lib/routes/chub/characters.ts +1 -1
  65. package/lib/routes/cnbeta/namespace.ts +1 -1
  66. package/lib/routes/cngold/index.ts +195 -0
  67. package/lib/routes/cngold/namespace.ts +9 -0
  68. package/lib/routes/cnki/author.ts +120 -48
  69. package/lib/routes/cnki/utils.ts +4 -4
  70. package/lib/routes/coomer/artist.ts +1 -1
  71. package/lib/routes/coomer/namespace.ts +1 -1
  72. package/lib/routes/coomer/posts.ts +2 -2
  73. package/lib/routes/coomer/utils.ts +1 -1
  74. package/lib/routes/cpcaauto/index.ts +22 -22
  75. package/lib/routes/cs/zzkx.ts +1 -1
  76. package/lib/routes/csdn/blog.ts +17 -13
  77. package/lib/routes/cybersecurityventures/namespace.ts +7 -0
  78. package/lib/routes/cybersecurityventures/news.ts +121 -0
  79. package/lib/routes/cybersecurityventures/types.ts +17 -0
  80. package/lib/routes/daily/discussed.ts +22 -21
  81. package/lib/routes/daily/index.ts +14 -11
  82. package/lib/routes/daily/namespace.ts +1 -1
  83. package/lib/routes/daily/source.ts +186 -0
  84. package/lib/routes/daily/upvoted.ts +17 -17
  85. package/lib/routes/daily/user.ts +6 -23
  86. package/lib/routes/daily/utils.ts +27 -32
  87. package/lib/routes/dataguidance/index.ts +19 -30
  88. package/lib/routes/dcfever/news.ts +1 -1
  89. package/lib/routes/dcfever/reviews.ts +1 -1
  90. package/lib/routes/dcfever/trading-search.ts +1 -1
  91. package/lib/routes/dcfever/trading.ts +1 -1
  92. package/lib/routes/deeplearning/namespace.ts +3 -1
  93. package/lib/routes/deeplearning/templates/description.art +21 -0
  94. package/lib/routes/deeplearning/the-batch.ts +296 -0
  95. package/lib/routes/deepmind/blog.ts +1 -1
  96. package/lib/routes/digitalcameraworld/news.ts +1 -1
  97. package/lib/routes/discord/discord-api.ts +44 -2
  98. package/lib/routes/discord/search.ts +106 -0
  99. package/lib/routes/dn/news.ts +1 -1
  100. package/lib/routes/dockerhub/repositories.ts +42 -0
  101. package/lib/routes/dongqiudi/daily.ts +1 -1
  102. package/lib/routes/dw/namespace.ts +6 -0
  103. package/lib/routes/dw/news.ts +89 -0
  104. package/lib/routes/dw/rss.ts +62 -0
  105. package/lib/routes/dw/templates/description.art +23 -0
  106. package/lib/routes/dw/templates/liveblog.art +13 -0
  107. package/lib/routes/dw/templates/video.art +14 -0
  108. package/lib/routes/dw/utils.ts +172 -0
  109. package/lib/routes/ecnu/jwc.ts +5 -1
  110. package/lib/routes/espn/news.ts +1 -1
  111. package/lib/routes/fashionnetwork/namespace.ts +1 -1
  112. package/lib/routes/flyert/forum.ts +99 -0
  113. package/lib/routes/flyert/namespace.ts +1 -0
  114. package/lib/routes/flyert/templates/description.art +21 -0
  115. package/lib/routes/flyert/util.ts +188 -0
  116. package/lib/routes/follow/profile.ts +2 -2
  117. package/lib/routes/foresightnews/article.ts +1 -1
  118. package/lib/routes/foresightnews/column.ts +1 -1
  119. package/lib/routes/foresightnews/index.ts +3 -1
  120. package/lib/routes/foresightnews/news.ts +1 -1
  121. package/lib/routes/freecomputerbooks/index.ts +0 -10
  122. package/lib/routes/ftm/index.ts +1 -1
  123. package/lib/routes/furaffinity/art.ts +85 -0
  124. package/lib/routes/furaffinity/browse.ts +58 -0
  125. package/lib/routes/furaffinity/commissions.ts +55 -0
  126. package/lib/routes/furaffinity/home.ts +80 -0
  127. package/lib/routes/furaffinity/journal-comments.ts +64 -0
  128. package/lib/routes/furaffinity/journals.ts +56 -0
  129. package/lib/routes/furaffinity/namespace.ts +7 -0
  130. package/lib/routes/furaffinity/search.ts +72 -0
  131. package/lib/routes/furaffinity/shouts.ts +56 -0
  132. package/lib/routes/furaffinity/status.ts +58 -0
  133. package/lib/routes/furaffinity/submission-comments.ts +64 -0
  134. package/lib/{routes-deprecated/furaffinity/user.js → routes/furaffinity/user.ts} +53 -41
  135. package/lib/routes/furaffinity/watchers.ts +62 -0
  136. package/lib/routes/furaffinity/watching.ts +62 -0
  137. package/lib/routes/google/developers.ts +71 -0
  138. package/lib/routes/google/news.ts +26 -6
  139. package/lib/routes/gov/cbirc/index.ts +35 -35
  140. package/lib/routes/hamel/index.ts +81 -0
  141. package/lib/routes/hamel/namespace.ts +7 -0
  142. package/lib/routes/hellogithub/volume.ts +3 -0
  143. package/lib/routes/hket/index.ts +13 -1
  144. package/lib/routes/hostmonit/cloudflareyesv6.ts +1 -1
  145. package/lib/routes/hrbeu/sec/list.ts +80 -0
  146. package/lib/routes/hrbust/jwzx.ts +6 -0
  147. package/lib/routes/hunau/gfxy/index.ts +1 -1
  148. package/lib/routes/hunau/ied.ts +1 -1
  149. package/lib/routes/hunau/jwc.ts +1 -1
  150. package/lib/routes/hunau/xky/index.ts +1 -1
  151. package/lib/routes/hust/gs.ts +4 -3
  152. package/lib/routes/idolmaster/namespace.ts +7 -0
  153. package/lib/routes/idolmaster/news.ts +112 -0
  154. package/lib/routes/ieee/author.ts +95 -0
  155. package/lib/routes/ikea/cn/low-price.ts +2 -1
  156. package/lib/routes/imdb/chart.ts +1 -1
  157. package/lib/routes/inspirehep/author.ts +9 -1
  158. package/lib/routes/isct/namespace.ts +11 -0
  159. package/lib/routes/isct/news.ts +66 -0
  160. package/lib/routes/javtrailers/casts.ts +41 -0
  161. package/lib/routes/javtrailers/categories.ts +40 -0
  162. package/lib/routes/javtrailers/namespace.ts +7 -0
  163. package/lib/routes/javtrailers/studios.ts +39 -0
  164. package/lib/routes/javtrailers/templates/description.art +31 -0
  165. package/lib/routes/javtrailers/types.ts +59 -0
  166. package/lib/routes/javtrailers/utils.ts +48 -0
  167. package/lib/routes/jiemian/list.ts +1 -1
  168. package/lib/routes/jiuyangongshe/community.ts +1 -1
  169. package/lib/routes/jlu/phy/index.ts +55 -0
  170. package/lib/routes/joins/chinese.ts +13 -13
  171. package/lib/routes/kcna/news.ts +7 -5
  172. package/lib/routes/keep/user.ts +1 -1
  173. package/lib/routes/langchain/index.ts +74 -0
  174. package/lib/routes/langchain/namespace.ts +7 -0
  175. package/lib/routes/last-origin/namespace.ts +7 -0
  176. package/lib/routes/last-origin/news.ts +65 -0
  177. package/lib/routes/linkresearcher/index.ts +108 -46
  178. package/lib/routes/linkresearcher/namespace.ts +8 -2
  179. package/lib/routes/linkresearcher/templates/bilingual.art +7 -0
  180. package/lib/routes/linkresearcher/types.ts +103 -0
  181. package/lib/routes/liulinblog/itnews.ts +1 -1
  182. package/lib/routes/lofter/collection.ts +1 -1
  183. package/lib/routes/lofter/tag.ts +1 -1
  184. package/lib/routes/logrocket/index.ts +71 -0
  185. package/lib/routes/logrocket/namespace.ts +7 -0
  186. package/lib/routes/m-78/namespace.ts +7 -0
  187. package/lib/routes/m-78/news.ts +115 -0
  188. package/lib/routes/m-78/types.ts +13 -0
  189. package/lib/routes/mastodon/account-id.ts +1 -1
  190. package/lib/routes/mastodon/acct.ts +1 -1
  191. package/lib/routes/mastodon/timeline-local.ts +2 -2
  192. package/lib/routes/mastodon/timeline-remote.ts +2 -2
  193. package/lib/routes/mastodon/utils.ts +1 -1
  194. package/lib/routes/metacritic/index.ts +1 -1
  195. package/lib/routes/mi/utils.ts +1 -1
  196. package/lib/routes/mihoyo/bbs/official.ts +2 -1
  197. package/lib/routes/misskey/utils.ts +19 -1
  198. package/lib/routes/mittrchina/index.ts +2 -2
  199. package/lib/routes/natgeo/natgeo.ts +25 -24
  200. package/lib/routes/nbd/daily.ts +1 -1
  201. package/lib/routes/nielsberglund/index.ts +78 -0
  202. package/lib/routes/nielsberglund/namespace.ts +7 -0
  203. package/lib/routes/nytimes/rss.ts +57 -0
  204. package/lib/routes/openrice/chart.ts +68 -0
  205. package/lib/routes/openrice/templates/chart.art +9 -0
  206. package/lib/routes/openrice/voting.ts +84 -0
  207. package/lib/routes/oschina/news.ts +26 -7
  208. package/lib/routes/patreon/feed.ts +126 -0
  209. package/lib/routes/patreon/namespace.ts +7 -0
  210. package/lib/routes/patreon/templates/description.art +39 -0
  211. package/lib/routes/patreon/types.ts +387 -0
  212. package/lib/routes/pixiv/api/get-illust-detail.ts +22 -0
  213. package/lib/routes/pixiv/novel-api/content/nsfw.ts +73 -0
  214. package/lib/routes/pixiv/novel-api/content/sfw.ts +63 -0
  215. package/lib/routes/pixiv/novel-api/content/types.ts +254 -0
  216. package/lib/routes/pixiv/novel-api/content/utils.ts +133 -0
  217. package/lib/routes/pixiv/novel-api/series/nsfw.ts +84 -0
  218. package/lib/routes/pixiv/novel-api/series/sfw.ts +70 -0
  219. package/lib/routes/pixiv/novel-api/series/types.ts +94 -0
  220. package/lib/routes/pixiv/novel-api/user-novels/nsfw.ts +82 -0
  221. package/lib/routes/pixiv/novel-api/user-novels/sfw.ts +74 -0
  222. package/lib/routes/pixiv/novel-api/user-novels/types.ts +133 -0
  223. package/lib/routes/pixiv/novel-series.ts +52 -0
  224. package/lib/routes/pixiv/novels.ts +69 -44
  225. package/lib/routes/pixiv/utils.ts +3 -0
  226. package/lib/routes/plurk/anonymous.ts +1 -1
  227. package/lib/routes/plurk/hotlinks.ts +1 -1
  228. package/lib/routes/plurk/news.ts +1 -1
  229. package/lib/routes/plurk/search.ts +1 -1
  230. package/lib/routes/qstheory/index.ts +121 -0
  231. package/lib/routes/qstheory/magazine.ts +64 -0
  232. package/lib/routes/qstheory/namespace.ts +7 -0
  233. package/lib/routes/qstheory/utils.ts +25 -0
  234. package/lib/routes/ruc/ai.ts +1 -1
  235. package/lib/routes/scmp/coronavirus.ts +1 -1
  236. package/lib/routes/scu/jwc/tzgg.ts +75 -0
  237. package/lib/routes/scu/namespace.ts +7 -0
  238. package/lib/routes/scu/scupi/_utils.ts +62 -0
  239. package/lib/routes/scu/scupi/notice.ts +41 -0
  240. package/lib/routes/solidot/namespace.ts +1 -1
  241. package/lib/routes/stbu/jsjxy.ts +4 -1
  242. package/lib/routes/steam/search.ts +7 -0
  243. package/lib/routes/sycl/feeds.ts +1 -1
  244. package/lib/routes/syosetu/dev.ts +67 -0
  245. package/lib/routes/syosetu/index.ts +85 -0
  246. package/lib/routes/syosetu/namespace.ts +2 -2
  247. package/lib/routes/syosetu/ranking-isekai.ts +93 -0
  248. package/lib/routes/syosetu/ranking-r18.ts +192 -0
  249. package/lib/routes/syosetu/ranking.ts +285 -0
  250. package/lib/routes/syosetu/search.ts +161 -0
  251. package/lib/routes/syosetu/templates/description.art +73 -0
  252. package/lib/routes/syosetu/types/ranking-r18.ts +60 -0
  253. package/lib/routes/syosetu/types/ranking.ts +67 -0
  254. package/lib/routes/syosetu/types/search.ts +138 -0
  255. package/lib/routes/syosetu/utils.ts +50 -0
  256. package/lib/routes/telegram/channel.ts +31 -1
  257. package/lib/routes/telegram/scripts/get-telegram-session.mjs +16 -6
  258. package/lib/routes/telegram/stickerpack.ts +1 -1
  259. package/lib/routes/telegram/tglib/channel.ts +12 -9
  260. package/lib/routes/telegram/tglib/client.ts +13 -9
  261. package/lib/routes/test/index.ts +4 -0
  262. package/lib/routes/theblockbeats/index.ts +1 -1
  263. package/lib/routes/thegradient/index.ts +80 -0
  264. package/lib/routes/thegradient/namespace.ts +7 -0
  265. package/lib/routes/theinitium/app.ts +4 -0
  266. package/lib/routes/thepaper/channel.ts +1 -1
  267. package/lib/routes/thepaper/factpaper.ts +1 -1
  268. package/lib/routes/thepaper/featured.ts +1 -1
  269. package/lib/routes/thepaper/list.ts +1 -1
  270. package/lib/routes/thepaper/user.ts +174 -0
  271. package/lib/routes/tongji/sem/_utils.ts +65 -0
  272. package/lib/routes/tongji/sem/notice.ts +58 -0
  273. package/lib/routes/toutiao/a-bogus.ts +540 -0
  274. package/lib/routes/toutiao/namespace.ts +7 -0
  275. package/lib/routes/toutiao/templates/video.art +7 -0
  276. package/lib/routes/toutiao/types.ts +443 -0
  277. package/lib/routes/toutiao/user.ts +127 -0
  278. package/lib/routes/twitter/api/mobile-api/api.ts +8 -0
  279. package/lib/routes/twitter/api/web-api/utils.ts +21 -9
  280. package/lib/routes/twitter/namespace.ts +1 -0
  281. package/lib/routes/twitter/utils.ts +7 -1
  282. package/lib/routes/vertikal/latest.ts +73 -0
  283. package/lib/routes/vertikal/namespace.ts +7 -0
  284. package/lib/routes/vice/topic.ts +1 -1
  285. package/lib/routes/vocus/publication.ts +1 -1
  286. package/lib/routes/vocus/user.ts +1 -1
  287. package/lib/routes/wallstreetcn/calendar.ts +90 -0
  288. package/lib/routes/wallstreetcn/hot.ts +2 -2
  289. package/lib/routes/wallstreetcn/live.ts +1 -1
  290. package/lib/routes/wallstreetcn/news.ts +5 -3
  291. package/lib/routes/weibo/timeline.ts +3 -2
  292. package/lib/routes/wellcee/rent.ts +1 -1
  293. package/lib/routes/wufazhuce/namespace.ts +7 -0
  294. package/lib/routes/wufazhuce/one.ts +90 -0
  295. package/lib/routes/xiaoheihe/discount.ts +72 -28
  296. package/lib/routes/xiaohongshu/user.ts +40 -3
  297. package/lib/routes/xiaohongshu/util.ts +112 -105
  298. package/lib/routes/xsijishe/rank.ts +33 -7
  299. package/lib/routes/xueqiu/cookies.ts +13 -18
  300. package/lib/routes/yahoo/news/listid.ts +4 -1
  301. package/lib/routes/yahoo/news/provider-helper.ts +4 -1
  302. package/lib/routes/yahoo/news/provider.ts +4 -1
  303. package/lib/routes/yande/post.ts +13 -3
  304. package/lib/routes/youtube/user.ts +37 -25
  305. package/lib/routes/zhonglun/index.ts +5 -6
  306. package/lib/routes/zjut/cs/index.ts +1 -1
  307. package/lib/utils/got.ts +2 -1
  308. package/lib/utils/helpers.test.ts +13 -1
  309. package/lib/utils/helpers.ts +10 -0
  310. package/lib/utils/ofetch.ts +3 -0
  311. package/lib/utils/request-rewriter/fetch.test.ts +94 -0
  312. package/lib/utils/request-rewriter/fetch.ts +14 -1
  313. package/lib/views/error.tsx +1 -1
  314. package/package.json +40 -37
  315. package/lib/routes/78dm/templates/image.art +0 -1
  316. package/lib/routes/deeplearning/thebatch.ts +0 -74
  317. package/lib/routes/syosetu/chapter.ts +0 -87
  318. package/lib/routes/xiaohongshu/notes.ts +0 -39
  319. package/lib/routes-deprecated/furaffinity/browse.js +0 -44
  320. package/lib/routes-deprecated/furaffinity/commissions.js +0 -39
  321. package/lib/routes-deprecated/furaffinity/favorites.js +0 -56
  322. package/lib/routes-deprecated/furaffinity/gallery.js +0 -56
  323. package/lib/routes-deprecated/furaffinity/home.js +0 -72
  324. package/lib/routes-deprecated/furaffinity/journal-comments.js +0 -50
  325. package/lib/routes-deprecated/furaffinity/journals.js +0 -49
  326. package/lib/routes-deprecated/furaffinity/scraps.js +0 -56
  327. package/lib/routes-deprecated/furaffinity/search.js +0 -56
  328. package/lib/routes-deprecated/furaffinity/shouts.js +0 -40
  329. package/lib/routes-deprecated/furaffinity/status.js +0 -38
  330. package/lib/routes-deprecated/furaffinity/submission-comments.js +0 -50
  331. package/lib/routes-deprecated/furaffinity/watchers.js +0 -47
  332. package/lib/routes-deprecated/furaffinity/watching.js +0 -47
  333. package/lib/routes-deprecated/ieee/author.js +0 -30
  334. package/lib/routes-deprecated/qstheory/index.js +0 -122
@@ -0,0 +1,64 @@
1
+ import { Route } from '@/types';
2
+
3
+ import ofetch from '@/utils/ofetch';
4
+ import * as cheerio from 'cheerio';
5
+ import cache from '@/utils/cache';
6
+ import { baseUrl, getItem } from './utils';
7
+
8
+ export const route: Route = {
9
+ path: '/magazine/:magazine',
10
+ categories: ['traditional-media'],
11
+ example: '/qstheory/magazine/qs',
12
+ parameters: { magazine: '刊物,`qs` 为求是,`hqwglist` 为红旗文稿' },
13
+ radar: [
14
+ {
15
+ source: ['www.qstheory.cn/:magazine/mulu.htm'],
16
+ },
17
+ ],
18
+ name: '在线读刊',
19
+ maintainers: ['TonyRL'],
20
+ handler,
21
+ };
22
+
23
+ async function handler(ctx) {
24
+ const { magazine } = ctx.req.param();
25
+
26
+ const link = `${baseUrl}/${magazine}/mulu.htm`;
27
+ const yearResponse = await ofetch(link);
28
+
29
+ const $ = cheerio.load(yearResponse);
30
+
31
+ const yearList = $('.booktitle a')
32
+ .toArray()
33
+ .map((item) => {
34
+ const $item = $(item);
35
+ return {
36
+ title: $item.text(),
37
+ link: $item.attr('href')!,
38
+ };
39
+ });
40
+
41
+ const issueResponse = await ofetch(yearList[0].link);
42
+ const $$ = cheerio.load(issueResponse);
43
+
44
+ const list = $$('.highlight span a')
45
+ .toArray()
46
+ .map((item) => {
47
+ const $item = $$(item);
48
+ return {
49
+ title: $item.text(),
50
+ link: $item.attr('href')!,
51
+ };
52
+ })
53
+ .toReversed()
54
+ .filter((item) => item.title);
55
+
56
+ const items = await Promise.all(list.map((item) => cache.tryGet(item.link, () => getItem(item))));
57
+
58
+ return {
59
+ title: $('head title').text(),
60
+ link,
61
+ image: new URL($('.book img').attr('src')!, link).href,
62
+ item: items,
63
+ };
64
+ }
@@ -0,0 +1,7 @@
1
+ import type { Namespace } from '@/types';
2
+
3
+ export const namespace: Namespace = {
4
+ name: '求是网',
5
+ url: 'www.qstheory.cn',
6
+ lang: 'zh-CN',
7
+ };
@@ -0,0 +1,25 @@
1
+ import ofetch from '@/utils/ofetch';
2
+ import * as cheerio from 'cheerio';
3
+ import { parseDate } from '@/utils/parse-date';
4
+
5
+ export const baseUrl = 'http://www.qstheory.cn';
6
+
7
+ export const getItem = async (item) => {
8
+ const response = await ofetch(item.link);
9
+ const $ = cheerio.load(response);
10
+
11
+ $('.fs-text, .fs-pinglun, .hidden-xs').remove();
12
+
13
+ item.author = $('.appellation').text();
14
+ item.description = $('.highlight, .text').html() || $('.content').html();
15
+ item.pubDate = parseDate(
16
+ $('.puttime_mobi, .pubtime, .headtitle span')
17
+ .text()
18
+ .trim()
19
+ .replace('发表于', '')
20
+ .replaceAll(/(年|月)/g, '-')
21
+ .replace('日', '')
22
+ );
23
+
24
+ return item;
25
+ };
@@ -83,5 +83,5 @@ export const route: Route = {
83
83
  分类字段处填写的是对应中国人民大学高瓴人工智能学院分类页网址中介于 **\`http://ai.ruc.edu.cn/\`** 和 **/index.htm** 中间的一段,并将其中的 \`/\` 修改为 \`-\`。
84
84
 
85
85
  如 [中国人民大学高瓴人工智能学院 - 新闻公告 - 学院新闻](http://ai.ruc.edu.cn/newslist/newsdetail/index.htm) 的网址为 \`http://ai.ruc.edu.cn/newslist/newsdetail/index.htm\` 其中介于 **\`http://ai.ruc.edu.cn/\`** 和 **/index.htm** 中间的一段为 \`newslist/newsdetail\`。随后,并将其中的 \`/\` 修改为 \`-\`,可以得到 \`newslist-newsdetail\`。所以最终我们的路由为 [\`/ruc/ai/newslist-newsdetail\`](https://rsshub.app/ruc/ai/newslist-newsdetail)
86
- :::`,
86
+ :::`,
87
87
  };
@@ -18,5 +18,5 @@ export const route: Route = {
18
18
  };
19
19
 
20
20
  function handler(ctx) {
21
- ctx.redirect('/scmp/topics/coronavirus-pandemic-all-stories');
21
+ ctx.set('redirect', '/scmp/topics/coronavirus-pandemic-all-stories');
22
22
  }
@@ -0,0 +1,75 @@
1
+ import { Route } from '@/types';
2
+ import cache from '@/utils/cache';
3
+ import got from '@/utils/got';
4
+ import { parseDate } from '@/utils/parse-date';
5
+ import { load } from 'cheerio'; // 可以使用类似 jQuery 的 API HTML 解析器
6
+
7
+ const baseUrl = 'https://jwc.scu.edu.cn/tzgg.htm';
8
+ const baseIndexUrl = 'https://jwc.scu.edu.cn/';
9
+
10
+ export const route: Route = {
11
+ path: '/jwc',
12
+ categories: ['university'],
13
+ example: '/scu/jwc',
14
+ features: {
15
+ requireConfig: false,
16
+ requirePuppeteer: false,
17
+ antiCrawler: false,
18
+ supportBT: false,
19
+ supportPodcast: false,
20
+ supportScihub: false,
21
+ },
22
+ radar: [
23
+ {
24
+ source: ['jwc.scu.edu.cn'],
25
+ target: '/jwc',
26
+ },
27
+ ],
28
+ name: '教务处通知公告',
29
+ maintainers: ['Kyle-You'],
30
+ handler,
31
+ };
32
+
33
+ async function handler() {
34
+ const { data: response } = await got.get(baseUrl);
35
+ const $ = load(response);
36
+
37
+ const links: string[] = $('.tz-list ul li a')
38
+ .toArray()
39
+ .map((item) => {
40
+ item = $(item);
41
+ const link: string = item.attr('href');
42
+ return link.startsWith('http') ? link : baseIndexUrl + link;
43
+ });
44
+
45
+ const items = await Promise.all(
46
+ links.map((link) =>
47
+ cache.tryGet(link, async () => {
48
+ const { data: info } = await got.get(link);
49
+ const $ = load(info);
50
+
51
+ // 获取head里的meta标签
52
+ const title = $('head meta[name="ArticleTitle"]').attr('content') ?? '';
53
+ const pubDate = parseDate($('head meta[name="PubDate"]').attr('content') ?? '');
54
+ const description = $('.v_news_content').html();
55
+ return {
56
+ title,
57
+ link,
58
+ pubDate,
59
+ description,
60
+ };
61
+ })
62
+ )
63
+ );
64
+
65
+ return {
66
+ title: '四川大学教务处',
67
+ link: baseIndexUrl,
68
+ description: '四川大学教务处通知公告',
69
+ item: items,
70
+ language: 'zh-cn',
71
+ image: 'https://www.scu.edu.cn/__local/B/67/25/DFAF986CCD6529E52D7830F180D_C37C7DEE_4340.png',
72
+ logo: 'https://www.scu.edu.cn/__local/B/67/25/DFAF986CCD6529E52D7830F180D_C37C7DEE_4340.png',
73
+ icon: 'https://www.scu.edu.cn/__local/B/67/25/DFAF986CCD6529E52D7830F180D_C37C7DEE_4340.png',
74
+ };
75
+ }
@@ -0,0 +1,7 @@
1
+ import type { Namespace } from '@/types';
2
+
3
+ export const namespace: Namespace = {
4
+ name: '四川大学',
5
+ url: 'www.scu.edu.cn',
6
+ lang: 'zh-CN',
7
+ };
@@ -0,0 +1,62 @@
1
+ import got from '@/utils/got';
2
+ import { load } from 'cheerio';
3
+ import { parseDate } from '@/utils/parse-date';
4
+ import { config } from '@/config';
5
+
6
+ export async function getNotifList() {
7
+ try {
8
+ const response = await got.get('https://scupi.scu.edu.cn/activities/notice', {
9
+ headers: {
10
+ 'User-Agent': config.ua,
11
+ },
12
+ });
13
+ const html = response.body;
14
+ const $ = load(html);
15
+
16
+ const listElement = $('body > div.wrapper > main > section > div > div > div.news > div > ul');
17
+ return listElement
18
+ .find('article')
19
+ .toArray()
20
+ .map((articleElement) => {
21
+ const titleElement = $(articleElement).find('li > div > div.news-text > h4 > a');
22
+ const timeElement = $(articleElement).find('li > div > div.news-text > span');
23
+ const imageElement = $(articleElement).find('li > div > div.news-img > a > img');
24
+
25
+ const link = titleElement.attr('href');
26
+ const title = titleElement.attr('title');
27
+ const pubDate = timeElement.text().trim();
28
+
29
+ return {
30
+ title,
31
+ link,
32
+ itunes_item_image: imageElement.attr('src'),
33
+ pubDate: parseDate(pubDate, 'YYYY-MM-DD'),
34
+ };
35
+ });
36
+ } catch {
37
+ // console.error(error);
38
+ }
39
+
40
+ return [];
41
+ }
42
+
43
+ export async function getArticle(item) {
44
+ try {
45
+ const response = await got.get(item.link, {
46
+ headers: {
47
+ 'User-Agent': config.ua,
48
+ },
49
+ });
50
+ const html = response.body;
51
+ const $ = load(html);
52
+ const articleContentElement = $('body > div > main > section > div > div > div.post-content-contaier > div');
53
+ const content = articleContentElement.html();
54
+
55
+ item.description = content;
56
+ return item;
57
+ } catch {
58
+ // console.error(error);
59
+ }
60
+
61
+ return item;
62
+ }
@@ -0,0 +1,41 @@
1
+ // Warning: The author still knows nothing about javascript!
2
+
3
+ import { getNotifList, getArticle } from './_utils';
4
+ import { Route } from '@/types';
5
+ import cache from '@/utils/cache';
6
+
7
+ export const route: Route = {
8
+ path: '/scupi',
9
+ categories: ['university'],
10
+ example: '/scu/scupi',
11
+ parameters: {},
12
+ features: {
13
+ requireConfig: false,
14
+ requirePuppeteer: false,
15
+ antiCrawler: false,
16
+ supportBT: false,
17
+ supportPodcast: false,
18
+ supportScihub: false,
19
+ },
20
+ name: '匹兹堡学院通知',
21
+ maintainers: ['sitdownkevin'],
22
+ url: 'scupi.scu.edu.cn/activities/notice',
23
+ handler,
24
+ description: ``,
25
+ };
26
+
27
+ async function handler() {
28
+ // feed the data to rss
29
+ const items = await getNotifList();
30
+ const itemsWithContent = await Promise.all(items.map((item) => cache.tryGet(item.link, () => getArticle(item))));
31
+
32
+ return {
33
+ title: '四川大学匹兹堡学院',
34
+ description: '四川大学匹兹堡学院官网通知',
35
+ language: 'zh-cn',
36
+ image: 'https://upload.wikimedia.org/wikipedia/zh/4/45/Sichuan_University_logo.svg',
37
+ logo: 'https://upload.wikimedia.org/wikipedia/zh/4/45/Sichuan_University_logo.svg',
38
+ link: 'https://scupi.scu.edu.cn/',
39
+ item: itemsWithContent,
40
+ };
41
+ }
@@ -3,5 +3,5 @@ import type { Namespace } from '@/types';
3
3
  export const namespace: Namespace = {
4
4
  name: 'Solidot',
5
5
  url: 'www.solidot.org',
6
- lang: 'en',
6
+ lang: 'zh-CN',
7
7
  };
@@ -22,7 +22,10 @@ export const route: Route = {
22
22
  },
23
23
  radar: [
24
24
  {
25
- source: ['jsjxy.stbu.edu.cn/news', 'jsjxy.stbu.edu.cn', 'stbu.edu.cn'],
25
+ source: ['jsjxy.stbu.edu.cn/news', 'jsjxy.stbu.edu.cn'],
26
+ },
27
+ {
28
+ source: ['stbu.edu.cn'],
26
29
  },
27
30
  ],
28
31
  name: '计算机学院 - 通知公告',
@@ -34,6 +34,8 @@ async function handler(ctx) {
34
34
  const isBundle = !!$el.attr('data-ds-bundle-data');
35
35
  const isDiscounted = $el.find('.discount_original_price').length > 0;
36
36
  const hasReview = $el.find('.search_review_summary').length > 0;
37
+ const appID: string | undefined = $el.attr('data-ds-appid');
38
+
37
39
  let desc = '';
38
40
  if (isBundle) {
39
41
  const bundle = JSON.parse($el.attr('data-ds-bundle-data'));
@@ -57,6 +59,11 @@ async function handler(ctx) {
57
59
  title: $el.find('span.title').text(),
58
60
  link: $el.attr('href'),
59
61
  description: desc.replaceAll('\n', '<br>'),
62
+ media: {
63
+ thumbnail: {
64
+ url: `https://shared.akamai.steamstatic.com/store_item_assets/steam/apps/${appID}/header.jpg`,
65
+ },
66
+ },
60
67
  };
61
68
  })
62
69
  .filter((it) => it.title),
@@ -5,7 +5,7 @@ import { parseDate } from '@/utils/parse-date';
5
5
  export const route: Route = {
6
6
  path: '/:feed?',
7
7
  categories: ['programming'],
8
- example: '/sycltech/news',
8
+ example: '/sycl/news',
9
9
  parameters: { feed: 'Feed source, defaults to news, references https://feeds.sycl.tech/' },
10
10
  features: {
11
11
  requireConfig: false,
@@ -0,0 +1,67 @@
1
+ import { Data, Route } from '@/types';
2
+ import { load } from 'cheerio';
3
+ import { parseDate } from '@/utils/parse-date';
4
+ import ofetch from '@/utils/ofetch';
5
+
6
+ export const route: Route = {
7
+ path: '/dev',
8
+ categories: ['program-update'],
9
+ example: '/syosetu/dev',
10
+ features: {
11
+ requireConfig: false,
12
+ requirePuppeteer: false,
13
+ antiCrawler: false,
14
+ supportBT: false,
15
+ supportPodcast: false,
16
+ supportScihub: false,
17
+ },
18
+ name: 'なろう小説 API の更新履歴',
19
+ url: 'dev.syosetu.com',
20
+ maintainers: ['SnowAgar25'],
21
+ handler,
22
+ radar: [
23
+ {
24
+ title: 'なろう小説 API の更新履歴',
25
+ source: ['dev.syosetu.com'],
26
+ target: '/dev',
27
+ },
28
+ ],
29
+ };
30
+
31
+ async function handler(): Promise<Data> {
32
+ const url = 'https://dev.syosetu.com';
33
+
34
+ const data = await ofetch(url);
35
+ const $ = load(data);
36
+
37
+ const logContainer = $('.c-log');
38
+
39
+ const dates = logContainer
40
+ .find('dt')
41
+ .toArray()
42
+ .map((element) => $(element).text().trim());
43
+
44
+ const contents = logContainer
45
+ .find('dd')
46
+ .toArray()
47
+ .map((element) => $(element).text().trim());
48
+
49
+ const updates = dates
50
+ .map((date, index) => ({
51
+ date,
52
+ content: contents[index]?.replace(/\n/g, '<br>') ?? '',
53
+ }))
54
+ .filter((update) => update.content);
55
+
56
+ return {
57
+ title: 'なろうデベロッパー - なろう小説 API の更新履歴',
58
+ link: url,
59
+ language: 'ja',
60
+ item: updates.map((update) => ({
61
+ title: update.date,
62
+ description: update.content,
63
+ pubDate: parseDate(update.date.replace('/', '-')),
64
+ guid: `syosetu:dev:${update.date}`,
65
+ })),
66
+ };
67
+ }
@@ -0,0 +1,85 @@
1
+ import { Route, Data, DataItem } from '@/types';
2
+ import { fetchNovelInfo, fetchChapterContent } from './utils';
3
+ import { Context } from 'hono';
4
+ import { NovelType } from 'narou';
5
+
6
+ export const route: Route = {
7
+ path: '/:ncode',
8
+ categories: ['reading'],
9
+ example: '/syosetu/n9292ii',
10
+ parameters: {
11
+ ncode: 'Novel code, can be found in URL',
12
+ },
13
+ features: {
14
+ requireConfig: false,
15
+ requirePuppeteer: false,
16
+ antiCrawler: false,
17
+ supportBT: false,
18
+ supportPodcast: false,
19
+ supportScihub: false,
20
+ },
21
+ name: 'Novel Updates',
22
+ maintainers: ['eternasuno', 'SnowAgar25'],
23
+ handler,
24
+ radar: [
25
+ {
26
+ title: 'Novel Updates',
27
+ source: ['ncode.syosetu.com/:ncode', 'ncode.syosetu.com/:ncode/:chapter'],
28
+ target: '/:ncode',
29
+ },
30
+ {
31
+ title: 'Novel Updates',
32
+ source: ['novel18.syosetu.com/:ncode', 'novel18.syosetu.com/:ncode/:chapter'],
33
+ target: '/:ncode',
34
+ },
35
+ ],
36
+ };
37
+
38
+ async function handler(ctx: Context): Promise<Data> {
39
+ const { ncode } = ctx.req.param();
40
+ const limit = Math.min(Number(ctx.req.query('limit') ?? 5), 20);
41
+
42
+ const { baseUrl, novel } = await fetchNovelInfo(ncode);
43
+ novel.story = novel.story.replaceAll('\n', '<br>') || '';
44
+
45
+ // Tanpen = Short
46
+ if (novel.noveltype === NovelType.Tanpen) {
47
+ const chapterUrl = `${baseUrl}/${ncode}`;
48
+ const item = await fetchChapterContent(chapterUrl);
49
+
50
+ // Shorts are updated rather than having new chapters
51
+ // Use novelupdated_at as pubDate since RSS 2.0 doesn't have updated field
52
+ item.pubDate = novel.novelupdated_at;
53
+
54
+ return {
55
+ title: novel.title,
56
+ description: novel.story,
57
+ link: chapterUrl,
58
+ item: [item] as DataItem[],
59
+ language: 'ja',
60
+ };
61
+ }
62
+
63
+ // Rensai = Series
64
+ // if (novel.noveltype === NovelType.Rensai)
65
+ const totalChapters = novel.general_all_no ?? 1;
66
+ const startChapter = Math.max(totalChapters - limit + 1, 1);
67
+
68
+ const items = await Promise.all(
69
+ Array.from({ length: Math.min(limit, totalChapters) }, async (_, index) => {
70
+ const chapterNumber = startChapter + index;
71
+ const chapterUrl = `${baseUrl}/${ncode}/${chapterNumber}`;
72
+
73
+ const item = await fetchChapterContent(chapterUrl, chapterNumber);
74
+ return item;
75
+ }).reverse()
76
+ );
77
+
78
+ return {
79
+ title: novel.title,
80
+ description: novel.story,
81
+ link: `${baseUrl}/${ncode}`,
82
+ item: items as DataItem[],
83
+ language: 'ja',
84
+ };
85
+ }
@@ -1,7 +1,7 @@
1
1
  import type { Namespace } from '@/types';
2
2
 
3
3
  export const namespace: Namespace = {
4
- name: 'syosetu',
5
- url: 'ncode.syosetu.com',
4
+ name: 'Syosetu',
5
+ url: 'syosetu.com',
6
6
  lang: 'ja',
7
7
  };
@@ -0,0 +1,93 @@
1
+ import { Data, DataItem } from '@/types';
2
+ import { NarouNovelFetch, SearchBuilder, SearchParams, BigGenre } from 'narou';
3
+ import { art } from '@/utils/render';
4
+ import path from 'node:path';
5
+ import { getCurrentPath } from '@/utils/helpers';
6
+ import InvalidParameterError from '@/errors/types/invalid-parameter';
7
+ import { Join } from 'narou/util/type';
8
+ import { RankingPeriod, NovelType, periodToJapanese, novelTypeToJapanese, periodToOrder, periodToPointField, IsekaiCategory, isekaiCategoryToJapanese } from './types/ranking';
9
+
10
+ const __dirname = getCurrentPath(import.meta.url);
11
+
12
+ export function parseIsekaiRankingType(type: string): { period: RankingPeriod; category: IsekaiCategory; novelType: NovelType } {
13
+ const [periodStr, categoryStr, novelTypeStr = NovelType.TOTAL] = type.split('_');
14
+
15
+ const period = periodStr as RankingPeriod;
16
+ const category = categoryStr as IsekaiCategory;
17
+ const novelType = novelTypeStr as NovelType;
18
+
19
+ const isValid = [Object.values(RankingPeriod).includes(period), Object.values(IsekaiCategory).includes(category), Object.values(NovelType).includes(novelType)].every(Boolean);
20
+
21
+ if (!isValid) {
22
+ throw new InvalidParameterError(`Invalid isekai ranking type: ${type}`);
23
+ }
24
+
25
+ return { period, category, novelType };
26
+ }
27
+
28
+ function getIsekaiSearchParams(period, category, novelType, limit): SearchParams {
29
+ const searchParams: SearchParams = {
30
+ order: periodToOrder[period],
31
+ gzip: 5,
32
+ // Request 20% more items to compensate for potential duplicates between tensei/tenni
33
+ lim: Math.ceil((limit / 2) * 1.2),
34
+ };
35
+
36
+ if (novelType !== NovelType.TOTAL) {
37
+ searchParams.type = novelType;
38
+ }
39
+
40
+ switch (category) {
41
+ case IsekaiCategory.RENAI:
42
+ searchParams.biggenre = BigGenre.Renai;
43
+ break;
44
+ case IsekaiCategory.FANTASY:
45
+ searchParams.biggenre = BigGenre.Fantasy;
46
+ break;
47
+ case IsekaiCategory.OTHER:
48
+ searchParams.biggenre = `${BigGenre.Bungei}-${BigGenre.Sf}-${BigGenre.Sonota}` as Join<BigGenre>;
49
+ break;
50
+ default:
51
+ throw new InvalidParameterError(`Invalid Isekai category: ${category}`);
52
+ }
53
+
54
+ return searchParams;
55
+ }
56
+
57
+ export async function handleIsekaiRanking(type: string, limit: number): Promise<Data> {
58
+ const { period, category, novelType } = parseIsekaiRankingType(type);
59
+ const rankingUrl = `https://yomou.syosetu.com/rank/isekailist/type/${type}`;
60
+ const rankingTitle = `[${periodToJapanese[period]}] 異世界転生/転移${isekaiCategoryToJapanese[category]}ランキング - ${novelTypeToJapanese[novelType]} BEST${limit}`;
61
+
62
+ const searchParams = getIsekaiSearchParams(period, category, novelType, limit);
63
+ const api = new NarouNovelFetch();
64
+
65
+ const [tenseiResult, tenniResult] = await Promise.all([new SearchBuilder({ ...searchParams, istensei: 1 }, api).execute(), new SearchBuilder({ ...searchParams, istenni: 1 }, api).execute()]);
66
+
67
+ const combinedNovels = [...tenseiResult.values, ...tenniResult.values];
68
+ const uniqueNovels = [...new Map(combinedNovels.map((novel) => [novel.ncode, novel])).values()];
69
+
70
+ const pointField = periodToPointField[period];
71
+ if (!pointField) {
72
+ throw new InvalidParameterError(`Invalid period: ${period}`);
73
+ }
74
+
75
+ const items = uniqueNovels
76
+ .sort((a, b) => (b[pointField] || 0) - (a[pointField] || 0))
77
+ .map((novel, index) => ({
78
+ title: `#${index + 1} ${novel.title}`,
79
+ link: `https://ncode.syosetu.com/${String(novel.ncode).toLowerCase()}`,
80
+ description: art(path.join(__dirname, 'templates', 'description.art'), {
81
+ novel,
82
+ }),
83
+ author: novel.writer,
84
+ category: novel.keyword.split(/[\s/\uFF0F]/).filter(Boolean),
85
+ }));
86
+
87
+ return {
88
+ title: `小説家になろう - ${rankingTitle}`,
89
+ link: rankingUrl,
90
+ item: items.slice(0, limit) as DataItem[],
91
+ language: 'ja',
92
+ };
93
+ }