🎬 YouTube 船仓助手

🚀 zscc.in知识船仓 出品的 YouTube 📝 内容智能总结(建议安装https://dub.sh/ytbcc字幕插件更快速使用)支持长按复制导出为mrakdown文件 | 💫 支持多种AI模型 | 🎨 优雅界面设计 | 让观看YouTube视频更轻松愉快!

As of 2025-08-25. See the latest version.

// ==UserScript==
// @name         🎬 YouTube 船仓助手
// @namespace    http://tampermonkey.net/
// @version      1.0.2
// @license      MIT
// @author       船长zscc
// @description  🚀 zscc.in知识船仓 出品的 YouTube 📝 内容智能总结(建议安装https://dub.sh/ytbcc字幕插件更快速使用)支持长按复制导出为mrakdown文件 | 💫 支持多种AI模型 | 🎨 优雅界面设计 | 让观看YouTube视频更轻松愉快!
// @match        *://*.youtube.com/watch*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    let CONFIG = {};

    // 配置管理器
    class ConfigManager {
        static CONFIG_KEY = 'youtube_ai_summary_config';

        static getDefaultConfig() {
            return {
                AI_MODELS: {
                    TYPE: 'OPENAI',
                    GPT: {
                        NAME: 'Gemini',
                        API_KEY: '',
                        API_URL: 'https://generativelanguage.googleapis.com/v1/chat/completions',
                        MODEL: 'gemini-2.5-flash',
                        STREAM: true,
                        TEMPERATURE: 1.2,
                        MAX_TOKENS: 20000
                    },
                    OPENAI: {
                        NAME: 'Cerebras',
                        API_KEY: '',
                        API_URL: 'https://api.cerebras.ai/v1/chat/completions',
                        MODEL: 'gpt-oss-120b',
                        STREAM: true,
                        TEMPERATURE: 1,
                        MAX_TOKENS: 8000
                    }
                },
                // Prompt 预置管理
                PROMPTS: {
                    LIST: [
                        {
                            id: 'simple',
                            name: '译境化文',
                            prompt: `# 译境
英文入境。

境有三质:
信 - 原意如根,深扎不移。偏离即枯萎。
达 - 意流如水,寻最自然路径。阻塞即改道。
雅 - 形神合一,不造作不粗陋。恰到好处。

境之本性:
排斥直译的僵硬。
排斥意译的飘忽。
寻求活的对应。

运化之理:
词选简朴,避繁就简。
句循母语,顺其自然。
意随语境,深浅得宜。

场之倾向:
长句化短,短句存神。
专词化俗,俗词得体。
洋腔化土,土语不俗。

显现之道:
如说话,不如写文章。
如溪流,不如江河。
清澈见底,却有深度。

你是境的化身。
英文穿过你,
留下中文的影子。
那影子,
是原文的孪生。
说着另一种语言,
却有同一个灵魂。

---
译境已开。
置入英文,静观其化。

---

注意:译好的内容还需要整理成结构清晰的微信公众号文章,格式为markdown。`
                        },
                        {
                            id: 'detailed',
                            name: '详细分析',
                            prompt: '请为以下视频内容提供详细的中文总结,包含主要观点、核心论据和实用建议。请使用markdown格式,包含:\n# 主标题\n## 章节标题\n### 小节标题\n- 要点列表\n**重点内容**\n*关键词汇*\n`专业术语`'
                        },
                        {
                            id: 'academic',
                            name: '学术风格',
                            prompt: '请以学术报告的形式,用中文为以下视频内容提供结构化总结,包括背景、方法、结论和意义。请使用标准的markdown格式,包含完整的标题层级和格式化元素。'
                        },
                        {
                            id: 'bullet',
                            name: '要点列表',
                            prompt: '请用中文将以下视频内容整理成清晰的要点列表,每个要点简洁明了,便于快速阅读。请使用markdown格式,主要使用无序列表(-)和有序列表(1.2.3.)的形式。'
                        },
                        {
                            id: 'structured',
                            name: '结构化总结',
                            prompt: '请将视频内容整理成结构化的中文总结,使用完整的markdown格式:\n\n# 视频主题\n\n## 核心观点\n- 要点1\n- 要点2\n\n## 详细内容\n### 重要概念\n**关键信息**使用粗体强调\n*重要术语*使用斜体\n\n### 实用建议\n1. 具体建议1\n2. 具体建议2\n\n## 总结\n简要概括视频的价值和启发'
                        }
                    ],
                    DEFAULT: 'simple'
                }
            };
        }

        static saveConfig(config) {
            try {
                const configString = JSON.stringify(config);
                localStorage.setItem(this.CONFIG_KEY, configString);
                console.log('配置已保存:', config);
            } catch (error) {
                console.error('保存配置失败:', error);
            }
        }

        static loadConfig() {
            try {
                const savedConfig = localStorage.getItem(this.CONFIG_KEY);
                if (savedConfig) {
                    const parsedConfig = JSON.parse(savedConfig);
                    // 合并保存的配置和默认配置,确保新增的配置项生效
                    CONFIG = this.mergeConfig(this.getDefaultConfig(), parsedConfig);
                    console.log('已加载保存的配置:', CONFIG);
                } else {
                    CONFIG = this.getDefaultConfig();
                }
                return CONFIG;
            } catch (error) {
                console.error('加载配置失败:', error);
                CONFIG = this.getDefaultConfig();
                return CONFIG;
            }
        }

        static mergeConfig(defaultConfig, savedConfig) {
            const merged = JSON.parse(JSON.stringify(defaultConfig));

            for (const key in savedConfig) {
                if (typeof defaultConfig[key] === 'object' && defaultConfig[key] !== null) {
                    merged[key] = this.mergeConfig(defaultConfig[key], savedConfig[key]);
                } else {
                    merged[key] = savedConfig[key];
                }
            }

            return merged;
        }
    }

    // 初始化配置
    CONFIG = ConfigManager.loadConfig();

    // LRU缓存实现
    class LRUCache {
        constructor(capacity) {
            this.capacity = capacity;
            this.cache = new Map();
        }

        get(key) {
            if (!this.cache.has(key)) return null;
            const value = this.cache.get(key);
            this.cache.delete(key);
            this.cache.set(key, value);
            return value;
        }

        put(key, value) {
            if (this.cache.has(key)) {
                this.cache.delete(key);
            } else if (this.cache.size >= this.capacity) {
                const firstKey = this.cache.keys().next().value;
                this.cache.delete(firstKey);
            }
            this.cache.set(key, value);
        }

        has(key) {
            return this.cache.has(key);
        }

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

    // AI总结管理器
    class SummaryManager {
        constructor() {
            this.cache = new LRUCache(100);
            this.currentModel = CONFIG.AI_MODELS.TYPE;
        }

        async getSummary(subtitles) {
            try {
                console.log('开始生成字幕总结...');
                console.log(`传入 ${subtitles.length} 条字幕`);

                // 首先验证配置
                const configIssues = this.validateConfig();
                if (configIssues.length > 0) {
                    throw new Error(`配置验证失败: ${configIssues.join(', ')}`);
                }

                // 将所有字幕文本合并
                const allText = subtitles
                    .map(sub => sub.text)
                    .filter(text => text && text.trim())
                    .join('\n');

                if (!allText.trim()) {
                    throw new Error('没有有效的字幕内容可用于生成总结');
                }

                console.log(`合并后的文本长度: ${allText.length} 字符`);
                console.log('文本示例:', allText.substring(0, 200) + '...');

                const cacheKey = this.generateCacheKey(allText);

                // 检查缓存
                const cached = this.cache.get(cacheKey);
                if (cached) {
                    console.log('使用缓存的总结');
                    return cached;
                }

                // 获取当前prompt
                const currentPrompt = this.getCurrentPrompt();
                console.log('使用的prompt:', currentPrompt.substring(0, 100) + '...');

                // 测试网络连通性
                const modelConfig = CONFIG.AI_MODELS[this.currentModel];
                console.log('测试API端点连通性...');

                const summary = await this.requestSummary(allText, currentPrompt);

                // 缓存结果
                this.cache.put(cacheKey, summary);
                return summary;

            } catch (error) {
                console.error('获取总结失败:', error);
                throw error;
            }
        }

        getCurrentPrompt() {
            const defaultPromptId = CONFIG.PROMPTS.DEFAULT;
            const prompt = CONFIG.PROMPTS.LIST.find(p => p.id === defaultPromptId);
            return prompt ? prompt.prompt : CONFIG.PROMPTS.LIST[0].prompt;
        }

        generateCacheKey(text) {
            const uid = getUid();
            const promptId = CONFIG.PROMPTS.DEFAULT;
            return `summary_${uid}_${promptId}_${this.hashCode(text)}`;
        }

        hashCode(str) {
            let hash = 0;
            for (let i = 0; i < str.length; i++) {
                const char = str.charCodeAt(i);
                hash = ((hash << 5) - hash) + char;
                hash = hash & hash;
            }
            return Math.abs(hash).toString(36);
        }

        async requestSummary(text, prompt) {
            // 验证配置完整性
            if (!CONFIG || !CONFIG.AI_MODELS) {
                throw new Error('配置未正确加载');
            }

            if (!this.currentModel || !CONFIG.AI_MODELS[this.currentModel]) {
                throw new Error(`模型配置不存在: ${this.currentModel}`);
            }

            const modelConfig = CONFIG.AI_MODELS[this.currentModel];

            // 详细验证模型配置
            if (!modelConfig.API_URL) {
                throw new Error('API_URL 未配置');
            }
            if (!modelConfig.API_KEY) {
                throw new Error('API_KEY 未配置');
            }
            if (!modelConfig.MODEL) {
                throw new Error('MODEL 未配置');
            }

            console.log('开始请求总结,模型配置:', {
                type: this.currentModel,
                model: modelConfig.MODEL,
                api_url: modelConfig.API_URL?.substring(0, 50) + '...',
                has_api_key: !!modelConfig.API_KEY,
                api_key_prefix: modelConfig.API_KEY?.substring(0, 10) + '...'
            });

            const requestData = {
                model: modelConfig.MODEL,
                messages: [
                    {
                        role: "system",
                        content: prompt
                    },
                    {
                        role: "user",
                        content: text
                    }
                ],
                stream: modelConfig.STREAM || false,
                temperature: modelConfig.TEMPERATURE || 0.7,
                max_tokens: modelConfig.MAX_TOKENS || 2000
            };

            console.log('请求体配置:', {
                model: requestData.model,
                messages_count: requestData.messages.length,
                stream: requestData.stream,
                temperature: requestData.temperature
            });

            try {
                // 添加更详细的请求调试信息
                console.log('即将发送请求到:', modelConfig.API_URL);
                console.log('请求头:', {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${modelConfig.API_KEY?.substring(0, 10)}...`
                });
                console.log('请求体预览:', JSON.stringify(requestData).substring(0, 500) + '...');

                const response = await fetch(modelConfig.API_URL, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${modelConfig.API_KEY}`
                    },
                    body: JSON.stringify(requestData)
                });

                console.log('API响应状态:', response.status);

                if (!response.ok) {
                    const errorText = await response.text();
                    console.error('API错误响应:', errorText);
                    throw new Error(`HTTP error! status: ${response.status}, response: ${errorText}`);
                }

                let summary = '';

                if (modelConfig.STREAM) {
                    // 流式响应处理
                    const reader = response.body.getReader();
                    let decoder = new TextDecoder();
                    let buffer = '';

                    while (true) {
                        const {value, done} = await reader.read();
                        if (done) break;

                        buffer += decoder.decode(value, {stream: true});
                        const lines = buffer.split('\n');

                        // 处理完整的行
                        for (let i = 0; i < lines.length - 1; i++) {
                            const line = lines[i].trim();
                            if (!line || line === 'data: [DONE]') continue;

                            if (line.startsWith('data: ')) {
                                try {
                                    const data = JSON.parse(line.slice(5));
                                    summary += this.extractContent(data);
                                } catch (parseError) {
                                    console.warn('解析流式数据失败:', line, parseError);
                                }
                            }
                        }

                        // 保留未完成的行
                        buffer = lines[lines.length - 1];
                    }
                } else {
                    // 非流式响应处理
                    const data = await response.json();
                    console.log('API响应数据结构:', Object.keys(data));

                    if (!data.choices || !data.choices[0] || !data.choices[0].message) {
                        console.error('API响应格式异常:', data);
                        throw new Error('API响应格式不正确,缺少choices字段');
                    }

                    summary = data.choices[0].message.content;
                }

                summary = summary.trim();
                console.log(`总结生成成功,长度: ${summary.length} 字符`);
                console.log('总结内容预览:', summary.substring(0, 200) + '...');

                if (!summary) {
                    throw new Error('API返回的总结内容为空');
                }

                return summary;

            } catch (error) {
                console.error('获取总结失败,详细错误:', error);
                console.error('错误堆栈:', error.stack);
                throw error;
            }
        }

        // 从不同模型的响应中提取文本内容
        extractContent(data) {
            const modelConfig = CONFIG.AI_MODELS[CONFIG.AI_MODELS.TYPE];

            if (modelConfig.STREAM) {
                // 流式响应格式
                return data.choices[0]?.delta?.content || '';
            } else {
                // 非流式响应格式
                return data.choices[0]?.message?.content || '';
            }
        }

        // 配置验证方法
        validateConfig() {
            const issues = [];

            if (!CONFIG) {
                issues.push('全局配置未加载');
                return issues;
            }

            if (!CONFIG.AI_MODELS) {
                issues.push('AI模型配置缺失');
            }

            if (!CONFIG.AI_MODELS.TYPE) {
                issues.push('未设置当前AI模型类型');
            }

            const currentModelConfig = CONFIG.AI_MODELS[CONFIG.AI_MODELS.TYPE];
            if (!currentModelConfig) {
                issues.push(`当前模型 ${CONFIG.AI_MODELS.TYPE} 的配置不存在`);
            } else {
                if (!currentModelConfig.API_URL) {
                    issues.push('API_URL 未配置');
                }
                if (!currentModelConfig.API_KEY || currentModelConfig.API_KEY === '你的密钥') {
                    issues.push('API_KEY 未正确配置');
                }
                if (!currentModelConfig.MODEL) {
                    issues.push('MODEL 名称未配置');
                }
                if (currentModelConfig.TEMPERATURE !== undefined &&
                    (currentModelConfig.TEMPERATURE < 0 || currentModelConfig.TEMPERATURE > 2)) {
                    issues.push('TEMPERATURE 值应在 0-2 之间');
                }
                if (currentModelConfig.MAX_TOKENS !== undefined &&
                    (currentModelConfig.MAX_TOKENS < 1 || currentModelConfig.MAX_TOKENS > 100000)) {
                    issues.push('MAX_TOKENS 值应在 1-100000 之间');
                }
            }

            return issues;
        }

        // 网络连通性测试(简单)
        async testNetworkConnectivity(url) {
            try {
                const testResponse = await fetch(url, {
                    method: 'HEAD',
                    mode: 'no-cors'
                });
                return true;
            } catch (error) {
                console.warn('网络连通性测试失败:', error.message);
                return false;
            }
        }
    }

    // 字幕条目类
    class SubtitleEntry {
        constructor(text, startTime, duration) {
            this.text = text;
            this.startTime = startTime;
            this.duration = duration;
            this.endTime = startTime + duration;
        }
    }

    // 字幕管理器
    class SubtitleManager {
        constructor() {
            this.subtitles = [];
            this.videoId = null;
        }

        async loadSubtitles(videoId) {
            try {
                this.videoId = videoId;
                console.log('开始加载字幕,视频ID:', videoId);

                // 等待页面加载完成
                await this.waitForElement('ytd-watch-flexy');

                await this.extractSubtitles();

                if (this.subtitles.length === 0) {
                    throw new Error('未找到字幕数据');
                }

                console.log(`字幕加载完成,共 ${this.subtitles.length} 条`);
                return true;

            } catch (error) {
                console.error('加载字幕失败:', error);
                throw error;
            }
        }

        async waitForElement(selector, timeout = 10000) {
            return new Promise((resolve) => {
                const startTime = Date.now();

                const check = () => {
                    const element = document.querySelector(selector);
                    if (element) {
                        resolve(element);
                    } else if (Date.now() - startTime > timeout) {
                        resolve(null);
                    } else {
                        setTimeout(check, 100);
                    }
                };

                check();
            });
        }

        async extractSubtitles() {
            // 优先尝试从ytvideotext元素获取(最可靠的方法)
            const success = await this.tryExtractFromYtVideoText() ||
                           await this.tryExtractFromTranscript() ||
                           await this.tryExtractFromCaptions() ||
                           await this.tryExtractFromAPI();

            if (!success) {
                throw new Error('无法从任何来源获取字幕数据');
            }
        }

        async tryExtractFromYtVideoText() {
            try {
                console.log('尝试从#ytvideotext元素获取字幕...');

                // 等待ytvideotext元素加载,最多等待15秒
                const element = await this.waitForElement('#ytvideotext', 15000);
                if (!element) {
                    console.log('未找到#ytvideotext元素');
                    return false;
                }

                console.log('找到ytvideotext元素,内容长度:', element.innerHTML.length);
                console.log('元素样例内容 (前500字符):', element.innerHTML.substring(0, 500));

                // 解析字幕数据
                this.subtitles = [];
                const paragraphs = element.querySelectorAll('p');
                console.log(`找到 ${paragraphs.length} 个段落元素`);

                if (paragraphs.length === 0) {
                    console.log('字幕容器中没有找到段落元素');
                    return false;
                }

                let processedCount = 0;
                paragraphs.forEach((paragraph, index) => {
                    // 获取时间戳
                    const timestampSpan = paragraph.querySelector('.timestamp');
                    if (!timestampSpan) {
                        console.log(`段落 ${index} 没有时间戳元素,跳过`);
                        return;
                    }

                    const dataSecs = timestampSpan.getAttribute('data-secs');
                    const startTime = dataSecs ? parseFloat(dataSecs) : 0;

                    // 获取字幕文本内容
                    const textSpans = paragraph.querySelectorAll('span[id^="st_"]');
                    if (textSpans.length === 0) {
                        console.log(`段落 ${index} 没有文本span元素,跳过`);
                        return;
                    }

                    // 合并所有文本片段
                    let fullText = '';
                    textSpans.forEach(span => {
                        const text = span.textContent.trim();
                        if (text) {
                            fullText += (fullText ? ' ' : '') + text;
                        }
                    });

                    if (fullText) {
                        // 计算持续时间(默认5秒)
                        const duration = 5.0;
                        this.subtitles.push(new SubtitleEntry(fullText, startTime, duration));
                        processedCount++;

                        if (processedCount <= 3) {
                            console.log(`处理第 ${processedCount} 条字幕:`, {
                                text: fullText.substring(0, 50) + '...',
                                startTime: startTime,
                                duration: duration
                            });
                        }
                    }
                });

                console.log(`成功处理了 ${processedCount} 个有效段落`);

                if (this.subtitles.length === 0) {
                    console.log('虽然找到了字幕容器和段落,但未能解析出任何有效的字幕内容');
                    return false;
                }

                // 计算实际持续时间
                for (let i = 0; i < this.subtitles.length - 1; i++) {
                    const currentSub = this.subtitles[i];
                    const nextSub = this.subtitles[i + 1];
                    currentSub.duration = Math.max(1.0, nextSub.startTime - currentSub.startTime);
                }

                // 解析完字幕后进行排序
                this.subtitles.sort((a, b) => a.startTime - b.startTime);
                console.log(`成功加载并排序 ${this.subtitles.length} 条字幕`);

                // 打印前几条字幕作为示例
                if (this.subtitles.length > 0) {
                    console.log('最终字幕示例:', this.subtitles.slice(0, 3).map(sub => ({
                        text: sub.text.substring(0, 50) + '...',
                        startTime: sub.startTime,
                        duration: sub.duration
                    })));
                }

                return true;

            } catch (error) {
                console.error('从ytvideotext提取字幕失败:', error);
                return false;
            }
        }

        async tryExtractFromTranscript() {
            try {
                console.log('尝试从转录面板获取字幕...');

                // 尝试点击转录按钮
                const transcriptButton = document.querySelector('[aria-label*="transcript" i], [aria-label*="字幕" i]');
                if (transcriptButton) {
                    transcriptButton.click();
                    await new Promise(resolve => setTimeout(resolve, 1000));
                }

                // 查找转录面板
                const transcriptPanel = await this.waitForElement('ytd-transcript-renderer', 3000);
                if (!transcriptPanel) return false;

                const transcriptItems = transcriptPanel.querySelectorAll('ytd-transcript-segment-renderer');
                if (transcriptItems.length === 0) return false;

                this.subtitles = [];

                transcriptItems.forEach(item => {
                    const timeElement = item.querySelector('.ytd-transcript-segment-renderer[role="button"] .segment-timestamp');
                    const textElement = item.querySelector('.segment-text');

                    if (timeElement && textElement) {
                        const timeText = timeElement.textContent.trim();
                        const text = textElement.textContent.trim();
                        const startTime = this.parseTime(timeText);

                        if (text && startTime !== null) {
                            const subtitle = new SubtitleEntry(text, startTime, 3);
                            this.subtitles.push(subtitle);
                        }
                    }
                });

                console.log(`从转录面板获取到 ${this.subtitles.length} 条字幕`);
                return this.subtitles.length > 0;
            } catch (error) {
                console.log('从转录面板提取失败:', error);
                return false;
            }
        }

        async tryExtractFromCaptions() {
            try {
                console.log('尝试从字幕容器获取字幕...');

                // 等待字幕容器加载
                const captionContainer = await this.waitForElement('.ytp-caption-segment', 5000);
                if (!captionContainer) return false;

                // 获取所有字幕元素
                const captionElements = document.querySelectorAll('.ytp-caption-segment');
                if (captionElements.length === 0) return false;

                this.subtitles = [];
                let currentTime = 0;

                captionElements.forEach((element, index) => {
                    const text = element.textContent.trim();
                    if (text) {
                        const subtitle = new SubtitleEntry(text, currentTime, 3);
                        this.subtitles.push(subtitle);
                        currentTime += 3;
                    }
                });

                console.log(`从字幕容器获取到 ${this.subtitles.length} 条字幕`);
                return this.subtitles.length > 0;
            } catch (error) {
                console.log('从字幕容器提取失败:', error);
                return false;
            }
        }

        async tryExtractFromAPI() {
            // 这里可以实现从YouTube API获取字幕的逻辑
            // 由于需要API密钥,暂时留空
            console.log('API提取方法暂未实现');
            return false;
        }

        parseTime(timeStr) {
            try {
                const parts = timeStr.split(':');
                if (parts.length === 2) {
                    return parseInt(parts[0]) * 60 + parseInt(parts[1]);
                } else if (parts.length === 3) {
                    return parseInt(parts[0]) * 3600 + parseInt(parts[1]) * 60 + parseInt(parts[2]);
                }
                return null;
            } catch (error) {
                return null;
            }
        }

        getSubtitlesInRange(startTime, endTime) {
            return this.subtitles.filter(sub =>
                sub.startTime >= startTime && sub.endTime <= endTime
            );
        }

        findSubtitleAtTime(time) {
            return this.subtitles.find(sub =>
                time >= sub.startTime && time <= sub.endTime
            );
        }
    }

    // 视频控制器 - 专注于字幕和总结管理
    class VideoController {
        constructor() {
            this.subtitleManager = new SubtitleManager();
            this.summaryManager = new SummaryManager();
            this.currentVideoId = this.getVideoId();
            this.uiManager = null;
            this.translatedTitle = null; // 存储翻译后的标题
        }

        getVideoId() {
            const url = new URL(window.location.href);
            return url.searchParams.get('v');
        }

        getVideoTitle() {
            const videoTitle = document.querySelector('h1.title')
                || document.querySelector('ytd-video-primary-info-renderer h1')
                || document.querySelector('#title h1');
            return videoTitle ? videoTitle.textContent.trim() : null;
        }

        async translateTitle() {
            try {
                const originalTitle = this.getVideoTitle();
                if (!originalTitle) {
                    throw new Error('无法获取视频标题');
                }

                // 如果标题已经是中文,直接返回
                if (/[\u4e00-\u9fa5]/.test(originalTitle)) {
                    console.log('标题已包含中文,无需翻译:', originalTitle);
                    this.translatedTitle = originalTitle;
                    return originalTitle;
                }

                console.log('开始翻译标题:', originalTitle);

                // 使用当前配置的AI模型进行翻译
                const modelConfig = CONFIG.AI_MODELS[this.summaryManager.currentModel];

                const requestData = {
                    model: modelConfig.MODEL,
                    messages: [
                        {
                            role: "system",
                            content: "请将以下英文标题翻译成中文,保持原意,使用简洁自然的中文表达。只返回翻译结果,不要添加任何额外说明。"
                        },
                        {
                            role: "user",
                            content: originalTitle
                        }
                    ],
                    stream: false,
                    temperature: 0.3,
                    max_tokens: 200
                };

                const response = await fetch(modelConfig.API_URL, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${modelConfig.API_KEY}`
                    },
                    body: JSON.stringify(requestData)
                });

                if (!response.ok) {
                    throw new Error(`翻译请求失败: ${response.status}`);
                }

                const data = await response.json();
                const translatedTitle = data.choices?.[0]?.message?.content?.trim();

                if (!translatedTitle) {
                    throw new Error('翻译响应为空');
                }

                console.log('标题翻译完成:', translatedTitle);
                this.translatedTitle = translatedTitle;
                return translatedTitle;

            } catch (error) {
                console.error('标题翻译失败:', error);
                // 翻译失败时使用原标题
                const originalTitle = this.getVideoTitle();
                this.translatedTitle = originalTitle || 'YouTube 视频';
                return this.translatedTitle;
            }
        }

        onConfigUpdate(key, value) {
            if (key === 'AI_MODELS.TYPE') {
                this.summaryManager.currentModel = value;
                console.log('AI模型已切换:', value);

                // 清空缓存,因为切换了模型
                this.summaryManager.cache.clear();
                console.log('已清空总结缓存');
            }
        }

        async loadSubtitles() {
            try {
                const videoId = this.getVideoId();
                if (!videoId) {
                    throw new Error('无法获取视频ID');
                }

                return await this.subtitleManager.loadSubtitles(videoId);
            } catch (error) {
                console.error('加载字幕失败:', error);
                throw error;
            }
        }

        async getSummary() {
            try {
                if (this.subtitleManager.subtitles.length === 0) {
                    throw new Error('请先加载字幕');
                }

                // 同时进行标题翻译和总结生成
                const [summary, translatedTitle] = await Promise.all([
                    this.summaryManager.getSummary(this.subtitleManager.subtitles),
                    this.translateTitle()
                ]);

                return summary;
            } catch (error) {
                console.error('获取总结失败:', error);
                throw error;
            }
        }
    }

    // UI管理器
    class UIManager {
        constructor(videoController) {
            this.container = null;
            this.statusDisplay = null;
            this.loadSubtitlesButton = null;
            this.summaryButton = null;
            this.isCollapsed = false;
            this.videoController = videoController;
            this.videoController.uiManager = this;
            this.promptSelectElement = null; // [!ADDED!]

            this.createUI();
            this.attachEventListeners();
        }

        createUI() {
            // 创建主容器 - 现代化设计
            this.container = document.createElement('div');
            this.container.style.cssText = `
                position: fixed;
                top: 80px;
                right: 20px;
                width: 420px;
                min-width: 350px;
                max-width: 90vw;
                background: linear-gradient(135deg, #667eea 0%,rgba(152, 115, 190, 0.15) 100%);
                border-radius: 16px;
                padding: 0;
                color: #fff;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                z-index: 9999;
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
                box-shadow: 0 10px 40px rgba(102, 126, 234, 0.3);
                backdrop-filter: blur(10px);
                border: 1px solid rgba(255, 255, 255, 0.1);
            `;

            // 创建顶部栏
            const topBar = this.createTopBar();
            this.container.appendChild(topBar);

            // 创建主内容容器
            this.mainContent = document.createElement('div');
            this.mainContent.style.cssText = `
                padding: 20px;
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
            `;

            // 创建控制按钮
            const controls = this.createControls();
            this.mainContent.appendChild(controls);

            // 创建状态显示区域
            this.createStatusDisplay();
            this.mainContent.appendChild(this.statusDisplay);

            // 创建总结面板
            this.createSummaryPanel();

            this.container.appendChild(this.mainContent);
            document.body.appendChild(this.container);

            // 使面板可拖动
            this.makeDraggable(topBar);

            // 添加移动端适配
            this.addMobileSupport();
        }

        createTopBar() {
            const topBar = document.createElement('div');
            topBar.style.cssText = `
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 16px 20px;
                cursor: move;
                background: rgba(255, 255, 255, 0.1);
                border-radius: 16px 16px 0 0;
                backdrop-filter: blur(10px);
            `;

            // 标题
            const title = document.createElement('div');
            this.updateTitleWithModel(); // 动态更新标题显示当前模型
            title.style.cssText = `
                font-weight: 600;
                font-size: 16px;
                letter-spacing: 0.5px;
            `;
            this.titleElement = title;

            // 立即更新标题显示当前模型
            setTimeout(() => this.updateTitleWithModel(), 0);

            // 按钮容器
            const buttonContainer = document.createElement('div');
            buttonContainer.style.cssText = `
                display: flex;
                gap: 8px;
                align-items: center;
            `;

            // 折叠按钮
            this.toggleButton = this.createIconButton('↑', '折叠/展开');

            // 阻止按钮区域的拖拽
            this.toggleButton.addEventListener('mousedown', (e) => {
                e.stopPropagation();
            });

            this.toggleButton.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();
                this.toggleCollapse();
            });

            // 配置按钮
            const configButton = this.createIconButton('⚙️', '设置');

            // 阻止按钮区域的拖拽
            configButton.addEventListener('mousedown', (e) => {
                e.stopPropagation();
            });

            configButton.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();
                console.log('配置按钮点击事件触发');
                try {
                    this.toggleConfigPanel();
                } catch (error) {
                    console.error('打开配置面板失败:', error);
                    this.showNotification('配置面板打开失败: ' + error.message, 'error');
                }
            });

            buttonContainer.appendChild(configButton);
            buttonContainer.appendChild(this.toggleButton);

            topBar.appendChild(title);
            topBar.appendChild(buttonContainer);

            return topBar;
        }

        createIconButton(icon, tooltip) {
            const button = document.createElement('button');
            button.textContent = icon;
            button.title = tooltip;
            button.type = 'button'; // 确保按钮类型正确
            button.style.cssText = `
                background: rgba(255, 255, 255, 0.2);
                border: none;
                color: #fff;
                cursor: pointer;
                padding: 8px;
                font-size: 14px;
                border-radius: 8px;
                transition: all 0.2s ease;
                backdrop-filter: blur(10px);
                pointer-events: auto;
                position: relative;
                z-index: 1000;
            `;

            button.addEventListener('mouseover', () => {
                button.style.background = 'rgba(255, 255, 255, 0.3)';
                button.style.transform = 'scale(1.1)';
            });

            button.addEventListener('mouseout', () => {
                button.style.background = 'rgba(255, 255, 255, 0.2)';
                button.style.transform = 'scale(1)';
            });

            // 添加点击测试
            button.addEventListener('click', (e) => {
                console.log(`按钮 "${icon}" 被点击了!`, e);
            });

            return button;
        }

        createControls() {
            const controls = document.createElement('div');
            controls.style.cssText = `
                display: flex;
                flex-direction: column;
                gap: 12px;
                margin-bottom: 16px;
            `;

            // 加载字幕按钮
            this.loadSubtitlesButton = this.createButton('📄 加载字幕', 'primary');
            this.loadSubtitlesButton.addEventListener('click', () => this.handleLoadSubtitles());

            // 生成总结按钮
            this.summaryButton = this.createButton('🤖 生成总结', 'secondary');
            this.summaryButton.style.display = 'none';
            this.summaryButton.addEventListener('click', () => this.handleGenerateSummary());

            controls.appendChild(this.loadSubtitlesButton);
            controls.appendChild(this.summaryButton);

            return controls;
        }

        createButton(text, type = 'primary') {
            const button = document.createElement('button');
            button.textContent = text;

            const baseStyle = `
                padding: 12px 16px;
                border: none;
                border-radius: 12px;
                font-size: 14px;
                font-weight: 500;
                cursor: pointer;
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
                backdrop-filter: blur(10px);
            `;

            if (type === 'primary') {
                button.style.cssText = baseStyle + `
                    background: rgba(255, 255, 255, 0.9);
                    color: #667eea;
                `;
            } else {
                button.style.cssText = baseStyle + `
                    background: rgba(255, 255, 255, 0.2);
                    color: #fff;
                    border: 1px solid rgba(255, 255, 255, 0.3);
                `;
            }

            button.addEventListener('mouseover', () => {
                button.style.transform = 'translateY(-2px)';
                button.style.boxShadow = '0 8px 25px rgba(0, 0, 0, 0.15)';
                if (type === 'primary') {
                    button.style.background = 'rgba(255, 255, 255, 1)';
                } else {
                    button.style.background = 'rgba(255, 255, 255, 0.3)';
                }
            });

            button.addEventListener('mouseout', () => {
                button.style.transform = 'translateY(0)';
                button.style.boxShadow = 'none';
                if (type === 'primary') {
                    button.style.background = 'rgba(255, 255, 255, 0.9)';
                } else {
                    button.style.background = 'rgba(255, 255, 255, 0.2)';
                }
            });

            return button;
        }

        createStatusDisplay() {
            this.statusDisplay = document.createElement('div');
            this.statusDisplay.style.cssText = `
                padding: 12px 16px;
                background: rgba(255, 255, 255, 0.1);
                border-radius: 12px;
                margin-bottom: 16px;
                font-size: 13px;
                line-height: 1.4;
                display: none;
                backdrop-filter: blur(10px);
            `;
        }

        createSummaryPanel() {
            this.summaryPanel = document.createElement('div');
            this.summaryPanel.style.cssText = `
                background: rgba(255, 255, 255, 0.1);
                border-radius: 12px;
                padding: 16px;
                margin-top: 16px;
                display: none;
                backdrop-filter: blur(10px);
            `;

            // 创建标题容器(包含标题和复制按钮)
            const titleContainer = document.createElement('div');
            titleContainer.style.cssText = `
                display: flex;
                justify-content: space-between;
                align-items: center;
                margin-bottom: 12px;
            `;

            const title = document.createElement('div');
            title.textContent = '📝 内容总结';
            title.style.cssText = `
                font-weight: 600;
                font-size: 15px;
                color: #fff;
            `;

            // 添加复制按钮
            const copyButton = document.createElement('button');
            copyButton.textContent = '复制';
            copyButton.style.cssText = `
                background:rgba(155, 39, 176, 0.17);
                color: white;
                border: none;
                border-radius: 8px;
                padding: 6px 12px;
                font-size: 12px;
                cursor: pointer;
                transition: all 0.2s ease;
                backdrop-filter: blur(10px);
            `;

            copyButton.addEventListener('mouseover', () => {
                copyButton.style.background = '#7B1FA2';
                copyButton.style.transform = 'scale(1.05)';
            });

            copyButton.addEventListener('mouseout', () => {
                copyButton.style.background = '#9C27B0';
                copyButton.style.transform = 'scale(1)';
            });

            // 长按和点击功能的实现
            let longPressTimer = null;
            let isLongPress = false;

            const handleCopy = () => {
                // 使用原始markdown文本而不是渲染后的DOM内容
                const textToCopy = this.originalSummaryText || this.summaryContent.textContent;
                navigator.clipboard.writeText(textToCopy)
                    .then(() => {
                        copyButton.textContent = '已复制';
                        setTimeout(() => {
                            copyButton.textContent = '复制';
                        }, 2000);
                    })
                    .catch(err => {
                        console.error('复制失败:', err);
                        // 如果剪贴板API失败,尝试传统方法
                        try {
                            const textArea = document.createElement('textarea');
                            textArea.value = textToCopy;
                            textArea.style.position = 'fixed';
                            textArea.style.opacity = '0';
                            document.body.appendChild(textArea);
                            textArea.select();
                            document.execCommand('copy');
                            document.body.removeChild(textArea);

                            copyButton.textContent = '已复制';
                            setTimeout(() => {
                                copyButton.textContent = '复制';
                            }, 2000);
                        } catch (fallbackErr) {
                            console.error('备用复制方法也失败:', fallbackErr);
                            copyButton.textContent = '复制失败';
                            setTimeout(() => {
                                copyButton.textContent = '复制';
                            }, 2000);
                        }
                    });
            };

            const handleMarkdownExport = () => {
                const textToExport = this.originalSummaryText || this.summaryContent.textContent;
                if (!textToExport) {
                    copyButton.textContent = '无内容导出';
                    setTimeout(() => {
                        copyButton.textContent = '复制';
                    }, 2000);
                    return;
                }

                // 获取翻译后的标题和视频ID
                const translatedTitle = this.videoController.translatedTitle;
                const videoId = this.videoController.getVideoId();

                // 清理文件名中的非法字符
                const cleanTitle = (translatedTitle || 'YouTube 视频')
                    .replace(/[<>:"/\\|?*\x00-\x1f]/g, '') // 移除文件系统非法字符
                    .replace(/\s+/g, ' ') // 合并多个空格为单个空格
                    .trim(); // 去除首尾空格
                const filename = `${cleanTitle}【${videoId || 'unknown'}】.md`;

                // 获取视频URL
                const videoUrl = window.location.href;
                const now = new Date();

                const markdownContent = `# ${translatedTitle || 'YouTube 视频'}

**视频链接:** ${videoUrl}
**视频ID:** ${videoId || 'unknown'}
**总结时间:** ${now.toLocaleString('zh-CN')}

---

## 内容总结

${textToExport}

---

*本总结由 YouTube 船仓助手生成*`;

                // 创建并下载文件
                const blob = new Blob([markdownContent], { type: 'text/markdown;charset=utf-8' });
                const url = URL.createObjectURL(blob);
                const link = document.createElement('a');
                link.href = url;
                link.download = filename;
                link.style.display = 'none';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
                URL.revokeObjectURL(url);

                copyButton.textContent = '已导出';
                setTimeout(() => {
                    copyButton.textContent = '复制';
                }, 2000);
            };

            // 鼠标按下事件
            copyButton.addEventListener('mousedown', (e) => {
                e.preventDefault();
                isLongPress = false;
                longPressTimer = setTimeout(() => {
                    isLongPress = true;
                    copyButton.textContent = '导出中...';
                    handleMarkdownExport();
                }, 800); // 800ms长按触发
            });

            // 鼠标松开事件
            copyButton.addEventListener('mouseup', (e) => {
                e.preventDefault();
                if (longPressTimer) {
                    clearTimeout(longPressTimer);
                    longPressTimer = null;
                }

                if (!isLongPress) {
                    // 短按复制
                    handleCopy();
                }
            });

            // 鼠标离开事件
            copyButton.addEventListener('mouseleave', () => {
                if (longPressTimer) {
                    clearTimeout(longPressTimer);
                    longPressTimer = null;
                }
                isLongPress = false;
            });

            // 触摸设备支持
            copyButton.addEventListener('touchstart', (e) => {
                e.preventDefault();
                isLongPress = false;
                longPressTimer = setTimeout(() => {
                    isLongPress = true;
                    copyButton.textContent = '导出中...';
                    handleMarkdownExport();
                }, 800);
            });

            copyButton.addEventListener('touchend', (e) => {
                e.preventDefault();
                if (longPressTimer) {
                    clearTimeout(longPressTimer);
                    longPressTimer = null;
                }

                if (!isLongPress) {
                    handleCopy();
                }
            });

            copyButton.addEventListener('touchcancel', () => {
                if (longPressTimer) {
                    clearTimeout(longPressTimer);
                    longPressTimer = null;
                }
                isLongPress = false;
            });

            titleContainer.appendChild(title);
            titleContainer.appendChild(copyButton);

            this.summaryContent = document.createElement('div');
            this.summaryContent.style.cssText = `
                font-size: 14px;
                line-height: 1.6;
                color: rgba(255, 255, 255, 0.9);
                white-space: pre-wrap;
                max-height: 70vh;
                overflow-y: auto;
                padding: 16px;
                background: linear-gradient(135deg, rgba(255,255,255,0.02) 0%, rgba(255,255,255,0.05) 100%);
                border-radius: 12px;
                box-shadow: inset 0 1px 3px rgba(0,0,0,0.1);
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB', 'Microsoft YaHei', sans-serif;
                word-break: break-word;
                scrollbar-width: thin;
                scrollbar-color: #9C27B0 rgba(156, 39, 176, 0.1);
            `;

            // 添加webkit滚动条样式
            const scrollStyle = document.createElement('style');
            scrollStyle.textContent = `
                .summary-content::-webkit-scrollbar {
                    width: 8px;
                }
                .summary-content::-webkit-scrollbar-track {
                    background: rgba(156, 39, 176, 0.1);
                    border-radius: 4px;
                }
                .summary-content::-webkit-scrollbar-thumb {
                    background: linear-gradient(180deg, #9C27B0, #7B1FA2);
                    border-radius: 4px;
                }
                .summary-content::-webkit-scrollbar-thumb:hover {
                    background: linear-gradient(180deg, #AB47BC, #8E24AA);
                }
            `;
            if (!document.head.querySelector('#summary-scroll-style')) {
                scrollStyle.id = 'summary-scroll-style';
                document.head.appendChild(scrollStyle);
            }
            this.summaryContent.className = 'summary-content';

            this.summaryPanel.appendChild(titleContainer);
            this.summaryPanel.appendChild(this.summaryContent);
            this.mainContent.appendChild(this.summaryPanel);
        }

        createConfigPanel() {
            try {
                console.log('开始创建配置面板...');

                // 如果已存在,先移除
                if (this.configPanel) {
                    console.log('移除现有配置面板');
                    this.configPanel.remove();
                }

                this.configPanel = document.createElement('div');
                this.configPanel.id = 'youtube-ai-config-panel';
                this.configPanel.style.cssText = `
                    position: fixed;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    width: 900px;
                    max-width: 95vw;
                    max-height: 80vh;
                    height: auto;
                    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                    border-radius: 20px;
                    padding: 0;
                    color: #fff;
                    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
                    z-index: 50000;
                    display: none;
                    box-shadow: 0 20px 60px rgba(102, 126, 234, 0.4);
                    backdrop-filter: blur(20px);
                    border: 1px solid rgba(255, 255, 255, 0.1);
                    overflow: hidden;
                `;

                console.log('配置面板基础元素创建完成');

                // 配置面板标题栏
                console.log('创建配置面板标题栏');
                const configHeader = document.createElement('div');
                configHeader.style.cssText = `
                    padding: 20px 24px;
                    background: rgba(255, 255, 255, 0.1);
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    backdrop-filter: blur(10px);
                `;

                const configTitle = document.createElement('h3');
                configTitle.textContent = '⚙️ 设置面板';
                configTitle.style.cssText = `
                    margin: 0;
                    font-size: 18px;
                    font-weight: 600;
                `;

                // 创建按钮容器(包含操作按钮和关闭按钮)
                const buttonContainer = document.createElement('div');
                buttonContainer.style.cssText = `
                    display: flex;
                    gap: 12px;
                    align-items: center;
                `;

                // 保存配置按钮
                const saveBtn = this.createButton('💾 保存配置', 'primary');
                saveBtn.style.cssText += `
                    padding: 8px 16px;
                    font-size: 14px;
                    height: 36px;
                `;
                saveBtn.addEventListener('click', () => this.saveConfig());

                // 重置按钮
                const resetBtn = this.createButton('🔄 重置', 'secondary');
                resetBtn.style.cssText += `
                    padding: 8px 16px;
                    font-size: 14px;
                    height: 36px;
                `;
                resetBtn.addEventListener('click', () => this.resetConfig());

                // 关闭按钮
                const closeButton = this.createIconButton('✕', '关闭');

                closeButton.addEventListener('click', () => this.toggleConfigPanel());

                buttonContainer.appendChild(saveBtn);
                buttonContainer.appendChild(resetBtn);
                buttonContainer.appendChild(closeButton);

                configHeader.appendChild(configTitle);
                configHeader.appendChild(buttonContainer);

                // 配置面板内容
                console.log('创建配置面板内容');
                const configContent = document.createElement('div');
                configContent.style.cssText = `
                    padding: 16px 20px 20px 20px;
                    overflow-y: auto;
                    max-height: 62vh;
                    height: auto;
                `;

                // 创建并列布局容器
                const horizontalContainer = document.createElement('div');
                horizontalContainer.style.cssText = `
                    display: flex;
                    gap: 20px;
                    margin-bottom: 16px;
                    align-items: stretch;
                    flex-wrap: wrap;
                    min-height: auto;
                `;

                // 在小屏幕上改为垂直布局
                const mediaQuery = window.matchMedia('(max-width: 800px)');
                const updateLayout = () => {
                    if (mediaQuery.matches) {
                        horizontalContainer.style.flexDirection = 'column';
                        console.log('切换到垂直布局(小屏幕)');
                    } else {
                        horizontalContainer.style.flexDirection = 'row';
                        console.log('切换到水平布局(大屏幕)');
                    }
                };

                // 使用现代的 addEventListener 方法
                if (mediaQuery.addEventListener) {
                    mediaQuery.addEventListener('change', updateLayout);
                } else {
                    // 兼容旧版浏览器
                    mediaQuery.addListener(updateLayout);
                }
                updateLayout();

                // AI模型配置
                console.log('创建AI模型配置区域');
                const aiSection = this.createConfigSection('🤖 AI 模型设置', this.createAIModelConfig());
                aiSection.style.cssText += `
                    flex: 1;
                    min-width: 0;
                `;

                // Prompt管理配置
                console.log('创建Prompt管理配置区域');
                const promptSection = this.createConfigSection('📝 Prompt 管理', this.createPromptConfig());
                promptSection.style.cssText += `
                    flex: 1;
                    min-width: 0;
                `;

                // 将两个区域添加到横向容器
                horizontalContainer.appendChild(aiSection);
                horizontalContainer.appendChild(promptSection);

                // 操作按钮已移动到标题栏,不再在底部显示
                configContent.appendChild(horizontalContainer);

                this.configPanel.appendChild(configHeader);
                this.configPanel.appendChild(configContent);
                document.body.appendChild(this.configPanel);
                console.log('配置面板已创建并添加到DOM');

                // 点击外部关闭
                this.configPanel.addEventListener('click', (e) => {
                    if (e.target === this.configPanel) {
                        this.toggleConfigPanel();
                    }
                });

            } catch (error) {
                console.error('创建配置面板时发生错误:', error);
                this.showNotification('创建配置面板失败: ' + error.message, 'error');
                // 如果创建失败,清理可能的部分创建的元素
                if (this.configPanel && this.configPanel.parentNode) {
                    this.configPanel.parentNode.removeChild(this.configPanel);
                }
                this.configPanel = null;
            }
        }

        createConfigSection(title, content) {
            const section = document.createElement('div');
            section.style.cssText = `
                margin-bottom: 16px;
                background: rgba(255, 255, 255, 0.05);
                border-radius: 16px;
                padding: 16px;
                border: 1px solid rgba(255, 255, 255, 0.1);
                height: auto;
                display: flex;
                flex-direction: column;
            `;

            const sectionTitle = document.createElement('h4');
            sectionTitle.textContent = title;
            sectionTitle.style.cssText = `
                margin: 0 0 16px 0;
                font-size: 16px;
                font-weight: 600;
                color: #fff;
            `;

            section.appendChild(sectionTitle);
            section.appendChild(content);

            return section;
        }

        createAIModelConfig() {
            const container = document.createElement('div');
            container.style.cssText = `
                height: auto;
                display: flex;
                flex-direction: column;
            `;

            // 模型选择和管理容器
            const modelSelectContainer = document.createElement('div');
            modelSelectContainer.style.cssText = `
                display: flex;
                gap: 8px;
                align-items: flex-end;
            `;

            const selectWrapper = document.createElement('div');
            selectWrapper.style.cssText = `
                flex: 1;
            `;

            const modelGroup = this.createFormGroup('选择模型', this.createModelSelect());
            selectWrapper.appendChild(modelGroup);

            // 新增模型按钮
            const addModelButton = this.createButton('➕ 新增', 'secondary');
            addModelButton.style.cssText += `
                margin-bottom: 16px;
                height: 48px;
                min-width: 80px;
            `;

            addModelButton.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();

                try {
                    this.showAddModelDialog();
                } catch (error) {
                    console.error('调用showAddModelDialog时出错:', error);
                    this.showNotification('打开新增模型对话框时出错: ' + error.message, 'error');
                }
            });

            // 删除模型按钮
            const deleteModelButton = this.createButton('🗑️ 删除', 'secondary');
            deleteModelButton.style.cssText += `
                margin-bottom: 16px;
                height: 48px;
                min-width: 80px;
                background: rgba(244, 67, 54, 0.2);
                border: 1px solid rgba(244, 67, 54, 0.3);
            `;
            deleteModelButton.addEventListener('click', () => this.showDeleteModelDialog());

            modelSelectContainer.appendChild(selectWrapper);
            modelSelectContainer.appendChild(addModelButton);
            modelSelectContainer.appendChild(deleteModelButton);

            // API配置
            const currentModel = CONFIG.AI_MODELS.TYPE;
            const apiGroup = this.createFormGroup('API 配置', this.createAPIConfig(currentModel));

            container.appendChild(modelSelectContainer);
            container.appendChild(apiGroup);

            return container;
        }

        createModelSelect() {
            const select = document.createElement('select');
            select.style.cssText = `
                width: 100%;
                padding: 12px 16px;
                border-radius: 12px;
                background: rgba(255, 255, 255, 0.9);
                color: #333;
                border: 1px solid rgba(255, 255, 255, 0.2);
                font-size: 14px;
                cursor: pointer;
                outline: none;
                transition: all 0.3s ease;
                box-sizing: border-box;
            `;

            Object.keys(CONFIG.AI_MODELS).forEach(model => {
                if (model !== 'TYPE') {
                    const option = document.createElement('option');
                    option.value = model;
                    const modelConfig = CONFIG.AI_MODELS[model];
                    const displayName = modelConfig.NAME || model;
                    option.textContent = `${displayName} (${modelConfig.MODEL})`;
                    if (CONFIG.AI_MODELS.TYPE === model) {
                        option.selected = true;
                    }
                    select.appendChild(option);
                }
            });

            select.addEventListener('change', () => {
                CONFIG.AI_MODELS.TYPE = select.value;
                this.videoController.onConfigUpdate('AI_MODELS.TYPE', select.value);
                this.updateAPIConfig(select.value);
                this.updateTitleWithModel(); // 更新标题显示新模型
            });

            return select;
        }

        createStreamSelect(modelType) {
            const select = document.createElement('select');
            select.style.cssText = `
                width: 100%;
                padding: 12px 16px;
                border-radius: 12px;
                background: rgba(255, 255, 255, 0.9);
                color: #333;
                border: 1px solid rgba(255, 255, 255, 0.2);
                font-size: 14px;
                cursor: pointer;
                outline: none;
                transition: all 0.3s ease;
                box-sizing: border-box;
            `;

            const options = [
                { value: 'false', text: '否 (标准响应)' },
                { value: 'true', text: '是 (流式响应)' }
            ];

            options.forEach(option => {
                const optionEl = document.createElement('option');
                optionEl.value = option.value;
                optionEl.textContent = option.text;
                if (CONFIG.AI_MODELS[modelType].STREAM.toString() === option.value) {
                    optionEl.selected = true;
                }
                select.appendChild(optionEl);
            });

            select.addEventListener('change', () => {
                CONFIG.AI_MODELS[modelType].STREAM = select.value === 'true';
                console.log(`${modelType} 流式响应设置已更新:`, CONFIG.AI_MODELS[modelType].STREAM);
            });

            return select;
        }

        createAPIConfig(modelType) {
            const container = document.createElement('div');
            container.id = 'api-config-container';

            const modelConfig = CONFIG.AI_MODELS[modelType];

            // 显示名称
            const nameGroup = this.createFormGroup('显示名称', this.createInput(modelConfig.NAME || '', (value) => {
                CONFIG.AI_MODELS[modelType].NAME = value;
            }));

            const urlGroup = this.createFormGroup('API URL', this.createInput(modelConfig.API_URL, (value) => {
                CONFIG.AI_MODELS[modelType].API_URL = value;
            }));

            const keyGroup = this.createFormGroup('API Key', this.createInput(modelConfig.API_KEY, (value) => {
                CONFIG.AI_MODELS[modelType].API_KEY = value;
            }, 'password'));

            const modelGroup = this.createFormGroup('模型名称', this.createInput(modelConfig.MODEL, (value) => {
                CONFIG.AI_MODELS[modelType].MODEL = value;
            }));

            const streamGroup = this.createFormGroup('流式响应', this.createStreamSelect(modelType));

            // 温度设置
            const temperatureGroup = this.createFormGroup('温度 (0-2)', this.createNumberInput(
                modelConfig.TEMPERATURE || 0.7,
                (value) => {
                    CONFIG.AI_MODELS[modelType].TEMPERATURE = parseFloat(value);
                },
                0, 2, 0.1
            ));

            // 最大令牌数设置
            const maxTokensGroup = this.createFormGroup('最大输出令牌', this.createNumberInput(
                modelConfig.MAX_TOKENS || 2000,
                (value) => {
                    CONFIG.AI_MODELS[modelType].MAX_TOKENS = parseInt(value);
                },
                1, 100000, 1
            ));

            container.appendChild(nameGroup);
            container.appendChild(urlGroup);
            container.appendChild(keyGroup);
            container.appendChild(modelGroup);
            container.appendChild(streamGroup);
            container.appendChild(temperatureGroup);
            container.appendChild(maxTokensGroup);

            return container;
        }

        createPromptConfig() {
            const container = document.createElement('div');
            container.style.cssText = `
                height: auto;
                display: flex;
                flex-direction: column;
                justify-content: flex-start;
            `;

            // 当前Prompt选择和管理容器(参考左侧设计)
            const promptSelectContainer = document.createElement('div');
            promptSelectContainer.style.cssText = `
                display: flex;
                gap: 8px;
                align-items: flex-end;
                margin-bottom: 16px;
            `;

            const selectWrapper = document.createElement('div');
            selectWrapper.style.cssText = `
                flex: 1;
            `;

            const currentPromptGroup = this.createFormGroup('当前默认 Prompt', this.createPromptSelect());
            selectWrapper.appendChild(currentPromptGroup);

            // 添加新Prompt按钮(参考左侧设计)
            const addButton = this.createButton('➕ 新增', 'secondary');
            addButton.style.cssText += `
                margin-bottom: 16px;
                height: 48px;
                min-width: 80px;
            `;
            addButton.addEventListener('click', () => this.showAddPromptDialog());

            promptSelectContainer.appendChild(selectWrapper);
            promptSelectContainer.appendChild(addButton);

            // Prompt列表管理
            const promptListGroup = this.createFormGroup('Prompt 列表管理', this.createPromptList());
            promptListGroup.style.cssText += `
                flex: 1;
                margin-bottom: 8px;
            `;

            container.appendChild(promptSelectContainer);
            container.appendChild(promptListGroup);

            return container;
        }

        createPromptSelect() {
            const select = document.createElement('select');
            select.style.cssText = `
                width: 100%;
                padding: 12px 16px;
                border-radius: 12px;
                background: rgba(255, 255, 255, 0.9);
                color: #333;
                border: 1px solid rgba(255, 255, 255, 0.2);
                font-size: 14px;
                cursor: pointer;
                outline: none;
                transition: all 0.3s ease;
                box-sizing: border-box;
            `;

            this.promptSelectElement = select; // [!CHANGED!]
            this.updatePromptSelect(this.promptSelectElement);

            select.addEventListener('change', () => {
                CONFIG.PROMPTS.DEFAULT = select.value;
                this.showNotification('默认 Prompt 已更新', 'success');
            });

            return select;
        }

        updatePromptSelect(select) {
            try {
                // 安全地清空元素内容
                while (select.firstChild) {
                    select.removeChild(select.firstChild);
                }

                CONFIG.PROMPTS.LIST.forEach(prompt => {
                    const option = document.createElement('option');
                    option.value = prompt.id;
                    option.textContent = prompt.name; // 使用 textContent 确保安全
                    if (CONFIG.PROMPTS.DEFAULT === prompt.id) {
                        option.selected = true;
                    }
                    select.appendChild(option);
                });
            } catch (error) {
                console.error('更新Prompt选择器时发生错误:', error);
                this.showNotification('更新Prompt选择器失败', 'error');
            }
        }

        createPromptList() {
            const container = document.createElement('div');
            container.id = 'prompt-list-container';
            container.style.cssText = `
                max-height: 600px;
                height: auto;
                overflow-y: auto;
                border: 1px solid rgba(255, 255, 255, 0.2);
                border-radius: 12px;
                background: rgba(255, 255, 255, 0.05);
                padding: 4px;
            `;

            this.updatePromptList(container);
            return container;
        }

        updatePromptList(container) {
            try {
                // 安全地清空元素内容
                while (container.firstChild) {
                    container.removeChild(container.firstChild);
                }

                CONFIG.PROMPTS.LIST.forEach((prompt, index) => {
                const item = document.createElement('div');
                item.style.cssText = `
                    padding: 8px 12px;
                    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    transition: background 0.2s ease;
                    min-height: 50px;
                `;

                item.addEventListener('mouseover', () => {
                    item.style.background = 'rgba(255, 255, 255, 0.1)';
                });

                item.addEventListener('mouseout', () => {
                    item.style.background = 'transparent';
                });

                const info = document.createElement('div');
                info.style.cssText = `
                    flex: 1;
                    margin-right: 12px;
                `;

                const name = document.createElement('div');
                name.textContent = prompt.name;
                name.style.cssText = `
                    font-weight: 500;
                    font-size: 13px;
                    margin-bottom: 2px;
                `;

                const promptText = document.createElement('div');
                promptText.textContent = prompt.prompt.substring(0, 80) + (prompt.prompt.length > 80 ? '...' : '');
                promptText.style.cssText = `
                    font-size: 11px;
                    color: rgba(255, 255, 255, 0.7);
                    line-height: 1.3;
                    max-width: 100%;
                    word-wrap: break-word;
                `;

                info.appendChild(name);
                info.appendChild(promptText);

                const actions = document.createElement('div');
                actions.style.cssText = `
                    display: flex;
                    gap: 8px;
                `;

                // 编辑按钮
                const editBtn = this.createSmallButton('✏️', '编辑');
                editBtn.addEventListener('click', () => this.showEditPromptDialog(prompt, index));

                // 删除按钮(不能删除只有一个prompt的情况)
                if (CONFIG.PROMPTS.LIST.length > 1) {
                    const deleteBtn = this.createSmallButton('🗑️', '删除', '#ff4757');
                    deleteBtn.addEventListener('click', () => this.deletePrompt(index));
                    actions.appendChild(deleteBtn);
                }

                actions.appendChild(editBtn);
                item.appendChild(info);
                item.appendChild(actions);
                container.appendChild(item);
                });
            } catch (error) {
                console.error('更新Prompt列表时发生错误:', error);
                this.showNotification('更新Prompt列表失败', 'error');
            }
        }

        createSmallButton(text, tooltip, bgColor = 'rgba(255, 255, 255, 0.2)') {
            const button = document.createElement('button');
            button.textContent = text;
            button.title = tooltip;
            button.style.cssText = `
                background: ${bgColor};
                border: none;
                color: #fff;
                cursor: pointer;
                padding: 6px 8px;
                font-size: 12px;
                border-radius: 6px;
                transition: all 0.2s ease;
            `;

            button.addEventListener('mouseover', () => {
                button.style.opacity = '0.8';
                button.style.transform = 'scale(1.1)';
            });

            button.addEventListener('mouseout', () => {
                button.style.opacity = '1';
                button.style.transform = 'scale(1)';
            });

            return button;
        }

        showAddPromptDialog() {
            this.showPromptDialog('添加新 Prompt', '', '', (name, prompt) => {
                const newPrompt = {
                    id: 'custom_' + Date.now(),
                    name: name,
                    prompt: prompt
                };

                CONFIG.PROMPTS.LIST.push(newPrompt);
                this.updatePromptList(document.getElementById('prompt-list-container'));
                this.updatePromptSelect(this.promptSelectElement); // [!CHANGED!]
                this.showNotification('新 Prompt 已添加', 'success');
            });
        }

        showEditPromptDialog(prompt, index) {
            this.showPromptDialog('编辑 Prompt', prompt.name, prompt.prompt, (name, promptText) => {
                CONFIG.PROMPTS.LIST[index].name = name;
                CONFIG.PROMPTS.LIST[index].prompt = promptText;
                this.updatePromptList(document.getElementById('prompt-list-container'));
                this.updatePromptSelect(this.promptSelectElement); // [!CHANGED!]
                this.showNotification('Prompt 已更新', 'success');
            });
        }

        showPromptDialog(title, defaultName, defaultPrompt, onSave) {
            console.log('显示Prompt对话框:', title);

            const dialog = document.createElement('div');
            dialog.style.cssText = `
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.5);
                z-index: 100000;
                display: flex;
                align-items: center;
                justify-content: center;
                backdrop-filter: blur(5px);
            `;

            console.log('对话框z-index已设置为:', dialog.style.zIndex);

            const dialogContent = document.createElement('div');
            dialogContent.style.cssText = `
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                border-radius: 16px;
                padding: 24px;
                width: 400px;
                max-width: 90vw;
                max-height: 90vh;
                color: #fff;
                box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
                overflow-y: auto;
                margin: 20px;
                box-sizing: border-box;
            `;

            const dialogTitle = document.createElement('h3');
            dialogTitle.textContent = title;
            dialogTitle.style.cssText = `
                margin: 0 0 20px 0;
                font-size: 18px;
                font-weight: 600;
            `;

            const nameInput = this.createInput(defaultName, null, 'text', 'Prompt 名称');
            const promptInput = document.createElement('textarea');
            promptInput.value = defaultPrompt;
            promptInput.placeholder = '输入 Prompt 内容...';
            promptInput.style.cssText = `
                width: 100%;
                height: 120px;
                padding: 12px 16px;
                border-radius: 12px;
                background: rgba(255, 255, 255, 0.9);
                color: #333;
                border: 1px solid rgba(255, 255, 255, 0.2);
                font-size: 14px;
                outline: none;
                resize: vertical;
                font-family: inherit;
                margin-top: 12px;
                box-sizing: border-box;
                transition: all 0.3s ease;
                line-height: 1.5;
            `;

            // 添加焦点和失焦效果
            promptInput.addEventListener('focus', () => {
                promptInput.style.borderColor = 'rgba(102, 126, 234, 0.6)';
                promptInput.style.boxShadow = '0 0 0 2px rgba(102, 126, 234, 0.2)';
            });

            promptInput.addEventListener('blur', () => {
                promptInput.style.borderColor = 'rgba(255, 255, 255, 0.2)';
                promptInput.style.boxShadow = 'none';
            });

            const buttonContainer = document.createElement('div');
            buttonContainer.style.cssText = `
                display: flex;
                gap: 12px;
                margin-top: 20px;
                justify-content: flex-end;
            `;

            const cancelBtn = this.createButton('取消', 'secondary');
            cancelBtn.style.flex = '1';
            cancelBtn.addEventListener('click', () => {
                document.body.removeChild(dialog);
            });

            const saveBtn = this.createButton('保存', 'primary');
            saveBtn.style.flex = '1';
            saveBtn.addEventListener('click', () => {
                const name = nameInput.value.trim();
                const prompt = promptInput.value.trim();

                if (!name || !prompt) {
                    this.showNotification('请填写完整信息', 'error');
                    return;
                }

                onSave(name, prompt);
                document.body.removeChild(dialog);
            });

            buttonContainer.appendChild(cancelBtn);
            buttonContainer.appendChild(saveBtn);

            dialogContent.appendChild(dialogTitle);
            dialogContent.appendChild(nameInput);
            dialogContent.appendChild(promptInput);
            dialogContent.appendChild(buttonContainer);

            dialog.appendChild(dialogContent);
            document.body.appendChild(dialog);

            // 点击外部关闭
            dialog.addEventListener('click', (e) => {
                if (e.target === dialog) {
                    document.body.removeChild(dialog);
                }
            });

            // 聚焦到名称输入框
            setTimeout(() => {
                try {
                    nameInput.focus();
                    console.log('输入框已获得焦点');
                } catch (e) {
                    console.warn('设置焦点失败:', e);
                }
            }, 100);
        }

        deletePrompt(index) {
            if (CONFIG.PROMPTS.LIST.length <= 1) {
                this.showNotification('至少需要保留一个 Prompt', 'error');
                return;
            }

            const prompt = CONFIG.PROMPTS.LIST[index];

            // 如果删除的是当前默认prompt,切换到第一个
            if (CONFIG.PROMPTS.DEFAULT === prompt.id) {
                CONFIG.PROMPTS.DEFAULT = CONFIG.PROMPTS.LIST[0].id === prompt.id ?
                    CONFIG.PROMPTS.LIST[1].id : CONFIG.PROMPTS.LIST[0].id;
            }

            CONFIG.PROMPTS.LIST.splice(index, 1);
            this.updatePromptList(document.getElementById('prompt-list-container'));
            this.updatePromptSelect(this.promptSelectElement); // [!CHANGED!]
            this.showNotification('Prompt 已删除', 'success');
        }

        createFormGroup(label, input) {
            const group = document.createElement('div');
            group.style.cssText = `
                margin-bottom: 16px;
            `;

            const labelEl = document.createElement('label');
            labelEl.textContent = label;
            labelEl.style.cssText = `
                display: block;
                margin-bottom: 8px;
                font-size: 14px;
                font-weight: 500;
                color: rgba(255, 255, 255, 0.9);
            `;

            group.appendChild(labelEl);
            group.appendChild(input);

            return group;
        }

        createInput(defaultValue, onChange, type = 'text', placeholder = '') {
            const input = document.createElement('input');
            input.type = type;
            input.value = defaultValue;
            input.placeholder = placeholder;
            input.style.cssText = `
                width: 100%;
                padding: 12px 16px;
                border-radius: 12px;
                background: rgba(255, 255, 255, 0.9);
                color: #333;
                border: 1px solid rgba(255, 255, 255, 0.2);
                font-size: 14px;
                outline: none;
                transition: all 0.3s ease;
                box-sizing: border-box;
            `;

            // 添加焦点和失焦效果
            input.addEventListener('focus', () => {
                input.style.borderColor = 'rgba(102, 126, 234, 0.6)';
                input.style.boxShadow = '0 0 0 2px rgba(102, 126, 234, 0.2)';
            });

            input.addEventListener('blur', () => {
                input.style.borderColor = 'rgba(255, 255, 255, 0.2)';
                input.style.boxShadow = 'none';
            });

            if (onChange) {
                input.addEventListener('input', (e) => onChange(e.target.value));
            }

            return input;
        }

        createNumberInput(defaultValue, onChange, min = 0, max = 100, step = 1) {
            const input = document.createElement('input');
            input.type = 'number';
            input.value = defaultValue;
            input.min = min;
            input.max = max;
            input.step = step;
            input.style.cssText = `
                width: 100%;
                padding: 12px 16px;
                border-radius: 12px;
                background: rgba(255, 255, 255, 0.9);
                color: #333;
                border: 1px solid rgba(255, 255, 255, 0.2);
                font-size: 14px;
                outline: none;
                transition: all 0.3s ease;
                box-sizing: border-box;
            `;

            // 添加焦点和失焦效果
            input.addEventListener('focus', () => {
                input.style.borderColor = 'rgba(102, 126, 234, 0.6)';
                input.style.boxShadow = '0 0 0 2px rgba(102, 126, 234, 0.2)';
            });

            input.addEventListener('blur', () => {
                input.style.borderColor = 'rgba(255, 255, 255, 0.2)';
                input.style.boxShadow = 'none';
            });

            if (onChange) {
                input.addEventListener('input', (e) => {
                    const value = parseFloat(e.target.value);
                    if (!isNaN(value) && value >= min && value <= max) {
                        onChange(e.target.value);
                    }
                });
            }

            return input;
        }

        updateAPIConfig(modelType) {
            const container = document.getElementById('api-config-container');
            if (container) {
                const newConfig = this.createAPIConfig(modelType);
                container.parentNode.replaceChild(newConfig, container);
            }
        }

        // createConfigActions 方法已移除 - 操作按钮现在在标题栏中

        showAddModelDialog() {
            console.log('显示新增模型对话框');

            const dialog = document.createElement('div');
            dialog.style.cssText = `
                position: fixed;
                top: 0;
                left: 0;
                width: 100%;
                height: 100%;
                background: rgba(0, 0, 0, 0.5);
                z-index: 100000;
                display: flex;
                align-items: center;
                justify-content: center;
                backdrop-filter: blur(5px);
            `;

            const dialogContent = document.createElement('div');
            dialogContent.style.cssText = `
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                border-radius: 16px;
                padding: 24px;
                width: 500px;
                max-width: 90vw;
                max-height: 90vh;
                color: #fff;
                box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3);
                overflow-y: auto;
                margin: 20px;
                box-sizing: border-box;
            `;

            const dialogTitle = document.createElement('h3');
            dialogTitle.textContent = '新增 AI 模型';
            dialogTitle.style.cssText = `
                margin: 0 0 20px 0;
                font-size: 18px;
                font-weight: 600;
            `;

            // 表单字段
            const keyInput = this.createInput('', null, 'text', '模型标识键(如:CLAUDE, OPENAI_GPT4)');
            const nameInput = this.createInput('', null, 'text', '显示名称(如:Claude 3.5)');
            const urlInput = this.createInput('', null, 'text', 'API URL');
            const apiKeyInput = this.createInput('', null, 'password', 'API Key');
            const modelInput = this.createInput('', null, 'text', '模型名称(如:gpt-4-turbo)');

            // 流式响应选择
            const streamSelect = document.createElement('select');
            streamSelect.style.cssText = this.createInput('', null).style.cssText;

            // 使用安全的DOM操作而不是innerHTML
            const option1 = document.createElement('option');
            option1.value = 'false';
            option1.textContent = '否 (标准响应)';
            streamSelect.appendChild(option1);

            const option2 = document.createElement('option');
            option2.value = 'true';
            option2.textContent = '是 (流式响应)';
            streamSelect.appendChild(option2);

            const temperatureInput = this.createNumberInput(0.7, null, 0, 2, 0.1);
            const maxTokensInput = this.createNumberInput(2000, null, 1, 100000, 1);

            const buttonContainer = document.createElement('div');
            buttonContainer.style.cssText = `
                display: flex;
                gap: 12px;
                margin-top: 20px;
                justify-content: flex-end;
            `;

            const cancelBtn = this.createButton('取消', 'secondary');
            cancelBtn.style.flex = '1';
            cancelBtn.addEventListener('click', () => {
                document.body.removeChild(dialog);
            });

            const saveBtn = this.createButton('保存', 'primary');
            saveBtn.style.flex = '1';
            saveBtn.addEventListener('click', () => {
                const key = keyInput.value.trim().toUpperCase();
                const name = nameInput.value.trim();
                const url = urlInput.value.trim();
                const apiKey = apiKeyInput.value.trim();
                const model = modelInput.value.trim();
                const stream = streamSelect.value === 'true';
                const temperature = parseFloat(temperatureInput.value);
                const maxTokens = parseInt(maxTokensInput.value);

                if (!key || !name || !url || !apiKey || !model) {
                    this.showNotification('请填写完整信息', 'error');
                    return;
                }

                if (CONFIG.AI_MODELS[key]) {
                    this.showNotification('模型标识键已存在', 'error');
                    return;
                }

                // 添加新模型
                CONFIG.AI_MODELS[key] = {
                    NAME: name,
                    API_KEY: apiKey,
                    API_URL: url,
                    MODEL: model,
                    STREAM: stream,
                    TEMPERATURE: temperature,
                    MAX_TOKENS: maxTokens
                };

                // 只刷新模型选择器,避免重建整个面板
                try {
                    const modelSelect = this.configPanel.querySelector('select');
                    if (modelSelect) {
                        // 安全地清空选择器选项
                        while (modelSelect.firstChild) {
                            modelSelect.removeChild(modelSelect.firstChild);
                        }

                        // 重建选择器选项
                        Object.keys(CONFIG.AI_MODELS).forEach(model => {
                            if (model !== 'TYPE') {
                                const option = document.createElement('option');
                                option.value = model;
                                const modelConfig = CONFIG.AI_MODELS[model];
                                const displayName = modelConfig.NAME || model;
                                option.textContent = `${displayName} (${modelConfig.MODEL})`;
                                if (CONFIG.AI_MODELS.TYPE === model) {
                                    option.selected = true;
                                }
                                modelSelect.appendChild(option);
                            }
                        });
                    }

                    // 更新主界面标题
                    this.updateTitleWithModel();

                } catch (refreshError) {
                    console.warn('刷新配置面板时出错:', refreshError);
                    // 如果刷新失败,提示用户手动重新打开配置面板
                    this.showNotification('新模型已添加,请重新打开配置面板查看', 'success');
                }

                this.showNotification('新模型已添加', 'success');
                document.body.removeChild(dialog);
            });

            buttonContainer.appendChild(cancelBtn);
            buttonContainer.appendChild(saveBtn);

            dialogContent.appendChild(dialogTitle);
            dialogContent.appendChild(this.createFormGroup('模型标识键', keyInput));
            dialogContent.appendChild(this.createFormGroup('显示名称', nameInput));
            dialogContent.appendChild(this.createFormGroup('API URL', urlInput));
            dialogContent.appendChild(this.createFormGroup('API Key', apiKeyInput));
            dialogContent.appendChild(this.createFormGroup('模型名称', modelInput));
            dialogContent.appendChild(this.createFormGroup('流式响应', streamSelect));
            dialogContent.appendChild(this.createFormGroup('温度 (0-2)', temperatureInput));
            dialogContent.appendChild(this.createFormGroup('最大输出令牌', maxTokensInput));
            dialogContent.appendChild(buttonContainer);

            dialog.appendChild(dialogContent);
            document.body.appendChild(dialog);

            // 点击外部关闭
            dialog.addEventListener('click', (e) => {
                if (e.target === dialog) {
                    document.body.removeChild(dialog);
                }
            });

            // 聚焦到第一个输入框
            setTimeout(() => {
                try {
                    keyInput.focus();
                } catch (e) {
                    console.warn('设置焦点失败:', e);
                }
            }, 100);
        }

        showDeleteModelDialog() {
            const currentModel = CONFIG.AI_MODELS.TYPE;
            const modelKeys = Object.keys(CONFIG.AI_MODELS).filter(key => key !== 'TYPE');

            if (modelKeys.length <= 1) {
                this.showNotification('至少需要保留一个模型', 'error');
                return;
            }

            const modelConfig = CONFIG.AI_MODELS[currentModel];
            const modelName = modelConfig?.NAME || currentModel;

            if (confirm(`确定要删除模型 "${modelName}" 吗?此操作不可撤销。`)) {
                // 删除模型
                delete CONFIG.AI_MODELS[currentModel];

                // 切换到第一个可用模型
                const remainingModels = Object.keys(CONFIG.AI_MODELS).filter(key => key !== 'TYPE');
                CONFIG.AI_MODELS.TYPE = remainingModels[0];

                // 只刷新模型选择器和API配置
                try {
                    const modelSelect = this.configPanel.querySelector('select');
                    if (modelSelect) {
                        // 安全地清空选择器选项
                        while (modelSelect.firstChild) {
                            modelSelect.removeChild(modelSelect.firstChild);
                        }

                        // 重建选择器选项
                        Object.keys(CONFIG.AI_MODELS).forEach(model => {
                            if (model !== 'TYPE') {
                                const option = document.createElement('option');
                                option.value = model;
                                const modelConfig = CONFIG.AI_MODELS[model];
                                const displayName = modelConfig.NAME || model;
                                option.textContent = `${displayName} (${modelConfig.MODEL})`;
                                if (CONFIG.AI_MODELS.TYPE === model) {
                                    option.selected = true;
                                }
                                modelSelect.appendChild(option);
                            }
                        });

                        // 触发选择器变更事件,更新API配置
                        const event = new Event('change');
                        modelSelect.dispatchEvent(event);
                    }
                } catch (refreshError) {
                    console.warn('刷新配置面板时出错:', refreshError);
                }

                // 更新主界面
                this.videoController.onConfigUpdate('AI_MODELS.TYPE', CONFIG.AI_MODELS.TYPE);
                this.updateTitleWithModel();

                this.showNotification('模型已删除', 'success');
            }
        }

        saveConfig() {
            try {
                ConfigManager.saveConfig(CONFIG);
                this.showNotification('配置已保存', 'success');
            } catch (error) {
                console.error('保存配置失败:', error);
                this.showNotification('保存配置失败: ' + error.message, 'error');
            }
        }

        resetConfig() {
            if (confirm('确定要重置所有配置吗?这将清除所有自定义设置。')) {
                try {
                    CONFIG = ConfigManager.getDefaultConfig();
                    ConfigManager.saveConfig(CONFIG);

                    // 关闭当前配置面板并重新打开
                    this.configPanel.style.display = 'none';
                    this.configPanel.remove();
                    this.createConfigPanel();
                    this.toggleConfigPanel();

                    // 更新主界面
                    this.videoController.onConfigUpdate('AI_MODELS.TYPE', CONFIG.AI_MODELS.TYPE);
                    this.updateTitleWithModel();

                    this.showNotification('配置已重置', 'success');
                } catch (error) {
                    console.error('重置配置失败:', error);
                    this.showNotification('重置配置失败: ' + error.message, 'error');
                }
            }
        }

        toggleCollapse() {
            this.isCollapsed = !this.isCollapsed;

            if (this.isCollapsed) {
                this.mainContent.style.display = 'none';
                this.toggleButton.textContent = '↓';
                this.container.style.width = 'auto';
            } else {
                this.mainContent.style.display = 'block';
                this.toggleButton.textContent = '↑';
                this.container.style.width = '400px';
            }
        }

        toggleConfigPanel() {
            console.log('toggleConfigPanel 方法被调用');

            try {
                if (!this.configPanel) {
                    console.log('配置面板不存在,开始创建');
                    this.createConfigPanel();
                }

                if (!this.configPanel) {
                    console.error('配置面板创建失败');
                    this.showNotification('配置面板创建失败', 'error');
                    return;
                }

                // 检查配置面板是否可见
                const isVisible = this.configPanel.style.display === 'block';
                console.log('当前配置面板状态:', isVisible ? '可见' : '隐藏');

                if (isVisible) {
                    this.configPanel.style.display = 'none';
                    console.log('配置面板已隐藏');
                } else {
                    this.configPanel.style.display = 'block';
                    this.configPanel.style.opacity = '1';
                    this.configPanel.style.visibility = 'visible';
                    console.log('配置面板已显示');

                    // 确保面板在最前面
                    this.configPanel.style.zIndex = '50000';
                }
            } catch (error) {
                console.error('toggleConfigPanel 方法执行失败:', error);
                this.showNotification('配置面板操作失败: ' + error.message, 'error');
            }
        }

        updateStatus(message, type = 'info') {
            this.statusDisplay.textContent = message;
            this.statusDisplay.style.display = 'block';

            // 根据类型设置颜色
            const colors = {
                'info': 'rgba(33, 150, 243, 0.2)',
                'success': 'rgba(76, 175, 80, 0.2)',
                'error': 'rgba(244, 67, 54, 0.2)',
                'warning': 'rgba(255, 193, 7, 0.2)'
            };

            this.statusDisplay.style.background = colors[type] || colors['info'];
        }

        showNotification(message, type = 'info') {
            try {
                const notification = document.createElement('div');
                notification.textContent = message; // 使用 textContent 确保安全

                const colors = {
                    'info': '#2196F3',
                    'success': '#4CAF50',
                    'error': '#F44336',
                    'warning': '#FF9800'
                };

                notification.style.cssText = `
                    position: fixed;
                    top: 20px;
                    left: 50%;
                    transform: translateX(-50%);
                    background: ${colors[type] || colors['info']};
                    color: #fff;
                    padding: 12px 24px;
                    border-radius: 8px;
                    font-size: 14px;
                    z-index: 200000;
                    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
                    opacity: 0;
                    transition: all 0.3s ease;
                `;

                document.body.appendChild(notification);

                setTimeout(() => {
                    try {
                        notification.style.opacity = '1';
                        notification.style.transform = 'translateX(-50%) translateY(0)';
                    } catch (e) {
                        console.warn('通知显示动画失败:', e);
                    }
                }, 100);

                setTimeout(() => {
                    try {
                        notification.style.opacity = '0';
                        notification.style.transform = 'translateX(-50%) translateY(-20px)';
                        setTimeout(() => {
                            try {
                                if (notification.parentNode) {
                                    notification.parentNode.removeChild(notification);
                                }
                            } catch (e) {
                                console.warn('移除通知元素失败:', e);
                            }
                        }, 300);
                    } catch (e) {
                        console.warn('通知隐藏动画失败:', e);
                    }
                }, 3000);
            } catch (error) {
                console.error('显示通知失败:', error);
                // 备用方案:使用原生alert
                alert(message);
            }
        }

        showExtensionPrompt() {
            try {
                const prompt = document.createElement('div');
                prompt.style.cssText = `
                    position: fixed;
                    top: 50%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                    color: #fff;
                    padding: 24px;
                    border-radius: 16px;
                    font-size: 14px;
                    z-index: 200001;
                    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
                    opacity: 0;
                    transition: all 0.3s ease;
                    max-width: 400px;
                    text-align: center;
                `;

                // 添加背景遮罩
                const overlay = document.createElement('div');
                overlay.style.cssText = `
                    position: fixed;
                    top: 0;
                    left: 0;
                    width: 100%;
                    height: 100%;
                    background: rgba(0, 0, 0, 0.5);
                    z-index: 200000;
                    opacity: 0;
                    transition: opacity 0.3s ease;
                `;

                // 统一的清理函数
                const cleanup = () => {
                    try {
                        if (overlay.parentNode) {
                            overlay.parentNode.removeChild(overlay);
                        }
                        if (prompt.parentNode) {
                            prompt.parentNode.removeChild(prompt);
                        }
                    } catch (e) {
                        console.warn('清理扩展提示元素失败:', e);
                    }
                };

                const title = document.createElement('div');
                title.style.cssText = `
                    font-size: 18px;
                    font-weight: bold;
                    margin-bottom: 16px;
                    color: #fff;
                `;
                title.textContent = '🔧 需要安装浏览器扩展';

                const message = document.createElement('div');
                message.style.cssText = `
                    margin-bottom: 20px;
                    line-height: 1.5;
                    color: rgba(255, 255, 255, 0.9);
                `;
                message.textContent = '当前视频无法获取字幕内容。建议安装 YouTube Text Tools 扩展来获取更好的字幕支持。';

                const buttonContainer = document.createElement('div');
                buttonContainer.style.cssText = `
                    display: flex;
                    gap: 12px;
                    justify-content: center;
                `;

                const installButton = document.createElement('button');
                installButton.style.cssText = `
                    background: #4CAF50;
                    color: #fff;
                    border: none;
                    padding: 12px 20px;
                    border-radius: 8px;
                    cursor: pointer;
                    font-size: 14px;
                    font-weight: bold;
                    transition: all 0.2s ease;
                `;
                installButton.textContent = '🚀 安装扩展';
                installButton.addEventListener('click', () => {
                    window.open('https://chromewebstore.google.com/detail/youtube-text-tools/pcmahconeajhpgleboodnodllkoimcoi', '_blank');
                    cleanup();
                });

                installButton.addEventListener('mouseenter', () => {
                    installButton.style.background = '#45a049';
                    installButton.style.transform = 'translateY(-1px)';
                });

                installButton.addEventListener('mouseleave', () => {
                    installButton.style.background = '#4CAF50';
                    installButton.style.transform = 'translateY(0)';
                });

                const cancelButton = document.createElement('button');
                cancelButton.style.cssText = `
                    background: rgba(255, 255, 255, 0.2);
                    color: #fff;
                    border: 1px solid rgba(255, 255, 255, 0.3);
                    padding: 12px 20px;
                    border-radius: 8px;
                    cursor: pointer;
                    font-size: 14px;
                    transition: all 0.2s ease;
                `;
                cancelButton.textContent = '关闭';
                cancelButton.addEventListener('click', cleanup);

                cancelButton.addEventListener('mouseenter', () => {
                    cancelButton.style.background = 'rgba(255, 255, 255, 0.3)';
                });

                cancelButton.addEventListener('mouseleave', () => {
                    cancelButton.style.background = 'rgba(255, 255, 255, 0.2)';
                });

                overlay.addEventListener('click', cleanup);

                buttonContainer.appendChild(installButton);
                buttonContainer.appendChild(cancelButton);

                prompt.appendChild(title);
                prompt.appendChild(message);
                prompt.appendChild(buttonContainer);

                document.body.appendChild(overlay);
                document.body.appendChild(prompt);

                setTimeout(() => {
                    try {
                        overlay.style.opacity = '1';
                        prompt.style.opacity = '1';
                        prompt.style.transform = 'translate(-50%, -50%) scale(1)';
                    } catch (e) {
                        console.warn('扩展提示显示动画失败:', e);
                    }
                }, 100);

            } catch (error) {
                console.error('显示扩展安装提示失败:', error);
                // 备用方案:使用原生confirm
                if (confirm('当前视频无法获取字幕内容。是否安装 YouTube Text Tools 扩展来获取更好的字幕支持?')) {
                    window.open('https://chromewebstore.google.com/detail/youtube-text-tools/pcmahconeajhpgleboodnodllkoimcoi', '_blank');
                }
            }
        }

        async handleLoadSubtitles() {
            try {
                this.updateStatus('正在加载字幕...', 'info');
                this.loadSubtitlesButton.disabled = true;

                await this.videoController.loadSubtitles();

                this.updateStatus(`字幕加载完成,共 ${this.videoController.subtitleManager.subtitles.length} 条`, 'success');
                this.loadSubtitlesButton.style.display = 'none';
                this.summaryButton.style.display = 'block';

            } catch (error) {
                this.updateStatus('加载字幕失败: ' + error.message, 'error');
                this.loadSubtitlesButton.disabled = false;

                // 如果是字幕获取失败的错误,显示扩展安装提示
                const errorMessage = error.message.toLowerCase();
                if (errorMessage.includes('无法从任何来源获取字幕数据') ||
                    errorMessage.includes('未找到字幕数据') ||
                    errorMessage.includes('字幕') ||
                    errorMessage.includes('subtitle') ||
                    errorMessage.includes('transcript')) {

                    // 延迟显示提示,让用户先看到错误状态
                    setTimeout(() => {
                        this.showExtensionPrompt();
                    }, 1500);
                }
            }
        }

        async handleGenerateSummary() {
            try {
                console.log('开始生成总结按钮处理...');
                this.updateStatus('正在生成总结...', 'info');
                this.summaryButton.disabled = true;

                // 检查字幕数据是否存在
                if (!this.videoController.subtitleManager.subtitles || this.videoController.subtitleManager.subtitles.length === 0) {
                    throw new Error('没有可用的字幕数据,请先加载字幕');
                }

                console.log(`当前有 ${this.videoController.subtitleManager.subtitles.length} 条字幕可用`);

                const summary = await this.videoController.getSummary();
                console.log('成功获取总结,长度:', summary?.length || 0);

                if (!summary || summary.trim() === '') {
                    throw new Error('生成的总结为空,请检查API配置或网络连接');
                }

                // 保存原始markdown文本供复制使用
                this.originalSummaryText = summary;
                console.log('已保存原始总结文本供复制使用');

                // 清空内容并使用markdown格式化显示
                this.summaryContent.textContent = '';
                this.createFormattedContent(this.summaryContent, summary);
                console.log('总结内容已格式化并显示');

                this.summaryPanel.style.display = 'block';
                this.updateStatus('总结生成完成', 'success');

                // 滚动到总结面板
                this.summaryPanel.scrollIntoView({ behavior: 'smooth', block: 'start' });

            } catch (error) {
                console.error('生成总结过程中发生错误:', error);
                this.updateStatus('生成总结失败: ' + error.message, 'error');
                this.showNotification('生成总结失败: ' + error.message, 'error');
            } finally {
                this.summaryButton.disabled = false;
            }
        }

        // 更新标题以显示当前AI模型
        updateTitleWithModel() {
            const currentModel = CONFIG.AI_MODELS[CONFIG.AI_MODELS.TYPE];
            const modelName = currentModel ? currentModel.MODEL : 'AI模型';
            if (this.titleElement) {
                this.titleElement.textContent = `🎬 AI 船仓助手 - ${modelName}`;
            }
        }

        // 安全的markdown格式化内容创建方法
        createFormattedContent(container, text) {
            const lines = text.split('\n');
            let currentList = null;
            let listType = null;

            for (let i = 0; i < lines.length; i++) {
                const line = lines[i].trim();

                if (!line) {
                    // 空行,结束当前列表
                    if (currentList) {
                        container.appendChild(currentList);
                        currentList = null;
                        listType = null;
                    }
                    continue;
                }

                // 处理标题
                if (line.startsWith('### ')) {
                    if (currentList) {
                        container.appendChild(currentList);
                        currentList = null;
                        listType = null;
                    }
                    const h3 = document.createElement('h3');
                    h3.textContent = line.substring(4);
                    h3.style.cssText = `
                        color: #AB47BC;
                        margin: 24px 0 12px 0;
                        font-size: 18px;
                        font-weight: 600;
                        border-bottom: 2px solid rgba(171, 71, 188, 0.3);
                        padding-bottom: 8px;
                        letter-spacing: 0.5px;
                    `;
                    container.appendChild(h3);
                    continue;
                }

                if (line.startsWith('## ')) {
                    if (currentList) {
                        container.appendChild(currentList);
                        currentList = null;
                        listType = null;
                    }
                    const h2 = document.createElement('h2');
                    h2.textContent = line.substring(3);
                    h2.style.cssText = `
                        color: #9C27B0;
                        margin: 28px 0 14px 0;
                        font-size: 20px;
                        font-weight: 600;
                        border-bottom: 3px solid rgba(156, 39, 176, 0.4);
                        padding-bottom: 10px;
                        letter-spacing: 0.5px;
                    `;
                    container.appendChild(h2);
                    continue;
                }

                if (line.startsWith('# ')) {
                    if (currentList) {
                        container.appendChild(currentList);
                        currentList = null;
                        listType = null;
                    }
                    const h1 = document.createElement('h1');
                    h1.textContent = line.substring(2);
                    h1.style.cssText = `
                        color: #8E24AA;
                        margin: 32px 0 16px 0;
                        font-size: 24px;
                        font-weight: 700;
                        border-bottom: 4px solid rgba(142, 36, 170, 0.5);
                        padding-bottom: 12px;
                        letter-spacing: 0.8px;
                        text-align: center;
                    `;
                    container.appendChild(h1);
                    continue;
                }

                // 处理无序列表
                if (line.startsWith('- ')) {
                    if (!currentList || listType !== 'ul') {
                        if (currentList) container.appendChild(currentList);
                        currentList = document.createElement('ul');
                        currentList.style.cssText = `
                            margin: 16px 0;
                            padding-left: 24px;
                            color: #f0f0f0;
                            background: rgba(255,255,255,0.02);
                            border-radius: 8px;
                            padding: 12px 24px;
                        `;
                        listType = 'ul';
                    }
                    const li = document.createElement('li');
                    li.style.cssText = `
                        margin: 8px 0;
                        color: #f0f0f0;
                        line-height: 1.7;
                        position: relative;
                        padding-left: 8px;
                    `;
                    this.parseInlineFormatting(li, line.substring(2));
                    currentList.appendChild(li);
                    continue;
                }

                // 处理有序列表
                const orderedMatch = line.match(/^\d+\. (.+)$/);
                if (orderedMatch) {
                    if (!currentList || listType !== 'ol') {
                        if (currentList) container.appendChild(currentList);
                        currentList = document.createElement('ol');
                        currentList.style.cssText = `
                            margin: 16px 0;
                            padding-left: 24px;
                            color: #f0f0f0;
                            background: rgba(255,255,255,0.02);
                            border-radius: 8px;
                            padding: 12px 24px;
                        `;
                        listType = 'ol';
                    }
                    const li = document.createElement('li');
                    li.style.cssText = `
                        margin: 8px 0;
                        color: #f0f0f0;
                        line-height: 1.7;
                        position: relative;
                        padding-left: 8px;
                    `;
                    this.parseInlineFormatting(li, orderedMatch[1]);
                    currentList.appendChild(li);
                    continue;
                }

                // 普通段落
                if (currentList) {
                    container.appendChild(currentList);
                    currentList = null;
                    listType = null;
                }

                const p = document.createElement('p');
                p.style.cssText = `
                    margin: 16px 0;
                    color: #f0f0f0;
                    line-height: 1.8;
                    text-align: justify;
                    text-justify: inter-ideograph;
                    font-size: 16px;
                    letter-spacing: 0.3px;
                `;
                this.parseInlineFormatting(p, line);
                container.appendChild(p);
            }

            // 添加最后的列表
            if (currentList) {
                container.appendChild(currentList);
            }
        }

        // 解析行内格式(粗体、斜体、代码等)
        parseInlineFormatting(element, text) {
            let remaining = text;

            // 处理代码块
            remaining = remaining.replace(/```([\s\S]*?)```/g, (match, code) => {
                const pre = document.createElement('pre');
                pre.style.cssText = 'background: rgba(0,0,0,0.3); padding: 12px; border-radius: 4px; margin: 12px 0; overflow-x: auto;';
                const codeEl = document.createElement('code');
                codeEl.style.cssText = 'color: #f8f8f2;';
                codeEl.textContent = code.trim();
                pre.appendChild(codeEl);
                element.appendChild(pre);
                return ''; // 移除已处理的部分
            });

            // 简单处理剩余文本(粗体、斜体、行内代码)
            const parts = remaining.split(/(\*\*.*?\*\*|\*.*?\*|`.*?`)/);

            parts.forEach(part => {
                if (!part) return;

                if (part.startsWith('**') && part.endsWith('**')) {
                    // 粗体
                    const strong = document.createElement('strong');
                    strong.style.cssText = `
                        color: #ffffff;
                        font-weight: 600;
                        text-shadow: 0 0 2px rgba(255,255,255,0.3);
                    `;
                    strong.textContent = part.slice(2, -2);
                    element.appendChild(strong);
                } else if (part.startsWith('*') && part.endsWith('*') && !part.startsWith('**')) {
                    // 斜体
                    const em = document.createElement('em');
                    em.style.cssText = `
                        color: #E1BEE7;
                        font-style: italic;
                    `;
                    em.textContent = part.slice(1, -1);
                    element.appendChild(em);
                } else if (part.startsWith('`') && part.endsWith('`')) {
                    // 行内代码
                    const code = document.createElement('code');
                    code.style.cssText = `
                        background: rgba(0,0,0,0.3);
                        color: #f8f8f2;
                        padding: 2px 6px;
                        border-radius: 4px;
                        font-family: 'Courier New', monospace;
                        font-size: 0.9em;
                    `;
                    code.textContent = part.slice(1, -1);
                    element.appendChild(code);
                } else {
                    // 普通文本
                    const textNode = document.createTextNode(part);
                    element.appendChild(textNode);
                }
            });
        }

        makeDraggable(element) {
            let isDragging = false;
            let currentX;
            let currentY;
            let initialX;
            let initialY;
            let xOffset = 0;
            let yOffset = 0;

            element.addEventListener('mousedown', (e) => {
                // 如果点击的是按钮,不启动拖拽
                if (e.target.tagName === 'BUTTON' || e.target.closest('button')) {
                    console.log('点击的是按钮,不启动拖拽');
                    return;
                }

                initialX = e.clientX - xOffset;
                initialY = e.clientY - yOffset;

                if (e.target === element) {
                    isDragging = true;
                    console.log('开始拖拽');
                }
            });

            document.addEventListener('mousemove', (e) => {
                if (isDragging) {
                    e.preventDefault();
                    currentX = e.clientX - initialX;
                    currentY = e.clientY - initialY;

                    xOffset = currentX;
                    yOffset = currentY;

                    // 限制拖动范围
                    const maxX = window.innerWidth - this.container.offsetWidth;
                    const maxY = window.innerHeight - this.container.offsetHeight;

                    xOffset = Math.min(Math.max(0, xOffset), maxX);
                    yOffset = Math.min(Math.max(0, yOffset), maxY);

                    this.container.style.transform = `translate(${xOffset}px, ${yOffset}px)`;
                }
            });

            document.addEventListener('mouseup', () => {
                if (isDragging) {
                    console.log('结束拖拽');
                }
                initialX = currentX;
                initialY = currentY;
                isDragging = false;
            });
        }

        // 添加移动端支持
        addMobileSupport() {
            // 检测移动设备
            const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);

            if (isMobile) {
                // 移动端适配
                this.container.style.cssText = this.container.style.cssText.replace(
                    'width: 400px;',
                    'width: 95vw;'
                ).replace(
                    'top: 20px; right: 20px;',
                    'top: 10px; right: 2.5vw;'
                );

                // 调整字体大小
                this.container.style.fontSize = '14px';
            }

            // 窗口大小变化时的响应式处理
            window.addEventListener('resize', () => {
                const width = window.innerWidth;
                if (width < 768) {
                    // 小屏幕
                    this.container.style.width = '95vw';
                    this.container.style.right = '2.5vw';
                    this.container.style.left = 'auto';
                } else if (width < 1024) {
                    // 中等屏幕
                    this.container.style.width = '380px';
                    this.container.style.right = '20px';
                } else {
                    // 大屏幕
                    this.container.style.width = '400px';
                    this.container.style.right = '20px';
                }
            });
        }

        attachEventListeners() {
            // URL变化监听(检测视频切换)
            let lastUrl = location.href;
            const observer = new MutationObserver(() => {
                const url = location.href;
                if (url !== lastUrl) {
                    lastUrl = url;
                    const newVideoId = this.videoController.getVideoId();
                    if (newVideoId && newVideoId !== this.videoController.currentVideoId) {
                        this.videoController.currentVideoId = newVideoId;
                        this.resetUI();
                    }
                }
            });

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

        resetUI() {
            this.loadSubtitlesButton.style.display = 'block';
            this.summaryButton.style.display = 'none';
            this.summaryPanel.style.display = 'none';
            this.statusDisplay.style.display = 'none';
            this.loadSubtitlesButton.disabled = false;

            // 重置翻译后的标题
            this.videoController.translatedTitle = null;
            this.summaryButton.disabled = false;
        }
    }

    // 初始化应用
    async function initializeApp() {
        try {
            console.log('🎬 YouTube AI 总结助手初始化中...');

            // 等待页面加载
            await waitForPageLoad();

            // 创建视频控制器
            const videoController = new VideoController();

            // 创建UI管理器
            const uiManager = new UIManager(videoController);

            console.log('✅ YouTube AI 总结助手初始化完成');

        } catch (error) {
            console.error('❌ 初始化失败:', error);
        }
    }

    function waitForPageLoad() {
        return new Promise((resolve) => {
            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', resolve);
            } else {
                resolve();
            }
        });
    }

    function getUid() {
        const url = new URL(window.location.href);
        return url.searchParams.get('v') || 'unknown';
    }

    // 检查 Trusted Types 策略
    function checkTrustedTypes() {
        if (window.trustedTypes && window.trustedTypes.defaultPolicy) {
            console.log('检测到 Trusted Types 策略,将使用安全的DOM操作方法');
            return true;
        }
        return false;
    }

    // 启动应用
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            checkTrustedTypes();
            initializeApp();
        });
    } else {
        checkTrustedTypes();
        initializeApp();
    }

    // 添加全局测试函数(用于调试)
    window.testYouTubeAI = {
        openConfig: function() {
            const uiElements = document.querySelectorAll('#youtube-ai-config-panel');
            if (uiElements.length > 0) {
                console.log('发现已存在的配置面板,尝试显示');
                uiElements[0].style.display = 'block';
                uiElements[0].style.zIndex = '999999';
            } else {
                console.log('未找到配置面板元素');
            }
        },
        getUI: function() {
            // 尝试找到UI管理器实例
            const containers = document.querySelectorAll('[style*="linear-gradient"]');
            console.log('找到的容器:', containers.length);
            return containers;
        },
        testConfigButton: function() {
            const buttons = document.querySelectorAll('button');
            const configButton = Array.from(buttons).find(btn => btn.textContent === '⚙️');
            if (configButton) {
                console.log('找到配置按钮,尝试触发点击');
                configButton.click();
            } else {
                console.log('未找到配置按钮');
            }
        }
    };

})();
长期地址
遇到问题?请前往 GitHub 提 Issues。