@ikenxuan/amagi 5.7.2 → 5.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,19 +1,19 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import URL$1, { fileURLToPath } from "node:url";
3
+ import url from "node:url";
4
4
  import { Chalk } from "chalk";
5
5
  import log4js from "log4js";
6
6
  import axios, { AxiosError } from "axios";
7
7
  import crypto from "node:crypto";
8
- import { z } from "zod";
8
+ import zod from "zod";
9
9
  import { Xhshow } from "@ikenxuan/xhshow-ts";
10
- import express, { Router } from "express";
10
+ import express from "express";
11
11
 
12
12
  //#region src/model/logger.ts
13
13
  /** 获取包的绝对路径 */
14
14
  const getPackageLogsPath = () => {
15
15
  const currentFileUrl = import.meta.url;
16
- const currentFilePath = fileURLToPath(currentFileUrl);
16
+ const currentFilePath = url.fileURLToPath(currentFileUrl);
17
17
  let packageRoot = path.dirname(currentFilePath);
18
18
  while (packageRoot !== path.dirname(packageRoot)) {
19
19
  if (fs.existsSync(path.join(packageRoot, "package.json"))) break;
@@ -128,7 +128,7 @@ const logMiddleware = (pathsToLog) => {
128
128
  return (req, res, next) => {
129
129
  if (!pathsToLog || pathsToLog.some((path$1) => req.url.startsWith(path$1))) {
130
130
  const startTime = Date.now();
131
- const url = req.url;
131
+ const url$1 = req.url;
132
132
  const method = req.method;
133
133
  const clientIP = req.headers["x-forwarded-for"] ?? req.socket.remoteAddress;
134
134
  const referer = req.headers["referer"] ?? req.headers["referrer"] ?? "-";
@@ -142,7 +142,7 @@ const logMiddleware = (pathsToLog) => {
142
142
  const responseSize = res.get("content-length") ?? "0";
143
143
  const logData = {
144
144
  method,
145
- url,
145
+ url: url$1,
146
146
  statusCode,
147
147
  responseTime: `${responseTime}ms`,
148
148
  clientIP,
@@ -542,6 +542,10 @@ var BiLiBiLiAPI = class {
542
542
  评论区状态(data$1) {
543
543
  return `https://api.bilibili.com/x/v2/reply/subject/description?type=${data$1.type}&oid=${data$1.oid}`;
544
544
  }
545
+ /** 指定评论的回复 */
546
+ 指定评论的回复(data$1) {
547
+ return `https://api.bilibili.com/x/v2/reply/reply?type=${data$1.type}&oid=${data$1.oid}&root=${data$1.root}&ps=${data$1.number}`;
548
+ }
545
549
  表情列表() {
546
550
  return "https://api.bilibili.com/x/emote/user/panel/web?business=reply&web_location=0.0";
547
551
  }
@@ -634,6 +638,7 @@ const bilibili = {
634
638
  getVideoInfo: createBilibiliApiMethod("单个视频作品数据"),
635
639
  getVideoStream: createBilibiliApiMethod("单个视频下载信息数据"),
636
640
  getComments: createBilibiliApiMethod("评论数据"),
641
+ getCommentReply: createBilibiliApiMethod("指定评论的回复"),
637
642
  getUserProfile: createBilibiliApiMethod("用户主页数据"),
638
643
  getUserDynamic: createBilibiliApiMethod("用户主页动态列表数据"),
639
644
  getEmojiList: createBilibiliApiMethod("Emoji数据"),
@@ -664,6 +669,7 @@ const createBoundBilibiliApi = (cookie, requestConfig) => {
664
669
  getVideoInfo: createBoundBilibiliApiMethod("单个视频作品数据", cookie),
665
670
  getVideoStream: createBoundBilibiliApiMethod("单个视频下载信息数据", cookie),
666
671
  getComments: createBoundBilibiliApiMethod("评论数据", cookie),
672
+ getCommentReply: createBoundBilibiliApiMethod("指定评论的回复", cookie),
667
673
  getUserProfile: createBoundBilibiliApiMethod("用户主页数据", cookie),
668
674
  getUserDynamic: createBoundBilibiliApiMethod("用户主页动态列表数据", cookie),
669
675
  getEmojiList: createBoundBilibiliApiMethod("Emoji数据", cookie),
@@ -855,9 +861,9 @@ const getWbiKeys = async (cookie) => {
855
861
  */
856
862
  const wbi_sign = async (BASEURL, cookie) => {
857
863
  const web_keys = await getWbiKeys(cookie);
858
- const url = new URL(BASEURL);
864
+ const url$1 = new URL(BASEURL);
859
865
  const params = {};
860
- for (const [key, value] of url.searchParams.entries()) params[key] = value;
866
+ for (const [key, value] of url$1.searchParams.entries()) params[key] = value;
861
867
  return encWbi(params, web_keys.img_key, web_keys.sub_key);
862
868
  };
863
869
 
@@ -934,7 +940,7 @@ const handleError = (error, requestPath) => {
934
940
  platform: error.platform,
935
941
  requestPath
936
942
  };
937
- if (error instanceof z.ZodError) return handleError(ValidationError.fromZodError(error, requestPath), requestPath);
943
+ if (error instanceof zod.ZodError) return handleError(ValidationError.fromZodError(error, requestPath), requestPath);
938
944
  return {
939
945
  code: 500,
940
946
  message: error instanceof Error ? error.message : "未知错误",
@@ -946,8 +952,8 @@ const handleError = (error, requestPath) => {
946
952
  //#endregion
947
953
  //#region src/validation/utils.ts
948
954
  function smartNumber(errorMessage, minValue = 1, isInteger = false) {
949
- if (isInteger) return z.coerce.number({ error: errorMessage }).int({ error: `${errorMessage.replace("不能为空", "")}必须是整数,不能包含小数` }).min(minValue, { error: `${errorMessage.replace("不能为空", "")}必须大于等于${minValue}` });
950
- else return z.coerce.number({ error: errorMessage }).min(minValue, { error: `${errorMessage.replace("不能为空", "")}必须大于等于${minValue}` });
955
+ if (isInteger) return zod.coerce.number({ error: errorMessage }).int({ error: `${errorMessage.replace("不能为空", "")}必须是整数,不能包含小数` }).min(minValue, { error: `${errorMessage.replace("不能为空", "")}必须大于等于${minValue}` });
956
+ else return zod.coerce.number({ error: errorMessage }).min(minValue, { error: `${errorMessage.replace("不能为空", "")}必须大于等于${minValue}` });
951
957
  }
952
958
  /**
953
959
  * 智能正整数转换器 - 专门用于正整数类型的转换
@@ -976,18 +982,48 @@ const extractCreatorInfoFromHtml = (html) => {
976
982
 
977
983
  //#endregion
978
984
  //#region src/validation/bilibili.ts
979
- const BilibiliVideoParamsSchema = z.object({
980
- methodType: z.literal("单个视频作品数据", { error: "方法类型必须是\"单个视频作品数据\"" }),
981
- bvid: z.string({ error: "BVID必须是字符串" }).min(1, { error: "BVID不能为空" })
985
+ const BilibiliVideoParamsSchema = zod.object({
986
+ methodType: zod.literal("单个视频作品数据", { error: "方法类型必须是\"单个视频作品数据\"" }),
987
+ bvid: zod.string({ error: "BVID必须是字符串" }).min(1, { error: "BVID不能为空" })
982
988
  });
983
- const BilibiliVideoDownloadParamsSchema = z.object({
984
- methodType: z.literal("单个视频下载信息数据", { error: "方法类型必须是\"单个视频下载信息数据\"" }),
989
+ const BilibiliVideoDownloadParamsSchema = zod.object({
990
+ methodType: zod.literal("单个视频下载信息数据", { error: "方法类型必须是\"单个视频下载信息数据\"" }),
985
991
  avid: smartNumber("AVID不能为空", 1, true),
986
992
  cid: smartNumber("CID不能为空", 1, true)
987
993
  });
988
- const BilibiliCommentParamsSchema = z.object({
989
- methodType: z.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
990
- oid: z.string({ error: "OID必须是字符串" }).min(1, { error: "OID不能为空" }),
994
+ const BilibiliCommentParamsSchema = zod.object({
995
+ methodType: zod.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
996
+ oid: zod.string({ error: "OID必须是字符串" }).min(1, { error: "OID不能为空" }),
997
+ type: smartNumber("评论类型不能为空", 1, true).refine((val) => [
998
+ 1,
999
+ 2,
1000
+ 4,
1001
+ 5,
1002
+ 6,
1003
+ 7,
1004
+ 8,
1005
+ 9,
1006
+ 10,
1007
+ 11,
1008
+ 12,
1009
+ 13,
1010
+ 14,
1011
+ 15,
1012
+ 16,
1013
+ 17,
1014
+ 18,
1015
+ 19,
1016
+ 20,
1017
+ 21,
1018
+ 22,
1019
+ 33
1020
+ ].includes(val), { error: "无效的评论区类型" }),
1021
+ number: zod.coerce.number({ error: "评论数量必须是数字" }).int({ error: "评论数量必须是整数" }).positive({ error: "评论数量必须是正数" }).default(20).optional(),
1022
+ pn: zod.coerce.number({ error: "页码必须是数字" }).int({ error: "页码必须是整数" }).positive({ error: "页码必须是正数" }).default(1).optional()
1023
+ });
1024
+ const BilibiliCommentReplyParamsSchema = zod.object({
1025
+ methodType: zod.literal("指定评论的回复", { error: "方法类型必须是\"指定评论的回复\"" }),
1026
+ oid: zod.string({ error: "OID必须是字符串" }).min(1, { error: "OID不能为空" }),
991
1027
  type: smartNumber("评论类型不能为空", 1, true).refine((val) => [
992
1028
  1,
993
1029
  2,
@@ -1012,73 +1048,75 @@ const BilibiliCommentParamsSchema = z.object({
1012
1048
  22,
1013
1049
  33
1014
1050
  ].includes(val), { error: "无效的评论区类型" }),
1015
- number: z.coerce.number({ error: "评论数量必须是数字" }).int({ error: "评论数量必须是整数" }).positive({ error: "评论数量必须是正数" }).default(20).optional(),
1016
- pn: z.coerce.number({ error: "页码必须是数字" }).int({ error: "页码必须是整数" }).positive({ error: "页码必须是正数" }).default(1).optional()
1051
+ root: zod.string({ error: "根评论ID必须是字符串" }).min(1, { error: "根评论ID不能为空" }),
1052
+ number: zod.coerce.number({ error: "评论数量必须是数字" }).int({ error: "评论数量必须是整数" }).positive({ error: "评论数量必须是正数" }).default(20).optional(),
1053
+ pn: zod.coerce.number({ error: "页码必须是数字" }).int({ error: "页码必须是整数" }).positive({ error: "页码必须是正数" }).default(1).optional()
1017
1054
  });
1018
- const BilibiliUserParamsSchema = z.object({
1019
- methodType: z.enum([
1055
+ const BilibiliUserParamsSchema = zod.object({
1056
+ methodType: zod.enum([
1020
1057
  "用户主页数据",
1021
1058
  "用户主页动态列表数据",
1022
1059
  "获取UP主总播放量"
1023
1060
  ], { error: "方法类型必须是指定的枚举值之一" }),
1024
1061
  host_mid: smartNumber("UP主UID不能为空", 1, true)
1025
1062
  });
1026
- const BilibiliEmojiParamsSchema = z.object({ methodType: z.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
1027
- const BilibiliBangumiInfoParamsSchema = z.object({
1028
- methodType: z.literal("番剧基本信息数据", { error: "方法类型必须是\"番剧基本信息数据\"" }),
1029
- ep_id: z.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" }).optional(),
1030
- season_id: z.string({ error: "番剧季度ID必须是字符串" }).optional()
1063
+ const BilibiliEmojiParamsSchema = zod.object({ methodType: zod.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
1064
+ const BilibiliBangumiInfoParamsSchema = zod.object({
1065
+ methodType: zod.literal("番剧基本信息数据", { error: "方法类型必须是\"番剧基本信息数据\"" }),
1066
+ ep_id: zod.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" }).optional(),
1067
+ season_id: zod.string({ error: "番剧季度ID必须是字符串" }).optional()
1031
1068
  }).refine((data$1) => data$1.ep_id ?? data$1.season_id, {
1032
1069
  error: "ep_id 和 season_id 至少需要提供一个",
1033
1070
  path: ["ep_id"]
1034
1071
  });
1035
- const BilibiliBangumiStreamParamsSchema = z.object({
1036
- methodType: z.literal("番剧下载信息数据", { error: "方法类型必须是\"番剧下载信息数据\"" }),
1072
+ const BilibiliBangumiStreamParamsSchema = zod.object({
1073
+ methodType: zod.literal("番剧下载信息数据", { error: "方法类型必须是\"番剧下载信息数据\"" }),
1037
1074
  cid: smartNumber("CID不能为空", 1, true),
1038
- ep_id: z.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" })
1075
+ ep_id: zod.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" })
1039
1076
  });
1040
- const BilibiliDynamicParamsSchema = z.object({
1041
- methodType: z.enum(["动态详情数据", "动态卡片数据"], { error: "方法类型必须是\"动态详情数据\"或\"动态卡片数据\"" }),
1042
- dynamic_id: z.string({ error: "动态ID必须是字符串" }).min(1, { error: "动态ID不能为空" })
1077
+ const BilibiliDynamicParamsSchema = zod.object({
1078
+ methodType: zod.enum(["动态详情数据", "动态卡片数据"], { error: "方法类型必须是\"动态详情数据\"或\"动态卡片数据\"" }),
1079
+ dynamic_id: zod.string({ error: "动态ID必须是字符串" }).min(1, { error: "动态ID不能为空" })
1043
1080
  });
1044
- const BilibiliLiveParamsSchema = z.object({
1045
- methodType: z.enum(["直播间信息", "直播间初始化信息"], { error: "方法类型必须是\"直播间信息\"或\"直播间初始化信息\"" }),
1046
- room_id: z.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" })
1081
+ const BilibiliLiveParamsSchema = zod.object({
1082
+ methodType: zod.enum(["直播间信息", "直播间初始化信息"], { error: "方法类型必须是\"直播间信息\"或\"直播间初始化信息\"" }),
1083
+ room_id: zod.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" })
1047
1084
  });
1048
- const BilibiliLoginParamsSchema = z.object({ methodType: z.literal("登录基本信息", { error: "方法类型必须是\"登录基本信息\"" }) });
1049
- const BilibiliQrcodeParamsSchema = z.object({ methodType: z.literal("申请二维码", { error: "方法类型必须是\"申请二维码\"" }) });
1050
- const BilibiliQrcodeStatusParamsSchema = z.object({
1051
- methodType: z.literal("二维码状态", { error: "方法类型必须是\"二维码状态\"" }),
1052
- qrcode_key: z.string({ error: "二维码key必须是字符串" }).min(1, { error: "二维码key不能为空" })
1085
+ const BilibiliLoginParamsSchema = zod.object({ methodType: zod.literal("登录基本信息", { error: "方法类型必须是\"登录基本信息\"" }) });
1086
+ const BilibiliQrcodeParamsSchema = zod.object({ methodType: zod.literal("申请二维码", { error: "方法类型必须是\"申请二维码\"" }) });
1087
+ const BilibiliQrcodeStatusParamsSchema = zod.object({
1088
+ methodType: zod.literal("二维码状态", { error: "方法类型必须是\"二维码状态\"" }),
1089
+ qrcode_key: zod.string({ error: "二维码key必须是字符串" }).min(1, { error: "二维码key不能为空" })
1053
1090
  });
1054
- const BilibiliAv2BvParamsSchema = z.object({
1055
- methodType: z.literal("AV转BV", { error: "方法类型必须是\"AV转BV\"" }),
1056
- avid: z.coerce.number({ error: "AVID必须是数字" }).int({ error: "AVID必须是整数" }).positive({ error: "AVID必须是正数" })
1091
+ const BilibiliAv2BvParamsSchema = zod.object({
1092
+ methodType: zod.literal("AV转BV", { error: "方法类型必须是\"AV转BV\"" }),
1093
+ avid: zod.coerce.number({ error: "AVID必须是数字" }).int({ error: "AVID必须是整数" }).positive({ error: "AVID必须是正数" })
1057
1094
  });
1058
- const BilibiliBv2AvParamsSchema = z.object({
1059
- methodType: z.literal("BV转AV", { error: "方法类型必须是\"BV转AV\"" }),
1060
- bvid: z.string({ error: "BVID必须是字符串" }).min(1, { error: "BVID不能为空" })
1095
+ const BilibiliBv2AvParamsSchema = zod.object({
1096
+ methodType: zod.literal("BV转AV", { error: "方法类型必须是\"BV转AV\"" }),
1097
+ bvid: zod.string({ error: "BVID必须是字符串" }).min(1, { error: "BVID不能为空" })
1061
1098
  });
1062
- const BilibiliArticleParamsSchema = z.object({
1063
- methodType: z.literal("专栏正文内容", { error: "方法类型必须是\"专栏正文内容\"" }),
1064
- id: z.string({ error: "专栏ID必须是字符串" }).min(1, { error: "专栏ID不能为空" })
1099
+ const BilibiliArticleParamsSchema = zod.object({
1100
+ methodType: zod.literal("专栏正文内容", { error: "方法类型必须是\"专栏正文内容\"" }),
1101
+ id: zod.string({ error: "专栏ID必须是字符串" }).min(1, { error: "专栏ID不能为空" })
1065
1102
  });
1066
- const BilibiliArticleCardParamsSchema = z.object({
1067
- methodType: z.literal("专栏显示卡片信息", { error: "方法类型必须是\"专栏显示卡片信息\"" }),
1068
- ids: z.union([z.array(z.string({ error: "被查询的 id 列表必须是字符串数组" })).min(1, { error: "被查询的 id 列表不能为空" }), z.string({ error: "被查询的 id 列表必须是字符串" }).min(1, { error: "被查询的 id 列表不能为空" })])
1103
+ const BilibiliArticleCardParamsSchema = zod.object({
1104
+ methodType: zod.literal("专栏显示卡片信息", { error: "方法类型必须是\"专栏显示卡片信息\"" }),
1105
+ ids: zod.union([zod.array(zod.string({ error: "被查询的 id 列表必须是字符串数组" })).min(1, { error: "被查询的 id 列表不能为空" }), zod.string({ error: "被查询的 id 列表必须是字符串" }).min(1, { error: "被查询的 id 列表不能为空" })])
1069
1106
  });
1070
- const BilibiliArticleInfoParamsSchema = z.object({
1071
- methodType: z.literal("专栏文章基本信息", { error: "方法类型必须是\"专栏文章基本信息\"" }),
1072
- id: z.string({ error: "专栏ID必须是字符串" }).min(1, { error: "专栏ID不能为空" })
1107
+ const BilibiliArticleInfoParamsSchema = zod.object({
1108
+ methodType: zod.literal("专栏文章基本信息", { error: "方法类型必须是\"专栏文章基本信息\"" }),
1109
+ id: zod.string({ error: "专栏ID必须是字符串" }).min(1, { error: "专栏ID不能为空" })
1073
1110
  });
1074
- const BilibiliColumnInfoParamsSchema = z.object({
1075
- methodType: z.literal("文集基本信息", { error: "方法类型必须是\"文集基本信息\"" }),
1076
- id: z.string({ error: "文集ID必须是字符串" }).min(1, { error: "文集ID不能为空" })
1111
+ const BilibiliColumnInfoParamsSchema = zod.object({
1112
+ methodType: zod.literal("文集基本信息", { error: "方法类型必须是\"文集基本信息\"" }),
1113
+ id: zod.string({ error: "文集ID必须是字符串" }).min(1, { error: "文集ID不能为空" })
1077
1114
  });
1078
1115
  const BilibiliValidationSchemas = {
1079
1116
  单个视频作品数据: BilibiliVideoParamsSchema,
1080
1117
  单个视频下载信息数据: BilibiliVideoDownloadParamsSchema,
1081
1118
  评论数据: BilibiliCommentParamsSchema,
1119
+ 指定评论的回复: BilibiliCommentReplyParamsSchema,
1082
1120
  用户主页数据: BilibiliUserParamsSchema,
1083
1121
  用户主页动态列表数据: BilibiliUserParamsSchema,
1084
1122
  Emoji数据: BilibiliEmojiParamsSchema,
@@ -1099,62 +1137,87 @@ const BilibiliValidationSchemas = {
1099
1137
  专栏文章基本信息: BilibiliArticleInfoParamsSchema,
1100
1138
  文集基本信息: BilibiliColumnInfoParamsSchema
1101
1139
  };
1140
+ const BilibiliMethodRoutes = {
1141
+ 单个视频作品数据: "/fetch_one_video",
1142
+ 单个视频下载信息数据: "/fetch_video_playurl",
1143
+ 评论数据: "/fetch_work_comments",
1144
+ 指定评论的回复: "/fetch_comment_reply",
1145
+ 用户主页数据: "/fetch_user_profile",
1146
+ 用户主页动态列表数据: "/fetch_user_dynamic",
1147
+ Emoji数据: "/fetch_emoji_list",
1148
+ 番剧基本信息数据: "/fetch_bangumi_video_info",
1149
+ 番剧下载信息数据: "/fetch_bangumi_video_playurl",
1150
+ 动态详情数据: "/fetch_dynamic_info",
1151
+ 动态卡片数据: "/fetch_dynamic_card",
1152
+ 直播间信息: "/fetch_live_room_detail",
1153
+ 直播间初始化信息: "/fetch_liveroom_def",
1154
+ 登录基本信息: "/login_basic_info",
1155
+ 申请二维码: "/new_login_qrcode",
1156
+ 二维码状态: "/check_qrcode",
1157
+ 获取UP主总播放量: "/fetch_user_full_view",
1158
+ AV转BV: "/av_to_bv",
1159
+ BV转AV: "/bv_to_av",
1160
+ 专栏正文内容: "/fetch_article_content",
1161
+ 专栏显示卡片信息: "/fetch_article_card",
1162
+ 专栏文章基本信息: "/fetch_article_info",
1163
+ 文集基本信息: "/fetch_column_info"
1164
+ };
1102
1165
 
1103
1166
  //#endregion
1104
1167
  //#region src/validation/douyin.ts
1105
- const DouyinWorkParamsSchema = z.object({
1106
- methodType: z.enum([
1107
- "文字作品数据",
1168
+ const DouyinWorkParamsSchema = zod.object({
1169
+ methodType: zod.enum([
1108
1170
  "视频作品数据",
1109
1171
  "图集作品数据",
1110
1172
  "合辑作品数据",
1111
1173
  "聚合解析"
1112
1174
  ], { error: "方法类型必须是指定的枚举值之一" }),
1113
- aweme_id: z.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
1175
+ aweme_id: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
1114
1176
  });
1115
- const DouyinCommentParamsSchema = z.object({
1116
- methodType: z.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
1117
- aweme_id: z.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
1177
+ const DouyinCommentParamsSchema = zod.object({
1178
+ methodType: zod.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
1179
+ aweme_id: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
1118
1180
  number: smartPositiveInteger("评论数量必须是正整数").optional().default(50),
1119
- cursor: z.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
1181
+ cursor: zod.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
1120
1182
  });
1121
- const DouyinSearchParamsSchema = z.object({
1122
- methodType: z.enum(["热点词数据", "搜索数据"], { error: "方法类型必须是\"热点词数据\"或\"搜索数据\"" }),
1123
- query: z.string({ error: "搜索词必须是字符串" }).min(1, { error: "搜索词不能为空" }),
1183
+ const DouyinSearchParamsSchema = zod.object({
1184
+ methodType: zod.enum(["热点词数据", "搜索数据"], { error: "方法类型必须是\"热点词数据\"或\"搜索数据\"" }),
1185
+ query: zod.string({ error: "搜索词必须是字符串" }).min(1, { error: "搜索词不能为空" }),
1124
1186
  number: smartPositiveInteger("搜索数量必须是正整数").optional().default(10),
1125
- search_id: z.string({ error: "搜索ID必须是字符串" }).optional()
1187
+ search_id: zod.string({ error: "搜索ID必须是字符串" }).optional()
1126
1188
  });
1127
- const DouyinCommentReplyParamsSchema = z.object({
1128
- methodType: z.literal("指定评论回复数据", { error: "方法类型必须是\"指定评论回复数据\"" }),
1129
- aweme_id: z.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
1130
- comment_id: z.string({ error: "评论ID必须是字符串" }).min(1, { error: "评论ID不能为空" }),
1189
+ const DouyinCommentReplyParamsSchema = zod.object({
1190
+ methodType: zod.literal("指定评论回复数据", { error: "方法类型必须是\"指定评论回复数据\"" }),
1191
+ aweme_id: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
1192
+ comment_id: zod.string({ error: "评论ID必须z串" }).min(1, { error: "评论ID不能为空" }),
1131
1193
  number: smartPositiveInteger("评论数量必须是正整数").optional().default(5),
1132
- cursor: z.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
1194
+ cursor: zod.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
1133
1195
  });
1134
- const DouyinUserParamsSchema = z.object({
1135
- methodType: z.enum([
1136
- "用户主页数据",
1137
- "用户主页视频列表数据",
1138
- "直播间信息数据"
1139
- ], { error: "方法类型必须是指定的枚举值之一" }),
1140
- sec_uid: z.string({ error: "用户ID必须是字符串" }).min(1, { error: "用户ID不能为空" })
1196
+ const DouyinUserParamsSchema = zod.object({
1197
+ methodType: zod.enum(["用户主页数据", "用户主页视频列表数据"], { error: "方法类型必须是指定的枚举值之一" }),
1198
+ sec_uid: zod.string({ error: "用户ID必须是字符串" }).min(1, { error: "用户ID不能为空" })
1199
+ });
1200
+ const DouyinMusicParamsSchema = zod.object({
1201
+ methodType: zod.literal("音乐数据", { error: "方法类型必须是\"音乐数据\"" }),
1202
+ music_id: zod.string({ error: "音乐ID必须是字符串" }).min(1, { error: "音乐ID不能为空" })
1141
1203
  });
1142
- const DouyinMusicParamsSchema = z.object({
1143
- methodType: z.literal("音乐数据", { error: "方法类型必须是\"音乐数据\"" }),
1144
- music_id: z.string({ error: "音乐ID必须是字符串" }).min(1, { error: "音乐ID不能为空" })
1204
+ const DouyinLiveRoomParamsSchema = zod.object({
1205
+ methodType: zod.literal("直播间信息数据", { error: "方法类型必须是\"直播间信息数据\"" }),
1206
+ web_rid: zod.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" }),
1207
+ room_id: zod.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" })
1145
1208
  });
1146
- const DouyinQrcodeParamsSchema = z.object({
1147
- methodType: z.literal("申请二维码数据", { error: "方法类型必须是\"申请二维码数据\"" }),
1148
- verify_fp: z.string({ error: "fp指纹必须是字符串" }).min(1, { error: "fp指纹不能为空" })
1209
+ const DouyinQrcodeParamsSchema = zod.object({
1210
+ methodType: zod.literal("申请二维码数据", { error: "方法类型必须是\"申请二维码数据\"" }),
1211
+ verify_fp: zod.string({ error: "fp指纹必须是字符串" }).min(1, { error: "fp指纹不能为空" })
1149
1212
  });
1150
- const DouyinEmojiListParamsSchema = z.object({ methodType: z.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
1151
- const DouyinEmojiProParamsSchema = z.object({ methodType: z.literal("动态表情数据", { error: "方法类型必须是\"动态表情数据\"" }) });
1152
- const DouyinDanmakuParamsSchema = z.object({
1153
- methodType: z.literal("弹幕数据", { error: "方法类型必须是\"弹幕数据\"" }),
1154
- aweme_id: z.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
1155
- start_time: z.coerce.number({ error: "开始时间必须是数字" }).int({ error: "开始时间必须是整数" }).min(0, { error: "开始时间不能小于0" }).optional(),
1156
- end_time: z.coerce.number({ error: "结束时间必须是数字" }).int({ error: "结束时间必须是整数" }).min(0, { error: "结束时间不能小于0" }).optional(),
1157
- duration: z.coerce.number({ error: "视频时长必须是数字" }).int({ error: "视频时长必须是整数" }).min(0, { error: "视频时长不能小于0" })
1213
+ const DouyinEmojiListParamsSchema = zod.object({ methodType: zod.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
1214
+ const DouyinEmojiProParamsSchema = zod.object({ methodType: zod.literal("动态表情数据", { error: "方法类型必须是\"动态表情数据\"" }) });
1215
+ const DouyinDanmakuParamsSchema = zod.object({
1216
+ methodType: zod.literal("弹幕数据", { error: "方法类型必须是\"弹幕数据\"" }),
1217
+ aweme_id: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
1218
+ start_time: zod.coerce.number({ error: "开始时间必须是数字" }).int({ error: "开始时间必须是整数" }).min(0, { error: "开始时间不能小于0" }).optional(),
1219
+ end_time: zod.coerce.number({ error: "结束时间必须是数字" }).int({ error: "结束时间必须是整数" }).min(0, { error: "结束时间不能小于0" }).optional(),
1220
+ duration: zod.coerce.number({ error: "视频时长必须是数字" }).int({ error: "视频时长必须是整数" }).min(0, { error: "视频时长不能小于0" })
1158
1221
  }).refine((data$1) => {
1159
1222
  if (data$1.end_time !== void 0) return data$1.end_time <= data$1.duration;
1160
1223
  return true;
@@ -1180,30 +1243,53 @@ const DouyinValidationSchemas = {
1180
1243
  热点词数据: DouyinSearchParamsSchema,
1181
1244
  搜索数据: DouyinSearchParamsSchema,
1182
1245
  音乐数据: DouyinMusicParamsSchema,
1183
- 直播间信息数据: DouyinUserParamsSchema,
1246
+ 直播间信息数据: DouyinLiveRoomParamsSchema,
1184
1247
  申请二维码数据: DouyinQrcodeParamsSchema,
1185
1248
  Emoji数据: DouyinEmojiListParamsSchema,
1186
1249
  动态表情数据: DouyinEmojiProParamsSchema,
1187
1250
  指定评论回复数据: DouyinCommentReplyParamsSchema,
1188
1251
  弹幕数据: DouyinDanmakuParamsSchema
1189
1252
  };
1253
+ const DouyinMethodRoutes = {
1254
+ 聚合解析: "/fetch_one_work",
1255
+ 文字作品数据: "/fetch_one_work",
1256
+ 视频作品数据: "/fetch_one_work",
1257
+ 图集作品数据: "/fetch_one_work",
1258
+ 合辑作品数据: "/fetch_one_work",
1259
+ 评论数据: "/fetch_work_comments",
1260
+ 用户主页数据: "/fetch_user_info",
1261
+ 用户主页视频列表数据: "/fetch_user_post_videos",
1262
+ 搜索数据: "/fetch_search_info",
1263
+ 热点词数据: "/fetch_suggest_words",
1264
+ 音乐数据: "/fetch_music_work",
1265
+ Emoji数据: "/fetch_emoji_list",
1266
+ 动态表情数据: "/fetch_emoji_pro_list",
1267
+ 直播间信息数据: "/fetch_user_live_videos",
1268
+ 指定评论回复数据: "/fetch_video_comment_replies",
1269
+ 弹幕数据: "/fetch_work_danmaku"
1270
+ };
1190
1271
 
1191
1272
  //#endregion
1192
1273
  //#region src/validation/kuaishou.ts
1193
- const KuaishouVideoParamsSchema = z.object({
1194
- methodType: z.literal("单个视频作品数据", { error: "方法类型必须是\"单个视频作品数据\"" }),
1195
- photoId: z.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
1274
+ const KuaishouVideoParamsSchema = zod.object({
1275
+ methodType: zod.literal("单个视频作品数据", { error: "方法类型必须是\"单个视频作品数据\"" }),
1276
+ photoId: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
1196
1277
  });
1197
- const KuaishouCommentParamsSchema = z.object({
1198
- methodType: z.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
1199
- photoId: z.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
1278
+ const KuaishouCommentParamsSchema = zod.object({
1279
+ methodType: zod.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
1280
+ photoId: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
1200
1281
  });
1201
- const KuaishouEmojiParamsSchema = z.object({ methodType: z.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
1282
+ const KuaishouEmojiParamsSchema = zod.object({ methodType: zod.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
1202
1283
  const KuaishouValidationSchemas = {
1203
1284
  单个视频作品数据: KuaishouVideoParamsSchema,
1204
1285
  评论数据: KuaishouCommentParamsSchema,
1205
1286
  Emoji数据: KuaishouEmojiParamsSchema
1206
1287
  };
1288
+ const KuaishouMethodRoutes = {
1289
+ 单个视频作品数据: "/fetch_one_work",
1290
+ 评论数据: "/fetch_work_comments",
1291
+ Emoji数据: "/fetch_emoji_list"
1292
+ };
1207
1293
 
1208
1294
  //#endregion
1209
1295
  //#region src/platform/xiaohongshu/sign/index.ts
@@ -1243,9 +1329,9 @@ var xiaohongshuSign = class {
1243
1329
  * @param a1Cookie - a1 cookie值
1244
1330
  * @returns X-S签名
1245
1331
  */
1246
- static generateXS(url, body, userAgent, method = "POST", a1Cookie = "") {
1332
+ static generateXS(url$1, body, userAgent, method = "POST", a1Cookie = "") {
1247
1333
  try {
1248
- const urlObj = new URL(url);
1334
+ const urlObj = new URL(url$1);
1249
1335
  const path$1 = urlObj.pathname + urlObj.search;
1250
1336
  if (method.toUpperCase() === "GET") {
1251
1337
  const params = typeof body === "object" ? body : {};
@@ -1461,59 +1547,59 @@ const SearchNoteTypeValues = Object.values(SearchNoteType).filter((v) => typeof
1461
1547
  /**
1462
1548
  * 小红书首页推荐数据参数验证模式
1463
1549
  */
1464
- const HomeFeedParamsSchema = z.object({
1465
- methodType: z.literal("首页推荐数据", { error: "方法类型必须是\"首页推荐数据\"" }),
1466
- cursor_score: z.string({ error: "cursor_score必须是字符串" }).optional(),
1467
- num: z.coerce.number({ error: "数量必须是数字" }).int({ error: "数量必须是整数" }).min(1, { error: "数量不能小于1" }).max(100, { error: "数量不能大于100" }).optional(),
1468
- refresh_type: z.coerce.number({ error: "refresh_type必须是数字" }).int({ error: "refresh_type必须是整数" }).optional(),
1469
- note_index: z.coerce.number({ error: "note_index必须是数字" }).int({ error: "note_index必须是整数" }).optional(),
1470
- category: z.string({ error: "category必须是字符串" }).optional(),
1471
- search_key: z.string({ error: "search_key必须是字符串" }).optional()
1550
+ const HomeFeedParamsSchema = zod.object({
1551
+ methodType: zod.literal("首页推荐数据", { error: "方法类型必须是\"首页推荐数据\"" }),
1552
+ cursor_score: zod.string({ error: "cursor_score必须是字符串" }).optional(),
1553
+ num: zod.coerce.number({ error: "数量必须是数字" }).int({ error: "数量必须是整数" }).min(1, { error: "数量不能小于1" }).max(100, { error: "数量不能大于100" }).optional(),
1554
+ refresh_type: zod.coerce.number({ error: "refresh_type必须是数字" }).int({ error: "refresh_type必须是整数" }).optional(),
1555
+ note_index: zod.coerce.number({ error: "note_index必须是数字" }).int({ error: "note_index必须是整数" }).optional(),
1556
+ category: zod.string({ error: "category必须是字符串" }).optional(),
1557
+ search_key: zod.string({ error: "search_key必须是字符串" }).optional()
1472
1558
  });
1473
1559
  /**
1474
1560
  * 小红书单个笔记数据参数验证模式
1475
1561
  */
1476
- const NoteParamsSchema = z.object({
1477
- methodType: z.literal("单个笔记数据", { error: "方法类型必须是\"单个笔记数据\"" }),
1478
- note_id: z.string({ error: "note_id必须是字符串" }),
1479
- xsec_token: z.string({ error: "xsec_token必须是字符串" })
1562
+ const NoteParamsSchema = zod.object({
1563
+ methodType: zod.literal("单个笔记数据", { error: "方法类型必须是\"单个笔记数据\"" }),
1564
+ note_id: zod.string({ error: "note_id必须是字符串" }),
1565
+ xsec_token: zod.string({ error: "xsec_token必须是字符串" })
1480
1566
  });
1481
1567
  /**
1482
1568
  * 小红书评论数据参数验证模式
1483
1569
  */
1484
- const CommentParamsSchema = z.object({
1485
- methodType: z.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
1486
- note_id: z.string({ error: "note_id必须是字符串" }),
1487
- cursor: z.string({ error: "cursor必须是字符串" }).optional(),
1488
- xsec_token: z.string({ error: "xsec_token必须是字符串" })
1570
+ const CommentParamsSchema = zod.object({
1571
+ methodType: zod.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
1572
+ note_id: zod.string({ error: "note_id必须是字符串" }),
1573
+ cursor: zod.string({ error: "cursor必须是字符串" }).optional(),
1574
+ xsec_token: zod.string({ error: "xsec_token必须是字符串" })
1489
1575
  });
1490
1576
  /**
1491
1577
  * 小红书用户数据参数验证模式
1492
1578
  */
1493
- const UserParamsSchema = z.object({
1494
- methodType: z.literal("用户数据", { error: "方法类型必须是\"用户数据\"" }),
1495
- user_id: z.string({ error: "user_id必须是字符串" })
1579
+ const UserParamsSchema = zod.object({
1580
+ methodType: zod.literal("用户数据", { error: "方法类型必须是\"用户数据\"" }),
1581
+ user_id: zod.string({ error: "user_id必须是字符串" })
1496
1582
  });
1497
1583
  /**
1498
1584
  * 小红书用户笔记数据参数验证模式
1499
1585
  */
1500
- const UserNoteParamsSchema = z.object({
1501
- methodType: z.literal("用户笔记数据", { error: "方法类型必须是\"用户笔记数据\"" }),
1502
- user_id: z.string({ error: "user_id必须是字符串" }),
1503
- cursor: z.string({ error: "cursor必须是字符串" }).optional(),
1504
- num: z.coerce.number({ error: "数量必须是数字" }).int({ error: "数量必须是整数" }).min(1, { error: "数量不能小于1" }).max(100, { error: "数量不能大于100" }).optional()
1586
+ const UserNoteParamsSchema = zod.object({
1587
+ methodType: zod.literal("用户笔记数据", { error: "方法类型必须是\"用户笔记数据\"" }),
1588
+ user_id: zod.string({ error: "user_id必须是字符串" }),
1589
+ cursor: zod.string({ error: "cursor必须是字符串" }).optional(),
1590
+ num: zod.coerce.number({ error: "数量必须是数字" }).int({ error: "数量必须是整数" }).min(1, { error: "数量不能小于1" }).max(100, { error: "数量不能大于100" }).optional()
1505
1591
  });
1506
- const EmojiListParamsSchema = z.object({ methodType: z.literal("表情列表", { error: "方法类型必须是\"表情列表\"" }) });
1592
+ const EmojiListParamsSchema = zod.object({ methodType: zod.literal("表情列表", { error: "方法类型必须是\"表情列表\"" }) });
1507
1593
  /**
1508
1594
  * 小红书搜索笔记参数验证模式
1509
1595
  */
1510
- const SearchNoteParamsSchema = z.object({
1511
- methodType: z.literal("搜索笔记", { error: "方法类型必须是\"搜索笔记\"" }),
1512
- keyword: z.string({ error: "keyword必须是字符串" }),
1513
- page: z.coerce.number({ error: "page必须是数字" }).int({ error: "page必须是整数" }).min(1, { error: "page不能小于1" }).optional(),
1514
- page_size: z.coerce.number({ error: "page_size必须是数字" }).int({ error: "page_size必须是整数" }).min(1, { error: "page_size不能小于1" }).max(100, { error: "page_size不能大于100" }).optional(),
1515
- sort: z.enum(SearchSortTypeValues, { error: "排序类型不合法" }).optional(),
1516
- note_type: z.coerce.number({ error: "笔记类型必须是数字" }).int({ error: "笔记类型必须是整数" }).refine((val) => SearchNoteTypeValues.includes(val), { message: "笔记类型不合法" }).optional()
1596
+ const SearchNoteParamsSchema = zod.object({
1597
+ methodType: zod.literal("搜索笔记", { error: "方法类型必须是\"搜索笔记\"" }),
1598
+ keyword: zod.string({ error: "keyword必须是字符串" }),
1599
+ page: zod.coerce.number({ error: "page必须是数字" }).int({ error: "page必须是整数" }).min(1, { error: "page不能小于1" }).optional(),
1600
+ page_size: zod.coerce.number({ error: "page_size必须是数字" }).int({ error: "page_size必须是整数" }).min(1, { error: "page_size不能小于1" }).max(100, { error: "page_size不能大于100" }).optional(),
1601
+ sort: zod.enum(SearchSortTypeValues, { error: "排序类型不合法" }).optional(),
1602
+ note_type: zod.coerce.number({ error: "笔记类型必须是数字" }).int({ error: "笔记类型必须是整数" }).refine((val) => SearchNoteTypeValues.includes(val), { message: "笔记类型不合法" }).optional()
1517
1603
  });
1518
1604
  /**
1519
1605
  * 小红书验证模式映射
@@ -1528,19 +1614,16 @@ const XiaohongshuValidationSchemas = {
1528
1614
  搜索笔记: SearchNoteParamsSchema
1529
1615
  };
1530
1616
  /**
1531
- * 验证小红书参数
1532
- * @param methodType - 小红书方法类型
1533
- * @param params - 待验证的参数
1534
- * @returns 验证后的参数
1617
+ * 小红书方法类型
1535
1618
  */
1536
- const validateXiaohongshuParams = (methodType, params) => {
1537
- return XiaohongshuValidationSchemas[methodType].parse(typeof params === "object" && params !== null ? {
1538
- methodType,
1539
- ...params
1540
- } : {
1541
- methodType,
1542
- params
1543
- });
1619
+ const XiaohongshuMethodRoutes = {
1620
+ 首页推荐数据: "/fetch_home_feed",
1621
+ 单个笔记数据: "/fetch_one_note",
1622
+ 评论数据: "/fetch_note_comments",
1623
+ 用户数据: "/fetch_user_profile",
1624
+ 用户笔记数据: "/fetch_user_notes",
1625
+ 表情列表: "/fetch_emoji_list",
1626
+ 搜索笔记: "/fetch_search_notes"
1544
1627
  };
1545
1628
 
1546
1629
  //#endregion
@@ -1591,6 +1674,21 @@ const validateKuaishouParams = (methodType, params) => {
1591
1674
  });
1592
1675
  };
1593
1676
  /**
1677
+ * 验证小红书参数
1678
+ * @param methodType - 小红书方法类型
1679
+ * @param params - 待验证的参数
1680
+ * @returns 验证后的参数
1681
+ */
1682
+ const validateXiaohongshuParams = (methodType, params) => {
1683
+ return XiaohongshuValidationSchemas[methodType].parse(typeof params === "object" && params !== null ? {
1684
+ methodType,
1685
+ ...params
1686
+ } : {
1687
+ methodType,
1688
+ params
1689
+ });
1690
+ };
1691
+ /**
1594
1692
  * 创建成功响应格式
1595
1693
  * @param data - 响应数据
1596
1694
  * @param message - 响应消息(可选)
@@ -1703,29 +1801,8 @@ const createBilibiliRouteHandler = (dataFetcher, methodType, cookie, requestConf
1703
1801
  * @returns Express路由器
1704
1802
  */
1705
1803
  const createBilibiliRoutes = (cookie, requestConfig = getBilibiliDefaultConfig(cookie)) => {
1706
- const router = Router();
1707
- router.get("/fetch_one_video", createBilibiliValidationMiddleware("单个视频作品数据"), createBilibiliRouteHandler(getBilibiliData, "单个视频作品数据", cookie, requestConfig));
1708
- router.get("/fetch_video_playurl", createBilibiliValidationMiddleware("单个视频下载信息数据"), createBilibiliRouteHandler(getBilibiliData, "单个视频下载信息数据", cookie, requestConfig));
1709
- router.get("/fetch_work_comments", createBilibiliValidationMiddleware("评论数据"), createBilibiliRouteHandler(getBilibiliData, "评论数据", cookie, requestConfig));
1710
- router.get("/fetch_user_profile", createBilibiliValidationMiddleware("用户主页数据"), createBilibiliRouteHandler(getBilibiliData, "用户主页数据", cookie, requestConfig));
1711
- router.get("/fetch_user_dynamic", createBilibiliValidationMiddleware("用户主页动态列表数据"), createBilibiliRouteHandler(getBilibiliData, "用户主页动态列表数据", cookie, requestConfig));
1712
- router.get("/fetch_emoji_list", createBilibiliValidationMiddleware("Emoji数据"), createBilibiliRouteHandler(getBilibiliData, "Emoji数据", cookie, requestConfig));
1713
- router.get("/fetch_bangumi_video_info", createBilibiliValidationMiddleware("番剧基本信息数据"), createBilibiliRouteHandler(getBilibiliData, "番剧基本信息数据", cookie, requestConfig));
1714
- router.get("/fetch_bangumi_video_playurl", createBilibiliValidationMiddleware("番剧下载信息数据"), createBilibiliRouteHandler(getBilibiliData, "番剧下载信息数据", cookie, requestConfig));
1715
- router.get("/fetch_dynamic_info", createBilibiliValidationMiddleware("动态详情数据"), createBilibiliRouteHandler(getBilibiliData, "动态详情数据", cookie, requestConfig));
1716
- router.get("/fetch_dynamic_card", createBilibiliValidationMiddleware("动态卡片数据"), createBilibiliRouteHandler(getBilibiliData, "动态卡片数据", cookie, requestConfig));
1717
- router.get("/fetch_live_room_detail", createBilibiliValidationMiddleware("直播间信息"), createBilibiliRouteHandler(getBilibiliData, "直播间信息", cookie, requestConfig));
1718
- router.get("/fetch_liveroom_def", createBilibiliValidationMiddleware("直播间初始化信息"), createBilibiliRouteHandler(getBilibiliData, "直播间初始化信息", cookie, requestConfig));
1719
- router.get("/login_basic_info", createBilibiliValidationMiddleware("登录基本信息"), createBilibiliRouteHandler(getBilibiliData, "登录基本信息", cookie, requestConfig));
1720
- router.get("/new_login_qrcode", createBilibiliValidationMiddleware("申请二维码"), createBilibiliRouteHandler(getBilibiliData, "申请二维码", cookie, requestConfig));
1721
- router.get("/check_qrcode", createBilibiliValidationMiddleware("二维码状态"), createBilibiliRouteHandler(getBilibiliData, "二维码状态", cookie, requestConfig));
1722
- router.get("/fetch_user_full_view", createBilibiliValidationMiddleware("获取UP主总播放量"), createBilibiliRouteHandler(getBilibiliData, "获取UP主总播放量", cookie, requestConfig));
1723
- router.get("/av_to_bv", createBilibiliValidationMiddleware("AV转BV"), createBilibiliRouteHandler(getBilibiliData, "AV转BV", cookie, requestConfig));
1724
- router.get("/bv_to_av", createBilibiliValidationMiddleware("BV转AV"), createBilibiliRouteHandler(getBilibiliData, "BV转AV", cookie, requestConfig));
1725
- router.get("/fetch_article_content", createBilibiliValidationMiddleware("专栏正文内容"), createBilibiliRouteHandler(getBilibiliData, "专栏正文内容", cookie, requestConfig));
1726
- router.get("/fetch_article_card", createBilibiliValidationMiddleware("专栏显示卡片信息"), createBilibiliRouteHandler(getBilibiliData, "专栏显示卡片信息", cookie, requestConfig));
1727
- router.get("/fetch_article_info", createBilibiliValidationMiddleware("专栏文章基本信息"), createBilibiliRouteHandler(getBilibiliData, "专栏文章基本信息", cookie, requestConfig));
1728
- router.get("/fetch_column_info", createBilibiliValidationMiddleware("文集基本信息"), createBilibiliRouteHandler(getBilibiliData, "文集基本信息", cookie, requestConfig));
1804
+ const router = express.Router();
1805
+ for (const [method, path$1] of Object.entries(BilibiliMethodRoutes)) router.get(path$1, createBilibiliValidationMiddleware(method), createBilibiliRouteHandler(getBilibiliData, method, cookie, requestConfig));
1729
1806
  return router;
1730
1807
  };
1731
1808
 
@@ -1791,6 +1868,12 @@ const qtparam = async (BASEURL, cookie) => {
1791
1868
  //#endregion
1792
1869
  //#region src/platform/bilibili/getdata.ts
1793
1870
  /**
1871
+ * B站数据获取模块
1872
+ *
1873
+ * 注意:为避免循环依赖,此文件直接从具体模块导入,而不是从平台 index 文件导入
1874
+ * 循环依赖链:DataFetchers → getdata → platform/bilibili → DataFetchers
1875
+ */
1876
+ /**
1794
1877
  * B站数据获取函数
1795
1878
  * @param data - 请求数据参数
1796
1879
  * @param cookie - 用户Cookie
@@ -1886,6 +1969,10 @@ const fetchBilibili = async (data$1, cookie, requestConfig) => {
1886
1969
  }
1887
1970
  };
1888
1971
  }
1972
+ case "指定评论的回复": return await GlobalGetData$3(data$1.methodType, {
1973
+ ...baseRequestConfig,
1974
+ url: bilibiliApiUrls.指定评论的回复(data$1)
1975
+ });
1889
1976
  case "Emoji数据": return await GlobalGetData$3(data$1.methodType, {
1890
1977
  ...baseRequestConfig,
1891
1978
  url: bilibiliApiUrls.表情列表()
@@ -2579,9 +2666,9 @@ const cleanUserAgentForSigning = (userAgent) => {
2579
2666
  * @param user_agent - 用户代理字符串
2580
2667
  * @returns 生成的a_bogus签名
2581
2668
  */
2582
- var a_bogus_default = (url, user_agent) => {
2669
+ var a_bogus_default = (url$1, user_agent) => {
2583
2670
  const cleanedUserAgent = cleanUserAgentForSigning(user_agent);
2584
- return result_encrypt(generate_random_str() + generate_rc4_bb_str(new URLSearchParams(new URL(url).search).toString(), cleanedUserAgent, "1536|747|1536|834|0|30|0|0|1536|834|1536|864|1525|747|24|24|Win32"), "s4") + "=";
2671
+ return result_encrypt(generate_random_str() + generate_rc4_bb_str(new URLSearchParams(new URL(url$1).search).toString(), cleanedUserAgent, "1536|747|1536|834|0|30|0|0|1536|834|1536|864|1525|747|24|24|Win32"), "s4") + "=";
2585
2672
  };
2586
2673
 
2587
2674
  //#endregion
@@ -2683,8 +2770,8 @@ var XBogus = class {
2683
2770
  * @param ua 可选的User-Agent,不提供则使用默认值
2684
2771
  * @returns 包含完整URL、X-Bogus值和使用的User-Agent的元组
2685
2772
  */
2686
- getXBogus(url, ua) {
2687
- const parsedUrl = new URL$1.URL(url);
2773
+ getXBogus(url$1, ua) {
2774
+ const parsedUrl = new url.URL(url$1);
2688
2775
  const urlPath = parsedUrl.pathname + parsedUrl.search;
2689
2776
  const currentUa = ua ?? this.defaultUa;
2690
2777
  const rc4EncryptedUa = this.rc4Encrypt(this.uaKey, currentUa);
@@ -2741,7 +2828,7 @@ var XBogus = class {
2741
2828
  idx += 3;
2742
2829
  }
2743
2830
  return {
2744
- fullUrl: url.includes("?") ? `${url}&X-Bogus=${xb}` : `${url}?X-Bogus=${xb}`,
2831
+ fullUrl: url$1.includes("?") ? `${url$1}&X-Bogus=${xb}` : `${url$1}?X-Bogus=${xb}`,
2745
2832
  xbogus: xb,
2746
2833
  userAgent: currentUa
2747
2834
  };
@@ -2767,16 +2854,16 @@ var douyinSign = class {
2767
2854
  * @param url 需要签名的地址
2768
2855
  * @returns 对此地址签名后的URL查询参数
2769
2856
  */
2770
- static AB(url, userAgent) {
2771
- return a_bogus_default(url, userAgent ?? defaultUserAgent);
2857
+ static AB(url$1, userAgent) {
2858
+ return a_bogus_default(url$1, userAgent ?? defaultUserAgent);
2772
2859
  }
2773
2860
  /**
2774
2861
  * X-Bogus 签名算法
2775
2862
  * @param url 需要签名的地址
2776
2863
  * @returns 对此地址签名后的URL查询参数
2777
2864
  */
2778
- static XB(url, userAgent) {
2779
- return new XBogus().getXBogus(url, userAgent ?? defaultUserAgent).xbogus;
2865
+ static XB(url$1, userAgent) {
2866
+ return new XBogus().getXBogus(url$1, userAgent ?? defaultUserAgent).xbogus;
2780
2867
  }
2781
2868
  /** 生成一个唯一的验证字符串 */
2782
2869
  static VerifyFpManager() {
@@ -3242,17 +3329,23 @@ const douyinApiUrls = new DouyinAPI();
3242
3329
  //#endregion
3243
3330
  //#region src/platform/douyin/getdata.ts
3244
3331
  /**
3332
+ * 抖音数据获取模块
3333
+ *
3334
+ * 注意:为避免循环依赖,此文件直接从具体模块导入,而不是从平台 index 文件导入
3335
+ * 循环依赖链:DataFetchers → getdata → platform/douyin → DataFetchers
3336
+ */
3337
+ /**
3245
3338
  * 获取签名参数
3246
3339
  * @param url - 需要签名的URL
3247
3340
  * @param signType - 签名算法类型
3248
3341
  * @param userAgent - 用户代理
3249
3342
  * @returns 签名后的参数字符串
3250
3343
  */
3251
- const getSignature = (url, signType = "a_bogus", userAgent) => {
3344
+ const getSignature = (url$1, signType = "a_bogus", userAgent) => {
3252
3345
  switch (signType) {
3253
- case "x_bogus": return douyinSign.XB(url, userAgent);
3346
+ case "x_bogus": return douyinSign.XB(url$1, userAgent);
3254
3347
  case "a_bogus":
3255
- default: return douyinSign.AB(url, userAgent);
3348
+ default: return douyinSign.AB(url$1, userAgent);
3256
3349
  }
3257
3350
  };
3258
3351
  /**
@@ -3274,9 +3367,9 @@ const getSignParamName = (signType = "a_bogus") => {
3274
3367
  * @param userAgent - 用户代理
3275
3368
  * @returns 带签名的完整URL
3276
3369
  */
3277
- const buildSignedUrl = (url, signType = "a_bogus", userAgent) => {
3278
- const signature = getSignature(url, signType, userAgent);
3279
- return `${url}&${getSignParamName(signType)}=${signature}`;
3370
+ const buildSignedUrl = (url$1, signType = "a_bogus", userAgent) => {
3371
+ const signature = getSignature(url$1, signType, userAgent);
3372
+ return `${url$1}&${getSignParamName(signType)}=${signature}`;
3280
3373
  };
3281
3374
  /**
3282
3375
  * 抖音数据获取函数
@@ -3305,10 +3398,10 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3305
3398
  case "视频作品数据":
3306
3399
  case "图集作品数据":
3307
3400
  case "合辑作品数据": {
3308
- const url = douyinApiUrls$1.视频或图集({ aweme_id: data$1.aweme_id });
3401
+ const url$1 = douyinApiUrls$1.视频或图集({ aweme_id: data$1.aweme_id });
3309
3402
  return await GlobalGetData$2(data$1.methodType, {
3310
3403
  ...baseRequestConfig,
3311
- url: buildSignedUrl(url, signType, userAgent)
3404
+ url: buildSignedUrl(url$1, signType, userAgent)
3312
3405
  });
3313
3406
  }
3314
3407
  case "评论数据": {
@@ -3320,7 +3413,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3320
3413
  return await fetchPaginatedData(data$1.methodType, urlGenerator, data$1, 3, baseRequestConfig, "x_bogus");
3321
3414
  }
3322
3415
  case "用户主页数据": {
3323
- const url = douyinApiUrls$1.用户主页信息({ sec_uid: data$1.sec_uid });
3416
+ const url$1 = douyinApiUrls$1.用户主页信息({ sec_uid: data$1.sec_uid });
3324
3417
  const customConfig = {
3325
3418
  ...baseRequestConfig,
3326
3419
  headers: {
@@ -3330,18 +3423,18 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3330
3423
  };
3331
3424
  return await GlobalGetData$2(data$1.methodType, {
3332
3425
  ...customConfig,
3333
- url: buildSignedUrl(url, signType, userAgent)
3426
+ url: buildSignedUrl(url$1, signType, userAgent)
3334
3427
  });
3335
3428
  }
3336
3429
  case "Emoji数据": {
3337
- const url = douyinApiUrls$1.表情();
3430
+ const url$1 = douyinApiUrls$1.表情();
3338
3431
  return await GlobalGetData$2(data$1.methodType, {
3339
3432
  ...baseRequestConfig,
3340
- url
3433
+ url: url$1
3341
3434
  });
3342
3435
  }
3343
3436
  case "用户主页视频列表数据": {
3344
- const url = douyinApiUrls$1.用户主页视频({ sec_uid: data$1.sec_uid });
3437
+ const url$1 = douyinApiUrls$1.用户主页视频({ sec_uid: data$1.sec_uid });
3345
3438
  const customConfig = {
3346
3439
  ...baseRequestConfig,
3347
3440
  headers: {
@@ -3351,11 +3444,11 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3351
3444
  };
3352
3445
  return await GlobalGetData$2(data$1.methodType, {
3353
3446
  ...customConfig,
3354
- url: buildSignedUrl(url, signType, userAgent)
3447
+ url: buildSignedUrl(url$1, signType, userAgent)
3355
3448
  });
3356
3449
  }
3357
3450
  case "热点词数据": {
3358
- const url = douyinApiUrls$1.热点词({
3451
+ const url$1 = douyinApiUrls$1.热点词({
3359
3452
  query: data$1.query,
3360
3453
  number: data$1.number ?? 10
3361
3454
  });
@@ -3368,7 +3461,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3368
3461
  };
3369
3462
  return await GlobalGetData$2(data$1.methodType, {
3370
3463
  ...customConfig,
3371
- url: buildSignedUrl(url, signType, userAgent)
3464
+ url: buildSignedUrl(url$1, signType, userAgent)
3372
3465
  });
3373
3466
  }
3374
3467
  case "搜索数据": {
@@ -3385,19 +3478,22 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3385
3478
  };
3386
3479
  while (fetchedSearchList.length < Number(data$1.number ?? 10)) {
3387
3480
  const requestCount = Math.min(Number(data$1.number ?? 50) - fetchedSearchList.length, maxPageSize);
3388
- const url = douyinApiUrls$1.搜索({
3481
+ const url$1 = douyinApiUrls$1.搜索({
3389
3482
  query: data$1.query,
3390
3483
  number: requestCount,
3391
3484
  search_id: search_id === "" ? void 0 : search_id
3392
3485
  });
3393
3486
  const raw = await GlobalGetData$2(data$1.methodType, {
3394
3487
  ...customConfig,
3395
- url: buildSignedUrl(url, "x_bogus", userAgent)
3488
+ url: buildSignedUrl(url$1, "x_bogus", userAgent)
3396
3489
  });
3397
3490
  const responses = filterSearchResponses(typeof raw === "string" ? parseDouyinMultiJson(raw) : [raw]);
3398
3491
  if (responses.length === 0) {
3399
3492
  logger.warn("抖音搜索返回无有效数据,疑似触发反爬\n你的抖音ck可能已经失效!\n请求类型:" + data$1.methodType);
3400
- return false;
3493
+ return {
3494
+ success: false,
3495
+ amagiError: "抖音搜索返回无有效数据,疑似触发反爬\n你的抖音ck可能已经失效!\n请求类型:" + data$1.methodType
3496
+ };
3401
3497
  }
3402
3498
  for (const resp of responses) {
3403
3499
  if (Array.isArray(resp.data) && resp.data.length > 0) fetchedSearchList.push(...resp.data);
@@ -3405,8 +3501,11 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3405
3501
  search_id = resp.log_pb?.impr_id ?? search_id;
3406
3502
  }
3407
3503
  if (fetchedSearchList.length === 0) {
3408
- logger.warn("抖音搜索返回数据长度为空,\n你的抖音ck疑似触发验证码!\n请求类型:" + data$1.methodType);
3409
- return false;
3504
+ logger.warn("抖音搜索API请求成功,但返回数据长度为0,\n此问题暂时无法处理,也可能被风控!\n请求类型:" + data$1.methodType);
3505
+ return {
3506
+ success: false,
3507
+ amagiError: "抖音搜索API请求成功,但返回数据长度为0,\n此问题暂时无法处理,也可能被风控!\n请求类型:" + data$1.methodType
3508
+ };
3410
3509
  }
3411
3510
  if (tmpresp && typeof tmpresp.has_more === "number" && tmpresp.has_more === 0) break;
3412
3511
  }
@@ -3416,77 +3515,42 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3416
3515
  };
3417
3516
  }
3418
3517
  case "动态表情数据": {
3419
- const url = douyinApiUrls$1.互动表情();
3518
+ const url$1 = douyinApiUrls$1.互动表情();
3420
3519
  return await GlobalGetData$2(data$1.methodType, {
3421
3520
  ...baseRequestConfig,
3422
- url: buildSignedUrl(url, signType, userAgent)
3521
+ url: buildSignedUrl(url$1, signType, userAgent)
3423
3522
  });
3424
3523
  }
3425
3524
  case "音乐数据": {
3426
- const url = douyinApiUrls$1.背景音乐({ music_id: data$1.music_id });
3525
+ const url$1 = douyinApiUrls$1.背景音乐({ music_id: data$1.music_id });
3427
3526
  return await GlobalGetData$2(data$1.methodType, {
3428
3527
  ...baseRequestConfig,
3429
- url: buildSignedUrl(url, signType, userAgent)
3528
+ url: buildSignedUrl(url$1, signType, userAgent)
3430
3529
  });
3431
3530
  }
3432
3531
  case "直播间信息数据": {
3433
- let url = douyinApiUrls$1.用户主页信息({ sec_uid: data$1.sec_uid });
3434
- const fetchUrl = buildSignedUrl(url, signType, userAgent);
3435
- const customConfig = {
3436
- ...baseRequestConfig,
3437
- headers: {
3438
- ...baseRequestConfig.headers,
3439
- ...(!requestConfig?.headers || !("Referer" in requestConfig.headers)) && { Referer: `https://www.douyin.com/user/${data$1.sec_uid}` }
3440
- }
3441
- };
3442
- const UserInfoData = await GlobalGetData$2(data$1.methodType, {
3443
- ...customConfig,
3444
- url: fetchUrl
3445
- });
3446
- if (!UserInfoData?.user?.live_status || UserInfoData.user.live_status !== 1) {
3447
- logger.error((UserInfoData?.user?.nickname ?? "用户") + "当前未在直播");
3448
- const Err = {
3449
- errorDescription: "检查失败!该用户当前未在直播! TypeError: Cannot read properties of undefined (reading 'live_status')",
3450
- requestType: data$1.methodType ?? "未知请求类型",
3451
- requestUrl: fetchUrl
3452
- };
3453
- return {
3454
- code: douoyinAPIErrorCode.NOT_LIVE,
3455
- data: UserInfoData,
3456
- amagiError: Err,
3457
- amagiMessage: Err.errorDescription
3458
- };
3459
- }
3460
- if (!UserInfoData.user.room_data) {
3461
- logger.error("未获取到直播间信息!");
3462
- return {
3463
- code: 500,
3464
- message: "未获取到直播间信息!",
3465
- data: null
3466
- };
3467
- }
3468
- const room_data = JSON.parse(UserInfoData.user.room_data);
3469
- url = douyinApiUrls$1.直播间信息({
3470
- room_id: UserInfoData.user.room_id_str,
3471
- web_rid: room_data.owner.web_rid
3532
+ let url$1 = douyinApiUrls$1.直播间信息({
3533
+ room_id: data$1.room_id,
3534
+ web_rid: data$1.web_rid
3472
3535
  });
3473
3536
  const liveCustomConfig = {
3474
3537
  ...baseRequestConfig,
3538
+ url: buildSignedUrl(url$1, signType, userAgent),
3475
3539
  headers: {
3476
3540
  ...baseRequestConfig.headers,
3477
- ...(!requestConfig?.headers || !("Referer" in requestConfig.headers)) && { Referer: `https://live.douyin.com/${room_data.owner.web_rid}` }
3541
+ ...(!requestConfig?.headers || !("Referer" in requestConfig.headers)) && { Referer: `https://live.douyin.com/${data$1.web_rid}` }
3478
3542
  }
3479
3543
  };
3480
3544
  return await GlobalGetData$2(data$1.methodType, {
3481
3545
  ...liveCustomConfig,
3482
- url: buildSignedUrl(url, signType, userAgent)
3546
+ url: buildSignedUrl(url$1, signType, userAgent)
3483
3547
  });
3484
3548
  }
3485
3549
  case "申请二维码数据": {
3486
- const url = douyinApiUrls$1.申请二维码({ verify_fp: data$1.verify_fp });
3550
+ const url$1 = douyinApiUrls$1.申请二维码({ verify_fp: data$1.verify_fp });
3487
3551
  return await GlobalGetData$2(data$1.methodType, {
3488
3552
  ...baseRequestConfig,
3489
- url: buildSignedUrl(url, signType, userAgent)
3553
+ url: buildSignedUrl(url$1, signType, userAgent)
3490
3554
  });
3491
3555
  }
3492
3556
  case "弹幕数据": {
@@ -3495,7 +3559,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3495
3559
  const endTime = data$1.end_time ?? data$1.duration;
3496
3560
  const totalDuration = endTime - startTime;
3497
3561
  if (totalDuration <= MAX_SEGMENT_DURATION) {
3498
- const url = douyinApiUrls$1.弹幕({
3562
+ const url$1 = douyinApiUrls$1.弹幕({
3499
3563
  aweme_id: data$1.aweme_id,
3500
3564
  start_time: startTime,
3501
3565
  end_time: endTime,
@@ -3503,7 +3567,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3503
3567
  });
3504
3568
  return await GlobalGetData$2(data$1.methodType, {
3505
3569
  ...baseRequestConfig,
3506
- url: buildSignedUrl(url, signType, userAgent)
3570
+ url: buildSignedUrl(url$1, signType, userAgent)
3507
3571
  });
3508
3572
  }
3509
3573
  const segments = [];
@@ -3518,7 +3582,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3518
3582
  }
3519
3583
  logger.debug(`弹幕数据需要分${segments.length}段获取,总时长:${totalDuration}ms`);
3520
3584
  const segmentPromises = segments.map(async (segment, index) => {
3521
- const url = douyinApiUrls$1.弹幕({
3585
+ const url$1 = douyinApiUrls$1.弹幕({
3522
3586
  aweme_id: data$1.aweme_id,
3523
3587
  start_time: segment.start,
3524
3588
  end_time: segment.end,
@@ -3527,7 +3591,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3527
3591
  try {
3528
3592
  const segmentData = await GlobalGetData$2(`${data$1.methodType}-段${index + 1}`, {
3529
3593
  ...baseRequestConfig,
3530
- url: buildSignedUrl(url, signType, userAgent)
3594
+ url: buildSignedUrl(url$1, signType, userAgent)
3531
3595
  });
3532
3596
  logger.debug(`弹幕第${index + 1}段获取成功 (${segment.start}ms-${segment.end}ms)`);
3533
3597
  return segmentData;
@@ -3568,9 +3632,18 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3568
3632
  logger.debug(`弹幕数据合并完成,共获取${mergedDanmakuList.length}条弹幕`);
3569
3633
  return finalDanmakuData;
3570
3634
  }
3571
- default:
3635
+ default: {
3636
+ const customUrl = data$1.custom_url;
3637
+ if (typeof customUrl === "string" && customUrl.length > 0) {
3638
+ const url$1 = buildSignedUrl(customUrl, signType, userAgent);
3639
+ return await GlobalGetData$2(data$1.methodType ?? "自定义请求", {
3640
+ ...baseRequestConfig,
3641
+ url: url$1
3642
+ });
3643
+ }
3572
3644
  logger.warn(`未知的抖音数据接口:「${logger.red(data$1.methodType)}」`);
3573
3645
  return null;
3646
+ }
3574
3647
  }
3575
3648
  };
3576
3649
  /**
@@ -3590,14 +3663,14 @@ const fetchPaginatedData = async (type, apiUrlGenerator, params, maxPageSize, re
3590
3663
  const userAgent = requestConfig.headers?.["User-Agent"];
3591
3664
  while (fetchedData.length < Number(params.number ?? maxPageSize)) {
3592
3665
  const requestCount = Math.min(Number(params.number ?? maxPageSize) - fetchedData.length, maxPageSize);
3593
- const url = apiUrlGenerator({
3666
+ const url$1 = apiUrlGenerator({
3594
3667
  ...params,
3595
3668
  number: requestCount,
3596
3669
  cursor
3597
3670
  });
3598
3671
  const response = await GlobalGetData$2(type, {
3599
3672
  ...requestConfig,
3600
- url: buildSignedUrl(url, signType, userAgent)
3673
+ url: buildSignedUrl(url$1, signType, userAgent)
3601
3674
  });
3602
3675
  fetchedData.push(...response.comments ?? response.data ?? []);
3603
3676
  tmpresp = response;
@@ -3762,6 +3835,12 @@ const kuaishouApiUrls = new API();
3762
3835
  //#endregion
3763
3836
  //#region src/platform/kuaishou/getdata.ts
3764
3837
  /**
3838
+ * 快手数据获取模块
3839
+ *
3840
+ * 注意:为避免循环依赖,此文件直接从具体模块导入,而不是从平台 index 文件导入
3841
+ * 循环依赖链:DataFetchers → getdata → platform/kuaishou → DataFetchers
3842
+ */
3843
+ /**
3765
3844
  * 快手数据获取函数
3766
3845
  * @param data - 请求数据参数
3767
3846
  * @param cookie - 用户Cookie
@@ -4039,7 +4118,7 @@ async function getDouyinData(methodType, optionsOrCookie, cookieOrOptions, reque
4039
4118
  cookie = cookieOrOptions;
4040
4119
  config = requestConfig;
4041
4120
  }
4042
- const { typeMode: _,...validationOptions } = options ?? {};
4121
+ const { typeMode: _, ...validationOptions } = options ?? {};
4043
4122
  const rawData = await DouyinData({ ...validateDouyinParams(methodType, validationOptions) }, cookie, config);
4044
4123
  if (rawData.data === "" || rawData.status_code !== 0) return createErrorResponse(rawData.amagiError, rawData.status_msg ?? "抖音数据获取失败");
4045
4124
  return createSuccessResponse(rawData, "获取成功", 200);
@@ -4062,7 +4141,7 @@ async function getBilibiliData(methodType, optionsOrCookie, cookieOrOptions, req
4062
4141
  options = optionsOrCookie;
4063
4142
  cookie = cookieOrOptions;
4064
4143
  }
4065
- const { typeMode: _,...validationOptions } = options ?? {};
4144
+ const { typeMode: _, ...validationOptions } = options ?? {};
4066
4145
  const rawData = await fetchBilibili({ ...validateBilibiliParams(methodType, validationOptions) }, cookie);
4067
4146
  if (rawData.code !== 0) return createErrorResponse(rawData.amagiError, "B站数据获取失败");
4068
4147
  return createSuccessResponse(rawData, "获取成功", 200);
@@ -4085,7 +4164,7 @@ async function getKuaishouData(methodType, optionsOrCookie, cookieOrOptions, req
4085
4164
  options = optionsOrCookie;
4086
4165
  cookie = cookieOrOptions;
4087
4166
  }
4088
- const { typeMode: _,...validationOptions } = options ?? {};
4167
+ const { typeMode: _, ...validationOptions } = options ?? {};
4089
4168
  const rawData = await KuaishouData({ ...validateKuaishouParams(methodType, validationOptions) }, cookie);
4090
4169
  if (rawData.code && Object.values(kuaishouAPIErrorCode).includes(rawData.code)) return createErrorResponse(rawData.amagiError, "快手数据获取失败");
4091
4170
  return createSuccessResponse(rawData, "获取成功", 200);
@@ -4108,7 +4187,7 @@ async function getXiaohongshuData(methodType, optionsOrCookie, cookieOrOptions,
4108
4187
  options = optionsOrCookie;
4109
4188
  cookie = cookieOrOptions;
4110
4189
  }
4111
- const { typeMode: _,...validationOptions } = options ?? {};
4190
+ const { typeMode: _, ...validationOptions } = options ?? {};
4112
4191
  const rawData = await XiaohongshuData({ ...validateXiaohongshuParams(methodType, validationOptions) }, cookie);
4113
4192
  if (rawData.code && Object.values(xiaohongshuAPIErrorCode).includes(rawData.code)) return createErrorResponse(rawData.amagiError, "小红书数据获取失败");
4114
4193
  return createSuccessResponse(rawData, "获取成功", 200);
@@ -4166,7 +4245,10 @@ const douyin = {
4166
4245
  getSuggestWords: createDouyinApiMethod("热点词数据"),
4167
4246
  search: createDouyinApiMethod("搜索数据"),
4168
4247
  getLiveRoomInfo: createDouyinApiMethod("直播间信息数据"),
4169
- getDanmaku: createDouyinApiMethod("弹幕数据")
4248
+ getDanmaku: createDouyinApiMethod("弹幕数据"),
4249
+ invoke: async (methodType, options, cookie, requestConfig) => {
4250
+ return await getDouyinData(methodType, options, cookie, requestConfig);
4251
+ }
4170
4252
  };
4171
4253
  /**
4172
4254
  * 创建绑定了cookie的抖音API对象
@@ -4188,9 +4270,12 @@ const createBoundDouyinApi = (cookie, requestConfig) => {
4188
4270
  getUserVideos: createBoundDouyinApiMethod("用户主页视频列表数据", cookie, requestConfig),
4189
4271
  getMusicInfo: createBoundDouyinApiMethod("音乐数据", cookie, requestConfig),
4190
4272
  getSuggestWords: createBoundDouyinApiMethod("热点词数据", cookie, requestConfig),
4191
- search: createBoundDouyinApiMethod("搜索数据", cookie, requestConfig),
4273
+ getSearchData: createBoundDouyinApiMethod("搜索数据", cookie, requestConfig),
4192
4274
  getLiveRoomInfo: createBoundDouyinApiMethod("直播间信息数据", cookie, requestConfig),
4193
- getDanmaku: createBoundDouyinApiMethod("弹幕数据", cookie, requestConfig)
4275
+ getDanmaku: createBoundDouyinApiMethod("弹幕数据", cookie, requestConfig),
4276
+ invoke: async (methodType, options) => {
4277
+ return await getDouyinData(methodType, options, cookie, requestConfig);
4278
+ }
4194
4279
  };
4195
4280
  };
4196
4281
 
@@ -4228,22 +4313,8 @@ const createDouyinRouteHandler = (dataFetcher, methodType, cookie, requestConfig
4228
4313
  * @returns Express路由器
4229
4314
  */
4230
4315
  const createDouyinRoutes = (cookie, requestConfig = getDouyinDefaultConfig(cookie)) => {
4231
- const router = Router();
4232
- router.get("/fetch_one_work", createDouyinValidationMiddleware("聚合解析"), createDouyinRouteHandler(getDouyinData, "聚合解析", cookie, requestConfig));
4233
- router.get("/fetch_one_work", createDouyinValidationMiddleware("视频作品数据"), createDouyinRouteHandler(getDouyinData, "视频作品数据", cookie, requestConfig));
4234
- router.get("/fetch_one_work", createDouyinValidationMiddleware("图集作品数据"), createDouyinRouteHandler(getDouyinData, "图集作品数据", cookie, requestConfig));
4235
- router.get("/fetch_one_work", createDouyinValidationMiddleware("合辑作品数据"), createDouyinRouteHandler(getDouyinData, "合辑作品数据", cookie, requestConfig));
4236
- router.get("/fetch_work_comments", createDouyinValidationMiddleware("评论数据"), createDouyinRouteHandler(getDouyinData, "评论数据", cookie, requestConfig));
4237
- router.get("/fetch_user_info", createDouyinValidationMiddleware("用户主页数据"), createDouyinRouteHandler(getDouyinData, "用户主页数据", cookie, requestConfig));
4238
- router.get("/fetch_user_post_videos", createDouyinValidationMiddleware("用户主页视频列表数据"), createDouyinRouteHandler(getDouyinData, "用户主页视频列表数据", cookie, requestConfig));
4239
- router.get("/fetch_search_info", createDouyinValidationMiddleware("搜索数据"), createDouyinRouteHandler(getDouyinData, "搜索数据", cookie, requestConfig));
4240
- router.get("/fetch_suggest_words", createDouyinValidationMiddleware("热点词数据"), createDouyinRouteHandler(getDouyinData, "热点词数据", cookie, requestConfig));
4241
- router.get("/fetch_music_work", createDouyinValidationMiddleware("音乐数据"), createDouyinRouteHandler(getDouyinData, "音乐数据", cookie, requestConfig));
4242
- router.get("/fetch_emoji_list", createDouyinValidationMiddleware("Emoji数据"), createDouyinRouteHandler(getDouyinData, "Emoji数据", cookie, requestConfig));
4243
- router.get("/fetch_emoji_pro_list", createDouyinValidationMiddleware("动态表情数据"), createDouyinRouteHandler(getDouyinData, "动态表情数据", cookie, requestConfig));
4244
- router.get("/fetch_user_live_videos", createDouyinValidationMiddleware("直播间信息数据"), createDouyinRouteHandler(getDouyinData, "直播间信息数据", cookie, requestConfig));
4245
- router.get("/fetch_video_comment_replies", createDouyinValidationMiddleware("指定评论回复数据"), createDouyinRouteHandler(getDouyinData, "指定评论回复数据", cookie, requestConfig));
4246
- router.get("/fetch_work_danmaku", createDouyinValidationMiddleware("弹幕数据"), createDouyinRouteHandler(getDouyinData, "弹幕数据", cookie, requestConfig));
4316
+ const router = express.Router();
4317
+ for (const [method, path$1] of Object.entries(DouyinMethodRoutes)) router.get(path$1, createDouyinValidationMiddleware(method), createDouyinRouteHandler(getDouyinData, method, cookie, requestConfig));
4247
4318
  return router;
4248
4319
  };
4249
4320
 
@@ -4335,10 +4406,8 @@ const createKuaishouRouteHandler = (dataFetcher, methodType, cookie, requestConf
4335
4406
  * @returns Express路由器
4336
4407
  */
4337
4408
  const createKuaishouRoutes = (cookie, requestConfig = getKuaishouDefaultConfig(cookie)) => {
4338
- const router = Router();
4339
- router.get("/fetch_one_work", createKuaishouValidationMiddleware("单个视频作品数据"), createKuaishouRouteHandler(getKuaishouData, "单个视频作品数据", cookie, requestConfig));
4340
- router.get("/fetch_work_comments", createKuaishouValidationMiddleware("评论数据"), createKuaishouRouteHandler(getKuaishouData, "评论数据", cookie, requestConfig));
4341
- router.get("/fetch_emoji_list", createKuaishouValidationMiddleware("Emoji数据"), createKuaishouRouteHandler(getKuaishouData, "Emoji数据", cookie, requestConfig));
4409
+ const router = express.Router();
4410
+ for (const [method, path$1] of Object.entries(KuaishouMethodRoutes)) router.get(path$1, createKuaishouValidationMiddleware(method), createKuaishouRouteHandler(getKuaishouData, method, cookie, requestConfig));
4342
4411
  return router;
4343
4412
  };
4344
4413
 
@@ -4442,14 +4511,8 @@ const createXiaohongshuRouteHandler = (dataFetcher, methodType, cookie, requestC
4442
4511
  * @returns Express路由器
4443
4512
  */
4444
4513
  const createXiaohongshuRoutes = (cookie, requestConfig = getXiaohongshuDefaultConfig(cookie)) => {
4445
- const router = Router();
4446
- router.get("/fetch_home_feed", createXiaohongshuValidationMiddleware("首页推荐数据"), createXiaohongshuRouteHandler(getXiaohongshuData, "首页推荐数据", cookie, requestConfig));
4447
- router.get("/fetch_one_note", createXiaohongshuValidationMiddleware("单个笔记数据"), createXiaohongshuRouteHandler(getXiaohongshuData, "单个笔记数据", cookie, requestConfig));
4448
- router.get("/fetch_note_comments", createXiaohongshuValidationMiddleware("评论数据"), createXiaohongshuRouteHandler(getXiaohongshuData, "评论数据", cookie, requestConfig));
4449
- router.get("/fetch_user_profile", createXiaohongshuValidationMiddleware("用户数据"), createXiaohongshuRouteHandler(getXiaohongshuData, "用户数据", cookie, requestConfig));
4450
- router.get("/fetch_user_notes", createXiaohongshuValidationMiddleware("用户笔记数据"), createXiaohongshuRouteHandler(getXiaohongshuData, "用户笔记数据", cookie, requestConfig));
4451
- router.get("/fetch_emoji_list", createXiaohongshuValidationMiddleware("表情列表"), createXiaohongshuRouteHandler(getXiaohongshuData, "表情列表", cookie, requestConfig));
4452
- router.get("/fetch_search_notes", createXiaohongshuValidationMiddleware("搜索笔记"), createXiaohongshuRouteHandler(getXiaohongshuData, "搜索笔记", cookie, requestConfig));
4514
+ const router = express.Router();
4515
+ for (const [method, path$1] of Object.entries(XiaohongshuMethodRoutes)) router.get(path$1, createXiaohongshuValidationMiddleware(method), createXiaohongshuRouteHandler(getXiaohongshuData, method, cookie, requestConfig));
4453
4516
  return router;
4454
4517
  };
4455
4518
 
@@ -4560,6 +4623,60 @@ const createAmagiClient = (options) => {
4560
4623
  };
4561
4624
  };
4562
4625
 
4626
+ //#endregion
4627
+ //#region src/types/BilibiliAPIParams.ts
4628
+ /**
4629
+ * 评论区类型枚举
4630
+ * 对应 CommentParams.type 与 CommentReplyParams.type
4631
+ */
4632
+ let CommentType = /* @__PURE__ */ function(CommentType$1) {
4633
+ /** 视频稿件:oid 为稿件 avid */
4634
+ CommentType$1[CommentType$1["Video"] = 1] = "Video";
4635
+ /** 话题:oid 为话题 id */
4636
+ CommentType$1[CommentType$1["Topic"] = 2] = "Topic";
4637
+ /** 活动:oid 为活动 id */
4638
+ CommentType$1[CommentType$1["Activity"] = 4] = "Activity";
4639
+ /** 小视频:oid 为小视频 id */
4640
+ CommentType$1[CommentType$1["SmallVideo"] = 5] = "SmallVideo";
4641
+ /** 小黑屋封禁信息:oid 为封禁公示 id */
4642
+ CommentType$1[CommentType$1["BlockInfo"] = 6] = "BlockInfo";
4643
+ /** 公告信息:oid 为公告 id */
4644
+ CommentType$1[CommentType$1["Announcement"] = 7] = "Announcement";
4645
+ /** 直播活动:oid 为直播间 id */
4646
+ CommentType$1[CommentType$1["LiveActivity"] = 8] = "LiveActivity";
4647
+ /** 活动稿件:oid 含义未知 */
4648
+ CommentType$1[CommentType$1["ActivityVideo"] = 9] = "ActivityVideo";
4649
+ /** 直播公告:oid 含义未知 */
4650
+ CommentType$1[CommentType$1["LiveAnnouncement"] = 10] = "LiveAnnouncement";
4651
+ /** 相簿(图片动态):oid 为相簿 id */
4652
+ CommentType$1[CommentType$1["Album"] = 11] = "Album";
4653
+ /** 专栏:oid 为专栏 cvid */
4654
+ CommentType$1[CommentType$1["Article"] = 12] = "Article";
4655
+ /** 票务:oid 含义未知 */
4656
+ CommentType$1[CommentType$1["Ticket"] = 13] = "Ticket";
4657
+ /** 音频:oid 为音频 auid */
4658
+ CommentType$1[CommentType$1["Audio"] = 14] = "Audio";
4659
+ /** 风纪委员会:oid 为众裁项目 id */
4660
+ CommentType$1[CommentType$1["Jury"] = 15] = "Jury";
4661
+ /** 点评:oid 含义未知 */
4662
+ CommentType$1[CommentType$1["Review"] = 16] = "Review";
4663
+ /** 动态(纯文字动态&分享):oid 为动态 id */
4664
+ CommentType$1[CommentType$1["Dynamic"] = 17] = "Dynamic";
4665
+ /** 播单:oid 含义未知 */
4666
+ CommentType$1[CommentType$1["Playlist"] = 18] = "Playlist";
4667
+ /** 音乐播单:oid 含义未知 */
4668
+ CommentType$1[CommentType$1["MusicPlaylist"] = 19] = "MusicPlaylist";
4669
+ /** 漫画:oid 含义未知 */
4670
+ CommentType$1[CommentType$1["Comic1"] = 20] = "Comic1";
4671
+ /** 漫画:oid 含义未知 */
4672
+ CommentType$1[CommentType$1["Comic2"] = 21] = "Comic2";
4673
+ /** 漫画:oid 为漫画 mcid */
4674
+ CommentType$1[CommentType$1["Comic"] = 22] = "Comic";
4675
+ /** 课程:oid 为课程 epid */
4676
+ CommentType$1[CommentType$1["Course"] = 33] = "Course";
4677
+ return CommentType$1;
4678
+ }({});
4679
+
4563
4680
  //#endregion
4564
4681
  //#region src/types/ReturnDataType/Bilibili/Dynamic/index.ts
4565
4682
  /**
@@ -4673,4 +4790,4 @@ const Client = CreateApp;
4673
4790
  const amagi = Client;
4674
4791
 
4675
4792
  //#endregion
4676
- export { AdditionalType, ApiError, BilibiliArticleCardParamsSchema, BilibiliArticleInfoParamsSchema, BilibiliArticleParamsSchema, BilibiliAv2BvParamsSchema, BilibiliBangumiInfoParamsSchema, BilibiliBangumiStreamParamsSchema, BilibiliBv2AvParamsSchema, BilibiliColumnInfoParamsSchema, BilibiliCommentParamsSchema, BilibiliDynamicParamsSchema, BilibiliEmojiParamsSchema, BilibiliLiveParamsSchema, BilibiliLoginParamsSchema, BilibiliQrcodeParamsSchema, BilibiliQrcodeStatusParamsSchema, BilibiliUserParamsSchema, BilibiliValidationSchemas, BilibiliVideoDownloadParamsSchema, BilibiliVideoParamsSchema, CreateApp, DouyinCommentParamsSchema, DouyinCommentReplyParamsSchema, DouyinDanmakuParamsSchema, DouyinEmojiListParamsSchema, DouyinEmojiProParamsSchema, DouyinMusicParamsSchema, DouyinQrcodeParamsSchema, DouyinSearchParamsSchema, DouyinUserParamsSchema, DouyinValidationSchemas, DouyinWorkParamsSchema, DynamicType, KuaishouCommentParamsSchema, KuaishouEmojiParamsSchema, KuaishouValidationSchemas, KuaishouVideoParamsSchema, MajorType, ValidationError, 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, kuaishou, kuaishouApiUrls, kuaishouUtils, logMiddleware, logger, qtparam, validateBilibiliParams, validateDouyinParams, validateKuaishouParams, validateXiaohongshuParams, wbi_sign, xiaohongshu, xiaohongshuApiUrls, xiaohongshuSign, xiaohongshuUtils };
4793
+ export { AdditionalType, ApiError, BilibiliArticleCardParamsSchema, BilibiliArticleInfoParamsSchema, BilibiliArticleParamsSchema, BilibiliAv2BvParamsSchema, BilibiliBangumiInfoParamsSchema, BilibiliBangumiStreamParamsSchema, BilibiliBv2AvParamsSchema, BilibiliColumnInfoParamsSchema, BilibiliCommentParamsSchema, BilibiliCommentReplyParamsSchema, BilibiliDynamicParamsSchema, BilibiliEmojiParamsSchema, BilibiliLiveParamsSchema, BilibiliLoginParamsSchema, BilibiliMethodRoutes, BilibiliQrcodeParamsSchema, BilibiliQrcodeStatusParamsSchema, BilibiliUserParamsSchema, BilibiliValidationSchemas, BilibiliVideoDownloadParamsSchema, BilibiliVideoParamsSchema, CommentType, CreateApp, DouyinCommentParamsSchema, DouyinCommentReplyParamsSchema, DouyinDanmakuParamsSchema, DouyinEmojiListParamsSchema, DouyinEmojiProParamsSchema, 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, kuaishou, kuaishouApiUrls, kuaishouUtils, logMiddleware, logger, qtparam, validateBilibiliParams, validateDouyinParams, validateKuaishouParams, validateXiaohongshuParams, wbi_sign, xiaohongshu, xiaohongshuApiUrls, xiaohongshuSign, xiaohongshuUtils };