@ikenxuan/amagi 6.1.3 → 6.3.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/README.md +3 -2
- package/dist/default/index.cjs +399 -157
- package/dist/default/index.d.ts +813 -248
- package/dist/default/index.mjs +394 -152
- package/dist/exports/axios.cjs +2 -2
- package/dist/exports/express.cjs +2 -2
- package/package.json +21 -21
- /package/dist/{chunk-CKQMccvm.cjs → rolldown-runtime-D6vf50IK.cjs} +0 -0
package/dist/default/index.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import URL$1 from "node:url";
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
3
|
import zod from "zod";
|
|
4
|
-
import { Xhshow } from "@ikenxuan/xhshow-ts";
|
|
5
|
-
import crypto from "node:crypto";
|
|
4
|
+
import { CryptoConfig, FingerprintGenerator, Xhshow } from "@ikenxuan/xhshow-ts";
|
|
5
|
+
import crypto, { createCipheriv, createHash, randomBytes, randomUUID } from "node:crypto";
|
|
6
6
|
import axios, { AxiosError } from "axios";
|
|
7
7
|
import { Chalk } from "chalk";
|
|
8
8
|
import protobuf from "protobufjs";
|
|
@@ -530,6 +530,15 @@ var BilibiliAPI = class {
|
|
|
530
530
|
getUserCard(data) {
|
|
531
531
|
return `https://api.bilibili.com/x/web-interface/card?mid=${data.host_mid}&photo=true`;
|
|
532
532
|
}
|
|
533
|
+
/**
|
|
534
|
+
* 按用户 UID 获取直播状态。
|
|
535
|
+
*
|
|
536
|
+
* @remarks
|
|
537
|
+
* 该接口直接返回用户当前直播状态,不依赖空间动态中的直播推荐卡片。
|
|
538
|
+
*/
|
|
539
|
+
getUserLiveStatus(data) {
|
|
540
|
+
return `https://api.live.bilibili.com/room/v1/Room/getRoomInfoOld?mid=${data.host_mid}`;
|
|
541
|
+
}
|
|
533
542
|
/** 获取直播间信息 */
|
|
534
543
|
getLiveRoomInfo(data) {
|
|
535
544
|
return `https://api.live.bilibili.com/room/v1/Room/get_info?room_id=${data.room_id}`;
|
|
@@ -975,6 +984,7 @@ const BilibiliUserParamsSchema = zod.object({
|
|
|
975
984
|
methodType: zod.enum([
|
|
976
985
|
"userCard",
|
|
977
986
|
"userDynamicList",
|
|
987
|
+
"userLiveStatus",
|
|
978
988
|
"uploaderTotalViews",
|
|
979
989
|
"userSpaceInfo"
|
|
980
990
|
], { error: "方法类型必须是指定的枚举值之一" }),
|
|
@@ -1075,6 +1085,7 @@ const BilibiliValidationSchemas = {
|
|
|
1075
1085
|
commentReplies: BilibiliCommentReplyParamsSchema,
|
|
1076
1086
|
userCard: BilibiliUserParamsSchema,
|
|
1077
1087
|
userDynamicList: BilibiliUserParamsSchema,
|
|
1088
|
+
userLiveStatus: BilibiliUserParamsSchema,
|
|
1078
1089
|
userSpaceInfo: BilibiliUserParamsSchema,
|
|
1079
1090
|
emojiList: BilibiliEmojiParamsSchema,
|
|
1080
1091
|
bangumiInfo: BilibiliBangumiInfoParamsSchema,
|
|
@@ -1105,6 +1116,7 @@ const BilibiliMethodRoutes = {
|
|
|
1105
1116
|
commentReplies: "/fetch_comment_reply",
|
|
1106
1117
|
userCard: "/fetch_user_profile",
|
|
1107
1118
|
userDynamicList: "/fetch_user_dynamic",
|
|
1119
|
+
userLiveStatus: "/fetch_user_live_status",
|
|
1108
1120
|
userSpaceInfo: "/fetch_user_space_info",
|
|
1109
1121
|
emojiList: "/fetch_emoji_list",
|
|
1110
1122
|
bangumiInfo: "/fetch_bangumi_video_info",
|
|
@@ -1338,12 +1350,194 @@ const KuaishouMethodRoutes = {
|
|
|
1338
1350
|
emojiList: "/fetch_emoji_list"
|
|
1339
1351
|
};
|
|
1340
1352
|
//#endregion
|
|
1353
|
+
//#region src/platform/xiaohongshu/sign/config.ts
|
|
1354
|
+
/** 初始化签名配置。 */
|
|
1355
|
+
const createXiaohongshuCryptoConfig = () => new CryptoConfig().withOverrides({
|
|
1356
|
+
DATA_WEB_BUILD: "6.12.3",
|
|
1357
|
+
SIGNATURE_DATA_TEMPLATE: {
|
|
1358
|
+
x0: "4.3.5",
|
|
1359
|
+
x1: "xhs-pc-web",
|
|
1360
|
+
x2: "Windows",
|
|
1361
|
+
x3: "",
|
|
1362
|
+
x4: ""
|
|
1363
|
+
},
|
|
1364
|
+
SIGNATURE_XSCOMMON_TEMPLATE: {
|
|
1365
|
+
s0: 5,
|
|
1366
|
+
s1: "",
|
|
1367
|
+
x0: "1",
|
|
1368
|
+
x1: "4.3.5",
|
|
1369
|
+
x2: "Windows",
|
|
1370
|
+
x3: "xhs-pc-web",
|
|
1371
|
+
x4: "6.12.3",
|
|
1372
|
+
x5: "",
|
|
1373
|
+
x6: "",
|
|
1374
|
+
x7: "",
|
|
1375
|
+
x8: "",
|
|
1376
|
+
x9: -596800761,
|
|
1377
|
+
x10: 0,
|
|
1378
|
+
x11: "normal"
|
|
1379
|
+
}
|
|
1380
|
+
});
|
|
1381
|
+
//#endregion
|
|
1382
|
+
//#region src/platform/xiaohongshu/sign/guestCookie.ts
|
|
1383
|
+
/** @see https://github.com/Cialle/RedCrack */
|
|
1384
|
+
/** 小红书 Web 端游客会话初始化使用的浏览器请求头。 */
|
|
1385
|
+
const GUEST_HEADERS = {
|
|
1386
|
+
accept: "application/json, text/plain, */*",
|
|
1387
|
+
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
1388
|
+
"content-type": "application/json;charset=UTF-8",
|
|
1389
|
+
origin: "https://www.xiaohongshu.com",
|
|
1390
|
+
priority: "u=1, i",
|
|
1391
|
+
referer: "https://www.xiaohongshu.com/",
|
|
1392
|
+
"sec-ch-ua": "\"Microsoft Edge\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
|
1393
|
+
"sec-ch-ua-mobile": "?0",
|
|
1394
|
+
"sec-ch-ua-platform": "\"Windows\"",
|
|
1395
|
+
"sec-fetch-dest": "empty",
|
|
1396
|
+
"sec-fetch-mode": "cors",
|
|
1397
|
+
"sec-fetch-site": "same-site",
|
|
1398
|
+
"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"
|
|
1399
|
+
};
|
|
1400
|
+
/** 生成 a1 随机段时使用的 Web 端字符集。 */
|
|
1401
|
+
const COOKIE_RANDOM_CHARS = "abcdefghijklmnopqrstuvwxyz1234567890";
|
|
1402
|
+
/** 将 Cookie Jar 序列化为可直接写入 HTTP Cookie 请求头的字符串。 */
|
|
1403
|
+
const toCookieString = (cookies) => Object.entries(cookies).map(([key, value]) => `${key}=${value}`).join("; ");
|
|
1404
|
+
/** 将响应头中的 Set-Cookie 字段合并到当前游客会话的 Cookie Jar。 */
|
|
1405
|
+
const updateCookiesFromResponse = (cookies, setCookie) => {
|
|
1406
|
+
const headers = Array.isArray(setCookie) ? setCookie : setCookie ? [setCookie] : [];
|
|
1407
|
+
for (const header of headers) {
|
|
1408
|
+
const [nameValue] = header.split(";", 1);
|
|
1409
|
+
const separatorIndex = nameValue.indexOf("=");
|
|
1410
|
+
if (separatorIndex > 0) cookies[nameValue.slice(0, separatorIndex).trim()] = nameValue.slice(separatorIndex + 1).trim();
|
|
1411
|
+
}
|
|
1412
|
+
};
|
|
1413
|
+
/** 按小红书 Web 端规则生成 a1,以及由 a1 派生的 webId。 */
|
|
1414
|
+
const generateA1AndWebId = () => {
|
|
1415
|
+
const source = `${Date.now().toString(16)}${Array.from(randomBytes(30), (byte) => COOKIE_RANDOM_CHARS[byte % 36]).join("")}5000`;
|
|
1416
|
+
const a1 = `${source}${crc32(source)}`.slice(0, 52);
|
|
1417
|
+
return {
|
|
1418
|
+
a1,
|
|
1419
|
+
webId: createHash("md5").update(a1).digest("hex")
|
|
1420
|
+
};
|
|
1421
|
+
};
|
|
1422
|
+
/** 计算与浏览器端实现兼容的无符号 CRC32 校验值。 */
|
|
1423
|
+
const crc32 = (input) => {
|
|
1424
|
+
let value = 4294967295;
|
|
1425
|
+
for (const byte of Buffer.from(input)) {
|
|
1426
|
+
value ^= byte;
|
|
1427
|
+
for (let bit = 0; bit < 8; bit += 1) value = value & 1 ? value >>> 1 ^ 3988292384 : value >>> 1;
|
|
1428
|
+
}
|
|
1429
|
+
return (value ^ 4294967295) >>> 0;
|
|
1430
|
+
};
|
|
1431
|
+
/** 从 scripting 接口返回的 VMP 数据中解码 websectiga Cookie。 */
|
|
1432
|
+
const generateWebsectiga = (payload) => {
|
|
1433
|
+
const bMatch = payload.match(/"b":"(.*?)",/);
|
|
1434
|
+
const dMatch = payload.match(/"d":(.*?)\}\)/);
|
|
1435
|
+
if (!bMatch || !dMatch) throw new Error("小红书 scripting 响应格式异常,无法生成 websectiga");
|
|
1436
|
+
const decoderData = JSON.parse(dMatch[1]);
|
|
1437
|
+
const encoded = Buffer.from(bMatch[1], "base64").toString("utf8");
|
|
1438
|
+
const logicList = [];
|
|
1439
|
+
for (let index = 0; index < encoded.length; index += 5) logicList.push(Array.from(encoded.slice(index, index + 5), (char) => char.charCodeAt(0) - 1));
|
|
1440
|
+
const start = decoderData[92];
|
|
1441
|
+
const end = decoderData[93];
|
|
1442
|
+
const target = logicList.slice(start, end + 1);
|
|
1443
|
+
const key = Array.from({ length: 64 }, (_, index) => {
|
|
1444
|
+
const item = target[675 + index * 2];
|
|
1445
|
+
if (!item) throw new Error("小红书 scripting 响应缺少 websectiga 解码数据");
|
|
1446
|
+
return decoderData[item[2]];
|
|
1447
|
+
});
|
|
1448
|
+
return Array.from({ length: 8 }, (_, group) => {
|
|
1449
|
+
const offset = 56 - group * 8;
|
|
1450
|
+
return String.fromCharCode(...key.slice(offset, offset + 8));
|
|
1451
|
+
}).join("");
|
|
1452
|
+
};
|
|
1453
|
+
/** 将浏览器指纹编码为 webprofile 接口要求的 DES-ECB profileData。 */
|
|
1454
|
+
const encryptProfileData = (fingerprint, desKey) => {
|
|
1455
|
+
const encoded = Buffer.from(JSON.stringify(fingerprint)).toString("base64");
|
|
1456
|
+
const blockSize = 8;
|
|
1457
|
+
const padding = blockSize - encoded.length % blockSize;
|
|
1458
|
+
const plaintext = Buffer.concat([Buffer.from(encoded), Buffer.alloc(padding)]);
|
|
1459
|
+
const cipher = createCipheriv("des-ede3", Buffer.from(desKey.repeat(3)), null);
|
|
1460
|
+
cipher.setAutoPadding(false);
|
|
1461
|
+
return Buffer.concat([cipher.update(plaintext), cipher.final()]).toString("hex");
|
|
1462
|
+
};
|
|
1463
|
+
/** 将 scripting 的 JSON 或 JSONP 响应统一还原为结构化数据。 */
|
|
1464
|
+
const unwrapScriptingResponse = (data) => {
|
|
1465
|
+
if (typeof data === "string") {
|
|
1466
|
+
const json = data.match(/^[^(]+\((.*)\)$/s)?.[1];
|
|
1467
|
+
return JSON.parse(json ?? data);
|
|
1468
|
+
}
|
|
1469
|
+
return data;
|
|
1470
|
+
};
|
|
1471
|
+
/**
|
|
1472
|
+
* 创建小红书 Web 端游客会话 Cookie。
|
|
1473
|
+
*
|
|
1474
|
+
* 该流程对应 Web 端首次访问时的 Cookie 初始化:生成 a1/webId,完成
|
|
1475
|
+
* scripting、webprofile 与 activate 三个会话请求,并返回最终 Cookie 字符串。
|
|
1476
|
+
*/
|
|
1477
|
+
const createXiaohongshuGuestCookie = async (requestConfig) => {
|
|
1478
|
+
const cryptoConfig = createXiaohongshuCryptoConfig();
|
|
1479
|
+
const signer = new Xhshow(cryptoConfig);
|
|
1480
|
+
const cookies = {
|
|
1481
|
+
...generateA1AndWebId(),
|
|
1482
|
+
webBuild: cryptoConfig.DATA_WEB_BUILD,
|
|
1483
|
+
xsecappid: "xhs-pc-web",
|
|
1484
|
+
loadts: String(Date.now()),
|
|
1485
|
+
abRequestId: randomUUID()
|
|
1486
|
+
};
|
|
1487
|
+
const { headers: requestHeaders, params: _params, ...transportConfig } = requestConfig ?? {};
|
|
1488
|
+
/** 发送会话初始化请求,并将响应中的 Set-Cookie 合并回当前 Cookie Jar。 */
|
|
1489
|
+
const request = async (url, data, signed = false) => {
|
|
1490
|
+
const signatureHeaders = signed ? signer.signHeadersPost(new URL(url).pathname, cookies, "xhs-pc-web", data) : {};
|
|
1491
|
+
const response = await axios({
|
|
1492
|
+
...transportConfig,
|
|
1493
|
+
method: "POST",
|
|
1494
|
+
url,
|
|
1495
|
+
data,
|
|
1496
|
+
validateStatus: () => true,
|
|
1497
|
+
headers: {
|
|
1498
|
+
...GUEST_HEADERS,
|
|
1499
|
+
...requestHeaders,
|
|
1500
|
+
...signatureHeaders,
|
|
1501
|
+
Cookie: toCookieString(cookies)
|
|
1502
|
+
}
|
|
1503
|
+
});
|
|
1504
|
+
updateCookiesFromResponse(cookies, response.headers["set-cookie"]);
|
|
1505
|
+
if (response.status < 200 || response.status >= 300) throw new Error(`小红书游客会话初始化失败:${url} 返回 HTTP ${response.status}`);
|
|
1506
|
+
return response.data;
|
|
1507
|
+
};
|
|
1508
|
+
const scriptingData = unwrapScriptingResponse(await request("https://as.xiaohongshu.com/api/sec/v1/scripting", {
|
|
1509
|
+
callFrom: "web",
|
|
1510
|
+
callback: "seccallback"
|
|
1511
|
+
})).data;
|
|
1512
|
+
if (!scriptingData?.data || !scriptingData.secPoisonId) throw new Error("小红书 scripting 响应缺少游客会话数据");
|
|
1513
|
+
cookies.websectiga = generateWebsectiga(scriptingData.data);
|
|
1514
|
+
cookies.sec_poison_id = scriptingData.secPoisonId;
|
|
1515
|
+
const fingerprint = new FingerprintGenerator(cryptoConfig).generate(cookies, GUEST_HEADERS["user-agent"]);
|
|
1516
|
+
await request(cryptoConfig.GID_URL, {
|
|
1517
|
+
platform: cryptoConfig.DATA_PLATFORM,
|
|
1518
|
+
profileData: encryptProfileData(fingerprint, cryptoConfig.DES_KEY),
|
|
1519
|
+
sdkVersion: cryptoConfig.DATA_SDK_VERSION,
|
|
1520
|
+
svn: cryptoConfig.DATA_SVN
|
|
1521
|
+
}, true);
|
|
1522
|
+
await request("https://edith.xiaohongshu.com/api/sns/web/v1/login/activate", {}, true);
|
|
1523
|
+
if (!cookies.web_session) throw new Error("小红书游客会话初始化失败:未获取到 web_session");
|
|
1524
|
+
return toCookieString(cookies);
|
|
1525
|
+
};
|
|
1526
|
+
//#endregion
|
|
1341
1527
|
//#region src/platform/xiaohongshu/sign/index.ts
|
|
1342
1528
|
/**
|
|
1343
1529
|
* 小红书签名算法类
|
|
1344
1530
|
*/
|
|
1345
1531
|
var xiaohongshuSign = class {
|
|
1346
|
-
static client = new Xhshow();
|
|
1532
|
+
static client = new Xhshow(createXiaohongshuCryptoConfig());
|
|
1533
|
+
/**
|
|
1534
|
+
* 创建包含 web_session 的小红书 Web 端游客 Cookie。
|
|
1535
|
+
*
|
|
1536
|
+
* `requestConfig` 会透传到游客会话初始化请求,可用于配置代理、超时等传输参数。
|
|
1537
|
+
*/
|
|
1538
|
+
static createGuestCookie(requestConfig) {
|
|
1539
|
+
return createXiaohongshuGuestCookie(requestConfig);
|
|
1540
|
+
}
|
|
1347
1541
|
/**
|
|
1348
1542
|
* 生成GET请求的X-S签名
|
|
1349
1543
|
* @param path - API路径
|
|
@@ -1556,7 +1750,7 @@ const xiaohongshuApiUrls = {
|
|
|
1556
1750
|
* @param data - 请求参数
|
|
1557
1751
|
* @returns 完整的接口URL
|
|
1558
1752
|
*/
|
|
1559
|
-
emojiList(
|
|
1753
|
+
emojiList(_data) {
|
|
1560
1754
|
return {
|
|
1561
1755
|
apiPath: "/api/im/redmoji/detail",
|
|
1562
1756
|
Url: "https://edith.xiaohongshu.com/api/im/redmoji/detail"
|
|
@@ -2194,6 +2388,27 @@ async function fetchUserDynamicList(options, cookie, requestConfig) {
|
|
|
2194
2388
|
});
|
|
2195
2389
|
}
|
|
2196
2390
|
/**
|
|
2391
|
+
* 按用户 UID 获取B站直播状态
|
|
2392
|
+
* @param options - 用户参数
|
|
2393
|
+
* @param options.host_mid - 用户 UID
|
|
2394
|
+
* @param cookie - B站 Cookie (可选)
|
|
2395
|
+
* @param requestConfig - 请求配置 (可选)
|
|
2396
|
+
* @returns 用户直播状态与直播间基础信息
|
|
2397
|
+
* @example
|
|
2398
|
+
* ```typescript
|
|
2399
|
+
* const result = await fetchUserLiveStatus({ host_mid: 123456, typeMode: 'strict' }, cookie)
|
|
2400
|
+
* if (result.success && result.data.data.liveStatus === 1) {
|
|
2401
|
+
* console.log(result.data.data.roomid) // 正在直播的房间 ID
|
|
2402
|
+
* }
|
|
2403
|
+
* ```
|
|
2404
|
+
*/
|
|
2405
|
+
async function fetchUserLiveStatus(options, cookie, requestConfig) {
|
|
2406
|
+
return fetchBilibiliInternal("userLiveStatus", options, {
|
|
2407
|
+
cookie,
|
|
2408
|
+
requestConfig
|
|
2409
|
+
});
|
|
2410
|
+
}
|
|
2411
|
+
/**
|
|
2197
2412
|
* 获取B站用户空间详细信息
|
|
2198
2413
|
* @param options - 用户参数
|
|
2199
2414
|
* @param options.host_mid - 用户 UID
|
|
@@ -2374,6 +2589,7 @@ function createBoundBilibiliFetcher(cookie, requestConfig) {
|
|
|
2374
2589
|
fetchCommentReplies: (options) => fetchCommentReplies$1(options, cookie, requestConfig),
|
|
2375
2590
|
fetchUserCard: (options) => fetchUserCard(options, cookie, requestConfig),
|
|
2376
2591
|
fetchUserDynamicList: (options) => fetchUserDynamicList(options, cookie, requestConfig),
|
|
2592
|
+
fetchUserLiveStatus: (options) => fetchUserLiveStatus(options, cookie, requestConfig),
|
|
2377
2593
|
fetchUserSpaceInfo: (options) => fetchUserSpaceInfo(options, cookie, requestConfig),
|
|
2378
2594
|
fetchUploaderTotalViews: (options) => fetchUploaderTotalViews(options, cookie, requestConfig),
|
|
2379
2595
|
fetchDynamicDetail: (options) => fetchDynamicDetail(options, cookie, requestConfig),
|
|
@@ -2421,6 +2637,7 @@ const bilibiliFetcher = {
|
|
|
2421
2637
|
fetchCommentReplies: fetchCommentReplies$1,
|
|
2422
2638
|
fetchUserCard,
|
|
2423
2639
|
fetchUserDynamicList,
|
|
2640
|
+
fetchUserLiveStatus,
|
|
2424
2641
|
fetchUserSpaceInfo,
|
|
2425
2642
|
fetchUploaderTotalViews,
|
|
2426
2643
|
fetchDynamicDetail,
|
|
@@ -2462,7 +2679,7 @@ const generateSecChUa = (userAgent) => {
|
|
|
2462
2679
|
*/
|
|
2463
2680
|
const getDouyinDefaultConfig = (cookie, requestConfig) => {
|
|
2464
2681
|
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";
|
|
2465
|
-
finalUserAgent = finalUserAgent.replace(/\s+Edg\/[\d
|
|
2682
|
+
finalUserAgent = finalUserAgent.replace(/\s+Edg\/[\d.]+/g, "");
|
|
2466
2683
|
const defHeaders = {
|
|
2467
2684
|
Accept: "application/json, text/plain, */*",
|
|
2468
2685
|
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
@@ -2637,7 +2854,8 @@ var SM3 = class {
|
|
|
2637
2854
|
this.chunk = this.chunk.concat(a.slice(0, f));
|
|
2638
2855
|
while (this.chunk.length >= 64) {
|
|
2639
2856
|
this._compress(this.chunk);
|
|
2640
|
-
f < a.length
|
|
2857
|
+
if (f < a.length) this.chunk = a.slice(f, Math.min(f + 64, a.length));
|
|
2858
|
+
else this.chunk = [];
|
|
2641
2859
|
f += 64;
|
|
2642
2860
|
}
|
|
2643
2861
|
}
|
|
@@ -2673,10 +2891,17 @@ var SM3 = class {
|
|
|
2673
2891
|
if (t.length < 64) console.error("compress error: not enough data");
|
|
2674
2892
|
else {
|
|
2675
2893
|
for (var f = ((e) => {
|
|
2676
|
-
for (var r = new Array(132), t = 0; t < 16; t++)
|
|
2894
|
+
for (var r = new Array(132), t = 0; t < 16; t++) {
|
|
2895
|
+
r[t] = e[4 * t] << 24;
|
|
2896
|
+
r[t] |= e[4 * t + 1] << 16;
|
|
2897
|
+
r[t] |= e[4 * t + 2] << 8;
|
|
2898
|
+
r[t] |= e[4 * t + 3];
|
|
2899
|
+
r[t] >>>= 0;
|
|
2900
|
+
}
|
|
2677
2901
|
for (var n = 16; n < 68; n++) {
|
|
2678
2902
|
let a = r[n - 16] ^ r[n - 9] ^ this.le(r[n - 3], 15);
|
|
2679
|
-
a = a ^ this.le(a, 15) ^ this.le(a, 23)
|
|
2903
|
+
a = a ^ this.le(a, 15) ^ this.le(a, 23);
|
|
2904
|
+
r[n] = (a ^ this.le(r[n - 13], 7) ^ r[n - 6]) >>> 0;
|
|
2680
2905
|
}
|
|
2681
2906
|
for (n = 0; n < 64; n++) r[n + 68] = (r[n] ^ r[n + 4]) >>> 0;
|
|
2682
2907
|
return r;
|
|
@@ -2686,7 +2911,15 @@ var SM3 = class {
|
|
|
2686
2911
|
let u = this.pe(c, i[0], i[1], i[2]);
|
|
2687
2912
|
u = (4294967295 & (u = u + i[3] + s + f[c + 68])) >>> 0;
|
|
2688
2913
|
let b = this.he(c, i[4], i[5], i[6]);
|
|
2689
|
-
b = (4294967295 & (b = b + i[7] + o + f[c])) >>> 0
|
|
2914
|
+
b = (4294967295 & (b = b + i[7] + o + f[c])) >>> 0;
|
|
2915
|
+
i[3] = i[2];
|
|
2916
|
+
i[2] = this.le(i[1], 9);
|
|
2917
|
+
i[1] = i[0];
|
|
2918
|
+
i[0] = u;
|
|
2919
|
+
i[7] = i[6];
|
|
2920
|
+
i[6] = this.le(i[5], 19);
|
|
2921
|
+
i[5] = i[4];
|
|
2922
|
+
i[4] = (b ^ this.le(b, 9) ^ this.le(b, 17)) >>> 0;
|
|
2690
2923
|
}
|
|
2691
2924
|
for (let l = 0; l < 8; l++) this.reg[l] = (this.reg[l] ^ i[l]) >>> 0;
|
|
2692
2925
|
}
|
|
@@ -2997,7 +3230,7 @@ function generate_random_str() {
|
|
|
2997
3230
|
* @returns 清理后的User-Agent字符串
|
|
2998
3231
|
*/
|
|
2999
3232
|
const cleanUserAgentForSigning = (userAgent) => {
|
|
3000
|
-
return userAgent.replace(/\s+Edg\/[\d
|
|
3233
|
+
return userAgent.replace(/\s+Edg\/[\d.]+/g, "");
|
|
3001
3234
|
};
|
|
3002
3235
|
/**
|
|
3003
3236
|
* 抖音a_bogus签名算法
|
|
@@ -3119,7 +3352,6 @@ var XBogus = class {
|
|
|
3119
3352
|
const array2 = this.md5StrToArray(this.md5(this.md5StrToArray("d41d8cd98f00b204e9800998ecf8427e")));
|
|
3120
3353
|
const urlEncryptedArray = this.md5Encrypt(urlPath);
|
|
3121
3354
|
const timestamp = Math.floor(Date.now() / 1e3);
|
|
3122
|
-
const ct = 536919696;
|
|
3123
3355
|
const newArray = [
|
|
3124
3356
|
64,
|
|
3125
3357
|
1,
|
|
@@ -3135,10 +3367,10 @@ var XBogus = class {
|
|
|
3135
3367
|
timestamp >> 16 & 255,
|
|
3136
3368
|
timestamp >> 8 & 255,
|
|
3137
3369
|
timestamp & 255,
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3370
|
+
32,
|
|
3371
|
+
0,
|
|
3372
|
+
190,
|
|
3373
|
+
144
|
|
3142
3374
|
];
|
|
3143
3375
|
let xorResult = newArray[0];
|
|
3144
3376
|
for (let i = 1; i < newArray.length; i++) xorResult ^= newArray[i];
|
|
@@ -4058,7 +4290,7 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4058
4290
|
if (isInvalidResponse) {
|
|
4059
4291
|
const desc = `抖音${typeStr}搜索返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!`;
|
|
4060
4292
|
const warningMessage = `
|
|
4061
|
-
获取响应数据失败!原因:${
|
|
4293
|
+
获取响应数据失败!原因:${typeStr}搜索返回无有效数据,疑似触发反爬机制
|
|
4062
4294
|
请求类型:「${data.methodType}」
|
|
4063
4295
|
搜索关键词:「${data.query}」
|
|
4064
4296
|
请求URL:${url}
|
|
@@ -4077,12 +4309,12 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4077
4309
|
if (!list || list.length === 0) {
|
|
4078
4310
|
const desc = `抖音${typeStr}搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!`;
|
|
4079
4311
|
const warningMessage = `
|
|
4080
|
-
获取响应数据失败!原因:${
|
|
4312
|
+
获取响应数据失败!原因:${typeStr}搜索接口第一次请求就返回空数组,你的抖音Cookie可能已经失效!
|
|
4081
4313
|
请求类型:「${data.methodType}」
|
|
4082
4314
|
搜索关键词:「${data.query}」
|
|
4083
4315
|
请求URL:${url}
|
|
4084
4316
|
`;
|
|
4085
|
-
|
|
4317
|
+
emitLogWarn(warningMessage);
|
|
4086
4318
|
return {
|
|
4087
4319
|
data: raw,
|
|
4088
4320
|
amagiError: {
|
|
@@ -4173,7 +4405,7 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4173
4405
|
});
|
|
4174
4406
|
currentStart = currentEnd;
|
|
4175
4407
|
}
|
|
4176
|
-
|
|
4408
|
+
emitLogDebug(`弹幕数据需要分${segments.length}段获取,总时长:${totalDuration}ms`);
|
|
4177
4409
|
const segmentPromises = segments.map(async (segment, index) => {
|
|
4178
4410
|
const url = douyinApiUrls.getDanmakuList({
|
|
4179
4411
|
aweme_id: data.aweme_id,
|
|
@@ -4186,10 +4418,10 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4186
4418
|
...baseRequestConfig,
|
|
4187
4419
|
url: buildSignedUrl(url, signType, userAgent)
|
|
4188
4420
|
});
|
|
4189
|
-
|
|
4421
|
+
emitLogDebug(`弹幕第${index + 1}段获取成功 (${segment.start}ms-${segment.end}ms)`);
|
|
4190
4422
|
return segmentData;
|
|
4191
4423
|
} catch (error) {
|
|
4192
|
-
|
|
4424
|
+
emitLogDebug(`弹幕第${index + 1}段获取失败 (${segment.start}ms-${segment.end}ms):`, error);
|
|
4193
4425
|
return null;
|
|
4194
4426
|
}
|
|
4195
4427
|
});
|
|
@@ -4218,7 +4450,7 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4218
4450
|
extra: finalExtra,
|
|
4219
4451
|
log_pb: finalLogPb
|
|
4220
4452
|
};
|
|
4221
|
-
|
|
4453
|
+
emitLogDebug(`弹幕数据合并完成,共获取${mergedDanmakuList.length}条弹幕`);
|
|
4222
4454
|
return finalDanmakuData;
|
|
4223
4455
|
}
|
|
4224
4456
|
default: {
|
|
@@ -4230,7 +4462,7 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4230
4462
|
url
|
|
4231
4463
|
});
|
|
4232
4464
|
}
|
|
4233
|
-
|
|
4465
|
+
emitLogWarn(`未知的抖音数据接口:「${data.methodType}」`);
|
|
4234
4466
|
return null;
|
|
4235
4467
|
}
|
|
4236
4468
|
}
|
|
@@ -4298,11 +4530,11 @@ const GlobalGetData$3 = async (type, config) => {
|
|
|
4298
4530
|
requestUrl: config.url
|
|
4299
4531
|
};
|
|
4300
4532
|
warningMessage = `
|
|
4301
|
-
|
|
4533
|
+
获取响应数据失败!原因:接口返回内容为空,你的抖音ck可能已经失效!
|
|
4302
4534
|
请求类型:「${type}」
|
|
4303
4535
|
请求URL:${config.url}
|
|
4304
4536
|
`;
|
|
4305
|
-
|
|
4537
|
+
emitLogWarn(warningMessage);
|
|
4306
4538
|
const cookieError = new Error(Err.errorDescription);
|
|
4307
4539
|
Object.assign(cookieError, {
|
|
4308
4540
|
code: "INVALID_COOKIE",
|
|
@@ -4319,11 +4551,11 @@ const GlobalGetData$3 = async (type, config) => {
|
|
|
4319
4551
|
requestUrl: config.url
|
|
4320
4552
|
};
|
|
4321
4553
|
warningMessage = `
|
|
4322
|
-
获取响应数据失败!原因:${
|
|
4554
|
+
获取响应数据失败!原因:${filterReason}
|
|
4323
4555
|
请求类型:「${type}」
|
|
4324
4556
|
请求URL:${config.url}
|
|
4325
4557
|
`;
|
|
4326
|
-
|
|
4558
|
+
emitLogWarn(warningMessage);
|
|
4327
4559
|
const filterError = new Error(Err.errorDescription);
|
|
4328
4560
|
Object.assign(filterError, {
|
|
4329
4561
|
code: "CONTENT_FILTERED",
|
|
@@ -5301,6 +5533,8 @@ const encodeBase64Url = (bytes) => {
|
|
|
5301
5533
|
* 数据流而最小化保留的局部算法。
|
|
5302
5534
|
*/
|
|
5303
5535
|
var KuaishouChaChaCipher = class {
|
|
5536
|
+
key;
|
|
5537
|
+
nonce;
|
|
5304
5538
|
wordIndex = 0;
|
|
5305
5539
|
state = new Array(16).fill(0);
|
|
5306
5540
|
constructor(key, nonce) {
|
|
@@ -6133,7 +6367,7 @@ const captureKuaishouEncodeStack = () => {
|
|
|
6133
6367
|
* @returns 用于 `SECS.s` 的栈尾字符串
|
|
6134
6368
|
*/
|
|
6135
6369
|
const deriveKuaishouSecsStackTail = (stack = captureKuaishouEncodeStack()) => {
|
|
6136
|
-
return stack.length > KUAISHOU_SECS_STACK_LIMIT ? stack.slice(-
|
|
6370
|
+
return stack.length > KUAISHOU_SECS_STACK_LIMIT ? stack.slice(-100) : stack;
|
|
6137
6371
|
};
|
|
6138
6372
|
/**
|
|
6139
6373
|
* 构造快手 `window.SECS` 的纯算法等价状态。
|
|
@@ -6986,7 +7220,7 @@ const KuaishouData = async (data, cookie, requestConfig) => {
|
|
|
6986
7220
|
}
|
|
6987
7221
|
case "emojiList": return fetchKuaishouGraphqlPayload(data.methodType, kuaishouApiUrls.emojiList());
|
|
6988
7222
|
default:
|
|
6989
|
-
|
|
7223
|
+
emitLogWarn(`Unknown Kuaishou API method: "${data.methodType}"`);
|
|
6990
7224
|
return null;
|
|
6991
7225
|
}
|
|
6992
7226
|
};
|
|
@@ -7025,12 +7259,12 @@ const GlobalGetData$2 = async (type, options, config) => {
|
|
|
7025
7259
|
requestBody: JSON.stringify(options.data)
|
|
7026
7260
|
};
|
|
7027
7261
|
warningMessage = `
|
|
7028
|
-
|
|
7262
|
+
获取响应数据失败!原因:接口返回内容为空,你的快手ck可能已经失效!
|
|
7029
7263
|
请求类型:「${type}」
|
|
7030
7264
|
请求URL:${options.url}
|
|
7031
7265
|
请求参数:${JSON.stringify(options.data, null, 2)}
|
|
7032
7266
|
`;
|
|
7033
|
-
|
|
7267
|
+
emitLogWarn(warningMessage);
|
|
7034
7268
|
const cookieError = new Error(Err.errorDescription);
|
|
7035
7269
|
Object.assign(cookieError, {
|
|
7036
7270
|
code: "INVALID_COOKIE",
|
|
@@ -7265,132 +7499,136 @@ function createBoundKuaishouFetcher(cookie, requestConfig) {
|
|
|
7265
7499
|
* @returns 返回小红书数据
|
|
7266
7500
|
*/
|
|
7267
7501
|
const XiaohongshuData = async (data, cookie, requestConfig) => {
|
|
7268
|
-
|
|
7269
|
-
const
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
|
|
7273
|
-
|
|
7274
|
-
...
|
|
7275
|
-
...requestConfig?.headers ?? {}
|
|
7276
|
-
}
|
|
7277
|
-
};
|
|
7278
|
-
const xiaohongshuApiUrls = createXiaohongshuApiUrls();
|
|
7279
|
-
switch (data.methodType) {
|
|
7280
|
-
case "homeFeed": return await GlobalGetData$1(data.methodType, {
|
|
7281
|
-
...baseRequestConfig,
|
|
7282
|
-
url: xiaohongshuApiUrls.homeFeed(data).Url,
|
|
7283
|
-
data: JSON.stringify(xiaohongshuApiUrls.homeFeed(data).Body),
|
|
7284
|
-
headers: {
|
|
7285
|
-
...baseRequestConfig.headers,
|
|
7286
|
-
"x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls.homeFeed(data).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web", xiaohongshuApiUrls.homeFeed(data).Body),
|
|
7287
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
|
|
7288
|
-
"x-t": xiaohongshuSign.generateXT()
|
|
7289
|
-
}
|
|
7290
|
-
});
|
|
7291
|
-
case "noteDetail": return await GlobalGetData$1(data.methodType, {
|
|
7292
|
-
...baseRequestConfig,
|
|
7293
|
-
url: xiaohongshuApiUrls.noteDetail(data).Url,
|
|
7294
|
-
data: xiaohongshuApiUrls.noteDetail(data).Body,
|
|
7502
|
+
/** 使用指定 Cookie 构建一次完整的小红书 API 请求。 */
|
|
7503
|
+
const requestWithCookie = async (requestCookie) => {
|
|
7504
|
+
const defHeaders = getXiaohongshuDefaultConfig(requestCookie)["headers"];
|
|
7505
|
+
const baseRequestConfig = {
|
|
7506
|
+
method: "POST",
|
|
7507
|
+
timeout: 1e4,
|
|
7508
|
+
...requestConfig,
|
|
7295
7509
|
headers: {
|
|
7296
|
-
...
|
|
7297
|
-
|
|
7298
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
|
|
7299
|
-
"x-t": xiaohongshuSign.generateXT()
|
|
7510
|
+
...defHeaders,
|
|
7511
|
+
...requestConfig?.headers ?? {}
|
|
7300
7512
|
}
|
|
7301
|
-
}
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
timeout: 1e4,
|
|
7306
|
-
...requestConfig,
|
|
7307
|
-
headers: {
|
|
7308
|
-
...defHeaders,
|
|
7309
|
-
...requestConfig?.headers ?? {}
|
|
7310
|
-
}
|
|
7311
|
-
};
|
|
7312
|
-
return await GlobalGetData$1(data.methodType, {
|
|
7513
|
+
};
|
|
7514
|
+
const xiaohongshuApiUrls = createXiaohongshuApiUrls();
|
|
7515
|
+
switch (data.methodType) {
|
|
7516
|
+
case "homeFeed": return await GlobalGetData$1(data.methodType, {
|
|
7313
7517
|
...baseRequestConfig,
|
|
7314
|
-
url: xiaohongshuApiUrls.
|
|
7518
|
+
url: xiaohongshuApiUrls.homeFeed(data).Url,
|
|
7519
|
+
data: JSON.stringify(xiaohongshuApiUrls.homeFeed(data).Body),
|
|
7315
7520
|
headers: {
|
|
7316
7521
|
...baseRequestConfig.headers,
|
|
7317
|
-
"x-s": xiaohongshuSign.
|
|
7318
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(
|
|
7522
|
+
"x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls.homeFeed(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web", xiaohongshuApiUrls.homeFeed(data).Body),
|
|
7523
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7319
7524
|
"x-t": xiaohongshuSign.generateXT()
|
|
7320
7525
|
}
|
|
7321
7526
|
});
|
|
7322
|
-
|
|
7323
|
-
|
|
7324
|
-
|
|
7325
|
-
|
|
7326
|
-
timeout: 1e4,
|
|
7327
|
-
...requestConfig,
|
|
7527
|
+
case "noteDetail": return await GlobalGetData$1(data.methodType, {
|
|
7528
|
+
...baseRequestConfig,
|
|
7529
|
+
url: xiaohongshuApiUrls.noteDetail(data).Url,
|
|
7530
|
+
data: xiaohongshuApiUrls.noteDetail(data).Body,
|
|
7328
7531
|
headers: {
|
|
7329
|
-
...
|
|
7330
|
-
|
|
7532
|
+
...baseRequestConfig.headers,
|
|
7533
|
+
"x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls.noteDetail(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web", xiaohongshuApiUrls.noteDetail(data).Body),
|
|
7534
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7535
|
+
"x-t": xiaohongshuSign.generateXT()
|
|
7331
7536
|
}
|
|
7332
|
-
};
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7537
|
+
});
|
|
7538
|
+
case "noteComments": {
|
|
7539
|
+
const baseRequestConfig = {
|
|
7540
|
+
method: "GET",
|
|
7541
|
+
timeout: 1e4,
|
|
7542
|
+
...requestConfig,
|
|
7543
|
+
headers: {
|
|
7544
|
+
...defHeaders,
|
|
7545
|
+
...requestConfig?.headers ?? {}
|
|
7546
|
+
}
|
|
7547
|
+
};
|
|
7548
|
+
return await GlobalGetData$1(data.methodType, {
|
|
7336
7549
|
...baseRequestConfig,
|
|
7337
|
-
url: xiaohongshuApiUrls.
|
|
7550
|
+
url: xiaohongshuApiUrls.noteComments(data).Url,
|
|
7338
7551
|
headers: {
|
|
7339
7552
|
...baseRequestConfig.headers,
|
|
7340
|
-
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.
|
|
7341
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(
|
|
7553
|
+
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.noteComments(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web"),
|
|
7554
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7342
7555
|
"x-t": xiaohongshuSign.generateXT()
|
|
7343
7556
|
}
|
|
7344
|
-
})
|
|
7345
|
-
msg: "success"
|
|
7346
|
-
};
|
|
7347
|
-
}
|
|
7348
|
-
case "userNoteList": return await GlobalGetData$1(data.methodType, {
|
|
7349
|
-
...baseRequestConfig,
|
|
7350
|
-
method: "GET",
|
|
7351
|
-
url: xiaohongshuApiUrls.userNoteList(data).Url,
|
|
7352
|
-
headers: {
|
|
7353
|
-
...baseRequestConfig.headers,
|
|
7354
|
-
"x-b3-traceid": xiaohongshuSign.generateXB3Traceid(),
|
|
7355
|
-
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.userNoteList(data).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
|
|
7356
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
|
|
7357
|
-
"x-t": xiaohongshuSign.generateXT()
|
|
7557
|
+
});
|
|
7358
7558
|
}
|
|
7359
|
-
|
|
7360
|
-
|
|
7361
|
-
|
|
7559
|
+
case "userProfile": {
|
|
7560
|
+
const baseRequestConfig = {
|
|
7561
|
+
method: "GET",
|
|
7562
|
+
timeout: 1e4,
|
|
7563
|
+
...requestConfig,
|
|
7564
|
+
headers: {
|
|
7565
|
+
...defHeaders,
|
|
7566
|
+
...requestConfig?.headers ?? {}
|
|
7567
|
+
}
|
|
7568
|
+
};
|
|
7569
|
+
return {
|
|
7570
|
+
code: 0,
|
|
7571
|
+
data: extractCreatorInfoFromHtml(await GlobalGetData$1(data.methodType, {
|
|
7572
|
+
...baseRequestConfig,
|
|
7573
|
+
url: xiaohongshuApiUrls.userProfile(data).Url,
|
|
7574
|
+
headers: {
|
|
7575
|
+
...baseRequestConfig.headers,
|
|
7576
|
+
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.userProfile(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web"),
|
|
7577
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7578
|
+
"x-t": xiaohongshuSign.generateXT()
|
|
7579
|
+
}
|
|
7580
|
+
})),
|
|
7581
|
+
msg: "success"
|
|
7582
|
+
};
|
|
7583
|
+
}
|
|
7584
|
+
case "userNoteList": return await GlobalGetData$1(data.methodType, {
|
|
7585
|
+
...baseRequestConfig,
|
|
7362
7586
|
method: "GET",
|
|
7363
|
-
|
|
7364
|
-
...requestConfig,
|
|
7587
|
+
url: xiaohongshuApiUrls.userNoteList(data).Url,
|
|
7365
7588
|
headers: {
|
|
7366
|
-
...
|
|
7367
|
-
|
|
7589
|
+
...baseRequestConfig.headers,
|
|
7590
|
+
"x-b3-traceid": xiaohongshuSign.generateXB3Traceid(),
|
|
7591
|
+
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.userNoteList(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web"),
|
|
7592
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7593
|
+
"x-t": xiaohongshuSign.generateXT()
|
|
7368
7594
|
}
|
|
7369
|
-
};
|
|
7370
|
-
|
|
7595
|
+
});
|
|
7596
|
+
case "emojiList": {
|
|
7597
|
+
const baseRequestConfig = {
|
|
7598
|
+
method: "GET",
|
|
7599
|
+
timeout: 1e4,
|
|
7600
|
+
...requestConfig,
|
|
7601
|
+
headers: {
|
|
7602
|
+
...defHeaders,
|
|
7603
|
+
...requestConfig?.headers ?? {}
|
|
7604
|
+
}
|
|
7605
|
+
};
|
|
7606
|
+
return await GlobalGetData$1(data.methodType, {
|
|
7607
|
+
...baseRequestConfig,
|
|
7608
|
+
url: xiaohongshuApiUrls.emojiList(data).Url,
|
|
7609
|
+
headers: {
|
|
7610
|
+
...baseRequestConfig.headers,
|
|
7611
|
+
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.emojiList(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web"),
|
|
7612
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7613
|
+
"x-t": xiaohongshuSign.generateXT()
|
|
7614
|
+
}
|
|
7615
|
+
});
|
|
7616
|
+
}
|
|
7617
|
+
case "searchNotes": return await GlobalGetData$1(data.methodType, {
|
|
7371
7618
|
...baseRequestConfig,
|
|
7372
|
-
url: xiaohongshuApiUrls.
|
|
7619
|
+
url: xiaohongshuApiUrls.searchNotes(data).Url,
|
|
7620
|
+
data: xiaohongshuApiUrls.searchNotes(data).Body,
|
|
7373
7621
|
headers: {
|
|
7374
7622
|
...baseRequestConfig.headers,
|
|
7375
|
-
"x-s": xiaohongshuSign.
|
|
7376
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(
|
|
7623
|
+
"x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls.searchNotes(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web"),
|
|
7624
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7377
7625
|
"x-t": xiaohongshuSign.generateXT()
|
|
7378
7626
|
}
|
|
7379
7627
|
});
|
|
7628
|
+
default: throw new Error(`Unknown Xiaohongshu API method: "${data.methodType}"`);
|
|
7380
7629
|
}
|
|
7381
|
-
|
|
7382
|
-
|
|
7383
|
-
url: xiaohongshuApiUrls.searchNotes(data).Url,
|
|
7384
|
-
data: xiaohongshuApiUrls.searchNotes(data).Body,
|
|
7385
|
-
headers: {
|
|
7386
|
-
...baseRequestConfig.headers,
|
|
7387
|
-
"x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls.searchNotes(data).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
|
|
7388
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
|
|
7389
|
-
"x-t": xiaohongshuSign.generateXT()
|
|
7390
|
-
}
|
|
7391
|
-
});
|
|
7392
|
-
default: throw new Error(`Unknown Xiaohongshu API method: "${logger.red(data.methodType)}"`);
|
|
7393
|
-
}
|
|
7630
|
+
};
|
|
7631
|
+
return requestWithCookie(cookie?.trim() ?? "");
|
|
7394
7632
|
};
|
|
7395
7633
|
/**
|
|
7396
7634
|
* 全局数据获取函数
|
|
@@ -7414,7 +7652,7 @@ const GlobalGetData$1 = async (methodType, config) => {
|
|
|
7414
7652
|
if (response.code !== 0) throw new Error(`API request failed: ${response.data?.msg ?? response.msg ?? "Unknown error"}, code: ${response.code}`);
|
|
7415
7653
|
return response;
|
|
7416
7654
|
} catch (error) {
|
|
7417
|
-
|
|
7655
|
+
emitLogError(`Xiaohongshu API request failed [${methodType}]:`, error.message);
|
|
7418
7656
|
return {
|
|
7419
7657
|
code: 500,
|
|
7420
7658
|
message: "error",
|
|
@@ -7755,7 +7993,7 @@ const createNetworkErrorResult = (error, retries) => {
|
|
|
7755
7993
|
* @returns 清理后的User-Agent字符串
|
|
7756
7994
|
*/
|
|
7757
7995
|
const cleanUserAgent = (userAgent) => {
|
|
7758
|
-
return userAgent.replace(/\s+Edg\/[\d
|
|
7996
|
+
return userAgent.replace(/\s+Edg\/[\d.]+/g, "");
|
|
7759
7997
|
};
|
|
7760
7998
|
/**
|
|
7761
7999
|
* 执行网络请求并返回数据(带自动重试)
|
|
@@ -8007,8 +8245,7 @@ const qtparam = async (BASEURL, cookie) => {
|
|
|
8007
8245
|
126,
|
|
8008
8246
|
127
|
|
8009
8247
|
];
|
|
8010
|
-
|
|
8011
|
-
logininfo.data.vipStatus === 1 ? isvip = true : isvip = false;
|
|
8248
|
+
const isvip = logininfo.data.vipStatus === 1;
|
|
8012
8249
|
if (isvip) return {
|
|
8013
8250
|
QUERY: `&fnval=4048&fourk=1&${sign}`,
|
|
8014
8251
|
STATUS: "isLogin",
|
|
@@ -8343,7 +8580,7 @@ const fetchBilibili = async (data, cookie, requestConfig) => {
|
|
|
8343
8580
|
...baseRequestConfig,
|
|
8344
8581
|
url: checkStatusUrl
|
|
8345
8582
|
})).data === null) {
|
|
8346
|
-
|
|
8583
|
+
emitLogError("评论区未开放");
|
|
8347
8584
|
return {
|
|
8348
8585
|
code: 404,
|
|
8349
8586
|
message: "评论区未开放",
|
|
@@ -8374,7 +8611,7 @@ const fetchBilibili = async (data, cookie, requestConfig) => {
|
|
|
8374
8611
|
} else isEnd = true;
|
|
8375
8612
|
requestCount++;
|
|
8376
8613
|
if (isEnd || currentComments.length === 0 || !nextPaginationStr) {
|
|
8377
|
-
|
|
8614
|
+
emitLogInfo("已到达评论末尾或无更多评论");
|
|
8378
8615
|
break;
|
|
8379
8616
|
}
|
|
8380
8617
|
}
|
|
@@ -8457,6 +8694,10 @@ const fetchBilibili = async (data, cookie, requestConfig) => {
|
|
|
8457
8694
|
url: bilibiliApiUrls.getUserCard({ host_mid })
|
|
8458
8695
|
});
|
|
8459
8696
|
}
|
|
8697
|
+
case "userLiveStatus": return await GlobalGetData(data.methodType, {
|
|
8698
|
+
...baseRequestConfig,
|
|
8699
|
+
url: bilibiliApiUrls.getUserLiveStatus({ host_mid: data.host_mid })
|
|
8700
|
+
});
|
|
8460
8701
|
case "userSpaceInfo": {
|
|
8461
8702
|
const wbiSignQuery = await wbi_sign(bilibiliApiUrls.getUserSpaceInfo({ host_mid: data.host_mid }), baseRequestConfig.headers?.cookie);
|
|
8462
8703
|
return await GlobalGetData(data.methodType, {
|
|
@@ -8613,7 +8854,7 @@ const fetchBilibili = async (data, cookie, requestConfig) => {
|
|
|
8613
8854
|
}
|
|
8614
8855
|
}
|
|
8615
8856
|
default:
|
|
8616
|
-
|
|
8857
|
+
emitLogWarn(`未知的B站数据接口:「${data.methodType}」`);
|
|
8617
8858
|
return null;
|
|
8618
8859
|
}
|
|
8619
8860
|
};
|
|
@@ -8649,11 +8890,11 @@ const GlobalGetData = async (type, options, retryCount = 0) => {
|
|
|
8649
8890
|
requestUrl: options.url
|
|
8650
8891
|
};
|
|
8651
8892
|
warningMessage = `
|
|
8652
|
-
|
|
8893
|
+
获取响应数据失败!原因:接口返回内容为空,你的B站ck可能已经失效!
|
|
8653
8894
|
请求类型:「${type}」
|
|
8654
8895
|
请求URL:${options.url}
|
|
8655
8896
|
`;
|
|
8656
|
-
|
|
8897
|
+
emitLogWarn(warningMessage);
|
|
8657
8898
|
const riskError = new Error(Err.errorDescription);
|
|
8658
8899
|
Object.assign(riskError, {
|
|
8659
8900
|
code: "-352",
|
|
@@ -8675,12 +8916,12 @@ const GlobalGetData = async (type, options, retryCount = 0) => {
|
|
|
8675
8916
|
responseCode: result.code
|
|
8676
8917
|
};
|
|
8677
8918
|
warningMessage = `
|
|
8678
|
-
获取响应数据失败!原因:${
|
|
8919
|
+
获取响应数据失败!原因:${errorMessage}
|
|
8679
8920
|
错误代码:${result.code}
|
|
8680
8921
|
请求类型:「${type}」
|
|
8681
8922
|
请求URL:${options.url}
|
|
8682
8923
|
`;
|
|
8683
|
-
|
|
8924
|
+
emitLogWarn(warningMessage);
|
|
8684
8925
|
const apiError = new Error(Err.errorDescription);
|
|
8685
8926
|
Object.assign(apiError, {
|
|
8686
8927
|
code: result.code,
|
|
@@ -9164,15 +9405,6 @@ const kuaishouUtils = {
|
|
|
9164
9405
|
//#endregion
|
|
9165
9406
|
//#region src/platform/xiaohongshu/XiaohongshuApi.ts
|
|
9166
9407
|
/**
|
|
9167
|
-
* 小红书 API 模块 (已废弃)
|
|
9168
|
-
*
|
|
9169
|
-
* 此模块中的 API 已在 v6 版本废弃
|
|
9170
|
-
* 请使用 xiaohongshuFetcher 或 client.xiaohongshu.fetcher 替代
|
|
9171
|
-
*
|
|
9172
|
-
* @module platform/xiaohongshu/XiaohongshuApi
|
|
9173
|
-
* @deprecated v6 已废弃,请使用 fetcher API 替代
|
|
9174
|
-
*/
|
|
9175
|
-
/**
|
|
9176
9408
|
* 创建废弃的 API 存根函数
|
|
9177
9409
|
*/
|
|
9178
9410
|
const createDeprecatedStub = (methodName) => {
|
|
@@ -9551,6 +9783,7 @@ const BilibiliInternalMethods = {
|
|
|
9551
9783
|
COMMENT_REPLIES: "指定评论的回复",
|
|
9552
9784
|
USER_CARD: "用户主页数据",
|
|
9553
9785
|
USER_DYNAMICS: "用户主页动态列表数据",
|
|
9786
|
+
USER_LIVE_STATUS: "用户直播状态",
|
|
9554
9787
|
USER_SPACE_INFO: "用户空间详细信息",
|
|
9555
9788
|
USER_TOTAL_VIEWS: "获取UP主总播放量",
|
|
9556
9789
|
DYNAMIC_DETAIL: "动态详情数据",
|
|
@@ -9581,6 +9814,7 @@ const BilibiliFetcherMethods = {
|
|
|
9581
9814
|
COMMENT_REPLIES: "fetchCommentReplies",
|
|
9582
9815
|
USER_CARD: "fetchUserCard",
|
|
9583
9816
|
USER_DYNAMICS: "fetchUserDynamicList",
|
|
9817
|
+
USER_LIVE_STATUS: "fetchUserLiveStatus",
|
|
9584
9818
|
USER_SPACE_INFO: "fetchUserSpaceInfo",
|
|
9585
9819
|
USER_TOTAL_VIEWS: "fetchUploaderTotalViews",
|
|
9586
9820
|
DYNAMIC_DETAIL: "fetchDynamicDetail",
|
|
@@ -9689,6 +9923,7 @@ const BilibiliMethodToFetcher = {
|
|
|
9689
9923
|
[BilibiliInternalMethods.COMMENT_REPLIES]: BilibiliFetcherMethods.COMMENT_REPLIES,
|
|
9690
9924
|
[BilibiliInternalMethods.USER_CARD]: BilibiliFetcherMethods.USER_CARD,
|
|
9691
9925
|
[BilibiliInternalMethods.USER_DYNAMICS]: BilibiliFetcherMethods.USER_DYNAMICS,
|
|
9926
|
+
[BilibiliInternalMethods.USER_LIVE_STATUS]: BilibiliFetcherMethods.USER_LIVE_STATUS,
|
|
9692
9927
|
[BilibiliInternalMethods.USER_SPACE_INFO]: BilibiliFetcherMethods.USER_SPACE_INFO,
|
|
9693
9928
|
[BilibiliInternalMethods.USER_TOTAL_VIEWS]: BilibiliFetcherMethods.USER_TOTAL_VIEWS,
|
|
9694
9929
|
[BilibiliInternalMethods.DYNAMIC_DETAIL]: BilibiliFetcherMethods.DYNAMIC_DETAIL,
|
|
@@ -9820,6 +10055,7 @@ const BilibiliMethodMapping = {
|
|
|
9820
10055
|
指定评论的回复: "fetchCommentReplies",
|
|
9821
10056
|
用户主页数据: "fetchUserCard",
|
|
9822
10057
|
用户主页动态列表数据: "fetchUserDynamicList",
|
|
10058
|
+
用户直播状态: "fetchUserLiveStatus",
|
|
9823
10059
|
用户空间详细信息: "fetchUserSpaceInfo",
|
|
9824
10060
|
获取UP主总播放量: "fetchUploaderTotalViews",
|
|
9825
10061
|
动态详情数据: "fetchDynamicDetail",
|
|
@@ -9902,6 +10138,7 @@ const BilibiliApiRoutes = {
|
|
|
9902
10138
|
commentReplies: "/comment-replies",
|
|
9903
10139
|
userCard: "/user",
|
|
9904
10140
|
userDynamicList: "/user/dynamics",
|
|
10141
|
+
userLiveStatus: "/user/live-status",
|
|
9905
10142
|
userSpaceInfo: "/user/space",
|
|
9906
10143
|
uploaderTotalViews: "/user/total-views",
|
|
9907
10144
|
dynamicDetail: "/dynamic",
|
|
@@ -9975,7 +10212,7 @@ function getApiRoute(platform, methodType) {
|
|
|
9975
10212
|
* 构建后使用 __VERSION__,开发环境从 package.json 读取
|
|
9976
10213
|
*/
|
|
9977
10214
|
const getVersion = () => {
|
|
9978
|
-
return "6.
|
|
10215
|
+
return "6.3.0";
|
|
9979
10216
|
};
|
|
9980
10217
|
const VERSION = getVersion();
|
|
9981
10218
|
/**
|
|
@@ -10022,6 +10259,11 @@ const CreateApp = CreateAmagiApp;
|
|
|
10022
10259
|
/** After instantiation, it can interact with the specified platform API to quickly obtain data. */
|
|
10023
10260
|
const Client = CreateApp;
|
|
10024
10261
|
const amagi = Client;
|
|
10262
|
+
/*!
|
|
10263
|
+
* @ikenxuan/amagi
|
|
10264
|
+
* Copyright(c) 2023 ikenxuan
|
|
10265
|
+
* GPL-3.0 Licensed
|
|
10266
|
+
*/
|
|
10025
10267
|
//#endregion
|
|
10026
10268
|
export { AdditionalType, ApiError, BilibiliApiRoutes, BilibiliApplyCaptchaParamsSchema, BilibiliArticleCardParamsSchema, BilibiliArticleInfoParamsSchema, BilibiliArticleParamsSchema, BilibiliAv2BvParamsSchema, BilibiliBangumiInfoParamsSchema, BilibiliBangumiStreamParamsSchema, BilibiliBv2AvParamsSchema, BilibiliColumnInfoParamsSchema, BilibiliCommentParamsSchema, BilibiliCommentReplyParamsSchema, BilibiliDanmakuParamsSchema, BilibiliDynamicParamsSchema, BilibiliEmojiParamsSchema, BilibiliFetcherMethods, BilibiliInternalMethods, BilibiliLiveParamsSchema, BilibiliLoginParamsSchema, BilibiliMethodMapping, BilibiliMethodRoutes, BilibiliMethodToFetcher, BilibiliQrcodeParamsSchema, BilibiliQrcodeStatusParamsSchema, BilibiliUserParamsSchema, BilibiliValidateCaptchaParamsSchema, BilibiliValidationSchemas, BilibiliVideoDownloadParamsSchema, BilibiliVideoParamsSchema, CommentType, CreateApp, DouyinApiRoutes, DouyinCommentParamsSchema, DouyinCommentReplyParamsSchema, DouyinDanmakuParamsSchema, DouyinEmojiListParamsSchema, DouyinEmojiProParamsSchema, DouyinFetcherMethods, DouyinHotWordsParamsSchema, DouyinInternalMethods, DouyinLiveRoomParamsSchema, DouyinMethodMapping, DouyinMethodRoutes, DouyinMethodToFetcher, DouyinMusicParamsSchema, DouyinQrcodeParamsSchema, DouyinSearchParamsSchema, DouyinUserListParamsSchema, DouyinUserParamsSchema, DouyinValidationSchemas, DouyinWorkParamsSchema, DynamicType, KuaishouApiRoutes, KuaishouCommentParamsSchema, KuaishouEmojiParamsSchema, KuaishouFetcherMethods, KuaishouInternalMethods, KuaishouLiveRoomInfoParamsSchema, KuaishouMethodMapping, KuaishouMethodRoutes, KuaishouMethodToFetcher, KuaishouUserProfileParamsSchema, KuaishouUserWorkListParamsSchema, KuaishouValidationSchemas, KuaishouVideoParamsSchema, MajorType, MethodMaps, ValidationError, XiaohongshuApiRoutes, XiaohongshuFetcherMethods, XiaohongshuInternalMethods, XiaohongshuMethodMapping, XiaohongshuMethodRoutes, XiaohongshuMethodToFetcher, XiaohongshuValidationSchemas, amagi, amagiClient, amagiEvents, av2bv, bilibili, bilibiliApiUrls, bilibiliErrorCodeMap, bilibiliFetcher, bilibiliUtils, bv2av, createAmagiClient, createBilibiliRoutes, createBilibiliRoutes as registerBilibiliRoutes, createBoundBilibiliApi, createBoundBilibiliFetcher, createBoundDouyinApi, createBoundDouyinFetcher, createBoundKuaishouApi, createBoundKuaishouFetcher, createBoundXiaohongshuApi, createBoundXiaohongshuFetcher, createDouyinRoutes, createDouyinRoutes as registerDouyinRoutes, createErrorResponse, createKuaishouRoutes, createKuaishouRoutes as registerKuaishouRoutes, createSuccessResponse, createXiaohongshuRoutes, createXiaohongshuRoutes as registerXiaohongshuRoutes, Client as default, douyin, douyinApiUrls, douyinFetcher, douyinSign, douyinUtils, emitApiError, emitApiSuccess, emitHttpRequest, emitHttpResponse, emitLog, emitLogDebug, emitLogError, emitLogInfo, emitLogMark, emitLogWarn, emitNetworkError, emitNetworkRetry, fetchData, fetchResponse, getApiRoute, getBilibiliData, getDouyinData, getEnglishMethodName, getHeadersAndData, getKuaishouData, handleError, httpLogger, initLogger, isNetworkErrorResult, kuaishou, kuaishouApiUrls, kuaishouFetcher, kuaishouSign, kuaishouUtils, logMiddleware, logger, parseDmSegMobileReply, qtparam, toFetcherMethod, validateBilibiliParams, validateDouyinParams, validateKuaishouParams, validateXiaohongshuParams, wbi_sign, xiaohongshu, xiaohongshuApiUrls, xiaohongshuFetcher, xiaohongshuSign, xiaohongshuUtils };
|
|
10027
10269
|
|