rsshub 1.0.0-master.f7cdf8b → 1.0.0-master.f7f8b7a

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 (273) hide show
  1. package/README.md +3 -3
  2. package/lib/config.js +21 -8
  3. package/lib/middleware/cache/index.js +4 -3
  4. package/lib/middleware/cache/redis.js +3 -3
  5. package/lib/middleware/onerror.js +8 -0
  6. package/lib/middleware/template.js +79 -85
  7. package/lib/router.js +7 -7
  8. package/lib/routes/index.js +6 -13
  9. package/lib/utils/common-utils.js +2 -6
  10. package/lib/utils/render.js +2 -0
  11. package/lib/v2/1point3acres/maintainer.js +2 -2
  12. package/lib/v2/95mm/utils.js +3 -2
  13. package/lib/v2/aliyun/notice.js +1 -1
  14. package/lib/v2/amazon/maintainer.js +1 -1
  15. package/lib/v2/apnews/topics.js +1 -1
  16. package/lib/v2/arcteryx/maintainer.js +3 -3
  17. package/lib/v2/bangumi/maintainer.js +1 -0
  18. package/lib/v2/bangumi/radar.js +6 -0
  19. package/lib/v2/bangumi/router.js +1 -0
  20. package/lib/v2/bangumi/tv/user/wish.js +38 -0
  21. package/lib/v2/bellroy/maintainer.js +1 -1
  22. package/lib/v2/bilibili/cache.js +10 -7
  23. package/lib/v2/bilibili/maintainer.js +1 -0
  24. package/lib/v2/bilibili/platform.js +43 -0
  25. package/lib/v2/bilibili/radar.js +8 -0
  26. package/lib/v2/bilibili/router.js +1 -0
  27. package/lib/v2/bilibili/video.js +8 -1
  28. package/lib/v2/bossdesign/index.js +41 -0
  29. package/lib/v2/bossdesign/maintainer.js +3 -0
  30. package/lib/v2/bossdesign/radar.js +13 -0
  31. package/lib/v2/bossdesign/router.js +3 -0
  32. package/lib/v2/brave/latest.js +4 -2
  33. package/lib/v2/buaa/maintainer.js +4 -0
  34. package/lib/v2/buaa/news/index.js +46 -0
  35. package/lib/v2/buaa/radar.js +21 -0
  36. package/lib/v2/buaa/router.js +4 -0
  37. package/lib/v2/buaa/sme.js +59 -0
  38. package/lib/v2/cfachina/analygarden.js +60 -0
  39. package/lib/v2/cfachina/maintainer.js +3 -0
  40. package/lib/v2/cfachina/radar.js +13 -0
  41. package/lib/v2/cfachina/router.js +3 -0
  42. package/lib/v2/cna/maintainer.js +1 -0
  43. package/lib/v2/cna/radar.js +6 -0
  44. package/lib/v2/cna/router.js +1 -0
  45. package/lib/v2/cna/web/index.js +62 -0
  46. package/lib/v2/cste/radar.js +1 -1
  47. package/lib/v2/dahecube/radar.js +40 -4
  48. package/lib/v2/dongqiudi/utils.js +1 -1
  49. package/lib/v2/douban/maintainer.js +1 -0
  50. package/lib/v2/douban/other/discussion.js +58 -0
  51. package/lib/v2/douban/radar.js +8 -0
  52. package/lib/v2/douban/router.js +1 -0
  53. package/lib/v2/dut/defaults.js +4 -0
  54. package/lib/v2/dut/index.js +21 -9
  55. package/lib/v2/dut/maintainer.js +8 -7
  56. package/lib/v2/dut/radar.js +37 -29
  57. package/lib/v2/dut/shortcuts.js +5 -0
  58. package/lib/v2/egsea/flash.js +30 -0
  59. package/lib/v2/egsea/maintainer.js +3 -0
  60. package/lib/v2/egsea/radar.js +13 -0
  61. package/lib/v2/egsea/router.js +3 -0
  62. package/lib/v2/fisher-spb/news.js +1 -2
  63. package/lib/v2/fosshub/radar.js +1 -1
  64. package/lib/v2/fxiaoke/crm.js +63 -0
  65. package/lib/v2/fxiaoke/maintainer.js +3 -0
  66. package/lib/v2/fxiaoke/radar.js +37 -0
  67. package/lib/v2/fxiaoke/router.js +3 -0
  68. package/lib/v2/gdsrx/index.js +72 -0
  69. package/lib/v2/gdsrx/maintainer.js +3 -0
  70. package/lib/v2/gdsrx/radar.js +61 -0
  71. package/lib/v2/gdsrx/router.js +3 -0
  72. package/lib/v2/gogoanimehd/radar.js +1 -1
  73. package/lib/v2/gogoanimehd/recent-releases.js +1 -1
  74. package/lib/v2/google/alerts.js +33 -0
  75. package/lib/v2/google/maintainer.js +1 -0
  76. package/lib/v2/google/router.js +1 -0
  77. package/lib/v2/gov/maintainer.js +9 -2
  78. package/lib/v2/gov/moa/zdscxx.js +104 -0
  79. package/lib/v2/gov/mot/index.js +66 -0
  80. package/lib/v2/gov/nea/ghs.js +58 -0
  81. package/lib/v2/gov/nifdc/index.js +40 -33
  82. package/lib/v2/gov/radar.js +232 -4
  83. package/lib/v2/gov/router.js +10 -2
  84. package/lib/v2/gov/safe/business.js +8 -0
  85. package/lib/v2/gov/safe/complaint.js +8 -0
  86. package/lib/v2/gov/safe/templates/message.art +25 -0
  87. package/lib/v2/gov/safe/util.js +87 -0
  88. package/lib/v2/gov/zhengce/index.js +99 -0
  89. package/lib/v2/greasyfork/maintainer.js +1 -0
  90. package/lib/v2/greasyfork/router.js +1 -0
  91. package/lib/v2/greasyfork/scripts.js +25 -20
  92. package/lib/{routes/universities → v2}/harvard/health/blog.js +8 -7
  93. package/lib/v2/harvard/maintainer.js +3 -0
  94. package/lib/v2/harvard/radar.js +13 -0
  95. package/lib/v2/harvard/router.js +3 -0
  96. package/lib/v2/huxiu/briefColumn.js +13 -25
  97. package/lib/v2/huxiu/channel.js +28 -0
  98. package/lib/v2/huxiu/club.js +30 -0
  99. package/lib/v2/huxiu/collection.js +14 -26
  100. package/lib/v2/huxiu/maintainer.js +8 -5
  101. package/lib/v2/huxiu/member.js +27 -0
  102. package/lib/v2/huxiu/moment.js +11 -25
  103. package/lib/v2/huxiu/radar.js +24 -16
  104. package/lib/v2/huxiu/router.js +7 -4
  105. package/lib/v2/huxiu/search.js +16 -21
  106. package/lib/v2/huxiu/tag.js +13 -25
  107. package/lib/v2/huxiu/templates/description.art +46 -0
  108. package/lib/v2/huxiu/util.js +460 -0
  109. package/lib/v2/ifi-audio/maintainer.js +1 -1
  110. package/lib/v2/imiker/jinghua.js +87 -0
  111. package/lib/v2/imiker/maintainer.js +3 -0
  112. package/lib/v2/imiker/radar.js +13 -0
  113. package/lib/v2/imiker/router.js +3 -0
  114. package/lib/v2/imiker/templates/description.art +32 -0
  115. package/lib/v2/inoreader/maintainer.js +1 -1
  116. package/lib/v2/instagram/common-utils.js +7 -4
  117. package/lib/v2/instagram/templates/images.art +9 -2
  118. package/lib/v2/instagram/templates/video.art +4 -1
  119. package/lib/v2/instagram/web-api/index.js +30 -9
  120. package/lib/v2/instagram/web-api/utils.js +149 -25
  121. package/lib/v2/kemono/index.js +26 -2
  122. package/lib/v2/kemono/radar.js +1 -1
  123. package/lib/v2/kepu/live.js +89 -0
  124. package/lib/v2/kepu/maintainer.js +3 -0
  125. package/lib/v2/kepu/radar.js +13 -0
  126. package/lib/v2/kepu/router.js +3 -0
  127. package/lib/v2/kepu/templates/description.art +33 -0
  128. package/lib/v2/leetcode/maintainer.js +1 -1
  129. package/lib/v2/lightnovel/lightNovel.js +62 -0
  130. package/lib/v2/lightnovel/maintainer.js +3 -0
  131. package/lib/v2/lightnovel/radar.js +13 -0
  132. package/lib/v2/lightnovel/router.js +3 -0
  133. package/lib/v2/line/radar.js +1 -1
  134. package/lib/v2/liquipedia/cs_matches.js +52 -0
  135. package/lib/v2/liquipedia/dota2_matches.js +47 -0
  136. package/lib/v2/liquipedia/maintainer.js +4 -0
  137. package/lib/v2/liquipedia/radar.js +19 -0
  138. package/lib/v2/liquipedia/router.js +4 -0
  139. package/lib/v2/magazinelib/maintainer.js +1 -1
  140. package/lib/v2/mihoyo/radar.js +1 -1
  141. package/lib/v2/missav/maintainer.js +3 -0
  142. package/lib/v2/missav/new.js +36 -0
  143. package/lib/v2/missav/radar.js +13 -0
  144. package/lib/v2/missav/router.js +3 -0
  145. package/lib/v2/missav/templates/preview.art +3 -0
  146. package/lib/v2/modb/maintainer.js +3 -0
  147. package/lib/v2/modb/radar.js +13 -0
  148. package/lib/v2/modb/router.js +3 -0
  149. package/lib/v2/modb/topic.js +59 -0
  150. package/lib/v2/nature/cover.js +32 -42
  151. package/lib/v2/nature/highlight.js +2 -2
  152. package/lib/v2/nature/news-and-comment.js +2 -2
  153. package/lib/v2/nature/news.js +2 -2
  154. package/lib/v2/nature/research.js +2 -2
  155. package/lib/v2/nature/siteindex.js +5 -5
  156. package/lib/v2/nature/utils.js +124 -5
  157. package/lib/v2/ncu/jwc.js +33 -0
  158. package/lib/v2/ncu/maintainer.js +3 -0
  159. package/lib/v2/ncu/radar.js +13 -0
  160. package/lib/v2/ncu/router.js +3 -0
  161. package/lib/v2/nmtv/radar.js +1 -1
  162. package/lib/v2/oo-software/radar.js +1 -1
  163. package/lib/v2/patagonia/maintainer.js +1 -1
  164. package/lib/v2/phoronix/index.js +177 -48
  165. package/lib/v2/phoronix/maintainer.js +1 -1
  166. package/lib/v2/phoronix/radar.js +3 -3
  167. package/lib/v2/phoronix/router.js +1 -1
  168. package/lib/v2/picnob/maintainer.js +1 -1
  169. package/lib/v2/picnob/templates/desc.art +3 -3
  170. package/lib/v2/picnob/user.js +74 -37
  171. package/lib/v2/picnob/utils.js +24 -0
  172. package/lib/v2/qbitai/category.js +27 -0
  173. package/lib/v2/qbitai/maintainer.js +4 -0
  174. package/lib/v2/qbitai/radar.js +19 -0
  175. package/lib/v2/qbitai/router.js +4 -0
  176. package/lib/v2/qbitai/tag.js +27 -0
  177. package/lib/v2/questmobile/maintainer.js +3 -0
  178. package/lib/v2/questmobile/radar.js +18 -0
  179. package/lib/v2/questmobile/report.js +127 -0
  180. package/lib/v2/questmobile/router.js +3 -0
  181. package/lib/v2/questmobile/templates/description.art +17 -0
  182. package/lib/v2/readhub/daily.js +43 -0
  183. package/lib/v2/readhub/index.js +19 -72
  184. package/lib/v2/readhub/maintainer.js +1 -0
  185. package/lib/v2/readhub/radar.js +6 -0
  186. package/lib/v2/readhub/router.js +1 -0
  187. package/lib/v2/readhub/util.js +69 -0
  188. package/lib/v2/routledge/book-series.js +78 -0
  189. package/lib/v2/routledge/maintainer.js +3 -0
  190. package/lib/v2/routledge/radar.js +13 -0
  191. package/lib/v2/routledge/router.js +3 -0
  192. package/lib/v2/routledge/templates/description.art +7 -0
  193. package/lib/v2/showstart/artist.js +15 -0
  194. package/lib/v2/showstart/brand.js +15 -0
  195. package/lib/v2/showstart/const.js +4 -0
  196. package/lib/v2/showstart/event.js +18 -0
  197. package/lib/v2/showstart/maintainer.js +6 -0
  198. package/lib/v2/showstart/radar.js +40 -0
  199. package/lib/v2/showstart/router.js +6 -0
  200. package/lib/v2/showstart/search.js +51 -0
  201. package/lib/v2/showstart/service.js +166 -0
  202. package/lib/v2/showstart/utils.js +92 -0
  203. package/lib/v2/snowpeak/maintainer.js +1 -1
  204. package/lib/v2/sony/maintainer.js +1 -1
  205. package/lib/v2/sse/disclosure.js +4 -3
  206. package/lib/v2/sspu/jwc.js +44 -0
  207. package/lib/v2/sspu/maintainer.js +3 -0
  208. package/lib/v2/sspu/radar.js +13 -0
  209. package/lib/v2/sspu/router.js +3 -0
  210. package/lib/v2/techcrunch/maintainer.js +1 -1
  211. package/lib/v2/theatlantic/maintainer.js +1 -1
  212. package/lib/v2/thepaper/radar.js +2 -2
  213. package/lib/v2/threads/index.js +20 -150
  214. package/lib/v2/threads/utils.js +147 -0
  215. package/lib/v2/twitter/keyword.js +1 -3
  216. package/lib/v2/twitter/media.js +1 -5
  217. package/lib/v2/twitter/user.js +1 -3
  218. package/lib/v2/twitter/utils.js +5 -3
  219. package/lib/v2/twitter/web-api/constants.js +80 -68
  220. package/lib/v2/twitter/web-api/twitter-api.js +96 -103
  221. package/lib/v2/uniqlo/maintainer.js +3 -0
  222. package/lib/v2/uniqlo/new.js +62 -0
  223. package/lib/v2/uniqlo/radar.js +12 -0
  224. package/lib/v2/uniqlo/router.js +3 -0
  225. package/lib/v2/wechat/maintainer.js +1 -1
  226. package/lib/v2/weibo/maintainer.js +1 -1
  227. package/lib/v2/weibo/radar.js +1 -1
  228. package/lib/v2/weibo/router.js +1 -1
  229. package/lib/v2/weibo/search/hot.js +118 -7
  230. package/lib/v2/weibo/search/template/digest.art +17 -0
  231. package/lib/v2/xiaohongshu/util.js +17 -7
  232. package/lib/v2/xmnn/docs.js +0 -0
  233. package/lib/v2/xmnn/maintainer.js +1 -0
  234. package/lib/v2/xmnn/news.js +65 -0
  235. package/lib/v2/xmnn/radar.js +67 -1
  236. package/lib/v2/xmnn/router.js +1 -0
  237. package/lib/v2/xsijishe/maintainer.js +1 -0
  238. package/lib/v2/xsijishe/radar.js +12 -0
  239. package/lib/v2/xsijishe/rank.js +60 -0
  240. package/lib/v2/xsijishe/router.js +1 -0
  241. package/lib/v2/yahoo/maintainer.js +2 -0
  242. package/lib/v2/yahoo/news/tw/index.js +24 -0
  243. package/lib/v2/yahoo/news/tw/provider-helper.js +22 -0
  244. package/lib/v2/yahoo/news/tw/provider.js +24 -0
  245. package/lib/v2/yahoo/news/tw/utils.js +129 -0
  246. package/lib/v2/yahoo/radar.js +29 -1
  247. package/lib/v2/yahoo/router.js +4 -1
  248. package/lib/v2/yahoo/templates/youtube.art +1 -0
  249. package/lib/v2/yuque/book.js +6 -1
  250. package/lib/v2/yuque/utils.js +16 -0
  251. package/lib/v2/zagg/maintainer.js +1 -1
  252. package/lib/views/error.art +1 -1
  253. package/lib/views/rss3-ums.js +62 -0
  254. package/lib/views/welcome.art +1 -1
  255. package/package.json +45 -39
  256. package/lib/routes/egsea/flash.js +0 -40
  257. package/lib/routes/gov/moa/sjzxfb.js +0 -20
  258. package/lib/routes/liquipedia/dota2_matches.js +0 -50
  259. package/lib/routes/questmobile/report.js +0 -121
  260. package/lib/routes/uniqlo/stylingbook.js +0 -24
  261. package/lib/routes/universities/buaa/news/index.js +0 -66
  262. package/lib/routes/universities/buaa/utils.js +0 -57
  263. package/lib/v2/gov/zhengce/zuixin.js +0 -39
  264. package/lib/v2/huxiu/article.js +0 -33
  265. package/lib/v2/huxiu/author.js +0 -36
  266. package/lib/v2/huxiu/templates/brief.art +0 -22
  267. package/lib/v2/huxiu/templates/img.art +0 -3
  268. package/lib/v2/huxiu/templates/moment.art +0 -16
  269. package/lib/v2/huxiu/templates/video.art +0 -7
  270. package/lib/v2/huxiu/utils.js +0 -154
  271. package/lib/v2/twitter/web-api/twitter-got.js +0 -113
  272. /package/lib/{routes → v2}/gov/moa/moa.js +0 -0
  273. /package/lib/v2/yahoo/news/{index.js → us/index.js} +0 -0
@@ -1,12 +1,12 @@
1
1
  const { CookieJar } = require('tough-cookie');
2
2
  const config = require('@/config').value;
3
3
  const { renderItems } = require('../common-utils');
4
- const { baseUrl, COOKIE_URL, getUserInfo, getUserFeedItems, getTagsFeedItems } = require('./utils');
4
+ const { baseUrl, COOKIE_URL, checkLogin, getUserInfo, getUserFeedItems, getTagsFeedItems, getLoggedOutTagsFeedItems, renderGuestItems } = require('./utils');
5
5
 
6
6
  module.exports = async (ctx) => {
7
- if (!config.instagram || !config.instagram.cookie) {
8
- throw Error('Instagram RSS is disabled due to the lack of <a href="https://docs.rsshub.app/install/#pei-zhi-bu-fen-rss-mo-kuai-pei-zhi">relevant config</a>');
9
- }
7
+ // if (!config.instagram || !config.instagram.cookie) {
8
+ // throw Error('Instagram RSS is disabled due to the lack of <a href="https://docs.rsshub.app/install/#pei-zhi-bu-fen-rss-mo-kuai-pei-zhi">relevant config</a>');
9
+ // }
10
10
  const availableCategories = ['user', 'tags'];
11
11
  const { category, key } = ctx.params;
12
12
  const { cookie } = config.instagram;
@@ -15,16 +15,26 @@ module.exports = async (ctx) => {
15
15
  }
16
16
 
17
17
  let cookieJar = await ctx.cache.get('instagram:cookieJar');
18
+ const wwwClaimV2 = await ctx.cache.get('instagram:wwwClaimV2');
18
19
  const cacheMiss = !cookieJar;
20
+
19
21
  if (cacheMiss) {
20
22
  cookieJar = new CookieJar();
21
- for await (const c of cookie.split('; ')) {
22
- await cookieJar.setCookie(c, COOKIE_URL);
23
+ if (cookie) {
24
+ for await (const c of cookie.split('; ')) {
25
+ await cookieJar.setCookie(c, COOKIE_URL);
26
+ }
23
27
  }
24
28
  } else {
25
29
  cookieJar = CookieJar.fromJSON(cookieJar);
26
30
  }
27
31
 
32
+ if (!wwwClaimV2 && cookie) {
33
+ if (!(await checkLogin(cookieJar, ctx.cache))) {
34
+ throw Error('Invalid cookie');
35
+ }
36
+ }
37
+
28
38
  let feedTitle, feedLink, feedDescription, feedLogo;
29
39
  let items;
30
40
  switch (category) {
@@ -39,7 +49,12 @@ module.exports = async (ctx) => {
39
49
  feedLogo = userInfo.profile_pic_url_hd ?? userInfo.hd_profile_pic_url_info?.url ?? userInfo.profile_pic_url;
40
50
  feedLink = `${baseUrl}/${username}`;
41
51
 
42
- items = await getUserFeedItems(id, username, cookieJar, ctx.cache.tryGet);
52
+ if (cookie) {
53
+ items = await getUserFeedItems(id, username, cookieJar, ctx.cache);
54
+ } else {
55
+ items = [...userInfo.edge_felix_video_timeline.edges, ...userInfo.edge_owner_to_timeline_media.edges];
56
+ }
57
+
43
58
  break;
44
59
  }
45
60
  case 'tags': {
@@ -48,7 +63,13 @@ module.exports = async (ctx) => {
48
63
  feedTitle = `#${tag} - Instagram`;
49
64
  feedLink = `${baseUrl}/explore/tags/${tag}`;
50
65
 
51
- items = await getTagsFeedItems(tag, 'recent', cookieJar, ctx.cache.tryGet);
66
+ if (cookie) {
67
+ items = await getTagsFeedItems(tag, 'recent', cookieJar, ctx.cache.tryGet);
68
+ } else {
69
+ const hashTag = await getLoggedOutTagsFeedItems(tag, cookieJar);
70
+ items = [...hashTag.edge_hashtag_to_media.edges, ...hashTag.edge_hashtag_to_top_posts.edges];
71
+ }
72
+
52
73
  break;
53
74
  }
54
75
  default:
@@ -61,7 +82,7 @@ module.exports = async (ctx) => {
61
82
  title: feedTitle,
62
83
  link: feedLink,
63
84
  description: feedDescription,
64
- item: renderItems(items),
85
+ item: cookie ? renderItems(items) : renderGuestItems(items),
65
86
  icon: `${baseUrl}/static/images/ico/xxhdpi_launcher.png/99cf3909d459.png`,
66
87
  logo: feedLogo,
67
88
  image: feedLogo,
@@ -1,9 +1,11 @@
1
1
  const got = require('@/utils/got');
2
+ const { parseDate } = require('@/utils/parse-date');
2
3
  const config = require('@/config').value;
4
+ const { art } = require('@/utils/render');
5
+ const path = require('path');
3
6
 
4
7
  const baseUrl = 'https://www.instagram.com';
5
8
  const COOKIE_URL = 'https://instagram.com';
6
- let igWwwClaim;
7
9
 
8
10
  const getCSRFTokenFromJar = async (cookieJar) => {
9
11
  const cookieString = await cookieJar.getCookieString(COOKIE_URL);
@@ -14,32 +16,60 @@ const getHeaders = async (cookieJar) => ({
14
16
  'X-ASBD-ID': 198387,
15
17
  'X-CSRFToken': await getCSRFTokenFromJar(cookieJar),
16
18
  'X-IG-App-ID': 936619743392459,
17
- 'X-IG-WWW-Claim': igWwwClaim,
19
+ 'X-IG-WWW-Claim': undefined,
18
20
  });
19
21
 
22
+ const checkLogin = async (cookieJar, cache) => {
23
+ const response = await got.post(`${baseUrl}/api/v1/web/fxcal/ig_sso_users/`, {
24
+ // cookieJar,
25
+ headers: {
26
+ cookie: await cookieJar.getCookieString(COOKIE_URL),
27
+ ...(await getHeaders(cookieJar)),
28
+ 'X-IG-WWW-Claim': '0',
29
+ },
30
+ });
31
+
32
+ const wwwClaimV2 = response.headers['x-ig-set-www-claim'];
33
+
34
+ if (wwwClaimV2) {
35
+ cache.set('instagram:wwwClaimV2', wwwClaimV2);
36
+ }
37
+
38
+ return Boolean(response.data.status === 'ok');
39
+ };
40
+
20
41
  const getUserInfo = async (username, cookieJar, cache) => {
21
42
  let webProfileInfo;
22
43
  let id = await cache.get(`instagram:getIdByUsername:${username}`);
23
44
  let userInfoCache = await cache.get(`instagram:userInfo:${id}`);
24
45
 
25
46
  if (!userInfoCache) {
26
- const response = await got(`${baseUrl}/api/v1/users/web_profile_info/`, {
27
- cookieJar,
28
- headers: await getHeaders(cookieJar),
29
- searchParams: {
30
- username,
31
- },
32
- });
33
- if (response.url.includes('/accounts/login/')) {
34
- throw Error('Invalid cookie');
35
- }
36
- igWwwClaim = response.headers['x-ig-set-www-claim'] || igWwwClaim;
47
+ try {
48
+ const response = await got(`${baseUrl}/api/v1/users/web_profile_info/`, {
49
+ cookieJar,
50
+ headers: {
51
+ ...(await getHeaders(cookieJar)),
52
+ 'X-IG-WWW-Claim': (await cache.get('instagram:wwwClaimV2')) ?? undefined,
53
+ },
54
+ searchParams: {
55
+ username,
56
+ },
57
+ });
58
+ if (response.url.includes('/accounts/login/')) {
59
+ throw Error('Invalid cookie');
60
+ }
37
61
 
38
- webProfileInfo = response.data.data.user;
39
- id = webProfileInfo.id;
62
+ webProfileInfo = response.data.data.user;
63
+ id = webProfileInfo.id;
40
64
 
41
- await cache.set(`instagram:getIdByUsername:${username}`, id, 31536000); // 1 year since it will never change
42
- await cache.set(`instagram:userInfo:${id}`, webProfileInfo);
65
+ await cache.set(`instagram:getIdByUsername:${username}`, id, 31536000); // 1 year since it will never change
66
+ await cache.set(`instagram:userInfo:${id}`, webProfileInfo);
67
+ } catch (e) {
68
+ if (e.message.includes("Cookie not in this host's domain")) {
69
+ throw Error('Invalid cookie');
70
+ }
71
+ throw e;
72
+ }
43
73
  }
44
74
 
45
75
  userInfoCache = typeof userInfoCache === 'string' ? JSON.parse(userInfoCache) : userInfoCache;
@@ -47,19 +77,26 @@ const getUserInfo = async (username, cookieJar, cache) => {
47
77
  return userInfoCache || webProfileInfo;
48
78
  };
49
79
 
50
- const getUserFeedItems = (id, username, cookieJar, tryGet) =>
51
- tryGet(
80
+ const getUserFeedItems = (id, username, cookieJar, cache) =>
81
+ cache.tryGet(
52
82
  `instagram:feed:${id}`,
53
83
  async () => {
54
84
  const response = await got(`${baseUrl}/api/v1/feed/user/${username}/username/`, {
55
- cookieJar,
56
- headers: await getHeaders(cookieJar),
85
+ // cookieJar,
86
+ headers: {
87
+ cookie: await cookieJar.getCookieString(COOKIE_URL),
88
+ ...(await getHeaders(cookieJar)),
89
+ // 401 Unauthorized if cookie does not match with IP
90
+ 'X-IG-WWW-Claim': await cache.get('instagram:wwwClaimV2'),
91
+ },
57
92
  searchParams: {
58
93
  count: 30,
59
94
  },
60
95
  });
61
- // 401 Unauthorized if cookie does not match with IP
62
- igWwwClaim = response.headers['x-ig-set-www-claim'] || igWwwClaim;
96
+ if (response.url.includes('/accounts/login/')) {
97
+ throw Error(`Invalid cookie.
98
+ Please also check if your account is being blocked by Instagram.`);
99
+ }
63
100
 
64
101
  return response.data.items;
65
102
  },
@@ -81,8 +118,6 @@ const getTagsFeedItems = (tag, tab, cookieJar, tryGet) =>
81
118
  tag_name: tag,
82
119
  },
83
120
  });
84
- // Looks like cookie IP check is not applied to tags
85
- igWwwClaim = response.headers['x-ig-set-www-claim'] || igWwwClaim;
86
121
 
87
122
  return response.data.data[tab].sections.flatMap((section) => section.layout_content.medias.map((media) => media.media));
88
123
  },
@@ -90,10 +125,99 @@ const getTagsFeedItems = (tag, tab, cookieJar, tryGet) =>
90
125
  false
91
126
  );
92
127
 
128
+ const getLoggedOutTagsFeedItems = async (tag, cookieJar) => {
129
+ const response = await got(`${baseUrl}/api/v1/tags/logged_out_web_info/`, {
130
+ // cookieJar, cookieJar is behaving weirdly here, so we use cookie header instead
131
+ headers: {
132
+ cookie: await cookieJar.getCookieString(COOKIE_URL),
133
+ ...(await getHeaders(cookieJar)),
134
+ 'X-IG-WWW-Claim': '0',
135
+ },
136
+ searchParams: {
137
+ tag_name: tag,
138
+ },
139
+ });
140
+
141
+ const cookies = response.headers['set-cookie'];
142
+ if (cookies) {
143
+ for await (const cookie of cookies) {
144
+ await cookieJar.setCookie(cookie, COOKIE_URL);
145
+ }
146
+ }
147
+
148
+ return response.data.data.hashtag;
149
+ };
150
+
151
+ const renderGuestItems = (items) => {
152
+ const renderVideo = (node, summary) =>
153
+ art(path.join(__dirname, '../templates/video.art'), {
154
+ summary,
155
+ image: node.display_url,
156
+ video: {
157
+ url: node.video_url,
158
+ height: node.dimensions.height,
159
+ width: node.dimensions.width,
160
+ },
161
+ });
162
+ const renderImages = (node, summary) =>
163
+ art(path.join(__dirname, '../templates/images.art'), {
164
+ summary,
165
+ images: [{ url: node.display_url, height: node.dimensions.height, width: node.dimensions.width }],
166
+ });
167
+
168
+ return items.map(({ node }) => {
169
+ const type = node.__typename;
170
+ const summary = node.edge_media_to_caption.edges[0]?.node.text ?? '';
171
+
172
+ let description = '';
173
+ switch (type) {
174
+ // carousel, can include GraphVideo and GraphImage
175
+ case 'GraphSidecar':
176
+ description = node.edge_sidecar_to_children
177
+ ? node.edge_sidecar_to_children.edges
178
+ .map(({ node }, i) => {
179
+ const _type = node.__typename;
180
+ switch (_type) {
181
+ case 'GraphVideo':
182
+ return renderVideo(node, i === 0 ? summary : '');
183
+ case 'GraphImage':
184
+ return renderImages(node, i === 0 ? summary : '');
185
+ default:
186
+ throw Error(`Instagram: Unhandled carousel type: ${_type}`);
187
+ }
188
+ })
189
+ .join('')
190
+ : renderImages(node, summary);
191
+ break;
192
+ case 'GraphVideo':
193
+ description = renderVideo(node, summary);
194
+ break;
195
+ case 'GraphImage':
196
+ description = renderImages(node, summary);
197
+ break;
198
+ default:
199
+ throw Error(`Instagram: Unhandled feed type: ${type}`);
200
+ }
201
+
202
+ return {
203
+ title: summary.split('\n')[0],
204
+ id: node.id,
205
+ pubDate: parseDate(node.taken_at_timestamp, 'X'),
206
+ author: node.owner.username,
207
+ link: `${baseUrl}/p/${node.shortcode}/`,
208
+ summary,
209
+ description,
210
+ };
211
+ });
212
+ };
213
+
93
214
  module.exports = {
94
215
  baseUrl,
95
216
  COOKIE_URL,
217
+ checkLogin,
96
218
  getUserInfo,
97
219
  getUserFeedItems,
98
220
  getTagsFeedItems,
221
+ getLoggedOutTagsFeedItems,
222
+ renderGuestItems,
99
223
  };
@@ -8,7 +8,7 @@ module.exports = async (ctx) => {
8
8
  const source = ctx.params.source ?? '';
9
9
  const id = ctx.params.id;
10
10
 
11
- const rootUrl = 'https://kemono.party';
11
+ const rootUrl = 'https://kemono.su';
12
12
  const apiUrl = `${rootUrl}/api/v1/discord/channel/lookup/${id}`;
13
13
  const currentUrl = `${rootUrl}/${source ? `${source}/${source === 'discord' ? `server/${id}` : `user/${id}`}` : 'posts'}`;
14
14
 
@@ -23,7 +23,8 @@ module.exports = async (ctx) => {
23
23
  });
24
24
 
25
25
  let items = [],
26
- title = '';
26
+ title = '',
27
+ image = undefined;
27
28
 
28
29
  if (source === 'discord') {
29
30
  title = `Posts of ${id} from Discord | Kemono`;
@@ -56,6 +57,7 @@ module.exports = async (ctx) => {
56
57
  const $ = cheerio.load(response.data);
57
58
 
58
59
  title = $('title').text();
60
+ image = $('.user-header__avatar img[src]').attr('src');
59
61
 
60
62
  items = await Promise.all(
61
63
  $('.card-list__items')
@@ -87,8 +89,29 @@ module.exports = async (ctx) => {
87
89
  item.description = content('.post__body').html();
88
90
  item.author = content('.post__user-name').text();
89
91
  item.title = content('.post__title span').first().text();
92
+ item.guid = item.link.replace('kemono.su', 'kemono.party');
90
93
  item.pubDate = parseDate(content('.timestamp').attr('datetime'));
91
94
 
95
+ // find the first attachment with a file extension we
96
+ // want, and set it as the enclosure
97
+ content('.post__attachment-link[href][download]').each(function () {
98
+ const extension = content(this).attr('download').replace(/.*\./, '').toLowerCase();
99
+ const mimeType =
100
+ {
101
+ m4a: 'audio/mp4',
102
+ mp3: 'audio/mpeg',
103
+ mp4: 'video/mp4',
104
+ }[extension] || null;
105
+ if (mimeType === null) {
106
+ return;
107
+ }
108
+
109
+ item.enclosure_url = content(this).attr('href');
110
+ item.enclosure_type = mimeType;
111
+
112
+ return false;
113
+ });
114
+
92
115
  return item;
93
116
  })
94
117
  )
@@ -97,6 +120,7 @@ module.exports = async (ctx) => {
97
120
 
98
121
  ctx.state.data = {
99
122
  title,
123
+ image,
100
124
  link: currentUrl,
101
125
  item: items,
102
126
  };
@@ -1,5 +1,5 @@
1
1
  module.exports = {
2
- 'kemono.party': {
2
+ 'kemono.su': {
3
3
  _name: 'Kemono',
4
4
  '.': [
5
5
  {
@@ -0,0 +1,89 @@
1
+ const got = require('@/utils/got');
2
+ const timezone = require('@/utils/timezone');
3
+ const { parseDate } = require('@/utils/parse-date');
4
+ const { art } = require('@/utils/render');
5
+ const path = require('path');
6
+
7
+ module.exports = async (ctx) => {
8
+ const limit = ctx.query.limit ? parseInt(ctx.query.limit, 10) : 50;
9
+
10
+ const rootUrl = 'https://live.kepu.net.cn';
11
+ const apiRootUrl = 'https://live.kepu.net.cn:8089';
12
+
13
+ const currentUrl = new URL('replay/index', rootUrl).href;
14
+ const apiUrl = new URL('index.php/front/index/replay_list', apiRootUrl).href;
15
+
16
+ const { data: response } = await got.post(apiUrl, {
17
+ form: {
18
+ page: 1,
19
+ size: limit,
20
+ },
21
+ });
22
+
23
+ let items = response.data.data.slice(0, limit).map((item) => ({
24
+ title: item.title,
25
+ link: new URL(`live/index?id=${item.id}`, rootUrl).href,
26
+ description: item.desc,
27
+ author: item.company,
28
+ guid: item.id,
29
+ pubDate: timezone(parseDate(item.live_start_time ?? item.start_time), +8),
30
+ updated: timezone(parseDate(item.live_end_time ?? item.end_time), +8),
31
+ itunes_item_image: new URL(item.cover, apiRootUrl).href,
32
+ comments: item.display_comment ?? 0,
33
+ }));
34
+
35
+ items = await Promise.all(
36
+ items.map((item) =>
37
+ ctx.cache.tryGet(item.link, async () => {
38
+ const apiReplayUrl = new URL('index.php/front/live/replay_url', apiRootUrl).href;
39
+
40
+ const { data: detailResponse } = await got.post(apiReplayUrl, {
41
+ form: {
42
+ id: item.guid,
43
+ },
44
+ });
45
+
46
+ item.guid = `kepu-live#${item.guid}`;
47
+ item.enclosure_url = detailResponse.data.RecordIndexInfoList.RecordIndexInfo.pop()?.RecordUrl;
48
+
49
+ if (item.enclosure_url) {
50
+ item.enclosure_type = `video/${item.enclosure_url.split(/\./).pop()}`;
51
+ }
52
+
53
+ item.description = art(path.join(__dirname, 'templates/description.art'), {
54
+ image: {
55
+ src: item.itunes_item_image,
56
+ alt: item.title,
57
+ },
58
+ video: {
59
+ src: item.enclosure_url,
60
+ type: item.enclosure_type,
61
+ poster: item.itunes_item_image,
62
+ },
63
+ description: item.description,
64
+ });
65
+
66
+ return item;
67
+ })
68
+ )
69
+ );
70
+
71
+ const icon = new URL('favicon.ico', rootUrl).href;
72
+ const author = '中国科普博览';
73
+ const subtitle = '直播回看';
74
+
75
+ ctx.state.data = {
76
+ item: items,
77
+ title: `${author} - ${subtitle}`,
78
+ link: currentUrl,
79
+ description: '科学直播(live.kepu.net.cn)',
80
+ language: 'zh',
81
+ icon,
82
+ logo: icon,
83
+ subtitle,
84
+ author,
85
+ itunes_author: author,
86
+ itunes_category: 'Science',
87
+ allowEmpty: true,
88
+ };
89
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ '/live': ['nczitzk'],
3
+ };
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ 'kepu.net.cn': {
3
+ _name: '中国科普博览',
4
+ live: [
5
+ {
6
+ title: '直播回看',
7
+ docs: 'https://docs.rsshub.app/routes/new-media#zhong-guo-ke-pu-bo-lan-zhi-bo-hui-kan',
8
+ source: ['/replay/index'],
9
+ target: '/kepu/live',
10
+ },
11
+ ],
12
+ },
13
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = (router) => {
2
+ router.get('/live', require('./live'));
3
+ };
@@ -0,0 +1,33 @@
1
+ {{ if image?.src }}
2
+ <figure>
3
+ <img
4
+ {{ if image.alt }}
5
+ alt="{{ image.alt }}"
6
+ {{ /if }}
7
+ src="{{ image.src }}">
8
+ </figure>
9
+ {{ /if }}
10
+
11
+ {{ if intro }}
12
+ <p>{{ intro }}</p>
13
+ {{ /if }}
14
+
15
+ {{ if video?.src }}
16
+ <video
17
+ {{ set poster = video.poster || image?.src }}
18
+ {{ if poster }}
19
+ poster="{{ poster }}"
20
+ {{ /if }}
21
+ controls>
22
+ <source
23
+ src="{{ video.src }}"
24
+ type="{{ video.type }}">
25
+ <object data="{{ video.src }}">
26
+ <embed src="{{ video.src }}">
27
+ </object>
28
+ </video>
29
+ {{ /if }}
30
+
31
+ {{ if description }}
32
+ <p>{{ description }}</p>
33
+ {{ /if }}
@@ -1,6 +1,6 @@
1
1
  module.exports = {
2
2
  '/articles': ['LogicJake'],
3
- '/dailyquestion/:lang': ['NavePnow'],
3
+ '/dailyquestion/:lang': ['EthanWng97'],
4
4
  '/dailyquestion/solution/:lang': ['woaidouya123'],
5
5
  '/submission/:country/:user': ['NathanDai'],
6
6
  };
@@ -0,0 +1,62 @@
1
+ const { parseDate } = require('@/utils/parse-date');
2
+ const got = require('@/utils/got');
3
+ const cheerio = require('cheerio');
4
+ const config = require('@/config').value;
5
+
6
+ module.exports = async (ctx) => {
7
+ const baseUrl = 'https://www.lightnovel.us';
8
+ const { type, keywords, security_key = config.lightnovel.cookie } = ctx.params;
9
+ const { data: response } = await got({
10
+ method: 'POST',
11
+ url: `${baseUrl}/proxy/api/search/search-result`,
12
+ headers: {
13
+ // 此处是为什么
14
+ 'User-Agent': config.trueUA,
15
+ },
16
+ json: {
17
+ is_encrypted: 0,
18
+ platform: 'pc',
19
+ client: 'web',
20
+ sign: '',
21
+ gz: 0,
22
+ d: {
23
+ q: keywords,
24
+ type: 0,
25
+ page: 1,
26
+ security_key,
27
+ },
28
+ },
29
+ });
30
+ const list = response.data.articles
31
+ .map((item) => ({
32
+ title: item.title,
33
+ link: `${baseUrl}/cn/detail/${item.aid}`,
34
+ pubDate: parseDate(item.time),
35
+ author: item.author,
36
+ }))
37
+ .slice(0, ctx.query.limit ? parseInt(ctx.query.limit) : 5);
38
+
39
+ const items = await Promise.all(
40
+ list.map((item) =>
41
+ ctx.cache.tryGet(item.link, async () => {
42
+ const { data: response } = await got({
43
+ method: 'GET',
44
+ url: item.link,
45
+ headers: {
46
+ 'User-Agent': config.trueUA,
47
+ },
48
+ });
49
+
50
+ const $ = cheerio.load(response);
51
+ item.description = $('#article-main-contents').html();
52
+ return item;
53
+ })
54
+ )
55
+ );
56
+
57
+ ctx.state.data = {
58
+ title: `轻之国度-追踪${keywords}更新-${type} `,
59
+ link: baseUrl,
60
+ item: items,
61
+ };
62
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ '/:keywords/:security_key?': ['nightmare-mio'],
3
+ };
@@ -0,0 +1,13 @@
1
+ module.exports = {
2
+ 'lightNovel.us': {
3
+ _name: '轻之国度',
4
+ '.': [
5
+ {
6
+ title: '文章更新阅读',
7
+ docs: 'https://docs.rsshub.app/routes/anime#qing-zhi-guo-du',
8
+ source: '/',
9
+ target: '/lightnovel/:keywords/:security_key',
10
+ },
11
+ ],
12
+ },
13
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = function (router) {
2
+ router.get('/:keywords/:security_key?', require('./lightNovel'));
3
+ };
@@ -1,7 +1,7 @@
1
1
  module.exports = {
2
2
  'line.me': {
3
3
  _name: 'LINE',
4
- '.': [
4
+ today: [
5
5
  {
6
6
  title: 'Today',
7
7
  docs: 'https://docs.rsshub.app/routes/new-media#line-today',