fix(userscript): #40 无效支付页不自动关闭 - 加无金额1.7s兜底 (v23.9)

根因: checkPayDialog 只看接口(busy/sold_out才关),接口success时一律keep,
导致金额为空的无效支付页留着不关——即使开了AUTO_CLOSE_INVALID也没用(该开关
只在verdict=close时生效)。#40用户已开开关仍不关。

修复: 接口非busy/sold_out时读弹窗实际金额:
- 有金额(真支付页)→keep并清计时
- 无金额不立刻关——GLM有时先显示无金额/没抢到、约1s后才弹出真金额订单(#16/#40
  反馈的时序),持续无金额超1.7s宽限期才判无效页close

关键: 不误关真支付页。10个单测覆盖真支付页keep/无金额1s后金额出现keep/
无金额1.7s关/busy直接关/弹窗消失重置计时。

fix #40
This commit is contained in:
OLmatter
2026-06-26 01:42:01 +08:00
parent 1e01fad01e
commit cf4e594d49
2 changed files with 22 additions and 3 deletions
+1
View File
@@ -2,6 +2,7 @@
## 2026-06-26
- 发布用户脚本 v23.9:修复 #40「识别验证码后无法自动关闭无效支付界面」。根因是 `checkPayDialog` 决策函数只看接口返回(`busy`/`sold_out` 才关),接口返回 success/其它时一律 keep,导致**金额为空的无效支付页不会被关**——即使开了 `AUTO_CLOSE_INVALID` 也没用(该开关只在 verdict='close' 时生效)。修复:在接口非 busy/sold_out 的分支里读弹窗实际金额,有金额(真支付页)就 keep 并清计时;**无金额不立刻关**——GLM 有时会先显示无金额/没抢到、过约 1 秒才弹出真金额订单(#16/#40 反馈的时序),所以持续无金额超过 **1.7 秒宽限期**才判无效页 close。10 个单元测试覆盖:真支付页不误关 / 无金额 1s 后金额出现不误关 / 无金额 1.7s 关闭 / busy 直接关 / 弹窗消失重置计时。
- 发布用户脚本 v23.8:修复后端日志反复出现 `[captcha] FAIL: detected 0 boxes, need 3` 的问题。根因是 `isPointClickPrompt` 的兜底分支「3-8 个汉字即视为合法点选目标」太宽,把验证码容器的说明性文字(如 aria-label="验证码"、标题「安全验证」「图形验证码」「请点击图中文字」「点击进行验证」等)也判成了目标字,传给后端后 YOLO 在点选图里找不到「验」「证」「码」这些字 → detected 0 boxes,且因每分钟轮询会反复刷屏。修复:① `isPointClickPrompt`/`findPromptText` 加说明性文字黑名单(验证码/安全验证/图形验证/请点击/完成验证/进行验证/点击图中/点击进行);② 收紧 in-page 的 `[aria-label]` 兜底选择器,限定在腾讯验证码容器内,避免抓到页面其它元素。真目标字(山水木/请依次点击)不受影响。
- 修复后端调试图片无限增长占满磁盘的问题:`/captcha_direct` 每次识别都把原图存到 `dataset/debug_captcha_direct/`,加上 `dataset/auto_captured/`(截屏)和 `logs/ppocr_live_crops/`(字裁剪图),三个目录都**没有任何清理**,长时间挂着抢会累积几百上千张。现改为两层清理:① **启动时清空**上次的调试图(重启即放弃旧图);② **运行时滚动**保留最近 N 个(debug 60 / auto_captured 120 / crops 200),连挂几天不重启时兜底。这些目录纯属调试用途,对识别功能无影响。
- 发布用户脚本 v23.7:修复 rush 模式 10:00 到点不自动点验证码确定的问题。根因是 PR #36 的验证码熔断(防自激振荡)有两个缺陷:① `captchaSession.stopped` 一旦置 true 后全文件无任何重置路径(`resetCaptchaSession`/`noteCaptchaSuccess` 都漏清),用户 10:00 前提前开页面、后端没起好或网络抖动累积 3 次失败后,验证码流程被永久焊死,到点也不再识别 → 自然不点确定;② 失败计数跨所有图累计,但自激振荡只在「同一张图反复开火」时才发生。修复:失败计数绑定到 `bgUrl`(换图即重置 failCount/stopped);rush 黄金窗口(到点后 `holdWindowMs` 内)失败只冷却不 hard-stop;`resetCaptchaSession` 和 `noteCaptchaSuccess` 补齐清 `stopped`/`failCount`/`failBgUrl`。保留了 PR #36 对「同一张图自激振荡」的熔断保护,只消除误伤 rush 窗口和永久不可逆两个副作用。15 个单元测试覆盖同图熔断/换图重置/rush 窗口不焊死/窗口外熔断可恢复等场景。
+21 -3
View File
@@ -1,7 +1,7 @@
// ==UserScript==
// @name 智谱 GLM Coding Plan 抢购助手 + 本地 OCR 自动验证码
// @namespace http://tampermonkey.net/
// @version 23.8
// @version 23.9
// @description GLM Coding Rush / 智谱 GLM Coding Plan 抢购助手,一键抢购油猴脚本 / Tampermonkey userscript,配合本地 CPU/GPU OCR(PP-OCRv6)自动识别中文点选验证码并点击,支持多窗口并发、限流重试和支付页安全保护。订阅入口被风控拦截时手动点「特惠订阅」即可,验证码自动打。
// @author mumumi
// @include https://*bigmodel.cn/glm-coding*
@@ -994,9 +994,13 @@
}
// ── v8.9: 弹窗关闭决策(三态返回)────────────────────────────────────────
// 返回: 'close' → 关弹窗试下一个 | 'keep' → 不关 | 'warn' → 异常,告知用户
// 无金额无效页兜底:GLM 有时先显示无金额/没抢到,过 ~1 秒才弹出真金额订单(#16/#40),
// 所以无金额不能立刻关,要持续无金额超过 1.7s 才判无效页关闭。
let noPriceSince = 0;
const NO_PRICE_GRACE_MS = 1700;
function checkPayDialog() {
const dlg = getPayDialog();
if (!dlg) return 'keep';
if (!dlg) { noPriceSince = 0; return 'keep'; }
if (window.__glmRushConfirmed) {
window.__glmRushDialogSeen = 1;
return 'keep';
@@ -1020,7 +1024,21 @@
}
// ── 情况 D:接口没说售罄/繁忙,但弹窗里出现小飞机 → 异常不一致
if (hasAirplaneInDialog()) return 'warn';
// ── 情况 C:接口成功 + 有价格 → 不关
// ── 情况 C:接口成功/其它 → 看弹窗实际有没有金额
const prices = readDialogPrices();
if (prices?.any) {
// 有有效金额(真支付页),清掉无金额计时,保留弹窗等用户支付。
noPriceSince = 0;
return 'keep';
}
// 无金额(疑似无效支付页)。GLM 有时会延迟 ~1s 才渲染出真金额订单,
// 不能立刻关——持续无金额超过宽限期才判无效页关闭。
if (!noPriceSince) noPriceSince = Date.now();
if (Date.now() - noPriceSince >= NO_PRICE_GRACE_MS) {
console.log('[GLM v8.9] 无金额持续 ' + (Date.now() - noPriceSince) + 'ms,判定为无效支付页');
return 'close';
}
console.log('[GLM v8.9] 弹窗暂无金额,宽限等待 ' + (Date.now() - noPriceSince) + '/' + NO_PRICE_GRACE_MS + 'ms');
return 'keep';
}
// ── 底部状态栏 ────────────────────────────────────────────────────────────