From da10cf4ad439c083a3d062ab3f4dbcb6e915741b Mon Sep 17 00:00:00 2001 From: qtaxm <17772864223@163.com> Date: Wed, 8 Apr 2026 11:37:24 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=81=A2=E5=A4=8D=E5=85=A8=E5=B1=80=20J?= =?UTF-8?q?SON.parse=20patch,=20=E4=BF=AE=E5=A4=8D=E5=94=AE=E7=BD=84?= =?UTF-8?q?=E6=8C=89=E9=92=AE=E4=B8=8D=E5=8F=AF=E7=82=B9=E5=87=BB=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- glm-rush-v4.user.js | 11 +---- inject.js | 99 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 82 insertions(+), 28 deletions(-) diff --git a/glm-rush-v4.user.js b/glm-rush-v4.user.js index 670cdfd..f0f3ab1 100644 --- a/glm-rush-v4.user.js +++ b/glm-rush-v4.user.js @@ -124,15 +124,10 @@ } } - // 仅对目标URL响应做patch的标记 - let _shouldPatch = false; - + // 全局 patch: 页面加载时也需要解除售罄状态,否则按钮不可点击 JSON.parse = function (text, reviver) { const result = _parse(text, reviver); - if (_shouldPatch) { - try { patchSoldOut(result); } catch {} - _shouldPatch = false; - } + try { patchSoldOut(result); } catch {} return result; }; Object.defineProperty(JSON.parse, 'toString', { value: () => 'function parse() { [native code] }' }); @@ -155,11 +150,9 @@ return { ok: false, reason: '429 限流', attempt: attemptNum }; } - _shouldPatch = true; // 让 JSON.parse 对此响应做 patch const text = await resp.text(); let data; try { data = _parse(text); } catch { data = null; } - _shouldPatch = false; if (data && data.code === 200 && data.data && data.data.bizId) { const bizId = data.data.bizId; diff --git a/inject.js b/inject.js index c170d60..6caf9c5 100644 --- a/inject.js +++ b/inject.js @@ -112,15 +112,10 @@ } } - // 仅对目标URL响应做patch的标记 - let _shouldPatch = false; - + // 全局 patch: 页面加载时也需要解除售罄状态,否则按钮不可点击 JSON.parse = function (text, reviver) { const result = _parse(text, reviver); - if (_shouldPatch) { - try { patchSoldOut(result); } catch {} - _shouldPatch = false; - } + try { patchSoldOut(result); } catch {} return result; }; Object.defineProperty(JSON.parse, 'toString', { value: () => 'function parse() { [native code] }' }); @@ -143,11 +138,9 @@ return { ok: false, reason: '429 限流', attempt: attemptNum }; } - _shouldPatch = true; // 让 JSON.parse 对此响应做 patch const text = await resp.text(); let data; try { data = _parse(text); } catch { data = null; } - _shouldPatch = false; if (data && data.code === 200 && data.data && data.data.bizId) { const bizId = data.data.bizId; @@ -458,25 +451,93 @@ async function autoRecover() { if (recovering || recoveryAttempts >= CFG.recoveryMax || !state.lastSuccess) return; - const dialog = findErrorDialog(); - if (!dialog) return; recovering = true; recoveryAttempts++; try { - log('检测到错误弹窗, 自动恢复...'); - setState({ cache: state.lastSuccess }); - dismissDialog(dialog); - await sleep(400); - const still = findErrorDialog(); - if (still) { dismissDialog(still); await sleep(200); } + // 策略1: 关闭所有弹窗/遮罩 (暴力清理) + const dialog = findErrorDialog(); + if (dialog) { + log('检测到错误弹窗, 清理中...'); + dismissDialog(dialog); + await sleep(300); + } + // 清理所有可能残留的遮罩层 + document.querySelectorAll('.el-overlay, .v-modal, .el-overlay-dialog, [class*="overlay"], [class*="mask"]').forEach(el => { + el.style.display = 'none'; + }); + document.querySelectorAll('.el-dialog__wrapper, .el-message-box__wrapper').forEach(el => { + el.style.display = 'none'; + }); + // 移除 body 上的 overflow:hidden (弹窗锁定滚动) + document.body.style.overflow = ''; + document.body.classList.remove('el-popup-parent--hidden'); + await sleep(200); + // 策略2: 缓存响应 + 重新点购买按钮 + setState({ cache: state.lastSuccess }); const btn = findBuyButton(); - if (btn) { btn.click(); log('已重新点击购买按钮'); } - else { log('未找到购买按钮'); alert('已获取到商品! 请手动点击购买!'); } + if (btn) { + btn.click(); + log('已重新点击购买按钮 (策略2)'); + await sleep(2000); + } + + // 策略3: 检查支付弹窗是否出现, 没有则直接用 bizId 构造支付 + const payDialog = document.querySelector('[class*="pay"], [class*="qrcode"], [class*="wechat"], [class*="alipay"]'); + if (!payDialog || payDialog.offsetParent === null) { + const bizId = state.bizId; + if (bizId) { + log('支付弹窗未出现, 尝试直接调用 check 页面...'); + // 尝试直接打开支付 — 有些网站 check 接口会返回支付链接 + try { + const checkUrl = `${location.origin}${CFG.CHECK}?bizId=${encodeURIComponent(bizId)}`; + const resp = await _fetch(checkUrl, { credentials: 'include' }); + const data = await resp.json(); + log('check响应: ' + JSON.stringify(data).substring(0, 200)); + + // 如果有支付URL, 直接跳转 + if (data.data && typeof data.data === 'string' && data.data.startsWith('http')) { + log('获取到支付链接, 跳转中...'); + window.open(data.data, '_blank'); + } else if (data.data && data.data.payUrl) { + log('获取到payUrl, 跳转中...'); + window.open(data.data.payUrl, '_blank'); + } else if (data.data && data.data.qrCode) { + log('获取到二维码数据'); + showQRCodeFallback(data.data.qrCode, bizId); + } + } catch (e) { + log('check调用失败: ' + e.message); + } + } + + // 策略4: 最终兜底 — 弹窗提醒手动操作 + if (!document.querySelector('[class*="pay"], [class*="qrcode"]')) { + log('所有自动恢复策略已尝试, 请手动操作'); + const bizId = state.bizId; + alert(`已抢到 bizId=${bizId}\n\n请尝试:\n1. 刷新页面后立即点击购买\n2. 或手动访问支付页面`); + } + } else { + log('支付弹窗已出现!'); + } } finally { recovering = false; } } + /** 兜底: 直接在页面上显示二维码 */ + function showQRCodeFallback(qrData, bizId) { + const div = document.createElement('div'); + div.style.cssText = 'position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);z-index:999999;background:#fff;padding:30px;border-radius:12px;box-shadow:0 8px 32px rgba(0,0,0,.3);text-align:center'; + div.innerHTML = ` +

扫码支付

+ +

bizId: ${bizId}

+ + `; + document.body.appendChild(div); + log('已显示兜底支付二维码'); + } + // MutationObserver 监控弹窗 (替代 setInterval) function setupDialogWatcher() { const observer = new MutationObserver(() => {