koishi-plugin-maibot 1.7.31 → 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/index.js CHANGED
@@ -674,13 +674,26 @@ async function waitForUserReply(session, ctx, timeout) {
674
674
  }
675
675
  /**
676
676
  * 交互式获取二维码文本(qr_text)
677
- * 废弃旧的uid策略,每次都需要新的二维码
678
- * 不再使用binding.qrCode缓存,每次操作都要求用户提供新二维码
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
- // 废弃旧的uid策略,每次都需要新的二维码
683
- // 不再使用binding.qrCode缓存,直接提示用户输入
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` : '') +
@@ -2400,34 +2419,73 @@ function apply(ctx, config) {
2400
2419
  await session.send('请求成功提交,请等待服务器响应。(通常需要2-3分钟)');
2401
2420
  // 使用新API获取功能票(需要qr_text)
2402
2421
  let ticketResult;
2422
+ let usedCache = qrTextResult.fromCache === true;
2403
2423
  try {
2404
2424
  ticketResult = await api.getTicket(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, multiple, qrTextResult.qrText);
2405
2425
  }
2406
2426
  catch (error) {
2407
- // 如果API返回失败,可能需要重新绑定
2408
- const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
2409
- if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
2410
- // 重新绑定成功,重试获取功能票
2411
- 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); // 禁用缓存,强制重新输入
2412
2431
  if (retryQrText.error) {
2413
- return `❌ 重新绑定后获取二维码失败:${retryQrText.error}`;
2432
+ return `❌ 获取二维码失败:${retryQrText.error}`;
2414
2433
  }
2434
+ // 在调用API前加入队列
2435
+ await waitForQueue(session);
2415
2436
  ticketResult = await api.getTicket(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, multiple, retryQrText.qrText);
2416
2437
  }
2417
2438
  else {
2418
- throw error;
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
+ }
2419
2454
  }
2420
2455
  }
2421
2456
  if (!ticketResult.TicketStatus || !ticketResult.LoginStatus || !ticketResult.LogoutStatus) {
2422
- // 如果返回失败,可能需要重新绑定
2423
- if (!ticketResult.QrStatus || ticketResult.LoginStatus === false) {
2424
- const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
2425
- if (rebindResult.success && rebindResult.newBinding) {
2426
- return `✅ 重新绑定成功!请重新执行发票操作。`;
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}`;
2463
+ }
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 '❌ 发票失败:服务器返回未成功,请确认是否已在短时间内多次执行发票指令或稍后再试或点击获取二维码刷新账号后再试。';
2427
2476
  }
2428
- return `❌ 发放功能票失败:服务器返回未成功\n重新绑定失败:${rebindResult.error || '未知错误'}`;
2429
2477
  }
2430
- return '❌ 发票失败:服务器返回未成功,请确认是否已在短时间内多次执行发票指令或稍后再试或点击获取二维码刷新账号后再试。';
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 '❌ 发票失败:服务器返回未成功,请确认是否已在短时间内多次执行发票指令或稍后再试或点击获取二维码刷新账号后再试。';
2488
+ }
2431
2489
  }
2432
2490
  return `✅ 已发放 ${multiple} 倍票\n请稍等几分钟在游戏内确认`;
2433
2491
  }
@@ -2629,41 +2687,76 @@ function apply(ctx, config) {
2629
2687
  await waitForQueue(session);
2630
2688
  // 上传B50(使用新API,需要qr_text)
2631
2689
  let result;
2690
+ let usedCache = qrTextResult.fromCache === true;
2632
2691
  try {
2633
2692
  result = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText, binding.fishToken);
2634
2693
  }
2635
2694
  catch (error) {
2636
- // 如果API返回失败,可能需要重新绑定
2637
- const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
2638
- if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
2639
- // 重新绑定成功,重试上传
2640
- 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); // 禁用缓存,强制重新输入
2641
2699
  if (retryQrText.error) {
2642
- return `❌ 重新绑定后获取二维码失败:${retryQrText.error}`;
2700
+ return `❌ 获取二维码失败:${retryQrText.error}`;
2643
2701
  }
2644
2702
  // 在调用API前加入队列
2645
2703
  await waitForQueue(session);
2646
2704
  result = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, binding.fishToken);
2647
2705
  }
2648
2706
  else {
2649
- throw error;
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
+ }
2650
2722
  }
2651
2723
  }
2652
2724
  if (!result.UploadStatus) {
2653
- if (result.msg === '该账号下存在未完成的任务') {
2654
- return '⚠️ 当前账号已有未完成的水鱼B50任务,请耐心等待任务完成,预计1-10分钟,无需重复上传。';
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
+ }
2655
2743
  }
2656
- // 如果返回失败,可能需要重新绑定
2657
- if (result.msg?.includes('二维码') || result.msg?.includes('qr_text') || result.msg?.includes('无效')) {
2658
- const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
2659
- if (rebindResult.success && rebindResult.newBinding) {
2660
- return `✅ 重新绑定成功!请重新执行上传操作。`;
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}`;
2661
2756
  }
2662
2757
  const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
2663
- return `❌ 上传失败:${result.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}`;
2758
+ return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
2664
2759
  }
2665
- const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
2666
- return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
2667
2760
  }
2668
2761
  scheduleB50Notification(session, result.task_id);
2669
2762
  return `✅ B50上传任务已提交!\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;
@@ -2775,7 +2868,20 @@ function apply(ctx, config) {
2775
2868
  const fishAbort = await (async () => {
2776
2869
  try {
2777
2870
  await waitForQueue(session);
2778
- const fishResult = await api.uploadB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText, fishToken);
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
+ }
2779
2885
  if (!fishResult.UploadStatus) {
2780
2886
  if (fishResult.msg === '该账号下存在未完成的任务') {
2781
2887
  results.push('🐟 水鱼: ⚠️ 当前账号已有未完成的B50任务,请稍后再试,无需重复上传。');
@@ -2798,20 +2904,64 @@ function apply(ctx, config) {
2798
2904
  return null;
2799
2905
  }
2800
2906
  catch (error) {
2801
- const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
2802
- if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
2803
- return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
2804
- }
2805
- if (error?.code === 'ECONNABORTED' || String(error?.message || '').includes('timeout')) {
2806
- results.push('🐟 水鱼: ❌ 上传超时,请稍后再试一次。');
2807
- return null;
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
+ }
2808
2948
  }
2809
- if (error?.response) {
2810
- results.push(`🐟 水鱼: API请求失败: ${error.response.status} ${error.response.statusText}`);
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 || '未知错误'}`);
2811
2963
  return null;
2812
2964
  }
2813
- results.push(`🐟 水鱼: ❌ 上传失败: ${error?.message || '未知错误'}`);
2814
- return null;
2815
2965
  }
2816
2966
  })();
2817
2967
  if (fishAbort) {
@@ -2821,7 +2971,20 @@ function apply(ctx, config) {
2821
2971
  const lxnsAbort = await (async () => {
2822
2972
  try {
2823
2973
  await waitForQueue(session);
2824
- const lxResult = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText, finalLxnsCode);
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
+ }
2825
2988
  if (!lxResult.UploadStatus) {
2826
2989
  if (lxResult.msg === '该账号下存在未完成的任务') {
2827
2990
  results.push('❄️ 落雪: ⚠️ 当前账号已有未完成的B50任务,请稍后再试,无需重复上传。');
@@ -2844,20 +3007,64 @@ function apply(ctx, config) {
2844
3007
  return null;
2845
3008
  }
2846
3009
  catch (error) {
2847
- const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
2848
- if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
2849
- return '✅ 重新绑定成功!请重新执行 /maiua 上传操作。';
2850
- }
2851
- if (error?.code === 'ECONNABORTED' || String(error?.message || '').includes('timeout')) {
2852
- results.push('❄️ 落雪: ❌ 上传超时,请稍后再试一次。');
2853
- return null;
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
+ }
2854
3051
  }
2855
- if (error?.response) {
2856
- results.push(`❄️ 落雪: API请求失败: ${error.response.status} ${error.response.statusText}`);
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 || '未知错误'}`);
2857
3066
  return null;
2858
3067
  }
2859
- results.push(`❄️ 落雪: ❌ 上传失败: ${error?.message || '未知错误'}`);
2860
- return null;
2861
3068
  }
2862
3069
  })();
2863
3070
  if (lxnsAbort) {
@@ -3060,18 +3267,18 @@ function apply(ctx, config) {
3060
3267
  // 使用新API获取收藏品(需要qr_text)
3061
3268
  const machineInfo = config.machineInfo;
3062
3269
  let result;
3270
+ let usedCache = qrTextResult.fromCache === true;
3063
3271
  try {
3064
3272
  result = await api.getItem(machineInfo.regionId, machineInfo.regionName, machineInfo.clientId, machineInfo.placeId, machineInfo.placeName, parseInt(itemId, 10), itemKind, 1, // item_stock: 1
3065
3273
  qrTextResult.qrText);
3066
3274
  }
3067
3275
  catch (error) {
3068
- // 如果API返回失败,可能需要重新绑定
3069
- const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
3070
- if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
3071
- // 重新绑定成功,重试获取收藏品
3072
- const retryQrText = await getQrText(session, ctx, api, failureResult.rebindResult.newBinding, config, rebindTimeout);
3276
+ // 如果使用了缓存且失败,尝试重新获取SGID
3277
+ if (usedCache) {
3278
+ logger.info('使用缓存的SGID失败,尝试重新获取SGID');
3279
+ const retryQrText = await getQrText(session, ctx, api, binding, config, rebindTimeout, undefined, false); // 禁用缓存,强制重新输入
3073
3280
  if (retryQrText.error) {
3074
- return `❌ 重新绑定后获取二维码失败:${retryQrText.error}`;
3281
+ return `❌ 获取二维码失败:${retryQrText.error}`;
3075
3282
  }
3076
3283
  // 在调用API前加入队列
3077
3284
  await waitForQueue(session);
@@ -3079,19 +3286,58 @@ function apply(ctx, config) {
3079
3286
  retryQrText.qrText);
3080
3287
  }
3081
3288
  else {
3082
- throw error;
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
+ }
3083
3305
  }
3084
3306
  }
3085
3307
  if (!result.UserAllStatus || !result.LoginStatus || !result.LogoutStatus) {
3086
- // 如果返回失败,可能需要重新绑定
3087
- if (!result.QrStatus || result.LoginStatus === false) {
3088
- const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
3089
- if (rebindResult.success && rebindResult.newBinding) {
3090
- return `✅ 重新绑定成功!请重新执行发收藏品操作。`;
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 || '未知错误'}`;
3091
3338
  }
3092
- return `❌ 发放收藏品失败:服务器返回未成功\n重新绑定失败:${rebindResult.error || '未知错误'}`;
3339
+ return '❌ 发放收藏品失败:服务器返回未成功,请确认是否已在短时间内多次执行发收藏品指令或稍后再试或点击获取二维码刷新账号后再试。';
3093
3340
  }
3094
- return '❌ 发放收藏品失败:服务器返回未成功,请确认是否已在短时间内多次执行发收藏品指令或稍后再试或点击获取二维码刷新账号后再试。';
3095
3341
  }
3096
3342
  return `✅ 已为 ${maskUserId(binding.maiUid)} 发放收藏品${proxyTip}\n类型: ${selectedType?.label}\nID: ${itemId}`;
3097
3343
  }
@@ -3464,41 +3710,76 @@ function apply(ctx, config) {
3464
3710
  await waitForQueue(session);
3465
3711
  // 上传落雪B50(使用新API,需要qr_text)
3466
3712
  let result;
3713
+ let usedCache = qrTextResult.fromCache === true;
3467
3714
  try {
3468
3715
  result = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, qrTextResult.qrText, finalLxnsCode);
3469
3716
  }
3470
3717
  catch (error) {
3471
- // 如果API返回失败,可能需要重新绑定
3472
- const failureResult = await handleApiFailure(session, ctx, api, binding, config, error, rebindTimeout);
3473
- if (failureResult.rebindResult && failureResult.rebindResult.success && failureResult.rebindResult.newBinding) {
3474
- // 重新绑定成功,重试上传
3475
- 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); // 禁用缓存,强制重新输入
3476
3722
  if (retryQrText.error) {
3477
- return `❌ 重新绑定后获取二维码失败:${retryQrText.error}`;
3723
+ return `❌ 获取二维码失败:${retryQrText.error}`;
3478
3724
  }
3479
3725
  // 在调用API前加入队列
3480
3726
  await waitForQueue(session);
3481
3727
  result = await api.uploadLxB50(machineInfo.regionId, machineInfo.clientId, machineInfo.placeId, retryQrText.qrText, finalLxnsCode);
3482
3728
  }
3483
3729
  else {
3484
- throw error;
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
+ }
3485
3745
  }
3486
3746
  }
3487
3747
  if (!result.UploadStatus) {
3488
- if (result.msg === '该账号下存在未完成的任务') {
3489
- return '⚠️ 当前账号已有未完成的落雪B50任务,请耐心等待任务完成,预计1-10分钟,无需重复上传。';
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
+ }
3490
3766
  }
3491
- // 如果返回失败,可能需要重新绑定
3492
- if (result.msg?.includes('二维码') || result.msg?.includes('qr_text') || result.msg?.includes('无效')) {
3493
- const rebindResult = await promptForRebind(session, ctx, api, binding, config, rebindTimeout);
3494
- if (rebindResult.success && rebindResult.newBinding) {
3495
- return `✅ 重新绑定成功!请重新执行上传操作。`;
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}`;
3496
3779
  }
3497
3780
  const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
3498
- return `❌ 上传失败:${result.msg || '未知错误'}\n重新绑定失败:${rebindResult.error || '未知错误'}${taskIdInfo}`;
3781
+ return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
3499
3782
  }
3500
- const taskIdInfo = result.task_id ? `\n任务ID: ${result.task_id}` : '';
3501
- return `❌ 上传失败:${result.msg || '未知错误'}${taskIdInfo}`;
3502
3783
  }
3503
3784
  scheduleLxB50Notification(session, result.task_id);
3504
3785
  return `✅ 落雪B50上传任务已提交!\n任务ID: ${result.task_id}\n\n请耐心等待任务完成,预计1-10分钟`;