koishi-plugin-maibot 1.7.30 → 1.7.32
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/lib/api.d.ts +33 -0
- package/lib/api.d.ts.map +1 -1
- package/lib/api.js +37 -0
- package/lib/api.js.map +1 -1
- package/lib/database.d.ts +2 -0
- package/lib/database.d.ts.map +1 -1
- package/lib/database.js +3 -1
- package/lib/database.js.map +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +550 -172
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -674,13 +674,26 @@ async function waitForUserReply(session, ctx, timeout) {
|
|
|
674
674
|
}
|
|
675
675
|
/**
|
|
676
676
|
* 交互式获取二维码文本(qr_text)
|
|
677
|
-
*
|
|
678
|
-
*
|
|
677
|
+
* 支持10分钟内使用上次输入的SGID缓存
|
|
678
|
+
* 如果缓存存在且有效,直接使用;否则提示用户输入
|
|
679
679
|
*/
|
|
680
|
-
async function getQrText(session, ctx, api, binding, config, timeout = 60000, promptMessage
|
|
680
|
+
async function getQrText(session, ctx, api, binding, config, timeout = 60000, promptMessage, useCache = true // 是否使用缓存(默认启用)
|
|
681
|
+
) {
|
|
681
682
|
const logger = ctx.logger('maibot');
|
|
682
|
-
//
|
|
683
|
-
|
|
683
|
+
// 如果启用缓存且binding存在,检查是否有10分钟内的SGID缓存
|
|
684
|
+
if (useCache && binding && binding.lastQrCode && binding.lastQrCodeTime) {
|
|
685
|
+
const cacheAge = Date.now() - new Date(binding.lastQrCodeTime).getTime();
|
|
686
|
+
const cacheValidDuration = 10 * 60 * 1000; // 10分钟
|
|
687
|
+
if (cacheAge < cacheValidDuration && binding.lastQrCode.startsWith('SGWCMAID')) {
|
|
688
|
+
logger.info(`使用缓存的SGID(${Math.floor(cacheAge / 1000)}秒前输入)`);
|
|
689
|
+
// 直接返回缓存的SGID,不验证(让调用方验证,如果失败再提示输入)
|
|
690
|
+
return { qrText: binding.lastQrCode, fromCache: true };
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
logger.debug(`缓存已过期(${Math.floor(cacheAge / 1000)}秒前输入,超过10分钟)`);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
// 没有有效缓存,提示用户输入
|
|
684
697
|
const actualTimeout = timeout;
|
|
685
698
|
const message = promptMessage || `请在${actualTimeout / 1000}秒内发送SGID(长按玩家二维码识别后发送)或公众号提供的网页地址`;
|
|
686
699
|
try {
|
|
@@ -749,12 +762,14 @@ async function getQrText(session, ctx, api, binding, config, timeout = 60000, pr
|
|
|
749
762
|
await session.send('❌ 无效或过期的二维码,请重新发送');
|
|
750
763
|
return { qrText: '', error: '无效或过期的二维码' };
|
|
751
764
|
}
|
|
752
|
-
// 如果binding存在,更新数据库中的qrCode
|
|
765
|
+
// 如果binding存在,更新数据库中的qrCode和缓存
|
|
753
766
|
if (binding) {
|
|
754
767
|
await ctx.database.set('maibot_bindings', { userId: binding.userId }, {
|
|
755
768
|
qrCode: qrText,
|
|
769
|
+
lastQrCode: qrText, // 更新缓存
|
|
770
|
+
lastQrCodeTime: new Date(), // 更新时间戳
|
|
756
771
|
});
|
|
757
|
-
logger.info(`已更新用户 ${binding.userId} 的qrCode
|
|
772
|
+
logger.info(`已更新用户 ${binding.userId} 的qrCode和缓存`);
|
|
758
773
|
}
|
|
759
774
|
return { qrText: qrText };
|
|
760
775
|
}
|
|
@@ -907,6 +922,8 @@ async function promptForRebind(session, ctx, api, binding, config, timeout = 600
|
|
|
907
922
|
bindTime: new Date(),
|
|
908
923
|
userName,
|
|
909
924
|
rating,
|
|
925
|
+
lastQrCode: qrCode, // 保存为缓存
|
|
926
|
+
lastQrCodeTime: new Date(), // 保存时间戳
|
|
910
927
|
});
|
|
911
928
|
// 发送成功反馈
|
|
912
929
|
await session.send(`✅ 重新绑定成功!${userName ? `\n用户名: ${userName}` : ''}${rating ? `\nRating: ${rating}` : ''}\n\n⚠️ 为了确保账户安全,请手动撤回群内包含SGID的消息`);
|
|
@@ -1670,6 +1687,8 @@ function apply(ctx, config) {
|
|
|
1670
1687
|
bindTime: new Date(),
|
|
1671
1688
|
userName,
|
|
1672
1689
|
rating,
|
|
1690
|
+
lastQrCode: qrCode, // 保存为缓存
|
|
1691
|
+
lastQrCodeTime: new Date(), // 保存时间戳
|
|
1673
1692
|
});
|
|
1674
1693
|
return `✅ 绑定成功!\n` +
|
|
1675
1694
|
(userName ? `用户名: ${userName}\n` : '') +
|
|
@@ -1748,9 +1767,11 @@ function apply(ctx, config) {
|
|
|
1748
1767
|
`绑定时间: ${new Date(binding.bindTime).toLocaleString('zh-CN')}\n` +
|
|
1749
1768
|
`🚨 /maialert查看账号提醒状态\n`;
|
|
1750
1769
|
// 尝试获取最新状态并更新数据库(需要新二维码)
|
|
1770
|
+
let qrTextResultForCharge = null;
|
|
1751
1771
|
try {
|
|
1752
1772
|
// 废弃旧的uid策略,每次都需要新的二维码
|
|
1753
1773
|
const qrTextResult = await getQrText(session, ctx, api, binding, config, rebindTimeout, '请在60秒内发送SGID(长按玩家二维码识别后发送)或公众号提供的网页地址以查询账号状态');
|
|
1774
|
+
qrTextResultForCharge = qrTextResult;
|
|
1754
1775
|
if (qrTextResult.error) {
|
|
1755
1776
|
statusInfo += `\n⚠️ 无法获取最新状态:${qrTextResult.error}`;
|
|
1756
1777
|
}
|
|
@@ -1852,9 +1873,70 @@ function apply(ctx, config) {
|
|
|
1852
1873
|
statusInfo += `\n\n🔒 锁定状态: 未锁定\n使用 /mai锁定 可以锁定账号(防止他人登录)`;
|
|
1853
1874
|
}
|
|
1854
1875
|
}
|
|
1855
|
-
//
|
|
1856
|
-
|
|
1857
|
-
|
|
1876
|
+
// 显示票券信息(使用新的getCharge API)
|
|
1877
|
+
try {
|
|
1878
|
+
if (qrTextResultForCharge && !qrTextResultForCharge.error) {
|
|
1879
|
+
// 在调用API前加入队列
|
|
1880
|
+
await waitForQueue(session);
|
|
1881
|
+
const chargeResult = await api.getCharge(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResultForCharge.qrText);
|
|
1882
|
+
if (chargeResult.ChargeStatus && chargeResult.userChargeList) {
|
|
1883
|
+
const now = new Date();
|
|
1884
|
+
const validTickets = [];
|
|
1885
|
+
const expiredTickets = [];
|
|
1886
|
+
for (const ticket of chargeResult.userChargeList) {
|
|
1887
|
+
const validDate = new Date(ticket.validDate);
|
|
1888
|
+
if (validDate > now) {
|
|
1889
|
+
validTickets.push(ticket);
|
|
1890
|
+
}
|
|
1891
|
+
else {
|
|
1892
|
+
expiredTickets.push(ticket);
|
|
1893
|
+
}
|
|
1894
|
+
}
|
|
1895
|
+
// 显示有效票券
|
|
1896
|
+
if (validTickets.length > 0 || (options?.expired && expiredTickets.length > 0)) {
|
|
1897
|
+
statusInfo += `\n\n🎫 票券情况:`;
|
|
1898
|
+
if (validTickets.length > 0) {
|
|
1899
|
+
statusInfo += `\n有效票券:`;
|
|
1900
|
+
for (const ticket of validTickets) {
|
|
1901
|
+
const ticketName = getTicketName(ticket.chargeId);
|
|
1902
|
+
const validDateStr = new Date(ticket.validDate).toLocaleString('zh-CN');
|
|
1903
|
+
statusInfo += `\n ${ticketName}: ${ticket.stock} 张(有效期至 ${validDateStr})`;
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
// 如果使用 --expired 选项,显示过期票券
|
|
1907
|
+
if (options?.expired && expiredTickets.length > 0) {
|
|
1908
|
+
statusInfo += `\n过期票券:`;
|
|
1909
|
+
for (const ticket of expiredTickets) {
|
|
1910
|
+
const ticketName = getTicketName(ticket.chargeId);
|
|
1911
|
+
const validDateStr = new Date(ticket.validDate).toLocaleString('zh-CN');
|
|
1912
|
+
statusInfo += `\n ${ticketName}: ${ticket.stock} 张(已过期,过期时间 ${validDateStr})`;
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
else if (expiredTickets.length > 0) {
|
|
1916
|
+
statusInfo += `\n(还有 ${expiredTickets.length} 种过期票券,使用 --expired 查看)`;
|
|
1917
|
+
}
|
|
1918
|
+
// 显示免费票券
|
|
1919
|
+
if (chargeResult.userFreeChargeList && chargeResult.userFreeChargeList.length > 0) {
|
|
1920
|
+
statusInfo += `\n免费票券:`;
|
|
1921
|
+
for (const freeTicket of chargeResult.userFreeChargeList) {
|
|
1922
|
+
const ticketName = getTicketName(freeTicket.chargeId);
|
|
1923
|
+
statusInfo += `\n ${ticketName}: ${freeTicket.stock} 张`;
|
|
1924
|
+
}
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
else {
|
|
1928
|
+
statusInfo += `\n\n🎫 票券情况: 暂无有效票券`;
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
else {
|
|
1932
|
+
statusInfo += `\n\n🎫 票券情况: 获取失败(${chargeResult.ChargeStatus === false ? 'API返回失败' : '数据格式错误'})`;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
catch (error) {
|
|
1937
|
+
logger.warn('获取票券信息失败:', error);
|
|
1938
|
+
statusInfo += `\n\n🎫 票券情况: 获取失败(${error?.message || '未知错误'})`;
|
|
1939
|
+
}
|
|
1858
1940
|
return statusInfo;
|
|
1859
1941
|
}
|
|
1860
1942
|
catch (error) {
|
|
@@ -2285,19 +2367,24 @@ function apply(ctx, config) {
|
|
|
2285
2367
|
const proxyTip = isProxy ? `(代操作用户 ${userId})` : '';
|
|
2286
2368
|
// 确认操作(如果未使用 -bypass)
|
|
2287
2369
|
if (!options?.bypass) {
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2370
|
+
if (multiple >= 4) {
|
|
2371
|
+
// 4-6倍:提示失败风险并二次确认
|
|
2372
|
+
const baseTip = `⚠️ 即将发放 ${multiple} 倍票${proxyTip}\n\n⚠️ 警告:4倍及以上票券极有可能失败,请谨慎操作!`;
|
|
2373
|
+
const confirmFirst = await promptYesLocal(session, `${baseTip}\n操作具有风险,请谨慎`);
|
|
2374
|
+
if (!confirmFirst) {
|
|
2375
|
+
return '操作已取消(第一次确认未通过)';
|
|
2376
|
+
}
|
|
2377
|
+
const confirmSecond = await promptYesLocal(session, `二次确认:${multiple}倍票券失败风险极高,确定要继续吗?\n若理解风险,请再次输入 Y 执行`);
|
|
2378
|
+
if (!confirmSecond) {
|
|
2379
|
+
return '操作已取消(第二次确认未通过)';
|
|
2380
|
+
}
|
|
2296
2381
|
}
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2382
|
+
else {
|
|
2383
|
+
// 2-3倍:一次确认
|
|
2384
|
+
const baseTip = `⚠️ 即将发放 ${multiple} 倍票${proxyTip}`;
|
|
2385
|
+
const confirmFirst = await promptYesLocal(session, `${baseTip}\n操作具有风险,请谨慎\n确认继续?`);
|
|
2386
|
+
if (!confirmFirst) {
|
|
2387
|
+
return '操作已取消(确认未通过)';
|
|
2301
2388
|
}
|
|
2302
2389
|
}
|
|
2303
2390
|
}
|
|
@@ -2332,34 +2419,73 @@ function apply(ctx, config) {
|
|
|
2332
2419
|
await session.send('请求成功提交,请等待服务器响应。(通常需要2-3分钟)');
|
|
2333
2420
|
// 使用新API获取功能票(需要qr_text)
|
|
2334
2421
|
let ticketResult;
|
|
2422
|
+
let usedCache = qrTextResult.fromCache === true;
|
|
2335
2423
|
try {
|
|
2336
2424
|
ticketResult = await api.getTicket(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, multiple, qrTextResult.qrText);
|
|
2337
2425
|
}
|
|
2338
2426
|
catch (error) {
|
|
2339
|
-
//
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
//
|
|
2343
|
-
const retryQrText = await getQrText(session, ctx, api, failureResult.rebindResult.newBinding, config, rebindTimeout);
|
|
2427
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
2428
|
+
if (usedCache) {
|
|
2429
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
2430
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
2344
2431
|
if (retryQrText.error) {
|
|
2345
|
-
return `❌
|
|
2432
|
+
return `❌ 获取二维码失败:${retryQrText.error}`;
|
|
2346
2433
|
}
|
|
2434
|
+
// 在调用API前加入队列
|
|
2435
|
+
await waitForQueue(session);
|
|
2347
2436
|
ticketResult = await api.getTicket(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, multiple, retryQrText.qrText);
|
|
2348
2437
|
}
|
|
2349
2438
|
else {
|
|
2350
|
-
|
|
2439
|
+
// 如果API返回失败,可能需要重新绑定
|
|
2440
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
|
|
2441
|
+
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
2442
|
+
// 重新绑定成功,重试获取功能票
|
|
2443
|
+
const retryQrText = await getQrText(session, ctx, api, failureResult.rebindResult.newBinding, config, rebindTimeout);
|
|
2444
|
+
if (retryQrText.error) {
|
|
2445
|
+
return `❌ 重新绑定后获取二维码失败:${retryQrText.error}`;
|
|
2446
|
+
}
|
|
2447
|
+
// 在调用API前加入队列
|
|
2448
|
+
await waitForQueue(session);
|
|
2449
|
+
ticketResult = await api.getTicket(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, multiple, retryQrText.qrText);
|
|
2450
|
+
}
|
|
2451
|
+
else {
|
|
2452
|
+
throw error;
|
|
2453
|
+
}
|
|
2351
2454
|
}
|
|
2352
2455
|
}
|
|
2353
2456
|
if (!ticketResult.TicketStatus || !ticketResult.LoginStatus || !ticketResult.LogoutStatus) {
|
|
2354
|
-
//
|
|
2355
|
-
if (!ticketResult.QrStatus || ticketResult.LoginStatus === false) {
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2457
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
2458
|
+
if (usedCache && (!ticketResult.QrStatus || ticketResult.LoginStatus === false)) {
|
|
2459
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
2460
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
2461
|
+
if (retryQrText.error) {
|
|
2462
|
+
return `❌ 获取二维码失败:${retryQrText.error}`;
|
|
2359
2463
|
}
|
|
2360
|
-
|
|
2464
|
+
// 在调用API前加入队列
|
|
2465
|
+
await waitForQueue(session);
|
|
2466
|
+
ticketResult = await api.getTicket(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, multiple, retryQrText.qrText);
|
|
2467
|
+
if (!ticketResult.TicketStatus || !ticketResult.LoginStatus || !ticketResult.LogoutStatus) {
|
|
2468
|
+
if (!ticketResult.QrStatus || ticketResult.LoginStatus === false) {
|
|
2469
|
+
const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
|
|
2470
|
+
if (rebindResult.success && rebindResult.newBinding) {
|
|
2471
|
+
return `✅ 重新绑定成功!请重新执行发票操作。`;
|
|
2472
|
+
}
|
|
2473
|
+
return `❌ 发放功能票失败:服务器返回未成功\n重新绑定失败:${rebindResult.error || '未知错误'}`;
|
|
2474
|
+
}
|
|
2475
|
+
return '❌ 发票失败:服务器返回未成功,请确认是否已在短时间内多次执行发票指令或稍后再试或点击获取二维码刷新账号后再试。';
|
|
2476
|
+
}
|
|
2477
|
+
}
|
|
2478
|
+
else {
|
|
2479
|
+
// 如果返回失败,可能需要重新绑定
|
|
2480
|
+
if (!ticketResult.QrStatus || ticketResult.LoginStatus === false) {
|
|
2481
|
+
const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
|
|
2482
|
+
if (rebindResult.success && rebindResult.newBinding) {
|
|
2483
|
+
return `✅ 重新绑定成功!请重新执行发票操作。`;
|
|
2484
|
+
}
|
|
2485
|
+
return `❌ 发放功能票失败:服务器返回未成功\n重新绑定失败:${rebindResult.error || '未知错误'}`;
|
|
2486
|
+
}
|
|
2487
|
+
return '❌ 发票失败:服务器返回未成功,请确认是否已在短时间内多次执行发票指令或稍后再试或点击获取二维码刷新账号后再试。';
|
|
2361
2488
|
}
|
|
2362
|
-
return '❌ 发票失败:服务器返回未成功,请确认是否已在短时间内多次执行发票指令或稍后再试或点击获取二维码刷新账号后再试。';
|
|
2363
2489
|
}
|
|
2364
2490
|
return `✅ 已发放 ${multiple} 倍票\n请稍等几分钟在游戏内确认`;
|
|
2365
2491
|
}
|
|
@@ -2561,41 +2687,76 @@ function apply(ctx, config) {
|
|
|
2561
2687
|
await waitForQueue(session);
|
|
2562
2688
|
// 上传B50(使用新API,需要qr_text)
|
|
2563
2689
|
let result;
|
|
2690
|
+
let usedCache = qrTextResult.fromCache === true;
|
|
2564
2691
|
try {
|
|
2565
2692
|
result = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText, binding.fishToken);
|
|
2566
2693
|
}
|
|
2567
2694
|
catch (error) {
|
|
2568
|
-
//
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
//
|
|
2572
|
-
const retryQrText = await getQrText(session, ctx, api, failureResult.rebindResult.newBinding, config, rebindTimeout);
|
|
2695
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
2696
|
+
if (usedCache) {
|
|
2697
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
2698
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
2573
2699
|
if (retryQrText.error) {
|
|
2574
|
-
return `❌
|
|
2700
|
+
return `❌ 获取二维码失败:${retryQrText.error}`;
|
|
2575
2701
|
}
|
|
2576
2702
|
// 在调用API前加入队列
|
|
2577
2703
|
await waitForQueue(session);
|
|
2578
2704
|
result = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, binding.fishToken);
|
|
2579
2705
|
}
|
|
2580
2706
|
else {
|
|
2581
|
-
|
|
2707
|
+
// 如果API返回失败,可能需要重新绑定
|
|
2708
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
|
|
2709
|
+
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
2710
|
+
// 重新绑定成功,重试上传
|
|
2711
|
+
const retryQrText = await getQrText(session, ctx, api, failureResult.rebindResult.newBinding, config, rebindTimeout);
|
|
2712
|
+
if (retryQrText.error) {
|
|
2713
|
+
return `❌ 重新绑定后获取二维码失败:${retryQrText.error}`;
|
|
2714
|
+
}
|
|
2715
|
+
// 在调用API前加入队列
|
|
2716
|
+
await waitForQueue(session);
|
|
2717
|
+
result = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, binding.fishToken);
|
|
2718
|
+
}
|
|
2719
|
+
else {
|
|
2720
|
+
throw error;
|
|
2721
|
+
}
|
|
2582
2722
|
}
|
|
2583
2723
|
}
|
|
2584
2724
|
if (!result.UploadStatus) {
|
|
2585
|
-
|
|
2586
|
-
|
|
2725
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
2726
|
+
if (usedCache && (result.msg?.includes('二维码') || result.msg?.includes('qr_text') || result.msg?.includes('无效'))) {
|
|
2727
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
2728
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
2729
|
+
if (retryQrText.error) {
|
|
2730
|
+
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
2731
|
+
return `❌ 上传失败:${result.msg || '未知错误'}\n获取新二维码失败:${retryQrText.error}${taskIdInfo}`;
|
|
2732
|
+
}
|
|
2733
|
+
// 在调用API前加入队列
|
|
2734
|
+
await waitForQueue(session);
|
|
2735
|
+
result = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, binding.fishToken);
|
|
2736
|
+
if (!result.UploadStatus) {
|
|
2737
|
+
if (result.msg === '该账号下存在未完成的任务') {
|
|
2738
|
+
return '⚠️ 当前账号已有未完成的水鱼B50任务,请耐心等待任务完成,预计1-10分钟,无需重复上传。';
|
|
2739
|
+
}
|
|
2740
|
+
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
2741
|
+
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
2742
|
+
}
|
|
2587
2743
|
}
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2744
|
+
else {
|
|
2745
|
+
if (result.msg === '该账号下存在未完成的任务') {
|
|
2746
|
+
return '⚠️ 当前账号已有未完成的水鱼B50任务,请耐心等待任务完成,预计1-10分钟,无需重复上传。';
|
|
2747
|
+
}
|
|
2748
|
+
// 如果返回失败,可能需要重新绑定
|
|
2749
|
+
if (result.msg?.includes('二维码') || result.msg?.includes('qr_text') || result.msg?.includes('无效')) {
|
|
2750
|
+
const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
|
|
2751
|
+
if (rebindResult.success && rebindResult.newBinding) {
|
|
2752
|
+
return `✅ 重新绑定成功!请重新执行上传操作。`;
|
|
2753
|
+
}
|
|
2754
|
+
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
2755
|
+
return `❌ 上传失败:${result.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}`;
|
|
2593
2756
|
}
|
|
2594
2757
|
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
2595
|
-
return `❌ 上传失败:${result.msg || '未知错误'}
|
|
2758
|
+
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
2596
2759
|
}
|
|
2597
|
-
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
2598
|
-
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
2599
2760
|
}
|
|
2600
2761
|
scheduleB50Notification(session, result.task_id);
|
|
2601
2762
|
return `✅ B50上传任务已提交!\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
|
|
@@ -2707,7 +2868,20 @@ function apply(ctx, config) {
|
|
|
2707
2868
|
const fishAbort = await (async () => {
|
|
2708
2869
|
try {
|
|
2709
2870
|
await waitForQueue(session);
|
|
2710
|
-
|
|
2871
|
+
let fishResult = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText, fishToken);
|
|
2872
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
2873
|
+
if (qrTextResult.fromCache && !fishResult.UploadStatus && (fishResult.msg?.includes('二维码') || fishResult.msg?.includes('qr_text') || fishResult.msg?.includes('无效'))) {
|
|
2874
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
2875
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
2876
|
+
if (retryQrText.error) {
|
|
2877
|
+
const taskIdInfo = fishResult.task_id ? `\n任务ID: ${fishResult.task_id}` : '';
|
|
2878
|
+
results.push(`🐟 水鱼: ❌ 上传失败:${fishResult.msg || '未知错误'}\n获取新二维码失败:${retryQrText.error}${taskIdInfo}`);
|
|
2879
|
+
return null;
|
|
2880
|
+
}
|
|
2881
|
+
// 在调用API前加入队列
|
|
2882
|
+
await waitForQueue(session);
|
|
2883
|
+
fishResult = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, fishToken);
|
|
2884
|
+
}
|
|
2711
2885
|
if (!fishResult.UploadStatus) {
|
|
2712
2886
|
if (fishResult.msg === '该账号下存在未完成的任务') {
|
|
2713
2887
|
results.push('🐟 水鱼: ⚠️ 当前账号已有未完成的B50任务,请稍后再试,无需重复上传。');
|
|
@@ -2730,20 +2904,64 @@ function apply(ctx, config) {
|
|
|
2730
2904
|
return null;
|
|
2731
2905
|
}
|
|
2732
2906
|
catch (error) {
|
|
2733
|
-
|
|
2734
|
-
if (
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2907
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
2908
|
+
if (qrTextResult.fromCache) {
|
|
2909
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
2910
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
2911
|
+
if (retryQrText.error) {
|
|
2912
|
+
results.push(`🐟 水鱼: ❌ 获取二维码失败:${retryQrText.error}`);
|
|
2913
|
+
return null;
|
|
2914
|
+
}
|
|
2915
|
+
// 在调用API前加入队列
|
|
2916
|
+
await waitForQueue(session);
|
|
2917
|
+
try {
|
|
2918
|
+
const fishResult = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, fishToken);
|
|
2919
|
+
if (!fishResult.UploadStatus) {
|
|
2920
|
+
if (fishResult.msg === '该账号下存在未完成的任务') {
|
|
2921
|
+
results.push('🐟 水鱼: ⚠️ 当前账号已有未完成的B50任务,请稍后再试,无需重复上传。');
|
|
2922
|
+
return null;
|
|
2923
|
+
}
|
|
2924
|
+
const taskIdInfo = fishResult.task_id ? `\n任务ID: ${fishResult.task_id}` : '';
|
|
2925
|
+
results.push(`🐟 水鱼: ❌ 上传失败:${fishResult.msg || '未知错误'}${taskIdInfo}`);
|
|
2926
|
+
return null;
|
|
2927
|
+
}
|
|
2928
|
+
scheduleB50Notification(session, fishResult.task_id);
|
|
2929
|
+
results.push(`🐟 水鱼: ✅ B50任务已提交!\n任务ID: ${fishResult.task_id}\n请耐心等待任务完成,预计1-10分钟`);
|
|
2930
|
+
return null;
|
|
2931
|
+
}
|
|
2932
|
+
catch (retryError) {
|
|
2933
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, retryError, rebindTimeout);
|
|
2934
|
+
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
2935
|
+
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
2936
|
+
}
|
|
2937
|
+
if (retryError?.code === 'ECONNABORTED' || String(retryError?.message || '').includes('timeout')) {
|
|
2938
|
+
results.push('🐟 水鱼: ❌ 上传超时,请稍后再试一次。');
|
|
2939
|
+
return null;
|
|
2940
|
+
}
|
|
2941
|
+
if (retryError?.response) {
|
|
2942
|
+
results.push(`🐟 水鱼: ❌ API请求失败: ${retryError.response.status} ${retryError.response.statusText}`);
|
|
2943
|
+
return null;
|
|
2944
|
+
}
|
|
2945
|
+
results.push(`🐟 水鱼: ❌ 上传失败: ${retryError?.message || '未知错误'}`);
|
|
2946
|
+
return null;
|
|
2947
|
+
}
|
|
2740
2948
|
}
|
|
2741
|
-
|
|
2742
|
-
|
|
2949
|
+
else {
|
|
2950
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
|
|
2951
|
+
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
2952
|
+
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
2953
|
+
}
|
|
2954
|
+
if (error?.code === 'ECONNABORTED' || String(error?.message || '').includes('timeout')) {
|
|
2955
|
+
results.push('🐟 水鱼: ❌ 上传超时,请稍后再试一次。');
|
|
2956
|
+
return null;
|
|
2957
|
+
}
|
|
2958
|
+
if (error?.response) {
|
|
2959
|
+
results.push(`🐟 水鱼: ❌ API请求失败: ${error.response.status} ${error.response.statusText}`);
|
|
2960
|
+
return null;
|
|
2961
|
+
}
|
|
2962
|
+
results.push(`🐟 水鱼: ❌ 上传失败: ${error?.message || '未知错误'}`);
|
|
2743
2963
|
return null;
|
|
2744
2964
|
}
|
|
2745
|
-
results.push(`🐟 水鱼: ❌ 上传失败: ${error?.message || '未知错误'}`);
|
|
2746
|
-
return null;
|
|
2747
2965
|
}
|
|
2748
2966
|
})();
|
|
2749
2967
|
if (fishAbort) {
|
|
@@ -2753,7 +2971,20 @@ function apply(ctx, config) {
|
|
|
2753
2971
|
const lxnsAbort = await (async () => {
|
|
2754
2972
|
try {
|
|
2755
2973
|
await waitForQueue(session);
|
|
2756
|
-
|
|
2974
|
+
let lxResult = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText, finalLxnsCode);
|
|
2975
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
2976
|
+
if (qrTextResult.fromCache && !lxResult.UploadStatus && (lxResult.msg?.includes('二维码') || lxResult.msg?.includes('qr_text') || lxResult.msg?.includes('无效'))) {
|
|
2977
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
2978
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
2979
|
+
if (retryQrText.error) {
|
|
2980
|
+
const taskIdInfo = lxResult.task_id ? `\n任务ID: ${lxResult.task_id}` : '';
|
|
2981
|
+
results.push(`❄️ 落雪: ❌ 上传失败:${lxResult.msg || '未知错误'}\n获取新二维码失败:${retryQrText.error}${taskIdInfo}`);
|
|
2982
|
+
return null;
|
|
2983
|
+
}
|
|
2984
|
+
// 在调用API前加入队列
|
|
2985
|
+
await waitForQueue(session);
|
|
2986
|
+
lxResult = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, finalLxnsCode);
|
|
2987
|
+
}
|
|
2757
2988
|
if (!lxResult.UploadStatus) {
|
|
2758
2989
|
if (lxResult.msg === '该账号下存在未完成的任务') {
|
|
2759
2990
|
results.push('❄️ 落雪: ⚠️ 当前账号已有未完成的B50任务,请稍后再试,无需重复上传。');
|
|
@@ -2776,20 +3007,64 @@ function apply(ctx, config) {
|
|
|
2776
3007
|
return null;
|
|
2777
3008
|
}
|
|
2778
3009
|
catch (error) {
|
|
2779
|
-
|
|
2780
|
-
if (
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
3010
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
3011
|
+
if (qrTextResult.fromCache) {
|
|
3012
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
3013
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
3014
|
+
if (retryQrText.error) {
|
|
3015
|
+
results.push(`❄️ 落雪: ❌ 获取二维码失败:${retryQrText.error}`);
|
|
3016
|
+
return null;
|
|
3017
|
+
}
|
|
3018
|
+
// 在调用API前加入队列
|
|
3019
|
+
await waitForQueue(session);
|
|
3020
|
+
try {
|
|
3021
|
+
const lxResult = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, finalLxnsCode);
|
|
3022
|
+
if (!lxResult.UploadStatus) {
|
|
3023
|
+
if (lxResult.msg === '该账号下存在未完成的任务') {
|
|
3024
|
+
results.push('❄️ 落雪: ⚠️ 当前账号已有未完成的B50任务,请稍后再试,无需重复上传。');
|
|
3025
|
+
return null;
|
|
3026
|
+
}
|
|
3027
|
+
const taskIdInfo = lxResult.task_id ? `\n任务ID: ${lxResult.task_id}` : '';
|
|
3028
|
+
results.push(`❄️ 落雪: ❌ 上传失败:${lxResult.msg || '未知错误'}${taskIdInfo}`);
|
|
3029
|
+
return null;
|
|
3030
|
+
}
|
|
3031
|
+
scheduleLxB50Notification(session, lxResult.task_id);
|
|
3032
|
+
results.push(`❄️ 落雪: ✅ B50任务已提交!\n任务ID: ${lxResult.task_id}\n请耐心等待任务完成,预计1-10分钟`);
|
|
3033
|
+
return null;
|
|
3034
|
+
}
|
|
3035
|
+
catch (retryError) {
|
|
3036
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, retryError, rebindTimeout);
|
|
3037
|
+
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
3038
|
+
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
3039
|
+
}
|
|
3040
|
+
if (retryError?.code === 'ECONNABORTED' || String(retryError?.message || '').includes('timeout')) {
|
|
3041
|
+
results.push('❄️ 落雪: ❌ 上传超时,请稍后再试一次。');
|
|
3042
|
+
return null;
|
|
3043
|
+
}
|
|
3044
|
+
if (retryError?.response) {
|
|
3045
|
+
results.push(`❄️ 落雪: ❌ API请求失败: ${retryError.response.status} ${retryError.response.statusText}`);
|
|
3046
|
+
return null;
|
|
3047
|
+
}
|
|
3048
|
+
results.push(`❄️ 落雪: ❌ 上传失败: ${retryError?.message || '未知错误'}`);
|
|
3049
|
+
return null;
|
|
3050
|
+
}
|
|
2786
3051
|
}
|
|
2787
|
-
|
|
2788
|
-
|
|
3052
|
+
else {
|
|
3053
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
|
|
3054
|
+
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
3055
|
+
return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
|
|
3056
|
+
}
|
|
3057
|
+
if (error?.code === 'ECONNABORTED' || String(error?.message || '').includes('timeout')) {
|
|
3058
|
+
results.push('❄️ 落雪: ❌ 上传超时,请稍后再试一次。');
|
|
3059
|
+
return null;
|
|
3060
|
+
}
|
|
3061
|
+
if (error?.response) {
|
|
3062
|
+
results.push(`❄️ 落雪: ❌ API请求失败: ${error.response.status} ${error.response.statusText}`);
|
|
3063
|
+
return null;
|
|
3064
|
+
}
|
|
3065
|
+
results.push(`❄️ 落雪: ❌ 上传失败: ${error?.message || '未知错误'}`);
|
|
2789
3066
|
return null;
|
|
2790
3067
|
}
|
|
2791
|
-
results.push(`❄️ 落雪: ❌ 上传失败: ${error?.message || '未知错误'}`);
|
|
2792
|
-
return null;
|
|
2793
3068
|
}
|
|
2794
3069
|
})();
|
|
2795
3070
|
if (lxnsAbort) {
|
|
@@ -2925,90 +3200,158 @@ function apply(ctx, config) {
|
|
|
2925
3200
|
/**
|
|
2926
3201
|
* 发收藏品
|
|
2927
3202
|
* 用法: /mai发收藏品
|
|
2928
|
-
* @deprecated 发收藏品功能已在新API中移除,已注释
|
|
2929
3203
|
*/
|
|
2930
|
-
/*
|
|
2931
3204
|
ctx.command('mai发收藏品 [targetUserId:text]', '发放收藏品')
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
3205
|
+
.userFields(['authority'])
|
|
3206
|
+
.option('bypass', '-bypass 绕过确认')
|
|
3207
|
+
.action(async ({ session, options }, targetUserId) => {
|
|
2935
3208
|
if (!session) {
|
|
2936
|
-
|
|
3209
|
+
return '❌ 无法获取会话信息';
|
|
3210
|
+
}
|
|
3211
|
+
// 检查白名单
|
|
3212
|
+
const whitelistCheck = checkWhitelist(session, config);
|
|
3213
|
+
if (!whitelistCheck.allowed) {
|
|
3214
|
+
return whitelistCheck.message || '本群暂时没有被授权使用本Bot的功能,请添加官方群聊1072033605。';
|
|
2937
3215
|
}
|
|
2938
|
-
|
|
2939
3216
|
try {
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
machineInfo.
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3217
|
+
// 获取目标用户绑定
|
|
3218
|
+
const { binding, isProxy, error } = await getTargetBinding(session, targetUserId);
|
|
3219
|
+
if (error || !binding) {
|
|
3220
|
+
return error || '❌ 获取用户绑定失败';
|
|
3221
|
+
}
|
|
3222
|
+
const userId = binding.userId;
|
|
3223
|
+
const proxyTip = isProxy ? `(代操作用户 ${userId})` : '';
|
|
3224
|
+
// 交互式选择收藏品类别
|
|
3225
|
+
const itemKind = await promptCollectionType(session);
|
|
3226
|
+
if (itemKind === null) {
|
|
3227
|
+
return '操作已取消';
|
|
3228
|
+
}
|
|
3229
|
+
const selectedType = COLLECTION_TYPE_OPTIONS.find(opt => opt.value === itemKind);
|
|
3230
|
+
await session.send(`已选择:${selectedType?.label} (${itemKind})\n\n` +
|
|
3231
|
+
`请输入收藏品ID(数字)\n` +
|
|
3232
|
+
`如果不知道收藏品ID,请前往 https://sdgb.lemonno.xyz/ 查询\n` +
|
|
3233
|
+
`乐曲解禁请输入乐曲ID\n\n` +
|
|
3234
|
+
`输入0取消操作`);
|
|
3235
|
+
const promptSession = await waitForUserReply(session, ctx, 60000);
|
|
3236
|
+
const itemIdInput = promptSession?.content?.trim() || '';
|
|
3237
|
+
if (!itemIdInput || itemIdInput === '0') {
|
|
3238
|
+
return '操作已取消';
|
|
3239
|
+
}
|
|
3240
|
+
const itemId = itemIdInput.trim();
|
|
3241
|
+
// 验证ID是否为数字
|
|
3242
|
+
if (!/^\d+$/.test(itemId)) {
|
|
3243
|
+
return '❌ ID必须是数字,请重新输入';
|
|
3244
|
+
}
|
|
3245
|
+
// 确认操作(如果未使用 -bypass)
|
|
3246
|
+
if (!options?.bypass) {
|
|
3247
|
+
const confirm = await promptYesLocal(session, `⚠️ 即将为 ${maskUserId(binding.maiUid)} 发放收藏品${proxyTip}\n类型: ${selectedType?.label} (${itemKind})\nID: ${itemId}\n确认继续?`);
|
|
3248
|
+
if (!confirm) {
|
|
3249
|
+
return '操作已取消';
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
// 获取qr_text(交互式或从绑定中获取)
|
|
3253
|
+
const qrTextResult = await getQrText(session, ctx, api, binding, config, rebindTimeout);
|
|
3254
|
+
if (qrTextResult.error) {
|
|
3255
|
+
if (qrTextResult.needRebind) {
|
|
3256
|
+
const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
|
|
3257
|
+
if (!rebindResult.success) {
|
|
3258
|
+
return `❌ 重新绑定失败:${rebindResult.error || '未知错误'}\n请使用 /mai绑定 重新绑定二维码`;
|
|
3259
|
+
}
|
|
3260
|
+
return '✅ 重新绑定成功!请重新执行 /mai发收藏品 操作。';
|
|
3261
|
+
}
|
|
3262
|
+
return `❌ 获取二维码失败:${qrTextResult.error}`;
|
|
3263
|
+
}
|
|
3264
|
+
// 在调用API前加入队列
|
|
3265
|
+
await waitForQueue(session);
|
|
3266
|
+
await session.send('请求成功提交,请等待服务器响应。(通常需要2-3分钟)');
|
|
3267
|
+
// 使用新API获取收藏品(需要qr_text)
|
|
3268
|
+
const machineInfo = config.machineInfo;
|
|
3269
|
+
let result;
|
|
3270
|
+
let usedCache = qrTextResult.fromCache === true;
|
|
3271
|
+
try {
|
|
3272
|
+
result = await api.getItem(machineInfo.regionId, machineInfo.regionName, machineInfo.clientId, machineInfo.placeId, machineInfo.placeName, parseInt(itemId, 10), itemKind, 1, // item_stock: 1
|
|
3273
|
+
qrTextResult.qrText);
|
|
3274
|
+
}
|
|
3275
|
+
catch (error) {
|
|
3276
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
3277
|
+
if (usedCache) {
|
|
3278
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
3279
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
3280
|
+
if (retryQrText.error) {
|
|
3281
|
+
return `❌ 获取二维码失败:${retryQrText.error}`;
|
|
3282
|
+
}
|
|
3283
|
+
// 在调用API前加入队列
|
|
3284
|
+
await waitForQueue(session);
|
|
3285
|
+
result = await api.getItem(machineInfo.regionId, machineInfo.regionName, machineInfo.clientId, machineInfo.placeId, machineInfo.placeName, parseInt(itemId, 10), itemKind, 1, // item_stock: 1
|
|
3286
|
+
retryQrText.qrText);
|
|
3287
|
+
}
|
|
3288
|
+
else {
|
|
3289
|
+
// 如果API返回失败,可能需要重新绑定
|
|
3290
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
|
|
3291
|
+
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
3292
|
+
// 重新绑定成功,重试获取收藏品
|
|
3293
|
+
const retryQrText = await getQrText(session, ctx, api, failureResult.rebindResult.newBinding, config, rebindTimeout);
|
|
3294
|
+
if (retryQrText.error) {
|
|
3295
|
+
return `❌ 重新绑定后获取二维码失败:${retryQrText.error}`;
|
|
3296
|
+
}
|
|
3297
|
+
// 在调用API前加入队列
|
|
3298
|
+
await waitForQueue(session);
|
|
3299
|
+
result = await api.getItem(machineInfo.regionId, machineInfo.regionName, machineInfo.clientId, machineInfo.placeId, machineInfo.placeName, parseInt(itemId, 10), itemKind, 1, // item_stock: 1
|
|
3300
|
+
retryQrText.qrText);
|
|
3301
|
+
}
|
|
3302
|
+
else {
|
|
3303
|
+
throw error;
|
|
3304
|
+
}
|
|
3305
|
+
}
|
|
3306
|
+
}
|
|
3307
|
+
if (!result.UserAllStatus || !result.LoginStatus || !result.LogoutStatus) {
|
|
3308
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
3309
|
+
if (usedCache && (!result.QrStatus || result.LoginStatus === false)) {
|
|
3310
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
3311
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
3312
|
+
if (retryQrText.error) {
|
|
3313
|
+
return `❌ 获取二维码失败:${retryQrText.error}`;
|
|
3314
|
+
}
|
|
3315
|
+
// 在调用API前加入队列
|
|
3316
|
+
await waitForQueue(session);
|
|
3317
|
+
result = await api.getItem(machineInfo.regionId, machineInfo.regionName, machineInfo.clientId, machineInfo.placeId, machineInfo.placeName, parseInt(itemId, 10), itemKind, 1, // item_stock: 1
|
|
3318
|
+
retryQrText.qrText);
|
|
3319
|
+
if (!result.UserAllStatus || !result.LoginStatus || !result.LogoutStatus) {
|
|
3320
|
+
if (!result.QrStatus || result.LoginStatus === false) {
|
|
3321
|
+
const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
|
|
3322
|
+
if (rebindResult.success && rebindResult.newBinding) {
|
|
3323
|
+
return `✅ 重新绑定成功!请重新执行发收藏品操作。`;
|
|
3324
|
+
}
|
|
3325
|
+
return `❌ 发放收藏品失败:服务器返回未成功\n重新绑定失败:${rebindResult.error || '未知错误'}`;
|
|
3326
|
+
}
|
|
3327
|
+
return '❌ 发放收藏品失败:服务器返回未成功,请确认是否已在短时间内多次执行发收藏品指令或稍后再试或点击获取二维码刷新账号后再试。';
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3330
|
+
else {
|
|
3331
|
+
// 如果返回失败,可能需要重新绑定
|
|
3332
|
+
if (!result.QrStatus || result.LoginStatus === false) {
|
|
3333
|
+
const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
|
|
3334
|
+
if (rebindResult.success && rebindResult.newBinding) {
|
|
3335
|
+
return `✅ 重新绑定成功!请重新执行发收藏品操作。`;
|
|
3336
|
+
}
|
|
3337
|
+
return `❌ 发放收藏品失败:服务器返回未成功\n重新绑定失败:${rebindResult.error || '未知错误'}`;
|
|
3338
|
+
}
|
|
3339
|
+
return '❌ 发放收藏品失败:服务器返回未成功,请确认是否已在短时间内多次执行发收藏品指令或稍后再试或点击获取二维码刷新账号后再试。';
|
|
3340
|
+
}
|
|
3341
|
+
}
|
|
3342
|
+
return `✅ 已为 ${maskUserId(binding.maiUid)} 发放收藏品${proxyTip}\n类型: ${selectedType?.label}\nID: ${itemId}`;
|
|
3009
3343
|
}
|
|
3010
|
-
|
|
3011
|
-
|
|
3344
|
+
catch (error) {
|
|
3345
|
+
logger.error('发收藏品失败:', error);
|
|
3346
|
+
if (maintenanceMode) {
|
|
3347
|
+
return maintenanceMessage;
|
|
3348
|
+
}
|
|
3349
|
+
if (error?.response) {
|
|
3350
|
+
return `❌ API请求失败: ${error.response.status} ${error.response.statusText}\n\n${maintenanceMessage}`;
|
|
3351
|
+
}
|
|
3352
|
+
return `❌ 发放失败: ${error?.message || '未知错误'}\n\n${maintenanceMessage}`;
|
|
3353
|
+
}
|
|
3354
|
+
});
|
|
3012
3355
|
/**
|
|
3013
3356
|
* 清收藏品
|
|
3014
3357
|
* 用法: /mai清收藏品
|
|
@@ -3367,41 +3710,76 @@ function apply(ctx, config) {
|
|
|
3367
3710
|
await waitForQueue(session);
|
|
3368
3711
|
// 上传落雪B50(使用新API,需要qr_text)
|
|
3369
3712
|
let result;
|
|
3713
|
+
let usedCache = qrTextResult.fromCache === true;
|
|
3370
3714
|
try {
|
|
3371
3715
|
result = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText, finalLxnsCode);
|
|
3372
3716
|
}
|
|
3373
3717
|
catch (error) {
|
|
3374
|
-
//
|
|
3375
|
-
|
|
3376
|
-
|
|
3377
|
-
//
|
|
3378
|
-
const retryQrText = await getQrText(session, ctx, api, failureResult.rebindResult.newBinding, config, rebindTimeout);
|
|
3718
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
3719
|
+
if (usedCache) {
|
|
3720
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
3721
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
3379
3722
|
if (retryQrText.error) {
|
|
3380
|
-
return `❌
|
|
3723
|
+
return `❌ 获取二维码失败:${retryQrText.error}`;
|
|
3381
3724
|
}
|
|
3382
3725
|
// 在调用API前加入队列
|
|
3383
3726
|
await waitForQueue(session);
|
|
3384
3727
|
result = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, finalLxnsCode);
|
|
3385
3728
|
}
|
|
3386
3729
|
else {
|
|
3387
|
-
|
|
3730
|
+
// 如果API返回失败,可能需要重新绑定
|
|
3731
|
+
const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
|
|
3732
|
+
if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
|
|
3733
|
+
// 重新绑定成功,重试上传
|
|
3734
|
+
const retryQrText = await getQrText(session, ctx, api, failureResult.rebindResult.newBinding, config, rebindTimeout);
|
|
3735
|
+
if (retryQrText.error) {
|
|
3736
|
+
return `❌ 重新绑定后获取二维码失败:${retryQrText.error}`;
|
|
3737
|
+
}
|
|
3738
|
+
// 在调用API前加入队列
|
|
3739
|
+
await waitForQueue(session);
|
|
3740
|
+
result = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, finalLxnsCode);
|
|
3741
|
+
}
|
|
3742
|
+
else {
|
|
3743
|
+
throw error;
|
|
3744
|
+
}
|
|
3388
3745
|
}
|
|
3389
3746
|
}
|
|
3390
3747
|
if (!result.UploadStatus) {
|
|
3391
|
-
|
|
3392
|
-
|
|
3748
|
+
// 如果使用了缓存且失败,尝试重新获取SGID
|
|
3749
|
+
if (usedCache && (result.msg?.includes('二维码') || result.msg?.includes('qr_text') || result.msg?.includes('无效'))) {
|
|
3750
|
+
logger.info('使用缓存的SGID失败,尝试重新获取SGID');
|
|
3751
|
+
const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
|
|
3752
|
+
if (retryQrText.error) {
|
|
3753
|
+
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
3754
|
+
return `❌ 上传失败:${result.msg || '未知错误'}\n获取新二维码失败:${retryQrText.error}${taskIdInfo}`;
|
|
3755
|
+
}
|
|
3756
|
+
// 在调用API前加入队列
|
|
3757
|
+
await waitForQueue(session);
|
|
3758
|
+
result = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, finalLxnsCode);
|
|
3759
|
+
if (!result.UploadStatus) {
|
|
3760
|
+
if (result.msg === '该账号下存在未完成的任务') {
|
|
3761
|
+
return '⚠️ 当前账号已有未完成的落雪B50任务,请耐心等待任务完成,预计1-10分钟,无需重复上传。';
|
|
3762
|
+
}
|
|
3763
|
+
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
3764
|
+
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
3765
|
+
}
|
|
3393
3766
|
}
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3767
|
+
else {
|
|
3768
|
+
if (result.msg === '该账号下存在未完成的任务') {
|
|
3769
|
+
return '⚠️ 当前账号已有未完成的落雪B50任务,请耐心等待任务完成,预计1-10分钟,无需重复上传。';
|
|
3770
|
+
}
|
|
3771
|
+
// 如果返回失败,可能需要重新绑定
|
|
3772
|
+
if (result.msg?.includes('二维码') || result.msg?.includes('qr_text') || result.msg?.includes('无效')) {
|
|
3773
|
+
const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
|
|
3774
|
+
if (rebindResult.success && rebindResult.newBinding) {
|
|
3775
|
+
return `✅ 重新绑定成功!请重新执行上传操作。`;
|
|
3776
|
+
}
|
|
3777
|
+
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
3778
|
+
return `❌ 上传失败:${result.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}`;
|
|
3399
3779
|
}
|
|
3400
3780
|
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
3401
|
-
return `❌ 上传失败:${result.msg || '未知错误'}
|
|
3781
|
+
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
3402
3782
|
}
|
|
3403
|
-
const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
|
|
3404
|
-
return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
|
|
3405
3783
|
}
|
|
3406
3784
|
scheduleLxB50Notification(session, result.task_id);
|
|
3407
3785
|
return `✅ 落雪B50上传任务已提交!\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
|