公益酒馆ComfyUI插图脚本 (WebSocket实时版 - 终极优化版)

移除轮询,使用WebSocket实时接收生成结果。IndexedDB无限容量缓存、自动暗黑模式、双指缩放、GPU硬件加速、requestIdleCallback非阻塞压缩、防抖节流性能优化、LRU智能淘汰、生成历史管理等完整功能。全新UI设计。

// ==UserScript==
// @name         公益酒馆ComfyUI插图脚本 (WebSocket实时版 - 终极优化版)
// @namespace    http://tampermonkey.net/
// @version      40.1 // UI优化:全新配色方案,深色渐变主题,蓝色科技风,增强交互动效
// @license      GPL
// @description  移除轮询,使用WebSocket实时接收生成结果。IndexedDB无限容量缓存、自动暗黑模式、双指缩放、GPU硬件加速、requestIdleCallback非阻塞压缩、防抖节流性能优化、LRU智能淘汰、生成历史管理等完整功能。全新UI设计。
// @author       feng zheng (升级 by Gemini, 终极优化 by Claude)
// @match        *://*/*
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @require      https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.7.5/socket.io.min.js
// @require      https://code.jquery.com/ui/1.13.2/jquery-ui.min.js
// ==/UserScript==

(function() {
    'use strict';

    // --- Configuration Constants ---
    const BUTTON_ID = 'comfyui-launcher-button';
    const PANEL_ID = 'comfyui-panel';
    const STORAGE_KEY_IMAGES = 'comfyui_generated_images';
    const STORAGE_KEY_PROMPT_PREFIX = 'comfyui_prompt_prefix';
    const STORAGE_KEY_MAX_WIDTH = 'comfyui_image_max_width';
    const STORAGE_KEY_CACHE_LIMIT = 'comfyui_cache_limit';
    const COOLDOWN_DURATION_MS = 60000;
    const CONFIG_VERSION = '2.0';
    const ENCRYPTION_KEY = 42; // 简单的XOR密钥

    // --- Notification Manager ---
    function showNotification(message, type = 'info', level = 'standard') {
        if (typeof toastr === 'undefined') return;

        const userLevel = cachedSettings.notificationLevel;

        // silent: 只显示错误
        // standard: 显示成功和错误
        // verbose: 显示所有

        if (userLevel === 'silent' && type !== 'error') return;
        if (userLevel === 'standard' && type === 'info') return;

        toastr[type](message);
    }

    // --- Security and Utility Functions ---
    function encryptApiKey(key) {
        if (!key) return '';
        try {
            return btoa(key.split('').map(c => String.fromCharCode(c.charCodeAt(0) ^ ENCRYPTION_KEY)).join(''));
        } catch (e) {
            console.error('API密钥加密失败:', e);
            return key;
        }
    }

    function decryptApiKey(encryptedKey) {
        if (!encryptedKey) return '';
        try {
            return atob(encryptedKey).split('').map(c => String.fromCharCode(c.charCodeAt(0) ^ ENCRYPTION_KEY)).join('');
        } catch (e) {
            console.error('API密钥解密失败:', e);
            return encryptedKey;
        }
    }

    function sanitizePrompt(prompt) {
        if (!prompt || typeof prompt !== 'string') return '';

        // 创建临时div元素进行HTML转义
        const div = document.createElement('div');
        div.textContent = prompt;

        return div.innerHTML
            .replace(/[<>]/g, '') // 移除尖括号
            .replace(/javascript:/gi, '') // 移除javascript:协议
            .replace(/on\w+\s*=/gi, '') // 移除事件处理器
            .trim();
    }

    function validateUrl(url) {
        if (!url || typeof url !== 'string') return false;
        try {
            const urlObj = new URL(url);
            // 强制要求HTTPS(除了localhost)
            if (urlObj.hostname !== 'localhost' && urlObj.hostname !== '127.0.0.1' && urlObj.protocol !== 'https:') {
                return false;
            }
            return ['http:', 'https:'].includes(urlObj.protocol);
        } catch (e) {
            return false;
        }
    }

    function validateConfig(config) {
        const errors = [];

        if (!config.comfyuiUrl || typeof config.comfyuiUrl !== 'string') {
            errors.push('调度器URL无效');
        } else if (!validateUrl(config.comfyuiUrl)) {
            errors.push('调度器URL格式错误或不安全');
        }

        if (config.maxWidth && (typeof config.maxWidth !== 'number' || config.maxWidth < 100 || config.maxWidth > 2000)) {
            errors.push('图片最大宽度必须在100-2000像素之间');
        }

        if (config.cacheLimit && (typeof config.cacheLimit !== 'number' || config.cacheLimit < 1 || config.cacheLimit > 100)) {
            errors.push('缓存限制必须在1-100之间');
        }

        return errors;
    }

    // --- Error Handling Classes ---
    class ComfyUIError extends Error {
        constructor(message, type = 'UNKNOWN', details = {}) {
            super(message);
            this.name = 'ComfyUIError';
            this.type = type;
            this.details = details;
            this.timestamp = Date.now();
        }
    }

    class ErrorHandler {
        static handle(error, context = '') {
            const errorLog = {
                message: error.message || '未知错误',
                type: error.type || 'UNKNOWN',
                context,
                timestamp: error.timestamp || Date.now(),
                stack: error.stack
            };

            console.error('[ComfyUI Error]', errorLog);

            const userMessage = this.getUserFriendlyMessage(error.type, error.message);
            if (typeof toastr !== 'undefined') {
                toastr.error(userMessage);
            }

            return errorLog;
        }

        static getUserFriendlyMessage(type, originalMessage) {
            const messages = {
                'NETWORK': '网络连接失败,请检查网络连接和服务器状态',
                'AUTH': '身份验证失败,请检查API密钥是否正确',
                'GENERATION': '图片生成失败,请稍后重试',
                'CONFIG': '配置错误,请检查设置',
                'VALIDATION': '输入验证失败,请检查输入内容',
                'CACHE': '缓存操作失败',
                'WEBSOCKET': 'WebSocket连接失败,将尝试重新连接'
            };

            return messages[type] || originalMessage || '操作失败,请重试';
        }
    }

    // --- Smart Reconnection System ---
    class SmartReconnector {
        constructor(getWsUrl, onConnect, onDisconnect) {
            this.getWsUrl = getWsUrl;
            this.onConnect = onConnect;
            this.onDisconnect = onDisconnect;
            this.reconnectAttempts = 0;
            this.maxAttempts = 10;
            this.baseDelay = 1000;
            this.maxDelay = 30000;
            this.isOnline = navigator.onLine;
            this.setupNetworkMonitoring();
        }

        setupNetworkMonitoring() {
            window.addEventListener('online', () => {
                this.isOnline = true;
                if (typeof toastr !== 'undefined') {
                    toastr.success('网络连接已恢复,正在重新连接...');
                }
                this.reconnect();
            });

            window.addEventListener('offline', () => {
                this.isOnline = false;
                if (typeof toastr !== 'undefined') {
                    toastr.warning('网络连接已断开,将在恢复后自动重连');
                }
                this.onDisconnect();
            });
        }

        async reconnect() {
            if (!this.isOnline) {
                console.log('网络离线,暂停重连尝试');
                return false;
            }

            if (this.reconnectAttempts >= this.maxAttempts) {
                this.showPermanentDisconnectionNotice();
                return false;
            }

            const delay = Math.min(
                this.baseDelay * Math.pow(2, this.reconnectAttempts),
                this.maxDelay
            );

            console.log(`尝试重连 (${this.reconnectAttempts + 1}/${this.maxAttempts}),延迟 ${delay}ms`);

            await this.wait(delay);

            try {
                await this.attemptConnection();
                this.reconnectAttempts = 0;
                if (typeof toastr !== 'undefined') {
                    toastr.success('WebSocket连接已恢复!');
                }
                return true;
            } catch (error) {
                this.reconnectAttempts++;
                console.warn(`重连失败 (${this.reconnectAttempts}/${this.maxAttempts}):`, error.message);
                return this.reconnect();
            }
        }

        async attemptConnection() {
            return new Promise((resolve, reject) => {
                try {
                    const wsUrl = this.getWsUrl();
                    if (!wsUrl) {
                        throw new ComfyUIError('WebSocket URL未配置', 'CONFIG');
                    }

                    const testSocket = io(wsUrl, {
                        timeout: 5000,
                        reconnection: false
                    });

                    const connectTimeout = setTimeout(() => {
                        testSocket.disconnect();
                        reject(new ComfyUIError('连接超时', 'WEBSOCKET'));
                    }, 5000);

                    testSocket.on('connect', () => {
                        clearTimeout(connectTimeout);
                        testSocket.disconnect();
                        this.onConnect();
                        resolve();
                    });

                    testSocket.on('connect_error', (error) => {
                        clearTimeout(connectTimeout);
                        reject(new ComfyUIError('连接失败: ' + error.message, 'WEBSOCKET'));
                    });

                } catch (error) {
                    reject(new ComfyUIError('连接尝试失败: ' + error.message, 'WEBSOCKET'));
                }
            });
        }

        wait(ms) {
            return new Promise(resolve => setTimeout(resolve, ms));
        }

        showPermanentDisconnectionNotice() {
            if (typeof toastr !== 'undefined') {
                toastr.error('无法连接到服务器,请检查网络和服务器状态');
            }

            // 在UI中显示离线提示
            this.showOfflineNotice();
        }

        showOfflineNotice() {
            // 移除现有的离线提示
            const existingNotice = document.querySelector('.comfy-offline-notice');
            if (existingNotice) {
                existingNotice.remove();
            }

            const notice = document.createElement('div');
            notice.className = 'comfy-offline-notice';
            notice.innerHTML = `
                <i class="fa fa-wifi-slash"></i>
                <span>连接断开,仅显示缓存内容</span>
                <button class="retry-connection">重试连接</button>
            `;

            notice.querySelector('.retry-connection').addEventListener('click', () => {
                notice.remove();
                this.reconnectAttempts = 0;
                this.reconnect();
            });

            document.body.appendChild(notice);
        }

        reset() {
            this.reconnectAttempts = 0;
        }
    }

    // --- Performance Monitor ---
    class PerformanceMonitor {
        constructor() {
            this.metrics = {};
            this.memoryCheckInterval = null;
        }

        startTimer(operation) {
            this.metrics[operation] = performance.now();
        }

        endTimer(operation) {
            if (this.metrics[operation]) {
                const duration = performance.now() - this.metrics[operation];
                console.log(`[Performance] ${operation}: ${duration.toFixed(2)}ms`);
                delete this.metrics[operation];
                return duration;
            }
            return 0;
        }

        trackMemoryUsage() {
            if (performance.memory) {
                const usage = {
                    used: Math.round(performance.memory.usedJSHeapSize / 1024 / 1024),
                    total: Math.round(performance.memory.totalJSHeapSize / 1024 / 1024),
                    limit: Math.round(performance.memory.jsHeapSizeLimit / 1024 / 1024)
                };

                console.log(`[Memory] Used: ${usage.used}MB, Total: ${usage.total}MB, Limit: ${usage.limit}MB`);

                // 内存使用超过80%时发出警告
                if (usage.used / usage.limit > 0.8) {
                    console.warn('[Memory Warning] 内存使用过高,建议清理缓存');
                    if (typeof toastr !== 'undefined') {
                        toastr.warning('内存使用过高,建议清理图片缓存');
                    }
                }

                return usage;
            }
            return null;
        }

        startMemoryMonitoring(interval = 30000) {
            this.stopMemoryMonitoring();
            this.memoryCheckInterval = setInterval(() => {
                this.trackMemoryUsage();
            }, interval);
        }

        stopMemoryMonitoring() {
            if (this.memoryCheckInterval) {
                clearInterval(this.memoryCheckInterval);
                this.memoryCheckInterval = null;
            }
        }
    }

    // --- Global State Variables ---
    let globalCooldownEndTime = 0;
    let socket = null;
    let activePrompts = {}; // 存储 prompt_id -> { button, generationId } 的映射
    let reconnector = null;
    let performanceMonitor = new PerformanceMonitor();
    let cachedDOMElements = {}; // DOM元素缓存
    let debugMode = false; // 调试模式开关

    // --- Cached User Settings ---
    let cachedSettings = {
        comfyuiUrl: '',
        startTag: 'image###',
        endTag: '###',
        promptPrefix: '',
        maxWidth: 600,
        cacheLimit: 20,
        apiKey: '', // 将存储加密后的密钥
        defaultModel: '',
        notificationLevel: 'silent', // 'silent' | 'standard' | 'verbose'
        enableRetry: true, // 启用自动重试
        retryCount: 3 // 重试次数
    };

    // --- Inject Custom CSS Styles ---
    GM_addStyle(`
        /* 新增:离线提示样式 */
        .comfy-offline-notice {
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(220, 53, 69, 0.9);
            color: white;
            padding: 10px 15px;
            border-radius: 5px;
            display: flex;
            align-items: center;
            gap: 10px;
            z-index: 10000;
            font-size: 14px;
            box-shadow: 0 2px 10px rgba(0,0,0,0.3);
        }

        .comfy-offline-notice .retry-connection {
            background: rgba(255,255,255,0.2);
            border: 1px solid rgba(255,255,255,0.3);
            color: white;
            padding: 5px 10px;
            border-radius: 3px;
            cursor: pointer;
            font-size: 12px;
        }

        .comfy-offline-notice .retry-connection:hover {
            background: rgba(255,255,255,0.3);
        }

        /* 新增:缓存状态显示样式 */
        #comfyui-cache-status {
            margin-top: 15px;
            margin-bottom: 10px;
            padding: 12px; /* 【优化】增加内边距 */
            background: linear-gradient(90deg, rgba(30, 144, 255, 0.1) 0%, rgba(135, 206, 235, 0.1) 100%); /* 【优化】蓝色渐变背景 */
            border: 1px solid rgba(135, 206, 235, 0.3); /* 【优化】蓝色边框 */
            border-radius: 6px;
            text-align: center;
            font-size: 0.9em;
            color: #87CEEB; /* 【优化】蓝色文字 */
            font-weight: 500;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); /* 【优化】添加阴影 */
        }

        /* 新增:配置验证错误提示 */
        .comfy-config-error {
            background-color: rgba(220, 53, 69, 0.1);
            border: 1px solid #dc3545;
            color: #dc3545;
            padding: 8px;
            border-radius: 4px;
            margin: 10px 0;
            font-size: 0.9em;
        }

        /* 控制面板主容器样式 */
        #${PANEL_ID} {
            display: none;
            position: fixed;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            width: 90vw;
            max-width: 500px;
            z-index: 9999;
            color: #e0e0e0; /* 【优化】使用固定的浅色文字 */
            background: linear-gradient(145deg, rgba(30, 30, 35, 0.98) 0%, rgba(20, 20, 25, 0.98) 100%); /* 【优化】渐变背景 */
            border: 1px solid rgba(135, 206, 235, 0.3); /* 【优化】蓝色边框 */
            border-radius: 12px; /* 【优化】更圆润 */
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(135, 206, 235, 0.1); /* 【优化】双层阴影 */
            padding: 15px;
            box-sizing: border-box;
            backdrop-filter: blur(20px); /* 【优化】增强毛玻璃效果 */
            flex-direction: column;
        }

        /* 面板标题栏 */
        #${PANEL_ID} .panel-control-bar {
            padding: 14px 18px; /* 【优化】增加内边距 */
            margin: -15px -15px 18px -15px;
            background: linear-gradient(135deg, rgba(135, 206, 235, 0.2) 0%, rgba(0, 191, 255, 0.25) 100%); /* 【优化】更明显的渐变 */
            border-bottom: 2px solid rgba(135, 206, 235, 0.4); /* 【优化】更粗的分隔线 */
            border-radius: 12px 12px 0 0; /* 【优化】匹配容器圆角 */
            display: flex;
            align-items: center;
            justify-content: space-between;
            flex-shrink: 0;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); /* 【优化】添加阴影 */
        }

        #${PANEL_ID} .panel-control-bar b {
            font-size: 1.15em; /* 【优化】稍大的字体 */
            margin-left: 10px;
            color: #87CEEB;
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); /* 【优化】文字阴影 */
            font-weight: 600; /* 【优化】更粗的字体 */
        }

        #${PANEL_ID} .panel-control-bar .drag-grabber {
            color: #87CEEB;
            cursor: move;
            transition: color 0.3s; /* 【优化】过渡动画 */
        }

        #${PANEL_ID} .panel-control-bar .drag-grabber:hover {
            color: #00BFFF; /* 【优化】悬停变色 */
        }

        #${PANEL_ID} .floating_panel_close {
            cursor: pointer;
            font-size: 1.8em;
            color: #87CEEB;
            transition: transform 0.2s, color 0.2s;
            padding: 5px; /* 【优化】增加点击区域 */
        }

        #${PANEL_ID} .floating_panel_close:hover {
            transform: scale(1.15) rotate(90deg); /* 【优化】旋转动画 */
            color: #ff6b6b;
        }

        #${PANEL_ID} .comfyui-panel-content {
            overflow-y: auto;
            flex-grow: 1;
            padding-right: 5px;
            max-height: 70vh;
        }

        /* 设置分组样式 */
        .comfy-settings-group {
            margin-bottom: 20px;
            padding: 16px; /* 【优化】增加内边距 */
            background: linear-gradient(135deg, rgba(40, 40, 50, 0.4) 0%, rgba(30, 30, 40, 0.4) 100%); /* 【优化】渐变背景 */
            border: 1px solid rgba(135, 206, 235, 0.25); /* 【优化】更明显的边框 */
            border-radius: 8px; /* 【优化】更圆润 */
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); /* 【优化】添加阴影 */
            transition: all 0.3s ease; /* 【优化】过渡动画 */
        }

        .comfy-settings-group:hover {
            border-color: rgba(135, 206, 235, 0.4); /* 【优化】悬停高亮 */
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
        }

        .comfy-settings-group-title {
            font-size: 1.05em; /* 【优化】稍大的字体 */
            font-weight: 600;
            color: #87CEEB; /* 天蓝色 */
            margin-bottom: 14px;
            padding-bottom: 10px;
            border-bottom: 2px solid rgba(135, 206, 235, 0.3); /* 【优化】更粗的分隔线 */
            display: flex;
            align-items: center;
            gap: 10px;
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); /* 【优化】文字阴影 */
        }

        .comfy-settings-group-title i {
            font-size: 1.1em; /* 【优化】图标稍大 */
            color: #00BFFF; /* 深天蓝色 */
        }

        .comfy-field {
            margin-bottom: 12px;
        }

        .comfy-field:last-child {
            margin-bottom: 0;
        }

        .comfy-field label {
            display: block;
            margin-bottom: 6px;
            font-size: 0.9em;
            color: #b0b0b0; /* 【优化】更浅的灰色 */
            font-weight: 500; /* 【优化】稍粗的字体 */
        }

        /* 输入框和文本域样式 */
        #${PANEL_ID} input[type="text"], #${PANEL_ID} textarea, #${PANEL_ID} input[type="number"], #${PANEL_ID} select, #${PANEL_ID} input[type="password"] {
            width: 100%;
            box-sizing: border-box;
            padding: 10px 12px; /* 【优化】增加内边距 */
            border-radius: 6px; /* 【优化】更圆润 */
            border: 1px solid rgba(100, 100, 120, 0.4); /* 【优化】更明显的边框 */
            background-color: rgba(15, 15, 20, 0.6); /* 【优化】更深的背景 */
            color: #e0e0e0; /* 【优化】浅色文字 */
            margin-bottom: 10px;
            font-size: 14px;
            transition: all 0.3s ease; /* 【优化】过渡动画 */
        }

        /* 【优化】输入框聚焦效果 */
        #${PANEL_ID} input[type="text"]:focus,
        #${PANEL_ID} textarea:focus,
        #${PANEL_ID} input[type="number"]:focus,
        #${PANEL_ID} select:focus,
        #${PANEL_ID} input[type="password"]:focus {
            outline: none;
            border-color: #87CEEB;
            background-color: rgba(20, 20, 30, 0.7);
            box-shadow: 0 0 0 3px rgba(135, 206, 235, 0.15);
        }

        /* 【优化】输入框占位符样式 */
        #${PANEL_ID} input::placeholder, #${PANEL_ID} textarea::placeholder {
            color: rgba(176, 176, 176, 0.5);
            font-style: italic;
        }

        #${PANEL_ID} textarea {
            min-height: 150px;
            resize: vertical;
        }

        #${PANEL_ID} .workflow-info {
            font-size: 0.9em;
            color: #aaa;
            margin-top: -5px;
            margin-bottom: 10px;
        }

        /* 通用按钮样式 */
        .comfy-button {
            padding: 11px 16px; /* 【优化】增加内边距 */
            border: none; /* 【优化】移除边框 */
            border-radius: 8px; /* 【优化】更圆润 */
            cursor: pointer;
            background: linear-gradient(135deg, #4A9EFF 0%, #1E90FF 100%); /* 【优化】更鲜艳的蓝色渐变 */
            color: white;
            font-weight: 600;
            transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); /* 【优化】缓动函数 */
            flex-shrink: 0;
            font-size: 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            gap: 8px;
            box-shadow: 0 2px 8px rgba(30, 144, 255, 0.3), 0 1px 3px rgba(0, 0, 0, 0.2); /* 【优化】双层阴影 */
            position: relative;
            overflow: hidden;
        }

        /* 【优化】按钮闪光效果 */
        .comfy-button::before {
            content: '';
            position: absolute;
            top: 0;
            left: -100%;
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.3), transparent);
            transition: left 0.5s;
        }

        .comfy-button:hover::before {
            left: 100%;
        }

        .comfy-button i {
            font-size: 1em;
            filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.2)); /* 【优化】图标阴影 */
        }

        .comfy-button:disabled {
            opacity: 0.5;
            cursor: not-allowed;
            background: linear-gradient(135deg, #6c757d 0%, #5a6268 100%); /* 【优化】禁用状态灰色 */
        }

        .comfy-button:hover:not(:disabled) {
            transform: translateY(-2px);
            box-shadow: 0 6px 16px rgba(30, 144, 255, 0.4), 0 2px 4px rgba(0, 0, 0, 0.2); /* 【优化】悬停阴影更明显 */
            background: linear-gradient(135deg, #5AADFF 0%, #2E9FFF 100%); /* 【优化】悬停颜色变化 */
        }

        .comfy-button:active:not(:disabled) {
            transform: translateY(0);
            box-shadow: 0 2px 4px rgba(30, 144, 255, 0.2);
        }

        /* 按钮状态样式 */
        .comfy-button.testing {
            background: linear-gradient(135deg, #6c757d 0%, #5a6268 100%); /* 【优化】灰色渐变 */
            box-shadow: 0 2px 8px rgba(108, 117, 125, 0.3);
        }

        .comfy-button.success {
            background: linear-gradient(135deg, #28a745 0%, #20c997 100%); /* 【优化】更鲜艳的绿色 */
            box-shadow: 0 2px 8px rgba(40, 167, 69, 0.4);
        }

        .comfy-button.error {
            background: linear-gradient(135deg, #dc3545 0%, #e74c3c 100%); /* 【优化】更鲜艳的红色 */
            box-shadow: 0 2px 8px rgba(220, 53, 69, 0.4);
        }

        .comfy-button.success:hover:not(:disabled) {
            background: linear-gradient(135deg, #34ce57 0%, #2dd4a7 100%);
            box-shadow: 0 6px 16px rgba(40, 167, 69, 0.5);
        }

        .comfy-button.error:hover:not(:disabled) {
            background: linear-gradient(135deg, #e74c3c 0%, #f85149 100%);
            box-shadow: 0 6px 16px rgba(220, 53, 69, 0.5);
        }

        /* 特殊布局样式 */
        #comfyui-test-conn {
            position: relative;
            top: -5px;
        }

        .comfy-url-container {
            display: flex;
            gap: 10px;
            align-items: center;
        }

        .comfy-url-container input {
            flex-grow: 1;
            margin-bottom: 0;
        }

        #${PANEL_ID} label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
        }

        #options > .options-content > a#${BUTTON_ID} {
            display: flex;
            align-items: center;
            gap: 10px;
        }

        /* 标记输入框容器样式 */
        #${PANEL_ID} .comfy-tags-container {
            display: flex;
            gap: 10px;
            align-items: flex-end;
            margin-top: 10px;
            margin-bottom: 10px;
        }

        #${PANEL_ID} .comfy-tags-container div {
            flex-grow: 1;
        }

        /* 聊天内按钮组容器 */
        .comfy-button-group {
            display: inline-flex;
            align-items: center;
            gap: 5px;
            margin: 5px 4px;
        }

        /* 生成的图片容器样式 */
        .comfy-image-container {
            margin-top: 10px;
            max-width: 100%;
        }

        .comfy-image-container img {
            max-width: var(--comfy-image-max-width, 100%);
            height: auto;
            border-radius: 8px;
            border: 1px solid var(--SmartThemeBorderColor, #555);
        }

        /* 图片加载动画 */
        .comfy-loading-indicator {
            text-align: center;
            color: #888;
            padding: 10px;
            font-style: italic;
        }

        .comfy-loading-indicator::after {
            content: '...';
            animation: comfy-dots 1.5s steps(4, end) infinite;
        }

        @keyframes comfy-dots {
            0%, 20% { content: '.'; }
            40% { content: '..'; }
            60%, 100% { content: '...'; }
        }

        /* 图片错误占位符 */
        .comfy-image-error {
            padding: 20px;
            text-align: center;
            color: #dc3545;
            border: 2px dashed #dc3545;
            border-radius: 8px;
            background: rgba(220, 53, 69, 0.1);
        }

        .comfy-image-error i {
            font-size: 2em;
            margin-bottom: 10px;
            display: block;
        }

        /* 图片容器悬停效果 */
        .comfy-image-container {
            position: relative;
            display: inline-block;
            contain: layout; /* 【优化】CSS Containment,减少重排 */
        }

        .comfy-image-container img {
            cursor: pointer;
            transition: opacity 0.3s ease, transform 0.3s ease;
            will-change: transform; /* 【优化】GPU加速 */
            transform: translateZ(0); /* 【优化】启用硬件加速 */
        }

        .comfy-image-container img:hover {
            opacity: 0.9;
            transform: scale(1.02) translateZ(0);
        }

        /* 图片工具栏 */
        .comfy-image-toolbar {
            position: absolute;
            top: 5px;
            right: 5px;
            display: none;
            gap: 5px;
            z-index: 10;
        }

        .comfy-image-container:hover .comfy-image-toolbar {
            display: flex;
        }

        .comfy-image-tool-btn {
            background: rgba(0, 0, 0, 0.7);
            border: none;
            border-radius: 4px;
            color: white;
            padding: 6px 10px;
            cursor: pointer;
            font-size: 14px;
            transition: background 0.2s;
        }

        .comfy-image-tool-btn:hover {
            background: rgba(0, 0, 0, 0.9);
        }

        /* Lightbox 图片放大查看器 */
        .comfy-lightbox {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            width: 100vw; /* 【修复】使用视口单位确保全屏 */
            height: 100vh;
            background: rgba(0, 0, 0, 0.95);
            z-index: 100000;
            justify-content: center;
            align-items: center;
            animation: comfy-fadeIn 0.3s ease;
            overflow: hidden; /* 【修复】防止滚动条 */
        }

        .comfy-lightbox.active {
            display: flex !important; /* 【修复】使用!important确保显示 */
        }

        .comfy-lightbox img {
            max-width: 90vw; /* 【修复】使用视口单位 */
            max-height: 90vh;
            width: auto;
            height: auto;
            object-fit: contain;
            border-radius: 8px;
            box-shadow: 0 0 50px rgba(0, 0, 0, 0.5);
            animation: comfy-zoomIn 0.3s ease;
            display: block; /* 【修复】确保图片是块级元素 */
            margin: auto; /* 【修复】额外的居中保障 */
        }

        .comfy-lightbox-close {
            position: absolute;
            top: 20px;
            right: 30px;
            font-size: 40px;
            color: white;
            cursor: pointer;
            z-index: 100001; /* 【修复】确保关闭按钮在Lightbox之上 */
            transition: transform 0.2s;
        }

        .comfy-lightbox-close:hover {
            transform: scale(1.2);
        }

        .comfy-lightbox-download {
            position: absolute;
            bottom: 30px;
            right: 30px;
            background: linear-gradient(135deg, #87CEEB 0%, #00BFFF 100%);
            border: none;
            border-radius: 8px;
            color: white;
            padding: 12px 24px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            transition: opacity 0.3s;
        }

        .comfy-lightbox-download:hover {
            opacity: 0.85;
        }

        @keyframes comfy-fadeIn {
            from { opacity: 0; }
            to { opacity: 1; }
        }

        @keyframes comfy-zoomIn {
            from { transform: scale(0.8); opacity: 0; }
            to { transform: scale(1); opacity: 1; }
        }

        /* 图片淡入动画 */
        .comfy-image-container img.fade-in {
            animation: comfy-imageFadeIn 0.5s ease;
        }

        @keyframes comfy-imageFadeIn {
            from { opacity: 0; transform: translateY(10px); }
            to { opacity: 1; transform: translateY(0); }
        }

        /* 骨架屏加载效果 */
        .comfy-skeleton {
            background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%);
            background-size: 200% 100%;
            animation: comfy-skeleton-loading 1.5s infinite;
            border-radius: 8px;
        }

        @keyframes comfy-skeleton-loading {
            0% { background-position: 200% 0; }
            100% { background-position: -200% 0; }
        }

        /* 移动端适配 */
        @media (max-width: 1000px) {
            #${PANEL_ID} {
                top: 20px;
                left: 50%;
                transform: translateX(-50%);
                max-height: calc(100vh - 40px);
                width: 95vw;
            }

            /* 【修复】移动端Lightbox优化 */
            .comfy-lightbox img {
                max-width: 95vw !important;
                max-height: 95vh !important;
            }

            .comfy-lightbox-close {
                top: 10px !important;
                right: 10px !important;
                font-size: 36px !important;
                background: rgba(0, 0, 0, 0.5);
                border-radius: 50%;
                width: 50px;
                height: 50px;
                display: flex;
                align-items: center;
                justify-content: center;
            }

            .comfy-lightbox-download {
                bottom: 10px !important;
                right: 10px !important;
                font-size: 14px !important;
                padding: 10px 20px !important;
            }
        }

        /* 历史记录面板 */
        #comfy-history-panel {
            display: none;
            position: fixed;
            top: 0;
            left: 0;
            right: 0;
            bottom: 0;
            z-index: 9999;
            justify-content: center;
            align-items: center;
            background: rgba(0, 0, 0, 0.5);
            padding: 20px;
            box-sizing: border-box;
        }

        #comfy-history-panel.active {
            display: flex;
        }

        .comfy-history-container {
            width: 90vw;
            max-width: 800px;
            max-height: 80vh;
            color: #e0e0e0; /* 【优化】浅色文字 */
            background: linear-gradient(145deg, rgba(30, 30, 35, 0.98) 0%, rgba(20, 20, 25, 0.98) 100%); /* 【优化】渐变背景 */
            border: 1px solid rgba(135, 206, 235, 0.3); /* 【优化】蓝色边框 */
            border-radius: 12px; /* 【优化】更圆润 */
            box-shadow: 0 8px 32px rgba(0, 0, 0, 0.6), 0 0 0 1px rgba(135, 206, 235, 0.1); /* 【优化】双层阴影 */
            backdrop-filter: blur(20px); /* 【优化】增强毛玻璃 */
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }

        .comfy-history-header {
            padding: 18px 20px; /* 【优化】增加内边距 */
            background: linear-gradient(135deg, rgba(135, 206, 235, 0.15) 0%, rgba(0, 191, 255, 0.2) 100%); /* 【优化】蓝色渐变背景 */
            border-bottom: 2px solid rgba(135, 206, 235, 0.3); /* 【优化】更粗的分隔线 */
            display: flex;
            justify-content: space-between;
            align-items: center;
            box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); /* 【优化】添加阴影 */
        }

        .comfy-history-header h3 {
            margin: 0;
            font-size: 1.25em; /* 【优化】稍大的字体 */
            color: #87CEEB; /* 【优化】蓝色标题 */
            text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); /* 【优化】文字阴影 */
            font-weight: 600;
        }

        .comfy-history-header h3 i {
            color: #00BFFF; /* 【优化】图标颜色 */
            margin-right: 8px;
        }

        .comfy-history-stats {
            font-size: 0.9em;
            color: #a0a0a0; /* 【优化】更浅的灰色 */
            margin-top: 6px;
        }

        /* 【优化】历史面板关闭按钮样式 */
        #comfy-history-close {
            color: #87CEEB !important;
            transition: all 0.3s ease;
            padding: 5px;
            cursor: pointer;
        }

        #comfy-history-close:hover {
            color: #ff6b6b !important;
            transform: scale(1.15) rotate(90deg);
        }

        .comfy-history-content {
            flex: 1;
            overflow-y: auto;
            padding: 15px;
            -webkit-overflow-scrolling: touch; /* 【优化】iOS平滑滚动 */
            will-change: scroll-position; /* 【优化】提示浏览器优化滚动 */
        }

        .comfy-history-item {
            display: flex;
            gap: 15px;
            padding: 12px; /* 【优化】增加内边距 */
            border: 1px solid rgba(100, 100, 120, 0.3); /* 【优化】更明显的边框 */
            border-radius: 10px; /* 【优化】更圆润 */
            margin-bottom: 12px;
            background: linear-gradient(135deg, rgba(35, 35, 45, 0.4) 0%, rgba(25, 25, 35, 0.4) 100%); /* 【优化】渐变背景 */
            transition: all 0.3s ease; /* 【优化】平滑过渡 */
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }

        .comfy-history-item:hover {
            background: linear-gradient(135deg, rgba(45, 45, 60, 0.5) 0%, rgba(35, 35, 50, 0.5) 100%); /* 【优化】悬停渐变 */
            border-color: rgba(135, 206, 235, 0.4); /* 【优化】悬停边框变色 */
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); /* 【优化】悬停阴影 */
            transform: translateY(-2px); /* 【优化】轻微上浮 */
        }

        .comfy-history-thumbnail {
            width: 120px;
            height: 120px;
            flex-shrink: 0;
            border-radius: 4px;
            overflow: hidden;
            cursor: pointer;
            position: relative;
        }

        .comfy-history-thumbnail img {
            width: 100%;
            height: 100%;
            object-fit: cover;
            transition: transform 0.3s;
            will-change: transform; /* 【优化】GPU加速 */
            transform: translateZ(0); /* 【优化】启用硬件加速 */
        }

        .comfy-history-thumbnail:hover img {
            transform: scale(1.1);
        }

        .comfy-history-thumbnail::after {
            content: '🔍';
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: 24px;
            opacity: 0;
            transition: opacity 0.3s;
        }

        .comfy-history-thumbnail:hover::after {
            opacity: 0.9;
        }

        .comfy-history-info {
            flex: 1;
            display: flex;
            flex-direction: column;
            justify-content: space-between;
        }

        .comfy-history-meta {
            font-size: 0.85em;
            color: #888;
        }

        .comfy-history-meta span {
            margin-right: 15px;
        }

        .comfy-history-actions {
            display: flex;
            gap: 8px;
            margin-top: 8px;
        }

        .comfy-history-btn {
            padding: 8px 14px; /* 【优化】增加内边距 */
            border: 1px solid rgba(135, 206, 235, 0.3); /* 【优化】蓝色边框 */
            border-radius: 6px; /* 【优化】更圆润 */
            background: linear-gradient(135deg, rgba(30, 30, 40, 0.6) 0%, rgba(20, 20, 30, 0.6) 100%); /* 【优化】渐变背景 */
            color: #e0e0e0; /* 【优化】浅色文字 */
            cursor: pointer;
            font-size: 0.9em;
            transition: all 0.3s ease; /* 【优化】过渡动画 */
            font-weight: 500;
            display: inline-flex;
            align-items: center;
            gap: 6px;
        }

        .comfy-history-btn i {
            font-size: 0.95em;
        }

        .comfy-history-btn:hover {
            background: linear-gradient(135deg, rgba(135, 206, 235, 0.2) 0%, rgba(0, 191, 255, 0.25) 100%); /* 【优化】悬停渐变 */
            border-color: rgba(135, 206, 235, 0.5);
            transform: translateY(-1px);
            box-shadow: 0 2px 8px rgba(135, 206, 235, 0.3);
        }

        .comfy-history-btn.danger {
            border-color: rgba(220, 53, 69, 0.4); /* 【优化】红色边框 */
        }

        .comfy-history-btn.danger:hover {
            background: linear-gradient(135deg, rgba(220, 53, 69, 0.3) 0%, rgba(231, 76, 60, 0.35) 100%); /* 【优化】红色悬停 */
            border-color: #dc3545;
            box-shadow: 0 2px 8px rgba(220, 53, 69, 0.4);
        }

        .comfy-history-empty {
            text-align: center;
            padding: 40px;
            color: #888;
        }

        .comfy-history-empty i {
            font-size: 48px;
            display: block;
            margin-bottom: 15px;
            opacity: 0.5;
        }

        /* 移动端适配 - 历史面板 */
        @media (max-width: 768px) {
            #comfy-history-panel {
                padding: 5px;
            }

            #comfy-history-panel.active {
                display: flex !important;
                justify-content: center !important;
                align-items: center !important;
            }

            .comfy-history-container {
                width: 95vw;
                max-width: 95vw;
                max-height: 90vh;
                border-radius: 12px;
                margin: auto;
            }

            .comfy-history-header {
                padding: 12px;
                flex-shrink: 0;
            }

            .comfy-history-header h3 {
                font-size: 1em;
            }

            .comfy-history-header #comfy-history-close {
                font-size: 28px !important;
            }

            .comfy-history-stats {
                font-size: 0.8em;
            }

            .comfy-history-content {
                overflow-y: auto;
                -webkit-overflow-scrolling: touch;
            }

            .comfy-history-item {
                flex-direction: column;
                padding: 8px;
            }

            .comfy-history-thumbnail {
                width: 100%;
                height: auto;
                max-height: 300px;
                object-fit: contain;
            }

            .comfy-history-actions {
                flex-wrap: wrap;
                gap: 5px;
            }

            .comfy-history-btn {
                flex: 1;
                min-width: 80px;
                font-size: 0.85em;
                padding: 8px;
            }

            /* 设置面板移动端适配 */
            #${PANEL_ID} {
                width: 95vw;
                max-height: 85vh;
                padding: 10px;
            }

            #${PANEL_ID} .panel-control-bar {
                padding: 10px;
                margin: -10px -10px 12px -10px;
            }

            #${PANEL_ID} .panel-control-bar b {
                font-size: 1em;
            }

            .comfy-settings-group {
                padding: 10px;
                margin-bottom: 15px;
            }

            .comfy-settings-group-title {
                font-size: 0.95em;
            }

            .comfy-url-container {
                flex-direction: column;
            }

            .comfy-url-container button {
                margin-top: 8px;
                margin-left: 0 !important;
            }
        }

        /* CSS变量,用于动态控制图片最大宽度 */
        :root {
            --comfy-image-max-width: 600px;
        }

        /* 【优化】暗黑模式支持 - 自动适配系统主题 */
        @media (prefers-color-scheme: dark) {
            .comfy-lightbox {
                background: rgba(0, 0, 0, 0.98);
            }

            .comfy-history-container {
                background-color: rgba(18, 18, 18, 0.98);
            }

            #${PANEL_ID} {
                background-color: rgba(18, 18, 18, 0.95);
            }
        }

        @media (prefers-color-scheme: light) {
            .comfy-lightbox {
                background: rgba(255, 255, 255, 0.98);
            }

            .comfy-lightbox-close {
                color: #333;
            }

            .comfy-history-container {
                background-color: rgba(255, 255, 255, 0.98);
                color: #333;
            }

            #${PANEL_ID} {
                background-color: rgba(255, 255, 255, 0.95);
                color: #333;
            }
        }

        /* 【优化】移动端触摸优化 - 增大可点击区域 */
        @media (max-width: 768px) and (hover: none) {
            .comfy-button {
                min-height: 44px; /* Apple人机界面指南推荐的最小触摸目标 */
                padding: 12px 16px;
                font-size: 16px; /* 防止iOS自动缩放 */
            }

            .comfy-history-btn {
                min-height: 44px;
                padding: 10px 16px;
            }

            .comfy-image-tool-btn {
                min-width: 44px;
                min-height: 44px;
                padding: 10px;
            }

            /* 优化长按效果 */
            .comfy-button:active {
                transform: scale(0.95);
                opacity: 0.8;
            }
        }
    `);

    // --- Configuration Migration ---
    async function migrateConfig() {
        try {
            const currentVersion = await GM_getValue('config_version', '1.0');

            if (currentVersion !== CONFIG_VERSION) {
                console.log(`配置迁移: ${currentVersion} -> ${CONFIG_VERSION}`);

                // 迁移旧版本的API密钥
                const oldApiKey = await GM_getValue('comfyui_api_key', '');
                if (oldApiKey && !oldApiKey.includes('=')) { // 检查是否已加密
                    const encryptedKey = encryptApiKey(oldApiKey);
                    await GM_setValue('comfyui_api_key', encryptedKey);
                    console.log('API密钥已加密存储');
                }

                await GM_setValue('config_version', CONFIG_VERSION);
                console.log('配置迁移完成');
            }
        } catch (error) {
            console.error('配置迁移失败:', error);
        }
    }

    // --- Cache Integrity and Management ---
    async function validateCacheIntegrity() {
        try {
            performanceMonitor.startTimer('validateCache');

            const records = await GM_getValue(STORAGE_KEY_IMAGES, {});
            const validRecords = {};
            let removedCount = 0;

            for (const [id, data] of Object.entries(records)) {
                try {
                    // 验证Base64数据完整性
                    if (typeof data === 'string' &&
                        data.startsWith('data:image/') &&
                        data.includes('base64,') &&
                        data.length > 100) { // 基本长度检查
                        validRecords[id] = data;
                    } else {
                        console.warn(`缓存记录 ${id} 数据格式无效,已清理`);
                        removedCount++;
                    }
                } catch (error) {
                    console.error(`缓存记录 ${id} 验证失败:`, error);
                    removedCount++;
                }
            }

            if (removedCount > 0) {
                await GM_setValue(STORAGE_KEY_IMAGES, validRecords);
                if (typeof toastr !== 'undefined') {
                    toastr.info(`已清理 ${removedCount} 条无效缓存记录`);
                }
            }

            performanceMonitor.endTimer('validateCache');
            return Object.keys(validRecords).length;
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('缓存验证失败: ' + error.message, 'CACHE'), 'validateCacheIntegrity');
            return 0;
        }
    }

    // --- Image Compression and Optimization ---

    // 【优化】创建内联WebWorker用于图片压缩(避免阻塞主线程)
    let compressionWorker = null;

    function createCompressionWorker() {
        // 由于油猴环境限制,使用OffscreenCanvas在主线程压缩
        // 但使用requestIdleCallback优化,避免阻塞UI
        return {
            compress: async (canvas, quality, maxWidth) => {
        return new Promise((resolve) => {
                    // 使用requestIdleCallback在浏览器空闲时压缩
                    const idleCallback = window.requestIdleCallback || ((cb) => setTimeout(cb, 1));

                    idleCallback(async () => {
            try {
                // 如果图片太大,先缩放
                if (canvas.width > maxWidth) {
                    const scale = maxWidth / canvas.width;
                    const scaledCanvas = document.createElement('canvas');
                    const ctx = scaledCanvas.getContext('2d');

                    scaledCanvas.width = maxWidth;
                    scaledCanvas.height = canvas.height * scale;

                    ctx.drawImage(canvas, 0, 0, scaledCanvas.width, scaledCanvas.height);
                    canvas = scaledCanvas;
                }

                // 压缩为JPEG格式
                canvas.toBlob((blob) => {
                    if (blob) {
                        const reader = new FileReader();
                        reader.onload = () => resolve(reader.result);
                        reader.readAsDataURL(blob);
                    } else {
                        resolve(null);
                    }
                }, 'image/jpeg', quality);
            } catch (error) {
                console.error('图片压缩失败:', error);
                resolve(null);
            }
                    }, { timeout: 2000 });
                });
            }
        };
    }

    function compressImage(canvas, quality = 0.8, maxWidth = 1024) {
        // 【优化】使用compressionWorker处理(如果可用)
        if (!compressionWorker) {
            compressionWorker = createCompressionWorker();
        }

        return compressionWorker.compress(canvas, quality, maxWidth);
    }

    async function fetchImageAsBase64(imageUrl) {
        return new Promise((resolve, reject) => {
            if (debugMode) {
                console.log(`[ComfyUI Debug] 开始获取图片: ${imageUrl}`);
            }

            performanceMonitor.startTimer('fetchImage');

            GM_xmlhttpRequest({
                method: 'GET',
                url: imageUrl,
                responseType: 'blob',
                timeout: 30000,
                onload: async (response) => {
                    try {
                        if (debugMode) {
                            console.log(`[ComfyUI Debug] 图片请求响应: 状态=${response.status}, 大小=${response.response?.size || 0}字节`);
                        }

                        if (response.status === 200) {
                            const blob = response.response;

                            // 检查文件大小
                            if (blob.size > 10 * 1024 * 1024) { // 10MB限制
                                throw new ComfyUIError('图片文件过大', 'VALIDATION');
                            }

                            if (blob.size === 0) {
                                throw new ComfyUIError('图片文件为空', 'VALIDATION');
                            }

                            // 【优化】降低压缩阈值,移动端更激进
                            const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
                            const compressionThreshold = isMobile ? 1 * 1024 * 1024 : 2 * 1024 * 1024; // 移动端1MB,PC端2MB

                            // 尝试压缩大图片
                            if (blob.size > compressionThreshold) {
                                if (debugMode) {
                                    console.log(`[ComfyUI Debug] 图片较大(${(blob.size / 1024).toFixed(1)}KB),开始压缩...`);
                                    console.log(`[ComfyUI Debug] 设备: ${isMobile ? '移动端' : 'PC端'}, 压缩阈值: ${(compressionThreshold / 1024).toFixed(0)}KB`);
                                }

                                const img = new Image();
                                const canvas = document.createElement('canvas');
                                const ctx = canvas.getContext('2d');

                                img.onload = async () => {
                                    canvas.width = img.width;
                                    canvas.height = img.height;
                                    ctx.drawImage(img, 0, 0);

                                    // 【优化】移动端使用更激进的压缩
                                    const quality = isMobile ? 0.6 : 0.75;
                                    const maxWidth = isMobile ? 800 : 1024;

                                    const compressedData = await compressImage(canvas, quality, maxWidth);
                                    if (compressedData) {
                                        const compressedSize = (compressedData.length * 0.75 / 1024).toFixed(1);
                                        console.log(`图片已压缩: ${(blob.size / 1024).toFixed(1)}KB -> ${compressedSize}KB (质量:${quality}, 最大宽度:${maxWidth}px)`);
                                        if (debugMode) {
                                            console.log(`[ComfyUI Debug] 压缩比: ${(100 - (compressedSize / (blob.size / 1024) * 100)).toFixed(1)}%`);
                                        }
                                        performanceMonitor.endTimer('fetchImage');
                                        resolve(compressedData);
                                    } else {
                                        // 压缩失败,使用原图
                                        console.warn('图片压缩失败,使用原始图片');
                                        const reader = new FileReader();
                                        reader.onloadend = () => {
                                            performanceMonitor.endTimer('fetchImage');
                                            resolve(reader.result);
                                        };
                                        reader.readAsDataURL(blob);
                                    }
                                };

                                img.onerror = () => {
                                    // 图片解析失败,使用原始数据
                                    console.warn('图片解析失败,使用原始数据');
                                    const reader = new FileReader();
                                    reader.onloadend = () => {
                                        performanceMonitor.endTimer('fetchImage');
                                        resolve(reader.result);
                                    };
                                    reader.readAsDataURL(blob);
                                };

                                const reader = new FileReader();
                                reader.onload = () => img.src = reader.result;
                                reader.readAsDataURL(blob);
                            } else {
                                // 小文件直接转换
                                if (debugMode) {
                                    console.log(`[ComfyUI Debug] 图片较小(${(blob.size / 1024).toFixed(1)}KB),直接转换base64`);
                                }

                                const reader = new FileReader();
                                reader.onloadend = () => {
                                    performanceMonitor.endTimer('fetchImage');
                                    if (debugMode) {
                                        console.log(`[ComfyUI Debug] Base64转换完成`);
                                    }
                                    resolve(reader.result);
                                };
                                reader.onerror = (err) => {
                                    performanceMonitor.endTimer('fetchImage');
                                    reject(new ComfyUIError('FileReader error: ' + err, 'CACHE'));
                                };
                                reader.readAsDataURL(blob);
                            }
                        } else {
                            reject(new ComfyUIError(`获取图片失败,状态: ${response.status}`, 'NETWORK'));
                        }
                    } catch (error) {
                        reject(error);
                    } finally {
                        performanceMonitor.endTimer('fetchImage');
                    }
                },
                onerror: (err) => {
                    performanceMonitor.endTimer('fetchImage');
                    reject(new ComfyUIError('网络错误: ' + err, 'NETWORK'));
                },
                ontimeout: () => {
                    performanceMonitor.endTimer('fetchImage');
                    reject(new ComfyUIError('下载图片超时', 'NETWORK'));
                }
            });
        });
    }

    // --- WebSocket & State Management ---
    function connectWebSocket() {
        try {
            if (socket && socket.connected) return;

            const schedulerUrl = new URL(cachedSettings.comfyuiUrl);
            const wsUrl = `${schedulerUrl.protocol}//${schedulerUrl.host}`;

            if (typeof io === 'undefined') {
                throw new ComfyUIError('Socket.IO 客户端库未加载!', 'CONFIG');
            }

            socket = io(wsUrl, {
                reconnectionAttempts: 5,
                timeout: 20000,
                transports: ['websocket', 'polling'] // 添加备用传输方式
            });

            socket.on('connect', () => {
                console.log('成功连接到调度器 WebSocket!');
                if (typeof toastr !== 'undefined') toastr.success('已建立实时连接!');

                // 重置重连器状态
                if (reconnector) {
                    reconnector.reset();
                }

                // 移除离线提示
                const offlineNotice = document.querySelector('.comfy-offline-notice');
                if (offlineNotice) {
                    offlineNotice.remove();
                }
            });

            socket.on('disconnect', (reason) => {
                console.log('与调度器 WebSocket 断开连接:', reason);

                // 只在非主动断开时尝试重连
                if (reason !== 'io client disconnect' && reason !== 'io server disconnect') {
                    if (reconnector) {
                        reconnector.reconnect();
                    }
                }
            });

            socket.on('connect_error', (error) => {
                console.error('WebSocket连接错误:', error);
                ErrorHandler.handle(new ComfyUIError('WebSocket连接失败: ' + error.message, 'WEBSOCKET'), 'connectWebSocket');
            });

            socket.on('generation_complete', async (data) => {
                try {
                    const { prompt_id, status, imageUrl, error } = data;
                    const promptInfo = activePrompts[prompt_id];

                    if (!promptInfo) return;

                    const { button, generationId } = promptInfo;
                    const group = button.closest('.comfy-button-group');

                    if (status === 'success' && imageUrl) {
                        showNotification('图片已生成,正在下载...', 'info', 'verbose');

                        try {
                            // 通过GM_xmlhttpRequest获取图片并转换为base64(绕过CORS限制)
                            if (debugMode) {
                                console.log(`[ComfyUI Debug] 开始获取图片: ${imageUrl}`);
                            }

                            // 使用重试机制获取图片
                            let imageBase64Data;
                            if (cachedSettings.enableRetry) {
                                imageBase64Data = await retryWithBackoff(
                                    () => fetchImageAsBase64(imageUrl),
                                    cachedSettings.retryCount,
                                    1000
                                );
                            } else {
                                imageBase64Data = await fetchImageAsBase64(imageUrl);
                            }

                            if (!imageBase64Data) {
                                throw new ComfyUIError('获取图片数据失败', 'NETWORK');
                            }

                            if (debugMode) {
                                console.log(`[ComfyUI Debug] 图片下载成功,大小: ${(imageBase64Data.length / 1024).toFixed(2)}KB`);
                            }

                            // 使用base64数据显示图片
                            await displayImageWithValidation(group, imageBase64Data, generationId);

                            // 保存到缓存
                            await saveImageRecord(generationId, imageBase64Data);

                            showNotification('图片加载完成!', 'success', 'standard');

                        button.textContent = '生成成功';
                        button.classList.remove('testing');
                        button.classList.add('success');
                        setTimeout(() => {
                            setupGeneratedState(button, generationId);
                        }, 2000);
                        } catch (imgError) {
                            console.error('图片下载或加载失败:', imgError);
                            showNotification(`图片加载失败: ${imgError.message}`, 'error');

                            button.textContent = '图片加载失败';
                            button.classList.remove('testing');
                            button.classList.add('error');
                            setTimeout(() => {
                                button.disabled = false;
                                button.classList.remove('error');
                                button.textContent = group.querySelector('.comfy-delete-button') ? '重新生成' : '开始生成';
                            }, 3000);
                        }

                    } else {
                        if (typeof toastr !== 'undefined') toastr.error(`生成失败: ${error || '未知错误'}`);
                        button.textContent = '生成失败';
                        button.classList.remove('testing');
                        button.classList.add('error');
                        setTimeout(() => {
                            button.disabled = false;
                            button.classList.remove('error');
                            button.textContent = group.querySelector('.comfy-delete-button') ? '重新生成' : '开始生成';
                        }, 3000);
                    }
                    delete activePrompts[prompt_id];
                } catch (error) {
                    ErrorHandler.handle(new ComfyUIError('处理生成完成事件失败: ' + error.message, 'WEBSOCKET'), 'generation_complete');
                }
            });

        } catch (error) {
            ErrorHandler.handle(error, 'connectWebSocket');
        }
    }

    // --- History Panel ---
    function createHistoryPanel() {
        if (document.getElementById('comfy-history-panel')) return;

        const panel = document.createElement('div');
        panel.id = 'comfy-history-panel';
        panel.innerHTML = `
            <div class="comfy-history-container">
                <div class="comfy-history-header">
                    <div>
                        <h3><i class="fa fa-history"></i> 生成历史记录</h3>
                        <div class="comfy-history-stats" id="comfy-history-stats"></div>
                    </div>
                    <i class="fa fa-times" style="cursor: pointer; font-size: 24px;" id="comfy-history-close"></i>
                </div>
                <div class="comfy-history-content" id="comfy-history-content">
                    <!-- 动态内容 -->
                </div>
            </div>
        `;

        document.body.appendChild(panel);

        // 关闭按钮
        const closeBtn = document.getElementById('comfy-history-close');
        closeBtn.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            panel.classList.remove('active');
            // 【修复】清除内联样式,避免display属性冲突
            panel.style.display = '';
            console.log('[ComfyUI] 历史面板已关闭');
        });

        // 点击背景遮罩关闭(点击container内部不关闭)
        panel.addEventListener('click', (e) => {
            if (e.target === panel) {
                panel.classList.remove('active');
                // 【修复】清除内联样式
                panel.style.display = '';
                console.log('[ComfyUI] 点击背景关闭历史面板');
            }
        });

        // 阻止点击container内部时关闭
        const container = panel.querySelector('.comfy-history-container');
        container.addEventListener('click', (e) => {
            e.stopPropagation();
        });

        // ESC键关闭
        const handleEsc = (e) => {
            if (e.key === 'Escape' && panel.classList.contains('active')) {
                panel.classList.remove('active');
                // 【修复】清除内联样式
                panel.style.display = '';
                console.log('[ComfyUI] ESC键关闭历史面板');
            }
        };
        document.addEventListener('keydown', handleEsc);
    }

    async function openHistoryPanel() {
        const panel = document.getElementById('comfy-history-panel');
        if (!panel) {
            createHistoryPanel();
            setTimeout(() => openHistoryPanel(), 100);
            return;
        }

        // 显示面板
        panel.classList.add('active');

        // 加载历史记录
        await refreshHistoryPanel();
    }

    async function refreshHistoryPanel() {
        const content = document.getElementById('comfy-history-content');
        const statsDiv = document.getElementById('comfy-history-stats');

        if (!content || !lruCache) return;

        const items = lruCache.getAll();
        const stats = lruCache.getStats();

        // 更新统计信息
        statsDiv.innerHTML = `
            总计: ${stats.count} 张 |
            大小: ${stats.totalSizeMB}MB |
            平均访问: ${stats.avgAccessCount} 次
        `;

        // 按时间倒序排列
        items.sort((a, b) => b.timestamp - a.timestamp);

        if (items.length === 0) {
            content.innerHTML = `
                <div class="comfy-history-empty">
                    <i class="fa fa-image"></i>
                    <p>还没有生成任何图片</p>
                </div>
            `;
            return;
        }

        content.innerHTML = items.map(item => `
            <div class="comfy-history-item" data-id="${item.id}">
                <div class="comfy-history-thumbnail" data-src="${item.data}">
                    <img src="${item.data}" alt="生成的图片">
                </div>
                <div class="comfy-history-info">
                    <div>
                        <strong>ID:</strong> ${item.id}
                    </div>
                    <div class="comfy-history-meta">
                        <span><i class="fa fa-clock"></i> ${item.ageInHours}小时前</span>
                        <span><i class="fa fa-eye"></i> 访问 ${item.accessCount} 次</span>
                        <span><i class="fa fa-file"></i> ${item.sizeMB}MB</span>
                    </div>
                    <div class="comfy-history-actions">
                        <button class="comfy-history-btn" data-action="view" data-id="${item.id}">
                            <i class="fa fa-search-plus"></i> 查看
                        </button>
                        <button class="comfy-history-btn" data-action="download" data-id="${item.id}">
                            <i class="fa fa-download"></i> 下载
                        </button>
                        <button class="comfy-history-btn danger" data-action="delete" data-id="${item.id}">
                            <i class="fa fa-trash"></i> 删除
                        </button>
                    </div>
                </div>
            </div>
        `).join('');

        // 绑定事件
        content.querySelectorAll('.comfy-history-thumbnail').forEach(thumb => {
            thumb.addEventListener('click', () => {
                openLightbox(thumb.dataset.src);
            });
        });

        content.querySelectorAll('.comfy-history-btn').forEach(btn => {
            btn.addEventListener('click', async (e) => {
                const action = btn.dataset.action;
                const id = btn.dataset.id;
                const item = items.find(i => i.id === id);

                if (!item) return;

                if (action === 'view') {
                    openLightbox(item.data);
                } else if (action === 'download') {
                    const filename = `comfyui-${id}-${Date.now()}.png`;
                    downloadImage(item.data, filename);
                } else if (action === 'delete') {
                    if (confirm('确定要删除这张图片吗?')) {
                        await deleteImageRecord(id);
                        await refreshHistoryPanel();
                        showNotification('图片已删除', 'success', 'standard');
                    }
                }
            });
        });
    }

    // --- Lightbox (Image Viewer) ---
    function createLightbox() {
        if (document.getElementById('comfy-lightbox')) return;

        const lightbox = document.createElement('div');
        lightbox.id = 'comfy-lightbox';
        lightbox.className = 'comfy-lightbox';
        lightbox.innerHTML = `
            <span class="comfy-lightbox-close">×</span>
            <img src="" alt="查看大图" data-current-index="-1">
            <button class="comfy-lightbox-download">
                <i class="fa fa-download"></i> 下载图片
            </button>
        `;

        document.body.appendChild(lightbox);

        const closeBtn = lightbox.querySelector('.comfy-lightbox-close');
        const downloadBtn = lightbox.querySelector('.comfy-lightbox-download');
        const img = lightbox.querySelector('img');

        // 【优化】添加移动端触摸手势支持(双指缩放、左右滑动)
        let touchStartX = 0;
        let touchStartY = 0;
        let touchStartDistance = 0;
        let currentScale = 1;

        lightbox.addEventListener('touchstart', (e) => {
            if (e.touches.length === 1) {
                // 单指触摸 - 准备滑动
                touchStartX = e.touches[0].clientX;
                touchStartY = e.touches[0].clientY;
            } else if (e.touches.length === 2) {
                // 双指触摸 - 准备缩放
                const dx = e.touches[0].clientX - e.touches[1].clientX;
                const dy = e.touches[0].clientY - e.touches[1].clientY;
                touchStartDistance = Math.sqrt(dx * dx + dy * dy);
            }
        }, { passive: true });

        lightbox.addEventListener('touchmove', (e) => {
            if (e.touches.length === 2) {
                // 双指缩放
                e.preventDefault();
                const dx = e.touches[0].clientX - e.touches[1].clientX;
                const dy = e.touches[0].clientY - e.touches[1].clientY;
                const distance = Math.sqrt(dx * dx + dy * dy);

                if (touchStartDistance > 0) {
                    const scale = (distance / touchStartDistance) * currentScale;
                    const clampedScale = Math.min(Math.max(scale, 0.5), 3); // 限制缩放范围
                    img.style.transform = `scale(${clampedScale})`;
                }
            }
        }, { passive: false });

        lightbox.addEventListener('touchend', (e) => {
            if (e.changedTouches.length === 1 && e.touches.length === 0) {
                // 单指离开 - 检查是否滑动
                const touchEndX = e.changedTouches[0].clientX;
                const touchEndY = e.changedTouches[0].clientY;
                const deltaX = touchEndX - touchStartX;
                const deltaY = touchEndY - touchStartY;

                // 水平滑动超过50px且垂直滑动小于30px
                if (Math.abs(deltaX) > 50 && Math.abs(deltaY) < 30) {
                    if (debugMode) {
                        console.log('[ComfyUI] 检测到滑动手势:', deltaX > 0 ? '右滑' : '左滑');
                    }
                    // 这里可以添加切换上一张/下一张图片的逻辑
                    // 暂时只做提示
                }
            } else if (e.touches.length === 0) {
                // 双指离开 - 保存当前缩放比例
                const transform = window.getComputedStyle(img).transform;
                if (transform !== 'none') {
                    const matrix = new DOMMatrix(transform);
                    currentScale = matrix.a; // a 是 scaleX
                }
            }
        }, { passive: true });

        // 【修复】关闭Lightbox的统一处理函数
        const closeLightbox = () => {
            lightbox.classList.remove('active');

            // 【优化】重置图片缩放和变换
            img.style.transform = '';
            currentScale = 1;

            // 【修复】恢复历史面板显示 - 清除内联样式即可,让CSS类控制
            const historyPanel = document.getElementById('comfy-history-panel');
            if (historyPanel && historyPanel.classList.contains('active')) {
                // 不再直接设置display:flex,而是清除内联样式,让.active类的CSS生效
                historyPanel.style.display = '';
            }

            console.log('[ComfyUI] Lightbox已关闭,历史面板已恢复');
        };

        // 关闭按钮
        closeBtn.addEventListener('click', closeLightbox);

        // 点击背景关闭
        lightbox.addEventListener('click', (e) => {
            if (e.target === lightbox) {
                closeLightbox();
            }
        });

        // ESC键关闭
        document.addEventListener('keydown', (e) => {
            if (e.key === 'Escape' && lightbox.classList.contains('active')) {
                closeLightbox();
            }
        });

        // 下载按钮
        downloadBtn.addEventListener('click', () => {
            const imageSrc = img.src;
            if (imageSrc) {
                const filename = `comfyui-${Date.now()}.png`;
                downloadImage(imageSrc, filename);
            }
        });
    }

    function openLightbox(imageSrc) {
        console.log('[ComfyUI] 尝试打开Lightbox');

        const lightbox = document.getElementById('comfy-lightbox');
        if (!lightbox) {
            console.log('[ComfyUI] Lightbox不存在,创建中...');
            createLightbox();
            // 递归调用以打开lightbox
            setTimeout(() => openLightbox(imageSrc), 100);
            return;
        }

        console.log('[ComfyUI] Lightbox元素已找到');

        // 【修复】在打开Lightbox时,暂时隐藏历史面板(避免层级冲突)
        const historyPanel = document.getElementById('comfy-history-panel');
        if (historyPanel && historyPanel.classList.contains('active')) {
            historyPanel.style.display = 'none';
            console.log('[ComfyUI] 历史面板已暂时隐藏');
        }

        const img = lightbox.querySelector('img');
        if (!img) {
            console.error('[ComfyUI Error] Lightbox中未找到img元素!');
            return;
        }

        console.log('[ComfyUI] 设置图片src,数据大小:', (imageSrc.length / 1024).toFixed(2), 'KB');
        console.log('[ComfyUI] 图片src前缀:', imageSrc.substring(0, 50));

        img.src = imageSrc;
        lightbox.classList.add('active');

        // 【修复】强制重绘,确保样式生效
        void lightbox.offsetHeight;

        console.log('[ComfyUI] Lightbox已添加active类');
        console.log('[ComfyUI] Lightbox display样式:', window.getComputedStyle(lightbox).display);
        console.log('[ComfyUI] 图片naturalWidth:', img.naturalWidth, 'naturalHeight:', img.naturalHeight);

        // 【修复】等待图片加载完成后再检查
        img.onload = () => {
            console.log('[ComfyUI] Lightbox图片加载成功!尺寸:', img.naturalWidth, 'x', img.naturalHeight);
        };

        img.onerror = () => {
            console.error('[ComfyUI Error] Lightbox图片加载失败!');
        };
    }

    // --- Core Application Logic (UI, Settings, Image Handling) ---

    // A flag to prevent duplicate execution
    let lastTapTimestamp = 0;
    const TAP_THRESHOLD = 300;

    function createComfyUIPanel() {
        if (document.getElementById(PANEL_ID)) return;

        const panelHTML = `
            <div id="${PANEL_ID}">
                <div class="panel-control-bar">
                    <div style="display: flex; align-items: center;">
                        <i class="fa-fw fa-solid fa-grip drag-grabber"></i>
                        <b>ComfyUI 插件设置</b>
                    </div>
                    <i class="fa-fw fa-solid fa-circle-xmark floating_panel_close"></i>
                </div>
                <div class="comfyui-panel-content">
                    <div id="comfyui-config-errors" class="comfy-config-error" style="display: none;"></div>

                    <!-- 基础设置 -->
                    <div class="comfy-settings-group">
                        <div class="comfy-settings-group-title">
                            <i class="fa fa-server"></i>
                            <span>连接设置</span>
                        </div>
                        <div class="comfy-field">
                            <label for="comfyui-url">调度器 URL (推荐使用HTTPS)</label>
                            <div class="comfy-url-container">
                                <input id="comfyui-url" type="text" placeholder="例如: https://127.0.0.1:5001">
                                <button id="comfyui-test-conn" class="comfy-button">测试连接</button>
                            </div>
                        </div>
                        <div class="comfy-field">
                            <label for="comfyui-api-key">API 密钥 (已加密存储)</label>
                            <input id="comfyui-api-key" type="password" placeholder="在此输入您的密钥">
                        </div>
                    </div>

                    <!-- 标记设置 -->
                    <div class="comfy-settings-group">
                        <div class="comfy-settings-group-title">
                            <i class="fa fa-tags"></i>
                            <span>标记与提示词</span>
                        </div>
                        <div class="comfy-tags-container">
                            <div class="comfy-field">
                                <label for="comfyui-start-tag">开始标记</label>
                                <input id="comfyui-start-tag" type="text">
                            </div>
                            <div class="comfy-field">
                                <label for="comfyui-end-tag">结束标记</label>
                                <input id="comfyui-end-tag" type="text">
                            </div>
                        </div>
                        <div class="comfy-field">
                            <label for="comfyui-prompt-prefix">提示词固定前缀 (LoRA等)</label>
                            <input id="comfyui-prompt-prefix" type="text" placeholder="例如: <lora:cool_style:0.8>">
                        </div>
                    </div>

                    <!-- 生成设置 -->
                    <div class="comfy-settings-group">
                        <div class="comfy-settings-group-title">
                            <i class="fa fa-image"></i>
                            <span>图片生成</span>
                        </div>
                        <div class="comfy-field">
                            <label for="comfyui-default-model">默认模型 (不指定时生效)</label>
                            <select id="comfyui-default-model">
                                <option value="">自动选择</option>
                                <option value="waiNSFWIllustrious_v140">waiNSFWIllustrious_v140</option>
                                <option value="Pony_alpha">Pony_alpha</option>
                            </select>
                        </div>
                        <div class="comfy-field">
                            <label for="comfyui-max-width">最大图片宽度 (px, 100-2000)</label>
                            <input id="comfyui-max-width" type="number" placeholder="600" min="100" max="2000">
                        </div>
                    </div>

                    <!-- 缓存与性能 -->
                    <div class="comfy-settings-group">
                        <div class="comfy-settings-group-title">
                            <i class="fa fa-database"></i>
                            <span>缓存管理</span>
                        </div>
                        <div class="comfy-field">
                            <label for="comfyui-cache-limit">最大缓存数量 (1-100)</label>
                            <input id="comfyui-cache-limit" type="number" placeholder="20" min="1" max="100">
                        </div>
                        <div id="comfyui-cache-status" style="margin-top: 8px;">当前缓存: ...</div>
                    </div>

                    <!-- 通知与行为 -->
                    <div class="comfy-settings-group">
                        <div class="comfy-settings-group-title">
                            <i class="fa fa-bell"></i>
                            <span>通知与行为</span>
                        </div>
                        <div class="comfy-field">
                            <label for="comfyui-notification-level">通知级别</label>
                            <select id="comfyui-notification-level">
                                <option value="silent">静默(仅错误)</option>
                                <option value="standard">标准(成功+错误)</option>
                                <option value="verbose">详细(所有通知)</option>
                            </select>
                        </div>
                        <div class="comfy-field">
                            <label>
                                <input type="checkbox" id="comfyui-enable-retry" style="width: auto; margin-right: 8px;">
                                启用自动重试(图片下载失败时)
                            </label>
                        </div>
                        <div style="margin-left: 24px; display: none;" id="comfyui-retry-options" class="comfy-field">
                            <label for="comfyui-retry-count">重试次数 (1-5)</label>
                            <input id="comfyui-retry-count" type="number" placeholder="3" min="1" max="5" style="width: 80px;">
                        </div>
                        <div class="comfy-field">
                            <label>
                                <input type="checkbox" id="comfyui-debug-mode" style="width: auto; margin-right: 8px;">
                                启用调试模式(在控制台查看详细日志)
                            </label>
                        </div>
                    </div>

                    <!-- 操作按钮 -->
                    <div class="comfy-settings-group">
                        <div class="comfy-settings-group-title">
                            <i class="fa fa-cogs"></i>
                            <span>操作</span>
                        </div>
                        <button id="comfyui-view-history" class="comfy-button" style="width: 100%; margin-bottom: 8px;">
                            <i class="fa fa-history"></i> 查看生成历史
                        </button>
                        <button id="comfyui-force-rescan" class="comfy-button" style="width: 100%; margin-bottom: 8px;">
                            <i class="fa fa-refresh"></i> 强制重新扫描所有消息
                        </button>
                        <button id="comfyui-validate-cache" class="comfy-button" style="width: 100%; margin-bottom: 8px;">
                            <i class="fa fa-check-circle"></i> 验证缓存完整性
                        </button>
                        <button id="comfyui-clear-cache" class="comfy-button error" style="width: 100%;">
                            <i class="fa fa-trash"></i> 删除所有图片缓存
                        </button>
                    </div>
                </div>
            </div>
        `;
        document.body.insertAdjacentHTML('beforeend', panelHTML);
        initPanelLogic();
    }

    async function updateCacheStatusDisplay() {
        try {
            const display = getCachedDOMElement('comfyui-cache-status') || document.getElementById('comfyui-cache-status');
            if (!display) return;

            let count, sizeMB;

            if (lruCache) {
                // 使用LRU缓存统计
                const stats = lruCache.getStats();
                count = stats.count;
                sizeMB = stats.totalSizeMB;
            } else {
                // 使用旧方法统计
            const records = await GM_getValue(STORAGE_KEY_IMAGES, {});
                count = Object.keys(records).length;
            const totalSize = Object.values(records).reduce((total, data) => {
                return total + (typeof data === 'string' ? data.length : 0);
            }, 0);
                sizeMB = (totalSize * 0.75 / 1024 / 1024).toFixed(1);
            }

            display.textContent = `当前缓存: ${count} / ${cachedSettings.cacheLimit} 张 (约 ${sizeMB}MB)`;

            setCachedDOMElement('comfyui-cache-status', display);
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('更新缓存状态失败: ' + error.message, 'CACHE'), 'updateCacheStatusDisplay');
        }
    }

    // 【优化】创建防抖版本的缓存状态更新函数
    const debouncedUpdateCacheStatus = debounce(updateCacheStatusDisplay, 300);

    // DOM缓存管理
    function getCachedDOMElement(id) {
        return cachedDOMElements[id];
    }

    function setCachedDOMElement(id, element) {
        cachedDOMElements[id] = element;
    }

    function clearDOMCache() {
        cachedDOMElements = {};
    }

    function showConfigErrors(errors) {
        const errorContainer = document.getElementById('comfyui-config-errors');
        if (errorContainer) {
            if (errors.length > 0) {
                errorContainer.innerHTML = errors.map(error => `• ${error}`).join('<br>');
                errorContainer.style.display = 'block';
            } else {
                errorContainer.style.display = 'none';
            }
        }
    }

    function initPanelLogic() {
        const panel = document.getElementById(PANEL_ID);
        const closeButton = panel.querySelector('.floating_panel_close');
        const testButton = document.getElementById('comfyui-test-conn');
        const clearCacheButton = document.getElementById('comfyui-clear-cache');
        const validateCacheButton = document.getElementById('comfyui-validate-cache');
        const forceRescanButton = document.getElementById('comfyui-force-rescan');
        const viewHistoryButton = document.getElementById('comfyui-view-history');
        const debugModeCheckbox = document.getElementById('comfyui-debug-mode');
        const urlInput = document.getElementById('comfyui-url');
        const startTagInput = document.getElementById('comfyui-start-tag');
        const endTagInput = document.getElementById('comfyui-end-tag');
        const promptPrefixInput = document.getElementById('comfyui-prompt-prefix');
        const maxWidthInput = document.getElementById('comfyui-max-width');
        const cacheLimitInput = document.getElementById('comfyui-cache-limit');
        const apiKeyInput = document.getElementById('comfyui-api-key');
        const defaultModelSelect = document.getElementById('comfyui-default-model');
        const notificationLevelSelect = document.getElementById('comfyui-notification-level');
        const enableRetryCheckbox = document.getElementById('comfyui-enable-retry');
        const retryCountInput = document.getElementById('comfyui-retry-count');
        const retryOptions = document.getElementById('comfyui-retry-options');

        // 缓存常用DOM元素
        setCachedDOMElement('panel', panel);
        setCachedDOMElement('testButton', testButton);

        // 重试选项显示/隐藏控制
        enableRetryCheckbox.addEventListener('change', () => {
            retryOptions.style.display = enableRetryCheckbox.checked ? 'block' : 'none';
        });

        // 查看历史记录按钮
        viewHistoryButton.addEventListener('click', () => {
            panel.style.display = 'none';
            openHistoryPanel();
        });

        closeButton.addEventListener('click', () => {
            panel.style.display = 'none';
        });

        testButton.addEventListener('click', () => {
            try {
                let url = urlInput.value.trim();
                if (!url) {
                    throw new ComfyUIError('请输入调度器的URL', 'VALIDATION');
                }

                if (!url.startsWith('http')) {
                    url = 'https://' + url; // 默认使用HTTPS
                }
                if (url.endsWith('/')) {
                    url = url.slice(0, -1);
                }

                // 验证URL
                if (!validateUrl(url)) {
                    throw new ComfyUIError('URL格式无效或不安全,请使用HTTPS', 'VALIDATION');
                }

                urlInput.value = url;
                const testUrl = url + '/system_stats';

                if (typeof toastr !== 'undefined') toastr.info('正在尝试连接服务...');
                testButton.className = 'comfy-button testing';
                testButton.disabled = true;

                performanceMonitor.startTimer('testConnection');

                GM_xmlhttpRequest({
                    method: "GET",
                    url: testUrl,
                    timeout: 10000,
                    onload: (res) => {
                        performanceMonitor.endTimer('testConnection');
                        testButton.disabled = false;
                        testButton.className = res.status === 200 ? 'comfy-button success' : 'comfy-button error';
                        if (res.status === 200) {
                            if (typeof toastr !== 'undefined') toastr.success('连接成功!');
                        } else {
                            if (typeof toastr !== 'undefined') toastr.error(`连接失败!状态: ${res.status}`);
                        }
                    },
                    onerror: (error) => {
                        performanceMonitor.endTimer('testConnection');
                        testButton.disabled = false;
                        testButton.className = 'comfy-button error';
                        ErrorHandler.handle(new ComfyUIError('连接失败', 'NETWORK'), 'testConnection');
                    },
                    ontimeout: () => {
                        performanceMonitor.endTimer('testConnection');
                        testButton.disabled = false;
                        testButton.className = 'comfy-button error';
                        ErrorHandler.handle(new ComfyUIError('连接超时', 'NETWORK'), 'testConnection');
                    }
                });
            } catch (error) {
                ErrorHandler.handle(error, 'testConnection');
                testButton.disabled = false;
                testButton.className = 'comfy-button error';
            }
        });

        clearCacheButton.addEventListener('click', async () => {
            if (confirm('您确定要删除所有已生成的图片缓存吗?')) {
                try {
                    performanceMonitor.startTimer('clearCache');

                    if (lruCache) {
                        await lruCache.clear();
                    } else {
                    await GM_setValue(STORAGE_KEY_IMAGES, {});
                    }

                    await updateCacheStatusDisplay();  // 【注意】这里立即更新,不使用防抖
                    performanceMonitor.endTimer('clearCache');
                    showNotification('图片缓存已清空!', 'success', 'standard');
                } catch (error) {
                    ErrorHandler.handle(new ComfyUIError('清空缓存失败: ' + error.message, 'CACHE'), 'clearCache');
                }
            }
        });

        validateCacheButton.addEventListener('click', async () => {
            try {
                validateCacheButton.disabled = true;
                validateCacheButton.textContent = '验证中...';

                const validCount = await validateCacheIntegrity();
                await updateCacheStatusDisplay();  // 【注意】这里立即更新,不使用防抖

                validateCacheButton.disabled = false;
                validateCacheButton.textContent = '验证缓存完整性';

                if (typeof toastr !== 'undefined') {
                    toastr.success(`缓存验证完成,有效记录: ${validCount} 条`);
                }
            } catch (error) {
                validateCacheButton.disabled = false;
                validateCacheButton.textContent = '验证缓存完整性';
                ErrorHandler.handle(error, 'validateCache');
            }
        });

        // 调试模式开关
        debugModeCheckbox.addEventListener('change', async () => {
            debugMode = debugModeCheckbox.checked;
            await GM_setValue('comfyui_debug_mode', debugMode);

            if (debugMode) {
                console.log('[ComfyUI Debug] 调试模式已启用');
                if (typeof toastr !== 'undefined') {
                    toastr.info('调试模式已启用,请查看浏览器控制台');
                }
            } else {
                console.log('[ComfyUI Debug] 调试模式已禁用');
            }
        });

        // 强制重新扫描所有消息
        forceRescanButton.addEventListener('click', async () => {
            try {
                forceRescanButton.disabled = true;
                forceRescanButton.textContent = '扫描中...';

                const chatElement = document.getElementById('chat');
                if (chatElement) {
                    const allMessages = chatElement.querySelectorAll('.mes');
                    const savedImages = await GM_getValue(STORAGE_KEY_IMAGES, {});

                    console.log(`[ComfyUI] 开始强制重新扫描 ${allMessages.length} 条消息`);

                    // 清除已有的监听器标记
                    allMessages.forEach(node => {
                        const mesTextElement = node.querySelector('.mes_text');
                        if (mesTextElement) {
                            mesTextElement.dataset.listenersAttached = '';
                            // 移除现有的按钮组以避免重复
                            const existingButtons = mesTextElement.querySelectorAll('.comfy-button-group');
                            existingButtons.forEach(btn => btn.remove());
                        }
                    });

                    // 重新处理所有消息
                    for (const node of allMessages) {
                        try {
                            const mesTextElement = node.querySelector('.mes_text');
                            if (mesTextElement && !mesTextElement.dataset.listenersAttached) {
                                mesTextElement.addEventListener('touchstart', (event) => handleComfyButtonClick(event, true), { passive: false });
                                mesTextElement.addEventListener('click', (event) => handleComfyButtonClick(event, false));
                                mesTextElement.dataset.listenersAttached = 'true';
                            }
                            await processMessageForComfyButton(node, savedImages);
                        } catch (error) {
                            console.error('处理消息节点失败:', error);
                        }
                    }

                    console.log('[ComfyUI] 强制重新扫描完成');
                    if (typeof toastr !== 'undefined') {
                        toastr.success(`已重新扫描 ${allMessages.length} 条消息`);
                    }
                } else {
                    if (typeof toastr !== 'undefined') {
                        toastr.error('未找到聊天区域,无法执行扫描');
                    }
                }

                forceRescanButton.disabled = false;
                forceRescanButton.textContent = '强制重新扫描所有消息';

            } catch (error) {
                forceRescanButton.disabled = false;
                forceRescanButton.textContent = '强制重新扫描所有消息';
                ErrorHandler.handle(new ComfyUIError('强制重新扫描失败: ' + error.message, 'UI'), 'forceRescan');
            }
        });

        loadSettings(urlInput, startTagInput, endTagInput, promptPrefixInput, maxWidthInput, cacheLimitInput, apiKeyInput, defaultModelSelect, notificationLevelSelect, enableRetryCheckbox, retryCountInput, debugModeCheckbox).then(() => {
            applyCurrentMaxWidthToAllImages();
        });

        [urlInput, startTagInput, endTagInput, promptPrefixInput, maxWidthInput, cacheLimitInput, apiKeyInput, defaultModelSelect, notificationLevelSelect, enableRetryCheckbox, retryCountInput, debugModeCheckbox].forEach(input => {
            const eventType = input.type === 'checkbox' ? 'change' : (input.tagName.toLowerCase() === 'select' ? 'change' : 'input');
            input.addEventListener(eventType, async () => {
                try {
                    if (input === urlInput) testButton.className = 'comfy-button';

                    // 【优化】使用防抖版本的saveSettings,减少频繁保存
                    debouncedSaveSettings(urlInput, startTagInput, endTagInput, promptPrefixInput, maxWidthInput, cacheLimitInput, apiKeyInput, defaultModelSelect, notificationLevelSelect, enableRetryCheckbox, retryCountInput);

                    if (input === maxWidthInput) applyCurrentMaxWidthToAllImages();
                    if (input === urlInput) {
                        if (socket) socket.disconnect();
                        setTimeout(connectWebSocket, 500); // 延迟重连
                    }
                } catch (error) {
                    ErrorHandler.handle(error, 'saveSettings');
                }
            });
        });
    }

    async function loadSettings(urlInput, startTagInput, endTagInput, promptPrefixInput, maxWidthInput, cacheLimitInput, apiKeyInput, defaultModelSelect, notificationLevelSelect, enableRetryCheckbox, retryCountInput, debugModeCheckbox) {
        try {
            performanceMonitor.startTimer('loadSettings');

            cachedSettings.comfyuiUrl = await GM_getValue('comfyui_url', 'https://127.0.0.1:5001');
            cachedSettings.startTag = await GM_getValue('comfyui_start_tag', 'image###');
            cachedSettings.endTag = await GM_getValue('comfyui_end_tag', '###');
            cachedSettings.promptPrefix = await GM_getValue(STORAGE_KEY_PROMPT_PREFIX, '');
            cachedSettings.maxWidth = await GM_getValue(STORAGE_KEY_MAX_WIDTH, 600);
            cachedSettings.cacheLimit = await GM_getValue(STORAGE_KEY_CACHE_LIMIT, 20);

            // 解密API密钥
            const encryptedApiKey = await GM_getValue('comfyui_api_key', '');
            cachedSettings.apiKey = decryptApiKey(encryptedApiKey);

            cachedSettings.defaultModel = await GM_getValue('comfyui_default_model', '');
            cachedSettings.notificationLevel = await GM_getValue('comfyui_notification_level', 'silent');
            cachedSettings.enableRetry = await GM_getValue('comfyui_enable_retry', true);
            cachedSettings.retryCount = await GM_getValue('comfyui_retry_count', 3);

            urlInput.value = cachedSettings.comfyuiUrl;
            startTagInput.value = cachedSettings.startTag;
            endTagInput.value = cachedSettings.endTag;
            promptPrefixInput.value = cachedSettings.promptPrefix;
            maxWidthInput.value = cachedSettings.maxWidth;
            cacheLimitInput.value = cachedSettings.cacheLimit;
            apiKeyInput.value = cachedSettings.apiKey;
            defaultModelSelect.value = cachedSettings.defaultModel;
            notificationLevelSelect.value = cachedSettings.notificationLevel;
            enableRetryCheckbox.checked = cachedSettings.enableRetry;
            retryCountInput.value = cachedSettings.retryCount;

            // 显示/隐藏重试选项
            document.getElementById('comfyui-retry-options').style.display = cachedSettings.enableRetry ? 'block' : 'none';

            // 加载调试模式设置
            debugMode = await GM_getValue('comfyui_debug_mode', false);
            debugModeCheckbox.checked = debugMode;

            document.documentElement.style.setProperty('--comfy-image-max-width', (cachedSettings.maxWidth || 600) + 'px');
            await updateCacheStatusDisplay();

            // 验证配置
            const configErrors = validateConfig(cachedSettings);
            showConfigErrors(configErrors);

            performanceMonitor.endTimer('loadSettings');
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('加载设置失败: ' + error.message, 'CONFIG'), 'loadSettings');
        }
    }

    async function saveSettings(urlInput, startTagInput, endTagInput, promptPrefixInput, maxWidthInput, cacheLimitInput, apiKeyInput, defaultModelSelect, notificationLevelSelect, enableRetryCheckbox, retryCountInput) {
        try {
            performanceMonitor.startTimer('saveSettings');

            const newSettings = {
                comfyuiUrl: urlInput.value.trim(),
                startTag: startTagInput.value,
                endTag: endTagInput.value,
                promptPrefix: promptPrefixInput.value.trim(),
                maxWidth: parseInt(maxWidthInput.value) || 600,
                cacheLimit: parseInt(cacheLimitInput.value) || 20,
                apiKey: apiKeyInput.value.trim(),
                defaultModel: defaultModelSelect.value,
                notificationLevel: notificationLevelSelect.value,
                enableRetry: enableRetryCheckbox.checked,
                retryCount: parseInt(retryCountInput.value) || 3
            };

            // 验证新配置
            const configErrors = validateConfig(newSettings);
            showConfigErrors(configErrors);

            // 如果有严重错误,不保存配置
            if (configErrors.length > 0 && configErrors.some(error => error.includes('URL'))) {
                return;
            }

            // 更新缓存设置
            Object.assign(cachedSettings, newSettings);

            // 加密并保存API密钥
            const encryptedApiKey = encryptApiKey(cachedSettings.apiKey);

            await GM_setValue('comfyui_url', cachedSettings.comfyuiUrl);
            await GM_setValue('comfyui_start_tag', cachedSettings.startTag);
            await GM_setValue('comfyui_end_tag', cachedSettings.endTag);
            await GM_setValue(STORAGE_KEY_PROMPT_PREFIX, cachedSettings.promptPrefix);
            await GM_setValue(STORAGE_KEY_MAX_WIDTH, cachedSettings.maxWidth);
            await GM_setValue(STORAGE_KEY_CACHE_LIMIT, cachedSettings.cacheLimit);
            await GM_setValue('comfyui_api_key', encryptedApiKey);
            await GM_setValue('comfyui_default_model', cachedSettings.defaultModel);
            await GM_setValue('comfyui_notification_level', cachedSettings.notificationLevel);
            await GM_setValue('comfyui_enable_retry', cachedSettings.enableRetry);
            await GM_setValue('comfyui_retry_count', cachedSettings.retryCount);

            // 如果缓存限制改变,更新LRU缓存大小
            if (lruCache && lruCache.maxSize !== cachedSettings.cacheLimit) {
                lruCache.maxSize = cachedSettings.cacheLimit;
                if (lruCache.cache.size > lruCache.maxSize) {
                    await lruCache.evict();
                }
            }

            document.documentElement.style.setProperty('--comfy-image-max-width', cachedSettings.maxWidth + 'px');
            debouncedUpdateCacheStatus();  // 【优化】使用防抖版本

            performanceMonitor.endTimer('saveSettings');
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('保存设置失败: ' + error.message, 'CONFIG'), 'saveSettings');
        }
    }

    // 【优化】创建防抖版本的设置保存函数
    const debouncedSaveSettings = debounce(saveSettings, 500);

    async function applyCurrentMaxWidthToAllImages() {
        try {
            const images = document.querySelectorAll('.comfy-image-container img');
            const maxWidthPx = (cachedSettings.maxWidth || 600) + 'px';
            images.forEach(img => {
                img.style.maxWidth = maxWidthPx;
            });
        } catch (error) {
            console.error('应用图片宽度设置失败:', error);
        }
    }

    function addMainButton() {
        if (document.getElementById(BUTTON_ID)) return;

        const optionsMenuContent = document.querySelector('#options .options-content');
        if (optionsMenuContent) {
            const continueButton = optionsMenuContent.querySelector('#option_continue');
            if (continueButton) {
                const comfyButton = document.createElement('a');
                comfyButton.id = BUTTON_ID;
                comfyButton.className = 'interactable';
                comfyButton.innerHTML = `<i class="fa-lg fa-solid fa-image"></i><span>ComfyUI生图 (优化版)</span>`;
                comfyButton.style.cursor = 'pointer';
                comfyButton.addEventListener('click', (event) => {
                    event.preventDefault();
                    document.getElementById(PANEL_ID).style.display = 'flex';
                    document.getElementById('options').style.display = 'none';
                });
                continueButton.parentNode.insertBefore(comfyButton, continueButton.nextSibling);
            }
        }
    }

    // --- Helper and Cache Management ---
    function escapeRegex(string) {
        return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
    }

    function generateClientId() {
        return 'client-' + Math.random().toString(36).substring(2, 15) + '-' + Date.now();
    }

    function simpleHash(str) {
        let hash = 0;
        for (let i = 0; i < str.length; i++) {
            const char = str.charCodeAt(i);
            hash = (hash << 5) - hash + char;
            hash |= 0;
        }
        return 'comfy-id-' + Math.abs(hash).toString(36);
    }

    // --- 防抖节流工具函数 ---
    /**
     * 防抖函数 - 延迟执行,多次触发只执行最后一次
     * @param {Function} func - 要执行的函数
     * @param {number} wait - 延迟时间(毫秒)
     * @returns {Function} 防抖后的函数
     */
    function debounce(func, wait = 300) {
        let timeout;
        return function executedFunction(...args) {
            const later = () => {
                clearTimeout(timeout);
                func.apply(this, args);
            };
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    }

    /**
     * 节流函数 - 限制执行频率,固定时间内只执行一次
     * @param {Function} func - 要执行的函数
     * @param {number} limit - 时间间隔(毫秒)
     * @returns {Function} 节流后的函数
     */
    function throttle(func, limit = 200) {
        let inThrottle;
        return function executedFunction(...args) {
            if (!inThrottle) {
                func.apply(this, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        };
    }

    // --- Image Download Helper ---
    function downloadImage(imageData, filename = 'comfyui-image.png') {
        try {
            const link = document.createElement('a');
            link.href = imageData;
            link.download = filename;
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            showNotification('图片已保存!', 'success', 'standard');
        } catch (error) {
            console.error('下载图片失败:', error);
            showNotification('下载失败,请重试', 'error');
        }
    }

    // --- IndexedDB Cache Manager ---
    class IndexedDBCache {
        constructor(dbName = 'ComfyUICache', version = 1) {
            this.dbName = dbName;
            this.version = version;
            this.db = null;
            this.storeName = 'images';
        }

        async init() {
            return new Promise((resolve, reject) => {
                const request = indexedDB.open(this.dbName, this.version);

                request.onerror = () => {
                    console.error('[IndexedDB] 打开数据库失败:', request.error);
                    reject(new ComfyUIError('IndexedDB初始化失败', 'CACHE'));
                };

                request.onsuccess = () => {
                    this.db = request.result;
                    console.log('[IndexedDB] 数据库已打开');
                    resolve();
                };

                request.onupgradeneeded = (event) => {
                    const db = event.target.result;

                    // 创建对象存储
                    if (!db.objectStoreNames.contains(this.storeName)) {
                        const objectStore = db.createObjectStore(this.storeName, { keyPath: 'id' });
                        objectStore.createIndex('timestamp', 'timestamp', { unique: false });
                        objectStore.createIndex('size', 'size', { unique: false });
                        console.log('[IndexedDB] 对象存储已创建');
                    }
                };
            });
        }

        async set(id, data, metadata = {}) {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new ComfyUIError('IndexedDB未初始化', 'CACHE'));
                    return;
                }

                const transaction = this.db.transaction([this.storeName], 'readwrite');
                const objectStore = transaction.objectStore(this.storeName);

                const record = {
                    id,
                    data,
                    timestamp: Date.now(),
                    size: data.length,
                    accessCount: metadata.accessCount || 0,
                    ...metadata
                };

                const request = objectStore.put(record);

                request.onsuccess = () => {
                    if (debugMode) {
                        console.log(`[IndexedDB] 已保存: ${id}, 大小: ${(data.length / 1024).toFixed(2)}KB`);
                    }
                    resolve();
                };

                request.onerror = () => {
                    console.error('[IndexedDB] 保存失败:', request.error);
                    reject(new ComfyUIError('IndexedDB保存失败', 'CACHE'));
                };
            });
        }

        async get(id) {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new ComfyUIError('IndexedDB未初始化', 'CACHE'));
                    return;
                }

                const transaction = this.db.transaction([this.storeName], 'readonly');
                const objectStore = transaction.objectStore(this.storeName);
                const request = objectStore.get(id);

                request.onsuccess = () => {
                    const record = request.result;
                    if (record) {
                        if (debugMode) {
                            console.log(`[IndexedDB] 读取成功: ${id}`);
                        }
                        resolve(record);
                    } else {
                        resolve(null);
                    }
                };

                request.onerror = () => {
                    console.error('[IndexedDB] 读取失败:', request.error);
                    reject(new ComfyUIError('IndexedDB读取失败', 'CACHE'));
                };
            });
        }

        async delete(id) {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new ComfyUIError('IndexedDB未初始化', 'CACHE'));
                    return;
                }

                const transaction = this.db.transaction([this.storeName], 'readwrite');
                const objectStore = transaction.objectStore(this.storeName);
                const request = objectStore.delete(id);

                request.onsuccess = () => {
                    if (debugMode) {
                        console.log(`[IndexedDB] 已删除: ${id}`);
                    }
                    resolve();
                };

                request.onerror = () => {
                    console.error('[IndexedDB] 删除失败:', request.error);
                    reject(new ComfyUIError('IndexedDB删除失败', 'CACHE'));
                };
            });
        }

        async getAll() {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new ComfyUIError('IndexedDB未初始化', 'CACHE'));
                    return;
                }

                const transaction = this.db.transaction([this.storeName], 'readonly');
                const objectStore = transaction.objectStore(this.storeName);
                const request = objectStore.getAll();

                request.onsuccess = () => {
                    resolve(request.result || []);
                };

                request.onerror = () => {
                    console.error('[IndexedDB] 获取全部数据失败:', request.error);
                    reject(new ComfyUIError('IndexedDB查询失败', 'CACHE'));
                };
            });
        }

        async clear() {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new ComfyUIError('IndexedDB未初始化', 'CACHE'));
                    return;
                }

                const transaction = this.db.transaction([this.storeName], 'readwrite');
                const objectStore = transaction.objectStore(this.storeName);
                const request = objectStore.clear();

                request.onsuccess = () => {
                    console.log('[IndexedDB] 已清空所有数据');
                    resolve();
                };

                request.onerror = () => {
                    console.error('[IndexedDB] 清空失败:', request.error);
                    reject(new ComfyUIError('IndexedDB清空失败', 'CACHE'));
                };
            });
        }

        async count() {
            return new Promise((resolve, reject) => {
                if (!this.db) {
                    reject(new ComfyUIError('IndexedDB未初始化', 'CACHE'));
                    return;
                }

                const transaction = this.db.transaction([this.storeName], 'readonly');
                const objectStore = transaction.objectStore(this.storeName);
                const request = objectStore.count();

                request.onsuccess = () => {
                    resolve(request.result);
                };

                request.onerror = () => {
                    reject(new ComfyUIError('IndexedDB计数失败', 'CACHE'));
                };
            });
        }

        async getTotalSize() {
            const records = await this.getAll();
            return records.reduce((total, record) => total + (record.size || 0), 0);
        }
    }

    // --- LRU Cache Manager (增强版 - 配合IndexedDB使用) ---
    class LRUCache {
        constructor(maxSize = 20, useIndexedDB = true) {
            this.maxSize = maxSize;
            this.cache = new Map(); // key -> {data, timestamp, size, accessCount}
            this.useIndexedDB = useIndexedDB;
            this.indexedDB = null;
        }

        async load() {
            try {
                // 【优化】优先从IndexedDB加载
                if (this.useIndexedDB && this.indexedDB) {
                    const records = await this.indexedDB.getAll();
                    this.cache.clear();

                    for (const record of records) {
                        this.cache.set(record.id, {
                            data: record.data,
                            timestamp: record.timestamp || Date.now(),
                            size: record.size || record.data.length,
                            accessCount: record.accessCount || 0
                        });
                    }

                    console.log(`[LRU Cache] 从IndexedDB加载 ${this.cache.size} 条记录`);
                } else {
                    // 回退到GM_getValue
                const records = await GM_getValue(STORAGE_KEY_IMAGES, {});
                this.cache.clear();

                for (const [id, data] of Object.entries(records)) {
                    this.cache.set(id, {
                        data,
                        timestamp: Date.now(),
                        size: data.length,
                        accessCount: 0
                    });
                }

                    console.log(`[LRU Cache] 从GM_getValue加载 ${this.cache.size} 条记录`);
                }
            } catch (error) {
                console.error('LRU缓存加载失败:', error);
            }
        }

        async get(key) {
            const item = this.cache.get(key);
            if (item) {
                // 更新访问时间和计数
                item.timestamp = Date.now();
                item.accessCount++;
                this.cache.delete(key);
                this.cache.set(key, item); // 移到末尾(最近使用)

                if (debugMode) {
                    console.log(`[LRU Cache] 缓存命中: ${key}, 访问次数: ${item.accessCount}`);
                }

                return item.data;
            }
            return null;
        }

        async set(key, data) {
            // 如果已存在,先删除
            if (this.cache.has(key)) {
                this.cache.delete(key);
            }

            // 添加新项
            const item = {
                data,
                timestamp: Date.now(),
                size: data.length,
                accessCount: 1
            };

            this.cache.set(key, item);

            // 【优化】如果使用IndexedDB,直接保存到IndexedDB
            if (this.useIndexedDB && this.indexedDB) {
                try {
                    await this.indexedDB.set(key, data, {
                        timestamp: item.timestamp,
                        accessCount: item.accessCount
                    });
                } catch (error) {
                    console.error('[LRU Cache] IndexedDB保存失败,回退到GM_setValue:', error);
                    await this.save(); // 回退方案
                }
            } else {
                // 回退到GM_setValue
                await this.save();
            }

            // 如果超过最大容量,移除最少使用的项
            if (this.cache.size > this.maxSize) {
                await this.evict();
            }
        }

        async evict() {
            // 获取所有缓存项并按优先级排序
            const items = Array.from(this.cache.entries()).map(([key, value]) => ({
                key,
                ...value,
                score: this.calculateScore(value)
            }));

            // 按分数排序(分数越低越应该被删除)
            items.sort((a, b) => a.score - b.score);

            // 删除最低优先级的项
            const toRemove = items.slice(0, this.cache.size - this.maxSize + 1);

            for (const item of toRemove) {
                this.cache.delete(item.key);

                // 【优化】同时从IndexedDB删除
                if (this.useIndexedDB && this.indexedDB) {
                    try {
                        await this.indexedDB.delete(item.key);
                    } catch (error) {
                        console.error('[LRU Cache] IndexedDB删除失败:', error);
                    }
                }

                if (debugMode) {
                    console.log(`[LRU Cache] 移除缓存: ${item.key}, 分数: ${item.score.toFixed(2)}`);
                }
            }
        }

        calculateScore(item) {
            // 计算缓存项的重要性分数
            const ageInDays = (Date.now() - item.timestamp) / (1000 * 60 * 60 * 24);
            const sizeInMB = item.size / (1024 * 1024);

            // 分数 = 访问次数 / (年龄 + 1) - 大小惩罚
            // 访问次数越多、越新的项分数越高
            // 文件越大会降低分数
            return (item.accessCount / (ageInDays + 1)) - (sizeInMB * 0.5);
        }

        async delete(key) {
            if (this.cache.has(key)) {
                this.cache.delete(key);

                // 【优化】从IndexedDB删除
                if (this.useIndexedDB && this.indexedDB) {
                    try {
                        await this.indexedDB.delete(key);
                    } catch (error) {
                        console.error('[LRU Cache] IndexedDB删除失败:', error);
                        await this.save(); // 回退方案
                    }
                } else {
                await this.save();
                }

                return true;
            }
            return false;
        }

        async save() {
            try {
                // 【优化】如果使用IndexedDB,不需要批量保存
                if (this.useIndexedDB && this.indexedDB) {
                    // IndexedDB已经实时保存,这里不需要做任何事
                    return;
                }

                // 回退到GM_setValue
                const records = {};
                for (const [key, value] of this.cache.entries()) {
                    records[key] = value.data;
                }
                await GM_setValue(STORAGE_KEY_IMAGES, records);
            } catch (error) {
                console.error('LRU缓存保存失败:', error);
            }
        }

        async clear() {
            this.cache.clear();

            // 【优化】同时清空IndexedDB
            if (this.useIndexedDB && this.indexedDB) {
                try {
                    await this.indexedDB.clear();
                } catch (error) {
                    console.error('[LRU Cache] IndexedDB清空失败:', error);
                    await GM_setValue(STORAGE_KEY_IMAGES, {}); // 回退方案
                }
            } else {
            await GM_setValue(STORAGE_KEY_IMAGES, {});
            }
        }

        getStats() {
            const items = Array.from(this.cache.values());
            const totalSize = items.reduce((sum, item) => sum + item.size, 0);
            const totalAccess = items.reduce((sum, item) => sum + item.accessCount, 0);

            return {
                count: this.cache.size,
                maxSize: this.maxSize,
                totalSize,
                totalSizeMB: (totalSize * 0.75 / 1024 / 1024).toFixed(1),
                totalAccess,
                avgAccessCount: items.length > 0 ? (totalAccess / items.length).toFixed(1) : 0
            };
        }

        getAll() {
            return Array.from(this.cache.entries()).map(([key, value]) => ({
                id: key,
                ...value,
                sizeMB: (value.size * 0.75 / 1024 / 1024).toFixed(2),
                ageInHours: ((Date.now() - value.timestamp) / (1000 * 60 * 60)).toFixed(1)
            }));
        }
    }

    // 全局LRU缓存实例
    let lruCache = null;

    // --- Retry with Exponential Backoff ---
    async function retryWithBackoff(fn, maxRetries = 3, baseDelay = 1000) {
        for (let i = 0; i < maxRetries; i++) {
            try {
                return await fn();
            } catch (error) {
                if (i === maxRetries - 1) {
                    throw error;
                }

                const delay = baseDelay * Math.pow(2, i);
                console.log(`重试 ${i + 1}/${maxRetries},等待 ${delay}ms...`);

                if (debugMode) {
                    console.log(`[ComfyUI Debug] 重试原因: ${error.message}`);
                }

                await new Promise(resolve => setTimeout(resolve, delay));
            }
        }
    }

    async function saveImageRecord(generationId, imageBase64Data) {
        try {
            performanceMonitor.startTimer('saveImageRecord');

            if (lruCache) {
                await lruCache.set(generationId, imageBase64Data);

                const stats = lruCache.getStats();
                if (debugMode) {
                    console.log(`[LRU Cache] 保存成功: ${generationId}, 当前: ${stats.count}/${stats.maxSize}`);
                }
            } else {
                // 回退到旧方法
            let records = await GM_getValue(STORAGE_KEY_IMAGES, {});
            if (records.hasOwnProperty(generationId)) delete records[generationId];
            records[generationId] = imageBase64Data;

            const keys = Object.keys(records);
            if (keys.length > cachedSettings.cacheLimit) {
                const keysToDelete = keys.slice(0, keys.length - cachedSettings.cacheLimit);
                keysToDelete.forEach(key => delete records[key]);
                console.log(`缓存已满,删除了 ${keysToDelete.length} 条旧记录。`);
            }

            await GM_setValue(STORAGE_KEY_IMAGES, records);
            }

            debouncedUpdateCacheStatus();  // 【优化】使用防抖版本
            performanceMonitor.endTimer('saveImageRecord');
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('保存图片记录失败: ' + error.message, 'CACHE'), 'saveImageRecord');
        }
    }

    async function deleteImageRecord(generationId) {
        try {
            if (lruCache) {
                await lruCache.delete(generationId);
            } else {
            const records = await GM_getValue(STORAGE_KEY_IMAGES, {});
            delete records[generationId];
            await GM_setValue(STORAGE_KEY_IMAGES, records);
            }
            debouncedUpdateCacheStatus();  // 【优化】使用防抖版本
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('删除图片记录失败: ' + error.message, 'CACHE'), 'deleteImageRecord');
        }
    }


    // --- Chat Message Processing and Image Generation ---
    function handleComfyButtonClick(event, isTouch = false) {
        try {
            const button = event.target.closest('.comfy-chat-generate-button');
            if (!button) return;

            if (isTouch) {
                event.preventDefault();
                const now = Date.now();
                if (now - lastTapTimestamp < TAP_THRESHOLD) return;
                lastTapTimestamp = now;
                onGenerateButtonClickLogic(button);
            } else {
                if (Date.now() - lastTapTimestamp < TAP_THRESHOLD) return;
                onGenerateButtonClickLogic(button);
            }
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('处理按钮点击失败: ' + error.message, 'UI'), 'handleComfyButtonClick');
        }
    }

    async function processMessageForComfyButton(messageNode, savedImagesCache) {
        try {
            const mesText = messageNode.querySelector('.mes_text');
            if (!mesText) {
                if (debugMode) console.log('[ComfyUI Debug] 未找到 .mes_text 元素');
                return;
            }

            const { startTag, endTag } = cachedSettings;
            if (!startTag || !endTag) {
                if (debugMode) console.log('[ComfyUI Debug] 开始或结束标签未配置:', { startTag, endTag });
                return;
            }

            if (debugMode) {
                console.log('[ComfyUI Debug] 开始处理消息, 标签:', { startTag, endTag });
                console.log('[ComfyUI Debug] 消息内容:', mesText.innerHTML);
            }

            const regex = new RegExp(
                escapeRegex(startTag) +
                '(?:\\[model=([\\w.-]+)\\])?' +
                '([\\s\\S]*?)' +
                escapeRegex(endTag),
                'g'
            );

            if (debugMode) console.log('[ComfyUI Debug] 使用的正则表达式:', regex);

            const currentHtml = mesText.innerHTML;
            const matches = currentHtml.match(regex);
            if (debugMode) console.log('[ComfyUI Debug] 正则匹配结果:', matches);

            // 检查是否存在文本内容中的标签(未被HTML转义的)
            const textContent = mesText.textContent || mesText.innerText || '';
            if (debugMode) console.log('[ComfyUI Debug] 纯文本内容:', textContent);

            const textMatches = textContent.match(regex);
            if (debugMode) console.log('[ComfyUI Debug] 纯文本匹配结果:', textMatches);

            // 尝试处理HTML内容
            let processedHtml = false;
            if (regex.test(currentHtml) && !mesText.querySelector('.comfy-button-group')) {
                if (debugMode) console.log('[ComfyUI Debug] 在HTML中发现匹配,开始替换');
                mesText.innerHTML = currentHtml.replace(regex, (match, model, prompt) => {
                    if (debugMode) console.log('[ComfyUI Debug] 替换匹配项:', { match, model, prompt });
                    const cleanPrompt = sanitizePrompt(prompt.trim());
                    const encodedPrompt = cleanPrompt.replace(/"/g, '&quot;');
                    const modelName = model ? model.trim() : '';
                    const generationId = simpleHash(modelName + cleanPrompt);
                    return `<span class="comfy-button-group" data-generation-id="${generationId}"><button class="comfy-button comfy-chat-generate-button" data-prompt="${encodedPrompt}" data-model="${modelName}">开始生成</button></span>`;
                });
                processedHtml = true;
            }

            // 如果HTML中没有找到,尝试处理纯文本内容
            if (!processedHtml && textMatches && textMatches.length > 0 && !mesText.querySelector('.comfy-button-group')) {
                if (debugMode) console.log('[ComfyUI Debug] HTML中未找到匹配,尝试处理纯文本内容');

                // 重置正则表达式状态
                regex.lastIndex = 0;

                let newHtml = currentHtml;
                let match;
                while ((match = regex.exec(textContent)) !== null) {
                    if (debugMode) console.log('[ComfyUI Debug] 处理纯文本匹配:', match);
                    const fullMatch = match[0];
                    const model = match[1] || '';
                    const prompt = match[2] || '';

                    const cleanPrompt = sanitizePrompt(prompt.trim());
                    const encodedPrompt = cleanPrompt.replace(/"/g, '&quot;');
                    const modelName = model.trim();
                    const generationId = simpleHash(modelName + cleanPrompt);

                    const buttonHtml = `<span class="comfy-button-group" data-generation-id="${generationId}"><button class="comfy-button comfy-chat-generate-button" data-prompt="${encodedPrompt}" data-model="${modelName}">开始生成</button></span>`;

                    // 在HTML中查找并替换对应的文本
                    newHtml = newHtml.replace(escapeRegex(fullMatch), buttonHtml);
                }

                if (newHtml !== currentHtml) {
                    mesText.innerHTML = newHtml;
                    processedHtml = true;
                }
            }

            // 特殊处理:检查是否有被HTML编码的标签
            const htmlEncodedStartTag = startTag.replace(/</g, '&lt;').replace(/>/g, '&gt;');
            const htmlEncodedEndTag = endTag.replace(/</g, '&lt;').replace(/>/g, '&gt;');

            if (htmlEncodedStartTag !== startTag || htmlEncodedEndTag !== endTag) {
                if (debugMode) console.log('[ComfyUI Debug] 检查HTML编码的标签:', { htmlEncodedStartTag, htmlEncodedEndTag });

                const htmlEncodedRegex = new RegExp(
                    escapeRegex(htmlEncodedStartTag) +
                    '(?:\\[model=([\\w.-]+)\\])?' +
                    '([\\s\\S]*?)' +
                    escapeRegex(htmlEncodedEndTag),
                    'g'
                );

                if (htmlEncodedRegex.test(currentHtml) && !mesText.querySelector('.comfy-button-group')) {
                    if (debugMode) console.log('[ComfyUI Debug] 发现HTML编码的标签,进行替换');
                    mesText.innerHTML = currentHtml.replace(htmlEncodedRegex, (match, model, prompt) => {
                        if (debugMode) console.log('[ComfyUI Debug] 替换HTML编码匹配项:', { match, model, prompt });
                        const cleanPrompt = sanitizePrompt(prompt.trim());
                        const encodedPrompt = cleanPrompt.replace(/"/g, '&quot;');
                        const modelName = model ? model.trim() : '';
                        const generationId = simpleHash(modelName + cleanPrompt);
                        return `<span class="comfy-button-group" data-generation-id="${generationId}"><button class="comfy-button comfy-chat-generate-button" data-prompt="${encodedPrompt}" data-model="${modelName}">开始生成</button></span>`;
                    });
                    processedHtml = true;
                }
            }

            if (debugMode && !processedHtml) {
                console.log('[ComfyUI Debug] 未找到任何匹配的标签');
            }

            const buttonGroups = mesText.querySelectorAll('.comfy-button-group');
            if (debugMode) console.log('[ComfyUI Debug] 找到的按钮组数量:', buttonGroups.length);

            buttonGroups.forEach(group => {
                if (group.dataset.listenerAttached) return;
                const generationId = group.dataset.generationId;
                if (savedImagesCache[generationId]) {
                    displayImage(group, savedImagesCache[generationId]);
                    const generateButton = group.querySelector('.comfy-chat-generate-button');
                    if(generateButton) setupGeneratedState(generateButton, generationId);
                }
                group.dataset.listenerAttached = 'true';
            });
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('处理消息失败: ' + error.message, 'UI'), 'processMessageForComfyButton');
        }
    }

    function setupGeneratedState(generateButton, generationId) {
        try {
            generateButton.textContent = '重新生成';
            generateButton.disabled = false;
            generateButton.classList.remove('testing', 'success', 'error');
            const group = generateButton.closest('.comfy-button-group');
            let deleteButton = group.querySelector('.comfy-delete-button');
            if (!deleteButton) {
                deleteButton = document.createElement('button');
                deleteButton.textContent = '删除';
                deleteButton.className = 'comfy-button error comfy-delete-button';
                deleteButton.addEventListener('click', async () => {
                    try {
                        await deleteImageRecord(generationId);
                        const imageContainer = group.nextElementSibling;
                        if (imageContainer?.classList.contains('comfy-image-container')) {
                            imageContainer.remove();
                        }
                        deleteButton.remove();
                        generateButton.textContent = '开始生成';
                    } catch (error) {
                        ErrorHandler.handle(new ComfyUIError('删除图片失败: ' + error.message, 'CACHE'), 'deleteImage');
                    }
                });
                generateButton.insertAdjacentElement('afterend', deleteButton);
            }
            deleteButton.style.display = 'inline-flex';
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('设置生成状态失败: ' + error.message, 'UI'), 'setupGeneratedState');
        }
    }

    async function onGenerateButtonClickLogic(button) {
        try {
            const group = button.closest('.comfy-button-group');
            let prompt = button.dataset.prompt;
            const generationId = group.dataset.generationId;

            let model = button.dataset.model || '';
            if (!model) {
                model = await GM_getValue('comfyui_default_model', '');
            }

            if (button.disabled) return;

            // 获取并解密API密钥
            const encryptedApiKey = await GM_getValue('comfyui_api_key', '');
            const apiKey = decryptApiKey(encryptedApiKey);

            if (!apiKey) {
                throw new ComfyUIError('请先在设置面板中配置 API 密钥!', 'AUTH');
            }

            if (Date.now() < globalCooldownEndTime) {
                const remainingTime = Math.ceil((globalCooldownEndTime - Date.now()) / 1000);
                if (typeof toastr !== 'undefined') toastr.warning(`请稍候,冷却中 (${remainingTime}s)。`);
                return;
            }

            // 验证和净化提示词
            prompt = sanitizePrompt(prompt);
            if (!prompt) {
                throw new ComfyUIError('提示词内容无效', 'VALIDATION');
            }

            button.textContent = '请求中...';
            button.disabled = true;
            button.classList.add('testing');
            const deleteButton = group.querySelector('.comfy-delete-button');
            if (deleteButton) deleteButton.style.display = 'none';
            const oldImageContainer = group.nextElementSibling;
            if (oldImageContainer?.classList.contains('comfy-image-container')) {
                oldImageContainer.style.opacity = '0.5';
            }

            performanceMonitor.startTimer('generateImage');

            connectWebSocket();
            const { comfyuiUrl, promptPrefix } = cachedSettings;

            if (!comfyuiUrl) {
                throw new ComfyUIError('调度器 URL 未配置', 'CONFIG');
            }

            if (!validateUrl(comfyuiUrl)) {
                throw new ComfyUIError('调度器 URL 格式无效', 'CONFIG');
            }

            if (promptPrefix) prompt = promptPrefix + ' ' + prompt;

            if (typeof toastr !== 'undefined') toastr.info('正在向调度器发送请求...');

            const promptResponse = await sendPromptRequestToScheduler(comfyuiUrl, {
                client_id: generateClientId(),
                positive_prompt: prompt,
                api_key: apiKey,
                model: model
            });

            const promptId = promptResponse.prompt_id;
            if (!promptId) {
                throw new ComfyUIError('调度器未返回有效的任务 ID', 'GENERATION');
            }

            if (socket && socket.connected) {
                socket.emit('subscribe_to_prompt', { prompt_id: promptId });
            } else {
                throw new ComfyUIError('WebSocket连接未建立', 'WEBSOCKET');
            }

            activePrompts[promptId] = { button, generationId };
            button.textContent = '生成中...';

            if(promptResponse.assigned_instance_name) {
                if (typeof toastr !== 'undefined') {
                    toastr.success(`任务已分配到: ${promptResponse.assigned_instance_name} (队列: ${promptResponse.assigned_instance_queue_size})`);
                }
            }

            performanceMonitor.endTimer('generateImage');

        } catch (error) {
            performanceMonitor.endTimer('generateImage');
            ErrorHandler.handle(error, 'generateImage');

            button.textContent = error.type === 'AUTH' ? '认证失败' : '请求失败';
            button.classList.add('error');

            setTimeout(() => {
                button.classList.remove('testing', 'error');
                button.textContent = group.querySelector('.comfy-delete-button') ? '重新生成' : '开始生成';
                button.disabled = false;
                if(oldImageContainer) oldImageContainer.style.opacity = '1';
                if(deleteButton) deleteButton.style.display = 'inline-flex';
            }, 3000);

            if (error.type === 'AUTH') {
                // 认证失败时打开设置面板
                document.getElementById(PANEL_ID).style.display = 'flex';
            }
        }
    }

    // --- API Request Functions ---
    function sendPromptRequestToScheduler(url, payload) {
        return new Promise((resolve, reject) => {
            // 验证payload
            if (!payload.api_key) {
                reject(new ComfyUIError('API密钥缺失', 'AUTH'));
                return;
            }

            if (!payload.positive_prompt || payload.positive_prompt.trim().length === 0) {
                reject(new ComfyUIError('提示词不能为空', 'VALIDATION'));
                return;
            }

            GM_xmlhttpRequest({
                method: 'POST',
                url: `${url}/generate`,
                headers: {
                    'Content-Type': 'application/json',
                    'User-Agent': 'ComfyUI-TamperMonkey-Script/2.0'
                },
                data: JSON.stringify(payload),
                timeout: 15000,
                onload: (res) => {
                    try {
                        if (res.status === 202 || res.status === 200) {
                            const responseData = JSON.parse(res.responseText);
                            resolve(responseData);
                        } else if (res.status === 401 || res.status === 403) {
                            reject(new ComfyUIError('API密钥无效或权限不足', 'AUTH'));
                        } else {
                            let errorMsg = `调度器 API 错误: ${res.status}`;
                            try {
                                const errorJson = JSON.parse(res.responseText);
                                if (errorJson.error) errorMsg = errorJson.error;
                            } catch (e) {
                                // JSON解析失败,使用默认错误消息
                            }
                            reject(new ComfyUIError(errorMsg, 'GENERATION'));
                        }
                    } catch (error) {
                        reject(new ComfyUIError('解析服务器响应失败: ' + error.message, 'NETWORK'));
                    }
                },
                onerror: (e) => reject(new ComfyUIError('无法连接到调度器 API', 'NETWORK')),
                ontimeout: () => reject(new ComfyUIError('连接调度器 API 超时', 'NETWORK')),
            });
        });
    }

    // 验证图片URL是否可访问
    function validateImageUrl(imageUrl) {
        return new Promise((resolve, reject) => {
            // 如果是base64数据,直接通过验证
            if (imageUrl.startsWith('data:image/')) {
                resolve(true);
                return;
            }

            // 验证URL格式
            try {
                new URL(imageUrl);
            } catch (e) {
                reject(new ComfyUIError('图片URL格式无效', 'VALIDATION'));
                return;
            }

            // 尝试HEAD请求验证图片是否可访问
            GM_xmlhttpRequest({
                method: 'HEAD',
                url: imageUrl,
                timeout: 5000,
                onload: (response) => {
                    if (response.status === 200 || response.status === 304) {
                        resolve(true);
                    } else {
                        reject(new ComfyUIError(`图片URL不可访问 (状态: ${response.status})`, 'NETWORK'));
                    }
                },
                onerror: () => reject(new ComfyUIError('无法访问图片URL', 'NETWORK')),
                ontimeout: () => reject(new ComfyUIError('验证图片URL超时', 'NETWORK'))
            });
        });
    }

    // 带验证的图片显示函数(用于新生成的图片)- 简化版(参考34.0)+ 移动端优化
    async function displayImageWithValidation(anchorElement, imageBase64Data, generationId) {
        return new Promise((resolve, reject) => {
            try {
                // 验证base64数据
                if (!imageBase64Data || !imageBase64Data.startsWith('data:image/')) {
                    throw new ComfyUIError('无效的图片数据格式', 'VALIDATION');
                }

                const group = anchorElement.closest('.comfy-button-group') || anchorElement;
                let container = group.nextElementSibling;

                if (!container || !container.classList.contains('comfy-image-container')) {
                    container = document.createElement('div');
                    container.className = 'comfy-image-container';
                    const img = document.createElement('img');
                    img.alt = 'ComfyUI 生成的图片';
                    img.loading = 'eager'; // 【修复】改为立即加载,不使用lazy
                    container.appendChild(img);
                    group.insertAdjacentElement('afterend', container);
                }

                container.style.opacity = '1';
                const imgElement = container.querySelector('img');

                // 清除之前的错误提示(如果有)
                const oldError = container.querySelector('.comfy-image-error');
                if (oldError) {
                    oldError.remove();
                }
                imgElement.style.display = '';

                // 添加加载状态提示(简化版)
                const loadingIndicator = document.createElement('div');
                loadingIndicator.className = 'comfy-loading-indicator';
                loadingIndicator.textContent = '图片渲染中';
                container.insertBefore(loadingIndicator, imgElement);

                // 设置图片加载成功处理
                imgElement.onload = () => {
                    if (loadingIndicator.parentNode) {
                        loadingIndicator.remove();
                    }
                    container.style.opacity = '1';

                    if (debugMode) {
                        console.log(`[ComfyUI Debug] 图片显示成功: ${generationId}`);
                        console.log(`[ComfyUI Debug] 图片尺寸: ${imgElement.naturalWidth}x${imgElement.naturalHeight}`);
                    }

                    resolve();
                };

                // 设置图片加载失败处理
                imgElement.onerror = () => {
                    if (loadingIndicator.parentNode) {
                        loadingIndicator.remove();
                    }

                    console.error(`[ComfyUI Error] Base64图片渲染失败: ${generationId}`);

                    // 显示错误占位图
                    const errorDiv = document.createElement('div');
                    errorDiv.className = 'comfy-image-error';
                    errorDiv.style.maxWidth = `${cachedSettings.maxWidth || 600}px`;
                    errorDiv.innerHTML = `
                        <i class="fa fa-exclamation-triangle"></i>
                        <strong>图片渲染失败</strong><br>
                        <small>图片数据可能已损坏,请重新生成</small>
                    `;

                    imgElement.style.display = 'none';
                    container.appendChild(errorDiv);

                    reject(new ComfyUIError('图片渲染失败', 'UI'));
                };

                // 设置图片源(base64数据)
                imgElement.style.maxWidth = (cachedSettings.maxWidth || 600) + 'px';

                if (debugMode) {
                    console.log(`[ComfyUI Debug] 开始渲染图片: ${generationId}`);
                    console.log(`[ComfyUI Debug] Base64数据大小: ${(imageBase64Data.length / 1024).toFixed(2)}KB`);
                }

                imgElement.src = imageBase64Data;

                // 【修复】超时检查 - 使用 imgElement.complete(旧版本方式)
                const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
                const timeoutDuration = isMobile ? 90000 : 30000; // 移动端90秒,PC端30秒(更宽松)

                setTimeout(() => {
                    if (!imgElement.complete) {
                        if (loadingIndicator.parentNode) {
                            loadingIndicator.remove();
                        }

                        console.error(`[ComfyUI Error] 图片渲染超时(${timeoutDuration/1000}秒): ${generationId}`);
                        console.error('[ComfyUI] 图片数据大小:', (imageBase64Data.length / 1024).toFixed(2), 'KB');
                        console.error('[ComfyUI] 设备类型:', isMobile ? '移动端' : 'PC端');
                        console.error('[ComfyUI] imgElement.complete:', imgElement.complete);
                        console.error('[ComfyUI] imgElement.naturalWidth:', imgElement.naturalWidth);

                        // 显示超时错误 - 但图片可能实际已加载,只是complete标志未设置
                        const errorDiv = document.createElement('div');
                        errorDiv.className = 'comfy-image-error';
                        errorDiv.style.maxWidth = `${cachedSettings.maxWidth || 600}px`;
                        errorDiv.innerHTML = `
                            <i class="fa fa-clock"></i>
                            <strong>图片渲染超时</strong><br>
                            <small>图片已压缩至 ${(imageBase64Data.length / 1024).toFixed(0)}KB,但渲染仍然超时<br>建议在ComfyUI后端降低输出分辨率</small>
                        `;

                        imgElement.style.display = 'none';
                        container.appendChild(errorDiv);

                        reject(new ComfyUIError('图片渲染超时', 'UI'));
                    }
                }, timeoutDuration);

            } catch (error) {
                reject(error);
            }
        });
    }

    // 显示图片,现在可以接受URL或Base64数据(用于缓存恢复)
    async function displayImage(anchorElement, imageData) {
        try {
            const group = anchorElement.closest('.comfy-button-group') || anchorElement;
            let container = group.nextElementSibling;
            if (!container || !container.classList.contains('comfy-image-container')) {
                container = document.createElement('div');
                container.className = 'comfy-image-container';
                const img = document.createElement('img');
                img.alt = 'ComfyUI 生成的图片';
                img.loading = 'lazy'; // 懒加载优化
                container.appendChild(img);
                group.insertAdjacentElement('afterend', container);
            }
            container.style.opacity = '1';
            const imgElement = container.querySelector('img');
            imgElement.src = imageData;
            imgElement.style.maxWidth = (cachedSettings.maxWidth || 600) + 'px';
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('显示图片失败: ' + error.message, 'UI'), 'displayImage');
        }
    }

    // --- Main Execution Logic ---
    console.log('[ComfyUI] 插件开始加载...');
    createComfyUIPanel();

    const chatObserver = new MutationObserver(async (mutations) => {
        try {
            const nodesToProcess = new Set();
            for (const mutation of mutations) {
                mutation.addedNodes.forEach(node => {
                    if (node.nodeType === Node.ELEMENT_NODE) {
                        if (node.matches('.mes')) nodesToProcess.add(node);
                        node.querySelectorAll('.mes').forEach(mes => nodesToProcess.add(mes));
                    }
                });
                if (mutation.target.nodeType === Node.ELEMENT_NODE && mutation.target.closest('.mes')) {
                     nodesToProcess.add(mutation.target.closest('.mes'));
                }
            }

            if (nodesToProcess.size > 0) {
                // 从LRU缓存或旧存储获取缓存图片
                let savedImages = {};
                if (lruCache) {
                    // 从LRU缓存获取所有数据
                    const items = lruCache.getAll();
                    items.forEach(item => {
                        savedImages[item.id] = item.data;
                    });
                } else {
                    savedImages = await GM_getValue(STORAGE_KEY_IMAGES, {});
                }

                nodesToProcess.forEach(node => {
                    try {
                        const mesTextElement = node.querySelector('.mes_text');
                        if (mesTextElement && !mesTextElement.dataset.listenersAttached) {
                            mesTextElement.addEventListener('touchstart', (event) => handleComfyButtonClick(event, true), { passive: false });
                            mesTextElement.addEventListener('click', (event) => handleComfyButtonClick(event, false));
                            mesTextElement.dataset.listenersAttached = 'true';
                        }
                        processMessageForComfyButton(node, savedImages);
                    } catch (error) {
                        console.error('处理消息节点失败:', error);
                    }
                });
            }
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('聊天观察器处理失败: ' + error.message, 'UI'), 'chatObserver');
        }
    });

    async function loadSettingsFromStorageAndApplyToCache() {
        try {
            await migrateConfig(); // 执行配置迁移

            cachedSettings.comfyuiUrl = await GM_getValue('comfyui_url', 'https://127.0.0.1:5001');
            cachedSettings.startTag = await GM_getValue('comfyui_start_tag', 'image###');
            cachedSettings.endTag = await GM_getValue('comfyui_end_tag', '###');
            cachedSettings.promptPrefix = await GM_getValue(STORAGE_KEY_PROMPT_PREFIX, '');
            cachedSettings.maxWidth = await GM_getValue(STORAGE_KEY_MAX_WIDTH, 600);
            cachedSettings.cacheLimit = await GM_getValue(STORAGE_KEY_CACHE_LIMIT, 20);

            document.documentElement.style.setProperty('--comfy-image-max-width', (cachedSettings.maxWidth || 600) + 'px');
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('加载初始设置失败: ' + error.message, 'CONFIG'), 'loadSettingsFromStorageAndApplyToCache');
        }
    }

    function observeChat() {
        const chatElement = document.getElementById('chat');
        if (chatElement) {
            loadSettingsFromStorageAndApplyToCache().then(async () => {
                try {
                    // 从LRU缓存或旧存储获取缓存图片
                    let initialSavedImages = {};
                    if (lruCache) {
                        const items = lruCache.getAll();
                        items.forEach(item => {
                            initialSavedImages[item.id] = item.data;
                        });
                    } else {
                        initialSavedImages = await GM_getValue(STORAGE_KEY_IMAGES, {});
                    }

                    chatElement.querySelectorAll('.mes').forEach(node => {
                        try {
                            const mesTextElement = node.querySelector('.mes_text');
                            if (mesTextElement && !mesTextElement.dataset.listenersAttached) {
                                mesTextElement.addEventListener('touchstart', (event) => handleComfyButtonClick(event, true), { passive: false });
                                mesTextElement.addEventListener('click', (event) => handleComfyButtonClick(event, false));
                                mesTextElement.dataset.listenersAttached = 'true';
                            }
                            processMessageForComfyButton(node, initialSavedImages);
                        } catch (error) {
                            console.error('初始化消息节点失败:', error);
                        }
                    });
                    chatObserver.observe(chatElement, { childList: true, subtree: true });
                } catch (error) {
                    ErrorHandler.handle(new ComfyUIError('初始化聊天观察失败: ' + error.message, 'UI'), 'observeChat');
                }
            });
        } else {
            setTimeout(observeChat, 500);
        }
    }

    const optionsObserver = new MutationObserver(() => {
        try {
            const optionsMenu = document.getElementById('options');
            if (optionsMenu && optionsMenu.style.display !== 'none') {
                addMainButton();
            }
        } catch (error) {
            console.error('选项观察器错误:', error);
        }
    });

    // 初始化重连器
    function initializeReconnector() {
        reconnector = new SmartReconnector(
            () => {
                if (cachedSettings.comfyuiUrl) {
                    const schedulerUrl = new URL(cachedSettings.comfyuiUrl);
                    return `${schedulerUrl.protocol}//${schedulerUrl.host}`;
                }
                return null;
            },
            connectWebSocket,
            () => {
                if (socket) {
                    socket.disconnect();
                    socket = null;
                }
            }
        );
    }

    // 页面卸载时清理资源
    window.addEventListener('beforeunload', () => {
        try {
            performanceMonitor.stopMemoryMonitoring();
            if (socket) {
                socket.disconnect();
            }
            clearDOMCache();
        } catch (error) {
            console.error('清理资源失败:', error);
        }
    });

    window.addEventListener('load', () => {
        try {
            loadSettingsFromStorageAndApplyToCache().then(async () => {
                initializeReconnector();

                if (cachedSettings.comfyuiUrl && validateUrl(cachedSettings.comfyuiUrl)) {
                    connectWebSocket(); // 页面加载后立即尝试连接
                }

                // 启动性能监控
                performanceMonitor.startMemoryMonitoring();

                // 定期验证缓存完整性
                setInterval(async () => {
                    try {
                        await validateCacheIntegrity();
                    } catch (error) {
                        console.error('定期缓存验证失败:', error);
                    }
                }, 300000); // 每5分钟验证一次

                // 【优化】初始化IndexedDB + LRU缓存
                console.log('[ComfyUI] 正在初始化缓存系统...');

                try {
                    // 创建IndexedDB实例
                    const indexedDBCache = new IndexedDBCache();
                    await indexedDBCache.init();

                    // 创建LRU缓存并关联IndexedDB
                    lruCache = new LRUCache(cachedSettings.cacheLimit || 20, true);
                    lruCache.indexedDB = indexedDBCache;

                    // 从IndexedDB加载缓存
                await lruCache.load();

                const stats = lruCache.getStats();
                    const totalSize = await indexedDBCache.getTotalSize();
                    const totalSizeMB = (totalSize * 0.75 / 1024 / 1024).toFixed(1);

                    console.log('[ComfyUI] IndexedDB + LRU缓存已初始化');
                    console.log(`[ComfyUI] 缓存统计: ${stats.count}张图片, 总大小约${totalSizeMB}MB`);

                    // 数据迁移:从GM_getValue迁移到IndexedDB
                    const oldRecords = await GM_getValue(STORAGE_KEY_IMAGES, {});
                    const oldKeys = Object.keys(oldRecords);

                    if (oldKeys.length > 0 && stats.count === 0) {
                        console.log(`[ComfyUI] 检测到${oldKeys.length}条旧缓存,开始迁移到IndexedDB...`);
                        let migratedCount = 0;

                        for (const [id, data] of Object.entries(oldRecords)) {
                            try {
                                await indexedDBCache.set(id, data, {
                                    timestamp: Date.now(),
                                    accessCount: 0
                                });
                                migratedCount++;
                            } catch (error) {
                                console.error(`[ComfyUI] 迁移失败: ${id}`, error);
                            }
                        }

                        console.log(`[ComfyUI] 数据迁移完成: ${migratedCount}/${oldKeys.length}条`);

                        // 重新加载缓存
                        await lruCache.load();

                        // 清空旧的GM_setValue缓存(可选)
                        // await GM_setValue(STORAGE_KEY_IMAGES, {});
                    }

                } catch (error) {
                    console.error('[ComfyUI] IndexedDB初始化失败,回退到GM_getValue:', error);
                    // 回退方案:使用GM_getValue
                    lruCache = new LRUCache(cachedSettings.cacheLimit || 20, false);
                    await lruCache.load();

                    const stats = lruCache.getStats();
                    console.log('[ComfyUI] LRU缓存已初始化(GM_getValue模式):', stats);
                }

                // 初始化Lightbox(图片放大查看器)
                console.log('[ComfyUI] 正在初始化Lightbox...');
                createLightbox();

                // 初始化历史记录面板
                console.log('[ComfyUI] 正在初始化历史记录面板...');
                createHistoryPanel();

                console.log('[ComfyUI] 所有组件初始化完成!');

            }).catch(error => {
                ErrorHandler.handle(new ComfyUIError('初始化失败: ' + error.message, 'CONFIG'), 'window.load');
            });

            observeChat();

            const body = document.querySelector('body');
            if (body) {
                optionsObserver.observe(body, {
                    childList: true,
                    subtree: true,
                    attributes: true,
                    attributeFilter: ['style']
                });
            }
        } catch (error) {
            ErrorHandler.handle(new ComfyUIError('页面加载初始化失败: ' + error.message, 'CONFIG'), 'window.load');
        }
    });

})();