@ikenxuan/amagi 5.10.0 → 5.11.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.
- package/dist/default/index.cjs +1457 -1316
- package/dist/default/index.d.cts +32 -25
- package/dist/default/index.d.ts +32 -25
- package/dist/default/index.js +1456 -1316
- package/package.json +1 -1
package/dist/default/index.js
CHANGED
|
@@ -4,8 +4,8 @@ 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
|
-
import crypto from "node:crypto";
|
|
8
7
|
import zod from "zod";
|
|
8
|
+
import crypto from "node:crypto";
|
|
9
9
|
import { Xhshow } from "@ikenxuan/xhshow-ts";
|
|
10
10
|
import express from "express";
|
|
11
11
|
|
|
@@ -161,206 +161,6 @@ const logMiddleware = (pathsToLog) => {
|
|
|
161
161
|
};
|
|
162
162
|
};
|
|
163
163
|
|
|
164
|
-
//#endregion
|
|
165
|
-
//#region src/model/networks.ts
|
|
166
|
-
/**
|
|
167
|
-
* 清理User-Agent中的Edge标识,确保请求兼容性
|
|
168
|
-
* @param userAgent - 原始User-Agent字符串
|
|
169
|
-
* @returns 清理后的User-Agent字符串
|
|
170
|
-
*/
|
|
171
|
-
const cleanUserAgent = (userAgent) => {
|
|
172
|
-
return userAgent.replace(/\s+Edg\/[\d\.]+/g, "");
|
|
173
|
-
};
|
|
174
|
-
/**
|
|
175
|
-
* 执行网络请求并返回数据
|
|
176
|
-
* @param config - axios请求配置
|
|
177
|
-
* @returns 响应数据
|
|
178
|
-
*/
|
|
179
|
-
const fetchData = async (config) => {
|
|
180
|
-
try {
|
|
181
|
-
const cleanedConfig = { ...config };
|
|
182
|
-
if (cleanedConfig.headers && cleanedConfig.headers["User-Agent"]) cleanedConfig.headers["User-Agent"] = cleanUserAgent(cleanedConfig.headers["User-Agent"]);
|
|
183
|
-
return (await axios({
|
|
184
|
-
...cleanedConfig,
|
|
185
|
-
validateStatus: () => true
|
|
186
|
-
})).data;
|
|
187
|
-
} catch (error) {
|
|
188
|
-
if (error instanceof AxiosError) {
|
|
189
|
-
logger.error("网络请求失败:", error.message);
|
|
190
|
-
throw error;
|
|
191
|
-
}
|
|
192
|
-
throw error;
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
const normalizeHeaders = (headers) => {
|
|
196
|
-
if (headers && typeof headers.toJSON === "function") return headers.toJSON();
|
|
197
|
-
return headers ?? {};
|
|
198
|
-
};
|
|
199
|
-
const fetchResponse = async (config) => {
|
|
200
|
-
try {
|
|
201
|
-
const cleanedConfig = { ...config };
|
|
202
|
-
if (cleanedConfig.headers && cleanedConfig.headers["User-Agent"]) cleanedConfig.headers["User-Agent"] = cleanUserAgent(cleanedConfig.headers["User-Agent"]);
|
|
203
|
-
return await axios({
|
|
204
|
-
...cleanedConfig,
|
|
205
|
-
validateStatus: () => true
|
|
206
|
-
});
|
|
207
|
-
} catch (error) {
|
|
208
|
-
if (error instanceof AxiosError) throw error;
|
|
209
|
-
throw new Error("网络请求失败");
|
|
210
|
-
}
|
|
211
|
-
};
|
|
212
|
-
/**
|
|
213
|
-
* 获取响应头和数据
|
|
214
|
-
* @param config - axios请求配置
|
|
215
|
-
* @returns 包含headers和data的对象
|
|
216
|
-
*/
|
|
217
|
-
const getHeadersAndData = async (config) => {
|
|
218
|
-
try {
|
|
219
|
-
const response = await fetchResponse(config);
|
|
220
|
-
return {
|
|
221
|
-
headers: normalizeHeaders(response.headers),
|
|
222
|
-
data: response.data
|
|
223
|
-
};
|
|
224
|
-
} catch (error) {
|
|
225
|
-
logger.error("获取响应头和数据失败:", error);
|
|
226
|
-
return {
|
|
227
|
-
headers: {},
|
|
228
|
-
data: {}
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
};
|
|
232
|
-
|
|
233
|
-
//#endregion
|
|
234
|
-
//#region src/platform/defaultConfigs.ts
|
|
235
|
-
/**
|
|
236
|
-
* 根据User-Agent生成对应的Sec-Ch-Ua值
|
|
237
|
-
* @param userAgent - 用户代理字符串
|
|
238
|
-
* @returns 对应的Sec-Ch-Ua值
|
|
239
|
-
*/
|
|
240
|
-
const generateSecChUa = (userAgent) => {
|
|
241
|
-
const chromeMatch = userAgent.match(/Chrome\/(\d+)/);
|
|
242
|
-
const chromeVersion = chromeMatch ? chromeMatch[1] : "125";
|
|
243
|
-
return `"Not)A;Brand";v="8", "Chromium";v="${chromeVersion}", "Google Chrome";v="${chromeVersion}"`;
|
|
244
|
-
};
|
|
245
|
-
/**
|
|
246
|
-
* 抖音平台默认请求配置
|
|
247
|
-
* @param cookie - 用户Cookie
|
|
248
|
-
* @param requestConfig - 外部请求配置(优先级最高)
|
|
249
|
-
* @returns 合并后的请求配置
|
|
250
|
-
*/
|
|
251
|
-
const getDouyinDefaultConfig = (cookie, requestConfig) => {
|
|
252
|
-
let finalUserAgent = requestConfig?.headers?.["User-Agent"] ?? "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36";
|
|
253
|
-
finalUserAgent = finalUserAgent.replace(/\s+Edg\/[\d\.]+/g, "");
|
|
254
|
-
const defHeaders = {
|
|
255
|
-
Accept: "application/json, text/plain, */*",
|
|
256
|
-
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
257
|
-
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
258
|
-
Cookie: cookie ? cookie.replace(/\s+/g, "") : "",
|
|
259
|
-
Priority: "u=1, i",
|
|
260
|
-
Referer: "https://www.douyin.com/",
|
|
261
|
-
"Sec-Ch-Ua": generateSecChUa(finalUserAgent),
|
|
262
|
-
"Sec-Ch-Ua-Mobile": "?0",
|
|
263
|
-
"Sec-Ch-Ua-Platform": "\"Windows\"",
|
|
264
|
-
"Sec-Fetch-Dest": "empty",
|
|
265
|
-
"Sec-Fetch-Mode": "cors",
|
|
266
|
-
"Sec-Fetch-Site": "same-origin",
|
|
267
|
-
"User-Agent": finalUserAgent
|
|
268
|
-
};
|
|
269
|
-
return {
|
|
270
|
-
method: "GET",
|
|
271
|
-
timeout: 1e4,
|
|
272
|
-
...requestConfig,
|
|
273
|
-
headers: {
|
|
274
|
-
...defHeaders,
|
|
275
|
-
...requestConfig?.headers ?? {}
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
};
|
|
279
|
-
/**
|
|
280
|
-
* B站平台默认请求配置
|
|
281
|
-
* @param cookie - 用户Cookie
|
|
282
|
-
* @param requestConfig - 外部请求配置(优先级最高)
|
|
283
|
-
* @returns 合并后的请求配置
|
|
284
|
-
*/
|
|
285
|
-
const getBilibiliDefaultConfig = (cookie, requestConfig) => {
|
|
286
|
-
const defHeaders = {
|
|
287
|
-
Accept: "application/json, text/plain, */*",
|
|
288
|
-
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
289
|
-
"Accept-Encoding": "gzip, deflate, br",
|
|
290
|
-
Origin: "https://www.bilibili.com",
|
|
291
|
-
Referer: "https://www.bilibili.com/",
|
|
292
|
-
Priority: "u=1, i",
|
|
293
|
-
"Sec-Ch-Ua": "\"Microsoft Edge\";v=\"141\", \"Chromium\";v=\"141\", \"Not_A Brand\";v=\"24\"",
|
|
294
|
-
"Sec-Ch-Ua-Mobile": "?0",
|
|
295
|
-
"Sec-Ch-Ua-Platform": "\"Windows\"",
|
|
296
|
-
"Sec-Fetch-Dest": "empty",
|
|
297
|
-
"Sec-Fetch-Mode": "cors",
|
|
298
|
-
"Sec-Fetch-Site": "same-site",
|
|
299
|
-
Cookie: cookie ? cookie.replace(/\s+/g, "") : ""
|
|
300
|
-
};
|
|
301
|
-
return {
|
|
302
|
-
method: "GET",
|
|
303
|
-
timeout: 1e4,
|
|
304
|
-
...requestConfig,
|
|
305
|
-
headers: {
|
|
306
|
-
...defHeaders,
|
|
307
|
-
...requestConfig?.headers ?? {}
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
};
|
|
311
|
-
/**
|
|
312
|
-
* 快手平台默认请求配置
|
|
313
|
-
* @param cookie - 用户Cookie
|
|
314
|
-
* @param requestConfig - 外部请求配置(优先级最高)
|
|
315
|
-
* @returns 合并后的请求配置
|
|
316
|
-
*/
|
|
317
|
-
const getKuaishouDefaultConfig = (cookie, requestConfig) => {
|
|
318
|
-
const defHeaders = {
|
|
319
|
-
Referer: "https://www.kuaishou.com/new-reco",
|
|
320
|
-
Origin: "https://www.kuaishou.com",
|
|
321
|
-
Accept: "application/json, text/plain, */*",
|
|
322
|
-
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
323
|
-
"Content-Type": "application/json",
|
|
324
|
-
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
325
|
-
Priority: "u=0, i",
|
|
326
|
-
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0",
|
|
327
|
-
Cookie: cookie ? cookie.replace(/\s+/g, "") : ""
|
|
328
|
-
};
|
|
329
|
-
return {
|
|
330
|
-
method: "POST",
|
|
331
|
-
timeout: 1e4,
|
|
332
|
-
...requestConfig,
|
|
333
|
-
headers: {
|
|
334
|
-
...defHeaders,
|
|
335
|
-
...requestConfig?.headers ?? {}
|
|
336
|
-
}
|
|
337
|
-
};
|
|
338
|
-
};
|
|
339
|
-
/**
|
|
340
|
-
* 获取小红书默认配置
|
|
341
|
-
* @param cookie - 用户Cookie
|
|
342
|
-
* @returns 小红书请求配置
|
|
343
|
-
*/
|
|
344
|
-
const getXiaohongshuDefaultConfig = (cookie) => {
|
|
345
|
-
return { headers: {
|
|
346
|
-
accept: "application/json, text/plain, */*",
|
|
347
|
-
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
348
|
-
"cache-control": "no-cache",
|
|
349
|
-
"content-type": "application/json;charset=UTF-8",
|
|
350
|
-
pragma: "no-cache",
|
|
351
|
-
priority: "u=1, i",
|
|
352
|
-
referer: "https://www.xiaohongshu.com/",
|
|
353
|
-
"sec-ch-ua": "\"Microsoft Edge\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
|
354
|
-
"sec-ch-ua-mobile": "?0",
|
|
355
|
-
"sec-ch-ua-platform": "\"Windows\"",
|
|
356
|
-
"sec-fetch-dest": "empty",
|
|
357
|
-
"sec-fetch-mode": "cors",
|
|
358
|
-
"sec-fetch-site": "same-site",
|
|
359
|
-
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0",
|
|
360
|
-
cookie: cookie ?? ""
|
|
361
|
-
} };
|
|
362
|
-
};
|
|
363
|
-
|
|
364
164
|
//#endregion
|
|
365
165
|
//#region src/types/NetworksConfigType.ts
|
|
366
166
|
/** 未知错误 */
|
|
@@ -513,1219 +313,1499 @@ let xiaohongshuAPIErrorCode = /* @__PURE__ */ function(xiaohongshuAPIErrorCode$1
|
|
|
513
313
|
}({});
|
|
514
314
|
|
|
515
315
|
//#endregion
|
|
516
|
-
//#region src/
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
return
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
return
|
|
543
|
-
}
|
|
544
|
-
/** 指定评论的回复 */
|
|
545
|
-
指定评论的回复(data$1) {
|
|
546
|
-
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}`;
|
|
547
|
-
}
|
|
548
|
-
表情列表() {
|
|
549
|
-
return "https://api.bilibili.com/x/emote/user/panel/web?business=reply&web_location=0.0";
|
|
550
|
-
}
|
|
551
|
-
番剧明细(data$1) {
|
|
552
|
-
if (data$1.ep_id) return `https://api.bilibili.com/pgc/view/web/season?ep_id=${data$1.ep_id}`;
|
|
553
|
-
else if (data$1.season_id) return `https://api.bilibili.com/pgc/view/web/season?season_id=${data$1.season_id}`;
|
|
554
|
-
else throw new Error("拟造接口地址出错,缺少 ep_id 或 season_id 参数");
|
|
555
|
-
}
|
|
556
|
-
番剧视频流信息(data$1) {
|
|
557
|
-
return `https://api.bilibili.com/pgc/player/web/playurl?cid=${data$1.cid}&ep_id=${data$1.ep_id}`;
|
|
558
|
-
}
|
|
559
|
-
用户空间动态(data$1) {
|
|
560
|
-
return `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?host_mid=${data$1.host_mid}&dm_img_switch=0&&features=itemOpusStyle,listOnlyfans,opusBigCover,onlyfansVote,forwardListHidden,decorationCard,commentsNewVersion,onlyfansAssetsV2,ugcDelete,onlyfansQaCard`;
|
|
561
|
-
}
|
|
562
|
-
动态详情(data$1) {
|
|
563
|
-
return `https://api.bilibili.com/x/polymer/web-dynamic/v1/detail?id=${data$1.dynamic_id}&features=itemOpusStyle,opusBigCover,onlyfansVote,endFooterHidden,decorationCard,onlyfansAssetsV2,ugcDelete,onlyfansQaCard,editable,opusPrivateVisible,avatarAutoTheme`;
|
|
564
|
-
}
|
|
565
|
-
动态卡片信息(data$1) {
|
|
566
|
-
return `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=${data$1.dynamic_id}`;
|
|
567
|
-
}
|
|
568
|
-
用户名片信息(data$1) {
|
|
569
|
-
return `https://api.bilibili.com/x/web-interface/card?mid=${data$1.host_mid}&photo=true`;
|
|
570
|
-
}
|
|
571
|
-
直播间信息(data$1) {
|
|
572
|
-
return `https://api.live.bilibili.com/room/v1/Room/get_info?room_id=${data$1.room_id}`;
|
|
573
|
-
}
|
|
574
|
-
直播间初始化信息(data$1) {
|
|
575
|
-
return `https://api.live.bilibili.com/room/v1/Room/room_init?id=${data$1.room_id}`;
|
|
576
|
-
}
|
|
577
|
-
申请二维码() {
|
|
578
|
-
return "https://passport.bilibili.com/x/passport-login/web/qrcode/generate";
|
|
579
|
-
}
|
|
580
|
-
二维码状态(data$1) {
|
|
581
|
-
return `https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key=${data$1.qrcode_key}`;
|
|
582
|
-
}
|
|
583
|
-
获取UP主总播放量(data$1) {
|
|
584
|
-
return `https://api.bilibili.com/x/space/upstat?mid=${data$1.host_mid}`;
|
|
585
|
-
}
|
|
586
|
-
专栏正文内容(data$1) {
|
|
587
|
-
return `https://api.bilibili.com/x/article/view?id=${data$1.id}`;
|
|
588
|
-
}
|
|
589
|
-
专栏显示卡片信息(data$1) {
|
|
590
|
-
return `https://api.bilibili.com/x/article/cards?ids=${Array.isArray(data$1.ids) ? data$1.ids.join(",") : data$1.ids}`;
|
|
591
|
-
}
|
|
592
|
-
专栏文章基本信息(data$1) {
|
|
593
|
-
return `https://api.bilibili.com/x/article/viewinfo?id=${data$1.id}`;
|
|
594
|
-
}
|
|
595
|
-
文集基本信息(data$1) {
|
|
596
|
-
return `https://api.bilibili.com/x/article/list/web/articles?id=${data$1.id}`;
|
|
316
|
+
//#region src/validation/utils.ts
|
|
317
|
+
function smartNumber(errorMessage, minValue = 1, isInteger = false) {
|
|
318
|
+
if (isInteger) return zod.coerce.number({ error: errorMessage }).int({ error: `${errorMessage.replace("不能为空", "")}必须是整数,不能包含小数` }).min(minValue, { error: `${errorMessage.replace("不能为空", "")}必须大于等于${minValue}` });
|
|
319
|
+
else return zod.coerce.number({ error: errorMessage }).min(minValue, { error: `${errorMessage.replace("不能为空", "")}必须大于等于${minValue}` });
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* 智能正整数转换器 - 专门用于正整数类型的转换
|
|
323
|
+
* @param errorMessage - 自定义错误信息
|
|
324
|
+
* @returns Zod正整数验证器
|
|
325
|
+
*/
|
|
326
|
+
const smartPositiveInteger = (errorMessage) => {
|
|
327
|
+
return smartNumber(errorMessage, 1, true);
|
|
328
|
+
};
|
|
329
|
+
/**
|
|
330
|
+
* 从页面HTML中提取用户信息
|
|
331
|
+
* @param html - 包含用户页面HTML的字符串
|
|
332
|
+
* @returns 提取到的用户信息对象或null
|
|
333
|
+
*/
|
|
334
|
+
const extractCreatorInfoFromHtml = (html) => {
|
|
335
|
+
const match = html.match(/<script>window\.__INITIAL_STATE__=(.+)<\/script>/m);
|
|
336
|
+
if (!match) return null;
|
|
337
|
+
try {
|
|
338
|
+
const jsonStr = match[1].replace(/:undefined/g, ":null");
|
|
339
|
+
return JSON.parse(jsonStr)?.user?.userPageData ?? null;
|
|
340
|
+
} catch (error) {
|
|
341
|
+
console.error("解析用户信息失败:", error);
|
|
342
|
+
return null;
|
|
597
343
|
}
|
|
598
344
|
};
|
|
599
|
-
/** 该类下的所有方法只会返回拼接好参数后的 Url 地址,需要手动请求该地址以获取数据 */
|
|
600
|
-
const bilibiliApiUrls = new BiLiBiLiAPI();
|
|
601
345
|
|
|
602
346
|
//#endregion
|
|
603
|
-
//#region src/
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
347
|
+
//#region src/validation/bilibili.ts
|
|
348
|
+
const BilibiliVideoParamsSchema = zod.object({
|
|
349
|
+
methodType: zod.literal("单个视频作品数据", { error: "方法类型必须是\"单个视频作品数据\"" }),
|
|
350
|
+
bvid: zod.string({ error: "BVID必须是字符串" }).min(1, { error: "BVID不能为空" })
|
|
351
|
+
});
|
|
352
|
+
const BilibiliVideoDownloadParamsSchema = zod.object({
|
|
353
|
+
methodType: zod.literal("单个视频下载信息数据", { error: "方法类型必须是\"单个视频下载信息数据\"" }),
|
|
354
|
+
avid: smartNumber("AVID不能为空", 1, true),
|
|
355
|
+
cid: smartNumber("CID不能为空", 1, true)
|
|
356
|
+
});
|
|
357
|
+
const BilibiliCommentParamsSchema = zod.object({
|
|
358
|
+
methodType: zod.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
|
|
359
|
+
oid: zod.string({ error: "OID必须是字符串" }).min(1, { error: "OID不能为空" }),
|
|
360
|
+
type: smartNumber("评论类型不能为空", 1, true).refine((val) => [
|
|
361
|
+
1,
|
|
362
|
+
2,
|
|
363
|
+
4,
|
|
364
|
+
5,
|
|
365
|
+
6,
|
|
366
|
+
7,
|
|
367
|
+
8,
|
|
368
|
+
9,
|
|
369
|
+
10,
|
|
370
|
+
11,
|
|
371
|
+
12,
|
|
372
|
+
13,
|
|
373
|
+
14,
|
|
374
|
+
15,
|
|
375
|
+
16,
|
|
376
|
+
17,
|
|
377
|
+
18,
|
|
378
|
+
19,
|
|
379
|
+
20,
|
|
380
|
+
21,
|
|
381
|
+
22,
|
|
382
|
+
33
|
|
383
|
+
].includes(val), { error: "无效的评论区类型" }),
|
|
384
|
+
number: zod.coerce.number({ error: "评论数量必须是数字" }).int({ error: "评论数量必须是整数" }).positive({ error: "评论数量必须是正数" }).default(20).optional(),
|
|
385
|
+
pn: zod.coerce.number({ error: "页码必须是数字" }).int({ error: "页码必须是整数" }).positive({ error: "页码必须是正数" }).default(1).optional()
|
|
386
|
+
});
|
|
387
|
+
const BilibiliCommentReplyParamsSchema = zod.object({
|
|
388
|
+
methodType: zod.literal("指定评论的回复", { error: "方法类型必须是\"指定评论的回复\"" }),
|
|
389
|
+
oid: zod.string({ error: "OID必须是字符串" }).min(1, { error: "OID不能为空" }),
|
|
390
|
+
type: smartNumber("评论类型不能为空", 1, true).refine((val) => [
|
|
391
|
+
1,
|
|
392
|
+
2,
|
|
393
|
+
4,
|
|
394
|
+
5,
|
|
395
|
+
6,
|
|
396
|
+
7,
|
|
397
|
+
8,
|
|
398
|
+
9,
|
|
399
|
+
10,
|
|
400
|
+
11,
|
|
401
|
+
12,
|
|
402
|
+
13,
|
|
403
|
+
14,
|
|
404
|
+
15,
|
|
405
|
+
16,
|
|
406
|
+
17,
|
|
407
|
+
18,
|
|
408
|
+
19,
|
|
409
|
+
20,
|
|
410
|
+
21,
|
|
411
|
+
22,
|
|
412
|
+
33
|
|
413
|
+
].includes(val), { error: "无效的评论区类型" }),
|
|
414
|
+
root: zod.string({ error: "根评论ID必须是字符串" }).min(1, { error: "根评论ID不能为空" }),
|
|
415
|
+
number: zod.coerce.number({ error: "评论数量必须是数字" }).int({ error: "评论数量必须是整数" }).positive({ error: "评论数量必须是正数" }).default(20).optional(),
|
|
416
|
+
pn: zod.coerce.number({ error: "页码必须是数字" }).int({ error: "页码必须是整数" }).positive({ error: "页码必须是正数" }).default(1).optional()
|
|
417
|
+
});
|
|
418
|
+
const BilibiliUserParamsSchema = zod.object({
|
|
419
|
+
methodType: zod.enum([
|
|
420
|
+
"用户主页数据",
|
|
421
|
+
"用户主页动态列表数据",
|
|
422
|
+
"获取UP主总播放量"
|
|
423
|
+
], { error: "方法类型必须是指定的枚举值之一" }),
|
|
424
|
+
host_mid: smartNumber("UP主UID不能为空", 1, true)
|
|
425
|
+
});
|
|
426
|
+
const BilibiliEmojiParamsSchema = zod.object({ methodType: zod.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
|
|
427
|
+
const BilibiliBangumiInfoParamsSchema = zod.object({
|
|
428
|
+
methodType: zod.literal("番剧基本信息数据", { error: "方法类型必须是\"番剧基本信息数据\"" }),
|
|
429
|
+
ep_id: zod.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" }).optional(),
|
|
430
|
+
season_id: zod.string({ error: "番剧季度ID必须是字符串" }).optional()
|
|
431
|
+
}).refine((data$1) => data$1.ep_id ?? data$1.season_id, {
|
|
432
|
+
error: "ep_id 和 season_id 至少需要提供一个",
|
|
433
|
+
path: ["ep_id"]
|
|
434
|
+
});
|
|
435
|
+
const BilibiliBangumiStreamParamsSchema = zod.object({
|
|
436
|
+
methodType: zod.literal("番剧下载信息数据", { error: "方法类型必须是\"番剧下载信息数据\"" }),
|
|
437
|
+
cid: smartNumber("CID不能为空", 1, true),
|
|
438
|
+
ep_id: zod.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" })
|
|
439
|
+
});
|
|
440
|
+
const BilibiliDynamicParamsSchema = zod.object({
|
|
441
|
+
methodType: zod.enum(["动态详情数据", "动态卡片数据"], { error: "方法类型必须是\"动态详情数据\"或\"动态卡片数据\"" }),
|
|
442
|
+
dynamic_id: zod.string({ error: "动态ID必须是字符串" }).min(1, { error: "动态ID不能为空" })
|
|
443
|
+
});
|
|
444
|
+
const BilibiliLiveParamsSchema = zod.object({
|
|
445
|
+
methodType: zod.enum(["直播间信息", "直播间初始化信息"], { error: "方法类型必须是\"直播间信息\"或\"直播间初始化信息\"" }),
|
|
446
|
+
room_id: zod.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" })
|
|
447
|
+
});
|
|
448
|
+
const BilibiliLoginParamsSchema = zod.object({ methodType: zod.literal("登录基本信息", { error: "方法类型必须是\"登录基本信息\"" }) });
|
|
449
|
+
const BilibiliQrcodeParamsSchema = zod.object({ methodType: zod.literal("申请二维码", { error: "方法类型必须是\"申请二维码\"" }) });
|
|
450
|
+
const BilibiliQrcodeStatusParamsSchema = zod.object({
|
|
451
|
+
methodType: zod.literal("二维码状态", { error: "方法类型必须是\"二维码状态\"" }),
|
|
452
|
+
qrcode_key: zod.string({ error: "二维码key必须是字符串" }).min(1, { error: "二维码key不能为空" })
|
|
453
|
+
});
|
|
454
|
+
const BilibiliAv2BvParamsSchema = zod.object({
|
|
455
|
+
methodType: zod.literal("AV转BV", { error: "方法类型必须是\"AV转BV\"" }),
|
|
456
|
+
avid: zod.coerce.number({ error: "AVID必须是数字" }).int({ error: "AVID必须是整数" }).positive({ error: "AVID必须是正数" })
|
|
457
|
+
});
|
|
458
|
+
const BilibiliBv2AvParamsSchema = zod.object({
|
|
459
|
+
methodType: zod.literal("BV转AV", { error: "方法类型必须是\"BV转AV\"" }),
|
|
460
|
+
bvid: zod.string({ error: "BVID必须是字符串" }).min(1, { error: "BVID不能为空" })
|
|
461
|
+
});
|
|
462
|
+
const BilibiliArticleParamsSchema = zod.object({
|
|
463
|
+
methodType: zod.literal("专栏正文内容", { error: "方法类型必须是\"专栏正文内容\"" }),
|
|
464
|
+
id: zod.string({ error: "专栏ID必须是字符串" }).min(1, { error: "专栏ID不能为空" })
|
|
465
|
+
});
|
|
466
|
+
const BilibiliArticleCardParamsSchema = zod.object({
|
|
467
|
+
methodType: zod.literal("专栏显示卡片信息", { error: "方法类型必须是\"专栏显示卡片信息\"" }),
|
|
468
|
+
ids: zod.union([zod.array(zod.string({ error: "被查询的 id 列表必须是字符串数组" })).min(1, { error: "被查询的 id 列表不能为空" }), zod.string({ error: "被查询的 id 列表必须是字符串" }).min(1, { error: "被查询的 id 列表不能为空" })])
|
|
469
|
+
});
|
|
470
|
+
const BilibiliArticleInfoParamsSchema = zod.object({
|
|
471
|
+
methodType: zod.literal("专栏文章基本信息", { error: "方法类型必须是\"专栏文章基本信息\"" }),
|
|
472
|
+
id: zod.string({ error: "专栏ID必须是字符串" }).min(1, { error: "专栏ID不能为空" })
|
|
473
|
+
});
|
|
474
|
+
const BilibiliColumnInfoParamsSchema = zod.object({
|
|
475
|
+
methodType: zod.literal("文集基本信息", { error: "方法类型必须是\"文集基本信息\"" }),
|
|
476
|
+
id: zod.string({ error: "文集ID必须是字符串" }).min(1, { error: "文集ID不能为空" })
|
|
477
|
+
});
|
|
478
|
+
const BilibiliValidationSchemas = {
|
|
479
|
+
单个视频作品数据: BilibiliVideoParamsSchema,
|
|
480
|
+
单个视频下载信息数据: BilibiliVideoDownloadParamsSchema,
|
|
481
|
+
评论数据: BilibiliCommentParamsSchema,
|
|
482
|
+
指定评论的回复: BilibiliCommentReplyParamsSchema,
|
|
483
|
+
用户主页数据: BilibiliUserParamsSchema,
|
|
484
|
+
用户主页动态列表数据: BilibiliUserParamsSchema,
|
|
485
|
+
Emoji数据: BilibiliEmojiParamsSchema,
|
|
486
|
+
番剧基本信息数据: BilibiliBangumiInfoParamsSchema,
|
|
487
|
+
番剧下载信息数据: BilibiliBangumiStreamParamsSchema,
|
|
488
|
+
动态详情数据: BilibiliDynamicParamsSchema,
|
|
489
|
+
动态卡片数据: BilibiliDynamicParamsSchema,
|
|
490
|
+
直播间信息: BilibiliLiveParamsSchema,
|
|
491
|
+
直播间初始化信息: BilibiliLiveParamsSchema,
|
|
492
|
+
登录基本信息: BilibiliLoginParamsSchema,
|
|
493
|
+
申请二维码: BilibiliQrcodeParamsSchema,
|
|
494
|
+
二维码状态: BilibiliQrcodeStatusParamsSchema,
|
|
495
|
+
获取UP主总播放量: BilibiliUserParamsSchema,
|
|
496
|
+
AV转BV: BilibiliAv2BvParamsSchema,
|
|
497
|
+
BV转AV: BilibiliBv2AvParamsSchema,
|
|
498
|
+
专栏正文内容: BilibiliArticleParamsSchema,
|
|
499
|
+
专栏显示卡片信息: BilibiliArticleCardParamsSchema,
|
|
500
|
+
专栏文章基本信息: BilibiliArticleInfoParamsSchema,
|
|
501
|
+
文集基本信息: BilibiliColumnInfoParamsSchema
|
|
614
502
|
};
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
503
|
+
const BilibiliMethodRoutes = {
|
|
504
|
+
单个视频作品数据: "/fetch_one_video",
|
|
505
|
+
单个视频下载信息数据: "/fetch_video_playurl",
|
|
506
|
+
评论数据: "/fetch_work_comments",
|
|
507
|
+
指定评论的回复: "/fetch_comment_reply",
|
|
508
|
+
用户主页数据: "/fetch_user_profile",
|
|
509
|
+
用户主页动态列表数据: "/fetch_user_dynamic",
|
|
510
|
+
Emoji数据: "/fetch_emoji_list",
|
|
511
|
+
番剧基本信息数据: "/fetch_bangumi_video_info",
|
|
512
|
+
番剧下载信息数据: "/fetch_bangumi_video_playurl",
|
|
513
|
+
动态详情数据: "/fetch_dynamic_info",
|
|
514
|
+
动态卡片数据: "/fetch_dynamic_card",
|
|
515
|
+
直播间信息: "/fetch_live_room_detail",
|
|
516
|
+
直播间初始化信息: "/fetch_liveroom_def",
|
|
517
|
+
登录基本信息: "/login_basic_info",
|
|
518
|
+
申请二维码: "/new_login_qrcode",
|
|
519
|
+
二维码状态: "/check_qrcode",
|
|
520
|
+
获取UP主总播放量: "/fetch_user_full_view",
|
|
521
|
+
AV转BV: "/av_to_bv",
|
|
522
|
+
BV转AV: "/bv_to_av",
|
|
523
|
+
专栏正文内容: "/fetch_article_content",
|
|
524
|
+
专栏显示卡片信息: "/fetch_article_card",
|
|
525
|
+
专栏文章基本信息: "/fetch_article_info",
|
|
526
|
+
文集基本信息: "/fetch_column_info"
|
|
626
527
|
};
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
528
|
+
|
|
529
|
+
//#endregion
|
|
530
|
+
//#region src/validation/douyin.ts
|
|
531
|
+
const DouyinWorkParamsSchema = zod.object({
|
|
532
|
+
methodType: zod.enum([
|
|
533
|
+
"视频作品数据",
|
|
534
|
+
"图集作品数据",
|
|
535
|
+
"合辑作品数据",
|
|
536
|
+
"聚合解析"
|
|
537
|
+
], { error: "方法类型必须是指定的枚举值之一" }),
|
|
538
|
+
aweme_id: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
|
|
539
|
+
});
|
|
540
|
+
const DouyinCommentParamsSchema = zod.object({
|
|
541
|
+
methodType: zod.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
|
|
542
|
+
aweme_id: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
|
|
543
|
+
number: smartPositiveInteger("评论数量必须是正整数").optional().default(50),
|
|
544
|
+
cursor: zod.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
|
|
545
|
+
});
|
|
546
|
+
const DouyinHotWordsParamsSchema = zod.object({
|
|
547
|
+
methodType: zod.literal("热点词数据", { error: "方法类型必须是\"热点词数据\"" }),
|
|
548
|
+
query: zod.string({ error: "搜索词必须是字符串" }).min(1, { error: "搜索词不能为空" })
|
|
549
|
+
});
|
|
550
|
+
const DouyinSearchParamsSchema = zod.object({
|
|
551
|
+
methodType: zod.literal("搜索数据", { error: "方法类型必须是\"搜索数据\"" }),
|
|
552
|
+
query: zod.string({ error: "搜索词必须是字符串" }).min(1, { error: "搜索词不能为空" }),
|
|
553
|
+
type: zod.enum([
|
|
554
|
+
"综合",
|
|
555
|
+
"用户",
|
|
556
|
+
"视频"
|
|
557
|
+
], { error: "搜索类型必须是\"综合\"、\"用户\"或\"视频\"" }).optional().default("综合"),
|
|
558
|
+
number: smartPositiveInteger("搜索数量必须是正整数").optional().default(10),
|
|
559
|
+
search_id: zod.string({ error: "搜索ID必须是字符串" }).optional()
|
|
560
|
+
});
|
|
561
|
+
const DouyinCommentReplyParamsSchema = zod.object({
|
|
562
|
+
methodType: zod.literal("指定评论回复数据", { error: "方法类型必须是\"指定评论回复数据\"" }),
|
|
563
|
+
aweme_id: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
|
|
564
|
+
comment_id: zod.string({ error: "评论ID必须z串" }).min(1, { error: "评论ID不能为空" }),
|
|
565
|
+
number: smartPositiveInteger("评论数量必须是正整数").optional().default(5),
|
|
566
|
+
cursor: zod.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
|
|
567
|
+
});
|
|
568
|
+
const DouyinUserParamsSchema = zod.object({
|
|
569
|
+
methodType: zod.enum(["用户主页数据", "用户主页视频列表数据"], { error: "方法类型必须是指定的枚举值之一" }),
|
|
570
|
+
sec_uid: zod.string({ error: "用户ID必须是字符串" }).min(1, { error: "用户ID不能为空" })
|
|
571
|
+
});
|
|
572
|
+
const DouyinMusicParamsSchema = zod.object({
|
|
573
|
+
methodType: zod.literal("音乐数据", { error: "方法类型必须是\"音乐数据\"" }),
|
|
574
|
+
music_id: zod.string({ error: "音乐ID必须是字符串" }).min(1, { error: "音乐ID不能为空" })
|
|
575
|
+
});
|
|
576
|
+
const DouyinLiveRoomParamsSchema = zod.object({
|
|
577
|
+
methodType: zod.literal("直播间信息数据", { error: "方法类型必须是\"直播间信息数据\"" }),
|
|
578
|
+
web_rid: zod.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" }),
|
|
579
|
+
room_id: zod.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" })
|
|
580
|
+
});
|
|
581
|
+
const DouyinQrcodeParamsSchema = zod.object({
|
|
582
|
+
methodType: zod.literal("申请二维码数据", { error: "方法类型必须是\"申请二维码数据\"" }),
|
|
583
|
+
verify_fp: zod.string({ error: "fp指纹必须是字符串" }).min(1, { error: "fp指纹不能为空" })
|
|
584
|
+
});
|
|
585
|
+
const DouyinEmojiListParamsSchema = zod.object({ methodType: zod.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
|
|
586
|
+
const DouyinEmojiProParamsSchema = zod.object({ methodType: zod.literal("动态表情数据", { error: "方法类型必须是\"动态表情数据\"" }) });
|
|
587
|
+
const DouyinDanmakuParamsSchema = zod.object({
|
|
588
|
+
methodType: zod.literal("弹幕数据", { error: "方法类型必须是\"弹幕数据\"" }),
|
|
589
|
+
aweme_id: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
|
|
590
|
+
start_time: zod.coerce.number({ error: "开始时间必须是数字" }).int({ error: "开始时间必须是整数" }).min(0, { error: "开始时间不能小于0" }).optional(),
|
|
591
|
+
end_time: zod.coerce.number({ error: "结束时间必须是数字" }).int({ error: "结束时间必须是整数" }).min(0, { error: "结束时间不能小于0" }).optional(),
|
|
592
|
+
duration: zod.coerce.number({ error: "视频时长必须是数字" }).int({ error: "视频时长必须是整数" }).min(0, { error: "视频时长不能小于0" })
|
|
593
|
+
}).refine((data$1) => {
|
|
594
|
+
if (data$1.end_time !== void 0) return data$1.end_time <= data$1.duration;
|
|
595
|
+
return true;
|
|
596
|
+
}, {
|
|
597
|
+
error: "获取弹幕区间的结束时间不能超过视频总时长",
|
|
598
|
+
path: ["end_time"]
|
|
599
|
+
}).refine((data$1) => {
|
|
600
|
+
if (data$1.start_time !== void 0 && data$1.end_time !== void 0) return data$1.start_time < data$1.end_time;
|
|
601
|
+
return true;
|
|
602
|
+
}, {
|
|
603
|
+
error: "获取弹幕区间的开始时间必须小于结束时间",
|
|
604
|
+
path: ["start_time"]
|
|
605
|
+
});
|
|
606
|
+
const DouyinValidationSchemas = {
|
|
607
|
+
文字作品数据: DouyinWorkParamsSchema,
|
|
608
|
+
聚合解析: DouyinWorkParamsSchema,
|
|
609
|
+
视频作品数据: DouyinWorkParamsSchema,
|
|
610
|
+
图集作品数据: DouyinWorkParamsSchema,
|
|
611
|
+
合辑作品数据: DouyinWorkParamsSchema,
|
|
612
|
+
评论数据: DouyinCommentParamsSchema,
|
|
613
|
+
用户主页数据: DouyinUserParamsSchema,
|
|
614
|
+
用户主页视频列表数据: DouyinUserParamsSchema,
|
|
615
|
+
热点词数据: DouyinHotWordsParamsSchema,
|
|
616
|
+
搜索数据: DouyinSearchParamsSchema,
|
|
617
|
+
音乐数据: DouyinMusicParamsSchema,
|
|
618
|
+
直播间信息数据: DouyinLiveRoomParamsSchema,
|
|
619
|
+
申请二维码数据: DouyinQrcodeParamsSchema,
|
|
620
|
+
Emoji数据: DouyinEmojiListParamsSchema,
|
|
621
|
+
动态表情数据: DouyinEmojiProParamsSchema,
|
|
622
|
+
指定评论回复数据: DouyinCommentReplyParamsSchema,
|
|
623
|
+
弹幕数据: DouyinDanmakuParamsSchema
|
|
660
624
|
};
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
getDynamicCard: createBoundBilibiliApiMethod("动态卡片数据", cookie),
|
|
679
|
-
getLiveRoomDetail: createBoundBilibiliApiMethod("直播间信息", cookie),
|
|
680
|
-
getLiveRoomInitInfo: createBoundBilibiliApiMethod("直播间初始化信息", cookie),
|
|
681
|
-
getLoginBasicInfo: createBoundBilibiliApiMethod("登录基本信息", cookie),
|
|
682
|
-
getLoginQrcode: createBoundBilibiliApiMethod("申请二维码", cookie),
|
|
683
|
-
checkQrcodeStatus: createBoundBilibiliApiMethod("二维码状态", cookie),
|
|
684
|
-
getUserTotalPlayCount: createBoundBilibiliApiMethod("获取UP主总播放量", cookie),
|
|
685
|
-
convertAvToBv: createBoundBilibiliApiMethod("AV转BV", cookie),
|
|
686
|
-
convertBvToAv: createBoundBilibiliApiMethod("BV转AV", cookie),
|
|
687
|
-
getArticleContent: createBoundBilibiliApiMethod("专栏正文内容", cookie),
|
|
688
|
-
getArticleCard: createBoundBilibiliApiMethod("专栏显示卡片信息", cookie),
|
|
689
|
-
getArticleInfo: createBoundBilibiliApiMethod("专栏文章基本信息", cookie),
|
|
690
|
-
getColumnInfo: createBoundBilibiliApiMethod("文集基本信息", cookie)
|
|
691
|
-
};
|
|
625
|
+
const DouyinMethodRoutes = {
|
|
626
|
+
聚合解析: "/fetch_one_work",
|
|
627
|
+
文字作品数据: "/fetch_one_work",
|
|
628
|
+
视频作品数据: "/fetch_one_work",
|
|
629
|
+
图集作品数据: "/fetch_one_work",
|
|
630
|
+
合辑作品数据: "/fetch_one_work",
|
|
631
|
+
评论数据: "/fetch_work_comments",
|
|
632
|
+
用户主页数据: "/fetch_user_info",
|
|
633
|
+
用户主页视频列表数据: "/fetch_user_post_videos",
|
|
634
|
+
搜索数据: "/fetch_search_info",
|
|
635
|
+
热点词数据: "/fetch_suggest_words",
|
|
636
|
+
音乐数据: "/fetch_music_work",
|
|
637
|
+
Emoji数据: "/fetch_emoji_list",
|
|
638
|
+
动态表情数据: "/fetch_emoji_pro_list",
|
|
639
|
+
直播间信息数据: "/fetch_user_live_videos",
|
|
640
|
+
指定评论回复数据: "/fetch_video_comment_replies",
|
|
641
|
+
弹幕数据: "/fetch_work_danmaku"
|
|
692
642
|
};
|
|
693
643
|
|
|
694
644
|
//#endregion
|
|
695
|
-
//#region src/
|
|
696
|
-
const
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
"V",
|
|
710
|
-
"1",
|
|
711
|
-
"0",
|
|
712
|
-
"0",
|
|
713
|
-
"0",
|
|
714
|
-
"0",
|
|
715
|
-
"0",
|
|
716
|
-
"0",
|
|
717
|
-
"0",
|
|
718
|
-
"0",
|
|
719
|
-
"0"
|
|
720
|
-
];
|
|
721
|
-
let bvIndex = bytes.length - 1;
|
|
722
|
-
let tmp = (MAX_AID | BigInt(aid)) ^ XOR_CODE;
|
|
723
|
-
while (tmp > 0) {
|
|
724
|
-
bytes[bvIndex] = data[Number(tmp % BigInt(BASE))];
|
|
725
|
-
tmp = tmp / BASE;
|
|
726
|
-
bvIndex -= 1;
|
|
727
|
-
}
|
|
728
|
-
[bytes[3], bytes[9]] = [bytes[9], bytes[3]];
|
|
729
|
-
[bytes[4], bytes[7]] = [bytes[7], bytes[4]];
|
|
730
|
-
return bytes.join("");
|
|
645
|
+
//#region src/validation/kuaishou.ts
|
|
646
|
+
const KuaishouVideoParamsSchema = zod.object({
|
|
647
|
+
methodType: zod.literal("单个视频作品数据", { error: "方法类型必须是\"单个视频作品数据\"" }),
|
|
648
|
+
photoId: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
|
|
649
|
+
});
|
|
650
|
+
const KuaishouCommentParamsSchema = zod.object({
|
|
651
|
+
methodType: zod.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
|
|
652
|
+
photoId: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" })
|
|
653
|
+
});
|
|
654
|
+
const KuaishouEmojiParamsSchema = zod.object({ methodType: zod.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
|
|
655
|
+
const KuaishouValidationSchemas = {
|
|
656
|
+
单个视频作品数据: KuaishouVideoParamsSchema,
|
|
657
|
+
评论数据: KuaishouCommentParamsSchema,
|
|
658
|
+
Emoji数据: KuaishouEmojiParamsSchema
|
|
731
659
|
};
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
*/
|
|
737
|
-
const bv2av = (bvid) => {
|
|
738
|
-
const bvidArr = Array.from(bvid);
|
|
739
|
-
[bvidArr[3], bvidArr[9]] = [bvidArr[9], bvidArr[3]];
|
|
740
|
-
[bvidArr[4], bvidArr[7]] = [bvidArr[7], bvidArr[4]];
|
|
741
|
-
bvidArr.splice(0, 3);
|
|
742
|
-
const tmp = bvidArr.reduce((pre, bvidChar) => pre * BASE + BigInt(data.indexOf(bvidChar)), 0n);
|
|
743
|
-
return Number(tmp & MASK_CODE ^ XOR_CODE);
|
|
660
|
+
const KuaishouMethodRoutes = {
|
|
661
|
+
单个视频作品数据: "/fetch_one_work",
|
|
662
|
+
评论数据: "/fetch_work_comments",
|
|
663
|
+
Emoji数据: "/fetch_emoji_list"
|
|
744
664
|
};
|
|
745
665
|
|
|
746
666
|
//#endregion
|
|
747
|
-
//#region src/platform/
|
|
667
|
+
//#region src/platform/xiaohongshu/sign/index.ts
|
|
748
668
|
/**
|
|
749
|
-
*
|
|
669
|
+
* 小红书签名算法类
|
|
750
670
|
*/
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
*
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
*
|
|
825
|
-
* @
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
const value = params[key].toString().replace(chr_filter, "");
|
|
837
|
-
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
|
838
|
-
}).join("&");
|
|
839
|
-
return `&wts=${curr_time}&w_rid=${crypto.createHash("md5").update(query + mixin_key).digest("hex")}`;
|
|
840
|
-
};
|
|
841
|
-
/**
|
|
842
|
-
* 获取最新的 img_key 和 sub_key
|
|
843
|
-
* @param cookie - 有效的用户 Cookie 字符串
|
|
844
|
-
* @returns 返回包含 img_key 和 sub_key 的对象
|
|
845
|
-
* @throws 当网络请求失败或响应格式不正确时抛出错误
|
|
846
|
-
*/
|
|
847
|
-
const getWbiKeys = async (cookie) => {
|
|
848
|
-
const { data: { wbi_img: { img_url, sub_url } } } = (await axios("https://api.bilibili.com/x/web-interface/nav", { headers: { Cookie: cookie } })).data;
|
|
849
|
-
return {
|
|
850
|
-
img_key: img_url.slice(img_url.lastIndexOf("/") + 1, img_url.lastIndexOf(".")),
|
|
851
|
-
sub_key: sub_url.slice(sub_url.lastIndexOf("/") + 1, sub_url.lastIndexOf("."))
|
|
852
|
-
};
|
|
853
|
-
};
|
|
854
|
-
/**
|
|
855
|
-
* 对请求链接进行 WBI 签名
|
|
856
|
-
* @param BASEURL - 完整的请求地址,可以是字符串或 URL 对象
|
|
857
|
-
* @param cookie - 有效的用户 Cookie 字符串
|
|
858
|
-
* @returns 返回包含 WBI 签名的查询字符串
|
|
859
|
-
* @throws 当获取 WBI 密钥失败或 URL 解析失败时抛出错误
|
|
860
|
-
*/
|
|
861
|
-
const wbi_sign = async (BASEURL, cookie) => {
|
|
862
|
-
const web_keys = await getWbiKeys(cookie);
|
|
863
|
-
const url$1 = new URL(BASEURL);
|
|
864
|
-
const params = {};
|
|
865
|
-
for (const [key, value] of url$1.searchParams.entries()) params[key] = value;
|
|
866
|
-
return encWbi(params, web_keys.img_key, web_keys.sub_key);
|
|
671
|
+
var xiaohongshuSign = class {
|
|
672
|
+
static client = new Xhshow();
|
|
673
|
+
/**
|
|
674
|
+
* 生成GET请求的X-S签名
|
|
675
|
+
* @param path - API路径
|
|
676
|
+
* @param a1Cookie - a1 cookie值
|
|
677
|
+
* @param clientType - 客户端类型,默认为 'xhs-pc-web'
|
|
678
|
+
* @param params - 查询参数对象
|
|
679
|
+
* @returns X-S签名
|
|
680
|
+
*/
|
|
681
|
+
static generateXSGet(path$1, a1Cookie, clientType = "xhs-pc-web", params = {}) {
|
|
682
|
+
return this.client.signXsGet(path$1, a1Cookie, clientType, params);
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* 生成POST请求的X-S签名
|
|
686
|
+
* @param path - API路径
|
|
687
|
+
* @param a1Cookie - a1 cookie值
|
|
688
|
+
* @param clientType - 客户端类型,默认为 'xhs-pc-web'
|
|
689
|
+
* @param body - 请求体对象
|
|
690
|
+
* @returns X-S签名
|
|
691
|
+
*/
|
|
692
|
+
static generateXSPost(path$1, a1Cookie, clientType = "xhs-pc-web", body = {}) {
|
|
693
|
+
return this.client.signXsPost(path$1, a1Cookie, clientType, body);
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* 生成X-S签名(兼容旧接口)
|
|
697
|
+
* @param url - 请求URL
|
|
698
|
+
* @param body - 请求体
|
|
699
|
+
* @param userAgent - User-Agent(暂未使用)
|
|
700
|
+
* @param method - 请求方法,默认为 'POST'
|
|
701
|
+
* @param a1Cookie - a1 cookie值
|
|
702
|
+
* @returns X-S签名
|
|
703
|
+
*/
|
|
704
|
+
static generateXS(url$1, body, userAgent, method = "POST", a1Cookie = "") {
|
|
705
|
+
try {
|
|
706
|
+
const urlObj = new URL(url$1);
|
|
707
|
+
const path$1 = urlObj.pathname + urlObj.search;
|
|
708
|
+
if (method.toUpperCase() === "GET") {
|
|
709
|
+
const params = typeof body === "object" ? body : {};
|
|
710
|
+
return this.generateXSGet(path$1, a1Cookie, "xhs-pc-web", params);
|
|
711
|
+
} else {
|
|
712
|
+
const requestBody = typeof body === "object" ? body : {};
|
|
713
|
+
return this.generateXSPost(path$1, a1Cookie, "xhs-pc-web", requestBody);
|
|
714
|
+
}
|
|
715
|
+
} catch (error) {
|
|
716
|
+
console.error("生成X-S签名失败:", error);
|
|
717
|
+
throw new Error(`签名生成失败: ${error}`);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
/**
|
|
721
|
+
* 生成X-S-Common参数
|
|
722
|
+
* @param length - 长度
|
|
723
|
+
* @returns Base64编码的随机字符串
|
|
724
|
+
*/
|
|
725
|
+
static generateXSCommon(length = 945) {
|
|
726
|
+
return crypto.randomBytes(length).toString("base64").replace(/=+$/, "");
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* 生成X-T时间戳
|
|
730
|
+
* @returns 当前时间戳字符串
|
|
731
|
+
*/
|
|
732
|
+
static generateXT() {
|
|
733
|
+
return Date.now().toString();
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* 生成X-B3-Traceid
|
|
737
|
+
* @returns 16位随机字符串
|
|
738
|
+
*/
|
|
739
|
+
static generateXB3Traceid() {
|
|
740
|
+
return Array.from({ length: 16 }, () => "abcdef0123456789"[Math.floor(Math.random() * 16)]).join("");
|
|
741
|
+
}
|
|
742
|
+
/**
|
|
743
|
+
* 从cookie字符串中提取a1值
|
|
744
|
+
* @param cookieString - 完整的cookie字符串
|
|
745
|
+
* @returns a1 cookie值
|
|
746
|
+
*/
|
|
747
|
+
static extractA1FromCookie(cookieString) {
|
|
748
|
+
const match = cookieString.match(/a1=([^;]+)/);
|
|
749
|
+
return match ? match[1] : "";
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* 生成搜索ID
|
|
753
|
+
* @returns 搜索ID字符串
|
|
754
|
+
*/
|
|
755
|
+
static getSearchId = () => (BigInt(Date.now()) << 64n) + BigInt(Math.floor(Math.random() * 2147483646)).toString(36);
|
|
867
756
|
};
|
|
868
757
|
|
|
869
758
|
//#endregion
|
|
870
|
-
//#region src/
|
|
759
|
+
//#region src/platform/xiaohongshu/API.ts
|
|
871
760
|
/**
|
|
872
|
-
*
|
|
761
|
+
* 搜索排序类型枚举
|
|
873
762
|
*/
|
|
874
|
-
|
|
875
|
-
code;
|
|
876
|
-
platform;
|
|
763
|
+
let SearchSortType = /* @__PURE__ */ function(SearchSortType$1) {
|
|
877
764
|
/**
|
|
878
|
-
*
|
|
879
|
-
* @param message - 错误消息
|
|
880
|
-
* @param code - 错误代码
|
|
881
|
-
* @param platform - 平台名称
|
|
765
|
+
* 默认排序
|
|
882
766
|
*/
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
767
|
+
SearchSortType$1["GENERAL"] = "general";
|
|
768
|
+
/**
|
|
769
|
+
* 最受欢迎(按热度降序)
|
|
770
|
+
*/
|
|
771
|
+
SearchSortType$1["MOST_POPULAR"] = "popularity_descending";
|
|
772
|
+
/**
|
|
773
|
+
* 最新发布(按时间降序)
|
|
774
|
+
*/
|
|
775
|
+
SearchSortType$1["LATEST"] = "time_descending";
|
|
776
|
+
return SearchSortType$1;
|
|
777
|
+
}({});
|
|
890
778
|
/**
|
|
891
|
-
*
|
|
779
|
+
* 搜索笔记类型枚举
|
|
892
780
|
*/
|
|
893
|
-
|
|
894
|
-
errors;
|
|
895
|
-
requestPath;
|
|
781
|
+
let SearchNoteType = /* @__PURE__ */ function(SearchNoteType$1) {
|
|
896
782
|
/**
|
|
897
|
-
*
|
|
898
|
-
* @param message - 错误消息
|
|
899
|
-
* @param errors - 详细错误信息
|
|
900
|
-
* @param requestPath - HTTP请求路径
|
|
783
|
+
* 默认(全部类型)
|
|
901
784
|
*/
|
|
902
|
-
|
|
903
|
-
super(message);
|
|
904
|
-
this.name = "ValidationError";
|
|
905
|
-
this.errors = errors;
|
|
906
|
-
this.requestPath = requestPath;
|
|
907
|
-
}
|
|
785
|
+
SearchNoteType$1[SearchNoteType$1["ALL"] = 0] = "ALL";
|
|
908
786
|
/**
|
|
909
|
-
*
|
|
910
|
-
* @param zodError - Zod验证错误
|
|
911
|
-
* @param requestPath - HTTP请求路径
|
|
912
|
-
* @returns 验证错误实例
|
|
787
|
+
* 仅视频
|
|
913
788
|
*/
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
789
|
+
SearchNoteType$1[SearchNoteType$1["VIDEO"] = 1] = "VIDEO";
|
|
790
|
+
/**
|
|
791
|
+
* 仅图片
|
|
792
|
+
*/
|
|
793
|
+
SearchNoteType$1[SearchNoteType$1["IMAGE"] = 2] = "IMAGE";
|
|
794
|
+
return SearchNoteType$1;
|
|
795
|
+
}({});
|
|
796
|
+
/**
|
|
797
|
+
* 构建查询字符串
|
|
798
|
+
* @param params - 参数对象
|
|
799
|
+
* @returns 查询字符串
|
|
800
|
+
*/
|
|
801
|
+
const buildQueryString$1 = (params) => {
|
|
802
|
+
return Object.entries(params).filter(([_, value]) => value !== void 0 && value !== null).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join("&");
|
|
920
803
|
};
|
|
921
804
|
/**
|
|
922
|
-
*
|
|
923
|
-
* @param error - 错误对象
|
|
924
|
-
* @param requestPath - HTTP请求路径(可选)
|
|
925
|
-
* @returns 统一的错误响应格式
|
|
805
|
+
* 小红书API地址配置
|
|
926
806
|
*/
|
|
927
|
-
const
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
8,
|
|
1034
|
-
9,
|
|
1035
|
-
10,
|
|
1036
|
-
11,
|
|
1037
|
-
12,
|
|
1038
|
-
13,
|
|
1039
|
-
14,
|
|
1040
|
-
15,
|
|
1041
|
-
16,
|
|
1042
|
-
17,
|
|
1043
|
-
18,
|
|
1044
|
-
19,
|
|
1045
|
-
20,
|
|
1046
|
-
21,
|
|
1047
|
-
22,
|
|
1048
|
-
33
|
|
1049
|
-
].includes(val), { error: "无效的评论区类型" }),
|
|
1050
|
-
root: zod.string({ error: "根评论ID必须是字符串" }).min(1, { error: "根评论ID不能为空" }),
|
|
1051
|
-
number: zod.coerce.number({ error: "评论数量必须是数字" }).int({ error: "评论数量必须是整数" }).positive({ error: "评论数量必须是正数" }).default(20).optional(),
|
|
1052
|
-
pn: zod.coerce.number({ error: "页码必须是数字" }).int({ error: "页码必须是整数" }).positive({ error: "页码必须是正数" }).default(1).optional()
|
|
1053
|
-
});
|
|
1054
|
-
const BilibiliUserParamsSchema = zod.object({
|
|
1055
|
-
methodType: zod.enum([
|
|
1056
|
-
"用户主页数据",
|
|
1057
|
-
"用户主页动态列表数据",
|
|
1058
|
-
"获取UP主总播放量"
|
|
1059
|
-
], { error: "方法类型必须是指定的枚举值之一" }),
|
|
1060
|
-
host_mid: smartNumber("UP主UID不能为空", 1, true)
|
|
1061
|
-
});
|
|
1062
|
-
const BilibiliEmojiParamsSchema = zod.object({ methodType: zod.literal("Emoji数据", { error: "方法类型必须是\"Emoji数据\"" }) });
|
|
1063
|
-
const BilibiliBangumiInfoParamsSchema = zod.object({
|
|
1064
|
-
methodType: zod.literal("番剧基本信息数据", { error: "方法类型必须是\"番剧基本信息数据\"" }),
|
|
1065
|
-
ep_id: zod.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" }).optional(),
|
|
1066
|
-
season_id: zod.string({ error: "番剧季度ID必须是字符串" }).optional()
|
|
1067
|
-
}).refine((data$1) => data$1.ep_id ?? data$1.season_id, {
|
|
1068
|
-
error: "ep_id 和 season_id 至少需要提供一个",
|
|
1069
|
-
path: ["ep_id"]
|
|
1070
|
-
});
|
|
1071
|
-
const BilibiliBangumiStreamParamsSchema = zod.object({
|
|
1072
|
-
methodType: zod.literal("番剧下载信息数据", { error: "方法类型必须是\"番剧下载信息数据\"" }),
|
|
1073
|
-
cid: smartNumber("CID不能为空", 1, true),
|
|
1074
|
-
ep_id: zod.string({ error: "番剧EP ID必须是字符串" }).min(1, { error: "番剧EP ID不能为空" })
|
|
1075
|
-
});
|
|
1076
|
-
const BilibiliDynamicParamsSchema = zod.object({
|
|
1077
|
-
methodType: zod.enum(["动态详情数据", "动态卡片数据"], { error: "方法类型必须是\"动态详情数据\"或\"动态卡片数据\"" }),
|
|
1078
|
-
dynamic_id: zod.string({ error: "动态ID必须是字符串" }).min(1, { error: "动态ID不能为空" })
|
|
1079
|
-
});
|
|
1080
|
-
const BilibiliLiveParamsSchema = zod.object({
|
|
1081
|
-
methodType: zod.enum(["直播间信息", "直播间初始化信息"], { error: "方法类型必须是\"直播间信息\"或\"直播间初始化信息\"" }),
|
|
1082
|
-
room_id: zod.string({ error: "直播间ID必须是字符串" }).min(1, { error: "直播间ID不能为空" })
|
|
1083
|
-
});
|
|
1084
|
-
const BilibiliLoginParamsSchema = zod.object({ methodType: zod.literal("登录基本信息", { error: "方法类型必须是\"登录基本信息\"" }) });
|
|
1085
|
-
const BilibiliQrcodeParamsSchema = zod.object({ methodType: zod.literal("申请二维码", { error: "方法类型必须是\"申请二维码\"" }) });
|
|
1086
|
-
const BilibiliQrcodeStatusParamsSchema = zod.object({
|
|
1087
|
-
methodType: zod.literal("二维码状态", { error: "方法类型必须是\"二维码状态\"" }),
|
|
1088
|
-
qrcode_key: zod.string({ error: "二维码key必须是字符串" }).min(1, { error: "二维码key不能为空" })
|
|
1089
|
-
});
|
|
1090
|
-
const BilibiliAv2BvParamsSchema = zod.object({
|
|
1091
|
-
methodType: zod.literal("AV转BV", { error: "方法类型必须是\"AV转BV\"" }),
|
|
1092
|
-
avid: zod.coerce.number({ error: "AVID必须是数字" }).int({ error: "AVID必须是整数" }).positive({ error: "AVID必须是正数" })
|
|
1093
|
-
});
|
|
1094
|
-
const BilibiliBv2AvParamsSchema = zod.object({
|
|
1095
|
-
methodType: zod.literal("BV转AV", { error: "方法类型必须是\"BV转AV\"" }),
|
|
1096
|
-
bvid: zod.string({ error: "BVID必须是字符串" }).min(1, { error: "BVID不能为空" })
|
|
1097
|
-
});
|
|
1098
|
-
const BilibiliArticleParamsSchema = zod.object({
|
|
1099
|
-
methodType: zod.literal("专栏正文内容", { error: "方法类型必须是\"专栏正文内容\"" }),
|
|
1100
|
-
id: zod.string({ error: "专栏ID必须是字符串" }).min(1, { error: "专栏ID不能为空" })
|
|
1101
|
-
});
|
|
1102
|
-
const BilibiliArticleCardParamsSchema = zod.object({
|
|
1103
|
-
methodType: zod.literal("专栏显示卡片信息", { error: "方法类型必须是\"专栏显示卡片信息\"" }),
|
|
1104
|
-
ids: zod.union([zod.array(zod.string({ error: "被查询的 id 列表必须是字符串数组" })).min(1, { error: "被查询的 id 列表不能为空" }), zod.string({ error: "被查询的 id 列表必须是字符串" }).min(1, { error: "被查询的 id 列表不能为空" })])
|
|
1105
|
-
});
|
|
1106
|
-
const BilibiliArticleInfoParamsSchema = zod.object({
|
|
1107
|
-
methodType: zod.literal("专栏文章基本信息", { error: "方法类型必须是\"专栏文章基本信息\"" }),
|
|
1108
|
-
id: zod.string({ error: "专栏ID必须是字符串" }).min(1, { error: "专栏ID不能为空" })
|
|
1109
|
-
});
|
|
1110
|
-
const BilibiliColumnInfoParamsSchema = zod.object({
|
|
1111
|
-
methodType: zod.literal("文集基本信息", { error: "方法类型必须是\"文集基本信息\"" }),
|
|
1112
|
-
id: zod.string({ error: "文集ID必须是字符串" }).min(1, { error: "文集ID不能为空" })
|
|
1113
|
-
});
|
|
1114
|
-
const BilibiliValidationSchemas = {
|
|
1115
|
-
单个视频作品数据: BilibiliVideoParamsSchema,
|
|
1116
|
-
单个视频下载信息数据: BilibiliVideoDownloadParamsSchema,
|
|
1117
|
-
评论数据: BilibiliCommentParamsSchema,
|
|
1118
|
-
指定评论的回复: BilibiliCommentReplyParamsSchema,
|
|
1119
|
-
用户主页数据: BilibiliUserParamsSchema,
|
|
1120
|
-
用户主页动态列表数据: BilibiliUserParamsSchema,
|
|
1121
|
-
Emoji数据: BilibiliEmojiParamsSchema,
|
|
1122
|
-
番剧基本信息数据: BilibiliBangumiInfoParamsSchema,
|
|
1123
|
-
番剧下载信息数据: BilibiliBangumiStreamParamsSchema,
|
|
1124
|
-
动态详情数据: BilibiliDynamicParamsSchema,
|
|
1125
|
-
动态卡片数据: BilibiliDynamicParamsSchema,
|
|
1126
|
-
直播间信息: BilibiliLiveParamsSchema,
|
|
1127
|
-
直播间初始化信息: BilibiliLiveParamsSchema,
|
|
1128
|
-
登录基本信息: BilibiliLoginParamsSchema,
|
|
1129
|
-
申请二维码: BilibiliQrcodeParamsSchema,
|
|
1130
|
-
二维码状态: BilibiliQrcodeStatusParamsSchema,
|
|
1131
|
-
获取UP主总播放量: BilibiliUserParamsSchema,
|
|
1132
|
-
AV转BV: BilibiliAv2BvParamsSchema,
|
|
1133
|
-
BV转AV: BilibiliBv2AvParamsSchema,
|
|
1134
|
-
专栏正文内容: BilibiliArticleParamsSchema,
|
|
1135
|
-
专栏显示卡片信息: BilibiliArticleCardParamsSchema,
|
|
1136
|
-
专栏文章基本信息: BilibiliArticleInfoParamsSchema,
|
|
1137
|
-
文集基本信息: BilibiliColumnInfoParamsSchema
|
|
1138
|
-
};
|
|
1139
|
-
const BilibiliMethodRoutes = {
|
|
1140
|
-
单个视频作品数据: "/fetch_one_video",
|
|
1141
|
-
单个视频下载信息数据: "/fetch_video_playurl",
|
|
1142
|
-
评论数据: "/fetch_work_comments",
|
|
1143
|
-
指定评论的回复: "/fetch_comment_reply",
|
|
1144
|
-
用户主页数据: "/fetch_user_profile",
|
|
1145
|
-
用户主页动态列表数据: "/fetch_user_dynamic",
|
|
1146
|
-
Emoji数据: "/fetch_emoji_list",
|
|
1147
|
-
番剧基本信息数据: "/fetch_bangumi_video_info",
|
|
1148
|
-
番剧下载信息数据: "/fetch_bangumi_video_playurl",
|
|
1149
|
-
动态详情数据: "/fetch_dynamic_info",
|
|
1150
|
-
动态卡片数据: "/fetch_dynamic_card",
|
|
1151
|
-
直播间信息: "/fetch_live_room_detail",
|
|
1152
|
-
直播间初始化信息: "/fetch_liveroom_def",
|
|
1153
|
-
登录基本信息: "/login_basic_info",
|
|
1154
|
-
申请二维码: "/new_login_qrcode",
|
|
1155
|
-
二维码状态: "/check_qrcode",
|
|
1156
|
-
获取UP主总播放量: "/fetch_user_full_view",
|
|
1157
|
-
AV转BV: "/av_to_bv",
|
|
1158
|
-
BV转AV: "/bv_to_av",
|
|
1159
|
-
专栏正文内容: "/fetch_article_content",
|
|
1160
|
-
专栏显示卡片信息: "/fetch_article_card",
|
|
1161
|
-
专栏文章基本信息: "/fetch_article_info",
|
|
1162
|
-
文集基本信息: "/fetch_column_info"
|
|
807
|
+
const xiaohongshuApiUrls = {
|
|
808
|
+
首页推荐数据(data$1 = {}) {
|
|
809
|
+
return {
|
|
810
|
+
apiPath: "/api/sns/web/v1/homefeed",
|
|
811
|
+
Url: "https://edith.xiaohongshu.com/api/sns/web/v1/homefeed",
|
|
812
|
+
Body: {
|
|
813
|
+
cursor_score: data$1.cursor_score ?? "1.7599348899670024E9",
|
|
814
|
+
num: data$1.num ?? 33,
|
|
815
|
+
refresh_type: data$1.refresh_type ?? 3,
|
|
816
|
+
note_index: data$1.note_index ?? 33,
|
|
817
|
+
category: data$1.category ?? "homefeed_recommend",
|
|
818
|
+
search_key: data$1.search_key ?? "",
|
|
819
|
+
image_formats: [
|
|
820
|
+
"jpg",
|
|
821
|
+
"webp",
|
|
822
|
+
"avif"
|
|
823
|
+
]
|
|
824
|
+
}
|
|
825
|
+
};
|
|
826
|
+
},
|
|
827
|
+
单个笔记数据(data$1) {
|
|
828
|
+
return {
|
|
829
|
+
apiPath: "/api/sns/web/v1/feed",
|
|
830
|
+
Url: "https://edith.xiaohongshu.com/api/sns/web/v1/feed",
|
|
831
|
+
Body: {
|
|
832
|
+
source_note_id: data$1.note_id,
|
|
833
|
+
image_formats: [
|
|
834
|
+
"jpg",
|
|
835
|
+
"webp",
|
|
836
|
+
"avif"
|
|
837
|
+
],
|
|
838
|
+
extra: { need_body_topic: "1" },
|
|
839
|
+
xsec_source: "pc_feed",
|
|
840
|
+
xsec_token: data$1.xsec_token
|
|
841
|
+
}
|
|
842
|
+
};
|
|
843
|
+
},
|
|
844
|
+
评论数据(data$1) {
|
|
845
|
+
return {
|
|
846
|
+
apiPath: "/api/sns/web/v2/comment/page",
|
|
847
|
+
Url: `https://edith.xiaohongshu.com/api/sns/web/v2/comment/page?${buildQueryString$1({
|
|
848
|
+
note_id: data$1.note_id,
|
|
849
|
+
cursor: data$1.cursor ?? "",
|
|
850
|
+
image_formats: [
|
|
851
|
+
"jpg",
|
|
852
|
+
"webp",
|
|
853
|
+
"avif"
|
|
854
|
+
].join(","),
|
|
855
|
+
xsec_token: data$1.xsec_token
|
|
856
|
+
})}`
|
|
857
|
+
};
|
|
858
|
+
},
|
|
859
|
+
用户数据(data$1) {
|
|
860
|
+
return {
|
|
861
|
+
apiPath: "/api/sns/web/v1/user/otherinfo",
|
|
862
|
+
Url: `https://www.xiaohongshu.com/user/profile/${data$1.user_id}`
|
|
863
|
+
};
|
|
864
|
+
},
|
|
865
|
+
用户笔记数据(data$1) {
|
|
866
|
+
return {
|
|
867
|
+
apiPath: "/api/sns/web/v1/user_posted",
|
|
868
|
+
Url: `https://edith.xiaohongshu.com/api/sns/web/v1/user_posted?${buildQueryString$1({
|
|
869
|
+
user_id: data$1.user_id,
|
|
870
|
+
cursor: data$1.cursor ?? "",
|
|
871
|
+
num: data$1.num ?? 30,
|
|
872
|
+
image_formats: [
|
|
873
|
+
"jpg",
|
|
874
|
+
"webp",
|
|
875
|
+
"avif"
|
|
876
|
+
].join(","),
|
|
877
|
+
xsec_source: "pc_feed"
|
|
878
|
+
})}`
|
|
879
|
+
};
|
|
880
|
+
},
|
|
881
|
+
表情列表(data$1) {
|
|
882
|
+
return {
|
|
883
|
+
apiPath: "/api/im/redmoji/detail",
|
|
884
|
+
Url: "https://edith.xiaohongshu.com/api/im/redmoji/detail"
|
|
885
|
+
};
|
|
886
|
+
},
|
|
887
|
+
搜索笔记(data$1) {
|
|
888
|
+
return {
|
|
889
|
+
apiPath: "/api/sns/web/v1/search/notes",
|
|
890
|
+
Body: {
|
|
891
|
+
keyword: data$1.keyword,
|
|
892
|
+
page: data$1.page ?? 1,
|
|
893
|
+
page_size: data$1.page_size ?? 20,
|
|
894
|
+
sort: SearchSortType.GENERAL,
|
|
895
|
+
note_type: SearchNoteType.ALL,
|
|
896
|
+
search_id: xiaohongshuSign.getSearchId(),
|
|
897
|
+
image_formats: [
|
|
898
|
+
"jpg",
|
|
899
|
+
"webp",
|
|
900
|
+
"avif"
|
|
901
|
+
]
|
|
902
|
+
},
|
|
903
|
+
Url: "https://edith.xiaohongshu.com/api/sns/web/v1/search/notes"
|
|
904
|
+
};
|
|
905
|
+
}
|
|
906
|
+
};
|
|
907
|
+
/**
|
|
908
|
+
* 创建小红书API URLs实例
|
|
909
|
+
* @returns 小红书API URLs对象
|
|
910
|
+
*/
|
|
911
|
+
const createXiaohongshuApiUrls = () => {
|
|
912
|
+
return xiaohongshuApiUrls;
|
|
1163
913
|
};
|
|
1164
914
|
|
|
1165
915
|
//#endregion
|
|
1166
|
-
//#region src/validation/
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
})
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
cursor: zod.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
|
|
1181
|
-
});
|
|
1182
|
-
const DouyinHotWordsParamsSchema = zod.object({
|
|
1183
|
-
methodType: zod.literal("热点词数据", { error: "方法类型必须是\"热点词数据\"" }),
|
|
1184
|
-
query: zod.string({ error: "搜索词必须是字符串" }).min(1, { error: "搜索词不能为空" })
|
|
1185
|
-
});
|
|
1186
|
-
const DouyinSearchParamsSchema = zod.object({
|
|
1187
|
-
methodType: zod.literal("搜索数据", { error: "方法类型必须是\"搜索数据\"" }),
|
|
1188
|
-
query: zod.string({ error: "搜索词必须是字符串" }).min(1, { error: "搜索词不能为空" }),
|
|
1189
|
-
type: zod.enum([
|
|
1190
|
-
"综合",
|
|
1191
|
-
"用户",
|
|
1192
|
-
"视频"
|
|
1193
|
-
], { error: "搜索类型必须是\"综合\"、\"用户\"或\"视频\"" }).optional().default("综合"),
|
|
1194
|
-
number: smartPositiveInteger("搜索数量必须是正整数").optional().default(10),
|
|
1195
|
-
search_id: zod.string({ error: "搜索ID必须是字符串" }).optional()
|
|
1196
|
-
});
|
|
1197
|
-
const DouyinCommentReplyParamsSchema = zod.object({
|
|
1198
|
-
methodType: zod.literal("指定评论回复数据", { error: "方法类型必须是\"指定评论回复数据\"" }),
|
|
1199
|
-
aweme_id: zod.string({ error: "视频ID必须是字符串" }).min(1, { error: "视频ID不能为空" }),
|
|
1200
|
-
comment_id: zod.string({ error: "评论ID必须z串" }).min(1, { error: "评论ID不能为空" }),
|
|
1201
|
-
number: smartPositiveInteger("评论数量必须是正整数").optional().default(5),
|
|
1202
|
-
cursor: zod.coerce.number({ error: "游标必须是数字" }).int({ error: "游标必须是整数" }).min(0, { error: "游标不能小于0" }).default(0).optional()
|
|
916
|
+
//#region src/validation/xiaohongshu.ts
|
|
917
|
+
const SearchSortTypeValues = Object.values(SearchSortType).filter((v) => typeof v === "string");
|
|
918
|
+
const SearchNoteTypeValues = Object.values(SearchNoteType).filter((v) => typeof v === "number");
|
|
919
|
+
/**
|
|
920
|
+
* 小红书首页推荐数据参数验证模式
|
|
921
|
+
*/
|
|
922
|
+
const HomeFeedParamsSchema = zod.object({
|
|
923
|
+
methodType: zod.literal("首页推荐数据", { error: "方法类型必须是\"首页推荐数据\"" }),
|
|
924
|
+
cursor_score: zod.string({ error: "cursor_score必须是字符串" }).optional(),
|
|
925
|
+
num: zod.coerce.number({ error: "数量必须是数字" }).int({ error: "数量必须是整数" }).min(1, { error: "数量不能小于1" }).max(100, { error: "数量不能大于100" }).optional(),
|
|
926
|
+
refresh_type: zod.coerce.number({ error: "refresh_type必须是数字" }).int({ error: "refresh_type必须是整数" }).optional(),
|
|
927
|
+
note_index: zod.coerce.number({ error: "note_index必须是数字" }).int({ error: "note_index必须是整数" }).optional(),
|
|
928
|
+
category: zod.string({ error: "category必须是字符串" }).optional(),
|
|
929
|
+
search_key: zod.string({ error: "search_key必须是字符串" }).optional()
|
|
1203
930
|
});
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
931
|
+
/**
|
|
932
|
+
* 小红书单个笔记数据参数验证模式
|
|
933
|
+
*/
|
|
934
|
+
const NoteParamsSchema = zod.object({
|
|
935
|
+
methodType: zod.literal("单个笔记数据", { error: "方法类型必须是\"单个笔记数据\"" }),
|
|
936
|
+
note_id: zod.string({ error: "note_id必须是字符串" }),
|
|
937
|
+
xsec_token: zod.string({ error: "xsec_token必须是字符串" })
|
|
1207
938
|
});
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
939
|
+
/**
|
|
940
|
+
* 小红书评论数据参数验证模式
|
|
941
|
+
*/
|
|
942
|
+
const CommentParamsSchema = zod.object({
|
|
943
|
+
methodType: zod.literal("评论数据", { error: "方法类型必须是\"评论数据\"" }),
|
|
944
|
+
note_id: zod.string({ error: "note_id必须是字符串" }),
|
|
945
|
+
cursor: zod.string({ error: "cursor必须是字符串" }).optional(),
|
|
946
|
+
xsec_token: zod.string({ error: "xsec_token必须是字符串" })
|
|
1211
947
|
});
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
948
|
+
/**
|
|
949
|
+
* 小红书用户数据参数验证模式
|
|
950
|
+
*/
|
|
951
|
+
const UserParamsSchema = zod.object({
|
|
952
|
+
methodType: zod.literal("用户数据", { error: "方法类型必须是\"用户数据\"" }),
|
|
953
|
+
user_id: zod.string({ error: "user_id必须是字符串" })
|
|
1216
954
|
});
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
955
|
+
/**
|
|
956
|
+
* 小红书用户笔记数据参数验证模式
|
|
957
|
+
*/
|
|
958
|
+
const UserNoteParamsSchema = zod.object({
|
|
959
|
+
methodType: zod.literal("用户笔记数据", { error: "方法类型必须是\"用户笔记数据\"" }),
|
|
960
|
+
user_id: zod.string({ error: "user_id必须是字符串" }),
|
|
961
|
+
cursor: zod.string({ error: "cursor必须是字符串" }).optional(),
|
|
962
|
+
num: zod.coerce.number({ error: "数量必须是数字" }).int({ error: "数量必须是整数" }).min(1, { error: "数量不能小于1" }).max(100, { error: "数量不能大于100" }).optional()
|
|
1220
963
|
});
|
|
1221
|
-
const
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
}).
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
}, {
|
|
1233
|
-
error: "获取弹幕区间的结束时间不能超过视频总时长",
|
|
1234
|
-
path: ["end_time"]
|
|
1235
|
-
}).refine((data$1) => {
|
|
1236
|
-
if (data$1.start_time !== void 0 && data$1.end_time !== void 0) return data$1.start_time < data$1.end_time;
|
|
1237
|
-
return true;
|
|
1238
|
-
}, {
|
|
1239
|
-
error: "获取弹幕区间的开始时间必须小于结束时间",
|
|
1240
|
-
path: ["start_time"]
|
|
964
|
+
const EmojiListParamsSchema = zod.object({ methodType: zod.literal("表情列表", { error: "方法类型必须是\"表情列表\"" }) });
|
|
965
|
+
/**
|
|
966
|
+
* 小红书搜索笔记参数验证模式
|
|
967
|
+
*/
|
|
968
|
+
const SearchNoteParamsSchema = zod.object({
|
|
969
|
+
methodType: zod.literal("搜索笔记", { error: "方法类型必须是\"搜索笔记\"" }),
|
|
970
|
+
keyword: zod.string({ error: "keyword必须是字符串" }),
|
|
971
|
+
page: zod.coerce.number({ error: "page必须是数字" }).int({ error: "page必须是整数" }).min(1, { error: "page不能小于1" }).optional(),
|
|
972
|
+
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(),
|
|
973
|
+
sort: zod.enum(SearchSortTypeValues, { error: "排序类型不合法" }).optional(),
|
|
974
|
+
note_type: zod.coerce.number({ error: "笔记类型必须是数字" }).int({ error: "笔记类型必须是整数" }).refine((val) => SearchNoteTypeValues.includes(val), { message: "笔记类型不合法" }).optional()
|
|
1241
975
|
});
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
评论数据:
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
976
|
+
/**
|
|
977
|
+
* 小红书验证模式映射
|
|
978
|
+
*/
|
|
979
|
+
const XiaohongshuValidationSchemas = {
|
|
980
|
+
首页推荐数据: HomeFeedParamsSchema,
|
|
981
|
+
单个笔记数据: NoteParamsSchema,
|
|
982
|
+
评论数据: CommentParamsSchema,
|
|
983
|
+
用户数据: UserParamsSchema,
|
|
984
|
+
用户笔记数据: UserNoteParamsSchema,
|
|
985
|
+
表情列表: EmojiListParamsSchema,
|
|
986
|
+
搜索笔记: SearchNoteParamsSchema
|
|
987
|
+
};
|
|
988
|
+
/**
|
|
989
|
+
* 小红书方法类型
|
|
990
|
+
*/
|
|
991
|
+
const XiaohongshuMethodRoutes = {
|
|
992
|
+
首页推荐数据: "/fetch_home_feed",
|
|
993
|
+
单个笔记数据: "/fetch_one_note",
|
|
994
|
+
评论数据: "/fetch_note_comments",
|
|
995
|
+
用户数据: "/fetch_user_profile",
|
|
996
|
+
用户笔记数据: "/fetch_user_notes",
|
|
997
|
+
表情列表: "/fetch_emoji_list",
|
|
998
|
+
搜索笔记: "/fetch_search_notes"
|
|
999
|
+
};
|
|
1000
|
+
|
|
1001
|
+
//#endregion
|
|
1002
|
+
//#region src/validation/index.ts
|
|
1003
|
+
/**
|
|
1004
|
+
* 验证抖音参数
|
|
1005
|
+
* @param methodType - 抖音方法类型
|
|
1006
|
+
* @param params - 待验证的参数
|
|
1007
|
+
* @returns 验证后的参数,符合原始API期望的类型
|
|
1008
|
+
*/
|
|
1009
|
+
const validateDouyinParams = (methodType, params) => {
|
|
1010
|
+
return DouyinValidationSchemas[methodType].parse(typeof params === "object" && params !== null ? {
|
|
1011
|
+
methodType,
|
|
1012
|
+
...params
|
|
1013
|
+
} : {
|
|
1014
|
+
methodType,
|
|
1015
|
+
params
|
|
1016
|
+
});
|
|
1017
|
+
};
|
|
1018
|
+
/**
|
|
1019
|
+
* 验证哔哩哔哩参数
|
|
1020
|
+
* @param methodType - 哔哩哔哩方法类型
|
|
1021
|
+
* @param params - 待验证的参数
|
|
1022
|
+
* @returns 验证后的参数,符合原始API期望的类型
|
|
1023
|
+
*/
|
|
1024
|
+
const validateBilibiliParams = (methodType, params) => {
|
|
1025
|
+
return BilibiliValidationSchemas[methodType].parse(typeof params === "object" && params !== null ? {
|
|
1026
|
+
methodType,
|
|
1027
|
+
...params
|
|
1028
|
+
} : {
|
|
1029
|
+
methodType,
|
|
1030
|
+
params
|
|
1031
|
+
});
|
|
1032
|
+
};
|
|
1033
|
+
/**
|
|
1034
|
+
* 验证快手参数
|
|
1035
|
+
* @param methodType - 快手方法类型
|
|
1036
|
+
* @param params - 待验证的参数
|
|
1037
|
+
* @returns 验证后的参数,符合原始API期望的类型
|
|
1038
|
+
*/
|
|
1039
|
+
const validateKuaishouParams = (methodType, params) => {
|
|
1040
|
+
return KuaishouValidationSchemas[methodType].parse(typeof params === "object" && params !== null ? {
|
|
1041
|
+
methodType,
|
|
1042
|
+
...params
|
|
1043
|
+
} : {
|
|
1044
|
+
methodType,
|
|
1045
|
+
params
|
|
1046
|
+
});
|
|
1047
|
+
};
|
|
1048
|
+
/**
|
|
1049
|
+
* 验证小红书参数
|
|
1050
|
+
* @param methodType - 小红书方法类型
|
|
1051
|
+
* @param params - 待验证的参数
|
|
1052
|
+
* @returns 验证后的参数
|
|
1053
|
+
*/
|
|
1054
|
+
const validateXiaohongshuParams = (methodType, params) => {
|
|
1055
|
+
return XiaohongshuValidationSchemas[methodType].parse(typeof params === "object" && params !== null ? {
|
|
1056
|
+
methodType,
|
|
1057
|
+
...params
|
|
1058
|
+
} : {
|
|
1059
|
+
methodType,
|
|
1060
|
+
params
|
|
1061
|
+
});
|
|
1062
|
+
};
|
|
1063
|
+
/**
|
|
1064
|
+
* 创建成功响应格式
|
|
1065
|
+
* @param data - 响应数据
|
|
1066
|
+
* @param message - 响应消息(可选)
|
|
1067
|
+
* @param code - 响应状态码(可选,默认200)
|
|
1068
|
+
* @returns 格式化的成功API响应对象
|
|
1069
|
+
*/
|
|
1070
|
+
const createSuccessResponse = (data$1, message, code = 200) => {
|
|
1071
|
+
return {
|
|
1072
|
+
success: true,
|
|
1073
|
+
data: data$1,
|
|
1074
|
+
message,
|
|
1075
|
+
code,
|
|
1076
|
+
error: void 0
|
|
1077
|
+
};
|
|
1260
1078
|
};
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
指定评论回复数据: "/fetch_video_comment_replies",
|
|
1277
|
-
弹幕数据: "/fetch_work_danmaku"
|
|
1079
|
+
/**
|
|
1080
|
+
* 创建失败响应格式
|
|
1081
|
+
* @param error - 错误信息
|
|
1082
|
+
* @param message - 详细错误消息(可选)
|
|
1083
|
+
* @param code - 错误状态码(可选,默认500)
|
|
1084
|
+
* @returns 格式化的错误响应对象
|
|
1085
|
+
*/
|
|
1086
|
+
const createErrorResponse = (error, message, code = 500) => {
|
|
1087
|
+
return {
|
|
1088
|
+
success: false,
|
|
1089
|
+
error,
|
|
1090
|
+
message,
|
|
1091
|
+
code,
|
|
1092
|
+
data: void 0
|
|
1093
|
+
};
|
|
1278
1094
|
};
|
|
1279
1095
|
|
|
1280
1096
|
//#endregion
|
|
1281
|
-
//#region src/
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1097
|
+
//#region src/model/networks.ts
|
|
1098
|
+
/** 可恢复的错误代码列表 */
|
|
1099
|
+
const RECOVERABLE_ERROR_CODES = [
|
|
1100
|
+
"ECONNRESET",
|
|
1101
|
+
"ETIMEDOUT",
|
|
1102
|
+
"ECONNREFUSED",
|
|
1103
|
+
"ENOTFOUND",
|
|
1104
|
+
"ENETUNREACH",
|
|
1105
|
+
"EHOSTUNREACH",
|
|
1106
|
+
"EPIPE",
|
|
1107
|
+
"EAI_AGAIN",
|
|
1108
|
+
"ECONNABORTED"
|
|
1109
|
+
];
|
|
1110
|
+
/** 默认最大重试次数 */
|
|
1111
|
+
const DEFAULT_MAX_RETRIES = 3;
|
|
1112
|
+
/** 重试延迟基数(毫秒) */
|
|
1113
|
+
const RETRY_DELAY_BASE = 1e3;
|
|
1114
|
+
/**
|
|
1115
|
+
* 判断错误是否可恢复
|
|
1116
|
+
* @param error - Axios错误对象
|
|
1117
|
+
* @returns 是否可恢复
|
|
1118
|
+
*/
|
|
1119
|
+
const isRecoverableError = (error) => {
|
|
1120
|
+
return RECOVERABLE_ERROR_CODES.includes(error.code);
|
|
1295
1121
|
};
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1122
|
+
/**
|
|
1123
|
+
* 延迟函数
|
|
1124
|
+
* @param ms - 延迟毫秒数
|
|
1125
|
+
*/
|
|
1126
|
+
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
1127
|
+
/**
|
|
1128
|
+
* 创建网络错误响应
|
|
1129
|
+
* @param error - 错误对象
|
|
1130
|
+
* @param retries - 已重试次数
|
|
1131
|
+
* @returns 符合Result类型的错误响应
|
|
1132
|
+
*/
|
|
1133
|
+
const createNetworkErrorResult = (error, retries) => {
|
|
1134
|
+
const errorCode = error.code ?? "UNKNOWN";
|
|
1135
|
+
const message = `网络请求失败 [${errorCode}]: ${error.message} (已重试 ${retries} 次)`;
|
|
1136
|
+
return createErrorResponse({
|
|
1137
|
+
code: amagiAPIErrorCode.UNKNOWN,
|
|
1138
|
+
data: null,
|
|
1139
|
+
amagiError: {
|
|
1140
|
+
errorDescription: `${error.message} (已重试 ${retries} 次)`,
|
|
1141
|
+
requestType: error.config?.method?.toUpperCase() ?? "UNKNOWN",
|
|
1142
|
+
requestUrl: error.config?.url ?? "",
|
|
1143
|
+
responseCode: errorCode
|
|
1144
|
+
},
|
|
1145
|
+
amagiMessage: error.message
|
|
1146
|
+
}, message, 500);
|
|
1300
1147
|
};
|
|
1301
|
-
|
|
1302
|
-
//#endregion
|
|
1303
|
-
//#region src/platform/xiaohongshu/sign/index.ts
|
|
1304
1148
|
/**
|
|
1305
|
-
*
|
|
1149
|
+
* 清理User-Agent中的Edge标识,确保请求兼容性
|
|
1150
|
+
* @param userAgent - 原始User-Agent字符串
|
|
1151
|
+
* @returns 清理后的User-Agent字符串
|
|
1306
1152
|
*/
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
* @param url - 请求URL
|
|
1334
|
-
* @param body - 请求体
|
|
1335
|
-
* @param userAgent - User-Agent(暂未使用)
|
|
1336
|
-
* @param method - 请求方法,默认为 'POST'
|
|
1337
|
-
* @param a1Cookie - a1 cookie值
|
|
1338
|
-
* @returns X-S签名
|
|
1339
|
-
*/
|
|
1340
|
-
static generateXS(url$1, body, userAgent, method = "POST", a1Cookie = "") {
|
|
1341
|
-
try {
|
|
1342
|
-
const urlObj = new URL(url$1);
|
|
1343
|
-
const path$1 = urlObj.pathname + urlObj.search;
|
|
1344
|
-
if (method.toUpperCase() === "GET") {
|
|
1345
|
-
const params = typeof body === "object" ? body : {};
|
|
1346
|
-
return this.generateXSGet(path$1, a1Cookie, "xhs-pc-web", params);
|
|
1347
|
-
} else {
|
|
1348
|
-
const requestBody = typeof body === "object" ? body : {};
|
|
1349
|
-
return this.generateXSPost(path$1, a1Cookie, "xhs-pc-web", requestBody);
|
|
1153
|
+
const cleanUserAgent = (userAgent) => {
|
|
1154
|
+
return userAgent.replace(/\s+Edg\/[\d\.]+/g, "");
|
|
1155
|
+
};
|
|
1156
|
+
/**
|
|
1157
|
+
* 执行网络请求并返回数据(带自动重试)
|
|
1158
|
+
* @param config - axios请求配置
|
|
1159
|
+
* @param maxRetries - 最大重试次数,默认3次
|
|
1160
|
+
* @returns 响应数据或错误结果
|
|
1161
|
+
*/
|
|
1162
|
+
const fetchData = async (config, maxRetries = DEFAULT_MAX_RETRIES) => {
|
|
1163
|
+
const cleanedConfig = { ...config };
|
|
1164
|
+
if (cleanedConfig.headers && cleanedConfig.headers["User-Agent"]) cleanedConfig.headers["User-Agent"] = cleanUserAgent(cleanedConfig.headers["User-Agent"]);
|
|
1165
|
+
let lastError = null;
|
|
1166
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) try {
|
|
1167
|
+
return (await axios({
|
|
1168
|
+
...cleanedConfig,
|
|
1169
|
+
validateStatus: () => true
|
|
1170
|
+
})).data;
|
|
1171
|
+
} catch (error) {
|
|
1172
|
+
if (error instanceof AxiosError) {
|
|
1173
|
+
lastError = error;
|
|
1174
|
+
if (isRecoverableError(error) && attempt < maxRetries) {
|
|
1175
|
+
const delayMs = RETRY_DELAY_BASE * Math.pow(2, attempt);
|
|
1176
|
+
logger.warn(`网络请求失败 [${error.code}],${delayMs}ms 后进行第 ${attempt + 1} 次重试...`);
|
|
1177
|
+
await delay(delayMs);
|
|
1178
|
+
continue;
|
|
1350
1179
|
}
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
throw new Error(`签名生成失败: ${error}`);
|
|
1180
|
+
logger.error("网络请求失败:", error.message);
|
|
1181
|
+
return createNetworkErrorResult(error, attempt);
|
|
1354
1182
|
}
|
|
1183
|
+
throw error;
|
|
1355
1184
|
}
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
}
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1185
|
+
return createNetworkErrorResult(lastError, maxRetries);
|
|
1186
|
+
};
|
|
1187
|
+
const normalizeHeaders = (headers) => {
|
|
1188
|
+
if (headers && typeof headers.toJSON === "function") return headers.toJSON();
|
|
1189
|
+
return headers ?? {};
|
|
1190
|
+
};
|
|
1191
|
+
/**
|
|
1192
|
+
* 执行网络请求并返回完整响应(带自动重试)
|
|
1193
|
+
* @param config - axios请求配置
|
|
1194
|
+
* @param maxRetries - 最大重试次数,默认3次
|
|
1195
|
+
* @returns 完整响应或错误结果
|
|
1196
|
+
*/
|
|
1197
|
+
const fetchResponse = async (config, maxRetries = DEFAULT_MAX_RETRIES) => {
|
|
1198
|
+
const cleanedConfig = { ...config };
|
|
1199
|
+
if (cleanedConfig.headers && cleanedConfig.headers["User-Agent"]) cleanedConfig.headers["User-Agent"] = cleanUserAgent(cleanedConfig.headers["User-Agent"]);
|
|
1200
|
+
let lastError = null;
|
|
1201
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) try {
|
|
1202
|
+
return await axios({
|
|
1203
|
+
...cleanedConfig,
|
|
1204
|
+
validateStatus: () => true
|
|
1205
|
+
});
|
|
1206
|
+
} catch (error) {
|
|
1207
|
+
if (error instanceof AxiosError) {
|
|
1208
|
+
lastError = error;
|
|
1209
|
+
if (isRecoverableError(error) && attempt < maxRetries) {
|
|
1210
|
+
const delayMs = RETRY_DELAY_BASE * Math.pow(2, attempt);
|
|
1211
|
+
logger.warn(`网络请求失败 [${error.code}],${delayMs}ms 后进行第 ${attempt + 1} 次重试...`);
|
|
1212
|
+
await delay(delayMs);
|
|
1213
|
+
continue;
|
|
1214
|
+
}
|
|
1215
|
+
logger.error("网络请求失败:", error.message);
|
|
1216
|
+
return createNetworkErrorResult(error, attempt);
|
|
1217
|
+
}
|
|
1218
|
+
throw error;
|
|
1386
1219
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1220
|
+
return createNetworkErrorResult(lastError, maxRetries);
|
|
1221
|
+
};
|
|
1222
|
+
/**
|
|
1223
|
+
* 判断结果是否为网络错误响应
|
|
1224
|
+
* @param result - 请求结果
|
|
1225
|
+
* @returns 是否为ErrorResult
|
|
1226
|
+
*/
|
|
1227
|
+
const isNetworkErrorResult = (result) => {
|
|
1228
|
+
return result !== null && typeof result === "object" && "success" in result && result.success === false;
|
|
1229
|
+
};
|
|
1230
|
+
/**
|
|
1231
|
+
* 获取响应头和数据(带自动重试)
|
|
1232
|
+
* @param config - axios请求配置
|
|
1233
|
+
* @param maxRetries - 最大重试次数,默认3次
|
|
1234
|
+
* @returns 包含headers和data的对象,或错误结果
|
|
1235
|
+
*/
|
|
1236
|
+
const getHeadersAndData = async (config, maxRetries = DEFAULT_MAX_RETRIES) => {
|
|
1237
|
+
const response = await fetchResponse(config, maxRetries);
|
|
1238
|
+
if ("success" in response && response.success === false) return response;
|
|
1239
|
+
return {
|
|
1240
|
+
headers: normalizeHeaders(response.headers),
|
|
1241
|
+
data: response.data
|
|
1242
|
+
};
|
|
1392
1243
|
};
|
|
1393
1244
|
|
|
1394
1245
|
//#endregion
|
|
1395
|
-
//#region src/platform/
|
|
1246
|
+
//#region src/platform/defaultConfigs.ts
|
|
1396
1247
|
/**
|
|
1397
|
-
*
|
|
1248
|
+
* 根据User-Agent生成对应的Sec-Ch-Ua值
|
|
1249
|
+
* @param userAgent - 用户代理字符串
|
|
1250
|
+
* @returns 对应的Sec-Ch-Ua值
|
|
1398
1251
|
*/
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1252
|
+
const generateSecChUa = (userAgent) => {
|
|
1253
|
+
const chromeMatch = userAgent.match(/Chrome\/(\d+)/);
|
|
1254
|
+
const chromeVersion = chromeMatch ? chromeMatch[1] : "125";
|
|
1255
|
+
return `"Not)A;Brand";v="8", "Chromium";v="${chromeVersion}", "Google Chrome";v="${chromeVersion}"`;
|
|
1256
|
+
};
|
|
1257
|
+
/**
|
|
1258
|
+
* 抖音平台默认请求配置
|
|
1259
|
+
* @param cookie - 用户Cookie
|
|
1260
|
+
* @param requestConfig - 外部请求配置(优先级最高)
|
|
1261
|
+
* @returns 合并后的请求配置
|
|
1262
|
+
*/
|
|
1263
|
+
const getDouyinDefaultConfig = (cookie, requestConfig) => {
|
|
1264
|
+
let finalUserAgent = requestConfig?.headers?.["User-Agent"] ?? "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36";
|
|
1265
|
+
finalUserAgent = finalUserAgent.replace(/\s+Edg\/[\d\.]+/g, "");
|
|
1266
|
+
const defHeaders = {
|
|
1267
|
+
Accept: "application/json, text/plain, */*",
|
|
1268
|
+
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
1269
|
+
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
1270
|
+
Cookie: cookie ? cookie.replace(/\s+/g, "") : "",
|
|
1271
|
+
Priority: "u=1, i",
|
|
1272
|
+
Referer: "https://www.douyin.com/",
|
|
1273
|
+
"Sec-Ch-Ua": generateSecChUa(finalUserAgent),
|
|
1274
|
+
"Sec-Ch-Ua-Mobile": "?0",
|
|
1275
|
+
"Sec-Ch-Ua-Platform": "\"Windows\"",
|
|
1276
|
+
"Sec-Fetch-Dest": "empty",
|
|
1277
|
+
"Sec-Fetch-Mode": "cors",
|
|
1278
|
+
"Sec-Fetch-Site": "same-origin",
|
|
1279
|
+
"User-Agent": finalUserAgent
|
|
1280
|
+
};
|
|
1281
|
+
return {
|
|
1282
|
+
method: "GET",
|
|
1283
|
+
timeout: 1e4,
|
|
1284
|
+
...requestConfig,
|
|
1285
|
+
headers: {
|
|
1286
|
+
...defHeaders,
|
|
1287
|
+
...requestConfig?.headers ?? {}
|
|
1288
|
+
}
|
|
1289
|
+
};
|
|
1290
|
+
};
|
|
1414
1291
|
/**
|
|
1415
|
-
*
|
|
1292
|
+
* B站平台默认请求配置
|
|
1293
|
+
* @param cookie - 用户Cookie
|
|
1294
|
+
* @param requestConfig - 外部请求配置(优先级最高)
|
|
1295
|
+
* @returns 合并后的请求配置
|
|
1416
1296
|
*/
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1297
|
+
const getBilibiliDefaultConfig = (cookie, requestConfig) => {
|
|
1298
|
+
const defHeaders = {
|
|
1299
|
+
Accept: "application/json, text/plain, */*",
|
|
1300
|
+
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
1301
|
+
"Accept-Encoding": "gzip, deflate, br",
|
|
1302
|
+
Origin: "https://www.bilibili.com",
|
|
1303
|
+
Referer: "https://www.bilibili.com/",
|
|
1304
|
+
Priority: "u=1, i",
|
|
1305
|
+
"Sec-Ch-Ua": "\"Microsoft Edge\";v=\"141\", \"Chromium\";v=\"141\", \"Not_A Brand\";v=\"24\"",
|
|
1306
|
+
"Sec-Ch-Ua-Mobile": "?0",
|
|
1307
|
+
"Sec-Ch-Ua-Platform": "\"Windows\"",
|
|
1308
|
+
"Sec-Fetch-Dest": "empty",
|
|
1309
|
+
"Sec-Fetch-Mode": "cors",
|
|
1310
|
+
"Sec-Fetch-Site": "same-site",
|
|
1311
|
+
Cookie: cookie ? cookie.replace(/\s+/g, "") : ""
|
|
1312
|
+
};
|
|
1313
|
+
return {
|
|
1314
|
+
method: "GET",
|
|
1315
|
+
timeout: 1e4,
|
|
1316
|
+
...requestConfig,
|
|
1317
|
+
headers: {
|
|
1318
|
+
...defHeaders,
|
|
1319
|
+
...requestConfig?.headers ?? {}
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
};
|
|
1432
1323
|
/**
|
|
1433
|
-
*
|
|
1434
|
-
* @param
|
|
1435
|
-
* @
|
|
1324
|
+
* 快手平台默认请求配置
|
|
1325
|
+
* @param cookie - 用户Cookie
|
|
1326
|
+
* @param requestConfig - 外部请求配置(优先级最高)
|
|
1327
|
+
* @returns 合并后的请求配置
|
|
1436
1328
|
*/
|
|
1437
|
-
const
|
|
1438
|
-
|
|
1329
|
+
const getKuaishouDefaultConfig = (cookie, requestConfig) => {
|
|
1330
|
+
const defHeaders = {
|
|
1331
|
+
Referer: "https://www.kuaishou.com/new-reco",
|
|
1332
|
+
Origin: "https://www.kuaishou.com",
|
|
1333
|
+
Accept: "application/json, text/plain, */*",
|
|
1334
|
+
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
1335
|
+
"Content-Type": "application/json",
|
|
1336
|
+
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
1337
|
+
Priority: "u=0, i",
|
|
1338
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0",
|
|
1339
|
+
Cookie: cookie ? cookie.replace(/\s+/g, "") : ""
|
|
1340
|
+
};
|
|
1341
|
+
return {
|
|
1342
|
+
method: "POST",
|
|
1343
|
+
timeout: 1e4,
|
|
1344
|
+
...requestConfig,
|
|
1345
|
+
headers: {
|
|
1346
|
+
...defHeaders,
|
|
1347
|
+
...requestConfig?.headers ?? {}
|
|
1348
|
+
}
|
|
1349
|
+
};
|
|
1439
1350
|
};
|
|
1440
1351
|
/**
|
|
1441
|
-
*
|
|
1352
|
+
* 获取小红书默认配置
|
|
1353
|
+
* @param cookie - 用户Cookie
|
|
1354
|
+
* @returns 小红书请求配置
|
|
1442
1355
|
*/
|
|
1443
|
-
const
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1356
|
+
const getXiaohongshuDefaultConfig = (cookie) => {
|
|
1357
|
+
return { headers: {
|
|
1358
|
+
accept: "application/json, text/plain, */*",
|
|
1359
|
+
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
1360
|
+
"cache-control": "no-cache",
|
|
1361
|
+
"content-type": "application/json;charset=UTF-8",
|
|
1362
|
+
pragma: "no-cache",
|
|
1363
|
+
priority: "u=1, i",
|
|
1364
|
+
referer: "https://www.xiaohongshu.com/",
|
|
1365
|
+
"sec-ch-ua": "\"Microsoft Edge\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
|
1366
|
+
"sec-ch-ua-mobile": "?0",
|
|
1367
|
+
"sec-ch-ua-platform": "\"Windows\"",
|
|
1368
|
+
"sec-fetch-dest": "empty",
|
|
1369
|
+
"sec-fetch-mode": "cors",
|
|
1370
|
+
"sec-fetch-site": "same-site",
|
|
1371
|
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0",
|
|
1372
|
+
cookie: cookie ?? ""
|
|
1373
|
+
} };
|
|
1374
|
+
};
|
|
1375
|
+
|
|
1376
|
+
//#endregion
|
|
1377
|
+
//#region src/platform/bilibili/API.ts
|
|
1378
|
+
var BiLiBiLiAPI = class {
|
|
1379
|
+
登录基本信息() {
|
|
1380
|
+
return "https://api.bilibili.com/x/web-interface/nav";
|
|
1381
|
+
}
|
|
1382
|
+
视频详细信息(data$1) {
|
|
1383
|
+
return `https://api.bilibili.com/x/web-interface/view?bvid=${data$1.bvid}`;
|
|
1384
|
+
}
|
|
1385
|
+
视频流信息(data$1) {
|
|
1386
|
+
return `https://api.bilibili.com/x/player/playurl?avid=${data$1.avid}&cid=${data$1.cid}`;
|
|
1387
|
+
}
|
|
1388
|
+
/** 评论区类型,type参数详见 [评论区类型代码](https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/comment/readme.md#评论区类型代码) */
|
|
1389
|
+
评论区明细(data$1) {
|
|
1390
|
+
const params = new URLSearchParams({
|
|
1391
|
+
oid: data$1.oid.toString(),
|
|
1392
|
+
type: data$1.type.toString(),
|
|
1393
|
+
mode: (data$1.mode ?? 3).toString(),
|
|
1394
|
+
plat: "1",
|
|
1395
|
+
seek_rpid: "",
|
|
1396
|
+
web_location: "1315875"
|
|
1397
|
+
});
|
|
1398
|
+
if (data$1.pagination_str) params.append("pagination_str", JSON.stringify({ offset: data$1.pagination_str }));
|
|
1399
|
+
else params.append("pagination_str", JSON.stringify({ offset: "" }));
|
|
1400
|
+
return `https://api.bilibili.com/x/v2/reply/wbi/main?${params.toString()}`;
|
|
1401
|
+
}
|
|
1402
|
+
评论区状态(data$1) {
|
|
1403
|
+
return `https://api.bilibili.com/x/v2/reply/subject/description?type=${data$1.type}&oid=${data$1.oid}`;
|
|
1404
|
+
}
|
|
1405
|
+
/** 指定评论的回复 */
|
|
1406
|
+
指定评论的回复(data$1) {
|
|
1407
|
+
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}`;
|
|
1408
|
+
}
|
|
1409
|
+
表情列表() {
|
|
1410
|
+
return "https://api.bilibili.com/x/emote/user/panel/web?business=reply&web_location=0.0";
|
|
1411
|
+
}
|
|
1412
|
+
番剧明细(data$1) {
|
|
1413
|
+
if (data$1.ep_id) return `https://api.bilibili.com/pgc/view/web/season?ep_id=${data$1.ep_id}`;
|
|
1414
|
+
else if (data$1.season_id) return `https://api.bilibili.com/pgc/view/web/season?season_id=${data$1.season_id}`;
|
|
1415
|
+
else throw new Error("拟造接口地址出错,缺少 ep_id 或 season_id 参数");
|
|
1416
|
+
}
|
|
1417
|
+
番剧视频流信息(data$1) {
|
|
1418
|
+
return `https://api.bilibili.com/pgc/player/web/playurl?cid=${data$1.cid}&ep_id=${data$1.ep_id}`;
|
|
1419
|
+
}
|
|
1420
|
+
用户空间动态(data$1) {
|
|
1421
|
+
return `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?host_mid=${data$1.host_mid}&dm_img_switch=0&&features=itemOpusStyle,listOnlyfans,opusBigCover,onlyfansVote,forwardListHidden,decorationCard,commentsNewVersion,onlyfansAssetsV2,ugcDelete,onlyfansQaCard`;
|
|
1422
|
+
}
|
|
1423
|
+
动态详情(data$1) {
|
|
1424
|
+
return `https://api.bilibili.com/x/polymer/web-dynamic/v1/detail?id=${data$1.dynamic_id}&features=itemOpusStyle,opusBigCover,onlyfansVote,endFooterHidden,decorationCard,onlyfansAssetsV2,ugcDelete,onlyfansQaCard,editable,opusPrivateVisible,avatarAutoTheme`;
|
|
1425
|
+
}
|
|
1426
|
+
动态卡片信息(data$1) {
|
|
1427
|
+
return `https://api.vc.bilibili.com/dynamic_svr/v1/dynamic_svr/get_dynamic_detail?dynamic_id=${data$1.dynamic_id}`;
|
|
1428
|
+
}
|
|
1429
|
+
用户名片信息(data$1) {
|
|
1430
|
+
return `https://api.bilibili.com/x/web-interface/card?mid=${data$1.host_mid}&photo=true`;
|
|
1431
|
+
}
|
|
1432
|
+
直播间信息(data$1) {
|
|
1433
|
+
return `https://api.live.bilibili.com/room/v1/Room/get_info?room_id=${data$1.room_id}`;
|
|
1434
|
+
}
|
|
1435
|
+
直播间初始化信息(data$1) {
|
|
1436
|
+
return `https://api.live.bilibili.com/room/v1/Room/room_init?id=${data$1.room_id}`;
|
|
1437
|
+
}
|
|
1438
|
+
申请二维码() {
|
|
1439
|
+
return "https://passport.bilibili.com/x/passport-login/web/qrcode/generate";
|
|
1440
|
+
}
|
|
1441
|
+
二维码状态(data$1) {
|
|
1442
|
+
return `https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key=${data$1.qrcode_key}`;
|
|
1443
|
+
}
|
|
1444
|
+
获取UP主总播放量(data$1) {
|
|
1445
|
+
return `https://api.bilibili.com/x/space/upstat?mid=${data$1.host_mid}`;
|
|
1446
|
+
}
|
|
1447
|
+
专栏正文内容(data$1) {
|
|
1448
|
+
return `https://api.bilibili.com/x/article/view?id=${data$1.id}`;
|
|
1449
|
+
}
|
|
1450
|
+
专栏显示卡片信息(data$1) {
|
|
1451
|
+
return `https://api.bilibili.com/x/article/cards?ids=${Array.isArray(data$1.ids) ? data$1.ids.join(",") : data$1.ids}`;
|
|
1452
|
+
}
|
|
1453
|
+
专栏文章基本信息(data$1) {
|
|
1454
|
+
return `https://api.bilibili.com/x/article/viewinfo?id=${data$1.id}`;
|
|
1455
|
+
}
|
|
1456
|
+
文集基本信息(data$1) {
|
|
1457
|
+
return `https://api.bilibili.com/x/article/list/web/articles?id=${data$1.id}`;
|
|
1541
1458
|
}
|
|
1542
1459
|
};
|
|
1460
|
+
/** 该类下的所有方法只会返回拼接好参数后的 Url 地址,需要手动请求该地址以获取数据 */
|
|
1461
|
+
const bilibiliApiUrls = new BiLiBiLiAPI();
|
|
1462
|
+
|
|
1463
|
+
//#endregion
|
|
1464
|
+
//#region src/platform/bilibili/BilibiliApi.ts
|
|
1543
1465
|
/**
|
|
1544
|
-
*
|
|
1545
|
-
* @
|
|
1466
|
+
* 创建B站API方法的通用工厂函数
|
|
1467
|
+
* @template T - B站方法类型键名
|
|
1468
|
+
* @param methodType - 方法类型
|
|
1469
|
+
* @returns 返回配置好的API方法
|
|
1546
1470
|
*/
|
|
1547
|
-
const
|
|
1548
|
-
return
|
|
1471
|
+
const createBilibiliApiMethod = (methodType) => {
|
|
1472
|
+
return async (options, cookie) => {
|
|
1473
|
+
return await getBilibiliData(methodType, options, cookie);
|
|
1474
|
+
};
|
|
1549
1475
|
};
|
|
1550
|
-
|
|
1551
|
-
//#endregion
|
|
1552
|
-
//#region src/validation/xiaohongshu.ts
|
|
1553
|
-
const SearchSortTypeValues = Object.values(SearchSortType).filter((v) => typeof v === "string");
|
|
1554
|
-
const SearchNoteTypeValues = Object.values(SearchNoteType).filter((v) => typeof v === "number");
|
|
1555
1476
|
/**
|
|
1556
|
-
*
|
|
1477
|
+
* 创建绑定cookie的B站API方法工厂函数
|
|
1478
|
+
* @template T - B站方法类型键名
|
|
1479
|
+
* @param methodType - 方法类型
|
|
1480
|
+
* @param cookie - 绑定的cookie
|
|
1481
|
+
* @returns 返回绑定了cookie的API方法
|
|
1557
1482
|
*/
|
|
1558
|
-
const
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
note_index: zod.coerce.number({ error: "note_index必须是数字" }).int({ error: "note_index必须是整数" }).optional(),
|
|
1564
|
-
category: zod.string({ error: "category必须是字符串" }).optional(),
|
|
1565
|
-
search_key: zod.string({ error: "search_key必须是字符串" }).optional()
|
|
1566
|
-
});
|
|
1483
|
+
const createBoundBilibiliApiMethod = (methodType, cookie) => {
|
|
1484
|
+
return async (options) => {
|
|
1485
|
+
return await getBilibiliData(methodType, options, cookie);
|
|
1486
|
+
};
|
|
1487
|
+
};
|
|
1567
1488
|
/**
|
|
1568
|
-
*
|
|
1489
|
+
* B站相关 API 的命名空间。
|
|
1490
|
+
*
|
|
1491
|
+
* 部分接口可能不需要 Cookie 但建议传递有效的用户 Cookie,以获取更多数据。
|
|
1492
|
+
*
|
|
1493
|
+
* 提供了一系列方法,用于与B站相关的 API 进行交互。
|
|
1494
|
+
*
|
|
1495
|
+
* 每个方法都接受参数和 Cookie,返回 Promise,解析为统一格式的API响应。
|
|
1569
1496
|
*/
|
|
1570
|
-
const
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1497
|
+
const bilibili = {
|
|
1498
|
+
getVideoInfo: createBilibiliApiMethod("单个视频作品数据"),
|
|
1499
|
+
getVideoStream: createBilibiliApiMethod("单个视频下载信息数据"),
|
|
1500
|
+
getComments: createBilibiliApiMethod("评论数据"),
|
|
1501
|
+
getCommentReply: createBilibiliApiMethod("指定评论的回复"),
|
|
1502
|
+
getUserProfile: createBilibiliApiMethod("用户主页数据"),
|
|
1503
|
+
getUserDynamic: createBilibiliApiMethod("用户主页动态列表数据"),
|
|
1504
|
+
getEmojiList: createBilibiliApiMethod("Emoji数据"),
|
|
1505
|
+
getBangumiInfo: createBilibiliApiMethod("番剧基本信息数据"),
|
|
1506
|
+
getBangumiStream: createBilibiliApiMethod("番剧下载信息数据"),
|
|
1507
|
+
getDynamicInfo: createBilibiliApiMethod("动态详情数据"),
|
|
1508
|
+
getDynamicCard: createBilibiliApiMethod("动态卡片数据"),
|
|
1509
|
+
getLiveRoomDetail: createBilibiliApiMethod("直播间信息"),
|
|
1510
|
+
getLiveRoomInitInfo: createBilibiliApiMethod("直播间初始化信息"),
|
|
1511
|
+
getLoginBasicInfo: createBilibiliApiMethod("登录基本信息"),
|
|
1512
|
+
getLoginQrcode: createBilibiliApiMethod("申请二维码"),
|
|
1513
|
+
checkQrcodeStatus: createBilibiliApiMethod("二维码状态"),
|
|
1514
|
+
getUserTotalPlayCount: createBilibiliApiMethod("获取UP主总播放量"),
|
|
1515
|
+
convertAvToBv: createBilibiliApiMethod("AV转BV"),
|
|
1516
|
+
convertBvToAv: createBilibiliApiMethod("BV转AV"),
|
|
1517
|
+
getArticleContent: createBilibiliApiMethod("专栏正文内容"),
|
|
1518
|
+
getArticleCard: createBilibiliApiMethod("专栏显示卡片信息"),
|
|
1519
|
+
getArticleInfo: createBilibiliApiMethod("专栏文章基本信息"),
|
|
1520
|
+
getColumnInfo: createBilibiliApiMethod("文集基本信息")
|
|
1521
|
+
};
|
|
1575
1522
|
/**
|
|
1576
|
-
*
|
|
1523
|
+
* 创建绑定了cookie的B站API对象
|
|
1524
|
+
* @param cookie - 要绑定的cookie(可选)
|
|
1525
|
+
* @returns 绑定了cookie的B站API对象,调用时不需要再传递cookie
|
|
1577
1526
|
*/
|
|
1578
|
-
const
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1527
|
+
const createBoundBilibiliApi = (cookie, requestConfig) => {
|
|
1528
|
+
return {
|
|
1529
|
+
getVideoInfo: createBoundBilibiliApiMethod("单个视频作品数据", cookie),
|
|
1530
|
+
getVideoStream: createBoundBilibiliApiMethod("单个视频下载信息数据", cookie),
|
|
1531
|
+
getComments: createBoundBilibiliApiMethod("评论数据", cookie),
|
|
1532
|
+
getCommentReply: createBoundBilibiliApiMethod("指定评论的回复", cookie),
|
|
1533
|
+
getUserProfile: createBoundBilibiliApiMethod("用户主页数据", cookie),
|
|
1534
|
+
getUserDynamic: createBoundBilibiliApiMethod("用户主页动态列表数据", cookie),
|
|
1535
|
+
getEmojiList: createBoundBilibiliApiMethod("Emoji数据", cookie),
|
|
1536
|
+
getBangumiInfo: createBoundBilibiliApiMethod("番剧基本信息数据", cookie),
|
|
1537
|
+
getBangumiStream: createBoundBilibiliApiMethod("番剧下载信息数据", cookie),
|
|
1538
|
+
getDynamicInfo: createBoundBilibiliApiMethod("动态详情数据", cookie),
|
|
1539
|
+
getDynamicCard: createBoundBilibiliApiMethod("动态卡片数据", cookie),
|
|
1540
|
+
getLiveRoomDetail: createBoundBilibiliApiMethod("直播间信息", cookie),
|
|
1541
|
+
getLiveRoomInitInfo: createBoundBilibiliApiMethod("直播间初始化信息", cookie),
|
|
1542
|
+
getLoginBasicInfo: createBoundBilibiliApiMethod("登录基本信息", cookie),
|
|
1543
|
+
getLoginQrcode: createBoundBilibiliApiMethod("申请二维码", cookie),
|
|
1544
|
+
checkQrcodeStatus: createBoundBilibiliApiMethod("二维码状态", cookie),
|
|
1545
|
+
getUserTotalPlayCount: createBoundBilibiliApiMethod("获取UP主总播放量", cookie),
|
|
1546
|
+
convertAvToBv: createBoundBilibiliApiMethod("AV转BV", cookie),
|
|
1547
|
+
convertBvToAv: createBoundBilibiliApiMethod("BV转AV", cookie),
|
|
1548
|
+
getArticleContent: createBoundBilibiliApiMethod("专栏正文内容", cookie),
|
|
1549
|
+
getArticleCard: createBoundBilibiliApiMethod("专栏显示卡片信息", cookie),
|
|
1550
|
+
getArticleInfo: createBoundBilibiliApiMethod("专栏文章基本信息", cookie),
|
|
1551
|
+
getColumnInfo: createBoundBilibiliApiMethod("文集基本信息", cookie)
|
|
1552
|
+
};
|
|
1553
|
+
};
|
|
1554
|
+
|
|
1555
|
+
//#endregion
|
|
1556
|
+
//#region src/platform/bilibili/sign/bv2av.ts
|
|
1557
|
+
const XOR_CODE = 23442827791579n;
|
|
1558
|
+
const MASK_CODE = 2251799813685247n;
|
|
1559
|
+
const MAX_AID = 1n << 51n;
|
|
1560
|
+
const BASE = 58n;
|
|
1561
|
+
const data = "FcwAPNKTMug3GV5Lj7EJnHpWsx4tb8haYeviqBz6rkCy12mUSDQX9RdoZf";
|
|
1584
1562
|
/**
|
|
1585
|
-
*
|
|
1563
|
+
* av号转bv号
|
|
1564
|
+
* @param aid av号
|
|
1565
|
+
* @returns
|
|
1586
1566
|
*/
|
|
1587
|
-
const
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1567
|
+
const av2bv = (aid) => {
|
|
1568
|
+
const bytes = [
|
|
1569
|
+
"B",
|
|
1570
|
+
"V",
|
|
1571
|
+
"1",
|
|
1572
|
+
"0",
|
|
1573
|
+
"0",
|
|
1574
|
+
"0",
|
|
1575
|
+
"0",
|
|
1576
|
+
"0",
|
|
1577
|
+
"0",
|
|
1578
|
+
"0",
|
|
1579
|
+
"0",
|
|
1580
|
+
"0"
|
|
1581
|
+
];
|
|
1582
|
+
let bvIndex = bytes.length - 1;
|
|
1583
|
+
let tmp = (MAX_AID | BigInt(aid)) ^ XOR_CODE;
|
|
1584
|
+
while (tmp > 0) {
|
|
1585
|
+
bytes[bvIndex] = data[Number(tmp % BigInt(BASE))];
|
|
1586
|
+
tmp = tmp / BASE;
|
|
1587
|
+
bvIndex -= 1;
|
|
1588
|
+
}
|
|
1589
|
+
[bytes[3], bytes[9]] = [bytes[9], bytes[3]];
|
|
1590
|
+
[bytes[4], bytes[7]] = [bytes[7], bytes[4]];
|
|
1591
|
+
return bytes.join("");
|
|
1592
|
+
};
|
|
1593
|
+
/**
|
|
1594
|
+
* bv号转av号
|
|
1595
|
+
* @param bvid bv号
|
|
1596
|
+
* @returns
|
|
1597
|
+
*/
|
|
1598
|
+
const bv2av = (bvid) => {
|
|
1599
|
+
const bvidArr = Array.from(bvid);
|
|
1600
|
+
[bvidArr[3], bvidArr[9]] = [bvidArr[9], bvidArr[3]];
|
|
1601
|
+
[bvidArr[4], bvidArr[7]] = [bvidArr[7], bvidArr[4]];
|
|
1602
|
+
bvidArr.splice(0, 3);
|
|
1603
|
+
const tmp = bvidArr.reduce((pre, bvidChar) => pre * BASE + BigInt(data.indexOf(bvidChar)), 0n);
|
|
1604
|
+
return Number(tmp & MASK_CODE ^ XOR_CODE);
|
|
1605
|
+
};
|
|
1606
|
+
|
|
1607
|
+
//#endregion
|
|
1608
|
+
//#region src/platform/bilibili/sign/wbi.ts
|
|
1609
|
+
/**
|
|
1610
|
+
* 混合密钥编码表,用于对 imgKey 和 subKey 进行字符顺序打乱编码
|
|
1611
|
+
*/
|
|
1612
|
+
const mixinKeyEncTab = [
|
|
1613
|
+
46,
|
|
1614
|
+
47,
|
|
1615
|
+
18,
|
|
1616
|
+
2,
|
|
1617
|
+
53,
|
|
1618
|
+
8,
|
|
1619
|
+
23,
|
|
1620
|
+
32,
|
|
1621
|
+
15,
|
|
1622
|
+
50,
|
|
1623
|
+
10,
|
|
1624
|
+
31,
|
|
1625
|
+
58,
|
|
1626
|
+
3,
|
|
1627
|
+
45,
|
|
1628
|
+
35,
|
|
1629
|
+
27,
|
|
1630
|
+
43,
|
|
1631
|
+
5,
|
|
1632
|
+
49,
|
|
1633
|
+
33,
|
|
1634
|
+
9,
|
|
1635
|
+
42,
|
|
1636
|
+
19,
|
|
1637
|
+
29,
|
|
1638
|
+
28,
|
|
1639
|
+
14,
|
|
1640
|
+
39,
|
|
1641
|
+
12,
|
|
1642
|
+
38,
|
|
1643
|
+
41,
|
|
1644
|
+
13,
|
|
1645
|
+
37,
|
|
1646
|
+
48,
|
|
1647
|
+
7,
|
|
1648
|
+
16,
|
|
1649
|
+
24,
|
|
1650
|
+
55,
|
|
1651
|
+
40,
|
|
1652
|
+
61,
|
|
1653
|
+
26,
|
|
1654
|
+
17,
|
|
1655
|
+
0,
|
|
1656
|
+
1,
|
|
1657
|
+
60,
|
|
1658
|
+
51,
|
|
1659
|
+
30,
|
|
1660
|
+
4,
|
|
1661
|
+
22,
|
|
1662
|
+
25,
|
|
1663
|
+
54,
|
|
1664
|
+
21,
|
|
1665
|
+
56,
|
|
1666
|
+
59,
|
|
1667
|
+
6,
|
|
1668
|
+
63,
|
|
1669
|
+
57,
|
|
1670
|
+
62,
|
|
1671
|
+
11,
|
|
1672
|
+
36,
|
|
1673
|
+
20,
|
|
1674
|
+
34,
|
|
1675
|
+
44,
|
|
1676
|
+
52
|
|
1677
|
+
];
|
|
1591
1678
|
/**
|
|
1592
|
-
*
|
|
1679
|
+
* 对 imgKey 和 subKey 进行字符顺序打乱编码
|
|
1680
|
+
* @param orig - 原始字符串数组,通常是 img_key + sub_key 的字符数组
|
|
1681
|
+
* @returns 返回经过编码表打乱后的32位字符串
|
|
1593
1682
|
*/
|
|
1594
|
-
const
|
|
1595
|
-
methodType: zod.literal("用户笔记数据", { error: "方法类型必须是\"用户笔记数据\"" }),
|
|
1596
|
-
user_id: zod.string({ error: "user_id必须是字符串" }),
|
|
1597
|
-
cursor: zod.string({ error: "cursor必须是字符串" }).optional(),
|
|
1598
|
-
num: zod.coerce.number({ error: "数量必须是数字" }).int({ error: "数量必须是整数" }).min(1, { error: "数量不能小于1" }).max(100, { error: "数量不能大于100" }).optional()
|
|
1599
|
-
});
|
|
1600
|
-
const EmojiListParamsSchema = zod.object({ methodType: zod.literal("表情列表", { error: "方法类型必须是\"表情列表\"" }) });
|
|
1683
|
+
const getMixinKey = (orig) => mixinKeyEncTab.map((n) => orig[n]).join("").slice(0, 32);
|
|
1601
1684
|
/**
|
|
1602
|
-
*
|
|
1685
|
+
* 为请求参数进行 WBI 签名
|
|
1686
|
+
* @param params - 请求参数对象,键值对形式
|
|
1687
|
+
* @param img_key - 图片密钥
|
|
1688
|
+
* @param sub_key - 子密钥
|
|
1689
|
+
* @returns 返回包含时间戳和签名的查询字符串
|
|
1603
1690
|
*/
|
|
1604
|
-
const
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
})
|
|
1691
|
+
const encWbi = (params, img_key, sub_key) => {
|
|
1692
|
+
const mixin_key = getMixinKey(img_key + sub_key);
|
|
1693
|
+
const curr_time = Math.round(Date.now() / 1e3);
|
|
1694
|
+
const chr_filter = /[!'()*]/g;
|
|
1695
|
+
Object.assign(params, { wts: curr_time });
|
|
1696
|
+
const query = Object.keys(params).sort().map((key) => {
|
|
1697
|
+
const value = params[key].toString().replace(chr_filter, "");
|
|
1698
|
+
return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
|
1699
|
+
}).join("&");
|
|
1700
|
+
return `&wts=${curr_time}&w_rid=${crypto.createHash("md5").update(query + mixin_key).digest("hex")}`;
|
|
1701
|
+
};
|
|
1612
1702
|
/**
|
|
1613
|
-
*
|
|
1703
|
+
* 获取最新的 img_key 和 sub_key
|
|
1704
|
+
* @param cookie - 有效的用户 Cookie 字符串
|
|
1705
|
+
* @returns 返回包含 img_key 和 sub_key 的对象
|
|
1706
|
+
* @throws 当网络请求失败或响应格式不正确时抛出错误
|
|
1614
1707
|
*/
|
|
1615
|
-
const
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
表情列表: EmojiListParamsSchema,
|
|
1622
|
-
搜索笔记: SearchNoteParamsSchema
|
|
1708
|
+
const getWbiKeys = async (cookie) => {
|
|
1709
|
+
const { data: { wbi_img: { img_url, sub_url } } } = (await axios("https://api.bilibili.com/x/web-interface/nav", { headers: { Cookie: cookie } })).data;
|
|
1710
|
+
return {
|
|
1711
|
+
img_key: img_url.slice(img_url.lastIndexOf("/") + 1, img_url.lastIndexOf(".")),
|
|
1712
|
+
sub_key: sub_url.slice(sub_url.lastIndexOf("/") + 1, sub_url.lastIndexOf("."))
|
|
1713
|
+
};
|
|
1623
1714
|
};
|
|
1624
1715
|
/**
|
|
1625
|
-
*
|
|
1716
|
+
* 对请求链接进行 WBI 签名
|
|
1717
|
+
* @param BASEURL - 完整的请求地址,可以是字符串或 URL 对象
|
|
1718
|
+
* @param cookie - 有效的用户 Cookie 字符串
|
|
1719
|
+
* @returns 返回包含 WBI 签名的查询字符串
|
|
1720
|
+
* @throws 当获取 WBI 密钥失败或 URL 解析失败时抛出错误
|
|
1626
1721
|
*/
|
|
1627
|
-
const
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
表情列表: "/fetch_emoji_list",
|
|
1634
|
-
搜索笔记: "/fetch_search_notes"
|
|
1722
|
+
const wbi_sign = async (BASEURL, cookie) => {
|
|
1723
|
+
const web_keys = await getWbiKeys(cookie);
|
|
1724
|
+
const url$1 = new URL(BASEURL);
|
|
1725
|
+
const params = {};
|
|
1726
|
+
for (const [key, value] of url$1.searchParams.entries()) params[key] = value;
|
|
1727
|
+
return encWbi(params, web_keys.img_key, web_keys.sub_key);
|
|
1635
1728
|
};
|
|
1636
1729
|
|
|
1637
1730
|
//#endregion
|
|
1638
|
-
//#region src/
|
|
1639
|
-
/**
|
|
1640
|
-
* 验证抖音参数
|
|
1641
|
-
* @param methodType - 抖音方法类型
|
|
1642
|
-
* @param params - 待验证的参数
|
|
1643
|
-
* @returns 验证后的参数,符合原始API期望的类型
|
|
1644
|
-
*/
|
|
1645
|
-
const validateDouyinParams = (methodType, params) => {
|
|
1646
|
-
return DouyinValidationSchemas[methodType].parse(typeof params === "object" && params !== null ? {
|
|
1647
|
-
methodType,
|
|
1648
|
-
...params
|
|
1649
|
-
} : {
|
|
1650
|
-
methodType,
|
|
1651
|
-
params
|
|
1652
|
-
});
|
|
1653
|
-
};
|
|
1654
|
-
/**
|
|
1655
|
-
* 验证哔哩哔哩参数
|
|
1656
|
-
* @param methodType - 哔哩哔哩方法类型
|
|
1657
|
-
* @param params - 待验证的参数
|
|
1658
|
-
* @returns 验证后的参数,符合原始API期望的类型
|
|
1659
|
-
*/
|
|
1660
|
-
const validateBilibiliParams = (methodType, params) => {
|
|
1661
|
-
return BilibiliValidationSchemas[methodType].parse(typeof params === "object" && params !== null ? {
|
|
1662
|
-
methodType,
|
|
1663
|
-
...params
|
|
1664
|
-
} : {
|
|
1665
|
-
methodType,
|
|
1666
|
-
params
|
|
1667
|
-
});
|
|
1668
|
-
};
|
|
1731
|
+
//#region src/utils/errors.ts
|
|
1669
1732
|
/**
|
|
1670
|
-
*
|
|
1671
|
-
* @param methodType - 快手方法类型
|
|
1672
|
-
* @param params - 待验证的参数
|
|
1673
|
-
* @returns 验证后的参数,符合原始API期望的类型
|
|
1733
|
+
* API错误类
|
|
1674
1734
|
*/
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1735
|
+
var ApiError = class extends Error {
|
|
1736
|
+
code;
|
|
1737
|
+
platform;
|
|
1738
|
+
/**
|
|
1739
|
+
* 构造API错误
|
|
1740
|
+
* @param message - 错误消息
|
|
1741
|
+
* @param code - 错误代码
|
|
1742
|
+
* @param platform - 平台名称
|
|
1743
|
+
*/
|
|
1744
|
+
constructor(message, code = 500, platform = "unknown") {
|
|
1745
|
+
super(message);
|
|
1746
|
+
this.name = "ApiError";
|
|
1747
|
+
this.code = code;
|
|
1748
|
+
this.platform = platform;
|
|
1749
|
+
}
|
|
1683
1750
|
};
|
|
1684
1751
|
/**
|
|
1685
|
-
*
|
|
1686
|
-
* @param methodType - 小红书方法类型
|
|
1687
|
-
* @param params - 待验证的参数
|
|
1688
|
-
* @returns 验证后的参数
|
|
1752
|
+
* 参数验证错误类
|
|
1689
1753
|
*/
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1754
|
+
var ValidationError = class ValidationError extends Error {
|
|
1755
|
+
errors;
|
|
1756
|
+
requestPath;
|
|
1757
|
+
/**
|
|
1758
|
+
* 构造参数验证错误
|
|
1759
|
+
* @param message - 错误消息
|
|
1760
|
+
* @param errors - 详细错误信息
|
|
1761
|
+
* @param requestPath - HTTP请求路径
|
|
1762
|
+
*/
|
|
1763
|
+
constructor(message, errors, requestPath) {
|
|
1764
|
+
super(message);
|
|
1765
|
+
this.name = "ValidationError";
|
|
1766
|
+
this.errors = errors;
|
|
1767
|
+
this.requestPath = requestPath;
|
|
1768
|
+
}
|
|
1769
|
+
/**
|
|
1770
|
+
* 从Zod错误创建验证错误
|
|
1771
|
+
* @param zodError - Zod验证错误
|
|
1772
|
+
* @param requestPath - HTTP请求路径
|
|
1773
|
+
* @returns 验证错误实例
|
|
1774
|
+
*/
|
|
1775
|
+
static fromZodError(zodError, requestPath) {
|
|
1776
|
+
return new ValidationError("参数验证失败", zodError.issues.map((err) => ({
|
|
1777
|
+
field: err.path.join("."),
|
|
1778
|
+
message: err.message
|
|
1779
|
+
})), requestPath);
|
|
1780
|
+
}
|
|
1698
1781
|
};
|
|
1699
1782
|
/**
|
|
1700
|
-
*
|
|
1701
|
-
* @param
|
|
1702
|
-
* @param
|
|
1703
|
-
* @
|
|
1704
|
-
* @returns 格式化的成功API响应对象
|
|
1783
|
+
* 处理错误并返回统一格式
|
|
1784
|
+
* @param error - 错误对象
|
|
1785
|
+
* @param requestPath - HTTP请求路径(可选)
|
|
1786
|
+
* @returns 统一的错误响应格式
|
|
1705
1787
|
*/
|
|
1706
|
-
const
|
|
1707
|
-
return {
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1788
|
+
const handleError = (error, requestPath) => {
|
|
1789
|
+
if (error instanceof ValidationError) return {
|
|
1790
|
+
code: 400,
|
|
1791
|
+
message: error.message,
|
|
1792
|
+
data: null,
|
|
1793
|
+
errors: error.errors,
|
|
1794
|
+
requestPath: error.requestPath ?? requestPath
|
|
1713
1795
|
};
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
const createErrorResponse = (error, message, code = 500) => {
|
|
1796
|
+
if (error instanceof ApiError) return {
|
|
1797
|
+
code: error.code,
|
|
1798
|
+
message: error.message,
|
|
1799
|
+
data: null,
|
|
1800
|
+
platform: error.platform,
|
|
1801
|
+
requestPath
|
|
1802
|
+
};
|
|
1803
|
+
if (error instanceof zod.ZodError) return handleError(ValidationError.fromZodError(error, requestPath), requestPath);
|
|
1723
1804
|
return {
|
|
1724
|
-
|
|
1725
|
-
error,
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
data: void 0
|
|
1805
|
+
code: 500,
|
|
1806
|
+
message: error instanceof Error ? error.message : "未知错误",
|
|
1807
|
+
data: null,
|
|
1808
|
+
requestPath
|
|
1729
1809
|
};
|
|
1730
1810
|
};
|
|
1731
1811
|
|
|
@@ -2078,6 +2158,18 @@ const fetchBilibili = async (data$1, cookie, requestConfig) => {
|
|
|
2078
2158
|
...baseRequestConfig,
|
|
2079
2159
|
url: bilibiliApiUrls.二维码状态({ qrcode_key: data$1.qrcode_key })
|
|
2080
2160
|
});
|
|
2161
|
+
if (isNetworkErrorResult(result)) {
|
|
2162
|
+
const networkError = new Error(result.error.amagiError.errorDescription);
|
|
2163
|
+
Object.assign(networkError, {
|
|
2164
|
+
code: result.error.code,
|
|
2165
|
+
data: null,
|
|
2166
|
+
amagiError: {
|
|
2167
|
+
...result.error.amagiError,
|
|
2168
|
+
requestType: data$1.methodType
|
|
2169
|
+
}
|
|
2170
|
+
});
|
|
2171
|
+
throw networkError;
|
|
2172
|
+
}
|
|
2081
2173
|
if (result.data.code !== 0) {
|
|
2082
2174
|
const Err = {
|
|
2083
2175
|
errorDescription: `获取响应数据失败!原因:${bilibiliErrorCodeMap[String(result.data.code)] || result.data.message || "未知错误"}!`,
|
|
@@ -2159,6 +2251,18 @@ const GlobalGetData$3 = async (type, options, retryCount = 0) => {
|
|
|
2159
2251
|
let warningMessage = "";
|
|
2160
2252
|
try {
|
|
2161
2253
|
const result = await fetchData(options);
|
|
2254
|
+
if (isNetworkErrorResult(result)) {
|
|
2255
|
+
const networkError = new Error(result.error.amagiError.errorDescription);
|
|
2256
|
+
Object.assign(networkError, {
|
|
2257
|
+
code: result.error.code,
|
|
2258
|
+
data: null,
|
|
2259
|
+
amagiError: {
|
|
2260
|
+
...result.error.amagiError,
|
|
2261
|
+
requestType: type
|
|
2262
|
+
}
|
|
2263
|
+
});
|
|
2264
|
+
throw networkError;
|
|
2265
|
+
}
|
|
2162
2266
|
if (!result || result === "") {
|
|
2163
2267
|
const Err = {
|
|
2164
2268
|
errorDescription: "获取响应数据失败!接口返回内容为空,你的B站ck可能已经失效!",
|
|
@@ -3892,6 +3996,18 @@ const GlobalGetData$2 = async (type, config) => {
|
|
|
3892
3996
|
let warningMessage = "";
|
|
3893
3997
|
try {
|
|
3894
3998
|
const result = await fetchData(config);
|
|
3999
|
+
if (isNetworkErrorResult(result)) {
|
|
4000
|
+
const networkError = new Error(result.error.amagiError.errorDescription);
|
|
4001
|
+
Object.assign(networkError, {
|
|
4002
|
+
code: result.error.code,
|
|
4003
|
+
data: null,
|
|
4004
|
+
amagiError: {
|
|
4005
|
+
...result.error.amagiError,
|
|
4006
|
+
requestType: type
|
|
4007
|
+
}
|
|
4008
|
+
});
|
|
4009
|
+
throw networkError;
|
|
4010
|
+
}
|
|
3895
4011
|
if (!result || result === "") {
|
|
3896
4012
|
const Err = {
|
|
3897
4013
|
errorDescription: "获取响应数据失败!接口返回内容为空,你的抖音ck可能已经失效!",
|
|
@@ -4095,6 +4211,18 @@ const GlobalGetData$1 = async (type, options) => {
|
|
|
4095
4211
|
let warningMessage = "";
|
|
4096
4212
|
try {
|
|
4097
4213
|
const result = await fetchData(options);
|
|
4214
|
+
if (isNetworkErrorResult(result)) {
|
|
4215
|
+
const networkError = new Error(result.error.amagiError.errorDescription);
|
|
4216
|
+
Object.assign(networkError, {
|
|
4217
|
+
code: result.error.code,
|
|
4218
|
+
data: null,
|
|
4219
|
+
amagiError: {
|
|
4220
|
+
...result.error.amagiError,
|
|
4221
|
+
requestType: type
|
|
4222
|
+
}
|
|
4223
|
+
});
|
|
4224
|
+
throw networkError;
|
|
4225
|
+
}
|
|
4098
4226
|
if (result === "" || !result || result.result === 2) {
|
|
4099
4227
|
const Err = {
|
|
4100
4228
|
errorDescription: "获取响应数据失败!接口返回内容为空!",
|
|
@@ -4279,6 +4407,18 @@ const XiaohongshuData = async (data$1, cookie, requestConfig) => {
|
|
|
4279
4407
|
const GlobalGetData = async (methodType, config) => {
|
|
4280
4408
|
try {
|
|
4281
4409
|
const response = await fetchData(config);
|
|
4410
|
+
if (isNetworkErrorResult(response)) {
|
|
4411
|
+
const networkError = new Error(response.error.amagiError.errorDescription);
|
|
4412
|
+
Object.assign(networkError, {
|
|
4413
|
+
code: response.error.code,
|
|
4414
|
+
data: null,
|
|
4415
|
+
amagiError: {
|
|
4416
|
+
...response.error.amagiError,
|
|
4417
|
+
requestType: methodType
|
|
4418
|
+
}
|
|
4419
|
+
});
|
|
4420
|
+
throw networkError;
|
|
4421
|
+
}
|
|
4282
4422
|
if (typeof response === "string" && response.includes("<html>")) return response;
|
|
4283
4423
|
if (response.code !== 0) throw new Error(`API请求失败: ${response.data?.msg ?? response.msg ?? "未知错误"}, code: ${response.code}`);
|
|
4284
4424
|
return response;
|
|
@@ -4960,7 +5100,7 @@ let DynamicType = /* @__PURE__ */ function(DynamicType$1) {
|
|
|
4960
5100
|
|
|
4961
5101
|
//#endregion
|
|
4962
5102
|
//#region src/index.ts
|
|
4963
|
-
const VERSION = "5.
|
|
5103
|
+
const VERSION = "5.11.0";
|
|
4964
5104
|
/**
|
|
4965
5105
|
* @deprecated 请使用 createAmagiClient 替代
|
|
4966
5106
|
*/
|
|
@@ -4996,4 +5136,4 @@ const Client = CreateApp;
|
|
|
4996
5136
|
const amagi = Client;
|
|
4997
5137
|
|
|
4998
5138
|
//#endregion
|
|
4999
|
-
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, DouyinHotWordsParamsSchema, DouyinLiveRoomParamsSchema, DouyinMethodRoutes, DouyinMusicParamsSchema, DouyinQrcodeParamsSchema, DouyinSearchParamsSchema, DouyinUserParamsSchema, DouyinValidationSchemas, DouyinWorkParamsSchema, DynamicType, KuaishouCommentParamsSchema, KuaishouEmojiParamsSchema, KuaishouMethodRoutes, KuaishouValidationSchemas, KuaishouVideoParamsSchema, MajorType, ValidationError, XiaohongshuMethodRoutes, XiaohongshuValidationSchemas, amagi, amagiClient, av2bv, bilibili, bilibiliApiUrls, bilibiliErrorCodeMap, bilibiliUtils, bv2av, createAmagiClient, createBilibiliRoutes, createBilibiliRoutes as registerBilibiliRoutes, createBoundBilibiliApi, createBoundDouyinApi, createBoundKuaishouApi, createBoundXiaohongshuApi, createDouyinRoutes, createDouyinRoutes as registerDouyinRoutes, createErrorResponse, createKuaishouRoutes, createKuaishouRoutes as registerKuaishouRoutes, createSuccessResponse, createXiaohongshuRoutes, createXiaohongshuRoutes as registerXiaohongshuRoutes, Client as default, douyin, douyinApiUrls, douyinSign, douyinUtils, fetchData, fetchResponse, getBilibiliData, getDouyinData, getHeadersAndData, getKuaishouData, handleError, httpLogger, kuaishou, kuaishouApiUrls, kuaishouUtils, logMiddleware, logger, qtparam, validateBilibiliParams, validateDouyinParams, validateKuaishouParams, validateXiaohongshuParams, wbi_sign, xiaohongshu, xiaohongshuApiUrls, xiaohongshuSign, xiaohongshuUtils };
|
|
5139
|
+
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, DouyinHotWordsParamsSchema, DouyinLiveRoomParamsSchema, DouyinMethodRoutes, DouyinMusicParamsSchema, DouyinQrcodeParamsSchema, DouyinSearchParamsSchema, DouyinUserParamsSchema, DouyinValidationSchemas, DouyinWorkParamsSchema, DynamicType, KuaishouCommentParamsSchema, KuaishouEmojiParamsSchema, KuaishouMethodRoutes, KuaishouValidationSchemas, KuaishouVideoParamsSchema, MajorType, ValidationError, XiaohongshuMethodRoutes, XiaohongshuValidationSchemas, amagi, amagiClient, av2bv, bilibili, bilibiliApiUrls, bilibiliErrorCodeMap, bilibiliUtils, bv2av, createAmagiClient, createBilibiliRoutes, createBilibiliRoutes as registerBilibiliRoutes, createBoundBilibiliApi, createBoundDouyinApi, createBoundKuaishouApi, createBoundXiaohongshuApi, createDouyinRoutes, createDouyinRoutes as registerDouyinRoutes, createErrorResponse, createKuaishouRoutes, createKuaishouRoutes as registerKuaishouRoutes, createSuccessResponse, createXiaohongshuRoutes, createXiaohongshuRoutes as registerXiaohongshuRoutes, Client as default, douyin, douyinApiUrls, douyinSign, douyinUtils, fetchData, fetchResponse, getBilibiliData, getDouyinData, getHeadersAndData, getKuaishouData, handleError, httpLogger, isNetworkErrorResult, kuaishou, kuaishouApiUrls, kuaishouUtils, logMiddleware, logger, qtparam, validateBilibiliParams, validateDouyinParams, validateKuaishouParams, validateXiaohongshuParams, wbi_sign, xiaohongshu, xiaohongshuApiUrls, xiaohongshuSign, xiaohongshuUtils };
|