specific-ai-cli 0.0.0-stage → 0.1.1

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 (277) hide show
  1. package/LICENSE +21 -0
  2. package/README.en.md +177 -0
  3. package/README.ja.md +177 -0
  4. package/README.ko.md +177 -0
  5. package/README.md +174 -2
  6. package/README.zh-TW.md +177 -0
  7. package/assets/banner.txt +3 -0
  8. package/dist/cli/argv.js +98 -0
  9. package/dist/cli/commands/auth.js +11 -0
  10. package/dist/cli/commands/config.js +23 -0
  11. package/dist/cli/commands/doctor.js +134 -0
  12. package/dist/cli/commands/platforms.js +24 -0
  13. package/dist/cli/commands/version.js +4 -0
  14. package/dist/cli/confirm.js +22 -0
  15. package/dist/cli/dispatch.js +440 -0
  16. package/dist/cli/help.js +223 -0
  17. package/dist/cli/hints.js +60 -0
  18. package/dist/cli/main.js +18 -0
  19. package/dist/cli/output.js +66 -0
  20. package/dist/core/auth-handlers.js +41 -0
  21. package/dist/core/auth-store.js +119 -0
  22. package/dist/core/capabilities.js +163 -0
  23. package/dist/core/config.js +121 -0
  24. package/dist/core/cookies.js +164 -0
  25. package/dist/core/errors.js +37 -0
  26. package/dist/core/files.js +89 -0
  27. package/dist/core/fsutil.js +52 -0
  28. package/dist/core/hash.js +4 -0
  29. package/dist/core/http.js +331 -0
  30. package/dist/core/image.js +280 -0
  31. package/dist/core/log.js +40 -0
  32. package/dist/core/login.js +191 -0
  33. package/dist/core/mp4.js +130 -0
  34. package/dist/core/normalize.js +207 -0
  35. package/dist/core/options.js +110 -0
  36. package/dist/core/paths.js +38 -0
  37. package/dist/core/pb.js +59 -0
  38. package/dist/core/py.js +181 -0
  39. package/dist/core/rand.js +131 -0
  40. package/dist/core/registry.js +129 -0
  41. package/dist/core/schemas.js +41 -0
  42. package/dist/core/stream.js +104 -0
  43. package/dist/core/toolkit.js +35 -0
  44. package/dist/core/vm.js +73 -0
  45. package/dist/core/vocab.js +157 -0
  46. package/dist/platforms/_shared/impaas.js +410 -0
  47. package/dist/platforms/bilibili/index.js +216 -0
  48. package/dist/platforms/bilibili/web/api.js +806 -0
  49. package/dist/platforms/bilibili/web/client.js +311 -0
  50. package/dist/platforms/bilibili/web/commands.js +783 -0
  51. package/dist/platforms/bilibili/web/ddddocr.js +342 -0
  52. package/dist/platforms/bilibili/web/gaia.js +130 -0
  53. package/dist/platforms/bilibili/web/geetest-manual.js +154 -0
  54. package/dist/platforms/bilibili/web/geetest-vision.js +232 -0
  55. package/dist/platforms/bilibili/web/geetest.js +450 -0
  56. package/dist/platforms/bilibili/web/normalize.js +234 -0
  57. package/dist/platforms/bilibili/web/profile.js +135 -0
  58. package/dist/platforms/bilibili/web/resolve.js +112 -0
  59. package/dist/platforms/bilibili/web/sign.js +223 -0
  60. package/dist/platforms/bilibili/web/upos.js +102 -0
  61. package/dist/platforms/douyin/index.js +142 -0
  62. package/dist/platforms/douyin/web/api.js +863 -0
  63. package/dist/platforms/douyin/web/client.js +413 -0
  64. package/dist/platforms/douyin/web/commands.js +712 -0
  65. package/dist/platforms/douyin/web/creator.js +601 -0
  66. package/dist/platforms/douyin/web/crypto.js +247 -0
  67. package/dist/platforms/douyin/web/dtrait.js +190 -0
  68. package/dist/platforms/douyin/web/im.js +502 -0
  69. package/dist/platforms/douyin/web/image.js +5 -0
  70. package/dist/platforms/douyin/web/live.js +225 -0
  71. package/dist/platforms/douyin/web/mssdk.js +148 -0
  72. package/dist/platforms/douyin/web/normalize.js +326 -0
  73. package/dist/platforms/douyin/web/passport.js +1247 -0
  74. package/dist/platforms/douyin/web/profile.js +221 -0
  75. package/dist/platforms/douyin/web/proto.js +26 -0
  76. package/dist/platforms/douyin/web/resolve.js +88 -0
  77. package/dist/platforms/douyin/web/sign.js +436 -0
  78. package/dist/platforms/douyin/web/tos.js +78 -0
  79. package/dist/platforms/index.js +17 -0
  80. package/dist/platforms/jd/index.js +67 -0
  81. package/dist/platforms/jd/web/aks.js +115 -0
  82. package/dist/platforms/jd/web/api.js +549 -0
  83. package/dist/platforms/jd/web/chat.js +132 -0
  84. package/dist/platforms/jd/web/client.js +470 -0
  85. package/dist/platforms/jd/web/commands.js +557 -0
  86. package/dist/platforms/jd/web/jcap/helper.js +90 -0
  87. package/dist/platforms/jd/web/jcap/host.js +107 -0
  88. package/dist/platforms/jd/web/jcap/lsd.js +300 -0
  89. package/dist/platforms/jd/web/jcap/solver.js +995 -0
  90. package/dist/platforms/jd/web/jcap.js +150 -0
  91. package/dist/platforms/jd/web/js.js +420 -0
  92. package/dist/platforms/jd/web/login.js +775 -0
  93. package/dist/platforms/jd/web/normalize.js +297 -0
  94. package/dist/platforms/jd/web/profile.js +256 -0
  95. package/dist/platforms/jd/web/util.js +175 -0
  96. package/dist/platforms/jd/web/webm.js +133 -0
  97. package/dist/platforms/kuaishou/index.js +98 -0
  98. package/dist/platforms/kuaishou/web/api.js +694 -0
  99. package/dist/platforms/kuaishou/web/captcha-crypto.js +134 -0
  100. package/dist/platforms/kuaishou/web/captcha-fp.js +180 -0
  101. package/dist/platforms/kuaishou/web/captcha.js +273 -0
  102. package/dist/platforms/kuaishou/web/client.js +487 -0
  103. package/dist/platforms/kuaishou/web/commands.js +863 -0
  104. package/dist/platforms/kuaishou/web/gap.js +144 -0
  105. package/dist/platforms/kuaishou/web/gdfp.js +376 -0
  106. package/dist/platforms/kuaishou/web/gql.js +11 -0
  107. package/dist/platforms/kuaishou/web/live.js +125 -0
  108. package/dist/platforms/kuaishou/web/normalize.js +241 -0
  109. package/dist/platforms/kuaishou/web/oracle.js +329 -0
  110. package/dist/platforms/kuaishou/web/profile.js +259 -0
  111. package/dist/platforms/kuaishou/web/resolve.js +84 -0
  112. package/dist/platforms/kuaishou/web/session.js +592 -0
  113. package/dist/platforms/kuaishou/web/sign.js +568 -0
  114. package/dist/platforms/taobao/index.js +56 -0
  115. package/dist/platforms/taobao/web/api.js +96 -0
  116. package/dist/platforms/taobao/web/client.js +102 -0
  117. package/dist/platforms/taobao/web/commands.js +172 -0
  118. package/dist/platforms/taobao/web/im.js +68 -0
  119. package/dist/platforms/taobao/web/normalize.js +103 -0
  120. package/dist/platforms/taobao/web/profile.js +85 -0
  121. package/dist/platforms/taobao/web/resolve.js +51 -0
  122. package/dist/platforms/taobao/web/sign.js +35 -0
  123. package/dist/platforms/tiktok/index.js +120 -0
  124. package/dist/platforms/tiktok/web/api.js +1234 -0
  125. package/dist/platforms/tiktok/web/client.js +362 -0
  126. package/dist/platforms/tiktok/web/commands.js +821 -0
  127. package/dist/platforms/tiktok/web/im.js +133 -0
  128. package/dist/platforms/tiktok/web/jsrun.js +126 -0
  129. package/dist/platforms/tiktok/web/normalize.js +286 -0
  130. package/dist/platforms/tiktok/web/profile.js +169 -0
  131. package/dist/platforms/tiktok/web/resolve.js +156 -0
  132. package/dist/platforms/tiktok/web/sign.js +585 -0
  133. package/dist/platforms/tiktok/web/upload.js +805 -0
  134. package/dist/platforms/tiktok/web/wire.js +490 -0
  135. package/dist/platforms/weibo/index.js +91 -0
  136. package/dist/platforms/weibo/web/api.js +206 -0
  137. package/dist/platforms/weibo/web/client.js +155 -0
  138. package/dist/platforms/weibo/web/commands.js +202 -0
  139. package/dist/platforms/weibo/web/normalize.js +137 -0
  140. package/dist/platforms/weibo/web/profile.js +246 -0
  141. package/dist/platforms/weibo/web/resolve.js +60 -0
  142. package/dist/platforms/weibo/web/sign.js +85 -0
  143. package/dist/platforms/x/index.js +107 -0
  144. package/dist/platforms/x/web/api.js +443 -0
  145. package/dist/platforms/x/web/article.js +212 -0
  146. package/dist/platforms/x/web/client.js +202 -0
  147. package/dist/platforms/x/web/commands.js +363 -0
  148. package/dist/platforms/x/web/graphql.js +108 -0
  149. package/dist/platforms/x/web/normalize.js +235 -0
  150. package/dist/platforms/x/web/profile.js +99 -0
  151. package/dist/platforms/x/web/resolve.js +44 -0
  152. package/dist/platforms/x/web/transaction.js +171 -0
  153. package/dist/platforms/xhs/index.js +101 -0
  154. package/dist/platforms/xhs/web/api.js +278 -0
  155. package/dist/platforms/xhs/web/client.js +540 -0
  156. package/dist/platforms/xhs/web/commands.js +1046 -0
  157. package/dist/platforms/xhs/web/creator-api.js +609 -0
  158. package/dist/platforms/xhs/web/creator.js +203 -0
  159. package/dist/platforms/xhs/web/js.js +194 -0
  160. package/dist/platforms/xhs/web/login.js +230 -0
  161. package/dist/platforms/xhs/web/normalize.js +166 -0
  162. package/dist/platforms/xhs/web/profile.js +127 -0
  163. package/dist/platforms/xhs/web/push.js +361 -0
  164. package/dist/platforms/xhs/web/resolve.js +69 -0
  165. package/dist/platforms/xhs/web/state.js +368 -0
  166. package/dist/platforms/xianyu/index.js +59 -0
  167. package/dist/platforms/xianyu/web/api.js +312 -0
  168. package/dist/platforms/xianyu/web/client.js +134 -0
  169. package/dist/platforms/xianyu/web/commands.js +305 -0
  170. package/dist/platforms/xianyu/web/im.js +73 -0
  171. package/dist/platforms/xianyu/web/normalize.js +123 -0
  172. package/dist/platforms/xianyu/web/profile.js +146 -0
  173. package/dist/platforms/xianyu/web/resolve.js +48 -0
  174. package/dist/platforms/xianyu/web/sign.js +79 -0
  175. package/package.json +77 -4
  176. package/static/douyin/Live.proto +194 -0
  177. package/static/douyin/Request.proto +89 -0
  178. package/static/douyin/Response.proto +46 -0
  179. package/static/douyin/acrawler_runtime/ac_vm.js +2 -0
  180. package/static/douyin/acrawler_runtime/browser_window_shape.json +1 -0
  181. package/static/douyin/acrawler_runtime/canvas_actual_exact.json +1 -0
  182. package/static/douyin/acrawler_runtime/run_ac_node.js +1005 -0
  183. package/static/douyin/acrawler_runtime/runner_window_keys_baseline.txt +240 -0
  184. package/static/douyin/challenge_profile.json +801 -0
  185. package/static/douyin/challenge_template_runner.js +217 -0
  186. package/static/douyin/dtrait_profile.json +66 -0
  187. package/static/douyin/mstoken_common_profile.json +1 -0
  188. package/static/douyin/mstoken_profile.json +214 -0
  189. package/static/jd/h5st5_env.js +750 -0
  190. package/static/jd/h5st5_lib.js +5 -0
  191. package/static/jd/h5st5_server.js +49 -0
  192. package/static/jd/jcap/env/env_core.js +512 -0
  193. package/static/jd/jcap/env/run.js +1307 -0
  194. package/static/jd/jcap/run/jcap_ujb96b.js +39 -0
  195. package/static/jd/package.json +4 -0
  196. package/static/jd/pc_tk_lib.js +1 -0
  197. package/static/jd/pc_tk_server.js +63 -0
  198. package/static/jd/summer_cryptico_runner.js +50 -0
  199. package/static/jd/webm/env/run.js +453 -0
  200. package/static/jd/webm/run/jdwebm-riskhandle.js +49 -0
  201. package/static/kuaishou/bundles/weapon/kwf-0.0.2.2cee19b4b7dec496.js +1 -0
  202. package/static/kuaishou/bundles/weapon/kws-0-0.0.1-obfuscated.4b7f3de1ab0ddcc2.js +1 -0
  203. package/static/kuaishou/bundles/weapon/kws-1-0.0.1-obfuscated.346ebdb1c78df316.js +1 -0
  204. package/static/kuaishou/bundles/weapon/kws-10-0.0.1-obfuscated.a33db41897b983af.js +1 -0
  205. package/static/kuaishou/bundles/weapon/kws-11-0.0.1-obfuscated.5e0a90af726d8a7e.js +1 -0
  206. package/static/kuaishou/bundles/weapon/kws-12-0.0.1-obfuscated.20ea29345706ec8c.js +1 -0
  207. package/static/kuaishou/bundles/weapon/kws-13-0.0.1-obfuscated.6b74e9640ff18648.js +1 -0
  208. package/static/kuaishou/bundles/weapon/kws-14-0.0.1-obfuscated.551e4429d156bf66.js +1 -0
  209. package/static/kuaishou/bundles/weapon/kws-15-0.0.1-obfuscated.8625b087aaba4a60.js +1 -0
  210. package/static/kuaishou/bundles/weapon/kws-16-0.0.1-obfuscated.d5ffa4020f3be99a.js +1 -0
  211. package/static/kuaishou/bundles/weapon/kws-17-0.0.1-obfuscated.6d13e19b22f50a80.js +1 -0
  212. package/static/kuaishou/bundles/weapon/kws-18-0.0.1-obfuscated.6d31405044166289.js +1 -0
  213. package/static/kuaishou/bundles/weapon/kws-19-0.0.1-obfuscated.a9a8d925942f19e4.js +1 -0
  214. package/static/kuaishou/bundles/weapon/kws-2-0.0.1-obfuscated.b849a136ae4a6b3e.js +1 -0
  215. package/static/kuaishou/bundles/weapon/kws-3-0.0.1-obfuscated.f9e77ebf6186e2ac.js +1 -0
  216. package/static/kuaishou/bundles/weapon/kws-4-0.0.1-obfuscated.2c3c155aa52ceb0e.js +1 -0
  217. package/static/kuaishou/bundles/weapon/kws-5-0.0.1-obfuscated.4e553d17691b3c5a.js +1 -0
  218. package/static/kuaishou/bundles/weapon/kws-6-0.0.1-obfuscated.f73ddd3ff13e1217.js +1 -0
  219. package/static/kuaishou/bundles/weapon/kws-7-0.0.1-obfuscated.1628b8729beaab7e.js +1 -0
  220. package/static/kuaishou/bundles/weapon/kws-8-0.0.1-obfuscated.6da6baef7aa81fff.js +1 -0
  221. package/static/kuaishou/bundles/weapon/kws-9-0.0.1-obfuscated.8645d55e5323b743.js +1 -0
  222. package/static/kuaishou/fixtures/current_follow_script_813.network-response +2 -0
  223. package/static/kuaishou/fixtures/live_ws_maps.json +61 -0
  224. package/static/kuaishou/fixtures/live_ws_proto.json +1342 -0
  225. package/static/kuaishou/js/cp-kwf.js +1 -0
  226. package/static/kuaishou/tools/kwf_oracle.js +799 -0
  227. package/static/kuaishou/tools/kws_oracle.js +885 -0
  228. package/static/kuaishou/tools/like_token_oracle.js +70 -0
  229. package/static/taobao/taobao_js_20260407.js +570 -0
  230. package/static/tiktok/Tiktok_Request.json +597 -0
  231. package/static/tiktok/package.json +3 -0
  232. package/static/tiktok/shop_bsid/core.js +1 -0
  233. package/static/tiktok/shop_bsid/env_core.js +512 -0
  234. package/static/tiktok/shop_bsid/loader.js +1 -0
  235. package/static/tiktok/shop_bsid/run.js +753 -0
  236. package/static/tiktok/shop_bsid/sign.js +100 -0
  237. package/static/tiktok/shop_bsid/webmssdk.js +1 -0
  238. package/static/tiktok/shop_bsid/webmssdk_ex.js +1 -0
  239. package/static/tiktok/signing/env/env_core.js +512 -0
  240. package/static/tiktok/signing/env/sign.js +455 -0
  241. package/static/tiktok/signing/sdk_config.json +230 -0
  242. package/static/tiktok/signing/source/webmssdk.js +1 -0
  243. package/static/tiktok/signing/source/webmssdk_ex.js +1 -0
  244. package/static/tiktok/signing/source/webmssdk_legacy.js +1 -0
  245. package/static/x/graphql.json +7777 -0
  246. package/static/x/transaction_l1.json +12 -0
  247. package/static/xhs/package.json +3 -0
  248. package/static/xhs/xhs_core/js/b1.js +210 -0
  249. package/static/xhs/xhs_core/js/mns.js +340 -0
  250. package/static/xhs/xhs_core/js/mns_0101_keystream.json +5 -0
  251. package/static/xhs/xhs_core/js/mns_keystreams.json +1 -0
  252. package/static/xhs/xhs_core/js/sign.js +225 -0
  253. package/static/xhs/xhs_core/js/websectiga_cli.js +220 -0
  254. package/static/xhs/xhs_core/js/websectiga_env.js +512 -0
  255. package/static/xhs/xhs_core/js/xs_common.js +79 -0
  256. package/static/xhs/xhs_creator/js/profile.js +115 -0
  257. package/static/xhs/xhs_creator/js/rap_fingerprint_creator.json +6 -0
  258. package/static/xhs/xhs_creator/js/reference_profile.json +282 -0
  259. package/static/xhs/xhs_creator/js/xhs_creator_sign.js +29 -0
  260. package/static/xhs/xhs_creator/js/xhs_creator_signature.js +23 -0
  261. package/static/xhs/xhs_pc/js/aes_decrypt.js +22 -0
  262. package/static/xhs/xhs_pc/js/aes_encrypt.js +30 -0
  263. package/static/xhs/xhs_pc/js/b1.js +9 -0
  264. package/static/xhs/xhs_pc/js/deflate.js +320 -0
  265. package/static/xhs/xhs_pc/js/mns.js +4 -0
  266. package/static/xhs/xhs_pc/js/profile.js +141 -0
  267. package/static/xhs/xhs_pc/js/rap.js +173 -0
  268. package/static/xhs/xhs_pc/js/rap_cli.js +30 -0
  269. package/static/xhs/xhs_pc/js/rap_crypto.js +73 -0
  270. package/static/xhs/xhs_pc/js/rap_fingerprint_template.json +8 -0
  271. package/static/xhs/xhs_pc/js/reference_profile.json +262 -0
  272. package/static/xhs/xhs_pc/js/sign.js +6 -0
  273. package/static/xhs/xhs_pc/js/web_ssk.js +82 -0
  274. package/static/xhs/xhs_pc/js/xs_common.js +4 -0
  275. package/static/xianyu/et_f.js +2 -0
  276. package/static/xianyu/gen_tfstk.js +410 -0
  277. package/static/xianyu/goofish_js_version_2.js +568 -0
@@ -0,0 +1,806 @@
1
+ import { SpecificAIError } from '../../../core/errors.js';
2
+ import {} from '../../../core/http.js';
3
+ import { compactJson, jsonDumps, quote } from '../../../core/py.js';
4
+ import * as rand from '../../../core/rand.js';
5
+ import { API, headers, LIVE_API, MEMBER, ORIGIN, PASSPORT, PROFILE } from './profile.js';
6
+ import { bv2av, dumps, qvId, randomHex } from './sign.js';
7
+ /**
8
+ * 上游 apis/*.py 的请求构造,一个函数对应一个上游方法,字段与顺序照抄(对拍测试逐字节比较)。
9
+ * 返回平台原始 JSON 的 data(`call`)或整个 JSON(`raw`)。
10
+ */
11
+ const MAIN = ORIGIN.main;
12
+ const VIDEO_SPMID = '333.788.0.0';
13
+ const STATISTICS = '{"appId":100,"platform":5}';
14
+ const STATISTICS_DM = '{"appId":100,"platform":5,"abtest":"","version":""}';
15
+ /** 设置 web_location:已有同名参数时原位替换,否则追加(上游 with_web_location)。 */
16
+ function withLocation(params, value) {
17
+ const i = params.findIndex(([k]) => k === 'web_location');
18
+ if (i >= 0)
19
+ params[i] = ['web_location', value];
20
+ else
21
+ params.push(['web_location', value]);
22
+ return params;
23
+ }
24
+ // ================================================================ 主站(BiliApi)
25
+ export function nav(b) {
26
+ return b.json({ url: `${API}/x/web-interface/nav`, headers: headers('GET', { accept: '*/*' }).get() });
27
+ }
28
+ export async function searchType(b, keyword, order = 'totalrank', page = 1, searchType = 'video') {
29
+ const h = headers('GET', { origin: ORIGIN.search }).referer(`https://search.bilibili.com/all?keyword=${quote(keyword)}`);
30
+ const params = [
31
+ ['__refresh__', 'true'],
32
+ ['_extra', ''],
33
+ ['ad_resource', '5654'],
34
+ ['category_id', ''],
35
+ ['context', ''],
36
+ ['dynamic_offset', (page - 1) * 24],
37
+ ['from_source', ''],
38
+ ['from_spmid', '333.337'],
39
+ ['gaia_vtoken', ''],
40
+ ['highlight', 1],
41
+ ['keyword', keyword],
42
+ ['order', order],
43
+ ['page', page],
44
+ ['page_size', 42],
45
+ ['platform', 'pc'],
46
+ ['qv_id', qvId()],
47
+ ['search_type', searchType],
48
+ ['single_column', 0],
49
+ ['source_tag', 3],
50
+ ];
51
+ return b.get(`${API}/x/web-interface/wbi/search/type`, { headers: h.get(), query: await b.wbi(withLocation(params, '1430654')) });
52
+ }
53
+ export async function videoInfo(b, bvid) {
54
+ const h = headers('GET').referer(`${MAIN}/video/${bvid}`);
55
+ return b.get(`${API}/x/web-interface/wbi/view`, { headers: h.get(), query: await b.wbi([['bvid', bvid]]) });
56
+ }
57
+ /** 稿件完整信息,含相关推荐 `Related`(上游 get_video_detail)。 */
58
+ export async function videoDetail(b, bvid, page = 1) {
59
+ const h = headers('GET').referer(`${MAIN}/video/${bvid}`);
60
+ const params = withLocation([
61
+ ['aid', bv2av(bvid)],
62
+ ['p', page],
63
+ ['isGaiaAvoided', 'false'],
64
+ ['platform', 'web'],
65
+ ], '1315873');
66
+ return b.get(`${API}/x/web-interface/wbi/view/detail`, { headers: h.get(), query: await b.wbi(params) });
67
+ }
68
+ export async function playerInfo(b, aid, cid) {
69
+ const h = headers('GET').referer(`${MAIN}/`);
70
+ const params = withLocation([
71
+ ['aid', aid],
72
+ ['cid', cid],
73
+ ['isGaiaAvoided', 'false'],
74
+ ], '1315873');
75
+ return b.get(`${API}/x/player/wbi/v2`, { headers: h.get(), query: await b.wbiDm(params) });
76
+ }
77
+ export async function playUrl(b, bvid, cid, qn = 80, fnval = 4048) {
78
+ const h = headers('GET').referer(`${MAIN}/video/${bvid}`);
79
+ const params = [
80
+ ['avid', bv2av(bvid)],
81
+ ['bvid', bvid],
82
+ ['cid', cid],
83
+ ['qn', qn],
84
+ ['fnver', 0],
85
+ ['fnval', fnval],
86
+ ['fourk', 1],
87
+ ['gaia_source', ''],
88
+ ['from_client', 'BROWSER'],
89
+ ['is_main_page', 'true'],
90
+ ['need_fragment', 'false'],
91
+ ['isGaiaAvoided', 'false'],
92
+ ['session', randomHex(32)],
93
+ ];
94
+ return b.get(`${API}/x/player/wbi/playurl`, { headers: h.get(), query: await b.wbi(withLocation(params, '1315873')) });
95
+ }
96
+ export async function danmakuSeg(b, aid, cid, segment = 1) {
97
+ const h = headers('GET', { accept: '*/*' }).referer(`${MAIN}/`);
98
+ const params = withLocation([
99
+ ['type', 1],
100
+ ['oid', cid],
101
+ ['pid', aid],
102
+ ['segment_index', segment],
103
+ ['pull_mode', 1],
104
+ ['ps', 0],
105
+ ['pe', 120000],
106
+ ], '1315873');
107
+ return b.bytes({ url: `${API}/x/v2/dm/wbi/web/seg.so`, headers: h.get(), query: await b.wbi(params) });
108
+ }
109
+ /**
110
+ * 评论区:type 1 视频(oid 为 aid)、12 专栏(cv 号)、17 动态(动态 ID);mode 3 热门、2 时间。
111
+ * offset 是翻页游标:首页传空串,下一页传上一页响应的 cursor.pagination_reply.next_offset。
112
+ * 旧的页码参数 next 服务端已经不认(cursor.next 恒为 0),只靠它翻页会一直拿到首页。上游 get_replies。
113
+ */
114
+ export async function replies(b, oid, type = 1, offset = '', mode = 3) {
115
+ const h = headers('GET').referer(`${MAIN}/`);
116
+ const params = [
117
+ ['oid', oid],
118
+ ['type', type],
119
+ ['mode', mode],
120
+ ['pagination_str', jsonDumps({ offset }, { separators: [',', ':'] })],
121
+ ['plat', 1],
122
+ ['seek_rpid', ''],
123
+ ];
124
+ return b.get(`${API}/x/v2/reply/wbi/main`, { headers: h.get(), query: await b.wbi(withLocation(params, '1315875')) });
125
+ }
126
+ export async function userInfo(b, mid) {
127
+ const h = headers('GET', { origin: ORIGIN.space }).referer(`https://space.bilibili.com/${mid}`);
128
+ const params = withLocation([
129
+ ['mid', mid],
130
+ ['token', ''],
131
+ ['platform', 'web'],
132
+ ], '1550101');
133
+ return b.get(`${API}/x/space/wbi/acc/info`, { headers: h.get(), query: await b.wbiDm(params) });
134
+ }
135
+ export async function userVideos(b, mid, page = 1, pageSize = 42, order = 'pubdate', keyword = '') {
136
+ const h = headers('GET', { origin: ORIGIN.space }).referer(`https://space.bilibili.com/${mid}/video`);
137
+ const params = withLocation([
138
+ ['pn', page],
139
+ ['ps', pageSize],
140
+ ['tid', 0],
141
+ ['special_type', ''],
142
+ ['order', order],
143
+ ['mid', mid],
144
+ ['index', 0],
145
+ ['keyword', keyword],
146
+ ['order_avoided', 'true'],
147
+ ['platform', 'web'],
148
+ ], '333.1387');
149
+ return b.get(`${API}/x/space/wbi/arc/search`, { headers: h.get(), query: await b.wbiDm(params) });
150
+ }
151
+ export async function rcmdFeed(b, freshIdx = 1, ps = 12, lastShowlist = '') {
152
+ const h = headers('GET').referer(`${MAIN}/`);
153
+ const params = [
154
+ ['web_location', '1430650'],
155
+ ['y_num', 4],
156
+ ['fresh_type', 4],
157
+ ['feed_version', 'V8'],
158
+ ['fresh_idx_1h', freshIdx],
159
+ ['fetch_row', 4],
160
+ ['fresh_idx', freshIdx],
161
+ ['brush', freshIdx],
162
+ ['device', 'win'],
163
+ ['homepage_ver', 1],
164
+ ['ps', ps],
165
+ ['last_y_num', 5],
166
+ ['screen', PROFILE.browserResolution],
167
+ ['seo_info', ''],
168
+ ['tt_exp', ''],
169
+ ['last_showlist', lastShowlist],
170
+ ['uniq_id', String(rand.randint(10 ** 12, 10 ** 13 - 1))],
171
+ ];
172
+ return b.get(`${API}/x/web-interface/wbi/index/top/feed/rcmd`, { headers: h.get(), query: await b.wbi(params) });
173
+ }
174
+ export async function popular(b, page = 1, pageSize = 20) {
175
+ const h = headers('GET').referer(`${MAIN}/v/popular/all/`);
176
+ const params = withLocation([
177
+ ['ps', pageSize],
178
+ ['pn', page],
179
+ ], '333.934');
180
+ return b.get(`${API}/x/web-interface/popular`, { headers: h.get(), query: await b.wbi(params) });
181
+ }
182
+ // ================================================================ 互动(BiliInteractApi)
183
+ function playerFields(paused = false, played = 0) {
184
+ return [
185
+ ['eab_x', paused ? 2 : 1],
186
+ ['ramval', played],
187
+ ['source', 'web_normal'],
188
+ ['ga', 1],
189
+ ];
190
+ }
191
+ export function like(b, bvid, on = true) {
192
+ const h = headers('FORM').referer(`${MAIN}/video/${bvid}`);
193
+ const form = [
194
+ ['aid', bv2av(bvid)],
195
+ ['like', on ? 1 : 2],
196
+ ['from_spmid', ''],
197
+ ['spmid', VIDEO_SPMID],
198
+ ['statistics', STATISTICS],
199
+ ...playerFields(),
200
+ ['csrf', b.csrf],
201
+ ];
202
+ return b.post(`${API}/x/web-interface/archive/like`, { headers: h.get(), form });
203
+ }
204
+ export function addCoin(b, bvid, num = 1, alsoLike = false) {
205
+ const h = headers('FORM').referer(`${MAIN}/video/${bvid}`);
206
+ const form = [
207
+ ['aid', bv2av(bvid)],
208
+ ['multiply', num],
209
+ ['select_like', alsoLike ? 1 : 0],
210
+ ['cross_domain', 'true'],
211
+ ['from_spmid', ''],
212
+ ['spmid', VIDEO_SPMID],
213
+ ['statistics', STATISTICS],
214
+ ...playerFields(),
215
+ ['csrf', b.csrf],
216
+ ];
217
+ return b.post(`${API}/x/web-interface/coin/add`, { headers: h.get(), form });
218
+ }
219
+ /** 我创建的收藏夹(上游 get_fav_folders),data.list[].id 即收藏时用的 media_id。 */
220
+ export function favFolders(b, mid) {
221
+ const h = headers('GET').referer(`${MAIN}/`);
222
+ const query = [
223
+ ['up_mid', mid ?? b.mid],
224
+ ['web_location', '333.999'],
225
+ ];
226
+ return b.get(`${API}/x/v3/fav/folder/created/list-all`, { headers: h.get(), query });
227
+ }
228
+ /**
229
+ * 非上游:同一个接口多带 `type=2&rid=<aid>`(网页端收藏弹窗的请求),每项多一个 fav_state(这个稿件在不在该收藏夹里)。
230
+ * 只给 `item uncollect` 不带 --folder 时找「收着它的收藏夹」用,没有对拍。
231
+ */
232
+ export function favFoldersOf(b, aid) {
233
+ const h = headers('GET').referer(`${MAIN}/`);
234
+ const query = [
235
+ ['up_mid', b.mid],
236
+ ['type', 2],
237
+ ['rid', aid],
238
+ ['web_location', '333.999'],
239
+ ];
240
+ return b.get(`${API}/x/v3/fav/folder/created/list-all`, { headers: h.get(), query });
241
+ }
242
+ /**
243
+ * 非上游:收藏夹内容(`folder items`)。上游没有这个接口,按网页端收藏夹页的请求补的,没有对拍。
244
+ * media_id 是收藏夹 ID(folder list 的 id)。
245
+ */
246
+ export function favResources(b, mediaId, page = 1, pageSize = 20) {
247
+ const h = headers('GET').referer('https://space.bilibili.com/');
248
+ const query = [
249
+ ['media_id', mediaId],
250
+ ['pn', page],
251
+ ['ps', pageSize],
252
+ ['keyword', ''],
253
+ ['order', 'mtime'],
254
+ ['type', 0],
255
+ ['tid', 0],
256
+ ['platform', 'web'],
257
+ ['web_location', '333.1387'],
258
+ ];
259
+ return b.get(`${API}/x/v3/fav/resource/list`, { headers: h.get(), query });
260
+ }
261
+ export async function favour(b, aid, addMediaIds = '', delMediaIds = '') {
262
+ if (!addMediaIds && !delMediaIds) {
263
+ const folders = (await favFolders(b))?.list ?? [];
264
+ if (!folders.length)
265
+ throw new SpecificAIError('UPSTREAM', '没有可用的收藏夹', { hint: '先在网页端建一个收藏夹,或者用 --folder 指定' });
266
+ addMediaIds = String(folders[0].id);
267
+ }
268
+ const h = headers('FORM').referer(`${MAIN}/`);
269
+ const form = [
270
+ ['rid', aid],
271
+ ['type', 2],
272
+ ];
273
+ if (addMediaIds)
274
+ form.push(['add_media_ids', addMediaIds]);
275
+ if (delMediaIds)
276
+ form.push(['del_media_ids', delMediaIds]);
277
+ form.push(['platform', 'web'], ['from_spmid', ''], ['spmid', VIDEO_SPMID], ['statistics', STATISTICS], ['csrf', b.csrf]);
278
+ return b.post(`${API}/x/v3/fav/resource/deal`, { headers: h.get(), form });
279
+ }
280
+ export function triple(b, bvid) {
281
+ const h = headers('FORM').referer(`${MAIN}/video/${bvid}`);
282
+ const form = [
283
+ ['aid', bv2av(bvid)],
284
+ ['from_spmid', ''],
285
+ ['spmid', VIDEO_SPMID],
286
+ ['statistics', STATISTICS],
287
+ ...playerFields(),
288
+ ['csrf', b.csrf],
289
+ ];
290
+ return b.post(`${API}/x/web-interface/archive/like/triple`, { headers: h.get(), form });
291
+ }
292
+ /** 发评论;回复楼中楼时 root 为根评论、parent 为被回复的那条,parent 缺省同 root。 */
293
+ export async function addReply(b, oid, message, type = 1, root = '', parent = '') {
294
+ const h = headers('FORM').referer(`${MAIN}/`);
295
+ const query = await b.wbiDm([]);
296
+ const form = [
297
+ ['plat', 1],
298
+ ['oid', oid],
299
+ ['type', type],
300
+ ['message', message],
301
+ ['at_name_to_mid', '{}'],
302
+ ];
303
+ if (root)
304
+ form.push(['root', root], ['parent', parent || root]);
305
+ form.push(['gaia_source', 'main_web'], ['csrf', b.csrf], ['statistics', STATISTICS]);
306
+ return b.post(`${API}/x/v2/reply/add`, { headers: h.get(), query, form });
307
+ }
308
+ export function deleteReply(b, oid, rpid, type = 1) {
309
+ const h = headers('FORM').referer(`${MAIN}/`);
310
+ const form = [
311
+ ['oid', oid],
312
+ ['type', type],
313
+ ['rpid', rpid],
314
+ ['csrf', b.csrf],
315
+ ];
316
+ return b.post(`${API}/x/v2/reply/del`, { headers: h.get(), form });
317
+ }
318
+ /** 弹幕的 rnd:会话内自增序号(上游 itertools.count(1)),每条命令从 1 开始。 */
319
+ let dmSeq = 0;
320
+ export async function sendVideoDanmaku(b, aid, cid, message, progress = 0, style = {}) {
321
+ const h = headers('FORM').referer(`${MAIN}/`);
322
+ const query = await b.wbiDm([
323
+ ['web_location', '1315873'],
324
+ ['csrf', b.csrf],
325
+ ]);
326
+ const form = [
327
+ ['color', style.color ?? 16777215],
328
+ ['fontsize', style.fontsize ?? 25],
329
+ ['pool', 0],
330
+ ['mode', style.mode ?? 1],
331
+ ['type', 1],
332
+ ['oid', cid],
333
+ ['msg', message],
334
+ ['aid', aid],
335
+ ['progress', progress],
336
+ ['rnd', ++dmSeq],
337
+ ['plat', 1],
338
+ ['checkbox_type', 0],
339
+ ['colorful', ''],
340
+ ['gaiasource', 'main_web'],
341
+ ['polaris_app_id', 100],
342
+ ['polaris_platform', 5],
343
+ ['spmid', VIDEO_SPMID],
344
+ ['from_spmid', VIDEO_SPMID],
345
+ ['statistics', STATISTICS_DM],
346
+ ['csrf', b.csrf],
347
+ ];
348
+ return b.post(`${API}/x/v2/dm/post`, { headers: h.get(), query, form });
349
+ }
350
+ // ================================================================ 创作(BiliCreatorApi)
351
+ const UPLOAD_PAGE = 'https://member.bilibili.com/platform/upload/video/frame';
352
+ export function archivePre(b) {
353
+ const h = headers('GET', { origin: ORIGIN.member, sameOrigin: true }).referer(UPLOAD_PAGE);
354
+ return b.get(`${MEMBER}/x/vupre/web/archive/pre`, {
355
+ headers: h.get(),
356
+ query: [
357
+ ['lang', 'cn'],
358
+ ['t', rand.now()],
359
+ ],
360
+ });
361
+ }
362
+ export function myArchives(b, page = 1, pageSize = 20, status = 'is_pubing,pubed,not_pubed') {
363
+ const h = headers('GET', { origin: ORIGIN.member, sameOrigin: true });
364
+ return b.get(`${MEMBER}/x/web/archives`, {
365
+ headers: h.get(),
366
+ query: [
367
+ ['status', status],
368
+ ['pn', page],
369
+ ['ps', pageSize],
370
+ ['coop', 1],
371
+ ['interactive', 1],
372
+ ],
373
+ });
374
+ }
375
+ export function uploadCover(b, data, suffix) {
376
+ const h = headers('FORM', { origin: ORIGIN.member, sameOrigin: true });
377
+ const form = [
378
+ ['cover', `data:image/${suffix};base64,${Buffer.from(data).toString('base64')}`],
379
+ ['csrf', b.csrf],
380
+ ];
381
+ return b.post(`${MEMBER}/x/vu/web/cover/up`, { headers: h.get(), form });
382
+ }
383
+ export function submitArchive(b, a) {
384
+ const h = headers('POST', { origin: ORIGIN.member, sameOrigin: true }).referer(UPLOAD_PAGE);
385
+ const body = {
386
+ copyright: a.copyright ?? 1,
387
+ source: a.source ?? '',
388
+ cover: a.cover ?? '',
389
+ title: a.title,
390
+ tid: a.tid,
391
+ tag: a.tag,
392
+ desc: a.desc ?? '',
393
+ desc_format_id: 0,
394
+ dynamic: a.dynamic ?? '',
395
+ recreate: -1,
396
+ interactive: 0,
397
+ no_reprint: a.noReprint ?? 1,
398
+ subtitle: { open: 0, lan: '' },
399
+ videos: a.videos.map((v) => ({ filename: v.filename, title: v.title || a.title, desc: v.desc ?? '', cid: v.biz_id ?? null })),
400
+ human_type2: 0,
401
+ topic_id: 0,
402
+ mission_id: 0,
403
+ topic_name: '',
404
+ topic_from: '',
405
+ act_reserve_create: 0,
406
+ is_only_self: a.private === false ? 0 : 1,
407
+ web_os: 2,
408
+ csrf: b.csrf,
409
+ };
410
+ return b.post(`${MEMBER}/x/vu/web/add/v3`, {
411
+ headers: h.get(),
412
+ query: [
413
+ ['web_location', '333.1024'],
414
+ ['t', rand.now()],
415
+ ['csrf', b.csrf],
416
+ ],
417
+ json: body,
418
+ });
419
+ }
420
+ /** 撤稿。平台要求先过极验,不带验证结果固定返回 340022(上游 delete_archive)。 */
421
+ export function deleteArchive(b, aid, gt) {
422
+ const h = headers('FORM', { origin: ORIGIN.member, sameOrigin: true }).referer('https://member.bilibili.com/platform/upload-manager/article');
423
+ const form = [
424
+ ['aid', aid],
425
+ ['csrf', b.csrf],
426
+ ];
427
+ if (gt?.validate)
428
+ form.push(['validate', gt.validate], ['seccode', gt.seccode || `${gt.validate}|jordan`], ['challenge', gt.challenge ?? '']);
429
+ return b.post(`${MEMBER}/x/web/archive/delete`, { headers: h.get(), form });
430
+ }
431
+ export function uploadDynamicImage(b, data, filename, contentType) {
432
+ const h = headers('GET', { origin: ORIGIN.dynamic });
433
+ const multipart = [
434
+ { name: 'file_up', filename, data, contentType },
435
+ { name: 'biz', data: 'new_dyn' },
436
+ { name: 'category', data: 'daily' },
437
+ { name: 'csrf', data: b.csrf },
438
+ ];
439
+ return b.post(`${API}/x/dynamic/feed/draw/upload_bfs`, { headers: h.get(), multipart, timeout: 120 });
440
+ }
441
+ export function createDynamic(b, text, pics) {
442
+ const h = headers('POST', { origin: ORIGIN.dynamic });
443
+ const dynReq = {
444
+ content: { contents: [{ raw_text: text, type: 1, biz_id: '' }] },
445
+ scene: pics.length ? 2 : 1,
446
+ attach_card: null,
447
+ upload_id: `${b.mid}_${rand.nowSeconds()}_${rand.randint(1000, 9999)}`,
448
+ meta: { app_meta: { from: 'create.dynamic.web', mobi_app: 'web' } },
449
+ };
450
+ if (pics.length)
451
+ dynReq.pics = pics;
452
+ return b.post(`${API}/x/dynamic/feed/create/dyn`, {
453
+ headers: h.get(),
454
+ query: [
455
+ ['platform', 'web'],
456
+ ['csrf', b.csrf],
457
+ ],
458
+ json: { dyn_req: dynReq },
459
+ });
460
+ }
461
+ export function removeDynamic(b, id) {
462
+ const h = headers('POST', { origin: ORIGIN.dynamic });
463
+ return b.post(`${API}/x/dynamic/feed/operate/remove`, { headers: h.get(), query: [['csrf', b.csrf]], json: { dyn_id_str: id } });
464
+ }
465
+ /** 上游 save_article_draft / submit_article 的表单:banner_url(封面)固定为空串,上游没有专栏封面。 */
466
+ function articleForm(b, a) {
467
+ return [
468
+ ['title', a.title],
469
+ ['content', a.content],
470
+ ['summary', a.summary ?? ''],
471
+ ['banner_url', ''],
472
+ ['category', a.category ?? 0],
473
+ ['tags', a.tags ?? ''],
474
+ ['list_id', 0],
475
+ ['reprint', 0],
476
+ ['media_id', 0],
477
+ ['spoiler', 0],
478
+ ['original', 1],
479
+ ['csrf', b.csrf],
480
+ ];
481
+ }
482
+ const EDITOR = 'https://member.bilibili.com/read/editor/';
483
+ /** 保存专栏草稿;传 aid 时更新已有草稿。返回的 aid 是草稿 ID。 */
484
+ export function saveArticleDraft(b, a, aid) {
485
+ const h = headers('FORM').referer(EDITOR);
486
+ const form = articleForm(b, a);
487
+ if (aid)
488
+ form.push(['aid', aid]);
489
+ return b.post(`${API}/x/article/creative/draft/addupdate`, { headers: h.get(), form });
490
+ }
491
+ export function submitArticle(b, aid, a) {
492
+ const h = headers('FORM').referer(EDITOR);
493
+ return b.post(`${API}/x/article/creative/article/submit`, { headers: h.get(), form: [['aid', aid], ...articleForm(b, a)] });
494
+ }
495
+ /** 按 ID 读专栏草稿(上游 get_article_draft)。 */
496
+ export function articleDraft(b, aid) {
497
+ return b.get(`${API}/x/article/creative/draft/view`, { headers: headers('GET').referer(EDITOR).get(), query: [['aid', aid]] });
498
+ }
499
+ export function deleteArticleDraft(b, aid) {
500
+ const form = [
501
+ ['aid', aid],
502
+ ['csrf', b.csrf],
503
+ ];
504
+ return b.post(`${API}/x/article/creative/draft/delete`, { headers: headers('FORM').referer(EDITOR).get(), form });
505
+ }
506
+ // ================================================================ 直播(BiliLiveApi)
507
+ const LIVE = ORIGIN.live;
508
+ export function roomInit(b, roomId) {
509
+ const h = headers('GET', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
510
+ return b.get(`${LIVE_API}/room/v1/Room/room_init`, { headers: h.get(), query: [['id', roomId]] });
511
+ }
512
+ export function roomByMid(b, mid) {
513
+ return b.get(`${LIVE_API}/room/v1/Room/getRoomInfoOld`, { headers: headers('GET', { origin: LIVE }).get(), query: [['mid', mid]] });
514
+ }
515
+ export async function roomInfo(b, roomId) {
516
+ const h = headers('GET', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
517
+ const params = withLocation([['room_id', roomId]], '444.8');
518
+ return b.get(`${LIVE_API}/xlive/web-room/v1/index/getInfoByRoom`, { headers: h.get(), query: await b.wbi(params) });
519
+ }
520
+ export async function roomPlayInfo(b, roomId, qn = 0) {
521
+ const h = headers('GET', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
522
+ const params = [
523
+ ['room_id', roomId],
524
+ ['protocol', '0,1'],
525
+ ['format', '0,1,2'],
526
+ ['codec', '0,1,2'],
527
+ ['qn', qn],
528
+ ['platform', 'web'],
529
+ ['ptype', 8],
530
+ ['dolby', 5],
531
+ ['panorama', 1],
532
+ ['eotf', '0,1,2'],
533
+ ['supported_drms', '0,1,2,3'],
534
+ ['req_reason', 0],
535
+ ];
536
+ return b.get(`${LIVE_API}/xlive/web-room/v2/index/getRoomPlayInfo`, { headers: h.get(), query: await b.wbi(withLocation(params, '444.8')) });
537
+ }
538
+ export async function danmuInfo(b, roomId) {
539
+ const h = headers('GET', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
540
+ const params = withLocation([
541
+ ['id', roomId],
542
+ ['type', 0],
543
+ ], '444.8');
544
+ return b.get(`${LIVE_API}/xlive/web-room/v1/index/getDanmuInfo`, { headers: h.get(), query: await b.wbi(params) });
545
+ }
546
+ export function danmakuHistory(b, roomId) {
547
+ const h = headers('GET', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
548
+ return b.get(`${LIVE_API}/xlive/web-room/v1/dM/gethistory`, {
549
+ headers: h.get(),
550
+ query: [
551
+ ['roomid', roomId],
552
+ ['room_type', 0],
553
+ ],
554
+ });
555
+ }
556
+ export async function giftList(b, roomId, areaParentId, areaId, ruid) {
557
+ const h = headers('GET', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
558
+ const params = [
559
+ ['platform', 'pc'],
560
+ ['room_id', roomId],
561
+ ['area_parent_id', areaParentId],
562
+ ['area_id', areaId],
563
+ ['source', 'live'],
564
+ ['build', 0],
565
+ ['ruid', ruid],
566
+ ['base_version', 0],
567
+ ['receive_users', ''],
568
+ ];
569
+ return b.get(`${LIVE_API}/xlive/web-room/v1/giftPanel/roomGiftList`, { headers: h.get(), query: await b.wbi(withLocation(params, '444.8')) });
570
+ }
571
+ export function areaList(b) {
572
+ return b.get(`${LIVE_API}/xlive/web-interface/v1/index/getWebAreaList`, { headers: headers('GET', { origin: LIVE }).get(), query: [['source_id', 2]] });
573
+ }
574
+ export function bagList(b, roomId) {
575
+ const h = headers('GET', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
576
+ return b.get(`${LIVE_API}/xlive/web-room/v1/gift/bag_list`, {
577
+ headers: h.get(),
578
+ query: [
579
+ ['t', rand.now()],
580
+ ['room_id', roomId],
581
+ ],
582
+ });
583
+ }
584
+ export function sendGift(b, roomId, ruid, giftId, giftNum = 1, bagId = 0, coinType = 'silver', price = 0) {
585
+ const path = bagId && bagId !== '0' ? '/xlive/revenue/v2/gift/sendBagMultiUser' : coinType === 'gold' ? '/xlive/revenue/v2/gift/sendGoldMultiUser' : '/xlive/revenue/v2/gift/sendSilverMultiUser';
586
+ const h = headers('FORM', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
587
+ const query = [
588
+ ['uid', b.mid],
589
+ ['gift_id', giftId],
590
+ ['ruid', ruid],
591
+ ['send_ruid', 0],
592
+ ['gift_num', giftNum],
593
+ ['coin_type', coinType],
594
+ ['bag_id', bagId],
595
+ ['platform', 'pc'],
596
+ ['biz_code', 'Live'],
597
+ ['biz_id', roomId],
598
+ ['storm_beat_id', 0],
599
+ ['metadata', ''],
600
+ ['price', price],
601
+ ['receive_users', dumps([{ uid: Number(ruid) }])],
602
+ ['all_flag', 1],
603
+ [
604
+ 'live_statistics',
605
+ dumps({
606
+ pc_client: 'pc_web',
607
+ jumpfrom: '-99998',
608
+ room_category: '-99998',
609
+ source_event: 0,
610
+ official_channel: { program_room_id: '-99998', program_up_id: '-99998' },
611
+ }),
612
+ ],
613
+ ['statistics', dumps({ platform: 5, pc_client: 'pc_web', appId: 100 })],
614
+ ['web_location', '444.8'],
615
+ ['csrf_token', b.csrf],
616
+ ['csrf', b.csrf],
617
+ ['visit_id', ''],
618
+ ];
619
+ return b.post(`${LIVE_API}${path}`, { headers: h.get(), query });
620
+ }
621
+ export async function sendLiveDanmaku(b, roomId, msg, style = {}) {
622
+ const h = headers('GET', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
623
+ const query = await b.wbi([['web_location', '444.8']]);
624
+ const fields = [
625
+ ['bubble', 0],
626
+ ['msg', msg],
627
+ ['color', style.color ?? 16777215],
628
+ ['mode', style.mode ?? 1],
629
+ ['room_type', 0],
630
+ ['jumpfrom', 0],
631
+ ['reply_mid', style.replyMid ?? 0],
632
+ ['reply_attr', 0],
633
+ ['replay_dmid', ''],
634
+ ['statistics', STATISTICS],
635
+ ['reply_type', 0],
636
+ ['reply_uname', style.replyUname ?? ''],
637
+ ['data_extend', dumps({ trackid: '-99998' })],
638
+ ['fontsize', style.fontsize ?? 25],
639
+ ['rnd', rand.nowSeconds()],
640
+ ['roomid', roomId],
641
+ ['csrf', b.csrf],
642
+ ['csrf_token', b.csrf],
643
+ ];
644
+ const multipart = fields.map(([name, value]) => ({ name, data: String(value) }));
645
+ return b.post(`${LIVE_API}/msg/send`, { headers: h.get(), query, multipart });
646
+ }
647
+ export function startLive(b, roomId, areaV2, platform = 'pc_link') {
648
+ const h = headers('FORM', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
649
+ const form = [
650
+ ['room_id', roomId],
651
+ ['platform', platform],
652
+ ['area_v2', areaV2],
653
+ ['backup_stream', 0],
654
+ ['csrf', b.csrf],
655
+ ['csrf_token', b.csrf],
656
+ ];
657
+ return b.post(`${LIVE_API}/room/v1/Room/startLive`, { headers: h.get(), form });
658
+ }
659
+ export function stopLive(b, roomId, platform = 'pc_link') {
660
+ const h = headers('FORM', { origin: LIVE }).referer(`${LIVE}/${roomId}`);
661
+ const form = [
662
+ ['room_id', roomId],
663
+ ['platform', platform],
664
+ ['csrf', b.csrf],
665
+ ['csrf_token', b.csrf],
666
+ ];
667
+ return b.post(`${LIVE_API}/room/v1/Room/stopLive`, { headers: h.get(), form });
668
+ }
669
+ // ================================================================ 登录(BiliLoginApi)
670
+ const LOCALE_JSON = compactJson({ c_locale: { language: 'zh', region: 'CN' }, always_translate: true });
671
+ function passportParams(params) {
672
+ const merged = [...params];
673
+ if (!merged.some(([k]) => k === 'web_location'))
674
+ merged.push(['web_location', '333.1228']);
675
+ merged.push(['x-bili-redirect', 1], ['x-bili-locale-json', LOCALE_JSON]);
676
+ return merged;
677
+ }
678
+ const PASSPORT_BARE = [
679
+ ['x-bili-redirect', 1],
680
+ ['x-bili-locale-json', LOCALE_JSON],
681
+ ];
682
+ function passportHeaders(type = 'GET') {
683
+ return headers(type, { origin: PASSPORT, accept: '*/*', sameOrigin: true }).set('accept-language', 'zh-CN,zh;q=0.9').referer(`${PASSPORT}/login`).get();
684
+ }
685
+ export function qrcodeGenerate(b) {
686
+ return b.json({
687
+ url: `${PASSPORT}/x/passport-login/web/qrcode/generate`,
688
+ headers: passportHeaders(),
689
+ query: passportParams([
690
+ ['source', 'main_web'],
691
+ ['go_url', ''],
692
+ ]),
693
+ });
694
+ }
695
+ export function qrcodePoll(b, qrcodeKey, bRet) {
696
+ const query = passportParams([
697
+ ['qrcode_key', qrcodeKey],
698
+ ['source', 'main_web'],
699
+ ]);
700
+ if (bRet)
701
+ query.push(['b_ret', bRet]);
702
+ return b.json({
703
+ url: `${PASSPORT}/x/passport-login/web/qrcode/poll`,
704
+ headers: passportHeaders(),
705
+ query,
706
+ });
707
+ }
708
+ export function captcha(b) {
709
+ return b.json({
710
+ url: `${PASSPORT}/x/passport-login/captcha`,
711
+ headers: passportHeaders(),
712
+ query: passportParams([['source', 'main-fe']]),
713
+ });
714
+ }
715
+ export function smsSend(b, tel, gt, cid = 86) {
716
+ const form = [
717
+ ['source', 'main_web'],
718
+ ['tel', tel],
719
+ ['cid', cid],
720
+ ['go_url', ''],
721
+ ['token', gt.token],
722
+ ['validate', gt.validate],
723
+ ['seccode', gt.seccode || `${gt.validate}|jordan`],
724
+ ['challenge', gt.challenge],
725
+ ];
726
+ return b.json({
727
+ method: 'POST',
728
+ url: `${PASSPORT}/x/passport-login/web/sms/send`,
729
+ headers: passportHeaders('FORM'),
730
+ query: PASSPORT_BARE,
731
+ form,
732
+ });
733
+ }
734
+ export function smsLogin(b, tel, code, captchaKey, cid = 86) {
735
+ const form = [
736
+ ['source', 'main_web'],
737
+ ['captcha_key', captchaKey],
738
+ ['cid', cid],
739
+ ['tel', tel],
740
+ ['code', code],
741
+ ['go_url', ''],
742
+ ];
743
+ return b.json({
744
+ method: 'POST',
745
+ url: `${PASSPORT}/x/passport-login/web/login/sms`,
746
+ headers: passportHeaders('FORM'),
747
+ query: PASSPORT_BARE,
748
+ form,
749
+ });
750
+ }
751
+ export function loginKey(b) {
752
+ const h = headers('GET', { origin: PASSPORT }).referer(`${PASSPORT}/login`);
753
+ return b.json({ url: `${PASSPORT}/x/passport-login/web/key`, headers: h.get() });
754
+ }
755
+ export function passwordLogin(b, username, encPassword, gt) {
756
+ const h = headers('FORM', { origin: PASSPORT }).referer(`${PASSPORT}/login`);
757
+ const form = [
758
+ ['username', username],
759
+ ['password', encPassword],
760
+ ['keep', 0],
761
+ ['token', gt.token],
762
+ ['challenge', gt.challenge],
763
+ ['validate', gt.validate],
764
+ ['seccode', gt.seccode || `${gt.validate}|jordan`],
765
+ ['source', 'main-fe-header'],
766
+ ['go_url', 'https://www.bilibili.com/'],
767
+ ];
768
+ return b.json({ method: 'POST', url: `${PASSPORT}/x/passport-login/web/login`, headers: h.get(), form });
769
+ }
770
+ export function cookieInfo(b) {
771
+ return b.json({
772
+ url: `${PASSPORT}/x/passport-login/web/cookie/info`,
773
+ headers: headers('GET', { origin: PASSPORT }).get(),
774
+ query: [
775
+ ['web_location', '333.788'],
776
+ ['csrf', b.csrf],
777
+ ],
778
+ });
779
+ }
780
+ export async function refreshCsrf(b, correspondPath) {
781
+ const h = headers('DOC').remove('sec-fetch-user').set('sec-fetch-site', 'same-origin').set('sec-fetch-dest', 'iframe');
782
+ h.insertBefore('accept-encoding', 'referer', 'https://www.bilibili.com/');
783
+ const res = await b.request({ url: `https://www.bilibili.com/correspond/1/${correspondPath}`, headers: h.get() });
784
+ if (res.status !== 200)
785
+ return '';
786
+ return /id="1-name"[^>]*>\s*([^<\s]+)\s*</.exec(await res.text())?.[1] ?? '';
787
+ }
788
+ export function cookieRefresh(b, refreshCsrf, refreshToken) {
789
+ const form = [
790
+ ['csrf', b.csrf],
791
+ ['refresh_csrf', refreshCsrf],
792
+ ['source', 'main_web'],
793
+ ['refresh_token', refreshToken],
794
+ ];
795
+ return b.json({ method: 'POST', url: `${PASSPORT}/x/passport-login/web/cookie/refresh`, headers: headers('FORM').get(), form });
796
+ }
797
+ export function confirmRefresh(b, oldRefreshToken) {
798
+ const form = [
799
+ ['csrf', b.csrf],
800
+ ['refresh_token', oldRefreshToken],
801
+ ];
802
+ return b.json({ method: 'POST', url: `${PASSPORT}/x/passport-login/web/confirm/refresh`, headers: headers('FORM').get(), form });
803
+ }
804
+ export function logout(b) {
805
+ return b.json({ method: 'POST', url: `${PASSPORT}/login/exit/v2`, headers: headers('FORM', { origin: PASSPORT }).get(), form: [['biliCSRF', b.csrf]] });
806
+ }