@ybgnb/bili-api 0.0.1 → 0.0.3

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 (103) hide show
  1. package/LICENSE +1 -1
  2. package/dist/index.d.ts +5832 -9
  3. package/dist/index.js +1 -7
  4. package/package.json +23 -13
  5. package/readme.md +2 -1
  6. package/dist/client/api.d.ts +0 -23
  7. package/dist/client/api.d.ts.map +0 -1
  8. package/dist/client/api.js +0 -128
  9. package/dist/client/api.js.map +0 -1
  10. package/dist/client/client.d.ts +0 -25
  11. package/dist/client/client.d.ts.map +0 -1
  12. package/dist/client/client.js +0 -22
  13. package/dist/client/client.js.map +0 -1
  14. package/dist/client/common.d.ts +0 -6
  15. package/dist/client/common.d.ts.map +0 -1
  16. package/dist/client/common.js +0 -13
  17. package/dist/client/common.js.map +0 -1
  18. package/dist/config/index.d.ts +0 -22
  19. package/dist/config/index.d.ts.map +0 -1
  20. package/dist/config/index.js +0 -32
  21. package/dist/config/index.js.map +0 -1
  22. package/dist/error/handle-error.d.ts +0 -6
  23. package/dist/error/handle-error.d.ts.map +0 -1
  24. package/dist/error/handle-error.js +0 -32
  25. package/dist/error/handle-error.js.map +0 -1
  26. package/dist/error/index.d.ts +0 -40
  27. package/dist/error/index.d.ts.map +0 -1
  28. package/dist/error/index.js +0 -79
  29. package/dist/error/index.js.map +0 -1
  30. package/dist/index.d.ts.map +0 -1
  31. package/dist/index.js.map +0 -1
  32. package/dist/index.mjs +0 -704
  33. package/dist/index.mjs.map +0 -1
  34. package/dist/index.umd.js +0 -742
  35. package/dist/index.umd.js.map +0 -1
  36. package/dist/service/base.d.ts +0 -17
  37. package/dist/service/base.d.ts.map +0 -1
  38. package/dist/service/base.js +0 -34
  39. package/dist/service/base.js.map +0 -1
  40. package/dist/service/user/index.d.ts +0 -28
  41. package/dist/service/user/index.d.ts.map +0 -1
  42. package/dist/service/user/index.js +0 -148
  43. package/dist/service/user/index.js.map +0 -1
  44. package/dist/service/user/qrcode-login.d.ts +0 -13
  45. package/dist/service/user/qrcode-login.d.ts.map +0 -1
  46. package/dist/service/user/qrcode-login.js +0 -88
  47. package/dist/service/user/qrcode-login.js.map +0 -1
  48. package/dist/stores/mixinkey.d.ts +0 -8
  49. package/dist/stores/mixinkey.d.ts.map +0 -1
  50. package/dist/stores/mixinkey.js +0 -86
  51. package/dist/stores/mixinkey.js.map +0 -1
  52. package/dist/test.d.ts +0 -2
  53. package/dist/test.d.ts.map +0 -1
  54. package/dist/test.js +0 -4
  55. package/dist/test.js.map +0 -1
  56. package/dist/types/business/auth.d.ts +0 -15
  57. package/dist/types/business/auth.d.ts.map +0 -1
  58. package/dist/types/business/auth.js +0 -2
  59. package/dist/types/business/auth.js.map +0 -1
  60. package/dist/types/business/level.d.ts +0 -22
  61. package/dist/types/business/level.d.ts.map +0 -1
  62. package/dist/types/business/level.js +0 -2
  63. package/dist/types/business/level.js.map +0 -1
  64. package/dist/types/business/login.d.ts +0 -35
  65. package/dist/types/business/login.d.ts.map +0 -1
  66. package/dist/types/business/login.js +0 -2
  67. package/dist/types/business/login.js.map +0 -1
  68. package/dist/types/business/misc.d.ts +0 -9
  69. package/dist/types/business/misc.d.ts.map +0 -1
  70. package/dist/types/business/misc.js +0 -2
  71. package/dist/types/business/misc.js.map +0 -1
  72. package/dist/types/business/user.d.ts +0 -34
  73. package/dist/types/business/user.d.ts.map +0 -1
  74. package/dist/types/business/user.js +0 -10
  75. package/dist/types/business/user.js.map +0 -1
  76. package/dist/types/business/vip.d.ts +0 -36
  77. package/dist/types/business/vip.d.ts.map +0 -1
  78. package/dist/types/business/vip.js +0 -19
  79. package/dist/types/business/vip.js.map +0 -1
  80. package/dist/types/core/client.d.ts +0 -38
  81. package/dist/types/core/client.d.ts.map +0 -1
  82. package/dist/types/core/client.js +0 -2
  83. package/dist/types/core/client.js.map +0 -1
  84. package/dist/types/core/request.d.ts +0 -87
  85. package/dist/types/core/request.d.ts.map +0 -1
  86. package/dist/types/core/request.js +0 -2
  87. package/dist/types/core/request.js.map +0 -1
  88. package/dist/types/core/response.d.ts +0 -26
  89. package/dist/types/core/response.d.ts.map +0 -1
  90. package/dist/types/core/response.js +0 -2
  91. package/dist/types/core/response.js.map +0 -1
  92. package/dist/utils/cookies.d.ts +0 -3
  93. package/dist/utils/cookies.d.ts.map +0 -1
  94. package/dist/utils/cookies.js +0 -26
  95. package/dist/utils/cookies.js.map +0 -1
  96. package/dist/utils/time.d.ts +0 -3
  97. package/dist/utils/time.d.ts.map +0 -1
  98. package/dist/utils/time.js +0 -26
  99. package/dist/utils/time.js.map +0 -1
  100. package/dist/utils/url.d.ts +0 -31
  101. package/dist/utils/url.d.ts.map +0 -1
  102. package/dist/utils/url.js +0 -93
  103. package/dist/utils/url.js.map +0 -1
package/dist/index.mjs DELETED
@@ -1,704 +0,0 @@
1
- import md5 from "md5";
2
- import { BaseUtils } from "@ybgnb/utils";
3
- //#region src/error/index.ts
4
- /**
5
- * bili 错误
6
- */
7
- var BiliError = class extends Error {
8
- constructor(clientConfig, errorMsg, rawError) {
9
- super(errorMsg || "操作失败");
10
- this.name = "BiliError";
11
- this.rawError = rawError instanceof Error ? rawError : new Error(String(rawError));
12
- const { timeout, userAgent, context } = clientConfig;
13
- if (context) {
14
- const { userInfo, userCookie } = context;
15
- this.clientConfig = {
16
- timeout,
17
- userAgent,
18
- context: {
19
- userInfo,
20
- userCookie
21
- }
22
- };
23
- } else this.clientConfig = {
24
- timeout,
25
- userAgent
26
- };
27
- }
28
- };
29
- /**
30
- * bili api 错误
31
- */
32
- var BiliApiError = class extends BiliError {
33
- constructor(clientConfig, requestOptions, errorMsg, rawError) {
34
- super(clientConfig, errorMsg, rawError);
35
- this.name = "BiliApiError";
36
- const { url, method, query, data, skipWbiSign, autoCsrf } = requestOptions;
37
- this.requestOptions = {
38
- url,
39
- method,
40
- query,
41
- data,
42
- skipWbiSign,
43
- autoCsrf
44
- };
45
- }
46
- };
47
- /**
48
- * bili api HTTP 网络请求层面的错误(网络错误、超时、状态码超出2xx)
49
- */
50
- var BiliApiHttpError = class extends BiliApiError {
51
- constructor(clientConfig, requestOptions, response, errorMsg, rawError) {
52
- super(clientConfig, requestOptions, errorMsg || response.statusText || `HTTP ${response.status}`, rawError);
53
- this.status = 0;
54
- this.name = "BiliApiHttpError";
55
- this.status = response.status;
56
- }
57
- };
58
- /**
59
- * bili api 业务出错
60
- */
61
- var BiliApiBusinessError = class extends BiliApiError {
62
- constructor(clientConfig, requestOptions, apiResponse, errorMsg, rawError) {
63
- super(clientConfig, requestOptions, errorMsg || apiResponse.message, rawError);
64
- this.name = "BiliApiBusinessError";
65
- this.responseCode = apiResponse.code ?? -1;
66
- this.responseData = apiResponse.data;
67
- }
68
- };
69
- /**
70
- * 操作取消
71
- */
72
- var BiliAbortError = class extends BiliError {
73
- constructor(clientConfig, errorMsg) {
74
- super(clientConfig, errorMsg || "操作已取消");
75
- this.name = "BiliAbortError";
76
- }
77
- };
78
- //#endregion
79
- //#region src/service/base.ts
80
- var BaseService = class {
81
- constructor(api) {
82
- this.api = api;
83
- }
84
- get clientConfig() {
85
- return this.api.clientConfig;
86
- }
87
- get logging() {
88
- return this.api.logging;
89
- }
90
- /**
91
- * 抛出封装的错误
92
- * @param errorOrMsg 错误对象或者错误信息
93
- * @param rawError 原始错误对象
94
- * @protected
95
- */
96
- throwError(errorOrMsg, rawError) {
97
- throw new BiliError(this.clientConfig, BaseUtils.getErrorMessage(errorOrMsg), rawError);
98
- }
99
- handleError(error, className, methodName) {
100
- this.logging.error(`${className}.${methodName} 出现错误`, error);
101
- if (!(error instanceof BiliError)) this.throwError(error);
102
- }
103
- };
104
- //#endregion
105
- //#region src/utils/cookies.ts
106
- function parseUserCookie(setCookie) {
107
- if (!setCookie) throw new Error("setCookie 为空");
108
- const cookies = [];
109
- let bili_jct;
110
- let uid;
111
- for (const cookie of setCookie) if (cookie) {
112
- const item = cookie.slice(0, cookie.indexOf(";") + 1);
113
- cookies.push(item);
114
- if (item.startsWith("bili_jct=")) bili_jct = item.slice(9, -1);
115
- if (item.startsWith("DedeUserID=")) uid = item.slice(11, -1);
116
- }
117
- if (!bili_jct || !uid) throw new Error("setCookie 解析错误,不存在 bili_jct/uid");
118
- return {
119
- cookie: cookies.join(" "),
120
- bili_jct
121
- };
122
- }
123
- //#endregion
124
- //#region src/error/handle-error.ts
125
- /**
126
- * 错误处理装饰器
127
- * @constructor
128
- */
129
- function CatchError() {
130
- return function(originalMethod, context) {
131
- const methodName = String(context.name);
132
- return function(...args) {
133
- const className = this.constructor.name;
134
- try {
135
- return originalMethod.call(this, ...args);
136
- } catch (error) {
137
- if (typeof this.handleError === "function") this.handleError(error, className, methodName);
138
- else {
139
- console.error(`${className}.${methodName} 未知错误`, error);
140
- throw error;
141
- }
142
- }
143
- };
144
- };
145
- }
146
- //#endregion
147
- //#region src/service/user/qrcode-login.ts
148
- /**
149
- * 登录轮询间隔时间
150
- */
151
- var QR_CODE_POLL_INTERVAL_MS = 1111;
152
- /**
153
- * 通过二维码登录
154
- *
155
- * @param userService - 用户服务实例
156
- * @param callback - 状态回调接口
157
- * @param loginOptions - 可选配置(自动刷新、更新上下文、取消信号等)
158
- * @returns 登录成功后的请求上下文
159
- */
160
- function loginWithQRCode(userService, callback, loginOptions) {
161
- const options = {
162
- updateRequestContext: true,
163
- autoRefresh: true,
164
- pollIntervalMs: 1111,
165
- ...loginOptions
166
- };
167
- let pollTimer = null;
168
- let isPolling = false;
169
- let isRefreshing = false;
170
- let currentQrCodeKey = null;
171
- const internalAbortController = new AbortController();
172
- const finalSignal = options.signal ? (() => {
173
- if (options.signal?.aborted) internalAbortController.abort();
174
- else if (options.signal) options.signal.addEventListener("abort", () => internalAbortController.abort());
175
- return internalAbortController.signal;
176
- })() : internalAbortController.signal;
177
- let resolvePromise = null;
178
- let rejectPromise = null;
179
- const safeStatusChange = (msg) => {
180
- try {
181
- callback.onStatusChange(msg);
182
- } catch (err) {
183
- userService.logging.error("[QRCodeLogin] onStatusChange callback error:", err);
184
- }
185
- };
186
- const safeQRCodeReceived = (url) => {
187
- try {
188
- callback.onQRCodeReceived(url);
189
- } catch (err) {
190
- userService.logging.error("[QRCodeLogin] onQRCodeReceived callback error:", err);
191
- }
192
- };
193
- const clearPollTimer = () => {
194
- if (pollTimer) {
195
- clearTimeout(pollTimer);
196
- pollTimer = null;
197
- }
198
- };
199
- const stopLoginFlow = () => {
200
- clearPollTimer();
201
- isPolling = false;
202
- isRefreshing = false;
203
- currentQrCodeKey = null;
204
- internalAbortController.abort();
205
- };
206
- const handlePollError = (err) => {
207
- if (finalSignal.aborted) return;
208
- clearPollTimer();
209
- const errorMsg = BaseUtils.getErrorMessage(err);
210
- safeStatusChange(errorMsg);
211
- if (rejectPromise) {
212
- rejectPromise(new BiliError(userService.clientConfig, errorMsg, err));
213
- rejectPromise = null;
214
- }
215
- stopLoginFlow();
216
- };
217
- const pollLoginResult = async (qrCodeKey) => {
218
- if (finalSignal.aborted) return;
219
- if (isPolling) return;
220
- isPolling = true;
221
- try {
222
- if (finalSignal.aborted) return;
223
- const loginResult = await userService.getQRCodeLoginResult(qrCodeKey, finalSignal);
224
- if (!pollTimer || finalSignal.aborted) return;
225
- safeStatusChange(loginResult.message);
226
- if (loginResult.code === 0) {
227
- clearPollTimer();
228
- safeStatusChange("已登录,正在获取用户信息...");
229
- const context = await userService.initLoginSession(loginResult.setCookie, options.updateRequestContext, finalSignal);
230
- if (resolvePromise) {
231
- resolvePromise(context);
232
- resolvePromise = null;
233
- rejectPromise = null;
234
- }
235
- stopLoginFlow();
236
- return;
237
- }
238
- if (loginResult.code === 86038) if (options.autoRefresh) {
239
- safeStatusChange("二维码已失效,正在刷新...");
240
- clearPollTimer();
241
- await refreshQRCode();
242
- return;
243
- } else throw new BiliError(userService.clientConfig, "二维码已失效");
244
- if (!finalSignal.aborted && pollTimer === null) pollTimer = setTimeout(() => {
245
- pollTimer = null;
246
- pollLoginResult(qrCodeKey).catch(handlePollError);
247
- }, options.pollIntervalMs || QR_CODE_POLL_INTERVAL_MS);
248
- } catch (err) {
249
- handlePollError(err);
250
- } finally {
251
- isPolling = false;
252
- }
253
- };
254
- const refreshQRCode = async () => {
255
- if (isRefreshing || finalSignal.aborted) return;
256
- isRefreshing = true;
257
- clearPollTimer();
258
- isPolling = false;
259
- currentQrCodeKey = null;
260
- try {
261
- safeStatusChange("获取二维码中...");
262
- const qrCode = await userService.getLoginQRCode(finalSignal);
263
- if (finalSignal.aborted) return;
264
- currentQrCodeKey = qrCode.qrcode_key;
265
- safeQRCodeReceived(qrCode.url);
266
- safeStatusChange("请使用手机App扫码登录...");
267
- if (!finalSignal.aborted) {
268
- clearPollTimer();
269
- pollLoginResult(currentQrCodeKey).catch(handlePollError);
270
- }
271
- } catch (err) {
272
- if (!finalSignal.aborted) {
273
- const errorMsg = BaseUtils.getErrorMessage(err);
274
- safeStatusChange(errorMsg);
275
- if (rejectPromise) {
276
- rejectPromise(new BiliError(userService.clientConfig, errorMsg, err));
277
- rejectPromise = null;
278
- }
279
- stopLoginFlow();
280
- }
281
- } finally {
282
- isRefreshing = false;
283
- }
284
- };
285
- const onExternalAbort = () => {
286
- stopLoginFlow();
287
- if (rejectPromise) {
288
- rejectPromise("取消登录");
289
- rejectPromise = null;
290
- }
291
- };
292
- options.signal?.addEventListener("abort", onExternalAbort);
293
- return new Promise((resolve, reject) => {
294
- resolvePromise = resolve;
295
- rejectPromise = reject;
296
- if (options.signal?.aborted) {
297
- reject("取消登录");
298
- return;
299
- }
300
- refreshQRCode().catch((err) => {
301
- if (rejectPromise) {
302
- rejectPromise(err);
303
- rejectPromise = null;
304
- }
305
- });
306
- }).finally(() => {
307
- options.signal?.removeEventListener("abort", onExternalAbort);
308
- stopLoginFlow();
309
- resolvePromise = null;
310
- rejectPromise = null;
311
- });
312
- }
313
- //#endregion
314
- //#region \0@oxc-project+runtime@0.122.0/helpers/decorate.js
315
- function __decorate(decorators, target, key, desc) {
316
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
317
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
318
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
319
- return c > 3 && r && Object.defineProperty(target, key, r), r;
320
- }
321
- //#endregion
322
- //#region src/service/user/index.ts
323
- var UserService = class extends BaseService {
324
- /**
325
- * 获取登录二维码
326
- */
327
- getLoginQRCode(signal) {
328
- return this.api.request(`https://passport.bilibili.com/x/passport-login/web/qrcode/generate`, { signal });
329
- }
330
- /**
331
- * 获取二维码登录结果
332
- */
333
- async getQRCodeLoginResult(qrcode_key, signal) {
334
- const response = await this.api.request("https://passport.bilibili.com/x/passport-login/web/qrcode/poll", {
335
- query: { qrcode_key },
336
- skipWbiSign: true,
337
- returnFormat: "RawResponse",
338
- signal
339
- });
340
- return {
341
- ...(await response.json()).data,
342
- setCookie: response.headers.getSetCookie()
343
- };
344
- }
345
- async loginWithQRCode(callback, loginOptions) {
346
- return loginWithQRCode(this, callback, loginOptions);
347
- }
348
- getBuvids(signal) {
349
- return this.api.request("https://api.bilibili.com/x/frontend/finger/spi", { signal });
350
- }
351
- getUserInfo(cookie, signal) {
352
- return this.api.request("https://api.bilibili.com/x/space/myinfo", {
353
- cookie,
354
- signal
355
- });
356
- }
357
- /**
358
- * 登录后初始化(cookie / 用户信息等)
359
- */
360
- async initLoginSession(setCookie, updateRequestContext = true, signal) {
361
- this.logging.info(`初始化用户数据...`);
362
- const userCookie = parseUserCookie(setCookie);
363
- const { b_3, b_4 } = await this.getBuvids(signal);
364
- userCookie.cookie = `${userCookie.cookie} buvid3=${b_3}; buvid4=${b_4}; `;
365
- const userInfo = await this.getUserInfo(userCookie, signal);
366
- const context = {
367
- userCookie,
368
- userInfo
369
- };
370
- if (updateRequestContext) this.clientConfig.context = context;
371
- this.logging.info(`已完成用户登录:${userInfo.name} ${userInfo.mid}`);
372
- return context;
373
- }
374
- };
375
- __decorate([CatchError()], UserService.prototype, "getLoginQRCode", null);
376
- __decorate([CatchError()], UserService.prototype, "getQRCodeLoginResult", null);
377
- __decorate([CatchError()], UserService.prototype, "loginWithQRCode", null);
378
- __decorate([CatchError()], UserService.prototype, "getBuvids", null);
379
- __decorate([CatchError()], UserService.prototype, "getUserInfo", null);
380
- __decorate([CatchError()], UserService.prototype, "initLoginSession", null);
381
- //#endregion
382
- //#region src/config/index.ts
383
- /**
384
- * 默认的客户端配置
385
- */
386
- var defaultClientConfig = {
387
- timeout: 5e3,
388
- userAgent: "\"Chromium\";v=\"146\", \"Not-A.Brand\";v=\"24\", \"Google Chrome\";v=\"146\"",
389
- referer: "https://space.bilibili.com/10000",
390
- logLevel: "info",
391
- logging: {
392
- debug: (...data) => {
393
- console.error(`[${(/* @__PURE__ */ new Date()).toLocaleString()}]`, ...data);
394
- },
395
- info: (...data) => {
396
- console.info(`[${(/* @__PURE__ */ new Date()).toLocaleString()}]`, ...data);
397
- },
398
- error: (...data) => {
399
- console.error(`[${(/* @__PURE__ */ new Date()).toLocaleString()}]`, ...data);
400
- }
401
- }
402
- };
403
- /**
404
- * 默认的请求选项
405
- */
406
- var defaultRequestOptions = {
407
- method: "GET",
408
- returnFormat: "ApiResponseData",
409
- ignoreBusinessError: false,
410
- skipWbiSign: false,
411
- autoCsrf: true
412
- };
413
- //#endregion
414
- //#region src/client/client.ts
415
- /**
416
- * bili 客户端
417
- */
418
- var BiliClient = class {
419
- get logging() {
420
- return this.config.logging;
421
- }
422
- constructor(config) {
423
- this.config = {
424
- ...defaultClientConfig,
425
- ...config ?? {}
426
- };
427
- this.api = new BiliApi(this);
428
- this.user = new UserService(this.api);
429
- }
430
- updateRequestContext(requestContext) {
431
- this.config.context = requestContext;
432
- }
433
- };
434
- /**
435
- * 公用的Bili客户端
436
- */
437
- var commonBiliClient = new BiliClient();
438
- //#endregion
439
- //#region src/stores/mixinkey.ts
440
- var mixinKey;
441
- var initPromise = null;
442
- var wbiKeyLastUpdatedAt = 0;
443
- var mixinKeyUpdateTimer = void 0;
444
- var MILLIS_PER_DAY = 1440 * 60 * 1e3;
445
- /**
446
- * mixinKey(wbi签名需要的参数)
447
- */
448
- var mixinKeyStore = { get: async () => {
449
- if (mixinKey) return mixinKey;
450
- if (!initPromise) initPromise = initMixinKey().catch(() => {
451
- initPromise = null;
452
- });
453
- await initPromise;
454
- return mixinKey;
455
- } };
456
- function isNotSameDay(timestamp1, timestamp2) {
457
- return Math.floor(timestamp1 / MILLIS_PER_DAY) !== Math.floor(timestamp2 / MILLIS_PER_DAY);
458
- }
459
- var mixinKeyEncTab = [
460
- 46,
461
- 47,
462
- 18,
463
- 2,
464
- 53,
465
- 8,
466
- 23,
467
- 32,
468
- 15,
469
- 50,
470
- 10,
471
- 31,
472
- 58,
473
- 3,
474
- 45,
475
- 35,
476
- 27,
477
- 43,
478
- 5,
479
- 49,
480
- 33,
481
- 9,
482
- 42,
483
- 19,
484
- 29,
485
- 28,
486
- 14,
487
- 39,
488
- 12,
489
- 38,
490
- 41,
491
- 13,
492
- 37,
493
- 48,
494
- 7,
495
- 16,
496
- 24,
497
- 55,
498
- 40,
499
- 61,
500
- 26,
501
- 17,
502
- 0,
503
- 1,
504
- 60,
505
- 51,
506
- 30,
507
- 4,
508
- 22,
509
- 25,
510
- 54,
511
- 21,
512
- 56,
513
- 59,
514
- 6,
515
- 63,
516
- 57,
517
- 62,
518
- 11,
519
- 36,
520
- 20,
521
- 34,
522
- 44,
523
- 52
524
- ];
525
- var generateMixinKey = (imgKey, subKey) => {
526
- const raw_wbi_key = imgKey + subKey;
527
- return mixinKeyEncTab.map((n) => raw_wbi_key[n]).join("").slice(0, 32);
528
- };
529
- var initMixinKey = async () => {
530
- await updateMixinKey();
531
- if (!mixinKeyUpdateTimer) clearInterval(mixinKeyUpdateTimer);
532
- mixinKeyUpdateTimer = setInterval(() => {
533
- if (isNotSameDay(wbiKeyLastUpdatedAt, Date.now())) updateMixinKey();
534
- }, 3e5);
535
- };
536
- var updateMixinKey = async () => {
537
- try {
538
- const now = Date.now();
539
- const nav = (await (await fetch("https://api.bilibili.com/x/web-interface/nav")).json()).data;
540
- const getKey = (url) => {
541
- return new URL(url).pathname.split("/").pop().replace(/\.[^.]+$/, "");
542
- };
543
- mixinKey = generateMixinKey(getKey(nav.wbi_img.img_url), getKey(nav.wbi_img.sub_url));
544
- commonBiliClient.logging.info(`初始化 MixinKey:${mixinKey}`);
545
- wbiKeyLastUpdatedAt = now;
546
- } catch (err) {
547
- commonBiliClient.logging.error("初始化 MixinKey 失败", err);
548
- throw err;
549
- }
550
- };
551
- //#endregion
552
- //#region src/utils/url.ts
553
- var invalidCharRegex = /[!'()*]/g;
554
- /**
555
- * 解析 url
556
- * @param urlStr
557
- */
558
- function parseURL(urlStr) {
559
- try {
560
- const url = new URL(urlStr);
561
- return {
562
- baseUrl: url.origin + url.pathname,
563
- searchParams: url.searchParams
564
- };
565
- } catch (_) {
566
- throw new Error("URL 无效");
567
- }
568
- }
569
- /**
570
- * 编码 URL 参数
571
- * @param params 查询参数
572
- */
573
- function encodeURLParams(params) {
574
- return Object.keys(params).sort().map((key) => {
575
- const raw = params[key];
576
- if (raw === void 0 || raw === null) return "";
577
- const value = String(raw).replace(invalidCharRegex, "");
578
- return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
579
- }).join("&");
580
- }
581
- /**
582
- * wbi 签名
583
- * @param params
584
- */
585
- function wbiSign(params) {
586
- const query = encodeURLParams(params);
587
- return query + "&w_rid=" + md5(query + mixinKeyStore.get());
588
- }
589
- /**
590
- * 处理 url 查询参数
591
- * @param urlSearchParams
592
- * @param params
593
- * @param skipWbiSign
594
- * @return 查询字符串
595
- */
596
- function handleUrlParams(urlSearchParams, params, skipWbiSign) {
597
- try {
598
- let finalParams = {};
599
- if (urlSearchParams.size > 0) urlSearchParams.forEach((value, key) => {
600
- finalParams[key] = value;
601
- });
602
- if (params) finalParams = {
603
- ...finalParams,
604
- ...params
605
- };
606
- if (!finalParams.wts) finalParams.wts = Math.floor(Date.now() / 1e3);
607
- if (skipWbiSign || Object.keys(finalParams).length === 1) return `${encodeURLParams(finalParams)}`;
608
- else return `${wbiSign(finalParams)}`;
609
- } catch (_) {
610
- throw new Error("查询参数无效");
611
- }
612
- }
613
- //#endregion
614
- //#region src/client/api.ts
615
- /**
616
- * bili 接口
617
- */
618
- var BiliApi = class {
619
- constructor(client) {
620
- this.client = client;
621
- }
622
- get clientConfig() {
623
- return this.client.config;
624
- }
625
- get logging() {
626
- return this.clientConfig.logging;
627
- }
628
- get isDebug() {
629
- return this.clientConfig.logLevel === "debug";
630
- }
631
- /**
632
- * 记录接口成功的日志
633
- */
634
- logApiSuccess(prefix, returnFormat, response) {
635
- if (returnFormat === "RawResponse") this.logging.info(`${prefix} 请求成功 [RawResponse]`);
636
- else if (returnFormat === "ApiResponse") this.logging.info(`${prefix} 请求成功 [ApiResponse]`, this.isDebug ? JSON.stringify(response) : "");
637
- else this.logging.info(`${prefix} 请求成功`, this.isDebug ? JSON.stringify(response) : "");
638
- }
639
- /**
640
- * 记录接口错误的日志
641
- */
642
- logApiError(prefix, error) {
643
- if (error instanceof BiliAbortError) this.logging.info(`${prefix} [${error.message}]`);
644
- else if (error instanceof BiliApiHttpError) this.logging.info(`${prefix} [http error]:${error.message}(${error.status})`);
645
- else if (error instanceof BiliError) this.logging.info(`${prefix} ${error.message}`);
646
- else this.logging.info(`${prefix} 出现未知错误`, error);
647
- }
648
- async request(url, options) {
649
- const { context, userAgent, timeout: timeoutMS, referer } = this.clientConfig;
650
- const finalOptions = {
651
- ...defaultRequestOptions,
652
- url,
653
- ...options
654
- };
655
- const prefix = `[bili API]${context?.userInfo.mid ? ` [${context?.userInfo.mid}]` : ""} ${finalOptions.method} ${new URL(url).pathname}`;
656
- try {
657
- const { baseUrl, searchParams } = parseURL(url);
658
- const searchStr = handleUrlParams(searchParams, finalOptions.query, finalOptions.skipWbiSign);
659
- const finalUrl = `${baseUrl}?${searchStr}`;
660
- finalOptions.url = finalUrl;
661
- this.logging.info(`${prefix} 请求中 ${searchStr}`);
662
- if (finalOptions.method === "POST" && finalOptions.data && finalOptions.autoCsrf) {
663
- if (finalOptions.data instanceof FormData) finalOptions.data.set("csrf", context?.userCookie.bili_jct ?? "");
664
- }
665
- const fetchInit = {
666
- signal: options?.signal ? AbortSignal.any([options?.signal, AbortSignal.timeout(timeoutMS)]) : AbortSignal.timeout(timeoutMS),
667
- headers: {
668
- "User-Agent": userAgent,
669
- cookie: finalOptions.cookie?.cookie || context?.userCookie.cookie || "",
670
- Referer: typeof referer === "function" ? referer(finalUrl) : referer
671
- },
672
- method: finalOptions.method,
673
- body: finalOptions.data,
674
- ...options?.init ?? {}
675
- };
676
- const httpResponse = await fetch(finalUrl, fetchInit);
677
- if (!httpResponse.ok) throw new BiliApiHttpError(this.clientConfig, finalOptions, httpResponse);
678
- if (finalOptions.returnFormat === "RawResponse") {
679
- this.logApiSuccess(prefix, "RawResponse", httpResponse);
680
- return httpResponse;
681
- }
682
- let biliResponse;
683
- try {
684
- biliResponse = await httpResponse.json();
685
- } catch (e) {
686
- throw new BiliApiHttpError(this.clientConfig, finalOptions, httpResponse, "解析响应数据错误", e);
687
- }
688
- if (!finalOptions.ignoreBusinessError && biliResponse.code !== 0) throw new BiliApiBusinessError(this.clientConfig, finalOptions, biliResponse);
689
- if (finalOptions.returnFormat === "ApiResponse") {
690
- this.logApiSuccess(prefix, "ApiResponse", biliResponse);
691
- return biliResponse;
692
- }
693
- this.logApiSuccess(prefix, "ApiResponseData", biliResponse.data);
694
- return biliResponse.data;
695
- } catch (error) {
696
- this.logApiError("", error);
697
- throw error;
698
- }
699
- }
700
- };
701
- //#endregion
702
- export { BaseService, BiliAbortError, BiliApi, BiliApiBusinessError, BiliApiError, BiliApiHttpError, BiliClient, BiliError, UserService };
703
-
704
- //# sourceMappingURL=index.mjs.map