@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.cjs
CHANGED
|
@@ -2,22 +2,22 @@ Object.defineProperties(exports, {
|
|
|
2
2
|
__esModule: { value: true },
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
|
-
const
|
|
5
|
+
const require_rolldown_runtime = require("../rolldown-runtime-D6vf50IK.cjs");
|
|
6
6
|
let node_url = require("node:url");
|
|
7
|
-
node_url =
|
|
7
|
+
node_url = require_rolldown_runtime.__toESM(node_url, 1);
|
|
8
8
|
let node_events = require("node:events");
|
|
9
9
|
let zod = require("zod");
|
|
10
|
-
zod =
|
|
10
|
+
zod = require_rolldown_runtime.__toESM(zod, 1);
|
|
11
11
|
let _ikenxuan_xhshow_ts = require("@ikenxuan/xhshow-ts");
|
|
12
12
|
let node_crypto = require("node:crypto");
|
|
13
|
-
node_crypto =
|
|
13
|
+
node_crypto = require_rolldown_runtime.__toESM(node_crypto, 1);
|
|
14
14
|
let axios = require("axios");
|
|
15
|
-
axios =
|
|
15
|
+
axios = require_rolldown_runtime.__toESM(axios, 1);
|
|
16
16
|
let chalk = require("chalk");
|
|
17
17
|
let protobufjs = require("protobufjs");
|
|
18
|
-
protobufjs =
|
|
18
|
+
protobufjs = require_rolldown_runtime.__toESM(protobufjs, 1);
|
|
19
19
|
let express = require("express");
|
|
20
|
-
express =
|
|
20
|
+
express = require_rolldown_runtime.__toESM(express, 1);
|
|
21
21
|
//#region src/utils/deprecation.ts
|
|
22
22
|
/**
|
|
23
23
|
* 废弃 API 注册表
|
|
@@ -541,6 +541,15 @@ var BilibiliAPI = class {
|
|
|
541
541
|
getUserCard(data) {
|
|
542
542
|
return `https://api.bilibili.com/x/web-interface/card?mid=${data.host_mid}&photo=true`;
|
|
543
543
|
}
|
|
544
|
+
/**
|
|
545
|
+
* 按用户 UID 获取直播状态。
|
|
546
|
+
*
|
|
547
|
+
* @remarks
|
|
548
|
+
* 该接口直接返回用户当前直播状态,不依赖空间动态中的直播推荐卡片。
|
|
549
|
+
*/
|
|
550
|
+
getUserLiveStatus(data) {
|
|
551
|
+
return `https://api.live.bilibili.com/room/v1/Room/getRoomInfoOld?mid=${data.host_mid}`;
|
|
552
|
+
}
|
|
544
553
|
/** 获取直播间信息 */
|
|
545
554
|
getLiveRoomInfo(data) {
|
|
546
555
|
return `https://api.live.bilibili.com/room/v1/Room/get_info?room_id=${data.room_id}`;
|
|
@@ -986,6 +995,7 @@ const BilibiliUserParamsSchema = zod.default.object({
|
|
|
986
995
|
methodType: zod.default.enum([
|
|
987
996
|
"userCard",
|
|
988
997
|
"userDynamicList",
|
|
998
|
+
"userLiveStatus",
|
|
989
999
|
"uploaderTotalViews",
|
|
990
1000
|
"userSpaceInfo"
|
|
991
1001
|
], { error: "方法类型必须是指定的枚举值之一" }),
|
|
@@ -1086,6 +1096,7 @@ const BilibiliValidationSchemas = {
|
|
|
1086
1096
|
commentReplies: BilibiliCommentReplyParamsSchema,
|
|
1087
1097
|
userCard: BilibiliUserParamsSchema,
|
|
1088
1098
|
userDynamicList: BilibiliUserParamsSchema,
|
|
1099
|
+
userLiveStatus: BilibiliUserParamsSchema,
|
|
1089
1100
|
userSpaceInfo: BilibiliUserParamsSchema,
|
|
1090
1101
|
emojiList: BilibiliEmojiParamsSchema,
|
|
1091
1102
|
bangumiInfo: BilibiliBangumiInfoParamsSchema,
|
|
@@ -1116,6 +1127,7 @@ const BilibiliMethodRoutes = {
|
|
|
1116
1127
|
commentReplies: "/fetch_comment_reply",
|
|
1117
1128
|
userCard: "/fetch_user_profile",
|
|
1118
1129
|
userDynamicList: "/fetch_user_dynamic",
|
|
1130
|
+
userLiveStatus: "/fetch_user_live_status",
|
|
1119
1131
|
userSpaceInfo: "/fetch_user_space_info",
|
|
1120
1132
|
emojiList: "/fetch_emoji_list",
|
|
1121
1133
|
bangumiInfo: "/fetch_bangumi_video_info",
|
|
@@ -1349,12 +1361,194 @@ const KuaishouMethodRoutes = {
|
|
|
1349
1361
|
emojiList: "/fetch_emoji_list"
|
|
1350
1362
|
};
|
|
1351
1363
|
//#endregion
|
|
1364
|
+
//#region src/platform/xiaohongshu/sign/config.ts
|
|
1365
|
+
/** 初始化签名配置。 */
|
|
1366
|
+
const createXiaohongshuCryptoConfig = () => new _ikenxuan_xhshow_ts.CryptoConfig().withOverrides({
|
|
1367
|
+
DATA_WEB_BUILD: "6.12.3",
|
|
1368
|
+
SIGNATURE_DATA_TEMPLATE: {
|
|
1369
|
+
x0: "4.3.5",
|
|
1370
|
+
x1: "xhs-pc-web",
|
|
1371
|
+
x2: "Windows",
|
|
1372
|
+
x3: "",
|
|
1373
|
+
x4: ""
|
|
1374
|
+
},
|
|
1375
|
+
SIGNATURE_XSCOMMON_TEMPLATE: {
|
|
1376
|
+
s0: 5,
|
|
1377
|
+
s1: "",
|
|
1378
|
+
x0: "1",
|
|
1379
|
+
x1: "4.3.5",
|
|
1380
|
+
x2: "Windows",
|
|
1381
|
+
x3: "xhs-pc-web",
|
|
1382
|
+
x4: "6.12.3",
|
|
1383
|
+
x5: "",
|
|
1384
|
+
x6: "",
|
|
1385
|
+
x7: "",
|
|
1386
|
+
x8: "",
|
|
1387
|
+
x9: -596800761,
|
|
1388
|
+
x10: 0,
|
|
1389
|
+
x11: "normal"
|
|
1390
|
+
}
|
|
1391
|
+
});
|
|
1392
|
+
//#endregion
|
|
1393
|
+
//#region src/platform/xiaohongshu/sign/guestCookie.ts
|
|
1394
|
+
/** @see https://github.com/Cialle/RedCrack */
|
|
1395
|
+
/** 小红书 Web 端游客会话初始化使用的浏览器请求头。 */
|
|
1396
|
+
const GUEST_HEADERS = {
|
|
1397
|
+
accept: "application/json, text/plain, */*",
|
|
1398
|
+
"accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
|
|
1399
|
+
"content-type": "application/json;charset=UTF-8",
|
|
1400
|
+
origin: "https://www.xiaohongshu.com",
|
|
1401
|
+
priority: "u=1, i",
|
|
1402
|
+
referer: "https://www.xiaohongshu.com/",
|
|
1403
|
+
"sec-ch-ua": "\"Microsoft Edge\";v=\"141\", \"Not?A_Brand\";v=\"8\", \"Chromium\";v=\"141\"",
|
|
1404
|
+
"sec-ch-ua-mobile": "?0",
|
|
1405
|
+
"sec-ch-ua-platform": "\"Windows\"",
|
|
1406
|
+
"sec-fetch-dest": "empty",
|
|
1407
|
+
"sec-fetch-mode": "cors",
|
|
1408
|
+
"sec-fetch-site": "same-site",
|
|
1409
|
+
"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"
|
|
1410
|
+
};
|
|
1411
|
+
/** 生成 a1 随机段时使用的 Web 端字符集。 */
|
|
1412
|
+
const COOKIE_RANDOM_CHARS = "abcdefghijklmnopqrstuvwxyz1234567890";
|
|
1413
|
+
/** 将 Cookie Jar 序列化为可直接写入 HTTP Cookie 请求头的字符串。 */
|
|
1414
|
+
const toCookieString = (cookies) => Object.entries(cookies).map(([key, value]) => `${key}=${value}`).join("; ");
|
|
1415
|
+
/** 将响应头中的 Set-Cookie 字段合并到当前游客会话的 Cookie Jar。 */
|
|
1416
|
+
const updateCookiesFromResponse = (cookies, setCookie) => {
|
|
1417
|
+
const headers = Array.isArray(setCookie) ? setCookie : setCookie ? [setCookie] : [];
|
|
1418
|
+
for (const header of headers) {
|
|
1419
|
+
const [nameValue] = header.split(";", 1);
|
|
1420
|
+
const separatorIndex = nameValue.indexOf("=");
|
|
1421
|
+
if (separatorIndex > 0) cookies[nameValue.slice(0, separatorIndex).trim()] = nameValue.slice(separatorIndex + 1).trim();
|
|
1422
|
+
}
|
|
1423
|
+
};
|
|
1424
|
+
/** 按小红书 Web 端规则生成 a1,以及由 a1 派生的 webId。 */
|
|
1425
|
+
const generateA1AndWebId = () => {
|
|
1426
|
+
const source = `${Date.now().toString(16)}${Array.from((0, node_crypto.randomBytes)(30), (byte) => COOKIE_RANDOM_CHARS[byte % 36]).join("")}5000`;
|
|
1427
|
+
const a1 = `${source}${crc32(source)}`.slice(0, 52);
|
|
1428
|
+
return {
|
|
1429
|
+
a1,
|
|
1430
|
+
webId: (0, node_crypto.createHash)("md5").update(a1).digest("hex")
|
|
1431
|
+
};
|
|
1432
|
+
};
|
|
1433
|
+
/** 计算与浏览器端实现兼容的无符号 CRC32 校验值。 */
|
|
1434
|
+
const crc32 = (input) => {
|
|
1435
|
+
let value = 4294967295;
|
|
1436
|
+
for (const byte of Buffer.from(input)) {
|
|
1437
|
+
value ^= byte;
|
|
1438
|
+
for (let bit = 0; bit < 8; bit += 1) value = value & 1 ? value >>> 1 ^ 3988292384 : value >>> 1;
|
|
1439
|
+
}
|
|
1440
|
+
return (value ^ 4294967295) >>> 0;
|
|
1441
|
+
};
|
|
1442
|
+
/** 从 scripting 接口返回的 VMP 数据中解码 websectiga Cookie。 */
|
|
1443
|
+
const generateWebsectiga = (payload) => {
|
|
1444
|
+
const bMatch = payload.match(/"b":"(.*?)",/);
|
|
1445
|
+
const dMatch = payload.match(/"d":(.*?)\}\)/);
|
|
1446
|
+
if (!bMatch || !dMatch) throw new Error("小红书 scripting 响应格式异常,无法生成 websectiga");
|
|
1447
|
+
const decoderData = JSON.parse(dMatch[1]);
|
|
1448
|
+
const encoded = Buffer.from(bMatch[1], "base64").toString("utf8");
|
|
1449
|
+
const logicList = [];
|
|
1450
|
+
for (let index = 0; index < encoded.length; index += 5) logicList.push(Array.from(encoded.slice(index, index + 5), (char) => char.charCodeAt(0) - 1));
|
|
1451
|
+
const start = decoderData[92];
|
|
1452
|
+
const end = decoderData[93];
|
|
1453
|
+
const target = logicList.slice(start, end + 1);
|
|
1454
|
+
const key = Array.from({ length: 64 }, (_, index) => {
|
|
1455
|
+
const item = target[675 + index * 2];
|
|
1456
|
+
if (!item) throw new Error("小红书 scripting 响应缺少 websectiga 解码数据");
|
|
1457
|
+
return decoderData[item[2]];
|
|
1458
|
+
});
|
|
1459
|
+
return Array.from({ length: 8 }, (_, group) => {
|
|
1460
|
+
const offset = 56 - group * 8;
|
|
1461
|
+
return String.fromCharCode(...key.slice(offset, offset + 8));
|
|
1462
|
+
}).join("");
|
|
1463
|
+
};
|
|
1464
|
+
/** 将浏览器指纹编码为 webprofile 接口要求的 DES-ECB profileData。 */
|
|
1465
|
+
const encryptProfileData = (fingerprint, desKey) => {
|
|
1466
|
+
const encoded = Buffer.from(JSON.stringify(fingerprint)).toString("base64");
|
|
1467
|
+
const blockSize = 8;
|
|
1468
|
+
const padding = blockSize - encoded.length % blockSize;
|
|
1469
|
+
const plaintext = Buffer.concat([Buffer.from(encoded), Buffer.alloc(padding)]);
|
|
1470
|
+
const cipher = (0, node_crypto.createCipheriv)("des-ede3", Buffer.from(desKey.repeat(3)), null);
|
|
1471
|
+
cipher.setAutoPadding(false);
|
|
1472
|
+
return Buffer.concat([cipher.update(plaintext), cipher.final()]).toString("hex");
|
|
1473
|
+
};
|
|
1474
|
+
/** 将 scripting 的 JSON 或 JSONP 响应统一还原为结构化数据。 */
|
|
1475
|
+
const unwrapScriptingResponse = (data) => {
|
|
1476
|
+
if (typeof data === "string") {
|
|
1477
|
+
const json = data.match(/^[^(]+\((.*)\)$/s)?.[1];
|
|
1478
|
+
return JSON.parse(json ?? data);
|
|
1479
|
+
}
|
|
1480
|
+
return data;
|
|
1481
|
+
};
|
|
1482
|
+
/**
|
|
1483
|
+
* 创建小红书 Web 端游客会话 Cookie。
|
|
1484
|
+
*
|
|
1485
|
+
* 该流程对应 Web 端首次访问时的 Cookie 初始化:生成 a1/webId,完成
|
|
1486
|
+
* scripting、webprofile 与 activate 三个会话请求,并返回最终 Cookie 字符串。
|
|
1487
|
+
*/
|
|
1488
|
+
const createXiaohongshuGuestCookie = async (requestConfig) => {
|
|
1489
|
+
const cryptoConfig = createXiaohongshuCryptoConfig();
|
|
1490
|
+
const signer = new _ikenxuan_xhshow_ts.Xhshow(cryptoConfig);
|
|
1491
|
+
const cookies = {
|
|
1492
|
+
...generateA1AndWebId(),
|
|
1493
|
+
webBuild: cryptoConfig.DATA_WEB_BUILD,
|
|
1494
|
+
xsecappid: "xhs-pc-web",
|
|
1495
|
+
loadts: String(Date.now()),
|
|
1496
|
+
abRequestId: (0, node_crypto.randomUUID)()
|
|
1497
|
+
};
|
|
1498
|
+
const { headers: requestHeaders, params: _params, ...transportConfig } = requestConfig ?? {};
|
|
1499
|
+
/** 发送会话初始化请求,并将响应中的 Set-Cookie 合并回当前 Cookie Jar。 */
|
|
1500
|
+
const request = async (url, data, signed = false) => {
|
|
1501
|
+
const signatureHeaders = signed ? signer.signHeadersPost(new URL(url).pathname, cookies, "xhs-pc-web", data) : {};
|
|
1502
|
+
const response = await (0, axios.default)({
|
|
1503
|
+
...transportConfig,
|
|
1504
|
+
method: "POST",
|
|
1505
|
+
url,
|
|
1506
|
+
data,
|
|
1507
|
+
validateStatus: () => true,
|
|
1508
|
+
headers: {
|
|
1509
|
+
...GUEST_HEADERS,
|
|
1510
|
+
...requestHeaders,
|
|
1511
|
+
...signatureHeaders,
|
|
1512
|
+
Cookie: toCookieString(cookies)
|
|
1513
|
+
}
|
|
1514
|
+
});
|
|
1515
|
+
updateCookiesFromResponse(cookies, response.headers["set-cookie"]);
|
|
1516
|
+
if (response.status < 200 || response.status >= 300) throw new Error(`小红书游客会话初始化失败:${url} 返回 HTTP ${response.status}`);
|
|
1517
|
+
return response.data;
|
|
1518
|
+
};
|
|
1519
|
+
const scriptingData = unwrapScriptingResponse(await request("https://as.xiaohongshu.com/api/sec/v1/scripting", {
|
|
1520
|
+
callFrom: "web",
|
|
1521
|
+
callback: "seccallback"
|
|
1522
|
+
})).data;
|
|
1523
|
+
if (!scriptingData?.data || !scriptingData.secPoisonId) throw new Error("小红书 scripting 响应缺少游客会话数据");
|
|
1524
|
+
cookies.websectiga = generateWebsectiga(scriptingData.data);
|
|
1525
|
+
cookies.sec_poison_id = scriptingData.secPoisonId;
|
|
1526
|
+
const fingerprint = new _ikenxuan_xhshow_ts.FingerprintGenerator(cryptoConfig).generate(cookies, GUEST_HEADERS["user-agent"]);
|
|
1527
|
+
await request(cryptoConfig.GID_URL, {
|
|
1528
|
+
platform: cryptoConfig.DATA_PLATFORM,
|
|
1529
|
+
profileData: encryptProfileData(fingerprint, cryptoConfig.DES_KEY),
|
|
1530
|
+
sdkVersion: cryptoConfig.DATA_SDK_VERSION,
|
|
1531
|
+
svn: cryptoConfig.DATA_SVN
|
|
1532
|
+
}, true);
|
|
1533
|
+
await request("https://edith.xiaohongshu.com/api/sns/web/v1/login/activate", {}, true);
|
|
1534
|
+
if (!cookies.web_session) throw new Error("小红书游客会话初始化失败:未获取到 web_session");
|
|
1535
|
+
return toCookieString(cookies);
|
|
1536
|
+
};
|
|
1537
|
+
//#endregion
|
|
1352
1538
|
//#region src/platform/xiaohongshu/sign/index.ts
|
|
1353
1539
|
/**
|
|
1354
1540
|
* 小红书签名算法类
|
|
1355
1541
|
*/
|
|
1356
1542
|
var xiaohongshuSign = class {
|
|
1357
|
-
static client = new _ikenxuan_xhshow_ts.Xhshow();
|
|
1543
|
+
static client = new _ikenxuan_xhshow_ts.Xhshow(createXiaohongshuCryptoConfig());
|
|
1544
|
+
/**
|
|
1545
|
+
* 创建包含 web_session 的小红书 Web 端游客 Cookie。
|
|
1546
|
+
*
|
|
1547
|
+
* `requestConfig` 会透传到游客会话初始化请求,可用于配置代理、超时等传输参数。
|
|
1548
|
+
*/
|
|
1549
|
+
static createGuestCookie(requestConfig) {
|
|
1550
|
+
return createXiaohongshuGuestCookie(requestConfig);
|
|
1551
|
+
}
|
|
1358
1552
|
/**
|
|
1359
1553
|
* 生成GET请求的X-S签名
|
|
1360
1554
|
* @param path - API路径
|
|
@@ -1567,7 +1761,7 @@ const xiaohongshuApiUrls = {
|
|
|
1567
1761
|
* @param data - 请求参数
|
|
1568
1762
|
* @returns 完整的接口URL
|
|
1569
1763
|
*/
|
|
1570
|
-
emojiList(
|
|
1764
|
+
emojiList(_data) {
|
|
1571
1765
|
return {
|
|
1572
1766
|
apiPath: "/api/im/redmoji/detail",
|
|
1573
1767
|
Url: "https://edith.xiaohongshu.com/api/im/redmoji/detail"
|
|
@@ -2205,6 +2399,27 @@ async function fetchUserDynamicList(options, cookie, requestConfig) {
|
|
|
2205
2399
|
});
|
|
2206
2400
|
}
|
|
2207
2401
|
/**
|
|
2402
|
+
* 按用户 UID 获取B站直播状态
|
|
2403
|
+
* @param options - 用户参数
|
|
2404
|
+
* @param options.host_mid - 用户 UID
|
|
2405
|
+
* @param cookie - B站 Cookie (可选)
|
|
2406
|
+
* @param requestConfig - 请求配置 (可选)
|
|
2407
|
+
* @returns 用户直播状态与直播间基础信息
|
|
2408
|
+
* @example
|
|
2409
|
+
* ```typescript
|
|
2410
|
+
* const result = await fetchUserLiveStatus({ host_mid: 123456, typeMode: 'strict' }, cookie)
|
|
2411
|
+
* if (result.success && result.data.data.liveStatus === 1) {
|
|
2412
|
+
* console.log(result.data.data.roomid) // 正在直播的房间 ID
|
|
2413
|
+
* }
|
|
2414
|
+
* ```
|
|
2415
|
+
*/
|
|
2416
|
+
async function fetchUserLiveStatus(options, cookie, requestConfig) {
|
|
2417
|
+
return fetchBilibiliInternal("userLiveStatus", options, {
|
|
2418
|
+
cookie,
|
|
2419
|
+
requestConfig
|
|
2420
|
+
});
|
|
2421
|
+
}
|
|
2422
|
+
/**
|
|
2208
2423
|
* 获取B站用户空间详细信息
|
|
2209
2424
|
* @param options - 用户参数
|
|
2210
2425
|
* @param options.host_mid - 用户 UID
|
|
@@ -2385,6 +2600,7 @@ function createBoundBilibiliFetcher(cookie, requestConfig) {
|
|
|
2385
2600
|
fetchCommentReplies: (options) => fetchCommentReplies$1(options, cookie, requestConfig),
|
|
2386
2601
|
fetchUserCard: (options) => fetchUserCard(options, cookie, requestConfig),
|
|
2387
2602
|
fetchUserDynamicList: (options) => fetchUserDynamicList(options, cookie, requestConfig),
|
|
2603
|
+
fetchUserLiveStatus: (options) => fetchUserLiveStatus(options, cookie, requestConfig),
|
|
2388
2604
|
fetchUserSpaceInfo: (options) => fetchUserSpaceInfo(options, cookie, requestConfig),
|
|
2389
2605
|
fetchUploaderTotalViews: (options) => fetchUploaderTotalViews(options, cookie, requestConfig),
|
|
2390
2606
|
fetchDynamicDetail: (options) => fetchDynamicDetail(options, cookie, requestConfig),
|
|
@@ -2432,6 +2648,7 @@ const bilibiliFetcher = {
|
|
|
2432
2648
|
fetchCommentReplies: fetchCommentReplies$1,
|
|
2433
2649
|
fetchUserCard,
|
|
2434
2650
|
fetchUserDynamicList,
|
|
2651
|
+
fetchUserLiveStatus,
|
|
2435
2652
|
fetchUserSpaceInfo,
|
|
2436
2653
|
fetchUploaderTotalViews,
|
|
2437
2654
|
fetchDynamicDetail,
|
|
@@ -2473,7 +2690,7 @@ const generateSecChUa = (userAgent) => {
|
|
|
2473
2690
|
*/
|
|
2474
2691
|
const getDouyinDefaultConfig = (cookie, requestConfig) => {
|
|
2475
2692
|
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";
|
|
2476
|
-
finalUserAgent = finalUserAgent.replace(/\s+Edg\/[\d
|
|
2693
|
+
finalUserAgent = finalUserAgent.replace(/\s+Edg\/[\d.]+/g, "");
|
|
2477
2694
|
const defHeaders = {
|
|
2478
2695
|
Accept: "application/json, text/plain, */*",
|
|
2479
2696
|
"Accept-Encoding": "gzip, deflate, br, zstd",
|
|
@@ -2648,7 +2865,8 @@ var SM3 = class {
|
|
|
2648
2865
|
this.chunk = this.chunk.concat(a.slice(0, f));
|
|
2649
2866
|
while (this.chunk.length >= 64) {
|
|
2650
2867
|
this._compress(this.chunk);
|
|
2651
|
-
f < a.length
|
|
2868
|
+
if (f < a.length) this.chunk = a.slice(f, Math.min(f + 64, a.length));
|
|
2869
|
+
else this.chunk = [];
|
|
2652
2870
|
f += 64;
|
|
2653
2871
|
}
|
|
2654
2872
|
}
|
|
@@ -2684,10 +2902,17 @@ var SM3 = class {
|
|
|
2684
2902
|
if (t.length < 64) console.error("compress error: not enough data");
|
|
2685
2903
|
else {
|
|
2686
2904
|
for (var f = ((e) => {
|
|
2687
|
-
for (var r = new Array(132), t = 0; t < 16; t++)
|
|
2905
|
+
for (var r = new Array(132), t = 0; t < 16; t++) {
|
|
2906
|
+
r[t] = e[4 * t] << 24;
|
|
2907
|
+
r[t] |= e[4 * t + 1] << 16;
|
|
2908
|
+
r[t] |= e[4 * t + 2] << 8;
|
|
2909
|
+
r[t] |= e[4 * t + 3];
|
|
2910
|
+
r[t] >>>= 0;
|
|
2911
|
+
}
|
|
2688
2912
|
for (var n = 16; n < 68; n++) {
|
|
2689
2913
|
let a = r[n - 16] ^ r[n - 9] ^ this.le(r[n - 3], 15);
|
|
2690
|
-
a = a ^ this.le(a, 15) ^ this.le(a, 23)
|
|
2914
|
+
a = a ^ this.le(a, 15) ^ this.le(a, 23);
|
|
2915
|
+
r[n] = (a ^ this.le(r[n - 13], 7) ^ r[n - 6]) >>> 0;
|
|
2691
2916
|
}
|
|
2692
2917
|
for (n = 0; n < 64; n++) r[n + 68] = (r[n] ^ r[n + 4]) >>> 0;
|
|
2693
2918
|
return r;
|
|
@@ -2697,7 +2922,15 @@ var SM3 = class {
|
|
|
2697
2922
|
let u = this.pe(c, i[0], i[1], i[2]);
|
|
2698
2923
|
u = (4294967295 & (u = u + i[3] + s + f[c + 68])) >>> 0;
|
|
2699
2924
|
let b = this.he(c, i[4], i[5], i[6]);
|
|
2700
|
-
b = (4294967295 & (b = b + i[7] + o + f[c])) >>> 0
|
|
2925
|
+
b = (4294967295 & (b = b + i[7] + o + f[c])) >>> 0;
|
|
2926
|
+
i[3] = i[2];
|
|
2927
|
+
i[2] = this.le(i[1], 9);
|
|
2928
|
+
i[1] = i[0];
|
|
2929
|
+
i[0] = u;
|
|
2930
|
+
i[7] = i[6];
|
|
2931
|
+
i[6] = this.le(i[5], 19);
|
|
2932
|
+
i[5] = i[4];
|
|
2933
|
+
i[4] = (b ^ this.le(b, 9) ^ this.le(b, 17)) >>> 0;
|
|
2701
2934
|
}
|
|
2702
2935
|
for (let l = 0; l < 8; l++) this.reg[l] = (this.reg[l] ^ i[l]) >>> 0;
|
|
2703
2936
|
}
|
|
@@ -3008,7 +3241,7 @@ function generate_random_str() {
|
|
|
3008
3241
|
* @returns 清理后的User-Agent字符串
|
|
3009
3242
|
*/
|
|
3010
3243
|
const cleanUserAgentForSigning = (userAgent) => {
|
|
3011
|
-
return userAgent.replace(/\s+Edg\/[\d
|
|
3244
|
+
return userAgent.replace(/\s+Edg\/[\d.]+/g, "");
|
|
3012
3245
|
};
|
|
3013
3246
|
/**
|
|
3014
3247
|
* 抖音a_bogus签名算法
|
|
@@ -3130,7 +3363,6 @@ var XBogus = class {
|
|
|
3130
3363
|
const array2 = this.md5StrToArray(this.md5(this.md5StrToArray("d41d8cd98f00b204e9800998ecf8427e")));
|
|
3131
3364
|
const urlEncryptedArray = this.md5Encrypt(urlPath);
|
|
3132
3365
|
const timestamp = Math.floor(Date.now() / 1e3);
|
|
3133
|
-
const ct = 536919696;
|
|
3134
3366
|
const newArray = [
|
|
3135
3367
|
64,
|
|
3136
3368
|
1,
|
|
@@ -3146,10 +3378,10 @@ var XBogus = class {
|
|
|
3146
3378
|
timestamp >> 16 & 255,
|
|
3147
3379
|
timestamp >> 8 & 255,
|
|
3148
3380
|
timestamp & 255,
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3381
|
+
32,
|
|
3382
|
+
0,
|
|
3383
|
+
190,
|
|
3384
|
+
144
|
|
3153
3385
|
];
|
|
3154
3386
|
let xorResult = newArray[0];
|
|
3155
3387
|
for (let i = 1; i < newArray.length; i++) xorResult ^= newArray[i];
|
|
@@ -4069,7 +4301,7 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4069
4301
|
if (isInvalidResponse) {
|
|
4070
4302
|
const desc = `抖音${typeStr}搜索返回无有效数据,疑似触发反爬机制,你的抖音Cookie可能已经失效!`;
|
|
4071
4303
|
const warningMessage = `
|
|
4072
|
-
获取响应数据失败!原因:${
|
|
4304
|
+
获取响应数据失败!原因:${typeStr}搜索返回无有效数据,疑似触发反爬机制
|
|
4073
4305
|
请求类型:「${data.methodType}」
|
|
4074
4306
|
搜索关键词:「${data.query}」
|
|
4075
4307
|
请求URL:${url}
|
|
@@ -4088,12 +4320,12 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4088
4320
|
if (!list || list.length === 0) {
|
|
4089
4321
|
const desc = `抖音${typeStr}搜索接口第一次请求就返回空数组,可能该关键词无搜索结果或触发风控限制,你的抖音Cookie可能已经失效!`;
|
|
4090
4322
|
const warningMessage = `
|
|
4091
|
-
获取响应数据失败!原因:${
|
|
4323
|
+
获取响应数据失败!原因:${typeStr}搜索接口第一次请求就返回空数组,你的抖音Cookie可能已经失效!
|
|
4092
4324
|
请求类型:「${data.methodType}」
|
|
4093
4325
|
搜索关键词:「${data.query}」
|
|
4094
4326
|
请求URL:${url}
|
|
4095
4327
|
`;
|
|
4096
|
-
|
|
4328
|
+
emitLogWarn(warningMessage);
|
|
4097
4329
|
return {
|
|
4098
4330
|
data: raw,
|
|
4099
4331
|
amagiError: {
|
|
@@ -4184,7 +4416,7 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4184
4416
|
});
|
|
4185
4417
|
currentStart = currentEnd;
|
|
4186
4418
|
}
|
|
4187
|
-
|
|
4419
|
+
emitLogDebug(`弹幕数据需要分${segments.length}段获取,总时长:${totalDuration}ms`);
|
|
4188
4420
|
const segmentPromises = segments.map(async (segment, index) => {
|
|
4189
4421
|
const url = douyinApiUrls.getDanmakuList({
|
|
4190
4422
|
aweme_id: data.aweme_id,
|
|
@@ -4197,10 +4429,10 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4197
4429
|
...baseRequestConfig,
|
|
4198
4430
|
url: buildSignedUrl(url, signType, userAgent)
|
|
4199
4431
|
});
|
|
4200
|
-
|
|
4432
|
+
emitLogDebug(`弹幕第${index + 1}段获取成功 (${segment.start}ms-${segment.end}ms)`);
|
|
4201
4433
|
return segmentData;
|
|
4202
4434
|
} catch (error) {
|
|
4203
|
-
|
|
4435
|
+
emitLogDebug(`弹幕第${index + 1}段获取失败 (${segment.start}ms-${segment.end}ms):`, error);
|
|
4204
4436
|
return null;
|
|
4205
4437
|
}
|
|
4206
4438
|
});
|
|
@@ -4229,7 +4461,7 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4229
4461
|
extra: finalExtra,
|
|
4230
4462
|
log_pb: finalLogPb
|
|
4231
4463
|
};
|
|
4232
|
-
|
|
4464
|
+
emitLogDebug(`弹幕数据合并完成,共获取${mergedDanmakuList.length}条弹幕`);
|
|
4233
4465
|
return finalDanmakuData;
|
|
4234
4466
|
}
|
|
4235
4467
|
default: {
|
|
@@ -4241,7 +4473,7 @@ const DouyinData = async (data, cookie, requestConfig) => {
|
|
|
4241
4473
|
url
|
|
4242
4474
|
});
|
|
4243
4475
|
}
|
|
4244
|
-
|
|
4476
|
+
emitLogWarn(`未知的抖音数据接口:「${data.methodType}」`);
|
|
4245
4477
|
return null;
|
|
4246
4478
|
}
|
|
4247
4479
|
}
|
|
@@ -4309,11 +4541,11 @@ const GlobalGetData$3 = async (type, config) => {
|
|
|
4309
4541
|
requestUrl: config.url
|
|
4310
4542
|
};
|
|
4311
4543
|
warningMessage = `
|
|
4312
|
-
|
|
4544
|
+
获取响应数据失败!原因:接口返回内容为空,你的抖音ck可能已经失效!
|
|
4313
4545
|
请求类型:「${type}」
|
|
4314
4546
|
请求URL:${config.url}
|
|
4315
4547
|
`;
|
|
4316
|
-
|
|
4548
|
+
emitLogWarn(warningMessage);
|
|
4317
4549
|
const cookieError = new Error(Err.errorDescription);
|
|
4318
4550
|
Object.assign(cookieError, {
|
|
4319
4551
|
code: "INVALID_COOKIE",
|
|
@@ -4330,11 +4562,11 @@ const GlobalGetData$3 = async (type, config) => {
|
|
|
4330
4562
|
requestUrl: config.url
|
|
4331
4563
|
};
|
|
4332
4564
|
warningMessage = `
|
|
4333
|
-
获取响应数据失败!原因:${
|
|
4565
|
+
获取响应数据失败!原因:${filterReason}
|
|
4334
4566
|
请求类型:「${type}」
|
|
4335
4567
|
请求URL:${config.url}
|
|
4336
4568
|
`;
|
|
4337
|
-
|
|
4569
|
+
emitLogWarn(warningMessage);
|
|
4338
4570
|
const filterError = new Error(Err.errorDescription);
|
|
4339
4571
|
Object.assign(filterError, {
|
|
4340
4572
|
code: "CONTENT_FILTERED",
|
|
@@ -5312,6 +5544,8 @@ const encodeBase64Url = (bytes) => {
|
|
|
5312
5544
|
* 数据流而最小化保留的局部算法。
|
|
5313
5545
|
*/
|
|
5314
5546
|
var KuaishouChaChaCipher = class {
|
|
5547
|
+
key;
|
|
5548
|
+
nonce;
|
|
5315
5549
|
wordIndex = 0;
|
|
5316
5550
|
state = new Array(16).fill(0);
|
|
5317
5551
|
constructor(key, nonce) {
|
|
@@ -6144,7 +6378,7 @@ const captureKuaishouEncodeStack = () => {
|
|
|
6144
6378
|
* @returns 用于 `SECS.s` 的栈尾字符串
|
|
6145
6379
|
*/
|
|
6146
6380
|
const deriveKuaishouSecsStackTail = (stack = captureKuaishouEncodeStack()) => {
|
|
6147
|
-
return stack.length > KUAISHOU_SECS_STACK_LIMIT ? stack.slice(-
|
|
6381
|
+
return stack.length > KUAISHOU_SECS_STACK_LIMIT ? stack.slice(-100) : stack;
|
|
6148
6382
|
};
|
|
6149
6383
|
/**
|
|
6150
6384
|
* 构造快手 `window.SECS` 的纯算法等价状态。
|
|
@@ -6997,7 +7231,7 @@ const KuaishouData = async (data, cookie, requestConfig) => {
|
|
|
6997
7231
|
}
|
|
6998
7232
|
case "emojiList": return fetchKuaishouGraphqlPayload(data.methodType, kuaishouApiUrls.emojiList());
|
|
6999
7233
|
default:
|
|
7000
|
-
|
|
7234
|
+
emitLogWarn(`Unknown Kuaishou API method: "${data.methodType}"`);
|
|
7001
7235
|
return null;
|
|
7002
7236
|
}
|
|
7003
7237
|
};
|
|
@@ -7036,12 +7270,12 @@ const GlobalGetData$2 = async (type, options, config) => {
|
|
|
7036
7270
|
requestBody: JSON.stringify(options.data)
|
|
7037
7271
|
};
|
|
7038
7272
|
warningMessage = `
|
|
7039
|
-
|
|
7273
|
+
获取响应数据失败!原因:接口返回内容为空,你的快手ck可能已经失效!
|
|
7040
7274
|
请求类型:「${type}」
|
|
7041
7275
|
请求URL:${options.url}
|
|
7042
7276
|
请求参数:${JSON.stringify(options.data, null, 2)}
|
|
7043
7277
|
`;
|
|
7044
|
-
|
|
7278
|
+
emitLogWarn(warningMessage);
|
|
7045
7279
|
const cookieError = new Error(Err.errorDescription);
|
|
7046
7280
|
Object.assign(cookieError, {
|
|
7047
7281
|
code: "INVALID_COOKIE",
|
|
@@ -7276,132 +7510,136 @@ function createBoundKuaishouFetcher(cookie, requestConfig) {
|
|
|
7276
7510
|
* @returns 返回小红书数据
|
|
7277
7511
|
*/
|
|
7278
7512
|
const XiaohongshuData = async (data, cookie, requestConfig) => {
|
|
7279
|
-
|
|
7280
|
-
const
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
...
|
|
7286
|
-
...requestConfig?.headers ?? {}
|
|
7287
|
-
}
|
|
7288
|
-
};
|
|
7289
|
-
const xiaohongshuApiUrls = createXiaohongshuApiUrls();
|
|
7290
|
-
switch (data.methodType) {
|
|
7291
|
-
case "homeFeed": return await GlobalGetData$1(data.methodType, {
|
|
7292
|
-
...baseRequestConfig,
|
|
7293
|
-
url: xiaohongshuApiUrls.homeFeed(data).Url,
|
|
7294
|
-
data: JSON.stringify(xiaohongshuApiUrls.homeFeed(data).Body),
|
|
7295
|
-
headers: {
|
|
7296
|
-
...baseRequestConfig.headers,
|
|
7297
|
-
"x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls.homeFeed(data).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web", xiaohongshuApiUrls.homeFeed(data).Body),
|
|
7298
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
|
|
7299
|
-
"x-t": xiaohongshuSign.generateXT()
|
|
7300
|
-
}
|
|
7301
|
-
});
|
|
7302
|
-
case "noteDetail": return await GlobalGetData$1(data.methodType, {
|
|
7303
|
-
...baseRequestConfig,
|
|
7304
|
-
url: xiaohongshuApiUrls.noteDetail(data).Url,
|
|
7305
|
-
data: xiaohongshuApiUrls.noteDetail(data).Body,
|
|
7513
|
+
/** 使用指定 Cookie 构建一次完整的小红书 API 请求。 */
|
|
7514
|
+
const requestWithCookie = async (requestCookie) => {
|
|
7515
|
+
const defHeaders = getXiaohongshuDefaultConfig(requestCookie)["headers"];
|
|
7516
|
+
const baseRequestConfig = {
|
|
7517
|
+
method: "POST",
|
|
7518
|
+
timeout: 1e4,
|
|
7519
|
+
...requestConfig,
|
|
7306
7520
|
headers: {
|
|
7307
|
-
...
|
|
7308
|
-
|
|
7309
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
|
|
7310
|
-
"x-t": xiaohongshuSign.generateXT()
|
|
7521
|
+
...defHeaders,
|
|
7522
|
+
...requestConfig?.headers ?? {}
|
|
7311
7523
|
}
|
|
7312
|
-
}
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
|
|
7316
|
-
timeout: 1e4,
|
|
7317
|
-
...requestConfig,
|
|
7318
|
-
headers: {
|
|
7319
|
-
...defHeaders,
|
|
7320
|
-
...requestConfig?.headers ?? {}
|
|
7321
|
-
}
|
|
7322
|
-
};
|
|
7323
|
-
return await GlobalGetData$1(data.methodType, {
|
|
7524
|
+
};
|
|
7525
|
+
const xiaohongshuApiUrls = createXiaohongshuApiUrls();
|
|
7526
|
+
switch (data.methodType) {
|
|
7527
|
+
case "homeFeed": return await GlobalGetData$1(data.methodType, {
|
|
7324
7528
|
...baseRequestConfig,
|
|
7325
|
-
url: xiaohongshuApiUrls.
|
|
7529
|
+
url: xiaohongshuApiUrls.homeFeed(data).Url,
|
|
7530
|
+
data: JSON.stringify(xiaohongshuApiUrls.homeFeed(data).Body),
|
|
7326
7531
|
headers: {
|
|
7327
7532
|
...baseRequestConfig.headers,
|
|
7328
|
-
"x-s": xiaohongshuSign.
|
|
7329
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(
|
|
7533
|
+
"x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls.homeFeed(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web", xiaohongshuApiUrls.homeFeed(data).Body),
|
|
7534
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7330
7535
|
"x-t": xiaohongshuSign.generateXT()
|
|
7331
7536
|
}
|
|
7332
7537
|
});
|
|
7333
|
-
|
|
7334
|
-
|
|
7335
|
-
|
|
7336
|
-
|
|
7337
|
-
timeout: 1e4,
|
|
7338
|
-
...requestConfig,
|
|
7538
|
+
case "noteDetail": return await GlobalGetData$1(data.methodType, {
|
|
7539
|
+
...baseRequestConfig,
|
|
7540
|
+
url: xiaohongshuApiUrls.noteDetail(data).Url,
|
|
7541
|
+
data: xiaohongshuApiUrls.noteDetail(data).Body,
|
|
7339
7542
|
headers: {
|
|
7340
|
-
...
|
|
7341
|
-
|
|
7543
|
+
...baseRequestConfig.headers,
|
|
7544
|
+
"x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls.noteDetail(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web", xiaohongshuApiUrls.noteDetail(data).Body),
|
|
7545
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7546
|
+
"x-t": xiaohongshuSign.generateXT()
|
|
7342
7547
|
}
|
|
7343
|
-
};
|
|
7344
|
-
|
|
7345
|
-
|
|
7346
|
-
|
|
7548
|
+
});
|
|
7549
|
+
case "noteComments": {
|
|
7550
|
+
const baseRequestConfig = {
|
|
7551
|
+
method: "GET",
|
|
7552
|
+
timeout: 1e4,
|
|
7553
|
+
...requestConfig,
|
|
7554
|
+
headers: {
|
|
7555
|
+
...defHeaders,
|
|
7556
|
+
...requestConfig?.headers ?? {}
|
|
7557
|
+
}
|
|
7558
|
+
};
|
|
7559
|
+
return await GlobalGetData$1(data.methodType, {
|
|
7347
7560
|
...baseRequestConfig,
|
|
7348
|
-
url: xiaohongshuApiUrls.
|
|
7561
|
+
url: xiaohongshuApiUrls.noteComments(data).Url,
|
|
7349
7562
|
headers: {
|
|
7350
7563
|
...baseRequestConfig.headers,
|
|
7351
|
-
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.
|
|
7352
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(
|
|
7564
|
+
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.noteComments(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web"),
|
|
7565
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7353
7566
|
"x-t": xiaohongshuSign.generateXT()
|
|
7354
7567
|
}
|
|
7355
|
-
})
|
|
7356
|
-
msg: "success"
|
|
7357
|
-
};
|
|
7358
|
-
}
|
|
7359
|
-
case "userNoteList": return await GlobalGetData$1(data.methodType, {
|
|
7360
|
-
...baseRequestConfig,
|
|
7361
|
-
method: "GET",
|
|
7362
|
-
url: xiaohongshuApiUrls.userNoteList(data).Url,
|
|
7363
|
-
headers: {
|
|
7364
|
-
...baseRequestConfig.headers,
|
|
7365
|
-
"x-b3-traceid": xiaohongshuSign.generateXB3Traceid(),
|
|
7366
|
-
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.userNoteList(data).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
|
|
7367
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
|
|
7368
|
-
"x-t": xiaohongshuSign.generateXT()
|
|
7568
|
+
});
|
|
7369
7569
|
}
|
|
7370
|
-
|
|
7371
|
-
|
|
7372
|
-
|
|
7570
|
+
case "userProfile": {
|
|
7571
|
+
const baseRequestConfig = {
|
|
7572
|
+
method: "GET",
|
|
7573
|
+
timeout: 1e4,
|
|
7574
|
+
...requestConfig,
|
|
7575
|
+
headers: {
|
|
7576
|
+
...defHeaders,
|
|
7577
|
+
...requestConfig?.headers ?? {}
|
|
7578
|
+
}
|
|
7579
|
+
};
|
|
7580
|
+
return {
|
|
7581
|
+
code: 0,
|
|
7582
|
+
data: extractCreatorInfoFromHtml(await GlobalGetData$1(data.methodType, {
|
|
7583
|
+
...baseRequestConfig,
|
|
7584
|
+
url: xiaohongshuApiUrls.userProfile(data).Url,
|
|
7585
|
+
headers: {
|
|
7586
|
+
...baseRequestConfig.headers,
|
|
7587
|
+
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.userProfile(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web"),
|
|
7588
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7589
|
+
"x-t": xiaohongshuSign.generateXT()
|
|
7590
|
+
}
|
|
7591
|
+
})),
|
|
7592
|
+
msg: "success"
|
|
7593
|
+
};
|
|
7594
|
+
}
|
|
7595
|
+
case "userNoteList": return await GlobalGetData$1(data.methodType, {
|
|
7596
|
+
...baseRequestConfig,
|
|
7373
7597
|
method: "GET",
|
|
7374
|
-
|
|
7375
|
-
...requestConfig,
|
|
7598
|
+
url: xiaohongshuApiUrls.userNoteList(data).Url,
|
|
7376
7599
|
headers: {
|
|
7377
|
-
...
|
|
7378
|
-
|
|
7600
|
+
...baseRequestConfig.headers,
|
|
7601
|
+
"x-b3-traceid": xiaohongshuSign.generateXB3Traceid(),
|
|
7602
|
+
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.userNoteList(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web"),
|
|
7603
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7604
|
+
"x-t": xiaohongshuSign.generateXT()
|
|
7379
7605
|
}
|
|
7380
|
-
};
|
|
7381
|
-
|
|
7606
|
+
});
|
|
7607
|
+
case "emojiList": {
|
|
7608
|
+
const baseRequestConfig = {
|
|
7609
|
+
method: "GET",
|
|
7610
|
+
timeout: 1e4,
|
|
7611
|
+
...requestConfig,
|
|
7612
|
+
headers: {
|
|
7613
|
+
...defHeaders,
|
|
7614
|
+
...requestConfig?.headers ?? {}
|
|
7615
|
+
}
|
|
7616
|
+
};
|
|
7617
|
+
return await GlobalGetData$1(data.methodType, {
|
|
7618
|
+
...baseRequestConfig,
|
|
7619
|
+
url: xiaohongshuApiUrls.emojiList(data).Url,
|
|
7620
|
+
headers: {
|
|
7621
|
+
...baseRequestConfig.headers,
|
|
7622
|
+
"x-s": xiaohongshuSign.generateXSGet(xiaohongshuApiUrls.emojiList(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web"),
|
|
7623
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7624
|
+
"x-t": xiaohongshuSign.generateXT()
|
|
7625
|
+
}
|
|
7626
|
+
});
|
|
7627
|
+
}
|
|
7628
|
+
case "searchNotes": return await GlobalGetData$1(data.methodType, {
|
|
7382
7629
|
...baseRequestConfig,
|
|
7383
|
-
url: xiaohongshuApiUrls.
|
|
7630
|
+
url: xiaohongshuApiUrls.searchNotes(data).Url,
|
|
7631
|
+
data: xiaohongshuApiUrls.searchNotes(data).Body,
|
|
7384
7632
|
headers: {
|
|
7385
7633
|
...baseRequestConfig.headers,
|
|
7386
|
-
"x-s": xiaohongshuSign.
|
|
7387
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(
|
|
7634
|
+
"x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls.searchNotes(data).apiPath, xiaohongshuSign.extractA1FromCookie(requestCookie), "xhs-pc-web"),
|
|
7635
|
+
"x-s-common": xiaohongshuSign.generateXSCommon(requestCookie),
|
|
7388
7636
|
"x-t": xiaohongshuSign.generateXT()
|
|
7389
7637
|
}
|
|
7390
7638
|
});
|
|
7639
|
+
default: throw new Error(`Unknown Xiaohongshu API method: "${data.methodType}"`);
|
|
7391
7640
|
}
|
|
7392
|
-
|
|
7393
|
-
|
|
7394
|
-
url: xiaohongshuApiUrls.searchNotes(data).Url,
|
|
7395
|
-
data: xiaohongshuApiUrls.searchNotes(data).Body,
|
|
7396
|
-
headers: {
|
|
7397
|
-
...baseRequestConfig.headers,
|
|
7398
|
-
"x-s": xiaohongshuSign.generateXSPost(xiaohongshuApiUrls.searchNotes(data).apiPath, xiaohongshuSign.extractA1FromCookie(cookie ?? ""), "xhs-pc-web"),
|
|
7399
|
-
"x-s-common": xiaohongshuSign.generateXSCommon(cookie ?? ""),
|
|
7400
|
-
"x-t": xiaohongshuSign.generateXT()
|
|
7401
|
-
}
|
|
7402
|
-
});
|
|
7403
|
-
default: throw new Error(`Unknown Xiaohongshu API method: "${logger.red(data.methodType)}"`);
|
|
7404
|
-
}
|
|
7641
|
+
};
|
|
7642
|
+
return requestWithCookie(cookie?.trim() ?? "");
|
|
7405
7643
|
};
|
|
7406
7644
|
/**
|
|
7407
7645
|
* 全局数据获取函数
|
|
@@ -7425,7 +7663,7 @@ const GlobalGetData$1 = async (methodType, config) => {
|
|
|
7425
7663
|
if (response.code !== 0) throw new Error(`API request failed: ${response.data?.msg ?? response.msg ?? "Unknown error"}, code: ${response.code}`);
|
|
7426
7664
|
return response;
|
|
7427
7665
|
} catch (error) {
|
|
7428
|
-
|
|
7666
|
+
emitLogError(`Xiaohongshu API request failed [${methodType}]:`, error.message);
|
|
7429
7667
|
return {
|
|
7430
7668
|
code: 500,
|
|
7431
7669
|
message: "error",
|
|
@@ -7766,7 +8004,7 @@ const createNetworkErrorResult = (error, retries) => {
|
|
|
7766
8004
|
* @returns 清理后的User-Agent字符串
|
|
7767
8005
|
*/
|
|
7768
8006
|
const cleanUserAgent = (userAgent) => {
|
|
7769
|
-
return userAgent.replace(/\s+Edg\/[\d
|
|
8007
|
+
return userAgent.replace(/\s+Edg\/[\d.]+/g, "");
|
|
7770
8008
|
};
|
|
7771
8009
|
/**
|
|
7772
8010
|
* 执行网络请求并返回数据(带自动重试)
|
|
@@ -8018,8 +8256,7 @@ const qtparam = async (BASEURL, cookie) => {
|
|
|
8018
8256
|
126,
|
|
8019
8257
|
127
|
|
8020
8258
|
];
|
|
8021
|
-
|
|
8022
|
-
logininfo.data.vipStatus === 1 ? isvip = true : isvip = false;
|
|
8259
|
+
const isvip = logininfo.data.vipStatus === 1;
|
|
8023
8260
|
if (isvip) return {
|
|
8024
8261
|
QUERY: `&fnval=4048&fourk=1&${sign}`,
|
|
8025
8262
|
STATUS: "isLogin",
|
|
@@ -8354,7 +8591,7 @@ const fetchBilibili = async (data, cookie, requestConfig) => {
|
|
|
8354
8591
|
...baseRequestConfig,
|
|
8355
8592
|
url: checkStatusUrl
|
|
8356
8593
|
})).data === null) {
|
|
8357
|
-
|
|
8594
|
+
emitLogError("评论区未开放");
|
|
8358
8595
|
return {
|
|
8359
8596
|
code: 404,
|
|
8360
8597
|
message: "评论区未开放",
|
|
@@ -8385,7 +8622,7 @@ const fetchBilibili = async (data, cookie, requestConfig) => {
|
|
|
8385
8622
|
} else isEnd = true;
|
|
8386
8623
|
requestCount++;
|
|
8387
8624
|
if (isEnd || currentComments.length === 0 || !nextPaginationStr) {
|
|
8388
|
-
|
|
8625
|
+
emitLogInfo("已到达评论末尾或无更多评论");
|
|
8389
8626
|
break;
|
|
8390
8627
|
}
|
|
8391
8628
|
}
|
|
@@ -8468,6 +8705,10 @@ const fetchBilibili = async (data, cookie, requestConfig) => {
|
|
|
8468
8705
|
url: bilibiliApiUrls.getUserCard({ host_mid })
|
|
8469
8706
|
});
|
|
8470
8707
|
}
|
|
8708
|
+
case "userLiveStatus": return await GlobalGetData(data.methodType, {
|
|
8709
|
+
...baseRequestConfig,
|
|
8710
|
+
url: bilibiliApiUrls.getUserLiveStatus({ host_mid: data.host_mid })
|
|
8711
|
+
});
|
|
8471
8712
|
case "userSpaceInfo": {
|
|
8472
8713
|
const wbiSignQuery = await wbi_sign(bilibiliApiUrls.getUserSpaceInfo({ host_mid: data.host_mid }), baseRequestConfig.headers?.cookie);
|
|
8473
8714
|
return await GlobalGetData(data.methodType, {
|
|
@@ -8624,7 +8865,7 @@ const fetchBilibili = async (data, cookie, requestConfig) => {
|
|
|
8624
8865
|
}
|
|
8625
8866
|
}
|
|
8626
8867
|
default:
|
|
8627
|
-
|
|
8868
|
+
emitLogWarn(`未知的B站数据接口:「${data.methodType}」`);
|
|
8628
8869
|
return null;
|
|
8629
8870
|
}
|
|
8630
8871
|
};
|
|
@@ -8660,11 +8901,11 @@ const GlobalGetData = async (type, options, retryCount = 0) => {
|
|
|
8660
8901
|
requestUrl: options.url
|
|
8661
8902
|
};
|
|
8662
8903
|
warningMessage = `
|
|
8663
|
-
|
|
8904
|
+
获取响应数据失败!原因:接口返回内容为空,你的B站ck可能已经失效!
|
|
8664
8905
|
请求类型:「${type}」
|
|
8665
8906
|
请求URL:${options.url}
|
|
8666
8907
|
`;
|
|
8667
|
-
|
|
8908
|
+
emitLogWarn(warningMessage);
|
|
8668
8909
|
const riskError = new Error(Err.errorDescription);
|
|
8669
8910
|
Object.assign(riskError, {
|
|
8670
8911
|
code: "-352",
|
|
@@ -8686,12 +8927,12 @@ const GlobalGetData = async (type, options, retryCount = 0) => {
|
|
|
8686
8927
|
responseCode: result.code
|
|
8687
8928
|
};
|
|
8688
8929
|
warningMessage = `
|
|
8689
|
-
获取响应数据失败!原因:${
|
|
8930
|
+
获取响应数据失败!原因:${errorMessage}
|
|
8690
8931
|
错误代码:${result.code}
|
|
8691
8932
|
请求类型:「${type}」
|
|
8692
8933
|
请求URL:${options.url}
|
|
8693
8934
|
`;
|
|
8694
|
-
|
|
8935
|
+
emitLogWarn(warningMessage);
|
|
8695
8936
|
const apiError = new Error(Err.errorDescription);
|
|
8696
8937
|
Object.assign(apiError, {
|
|
8697
8938
|
code: result.code,
|
|
@@ -9175,15 +9416,6 @@ const kuaishouUtils = {
|
|
|
9175
9416
|
//#endregion
|
|
9176
9417
|
//#region src/platform/xiaohongshu/XiaohongshuApi.ts
|
|
9177
9418
|
/**
|
|
9178
|
-
* 小红书 API 模块 (已废弃)
|
|
9179
|
-
*
|
|
9180
|
-
* 此模块中的 API 已在 v6 版本废弃
|
|
9181
|
-
* 请使用 xiaohongshuFetcher 或 client.xiaohongshu.fetcher 替代
|
|
9182
|
-
*
|
|
9183
|
-
* @module platform/xiaohongshu/XiaohongshuApi
|
|
9184
|
-
* @deprecated v6 已废弃,请使用 fetcher API 替代
|
|
9185
|
-
*/
|
|
9186
|
-
/**
|
|
9187
9419
|
* 创建废弃的 API 存根函数
|
|
9188
9420
|
*/
|
|
9189
9421
|
const createDeprecatedStub = (methodName) => {
|
|
@@ -9562,6 +9794,7 @@ const BilibiliInternalMethods = {
|
|
|
9562
9794
|
COMMENT_REPLIES: "指定评论的回复",
|
|
9563
9795
|
USER_CARD: "用户主页数据",
|
|
9564
9796
|
USER_DYNAMICS: "用户主页动态列表数据",
|
|
9797
|
+
USER_LIVE_STATUS: "用户直播状态",
|
|
9565
9798
|
USER_SPACE_INFO: "用户空间详细信息",
|
|
9566
9799
|
USER_TOTAL_VIEWS: "获取UP主总播放量",
|
|
9567
9800
|
DYNAMIC_DETAIL: "动态详情数据",
|
|
@@ -9592,6 +9825,7 @@ const BilibiliFetcherMethods = {
|
|
|
9592
9825
|
COMMENT_REPLIES: "fetchCommentReplies",
|
|
9593
9826
|
USER_CARD: "fetchUserCard",
|
|
9594
9827
|
USER_DYNAMICS: "fetchUserDynamicList",
|
|
9828
|
+
USER_LIVE_STATUS: "fetchUserLiveStatus",
|
|
9595
9829
|
USER_SPACE_INFO: "fetchUserSpaceInfo",
|
|
9596
9830
|
USER_TOTAL_VIEWS: "fetchUploaderTotalViews",
|
|
9597
9831
|
DYNAMIC_DETAIL: "fetchDynamicDetail",
|
|
@@ -9700,6 +9934,7 @@ const BilibiliMethodToFetcher = {
|
|
|
9700
9934
|
[BilibiliInternalMethods.COMMENT_REPLIES]: BilibiliFetcherMethods.COMMENT_REPLIES,
|
|
9701
9935
|
[BilibiliInternalMethods.USER_CARD]: BilibiliFetcherMethods.USER_CARD,
|
|
9702
9936
|
[BilibiliInternalMethods.USER_DYNAMICS]: BilibiliFetcherMethods.USER_DYNAMICS,
|
|
9937
|
+
[BilibiliInternalMethods.USER_LIVE_STATUS]: BilibiliFetcherMethods.USER_LIVE_STATUS,
|
|
9703
9938
|
[BilibiliInternalMethods.USER_SPACE_INFO]: BilibiliFetcherMethods.USER_SPACE_INFO,
|
|
9704
9939
|
[BilibiliInternalMethods.USER_TOTAL_VIEWS]: BilibiliFetcherMethods.USER_TOTAL_VIEWS,
|
|
9705
9940
|
[BilibiliInternalMethods.DYNAMIC_DETAIL]: BilibiliFetcherMethods.DYNAMIC_DETAIL,
|
|
@@ -9831,6 +10066,7 @@ const BilibiliMethodMapping = {
|
|
|
9831
10066
|
指定评论的回复: "fetchCommentReplies",
|
|
9832
10067
|
用户主页数据: "fetchUserCard",
|
|
9833
10068
|
用户主页动态列表数据: "fetchUserDynamicList",
|
|
10069
|
+
用户直播状态: "fetchUserLiveStatus",
|
|
9834
10070
|
用户空间详细信息: "fetchUserSpaceInfo",
|
|
9835
10071
|
获取UP主总播放量: "fetchUploaderTotalViews",
|
|
9836
10072
|
动态详情数据: "fetchDynamicDetail",
|
|
@@ -9913,6 +10149,7 @@ const BilibiliApiRoutes = {
|
|
|
9913
10149
|
commentReplies: "/comment-replies",
|
|
9914
10150
|
userCard: "/user",
|
|
9915
10151
|
userDynamicList: "/user/dynamics",
|
|
10152
|
+
userLiveStatus: "/user/live-status",
|
|
9916
10153
|
userSpaceInfo: "/user/space",
|
|
9917
10154
|
uploaderTotalViews: "/user/total-views",
|
|
9918
10155
|
dynamicDetail: "/dynamic",
|
|
@@ -9986,7 +10223,7 @@ function getApiRoute(platform, methodType) {
|
|
|
9986
10223
|
* 构建后使用 __VERSION__,开发环境从 package.json 读取
|
|
9987
10224
|
*/
|
|
9988
10225
|
const getVersion = () => {
|
|
9989
|
-
return "6.
|
|
10226
|
+
return "6.3.0";
|
|
9990
10227
|
};
|
|
9991
10228
|
const VERSION = getVersion();
|
|
9992
10229
|
/**
|
|
@@ -10033,6 +10270,11 @@ const CreateApp = CreateAmagiApp;
|
|
|
10033
10270
|
/** After instantiation, it can interact with the specified platform API to quickly obtain data. */
|
|
10034
10271
|
const Client = CreateApp;
|
|
10035
10272
|
const amagi = Client;
|
|
10273
|
+
/*!
|
|
10274
|
+
* @ikenxuan/amagi
|
|
10275
|
+
* Copyright(c) 2023 ikenxuan
|
|
10276
|
+
* GPL-3.0 Licensed
|
|
10277
|
+
*/
|
|
10036
10278
|
//#endregion
|
|
10037
10279
|
exports.AdditionalType = AdditionalType;
|
|
10038
10280
|
exports.ApiError = ApiError;
|