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,137 +1,124 @@
1
- const twitterGot = require('./twitter-got');
2
- const { graphQLMap, featuresMap, auth } = require('./constants');
1
+ const { baseUrl, gqlMap, gqlFeatures, consumerKey, consumerSecret } = require('./constants');
3
2
  const config = require('@/config').value;
4
- const got = require('@/utils/got');
5
3
  const logger = require('@/utils/logger');
4
+ const got = require('@/utils/got');
5
+ const OAuth = require('oauth-1.0a');
6
+ const CryptoJS = require('crypto-js');
7
+ const queryString = require('query-string');
6
8
 
7
- // https://github.com/mikf/gallery-dl/blob/a53cfc845e12d9e98fefd07e43ebffaec488c18f/gallery_dl/extractor/twitter.py#L727-L755
8
- const _params = {
9
- count: 20,
10
- include_profile_interstitial_type: 1,
11
- include_blocking: 1,
12
- include_blocked_by: 1,
13
- include_followed_by: 1,
14
- include_want_retweets: 1,
15
- include_mute_edge: 1,
16
- include_can_dm: 1,
17
- include_can_media_tag: 1,
18
- include_ext_has_nft_avatar: 1,
19
- skip_status: 1,
20
- cards_platform: 'Web-12',
21
- include_cards: 1,
22
- include_ext_alt_text: true,
23
- include_quote_count: true,
24
- include_reply_count: 1,
25
- tweet_mode: 'extended',
26
- include_entities: true,
27
- include_user_entities: true,
28
- include_ext_media_color: true,
29
- include_ext_media_availability: true,
30
- // include_ext_sensitive_media_warning: true, // IDK what it is, maybe disabling it will make NSFW lovers happy?
31
- send_error_codes: true,
32
- simple_quoted_tweet: true,
33
- include_tweet_replies: false,
34
- cursor: undefined,
35
- ext: 'mediaStats,highlightedLabel,hasNftAvatar,voiceInfo,superFollowMetadata',
36
- };
9
+ let tokenIndex = 0;
37
10
 
38
- // https://github.com/mikf/gallery-dl/blob/a53cfc845e12d9e98fefd07e43ebffaec488c18f/gallery_dl/extractor/twitter.py#L756--L770
39
- const _variables = {
40
- count: 20,
41
- includePromotedContent: false,
42
- withSuperFollowsUserFields: true,
43
- withBirdwatchPivots: false,
44
- withDownvotePerspective: false,
45
- withReactionsMetadata: false,
46
- withReactionsPerspective: false,
47
- withSuperFollowsTweetFields: true,
48
- withClientEventToken: false,
49
- withBirdwatchNotes: false,
50
- withVoice: true,
51
- withV2Timeline: false,
52
- __fs_interactive_text: false,
53
- __fs_dont_mention_me_view_api_enabled: false,
54
- };
11
+ const twitterGot = async (url, params) => {
12
+ if (!config.twitter.oauthTokens?.length || !config.twitter.oauthTokenSecrets?.length || config.twitter.oauthTokens.length !== config.twitter.oauthTokenSecrets.length) {
13
+ throw Error('Invalid twitter oauth tokens');
14
+ }
15
+
16
+ const oauth = OAuth({
17
+ consumer: {
18
+ key: consumerKey,
19
+ secret: consumerSecret,
20
+ },
21
+ signature_method: 'HMAC-SHA1',
22
+ hash_function: (base_string, key) => CryptoJS.HmacSHA1(base_string, key).toString(CryptoJS.enc.Base64),
23
+ });
24
+
25
+ const token = {
26
+ key: config.twitter.oauthTokens[tokenIndex],
27
+ secret: config.twitter.oauthTokenSecrets[tokenIndex],
28
+ };
29
+ tokenIndex++;
30
+ if (tokenIndex >= config.twitter.oauthTokens.length) {
31
+ tokenIndex = 0;
32
+ }
33
+
34
+ const requestData = {
35
+ url: `${url}?${queryString.stringify(params)}`,
36
+ method: 'GET',
37
+ headers: {
38
+ connection: 'keep-alive',
39
+ 'content-type': 'application/json',
40
+ 'x-twitter-active-user': 'yes',
41
+ authority: 'api.twitter.com',
42
+ 'accept-encoding': 'gzip',
43
+ 'accept-language': 'en-US,en;q=0.9',
44
+ accept: '*/*',
45
+ DNT: '1',
46
+ },
47
+ };
48
+
49
+ const response = await got(requestData.url, {
50
+ headers: oauth.toHeader(oauth.authorize(requestData, token)),
51
+ });
55
52
 
56
- // const paginationLegacy = (endpoint, userId, params) =>
57
- // twitterGot('https://api.twitter.com' + endpoint, {
58
- // ..._params,
59
- // ...params,
60
- // userId,
61
- // });
53
+ return response.data;
54
+ };
62
55
 
63
- // https://github.com/mikf/gallery-dl/blob/a53cfc845e12d9e98fefd07e43ebffaec488c18f/gallery_dl/extractor/twitter.py#L1075-L1093
64
56
  const paginationTweets = async (endpoint, userId, variables, path) => {
65
- const { data } = await twitterGot('https://twitter.com/i/api' + endpoint, {
57
+ const { data } = await twitterGot(baseUrl + endpoint, {
66
58
  variables: JSON.stringify({
67
- ..._variables,
68
59
  ...variables,
69
- userId,
60
+ rest_id: userId,
70
61
  }),
71
- features: featuresMap.UserTweets,
62
+ features: gqlFeatures,
72
63
  });
73
64
 
74
65
  let instructions;
75
66
  if (!path) {
76
- instructions = data.user.result.timeline.timeline.instructions;
67
+ instructions = data.user_result.result.timeline_response.timeline.instructions;
77
68
  } else {
78
69
  instructions = data;
79
70
  path.forEach((p) => (instructions = instructions[p]));
80
71
  instructions = instructions.instructions;
81
72
  }
82
73
 
83
- return instructions.filter((i) => i.type === 'TimelineAddEntries')[0].entries;
74
+ return instructions.filter((i) => i.__typename === 'TimelineAddEntries' || i.type === 'TimelineAddEntries')[0].entries;
84
75
  };
85
76
 
86
- // https://github.com/mikf/gallery-dl/blob/a53cfc845e12d9e98fefd07e43ebffaec488c18f/gallery_dl/extractor/twitter.py#L807-L814
87
77
  const timelineTweets = (userId, params = {}) =>
88
- paginationTweets(graphQLMap.UserTweets, userId, {
78
+ paginationTweets(gqlMap.UserWithProfileTweets, userId, {
89
79
  ...params,
90
80
  withQuickPromoteEligibilityTweetFields: true,
91
81
  });
92
82
 
93
- // https://github.com/mikf/gallery-dl/blob/a53cfc845e12d9e98fefd07e43ebffaec488c18f/gallery_dl/extractor/twitter.py#L816-L823
94
83
  const timelineTweetsAndReplies = (userId, params = {}) =>
95
- paginationTweets(graphQLMap.UserTweetsAndReplies, userId, {
84
+ paginationTweets(gqlMap.UserWithProfileTweetsAndReplies, userId, {
96
85
  ...params,
97
- withCommunity: true,
86
+ count: 20,
98
87
  });
99
88
 
100
- // https://github.com/mikf/gallery-dl/blob/a53cfc845e12d9e98fefd07e43ebffaec488c18f/gallery_dl/extractor/twitter.py#L825-L831
101
- const timelineMedia = (userId, params = {}) => paginationTweets(graphQLMap.UserMedia, userId, params);
89
+ const timelineMedia = (userId, params = {}) => paginationTweets(gqlMap.MediaTimeline, userId, params);
102
90
 
103
- // this query requires login
104
- // https://github.com/mikf/gallery-dl/blob/a53cfc845e12d9e98fefd07e43ebffaec488c18f/gallery_dl/extractor/twitter.py#L833-L839
105
- const timelineLikes = (userId, params = {}) => paginationTweets(graphQLMap.Likes, userId, params);
91
+ // const timelineLikes = (userId, params = {}) => paginationTweets(gqlMap.Likes, userId, params);
106
92
 
107
- // https://github.com/mikf/gallery-dl/blob/a53cfc845e12d9e98fefd07e43ebffaec488c18f/gallery_dl/extractor/twitter.py#L858-L866
108
93
  const timelineKeywords = (keywords, params = {}) =>
109
- got('https://api.twitter.com/1.1/search/universal.json', {
110
- headers: {
111
- Authorization: auth,
112
- },
113
- searchParams: {
114
- ..._params,
94
+ paginationTweets(
95
+ gqlMap.SearchTimeline,
96
+ null,
97
+ {
115
98
  ...params,
116
- q: keywords,
117
- modules: 'status',
118
- result_type: 'recent',
99
+ rawQuery: keywords,
100
+ count: 20,
101
+ product: 'Latest',
102
+ withDownvotePerspective: false,
103
+ withReactionsMetadata: false,
104
+ withReactionsPerspective: false,
119
105
  },
120
- });
106
+ ['search_by_raw_query', 'search_timeline', 'timeline']
107
+ );
121
108
 
122
- // https://github.com/mikf/gallery-dl/blob/a53cfc845e12d9e98fefd07e43ebffaec488c18f/gallery_dl/extractor/twitter.py#L795-L805
123
109
  const tweetDetail = (userId, params) =>
124
110
  paginationTweets(
125
- graphQLMap.TweetDetail,
111
+ gqlMap.TweetDetail,
126
112
  userId,
127
113
  {
128
114
  ...params,
129
- with_rux_injections: false,
130
- withCommunity: true,
131
- withQuickPromoteEligibilityTweetFields: false,
115
+ includeHasBirdwatchNotes: false,
116
+ includePromotedContent: false,
132
117
  withBirdwatchNotes: false,
118
+ withVoice: false,
119
+ withV2Timeline: true,
133
120
  },
134
- ['threaded_conversation_with_injections']
121
+ ['threaded_conversation_with_injections_v2']
135
122
  );
136
123
 
137
124
  function gatherLegacyFromData(entries, filterNested = undefined, userId = undefined) {
@@ -151,7 +138,7 @@ function gatherLegacyFromData(entries, filterNested = undefined, userId = undefi
151
138
  filteredEntries.forEach((entry) => {
152
139
  if (entry.entryId) {
153
140
  const content = entry.content || entry.item;
154
- let tweet = content?.itemContent?.tweet_results?.result;
141
+ let tweet = content?.content?.tweetResult?.result || content?.itemContent?.tweet_results?.result;
155
142
  if (tweet && tweet.tweet) {
156
143
  tweet = tweet.tweet;
157
144
  }
@@ -161,11 +148,11 @@ function gatherLegacyFromData(entries, filterNested = undefined, userId = undefi
161
148
  if (!t?.legacy) {
162
149
  continue;
163
150
  }
164
- t.legacy.user = t.core.user_results.result.legacy;
151
+ t.legacy.user = t.core?.user_result?.result?.legacy || t.core?.user_results?.result?.legacy;
165
152
  const quote = t.quoted_status_result?.result;
166
153
  if (quote) {
167
154
  t.legacy.quoted_status = quote.legacy;
168
- t.legacy.quoted_status.user = quote.core.user_results.result.legacy;
155
+ t.legacy.quoted_status.user = quote.core.user_result?.result?.legacy || quote.core.user_results?.result?.legacy;
169
156
  }
170
157
  }
171
158
  const legacy = tweet.legacy;
@@ -187,7 +174,7 @@ const getUserTweetsByID = async (id, params = {}) => gatherLegacyFromData(await
187
174
  // TODO: show the whole conversation instead of just the reply tweet
188
175
  const getUserTweetsAndRepliesByID = async (id, params = {}) => gatherLegacyFromData(await timelineTweetsAndReplies(id, params), ['profile-conversation-'], id);
189
176
  const getUserMediaByID = async (id, params = {}) => gatherLegacyFromData(await timelineMedia(id, params));
190
- const getUserLikesByID = async (id, params = {}) => gatherLegacyFromData(await timelineLikes(id, params));
177
+ // const getUserLikesByID = async (id, params = {}) => gatherLegacyFromData(await timelineLikes(id, params));
191
178
  const getUserTweetByStatus = async (id, params = {}) => gatherLegacyFromData(await tweetDetail(id, params), ['homeConversation-', 'conversationthread-']);
192
179
 
193
180
  const excludeRetweet = function (tweets) {
@@ -202,14 +189,14 @@ const excludeRetweet = function (tweets) {
202
189
  };
203
190
 
204
191
  const userByScreenName = (screenName) =>
205
- twitterGot(`https://twitter.com/i/api${graphQLMap.UserByScreenName}`, {
192
+ twitterGot(`${baseUrl}${gqlMap.UserResultByScreenName}`, {
206
193
  variables: `{"screen_name":"${screenName}","withHighlightedLabel":true}`,
207
- features: featuresMap.UserByScreenName,
194
+ features: gqlFeatures,
208
195
  });
209
196
  const userByRestId = (restId) =>
210
- twitterGot(`https://twitter.com/i/api${graphQLMap.UserByRestId}`, {
197
+ twitterGot(`${baseUrl}${gqlMap.UserByRestId}`, {
211
198
  variables: `{"userId":"${restId}","withHighlightedLabel":true}`,
212
- features: featuresMap.UserByRestId,
199
+ features: gqlFeatures,
213
200
  });
214
201
  const userByAuto = (id) => {
215
202
  if (id.startsWith('+')) {
@@ -218,8 +205,14 @@ const userByAuto = (id) => {
218
205
  return userByScreenName(id);
219
206
  };
220
207
  const getUserData = (cache, id) => cache.tryGet(`twitter-userdata-${id}`, () => userByAuto(id));
221
- const getUserID = async (cache, id) => (await getUserData(cache, id)).data.user.result.rest_id;
222
- const getUser = async (cache, id) => (await getUserData(cache, id)).data.user.result.legacy;
208
+ const getUserID = async (cache, id) => {
209
+ const userData = await getUserData(cache, id);
210
+ return (userData.data?.user || userData.data?.user_result)?.result?.rest_id;
211
+ };
212
+ const getUser = async (cache, id) => {
213
+ const userData = await getUserData(cache, id);
214
+ return (userData.data?.user || userData.data?.user_result)?.result?.legacy;
215
+ };
223
216
 
224
217
  const cacheTryGet = async (cache, _id, params, func) => {
225
218
  const id = await getUserID(cache, _id);
@@ -272,17 +265,17 @@ const getUserTweets = async (cache, id, params = {}) => {
272
265
  };
273
266
  const getUserTweetsAndReplies = (cache, id, params = {}) => cacheTryGet(cache, id, params, getUserTweetsAndRepliesByID);
274
267
  const getUserMedia = (cache, id, params = {}) => cacheTryGet(cache, id, params, getUserMediaByID);
275
- const getUserLikes = (cache, id, params = {}) => cacheTryGet(cache, id, params, getUserLikesByID);
268
+ // const getUserLikes = (cache, id, params = {}) => cacheTryGet(cache, id, params, getUserLikesByID);
276
269
  const getUserTweet = (cache, id, params) => cacheTryGet(cache, id, params, getUserTweetByStatus);
277
270
 
278
- const getSearch = async (keywords, params = {}) => (await timelineKeywords(keywords, params)).data.modules.map((module) => module.status.data);
271
+ const getSearch = async (keywords, params = {}) => gatherLegacyFromData(await timelineKeywords(keywords, params));
279
272
 
280
273
  module.exports = {
281
274
  getUser,
282
275
  getUserTweets,
283
276
  getUserTweetsAndReplies,
284
277
  getUserMedia,
285
- getUserLikes,
278
+ // getUserLikes,
286
279
  excludeRetweet,
287
280
  getSearch,
288
281
  getUserTweet,
@@ -0,0 +1,3 @@
1
+ module.exports = {
2
+ '/new/:country/:category': ['DIYgod'],
3
+ };
@@ -0,0 +1,62 @@
1
+ const got = require('@/utils/got');
2
+
3
+ module.exports = async (ctx) => {
4
+ const { country, category } = ctx.params;
5
+
6
+ const map = {
7
+ sg: {
8
+ url: 'https://www.uniqlo.com/sg/api/commerce/v3/en/products',
9
+ withFlag: true,
10
+ path: {
11
+ women: 5855,
12
+ men: 5856,
13
+ kids: 5857,
14
+ baby: 5858,
15
+ },
16
+ },
17
+ us: {
18
+ url: 'https://www.uniqlo.com/us/api/commerce/v5/en/products',
19
+ withFlag: false,
20
+ path: {
21
+ women: 22210,
22
+ men: 22211,
23
+ kids: 22212,
24
+ baby: 22213,
25
+ },
26
+ },
27
+ jp: {
28
+ url: 'https://www.uniqlo.com/jp/api/commerce/v5/ja/products',
29
+ withFlag: false,
30
+ path: {
31
+ women: 1071,
32
+ men: 1072,
33
+ kids: 1073,
34
+ baby: 1074,
35
+ },
36
+ lang: 'ja',
37
+ },
38
+ };
39
+ const { data } = await got(map[country].url, {
40
+ searchParams: {
41
+ path: map[country].path[category],
42
+ flagCodes: map[country].withFlag ? 'salesStart newSKU,salesStart newSKU,salesStart newSKU' : undefined,
43
+ sort: 1,
44
+ limit: 24,
45
+ offset: 0,
46
+ },
47
+ });
48
+
49
+ const items = data.result.items.map((item) => ({
50
+ title: item.name,
51
+ link: `https://www.uniqlo.com/${country}/${map[country].lang || 'en'}/products/${item.productId}`,
52
+ description: `${item.longDescription || item.name}<br><br>Price: ${(item.prices.base || item.prices.promo).currency.symbol}${(item.prices.base || item.prices.promo).value}<br><br>${
53
+ item.images.main.length ? item.images.main.map((image) => `<img src="${image.url || image.image}">`).join('') : ''
54
+ }${item.images.sub.map((image) => `<img src="${image.url || image.image}">`).join('')}`,
55
+ }));
56
+
57
+ ctx.state.data = {
58
+ title: `Uniqlo ${category} new arrivals in ${country}`,
59
+ link: `https://www.uniqlo.com/${country}/${map[country].lang || 'en'}/feature/new/${category}`,
60
+ item: items,
61
+ };
62
+ };
@@ -0,0 +1,12 @@
1
+ module.exports = {
2
+ 'uniqlo.com': {
3
+ _name: 'Uniqlo',
4
+ www: [
5
+ {
6
+ title: 'New Arrivals',
7
+ docs: 'https://docs.rsshub.app/routes/shopping#uniqlo',
8
+ source: ['/sg', '/us', '/jp'],
9
+ },
10
+ ],
11
+ },
12
+ };
@@ -0,0 +1,3 @@
1
+ module.exports = function (router) {
2
+ router.get('/new/:country/:category', require('./new'));
3
+ };
@@ -7,7 +7,7 @@ module.exports = {
7
7
  '/feeds': ['tylinux'],
8
8
  '/mp/homepage/:biz/:hid/:cid?': ['MisteryMonster'],
9
9
  '/mp/msgalbum/:biz/:aid': ['MisteryMonster'],
10
- '/sogou/:id': ['NavePnow'],
10
+ '/sogou/:id': ['EthanWng97'],
11
11
  '/tgchannel/:id/:mpName?/:searchQueryType?': ['LogicJake', 'Rongronggg9'],
12
12
  '/uread/:userid': ['kt286'],
13
13
  '/wechat2rss/:id': ['TonyRL'],
@@ -2,7 +2,7 @@ module.exports = {
2
2
  '/group/:gid/:gname?/:routeParams?': ['monologconnor', 'Rongronggg9'],
3
3
  '/keyword/:keyword/:routeParams?': ['DIYgod', 'Rongronggg9'],
4
4
  '/oasis/user/:userid': ['kt286'],
5
- '/search/hot': ['xyqfer'],
5
+ '/search/hot/:fulltext?': ['xyqfer', 'shinemoon'],
6
6
  '/super_index/:id/:type?/:routeParams?': ['zengxs', 'Rongronggg9'],
7
7
  '/timeline/:uid/:feature?/:routeParams?': ['zytomorrow', 'DIYgod', 'Rongronggg9'],
8
8
  '/user/:uid/:routeParams?': ['DIYgod', 'iplusx', 'Rongronggg9'],
@@ -30,7 +30,7 @@ module.exports = {
30
30
  title: '热搜榜',
31
31
  docs: 'https://docs.rsshub.app/routes/social-media#wei-bo',
32
32
  source: '/top/summary',
33
- target: '/weibo/search/hot',
33
+ target: '/weibo/search/hot/:fulltext?',
34
34
  },
35
35
  ],
36
36
  },
@@ -2,7 +2,7 @@ module.exports = (router) => {
2
2
  router.get('/group/:gid/:gname?/:routeParams?', require('./group'));
3
3
  router.get('/keyword/:keyword/:routeParams?', require('./keyword'));
4
4
  router.get('/oasis/user/:userid', require('./oasis/user'));
5
- router.get('/search/hot', require('./search/hot'));
5
+ router.get('/search/hot/:fulltext?', require('./search/hot'));
6
6
  router.get('/super_index/:id/:type?/:routeParams?', require('./super_index'));
7
7
  router.get('/timeline/:uid/:feature?/:routeParams?', require('./timeline'));
8
8
  router.get('/user/:uid/:routeParams?', require('./user'));
@@ -1,7 +1,17 @@
1
1
  const got = require('@/utils/got');
2
+ const config = require('@/config').value;
3
+ const { art } = require('@/utils/render');
4
+ const cheerio = require('cheerio');
5
+ const path = require('path');
2
6
  // const weiboUtils = require('../utils');
3
7
 
8
+ // Default hide all picture
9
+ let wpic = 'false';
10
+ let fullpic = 'false';
11
+
4
12
  module.exports = async (ctx) => {
13
+ wpic = ctx.query.pic ?? 'false';
14
+ fullpic = ctx.query.fullpic ?? 'false';
5
15
  const {
6
16
  data: { data },
7
17
  } = await got({
@@ -15,21 +25,122 @@ module.exports = async (ctx) => {
15
25
  },
16
26
  });
17
27
 
18
- ctx.state.data = {
19
- title: '微博热搜榜',
20
- link: 'https://s.weibo.com/top/summary?cate=realtimehot',
21
- description: '实时热点,每分钟更新一次',
22
- item: data.cards[0].card_group.map((item) => {
28
+ let resultItems = null;
29
+ if (ctx.params.fulltext === 'fulltext') {
30
+ const cardslist = data.cards[0].card_group;
31
+ // Topic List
32
+ const tlist = cardslist.map((item) => {
23
33
  const title = item.desc;
24
34
  const link = `https://m.weibo.cn/search?containerid=100103type%3D1%26q%3D${encodeURIComponent(item.desc)}`;
25
- const description = item.desc;
35
+ const plink = `https://m.weibo.cn/api/container/getIndex?containerid=100103type%3D1%26q%3D${encodeURIComponent(item.desc)}`;
36
+ return {
37
+ title,
38
+ link,
39
+ plink,
40
+ };
41
+ });
26
42
 
43
+ resultItems = await Promise.all(
44
+ tlist.map((i) =>
45
+ ctx.cache.tryGet(i.plink, async () => {
46
+ const pInfo = await fetchContent(i.plink);
47
+ i.description = pInfo.content;
48
+ return i;
49
+ })
50
+ )
51
+ );
52
+ } else {
53
+ resultItems = data.cards[0].card_group.map((item) => {
54
+ const title = item.desc;
55
+ const link = `https://m.weibo.cn/search?containerid=100103type%3D1%26q%3D${encodeURIComponent(item.desc)}`;
56
+ const description = item.desc;
27
57
  return {
28
58
  title,
29
59
  description,
30
60
  link,
31
61
  };
32
- }),
62
+ });
63
+ }
64
+
65
+ // Update ctx
66
+ ctx.state.data = {
67
+ title: '微博热搜榜',
68
+ link: 'https://s.weibo.com/top/summary?cate=realtimehot',
69
+ description: '实时热点,每分钟更新一次',
70
+ item: resultItems,
33
71
  };
34
72
  // ctx.state.data = weiboUtils.sinaimgTvax(ctx.state.data); // no image in the route
35
73
  };
74
+
75
+ async function fetchContent(url) {
76
+ // Fetch the subpageinof
77
+ const cookieString = config.weibo.cookies ? config.weibo.cookies : '';
78
+ const subres = await got(url, {
79
+ headers: {
80
+ Cookie: cookieString,
81
+ },
82
+ });
83
+ let demostr = '';
84
+ try {
85
+ const rdata = subres.data;
86
+ const cards = rdata.data.cards;
87
+ // Need to find one cards with 'type ==9'
88
+ demostr = seekContent(cards);
89
+ } catch (e) {
90
+ // console.log(e);
91
+ // console.log(url);
92
+ }
93
+ const ret = demostr;
94
+ return {
95
+ content: ret,
96
+ };
97
+ }
98
+
99
+ function seekContent(clist) {
100
+ const $ = cheerio.load('<div id="wbcontent"></div>');
101
+ const stub = $('#wbcontent');
102
+
103
+ // To for..of per reviewers comment
104
+ // Need to find one clist with 'type ==9'
105
+ for (const curitem of clist) {
106
+ if (curitem.card_type === 9) {
107
+ const tbpic = curitem.mblog.thumbnail_pic ?? '';
108
+ const index = tbpic.lastIndexOf('/');
109
+ const thumbfolder = tbpic.substring(0, index + 1);
110
+
111
+ const curcontent = cheerio.load(curitem.mblog.text);
112
+ if (wpic === 'true') {
113
+ curcontent('img').attr('width', '1em').attr('height', '1em');
114
+ } else {
115
+ curcontent('img').remove();
116
+ }
117
+ const section = art(path.join(__dirname, 'template/digest.art'), {
118
+ author: {
119
+ link: curitem.mblog.user.profile_url,
120
+ name: curitem.mblog.user.screen_name,
121
+ },
122
+ msg: curcontent.html(),
123
+ link: curitem.scheme,
124
+ postinfo: curitem.mblog.created_at,
125
+ picnum: wpic === 'true' ? curitem.mblog.pic_num : 0,
126
+ pics:
127
+ wpic === 'true' && curitem.mblog.pic_num > 0
128
+ ? curitem.mblog.pics.map((item) => {
129
+ // Get thumbnail_pic instead of orginal ones
130
+ const pid = item.pid;
131
+ if (fullpic === 'false') {
132
+ return { url: thumbfolder + pid + '.jpg', rurl: item.url };
133
+ } else {
134
+ return { url: item.url, rurl: item.url };
135
+ }
136
+ })
137
+ : [],
138
+ });
139
+ stub.append(section);
140
+ }
141
+ if (curitem.card_type === 11) {
142
+ stub.append(seekContent(curitem.card_group));
143
+ }
144
+ }
145
+ return stub.html();
146
+ }
@@ -0,0 +1,17 @@
1
+ <div class="quoted">
2
+ <a style="text-decoration: none;" href="{{ author.link }}">{{ author.name }}</a>
3
+ <span><a href="{{link }}"> | {{ postinfo }} </a></span>
4
+ </div>
5
+ <div class="content">
6
+ {{@ msg }}
7
+ </div>
8
+
9
+ {{if picnum > 0 }}
10
+ <br>
11
+ <div class='pic-row'>
12
+ {{each pics}}
13
+ <a href="{{$value.rurl}}"><img src="{{$value.url}}" ></a>
14
+ {{/each}}
15
+ </div>
16
+ {{/if}}
17
+ <hr>
@@ -14,20 +14,30 @@ const getUser = (url, cache) =>
14
14
  page.on('request', (request) => {
15
15
  request.resourceType() === 'document' || request.resourceType() === 'script' || request.resourceType() === 'xhr' || request.resourceType() === 'other' ? request.continue() : request.abort();
16
16
  });
17
- logger.debug(`Requesting ${url}`);
17
+ logger.http(`Requesting ${url}`);
18
18
  await page.goto(url, {
19
19
  waitUntil: 'domcontentloaded',
20
20
  });
21
21
  await page.waitForSelector('div.reds-tab-item:nth-child(2)');
22
- await page.click('div.reds-tab-item:nth-child(2)');
23
- const response = await page.waitForResponse((res) => {
24
- const req = res.request();
25
- return req.url().includes('/api/sns/web/v2/note/collect/page') && req.method() === 'GET' && req.resourceType() === 'xhr';
26
- });
27
- collect = await response.json();
28
22
 
29
23
  const initialState = await page.evaluate(() => window.__INITIAL_STATE__);
30
24
 
25
+ if (!(await page.$('.lock-icon'))) {
26
+ await page.click('div.reds-tab-item:nth-child(2)');
27
+ try {
28
+ const response = await page.waitForResponse(
29
+ (res) => {
30
+ const req = res.request();
31
+ return req.url().includes('/api/sns/web/v2/note/collect/page') && req.method() === 'GET' && req.resourceType() === 'xhr';
32
+ },
33
+ { timeout: 5000 }
34
+ );
35
+ collect = await response.json();
36
+ } catch (e) {
37
+ //
38
+ }
39
+ }
40
+
31
41
  let { userPageData, notes } = initialState.user;
32
42
  userPageData = userPageData._rawValue || userPageData;
33
43
  notes = notes._rawValue || notes;
File without changes
@@ -1,3 +1,4 @@
1
1
  module.exports = {
2
2
  '/epaper/:id?': ['nczitzk'],
3
+ '/news/:category?': ['nczitzk'],
3
4
  };