自動點擊生成 (Grok Imagine) v1.9

自動點擊生成影片按鈕,有使用者介面可調整閾值。

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         自動點擊生成 (Grok Imagine) v1.9
// @namespace    http://tampermonkey.net/
// @version      1.9
// @description  自動點擊生成影片按鈕,有使用者介面可調整閾值。
// @match        https://grok.com/*
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    // === 設定 ===
    const targetClassString = 'text-xs font-semibold w-[4ch] mb-[1px]';
    const selector = `div[class="${targetClassString}"]`;

    let lastValue = null;
    let wasPresent = false;
    let autoMode = true;
    let threshold = 30;
    let playBeepOnLow = true;
    let playBeepOnLimit = true;
    let beepVolume = 0.005;
    let limitAlertShown = false;
    let persistentSuccessNotify = false; // 新增: 成功後持續通知

    let zeroCount = 0;
    let consecutiveRetries = 0;
    let maxRetriesAlertShown = false; // 新增:記錄是否已經顯示過最大重試次數警報
    const zeroThreshold = 20; // seconds
    const checkInterval = 500; // ms
    const zeroMaxCount = Math.floor(zeroThreshold * 1000 / checkInterval);
    const maxConsecutiveRetries = 3; // 最多重試次數

    let worker = null;

    // 生成統計
    let stats = { total: 0, success: 0, fail: 0 };

    // === 輔助函式 ===
    function getTimeString() {
        const now = new Date();
        const pad = n => n.toString().padStart(2, '0');
        return `[${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}:${pad(now.getSeconds())}]`;
    }

    function parseNumber(text) {
        if (!text) return null;
        const match = text.match(/-?\d+(\.\d+)?/);
        return match ? parseFloat(match[0]) : null;
    }

    function beepTriple(frequency = 880, duration = 0.1, volume = beepVolume) {
        try {
            const ctx = new (window.AudioContext || window.webkitAudioContext)();
            const playBeep = () => {
                const oscillator = ctx.createOscillator();
                const gain = ctx.createGain();
                oscillator.connect(gain);
                gain.connect(ctx.destination);
                oscillator.type = 'square';
                oscillator.frequency.value = frequency;
                gain.gain.value = volume;
                oscillator.start();
                oscillator.stop(ctx.currentTime + duration);
            };
            playBeep();
            setTimeout(playBeep, duration * 1000 + 100);
            setTimeout(playBeep, 2 * (duration * 1000 + 100));
        } catch (e) {
            console.log(getTimeString(), '無法播放聲音:', e);
        }
    }

    function playCmaj7Arpeggio(volume = beepVolume, duration = 0.25) {
        try {
            const ctx = new (window.AudioContext || window.webkitAudioContext)();
            const d = 48;
            const notes = [16.35 * d, 20.6 * d, 24.5 * d, 30.87 * d]; // C, E, G, B
            notes.forEach((freq, i) => {
                const osc = ctx.createOscillator();
                const gain = ctx.createGain();
                osc.connect(gain);
                gain.connect(ctx.destination);
                osc.type = 'triangle';
                osc.frequency.value = freq;
                gain.gain.setValueAtTime(volume, ctx.currentTime + i * duration);
                osc.start(ctx.currentTime + i * duration);
                osc.stop(ctx.currentTime + (i + 1) * duration);
            });
        } catch (e) {
            console.log(getTimeString(), '無法播放 arpeggio:', e);
        }
    }

    // === 控制面板 ===
    function createControlPanel() {
        if (window.__grokImaginePanel) return window.__grokImaginePanel.querySelector('#grok-console');

        const panel = document.createElement('div');
        panel.style.position = 'fixed';
        panel.style.top = '80px';
        panel.style.right = '10px';
        panel.style.zIndex = '99999';
        panel.style.background = 'rgba(30,30,30,0.9)';
        panel.style.color = '#fff';
        panel.style.padding = '10px 12px';
        panel.style.borderRadius = '10px';
        panel.style.fontSize = '14px';
        panel.style.fontFamily = 'monospace';
        panel.style.boxShadow = '0 4px 12px rgba(0,0,0,0.6)';
        panel.style.backdropFilter = 'blur(5px)';
        panel.style.width = '360px';
        panel.style.maxHeight = '520px';
        panel.style.display = 'flex';
        panel.style.flexDirection = 'column';
        panel.style.pointerEvents = 'auto';
        panel.style.userSelect = 'none';

        // Header (用作拖曳)
        const header = document.createElement('div');
        header.style.display = 'flex';
        header.style.justifyContent = 'space-between';
        header.style.alignItems = 'center';
        header.style.cursor = 'move';
        header.style.marginBottom = '6px';
        header.style.gap = '8px';

        const title = document.createElement('div');
        title.style.fontWeight = 'bold';
        title.textContent = 'Grok 檢查控制';
        header.appendChild(title);

        // buttons group (minimize)
        const btnGroup = document.createElement('div');
        btnGroup.style.display = 'flex';
        btnGroup.style.alignItems = 'center';
        btnGroup.style.gap = '6px';

        const minimizeBtn = document.createElement('button');
        minimizeBtn.textContent = '-';
        minimizeBtn.title = '縮小/展開';
        minimizeBtn.style.background = 'transparent';
        minimizeBtn.style.border = 'none';
        minimizeBtn.style.color = '#fff';
        minimizeBtn.style.fontSize = '18px';
        minimizeBtn.style.cursor = 'pointer';
        minimizeBtn.style.padding = '0 6px';
        btnGroup.appendChild(minimizeBtn);

        header.appendChild(btnGroup);
        panel.appendChild(header);

        // 內容區塊(可縮放)
        const content = document.createElement('div');
        content.style.display = 'flex';
        content.style.flexDirection = 'column';
        content.style.gap = '6px';
        content.style.flex = '1';
        content.style.overflow = 'hidden';

        // Controls HTML (用 JS 建)
        const rowAuto = document.createElement('div');
        rowAuto.style.display = 'flex';
        rowAuto.style.alignItems = 'center';
        rowAuto.innerHTML = `<label style="display:flex;align-items:center;gap:6px;"><input type="checkbox" id="autoModeToggle" checked /> 自動模式</label>`;
        content.appendChild(rowAuto);

        const rowThreshold = document.createElement('div');
        rowThreshold.style.display = 'flex';
        rowThreshold.style.alignItems = 'center';
        rowThreshold.style.gap = '8px';
        rowThreshold.style.marginBottom = '2px';
        rowThreshold.innerHTML = `閥值(%):`;
        const thresholdInput = document.createElement('input');
        thresholdInput.type = 'number';
        thresholdInput.id = 'thresholdInput';
        thresholdInput.value = threshold;
        thresholdInput.min = 0;
        thresholdInput.max = 100;
        thresholdInput.step = 1;
        thresholdInput.style.width = '60px';
        thresholdInput.style.padding = '4px';
        thresholdInput.style.borderRadius = '4px';
        thresholdInput.style.border = 'none';
        thresholdInput.style.textAlign = 'center';

        const thresholdSlider = document.createElement('input');
        thresholdSlider.type = 'range';
        thresholdSlider.id = 'thresholdSlider';
        thresholdSlider.min = 0;
        thresholdSlider.max = 100;
        thresholdSlider.step = 1;
        thresholdSlider.value = threshold;
        thresholdSlider.style.flex = '1';

        rowThreshold.appendChild(thresholdInput);
        rowThreshold.appendChild(thresholdSlider);
        content.appendChild(rowThreshold);

        const rowBeep = document.createElement('div');
        rowBeep.style.display = 'flex';
        rowBeep.style.alignItems = 'center';
        rowBeep.innerHTML = `<label style="display:flex;align-items:center;gap:6px;"><input type="checkbox" id="beepToggle" checked /> 低於閾值播放音效</label>`;
        content.appendChild(rowBeep);

    const rowLimit = document.createElement('div');
    rowLimit.style.display = 'flex';
    rowLimit.style.alignItems = 'center';
    rowLimit.innerHTML = `<label style="display:flex;align-items:center;gap:6px;"><input type="checkbox" id="limitToggle" checked /> 額度用完提醒音效</label>`;
    content.appendChild(rowLimit);

    // 新增: 成功後持續通知勾選盒
    const rowPersistentSuccess = document.createElement('div');
    rowPersistentSuccess.style.display = 'flex';
    rowPersistentSuccess.style.alignItems = 'center';
    rowPersistentSuccess.innerHTML = `<label style="display:flex;align-items:center;gap:6px;"><input type="checkbox" id="persistentSuccessToggle" /> 成功後持續通知</label>`;
    content.appendChild(rowPersistentSuccess);

        // 音量 row 改百分比顯示
        const rowVolume = document.createElement('div');
        rowVolume.style.display = 'flex';
        rowVolume.style.alignItems = 'center';
        rowVolume.style.gap = '8px';
        rowVolume.innerHTML = `音量:`;
        const volumeSlider = document.createElement('input');
        volumeSlider.type = 'range';
        volumeSlider.id = 'volumeSlider';
        volumeSlider.min = 0;
        volumeSlider.max = 0.05;
        volumeSlider.step = 0.001;
        volumeSlider.value = beepVolume;
        volumeSlider.style.flex = '1';
        const volumeDisplay = document.createElement('span');
        volumeDisplay.id = 'volumeDisplay';
        volumeDisplay.textContent = Math.round(beepVolume / 0.05 * 100) + '%';
        rowVolume.appendChild(volumeSlider);
        rowVolume.appendChild(volumeDisplay);
        content.appendChild(rowVolume);

        // 統計顯示
        const statTitle = document.createElement('div');
        statTitle.style.fontWeight = 'bold';
        statTitle.textContent = '生成統計';
        content.appendChild(statTitle);

        const statRow = document.createElement('div');
        statRow.style.display = 'flex';
        statRow.style.gap = '10px';
        statRow.style.fontSize = '13px';
        statRow.innerHTML = `<span id="statTotal">總生成: 0</span><span id="statSuccess">成功: 0</span><span id="statFail">失敗: 0</span>`;
        content.appendChild(statRow);

        // console box
        const consoleBox = document.createElement('div');
        consoleBox.id = 'grok-console';
        consoleBox.style.flex = '1';
        consoleBox.style.background = 'rgba(0,0,0,0.28)';
        consoleBox.style.padding = '6px';
        consoleBox.style.borderRadius = '6px';
        consoleBox.style.overflowY = 'auto';
        consoleBox.style.fontSize = '12px';
        consoleBox.style.lineHeight = '1.4';
        consoleBox.style.whiteSpace = 'pre-wrap';
        consoleBox.style.minHeight = '120px';
        consoleBox.style.maxHeight = '250px'; // ⚡ 防止擠壓按鈕
        content.appendChild(consoleBox);

        // 按鈕列
        const btnRow = document.createElement('div');
        btnRow.style.display = 'flex';
        btnRow.style.gap = '8px';
        btnRow.style.marginTop = '6px';
        btnRow.style.justifyContent = 'flex-start';

        // 清空紀錄
        const clearBtn = document.createElement('button');
        clearBtn.textContent = '🧹 清空紀錄';
        clearBtn.style.background = 'rgba(255,255,255,0.06)';
        clearBtn.style.border = 'none';
        clearBtn.style.color = '#ccc';
        clearBtn.style.padding = '6px 10px';
        clearBtn.style.borderRadius = '6px';
        clearBtn.style.cursor = 'pointer';
        clearBtn.addEventListener('mouseenter', () => clearBtn.style.color = '#fff');
        clearBtn.addEventListener('mouseleave', () => clearBtn.style.color = '#ccc');
        clearBtn.addEventListener('click', () => {
            consoleBox.innerHTML = '';
            stats = { total: 0, success: 0, fail: 0 };
            if (window.__grokImaginePanel && window.__grokImaginePanel._updateStatsDisplay)
                window.__grokImaginePanel._updateStatsDisplay();
        });

        // 複製記錄
        const copyBtn = document.createElement('button');
        copyBtn.textContent = '📋 複製記錄';
        copyBtn.style.background = 'rgba(50,50,255,0.8)';
        copyBtn.style.border = 'none';
        copyBtn.style.color = '#fff';
        copyBtn.style.padding = '6px 10px';
        copyBtn.style.borderRadius = '6px';
        copyBtn.style.cursor = 'pointer';
        copyBtn.addEventListener('mouseenter', () => copyBtn.style.opacity = '0.85');
        copyBtn.addEventListener('mouseleave', () => copyBtn.style.opacity = '1');
        copyBtn.addEventListener('click', async () => {
            try {
                const text = consoleBox.innerText || '';
                const summary = `生成統計:總生成: ${stats.total},成功: ${stats.success},失敗: ${stats.fail}`;
                const finalText = text.trim() ? text + '\n\n' + summary : summary;
                await navigator.clipboard.writeText(finalText);
                console.log(`${getTimeString()} 已複製 console 記錄到剪貼簿`);
                console.log(summary);
            } catch (e) { console.log(`${getTimeString()} 複製失敗:`, e); }
        });

        // 登出按鈕
        const logoutBtn = document.createElement('button');
        logoutBtn.textContent = '🚪 登出';
        logoutBtn.style.background = 'rgba(255,50,50,0.8)';
        logoutBtn.style.border = 'none';
        logoutBtn.style.color = '#fff';
        logoutBtn.style.padding = '6px 10px';
        logoutBtn.style.borderRadius = '6px';
        logoutBtn.style.cursor = 'pointer';
        logoutBtn.addEventListener('mouseenter', () => logoutBtn.style.opacity = '0.85');
        logoutBtn.addEventListener('mouseleave', () => logoutBtn.style.opacity = '1');
        logoutBtn.addEventListener('click', tryLogout);

        btnRow.appendChild(clearBtn);
        btnRow.appendChild(copyBtn);
        btnRow.appendChild(logoutBtn);
        content.appendChild(btnRow);

        panel.appendChild(content);
        document.body.appendChild(panel);
        window.__grokImaginePanel = panel;

        // 變數綁定
    const autoModeToggle = panel.querySelector('#autoModeToggle');
    const thresholdInputEl = thresholdInput;
    const thresholdSliderEl = thresholdSlider;
    const beepToggle = panel.querySelector('#beepToggle');
    const limitToggle = panel.querySelector('#limitToggle');
    const persistentSuccessToggle = panel.querySelector('#persistentSuccessToggle');
    const volumeSliderEl = volumeSlider;
    const volumeDisplayEl = volumeDisplay;

        // hook console
        hookConsole(consoleBox);

        // 同步事件綁定
        autoModeToggle.addEventListener('change', () => { autoMode = autoModeToggle.checked; console.log(`${getTimeString()} 自動模式: ${autoMode ? '啟用' : '停用'}`); });

        thresholdInputEl.addEventListener('input', () => {
            let val = parseFloat(thresholdInputEl.value);
            if (isNaN(val)) val = 0;
            threshold = Math.min(Math.max(val, 0), 100);
            thresholdSliderEl.value = threshold;
        });
        thresholdSliderEl.addEventListener('input', () => {
            threshold = parseFloat(thresholdSliderEl.value);
            thresholdInputEl.value = threshold;
        });

    beepToggle.addEventListener('change', () => { playBeepOnLow = beepToggle.checked; });
    limitToggle.addEventListener('change', () => { playBeepOnLimit = limitToggle.checked; });
    persistentSuccessToggle.addEventListener('change', () => { persistentSuccessNotify = persistentSuccessToggle.checked; });

        volumeSliderEl.addEventListener('input', () => {
            beepVolume = parseFloat(volumeSliderEl.value);
            const percent = Math.round(beepVolume / 0.05 * 100);
            volumeDisplayEl.textContent = percent + '%';
        });

        function updateStatsDisplay() {
            const totalEl = panel.querySelector('#statTotal');
            const successEl = panel.querySelector('#statSuccess');
            const failEl = panel.querySelector('#statFail');
            if (totalEl) totalEl.textContent = `總生成: ${stats.total}`;
            if (successEl) successEl.textContent = `成功: ${stats.success}`;
            if (failEl) failEl.textContent = `失敗: ${stats.fail}`;
        }
        panel._updateStatsDisplay = updateStatsDisplay;

        // 拖曳功能 (保持在視窗內)
        let isDragging = false, offsetX = 0, offsetY = 0;
        header.addEventListener('mousedown', e => {
            isDragging = true;
            const rect = panel.getBoundingClientRect();
            offsetX = e.clientX - rect.left;
            offsetY = e.clientY - rect.top;
            panel.style.transition = 'none';
            document.body.style.userSelect = 'none';
        });
        document.addEventListener('mousemove', e => {
            if (!isDragging) return;
            let newLeft = e.clientX - offsetX;
            let newTop = e.clientY - offsetY;
            newLeft = Math.min(Math.max(newLeft, 0), window.innerWidth - panel.offsetWidth);
            newTop = Math.min(Math.max(newTop, 0), window.innerHeight - panel.offsetHeight);
            panel.style.left = newLeft + 'px';
            panel.style.top = newTop + 'px';
            panel.style.right = 'auto';
        });
        document.addEventListener('mouseup', () => {
            if (!isDragging) return;
            isDragging = false;
            panel.style.transition = '';
            document.body.style.userSelect = '';
        });

        // 縮小/展開
        let minimized = false;
        minimizeBtn.addEventListener('click', () => {
            minimized = !minimized;
            content.style.display = minimized ? 'none' : 'flex';
            minimizeBtn.textContent = minimized ? '+' : '-';
        });

        return consoleBox;
    }

    function hookConsole(consoleBox) {
        const originalLog = console.log;
        console.log = (...args) => {
            try {
                originalLog.apply(console, args);
                const msg = args.map(a => (typeof a === 'object' ? JSON.stringify(a) : String(a))).join(' ');
                const entry = document.createElement('div');
                if (msg.includes('成功')) entry.style.color = '#6eff9f';
                else if (msg.includes('失敗')) entry.style.color = '#ff7b7b';
                else entry.style.color = '#ffd966';
                entry.textContent = msg;
                consoleBox.appendChild(entry);
                consoleBox.scrollTop = consoleBox.scrollHeight;
            } catch (e) { originalLog('hookConsole error:', e); }
        };
    }

    // === 檢查邏輯 ===
    // 新增: 持續音效控制
    let persistentBeepInterval = null;
    function startPersistentBeep() {
        if (persistentBeepInterval) return;
        // 立即播放第一次
        playCmaj7Arpeggio(beepVolume);
        // 然後開始間隔播放
        persistentBeepInterval = setInterval(() => {
            playCmaj7Arpeggio(beepVolume);
        }, 2000); // 每2秒持續播放
    }
    function stopPersistentBeep() {
        if (persistentBeepInterval) {
            clearInterval(persistentBeepInterval);
            persistentBeepInterval = null;
        }
    }

    function showPersistentSuccessBox() {
        // 若已存在則不重複顯示
        if (document.getElementById('persistent-success-msgbox')) return;
        const box = document.createElement('div');
        box.id = 'persistent-success-msgbox';
        box.style.position = 'fixed';
        box.style.top = '50%';
        box.style.left = '50%';
        box.style.transform = 'translate(-50%, -50%)';
        box.style.zIndex = '100000';
        box.style.background = 'rgba(40,40,40,0.98)';
        box.style.color = '#fff';
        box.style.padding = '32px 36px';
        box.style.borderRadius = '16px';
        box.style.fontSize = '20px';
        box.style.fontFamily = 'monospace';
        box.style.boxShadow = '0 8px 32px rgba(0,0,0,0.7)';
        box.style.textAlign = 'center';
        box.innerHTML = `<div style="margin-bottom:18px;">成功提示!</div><button id="persistent-success-confirm" style="font-size:18px;padding:8px 24px;border-radius:8px;background:#6eff9f;color:#222;border:none;cursor:pointer;">停止</button>`;
        document.body.appendChild(box);
        const btn = box.querySelector('#persistent-success-confirm');
        btn.addEventListener('click', () => {
            stopPersistentBeep();
            box.remove();
        });
    }

    function check() {
        try {
            const upgradeElem = document.querySelector('span.text-secondary.font-medium');
            if (upgradeElem && upgradeElem.textContent.includes('Upgrade to unlock more')) {
                if (!limitAlertShown) {
                    limitAlertShown = true;
                    console.log(`${getTimeString()} 額度已用完!`);
                    if (playBeepOnLimit) beepTriple(440, 0.15);
                }
            } else { limitAlertShown = false; }

            const elem = document.querySelector(selector);
            if (elem) {
                wasPresent = true;
                const val = parseNumber(elem.textContent.trim());
                if (!isNaN(val)) lastValue = val;

                if (val === 0) {
                    zeroCount++;
                    if (zeroCount >= zeroMaxCount && autoMode) {
                        if (consecutiveRetries >= maxConsecutiveRetries) {
                            if (!maxRetriesAlertShown) {
                                console.log(`${getTimeString()} 已連續重試${consecutiveRetries}次仍卡在0%,停止自動重試`);
                                if (playBeepOnLimit) beepTriple(440, 0.15); // 播放提示音
                                maxRetriesAlertShown = true; // 標記已經顯示過警報
                            }
                            return;
                        }
                        const button = document.querySelector('button.bg-button-filled.inline-flex'); // 生成按鈕
                        if (button) { 
                            button.click(); 
                            console.log(`${getTimeString()} 長時間為0,已再次點擊生成按鈕 (第${consecutiveRetries + 1}次重試)`);
                            consecutiveRetries++;
                        }
                        else { console.log(`${getTimeString()} 長時間為0,但找不到生成按鈕`); }
                        zeroCount = 0;
                    }
                } else { 
                    zeroCount = 0;
                    consecutiveRetries = 0; // 當進度不為0時重置重試計數
                    maxRetriesAlertShown = false; // 重置警報標記
                }

            } else if (wasPresent) {
                wasPresent = false;
                stats.total++;
                const container = document.querySelector('div.relative.mx-auto.rounded-2xl.overflow-hidden');
                const progress = lastValue !== null ? `${lastValue}%` : "未知";
                let success = false;
                if (container) {
                    const grid = container.querySelector('div.grid');
                    if (grid && grid.querySelector('video#sd-video')) {
                        console.log(`${getTimeString()} 生成成功 (進度: ${progress})`);
                        success = true;
                        stats.success++;
                        if (persistentSuccessNotify) {
                            showPersistentSuccessBox();
                            startPersistentBeep();
                        } else {
                            playCmaj7Arpeggio(beepVolume);
                        }

                        // ===== 新增功能:生成成功後 10 秒內檢測 Content Moderated =====
                        const moderationCheckTime = 15000; // 10 秒
                        setTimeout(() => {
                            const moderatedElem = container.querySelector('span');
                            if (moderatedElem && moderatedElem.textContent.includes('Content Moderated. Try a different idea.')) {
                                const button = document.querySelector('button[aria-label="製作影片"]');
                                if (button) {
                                    button.click();
                                    console.log(`${getTimeString()} 生成成功後 15 秒檢測到 Content Moderated,自動再次點擊生成按鈕`);
                                } else {
                                    console.log(`${getTimeString()} 生成成功後 15 秒檢測到 Content Moderated,但找不到生成按鈕`);
                                }
                            }
                        }, moderationCheckTime);
                        // ===== End 新增功能 =====

                    }
                }
                if (!success) {
                    console.log(`${getTimeString()} 生成失敗 (進度: ${progress})`);
                    stats.fail++;
                    if (lastValue !== null && lastValue < threshold && playBeepOnLow) beepTriple();
                    if (autoMode && lastValue !== null && lastValue >= threshold) {
                        const button = document.querySelector('button.bg-button-filled.inline-flex'); // 生成按鈕
                        if (button) { button.click(); console.log(`${getTimeString()} 自動模式: 已重新點擊生成按鈕`); }
                        else { console.log(`${getTimeString()} 找不到生成按鈕,無法自動重新生成`); }
                    }
                }
                if (window.__grokImaginePanel && window.__grokImaginePanel._updateStatsDisplay) window.__grokImaginePanel._updateStatsDisplay();
                lastValue = null;
            }
        } catch (e) { console.log(getTimeString(), 'check() 發生錯誤:', e); }
    }

    function tryLogout() {
        const attemptLogout = () => {
            const sidebar = document.querySelector('div[data-variant="sidebar"][data-side="left"]');
            if (sidebar && sidebar.getAttribute('data-state') === 'expanded') {
                const triggerBtn = document.querySelector('button[data-sidebar="trigger"]');
                if (triggerBtn) { triggerBtn.click(); setTimeout(attemptLogout, 300); return; }
            }
            const trigger = document.querySelector('button[id^="radix-"][aria-haspopup="menu"]');
            if (trigger) {
                ['pointerdown','mousedown','mouseup','pointerup','click'].forEach(type => trigger.dispatchEvent(new MouseEvent(type,{bubbles:true,cancelable:true,view:window})));
                setTimeout(() => {
                    const allItems = document.querySelectorAll('div[role="menuitem"].flex.cursor-pointer');
                    const logoutBtn = allItems[allItems.length - 1]; // 通常登出是最後一個

                    if (logoutBtn) {
                        ['pointerdown','mousedown','mouseup','pointerup','click'].forEach(type =>
                            logoutBtn.dispatchEvent(new MouseEvent(type, { bubbles: true, cancelable: true, view: window }))
                        );
                        console.log('✅ 已嘗試點擊登出');
                    } else {
                        console.log('⚠️ 找不到登出');
                        setTimeout(attemptLogout, 1000);
                    }
                }, 500);
            } else setTimeout(attemptLogout,1000);
        };
        attemptLogout();
    }

    function startChecker() {
        if (worker) return;
        const workerCode = `setInterval(()=>postMessage('tick'), ${checkInterval});`;
        const blob = new Blob([workerCode], { type: 'application/javascript' });
        worker = new Worker(URL.createObjectURL(blob));
        worker.onmessage = () => check();
    }

    function stopChecker() { if(worker) { worker.terminate(); worker = null; } }

    function isImaginePage() { return location.pathname.startsWith('/imagine/'); }

    function handlePageChange() {
        if (isImaginePage()) { if(window.__grokImaginePanel) window.__grokImaginePanel.style.display='flex'; startChecker(); }
        else { if(window.__grokImaginePanel) window.__grokImaginePanel.style.display='none'; stopChecker(); }
    }

    const consoleBox = createControlPanel();
    handlePageChange();

    let lastPath = location.pathname;
    const observer = new MutationObserver(()=>{ if(location.pathname !== lastPath){ lastPath = location.pathname; handlePageChange(); }});

observer.observe(document, {subtree:true, childList:true});

document.addEventListener('visibilitychange',()=>{ if(!document.hidden) check(); });

})();