@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,15 +1,29 @@
1
- import fs from "node:fs";
2
1
  import path from "node:path";
3
2
  import url from "node:url";
3
+ import fs from "node:fs";
4
4
  import { Chalk } from "chalk";
5
- import log4js from "log4js";
6
5
  import axios, { AxiosError } from "axios";
7
6
  import zod from "zod";
8
- import crypto from "node:crypto";
9
7
  import { Xhshow } from "@ikenxuan/xhshow-ts";
8
+ import protobuf from "protobufjs";
9
+ import crypto from "node:crypto";
10
10
  import express from "express";
11
11
 
12
12
  //#region src/model/logger.ts
13
+ /**
14
+ * 动态获取 log4js 库
15
+ * 优先使用 node-karin/log4js (Karin 环境)
16
+ * 失败则回退到 log4js (独立环境,通过别名映射到 @karinjs/log4js)
17
+ */
18
+ const getLog4js = async () => {
19
+ try {
20
+ return (await import("node-karin/log4js")).default;
21
+ } catch {
22
+ const lib = await import("log4js");
23
+ return lib.default || lib;
24
+ }
25
+ };
26
+ const log4jsPromise = getLog4js();
13
27
  /** 获取包的绝对路径 */
14
28
  const getPackageLogsPath = () => {
15
29
  const currentFileUrl = import.meta.url;
@@ -19,7 +33,11 @@ const getPackageLogsPath = () => {
19
33
  if (fs.existsSync(path.join(packageRoot, "package.json"))) break;
20
34
  packageRoot = path.dirname(packageRoot);
21
35
  }
22
- return path.join(packageRoot, "logs");
36
+ const logsDir = path.join(packageRoot, "logs");
37
+ try {
38
+ if (!fs.existsSync(logsDir)) fs.mkdirSync(logsDir, { recursive: true });
39
+ } catch (error) {}
40
+ return logsDir;
23
41
  };
24
42
  const logsPath = getPackageLogsPath();
25
43
  /** 获取日志级别,优先使用环境变量,默认为 info */
@@ -27,59 +45,65 @@ const getLogLevel = () => {
27
45
  return process.env.LOG_LEVEL ?? "info";
28
46
  };
29
47
  const currentLogLevel = getLogLevel();
30
- log4js.configure({
31
- appenders: {
32
- console: {
33
- type: "stdout",
34
- layout: {
35
- type: "pattern",
36
- pattern: "%[[amagi][%d{hh:mm:ss.SSS}][%4.4p]%] %m"
37
- }
38
- },
39
- command: {
40
- type: "dateFile",
41
- filename: path.join(logsPath, "application", "command"),
42
- pattern: "yyyy-MM-dd.log",
43
- numBackups: 15,
44
- alwaysIncludePattern: true,
45
- layout: {
46
- type: "pattern",
47
- pattern: "[%d{hh:mm:ss.SSS}][%4.4p] %m"
48
- }
49
- },
50
- httpConsole: {
51
- type: "stdout",
52
- layout: {
53
- type: "pattern",
54
- pattern: "%[[amagi][%d{hh:mm:ss.SSS}][HTTP]%] %m"
55
- }
56
- },
57
- httpRequest: {
58
- type: "dateFile",
59
- filename: path.join(logsPath, "http", "requests"),
60
- pattern: "yyyy-MM-dd.log",
61
- numBackups: 30,
62
- alwaysIncludePattern: true,
63
- layout: {
64
- type: "pattern",
65
- pattern: "[%d{hh:mm:ss.SSS}][%4.4p] %m"
66
- }
67
- }
68
- },
69
- categories: {
70
- default: {
71
- appenders: ["console", "command"],
72
- level: currentLogLevel
73
- },
74
- http: {
75
- appenders: ["httpConsole", "httpRequest"],
76
- level: "debug"
77
- }
78
- },
79
- pm2: true
80
- });
48
+ /** 初始化 logger 配置 */
49
+ const initLogger = () => {
50
+ log4jsPromise.then((log4js) => {
51
+ log4js.configure({
52
+ appenders: {
53
+ console: {
54
+ type: "stdout",
55
+ layout: {
56
+ type: "pattern",
57
+ pattern: "%[[amagi][%d{hh:mm:ss.SSS}][%4.4p]%] %m"
58
+ }
59
+ },
60
+ command: {
61
+ type: "dateFile",
62
+ filename: path.join(logsPath, "application", "command"),
63
+ pattern: "yyyy-MM-dd.log",
64
+ numBackups: 15,
65
+ alwaysIncludePattern: true,
66
+ layout: {
67
+ type: "pattern",
68
+ pattern: "[%d{hh:mm:ss.SSS}][%4.4p] %m"
69
+ }
70
+ },
71
+ httpConsole: {
72
+ type: "stdout",
73
+ layout: {
74
+ type: "pattern",
75
+ pattern: "%[[amagi][%d{hh:mm:ss.SSS}][HTTP]%] %m"
76
+ }
77
+ },
78
+ httpRequest: {
79
+ type: "dateFile",
80
+ filename: path.join(logsPath, "http", "requests"),
81
+ pattern: "yyyy-MM-dd.log",
82
+ numBackups: 30,
83
+ alwaysIncludePattern: true,
84
+ layout: {
85
+ type: "pattern",
86
+ pattern: "[%d{hh:mm:ss.SSS}][%4.4p] %m"
87
+ }
88
+ }
89
+ },
90
+ categories: {
91
+ default: {
92
+ appenders: ["console", "command"],
93
+ level: currentLogLevel
94
+ },
95
+ http: {
96
+ appenders: ["httpConsole", "httpRequest"],
97
+ level: "debug"
98
+ }
99
+ },
100
+ pm2: true
101
+ });
102
+ });
103
+ };
81
104
  var CustomLogger = class {
82
105
  logger;
106
+ queue = [];
83
107
  chalk;
84
108
  red;
85
109
  green;
@@ -90,7 +114,10 @@ var CustomLogger = class {
90
114
  white;
91
115
  gray;
92
116
  constructor(name) {
93
- this.logger = log4js.getLogger(name);
117
+ log4jsPromise.then((log4js) => {
118
+ this.logger = log4js.getLogger(name);
119
+ this.flush();
120
+ });
94
121
  this.chalk = new Chalk();
95
122
  this.red = this.chalk.red;
96
123
  this.green = this.chalk.green;
@@ -101,20 +128,31 @@ var CustomLogger = class {
101
128
  this.white = this.chalk.white;
102
129
  this.gray = this.chalk.gray;
103
130
  }
131
+ flush() {
132
+ if (!this.logger) return;
133
+ while (this.queue.length) {
134
+ const [method, args] = this.queue.shift();
135
+ this.logger[method](...args);
136
+ }
137
+ }
138
+ proxy(method, args) {
139
+ if (this.logger) this.logger[method](...args);
140
+ else this.queue.push([method, args]);
141
+ }
104
142
  info(message, ...args) {
105
- this.logger.info(message, ...args);
143
+ this.proxy("info", [message, ...args]);
106
144
  }
107
145
  warn(message, ...args) {
108
- this.logger.warn(message, ...args);
146
+ this.proxy("warn", [message, ...args]);
109
147
  }
110
148
  error(message, ...args) {
111
- this.logger.error(message, ...args);
149
+ this.proxy("error", [message, ...args]);
112
150
  }
113
151
  mark(message, ...args) {
114
- this.logger.mark(message, ...args);
152
+ this.proxy("mark", [message, ...args]);
115
153
  }
116
154
  debug(message, ...args) {
117
- this.logger.debug(message, ...args);
155
+ this.proxy("debug", [message, ...args]);
118
156
  }
119
157
  };
120
158
  const logger = new CustomLogger("default");
@@ -489,6 +527,11 @@ const BilibiliValidateCaptchaParamsSchema = zod.object({
489
527
  validate: zod.string({ error: "验证码validate必须是字符串" }).min(1, { error: "验证码validate不能为空" }),
490
528
  seccode: zod.string({ error: "验证码seccode必须是字符串" }).min(1, { error: "验证码seccode不能为空" })
491
529
  });
530
+ const BilibiliDanmakuParamsSchema = zod.object({
531
+ methodType: zod.literal("实时弹幕", { error: "方法类型必须是\"实时弹幕\"" }),
532
+ cid: smartNumber("CID不能为空", 1, true),
533
+ segment_index: zod.coerce.number({ error: "分段序号必须是数字" }).int({ error: "分段序号必须是整数" }).positive({ error: "分段序号必须是正数" }).default(1).optional()
534
+ });
492
535
  const BilibiliValidationSchemas = {
493
536
  单个视频作品数据: BilibiliVideoParamsSchema,
494
537
  单个视频下载信息数据: BilibiliVideoDownloadParamsSchema,
@@ -515,7 +558,8 @@ const BilibiliValidationSchemas = {
515
558
  专栏文章基本信息: BilibiliArticleInfoParamsSchema,
516
559
  文集基本信息: BilibiliColumnInfoParamsSchema,
517
560
  从_v_voucher_申请_captcha: BilibiliApplyCaptchaParamsSchema,
518
- 验证验证码结果: BilibiliValidateCaptchaParamsSchema
561
+ 验证验证码结果: BilibiliValidateCaptchaParamsSchema,
562
+ 实时弹幕: BilibiliDanmakuParamsSchema
519
563
  };
520
564
  const BilibiliMethodRoutes = {
521
565
  单个视频作品数据: "/fetch_one_video",
@@ -543,7 +587,8 @@ const BilibiliMethodRoutes = {
543
587
  专栏文章基本信息: "/fetch_article_info",
544
588
  文集基本信息: "/fetch_column_info",
545
589
  从_v_voucher_申请_captcha: "/apply_captcha",
546
- 验证验证码结果: "/validate_captcha"
590
+ 验证验证码结果: "/validate_captcha",
591
+ 实时弹幕: "/fetch_danmaku"
547
592
  };
548
593
 
549
594
  //#endregion
@@ -713,51 +758,26 @@ var xiaohongshuSign = class {
713
758
  return this.client.signXsPost(path$1, a1Cookie, clientType, body);
714
759
  }
715
760
  /**
716
- * 生成X-S签名(兼容旧接口)
717
- * @param url - 请求URL
718
- * @param body - 请求体
719
- * @param userAgent - User-Agent(暂未使用)
720
- * @param method - 请求方法,默认为 'POST'
721
- * @param a1Cookie - a1 cookie值
722
- * @returns X-S签名
723
- */
724
- static generateXS(url$1, body, userAgent, method = "POST", a1Cookie = "") {
725
- try {
726
- const urlObj = new URL(url$1);
727
- const path$1 = urlObj.pathname + urlObj.search;
728
- if (method.toUpperCase() === "GET") {
729
- const params = typeof body === "object" ? body : {};
730
- return this.generateXSGet(path$1, a1Cookie, "xhs-pc-web", params);
731
- } else {
732
- const requestBody = typeof body === "object" ? body : {};
733
- return this.generateXSPost(path$1, a1Cookie, "xhs-pc-web", requestBody);
734
- }
735
- } catch (error) {
736
- console.error("生成X-S签名失败:", error);
737
- throw new Error(`签名生成失败: ${error}`);
738
- }
739
- }
740
- /**
741
761
  * 生成X-S-Common参数
742
- * @param length - 长度
762
+ * @param cookies - cookie字符串
743
763
  * @returns Base64编码的随机字符串
744
764
  */
745
- static generateXSCommon(length = 945) {
746
- return crypto.randomBytes(length).toString("base64").replace(/=+$/, "");
765
+ static generateXSCommon(cookies) {
766
+ return this.client.signXsCommon(cookies);
747
767
  }
748
768
  /**
749
769
  * 生成X-T时间戳
750
770
  * @returns 当前时间戳字符串
751
771
  */
752
772
  static generateXT() {
753
- return Date.now().toString();
773
+ return this.client.getXT();
754
774
  }
755
775
  /**
756
776
  * 生成X-B3-Traceid
757
777
  * @returns 16位随机字符串
758
778
  */
759
779
  static generateXB3Traceid() {
760
- return Array.from({ length: 16 }, () => "abcdef0123456789"[Math.floor(Math.random() * 16)]).join("");
780
+ return this.client.getB3TraceId();
761
781
  }
762
782
  /**
763
783
  * 从cookie字符串中提取a1值
@@ -1243,7 +1263,8 @@ const fetchResponse = async (config, maxRetries = DEFAULT_MAX_RETRIES) => {
1243
1263
  * 判断结果是否为网络错误响应
1244
1264
  * @param result - 请求结果
1245
1265
  * @returns 是否为ErrorResult
1246
- * @description 通过检查 error 字段中的 amagiError 来区分网络错误和业务错误
1266
+ *
1267
+ * 通过检查 error 字段中的 amagiError 来区分网络错误和业务错误
1247
1268
  */
1248
1269
  const isNetworkErrorResult = (result) => {
1249
1270
  if (result === null || typeof result !== "object") return false;
@@ -1512,6 +1533,17 @@ var BiLiBiLiAPI = class {
1512
1533
  }
1513
1534
  };
1514
1535
  }
1536
+ /**
1537
+ * 获取实时弹幕(web端 protobuf 接口)
1538
+ * @see https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/danmaku_proto.md
1539
+ */
1540
+ 实时弹幕(data$1) {
1541
+ return `https://api.bilibili.com/x/v2/dm/web/seg.so?${new URLSearchParams({
1542
+ type: "1",
1543
+ oid: data$1.cid.toString(),
1544
+ segment_index: (data$1.segment_index ?? 1).toString()
1545
+ }).toString()}`;
1546
+ }
1515
1547
  };
1516
1548
  /** 该类下的所有方法只会返回拼接好参数后的 Url 地址,需要手动请求该地址以获取数据 */
1517
1549
  const bilibiliApiUrls = new BiLiBiLiAPI();
@@ -1576,7 +1608,8 @@ const bilibili = {
1576
1608
  getColumnInfo: createBilibiliApiMethod("文集基本信息"),
1577
1609
  getUserProfileDetail: createBilibiliApiMethod("用户空间详细信息"),
1578
1610
  applyVoucherCaptcha: createBilibiliApiMethod("从_v_voucher_申请_captcha"),
1579
- validateCaptcha: createBilibiliApiMethod("验证验证码结果")
1611
+ validateCaptcha: createBilibiliApiMethod("验证验证码结果"),
1612
+ getDanmaku: createBilibiliApiMethod("实时弹幕")
1580
1613
  };
1581
1614
  /**
1582
1615
  * 创建绑定了cookie的B站API对象
@@ -1610,7 +1643,8 @@ const createBoundBilibiliApi = (cookie, requestConfig) => {
1610
1643
  getColumnInfo: createBoundBilibiliApiMethod("文集基本信息", cookie),
1611
1644
  getUserProfileDetail: createBoundBilibiliApiMethod("用户空间详细信息", cookie),
1612
1645
  applyVoucherCaptcha: createBoundBilibiliApiMethod("从_v_voucher_申请_captcha", cookie),
1613
- validateCaptcha: createBoundBilibiliApiMethod("验证验证码结果", cookie)
1646
+ validateCaptcha: createBoundBilibiliApiMethod("验证验证码结果", cookie),
1647
+ getDanmaku: createBoundBilibiliApiMethod("实时弹幕", cookie)
1614
1648
  };
1615
1649
  };
1616
1650
 
@@ -1666,6 +1700,101 @@ const bv2av = (bvid) => {
1666
1700
  return Number(tmp & MASK_CODE ^ XOR_CODE);
1667
1701
  };
1668
1702
 
1703
+ //#endregion
1704
+ //#region src/platform/bilibili/sign/danmaku_proto.ts
1705
+ /**
1706
+ * B站弹幕 Protobuf 定义(内联)
1707
+ * @see https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/danmaku/danmaku_proto.md
1708
+ */
1709
+ const DANMAKU_PROTO_JSON = { nested: { bilibili: { nested: { community: { nested: { service: { nested: { dm: { nested: { v1: { nested: {
1710
+ DmSegMobileReply: { fields: { elems: {
1711
+ rule: "repeated",
1712
+ type: "DanmakuElem",
1713
+ id: 1
1714
+ } } },
1715
+ DanmakuElem: { fields: {
1716
+ id: {
1717
+ type: "int64",
1718
+ id: 1
1719
+ },
1720
+ progress: {
1721
+ type: "int32",
1722
+ id: 2
1723
+ },
1724
+ mode: {
1725
+ type: "int32",
1726
+ id: 3
1727
+ },
1728
+ fontsize: {
1729
+ type: "int32",
1730
+ id: 4
1731
+ },
1732
+ color: {
1733
+ type: "uint32",
1734
+ id: 5
1735
+ },
1736
+ midHash: {
1737
+ type: "string",
1738
+ id: 6
1739
+ },
1740
+ content: {
1741
+ type: "string",
1742
+ id: 7
1743
+ },
1744
+ ctime: {
1745
+ type: "int64",
1746
+ id: 8
1747
+ },
1748
+ weight: {
1749
+ type: "int32",
1750
+ id: 9
1751
+ },
1752
+ action: {
1753
+ type: "string",
1754
+ id: 10
1755
+ },
1756
+ pool: {
1757
+ type: "int32",
1758
+ id: 11
1759
+ },
1760
+ idStr: {
1761
+ type: "string",
1762
+ id: 12
1763
+ },
1764
+ attr: {
1765
+ type: "int32",
1766
+ id: 13
1767
+ },
1768
+ animation: {
1769
+ type: "string",
1770
+ id: 22
1771
+ }
1772
+ } }
1773
+ } } } } } } } } } } } };
1774
+ let DmSegMobileReplyType = null;
1775
+ /**
1776
+ * 获取 protobuf 类型定义
1777
+ */
1778
+ function getProtoType() {
1779
+ if (DmSegMobileReplyType) return DmSegMobileReplyType;
1780
+ DmSegMobileReplyType = protobuf.Root.fromJSON(DANMAKU_PROTO_JSON).lookupType("bilibili.community.service.dm.v1.DmSegMobileReply");
1781
+ return DmSegMobileReplyType;
1782
+ }
1783
+ /**
1784
+ * 解析弹幕分段响应
1785
+ * @param data - 二进制 protobuf 数据
1786
+ * @returns 解析后的弹幕数据
1787
+ */
1788
+ function parseDmSegMobileReply(data$1) {
1789
+ const messageType = getProtoType();
1790
+ const buffer = data$1 instanceof Uint8Array ? data$1 : new Uint8Array(data$1);
1791
+ const message = messageType.decode(buffer);
1792
+ return messageType.toObject(message, {
1793
+ longs: String,
1794
+ defaults: true
1795
+ });
1796
+ }
1797
+
1669
1798
  //#endregion
1670
1799
  //#region src/platform/bilibili/sign/wbi.ts
1671
1800
  /**
@@ -1965,6 +2094,7 @@ const bilibiliUtils = {
1965
2094
  av2bv,
1966
2095
  bv2av
1967
2096
  },
2097
+ danmaku: { parseDmSegMobileReply },
1968
2098
  bilibiliApiUrls,
1969
2099
  api: bilibili
1970
2100
  };
@@ -2304,6 +2434,48 @@ const fetchBilibili = async (data$1, cookie, requestConfig) => {
2304
2434
  url: bilibiliApiUrls.验证验证码结果(data$1).Url,
2305
2435
  data: bilibiliApiUrls.验证验证码结果(data$1).Body
2306
2436
  });
2437
+ case "实时弹幕": {
2438
+ const url$1 = bilibiliApiUrls.实时弹幕({
2439
+ cid: data$1.cid,
2440
+ segment_index: data$1.segment_index
2441
+ });
2442
+ try {
2443
+ const response = await fetchData({
2444
+ ...baseRequestConfig,
2445
+ url: url$1,
2446
+ responseType: "arraybuffer"
2447
+ });
2448
+ if (isNetworkErrorResult(response)) {
2449
+ const networkError = new Error(response.error.amagiError.errorDescription);
2450
+ Object.assign(networkError, {
2451
+ code: response.error.code,
2452
+ data: null,
2453
+ amagiError: {
2454
+ ...response.error.amagiError,
2455
+ requestType: data$1.methodType
2456
+ }
2457
+ });
2458
+ throw networkError;
2459
+ }
2460
+ return {
2461
+ code: 0,
2462
+ message: "success",
2463
+ data: { elems: parseDmSegMobileReply(response).elems }
2464
+ };
2465
+ } catch (error) {
2466
+ if (error && typeof error === "object" && "code" in error) return error;
2467
+ const Err = {
2468
+ errorDescription: `获取弹幕数据失败:${error instanceof Error ? error.message : "未知错误"}`,
2469
+ requestType: data$1.methodType,
2470
+ requestUrl: url$1
2471
+ };
2472
+ return {
2473
+ code: amagiAPIErrorCode.UNKNOWN,
2474
+ data: null,
2475
+ amagiError: Err
2476
+ };
2477
+ }
2478
+ }
2307
2479
  default:
2308
2480
  logger.warn(`未知的B站数据接口:「${logger.red(data$1.methodType)}」`);
2309
2481
  return null;
@@ -3649,11 +3821,53 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3649
3821
  }
3650
3822
  case "评论数据": {
3651
3823
  const urlGenerator = (params) => douyinApiUrls$1.评论(params);
3652
- return await fetchPaginatedData(data$1.methodType, urlGenerator, data$1, 50, baseRequestConfig, signType);
3824
+ return await fetchPaginatedData({
3825
+ type: data$1.methodType,
3826
+ apiUrlGenerator: urlGenerator,
3827
+ params: {
3828
+ ...data$1,
3829
+ cursor: data$1.cursor ?? 0
3830
+ },
3831
+ maxPageSize: 50,
3832
+ requestConfig: baseRequestConfig,
3833
+ signType,
3834
+ extractList: (resp) => resp.comments ?? [],
3835
+ updateParams: (params, resp) => ({
3836
+ ...params,
3837
+ cursor: resp.cursor
3838
+ }),
3839
+ hasMore: (resp) => resp.has_more === 1,
3840
+ formatFinalResponse: (resp, list) => ({
3841
+ ...resp,
3842
+ comments: list,
3843
+ cursor: resp.cursor ?? list.length
3844
+ })
3845
+ });
3653
3846
  }
3654
3847
  case "指定评论回复数据": {
3655
3848
  const urlGenerator = (params) => douyinApiUrls$1.二级评论(params);
3656
- return await fetchPaginatedData(data$1.methodType, urlGenerator, data$1, 3, baseRequestConfig, "x_bogus");
3849
+ return await fetchPaginatedData({
3850
+ type: data$1.methodType,
3851
+ apiUrlGenerator: urlGenerator,
3852
+ params: {
3853
+ ...data$1,
3854
+ cursor: data$1.cursor ?? 0
3855
+ },
3856
+ maxPageSize: 3,
3857
+ requestConfig: baseRequestConfig,
3858
+ signType: "x_bogus",
3859
+ extractList: (resp) => resp.comments ?? [],
3860
+ updateParams: (params, resp) => ({
3861
+ ...params,
3862
+ cursor: resp.cursor
3863
+ }),
3864
+ hasMore: (resp) => resp.has_more === 1,
3865
+ formatFinalResponse: (resp, list) => ({
3866
+ ...resp,
3867
+ comments: list,
3868
+ cursor: resp.cursor ?? list.length
3869
+ })
3870
+ });
3657
3871
  }
3658
3872
  case "用户主页数据": {
3659
3873
  const url$1 = douyinApiUrls$1.用户主页信息({ sec_uid: data$1.sec_uid });
@@ -3705,10 +3919,6 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3705
3919
  });
3706
3920
  }
3707
3921
  case "搜索数据": {
3708
- let search_id = "";
3709
- const maxPageSize = 15;
3710
- let fetchedSearchList = [];
3711
- let tmpresp = null;
3712
3922
  const searchType = data$1.type ?? "综合";
3713
3923
  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))}`;
3714
3924
  const customConfig = {
@@ -3720,146 +3930,82 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3720
3930
  };
3721
3931
  const isUserSearch = searchType === "用户";
3722
3932
  const isVideoSearch = searchType === "视频";
3723
- let isFirstRequest = true;
3724
- while (fetchedSearchList.length < Number(data$1.number ?? 10)) {
3725
- const requestCount = Math.min(Number(data$1.number ?? 50) - fetchedSearchList.length, maxPageSize);
3726
- const url$1 = douyinApiUrls$1.搜索({
3933
+ return await fetchPaginatedData({
3934
+ type: data$1.methodType,
3935
+ apiUrlGenerator: (params) => douyinApiUrls$1.搜索(params),
3936
+ params: {
3727
3937
  query: data$1.query,
3728
3938
  type: data$1.type,
3729
- number: requestCount,
3730
- search_id: search_id === "" ? void 0 : search_id
3731
- });
3732
- const raw = await GlobalGetData$2(data$1.methodType, {
3733
- ...customConfig,
3734
- url: url$1
3735
- });
3736
- if (isUserSearch) {
3737
- if (!raw || typeof raw !== "object") {
3738
- const Err = {
3739
- errorDescription: "抖音用户搜索返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!",
3740
- requestType: data$1.methodType ?? "未知请求类型",
3741
- requestUrl: url$1
3742
- };
3743
- const warningMessage = `
3744
- 获取响应数据失败!原因:${logger.yellow("用户搜索返回无有效数据,疑似触发反爬机制")}
3745
- 请求类型:「${data$1.methodType}」
3746
- 搜索关键词:「${data$1.query}」
3747
- 请求URL:${url$1}
3748
- `;
3749
- !isFirstRequest && logger.warn(warningMessage);
3750
- return {
3751
- code: douoyinAPIErrorCode.COOKIE,
3752
- data: raw,
3753
- amagiError: Err,
3754
- amagiMessage: warningMessage
3755
- };
3756
- }
3757
- const userList = raw.user_list;
3758
- if (isFirstRequest && (!userList || userList.length === 0)) {
3759
- const Err = {
3760
- errorDescription: "抖音用户搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!",
3761
- requestType: data$1.methodType ?? "未知请求类型",
3762
- requestUrl: url$1
3763
- };
3764
- const warningMessage = `
3765
- 获取响应数据失败!原因:${logger.yellow("用户搜索接口第一次请求就返回空数组,你的抖音Cookie可能已经失效!")}
3766
- 请求类型:「${data$1.methodType}」
3767
- 搜索关键词:「${data$1.query}」
3768
- 请求URL:${url$1}
3769
- `;
3770
- logger.warn(warningMessage);
3771
- return {
3772
- data: raw,
3773
- amagiError: Err,
3774
- amagiMessage: warningMessage
3775
- };
3776
- }
3777
- if (Array.isArray(userList) && userList.length > 0) fetchedSearchList.push(...userList);
3778
- tmpresp = raw;
3779
- search_id = raw.rid ?? search_id;
3780
- if (typeof raw.has_more === "number" && raw.has_more === 0) break;
3781
- if (!userList || userList.length === 0) break;
3782
- } else if (isVideoSearch) {
3783
- if (!raw || typeof raw !== "object") {
3784
- const Err = {
3785
- errorDescription: "抖音视频搜索接口返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效,你的抖音Cookie可能已经失效!",
3786
- requestType: data$1.methodType ?? "未知请求类型",
3787
- requestUrl: url$1
3788
- };
3789
- const warningMessage = `
3790
- 获取响应数据失败!原因:${logger.yellow("视频搜索接口返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!")}
3791
- 请求类型:「${data$1.methodType}」
3792
- 搜索关键词:「${data$1.query}」
3793
- 请求URL:${url$1}
3794
- `;
3795
- !isFirstRequest && logger.warn(warningMessage);
3796
- return {
3797
- code: douoyinAPIErrorCode.COOKIE,
3798
- data: raw,
3799
- amagiError: Err,
3800
- amagiMessage: warningMessage
3801
- };
3802
- }
3803
- const videoList = raw.data;
3804
- if (isFirstRequest && (!videoList || videoList.length === 0)) {
3805
- const Err = {
3806
- errorDescription: "抖音视频搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!",
3807
- requestType: data$1.methodType ?? "未知请求类型",
3808
- requestUrl: url$1
3809
- };
3810
- const warningMessage = `
3811
- 获取响应数据失败!原因:${logger.yellow("视频搜索接口第一次请求就返回空数组,你的抖音Cookie可能已经失效!")}
3812
- 请求类型:「${data$1.methodType}」
3813
- 搜索关键词:「${data$1.query}」
3814
- 请求URL:${url$1}
3815
- `;
3816
- logger.warn(warningMessage);
3939
+ number: data$1.number ?? 10,
3940
+ search_id: ""
3941
+ },
3942
+ maxPageSize: 15,
3943
+ requestConfig: customConfig,
3944
+ signType: null,
3945
+ processRawResponse: (raw) => {
3946
+ if (!isUserSearch && !isVideoSearch) {
3947
+ const responses = filterSearchResponses(typeof raw === "string" ? parseDouyinMultiJson(raw) : [raw]);
3948
+ if (responses.length === 0) return raw;
3949
+ const mergedData = [];
3950
+ let lastValid = {};
3951
+ for (const resp of responses) {
3952
+ if (Array.isArray(resp.data) && resp.data.length > 0) mergedData.push(...resp.data);
3953
+ lastValid = resp;
3954
+ }
3817
3955
  return {
3818
- data: raw,
3819
- amagiError: Err,
3820
- amagiMessage: warningMessage
3956
+ ...lastValid,
3957
+ data: mergedData
3821
3958
  };
3822
3959
  }
3823
- if (Array.isArray(videoList) && videoList.length > 0) fetchedSearchList.push(...videoList);
3824
- tmpresp = raw;
3825
- search_id = raw.log_pb?.impr_id ?? search_id;
3826
- if (typeof raw.has_more === "number" && raw.has_more === 0) break;
3827
- if (!videoList || videoList.length === 0) break;
3828
- } else {
3829
- const responses = filterSearchResponses(typeof raw === "string" ? parseDouyinMultiJson(raw) : [raw]);
3830
- if (responses.length === 0) {
3831
- const Err = {
3832
- errorDescription: "抖音综合搜索接口返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!",
3833
- requestType: data$1.methodType ?? "未知请求类型",
3834
- requestUrl: url$1
3835
- };
3960
+ return raw;
3961
+ },
3962
+ extractList: (resp) => {
3963
+ if (isUserSearch) return resp.user_list ?? [];
3964
+ return resp.data ?? [];
3965
+ },
3966
+ updateParams: (params, resp) => {
3967
+ let nextSearchId = params.search_id;
3968
+ if (isUserSearch) nextSearchId = resp.rid ?? nextSearchId;
3969
+ else nextSearchId = resp.log_pb?.impr_id ?? nextSearchId;
3970
+ return {
3971
+ ...params,
3972
+ search_id: nextSearchId
3973
+ };
3974
+ },
3975
+ hasMore: (resp) => {
3976
+ return resp.has_more !== 0;
3977
+ },
3978
+ validateFirstPage: (list, raw, url$1) => {
3979
+ const typeStr = isUserSearch ? "用户" : isVideoSearch ? "视频" : "综合";
3980
+ let isInvalidResponse = false;
3981
+ const rawAny = raw;
3982
+ if (!rawAny || typeof rawAny !== "object") isInvalidResponse = true;
3983
+ else if (isUserSearch && !rawAny.user_list) isInvalidResponse = true;
3984
+ else if (isVideoSearch && !rawAny.data) isInvalidResponse = true;
3985
+ else if (!isUserSearch && !isVideoSearch && !rawAny.data) isInvalidResponse = true;
3986
+ if (isInvalidResponse) {
3987
+ const desc = `抖音${typeStr}搜索返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!`;
3836
3988
  const warningMessage = `
3837
- 获取响应数据失败!原因:${logger.yellow("综合搜索接口返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!")}
3989
+ 获取响应数据失败!原因:${logger.yellow(`${typeStr}搜索返回无有效数据,疑似触发反爬机制`)}
3838
3990
  请求类型:「${data$1.methodType}」
3839
3991
  搜索关键词:「${data$1.query}」
3840
3992
  请求URL:${url$1}
3841
3993
  `;
3842
- !isFirstRequest && logger.warn(warningMessage);
3843
3994
  return {
3844
3995
  code: douoyinAPIErrorCode.COOKIE,
3845
3996
  data: raw,
3846
- amagiError: Err,
3997
+ amagiError: {
3998
+ errorDescription: desc,
3999
+ requestType: data$1.methodType ?? "未知请求类型",
4000
+ requestUrl: url$1
4001
+ },
3847
4002
  amagiMessage: warningMessage
3848
4003
  };
3849
4004
  }
3850
- for (const resp of responses) {
3851
- if (Array.isArray(resp.data) && resp.data.length > 0) fetchedSearchList.push(...resp.data);
3852
- tmpresp = resp;
3853
- search_id = resp.log_pb?.impr_id ?? search_id;
3854
- }
3855
- if (isFirstRequest && fetchedSearchList.length === 0) {
3856
- const Err = {
3857
- errorDescription: "抖音综合搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!",
3858
- requestType: data$1.methodType ?? "未知请求类型",
3859
- requestUrl: url$1
3860
- };
4005
+ if (!list || list.length === 0) {
4006
+ const desc = `抖音${typeStr}搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!`;
3861
4007
  const warningMessage = `
3862
- 获取响应数据失败!原因:${logger.yellow("综合搜索索接第一次请求就返回空数组,你的抖音Cookie可能已经失效!")}
4008
+ 获取响应数据失败!原因:${logger.yellow(`${typeStr}搜索接口第一次请求就返回空数组,你的抖音Cookie可能已经失效!`)}
3863
4009
  请求类型:「${data$1.methodType}」
3864
4010
  搜索关键词:「${data$1.query}」
3865
4011
  请求URL:${url$1}
@@ -3867,25 +4013,27 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3867
4013
  logger.warn(warningMessage);
3868
4014
  return {
3869
4015
  data: raw,
3870
- amagiError: Err,
4016
+ amagiError: {
4017
+ errorDescription: desc,
4018
+ requestType: data$1.methodType ?? "未知请求类型",
4019
+ requestUrl: url$1
4020
+ },
3871
4021
  amagiMessage: warningMessage
3872
4022
  };
3873
4023
  }
3874
- if (tmpresp && typeof tmpresp.has_more === "number" && tmpresp.has_more === 0) break;
4024
+ return null;
4025
+ },
4026
+ formatFinalResponse: (resp, list) => {
4027
+ if (isUserSearch) return {
4028
+ ...resp,
4029
+ user_list: list
4030
+ };
4031
+ return {
4032
+ ...resp,
4033
+ data: list
4034
+ };
3875
4035
  }
3876
- isFirstRequest = false;
3877
- }
3878
- const slicedList = Number(data$1.number ?? 10) === 0 ? [] : fetchedSearchList.slice(0, Number(data$1.number ?? 10));
3879
- return isUserSearch ? {
3880
- ...tmpresp ?? {},
3881
- user_list: slicedList
3882
- } : isVideoSearch ? {
3883
- ...tmpresp ?? {},
3884
- data: slicedList
3885
- } : {
3886
- ...tmpresp ?? {},
3887
- data: slicedList
3888
- };
4036
+ });
3889
4037
  }
3890
4038
  case "动态表情数据": {
3891
4039
  const url$1 = douyinApiUrls$1.互动表情();
@@ -4021,40 +4169,48 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
4021
4169
  };
4022
4170
  /**
4023
4171
  * 通用的分页请求函数
4024
- * @param type - 请求类型
4025
- * @param apiUrlGenerator - 接口URL生成器
4026
- * @param params - 请求参数
4027
- * @param maxPageSize - 单次请求的最大数据量
4028
- * @param requestConfig - axios请求配置(外部配置优先)
4029
- * @param signType - 签名算法类型
4030
- * @returns 返回分页数据
4172
+ * 封装了循环分页请求、数据合并、错误处理和反爬检测逻辑
4173
+ *
4174
+ * @template T - 列表项类型
4175
+ * @template P - 参数类型
4176
+ * @template R - 返回值类型
4177
+ * @template RawResp - 原始响应类型
4178
+ * @param config - 分页请求配置对象
4179
+ * @returns Promise<R> 返回最终构造的数据对象
4031
4180
  */
4032
- const fetchPaginatedData = async (type, apiUrlGenerator, params, maxPageSize, requestConfig, signType = "a_bogus") => {
4033
- let cursor = params.cursor ?? 0;
4034
- let fetchedData = [];
4035
- let tmpresp = {};
4181
+ const fetchPaginatedData = async (config) => {
4182
+ const { type, apiUrlGenerator, params, maxPageSize, requestConfig, signType = "a_bogus", extractList, updateParams, hasMore, formatFinalResponse, processRawResponse, validateFirstPage } = config;
4183
+ let currentParams = { ...params };
4184
+ const fetchedData = [];
4185
+ let lastResponse = {};
4186
+ let isFirstRequest = true;
4036
4187
  const userAgent = requestConfig.headers?.["User-Agent"];
4037
- while (fetchedData.length < Number(params.number ?? maxPageSize)) {
4038
- const requestCount = Math.min(Number(params.number ?? maxPageSize) - fetchedData.length, maxPageSize);
4039
- const url$1 = apiUrlGenerator({
4040
- ...params,
4041
- number: requestCount,
4042
- cursor
4043
- });
4044
- const response = await GlobalGetData$2(type, {
4188
+ const targetNumber = Number(params.number ?? maxPageSize);
4189
+ while (fetchedData.length < targetNumber) {
4190
+ const remaining = targetNumber - fetchedData.length;
4191
+ currentParams.number = Math.min(remaining, maxPageSize);
4192
+ const url$1 = apiUrlGenerator(currentParams);
4193
+ const finalUrl = signType ? buildSignedUrl(url$1, signType, userAgent) : url$1;
4194
+ const raw = await GlobalGetData$2(type, {
4045
4195
  ...requestConfig,
4046
- url: buildSignedUrl(url$1, signType, userAgent)
4196
+ url: finalUrl
4047
4197
  });
4048
- fetchedData.push(...response.comments ?? response.data ?? []);
4049
- tmpresp = response;
4050
- if ((response.comments ?? response.data ?? []).length < requestCount) break;
4051
- cursor = response.cursor;
4198
+ const response = processRawResponse ? processRawResponse(raw) : raw;
4199
+ if (response && response.amagiError) return response;
4200
+ const list = extractList(response);
4201
+ if (isFirstRequest && validateFirstPage) {
4202
+ const error = validateFirstPage(list, response, finalUrl);
4203
+ if (error) return error;
4204
+ }
4205
+ if (Array.isArray(list) && list.length > 0) fetchedData.push(...list);
4206
+ lastResponse = response;
4207
+ if (!hasMore(response)) break;
4208
+ if (!list || list.length === 0) break;
4209
+ currentParams = updateParams(currentParams, response);
4210
+ isFirstRequest = false;
4052
4211
  }
4053
- return {
4054
- ...tmpresp,
4055
- comments: params.number === 0 ? [] : fetchedData.slice(0, Number(params.number ?? maxPageSize)),
4056
- cursor: params.number === 0 ? 0 : fetchedData.length
4057
- };
4212
+ const slicedData = targetNumber === 0 ? [] : fetchedData.slice(0, targetNumber);
4213
+ return formatFinalResponse(lastResponse, slicedData);
4058
4214
  };
4059
4215
  /**
4060
4216
  * 全局数据获取函数
@@ -4363,7 +4519,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4363
4519
  headers: {
4364
4520
  ...baseRequestConfig.headers,
4365
4521
  "x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls$1.首页推荐数据(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web", xiaohongshuApiUrls$1.首页推荐数据(data$1).Body),
4366
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4522
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4367
4523
  "x-t": xiaohongshuSign.generateXT()
4368
4524
  }
4369
4525
  });
@@ -4374,7 +4530,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4374
4530
  headers: {
4375
4531
  ...baseRequestConfig.headers,
4376
4532
  "x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls$1.单个笔记数据(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web", xiaohongshuApiUrls$1.单个笔记数据(data$1).Body),
4377
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4533
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4378
4534
  "x-t": xiaohongshuSign.generateXT()
4379
4535
  }
4380
4536
  });
@@ -4394,7 +4550,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4394
4550
  headers: {
4395
4551
  ...baseRequestConfig$1.headers,
4396
4552
  "x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls$1.评论数据(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
4397
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4553
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4398
4554
  "x-t": xiaohongshuSign.generateXT()
4399
4555
  }
4400
4556
  });
@@ -4417,7 +4573,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4417
4573
  headers: {
4418
4574
  ...baseRequestConfig$1.headers,
4419
4575
  "x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls$1.用户数据(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
4420
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4576
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4421
4577
  "x-t": xiaohongshuSign.generateXT()
4422
4578
  }
4423
4579
  })),
@@ -4432,7 +4588,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4432
4588
  ...baseRequestConfig.headers,
4433
4589
  "x-b3-traceid": xiaohongshuSign.generateXB3Traceid(),
4434
4590
  "x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls$1.用户笔记数据(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
4435
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4591
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4436
4592
  "x-t": xiaohongshuSign.generateXT()
4437
4593
  }
4438
4594
  });
@@ -4452,7 +4608,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4452
4608
  headers: {
4453
4609
  ...baseRequestConfig$1.headers,
4454
4610
  "x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls$1.表情列表(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
4455
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4611
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4456
4612
  "x-t": xiaohongshuSign.generateXT()
4457
4613
  }
4458
4614
  });
@@ -4464,7 +4620,7 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
4464
4620
  headers: {
4465
4621
  ...baseRequestConfig.headers,
4466
4622
  "x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls$1.搜索笔记(data$1).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
4467
- "x-s-common": xiaohongshuSign.generateXSCommon(),
4623
+ "x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
4468
4624
  "x-t": xiaohongshuSign.generateXT()
4469
4625
  }
4470
4626
  });
@@ -4956,6 +5112,7 @@ const createAmagiClient = (options) => {
4956
5112
  * @returns Express应用实例
4957
5113
  */
4958
5114
  const startServer = (port = 4567) => {
5115
+ initLogger();
4959
5116
  const app = express();
4960
5117
  app.use(express.json());
4961
5118
  app.use(express.urlencoded({ extended: true }));
@@ -5173,7 +5330,14 @@ let DynamicType = /* @__PURE__ */ function(DynamicType$1) {
5173
5330
 
5174
5331
  //#endregion
5175
5332
  //#region src/index.ts
5176
- const VERSION = "5.12.1";
5333
+ /**
5334
+ * 获取版本号
5335
+ * 构建后使用 __VERSION__,开发环境从 package.json 读取
5336
+ */
5337
+ const getVersion = () => {
5338
+ return "5.13.0";
5339
+ };
5340
+ const VERSION = getVersion();
5177
5341
  /**
5178
5342
  * @deprecated 请使用 createAmagiClient 替代
5179
5343
  */
@@ -5209,4 +5373,5 @@ const Client = CreateApp;
5209
5373
  const amagi = Client;
5210
5374
 
5211
5375
  //#endregion
5212
- export { AdditionalType, ApiError, BilibiliApplyCaptchaParamsSchema, BilibiliArticleCardParamsSchema, BilibiliArticleInfoParamsSchema, BilibiliArticleParamsSchema, BilibiliAv2BvParamsSchema, BilibiliBangumiInfoParamsSchema, BilibiliBangumiStreamParamsSchema, BilibiliBv2AvParamsSchema, BilibiliColumnInfoParamsSchema, BilibiliCommentParamsSchema, BilibiliCommentReplyParamsSchema, BilibiliDynamicParamsSchema, BilibiliEmojiParamsSchema, BilibiliLiveParamsSchema, BilibiliLoginParamsSchema, BilibiliMethodRoutes, BilibiliQrcodeParamsSchema, BilibiliQrcodeStatusParamsSchema, BilibiliUserParamsSchema, BilibiliValidateCaptchaParamsSchema, BilibiliValidationSchemas, BilibiliVideoDownloadParamsSchema, BilibiliVideoParamsSchema, CommentType, CreateApp, DouyinCommentParamsSchema, DouyinCommentReplyParamsSchema, DouyinDanmakuParamsSchema, DouyinEmojiListParamsSchema, DouyinEmojiProParamsSchema, DouyinHotWordsParamsSchema, DouyinLiveRoomParamsSchema, DouyinMethodRoutes, DouyinMusicParamsSchema, DouyinQrcodeParamsSchema, DouyinSearchParamsSchema, DouyinUserParamsSchema, DouyinValidationSchemas, DouyinWorkParamsSchema, DynamicType, KuaishouCommentParamsSchema, KuaishouEmojiParamsSchema, KuaishouMethodRoutes, KuaishouValidationSchemas, KuaishouVideoParamsSchema, MajorType, ValidationError, XiaohongshuMethodRoutes, XiaohongshuValidationSchemas, amagi, amagiClient, av2bv, bilibili, bilibiliApiUrls, bilibiliErrorCodeMap, bilibiliUtils, bv2av, createAmagiClient, createBilibiliRoutes, createBilibiliRoutes as registerBilibiliRoutes, createBoundBilibiliApi, createBoundDouyinApi, createBoundKuaishouApi, createBoundXiaohongshuApi, createDouyinRoutes, createDouyinRoutes as registerDouyinRoutes, createErrorResponse, createKuaishouRoutes, createKuaishouRoutes as registerKuaishouRoutes, createSuccessResponse, createXiaohongshuRoutes, createXiaohongshuRoutes as registerXiaohongshuRoutes, Client as default, douyin, douyinApiUrls, douyinSign, douyinUtils, fetchData, fetchResponse, getBilibiliData, getDouyinData, getHeadersAndData, getKuaishouData, handleError, httpLogger, isNetworkErrorResult, kuaishou, kuaishouApiUrls, kuaishouUtils, logMiddleware, logger, qtparam, validateBilibiliParams, validateDouyinParams, validateKuaishouParams, validateXiaohongshuParams, wbi_sign, xiaohongshu, xiaohongshuApiUrls, xiaohongshuSign, xiaohongshuUtils };
5376
+ export { AdditionalType, ApiError, BilibiliApplyCaptchaParamsSchema, BilibiliArticleCardParamsSchema, BilibiliArticleInfoParamsSchema, BilibiliArticleParamsSchema, BilibiliAv2BvParamsSchema, BilibiliBangumiInfoParamsSchema, BilibiliBangumiStreamParamsSchema, BilibiliBv2AvParamsSchema, BilibiliColumnInfoParamsSchema, BilibiliCommentParamsSchema, BilibiliCommentReplyParamsSchema, BilibiliDanmakuParamsSchema, BilibiliDynamicParamsSchema, BilibiliEmojiParamsSchema, BilibiliLiveParamsSchema, BilibiliLoginParamsSchema, BilibiliMethodRoutes, BilibiliQrcodeParamsSchema, BilibiliQrcodeStatusParamsSchema, BilibiliUserParamsSchema, BilibiliValidateCaptchaParamsSchema, BilibiliValidationSchemas, BilibiliVideoDownloadParamsSchema, BilibiliVideoParamsSchema, CommentType, CreateApp, DouyinCommentParamsSchema, DouyinCommentReplyParamsSchema, DouyinDanmakuParamsSchema, DouyinEmojiListParamsSchema, DouyinEmojiProParamsSchema, DouyinHotWordsParamsSchema, DouyinLiveRoomParamsSchema, DouyinMethodRoutes, DouyinMusicParamsSchema, DouyinQrcodeParamsSchema, DouyinSearchParamsSchema, DouyinUserParamsSchema, DouyinValidationSchemas, DouyinWorkParamsSchema, DynamicType, KuaishouCommentParamsSchema, KuaishouEmojiParamsSchema, KuaishouMethodRoutes, KuaishouValidationSchemas, KuaishouVideoParamsSchema, MajorType, ValidationError, XiaohongshuMethodRoutes, XiaohongshuValidationSchemas, amagi, amagiClient, av2bv, bilibili, bilibiliApiUrls, bilibiliErrorCodeMap, bilibiliUtils, bv2av, createAmagiClient, createBilibiliRoutes, createBilibiliRoutes as registerBilibiliRoutes, createBoundBilibiliApi, createBoundDouyinApi, createBoundKuaishouApi, createBoundXiaohongshuApi, createDouyinRoutes, createDouyinRoutes as registerDouyinRoutes, createErrorResponse, createKuaishouRoutes, createKuaishouRoutes as registerKuaishouRoutes, createSuccessResponse, createXiaohongshuRoutes, createXiaohongshuRoutes as registerXiaohongshuRoutes, Client as default, douyin, douyinApiUrls, douyinSign, douyinUtils, fetchData, fetchResponse, getBilibiliData, getDouyinData, getHeadersAndData, getKuaishouData, handleError, httpLogger, initLogger, isNetworkErrorResult, kuaishou, kuaishouApiUrls, kuaishouUtils, logMiddleware, logger, parseDmSegMobileReply, qtparam, validateBilibiliParams, validateDouyinParams, validateKuaishouParams, validateXiaohongshuParams, wbi_sign, xiaohongshu, xiaohongshuApiUrls, xiaohongshuSign, xiaohongshuUtils };
5377
+ //# sourceMappingURL=index.js.map