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,254 @@
1
+ export interface NovelContent {
2
+ id: string;
3
+ title: string;
4
+ description: string;
5
+ content: string;
6
+
7
+ userId: string;
8
+ userName: string | null;
9
+
10
+ bookmarkCount: number;
11
+ viewCount: number;
12
+ likeCount: number;
13
+
14
+ createDate: Date;
15
+ updateDate: Date | null;
16
+
17
+ tags: string[];
18
+
19
+ coverUrl: string;
20
+ images: Record<string, string>;
21
+
22
+ seriesId: string | null;
23
+ seriesTitle: string | null;
24
+ }
25
+
26
+ export interface SFWNovelDetail {
27
+ error: boolean;
28
+ message: string;
29
+ body: {
30
+ bookmarkCount: number;
31
+ commentCount: number;
32
+ markerCount: number;
33
+ createDate: string;
34
+ uploadDate: string;
35
+ description: string;
36
+ id: string;
37
+ title: string;
38
+ likeCount: number;
39
+ pageCount: number;
40
+ userId: string;
41
+ userName: string;
42
+ viewCount: number;
43
+ isOriginal: boolean;
44
+ isBungei: boolean;
45
+ xRestrict: number;
46
+ restrict: number;
47
+ content: string;
48
+ coverUrl: string;
49
+ suggestedSettings: {
50
+ viewMode: number;
51
+ themeBackground: number;
52
+ themeSize: null;
53
+ themeSpacing: null;
54
+ };
55
+ isBookmarkable: boolean;
56
+ bookmarkData: null;
57
+ likeData: boolean;
58
+ pollData: null;
59
+ marker: null;
60
+ tags: {
61
+ authorId: string;
62
+ isLocked: boolean;
63
+ tags: Array<{
64
+ tag: string;
65
+ locked: boolean;
66
+ deletable: boolean;
67
+ userId: string;
68
+ userName: string;
69
+ }>;
70
+ writable: boolean;
71
+ };
72
+ seriesNavData: {
73
+ seriesType: string;
74
+ seriesId: number;
75
+ title: string;
76
+ isConcluded: boolean;
77
+ isReplaceable: boolean;
78
+ isWatched: boolean;
79
+ isNotifying: boolean;
80
+ order: number;
81
+ next: {
82
+ title: string;
83
+ order: number;
84
+ id: string;
85
+ available: boolean;
86
+ } | null;
87
+ prev: null;
88
+ } | null;
89
+ descriptionBoothId: null;
90
+ descriptionYoutubeId: null;
91
+ comicPromotion: null;
92
+ fanboxPromotion: null;
93
+ contestBanners: any[];
94
+ contestData: null;
95
+ request: null;
96
+ imageResponseOutData: any[];
97
+ imageResponseData: any[];
98
+ imageResponseCount: number;
99
+ userNovels: {
100
+ [key: string]: {
101
+ id: string;
102
+ title: string;
103
+ genre: string;
104
+ xRestrict: number;
105
+ restrict: number;
106
+ url: string;
107
+ tags: string[];
108
+ userId: string;
109
+ userName: string;
110
+ profileImageUrl: string;
111
+ textCount: number;
112
+ wordCount: number;
113
+ readingTime: number;
114
+ useWordCount: boolean;
115
+ description: string;
116
+ isBookmarkable: boolean;
117
+ bookmarkData: null;
118
+ bookmarkCount: number | null;
119
+ isOriginal: boolean;
120
+ marker: null;
121
+ titleCaptionTranslation: {
122
+ workTitle: null;
123
+ workCaption: null;
124
+ };
125
+ createDate: string;
126
+ updateDate: string;
127
+ isMasked: boolean;
128
+ aiType: number;
129
+ seriesId?: string;
130
+ seriesTitle?: string;
131
+ isUnlisted: boolean;
132
+ } | null;
133
+ };
134
+ hasGlossary: boolean;
135
+ zoneConfig: {
136
+ [key: string]: {
137
+ url: string;
138
+ };
139
+ };
140
+ extraData: {
141
+ meta: {
142
+ title: string;
143
+ description: string;
144
+ canonical: string;
145
+ descriptionHeader: string;
146
+ ogp: {
147
+ description: string;
148
+ image: string;
149
+ title: string;
150
+ type: string;
151
+ };
152
+ twitter: {
153
+ description: string;
154
+ image: string;
155
+ title: string;
156
+ card: string;
157
+ };
158
+ };
159
+ };
160
+ titleCaptionTranslation: {
161
+ workTitle: null;
162
+ workCaption: null;
163
+ };
164
+ isUnlisted: boolean;
165
+ language: string;
166
+ textEmbeddedImages: {
167
+ [key: string]: {
168
+ novelImageId: string;
169
+ sl: string;
170
+ urls: {
171
+ '240mw': string;
172
+ '480mw': string;
173
+ '1200x1200': string;
174
+ '128x128': string;
175
+ original: string;
176
+ };
177
+ };
178
+ };
179
+ commentOff: number;
180
+ characterCount: number;
181
+ wordCount: number;
182
+ useWordCount: boolean;
183
+ readingTime: number;
184
+ genre: string;
185
+ aiType: number;
186
+ noLoginData: {
187
+ breadcrumbs: {
188
+ successor: any[];
189
+ current: {
190
+ ja: string;
191
+ };
192
+ };
193
+ zengoWorkData: {
194
+ nextWork: {
195
+ id: string;
196
+ title: string;
197
+ } | null;
198
+ prevWork: {
199
+ id: string;
200
+ title: string;
201
+ } | null;
202
+ };
203
+ };
204
+ };
205
+ }
206
+
207
+ export interface NSFWNovelDetail {
208
+ id: string;
209
+ title: string;
210
+ seriesId: string | null;
211
+ seriesTitle: string | null;
212
+ seriesIsWatched: boolean | null;
213
+ userId: string;
214
+ coverUrl: string;
215
+ tags: string[];
216
+ caption: string;
217
+ cdate: string;
218
+ rating: {
219
+ like: number;
220
+ bookmark: number;
221
+ view: number;
222
+ };
223
+ text: string;
224
+ marker: null;
225
+ illusts: string[];
226
+ images: {
227
+ [key: string]: {
228
+ novelImageId: string;
229
+ sl: string;
230
+ urls: {
231
+ '240mw': string;
232
+ '480mw': string;
233
+ '1200x1200': string;
234
+ '128x128': string;
235
+ original: string;
236
+ };
237
+ };
238
+ };
239
+ seriesNavigation: {
240
+ nextNovel: null;
241
+ prevNovel: {
242
+ id: number;
243
+ viewable: boolean;
244
+ contentOrder: string;
245
+ title: string;
246
+ coverUrl: string;
247
+ viewableMessage: null;
248
+ } | null;
249
+ } | null;
250
+ glossaryItems: string[];
251
+ replaceableItemIds: string[];
252
+ aiType: number;
253
+ isOriginal: boolean;
254
+ }
@@ -0,0 +1,133 @@
1
+ import { load } from 'cheerio';
2
+ import getIllustDetail from '../../api/get-illust-detail';
3
+ import pixivUtils from '../../utils';
4
+
5
+ export function convertPixivProtocolExtended(caption: string): string {
6
+ const protocolMap = new Map([
7
+ [/pixiv:\/\/novels\/(\d+)/g, 'https://www.pixiv.net/novel/show.php?id=$1'],
8
+ [/pixiv:\/\/illusts\/(\d+)/g, 'https://www.pixiv.net/artworks/$1'],
9
+ [/pixiv:\/\/users\/(\d+)/g, 'https://www.pixiv.net/users/$1'],
10
+ [/pixiv:\/\/novel\/series\/(\d+)/g, 'https://www.pixiv.net/novel/series/$1'],
11
+ ]);
12
+
13
+ let convertedText = caption;
14
+ for (const [pattern, replacement] of protocolMap) {
15
+ convertedText = convertedText.replace(pattern, replacement);
16
+ }
17
+ return convertedText;
18
+ }
19
+
20
+ // docs: https://www.pixiv.help/hc/ja/articles/235584168-小説作品の本文内に使える特殊タグとは
21
+ export async function parseNovelContent(content: string, images: Record<string, string>, token?: string): Promise<string> {
22
+ try {
23
+ // 如果有 token,處理 pixiv 圖片引用
24
+ // If token exists, process pixiv image references
25
+ if (token) {
26
+ const imageMatches = [...content.matchAll(/\[pixivimage:(\d+)(?:-(\d+))?\]/g)];
27
+ const imageIdToUrl = new Map<string, string>();
28
+
29
+ // 批量獲取圖片資訊
30
+ // Batch fetch image information
31
+ await Promise.all(
32
+ imageMatches.map(async ([, illustId, pageNum]) => {
33
+ if (!illustId) {
34
+ return;
35
+ }
36
+
37
+ try {
38
+ const illust = (await getIllustDetail(illustId, token)).data.illust;
39
+ const pixivimages = pixivUtils.getImgs(illust).map((img) => img.match(/src="([^"]+)"/)?.[1] || '');
40
+
41
+ const imageUrl = pixivimages[Number(pageNum) || 0];
42
+ if (imageUrl) {
43
+ imageIdToUrl.set(pageNum ? `${illustId}-${pageNum}` : illustId, imageUrl);
44
+ }
45
+ } catch (error) {
46
+ // 記錄錯誤但不中斷處理
47
+ // Log error but don't interrupt processing
48
+ logger.warn(`Failed to fetch illust detail for ID ${illustId}: ${error instanceof Error ? error.message : String(error)}`);
49
+ }
50
+ })
51
+ );
52
+
53
+ // 替換 pixiv 圖片引用為 img 標籤
54
+ // Replace pixiv image references with img tags
55
+ content = content.replaceAll(/\[pixivimage:(\d+)(?:-(\d+))?\]/g, (match, illustId, pageNum) => {
56
+ const key = pageNum ? `${illustId}-${pageNum}` : illustId;
57
+ const imageUrl = imageIdToUrl.get(key);
58
+ return imageUrl ? `<img src="${imageUrl}" alt="pixiv illustration ${illustId}${pageNum ? ` page ${pageNum}` : ''}">` : match;
59
+ });
60
+ } else {
61
+ /*
62
+ * 處理 get-novels-sfw 的情況
63
+ * 當沒有 PIXIV_REFRESHTOKEN 時,將 [pixivimage:(\d+)] 格式轉換為 artwork 連結
64
+ * 因無法獲取 Pixiv 作品詳情,改為提供直接連結到原始作品頁面
65
+ *
66
+ * Handle get-novels-sfw case
67
+ * When PIXIV_REFRESHTOKEN is not available, convert [pixivimage:(\d+)] format to artwork link
68
+ * Provide direct link to original artwork page since artwork details cannot be retrieved
69
+ */
70
+ content = content.replaceAll(/\[pixivimage:(\d+)(?:-(\d+))?\]/g, (_, illustId) => `<a href="https://www.pixiv.net/artworks/${illustId}" target="_blank" rel="noopener noreferrer">Pixiv Artwork #${illustId}</a>`);
71
+ }
72
+
73
+ // 處理作者上傳的圖片
74
+ // Process author uploaded images
75
+ content = content.replaceAll(/\[uploadedimage:(\d+)\]/g, (match, imageId) => {
76
+ if (images[imageId]) {
77
+ return `<img src="${pixivUtils.getProxiedImageUrl(images[imageId])}" alt="novel illustration ${imageId}">`;
78
+ }
79
+ return match;
80
+ });
81
+
82
+ // 基本格式處理
83
+ // Basic formatting
84
+ content = content
85
+ // 換行轉換為 HTML 換行
86
+ // Convert newlines to HTML breaks
87
+ .replaceAll('\n', '<br>')
88
+ // 連續換行轉換為段落
89
+ // Convert consecutive breaks to paragraphs
90
+ .replaceAll(/(<br>){2,}/g, '</p><p>')
91
+ // ruby 標籤(為日文漢字標註讀音)
92
+ // ruby tags (for Japanese kanji readings)
93
+ .replaceAll(/\[\[rb:(.*?)>(.*?)\]\]/g, '<ruby>$1<rt>$2</rt></ruby>')
94
+ // 外部連結
95
+ // external links
96
+ .replaceAll(/\[\[jumpuri:(.*?)>(.*?)\]\]/g, '<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>')
97
+ // 頁面跳轉,但由於 [newpage] 使用 hr 分隔,沒有頁數,沒必要跳轉,所以只顯示文字
98
+ // Page jumps, but since [newpage] uses hr separators, without the page numbers, jumping isn't needed, so just display text
99
+ .replaceAll(/\[jump:(\d+)\]/g, 'Jump to page $1')
100
+ // 章節標題
101
+ // chapter titles
102
+ .replaceAll(/\[chapter:(.*?)\]/g, '<h2>$1</h2>')
103
+ // 分頁符
104
+ // page breaks
105
+ .replaceAll('[newpage]', '<hr>');
106
+
107
+ // 使用 cheerio 進行 HTML 清理和優化
108
+ // Use cheerio for HTML cleanup and optimization
109
+ const $content = load(`<article><p>${content}</p></article>`);
110
+
111
+ // 處理嵌套段落:移除多餘的嵌套
112
+ // Handle nested paragraphs: remove unnecessary nesting
113
+ $content('p p').each((_, elem) => {
114
+ const $elem = $content(elem);
115
+ $elem.replaceWith($elem.html() || '');
116
+ });
117
+
118
+ // 處理段落中的標題:確保正確的 HTML 結構
119
+ // Handle headings in paragraphs: ensure correct HTML structure
120
+ $content('p h2').each((_, elem) => {
121
+ const $elem = $content(elem);
122
+ const $parent = $elem.parent('p');
123
+ const html = $elem.prop('outerHTML');
124
+ if ($parent.length && html) {
125
+ $parent.replaceWith(`</p>${html}<p>`);
126
+ }
127
+ });
128
+
129
+ return $content.html() || '';
130
+ } catch (error) {
131
+ throw new Error(`Error parsing novel content: ${error instanceof Error ? error.message : String(error)}`);
132
+ }
133
+ }
@@ -0,0 +1,84 @@
1
+ import got from '../../pixiv-got';
2
+ import { maskHeader } from '../../constants';
3
+ import { getNSFWNovelContent } from '../content/nsfw';
4
+ import pixivUtils from '../../utils';
5
+ import { AppNovelSeries, SeriesDetail, SeriesFeed } from './types';
6
+ import ConfigNotFoundError from '@/errors/types/config-not-found';
7
+ import { getToken } from '../../token';
8
+ import { config } from '@/config';
9
+ import cache from '@/utils/cache';
10
+ import queryString from 'query-string';
11
+
12
+ const baseUrl = 'https://www.pixiv.net';
13
+
14
+ async function getNovelSeries(seriesId: string, offset: number, token: string): Promise<AppNovelSeries> {
15
+ const rsp = await got('https://app-api.pixiv.net/v2/novel/series', {
16
+ headers: {
17
+ ...maskHeader,
18
+ Authorization: 'Bearer ' + token,
19
+ },
20
+ searchParams: queryString.stringify({
21
+ series_id: seriesId,
22
+ last_order: offset,
23
+ }),
24
+ });
25
+ return rsp.data as AppNovelSeries;
26
+ }
27
+
28
+ export async function getNSFWSeriesNovels(seriesId: string, limit: number = 10): Promise<SeriesFeed> {
29
+ if (limit > 30) {
30
+ limit = 30;
31
+ }
32
+
33
+ if (!config.pixiv || !config.pixiv.refreshToken) {
34
+ throw new ConfigNotFoundError('This user is an R18 creator, PIXIV_REFRESHTOKEN is required.\npixiv RSS is disabled due to the lack of relevant config.\n該用戶爲 R18 創作者,需要 PIXIV_REFRESHTOKEN。');
35
+ }
36
+
37
+ const token = await getToken(cache.tryGet);
38
+ if (!token) {
39
+ throw new ConfigNotFoundError('pixiv not login');
40
+ }
41
+
42
+ const seriesResponse = await got(`${baseUrl}/ajax/novel/series/${seriesId}`, {
43
+ headers: {
44
+ ...maskHeader,
45
+ Authorization: 'Bearer ' + token,
46
+ },
47
+ });
48
+ const seriesData = seriesResponse.data as SeriesDetail;
49
+
50
+ let offset = seriesData.body.total - limit;
51
+ if (offset < 0) {
52
+ offset = 0;
53
+ }
54
+ const appSeriesData = await getNovelSeries(seriesId, offset, token);
55
+
56
+ const items = await Promise.all(
57
+ appSeriesData.novels.map(async (novel) => {
58
+ const novelContent = await getNSFWNovelContent(novel.id, token);
59
+ return {
60
+ title: novel.title,
61
+ description: `
62
+ <img src="${pixivUtils.getProxiedImageUrl(novelContent.coverUrl)}" />
63
+ <div>
64
+ <p>${novelContent.description}</p>
65
+ <hr>
66
+ ${novelContent.content}
67
+ </div>
68
+ `,
69
+ link: `${baseUrl}/novel/show.php?id=${novel.id}`,
70
+ pubDate: novel.create_date,
71
+ author: novel.user.name,
72
+ category: novelContent.tags,
73
+ };
74
+ })
75
+ );
76
+
77
+ return {
78
+ title: appSeriesData.novel_series_detail.title,
79
+ description: appSeriesData.novel_series_detail.caption,
80
+ link: `${baseUrl}/novel/series/${seriesId}`,
81
+ image: pixivUtils.getProxiedImageUrl(seriesData.body.cover.urls.original),
82
+ item: items,
83
+ };
84
+ }
@@ -0,0 +1,70 @@
1
+ import got from '@/utils/got';
2
+ import { load } from 'cheerio';
3
+ import { getSFWNovelContent } from '../content/sfw';
4
+ import pixivUtils from '../../utils';
5
+ import { SeriesContentResponse, SeriesFeed } from './types';
6
+
7
+ const baseUrl = 'https://www.pixiv.net';
8
+
9
+ export async function getSFWSeriesNovels(seriesId: string, limit: number = 10): Promise<SeriesFeed> {
10
+ const seriesPage = await got(`${baseUrl}/novel/series/${seriesId}`);
11
+ const $ = load(seriesPage.data);
12
+
13
+ const title = $('meta[property="og:title"]').attr('content') || '';
14
+ const description = $('meta[property="og:description"]').attr('content') || '';
15
+ const image = $('meta[property="og:image"]').attr('content') || '';
16
+
17
+ const response = await got(`${baseUrl}/ajax/novel/series/${seriesId}/content_titles`, {
18
+ headers: {
19
+ referer: `${baseUrl}/novel/series/${seriesId}`,
20
+ },
21
+ });
22
+
23
+ const data = response.data as SeriesContentResponse;
24
+
25
+ if (data.error) {
26
+ throw new Error(data.message || 'Failed to get series data');
27
+ }
28
+
29
+ const chapters = data.body.slice(-Math.abs(limit));
30
+ const chapterStartNum = Math.max(data.body.length - limit + 1, 1);
31
+
32
+ const items = await Promise.all(
33
+ chapters
34
+ .map(async (chapter, index) => {
35
+ if (!chapter.available) {
36
+ return {
37
+ title: `#${chapterStartNum + index} ${chapter.title}`,
38
+ description: `PIXIV_REFRESHTOKEN is required to view the full content.<br>需要 PIXIV_REFRESHTOKEN 才能查看完整內文。`,
39
+ link: `${baseUrl}/novel/show.php?id=${chapter.id}`,
40
+ };
41
+ }
42
+
43
+ const novelContent = await getSFWNovelContent(chapter.id);
44
+ return {
45
+ title: `#${chapterStartNum + index} ${novelContent.title}`,
46
+ description: `
47
+ <img src="${pixivUtils.getProxiedImageUrl(novelContent.coverUrl)}" />
48
+ <div>
49
+ <p>${novelContent.description}</p>
50
+ <hr>
51
+ ${novelContent.content}
52
+ </div>
53
+ `,
54
+ link: `${baseUrl}/novel/show.php?id=${novelContent.id}`,
55
+ pubDate: novelContent.createDate,
56
+ author: novelContent.userName || `User ID: ${novelContent.userId}`,
57
+ category: novelContent.tags,
58
+ };
59
+ })
60
+ .reverse()
61
+ );
62
+
63
+ return {
64
+ title,
65
+ description,
66
+ image: pixivUtils.getProxiedImageUrl(image),
67
+ link: `${baseUrl}/novel/series/${seriesId}`,
68
+ item: items,
69
+ };
70
+ }
@@ -0,0 +1,94 @@
1
+ export interface SeriesChapter {
2
+ id: string;
3
+ title: string;
4
+ available: boolean;
5
+ }
6
+
7
+ export interface SeriesContentResponse {
8
+ error: boolean;
9
+ message: string;
10
+ body: SeriesChapter[];
11
+ }
12
+
13
+ export interface SeriesDetail {
14
+ error: boolean;
15
+ message: string;
16
+ body: {
17
+ id: string;
18
+ userId: string;
19
+ userName: string;
20
+ title: string;
21
+ caption: string;
22
+ description?: string;
23
+ tags: string[];
24
+ publishedContentCount: number;
25
+ createDate: string;
26
+ updateDate: string;
27
+ firstNovelId: string;
28
+ latestNovelId: string;
29
+ xRestrict: number;
30
+ isOriginal: boolean;
31
+ total: number;
32
+ cover: {
33
+ urls: {
34
+ original: string;
35
+ small?: string;
36
+ regular?: string;
37
+ original_square?: string;
38
+ };
39
+ };
40
+ extraData: {
41
+ meta: {
42
+ title: string;
43
+ description: string;
44
+ canonical: string;
45
+ ogp: {
46
+ description: string;
47
+ image: string;
48
+ title: string;
49
+ type: string;
50
+ };
51
+ };
52
+ };
53
+ };
54
+ }
55
+
56
+ export interface SeriesFeed {
57
+ title: string;
58
+ description: string;
59
+ image: string;
60
+ link: string;
61
+ item: Array<{
62
+ title: string;
63
+ description: string;
64
+ link: string;
65
+ pubDate?: Date;
66
+ author?: string;
67
+ category?: string[];
68
+ }>;
69
+ }
70
+
71
+ export interface AppUser {
72
+ id: number;
73
+ name: string;
74
+ }
75
+
76
+ export interface AppNovelSeriesDetail {
77
+ id: string;
78
+ title: string;
79
+ caption: string;
80
+ content_count: number;
81
+ is_concluded: boolean;
82
+ is_original: boolean;
83
+ user: AppUser;
84
+ }
85
+
86
+ export interface AppNovelSeries {
87
+ novel_series_detail: AppNovelSeriesDetail;
88
+ novels: {
89
+ id: string;
90
+ title: string;
91
+ create_date: Date;
92
+ user: AppUser;
93
+ }[];
94
+ }