From 83e57563d3885fe1cd121e6ebf4e84a07da1df79 Mon Sep 17 00:00:00 2001 From: sunshine Date: Tue, 16 Jun 2026 15:31:58 +0800 Subject: [PATCH 1/2] feat(userscript): CLOSE_INVALID_DELAY via closePlan pattern (v22.4) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - closePlan: single random delay generated once when preview settles (busy/sold_out), never recalculated per-tick - checkPayDialog: only consumes closePlan, no inline random or delay calc - exitTask: uses closePlan instead of hardcoded 2000ms - Config panel: delay input (default 1500ms, +-300ms jitter on plan creation) - scripts/userscripts: precise patch from main copy, no historical cruft This follows the schedule/plan/consume pattern: generate closePlan once → checkPayDialog/exitTask only check if ready --- glm-coding-helper.user.js | 39 ++++++++++++------- scripts/userscripts/glm-coding-helper.user.js | 36 ++++++++++------- 2 files changed, 48 insertions(+), 27 deletions(-) diff --git a/glm-coding-helper.user.js b/glm-coding-helper.user.js index 3935f11..f0d4545 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: (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,13 @@ 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) { - const prices = readDialogPrices(); - if (prices?.any) { - console.log('[GLM v8.9] soldOut但DOM有价格,保留弹窗(前端劫持覆盖了soldOut)'); - return 'keep'; - } + // ── 关闭计划:preview 返回 busy/sold_out 时,按 closePlan 判断是否关闭 ── + if ((PS.result === 'busy' || PS.result === 'sold_out') && closePlan) { + if (Date.now() - closePlan.startedAt >= closePlan.delayMs) { + closePlan = null; + return 'close'; } - return 'close'; + return 'keep'; } // ── 情况 D:接口没说售罄/繁忙,但弹窗里出现小飞机 → 异常不一致 if (hasAirplaneInDialog()) return 'warn'; @@ -863,6 +868,10 @@ 自动关闭无效支付/限流弹窗(默认关闭) ? +
+ 关闭无效弹窗等待延时 (ms): + +
+
+ 关闭无效弹窗等待延时 (ms): + +