@ikenxuan/amagi 5.8.0 → 5.9.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,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,
@@ -861,9 +861,9 @@ const getWbiKeys = async (cookie) => {
861
861
  */
862
862
  const wbi_sign = async (BASEURL, cookie) => {
863
863
  const web_keys = await getWbiKeys(cookie);
864
- const url = new URL(BASEURL);
864
+ const url$1 = new URL(BASEURL);
865
865
  const params = {};
866
- for (const [key, value] of url.searchParams.entries()) params[key] = value;
866
+ for (const [key, value] of url$1.searchParams.entries()) params[key] = value;
867
867
  return encWbi(params, web_keys.img_key, web_keys.sub_key);
868
868
  };
869
869
 
@@ -940,7 +940,7 @@ const handleError = (error, requestPath) => {
940
940
  platform: error.platform,
941
941
  requestPath
942
942
  };
943
- 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);
944
944
  return {
945
945
  code: 500,
946
946
  message: error instanceof Error ? error.message : "未知错误",
@@ -952,8 +952,8 @@ const handleError = (error, requestPath) => {
952
952
  //#endregion
953
953
  //#region src/validation/utils.ts
954
954
  function smartNumber(errorMessage, minValue = 1, isInteger = false) {
955
- if (isInteger) return z.coerce.number({ error: errorMessage }).int({ error: `${errorMessage.replace("不能为空", "")}必须是整数,不能包含小数` }).min(minValue, { error: `${errorMessage.replace("不能为空", "")}必须大于等于${minValue}` });
956
- 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}` });
957
957
  }
958
958
  /**
959
959
  * 智能正整数转换器 - 专门用于正整数类型的转换
@@ -982,18 +982,18 @@ const extractCreatorInfoFromHtml = (html) => {
982
982
 
983
983
  //#endregion
984
984
  //#region src/validation/bilibili.ts
985
- const BilibiliVideoParamsSchema = z.object({
986
- methodType: z.literal("单个视频作品数据", { error: "方法类型必须是\"单个视频作品数据\"" }),
987
- 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不能为空" })
988
988
  });
989
- const BilibiliVideoDownloadParamsSchema = z.object({
990
- methodType: z.literal("单个视频下载信息数据", { error: "方法类型必须是\"单个视频下载信息数据\"" }),
989
+ const BilibiliVideoDownloadParamsSchema = zod.object({
990
+ methodType: zod.literal("单个视频下载信息数据", { error: "方法类型必须是\"单个视频下载信息数据\"" }),
991
991
  avid: smartNumber("AVID不能为空", 1, true),
992
992
  cid: smartNumber("CID不能为空", 1, true)
993
993
  });
994
- const BilibiliCommentParamsSchema = z.object({
995
- methodType: z.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
996
- 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
997
  type: smartNumber("评论类型不能为空", 1, true).refine((val) => [
998
998
  1,
999
999
  2,
@@ -1018,12 +1018,12 @@ const BilibiliCommentParamsSchema = z.object({
1018
1018
  22,
1019
1019
  33
1020
1020
  ].includes(val), { error: "无效的评论区类型" }),
1021
- number: z.coerce.number({ error: "评论数量必须是数字" }).int({ error: "评论数量必须是整数" }).positive({ error: "评论数量必须是正数" }).default(20).optional(),
1022
- pn: z.coerce.number({ error: "页码必须是数字" }).int({ error: "页码必须是整数" }).positive({ error: "页码必须是正数" }).default(1).optional()
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
1023
  });
1024
- const BilibiliCommentReplyParamsSchema = z.object({
1025
- methodType: z.literal("指定评论的回复", { error: "方法类型必须是\"指定评论的回复\"" }),
1026
- oid: z.string({ error: "OID必须是字符串" }).min(1, { error: "OID不能为空" }),
1024
+ const BilibiliCommentReplyParamsSchema = zod.object({
1025
+ methodType: zod.literal("指定评论的回复", { error: "方法类型必须是\"指定评论的回复\"" }),
1026
+ oid: zod.string({ error: "OID必须是字符串" }).min(1, { error: "OID不能为空" }),
1027
1027
  type: smartNumber("评论类型不能为空", 1, true).refine((val) => [
1028
1028
  1,
1029
1029
  2,
@@ -1048,69 +1048,69 @@ const BilibiliCommentReplyParamsSchema = z.object({
1048
1048
  22,
1049
1049
  33
1050
1050
  ].includes(val), { error: "无效的评论区类型" }),
1051
- root: z.string({ error: "根评论ID必须是字符串" }).min(1, { error: "根评论ID不能为空" }),
1052
- number: z.coerce.number({ error: "评论数量必须是数字" }).int({ error: "评论数量必须是整数" }).positive({ error: "评论数量必须是正数" }).default(20).optional(),
1053
- 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()
1054
1054
  });
1055
- const BilibiliUserParamsSchema = z.object({
1056
- methodType: z.enum([
1055
+ const BilibiliUserParamsSchema = zod.object({
1056
+ methodType: zod.enum([
1057
1057
  "用户主页数据",
1058
1058
  "用户主页动态列表数据",
1059
1059
  "获取UP主总播放量"
1060
1060
  ], { error: "方法类型必须是指定的枚举值之一" }),
1061
1061
  host_mid: smartNumber("UP主UID不能为空", 1, true)
1062
1062
  });
1063
- const BilibiliEmojiParamsSchema = z.object({ methodType: z.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
1064
- const BilibiliBangumiInfoParamsSchema = z.object({
1065
- methodType: z.literal("番剧基本信息数据", { error: "方法类型必须是\"番剧基本信息数据\"" }),
1066
- ep_id: z.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" }).optional(),
1067
- 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()
1068
1068
  }).refine((data$1) => data$1.ep_id ?? data$1.season_id, {
1069
1069
  error: "ep_id 和 season_id 至少需要提供一个",
1070
1070
  path: ["ep_id"]
1071
1071
  });
1072
- const BilibiliBangumiStreamParamsSchema = z.object({
1073
- methodType: z.literal("番剧下载信息数据", { error: "方法类型必须是\"番剧下载信息数据\"" }),
1072
+ const BilibiliBangumiStreamParamsSchema = zod.object({
1073
+ methodType: zod.literal("番剧下载信息数据", { error: "方法类型必须是\"番剧下载信息数据\"" }),
1074
1074
  cid: smartNumber("CID不能为空", 1, true),
1075
- 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不能为空" })
1076
1076
  });
1077
- const BilibiliDynamicParamsSchema = z.object({
1078
- methodType: z.enum(["动态详情数据", "动态卡片数据"], { error: "方法类型必须是\"动态详情数据\"或\"动态卡片数据\"" }),
1079
- 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不能为空" })
1080
1080
  });
1081
- const BilibiliLiveParamsSchema = z.object({
1082
- methodType: z.enum(["直播间信息", "直播间初始化信息"], { error: "方法类型必须是\"直播间信息\"或\"直播间初始化信息\"" }),
1083
- 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不能为空" })
1084
1084
  });
1085
- const BilibiliLoginParamsSchema = z.object({ methodType: z.literal("登录基本信息", { error: "方法类型必须是\"登录基本信息\"" }) });
1086
- const BilibiliQrcodeParamsSchema = z.object({ methodType: z.literal("申请二维码", { error: "方法类型必须是\"申请二维码\"" }) });
1087
- const BilibiliQrcodeStatusParamsSchema = z.object({
1088
- methodType: z.literal("二维码状态", { error: "方法类型必须是\"二维码状态\"" }),
1089
- 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不能为空" })
1090
1090
  });
1091
- const BilibiliAv2BvParamsSchema = z.object({
1092
- methodType: z.literal("AV转BV", { error: "方法类型必须是\"AV转BV\"" }),
1093
- 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必须是正数" })
1094
1094
  });
1095
- const BilibiliBv2AvParamsSchema = z.object({
1096
- methodType: z.literal("BV转AV", { error: "方法类型必须是\"BV转AV\"" }),
1097
- 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不能为空" })
1098
1098
  });
1099
- const BilibiliArticleParamsSchema = z.object({
1100
- methodType: z.literal("专栏正文内容", { error: "方法类型必须是\"专栏正文内容\"" }),
1101
- 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不能为空" })
1102
1102
  });
1103
- const BilibiliArticleCardParamsSchema = z.object({
1104
- methodType: z.literal("专栏显示卡片信息", { error: "方法类型必须是\"专栏显示卡片信息\"" }),
1105
- 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 列表不能为空" })])
1106
1106
  });
1107
- const BilibiliArticleInfoParamsSchema = z.object({
1108
- methodType: z.literal("专栏文章基本信息", { error: "方法类型必须是\"专栏文章基本信息\"" }),
1109
- 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不能为空" })
1110
1110
  });
1111
- const BilibiliColumnInfoParamsSchema = z.object({
1112
- methodType: z.literal("文集基本信息", { error: "方法类型必须是\"文集基本信息\"" }),
1113
- 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不能为空" })
1114
1114
  });
1115
1115
  const BilibiliValidationSchemas = {
1116
1116
  单个视频作品数据: BilibiliVideoParamsSchema,
@@ -1137,62 +1137,87 @@ const BilibiliValidationSchemas = {
1137
1137
  专栏文章基本信息: BilibiliArticleInfoParamsSchema,
1138
1138
  文集基本信息: BilibiliColumnInfoParamsSchema
1139
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
+ };
1140
1165
 
1141
1166
  //#endregion
1142
1167
  //#region src/validation/douyin.ts
1143
- const DouyinWorkParamsSchema = z.object({
1144
- methodType: z.enum([
1145
- "文字作品数据",
1168
+ const DouyinWorkParamsSchema = zod.object({
1169
+ methodType: zod.enum([
1146
1170
  "视频作品数据",
1147
1171
  "图集作品数据",
1148
1172
  "合辑作品数据",
1149
1173
  "聚合解析"
1150
1174
  ], { error: "方法类型必须是指定的枚举值之一" }),
1151
- aweme_id: z.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
1175
+ aweme_id: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
1152
1176
  });
1153
- const DouyinCommentParamsSchema = z.object({
1154
- methodType: z.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
1155
- 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不能为空" }),
1156
1180
  number: smartPositiveInteger("评论数量必须是正整数").optional().default(50),
1157
- 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()
1158
1182
  });
1159
- const DouyinSearchParamsSchema = z.object({
1160
- methodType: z.enum(["热点词数据", "搜索数据"], { error: "方法类型必须是\"热点词数据\"或\"搜索数据\"" }),
1161
- 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: "搜索词不能为空" }),
1162
1186
  number: smartPositiveInteger("搜索数量必须是正整数").optional().default(10),
1163
- search_id: z.string({ error: "搜索ID必须是字符串" }).optional()
1187
+ search_id: zod.string({ error: "搜索ID必须是字符串" }).optional()
1164
1188
  });
1165
- const DouyinCommentReplyParamsSchema = z.object({
1166
- methodType: z.literal("指定评论回复数据", { error: "方法类型必须是\"指定评论回复数据\"" }),
1167
- aweme_id: z.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
1168
- 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不能为空" }),
1169
1193
  number: smartPositiveInteger("评论数量必须是正整数").optional().default(5),
1170
- 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()
1171
1195
  });
1172
- const DouyinUserParamsSchema = z.object({
1173
- methodType: z.enum([
1174
- "用户主页数据",
1175
- "用户主页视频列表数据",
1176
- "直播间信息数据"
1177
- ], { error: "方法类型必须是指定的枚举值之一" }),
1178
- 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不能为空" })
1179
1199
  });
1180
- const DouyinMusicParamsSchema = z.object({
1181
- methodType: z.literal("音乐数据", { error: "方法类型必须是\"音乐数据\"" }),
1182
- music_id: z.string({ error: "音乐ID必须是字符串" }).min(1, { error: "音乐ID不能为空" })
1200
+ const DouyinMusicParamsSchema = zod.object({
1201
+ methodType: zod.literal("音乐数据", { error: "方法类型必须是\"音乐数据\"" }),
1202
+ music_id: zod.string({ error: "音乐ID必须是字符串" }).min(1, { error: "音乐ID不能为空" })
1183
1203
  });
1184
- const DouyinQrcodeParamsSchema = z.object({
1185
- methodType: z.literal("申请二维码数据", { error: "方法类型必须是\"申请二维码数据\"" }),
1186
- verify_fp: z.string({ error: "fp指纹必须是字符串" }).min(1, { error: "fp指纹不能为空" })
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不能为空" })
1187
1208
  });
1188
- const DouyinEmojiListParamsSchema = z.object({ methodType: z.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
1189
- const DouyinEmojiProParamsSchema = z.object({ methodType: z.literal("动态表情数据", { error: "方法类型必须是\"动态表情数据\"" }) });
1190
- const DouyinDanmakuParamsSchema = z.object({
1191
- methodType: z.literal("弹幕数据", { error: "方法类型必须是\"弹幕数据\"" }),
1192
- aweme_id: z.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
1193
- start_time: z.coerce.number({ error: "开始时间必须是数字" }).int({ error: "开始时间必须是整数" }).min(0, { error: "开始时间不能小于0" }).optional(),
1194
- end_time: z.coerce.number({ error: "结束时间必须是数字" }).int({ error: "结束时间必须是整数" }).min(0, { error: "结束时间不能小于0" }).optional(),
1195
- duration: z.coerce.number({ error: "视频时长必须是数字" }).int({ error: "视频时长必须是整数" }).min(0, { error: "视频时长不能小于0" })
1209
+ const DouyinQrcodeParamsSchema = zod.object({
1210
+ methodType: zod.literal("申请二维码数据", { error: "方法类型必须是\"申请二维码数据\"" }),
1211
+ verify_fp: zod.string({ error: "fp指纹必须是字符串" }).min(1, { error: "fp指纹不能为空" })
1212
+ });
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" })
1196
1221
  }).refine((data$1) => {
1197
1222
  if (data$1.end_time !== void 0) return data$1.end_time <= data$1.duration;
1198
1223
  return true;
@@ -1218,30 +1243,53 @@ const DouyinValidationSchemas = {
1218
1243
  热点词数据: DouyinSearchParamsSchema,
1219
1244
  搜索数据: DouyinSearchParamsSchema,
1220
1245
  音乐数据: DouyinMusicParamsSchema,
1221
- 直播间信息数据: DouyinUserParamsSchema,
1246
+ 直播间信息数据: DouyinLiveRoomParamsSchema,
1222
1247
  申请二维码数据: DouyinQrcodeParamsSchema,
1223
1248
  Emoji数据: DouyinEmojiListParamsSchema,
1224
1249
  动态表情数据: DouyinEmojiProParamsSchema,
1225
1250
  指定评论回复数据: DouyinCommentReplyParamsSchema,
1226
1251
  弹幕数据: DouyinDanmakuParamsSchema
1227
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
+ };
1228
1271
 
1229
1272
  //#endregion
1230
1273
  //#region src/validation/kuaishou.ts
1231
- const KuaishouVideoParamsSchema = z.object({
1232
- methodType: z.literal("单个视频作品数据", { error: "方法类型必须是\"单个视频作品数据\"" }),
1233
- 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不能为空" })
1234
1277
  });
1235
- const KuaishouCommentParamsSchema = z.object({
1236
- methodType: z.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
1237
- 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不能为空" })
1238
1281
  });
1239
- const KuaishouEmojiParamsSchema = z.object({ methodType: z.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
1282
+ const KuaishouEmojiParamsSchema = zod.object({ methodType: zod.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
1240
1283
  const KuaishouValidationSchemas = {
1241
1284
  单个视频作品数据: KuaishouVideoParamsSchema,
1242
1285
  评论数据: KuaishouCommentParamsSchema,
1243
1286
  Emoji数据: KuaishouEmojiParamsSchema
1244
1287
  };
1288
+ const KuaishouMethodRoutes = {
1289
+ 单个视频作品数据: "/fetch_one_work",
1290
+ 评论数据: "/fetch_work_comments",
1291
+ Emoji数据: "/fetch_emoji_list"
1292
+ };
1245
1293
 
1246
1294
  //#endregion
1247
1295
  //#region src/platform/xiaohongshu/sign/index.ts
@@ -1281,9 +1329,9 @@ var xiaohongshuSign = class {
1281
1329
  * @param a1Cookie - a1 cookie值
1282
1330
  * @returns X-S签名
1283
1331
  */
1284
- static generateXS(url, body, userAgent, method = "POST", a1Cookie = "") {
1332
+ static generateXS(url$1, body, userAgent, method = "POST", a1Cookie = "") {
1285
1333
  try {
1286
- const urlObj = new URL(url);
1334
+ const urlObj = new URL(url$1);
1287
1335
  const path$1 = urlObj.pathname + urlObj.search;
1288
1336
  if (method.toUpperCase() === "GET") {
1289
1337
  const params = typeof body === "object" ? body : {};
@@ -1499,59 +1547,59 @@ const SearchNoteTypeValues = Object.values(SearchNoteType).filter((v) => typeof
1499
1547
  /**
1500
1548
  * 小红书首页推荐数据参数验证模式
1501
1549
  */
1502
- const HomeFeedParamsSchema = z.object({
1503
- methodType: z.literal("首页推荐数据", { error: "方法类型必须是\"首页推荐数据\"" }),
1504
- cursor_score: z.string({ error: "cursor_score必须是字符串" }).optional(),
1505
- num: z.coerce.number({ error: "数量必须是数字" }).int({ error: "数量必须是整数" }).min(1, { error: "数量不能小于1" }).max(100, { error: "数量不能大于100" }).optional(),
1506
- refresh_type: z.coerce.number({ error: "refresh_type必须是数字" }).int({ error: "refresh_type必须是整数" }).optional(),
1507
- note_index: z.coerce.number({ error: "note_index必须是数字" }).int({ error: "note_index必须是整数" }).optional(),
1508
- category: z.string({ error: "category必须是字符串" }).optional(),
1509
- 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()
1510
1558
  });
1511
1559
  /**
1512
1560
  * 小红书单个笔记数据参数验证模式
1513
1561
  */
1514
- const NoteParamsSchema = z.object({
1515
- methodType: z.literal("单个笔记数据", { error: "方法类型必须是\"单个笔记数据\"" }),
1516
- note_id: z.string({ error: "note_id必须是字符串" }),
1517
- 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必须是字符串" })
1518
1566
  });
1519
1567
  /**
1520
1568
  * 小红书评论数据参数验证模式
1521
1569
  */
1522
- const CommentParamsSchema = z.object({
1523
- methodType: z.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
1524
- note_id: z.string({ error: "note_id必须是字符串" }),
1525
- cursor: z.string({ error: "cursor必须是字符串" }).optional(),
1526
- 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必须是字符串" })
1527
1575
  });
1528
1576
  /**
1529
1577
  * 小红书用户数据参数验证模式
1530
1578
  */
1531
- const UserParamsSchema = z.object({
1532
- methodType: z.literal("用户数据", { error: "方法类型必须是\"用户数据\"" }),
1533
- 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必须是字符串" })
1534
1582
  });
1535
1583
  /**
1536
1584
  * 小红书用户笔记数据参数验证模式
1537
1585
  */
1538
- const UserNoteParamsSchema = z.object({
1539
- methodType: z.literal("用户笔记数据", { error: "方法类型必须是\"用户笔记数据\"" }),
1540
- user_id: z.string({ error: "user_id必须是字符串" }),
1541
- cursor: z.string({ error: "cursor必须是字符串" }).optional(),
1542
- 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()
1543
1591
  });
1544
- const EmojiListParamsSchema = z.object({ methodType: z.literal("表情列表", { error: "方法类型必须是\"表情列表\"" }) });
1592
+ const EmojiListParamsSchema = zod.object({ methodType: zod.literal("表情列表", { error: "方法类型必须是\"表情列表\"" }) });
1545
1593
  /**
1546
1594
  * 小红书搜索笔记参数验证模式
1547
1595
  */
1548
- const SearchNoteParamsSchema = z.object({
1549
- methodType: z.literal("搜索笔记", { error: "方法类型必须是\"搜索笔记\"" }),
1550
- keyword: z.string({ error: "keyword必须是字符串" }),
1551
- page: z.coerce.number({ error: "page必须是数字" }).int({ error: "page必须是整数" }).min(1, { error: "page不能小于1" }).optional(),
1552
- 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(),
1553
- sort: z.enum(SearchSortTypeValues, { error: "排序类型不合法" }).optional(),
1554
- 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()
1555
1603
  });
1556
1604
  /**
1557
1605
  * 小红书验证模式映射
@@ -1566,19 +1614,16 @@ const XiaohongshuValidationSchemas = {
1566
1614
  搜索笔记: SearchNoteParamsSchema
1567
1615
  };
1568
1616
  /**
1569
- * 验证小红书参数
1570
- * @param methodType - 小红书方法类型
1571
- * @param params - 待验证的参数
1572
- * @returns 验证后的参数
1617
+ * 小红书方法类型
1573
1618
  */
1574
- const validateXiaohongshuParams = (methodType, params) => {
1575
- return XiaohongshuValidationSchemas[methodType].parse(typeof params === "object" && params !== null ? {
1576
- methodType,
1577
- ...params
1578
- } : {
1579
- methodType,
1580
- params
1581
- });
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"
1582
1627
  };
1583
1628
 
1584
1629
  //#endregion
@@ -1629,6 +1674,21 @@ const validateKuaishouParams = (methodType, params) => {
1629
1674
  });
1630
1675
  };
1631
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
+ /**
1632
1692
  * 创建成功响应格式
1633
1693
  * @param data - 响应数据
1634
1694
  * @param message - 响应消息(可选)
@@ -1741,30 +1801,8 @@ const createBilibiliRouteHandler = (dataFetcher, methodType, cookie, requestConf
1741
1801
  * @returns Express路由器
1742
1802
  */
1743
1803
  const createBilibiliRoutes = (cookie, requestConfig = getBilibiliDefaultConfig(cookie)) => {
1744
- const router = Router();
1745
- router.get("/fetch_one_video", createBilibiliValidationMiddleware("单个视频作品数据"), createBilibiliRouteHandler(getBilibiliData, "单个视频作品数据", cookie, requestConfig));
1746
- router.get("/fetch_video_playurl", createBilibiliValidationMiddleware("单个视频下载信息数据"), createBilibiliRouteHandler(getBilibiliData, "单个视频下载信息数据", cookie, requestConfig));
1747
- router.get("/fetch_work_comments", createBilibiliValidationMiddleware("评论数据"), createBilibiliRouteHandler(getBilibiliData, "评论数据", cookie, requestConfig));
1748
- router.get("/fetch_comment_reply", createBilibiliValidationMiddleware("指定评论的回复"), createBilibiliRouteHandler(getBilibiliData, "指定评论的回复", cookie, requestConfig));
1749
- router.get("/fetch_user_profile", createBilibiliValidationMiddleware("用户主页数据"), createBilibiliRouteHandler(getBilibiliData, "用户主页数据", cookie, requestConfig));
1750
- router.get("/fetch_user_dynamic", createBilibiliValidationMiddleware("用户主页动态列表数据"), createBilibiliRouteHandler(getBilibiliData, "用户主页动态列表数据", cookie, requestConfig));
1751
- router.get("/fetch_emoji_list", createBilibiliValidationMiddleware("Emoji数据"), createBilibiliRouteHandler(getBilibiliData, "Emoji数据", cookie, requestConfig));
1752
- router.get("/fetch_bangumi_video_info", createBilibiliValidationMiddleware("番剧基本信息数据"), createBilibiliRouteHandler(getBilibiliData, "番剧基本信息数据", cookie, requestConfig));
1753
- router.get("/fetch_bangumi_video_playurl", createBilibiliValidationMiddleware("番剧下载信息数据"), createBilibiliRouteHandler(getBilibiliData, "番剧下载信息数据", cookie, requestConfig));
1754
- router.get("/fetch_dynamic_info", createBilibiliValidationMiddleware("动态详情数据"), createBilibiliRouteHandler(getBilibiliData, "动态详情数据", cookie, requestConfig));
1755
- router.get("/fetch_dynamic_card", createBilibiliValidationMiddleware("动态卡片数据"), createBilibiliRouteHandler(getBilibiliData, "动态卡片数据", cookie, requestConfig));
1756
- router.get("/fetch_live_room_detail", createBilibiliValidationMiddleware("直播间信息"), createBilibiliRouteHandler(getBilibiliData, "直播间信息", cookie, requestConfig));
1757
- router.get("/fetch_liveroom_def", createBilibiliValidationMiddleware("直播间初始化信息"), createBilibiliRouteHandler(getBilibiliData, "直播间初始化信息", cookie, requestConfig));
1758
- router.get("/login_basic_info", createBilibiliValidationMiddleware("登录基本信息"), createBilibiliRouteHandler(getBilibiliData, "登录基本信息", cookie, requestConfig));
1759
- router.get("/new_login_qrcode", createBilibiliValidationMiddleware("申请二维码"), createBilibiliRouteHandler(getBilibiliData, "申请二维码", cookie, requestConfig));
1760
- router.get("/check_qrcode", createBilibiliValidationMiddleware("二维码状态"), createBilibiliRouteHandler(getBilibiliData, "二维码状态", cookie, requestConfig));
1761
- router.get("/fetch_user_full_view", createBilibiliValidationMiddleware("获取UP主总播放量"), createBilibiliRouteHandler(getBilibiliData, "获取UP主总播放量", cookie, requestConfig));
1762
- router.get("/av_to_bv", createBilibiliValidationMiddleware("AV转BV"), createBilibiliRouteHandler(getBilibiliData, "AV转BV", cookie, requestConfig));
1763
- router.get("/bv_to_av", createBilibiliValidationMiddleware("BV转AV"), createBilibiliRouteHandler(getBilibiliData, "BV转AV", cookie, requestConfig));
1764
- router.get("/fetch_article_content", createBilibiliValidationMiddleware("专栏正文内容"), createBilibiliRouteHandler(getBilibiliData, "专栏正文内容", cookie, requestConfig));
1765
- router.get("/fetch_article_card", createBilibiliValidationMiddleware("专栏显示卡片信息"), createBilibiliRouteHandler(getBilibiliData, "专栏显示卡片信息", cookie, requestConfig));
1766
- router.get("/fetch_article_info", createBilibiliValidationMiddleware("专栏文章基本信息"), createBilibiliRouteHandler(getBilibiliData, "专栏文章基本信息", cookie, requestConfig));
1767
- 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));
1768
1806
  return router;
1769
1807
  };
1770
1808
 
@@ -1830,6 +1868,12 @@ const qtparam = async (BASEURL, cookie) => {
1830
1868
  //#endregion
1831
1869
  //#region src/platform/bilibili/getdata.ts
1832
1870
  /**
1871
+ * B站数据获取模块
1872
+ *
1873
+ * 注意:为避免循环依赖,此文件直接从具体模块导入,而不是从平台 index 文件导入
1874
+ * 循环依赖链:DataFetchers → getdata → platform/bilibili → DataFetchers
1875
+ */
1876
+ /**
1833
1877
  * B站数据获取函数
1834
1878
  * @param data - 请求数据参数
1835
1879
  * @param cookie - 用户Cookie
@@ -2622,9 +2666,9 @@ const cleanUserAgentForSigning = (userAgent) => {
2622
2666
  * @param user_agent - 用户代理字符串
2623
2667
  * @returns 生成的a_bogus签名
2624
2668
  */
2625
- var a_bogus_default = (url, user_agent) => {
2669
+ var a_bogus_default = (url$1, user_agent) => {
2626
2670
  const cleanedUserAgent = cleanUserAgentForSigning(user_agent);
2627
- 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") + "=";
2628
2672
  };
2629
2673
 
2630
2674
  //#endregion
@@ -2726,8 +2770,8 @@ var XBogus = class {
2726
2770
  * @param ua 可选的User-Agent,不提供则使用默认值
2727
2771
  * @returns 包含完整URL、X-Bogus值和使用的User-Agent的元组
2728
2772
  */
2729
- getXBogus(url, ua) {
2730
- const parsedUrl = new URL$1.URL(url);
2773
+ getXBogus(url$1, ua) {
2774
+ const parsedUrl = new url.URL(url$1);
2731
2775
  const urlPath = parsedUrl.pathname + parsedUrl.search;
2732
2776
  const currentUa = ua ?? this.defaultUa;
2733
2777
  const rc4EncryptedUa = this.rc4Encrypt(this.uaKey, currentUa);
@@ -2784,7 +2828,7 @@ var XBogus = class {
2784
2828
  idx += 3;
2785
2829
  }
2786
2830
  return {
2787
- 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}`,
2788
2832
  xbogus: xb,
2789
2833
  userAgent: currentUa
2790
2834
  };
@@ -2810,16 +2854,16 @@ var douyinSign = class {
2810
2854
  * @param url 需要签名的地址
2811
2855
  * @returns 对此地址签名后的URL查询参数
2812
2856
  */
2813
- static AB(url, userAgent) {
2814
- return a_bogus_default(url, userAgent ?? defaultUserAgent);
2857
+ static AB(url$1, userAgent) {
2858
+ return a_bogus_default(url$1, userAgent ?? defaultUserAgent);
2815
2859
  }
2816
2860
  /**
2817
2861
  * X-Bogus 签名算法
2818
2862
  * @param url 需要签名的地址
2819
2863
  * @returns 对此地址签名后的URL查询参数
2820
2864
  */
2821
- static XB(url, userAgent) {
2822
- return new XBogus().getXBogus(url, userAgent ?? defaultUserAgent).xbogus;
2865
+ static XB(url$1, userAgent) {
2866
+ return new XBogus().getXBogus(url$1, userAgent ?? defaultUserAgent).xbogus;
2823
2867
  }
2824
2868
  /** 生成一个唯一的验证字符串 */
2825
2869
  static VerifyFpManager() {
@@ -3285,17 +3329,23 @@ const douyinApiUrls = new DouyinAPI();
3285
3329
  //#endregion
3286
3330
  //#region src/platform/douyin/getdata.ts
3287
3331
  /**
3332
+ * 抖音数据获取模块
3333
+ *
3334
+ * 注意:为避免循环依赖,此文件直接从具体模块导入,而不是从平台 index 文件导入
3335
+ * 循环依赖链:DataFetchers → getdata → platform/douyin → DataFetchers
3336
+ */
3337
+ /**
3288
3338
  * 获取签名参数
3289
3339
  * @param url - 需要签名的URL
3290
3340
  * @param signType - 签名算法类型
3291
3341
  * @param userAgent - 用户代理
3292
3342
  * @returns 签名后的参数字符串
3293
3343
  */
3294
- const getSignature = (url, signType = "a_bogus", userAgent) => {
3344
+ const getSignature = (url$1, signType = "a_bogus", userAgent) => {
3295
3345
  switch (signType) {
3296
- case "x_bogus": return douyinSign.XB(url, userAgent);
3346
+ case "x_bogus": return douyinSign.XB(url$1, userAgent);
3297
3347
  case "a_bogus":
3298
- default: return douyinSign.AB(url, userAgent);
3348
+ default: return douyinSign.AB(url$1, userAgent);
3299
3349
  }
3300
3350
  };
3301
3351
  /**
@@ -3317,9 +3367,9 @@ const getSignParamName = (signType = "a_bogus") => {
3317
3367
  * @param userAgent - 用户代理
3318
3368
  * @returns 带签名的完整URL
3319
3369
  */
3320
- const buildSignedUrl = (url, signType = "a_bogus", userAgent) => {
3321
- const signature = getSignature(url, signType, userAgent);
3322
- 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}`;
3323
3373
  };
3324
3374
  /**
3325
3375
  * 抖音数据获取函数
@@ -3348,10 +3398,10 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3348
3398
  case "视频作品数据":
3349
3399
  case "图集作品数据":
3350
3400
  case "合辑作品数据": {
3351
- const url = douyinApiUrls$1.视频或图集({ aweme_id: data$1.aweme_id });
3401
+ const url$1 = douyinApiUrls$1.视频或图集({ aweme_id: data$1.aweme_id });
3352
3402
  return await GlobalGetData$2(data$1.methodType, {
3353
3403
  ...baseRequestConfig,
3354
- url: buildSignedUrl(url, signType, userAgent)
3404
+ url: buildSignedUrl(url$1, signType, userAgent)
3355
3405
  });
3356
3406
  }
3357
3407
  case "评论数据": {
@@ -3363,7 +3413,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3363
3413
  return await fetchPaginatedData(data$1.methodType, urlGenerator, data$1, 3, baseRequestConfig, "x_bogus");
3364
3414
  }
3365
3415
  case "用户主页数据": {
3366
- const url = douyinApiUrls$1.用户主页信息({ sec_uid: data$1.sec_uid });
3416
+ const url$1 = douyinApiUrls$1.用户主页信息({ sec_uid: data$1.sec_uid });
3367
3417
  const customConfig = {
3368
3418
  ...baseRequestConfig,
3369
3419
  headers: {
@@ -3373,18 +3423,18 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3373
3423
  };
3374
3424
  return await GlobalGetData$2(data$1.methodType, {
3375
3425
  ...customConfig,
3376
- url: buildSignedUrl(url, signType, userAgent)
3426
+ url: buildSignedUrl(url$1, signType, userAgent)
3377
3427
  });
3378
3428
  }
3379
3429
  case "Emoji数据": {
3380
- const url = douyinApiUrls$1.表情();
3430
+ const url$1 = douyinApiUrls$1.表情();
3381
3431
  return await GlobalGetData$2(data$1.methodType, {
3382
3432
  ...baseRequestConfig,
3383
- url
3433
+ url: url$1
3384
3434
  });
3385
3435
  }
3386
3436
  case "用户主页视频列表数据": {
3387
- const url = douyinApiUrls$1.用户主页视频({ sec_uid: data$1.sec_uid });
3437
+ const url$1 = douyinApiUrls$1.用户主页视频({ sec_uid: data$1.sec_uid });
3388
3438
  const customConfig = {
3389
3439
  ...baseRequestConfig,
3390
3440
  headers: {
@@ -3394,11 +3444,11 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3394
3444
  };
3395
3445
  return await GlobalGetData$2(data$1.methodType, {
3396
3446
  ...customConfig,
3397
- url: buildSignedUrl(url, signType, userAgent)
3447
+ url: buildSignedUrl(url$1, signType, userAgent)
3398
3448
  });
3399
3449
  }
3400
3450
  case "热点词数据": {
3401
- const url = douyinApiUrls$1.热点词({
3451
+ const url$1 = douyinApiUrls$1.热点词({
3402
3452
  query: data$1.query,
3403
3453
  number: data$1.number ?? 10
3404
3454
  });
@@ -3411,7 +3461,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3411
3461
  };
3412
3462
  return await GlobalGetData$2(data$1.methodType, {
3413
3463
  ...customConfig,
3414
- url: buildSignedUrl(url, signType, userAgent)
3464
+ url: buildSignedUrl(url$1, signType, userAgent)
3415
3465
  });
3416
3466
  }
3417
3467
  case "搜索数据": {
@@ -3428,19 +3478,22 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3428
3478
  };
3429
3479
  while (fetchedSearchList.length < Number(data$1.number ?? 10)) {
3430
3480
  const requestCount = Math.min(Number(data$1.number ?? 50) - fetchedSearchList.length, maxPageSize);
3431
- const url = douyinApiUrls$1.搜索({
3481
+ const url$1 = douyinApiUrls$1.搜索({
3432
3482
  query: data$1.query,
3433
3483
  number: requestCount,
3434
3484
  search_id: search_id === "" ? void 0 : search_id
3435
3485
  });
3436
3486
  const raw = await GlobalGetData$2(data$1.methodType, {
3437
3487
  ...customConfig,
3438
- url: buildSignedUrl(url, "x_bogus", userAgent)
3488
+ url: buildSignedUrl(url$1, "x_bogus", userAgent)
3439
3489
  });
3440
3490
  const responses = filterSearchResponses(typeof raw === "string" ? parseDouyinMultiJson(raw) : [raw]);
3441
3491
  if (responses.length === 0) {
3442
3492
  logger.warn("抖音搜索返回无有效数据,疑似触发反爬\n你的抖音ck可能已经失效!\n请求类型:" + data$1.methodType);
3443
- return false;
3493
+ return {
3494
+ success: false,
3495
+ amagiError: "抖音搜索返回无有效数据,疑似触发反爬\n你的抖音ck可能已经失效!\n请求类型:" + data$1.methodType
3496
+ };
3444
3497
  }
3445
3498
  for (const resp of responses) {
3446
3499
  if (Array.isArray(resp.data) && resp.data.length > 0) fetchedSearchList.push(...resp.data);
@@ -3448,8 +3501,11 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3448
3501
  search_id = resp.log_pb?.impr_id ?? search_id;
3449
3502
  }
3450
3503
  if (fetchedSearchList.length === 0) {
3451
- logger.warn("抖音搜索返回数据长度为空,\n你的抖音ck疑似触发验证码!\n请求类型:" + data$1.methodType);
3452
- 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
+ };
3453
3509
  }
3454
3510
  if (tmpresp && typeof tmpresp.has_more === "number" && tmpresp.has_more === 0) break;
3455
3511
  }
@@ -3459,77 +3515,42 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3459
3515
  };
3460
3516
  }
3461
3517
  case "动态表情数据": {
3462
- const url = douyinApiUrls$1.互动表情();
3518
+ const url$1 = douyinApiUrls$1.互动表情();
3463
3519
  return await GlobalGetData$2(data$1.methodType, {
3464
3520
  ...baseRequestConfig,
3465
- url: buildSignedUrl(url, signType, userAgent)
3521
+ url: buildSignedUrl(url$1, signType, userAgent)
3466
3522
  });
3467
3523
  }
3468
3524
  case "音乐数据": {
3469
- const url = douyinApiUrls$1.背景音乐({ music_id: data$1.music_id });
3525
+ const url$1 = douyinApiUrls$1.背景音乐({ music_id: data$1.music_id });
3470
3526
  return await GlobalGetData$2(data$1.methodType, {
3471
3527
  ...baseRequestConfig,
3472
- url: buildSignedUrl(url, signType, userAgent)
3528
+ url: buildSignedUrl(url$1, signType, userAgent)
3473
3529
  });
3474
3530
  }
3475
3531
  case "直播间信息数据": {
3476
- let url = douyinApiUrls$1.用户主页信息({ sec_uid: data$1.sec_uid });
3477
- const fetchUrl = buildSignedUrl(url, signType, userAgent);
3478
- const customConfig = {
3479
- ...baseRequestConfig,
3480
- headers: {
3481
- ...baseRequestConfig.headers,
3482
- ...(!requestConfig?.headers || !("Referer" in requestConfig.headers)) && { Referer: `https://www.douyin.com/user/${data$1.sec_uid}` }
3483
- }
3484
- };
3485
- const UserInfoData = await GlobalGetData$2(data$1.methodType, {
3486
- ...customConfig,
3487
- url: fetchUrl
3488
- });
3489
- if (!UserInfoData?.user?.live_status || UserInfoData.user.live_status !== 1) {
3490
- logger.error((UserInfoData?.user?.nickname ?? "用户") + "当前未在直播");
3491
- const Err = {
3492
- errorDescription: "检查失败!该用户当前未在直播! TypeError: Cannot read properties of undefined (reading 'live_status')",
3493
- requestType: data$1.methodType ?? "未知请求类型",
3494
- requestUrl: fetchUrl
3495
- };
3496
- return {
3497
- code: douoyinAPIErrorCode.NOT_LIVE,
3498
- data: UserInfoData,
3499
- amagiError: Err,
3500
- amagiMessage: Err.errorDescription
3501
- };
3502
- }
3503
- if (!UserInfoData.user.room_data) {
3504
- logger.error("未获取到直播间信息!");
3505
- return {
3506
- code: 500,
3507
- message: "未获取到直播间信息!",
3508
- data: null
3509
- };
3510
- }
3511
- const room_data = JSON.parse(UserInfoData.user.room_data);
3512
- url = douyinApiUrls$1.直播间信息({
3513
- room_id: UserInfoData.user.room_id_str,
3514
- 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
3515
3535
  });
3516
3536
  const liveCustomConfig = {
3517
3537
  ...baseRequestConfig,
3538
+ url: buildSignedUrl(url$1, signType, userAgent),
3518
3539
  headers: {
3519
3540
  ...baseRequestConfig.headers,
3520
- ...(!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}` }
3521
3542
  }
3522
3543
  };
3523
3544
  return await GlobalGetData$2(data$1.methodType, {
3524
3545
  ...liveCustomConfig,
3525
- url: buildSignedUrl(url, signType, userAgent)
3546
+ url: buildSignedUrl(url$1, signType, userAgent)
3526
3547
  });
3527
3548
  }
3528
3549
  case "申请二维码数据": {
3529
- const url = douyinApiUrls$1.申请二维码({ verify_fp: data$1.verify_fp });
3550
+ const url$1 = douyinApiUrls$1.申请二维码({ verify_fp: data$1.verify_fp });
3530
3551
  return await GlobalGetData$2(data$1.methodType, {
3531
3552
  ...baseRequestConfig,
3532
- url: buildSignedUrl(url, signType, userAgent)
3553
+ url: buildSignedUrl(url$1, signType, userAgent)
3533
3554
  });
3534
3555
  }
3535
3556
  case "弹幕数据": {
@@ -3538,7 +3559,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3538
3559
  const endTime = data$1.end_time ?? data$1.duration;
3539
3560
  const totalDuration = endTime - startTime;
3540
3561
  if (totalDuration <= MAX_SEGMENT_DURATION) {
3541
- const url = douyinApiUrls$1.弹幕({
3562
+ const url$1 = douyinApiUrls$1.弹幕({
3542
3563
  aweme_id: data$1.aweme_id,
3543
3564
  start_time: startTime,
3544
3565
  end_time: endTime,
@@ -3546,7 +3567,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3546
3567
  });
3547
3568
  return await GlobalGetData$2(data$1.methodType, {
3548
3569
  ...baseRequestConfig,
3549
- url: buildSignedUrl(url, signType, userAgent)
3570
+ url: buildSignedUrl(url$1, signType, userAgent)
3550
3571
  });
3551
3572
  }
3552
3573
  const segments = [];
@@ -3561,7 +3582,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3561
3582
  }
3562
3583
  logger.debug(`弹幕数据需要分${segments.length}段获取,总时长:${totalDuration}ms`);
3563
3584
  const segmentPromises = segments.map(async (segment, index) => {
3564
- const url = douyinApiUrls$1.弹幕({
3585
+ const url$1 = douyinApiUrls$1.弹幕({
3565
3586
  aweme_id: data$1.aweme_id,
3566
3587
  start_time: segment.start,
3567
3588
  end_time: segment.end,
@@ -3570,7 +3591,7 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3570
3591
  try {
3571
3592
  const segmentData = await GlobalGetData$2(`${data$1.methodType}-段${index + 1}`, {
3572
3593
  ...baseRequestConfig,
3573
- url: buildSignedUrl(url, signType, userAgent)
3594
+ url: buildSignedUrl(url$1, signType, userAgent)
3574
3595
  });
3575
3596
  logger.debug(`弹幕第${index + 1}段获取成功 (${segment.start}ms-${segment.end}ms)`);
3576
3597
  return segmentData;
@@ -3611,9 +3632,18 @@ const DouyinData = async (data$1, cookie, requestConfig) => {
3611
3632
  logger.debug(`弹幕数据合并完成,共获取${mergedDanmakuList.length}条弹幕`);
3612
3633
  return finalDanmakuData;
3613
3634
  }
3614
- 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
+ }
3615
3644
  logger.warn(`未知的抖音数据接口:「${logger.red(data$1.methodType)}」`);
3616
3645
  return null;
3646
+ }
3617
3647
  }
3618
3648
  };
3619
3649
  /**
@@ -3633,14 +3663,14 @@ const fetchPaginatedData = async (type, apiUrlGenerator, params, maxPageSize, re
3633
3663
  const userAgent = requestConfig.headers?.["User-Agent"];
3634
3664
  while (fetchedData.length < Number(params.number ?? maxPageSize)) {
3635
3665
  const requestCount = Math.min(Number(params.number ?? maxPageSize) - fetchedData.length, maxPageSize);
3636
- const url = apiUrlGenerator({
3666
+ const url$1 = apiUrlGenerator({
3637
3667
  ...params,
3638
3668
  number: requestCount,
3639
3669
  cursor
3640
3670
  });
3641
3671
  const response = await GlobalGetData$2(type, {
3642
3672
  ...requestConfig,
3643
- url: buildSignedUrl(url, signType, userAgent)
3673
+ url: buildSignedUrl(url$1, signType, userAgent)
3644
3674
  });
3645
3675
  fetchedData.push(...response.comments ?? response.data ?? []);
3646
3676
  tmpresp = response;
@@ -3805,6 +3835,12 @@ const kuaishouApiUrls = new API();
3805
3835
  //#endregion
3806
3836
  //#region src/platform/kuaishou/getdata.ts
3807
3837
  /**
3838
+ * 快手数据获取模块
3839
+ *
3840
+ * 注意:为避免循环依赖,此文件直接从具体模块导入,而不是从平台 index 文件导入
3841
+ * 循环依赖链:DataFetchers → getdata → platform/kuaishou → DataFetchers
3842
+ */
3843
+ /**
3808
3844
  * 快手数据获取函数
3809
3845
  * @param data - 请求数据参数
3810
3846
  * @param cookie - 用户Cookie
@@ -4082,7 +4118,7 @@ async function getDouyinData(methodType, optionsOrCookie, cookieOrOptions, reque
4082
4118
  cookie = cookieOrOptions;
4083
4119
  config = requestConfig;
4084
4120
  }
4085
- const { typeMode: _,...validationOptions } = options ?? {};
4121
+ const { typeMode: _, ...validationOptions } = options ?? {};
4086
4122
  const rawData = await DouyinData({ ...validateDouyinParams(methodType, validationOptions) }, cookie, config);
4087
4123
  if (rawData.data === "" || rawData.status_code !== 0) return createErrorResponse(rawData.amagiError, rawData.status_msg ?? "抖音数据获取失败");
4088
4124
  return createSuccessResponse(rawData, "获取成功", 200);
@@ -4105,7 +4141,7 @@ async function getBilibiliData(methodType, optionsOrCookie, cookieOrOptions, req
4105
4141
  options = optionsOrCookie;
4106
4142
  cookie = cookieOrOptions;
4107
4143
  }
4108
- const { typeMode: _,...validationOptions } = options ?? {};
4144
+ const { typeMode: _, ...validationOptions } = options ?? {};
4109
4145
  const rawData = await fetchBilibili({ ...validateBilibiliParams(methodType, validationOptions) }, cookie);
4110
4146
  if (rawData.code !== 0) return createErrorResponse(rawData.amagiError, "B站数据获取失败");
4111
4147
  return createSuccessResponse(rawData, "获取成功", 200);
@@ -4128,7 +4164,7 @@ async function getKuaishouData(methodType, optionsOrCookie, cookieOrOptions, req
4128
4164
  options = optionsOrCookie;
4129
4165
  cookie = cookieOrOptions;
4130
4166
  }
4131
- const { typeMode: _,...validationOptions } = options ?? {};
4167
+ const { typeMode: _, ...validationOptions } = options ?? {};
4132
4168
  const rawData = await KuaishouData({ ...validateKuaishouParams(methodType, validationOptions) }, cookie);
4133
4169
  if (rawData.code && Object.values(kuaishouAPIErrorCode).includes(rawData.code)) return createErrorResponse(rawData.amagiError, "快手数据获取失败");
4134
4170
  return createSuccessResponse(rawData, "获取成功", 200);
@@ -4151,7 +4187,7 @@ async function getXiaohongshuData(methodType, optionsOrCookie, cookieOrOptions,
4151
4187
  options = optionsOrCookie;
4152
4188
  cookie = cookieOrOptions;
4153
4189
  }
4154
- const { typeMode: _,...validationOptions } = options ?? {};
4190
+ const { typeMode: _, ...validationOptions } = options ?? {};
4155
4191
  const rawData = await XiaohongshuData({ ...validateXiaohongshuParams(methodType, validationOptions) }, cookie);
4156
4192
  if (rawData.code && Object.values(xiaohongshuAPIErrorCode).includes(rawData.code)) return createErrorResponse(rawData.amagiError, "小红书数据获取失败");
4157
4193
  return createSuccessResponse(rawData, "获取成功", 200);
@@ -4209,7 +4245,10 @@ const douyin = {
4209
4245
  getSuggestWords: createDouyinApiMethod("热点词数据"),
4210
4246
  search: createDouyinApiMethod("搜索数据"),
4211
4247
  getLiveRoomInfo: createDouyinApiMethod("直播间信息数据"),
4212
- getDanmaku: createDouyinApiMethod("弹幕数据")
4248
+ getDanmaku: createDouyinApiMethod("弹幕数据"),
4249
+ invoke: async (methodType, options, cookie, requestConfig) => {
4250
+ return await getDouyinData(methodType, options, cookie, requestConfig);
4251
+ }
4213
4252
  };
4214
4253
  /**
4215
4254
  * 创建绑定了cookie的抖音API对象
@@ -4231,9 +4270,12 @@ const createBoundDouyinApi = (cookie, requestConfig) => {
4231
4270
  getUserVideos: createBoundDouyinApiMethod("用户主页视频列表数据", cookie, requestConfig),
4232
4271
  getMusicInfo: createBoundDouyinApiMethod("音乐数据", cookie, requestConfig),
4233
4272
  getSuggestWords: createBoundDouyinApiMethod("热点词数据", cookie, requestConfig),
4234
- search: createBoundDouyinApiMethod("搜索数据", cookie, requestConfig),
4273
+ getSearchData: createBoundDouyinApiMethod("搜索数据", cookie, requestConfig),
4235
4274
  getLiveRoomInfo: createBoundDouyinApiMethod("直播间信息数据", cookie, requestConfig),
4236
- getDanmaku: createBoundDouyinApiMethod("弹幕数据", cookie, requestConfig)
4275
+ getDanmaku: createBoundDouyinApiMethod("弹幕数据", cookie, requestConfig),
4276
+ invoke: async (methodType, options) => {
4277
+ return await getDouyinData(methodType, options, cookie, requestConfig);
4278
+ }
4237
4279
  };
4238
4280
  };
4239
4281
 
@@ -4271,22 +4313,8 @@ const createDouyinRouteHandler = (dataFetcher, methodType, cookie, requestConfig
4271
4313
  * @returns Express路由器
4272
4314
  */
4273
4315
  const createDouyinRoutes = (cookie, requestConfig = getDouyinDefaultConfig(cookie)) => {
4274
- const router = Router();
4275
- router.get("/fetch_one_work", createDouyinValidationMiddleware("聚合解析"), createDouyinRouteHandler(getDouyinData, "聚合解析", cookie, requestConfig));
4276
- router.get("/fetch_one_work", createDouyinValidationMiddleware("视频作品数据"), createDouyinRouteHandler(getDouyinData, "视频作品数据", cookie, requestConfig));
4277
- router.get("/fetch_one_work", createDouyinValidationMiddleware("图集作品数据"), createDouyinRouteHandler(getDouyinData, "图集作品数据", cookie, requestConfig));
4278
- router.get("/fetch_one_work", createDouyinValidationMiddleware("合辑作品数据"), createDouyinRouteHandler(getDouyinData, "合辑作品数据", cookie, requestConfig));
4279
- router.get("/fetch_work_comments", createDouyinValidationMiddleware("评论数据"), createDouyinRouteHandler(getDouyinData, "评论数据", cookie, requestConfig));
4280
- router.get("/fetch_user_info", createDouyinValidationMiddleware("用户主页数据"), createDouyinRouteHandler(getDouyinData, "用户主页数据", cookie, requestConfig));
4281
- router.get("/fetch_user_post_videos", createDouyinValidationMiddleware("用户主页视频列表数据"), createDouyinRouteHandler(getDouyinData, "用户主页视频列表数据", cookie, requestConfig));
4282
- router.get("/fetch_search_info", createDouyinValidationMiddleware("搜索数据"), createDouyinRouteHandler(getDouyinData, "搜索数据", cookie, requestConfig));
4283
- router.get("/fetch_suggest_words", createDouyinValidationMiddleware("热点词数据"), createDouyinRouteHandler(getDouyinData, "热点词数据", cookie, requestConfig));
4284
- router.get("/fetch_music_work", createDouyinValidationMiddleware("音乐数据"), createDouyinRouteHandler(getDouyinData, "音乐数据", cookie, requestConfig));
4285
- router.get("/fetch_emoji_list", createDouyinValidationMiddleware("Emoji数据"), createDouyinRouteHandler(getDouyinData, "Emoji数据", cookie, requestConfig));
4286
- router.get("/fetch_emoji_pro_list", createDouyinValidationMiddleware("动态表情数据"), createDouyinRouteHandler(getDouyinData, "动态表情数据", cookie, requestConfig));
4287
- router.get("/fetch_user_live_videos", createDouyinValidationMiddleware("直播间信息数据"), createDouyinRouteHandler(getDouyinData, "直播间信息数据", cookie, requestConfig));
4288
- router.get("/fetch_video_comment_replies", createDouyinValidationMiddleware("指定评论回复数据"), createDouyinRouteHandler(getDouyinData, "指定评论回复数据", cookie, requestConfig));
4289
- 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));
4290
4318
  return router;
4291
4319
  };
4292
4320
 
@@ -4378,10 +4406,8 @@ const createKuaishouRouteHandler = (dataFetcher, methodType, cookie, requestConf
4378
4406
  * @returns Express路由器
4379
4407
  */
4380
4408
  const createKuaishouRoutes = (cookie, requestConfig = getKuaishouDefaultConfig(cookie)) => {
4381
- const router = Router();
4382
- router.get("/fetch_one_work", createKuaishouValidationMiddleware("单个视频作品数据"), createKuaishouRouteHandler(getKuaishouData, "单个视频作品数据", cookie, requestConfig));
4383
- router.get("/fetch_work_comments", createKuaishouValidationMiddleware("评论数据"), createKuaishouRouteHandler(getKuaishouData, "评论数据", cookie, requestConfig));
4384
- 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));
4385
4411
  return router;
4386
4412
  };
4387
4413
 
@@ -4485,14 +4511,8 @@ const createXiaohongshuRouteHandler = (dataFetcher, methodType, cookie, requestC
4485
4511
  * @returns Express路由器
4486
4512
  */
4487
4513
  const createXiaohongshuRoutes = (cookie, requestConfig = getXiaohongshuDefaultConfig(cookie)) => {
4488
- const router = Router();
4489
- router.get("/fetch_home_feed", createXiaohongshuValidationMiddleware("首页推荐数据"), createXiaohongshuRouteHandler(getXiaohongshuData, "首页推荐数据", cookie, requestConfig));
4490
- router.get("/fetch_one_note", createXiaohongshuValidationMiddleware("单个笔记数据"), createXiaohongshuRouteHandler(getXiaohongshuData, "单个笔记数据", cookie, requestConfig));
4491
- router.get("/fetch_note_comments", createXiaohongshuValidationMiddleware("评论数据"), createXiaohongshuRouteHandler(getXiaohongshuData, "评论数据", cookie, requestConfig));
4492
- router.get("/fetch_user_profile", createXiaohongshuValidationMiddleware("用户数据"), createXiaohongshuRouteHandler(getXiaohongshuData, "用户数据", cookie, requestConfig));
4493
- router.get("/fetch_user_notes", createXiaohongshuValidationMiddleware("用户笔记数据"), createXiaohongshuRouteHandler(getXiaohongshuData, "用户笔记数据", cookie, requestConfig));
4494
- router.get("/fetch_emoji_list", createXiaohongshuValidationMiddleware("表情列表"), createXiaohongshuRouteHandler(getXiaohongshuData, "表情列表", cookie, requestConfig));
4495
- 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));
4496
4516
  return router;
4497
4517
  };
4498
4518
 
@@ -4603,6 +4623,60 @@ const createAmagiClient = (options) => {
4603
4623
  };
4604
4624
  };
4605
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
+
4606
4680
  //#endregion
4607
4681
  //#region src/types/ReturnDataType/Bilibili/Dynamic/index.ts
4608
4682
  /**
@@ -4687,6 +4761,7 @@ let DynamicType = /* @__PURE__ */ function(DynamicType$1) {
4687
4761
 
4688
4762
  //#endregion
4689
4763
  //#region src/index.ts
4764
+ const VERSION = "5.9.0";
4690
4765
  /**
4691
4766
  * @deprecated 请使用 createAmagiClient 替代
4692
4767
  */
@@ -4701,6 +4776,12 @@ function CreateAmagiApp(options = {}) {
4701
4776
  if (!(this instanceof CreateAmagiApp)) return createAmagiClient(options);
4702
4777
  return createAmagiClient(options);
4703
4778
  }
4779
+ Object.defineProperty(CreateAmagiApp, "version", {
4780
+ value: VERSION,
4781
+ writable: false,
4782
+ enumerable: true,
4783
+ configurable: false
4784
+ });
4704
4785
  CreateAmagiApp.douyin = douyinUtils;
4705
4786
  CreateAmagiApp.bilibili = bilibiliUtils;
4706
4787
  CreateAmagiApp.kuaishou = kuaishouUtils;
@@ -4716,4 +4797,4 @@ const Client = CreateApp;
4716
4797
  const amagi = Client;
4717
4798
 
4718
4799
  //#endregion
4719
- export { AdditionalType, ApiError, BilibiliArticleCardParamsSchema, BilibiliArticleInfoParamsSchema, BilibiliArticleParamsSchema, BilibiliAv2BvParamsSchema, BilibiliBangumiInfoParamsSchema, BilibiliBangumiStreamParamsSchema, BilibiliBv2AvParamsSchema, BilibiliColumnInfoParamsSchema, BilibiliCommentParamsSchema, BilibiliCommentReplyParamsSchema, 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 };
4800
+ 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 };