diff --git a/glm-coding-helper.user.js b/glm-coding-helper.user.js
index 3935f11..e4b5f89 100644
--- a/glm-coding-helper.user.js
+++ b/glm-coding-helper.user.js
@@ -1,7 +1,7 @@
-// ==UserScript==
+// ==UserScript==
// @name 智谱 GLM Coding Plan 抢购助手 + 本地 OCR 自动验证码
// @namespace http://tampermonkey.net/
-// @version 22.2
+// @version 22.4
// @description GLM Coding Rush / 智谱 GLM Coding Plan 抢购助手,一键抢购油猴脚本 / Tampermonkey userscript,配合本地 CPU/GPU OCR 自动识别中文点选验证码并点击,支持多窗口并发、限流重试和支付页安全保护
// @author mumumi
// @include https://*bigmodel.cn/glm-coding*
@@ -347,6 +347,7 @@
rawCode : null, // v8.9: 记录原始错误码(555/500等)
};
let everSucceeded = false; // v8.9: 一旦拿到过有效 bizId,永不关闭弹窗
+ let closePlan = null; // pre-generated close plan for invalid dialogs {startedAt, delayMs, reason}
// ── fetch 拦截(/api/biz/pay/preview 和 check)──────────────────────────
const _oF = window.fetch;
// v8.0: 从 Cookie 提取 token 和从页面提取组织/项目信息
@@ -429,6 +430,14 @@
throw e;
}
}
+ // 生成关闭计划:preview 结果落定后,生成一次固定的 close plan
+ if ((PS.result === 'busy' || PS.result === 'sold_out') && !closePlan) {
+ closePlan = {
+ startedAt: Date.now(),
+ delayMs: Math.max(0, (CFG.CLOSE_INVALID_DELAY || 1500) + (Math.random() * 600 - 300)),
+ reason: PS.result
+ };
+ }
// 拦截 check:如果 bizId 为 null,直接返回失败
if (url.includes('/api/biz/pay/check')) {
if (url.includes('bizId=null') || !PS.bizId) {
@@ -519,6 +528,7 @@
RUSH_TARGET_SEC : 58,
RUSH_HOLD_WINDOW_MS : 10000,
RUSH_RELEASE_ADVANCE_MS: 40,
+ CLOSE_INVALID_DELAY : 1500,
};
function loadCfg() { try { const s = GM_getValue(STORAGE_KEY, null); return s ? { ...DEF, ...JSON.parse(s) } : { ...DEF }; } catch { return { ...DEF }; } }
function saveCfg(c) { GM_setValue(STORAGE_KEY, JSON.stringify(c)); }
@@ -724,18 +734,25 @@
if (everSucceeded && PS.bizId) return 'keep';
// 接口还没返回
if (PS.inProgress) return 'keep';
- // ── 情况 A:接口 555 系统繁忙 → 关弹窗试下一个
- if (PS.result === 'busy') return 'close';
- // ── 情况 B:接口返回 200+soldOut → 关弹窗试下一个(但前端可能因 JSON.parse 劫持而正常显示了价格)
- if (PS.result === 'sold_out') {
- if (Date.now() - taskClickTime >= 1500) {
+ // ── 关闭计划:preview 返回 busy/sold_out 时,按 closePlan 判断是否关闭 ──
+ if (PS.result === 'busy' && closePlan) {
+ if (Date.now() - closePlan.startedAt >= closePlan.delayMs) {
+ closePlan = null;
+ return 'close';
+ }
+ return 'keep';
+ }
+ if (PS.result === 'sold_out' && closePlan) {
+ if (Date.now() - closePlan.startedAt >= closePlan.delayMs) {
const prices = readDialogPrices();
if (prices?.any) {
- console.log('[GLM v8.9] soldOut但DOM有价格,保留弹窗(前端劫持覆盖了soldOut)');
+ closePlan = null;
return 'keep';
}
+ closePlan = null;
+ return 'close';
}
- return 'close';
+ return 'keep';
}
// ── 情况 D:接口没说售罄/繁忙,但弹窗里出现小飞机 → 异常不一致
if (hasAirplaneInDialog()) return 'warn';
@@ -863,6 +880,10 @@
自动关闭无效支付/限流弹窗(默认关闭)
?
+
+ 关闭无效弹窗等待延时 (ms):
+
+
+
+ 关闭无效弹窗等待延时 (ms):
+
+