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): + +