@ikenxuan/amagi 5.12.1 → 5.13.0

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.
@@ -1,25 +1,39 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
2
  const require_chunk = require('../chunk-CbDLau6x.cjs');
3
- let node_fs = require("node:fs");
4
- node_fs = require_chunk.__toESM(node_fs);
5
3
  let node_path = require("node:path");
6
4
  node_path = require_chunk.__toESM(node_path);
7
5
  let node_url = require("node:url");
8
6
  node_url = require_chunk.__toESM(node_url);
7
+ let node_fs = require("node:fs");
8
+ node_fs = require_chunk.__toESM(node_fs);
9
9
  let chalk = require("chalk");
10
- let log4js = require("log4js");
11
- log4js = require_chunk.__toESM(log4js);
12
10
  let axios = require("axios");
13
11
  axios = require_chunk.__toESM(axios);
14
12
  let zod = require("zod");
15
13
  zod = require_chunk.__toESM(zod);
14
+ let __ikenxuan_xhshow_ts = require("@ikenxuan/xhshow-ts");
15
+ let protobufjs = require("protobufjs");
16
+ protobufjs = require_chunk.__toESM(protobufjs);
16
17
  let node_crypto = require("node:crypto");
17
18
  node_crypto = require_chunk.__toESM(node_crypto);
18
- let __ikenxuan_xhshow_ts = require("@ikenxuan/xhshow-ts");
19
19
  let express = require("express");
20
20
  express = require_chunk.__toESM(express);
21
21
 
22
22
  //#region src/model/logger.ts
23
+ /**
24
+ * 动态获取 log4js 库
25
+ * 优先使用 node-karin/log4js (Karin 环境)
26
+ * 失败则回退到 log4js (独立环境,通过别名映射到 @karinjs/log4js)
27
+ */
28
+ const getLog4js = async () => {
29
+ try {
30
+ return (await import("node-karin/log4js")).default;
31
+ } catch {
32
+ const lib = await import("log4js");
33
+ return lib.default || lib;
34
+ }
35
+ };
36
+ const log4jsPromise = getLog4js();
23
37
  /** 获取包的绝对路径 */
24
38
  const getPackageLogsPath = () => {
25
39
  const currentFileUrl = require("url").pathToFileURL(__filename).href;
@@ -29,7 +43,11 @@ const getPackageLogsPath = () => {
29
43
  if (node_fs.default.existsSync(node_path.default.join(packageRoot, "package.json"))) break;
30
44
  packageRoot = node_path.default.dirname(packageRoot);
31
45
  }
32
- return node_path.default.join(packageRoot, "logs");
46
+ const logsDir = node_path.default.join(packageRoot, "logs");
47
+ try {
48
+ if (!node_fs.default.existsSync(logsDir)) node_fs.default.mkdirSync(logsDir, { recursive: true });
49
+ } catch (error) {}
50
+ return logsDir;
33
51
  };
34
52
  const logsPath = getPackageLogsPath();
35
53
  /** 获取日志级别,优先使用环境变量,默认为 info */
@@ -37,59 +55,65 @@ const getLogLevel = () => {
37
55
  return process.env.LOG_LEVEL ?? "info";
38
56
  };
39
57
  const currentLogLevel = getLogLevel();
40
- log4js.default.configure({
41
- appenders: {
42
- console: {
43
- type: "stdout",
44
- layout: {
45
- type: "pattern",
46
- pattern: "%[[amagi][%d{hh:mm:ss.SSS}][%4.4p]%] %m"
47
- }
48
- },
49
- command: {
50
- type: "dateFile",
51
- filename: node_path.default.join(logsPath, "application", "command"),
52
- pattern: "yyyy-MM-dd.log",
53
- numBackups: 15,
54
- alwaysIncludePattern: true,
55
- layout: {
56
- type: "pattern",
57
- pattern: "[%d{hh:mm:ss.SSS}][%4.4p] %m"
58
- }
59
- },
60
- httpConsole: {
61
- type: "stdout",
62
- layout: {
63
- type: "pattern",
64
- pattern: "%[[amagi][%d{hh:mm:ss.SSS}][HTTP]%] %m"
65
- }
66
- },
67
- httpRequest: {
68
- type: "dateFile",
69
- filename: node_path.default.join(logsPath, "http", "requests"),
70
- pattern: "yyyy-MM-dd.log",
71
- numBackups: 30,
72
- alwaysIncludePattern: true,
73
- layout: {
74
- type: "pattern",
75
- pattern: "[%d{hh:mm:ss.SSS}][%4.4p] %m"
76
- }
77
- }
78
- },
79
- categories: {
80
- default: {
81
- appenders: ["console", "command"],
82
- level: currentLogLevel
83
- },
84
- http: {
85
- appenders: ["httpConsole", "httpRequest"],
86
- level: "debug"
87
- }
88
- },
89
- pm2: true
90
- });
58
+ /** 初始化 logger 配置 */
59
+ const initLogger = () => {
60
+ log4jsPromise.then((log4js) => {
61
+ log4js.configure({
62
+ appenders: {
63
+ console: {
64
+ type: "stdout",
65
+ layout: {
66
+ type: "pattern",
67
+ pattern: "%[[amagi][%d{hh:mm:ss.SSS}][%4.4p]%] %m"
68
+ }
69
+ },
70
+ command: {
71
+ type: "dateFile",
72
+ filename: node_path.default.join(logsPath, "application", "command"),
73
+ pattern: "yyyy-MM-dd.log",
74
+ numBackups: 15,
75
+ alwaysIncludePattern: true,
76
+ layout: {
77
+ type: "pattern",
78
+ pattern: "[%d{hh:mm:ss.SSS}][%4.4p] %m"
79
+ }
80
+ },
81
+ httpConsole: {
82
+ type: "stdout",
83
+ layout: {
84
+ type: "pattern",
85
+ pattern: "%[[amagi][%d{hh:mm:ss.SSS}][HTTP]%] %m"
86
+ }
87
+ },
88
+ httpRequest: {
89
+ type: "dateFile",
90
+ filename: node_path.default.join(logsPath, "http", "requests"),
91
+ pattern: "yyyy-MM-dd.log",
92
+ numBackups: 30,
93
+ alwaysIncludePattern: true,
94
+ layout: {
95
+ type: "pattern",
96
+ pattern: "[%d{hh:mm:ss.SSS}][%4.4p] %m"
97
+ }
98
+ }
99
+ },
100
+ categories: {
101
+ default: {
102
+ appenders: ["console", "command"],
103
+ level: currentLogLevel
104
+ },
105
+ http: {
106
+ appenders: ["httpConsole", "httpRequest"],
107
+ level: "debug"
108
+ }
109
+ },
110
+ pm2: true
111
+ });
112
+ });
113
+ };
91
114
  var CustomLogger = class {
92
115
  logger;
116
+ queue = [];
93
117
  chalk;
94
118
  red;
95
119
  green;
@@ -100,7 +124,10 @@ var CustomLogger = class {
100
124
  white;
101
125
  gray;
102
126
  constructor(name) {
103
- this.logger = log4js.default.getLogger(name);
127
+ log4jsPromise.then((log4js) => {
128
+ this.logger = log4js.getLogger(name);
129
+ this.flush();
130
+ });
104
131
  this.chalk = new chalk.Chalk();
105
132
  this.red = this.chalk.red;
106
133
  this.green = this.chalk.green;
@@ -111,20 +138,31 @@ var CustomLogger = class {
111
138
  this.white = this.chalk.white;
112
139
  this.gray = this.chalk.gray;
113
140
  }
141
+ flush() {
142
+ if (!this.logger) return;
143
+ while (this.queue.length) {
144
+ const [method, args] = this.queue.shift();
145
+ this.logger[method](...args);
146
+ }
147
+ }
148
+ proxy(method, args) {
149
+ if (this.logger) this.logger[method](...args);
150
+ else this.queue.push([method, args]);
151
+ }
114
152
  info(message, ...args) {
115
- this.logger.info(message, ...args);
153
+ this.proxy("info", [message, ...args]);
116
154
  }
117
155
  warn(message, ...args) {
118
- this.logger.warn(message, ...args);
156
+ this.proxy("warn", [message, ...args]);
119
157
  }
120
158
  error(message, ...args) {
121
- this.logger.error(message, ...args);
159
+ this.proxy("error", [message, ...args]);
122
160
  }
123
161
  mark(message, ...args) {
124
- this.logger.mark(message, ...args);
162
+ this.proxy("mark", [message, ...args]);
125
163
  }
126
164
  debug(message, ...args) {
127
- this.logger.debug(message, ...args);
165
+ this.proxy("debug", [message, ...args]);
128
166
  }
129
167
  };
130
168
  const logger = new CustomLogger("default");
@@ -499,6 +537,11 @@ const BilibiliValidateCaptchaParamsSchema = zod.default.object({
499
537
  validate: zod.default.string({ error: "验证码validate必须是字符串" }).min(1, { error: "验证码validate不能为空" }),
500
538
  seccode: zod.default.string({ error: "验证码seccode必须是字符串" }).min(1, { error: "验证码seccode不能为空" })
501
539
  });
540
+ const BilibiliDanmakuParamsSchema = zod.default.object({
541
+ methodType: zod.default.literal("实时弹幕", { error: "方法类型必须是\"实时弹幕\"" }),
542
+ cid: smartNumber("CID不能为空", 1, true),
543
+ segment_index: zod.default.coerce.number({ error: "分段序号必须是数字" }).int({ error: "分段序号必须是整数" }).positive({ error: "分段序号必须是正数" }).default(1).optional()
544
+ });
502
545
  const BilibiliValidationSchemas = {
503
546
  单个视频作品数据: BilibiliVideoParamsSchema,
504
547
  单个视频下载信息数据: BilibiliVideoDownloadParamsSchema,
@@ -525,7 +568,8 @@ const BilibiliValidationSchemas = {
525
568
  专栏文章基本信息: BilibiliArticleInfoParamsSchema,
526
569
  文集基本信息: BilibiliColumnInfoParamsSchema,
527
570
  从_v_voucher_申请_captcha: BilibiliApplyCaptchaParamsSchema,
528
- 验证验证码结果: BilibiliValidateCaptchaParamsSchema
571
+ 验证验证码结果: BilibiliValidateCaptchaParamsSchema,
572
+ 实时弹幕: BilibiliDanmakuParamsSchema
529
573
  };
530
574
  const BilibiliMethodRoutes = {
531
575
  单个视频作品数据: "/fetch_one_video",
@@ -553,7 +597,8 @@ const BilibiliMethodRoutes = {
553
597
  专栏文章基本信息: "/fetch_article_info",
554
598
  文集基本信息: "/fetch_column_info",
555
599
  从_v_voucher_申请_captcha: "/apply_captcha",
556
- 验证验证码结果: "/validate_captcha"
600
+ 验证验证码结果: "/validate_captcha",
601
+ 实时弹幕: "/fetch_danmaku"
557
602
  };
558
603
 
559
604
  //#endregion
@@ -723,51 +768,26 @@ var xiaohongshuSign = class {
723
768
  return this.client.signXsPost(path$1, a1Cookie, clientType, body);
724
769
  }
725
770
  /**
726
- * 生成X-S签名(兼容旧接口)
727
- * @param url - 请求URL
728
- * @param body - 请求体
729
- * @param userAgent - User-Agent(暂未使用)
730
- * @param method - 请求方法,默认为 'POST'
731
- * @param a1Cookie - a1 cookie值
732
- * @returns X-S签名
733
- */
734
- static generateXS(url$1, body, userAgent, method = "POST", a1Cookie = "") {
735
- try {
736
- const urlObj = new URL(url$1);
737
- const path$1 = urlObj.pathname + urlObj.search;
738
- if (method.toUpperCase() === "GET") {
739
- const params = typeof body === "object" ? body : {};
740
- return this.generateXSGet(path$1, a1Cookie, "xhs-pc-web", params);
741
- } else {
742
- const requestBody = typeof body === "object" ? body : {};
743
- return this.generateXSPost(path$1, a1Cookie, "xhs-pc-web", requestBody);
744
- }
745
- } catch (error) {
746
- console.error("生成X-S签名失败:", error);
747
- throw new Error(`签名生成失败: ${error}`);
748
- }
749
- }
750
- /**
751
771
  * 生成X-S-Common参数
752
- * @param length - 长度
772
+ * @param cookies - cookie字符串
753
773
  * @returns Base64编码的随机字符串
754
774
  */
755
- static generateXSCommon(length = 945) {
756
- return node_crypto.default.randomBytes(length).toString("base64").replace(/=+$/, "");
775
+ static generateXSCommon(cookies) {
776
+ return this.client.signXsCommon(cookies);
757
777
  }
758
778
  /**
759
779
  * 生成X-T时间戳
760
780
  * @returns 当前时间戳字符串
761
781
  */
762
782
  static generateXT() {
763
- return Date.now().toString();
783
+ return this.client.getXT();
764
784
  }
765
785
  /**
766
786
  * 生成X-B3-Traceid
767
787
  * @returns 16位随机字符串
768
788
  */
769
789
  static generateXB3Traceid() {
770
- return Array.from({ length: 16 }, () => "abcdef0123456789"[Math.floor(Math.random() * 16)]).join("");
790
+ return this.client.getB3TraceId();
771
791
  }
772
792
  /**
773
793
  * 从cookie字符串中提取a1值
@@ -1153,7 +1173,7 @@ const isRecoverableError = (error) => {
1153
1173
  * 延迟函数
1154
1174
  * @param ms - 延迟毫秒数
1155
1175
  */
1156
- const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
1176
+ const delay = (ms) => new Promise((resolve$1) => setTimeout(resolve$1, ms));
1157
1177
  /**
1158
1178
  * 创建网络错误响应
1159
1179
  * @param error - 错误对象
@@ -1253,7 +1273,8 @@ const fetchResponse = async (config, maxRetries = DEFAULT_MAX_RETRIES) => {
1253
1273
  * 判断结果是否为网络错误响应
1254
1274
  * @param result - 请求结果
1255
1275
  * @returns 是否为ErrorResult
1256
- * @description 通过检查 error 字段中的 amagiError 来区分网络错误和业务错误
1276
+ *
1277
+ * 通过检查 error 字段中的 amagiError 来区分网络错误和业务错误
1257
1278
  */
1258
1279
  const isNetworkErrorResult = (result) => {
1259
1280
  if (result === null || typeof result !== "object") return false;
@@ -1522,6 +1543,17 @@ var BiLiBiLiAPI = class {
1522
1543
  }
1523
1544
  };
1524
1545
  }
1546
+ /**
1547
+ * 获取实时弹幕(web端 protobuf 接口)
1548
+ * @see https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/danmaku_proto.md
1549
+ */
1550
+ 实时弹幕(data$1) {
1551
+ return `https://api.bilibili.com/x/v2/dm/web/seg.so?${new URLSearchParams({
1552
+ type: "1",
1553
+ oid: data$1.cid.toString(),
1554
+ segment_index: (data$1.segment_index ?? 1).toString()
1555
+ }).toString()}`;
1556
+ }
1525
1557
  };
1526
1558
  /** 该类下的所有方法只会返回拼接好参数后的 Url 地址,需要手动请求该地址以获取数据 */
1527
1559
  const bilibiliApiUrls = new BiLiBiLiAPI();
@@ -1586,7 +1618,8 @@ const bilibili = {
1586
1618
  getColumnInfo: createBilibiliApiMethod("文集基本信息"),
1587
1619
  getUserProfileDetail: createBilibiliApiMethod("用户空间详细信息"),
1588
1620
  applyVoucherCaptcha: createBilibiliApiMethod("从_v_voucher_申请_captcha"),
1589
- validateCaptcha: createBilibiliApiMethod("验证验证码结果")
1621
+ validateCaptcha: createBilibiliApiMethod("验证验证码结果"),
1622
+ getDanmaku: createBilibiliApiMethod("实时弹幕")
1590
1623
  };
1591
1624
  /**
1592
1625
  * 创建绑定了cookie的B站API对象
@@ -1620,7 +1653,8 @@ const createBoundBilibiliApi = (cookie, requestConfig) => {
1620
1653
  getColumnInfo: createBoundBilibiliApiMethod("文集基本信息", cookie),
1621
1654
  getUserProfileDetail: createBoundBilibiliApiMethod("用户空间详细信息", cookie),
1622
1655
  applyVoucherCaptcha: createBoundBilibiliApiMethod("从_v_voucher_申请_captcha", cookie),
1623
- validateCaptcha: createBoundBilibiliApiMethod("验证验证码结果", cookie)
1656
+ validateCaptcha: createBoundBilibiliApiMethod("验证验证码结果", cookie),
1657
+ getDanmaku: createBoundBilibiliApiMethod("实时弹幕", cookie)
1624
1658
  };
1625
1659
  };
1626
1660
 
@@ -1676,6 +1710,101 @@ const bv2av = (bvid) => {
1676
1710
  return Number(tmp & MASK_CODE ^ XOR_CODE);
1677
1711
  };
1678
1712
 
1713
+ //#endregion
1714
+ //#region src/platform/bilibili/sign/danmaku_proto.ts
1715
+ /**
1716
+ * B站弹幕 Protobuf 定义(内联)
1717
+ * @see https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/danmaku_proto.md
1718
+ */
1719
+ const DANMAKU_PROTO_JSON = { nested: { bilibili: { nested: { community: { nested: { service: { nested: { dm: { nested: { v1: { nested: {
1720
+ DmSegMobileReply: { fields: { elems: {
1721
+ rule: "repeated",
1722
+ type: "DanmakuElem",
1723
+ id: 1
1724
+ } } },
1725
+ DanmakuElem: { fields: {
1726
+ id: {
1727
+ type: "int64",
1728
+ id: 1
1729
+ },
1730
+ progress: {
1731
+ type: "int32",
1732
+ id: 2
1733
+ },
1734
+ mode: {
1735
+ type: "int32",
1736
+ id: 3
1737
+ },
1738
+ fontsize: {
1739
+ type: "int32",
1740
+ id: 4
1741
+ },
1742
+ color: {
1743
+ type: "uint32",
1744
+ id: 5
1745
+ },
1746
+ midHash: {
1747
+ type: "string",
1748
+ id: 6
1749
+ },
1750
+ content: {
1751
+ type: "string",
1752
+ id: 7
1753
+ },
1754
+ ctime: {
1755
+ type: "int64",
1756
+ id: 8
1757
+ },
1758
+ weight: {
1759
+ type: "int32",
1760
+ id: 9
1761
+ },
1762
+ action: {
1763
+ type: "string",
1764
+ id: 10
1765
+ },
1766
+ pool: {
1767
+ type: "int32",
1768
+ id: 11
1769
+ },
1770
+ idStr: {
1771
+ type: "string",
1772
+ id: 12
1773
+ },
1774
+ attr: {
1775
+ type: "int32",
1776
+ id: 13
1777
+ },
1778
+ animation: {
1779
+ type: "string",
1780
+ id: 22
1781
+ }
1782
+ } }
1783
+ } } } } } } } } } } } };
1784
+ let DmSegMobileReplyType = null;
1785
+ /**
1786
+ * 获取 protobuf 类型定义
1787
+ */
1788
+ function getProtoType() {
1789
+ if (DmSegMobileReplyType) return DmSegMobileReplyType;
1790
+ DmSegMobileReplyType = protobufjs.default.Root.fromJSON(DANMAKU_PROTO_JSON).lookupType("bilibili.community.service.dm.v1.DmSegMobileReply");
1791
+ return DmSegMobileReplyType;
1792
+ }
1793
+ /**
1794
+ * 解析弹幕分段响应
1795
+ * @param data - 二进制 protobuf 数据
1796
+ * @returns 解析后的弹幕数据
1797
+ */
1798
+ function parseDmSegMobileReply(data$1) {
1799
+ const messageType = getProtoType();
1800
+ const buffer = data$1 instanceof Uint8Array ? data$1 : new Uint8Array(data$1);
1801
+ const message = messageType.decode(buffer);
1802
+ return messageType.toObject(message, {
1803
+ longs: String,
1804
+ defaults: true
1805
+ });
1806
+ }
1807
+
1679
1808
  //#endregion
1680
1809
  //#region src/platform/bilibili/sign/wbi.ts
1681
1810
  /**
@@ -1975,6 +2104,7 @@ const bilibiliUtils = {
1975
2104
  av2bv,
1976
2105
  bv2av
1977
2106
  },
2107
+ danmaku: { parseDmSegMobileReply },
1978
2108
  bilibiliApiUrls,
1979
2109
  api: bilibili
1980
2110
  };
@@ -2314,6 +2444,48 @@ const fetchBilibili = async (data$1, cookie, requestConfig) => {
2314
2444
  url: bilibiliApiUrls.验证验证码结果(data$1).Url,
2315
2445
  data: bilibiliApiUrls.验证验证码结果(data$1).Body
2316
2446
  });
2447
+ case "实时弹幕": {
2448
+ const url$1 = bilibiliApiUrls.实时弹幕({
2449
+ cid: data$1.cid,
2450
+ segment_index: data$1.segment_index
2451
+ });
2452
+ try {
2453
+ const response = await fetchData({
2454
+ ...baseRequestConfig,
2455
+ url: url$1,
2456
+ responseType: "arraybuffer"
2457
+ });
2458
+ if (isNetworkErrorResult(response)) {
2459
+ const networkError = new Error(response.error.amagiError.errorDescription);
2460
+ Object.assign(networkError, {
2461
+ code: response.error.code,
2462
+ data: null,
2463
+ amagiError: {
2464
+ ...response.error.amagiError,
2465
+ requestType: data$1.methodType
2466
+ }
2467
+ });
2468
+ throw networkError;
2469
+ }
2470
+ return {
2471
+ code: 0,
2472
+ message: "success",
2473
+ data: { elems: parseDmSegMobileReply(response).elems }
2474
+ };
2475
+ } catch (error) {
2476
+ if (error && typeof error === "object" && "code" in error) return error;
2477
+ const Err = {
2478
+ errorDescription: `获取弹幕数据失败:${error instanceof Error ? error.message : "未知错误"}`,
2479
+ requestType: data$1.methodType,
2480
+ requestUrl: url$1
2481
+ };
2482
+ return {
2483
+ code: amagiAPIErrorCode.UNKNOWN,
2484
+ data: null,
2485
+ amagiError: Err
2486
+ };
2487
+ }
2488
+ }
2317
2489
  default:
2318
2490
  logger.warn(`未知的B站数据接口:「${logger.red(data$1.methodType)}」`);
2319
2491
  return null;
@@ -3659,11 +3831,53 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3659
3831
  }
3660
3832
  case "评论数据": {
3661
3833
  const urlGenerator = (params) => douyinApiUrls$1.评论(params);
3662
- return await fetchPaginatedData(data$1.methodType, urlGenerator, data$1, 50, baseRequestConfig, signType);
3834
+ return await fetchPaginatedData({
3835
+ type: data$1.methodType,
3836
+ apiUrlGenerator: urlGenerator,
3837
+ params: {
3838
+ ...data$1,
3839
+ cursor: data$1.cursor ?? 0
3840
+ },
3841
+ maxPageSize: 50,
3842
+ requestConfig: baseRequestConfig,
3843
+ signType,
3844
+ extractList: (resp) => resp.comments ?? [],
3845
+ updateParams: (params, resp) => ({
3846
+ ...params,
3847
+ cursor: resp.cursor
3848
+ }),
3849
+ hasMore: (resp) => resp.has_more === 1,
3850
+ formatFinalResponse: (resp, list) => ({
3851
+ ...resp,
3852
+ comments: list,
3853
+ cursor: resp.cursor ?? list.length
3854
+ })
3855
+ });
3663
3856
  }
3664
3857
  case "指定评论回复数据": {
3665
3858
  const urlGenerator = (params) => douyinApiUrls$1.二级评论(params);
3666
- return await fetchPaginatedData(data$1.methodType, urlGenerator, data$1, 3, baseRequestConfig, "x_bogus");
3859
+ return await fetchPaginatedData({
3860
+ type: data$1.methodType,
3861
+ apiUrlGenerator: urlGenerator,
3862
+ params: {
3863
+ ...data$1,
3864
+ cursor: data$1.cursor ?? 0
3865
+ },
3866
+ maxPageSize: 3,
3867
+ requestConfig: baseRequestConfig,
3868
+ signType: "x_bogus",
3869
+ extractList: (resp) => resp.comments ?? [],
3870
+ updateParams: (params, resp) => ({
3871
+ ...params,
3872
+ cursor: resp.cursor
3873
+ }),
3874
+ hasMore: (resp) => resp.has_more === 1,
3875
+ formatFinalResponse: (resp, list) => ({
3876
+ ...resp,
3877
+ comments: list,
3878
+ cursor: resp.cursor ?? list.length
3879
+ })
3880
+ });
3667
3881
  }
3668
3882
  case "用户主页数据": {
3669
3883
  const url$1 = douyinApiUrls$1.用户主页信息({ sec_uid: data$1.sec_uid });
@@ -3715,10 +3929,6 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3715
3929
  });
3716
3930
  }
3717
3931
  case "搜索数据": {
3718
- let search_id = "";
3719
- const maxPageSize = 15;
3720
- let fetchedSearchList = [];
3721
- let tmpresp = null;
3722
3932
  const searchType = data$1.type ?? "综合";
3723
3933
  const refererUrl = searchType === "用户" ? `https://www.douyin.com/search/${encodeURIComponent(String(data$1.query))}?type=user` : searchType === "视频" ? `https://www.douyin.com/search/${encodeURIComponent(String(data$1.query))}?type=video` : `https://www.douyin.com/root/search/${encodeURIComponent(String(data$1.query))}`;
3724
3934
  const customConfig = {
@@ -3730,146 +3940,82 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3730
3940
  };
3731
3941
  const isUserSearch = searchType === "用户";
3732
3942
  const isVideoSearch = searchType === "视频";
3733
- let isFirstRequest = true;
3734
- while (fetchedSearchList.length < Number(data$1.number ?? 10)) {
3735
- const requestCount = Math.min(Number(data$1.number ?? 50) - fetchedSearchList.length, maxPageSize);
3736
- const url$1 = douyinApiUrls$1.搜索({
3943
+ return await fetchPaginatedData({
3944
+ type: data$1.methodType,
3945
+ apiUrlGenerator: (params) => douyinApiUrls$1.搜索(params),
3946
+ params: {
3737
3947
  query: data$1.query,
3738
3948
  type: data$1.type,
3739
- number: requestCount,
3740
- search_id: search_id === "" ? void 0 : search_id
3741
- });
3742
- const raw = await GlobalGetData$2(data$1.methodType, {
3743
- ...customConfig,
3744
- url: url$1
3745
- });
3746
- if (isUserSearch) {
3747
- if (!raw || typeof raw !== "object") {
3748
- const Err = {
3749
- errorDescription: "抖音用户搜索返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!",
3750
- requestType: data$1.methodType ?? "未知请求类型",
3751
- requestUrl: url$1
3752
- };
3753
- const warningMessage = `
3754
- 获取响应数据失败!原因:${logger.yellow("用户搜索返回无有效数据,疑似触发反爬机制")}
3755
- 请求类型:「${data$1.methodType}」
3756
- 搜索关键词:「${data$1.query}」
3757
- 请求URL:${url$1}
3758
- `;
3759
- !isFirstRequest && logger.warn(warningMessage);
3760
- return {
3761
- code: douoyinAPIErrorCode.COOKIE,
3762
- data: raw,
3763
- amagiError: Err,
3764
- amagiMessage: warningMessage
3765
- };
3766
- }
3767
- const userList = raw.user_list;
3768
- if (isFirstRequest && (!userList || userList.length === 0)) {
3769
- const Err = {
3770
- errorDescription: "抖音用户搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!",
3771
- requestType: data$1.methodType ?? "未知请求类型",
3772
- requestUrl: url$1
3773
- };
3774
- const warningMessage = `
3775
- 获取响应数据失败!原因:${logger.yellow("用户搜索接口第一次请求就返回空数组,你的抖音Cookie可能已经失效!")}
3776
- 请求类型:「${data$1.methodType}」
3777
- 搜索关键词:「${data$1.query}」
3778
- 请求URL:${url$1}
3779
- `;
3780
- logger.warn(warningMessage);
3781
- return {
3782
- data: raw,
3783
- amagiError: Err,
3784
- amagiMessage: warningMessage
3785
- };
3786
- }
3787
- if (Array.isArray(userList) && userList.length > 0) fetchedSearchList.push(...userList);
3788
- tmpresp = raw;
3789
- search_id = raw.rid ?? search_id;
3790
- if (typeof raw.has_more === "number" && raw.has_more === 0) break;
3791
- if (!userList || userList.length === 0) break;
3792
- } else if (isVideoSearch) {
3793
- if (!raw || typeof raw !== "object") {
3794
- const Err = {
3795
- errorDescription: "抖音视频搜索接口返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效,你的抖音Cookie可能已经失效!",
3796
- requestType: data$1.methodType ?? "未知请求类型",
3797
- requestUrl: url$1
3798
- };
3799
- const warningMessage = `
3800
- 获取响应数据失败!原因:${logger.yellow("视频搜索接口返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!")}
3801
- 请求类型:「${data$1.methodType}」
3802
- 搜索关键词:「${data$1.query}」
3803
- 请求URL:${url$1}
3804
- `;
3805
- !isFirstRequest && logger.warn(warningMessage);
3806
- return {
3807
- code: douoyinAPIErrorCode.COOKIE,
3808
- data: raw,
3809
- amagiError: Err,
3810
- amagiMessage: warningMessage
3811
- };
3812
- }
3813
- const videoList = raw.data;
3814
- if (isFirstRequest && (!videoList || videoList.length === 0)) {
3815
- const Err = {
3816
- errorDescription: "抖音视频搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!",
3817
- requestType: data$1.methodType ?? "未知请求类型",
3818
- requestUrl: url$1
3819
- };
3820
- const warningMessage = `
3821
- 获取响应数据失败!原因:${logger.yellow("视频搜索接口第一次请求就返回空数组,你的抖音Cookie可能已经失效!")}
3822
- 请求类型:「${data$1.methodType}」
3823
- 搜索关键词:「${data$1.query}」
3824
- 请求URL:${url$1}
3825
- `;
3826
- logger.warn(warningMessage);
3949
+ number: data$1.number ?? 10,
3950
+ search_id: ""
3951
+ },
3952
+ maxPageSize: 15,
3953
+ requestConfig: customConfig,
3954
+ signType: null,
3955
+ processRawResponse: (raw) => {
3956
+ if (!isUserSearch && !isVideoSearch) {
3957
+ const responses = filterSearchResponses(typeof raw === "string" ? parseDouyinMultiJson(raw) : [raw]);
3958
+ if (responses.length === 0) return raw;
3959
+ const mergedData = [];
3960
+ let lastValid = {};
3961
+ for (const resp of responses) {
3962
+ if (Array.isArray(resp.data) && resp.data.length > 0) mergedData.push(...resp.data);
3963
+ lastValid = resp;
3964
+ }
3827
3965
  return {
3828
- data: raw,
3829
- amagiError: Err,
3830
- amagiMessage: warningMessage
3966
+ ...lastValid,
3967
+ data: mergedData
3831
3968
  };
3832
3969
  }
3833
- if (Array.isArray(videoList) && videoList.length > 0) fetchedSearchList.push(...videoList);
3834
- tmpresp = raw;
3835
- search_id = raw.log_pb?.impr_id ?? search_id;
3836
- if (typeof raw.has_more === "number" && raw.has_more === 0) break;
3837
- if (!videoList || videoList.length === 0) break;
3838
- } else {
3839
- const responses = filterSearchResponses(typeof raw === "string" ? parseDouyinMultiJson(raw) : [raw]);
3840
- if (responses.length === 0) {
3841
- const Err = {
3842
- errorDescription: "抖音综合搜索接口返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!",
3843
- requestType: data$1.methodType ?? "未知请求类型",
3844
- requestUrl: url$1
3845
- };
3970
+ return raw;
3971
+ },
3972
+ extractList: (resp) => {
3973
+ if (isUserSearch) return resp.user_list ?? [];
3974
+ return resp.data ?? [];
3975
+ },
3976
+ updateParams: (params, resp) => {
3977
+ let nextSearchId = params.search_id;
3978
+ if (isUserSearch) nextSearchId = resp.rid ?? nextSearchId;
3979
+ else nextSearchId = resp.log_pb?.impr_id ?? nextSearchId;
3980
+ return {
3981
+ ...params,
3982
+ search_id: nextSearchId
3983
+ };
3984
+ },
3985
+ hasMore: (resp) => {
3986
+ return resp.has_more !== 0;
3987
+ },
3988
+ validateFirstPage: (list, raw, url$1) => {
3989
+ const typeStr = isUserSearch ? "用户" : isVideoSearch ? "视频" : "综合";
3990
+ let isInvalidResponse = false;
3991
+ const rawAny = raw;
3992
+ if (!rawAny || typeof rawAny !== "object") isInvalidResponse = true;
3993
+ else if (isUserSearch && !rawAny.user_list) isInvalidResponse = true;
3994
+ else if (isVideoSearch && !rawAny.data) isInvalidResponse = true;
3995
+ else if (!isUserSearch && !isVideoSearch && !rawAny.data) isInvalidResponse = true;
3996
+ if (isInvalidResponse) {
3997
+ const desc = `抖音${typeStr}搜索返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!`;
3846
3998
  const warningMessage = `
3847
- 获取响应数据失败!原因:${logger.yellow("综合搜索接口返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!")}
3999
+ 获取响应数据失败!原因:${logger.yellow(`${typeStr}搜索返回无有效数据,疑似触发反爬机制`)}
3848
4000
  请求类型:「${data$1.methodType}」
3849
4001
  搜索关键词:「${data$1.query}」
3850
4002
  请求URL:${url$1}
3851
4003
  `;
3852
- !isFirstRequest && logger.warn(warningMessage);
3853
4004
  return {
3854
4005
  code: douoyinAPIErrorCode.COOKIE,
3855
4006
  data: raw,
3856
- amagiError: Err,
4007
+ amagiError: {
4008
+ errorDescription: desc,
4009
+ requestType: data$1.methodType ?? "未知请求类型",
4010
+ requestUrl: url$1
4011
+ },
3857
4012
  amagiMessage: warningMessage
3858
4013
  };
3859
4014
  }
3860
- for (const resp of responses) {
3861
- if (Array.isArray(resp.data) && resp.data.length > 0) fetchedSearchList.push(...resp.data);
3862
- tmpresp = resp;
3863
- search_id = resp.log_pb?.impr_id ?? search_id;
3864
- }
3865
- if (isFirstRequest && fetchedSearchList.length === 0) {
3866
- const Err = {
3867
- errorDescription: "抖音综合搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!",
3868
- requestType: data$1.methodType ?? "未知请求类型",
3869
- requestUrl: url$1
3870
- };
4015
+ if (!list || list.length === 0) {
4016
+ const desc = `抖音${typeStr}搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!`;
3871
4017
  const warningMessage = `
3872
- 获取响应数据失败!原因:${logger.yellow("综合搜索索接第一次请求就返回空数组,你的抖音Cookie可能已经失效!")}
4018
+ 获取响应数据失败!原因:${logger.yellow(`${typeStr}搜索接口第一次请求就返回空数组,你的抖音Cookie可能已经失效!`)}
3873
4019
  请求类型:「${data$1.methodType}」
3874
4020
  搜索关键词:「${data$1.query}」
3875
4021
  请求URL:${url$1}
@@ -3877,25 +4023,27 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3877
4023
  logger.warn(warningMessage);
3878
4024
  return {
3879
4025
  data: raw,
3880
- amagiError: Err,
4026
+ amagiError: {
4027
+ errorDescription: desc,
4028
+ requestType: data$1.methodType ?? "未知请求类型",
4029
+ requestUrl: url$1
4030
+ },
3881
4031
  amagiMessage: warningMessage
3882
4032
  };
3883
4033
  }
3884
- if (tmpresp && typeof tmpresp.has_more === "number" && tmpresp.has_more === 0) break;
4034
+ return null;
4035
+ },
4036
+ formatFinalResponse: (resp, list) => {
4037
+ if (isUserSearch) return {
4038
+ ...resp,
4039
+ user_list: list
4040
+ };
4041
+ return {
4042
+ ...resp,
4043
+ data: list
4044
+ };
3885
4045
  }
3886
- isFirstRequest = false;
3887
- }
3888
- const slicedList = Number(data$1.number ?? 10) === 0 ? [] : fetchedSearchList.slice(0, Number(data$1.number ?? 10));
3889
- return isUserSearch ? {
3890
- ...tmpresp ?? {},
3891
- user_list: slicedList
3892
- } : isVideoSearch ? {
3893
- ...tmpresp ?? {},
3894
- data: slicedList
3895
- } : {
3896
- ...tmpresp ?? {},
3897
- data: slicedList
3898
- };
4046
+ });
3899
4047
  }
3900
4048
  case "动态表情数据": {
3901
4049
  const url$1 = douyinApiUrls$1.互动表情();
@@ -4031,40 +4179,48 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
4031
4179
  };
4032
4180
  /**
4033
4181
  * 通用的分页请求函数
4034
- * @param type - 请求类型
4035
- * @param apiUrlGenerator - 接口URL生成器
4036
- * @param params - 请求参数
4037
- * @param maxPageSize - 单次请求的最大数据量
4038
- * @param requestConfig - axios请求配置(外部配置优先)
4039
- * @param signType - 签名算法类型
4040
- * @returns 返回分页数据
4182
+ * 封装了循环分页请求、数据合并、错误处理和反爬检测逻辑
4183
+ *
4184
+ * @template T - 列表项类型
4185
+ * @template P - 参数类型
4186
+ * @template R - 返回值类型
4187
+ * @template RawResp - 原始响应类型
4188
+ * @param config - 分页请求配置对象
4189
+ * @returns Promise<R> 返回最终构造的数据对象
4041
4190
  */
4042
- const fetchPaginatedData = async (type, apiUrlGenerator, params, maxPageSize, requestConfig, signType = "a_bogus") => {
4043
- let cursor = params.cursor ?? 0;
4044
- let fetchedData = [];
4045
- let tmpresp = {};
4191
+ const fetchPaginatedData = async (config) => {
4192
+ const { type, apiUrlGenerator, params, maxPageSize, requestConfig, signType = "a_bogus", extractList, updateParams, hasMore, formatFinalResponse, processRawResponse, validateFirstPage } = config;
4193
+ let currentParams = { ...params };
4194
+ const fetchedData = [];
4195
+ let lastResponse = {};
4196
+ let isFirstRequest = true;
4046
4197
  const userAgent = requestConfig.headers?.["User-Agent"];
4047
- while (fetchedData.length < Number(params.number ?? maxPageSize)) {
4048
- const requestCount = Math.min(Number(params.number ?? maxPageSize) - fetchedData.length, maxPageSize);
4049
- const url$1 = apiUrlGenerator({
4050
- ...params,
4051
- number: requestCount,
4052
- cursor
4053
- });
4054
- const response = await GlobalGetData$2(type, {
4198
+ const targetNumber = Number(params.number ?? maxPageSize);
4199
+ while (fetchedData.length < targetNumber) {
4200
+ const remaining = targetNumber - fetchedData.length;
4201
+ currentParams.number = Math.min(remaining, maxPageSize);
4202
+ const url$1 = apiUrlGenerator(currentParams);
4203
+ const finalUrl = signType ? buildSignedUrl(url$1, signType, userAgent) : url$1;
4204
+ const raw = await GlobalGetData$2(type, {
4055
4205
  ...requestConfig,
4056
- url: buildSignedUrl(url$1, signType, userAgent)
4206
+ url: finalUrl
4057
4207
  });
4058
- fetchedData.push(...response.comments ?? response.data ?? []);
4059
- tmpresp = response;
4060
- if ((response.comments ?? response.data ?? []).length < requestCount) break;
4061
- cursor = response.cursor;
4208
+ const response = processRawResponse ? processRawResponse(raw) : raw;
4209
+ if (response && response.amagiError) return response;
4210
+ const list = extractList(response);
4211
+ if (isFirstRequest && validateFirstPage) {
4212
+ const error = validateFirstPage(list, response, finalUrl);
4213
+ if (error) return error;
4214
+ }
4215
+ if (Array.isArray(list) && list.length > 0) fetchedData.push(...list);
4216
+ lastResponse = response;
4217
+ if (!hasMore(response)) break;
4218
+ if (!list || list.length === 0) break;
4219
+ currentParams = updateParams(currentParams, response);
4220
+ isFirstRequest = false;
4062
4221
  }
4063
- return {
4064
- ...tmpresp,
4065
- comments: params.number === 0 ? [] : fetchedData.slice(0, Number(params.number ?? maxPageSize)),
4066
- cursor: params.number === 0 ? 0 : fetchedData.length
4067
- };
4222
+ const slicedData = targetNumber === 0 ? [] : fetchedData.slice(0, targetNumber);
4223
+ return formatFinalResponse(lastResponse, slicedData);
4068
4224
  };
4069
4225
  /**
4070
4226
  * 全局数据获取函数
@@ -4373,7 +4529,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4373
4529
  headers: {
4374
4530
  ...baseRequestConfig.headers,
4375
4531
  "x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls$1.首页推荐数据(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web", xiaohongshuApiUrls$1.首页推荐数据(data$1).Body),
4376
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4532
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4377
4533
  "x-t": xiaohongshuSign.generateXT()
4378
4534
  }
4379
4535
  });
@@ -4384,7 +4540,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4384
4540
  headers: {
4385
4541
  ...baseRequestConfig.headers,
4386
4542
  "x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls$1.单个笔记数据(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web", xiaohongshuApiUrls$1.单个笔记数据(data$1).Body),
4387
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4543
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4388
4544
  "x-t": xiaohongshuSign.generateXT()
4389
4545
  }
4390
4546
  });
@@ -4404,7 +4560,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4404
4560
  headers: {
4405
4561
  ...baseRequestConfig$1.headers,
4406
4562
  "x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls$1.评论数据(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
4407
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4563
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4408
4564
  "x-t": xiaohongshuSign.generateXT()
4409
4565
  }
4410
4566
  });
@@ -4427,7 +4583,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4427
4583
  headers: {
4428
4584
  ...baseRequestConfig$1.headers,
4429
4585
  "x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls$1.用户数据(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
4430
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4586
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4431
4587
  "x-t": xiaohongshuSign.generateXT()
4432
4588
  }
4433
4589
  })),
@@ -4442,7 +4598,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4442
4598
  ...baseRequestConfig.headers,
4443
4599
  "x-b3-traceid": xiaohongshuSign.generateXB3Traceid(),
4444
4600
  "x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls$1.用户笔记数据(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
4445
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4601
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4446
4602
  "x-t": xiaohongshuSign.generateXT()
4447
4603
  }
4448
4604
  });
@@ -4462,7 +4618,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4462
4618
  headers: {
4463
4619
  ...baseRequestConfig$1.headers,
4464
4620
  "x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls$1.表情列表(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
4465
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4621
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4466
4622
  "x-t": xiaohongshuSign.generateXT()
4467
4623
  }
4468
4624
  });
@@ -4474,7 +4630,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4474
4630
  headers: {
4475
4631
  ...baseRequestConfig.headers,
4476
4632
  "x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls$1.搜索笔记(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
4477
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4633
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4478
4634
  "x-t": xiaohongshuSign.generateXT()
4479
4635
  }
4480
4636
  });
@@ -4966,6 +5122,7 @@ const createAmagiClient = (options) => {
4966
5122
  * @returns Express应用实例
4967
5123
  */
4968
5124
  const startServer = (port = 4567) => {
5125
+ initLogger();
4969
5126
  const app = (0, express.default)();
4970
5127
  app.use(express.default.json());
4971
5128
  app.use(express.default.urlencoded({ extended: true }));
@@ -5183,7 +5340,14 @@ let DynamicType = /* @__PURE__ */ function(DynamicType$1) {
5183
5340
 
5184
5341
  //#endregion
5185
5342
  //#region src/index.ts
5186
- const VERSION = "5.12.1";
5343
+ /**
5344
+ * 获取版本号
5345
+ * 构建后使用 __VERSION__,开发环境从 package.json 读取
5346
+ */
5347
+ const getVersion = () => {
5348
+ return "5.13.0";
5349
+ };
5350
+ const VERSION = getVersion();
5187
5351
  /**
5188
5352
  * @deprecated 请使用 createAmagiClient 替代
5189
5353
  */
@@ -5232,6 +5396,7 @@ exports.BilibiliBv2AvParamsSchema = BilibiliBv2AvParamsSchema;
5232
5396
  exports.BilibiliColumnInfoParamsSchema = BilibiliColumnInfoParamsSchema;
5233
5397
  exports.BilibiliCommentParamsSchema = BilibiliCommentParamsSchema;
5234
5398
  exports.BilibiliCommentReplyParamsSchema = BilibiliCommentReplyParamsSchema;
5399
+ exports.BilibiliDanmakuParamsSchema = BilibiliDanmakuParamsSchema;
5235
5400
  exports.BilibiliDynamicParamsSchema = BilibiliDynamicParamsSchema;
5236
5401
  exports.BilibiliEmojiParamsSchema = BilibiliEmojiParamsSchema;
5237
5402
  exports.BilibiliLiveParamsSchema = BilibiliLiveParamsSchema;
@@ -5302,12 +5467,14 @@ exports.getHeadersAndData = getHeadersAndData;
5302
5467
  exports.getKuaishouData = getKuaishouData;
5303
5468
  exports.handleError = handleError;
5304
5469
  exports.httpLogger = httpLogger;
5470
+ exports.initLogger = initLogger;
5305
5471
  exports.isNetworkErrorResult = isNetworkErrorResult;
5306
5472
  exports.kuaishou = kuaishou;
5307
5473
  exports.kuaishouApiUrls = kuaishouApiUrls;
5308
5474
  exports.kuaishouUtils = kuaishouUtils;
5309
5475
  exports.logMiddleware = logMiddleware;
5310
5476
  exports.logger = logger;
5477
+ exports.parseDmSegMobileReply = parseDmSegMobileReply;
5311
5478
  exports.qtparam = qtparam;
5312
5479
  exports.registerBilibiliRoutes = createBilibiliRoutes;
5313
5480
  exports.registerDouyinRoutes = createDouyinRoutes;