glm_bypass

极致抢购助手 - 并发重试+验证码自动识别+直接锁单+时钟校准+反检测+Vue Hacking+多标签协同+登录兼容

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

Advertisement:

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

Advertisement:

// ==UserScript==
// @name         glm_bypass
// @namespace    https://github.com/langbyyi/GLM_bypass
// @version      1.0.0
// @description  极致抢购助手 - 并发重试+验证码自动识别+直接锁单+时钟校准+反检测+Vue Hacking+多标签协同+登录兼容
// @author       glm_bypass
// @match        *://open.bigmodel.cn/*
// @match        *://www.bigmodel.cn/*
// @match        *://bigmodel.cn/*
// @match        *://*.gtimg.com/*
// @match        *://*.captcha.qcloud.com/*
// @match        *://*.captcha.qq.com/*
// @match        *://*.qq.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_notification
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM_registerMenuCommand
// @grant        GM_openInTab
// @connect      127.0.0.1
// @connect      localhost
// @connect      127.0.0.1:8888
// @connect      localhost:8888
// @connect      gtimg.com
// @connect      *.gtimg.com
// @connect      captcha.qcloud.com
// @connect      *.captcha.qcloud.com
// @connect      captcha.qq.com
// @connect      *.captcha.qq.com
// @connect      turing.captcha.qcloud.com
// @connect      *
// @run-at       document-start
// ==/UserScript==

(function () {
  'use strict';

  // ═══════════════════════════════════════════════════════════════════
  //  1. 环境检测 (Iframe 模式 还是 主窗口 模式)
  // ═══════════════════════════════════════════════════════════════════
  const _host = (() => { try { return location.hostname || ''; } catch { return ''; } })();
  const inCaptchaFrame = _host.includes('gtimg.com') || _host.includes('captcha.qcloud.com') || _host.includes('captcha.qq.com') || _host.includes('tcaptcha.qq.com');

  if (inCaptchaFrame) {
    initCaptchaSolver();
    return;
  }

  // 既不是验证码 iframe,又不是大模型网站,则彻底退出,防污染其他 matched 域(如 qq.com)
  if (!_host.includes('bigmodel.cn')) {
    return;
  }

  // 接收来自验证码 iframe 的跨域日志
  window.addEventListener('message', (e) => {
    if (e.data && e.data.type === 'GLM_BYPASS_CAPTCHA_LOG') {
      log(e.data.msg);
    }
  });

  // ═══════════════════════════════════════════════════════════════════
  //  2. 验证码自动识别与模拟点击 (iframe 内部执行)
  // ═══════════════════════════════════════════════════════════════════
  function initCaptchaSolver() {
    const sleep = (ms) => new Promise(r => setTimeout(r, ms));
    const log = (msg) => {
      console.log('%c[CaptchaSolver] ' + msg, 'color:#fdcb6e');
      try {
        window.top.postMessage({
          type: 'GLM_BYPASS_CAPTCHA_LOG',
          msg: `[验证码] ${msg}`
        }, '*');
      } catch (e) {}
    };

    log('验证码 iframe 注入成功,开始监控...');

    function getOcrUrl() {
      try { return GM_getValue('glm_bypass_captcha_server', 'http://127.0.0.1:8888'); } 
      catch (e) { return 'http://127.0.0.1:8888'; }
    }

    function visible(el) {
      if (!el) return false;
      const s = getComputedStyle(el);
      if (s.display === 'none' || s.visibility === 'hidden') return false;
      const rect = el.getBoundingClientRect();
      return rect.width > 0 && rect.height > 0;
    }

    function bgUrlFrom(el) {
      if (!el) return '';
      const img = el.tagName === 'IMG' ? el : el.querySelector('img');
      if (img && img.src) {
        return img.src;
      }
      const text = (el.style && el.style.backgroundImage ? el.style.backgroundImage : '') || getComputedStyle(el).backgroundImage || '';
      const match = text.match(/url\(["']?([^"')]+)["']?\)/);
      if (!match) return '';
      try { return new URL(match[1], location.href).href; } 
      catch { return match[1]; }
    }

    function findBgElement() {
      const selectors = [
        '#slideBg',
        '.tencent-captcha-dy__verify-bg-img',
        '[class*="verify-bg"]',
        '.tencent-captcha-dy__bg-img',
        '.tencent-captcha-dy__image-area',
      ];
      for (const selector of selectors) {
        const el = document.querySelector(selector);
        if (visible(el) && bgUrlFrom(el)) return el;
      }
      return null;
    }

    function findPromptText() {
      const selectors = [
        '#instructionText',
        '.tencent-captcha-dy__header-text',
        '.tencent-captcha-dy__header-title-wrap .tencent-captcha-dy__header-text',
        '[class*="header-text"]',
      ];
      for (const selector of selectors) {
        const el = document.querySelector(selector);
        if (!visible(el)) continue;
        const raw = (el.textContent || el.getAttribute('aria-label') || '').trim();
        const cleaned = raw
          .replace(/^\s*\u8BF7\u4F9D\u6B21\u70B9\u51FB[:\uff1a]?\s*/, '') 
          .replace(/\s+/g, '');
        const chars = (cleaned.match(/[\u4e00-\u9fff]/g) || []).slice(-3); 
        if (chars.length >= 3) return chars.join('');
      }
      return '';
    }

    function fetchImageDataUrl(url) {
      return new Promise((resolve, reject) => {
        if (typeof GM_xmlhttpRequest !== 'undefined') {
          GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            responseType: 'blob',
            onload: (res) => {
              const reader = new FileReader();
              reader.onload = () => resolve(reader.result);
              reader.onerror = () => reject(new Error('FileReader 失败'));
              reader.readAsDataURL(res.response);
            },
            onerror: () => reject(new Error('验证码图片下载失败')),
          });
        } else {
          fetch(url)
            .then(r => r.blob())
            .then(blob => {
              const reader = new FileReader();
              reader.onload = () => resolve(reader.result);
              reader.readAsDataURL(blob);
            })
            .catch(reject);
        }
      });
    }

    function callOcrServer(dataUrl, chars) {
      const server = getOcrUrl().replace(/\/$/, '');
      const url = `${server}/captcha_direct`; 
      
      const payload = JSON.stringify({
        image: dataUrl,
        text: chars,
        remark: chars, 
        ts: Date.now()
      });

      return new Promise((resolve, reject) => {
        if (typeof GM_xmlhttpRequest !== 'undefined') {
          GM_xmlhttpRequest({
            method: 'POST',
            url: url,
            headers: { 'Content-Type': 'application/json' },
            data: payload,
            onload: (res) => {
              try {
                const data = JSON.parse(res.responseText);
                resolve(data);
              } catch (e) {
                log('captcha_direct 接口解析失败,降级尝试 /click...');
                callClickOcrFallback(dataUrl, chars).then(resolve).catch(reject);
              }
            },
            onerror: () => {
              log('captcha_direct 连接失败,降级尝试 /click...');
              callClickOcrFallback(dataUrl, chars).then(resolve).catch(reject);
            }
          });
        } else {
          fetch(url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: payload
          })
            .then(r => r.json())
            .then(resolve)
            .catch(err => {
              log('fetch captcha_direct 失败,降级尝试 /click...');
              callClickOcrFallback(dataUrl, chars).then(resolve).catch(reject);
            });
        }
      });
    }

    function callClickOcrFallback(dataUrl, chars) {
      const server = getOcrUrl().replace(/\/$/, '');
      const url = `${server}/click`;
      return new Promise((resolve, reject) => {
        const body = JSON.stringify({ image: dataUrl, remark: chars });
        if (typeof GM_xmlhttpRequest !== 'undefined') {
          GM_xmlhttpRequest({
            method: 'POST',
            url: url,
            headers: { 'Content-Type': 'application/json' },
            data: body,
            onload: (r) => {
              try { resolve(JSON.parse(r.responseText)); } 
              catch (e) { reject(new Error('Fallback 响应解析失败')); }
            },
            onerror: () => reject(new Error('ddddocr fallback 连接失败'))
          });
        } else {
          fetch(url, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: body
          })
            .then(r => r.json())
            .then(resolve)
            .catch(reject);
        }
      });
    }

    function dispatchClick(el, nx, ny, label) {
      const rect = el.getBoundingClientRect();
      const win = el.ownerDocument.defaultView || window;
      const clientX = rect.left + nx * rect.width;
      const clientY = rect.top + ny * rect.height;
      const base = { bubbles: true, cancelable: true, view: win, clientX, clientY, button: 0, buttons: 1 };
      const pointer = { ...base, pointerId: 1, pointerType: 'mouse', isPrimary: true, pressure: 0.5 };
      try { if (win.PointerEvent) el.dispatchEvent(new win.PointerEvent('pointerdown', pointer)); } catch {}
      el.dispatchEvent(new win.MouseEvent('mousedown', base));
      try { if (win.PointerEvent) el.dispatchEvent(new win.PointerEvent('pointerup', pointer)); } catch {}
      el.dispatchEvent(new win.MouseEvent('mouseup', base));
      el.dispatchEvent(new win.MouseEvent('click', base));
      log(`模拟点击 "${label}" @ 归一化: (${nx.toFixed(3)}, ${ny.toFixed(3)})`);
    }

    function hasError() {
      const note = document.querySelector('#tcaptcha_note, .tencent-captcha-dy__verify-error-text');
      return visible(note);
    }

    function clickConfirm() {
      const selectors = [
        '.verify-btn',
        '.tencent-captcha-dy__verify-confirm-btn',
        '.tencent-captcha-dy__btn-confirm',
        '.tencent-captcha-dy__footer .btn',
      ];
      for (const selector of selectors) {
        const btn = document.querySelector(selector);
        if (visible(btn)) {
          btn.click();
          log('已自动点击“确定”按钮');
          return true;
        }
      }
      return false;
    }

    let lastBgUrl = '';
    let solving = false;

    async function solveOnce() {
      const bgEl = findBgElement();
      if (!bgEl) return;
      const bgUrl = bgUrlFrom(bgEl);
      if (!bgUrl || bgUrl === lastBgUrl) return;

      const chars = findPromptText();
      if (chars.length < 3) return;

      if (hasError()) {
        log('检测到验证码错误,执行刷新...');
        const reload = document.querySelector('#reload, .tencent-captcha-dy__footer-icon--refresh img');
        if (reload) reload.click();
        lastBgUrl = '';
        await sleep(1000);
        return;
      }

      lastBgUrl = bgUrl;
      log(`捕获到图片: ${bgUrl.substring(0, 80)}... 提示文字: ${chars}`);

      try {
        const dataUrl = await fetchImageDataUrl(bgUrl);
        const response = await callOcrServer(dataUrl, chars);
        
        let coords = [];
        if (response.success && response.result && Array.isArray(response.result.click_coords)) {
          coords = response.result.click_coords;
        } else if (response.success && response.data && response.data.result) {
          const raw = response.data.result.split('|');
          coords = raw.map((p, idx) => {
            const xy = p.split(',');
            return {
              char: chars[idx] || '',
              nx: parseFloat(xy[0]) / 344.0,
              ny: parseFloat(xy[1]) / 344.0
            };
          });
        }

        if (!coords || coords.length === 0) {
          log('未识别出坐标数据');
          lastBgUrl = '';
          return;
        }

        for (const pt of coords) {
          const nx = Number(pt.nx);
          const ny = Number(pt.ny);
          if (!Number.isFinite(nx) || !Number.isFinite(ny)) continue;
          dispatchClick(bgEl, nx, ny, pt.char || '');
          await sleep(200); 
        }

        await sleep(300);
        const autoConfirm = GM_getValue('glm_bypass_auto_captcha_confirm', true);
        if (autoConfirm) {
          clickConfirm();
        }
      } catch (e) {
        log(`识别失败: ${e.message}`);
        lastBgUrl = '';
      }
    }

    async function tick() {
      if (solving) return;
      solving = true;
      try { await solveOnce(); } 
      catch (e) { log(`监控异常: ${e.message}`); lastBgUrl = ''; } 
      finally { solving = false; }
    }

    const observer = new MutationObserver(() => setTimeout(tick, 100));
    observer.observe(document.body || document.documentElement, {
      childList: true,
      subtree: true,
      attributes: true,
      attributeFilter: ['style', 'class']
    });

    setInterval(tick, 1000);
    setTimeout(tick, 500);
  }

  // ═══════════════════════════════════════════════════════════════════
  //  3. 主窗口模块(bigmodel.cn 抢购引擎)— 总入口
  //     3A. 配置与全局状态 (L402-)
  //     3B. 多标签页同步 (L484-)
  //     3C. JSON.parse 拦截 & 强制售罄重置 (L520-)
  //     3D. 工具函数 & fetch/XHR API 劫持 (L546-)
  //     3E. Vue Hacking & 支付恢复 (L1107-)
  //     3F. 时钟校准 & 产品ID预拉取 (L1380-)
  //     3G. 抢购调度 (L1469-)
  //     3H. OCR 服务健康检查 (L1670-)
  //     3I. Shadow DOM 控制面板 (L1722-)
  //     3J. UI 刷新 & 日志渲染 (L2166-)
  //     3K. 支付检测 & 验证码状态机 (L2227-)
  // ═══════════════════════════════════════════════════════════════════
  if (document.documentElement.dataset.glmBypass === '1') return;
  document.documentElement.dataset.glmBypass = '1';

  // ── 邀请码自动修正 ──
  const INVITE_CODE = 'FGSQNRBAAE';
  try {
    const url = new URL(location.href);
    const currentIc = url.searchParams.get('ic');
    if (currentIc !== INVITE_CODE) {
      url.searchParams.set('ic', INVITE_CODE);
      history.replaceState(null, '', url.toString());
      console.log(`[glm_bypass] 邀请码已修正: ${currentIc || '(空)'} → ${INVITE_CODE}`);
    }
  } catch (e) {}

  // ── 3A. 配置与全局状态 ──────────────────────────────────────────────
  // ── 默认配置项 ──
  const CFG = {
    planPriority: [
      { plan: 'pro', billingPeriod: 'quarterly' },
      { plan: 'lite', billingPeriod: 'quarterly' },
    ],
    targetHour: 10,
    targetMinute: 0,
    advanceMs: 200,
    autoCloseInvalid: true,
    previewTimeout: 10000, // preview单请求超时(毫秒),高峰期可能需要8-10s
    checkTimeout: 5000,    // check校验超时,高峰期放宽
    captchaServer: 'http://127.0.0.1:8888',
    autoCaptchaConfirm: true,
    preSolveMs: 2500, // 提前多少毫秒触发验证码预求解(OCR+验证在10:00前完成,preview刚好落在T+0)
    retryIntervalMs: 800,     // 均匀重试:单次请求间隔(ms),约1.25 req/s
    retryTicketTTL: 170000,   // ticket有效期(ms),3分钟-10s安全余量
    retryTimeout: 5000,       // 并行重试引擎:单请求超时(ms),正常preview响应<500ms,5秒足够
  };

  try {
    const saved = localStorage.getItem('glm_bypass_cfg');
    if (saved) Object.assign(CFG, JSON.parse(saved));
  } catch (e) {}

  GM_setValue('glm_bypass_captcha_server', CFG.captchaServer);
  GM_setValue('glm_bypass_auto_captcha_confirm', CFG.autoCaptchaConfirm);

  // 状态机
  let state = {
    status: 'idle', 
    count: 0,
    bizId: null,
    captured: null, 
    cache: null,    
    lastSuccess: null,
    proactive: false,
    timerId: null,
    logs: [],
  };

  try {
    const saved = sessionStorage.getItem('glm_bypass_captured_req');
    if (saved) state.captured = JSON.parse(saved);
  } catch (e) {}

  let _capturedProductId = null;
  let _capturedAuthHeader = null;
  try {
    _capturedAuthHeader = sessionStorage.getItem('glm_bypass_captured_auth');
  } catch (e) {}
  let _allProductIds = {}; 
  try {
    const savedPid = localStorage.getItem('glm_bypass_cached_pids');
    if (savedPid) _allProductIds = JSON.parse(savedPid);
  } catch (e) {}

  let _rushActive = false; // 抢购进行中标记
  let _rushStopped = false; // 用户点击停止后标记,刷新页面才重置
  let recovering = false;
  let recoveryAttempts = 0;
  let _shadowRef = null;
  let _serverTimeOffset = 0;
  let _confirmedSoldOut = false;
  let _currentPlanIdx = 0;

  // 💡 优化项 1: 多阶段时间同步
  function serverNow() { return new Date(Date.now() + _serverTimeOffset); }
  function getTargetTime() {
    const now = serverNow();
    const t = new Date(now);
    t.setHours(CFG.targetHour, CFG.targetMinute, 0, 0);
    if (now >= t) t.setDate(t.getDate() + 1); 
    return t;
  }
  function isNearTarget() {
    const diff = getTargetTime() - serverNow();
    // 抢购前 10 分钟到后 30 分钟为抢购敏感时段,才开启底层 API 修改
    return diff <= 600000 && diff >= -1800000;
  }

  // ── 3B. 多标签页同步 (BroadcastChannel) ────────────────────────────

  const channel = new BroadcastChannel('glm_bypass_channel');
  let isMasterTab = false;
  let tabId = Math.random().toString(36).substring(2, 8);
  let masterTabId = null;

  function sendHeartbeat() {
    channel.postMessage({ type: 'HEARTBEAT', tabId, status: state.status });
  }
  setInterval(sendHeartbeat, 1500);

  channel.onmessage = (e) => {
    const msg = e.data;
    if (msg.type === 'HEARTBEAT') {
      if (!masterTabId || msg.tabId < masterTabId || msg.tabId === tabId) {
        masterTabId = msg.tabId;
        isMasterTab = (masterTabId === tabId);
        updateMasterStatusDisplay();
      }
    } else if (msg.type === 'GLM_BYPASS_SUCCESS') {
      log(`[多端协同] 接收到 Tab [${msg.tabId}] 的成功通知,自动中止当前抢购...`);
      setState({
        status: 'success',
        bizId: msg.bizId,
        lastSuccess: msg.lastSuccess
      });
      stopAll();
    }
  };

  function updateMasterStatusDisplay() {}

  const curPlan = () => CFG.planPriority[_currentPlanIdx]?.plan || 'pro';
  const curPeriod = () => CFG.planPriority[_currentPlanIdx]?.billingPeriod || 'quarterly';

  // ── 3C. JSON.parse 拦截 & 强制售罄重置 ────────────────────────────
  const _parse = JSON.parse;

  function patchSoldOut(obj, visited = new WeakSet()) {
    if (!obj || typeof obj !== 'object' || visited.has(obj)) return;
    visited.add(obj);
    if (obj.isSoldOut === true) obj.isSoldOut = false;
    if (obj.soldOut === true) obj.soldOut = false;
    if (obj.isServerBusy === true) obj.isServerBusy = false;
    if (obj.disabled === true && (obj.price !== undefined || obj.productId || obj.title)) obj.disabled = false;
    if (obj.stock === 0) obj.stock = 999;
    for (const k of Object.keys(obj)) {
      if (k === '__proto__' || k === 'constructor' || k === 'prototype') continue;
      if (obj[k] && typeof obj[k] === 'object') patchSoldOut(obj[k], visited);
    }
  }

  JSON.parse = function (text, reviver) {
    const result = _parse(text, reviver);
    try {
      patchSoldOut(result);
    } catch (e) {}
    return result;
  };
  Object.defineProperty(JSON.parse, 'toString', { value: () => 'function parse() { [native code] }' });

  // ── 3D. 工具函数 & fetch/XHR API 劫持 ─────────────────────────────

  const sleep = (ms) => new Promise(r => setTimeout(r, ms));
  const ts = () => new Date().toLocaleTimeString('zh-CN', { hour12: false });

  // 带超时的fetch,超时自动abort并返回{ok:false, reason:'超时'}
  async function fetchWithTimeout(url, opts, timeoutMs) {
    const ac = new AbortController();
    const tid = setTimeout(() => ac.abort(), timeoutMs);
    try {
      const resp = await _fetch(url, { ...opts, signal: ac.signal });
      clearTimeout(tid);
      return { ok: true, resp };
    } catch (e) {
      clearTimeout(tid);
      if (e.name === 'AbortError') return { ok: false, reason: '超时' };
      return { ok: false, reason: e.message };
    }
  }

  function visible(el) {
    if (!el) return false;
    const s = window.getComputedStyle(el);
    if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') return false;
    return el.offsetWidth > 0 || el.offsetHeight > 0;
  }

  function setState(patch) {
    if (!patch || typeof patch !== 'object') return;
    Object.assign(state, patch);
    // 持久化关键状态
    if ('captured' in patch && patch.captured) {
      try { sessionStorage.setItem('glm_bypass_captured_req', JSON.stringify(patch.captured)); } catch {}
    }
    refreshUI();
  }

  function log(msg, level = 'info') {
    const entry = { ts: ts(), msg, level };
    state.logs.push(entry);
    const now = new Date();
    const hh = String(now.getHours()).padStart(2, '0');
    const mm = String(now.getMinutes()).padStart(2, '0');
    const ss = String(now.getSeconds()).padStart(2, '0');
    console.log(`${hh}:${mm}:${ss} [glm_bypass] ${msg}`);
    appendLogDOM(entry);
    refreshUI();
  }

  function extractHeaders(h) {
    const o = {};
    if (!h) return o;
    if (h instanceof Headers) h.forEach((v, k) => (o[k] = v));
    else if (Array.isArray(h)) h.forEach(([k, v]) => (o[k] = v));
    else Object.entries(h).forEach(([k, v]) => (o[k] = v));
    return o;
  }

  const _fetch = window.fetch;
  const _xhrOpen = XMLHttpRequest.prototype.open;
  const _xhrSend = XMLHttpRequest.prototype.send;
  const _xhrSetHeader = XMLHttpRequest.prototype.setRequestHeader;

  window.fetch = async function (input, init) {
    const url = typeof input === 'string' ? input : input?.url || '';

    // 自动捕获 fetch 中的 Authorization 头
    if (init && init.headers) {
      try {
        const h = new Headers(init.headers);
        const auth = h.get('Authorization') || h.get('authorization');
        if (auth && auth !== _capturedAuthHeader) {
          _capturedAuthHeader = auth;
          sessionStorage.setItem('glm_bypass_captured_auth', auth);
          setTimeout(autoFetchProductIds, 100);
        }
      } catch (e) {}
    }
    if (typeof input === 'object' && input.headers && typeof input.headers.get === 'function') {
      try {
        const auth = input.headers.get('Authorization') || input.headers.get('authorization');
        if (auth && auth !== _capturedAuthHeader) {
          _capturedAuthHeader = auth;
          sessionStorage.setItem('glm_bypass_captured_auth', auth);
          setTimeout(autoFetchProductIds, 100);
        }
      } catch (e) {}
    }
    
    // 💡 优化:拦截并静默阻断神策等埋点统计脚本(Sensorsdata),防检测并节省抢单带宽与CPU资源
    const isTelemetry = url.includes('sensorsdata') || url.includes('/sa.gif') || url.includes('analytics');
    if (isTelemetry) {
      return new Response('{"code":200,"msg":"Blocked by glm_bypass"}', { status: 200, headers: { 'Content-Type': 'application/json' } });
    }

    // 💡 优化:放行并忽略所有微信登录、账户信息、短信和登录相关的请求,彻底解决登录失败问题
    const isAuthRoute = url.includes('/login') || url.includes('/user/info') || url.includes('/user/login') || url.includes('/wechat') || url.includes('/auth') || url.includes('/sms') || url.includes('/phone') || url.includes('/oauth') || url.includes('/geetest') || url.includes('/turing');
    if (isAuthRoute) {
      return _fetch.apply(window, arguments);
    }

    if (isNearTarget() && init) {
      const headers = new Headers(init.headers || {});
      headers.set('X-Request-Id', Math.random().toString(36).slice(2, 15));
      headers.set('X-Timestamp', String(Date.now()));
      const q = (0.5 + Math.random() * 0.5).toFixed(1);
      headers.set('Accept-Language', `zh-CN,zh;q=${q},en;q=${(q * 0.7).toFixed(1)}`);
      init.headers = headers;
    }

    if (url.includes('/api/biz/pay/preview') && !url.includes('batch-preview')) {
      const method = init?.method || 'POST';
      let bodyText = init?.body || '';
      if (typeof bodyText !== 'string' && init?.body) {
        try { bodyText = await init.body.clone().text(); } catch (e) {}
      }

      const captured = {
        url,
        method,
        body: bodyText,
        headers: extractHeaders(init?.headers)
      };

      try {
        const bodyObj = JSON.parse(bodyText);
        if (bodyObj.productId) {
          const planKey = `${curPlan()}_${curPeriod()}`;
          _allProductIds[planKey] = bodyObj.productId;
          localStorage.setItem('glm_bypass_cached_pids', JSON.stringify(_allProductIds));
          _capturedProductId = bodyObj.productId;
          log(`成功捕获并保存 productId=${_capturedProductId}`);
        }
      } catch (e) {}

      setState({ captured });
      try { sessionStorage.setItem('glm_bypass_captured_req', JSON.stringify(captured)); } catch (e) {}

      // 并行重试引擎:将新ticket加入池
      if (_retryEngineActive && captured.body && !captured.body.includes('trerror')) {
        retryEngineAddTicket(captured);
      }

      if (state.status === 'success' && state.lastSuccess) {
        log('已抢购成功,拦截并返回成功响应');
        return new Response(state.lastSuccess.text, { status: 200, headers: { 'Content-Type': 'application/json' } });
      }

      if (state.cache) {
        log('返回重点击缓存响应');
        const c = state.cache;
        setState({ cache: null });
        recoveryAttempts = 0;
        return new Response(c.text, { status: 200, headers: { 'Content-Type': 'application/json' } });
      }

      log('已捕获 preview 请求数据,等待抢购开始...');
      // ── 拦截preview响应码,非成功立即重试(带超时) ──
      const fResult = await fetchWithTimeout(url, init || {}, CFG.previewTimeout);
      if (!fResult.ok) {
        _lastPreviewResult = 'timeout';
        log(`[Preview-fetch] 请求${fResult.reason},立即重试`, 'warn');
        triggerPreviewRetry(fResult.reason);
        return new Response('{"code":555,"msg":"系统繁忙","data":null,"success":false}', { status: 200, headers: { 'Content-Type': 'application/json' } });
      }
      const resp = fResult.resp;
      try {
        const cloned = resp.clone();
        const text = await cloned.text();
        // 非JSON响应(如WAF 405页面)→ 立即停止,提示用户
        if (text.trimStart().startsWith('<!') || text.trimStart().startsWith('<html')) {
          _lastPreviewResult = 'html';
          _wafBlocked = true;
          log('⛔ IP被WAF拦截(405),更换IP后刷新页面重试!', 'warn');
          retryEngineStop('WAF拦截');
          return new Response('{"code":555,"msg":"系统繁忙","data":null,"success":false}', { status: 200, headers: { 'Content-Type': 'application/json' } });
        }
        const respObj = _parse(text);
        const code = respObj?.code;
        const data = respObj?.data;
        const soldOut = data?.soldOut || data?.isSoldOut;

        if (code === 200 && data?.bizId) {
          _lastPreviewResult = 'ok';
        } else if (code === 555) {
          _lastPreviewResult = '555';
          log('[Preview-fetch] 555系统繁忙,拦截响应,立即重试', 'warn');
          triggerPreviewRetry('555系统繁忙');
          return new Response('{"code":555,"msg":"系统繁忙","data":null,"success":false}', { status: 200, headers: { 'Content-Type': 'application/json' } });
        } else if (soldOut || (code === 200 && !data?.bizId)) {
          _lastPreviewResult = 'soldOut';
          log('[Preview-fetch] 响应售罄/无bizId,拦截响应,立即重试', 'warn');
          triggerPreviewRetry('售罄');
          return new Response('{"code":555,"msg":"系统繁忙","data":null,"success":false}', { status: 200, headers: { 'Content-Type': 'application/json' } });
        } else if (code === 500 || code === 405) {
          _lastPreviewResult = 'error';
          log(`[Preview-fetch] code=${code},拦截响应,立即重试`, 'warn');
          triggerPreviewRetry(`code=${code}`);
          return new Response('{"code":555,"msg":"系统繁忙","data":null,"success":false}', { status: 200, headers: { 'Content-Type': 'application/json' } });
        }
      } catch (e) {}
      return resp;
    }

    if (url.includes('/api/biz/pay/check') && url.includes('bizId=null')) {
      return new Response('{"code":-1,"msg":"等待有效bizId"}', {
        status: 200, headers: { 'Content-Type': 'application/json' }
      });
    }

    if (url.includes('batch-preview')) {
      let res;
      try {
        res = await _fetch.apply(window, arguments);
      } catch (e) {
        res = null;
      }

      let needFallback = false;
      let data = null;
      if (!res || res.status !== 200) {
        needFallback = true;
      } else {
        try {
          const text = await res.clone().text();
          data = _parse(text);
          if (!data || data.code !== 200) {
            needFallback = true;
          }
        } catch (e) {
          needFallback = true;
        }
      }

      if (needFallback) {
        log('[容灾兜底] 检测到 batch-preview 接口返回繁忙或错误,正在启用本地及接口降级防线...');
        let cachedPids = {};
        try {
          const saved = localStorage.getItem('glm_bypass_cached_pids');
          if (saved) cachedPids = JSON.parse(saved);
        } catch (e) {}

        if (!cachedPids || Object.keys(cachedPids).length === 0) {
          log('[容灾兜底] 本地无缓存,尝试调用 productinfo API 实时拉取...');
          try {
            const auth = _capturedAuthHeader || sessionStorage.getItem('glm_bypass_captured_auth');
            const headers = { 'accept': 'application/json, text/plain, */*' };
            if (auth) headers['Authorization'] = auth;
            const resp = await _fetch(location.origin + '/api/biz/pay/productinfo', {
              method: 'GET',
              credentials: 'include',
              headers: headers
            });
            if (resp.ok) {
              const data2 = await resp.json();
              const pidMap = data2?.data || data2 || {};
              const pidPattern = /^product-[a-z0-9]+$/i;
              for (const [k, pid] of Object.entries(pidMap)) {
                if (typeof pid === 'string' && pidPattern.test(pid)) {
                  const kl = k.toLowerCase();
                  let plan = kl.includes('pro') ? 'pro' : kl.includes('lite') ? 'lite' : kl.includes('max') ? 'max' : null;
                  let period = kl.includes('quarter') ? 'quarterly' : kl.includes('year') ? 'yearly' : 'monthly';
                  if (plan) {
                    cachedPids[`${plan}_${period}`] = pid;
                  }
                }
              }
              localStorage.setItem('glm_bypass_cached_pids', JSON.stringify(cachedPids));
            }
          } catch (e) {
            log(`[容灾兜底] 调用 productinfo 接口失败: ${e.message}`, 'error');
          }
        }

        if (cachedPids && Object.keys(cachedPids).length > 0) {
          log('[容灾兜底] 成功重构成功响应,绕过 555 错误!');
          const mockProductList = [];
          for (const [key, pid] of Object.entries(cachedPids)) {
            const [plan, period] = key.split('_');
            const monthlyOriginalAmount = plan === 'pro' ? 149 : plan === 'lite' ? 49 : 469;
            const campaignName = period === 'quarterly' ? '包季折后特惠' : period === 'yearly' ? '包年折后特惠' : '无';
            mockProductList.push({
              productId: pid,
              monthlyOriginalAmount: monthlyOriginalAmount,
              campaignDiscountDetails: period !== 'monthly' ? [{ campaignName }] : [],
              isSoldOut: false,
              soldOut: false,
              stock: 999,
              disabled: false
            });
          }

          const mockResponseData = {
            code: 200,
            msg: 'success',
            data: {
              productList: mockProductList
            }
          };

          return new Response(JSON.stringify(mockResponseData), {
            status: 200,
            headers: { 'Content-Type': 'application/json;charset=UTF-8' }
          });
        }
      }

      if (res && res.status === 200 && data) {
        try {
          if (data.data?.productList && Array.isArray(data.data.productList)) {
            data.data.productList.forEach(item => {
              if (item && item.productId) {
                const plan = identifyPlanName(item.monthlyOriginalAmount);
                const period = identifyPeriodName(item);
                if (plan && period) {
                  _allProductIds[`${plan}_${period}`] = item.productId;
                }
              }
            });
            localStorage.setItem('glm_bypass_cached_pids', JSON.stringify(_allProductIds));
          }
        } catch (e) {}
      }

      return res;
    }

    let res = await _fetch.apply(window, arguments);
    const contentType = res.headers.get('content-type') || '';
    if (contentType.includes('json') && (url.includes('/api/') || url.includes('bigmodel'))) {
      try {
        const text = await res.clone().text();
        const parsed = _parse(text);
        
        if (parsed?.data?.productList && Array.isArray(parsed.data.productList)) {
          parsed.data.productList.forEach(item => {
            if (item && item.productId) {
              const plan = identifyPlanName(item.monthlyOriginalAmount);
              const period = identifyPeriodName(item);
              if (plan && period) {
                _allProductIds[`${plan}_${period}`] = item.productId;
              }
            }
          });
          localStorage.setItem('glm_bypass_cached_pids', JSON.stringify(_allProductIds));
        }

        if (isNearTarget()) {
          const modified = text
            .replace(/"isSoldOut"\s*:\s*true/g, '"isSoldOut":false')
            .replace(/"soldOut"\s*:\s*true/g, '"soldOut":false')
            .replace(/"stock"\s*:\s*0/g, '"stock":999')
            .replace(/"disabled"\s*:\s*true/g, '"disabled":false');
          if (modified !== text) {
            return new Response(modified, { status: res.status, statusText: res.statusText, headers: res.headers });
          }
        }
      } catch (e) {}
    }

    return res;
  };
  window.fetch.toString = () => 'function fetch() { [native code] }';

  XMLHttpRequest.prototype.setRequestHeader = function (k, v) {
    (this._h || (this._h = {}))[k] = v;
    if (/^authorization$/i.test(k) && v && v !== _capturedAuthHeader) {
      _capturedAuthHeader = v;
      sessionStorage.setItem('glm_bypass_captured_auth', v);
      setTimeout(autoFetchProductIds, 100);
    }
    return _xhrSetHeader.call(this, k, v);
  };
  XMLHttpRequest.prototype.open = function (method, url) {
    this._m = method; this._u = url;
    return _xhrOpen.apply(this, arguments);
  };
  XMLHttpRequest.prototype.send = function (body) {
    const url = this._u || '';
    const isTelemetry = url.includes('sensorsdata') || url.includes('/sa.gif') || url.includes('analytics');
    if (isTelemetry) {
      fakeXHR(this, '{"code":200,"msg":"Blocked by glm_bypass"}');
      return;
    }

    const isAuthRoute = url.includes('/login') || url.includes('/user/info') || url.includes('/user/login') || url.includes('/wechat') || url.includes('/auth') || url.includes('/sms') || url.includes('/phone') || url.includes('/oauth') || url.includes('/geetest');
    if (isAuthRoute) {
      return _xhrSend.call(this, body);
    }

    // 拦截验证码验证结果(errorCode: 0=成功, 50=失败)
    if (url.includes('cap_union_new_verify') || url.includes('turing.captcha.qcloud.com')) {
      const self = this;
      let handled = false; // 防止 load + readystatechange 重复处理
      const origHandler = () => {
        if (handled) return;
        handled = true;
        try {
          const respText = self.responseText || self.response || '';
          const respObj = typeof respText === 'string' ? JSON.parse(respText) : respText;
          const errorCode = String(respObj?.errorCode ?? respObj?.error_code ?? '');
          if (errorCode === '0' && respObj?.ticket) {
            log('[验证码回调] ✅ 验证通过 (errorCode=0)');
            _captchaCallbackResult = 'success';
          } else if (errorCode) {
            log(`[验证码回调] ❌ 验证失败 (errorCode=${errorCode})`);
            _captchaCallbackResult = 'error';
          }
          // errorCode 为空则忽略(刷新等操作触发的无关请求)
        } catch (e) {
          // 响应解析失败,忽略
        }
      };
      self.addEventListener('load', origHandler);
      self.addEventListener('readystatechange', () => {
        if (self.readyState === 4) origHandler();
      });
      return _xhrSend.call(this, body);
    }

    if (url.includes('/api/biz/pay/preview') && !url.includes('batch-preview')) {
      const self = this;
      // 超时处理:如果preview响应超时,直接触发重试
      const ac = new AbortController();
      const tid = setTimeout(() => {
        ac.abort();
        log('[Preview-XHR] 请求超时,触发重试', 'warn');
        _lastPreviewResult = 'timeout';
        triggerPreviewRetry('超时');
      }, CFG.previewTimeout);

      // 并行重试引擎:将XHR捕获的ticket加入池
      if (_retryEngineActive && body && !body.includes('trerror')) {
        retryEngineAddTicket({ body, headers: this._h || {} });
      }

      _fetch(url, { method: this._m || 'POST', body: body, headers: this._h || {}, credentials: 'include', signal: ac.signal })
        .then(async r => {
          clearTimeout(tid); // 响应到达,取消超时
          const text = await r.text();
          // 非JSON响应(如WAF 405页面)→ 立即停止,提示用户
          if (text.trimStart().startsWith('<!') || text.trimStart().startsWith('<html')) {
            _lastPreviewResult = 'html';
            _wafBlocked = true;
            log('⛔ IP被WAF拦截(405),更换IP后刷新页面重试!', 'warn');
            retryEngineStop('WAF拦截');
            return;
          }
          // ── API响应码检测 ──
          try {
            const respObj = _parse(text);
            const code = respObj?.code;
            const data = respObj?.data;
            const soldOut = data?.soldOut || data?.isSoldOut;

            if (code === 200 && data?.bizId) {
              // 真正成功:有bizId,让Vue正常渲染支付弹窗
              _lastPreviewResult = 'ok';
              log('[Preview] 响应成功 bizId=' + data.bizId.substring(0, 8) + '...');
            } else if (code === 555) {
              // 系统繁忙:抑制弹窗,立即重试购买
              _lastPreviewResult = '555';
              log('[Preview] 555系统繁忙,拦截弹窗,立即重试', 'warn');
              triggerPreviewRetry('555系统繁忙');
              return; // 不派发事件,Vue不渲染
            } else if (soldOut) {
              // 售罄:抑制弹窗,立即重试购买
              _lastPreviewResult = 'soldOut';
              log('[Preview] 响应售罄,拦截弹窗,立即重试', 'warn');
              triggerPreviewRetry('售罄');
              return;
            } else if (code === 500 || code === 405) {
              // 服务器错误:抑制弹窗,立即重试购买
              _lastPreviewResult = 'error';
              log(`[Preview] code=${code},拦截弹窗,立即重试`, 'warn');
              triggerPreviewRetry(`code=${code}`);
              return;
            } else if (code === 200 && !data?.bizId) {
              // code=200但无bizId = 实质售罄
              _lastPreviewResult = 'soldOut';
              log('[Preview] code=200但无bizId,拦截弹窗,立即重试', 'warn');
              triggerPreviewRetry('无bizId');
              return;
            }
          } catch (e) {}

          const dp = (k, v) => Object.defineProperty(self, k, { value: v, configurable: true });
          let patchedText = text
            .replace(/"isSoldOut"\s*:\s*true/g, '"isSoldOut":false')
            .replace(/"soldOut"\s*:\s*true/g, '"soldOut":false')
            .replace(/"stock"\s*:\s*0/g, '"stock":999')
            .replace(/"disabled"\s*:\s*true/g, '"disabled":false');
          let resVal = patchedText;
          if (self.responseType === 'json') { try { resVal = JSON.parse(patchedText); } catch(e){} }
          dp('readyState', 4); dp('status', r.status); dp('statusText', r.statusText);
          dp('responseText', patchedText); dp('response', resVal);
          self.getAllResponseHeaders = () => 'content-type: application/json\r\n';
          self.getResponseHeader = (n) => n.toLowerCase() === 'content-type' ? 'application/json' : null;
          const ev = new Event('readystatechange');
          if (typeof self.onreadystatechange === 'function') self.onreadystatechange(ev);
          self.dispatchEvent(ev);
          const ld = new ProgressEvent('load');
          if (typeof self.onload === 'function') self.onload(ld);
          self.dispatchEvent(ld);
        }).catch(() => { clearTimeout(tid); }); // 超时abort时清掉timer
      return;
    }
    

    if (url.includes('/api/biz/pay/check') && url.includes('bizId=null')) {
      fakeXHR(this, '{"code":-1,"msg":"等待有效bizId"}');
      return;
    }
    return _xhrSend.call(this, body);
  };

  function fakeXHR(xhr, text) {
    setTimeout(() => {
      const dp = (k, v) => Object.defineProperty(xhr, k, { value: v, configurable: true });
      let patchedText = text
        .replace(/"isSoldOut"\s*:\s*true/g, '"isSoldOut":false')
        .replace(/"soldOut"\s*:\s*true/g, '"soldOut":false')
        .replace(/"stock"\s*:\s*0/g, '"stock":999')
        .replace(/"disabled"\s*:\s*true/g, '"disabled":false');
      let resVal = patchedText;
      if (xhr.responseType === 'json') { try { resVal = JSON.parse(patchedText); } catch(e){} }
      dp('readyState', 4); dp('status', 200); dp('statusText', 'OK');
      dp('responseText', patchedText); dp('response', resVal);
      xhr.getAllResponseHeaders = () => 'content-type: application/json\r\n';
      xhr.getResponseHeader = (n) => n.toLowerCase() === 'content-type' ? 'application/json' : null;
      const ev = new Event('readystatechange');
      if (typeof xhr.onreadystatechange === 'function') xhr.onreadystatechange(ev);
      xhr.dispatchEvent(ev);
    }, 0);
  }

  function identifyPlanName(price) {
    if (price === 49 || (price >= 30 && price <= 80)) return 'lite';
    if (price === 149 || (price >= 100 && price <= 200)) return 'pro';
    if (price === 469 || (price >= 350 && price <= 550)) return 'max';
    return null;
  }
  function identifyPeriodName(item) {
    const campaigns = item?.campaignDiscountDetails || [];
    for (const c of campaigns) {
      const cn = c.campaignName || '';
      if (['包季', '季度', '季卡', '3个月'].some(kw => cn.includes(kw))) return 'quarterly';
      if (['包年', '年度', '年卡', '12个月'].some(kw => cn.includes(kw))) return 'yearly';
    }
    return 'monthly';
  }

  function getProductIdForCurrent() {
    const planKey = `${curPlan()}_${curPeriod()}`;
    if (_allProductIds[planKey]) return _allProductIds[planKey];
    for (const [key, val] of Object.entries(_allProductIds)) {
      if (key.startsWith(curPlan() + '_')) return val;
    }
    return _capturedProductId;
  }

  // ── 3E. Vue Hacking (Object.defineProperty 永久解除 busy) ─────────

  function makePermanentlyFalse(vm, prop) {
    if (!vm) return;
    try {
      const desc = Object.getOwnPropertyDescriptor(vm, prop) || Object.getOwnPropertyDescriptor(Object.getPrototypeOf(vm), prop);
      if (desc && desc.configurable) {
        Object.defineProperty(vm, prop, {
          get: () => false,
          set: (v) => {},
          configurable: true,
          enumerable: true
        });
      } else if (!desc) {
        Object.defineProperty(vm, prop, {
          get: () => false,
          set: (v) => {},
          configurable: true,
          enumerable: true
        });
      }
    } catch (e) {}
  }

  function removeAllDisabled() {
    document.querySelectorAll('button[disabled], a[disabled], input[disabled], .disabled, .is-disabled').forEach(el => {
      el.removeAttribute('disabled');
      if (el.disabled) el.disabled = false;
      el.classList.remove('disabled', 'is-disabled', 'btn-disabled');
      if (el.style.pointerEvents === 'none') {
        el.style.pointerEvents = 'auto';
      }
      if (el.style.opacity === '0.5' || el.style.opacity === '0.6') {
        el.style.opacity = '1';
      }
      const text = el.textContent.trim();
      if (/售罄|补货|抢光|人满|繁忙/.test(text)) {
        el.textContent = '特惠订阅';
      }
    });
  }

  function patchVueServerBusy() {
    // 强制解除 DOM 级别的禁用状态
    removeAllDisabled();

    const app = document.querySelector('#app');
    const vue = app && app.__vue__;
    if (!vue) return;
    
    let patched = 0;
    const walk = (vm, depth) => {
      if (depth > 8) return;
      if (vm.$data) {
        if ('isServerBusy' in vm.$data || vm.isServerBusy === true) {
          makePermanentlyFalse(vm, 'isServerBusy');
          patched++;
        }
        if ('soldOut' in vm.$data || vm.soldOut === true) {
          makePermanentlyFalse(vm, 'soldOut');
          patched++;
        }
        if ('isSoldOut' in vm.$data || vm.isSoldOut === true) {
          makePermanentlyFalse(vm, 'isSoldOut');
          patched++;
        }
      }
      for (const child of (vm.$children || [])) walk(child, depth + 1);
    };
    
    walk(vue, 0);
  }

  setInterval(patchVueServerBusy, 1000);

  // ── 成功后轮询等待支付弹窗:多策略重试确保支付弹窗弹出 ──
  async function waitForPaymentDialog(responseData) {
    const maxWait = 10000; // 增加到10秒
    const pollInterval = 300;
    const start = Date.now();

    // 策略1: 先尝试正常点击购买按钮触发
    const btn = findBuyButton();
    if (btn) { btn.click(); log('[支付等待] 已点击购买按钮触发弹窗'); }

    for (let round = 0; Date.now() - start < maxWait; round++) {
      // 检查支付弹窗是否已出现
      if (isPaymentUIVisible()) {
        // 检查是否有可扫描二维码(可能需要等canvas加载)
        if (hasScannableQR()) {
          freezeForPayment('[支付等待] ✅ 支付弹窗已出现且有二维码!');
          return;
        }
        // 弹窗出现但无QR → 等待加载
        log(`[支付等待] 支付弹窗已出现,等待二维码加载 (${(Date.now() - start) / 1000}s)...`);
        await sleep(1000);
        if (hasScannableQR()) {
          freezeForPayment('[支付等待] ✅ 二维码已加载!');
          return;
        }
        // 仍在加载 → 冻结并通知用户
        freezeForPayment('[支付等待] ✅ 支付弹窗已出现,二维码加载中,冻结保护!');
        return;
      }
      // 检查是否有错误弹窗阻挡
      const errDlg = findErrorDialog();
      if (errDlg) {
        dismissDialog(errDlg);
        log(`[支付等待] 第${round + 1}轮:关闭错误弹窗,重新尝试`);
      }
      // 每600ms重试一次 forcePayDialog
      if (round > 0 && round % 2 === 0) {
        forcePayDialog(responseData);
        log(`[支付等待] 第${round + 1}轮:Vue Hack 重试`);
      }
      await sleep(pollInterval);
    }

    // 超时后最终兜底:提取直接支付链接
    log('[支付等待] 支付弹窗未出现,尝试提取直接支付链接...', 'warn');
    await tryDirectPayLink();
  }

  // ── 兜底:通过 bizId 提取直接支付链接 ──
  async function tryDirectPayLink() {
    const bizId = state.bizId;
    if (!bizId) return;
    try {
      const checkUrl = `${location.origin}/api/biz/pay/check?bizId=${encodeURIComponent(bizId)}`;
      const resp = await _fetch(checkUrl, { credentials: 'include' });
      const checkData = await resp.json();

      if (checkData.data && typeof checkData.data === 'string' && checkData.data.startsWith('http')) {
        window.open(checkData.data, '_blank');
        freezeForPayment('[兜底] 已在新标签页打开支付链接');
      } else if (checkData.data && checkData.data.payUrl) {
        window.open(checkData.data.payUrl, '_blank');
        freezeForPayment('[兜底] 已在新标签页打开支付链接');
      } else if (checkData.data && checkData.data.qrCode) {
        showQRCodeFallback(checkData.data.qrCode, bizId);
        freezeForPayment('[兜底] 已显示支付二维码');
      } else {
        log('[兜底] bizId有效但无支付链接,请手动刷新页面查看', 'warn');
      }
    } catch (e) {
      log('[兜底] 提取支付链接失败: ' + e.message, 'error');
    }
  }

  function forcePayDialog(responseData) {
    const app = document.querySelector('#app');
    const vue = app && app.__vue__;
    if (!vue) return;

    let payComp = null;
    const findComp = (vm, depth) => {
      if (depth > 8) return;
      if (vm.$data && 'payDialogVisible' in vm.$data) { payComp = vm; return; }
      for (const child of (vm.$children || [])) { findComp(child, depth + 1); if (payComp) return; }
    };
    findComp(vue, 0);
    if (!payComp) { log('[Vue Hack] 未定位到支付组件'); return; }

    if (payComp.payDialogVisible) { log('支付窗口已正常开启'); return; }

    const data = responseData && responseData.data;
    if (data) {
      payComp.priceData = data;
      payComp.payDialogVisible = true;
      log('[Vue Hack] 暴力破解成功: 已设置 payDialogVisible=true');
    }
  }

  // ── 3E. 支付恢复 & 错误弹窗自动恢复 ─────────────────────────────

  function findErrorDialog() {
    const sels = [
      '.el-dialog', '.el-message-box', '.el-dialog__wrapper',
      '.ant-modal', '.ant-modal-wrap', '[class*="modal"]', '[class*="dialog"]',
    ];
    for (const sel of sels) {
      for (const el of document.querySelectorAll(sel)) {
        const s = window.getComputedStyle(el);
        if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') continue;
        if (/购买人数过多|系统繁忙|稍后再试|请重试|繁忙|失败|出错|异常/.test(el.textContent || '')) return el;
      }
    }
    return null;
  }

  function dismissDialog(dialog) {
    for (const sel of ['.el-dialog__headerbtn', '.el-message-box__headerbtn', '.ant-modal-close', '[aria-label="Close"]']) {
      const btn = dialog.querySelector(sel);
      if (btn && visible(btn)) { btn.click(); return true; }
    }
    for (const btn of dialog.querySelectorAll('button')) {
      const t = (btn.textContent || '').trim();
      if (/关闭|确定|知道了|确认/.test(t) && t.length < 10) { btn.click(); return true; }
    }
    dialog.style.display = 'none';
    return true;
  }

  async function autoRecover() {
    if (recovering || recoveryAttempts >= 3 || !state.lastSuccess) return;

    const payEl = document.querySelector('[class*="pay"], [class*="qrcode"], [class*="alipay"], iframe[src*="pay"]');
    if (payEl && visible(payEl)) {
      log('扫码支付界面已开启,停止自动恢复。');
      return;
    }

    const errDlg = findErrorDialog();
    if (!errDlg) return;

    recovering = true;
    recoveryAttempts++;
    log(`[自动恢复] 检测到错误弹窗,正在发起第 ${recoveryAttempts}/3 次自动恢复机制...`);

    try {
      dismissDialog(errDlg);
      document.querySelectorAll('.el-overlay, .v-modal, .el-overlay-dialog').forEach(el => el.style.display = 'none');
      document.body.style.overflow = '';
      document.body.classList.remove('el-popup-parent--hidden');
      await sleep(300);

      setState({ cache: state.lastSuccess });
      const btn = findBuyButton();
      if (btn) {
        btn.click();
        log('[恢复策略2] 已重新模拟点击购买按钮');
        await sleep(1500);
      }

      if (!isPaymentUIVisible()) {
        log('[恢复策略3] 支付弹窗未弹出,尝试提取直接支付链接...');
        await tryDirectPayLink();
      }
    } 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:2147483647;background:#fff;padding:30px;border-radius:12px;box-shadow:0 8px 32px rgba(0,0,0,.3);text-align:center';
    div.innerHTML = `
      <h3 style="margin:0 0 15px;color:#333;font-size:16px;font-weight:bold;">glm_bypass — 抢购成功,直接支付</h3>
      <img src="${qrData}" style="width:200px;height:200px">
      <p style="margin:15px 0 0;color:#666;font-size:12px">bizId: ${bizId}</p>
      <button id="close-qr-fallback" style="margin-top:15px;padding:6px 20px;background:#6c5ce7;border:none;color:#fff;border-radius:4px;cursor:pointer">关闭</button>
    `;
    document.body.appendChild(div);
    div.querySelector('#close-qr-fallback').onclick = () => div.remove();
  }

  function findBuyButton() {
    for (const el of document.querySelectorAll('button.buy-btn, button, [role="button"]')) {
      const t = el.textContent.trim();
      if (/特惠订阅|订阅升级|购买|下单/.test(t) && t.length < 15 && visible(el)) return el;
    }
    return null;
  }

  function setupDialogWatcher() {
    const observer = new MutationObserver(() => {
      if (state.lastSuccess && !recovering && recoveryAttempts < 3) {
        if (findErrorDialog()) autoRecover();
      }
    });
    observer.observe(document.body, { childList: true, subtree: true });
  }

  // ── 3F. 时钟校准 & 产品ID预拉取 ─────────────────────────────────

  async function calibrateClock() {
    log('开始校准系统时钟与服务器时间...');
    const offsets = [];
    for (let i = 0; i < 3; i++) {
      try {
        const t1 = Date.now();
        // 💡 优化:用 HEAD 方法请求首页,完全不带 credentials 凭证,彻底绕过风控检测
        const res = await _fetch(location.origin + '/', {
          method: 'HEAD',
          credentials: 'omit',
          cache: 'no-cache'
        });
        const t2 = Date.now();
        const dateStr = res.headers.get('Date');
        if (dateStr) {
          const serverTime = new Date(dateStr).getTime();
          const localTime = (t1 + t2) / 2;
          offsets.push(serverTime - localTime);
        }
      } catch (e) {}
      await sleep(200);
    }

    if (offsets.length >= 2) {
      offsets.sort((a, b) => a - b);
      _serverTimeOffset = offsets[Math.floor(offsets.length / 2)];
      log(`[时钟校准] 完成。偏移值: ${_serverTimeOffset}ms`);
    } else {
      log('[时钟校准] 失败,将使用本地时间');
    }
  }

  async function autoFetchProductIds() {
    const auth = _capturedAuthHeader || sessionStorage.getItem('glm_bypass_captured_auth');
    if (!auth) return;
    if (_allProductIds && Object.keys(_allProductIds).length > 0) {
      log('[自动获取] 检测到已缓存的产品 ID,跳过背景预拉取以防 555 限流。');
      return;
    }
    try {
      const resp = await _fetch(location.origin + '/api/biz/pay/batch-preview', {
        method: 'POST',
        credentials: 'include',
        headers: {
          'Content-Type': 'application/json;charset=UTF-8',
          'Authorization': auth
        },
        body: '{}'
      });
      if (resp.ok) {
        const data = await resp.json();
        if (data?.data?.productList && Array.isArray(data.data.productList)) {
          data.data.productList.forEach(item => {
            if (item && item.productId) {
              const plan = identifyPlanName(item.monthlyOriginalAmount);
              const period = identifyPeriodName(item);
              if (plan && period) {
                _allProductIds[`${plan}_${period}`] = item.productId;
              }
            }
          });
          localStorage.setItem('glm_bypass_cached_pids', JSON.stringify(_allProductIds));
          log(`[自动获取] 成功拉取并缓存产品 ID 列表`);
          refreshUI();
        }
      }
    } catch (e) {
      log(`[自动获取] 尝试拉取产品列表失败: ${e.message}`, 'warn');
    }
  }

  // 💡 优化:移除所有 normal 状态下的周期性时钟同步,极速抢购前 1 分钟再启动探测
  let highFreqSyncStarted = false;
  function startHighFreqSync() {
    if (highFreqSyncStarted) return;
    highFreqSyncStarted = true;
    log('[时钟校准] 临近抢购,启动安全错峰校准监控...');
    const tid = setInterval(() => {
      const diff = getTargetTime() - serverNow();
      if (diff <= 0 || _rushActive) {
        clearInterval(tid);
        return;
      }
      calibrateClock();
    }, 12000); // 间隔放宽到 12 秒,安全第一
  }

  // ── 3G. 抢购调度 (主动触发 & 错峰 & 定时) ────────────────────────
  async function startProactive() {
    // 确保授权和产品ID就绪
    if (!state.captured) {
      const auth = _capturedAuthHeader || sessionStorage.getItem('glm_bypass_captured_auth');
      const pid = getProductIdForCurrent();
      if (auth && pid) {
        state.captured = {
          url: location.origin + '/api/biz/pay/preview',
          method: 'POST',
          body: JSON.stringify({ productId: pid }),
          headers: {
            'Content-Type': 'application/json;charset=UTF-8',
            'Authorization': auth
          }
        };
        log(`[自动装配] 检测到已有授权凭证与产品 ID,已自动生成请求参数!`);
      } else {
        log('未检测到请求参数,正在尝试主动获取...', 'warn');
        if (auth) {
          await autoFetchProductIds();
          const retryPid = getProductIdForCurrent();
          if (retryPid) {
            state.captured = {
              url: location.origin + '/api/biz/pay/preview',
              method: 'POST',
              body: JSON.stringify({ productId: retryPid }),
              headers: {
                'Content-Type': 'application/json;charset=UTF-8',
                'Authorization': auth
              }
            };
            log(`[自动装配] 主动获取产品列表成功,已自动生成请求参数!`);
          } else {
            alert('请先手动点一次购买/订阅按钮,或稍候等脚本自动拉取产品列表完毕。');
            return;
          }
        } else {
          alert('未捕获到登录 Token,请确认已处于登录状态,或手动点击一次购买按钮。');
          return;
        }
      }
    }
    if (_paymentFrozen) {
      log('支付保护中,请先解冻再重新开始');
      return;
    }
    if (_wafBlocked) {
      log('⛔ IP已被WAF拦截,请更换IP后刷新页面重试!');
      return;
    }

    _rushActive = true;
    _rushStopped = false;
    // 注意:_wafBlocked 不在此重置,WAF拦截后只有刷新页面才能恢复
    setState({ status: 'active' });
    patchVueServerBusy();
    log('抢购已启动,自动点击购买按钮...');

    // 点击购买按钮触发验证码流程,后续由状态机自动处理
    const btn = findBuyButton();
    if (btn) {
      btn.click();
      log('已点击购买按钮,等待验证码弹窗...');
    } else {
      log('未找到购买按钮,请手动点击', 'warn');
    }
  }

  function stopAll() {
    _rushActive = false;
    _rushStopped = true;
    setState({ status: 'idle', count: 0 });
    if (state.timerId) { clearInterval(state.timerId); setState({ timerId: null }); }
    // 停止所有自动重试
    retryEngineCleanup();
    if (_previewRetryTimer) { clearTimeout(_previewRetryTimer); _previewRetryTimer = null; }
    _qrRetryEpoch++; // 使所有QR重试回调失效
    _captchaState = CAPTCHA_STATE.IDLE;
    _captchaProcessing = false;
    _captchaLastBgUrl = '';
    _captchaLastChars = '';
    _lastPreviewResult = '';
    // 关闭验证码弹窗
    try {
      const captchaClose = document.querySelector('.tencent-captcha-dy__close-btn') ||
        document.querySelector('#tcaptcha_transform_dy .close-btn');
      if (captchaClose) captchaClose.click();
    } catch (e) {}
    // 关闭支付弹窗
    try {
      const closeBtn = document.querySelector('[class*="pay-dialog"] [class*="close"], [class*="payDialog"] [class*="close"]');
      if (closeBtn) closeBtn.click();
      document.querySelectorAll('.el-overlay, .v-modal, .el-overlay-dialog').forEach(el => {
        el.style.display = 'none';
      });
      document.body.style.overflow = '';
    } catch (e) {}
    log('抢购已停止。');
  }

  function scheduleAt(timeStr) {
    if (state.timerId) clearInterval(state.timerId);

    const parts = timeStr.split(':').map(Number);
    const now = serverNow();
    const target = new Date(now);
    target.setHours(parts[0], parts[1], parts[2] || 0, 0);

    if (target.getTime() <= now.getTime()) {
      const overdue = now.getTime() - target.getTime();
      if (overdue < 300000) { // 5分钟内都立即激活
        log(`已超出设定时间 ${timeStr} ${(overdue/1000).toFixed(0)}秒,立即激活!`);
        startProactive();
        return;
      } else {
        log('目标时间已过期超过5分钟,自动调整为明天。');
        target.setDate(target.getDate() + 1);
      }
    }

    log(`已设定定时抢购: ${timeStr},等待中...`);

    // 第一阶段:远距离,1秒精度(省CPU)
    const farPhase = setInterval(() => {
      const diff = target.getTime() - serverNow().getTime();

      // 更新倒计时
      if (diff > 0) {
        const timerInfo = _shadowRef?.getElementById('timer-info');
        if (timerInfo) {
          const min = Math.floor(diff / 60000);
          const sec = Math.floor((diff % 60000) / 1000);
          timerInfo.textContent = min > 0 ? `-${min}m${sec}s` : `-${sec}s`;
        }
      }

      // 进入近距离阶段(60秒内),切换到10ms精度
      if (diff <= 60000) {
        clearInterval(farPhase);
        startNearPhase(target);
      }
    }, 1000);

    setState({ timerId: farPhase });
  }

  function startNearPhase(target) {
    let presolved = false;

    const tid = setInterval(() => {
      const diff = target.getTime() - serverNow().getTime();

      if (diff > 50000 && diff < 60000) {
        startHighFreqSync();
      }

      // T-preSolveMs: 预求解验证码(提前触发购买按钮,让OCR+验证在10:00前完成)
      if (!presolved && diff > 0 && diff < CFG.preSolveMs) {
        if (_wafBlocked) { log('⛔ IP已被WAF拦截,预求解中止'); return; }
        presolved = true;
        log(`[预求解] 提前${(CFG.preSolveMs / 1000).toFixed(1)}秒触发验证码流程`);
        _rushActive = true;
        _rushStopped = false;
        // _wafBlocked 不在此重置
        setState({ status: 'active' });
        patchVueServerBusy();
        const btn = findBuyButton();
        if (btn) {
          btn.click();
          log('[预求解] 已点击购买按钮,验证码自动识别中...');
        }
      }

      // 更新倒计时(精确到0.1秒)
      if (diff > 0) {
        const timerInfo = _shadowRef?.getElementById('timer-info');
        if (timerInfo) timerInfo.textContent = `-${(diff / 1000).toFixed(1)}s`;
      }

      const tabJitter = isMasterTab ? 0 : 180 + (tabId.charCodeAt(0) % 2) * 150;
      if (diff - CFG.advanceMs - tabJitter <= 0) {
        clearInterval(tid);
        setState({ timerId: null });
        const timerInfo = _shadowRef?.getElementById('timer-info');
        if (timerInfo) timerInfo.textContent = '';

        if (_rushActive) {
          // 预求解已在运行,验证码流程进行中,不再重复点击
          log(`[点火] 预求解已在运行中 (状态=${_captchaState}),继续等待结果`);
        } else {
          log(`[点火] 抢购启动!当前协同延迟: +${tabJitter}ms`);
          patchVueServerBusy();
          startProactive();
        }
      }
    }, 10);

    setState({ timerId: tid });
  }

  // ── 3H. OCR 服务健康检查 ──
  function checkOcrHealth() {
    const statusEl = _shadowRef?.getElementById('ocr-status');
    if (!statusEl) return;
    const server = CFG.captchaServer.replace(/\/$/, '');
    statusEl.textContent = '...';
    statusEl.style.color = '#52525b';

    const timeout = setTimeout(() => {
      statusEl.textContent = 'OFF';
      statusEl.style.color = '#f87171';
      log(`[OCR] 服务未连接: ${server}`, 'warn');
    }, 3000);

    const handleOk = (text) => {
      clearTimeout(timeout);
      try {
        const data = JSON.parse(text);
        statusEl.textContent = `OK (${data.fonts ?? '?'} fonts)`;
        statusEl.style.color = '#4ade80';
        log(`[OCR] 服务就绪: ${server} (${data.fonts ?? '?'} 字体, ${data.engine ?? '?'})`);
      } catch {
        statusEl.textContent = 'ERR';
        statusEl.style.color = '#f87171';
      }
    };
    const handleFail = () => {
      clearTimeout(timeout);
      statusEl.textContent = 'OFF';
      statusEl.style.color = '#f87171';
      log(`[OCR] 服务未连接: ${server}`, 'warn');
    };

    if (typeof GM_xmlhttpRequest !== 'undefined') {
      GM_xmlhttpRequest({
        method: 'GET',
        url: `${server}/health`,
        timeout: 3000,
        onload: (res) => {
          if (res.status === 200) handleOk(res.responseText);
          else handleFail();
        },
        onerror: handleFail,
        ontimeout: handleFail,
      });
    } else {
      fetch(`${server}/health`, { signal: AbortSignal.timeout(3000) })
        .then(r => r.ok ? r.text().then(handleOk) : handleFail())
        .catch(handleFail);
    }
  }

  // ── 3I. Shadow DOM 控制面板 (UI) ─────────────────────────────────

  function createPanel() {
    const host = document.createElement('div');
    host.id = 'glm-bypass-host';
    const shadow = host.attachShadow({ mode: 'closed' });

    shadow.innerHTML = `
<style>
:host {
  all: initial;
  position: fixed;
  top: 16px;
  right: 16px;
  z-index: 2147483647;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
.panel {
  width: 320px;
  background: #111113;
  border: 1px solid #2a2a2e;
  border-radius: 10px;
  color: #e4e4e7;
  font-size: 12px;
  user-select: none;
  overflow: hidden;
  box-shadow: 0 4px 24px rgba(0,0,0,.5);
}
.hdr {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 12px;
  cursor: move;
  border-bottom: 1px solid #2a2a2e;
  background: #16161a;
}
.hdr-title {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 1.5px;
  color: #a78bfa;
  text-transform: uppercase;
}
.hdr-right {
  display: flex;
  align-items: center;
  gap: 6px;
}
.hdr-tag {
  font-size: 10px;
  padding: 1px 6px;
  border-radius: 3px;
  background: #1e1e22;
  color: #71717a;
  font-weight: 500;
}
.hdr-btn {
  background: none;
  border: none;
  color: #71717a;
  cursor: pointer;
  font-size: 16px;
  line-height: 1;
  padding: 0 2px;
  transition: color .15s;
}
.hdr-btn:hover { color: #e4e4e7; }
.bdy { padding: 10px 12px 12px; }
.sts {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: 6px;
  margin-bottom: 8px;
  font-size: 11px;
  font-weight: 600;
  background: #1a1a1e;
  border: 1px solid #2a2a2e;
}
.sts-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  flex-shrink: 0;
}
.sts-idle .sts-dot { background: #52525b; }
.sts-active .sts-dot { background: #f97316; animation: blink 1s infinite; }
.sts-success .sts-dot { background: #22c55e; }
.sts-failed .sts-dot { background: #ef4444; }
@keyframes blink { 0%,100%{ opacity:1 } 50%{ opacity:.3 } }
.sts-active { border-color: #f9731633; }
.sts-success { border-color: #22c55e33; }
.sts-failed { border-color: #ef444433; }
.info-row {
  font-size: 10px;
  color: #71717a;
  padding: 4px 0;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 6px;
}
.cfg {
  display: grid;
  grid-template-columns: 36px 1fr 36px 1fr;
  gap: 6px;
  align-items: center;
  margin-bottom: 8px;
}
.cfg-label {
  font-size: 10px;
  color: #71717a;
}
.cfg select, .cfg input[type="text"] {
  width: 100%;
  padding: 4px 6px;
  border: 1px solid #2a2a2e;
  border-radius: 4px;
  background: #1a1a1e;
  color: #e4e4e7;
  font-size: 11px;
  outline: none;
  transition: border .15s;
}
.cfg select:focus, .cfg input:focus { border-color: #a78bfa; }
.cfg select option { background: #1a1a1e; color: #e4e4e7; }
.cfg-full {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 6px;
}
.cfg-full .cfg-label { width: 36px; flex-shrink: 0; }
.cfg-full input { flex: 1; }
.timer-row {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-bottom: 8px;
}
.timer-row input[type="time"] {
  flex: 1;
  padding: 4px 6px;
  border: 1px solid #2a2a2e;
  border-radius: 4px;
  background: #1a1a1e;
  color: #e4e4e7;
  font-size: 11px;
  outline: none;
}
.timer-row input:focus { border-color: #a78bfa; }
.t-btn {
  padding: 4px 8px;
  border: 1px solid #2a2a2e;
  border-radius: 4px;
  background: #1a1a1e;
  color: #a1a1aa;
  font-size: 10px;
  cursor: pointer;
  transition: all .15s;
  white-space: nowrap;
}
.t-btn:hover { border-color: #a78bfa; color: #e4e4e7; }
.t-btn-accent { background: #a78bfa22; border-color: #a78bfa44; color: #a78bfa; }
.t-btn-accent:hover { background: #a78bfa33; }
#timer-info {
  font-size: 11px;
  font-weight: 700;
  color: #a78bfa;
  min-width: 40px;
  text-align: right;
}
.acts {
  display: flex;
  gap: 4px;
  margin-bottom: 8px;
}
.abtn {
  flex: 1;
  padding: 6px 0;
  border: none;
  border-radius: 5px;
  font-weight: 600;
  font-size: 11px;
  cursor: pointer;
  transition: opacity .15s, transform .08s;
  text-align: center;
}
.abtn:active { transform: scale(.97); }
.abtn-go { background: #a78bfa; color: #fff; }
.abtn-stop { background: #ef4444; color: #fff; }
.abtn-sec { background: #27272a; color: #a1a1aa; }
.abtn-sec:hover { background: #323236; color: #e4e4e7; }
.log-hdr {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 4px;
}
.log-hdr span {
  font-size: 10px;
  color: #52525b;
  text-transform: uppercase;
  letter-spacing: .5px;
}
.log-copy {
  font-size: 9px;
  padding: 1px 6px;
  border: 1px solid #2a2a2e;
  border-radius: 3px;
  background: none;
  color: #52525b;
  cursor: pointer;
  transition: color .15s;
}
.log-copy:hover { color: #a1a1aa; }
.log-box {
  height: 120px;
  overflow-y: auto;
  background: #0a0a0b;
  border-radius: 6px;
  padding: 6px 8px;
  font-family: 'SF Mono', 'Cascadia Code', 'Fira Code', monospace;
  font-size: 10px;
  line-height: 1.5;
  border: 1px solid #1a1a1e;
}
.log-line {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  margin-bottom: 1px;
  user-select: text;
  cursor: text;
}
.log-info { color: #a1a1aa; }
.log-warn { color: #fbbf24; }
.log-error { color: #f87171; }
.log-success { color: #4ade80; }
.log-box::-webkit-scrollbar { width: 3px; }
.log-box::-webkit-scrollbar-thumb { background: #2a2a2e; border-radius: 2px; }
.log-box::-webkit-scrollbar-track { background: transparent; }
.foot {
  font-size: 9px;
  color: #3f3f46;
  text-align: center;
  margin-top: 6px;
}
</style>
<div class="panel">
  <div class="hdr" id="drag-bar">
    <span class="hdr-title">glm_bypass</span>
    <div class="hdr-right">
      <span class="hdr-tag">v1.0.0</span>
      <button class="hdr-btn" id="min-btn">_</button>
    </div>
  </div>
  <div class="bdy" id="body-section">
    <div class="sts sts-idle" id="lbl-status">
      <span class="sts-dot"></span>
      <span id="sts-text">STANDBY</span>
    </div>
    <div class="cfg">
      <span class="cfg-label">套餐</span>
      <select id="sel-plan">
        <option value="pro" ${curPlan() === 'pro' ? 'selected' : ''}>Pro</option>
        <option value="lite" ${curPlan() === 'lite' ? 'selected' : ''}>Lite</option>
        <option value="max" ${curPlan() === 'max' ? 'selected' : ''}>Max</option>
      </select>
      <span class="cfg-label">周期</span>
      <select id="sel-period">
        <option value="quarterly" ${curPeriod() === 'quarterly' ? 'selected' : ''}>包季</option>
        <option value="yearly" ${curPeriod() === 'yearly' ? 'selected' : ''}>包年</option>
        <option value="monthly" ${curPeriod() === 'monthly' ? 'selected' : ''}>包月</option>
      </select>
      <div class="cfg-full">
        <span class="cfg-label">OCR</span>
        <input type="text" id="inp-ocr" value="${CFG.captchaServer}">
        <span id="ocr-status" style="font-size:9px;color:#52525b;white-space:nowrap;"></span>
      </div>
    </div>
    <div class="timer-row">
      <input type="time" id="inp-time" step="1" value="10:00:00">
      <button class="t-btn" id="btn-set-time">SET</button>
      <button class="t-btn t-btn-accent" id="btn-auto-timer">10:00</button>
      <span id="timer-info"></span>
    </div>
    <div class="acts">
      <button class="abtn abtn-go" id="btn-start">START</button>
      <button class="abtn abtn-stop" id="btn-stop" style="display:none;">STOP</button>
      <button class="abtn abtn-sec" id="btn-unfreeze" style="display:none;color:#f97316;">UNFREEZE</button>
    </div>
    <div class="log-hdr">
      <span>log</span>
      <button class="log-copy" id="btn-copy-log">copy</button>
    </div>
    <div class="log-box" id="log-list"></div>
    <div class="foot"></div>
  </div>
</div>`;



    document.body.appendChild(host);

    const $ = (id) => shadow.getElementById(id);

    $('btn-start').onclick = startProactive;
    $('btn-stop').onclick = stopAll;
    $('btn-unfreeze').onclick = () => {
      _paymentFrozen = false;
      _frozenAt = 0;
      _captchaState = 0; // CAPTCHA_STATE.IDLE
      _captchaProcessing = false;
      _captchaLastBgUrl = '';
      _captchaLastChars = '';
      log('🔓 手动解冻,状态机已重置');
    };

    $('btn-set-time').onclick = () => {
      const v = $('inp-time').value;
      if (v) scheduleAt(v);
    };
    $('btn-auto-timer').onclick = () => {
      scheduleAt('10:00:00');
      $('inp-time').value = '10:00:00';
    };
    $('btn-copy-log').onclick = () => {
      const logEl = $('log-list');
      if (!logEl) return;
      const text = Array.from(logEl.children).map(c => c.textContent).join('\n');
      if (!text) return;
      navigator.clipboard.writeText(text).then(() => {
        const btn = $('btn-copy-log');
        btn.textContent = 'copied!';
        setTimeout(() => { btn.textContent = 'copy'; }, 1500);
      }).catch(() => {
        const ta = document.createElement('textarea');
        ta.value = text;
        shadow.appendChild(ta);
        ta.select();
        document.execCommand('copy');
        shadow.removeChild(ta);
        const btn = $('btn-copy-log');
        btn.textContent = 'copied!';
        setTimeout(() => { btn.textContent = 'copy'; }, 1500);
      });
    };

    $('inp-ocr').onchange = function () {
      CFG.captchaServer = this.value;
      localStorage.setItem('glm_bypass_cfg', JSON.stringify(CFG));
      GM_setValue('glm_bypass_captcha_server', CFG.captchaServer);
      checkOcrHealth();
    };

    $('sel-plan').onchange = function () {
      if (!CFG.planPriority) CFG.planPriority = [{}];
      if (!CFG.planPriority[0]) CFG.planPriority[0] = {};
      CFG.planPriority[0].plan = this.value;
      localStorage.setItem('glm_bypass_cfg', JSON.stringify(CFG));
      log(`[配置] 已将抢购首选套餐设置为: ${this.value.toUpperCase()}`);
      refreshUI();
    };
    $('sel-period').onchange = function () {
      if (!CFG.planPriority) CFG.planPriority = [{}];
      if (!CFG.planPriority[0]) CFG.planPriority[0] = {};
      CFG.planPriority[0].billingPeriod = this.value;
      localStorage.setItem('glm_bypass_cfg', JSON.stringify(CFG));
      log(`[配置] 已将抢购首选周期设置为: ${this.value === 'quarterly' ? '连续包季' : this.value === 'yearly' ? '连续包年' : '连续包月'}`);
      refreshUI();
    };

    $('min-btn').onclick = function () {
      const sect = $('body-section');
      const hidden = sect.style.display === 'none';
      sect.style.display = hidden ? '' : 'none';
      this.textContent = hidden ? '_' : '+';
    };

    let sx, sy, sl, st;
    $('drag-bar').onmousedown = function (e) {
      sx = e.clientX; sy = e.clientY;
      const rect = host.getBoundingClientRect();
      sl = rect.left; st = rect.top;
      const onMove = (evt) => {
        host.style.left = (sl + evt.clientX - sx) + 'px';
        host.style.top = (st + evt.clientY - sy) + 'px';
        host.style.right = 'auto';
        host.style.position = 'fixed';
      };
      const onUp = () => {
        document.removeEventListener('mousemove', onMove);
        document.removeEventListener('mouseup', onUp);
      };
      document.addEventListener('mousemove', onMove);
      document.addEventListener('mouseup', onUp);
    };

    _shadowRef = shadow;
    log('glm_bypass 面板已就绪。');
    if (state.captured) log('已从内存中读取捕获的 preview 请求参数,可直接抢购!');

    setupDialogWatcher();
    calibrateClock();
    updateMasterStatusDisplay();
    setTimeout(autoFetchProductIds, 500);
    checkOcrHealth();

    // 自动设定10:00定时抢购(或立即激活)
    const now = serverNow();
    const target = new Date(now);
    target.setHours(CFG.targetHour, CFG.targetMinute, 0, 0);
    const timeStr = `${String(CFG.targetHour).padStart(2,'0')}:${String(CFG.targetMinute).padStart(2,'0')}:00`;
    if (target > now) {
      // 还没到10点,自动设定定时
      scheduleAt(timeStr);
    } else if (now.getTime() - target.getTime() < 300000) {
      // 10点后5分钟内,立即激活
      log(`[自动激活] 已过10:00不到5分钟,立即开始抢购!`);
      startProactive();
    }
    // 超过5分钟则不自动激活,等用户手动操作

    // 监听购买按钮的手动点击,自动激活抢购
    document.addEventListener('click', (e) => {
      const btn = e.target.closest('button, [role="button"]');
      if (!btn) return;
      const t = btn.textContent.trim();
      if (/特惠订阅|订阅升级|购买|下单/.test(t) && t.length < 15) {
        if (!_rushActive && !_rushStopped && !_paymentFrozen && !_wafBlocked) {
          _rushActive = true;
          log('检测到手动点击购买按钮,自动激活抢购流程');
        }
      }
    }, true);

    if (Notification && Notification.permission === 'default') {
      Notification.requestPermission();
    }
  }

  // ── 3J. UI 刷新 & 日志渲染 ───────────────────────────────────────
  let uiPending = false;

  function refreshUI() {
    if (uiPending) return;
    uiPending = true;
    requestAnimationFrame(() => {
      uiPending = false;
      const shadow = _shadowRef;
      if (!shadow) return;
      
      const $ = (id) => shadow.getElementById(id);

      const statusEl = $('lbl-status');
      if (statusEl) {
        statusEl.className = 'sts sts-' + state.status;
        const textEl = $('sts-text');
        if (textEl) {
          textEl.textContent = state.status === 'idle' ? 'STANDBY'
            : state.status === 'active' ? 'RUNNING'
            : state.status === 'success' ? `OK — ${state.bizId?.substring(0, 8)}...`
            : 'FAILED';
        }
      }






      const goBtn = $('btn-start');
      const stopBtn = $('btn-stop');
      const unfreezeBtn = $('btn-unfreeze');
      if (goBtn && stopBtn) {
        goBtn.style.display = _rushActive ? 'none' : '';
        stopBtn.style.display = _rushActive ? '' : 'none';
      }
      if (unfreezeBtn) unfreezeBtn.style.display = _paymentFrozen ? '' : 'none';
    });
  }

  function appendLogDOM(entry) {
    const shadow = _shadowRef;
    if (!shadow) return;
    const el = shadow.getElementById('log-list');
    if (!el) return;
    const div = document.createElement('div');
    div.className = `log-line log-${entry.level === 'error' ? 'error' : entry.level === 'warn' ? 'warn' : entry.msg.includes('成功') ? 'success' : 'info'}`;
    div.textContent = `${entry.ts} ${entry.msg}`;
    el.appendChild(div);
    while (el.children.length > 500) el.removeChild(el.firstChild);
    el.scrollTop = el.scrollHeight;
  }

  window.addEventListener('beforeunload', e => {
    if (_rushActive) {
      e.preventDefault();
      e.returnValue = '抢购正在后台全力进行中,确定要离开吗?';
    }
  });

  // ── 3K. 支付检测 & 验证码状态机 ──────────────────────────────────
  //    统一状态机:
  //    IDLE → 验证码弹出 → SOLVING → 点击确定 → WAITING_RESULT
  //      → 验证码消失 + 支付弹窗出现 → SUCCESS (冻结,保护支付)
  //      → 验证码消失 + 错误弹窗出现 → FAIL (关闭弹窗,重新购买)
  //      → 验证码消失 + 什么都没有   → MAYBE_RETRY (等待后重试购买)
  //      → 验证码错误提示           → FAIL (刷新验证码,重新识别)
  //      → 等待超时                 → TIMEOUT (刷新验证码)
  //
  //  铁律: 支付二维码可见 = 一切自动化停止
  // ═══════════════════════════════════════════════════════════════════
  const CAPTCHA_STATE = { IDLE: 0, SOLVING: 1, WAITING: 2 };
  let _captchaState = CAPTCHA_STATE.IDLE;
  let _captchaLastBgUrl = '';
  let _captchaLastChars = '';    // 上次已提交的验证码提示文字
  let _captchaSkipCount = 0;     // 连续因相同验证码而跳过的次数
  let _captchaAttempt = 0;
  let _captchaProcessing = false; // 防止并发处理的锁
  let _captchaWaitStart = 0;
  let _qrRetryEpoch = 0; // 渐进重试轮次号,每轮+1,旧计时器检测到不匹配自动停止
  let _paymentFrozen = false;
  let _captchaPresolved = false;
  let _captchaPreconfirmEl = null;
  let _captchaQrRetried = false;
  let _captchaCallbackResult = ''; // 'success' | 'error' | '' — 验证码SDK回调结果
  let _lastPreviewResult = '';     // '555' | 'soldOut' | 'error' | 'ok' | '' — preview API响应码
  let _previewRetryTimer = null;   // preview失败时自动重试的定时器
  const CAPTCHA_MAX_ATTEMPT = 6;
  const CAPTCHA_WAIT_TIMEOUT = 4000; // 验证码提交后4秒无结果即刷新(高峰期放宽)

  // ── 并行Ticket复用重试引擎 ──
  let _retryEngineActive = false;
  let _retryEngineEpoch = 0;              // 每次启动+1,孤儿回调检测不匹配自动停止
  let _retryEngineTickets = [];           // Array<{body, headers, capturedAt}>
  let _retryEngineBatchTimer = null;
  let _retryEngineInflight = 0;
  let _retryEngineSuccessResult = null;   // {text, data} 完整成功响应
  let _retryEngineTotalAttempts = 0;
  let _retryEngineStartTime = 0;
  let _wafBlocked = false; // WAF 405拦截标记,停止一切并提示刷新

  // ── 3K-1. 支付冻结机制 ──
  let _frozenAt = 0; // 冻结时间戳

  function freezeForPayment(msg) {
    if (_paymentFrozen) return;
    if (_retryEngineActive) retryEngineStop('支付冻结');
    _paymentFrozen = true;
    _frozenAt = Date.now();
    _captchaState = CAPTCHA_STATE.IDLE;
    _captchaAttempt = 0;
    _emptyPayDialogCount = 0;
    _rushActive = false;
    setState({ status: 'success', count: (state.count || 0) + 1 });
    // 注意:不清空 _captchaLastBgUrl!
    // 如果弹窗是空白的,解冻后不应重新识别同一验证码
    log(msg || '✅ 支付界面出现,冻结所有自动化!');
    // 记录触发冻结的元素,方便排查(只检测支付弹窗内元素)
    const payEls = [];
    const payDialog = document.querySelector('.el-dialog.pay-dialog');
    if (payDialog) {
      const canvas = payDialog.querySelector('canvas');
      const price = payDialog.querySelector('.info-price span:last-child');
      payEls.push(`pay-dialog=visible`);
      payEls.push(`canvas=${canvas ? canvas.width + 'x' + canvas.height : 'none'}`);
      payEls.push(`price="${price?.textContent?.trim() || ''}"`);
    }
    if (payEls.length) log(`[冻结检测] ${payEls.join(', ')}`);
    else log('[冻结检测] 未找到支付弹窗元素');
    // 浏览器通知
    try { new Notification('glm_bypass 抢购成功!', { body: '请尽快完成支付' }); } catch {}
    // 声音提醒: 3 声 880Hz 蜂鸣
    try {
      const actx = new (window.AudioContext || window.webkitAudioContext)();
      for (let i = 0; i < 3; i++) {
        const osc = actx.createOscillator();
        const gain = actx.createGain();
        osc.connect(gain);
        gain.connect(actx.destination);
        osc.frequency.value = 880;
        osc.type = 'sine';
        gain.gain.value = 0.3;
        osc.start(actx.currentTime + i * 0.4);
        osc.stop(actx.currentTime + i * 0.4 + 0.15);
      }
    } catch {}
  }

  // ── 并行Ticket复用重试引擎 ──
  // preview返回555/500时,复用当前ticket高频重发,同时继续走验证码拿新ticket

  function retryEngineStart(initialCaptured) {
    if (_retryEngineActive) {
      retryEngineAddTicket(initialCaptured);
      return;
    }
    if (!initialCaptured?.body) { log('[重试引擎] 无请求体,跳过', 'warn'); return; }
    if (initialCaptured.body.includes('trerror')) { log('[重试引擎] trerror ticket,跳过', 'warn'); return; }

    _retryEngineActive = true;
    _retryEngineEpoch++;
    _retryEngineStartTime = Date.now();
    _retryEngineSuccessResult = null;
    _retryEngineTotalAttempts = 0;
    _retryEngineInflight = 0;
    _retryEngineTickets = [{
      body: initialCaptured.body,
      headers: initialCaptured.headers || {},
      capturedAt: Date.now()
    }];

    log(`[重试引擎] 启动 epoch=${_retryEngineEpoch} 间隔=${CFG.retryIntervalMs}ms`);

    // 立即发射第一个请求
    retryEngineFireOne();

    // 定时均匀发射
    _retryEngineBatchTimer = setInterval(retryEngineFireOne, CFG.retryIntervalMs);
  }

  function retryEngineStop(reason) {
    if (!_retryEngineActive && !_retryEngineBatchTimer) return;
    log(`[重试引擎] 停止: ${reason},总尝试=${_retryEngineTotalAttempts},耗时=${Date.now() - _retryEngineStartTime}ms`);
    _retryEngineActive = false;
    _retryEngineEpoch++; // 使孤儿回调失效
    if (_retryEngineBatchTimer) { clearInterval(_retryEngineBatchTimer); _retryEngineBatchTimer = null; }
    _retryEngineTickets = [];
    _retryEngineInflight = 0;
  }

  function retryEngineCleanup() {
    retryEngineStop('清理');
    _retryEngineSuccessResult = null;
    _retryEngineTotalAttempts = 0;
    _retryEngineStartTime = 0;
  }

  function retryEngineAddTicket(captured) {
    if (!_retryEngineActive) return;
    if (!captured?.body) return;
    if (captured.body.includes('trerror')) { log('[重试引擎] 跳过trerror ticket'); return; }
    // 去重
    if (_retryEngineTickets.some(t => t.body === captured.body)) return;
    _retryEngineTickets.push({
      body: captured.body,
      headers: captured.headers || {},
      capturedAt: Date.now()
    });
    log(`[重试引擎] 新ticket入池,池大小=${_retryEngineTickets.length}`);
  }

  function retryEngineFireOne() {
    if (_rushStopped) { retryEngineStop('用户停止'); return; }
    if (_paymentFrozen) { retryEngineStop('支付已冻结'); return; }
    if (!_retryEngineActive) return;
    if (_retryEngineSuccessResult) { retryEngineStop('已成功'); return; }

    // 修剪过期ticket
    const now = Date.now();
    _retryEngineTickets = _retryEngineTickets.filter(t => (now - t.capturedAt) < CFG.retryTicketTTL);
    if (_retryEngineTickets.length === 0) return;

    // 最多1个在途,保证均匀
    if (_retryEngineInflight >= 1) return;

    // Round-robin选ticket
    const ticket = _retryEngineTickets[_retryEngineTotalAttempts % _retryEngineTickets.length];
    retryEngineFireSingle(ticket);

    // 每10次打印日志
    if (_retryEngineTotalAttempts % 10 === 0) {
      log(`[重试引擎] 总计=${_retryEngineTotalAttempts}, 池=${_retryEngineTickets.length}`);
    }
  }

  async function retryEngineFireSingle(ticket) {
    const myEpoch = _retryEngineEpoch;
    _retryEngineInflight++;
    _retryEngineTotalAttempts++;

    try {
      const url = (state.captured?.url) || (location.origin + '/api/biz/pay/preview');
      const fResult = await fetchWithTimeout(url, {
        method: 'POST',
        body: ticket.body,
        headers: { ...ticket.headers },
        credentials: 'include'
      }, CFG.retryTimeout);

      if (myEpoch !== _retryEngineEpoch) { _retryEngineInflight--; return; }

      // WAF 405检测:retryEngine绕过拦截器,需自行检测
      if (!fResult.ok && (fResult.resp.status === 405 || fResult.resp.status === 403)) {
        try {
          const body = await fResult.resp.text();
          if (body.trimStart().startsWith('<!') || body.includes('<html')) {
            _wafBlocked = true;
            log('⛔ IP被WAF拦截(405),更换IP后刷新页面重试!');
            retryEngineStop('WAF拦截');
            return;
          }
        } catch (_) {}
        _retryEngineInflight--;
        return;
      }
      if (!fResult.ok) { _retryEngineInflight--; return; }

      const text = await fResult.resp.text();
      if (myEpoch !== _retryEngineEpoch) { _retryEngineInflight--; return; }

      const respObj = _parse(text);
      const code = respObj?.code;
      const data = respObj?.data;

      if (code === 200 && data?.bizId) {
        retryEngineHandleSuccess(text, respObj);
        return; // retryEngineStop已重置inflight,不重复递减
      }
      // 555/500/其他:ticket留在池中继续用
    } catch (e) {
      // 网络/解析错误,忽略
    }
    _retryEngineInflight--;
  }

  function retryEngineHandleSuccess(responseText, respObj) {
    if (_retryEngineSuccessResult) return; // 第一赢家锁定
    _retryEngineSuccessResult = { text: responseText, data: respObj };
    const bizId = respObj?.data?.bizId || '';
    log(`[重试引擎] ✅ 成功! bizId=${bizId.substring(0, 8)}... 总尝试=${_retryEngineTotalAttempts} 耗时=${Date.now() - _retryEngineStartTime}ms`);

    // 停止引擎
    retryEngineStop('成功');

    // 保存到state,让Vue下一次preview请求拿到成功响应
    state.cache = { text: responseText };
    state.lastSuccess = { text: responseText };
    setState({ status: 'success', bizId: bizId });

    // 持久化到sessionStorage
    try { sessionStorage.setItem('glm_bypass_last_success', JSON.stringify({ text: responseText, bizId, ts: Date.now() })); } catch {}

    // 通知其他标签页
    try {
      if (typeof channel !== 'undefined' && channel?.postMessage) {
        channel.postMessage({ type: 'GLM_BYPASS_SUCCESS', tabId: typeof tabId !== 'undefined' ? tabId : 0, bizId });
      }
    } catch {}

    // 触发支付弹窗:点击购买按钮让Vue发preview → fetch拦截器返回state.cache → Vue弹支付弹窗
    setTimeout(() => {
      if (_rushStopped || _paymentFrozen) return;
      const btn = findBuyButton();
      if (btn) {
        log('[重试引擎] 点击购买按钮触发Vue支付流程');
        btn.click();
      }
    }, 500);
  }

  // ── 3K-2. 支付 UI 检测 ──
  // 支付弹窗检测
  function isPaymentUIVisible() {
    // 策略1: 找到可见的 .pay-dialog
    const wrappers = document.querySelectorAll('.el-dialog__wrapper');
    for (const wrapper of wrappers) {
      const wrapperStyle = wrapper.getAttribute('style') || '';
      if (wrapperStyle.includes('display: none') || wrapperStyle.includes('display:none')) continue;
      const cs = getComputedStyle(wrapper);
      if (cs.display === 'none' || cs.visibility === 'hidden' || cs.opacity === '0') continue;
      const dialog = wrapper.querySelector('.el-dialog.pay-dialog');
      if (dialog && visible(dialog)) {
        // 排除"人数较多"错误弹窗
        if ((wrapper.innerText || '').includes('当前购买人数较多')) continue;
        // 排除小飞机(系统繁忙)弹窗
        if (dialog.querySelector('.empty-data-wrap, .empty-data')) continue;
        // 确认有支付内容
        const hasPayContent = dialog.querySelector('.scan-code-box, .scan-qrcode-box, .pay-model, .code-pic-box');
        if (hasPayContent) return true;
      }
    }

    // 策略2: Vue payDialogVisible === true(仅作辅助,上面DOM检测已覆盖主要场景)
    const app = document.querySelector('#app');
    const vue = app && app.__vue__;
    if (vue) {
      let found = false;
      const walk = (vm, depth) => {
        if (found || depth > 8) return;
        if (vm.$data && vm.$data.payDialogVisible === true) { found = true; return; }
        for (const child of (vm.$children || [])) { walk(child, depth + 1); if (found) return; }
      };
      walk(vue, 0);
      if (found) return true;
    }

    // 策略3: 支付 iframe
    for (const el of document.querySelectorAll('iframe')) {
      const src = (el.src || '').toLowerCase();
      if ((src.includes('cashier') || src.includes('alipay') || src.includes('pay')) && visible(el)) return true;
    }

    // 策略4: 检查 fallback 二维码
    if (document.querySelector('#close-qr-fallback')) return true;
    return false;
  }

  // ── 3K-3. 错误弹窗检测 ──
  function isErrorDialogVisible() {
    const sels = [
      '.el-dialog', '.el-message-box', '.el-dialog__wrapper',
      '.ant-modal', '.ant-modal-wrap', '[class*="modal"]', '[class*="dialog"]',
    ];
    for (const sel of sels) {
      for (const el of document.querySelectorAll(sel)) {
        const s = getComputedStyle(el);
        if (s.display === 'none' || s.visibility === 'hidden' || s.opacity === '0') continue;
        if (/购买人数过多|系统繁忙|稍后再试|请重试|繁忙|失败|出错|异常|售罄|已售完/.test(el.textContent || '')) return el;
      }
    }
    return null;
  }

  // ── 3K-4. 验证码可见性检测 (DOM 查询) ──
  function mainPageCaptchaVisible() {
    // 1. 查找遮罩层/弹窗容器 — 必须真正弹出
    const modalSelectors = [
      '.tencent-captcha-dy__overlay',
      '.tencent-captcha-dy__mask',
      '.tcaptcha-overlay',
      '#tcaptcha_transform_dy',
    ];
    let modalEl = null;
    for (const sel of modalSelectors) {
      const el = document.querySelector(sel);
      if (el) {
        const s = getComputedStyle(el);
        if (s.display !== 'none' && s.visibility !== 'hidden' && parseFloat(s.opacity) !== 0) {
          modalEl = el;
          break;
        }
      }
    }
    // 2. 查找弹窗主体
    const contentEl = document.querySelector('.tencent-captcha-dy__content');
    if (!contentEl) return false;
    const cs = getComputedStyle(contentEl);
    if (cs.display === 'none' || cs.visibility === 'hidden' || contentEl.offsetWidth < 50) return false;

    // 3. 最关键:必须有实际可见的背景图(有 background-image URL)
    const bgEl = mainPageFindBgEl();
    if (!bgEl) return false;
    const bgText = (bgEl.style && bgEl.style.backgroundImage ? bgEl.style.backgroundImage : '') || getComputedStyle(bgEl).backgroundImage || '';
    if (!bgText || bgText === 'none') return false;
    const hasUrl = /url\(/.test(bgText);
    if (!hasUrl) return false;

    // 4. 提示文字必须包含"请依次点击"或类似引导语(排除"完成验证"等按钮文字)
    const promptEl = document.querySelector('.tencent-captcha-dy__header-text, [class*="header-text"]');
    if (!promptEl) return false;
    const promptRaw = promptEl.textContent || '';
    if (!/请.*点击|请.*选择/.test(promptRaw)) return false;

    return true;
  }

  // ── 3K-5. 验证码元素查找 (背景图/URL/提示文字/点击) ──
  function mainPageFindBgEl() {
    const selectors = [
      '.tencent-captcha-dy__verify-bg-img',
      '[class*="verify-bg-img"]',
      '[class*="captcha-bg"]',
      '#slideBg',
      '[class*="verify-bg"]',
    ];
    for (const sel of selectors) {
      const el = document.querySelector(sel);
      if (el && el.offsetWidth > 0) return el;
    }
    return null;
  }

  function mainPageFindBgUrl() {
    const selectors = [
      '.tencent-captcha-dy__verify-bg-img',
      '[class*="verify-bg-img"]',
      '[class*="captcha-bg"]',
      '#slideBg',
      '[class*="verify-bg"]',
    ];
    for (const sel of selectors) {
      const el = document.querySelector(sel);
      if (!el) continue;

      // 尝试 background-image
      const bgText = (el.style && el.style.backgroundImage ? el.style.backgroundImage : '') || getComputedStyle(el).backgroundImage || '';
      const match = bgText.match(/url\(["']?([^"')]+)["']?\)/);
      if (match) {
        try { return new URL(match[1], location.href).href; } catch { return match[1]; }
      }

      // 尝试 src 属性 (img 标签)
      if (el.src && el.tagName === 'IMG') {
        try { return new URL(el.src, location.href).href; } catch { return el.src; }
      }
    }
    return '';
  }

  function mainPageFindPromptText() {
    const selectors = [
      '.tencent-captcha-dy__header-text',
      '[class*="header-text"]',
      '#instructionText',
      '[class*="captcha-prompt"]',
    ];
    for (const sel of selectors) {
      const el = document.querySelector(sel);
      if (!el) continue;
      const raw = (el.textContent || el.getAttribute('aria-label') || '').trim();
      // 严格模式:只从 "请依次点击:XXX" 或 "请点击:XXX" 之后提取
      // 支持冒号、空格、换行分隔
      const afterClick = raw.match(/(?:请依次点击|请点击|请按顺序点击)[::\s]*(.+)/);
      if (afterClick) {
        const chars = (afterClick[1].match(/[\u4e00-\u9fff]/g) || []).slice(0, 3);
        if (chars.length >= 3) return chars.join('');
      }
      // 备用:找所有独立汉字(排除常见引导词)
      const allChars = (raw.match(/[\u4e00-\u9fff]/g) || []);
      const stopWords = ['请','依','次','点','击','选','按','顺','序','完','成','验','证'];
      const filtered = allChars.filter(c => !stopWords.includes(c));
      if (filtered.length >= 3) return filtered.slice(0, 3).join('');
    }
    return '';
  }

  function mainPageDispatchClick(el, nx, ny, label) {
    const rect = el.getBoundingClientRect();
    const clientX = rect.left + nx * rect.width;
    const clientY = rect.top + ny * rect.height;
    const win = el.ownerDocument.defaultView;
    const base = { bubbles: true, cancelable: true, view: win, clientX, clientY, button: 0, buttons: 1 };
    const pointer = { ...base, pointerId: 1, pointerType: 'mouse', isPrimary: true, pressure: 0.5 };
    try { if (win.PointerEvent) el.dispatchEvent(new win.PointerEvent('pointerdown', pointer)); } catch {}
    el.dispatchEvent(new win.MouseEvent('mousedown', base));
    try { if (win.PointerEvent) el.dispatchEvent(new win.PointerEvent('pointerup', pointer)); } catch {}
    el.dispatchEvent(new win.MouseEvent('mouseup', base));
    el.dispatchEvent(new win.MouseEvent('click', base));
    log(`[主页面验证码] 模拟点击 "${label}" @ (${nx.toFixed(3)}, ${ny.toFixed(3)})`);
  }

  // ── 3K-6. 验证码自动识别主流程 (OCR → 模拟点击 → 提交) ──
  async function mainPageSolveCaptcha() {
    if (_rushStopped || _captchaState !== CAPTCHA_STATE.IDLE || _paymentFrozen) return;
    if (_captchaProcessing) return; // 防止并发处理

    _captchaProcessing = true;
    _captchaState = CAPTCHA_STATE.SOLVING;
    _captchaCallbackResult = ''; // 重置SDK回调结果

    try {
      // ── 1. 查找验证码图片元素 ──
      const bgEl = mainPageFindBgEl();
      if (!bgEl) { _captchaState = CAPTCHA_STATE.IDLE; _captchaProcessing = false; return; }

      // ── 2. 提取背景图 URL ──
      const bgUrl = mainPageFindBgUrl();
      if (!bgUrl) {
        log('[主页面验证码] 背景图 URL 为空');
        _captchaState = CAPTCHA_STATE.IDLE;
        _captchaProcessing = false;
        return;
      }

      // ── 3. 提取提示文字 ──
      const chars = mainPageFindPromptText();
      if (chars.length < 3) {
        const headerEl = document.querySelector('.tencent-captcha-dy__header, [class*="captcha-header"]');
        if (headerEl) log(`[主页面验证码] header 原始文本: "${headerEl.textContent.trim()}"`);
        _captchaState = CAPTCHA_STATE.IDLE;
        _captchaProcessing = false;
        return;
      }

      // ── 4. 检测重复验证码(URL相同 或 提示文字相同 = ticket已消费) ──
      const sameUrl = bgUrl === _captchaLastBgUrl;
      const sameChars = chars === _captchaLastChars && _captchaLastChars !== '';
      if (sameUrl || sameChars) {
        _captchaSkipCount++;
        if (_captchaSkipCount >= 3) {
          // 刷新3次仍是同一张 → 关闭验证码弹窗,重新点击购买按钮
          log(`[主页面验证码] 连续3次相同验证码(文字:${chars}),关闭弹窗重新购买`, 'warn');
          _captchaSkipCount = 0;
          // 不清空 _captchaLastChars!防止重新识别同一验证码
          _captchaState = CAPTCHA_STATE.IDLE;
          // 关闭验证码弹窗
          try {
            const captchaClose = document.querySelector('.tencent-captcha-dy__close-btn') ||
              document.querySelector('#tcaptcha_transform_dy .close-btn');
            if (captchaClose) captchaClose.click();
          } catch (e) {}
          // 延迟后重新点击购买按钮(会触发全新验证码会话)
          setTimeout(() => {
            _captchaProcessing = false;
            _captchaLastBgUrl = '';
            _captchaLastChars = '';
            if (_rushStopped) return;
            const btn = findBuyButton();
            if (btn && _rushActive) {
              btn.click();
              log('[验证码] 已关闭旧弹窗并重新点击购买');
            }
          }, 500);
          return;
        }
        const reason = sameChars ? `文字"${chars}"相同` : 'URL相同';
        log(`[主页面验证码] ${reason}(ticket已消费),第${_captchaSkipCount}次刷新`);
        _captchaState = CAPTCHA_STATE.IDLE;
        // 手动刷新,不清空 _captchaLastBgUrl 和 _captchaLastChars,以便检测刷新后是否仍是同一张
        const refreshBtn = document.querySelector('.tencent-captcha-dy__footer-icon--refresh img, [class*="refresh"] img, #reload');
        if (refreshBtn) { refreshBtn.click(); log('[验证码] 已刷新'); }
        // 延迟解锁,给刷新加载新图片的时间
        setTimeout(() => { if (_rushStopped) return; _captchaProcessing = false; }, 800);
        return;
      }

      // 新验证码,重置跳过计数
      _captchaSkipCount = 0;
      _captchaLastBgUrl = bgUrl;
      _captchaLastChars = chars;
      _captchaAttempt++;
      log(`[主页面验证码] 第 ${_captchaAttempt} 次识别 — 提示: "${chars}"`);

      // ── 4. 获取图片数据(优先 canvas 直接提取,跳过网络下载) ──
      let dataUrl = '';

      // 方案 A(最快): canvas 直接从 DOM 元素绘制,零网络开销
      try {
        const cvs = document.createElement('canvas');
        const rect = bgEl.getBoundingClientRect();
        cvs.width = rect.width || 344;
        cvs.height = rect.height || 344;
        const ctx = cvs.getContext('2d');
        // 如果是 img 标签,直接 drawImage
        if (bgEl.tagName === 'IMG' && bgEl.complete && bgEl.naturalWidth > 0) {
          ctx.drawImage(bgEl, 0, 0, cvs.width, cvs.height);
          dataUrl = cvs.toDataURL('image/jpeg', 0.85);
        }
        // 如果是带 background-image 的 div,用 Image 对象加载
        if (!dataUrl && bgUrl) {
          const img = new Image();
          img.crossOrigin = 'anonymous';
          dataUrl = await new Promise((resolve, reject) => {
            const tid = setTimeout(() => reject(new Error('img加载超时')), 3000);
            img.onload = () => {
              clearTimeout(tid);
              try {
                ctx.drawImage(img, 0, 0, cvs.width, cvs.height);
                resolve(cvs.toDataURL('image/jpeg', 0.85));
              } catch (e) { reject(e); }
            };
            img.onerror = () => { clearTimeout(tid); reject(new Error('img加载失败')); };
            img.src = bgUrl;
          });
        }
      } catch (canvasErr) {
        log(`[主页面验证码] canvas提取失败: ${canvasErr.message},回退网络下载`);
      }

      // 方案 B(兜底): 通过 GM_xmlhttpRequest 网络下载
      if (!dataUrl) {
        try {
          dataUrl = await new Promise((resolve, reject) => {
            const timeout = setTimeout(() => reject(new Error('图片下载超时')), 8000);
            if (typeof GM_xmlhttpRequest !== 'undefined') {
              GM_xmlhttpRequest({
                method: 'GET', url: bgUrl, responseType: 'blob',
                onload: (res) => {
                  clearTimeout(timeout);
                  if (res.status && res.status !== 200) { reject(new Error(`HTTP ${res.status}`)); return; }
                  if (!res.response || res.response.size < 100) { reject(new Error(`数据异常`)); return; }
                  const reader = new FileReader();
                  reader.onload = () => resolve(reader.result);
                  reader.onerror = () => reject(new Error('FileReader 失败'));
                  reader.readAsDataURL(res.response);
                },
                onerror: () => { clearTimeout(timeout); reject(new Error('图片下载失败')); },
              });
            } else {
              fetch(bgUrl, { mode: 'cors', credentials: 'include' })
                .then(r => { if (!r.ok) throw new Error(`HTTP ${r.status}`); return r.blob(); })
                .then(blob => {
                  clearTimeout(timeout);
                  if (blob.size < 100) throw new Error('blob太小');
                  const reader = new FileReader();
                  reader.onload = () => resolve(reader.result);
                  reader.readAsDataURL(blob);
                })
                .catch(err => { clearTimeout(timeout); reject(err); });
            }
          });
        } catch (imgErr) {
          log(`[主页面验证码] 图片获取失败: ${imgErr.message}`);
        }
      }

      if (!dataUrl) { _captchaLastBgUrl = ''; _captchaState = CAPTCHA_STATE.IDLE; _captchaProcessing = false; return; }

      // ── 5. 调用 OCR 服务 ──
      const server = CFG.captchaServer.replace(/\/$/, '');
      const payload = JSON.stringify({ image: dataUrl, text: chars, remark: chars, ts: Date.now() });

      const response = await new Promise((resolve, reject) => {
        const timeout = setTimeout(() => reject(new Error('OCR 超时(8s)')), 8000);
        if (typeof GM_xmlhttpRequest !== 'undefined') {
          GM_xmlhttpRequest({
            method: 'POST', url: `${server}/captcha_direct`,
            headers: { 'Content-Type': 'application/json' }, data: payload,
            onload: (res) => {
              clearTimeout(timeout);
              try { resolve(JSON.parse(res.responseText)); } catch (e) { reject(new Error('响应解析失败')); }
            },
            onerror: () => { clearTimeout(timeout); reject(new Error('OCR 连接失败')); },
          });
        } else {
          fetch(`${server}/captcha_direct`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: payload })
            .then(r => { clearTimeout(timeout); return r.json(); }).then(resolve).catch(err => { clearTimeout(timeout); reject(err); });
        }
      });

      // ── 6. 解析坐标 ──
      let coords = [];
      if (response.success && response.result && Array.isArray(response.result.click_coords)) {
        coords = response.result.click_coords;
      } else if (response.success && response.data && response.data.result) {
        const raw = response.data.result.split('|');
        coords = raw.map((p, idx) => {
          const xy = p.split(',');
          return { char: chars[idx] || '', nx: parseFloat(xy[0]) / 344.0, ny: parseFloat(xy[1]) / 344.0 };
        });
      }

      if (!coords || coords.length === 0) {
        log('[主页面验证码] OCR 未识别出有效坐标,刷新重试');
        captchaRefresh();
        return;
      }

      log(`[主页面验证码] 坐标: ${coords.map(c => `${c.char}(${c.nx.toFixed(2)},${c.ny.toFixed(2)})`).join(' ')}`);

      // ── 7. 模拟点击 ──
      for (const pt of coords) {
        const nx = Number(pt.nx), ny = Number(pt.ny);
        if (!Number.isFinite(nx) || !Number.isFinite(ny)) continue;
        mainPageDispatchClick(bgEl, nx, ny, pt.char || '');
        await sleep(150); // 150ms间隔,足够SDK响应
      }

      // ── 8. 点击确定 → 进入等待状态 ──
      await sleep(200);
      const confirmBtn = document.querySelector('.tencent-captcha-dy__verify-confirm-btn:not(.tencent-captcha-dy__verify-confirm-btn--disabled)');
      if (confirmBtn) {
        confirmBtn.click();
        _captchaState = CAPTCHA_STATE.WAITING;
        _captchaWaitStart = Date.now();
        // _captchaProcessing 保持 true,直到 SDK 回调后才解锁
        log('[主页面验证码] 已点击确定,等待验证结果...');
      } else {
        _captchaState = CAPTCHA_STATE.IDLE;
        _captchaLastBgUrl = '';
        _captchaProcessing = false;
      }
    } catch (e) {
      log(`[主页面验证码] 异常: ${e.message}`);
      _captchaLastBgUrl = '';
      _captchaState = CAPTCHA_STATE.IDLE;
      _captchaProcessing = false;
    }
  }

  function captchaRefresh() {
    if (_rushStopped) { _captchaState = CAPTCHA_STATE.IDLE; _captchaProcessing = false; return; }
    if (_paymentFrozen) return;
    const refreshBtn = document.querySelector('.tencent-captcha-dy__footer-icon--refresh img, [class*="refresh"] img, #reload');
    if (refreshBtn) {
      refreshBtn.click();
      log('[验证码] 已刷新');
    }
    _captchaLastBgUrl = '';
    _captchaLastChars = '';
    _captchaSkipCount = 0;
    _captchaState = CAPTCHA_STATE.IDLE;
    // 注意:不清除 _captchaProcessing!让整个链路结束后自然解锁
    // 新的验证码图片出现时,Observer/定时器触发的 mainPageSolveCaptcha
    // 会因为 _captchaProcessing=true 而被阻止
    // 等新图片加载完成后,500ms 延迟的 setTimeout 会再次被触发
    // 但我们需要在 refresh 后解锁以允许新识别
    // 解决方案:延迟解锁,给 refresh 加载新图片的时间
    setTimeout(() => { if (_rushStopped) return; _captchaProcessing = false; }, 800);
  }

  // ── 3K-7. QR码检测 (双通道价格 + canvas + iframe) ──
  // QR码检测 (双通道价格 + canvas + iframe)
  function hasScannableQR() {
    // 策略1: 双通道价格检测
    // 真实支付弹窗必有金额,空白/错误弹窗金额为空
    const prices = readPayDialogPrices();
    if (prices.any) return true;

    // 策略2: canvas 非空白检测
    const qrCanvas = document.querySelector('.scan-qrcode-box canvas');
    if (qrCanvas && visible(qrCanvas) && checkCanvasContent(qrCanvas)) return true;

    // 策略3: 支付弹窗内所有 canvas
    for (const c of document.querySelectorAll('.pay-model canvas, .pay-dialog canvas')) {
      if (visible(c) && checkCanvasContent(c)) return true;
    }

    // 策略4: 支付 iframe
    for (const el of document.querySelectorAll('iframe')) {
      const src = (el.src || '').toLowerCase();
      if ((src.includes('cashier') || src.includes('alipay') || src.includes('wechatpay') || src.includes('wxpay')) && visible(el)) return true;
    }

    // 策略5: data URL 图片
    for (const img of document.querySelectorAll('.scan-qrcode-box img[src^="data:image"], .pay-model img[src^="data:image"]')) {
      if (img.width > 80 && img.height > 80 && visible(img)) return true;
    }

    log('[QR检测] 未检测到有效二维码内容(canvas空白、无价格、无iframe)');
    return false;
  }

  // 双通道读价格
  function readPayDialogPrices() {
    const dlg = document.querySelector('.pay-dialog');
    let scanPrice = 0, actualPrice = 0;

    // 通道A: 扫码区 .info-price 最后一个 span(纯数字)
    if (dlg) {
      const infoPrice = dlg.querySelector('.info-price');
      if (infoPrice) {
        const spans = infoPrice.querySelectorAll('span');
        for (let i = spans.length - 1; i >= 0; i--) {
          const v = parseFloat(spans[i].textContent.trim());
          if (!isNaN(v) && v > 0) { scanPrice = v; break; }
        }
      }
      // 通道B: 计算明细区"实付金额"
      dlg.querySelectorAll('.calculate-content-item').forEach(li => {
        if ([...li.querySelectorAll('div')].some(d => d.textContent.includes('实付金额'))) {
          const v = parseFloat((li.querySelector('.price-item')?.textContent || '').replace(/[¥,]/g, '').trim());
          if (!isNaN(v) && v > 0) actualPrice = v;
        }
      });
    }

    return { scanPrice, actualPrice, any: scanPrice > 0 || actualPrice > 0 };
  }

  // 辅助:检查 canvas 是否绘制了实际内容
  function checkCanvasContent(canvas) {
    try {
      const ctx = canvas.getContext('2d', { willReadFrequently: true });
      if (!ctx) return false;
      const w = canvas.width, h = canvas.height;
      if (w <= 1 || h <= 1) return false;
      const imgData = ctx.getImageData(0, 0, w, h).data;
      let nonTransparent = 0;
      const step = 4; // 每4像素采样
      for (let i = 3; i < imgData.length; i += 4 * step) {
        if (imgData[i] > 0) nonTransparent++;
      }
      const total = imgData.length / (4 * step);
      if (total > 0 && nonTransparent / total > 0.03) {
        log(`[QR检测] canvas有内容: ${w}x${h}, 非透明像素比例=${(nonTransparent/total*100).toFixed(1)}%`);
        return true;
      }
    } catch (e) {
      // 跨域canvas无法读取 → 用尺寸判断
      if (canvas.width > 50 && canvas.height > 50) {
        log(`[QR检测] canvas跨域无法读取像素但有尺寸 ${canvas.width}x${canvas.height},假设有内容`);
        return true;
      }
    }
    return false;
  }

  // ── 3K-8. 空弹窗关闭 & 重试 ──
  function isPaymentLoading() {
    // 检查 spinner / loading 动画
    const loadingSels = [
      '.scan-qrcode-box [class*="loading"]',
      '.scan-qrcode-box [class*="spinner"]',
      '.scan-qrcode-box [class*="skeleton"]',
      '.pay-model [class*="loading"]',
      '[class*="pay-dialog"] [class*="loading"]',
      '[class*="payDialog"] [class*="loading"]',
      '.el-loading-mask',
      '.el-loading-spinner',
    ];
    for (const sel of loadingSels) {
      const el = document.querySelector(sel);
      if (el && visible(el)) return true;
    }
    // 检查 canvas 尺寸是否为 0(未初始化)
    const qrCanvas = document.querySelector('.scan-qrcode-box canvas');
    if (qrCanvas && qrCanvas.width <= 1 && qrCanvas.height <= 1) return true;
    return false;
  }

  let _emptyPayDialogCount = 0; // 空弹窗重试计数
  const MAX_EMPTY_PAY_DIALOG = 3; // 最多重试3次

  // ── 3K-8a. Preview API失败 → 立即重试购买 ──
  function triggerPreviewRetry(reason) {
    // ═══ 并行重试引擎:复用当前ticket高频重发 ═══
    if (!_paymentFrozen && _rushActive && state.captured?.body && !state.captured.body.includes('trerror')) {
      if (!_retryEngineActive) {
        retryEngineStart(state.captured);
      } else {
        retryEngineAddTicket(state.captured);
      }
    }

    // ═══ 原有逻辑:关闭弹窗 + 继续走验证码拿新ticket ═══
    // 立即关闭弹窗(同步操作,不防抖)
    if (!_paymentFrozen) {
      const closeBtn = document.querySelector('[class*="pay-dialog"] [class*="close"], [class*="payDialog"] [class*="close"], [class*="pay-dialog"] .el-dialog__headerbtn, [class*="payDialog"] .el-dialog__headerbtn');
      if (closeBtn) { closeBtn.click(); }
      document.querySelectorAll('.el-overlay, .v-modal, .el-overlay-dialog').forEach(el => {
        el.style.display = 'none';
      });
      document.body.style.overflow = '';
    }

    // 异步点击购买按钮(防抖)
    if (_previewRetryTimer) return;
    _previewRetryTimer = setTimeout(() => {
      if (_rushStopped || _paymentFrozen || _retryEngineSuccessResult || !_rushActive) { _previewRetryTimer = null; return; }

      // 关闭当前验证码弹窗(确保干净的状态)
      try {
        const captchaClose = document.querySelector('.tencent-captcha-dy__close-btn') ||
          document.querySelector('#tcaptcha_transform_dy .close-btn');
        if (captchaClose) captchaClose.click();
      } catch (e) {}

      // 重置验证码状态,允许重新触发验证码识别
      _captchaState = CAPTCHA_STATE.IDLE;
      // 不清空 _captchaLastBgUrl 和 _captchaLastChars!防止重新识别同一张验证码图
      _captchaSkipCount = 0;
      _captchaAttempt = 0; // preview失败不是OCR的问题,重置计数
      _captchaQrRetried = false;
      _qrRetryEpoch++;
      _emptyPayDialogCount = 0;

      // 点击购买按钮(会触发全新的验证码 → 新的ticket → 新的preview请求)
      const btn = findBuyButton();
      if (btn) {
        btn.click();
        log(`[Preview重试] 原因:${reason},已点击购买按钮`);
      } else {
        log(`[Preview重试] 原因:${reason},未找到购买按钮`, 'warn');
      }
      // 点击购买后延迟解锁,给验证码加载时间
      // 冷却期:1200ms 内不允许新的 preview 重试
      setTimeout(() => {
        if (!_rushStopped) _captchaProcessing = false;
        _previewRetryTimer = null; // 冷却结束,允许下一次重试
      }, 1200);
    }, 100); // 100ms防抖
  }
  function closeEmptyPayDialog() {
    if (_rushStopped) { _captchaState = CAPTCHA_STATE.IDLE; _captchaProcessing = false; return; }
    _emptyPayDialogCount++;
    _captchaState = 0; // IDLE
    // 延迟解锁,防止关闭后立即触发新识别
    setTimeout(() => { if (_rushStopped) return; _captchaProcessing = false; }, 600);
    // 不立刻清空 _captchaLastBgUrl!防止重新识别同一验证码

    if (_emptyPayDialogCount > MAX_EMPTY_PAY_DIALOG) {
      log(`[空弹窗] 已连续 ${_emptyPayDialogCount} 次空弹窗,停止自动重试,请手动处理`, 'warn');
      _captchaLastBgUrl = ''; // 最终清空,允许手动操作后继续
      _captchaLastChars = '';
      if (_paymentFrozen) {
        _paymentFrozen = false;
        _frozenAt = 0;
      }
      return;
    }

    // 关键:解除冻结,否则后续验证码无法自动识别
    if (_paymentFrozen) {
      _paymentFrozen = false;
      _frozenAt = 0;
      log(`[空弹窗] 第 ${_emptyPayDialogCount}/${MAX_EMPTY_PAY_DIALOG} 次解除冻结`);
    }
    // 关闭支付弹窗
    const closeBtn = document.querySelector('[class*="pay-dialog"] [class*="close"], [class*="payDialog"] [class*="close"], [class*="pay-dialog"] .el-dialog__headerbtn, [class*="payDialog"] .el-dialog__headerbtn');
    if (closeBtn) { closeBtn.click(); log('[空弹窗] 已关闭空支付弹窗'); }
    // 清理遮罩
    document.querySelectorAll('.el-overlay, .v-modal, .el-overlay-dialog').forEach(el => el.style.display = 'none');
    document.body.style.overflow = '';
    // 重置 Vue 支付弹窗状态
    const app = document.querySelector('#app');
    const vue = app && app.__vue__;
    if (vue) {
      const walk = (vm, d) => {
        if (d > 8) return;
        if (vm.$data && 'payDialogVisible' in vm.$data) { vm.payDialogVisible = false; return; }
        for (const c of (vm.$children || [])) walk(c, d + 1);
      };
      walk(vue, 0);
    }
    _captchaQrRetried = false;
    // 关闭验证码弹窗
    try {
      const captchaClose = document.querySelector('.tencent-captcha-dy__close-btn') ||
        document.querySelector('#tcaptcha_transform_dy .close-btn');
      if (captchaClose) captchaClose.click();
    } catch (e) {}
    // 延迟后清空URL缓存 + 重新点击购买(给验证码关闭+新验证码加载的时间)
    setTimeout(() => {
      _captchaLastBgUrl = '';
      _captchaLastChars = '';
      _captchaSkipCount = 0;
      log('[空弹窗] 已重置验证码缓存');
      if (_rushStopped) { log('[空弹窗] 已停止,不再重新点击购买'); return; }
      if (_rushActive) {
        const btn = findBuyButton();
        if (btn) { btn.click(); log(`[空弹窗] 第 ${_emptyPayDialogCount} 次重新点击购买按钮`); }
      } else {
        log('[空弹窗] 已停止抢购,不再重新点击购买');
      }
    }, 1500); // 1.5秒延迟后重试(原3秒,加速)
  }

  // ── 3K-9. 验证码结果判定 (captchaCheckResult) ──
  function captchaCheckResult() {
    if (_captchaState !== CAPTCHA_STATE.WAITING) return;
    if (_paymentFrozen) return;
    if (_rushStopped) { _captchaState = CAPTCHA_STATE.IDLE; _captchaProcessing = false; return; }

    // 重试引擎已成功 → 跳过验证码后续流程
    if (_retryEngineSuccessResult) {
      log('[验证码] 重试引擎已成功,跳过QR等待');
      _captchaState = CAPTCHA_STATE.IDLE;
      _captchaProcessing = false;
      return;
    }

    // ═══ 1. 先检查验证码SDK回调结果(最快最可靠) ═══
    if (_captchaCallbackResult === 'error') {
      log(`[验证码] SDK回调返回失败 (${_captchaAttempt}/${CAPTCHA_MAX_ATTEMPT})`);
      _captchaCallbackResult = ''; // 重置
      // 不在此处解锁!captchaRefresh() 会延迟解锁
      if (_captchaAttempt >= CAPTCHA_MAX_ATTEMPT) {
        log('[验证码] 已达最大重试次数,等待手动处理');
        _captchaAttempt = 0;
        _captchaState = CAPTCHA_STATE.IDLE;
        _captchaLastBgUrl = '';
        _captchaLastChars = '';
        _captchaProcessing = false; // 真正停止,解锁
        return;
      }
      captchaRefresh();
      return;
    }
    if (_captchaCallbackResult === 'success') {
      // 验证通过,跳到步骤3检查支付
      log('[验证码] SDK回调返回成功,检查支付结果...');
    } else {
      // ═══ 1b. 回调还没来,检查DOM错误提示 ═══
      // 验证码错误检测
      let hasVerifyError = false;

      // 方式A: 新版验证码错误提示
      const errEl = document.querySelector('.tencent-captcha-dy__verify-error-text, [class*="verify-error"]');
      if (errEl) {
        const es = getComputedStyle(errEl);
        if (es.display !== 'none' && es.visibility !== 'hidden' && errEl.offsetWidth > 0) {
          hasVerifyError = true;
        }
      }

      // 方式B: 旧版 #tcaptcha_note + .tc-note 可见性(参考 grabber 的 hasError)
      if (!hasVerifyError) {
        const noteEl = document.querySelector('#tcaptcha_note');
        if (noteEl) {
          const noteWrap = noteEl.closest('.tc-note');
          if (noteWrap && noteWrap.style.visibility !== 'hidden' && noteWrap.style.visibility !== '') {
            hasVerifyError = true;
          }
        }
      }

      if (hasVerifyError) {
        const errText = errEl ? errEl.textContent.trim() : '验证失败';
        log(`[验证码] DOM检测识别失败: "${errText}" (${_captchaAttempt}/${CAPTCHA_MAX_ATTEMPT})`);
        // 不在此处解锁!captchaRefresh() 会延迟解锁
        if (_captchaAttempt >= CAPTCHA_MAX_ATTEMPT) {
          log('[验证码] 已达最大重试次数,等待手动处理');
          _captchaAttempt = 0;
          _captchaState = CAPTCHA_STATE.IDLE;
          _captchaLastBgUrl = '';
          _captchaLastChars = '';
          _captchaProcessing = false; // 真正停止,解锁
          return;
        }
        captchaRefresh();
        return;
      }
    } // end of else (回调还没来)

    // ═══ 2. SDK回调成功时跳过容器检查,否则检查容器是否还在 ═══
    const sdkSuccess = _captchaCallbackResult === 'success';
    _captchaCallbackResult = ''; // 重置
    if (!sdkSuccess) {
      // 没收到success回调,检查容器
      const captchaContainer = document.querySelector(
        '.tencent-captcha-dy__content, .tencent-captcha-dy__overlay, #tcaptcha_transform_dy'
      );
      if (captchaContainer) {
        const cs = getComputedStyle(captchaContainer);
        const containerVisible = cs.display !== 'none' && cs.visibility !== 'hidden' && parseFloat(cs.opacity) !== 0;
        if (containerVisible) {
          // 容器可见 = 验证码还在(可能是转圈中/刷新中/等待结果)
          // 超时检查
          if (Date.now() - _captchaWaitStart > CAPTCHA_WAIT_TIMEOUT) {
            log(`[验证码] 等待超时 (${CAPTCHA_WAIT_TIMEOUT / 1000}s),刷新重试`);
            captchaRefresh();
            return;
          }
          // 还在转圈/刷新,继续等
          return;
        }
      }
    }

    // ═══ 3. 验证码容器已消失 或 SDK回调成功 = 检查支付结果 ═══
    _captchaAttempt = 0;

    // 3-waf: WAF拦截 → 停止一切(日志已由拦截器打印)
    if (_wafBlocked) {
      _captchaState = CAPTCHA_STATE.IDLE;
      _captchaProcessing = false;
      stopAll();
      return;
    }

    // 3-early: 如果preview已返回非成功结果,不进入QR等待,直接重试
    if (_retryEngineSuccessResult) {
      log('[验证码] 重试引擎已成功(3-early),跳过');
      _captchaState = CAPTCHA_STATE.IDLE;
      _captchaProcessing = false;
      return;
    }
    if (_lastPreviewResult && _lastPreviewResult !== 'ok') {
      log(`[验证码] preview=${_lastPreviewResult},跳过QR等待,直接重试`);
      const savedPreview = _lastPreviewResult;
      _lastPreviewResult = '';
      _captchaState = CAPTCHA_STATE.IDLE;
      _captchaLastBgUrl = '';
      // 不清空 _captchaLastChars!防止重试后重识别同一验证码
      // 不在此解锁!让 triggerPreviewRetry 统一管理解锁时序,避免竞态
      if (!_previewRetryTimer) {
        triggerPreviewRetry(`preview=${savedPreview}`);
      }
      return;
    }

    // 3a. 支付 UI 已出现 且有可扫描二维码 = 真正成功 = 冻结
    if (isPaymentUIVisible()) {
      if (hasScannableQR()) {
        freezeForPayment('[验证码] ✅ 验证通过 → 支付二维码已出现,冻结!');
        return;
      }
      // 支付框出现但没有二维码 → 可能是加载中,使用渐进式重试
      if (!_captchaQrRetried) {
        _captchaQrRetried = true;
        _captchaState = 99; // 临时状态:阻止主循环重复进入 captchaCheckResult
        _qrRetryEpoch++; // 新一轮,旧计时器将失效
        const myEpoch = _qrRetryEpoch;
        const retryDelays = [500, 1500, 3000, 5000, 8000]; // 渐进重试,高峰期给更多时间
        let retryIdx = 0;

        const tryNext = () => {
          if (_rushStopped) { _captchaState = CAPTCHA_STATE.IDLE; _captchaProcessing = false; return; }
          if (_wafBlocked) { _captchaState = CAPTCHA_STATE.IDLE; _captchaProcessing = false; stopAll(); return; }
          if (_paymentFrozen) return;
          if (_qrRetryEpoch !== myEpoch) return; // 已被新一轮取代
          // 拦截器已检测到非成功结果,立即中止QR等待
          if (_lastPreviewResult && _lastPreviewResult !== 'ok') {
            log(`[QR重试] preview=${_lastPreviewResult},中止等待`);
            _lastPreviewResult = '';
            _qrRetryEpoch++; // 作废后续回调
            return;
          }
          if (retryIdx >= retryDelays.length) {
            // 所有重试都失败 → 检查是否仍在加载
            if (isPaymentLoading()) {
              log('[验证码] 支付弹窗仍在加载中,额外等待10秒...', 'warn');
              setTimeout(() => {
                if (_rushStopped) return;
                if (_paymentFrozen) return;
                if (_qrRetryEpoch !== myEpoch) return;
                if (hasScannableQR()) {
                  freezeForPayment('[验证码] ✅ 二维码延迟加载成功,冻结!');
                } else if (!CFG.autoCloseInvalid) {
                  _captchaState = CAPTCHA_STATE.IDLE;
                  setTimeout(() => { if (!_rushStopped) _captchaProcessing = false; }, 500);
                  _captchaLastBgUrl = '';
                  log('[验证码] autoCloseInvalid=false,保持弹窗不关闭,停止重试');
                } else {
                  _captchaQrRetried = false;
                  closeEmptyPayDialog();
                }
              }, 10000);
            } else if (!CFG.autoCloseInvalid) {
              _captchaState = CAPTCHA_STATE.IDLE;
              setTimeout(() => { if (!_rushStopped) _captchaProcessing = false; }, 500);
              _captchaLastBgUrl = '';
              log('[验证码] autoCloseInvalid=false,保持弹窗不关闭,停止重试');
            } else {
              _captchaQrRetried = false;
              closeEmptyPayDialog();
            }
            return;
          }

          const delay = retryDelays[retryIdx++];
          log(`[验证码] 支付弹窗出现但无二维码,${delay / 1000}秒后第${retryIdx}次复查...`);
          setTimeout(() => {
            if (_rushStopped) return;
            if (_paymentFrozen) return;
            if (_qrRetryEpoch !== myEpoch) return; // 已被新一轮取代
            if (hasScannableQR()) {
              freezeForPayment(`[验证码] ✅ 二维码在第${retryIdx}次复查时加载成功,冻结!`);
            } else if (isPaymentLoading()) {
              log(`[验证码] 第${retryIdx}次复查:仍在加载中,继续等待...`);
              tryNext();
            } else {
              tryNext();
            }
          }, delay);
        };

        tryNext();
        return;
      }
      // 兜底:已在重试流程中
      return;
    }

    // ═══ 4. 验证码容器也消失了 = 验证已结束,但没有支付弹窗 ═══
    // 先检查preview API响应码(最快判断失败原因)
    if (_lastPreviewResult && _lastPreviewResult !== 'ok') {
      const reason = _lastPreviewResult;
      _lastPreviewResult = '';
      log(`[验证码] preview返回${reason},无需等待DOM,立即重试购买`);
      _captchaAttempt = 0;
      _captchaLastBgUrl = '';
      _captchaState = CAPTCHA_STATE.IDLE;
      // 不在此解锁!让 triggerPreviewRetry 统一管理解锁时序
      if (!_previewRetryTimer) {
        triggerPreviewRetry(`preview=${reason}`);
      }
      return;
    }
    _lastPreviewResult = '';

    // 超时兜底:如果长时间既无preview响应也无支付弹窗,直接重试
    if (Date.now() - _captchaWaitStart > CFG.previewTimeout + 5000) {
      log(`[验证码] 验证后${(CFG.previewTimeout + 5000) / 1000}s无任何响应,超时重试`, 'warn');
      _captchaAttempt = 0;
      _captchaLastBgUrl = '';
      _captchaState = CAPTCHA_STATE.IDLE;
      // 不在此解锁!让 triggerPreviewRetry 统一管理解锁时序
      if (!_previewRetryTimer) {
        triggerPreviewRetry('响应超时');
      }
      return;
    }

    _captchaAttempt = 0;
    _captchaLastBgUrl = '';
    _captchaState = CAPTCHA_STATE.IDLE;

    // 再查一次支付(可能有延迟),给二维码更多加载时间
    if (isPaymentUIVisible()) {
      if (hasScannableQR()) {
        freezeForPayment('[验证码] ✅ 验证通过 → 支付弹窗已出现,冻结!');
        return;
      }
      // 弹窗出现但无二维码 → 等待加载而不是立刻关闭
      _captchaState = 99; // 阻止主循环重复进入
      _qrRetryEpoch++;
      const myEpoch4 = _qrRetryEpoch;
      log('[验证码] 支付弹窗出现但无二维码,等待8秒让QR加载...', 'warn');
      setTimeout(() => {
        if (_rushStopped) return;
        if (_paymentFrozen) return;
        if (_qrRetryEpoch !== myEpoch4) return;
        if (hasScannableQR()) {
          freezeForPayment('[验证码] ✅ 二维码延迟加载成功,冻结!');
        } else if (isPaymentLoading()) {
          log('[验证码] 支付弹窗仍在加载中,再等10秒...', 'warn');
          setTimeout(() => {
            if (_rushStopped) return;
            if (_paymentFrozen) return;
            if (_qrRetryEpoch !== myEpoch4) return;
            if (hasScannableQR()) {
              freezeForPayment('[验证码] ✅ 二维码延迟加载成功!');
            } else if (!CFG.autoCloseInvalid) {
              log('[验证码] autoCloseInvalid=false,保持弹窗不关闭,请手动处理');
            } else {
              log('[验证码] 支付弹窗长时间无二维码,关闭重试', 'warn');
              closeEmptyPayDialog();
            }
          }, 10000);
        } else if (!CFG.autoCloseInvalid) {
          _captchaState = CAPTCHA_STATE.IDLE;
          setTimeout(() => { if (!_rushStopped) _captchaProcessing = false; }, 500);
          log('[验证码] autoCloseInvalid=false,保持弹窗不关闭,请手动处理');
        } else {
          closeEmptyPayDialog();
        }
      }, 8000);
      return;
    }

    // 检查错误弹窗(人数过多、售罄等)
    const errDlg = isErrorDialogVisible();
    if (errDlg) {
      const errText = (errDlg.textContent || '').trim().substring(0, 50);
      log(`[验证码] 验证通过但购买失败: "${errText}",关闭弹窗重新购买`);
      dismissDialog(errDlg);
      document.querySelectorAll('.el-overlay, .v-modal, .el-overlay-dialog').forEach(el => el.style.display = 'none');
      document.body.style.overflow = '';
      // 延迟后重新点击购买(可能触发新一轮验证码)
      setTimeout(() => {
        if (_rushStopped) return;
        _captchaProcessing = false;
        if (_paymentFrozen) return;
        const btn = findBuyButton();
        if (btn) { btn.click(); log('[验证码] 已重新点击购买按钮'); }
      }, 1000);
      return;
    }

    // 什么都没出现 — 可能后端处理中,也可能静默失败
    log('[验证码] 验证通过,但无支付弹窗也无错误,等待后重试购买...');
    setTimeout(() => {
      if (_rushStopped) return;
      _captchaProcessing = false;
      if (_paymentFrozen) return;
      if (isPaymentUIVisible() && hasScannableQR()) { freezeForPayment('[验证码] 支付弹窗延迟出现,冻结!'); return; }
      const btn = findBuyButton();
      if (btn) { btn.click(); log('[验证码] 延迟重试: 重新点击购买按钮'); }
    }, 2000);
  }

  function setupMainPageCaptchaWatcher() {
    // 状态机主循环
    setInterval(() => {
      // ── 解冻按钮同步显示 ──
      const ufBtn = _shadowRef?.getElementById('btn-unfreeze');
      if (ufBtn) ufBtn.style.display = _paymentFrozen ? '' : 'none';

      // 铁律: 支付保护锁
      if (_paymentFrozen) {
        // 支付UI仍在 → 保持冻结,即使QR还在加载
        if (isPaymentUIVisible()) {
          // QR已出现 → 完美
          if (hasScannableQR()) return;
          // QR未加载但弹窗在 → 检查是否刚冻结(30秒内不解除)
          if (Date.now() - _frozenAt < 30000) {
            return; // 30秒内不解除,等QR加载
          }
          log('[冻结保护] 支付弹窗存在但30秒内无二维码,解除冻结', 'warn');
        }
        // 支付UI已消失 → 解除冻结
        _paymentFrozen = false;
        _frozenAt = 0;
        log('[验证码] 支付弹窗已消失,自动解除冻结');
      }

      // 支付弹窗消失时,如果还在QR重试中(状态99),自动恢复到IDLE
      if (_captchaState === 99 && !isPaymentUIVisible()) {
        _captchaState = CAPTCHA_STATE.IDLE;
        setTimeout(() => { if (!_rushStopped) _captchaProcessing = false; }, 500);
        _captchaQrRetried = false;
        _qrRetryEpoch++;
        log('[状态机] 支付弹窗已消失,退出QR重试,恢复IDLE');
      }

      switch (_captchaState) {
        case CAPTCHA_STATE.IDLE:
          if (!_rushStopped && mainPageCaptchaVisible()) {
            log('[状态机] 检测到验证码弹窗,500ms后识别');
            setTimeout(mainPageSolveCaptcha, 200);
          }
          break;
        case CAPTCHA_STATE.WAITING:
          captchaCheckResult();
          break;
      }
    }, 1500);

    // MutationObserver 快速响应
    const observer = new MutationObserver(() => {
      // 冻结恢复:无论是否激活都处理
      if (_paymentFrozen) {
        if (isPaymentUIVisible()) return;
        _paymentFrozen = false;
        _frozenAt = 0;
        log('[Observer] 支付弹窗已消失,解除冻结');
      }
      // QR重试中(状态99)且支付弹窗消失 → 恢复IDLE
      if (_captchaState === 99 && !isPaymentUIVisible()) {
        _captchaState = CAPTCHA_STATE.IDLE;
        setTimeout(() => { if (!_rushStopped) _captchaProcessing = false; }, 500);
        _captchaQrRetried = false;
        _qrRetryEpoch++;
        log('[Observer] 支付弹窗已消失,退出QR重试,恢复IDLE');
      }
      // 验证码识别:停止后不自动处理,刷新恢复
      if (!_rushStopped && _captchaState === CAPTCHA_STATE.IDLE && mainPageCaptchaVisible()) {
        setTimeout(mainPageSolveCaptcha, 200);
      }
    });
    observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });

    log('[主页面验证码] 验证码+购买状态机已启动 (v1.0.0)');
  }

  console.log('[glm_bypass] userscript v1.0.0 注入成功');
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => { createPanel(); setupMainPageCaptchaWatcher(); });
  } else {
    createPanel();
    setupMainPageCaptchaWatcher();
  }
})();