LunaLens

通过HTTP API连接LunaTranslator实现浏览器上的原文的分词、翻译、朗读和查词功能

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         LunaLens
// @namespace    http://tampermonkey.net/
// @license      MIT
// @version      0.2.7
// @description  通过HTTP API连接LunaTranslator实现浏览器上的原文的分词、翻译、朗读和查词功能
// @description:en Split, translate, read and query words on the browser through the HTTP API of LunaTranslator
// @description:ja LunaTranslatorのHTTP APIを通じてブラウザ上で分詞、翻訳、読み上げ、辞書検索機能を実現
// @author       Raindrop213
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @connect      *
// ==/UserScript==

(function() {
    'use strict';

    // 默认配置
    const DEFAULT_CONFIG = {
        // ※重点:填写你的服务器地址,同步设置@connect如: @connect 192.168.6.229
        API_URL: 'http://127.0.0.1:2333',

        // 分句设置
        // 分句:断句的符号基准
        SENTENCE_DELIMITERS: '。..!?!?…',
        // 分句:句子字数阈值
        SENTENCE_LENGTH: 50, 
        // 最小内容长度
        MIN_CONTENT_LENGTH: 2,
        // 最大内容长度
        MAX_CONTENT_LENGTH: 1000,
        // 是否移除注音

        // 选择器设置
        // 选择的标签
        INCLUDE_TAGS: 'p, h1, h2, h3, h4, h5, h6',
        // 排除的标签
        EXCLUDE_TAGS: '',
        // 包含的class id
        INCLUDE_CLASS_IDS: '',
        // 排除的class id
        EXCLUDE_CLASS_IDS: '',
        // 停止容器
        STOP_CONTAINERS: 'article, main, section, div.content, div.main-content',

        // 顶栏常用设置
        // 是否使用句子模式
        DISPLAY_SENTENCE_MODE: false,
        // 是否打开翻译
        TRANSLATION_ENABLED: false,
        // 是否激活标签就自动朗读
        TTS_AUTO: false,
        // 是否打开设置栏
        SETTING_DISPLAY: false,
        BUTTON_TEXT: {
            TTS: {true: 'TTS:auto', false: 'TTS'},
            TRANSLATION: {true: '翻译:auto', false: '翻译'},
            DISPLAY: {true: '句子', false: '段落'}
        },

        // 其他设置
        // API请求等待的最大时限
        TIMEOUT: 5000
    };
    
    // 当前配置,初始化为默认配置的副本
    const CONFIG = JSON.parse(JSON.stringify(DEFAULT_CONFIG));

    // 面板样式
    const STYLE =  `
        .lunalens-highlighted {
            outline: 2px solid rgba(59, 122, 83, 0.52) !important;
        }
        .lunalens-word {
            display: inline-block;
            position: relative;
            margin: 1px;
            cursor: pointer;
        }
        .lunalens-word.flash {
            animation: word-flash 0.3s ease-out;
        }
        @keyframes word-flash {
            0% { background-color: rgba(255, 206, 30, 0.5); }
            100% { background-color: transparent; }
        }
        /* 仅在词典窗内使用的高亮样式 */
        .lunalens-dict-context .lunalens-word.active-word {
            background-color:rgba(255, 206, 30, 0.5);
        }
        .lunalens-word rt {
            font-size: 0.7em;
            color: #b91a1a;
        }
        /* LunaLens面板 */
        .lunalens-panel {
            position: fixed;
            bottom: 0;
            left: 0;
            right: 0;
            height: 92%;
            background-color: #fff;
            border-top: 1px solid #ccc;
            box-shadow: 0 -2px 10px rgba(0,0,0,0.1);
            z-index: 9999;
            display: flex;
            flex-direction: column;
            font-family: sans-serif;
            transition: transform 0.2s ease;
            transform: translateY(100%);
            writing-mode: horizontal-tb !important;
            -webkit-writing-mode: horizontal-tb !important;
        }
        .lunalens-panel.visible {
            transform: translateY(0);
        }
        .lunalens-panel input::placeholder {
            color: #aaa;
            opacity: 0.8;
        }
        .lunalens-header {
            display: flex;
            justify-content: space-between;
            background: #ffffff;
            border-bottom: 1px solid #ddd;
            height: 40px;
        }
        .lunalens-title {
            font-size: 16px;
            font-weight: bold;
            padding: 8px 10px;
            margin: 0;
            line-height: 20px;
            cursor: pointer;
            transition: color 0.2s ease;
        }
        .lunalens-title:hover {
            color: #007acc;
        }
        .lunalens-header-buttons {
            display: flex;
            align-items: stretch;
            height: 100%;
        }
        .lunalens-header-button {
            cursor: pointer;
            color: #666;
            font-size: 14px;
            padding: 0 12px;
            margin: 0;
            border: none;
            border-radius: 0;
            border-left: 1px solid #ddd;
            transition: all 0.2s ease;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .lunalens-square-button {
            width: 40px;
            color: white;
            border: none;
            border-radius: 0;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 20px;
            margin: 0;
        }
        .lunalens-setting-toggle {
            background-color: #929292;
        }
        .lunalens-setting-toggle.active {
            background-color: #1288ab;
        }
        .lunalens-close {
            background-color: #000000;
        }
        .lunalens-dict-context-wrapper {
            position: relative;
            background: #f9f9f9;
            border-bottom: 1px solid #eee;
            max-height: 20vh;
            overflow: hidden;
        }
        .lunalens-context-buttons {
            position: absolute;
            bottom: 4px;
            right: 4px;
            display: flex;
            gap: 4px;
            z-index: 10;
        }
        .lunalens-dict-context {
            padding: 8px 10px 30px 10px;
            font-size: 15px;
            line-height: 1.5;
            overflow-y: auto;
            height: 100%;
            box-sizing: border-box;
        }
        .lunalens-dict-query-box {
            display: flex;
            padding: 0;
            border-bottom: 1px solid #eee;
            height: 40px;
        }
        .lunalens-dict-query-input {
            flex: 1;
            padding: 0 10px;
            border: 1px solid transparent;
            border-right: 1px solid #ddd;
            border-radius: 0;
            margin: 0;
            height: 100%;
            outline: none;
            box-sizing: border-box;
        }
        .lunalens-dict-query-input:focus {
            border: 1px solid #000000;
        }
        .lunalens-dict-query-button {
            background: #23ab12;
        }
        .lunalens-tts-button {
            background: #a51dd1;
        }
        .lunalens-context-copy-button {
            width: 32px;
            height: 32px;
            color: #4a90e2;
            background: rgba(74, 144, 226, 0.1);
            border: 1px solid rgba(74, 144, 226, 0.3);
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 16px;
            transition: all 0.2s ease;
        }
        .lunalens-context-translate-button {
            width: 32px;
            height: 32px;
            color: #50c878;
            background: rgba(80, 200, 120, 0.1);
            border: 1px solid rgba(80, 200, 120, 0.3);
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            font-weight: bold;
            transition: all 0.2s ease;
        }
        .lunalens-context-tts-button {
            width: 32px;
            height: 32px;
            color: #a51dd1;
            background:rgba(165, 29, 209, 0.1);
            border: 1px solid rgba(165, 29, 209, 0.3);
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 18px;
            transition: all 0.2s ease;
        }
        .lunalens-dict-content {
            flex: 1;
            display: flex;
            flex-direction: column;
            overflow: hidden;
        }
        .lunalens-dict-tabs {
            display: flex;
            flex-direction: row;
            background: #f9f9f9;
            overflow-x: auto;
            white-space: nowrap;
        }
        .lunalens-dict-tab {
            padding: 8px 15px;
            cursor: pointer;
            border-right: 1px solid #eee;
            font-size: 13px;
        }
        .lunalens-dict-tab.active {
            background: #fff;
            font-weight: bold;
            border-top: 3px solid #b91a1a;
            border-left: none;
        }
        .lunalens-dict-entries {
            flex: 1;
            overflow-y: auto;
            padding-top: 10px;
        }
        .lunalens-dict-entry {
            display: none;
        }
        .lunalens-dict-entry.active {
            display: block;
        }
        .lunalens-dict-loading {
            text-align: center;
            padding: 20px;
            color: #666;
        }
        /* 翻译区域样式 */
        .lunalens-translation {
            padding: 8px 10px;
            border-bottom: 1px solid #e0e6f5;
            font-size: 13px;
            line-height: 1.5;
            max-height: 15vh;
            overflow-y: auto;
        }
        .lunalens-translator-item {
            position: relative;
            padding-right: 40px;
        }
        .lunalens-translator-name {
            position: absolute;
            right: 0;
            top: 0;
            font-size: 10px;
            color: #bbb;
            font-style: italic;
        }
        .lunalens-hr {
            border: none;
            border-top: 1px dashed #c1c1c17d;
            margin: 5px 0;
        }
        /* 设置窗口样式 */
        .lunalens-setting-window {
            display: none;
            flex-direction: column;
            width: 100%;
            height: 100%;
            overflow: hidden;
            padding: 10px;
            box-sizing: border-box;
            overflow-y: auto;
        }
        .lunalens-setting-window.visible {
            display: flex;
        }
        .lunalens-dict-window {
            display: none;
            flex-direction: column;
            width: 100%;
            height: 100%;
            overflow: hidden;
        }
        .lunalens-dict-window.visible {
            display: flex;
        }
        .lunalens-setting-api-url {
            padding: 8px 10px;
            border-bottom: 1px solid #eee;
        }
        .lunalens-setting-api-url label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            font-size: 13px;
            color: #333;
        }
        .lunalens-setting-api-url input {
            width: 100%;
            padding: 6px 10px;
            border: 1px solid #ddd;
            border-radius: 0;
            font-size: 14px;
            outline: none;
            box-sizing: border-box;
        }
        .lunalens-setting-api-url input:focus {
            border: 1px solid #000000;
        }
        .lunalens-setting-tabs {
            display: flex;
            flex-direction: row;
            background: #f9f9f9;
            overflow-x: auto;
            white-space: nowrap;
        }
        .lunalens-setting-tab {
            padding: 8px 15px;
            cursor: pointer;
            border-right: 1px solid #eee;
            font-size: 13px;
        }
        .lunalens-setting-tab.active {
            background: #fff;
            font-weight: bold;
            border-top: 3px solid #b91a1a;
            border-bottom: none;
            border-left: none;
        }
        .lunalens-setting-contents {
            flex: 1;
            overflow-y: auto;
        }
        .lunalens-setting-content {
            display: none;
            padding: 10px;
            border-top: none;
        }
        .lunalens-setting-content.active {
            display: block;
        }
        .lunalens-setting-item {
            margin-bottom: 12px;
            padding-bottom: 8px;
        }
        .lunalens-setting-item:last-child {
            border-bottom: none;
        }
        .lunalens-setting-item label {
            display: block;
            margin-bottom: 5px;
            font-weight: bold;
            font-size: 13px;
        }
        .lunalens-setting-item input[type="text"] {
            width: 100%;
            padding: 6px 10px;
            border: 1px solid #ddd;
            border-radius: 0;
            outline: none;
            box-sizing: border-box;
        }
        .lunalens-setting-item input[type="text"]:focus {
            border: 1px solid #000000;
        }
        .lunalens-setting-item input[type="checkbox"] {
            margin-right: 8px;
            vertical-align: middle;
        }
        .lunalens-setting-description {
            font-size: 12px;
            color: #666;
            margin-top: 5px;
        }
        .lunalens-setting-description kbd {
            background-color:rgba(223, 223, 223, 0.5);
            padding: 0px 3px;
            border-radius: 3px;
        }
        .lunalens-setting-button {
            background-color: #23ab12;
            color: white;
            border: none;
            padding: 8px 16px;
            cursor: pointer;
            border-radius: 0;
            margin-top: 10px;
            font-size: 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            align-self: flex-start;
            margin-right: 10px;
        }
        .lunalens-reset-settings {
            background-color: #cc3333;
        }
        .lunalens-setting-buttons {
            display: flex;
            flex-direction: row;
        }
        .lunalens-toast {
            position: fixed;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            background-color: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 10px 15px;
            border-radius: 4px;
            z-index: 10001;
            display: none;
            animation: fadeInOut 2s ease-in-out;
            box-shadow: 0 2px 8px rgba(0,0,0,0.2);
            font-size: 14px;
            max-width: 80%;
            text-align: center;
            writing-mode: horizontal-tb;
        }
        @keyframes fadeInOut {
            0% { opacity: 0; transform: translate(-50%, -10px); }
            10% { opacity: 1; transform: translate(-50%, 0); }
            90% { opacity: 1; transform: translate(-50%, 0); }
            100% { opacity: 0; transform: translate(-50%, -10px); }
        }
    `

    // 全局变量
    let activeElement = null;
    let originalContent = null;
    let dictionaryPanel = null;
    let currentWord = '';
    let activeWordElements = []; // 改为数组存储所有激活的单词元素
    let contextSentence = null;
    let translationArea = null; // 翻译区域
    let lastTranslatedText = ''; // 上次翻译的文本,用于避免重复翻译
    let currentAudio = null; // 当前播放的音频对象
    let pendingTTSRequests = []; // 待处理的TTS请求数组

    // 添加样式到文档
    function addStyle(doc) {
        if (!doc.querySelector('#anon-simple-style')) {
            const style = doc.createElement('style');
            style.id = 'anon-simple-style';
            style.textContent = STYLE;
            doc.head.appendChild(style);
        }
    }

    // 复制文本到剪贴板
    function copyToClipboard(text) {
        navigator.clipboard.writeText(text)
            .then(() => console.log(`Copy: ${text}`))
            .catch(err => console.log('Failed to copy text: ', err));
    }

    // 获取纯文本(移除rp、rt)
    function getPlainText(html) {
        const div = document.createElement('div');
        div.innerHTML = html;
        
        // 先找出所有ruby元素
        div.querySelectorAll('ruby').forEach(ruby => {
            // 创建文本节点,只包含主要内容(不包含rt中的注音)
            const mainText = Array.from(ruby.childNodes)
                .filter(node => node.nodeName !== 'RT' && node.nodeName !== 'RP')
                .map(node => node.textContent)
                .join('');
                
            // 替换整个ruby标签为纯文本
            const textNode = document.createTextNode(mainText);
            ruby.parentNode.replaceChild(textNode, ruby);
        });
        
        return div.textContent || '';
    }

    // 辅助函数:判断片假名和平假名是否等价
    function isKanaEquivalent(word, kana) {
        if (!word || !kana) return false;
        // 简单转换为片假名进行比较
        const toKatakana = str => {
            const hiraRange = [0x3041, 0x3096];
            return str.split('')
                .map(char => {
                    const code = char.charCodeAt(0);
                    if (code >= hiraRange[0] && code <= hiraRange[1]) {
                        return String.fromCharCode(code + 0x60);
                    }
                    return char;
                })
                .join('');
        };
        return toKatakana(word) === toKatakana(kana);
    }
    
    // 片假名转平假名
    function katakanaToHiragana(text) {
        if (!text) return '';
        
        // 片假名的Unicode范围是:U+30A0 to U+30FF
        return text.replace(/[\u30A0-\u30FF]/g, function(match) {
            const code = match.charCodeAt(0) - 0x60;
            return String.fromCharCode(code);
        });
    }

    // 处理分词API请求
    function processMecabAPI(text, callback) {
        GM_xmlhttpRequest({
            method: 'GET',
            url: `${CONFIG.API_URL}/api/mecab?text=${encodeURIComponent(text)}`,
            onload: function(response) {
                if (response.status === 200) {
                    try {
                        const data = JSON.parse(response.responseText);
                        callback(data);
                    } catch (e) {
                        console.error('解析API响应失败:', e);
                        showToast('分词API请求失败,请检查API连接', true);
                        callback(null);
                    }
                } else {
                    console.error('API请求失败:', response.status);
                    showToast('API请求失败,HTTP状态码: ' + response.status, true);
                    callback(null);
                }
            },
            onerror: function(error) {
                console.error('API请求错误:', error);
                showToast('分词API请求失败,请检查API连接', true);
                callback(null);
            },
            ontimeout: function() {
                console.error('API请求超时');
                showToast('分词API请求超时', true);
                callback(null);
            },
            timeout: CONFIG.TIMEOUT
        });
    }

    // 显示设置面板的辅助函数
    function showSettingsPanel() {
        // 先显示词典面板
        showPanel();
        
        // 然后切换到设置页面
        if (dictionaryPanel) {
            dictionaryPanel.querySelector('.lunalens-dict-window').classList.remove('visible');
            dictionaryPanel.querySelector('.lunalens-setting-window').classList.add('visible');
            dictionaryPanel.querySelector('.lunalens-setting-toggle').classList.add('active');
        }
    }

    // 生成带注音的HTML标记,添加唯一索引
    function generateRubyHTML(word, index) {
        const indexAttr = `data-original-index="${index}"`;
        
        if (word.isdeli || !word.kana || isKanaEquivalent(word.word, word.kana)) {
            return `<span class="lunalens-word" data-word="${word.word}" ${indexAttr}>${word.word}</span>`;
        } else {
            // 将片假名转换为平假名
            const hiragana = katakanaToHiragana(word.kana);
            return `<span class="lunalens-word" data-word="${word.word}" ${indexAttr}><ruby>${word.word}<rt>${hiragana}</rt></ruby></span>`;
        }
    }

    // 处理文本并生成带注音的分句HTML
    function processTextWithTokenization(html, callback) {
        // 1. 获取纯文本
        const plainText = getPlainText(html);
        
        // 2. 一次性请求API进行分词
        processMecabAPI(plainText, function(words) {
            if (!words) {
                callback(html); // 如果API失败,返回原HTML
                showSettingsPanel();
                return;
            }
            
            // 3. 按句子分隔符构建句子数组
            const sentences = [];
            let currentSentence = [];
            let currentSentenceLength = 0;
            let wordIndex = 0;
            
            // 遍历所有词汇,构建句子
            words.forEach(word => {
                // 生成当前词的HTML,添加唯一索引
                const wordHTML = generateRubyHTML(word, wordIndex++);
                currentSentence.push(wordHTML);
                currentSentenceLength += word.word.length;
                
                // 如果当前词是句子分隔符,检查是否应结束当前句子
                if (CONFIG.SENTENCE_DELIMITERS.indexOf(word.word) !== -1 && currentSentenceLength >= CONFIG.SENTENCE_LENGTH) {
                    sentences.push(`<span class="lunalens-sentence">${currentSentence.join('')}</span>`);
                    currentSentence = [];
                    currentSentenceLength = 0;
                }
            });
            
            // 处理剩余的词
            if (currentSentence.length > 0) {
                sentences.push(`<span class="lunalens-sentence">${currentSentence.join('')}</span>`);
            }
            
            callback(sentences.join(''));
        });
    }

    // 查询按钮点击事件(添加下一个单词)
    function setupQueryButton(queryButton, queryInput) {
        queryButton.addEventListener('click', function() {
            if (activeWordElements.length > 0) {
                // 获取最后一个激活的单词元素的索引
                const lastActiveIndex = activeWordElements[activeWordElements.length - 1];
                let lastActiveElement;
                
                // 在主页和词典上下文中查找元素
                const allWords = document.querySelectorAll('.lunalens-word');
                for (const word of allWords) {
                    if (word.dataset.originalIndex === lastActiveIndex || 
                        (typeof lastActiveIndex === 'object' && 
                         lastActiveIndex.dataset && 
                         lastActiveIndex.dataset.originalIndex === word.dataset.originalIndex)) {
                        lastActiveElement = word;
                        // 一旦在主页上找到匹配的元素,优先使用
                        if (activeElement.contains(word)) {
                            break;
                        }
                    }
                }
                
                if (!lastActiveElement) return;
                
                // 寻找下一个单词元素
                let nextWord = null;
                if (activeElement.contains(lastActiveElement)) {
                    // 如果最后激活的单词在主页上,直接找下一个相邻元素
                    nextWord = lastActiveElement.nextElementSibling;
                    while (nextWord && !nextWord.classList.contains('lunalens-word')) {
                        nextWord = nextWord.nextElementSibling;
                    }
                } else {
                    // 如果最后激活的单词在词典上下文中,需要找到主页上对应的单词,再找下一个
                    const mainPageWords = activeElement.querySelectorAll('.lunalens-word');
                    for (let i = 0; i < mainPageWords.length; i++) {
                        if (mainPageWords[i].dataset.originalIndex === lastActiveIndex) {
                            if (i < mainPageWords.length - 1) {
                                nextWord = mainPageWords[i + 1];
                            }
                            break;
                        }
                    }
                }
                
                if (nextWord && nextWord.classList.contains('lunalens-word')) {
                    
                    // 记录下一个单词,保留之前的记录
                    activeWordElements.push(nextWord.dataset.originalIndex || nextWord);
                    
                    // 获取当前查询框内容
                    const currentQuery = queryInput.value.trim();
                    
                    // 将下一个单词添加到查询框
                    queryInput.value = currentQuery + nextWord.dataset.word;
                    
                    // 更新上下文
                    updateContext();
                    
                    // 触发查询
                    lookupWord(queryInput.value);
                }
            }
        });
    }
    
    // 上下文区域点击事件处理
    function setupContextAreaEvents(contextArea, queryInput) {
        // 使用事件委托,避免在每次更新上下文时都要重新绑定事件
        contextArea.addEventListener('click', function(e) {
            // 阻止事件冒泡到document,防止触发deactivateElement
            e.stopPropagation();
            
            // 寻找被点击的单词元素,包括临时容器中的元素
            let targetWord = null;
            if (e.target.classList && e.target.classList.contains('lunalens-word')) {
                targetWord = e.target;
            } else {
                targetWord = e.target.closest('.lunalens-word');
            }
            
            if (targetWord) {
                // 清除所有已激活的高亮样式
                contextArea.querySelectorAll('.lunalens-word.active-word').forEach(word => {
                    word.classList.remove('active-word');
                });
                
                // 清空激活单词数组
                activeWordElements = [];
                
                // 直接给当前单词添加高亮类
                targetWord.classList.add('active-word');
                
                // 记录当前激活的单词
                activeWordElements.push(targetWord.dataset.originalIndex || targetWord);
                
                // 更新查询框内容
                queryInput.value = targetWord.dataset.word;
                
                // 触发查询
                lookupWord(targetWord.dataset.word);
                
                // 找到主页上对应的单词并添加临时闪烁效果
                const originalIndex = targetWord.dataset.originalIndex;
                if (originalIndex && activeElement) {
                    const mainPageWord = activeElement.querySelector(`.lunalens-word[data-original-index="${originalIndex}"]`);
                    if (mainPageWord) {
                        mainPageWord.classList.add('flash');
                        setTimeout(() => {
                            mainPageWord.classList.remove('flash');
                        }, 1000);
                    }
                }
            }
        });
    }

    // 创建词典面板
    function createDictionaryPanel() {
        // 检查是否已存在
        if (document.querySelector('.lunalens-panel')) {
            return document.querySelector('.lunalens-panel');
        }

        // 创建面板
        const panel = document.createElement('div');
        panel.className = 'lunalens-panel';
        panel.innerHTML = `
            <div class="lunalens-header">
                <div class="lunalens-title">LunaLens</div>
                <div class="lunalens-header-buttons">
                    <span class="lunalens-header-button lunalens-auto-tts-toggle" title="自动朗读开关">
                        ${CONFIG.BUTTON_TEXT.TTS[CONFIG.TTS_AUTO]}
                    </span>
                    <span class="lunalens-header-button lunalens-translation-toggle" title="切换翻译功能">
                        ${CONFIG.BUTTON_TEXT.TRANSLATION[CONFIG.TRANSLATION_ENABLED]}
                    </span>
                    <span class="lunalens-header-button lunalens-context-toggle" title="切换句子/段落">
                        ${CONFIG.BUTTON_TEXT.DISPLAY[CONFIG.DISPLAY_SENTENCE_MODE]}
                    </span>
                    <button class="lunalens-square-button lunalens-setting-toggle" title="设置">⚙</button>
                    <button class="lunalens-square-button lunalens-close" title="关闭面板">×</button>
                </div>
            </div>
            <div class="lunalens-dict-window">
                <div class="lunalens-dict-context-wrapper">
                    <div class="lunalens-dict-context"></div>
                    <div class="lunalens-context-buttons">
                        <button class="lunalens-context-copy-button" title="复制内容">⧉</button>
                        <button class="lunalens-context-translate-button" title="翻译内容">翻</button>
                        <button class="lunalens-context-tts-button" title="朗读上下文">♬</button>
                    </div>
                </div>
                <div class="lunalens-translation"></div>
                <div class="lunalens-dict-query-box">
                    <input type="text" class="lunalens-dict-query-input" placeholder="输入要查询的单词">
                    <button class="lunalens-square-button lunalens-dict-query-button">+</button>
                    <button class="lunalens-square-button lunalens-tts-button" title="朗读单词">♬</button>
                </div>
                <div class="lunalens-dict-content">
                    <div class="lunalens-dict-tabs"></div>
                    <div class="lunalens-dict-entries">
                        <div class="lunalens-dict-loading">请点击任意单词或输入要查询的词</div>
                    </div>
                </div>
            </div>
            <div class="lunalens-setting-window">
                <div class="lunalens-setting-api-url">
                    <label for="lunalens-api-url">API URL:</label>
                    <input type="text" id="lunalens-api-url" value="${CONFIG.API_URL}" placeholder="例如:http://127.0.0.1:2333">
                    <div class="lunalens-setting-description">通常为LunaTranslator的网络服务地址</div>
                </div>
                <div class="lunalens-setting-tabs">
                    <div class="lunalens-setting-tab active" data-tab="sentence-settings">分句设置</div>
                    <div class="lunalens-setting-tab" data-tab="selector-settings">选择器设置</div>
                    <div class="lunalens-setting-tab" data-tab="other-settings">其他设置</div>
                </div>
                <div class="lunalens-setting-contents">
                    <div class="lunalens-setting-content active" id="sentence-settings">
                        <div class="lunalens-setting-item">
                            <label for="sentence-delimiters">分句断句符号</label>
                            <input type="text" id="sentence-delimiters" value="${CONFIG.SENTENCE_DELIMITERS}" placeholder="切分为多个句子单元的符合">
                        </div>
                        <div class="lunalens-setting-item">
                            <label for="sentence-length">句子字数阈值</label>
                            <input type="text" id="sentence-length" value="${CONFIG.SENTENCE_LENGTH}" placeholder="防止句子过短而设置的最小句子长度">
                        </div>
                        <div class="lunalens-setting-item">
                            <label for="min-content-length">最小内容长度</label>
                            <input type="text" id="min-content-length" value="${CONFIG.MIN_CONTENT_LENGTH}" placeholder="过短的文本不会被选中">
                        </div>
                        <div class="lunalens-setting-item">
                            <label for="max-content-length">最大内容长度</label>
                            <input type="text" id="max-content-length" value="${CONFIG.MAX_CONTENT_LENGTH}" placeholder="过长的文本不会被选中">
                        </div>
                        <div class="lunalens-setting-description">※注意:默认去除原句的振假名注音(ruby 中的 rt 和 rp)</div>
                    </div>
                    <div class="lunalens-setting-content" id="selector-settings">
                        <div class="lunalens-setting-item">
                            <label for="include-tags">包含的标签</label>
                            <input type="text" id="include-tags" value="${CONFIG.INCLUDE_TAGS}" placeholder="例如:p, h1, h2, h3, h4, h5, h6, div">
                        </div>
                        <div class="lunalens-setting-item">
                            <label for="exclude-tags">排除的标签</label>
                            <input type="text" id="exclude-tags" value="${CONFIG.EXCLUDE_TAGS}" placeholder="例如: a, img, em, dd, code, button">
                        </div>
                        <div class="lunalens-setting-item">
                            <label for="include-class-ids">包含的class/id</label>
                            <input type="text" id="include-class-ids" value="${CONFIG.INCLUDE_CLASS_IDS}" placeholder="例如:.article-content, #main-content">
                        </div>
                        <div class="lunalens-setting-item">
                            <label for="exclude-class-ids">排除的class/id</label>
                            <input type="text" id="exclude-class-ids" value="${CONFIG.EXCLUDE_CLASS_IDS}" placeholder="例如:.sidebar, #ads, .popup, #comments">
                        </div>
                        <div class="lunalens-setting-item">
                            <label for="stop-containers">停止容器</label>
                            <input type="text" id="stop-containers" value="${CONFIG.STOP_CONTAINERS}" placeholder="例如:article, main, section, div.content, div.main-content">
                        </div>
                        <div class="lunalens-setting-description">※注意class和id的写法:<br><kbd>class</kbd> 前加 <kbd>.</kbd><br><kbd>id</kbd> 前加 <kbd>#</kbd><br>用逗号分隔</div>
                        <div class="lunalens-setting-description">如果你看不懂又选不中文本的时候,请试试在第一栏加多个加上 <kbd>div</kbd> 提高选中率</div>
                    </div>
                    <div class="lunalens-setting-content" id="other-settings">
                        <div class="lunalens-setting-item">
                            <label for="timeout">API请求超时(ms)</label>
                            <input type="text" id="timeout" value="${CONFIG.TIMEOUT}">
                        </div>
                    </div>
                </div>
                <div class="lunalens-setting-buttons">
                    <button class="lunalens-setting-button lunalens-save-settings">保存设置</button>
                    <button class="lunalens-setting-button lunalens-reset-settings">重置设置</button>
                </div>
            </div>
        `;
        document.body.appendChild(panel);

        // 保存翻译区域引用
        translationArea = panel.querySelector('.lunalens-translation');

        // 添加事件处理
        const titleElement = panel.querySelector('.lunalens-title');
        const closeButton = panel.querySelector('.lunalens-close');
        const contextToggle = panel.querySelector('.lunalens-context-toggle');
        const translationToggle = panel.querySelector('.lunalens-translation-toggle');
        const ttsToggle = panel.querySelector('.lunalens-auto-tts-toggle');
        const settingToggle = panel.querySelector('.lunalens-setting-toggle');
        const queryInput = panel.querySelector('.lunalens-dict-query-input');
        const queryButton = panel.querySelector('.lunalens-dict-query-button');
        const contextArea = panel.querySelector('.lunalens-dict-context');
        const ttsButton = panel.querySelector('.lunalens-tts-button');
        const contextTtsButton = panel.querySelector('.lunalens-context-tts-button');
        const contextCopyButton = panel.querySelector('.lunalens-context-copy-button');
        const contextTranslateButton = panel.querySelector('.lunalens-context-translate-button');
        const settingTabs = panel.querySelectorAll('.lunalens-setting-tab');
        const saveButton = panel.querySelector('.lunalens-save-settings');
        const dictWindow = panel.querySelector('.lunalens-dict-window');
        const settingWindow = panel.querySelector('.lunalens-setting-window');
        
        // 切换到设置面板
        settingToggle.addEventListener('click', function() {
            const isSettingVisible = this.classList.contains('active');
            this.classList.toggle('active');
            
            if (isSettingVisible) {
                // 从设置切换到词典
                dictWindow.classList.add('visible');
                settingWindow.classList.remove('visible');
            } else {
                // 从词典切换到设置
                dictWindow.classList.remove('visible');
                settingWindow.classList.add('visible');
                // 加载保存的设置
                loadSettings();
            }
        });
        
        // 设置面板中的标签切换
        settingTabs.forEach(tab => {
            tab.addEventListener('click', function() {
                // 移除所有标签的活动状态
                settingTabs.forEach(t => t.classList.remove('active'));
                // 添加当前标签的活动状态
                this.classList.add('active');
                
                // 隐藏所有内容
                panel.querySelectorAll('.lunalens-setting-content').forEach(content => {
                    content.classList.remove('active');
                });
                
                // 显示当前标签对应的内容
                const tabId = this.getAttribute('data-tab');
                const tabContent = panel.querySelector(`#${tabId}`);
                if (tabContent) {
                    tabContent.classList.add('active');
                }
            });
        });
        
        // 保存设置
        saveButton.addEventListener('click', function() {
            // 收集所有设置输入
            const apiUrl = panel.querySelector('#lunalens-api-url').value.trim();
            const sentenceDelimiters = panel.querySelector('#sentence-delimiters').value;
            const sentenceLength = parseInt(panel.querySelector('#sentence-length').value) || 50;
            const minContentLength = parseInt(panel.querySelector('#min-content-length').value) || 2;
            const maxContentLength = parseInt(panel.querySelector('#max-content-length').value) || 1000;
            const includeSelectors = panel.querySelector('#include-tags').value;
            const excludeSelectors = panel.querySelector('#exclude-tags').value;
            const includeClassIds = panel.querySelector('#include-class-ids').value;
            const excludeClassIds = panel.querySelector('#exclude-class-ids').value;
            const stopContainers = panel.querySelector('#stop-containers').value;
            const timeout = parseInt(panel.querySelector('#timeout').value) || 5000;
            
            // 更新配置
            CONFIG.API_URL = apiUrl;
            CONFIG.SENTENCE_DELIMITERS = sentenceDelimiters;
            CONFIG.SENTENCE_LENGTH = sentenceLength;
            CONFIG.MIN_CONTENT_LENGTH = minContentLength;
            CONFIG.MAX_CONTENT_LENGTH = maxContentLength;
            CONFIG.INCLUDE_TAGS = includeSelectors;
            CONFIG.EXCLUDE_TAGS = excludeSelectors;
            CONFIG.INCLUDE_CLASS_IDS = includeClassIds;
            CONFIG.EXCLUDE_CLASS_IDS = excludeClassIds;
            CONFIG.STOP_CONTAINERS = stopContainers;
            CONFIG.TIMEOUT = timeout;
            
            // 保存到本地存储
            saveSettings();
            
            // 显示通知
            showToast('设置已保存', false);
        });

        // 标题点击关闭面板
        titleElement.addEventListener('click', function() {
            // 停止当前播放的语音
            stopReading();
            hidePanel();
        });

        // 关闭词典面板
        closeButton.addEventListener('click', function() {
            // 停止当前播放的语音
            stopReading();
            hidePanel();
        });

        // 切换句子/段落
        contextToggle.addEventListener('click', function() {
            CONFIG.DISPLAY_SENTENCE_MODE = !CONFIG.DISPLAY_SENTENCE_MODE;
            this.textContent = CONFIG.BUTTON_TEXT.DISPLAY[CONFIG.DISPLAY_SENTENCE_MODE];
            
            // 更新上下文
            updateContext();
            
            // 保存设置到本地存储
            saveSettings();
        });

        // 切换翻译功能
        translationToggle.addEventListener('click', function() {
            CONFIG.TRANSLATION_ENABLED = !CONFIG.TRANSLATION_ENABLED;
            this.textContent = CONFIG.BUTTON_TEXT.TRANSLATION[CONFIG.TRANSLATION_ENABLED];
            this.classList.toggle('active', CONFIG.TRANSLATION_ENABLED);
            
            if (CONFIG.TRANSLATION_ENABLED) {
                translationArea.style.display = 'block';
                // 如果有上下文内容且不同于上次翻译的内容,立即翻译
                const currentContextText = getContextText();
                if (currentContextText && currentContextText !== lastTranslatedText) {
                    translateContextText(currentContextText);
                }
            } else {
                translationArea.style.display = 'none';
            }
            
            // 保存设置到本地存储
            saveSettings();
        });
        
        // 切换TTS功能
        ttsToggle.addEventListener('click', function() {
            CONFIG.TTS_AUTO = !CONFIG.TTS_AUTO;
            this.textContent = CONFIG.BUTTON_TEXT.TTS[CONFIG.TTS_AUTO];
            this.classList.toggle('active', CONFIG.TTS_AUTO);
            
            // 保存设置到本地存储
            saveSettings();
        });
        
        // 单词发音按钮
        ttsButton.addEventListener('click', function() {
            const word = queryInput.value.trim();
            if (word) {
                readText(word);
            }
        });
        
        // 上下文朗读按钮
        contextTtsButton.addEventListener('click', function() {
            const contextText = getContextText();
            if (contextText) {
                readText(contextText);
            }
        });
        
        // 上下文复制按钮
        contextCopyButton.addEventListener('click', function() {
            const contextText = getContextText();
            copyToClipboard(contextText);
        });
        
        // 上下文翻译按钮
        contextTranslateButton.addEventListener('click', function() {
            const contextText = getContextText();
            if (contextText) {
                // 临时显示翻译区域
                translationArea.style.display = 'block';
                // 手动触发翻译(即使总开关关闭也能工作)
                translateContextText(contextText, true);
            }
        });

        // 查询框输入事件
        queryInput.addEventListener('input', function() {
            const word = this.value.trim();
            if (word) {
                lookupWord(word);
            }
        });

        // 查询按钮点击事件(添加下一个单词)
        setupQueryButton(queryButton, queryInput);

        // 上下文区域点击事件:点击上下文中的单词
        setupContextAreaEvents(contextArea, queryInput);

        // 初始设置翻译区域显示状态
        translationArea.style.display = CONFIG.TRANSLATION_ENABLED ? 'block' : 'none';
        
        // 添加重置设置按钮事件处理
        const resetButton = panel.querySelector('.lunalens-reset-settings');
        resetButton.addEventListener('click', function() {
            resetSettings();
            showToast('设置已重置为默认值', false);
        });

        // 阻止滚动事件冒泡到主页
        panel.addEventListener('wheel', function(e) {
            e.stopPropagation();
        });
        panel.addEventListener('touchmove', function(e) {
            e.stopPropagation();
        });

        return panel;
    }

    // 显示词典面板
    function showPanel() {
        if (dictionaryPanel) {
            dictionaryPanel.classList.add('visible');
            dictionaryPanel.querySelector('.lunalens-dict-window').classList.add('visible');
            dictionaryPanel.querySelector('.lunalens-setting-window').classList.remove('visible');
            dictionaryPanel.querySelector('.lunalens-setting-toggle').classList.remove('active');
        }
        document.documentElement.style.overflow = 'hidden';
    }

    // 隐藏词典面板
    function hidePanel() {
        if (dictionaryPanel) {
            dictionaryPanel.classList.remove('visible');
        }
        document.documentElement.style.overflow = 'auto';
    }

    // 更新词典面板上下文(句子或段落)
    function updateContext() {
        if (!dictionaryPanel || !activeElement || !contextSentence) return;
        
        const contextArea = dictionaryPanel.querySelector('.lunalens-dict-context');
        
        // 保存当前滚动位置
        const scrollTop = contextArea.scrollTop;
        
        // 清空上下文区域
        contextArea.innerHTML = '';
        
        // 创建临时容器
        const tempContainer = document.createElement('div');
        
        if (!CONFIG.DISPLAY_SENTENCE_MODE) {
            // 段落模式:显示整个段落的内容
            tempContainer.innerHTML = activeElement.innerHTML;
        } else {
            // 句子模式:只显示当前句子的内容
            tempContainer.innerHTML = contextSentence.innerHTML;
        }
        
        // 将内容添加到上下文区域,不带原始事件监听器
        contextArea.appendChild(tempContainer);
        
        // 重新标记激活的单词
        if (activeWordElements.length > 0) {
            contextArea.querySelectorAll('.lunalens-word').forEach(word => {
                const isActive = activeWordElements.some(activeWord => 
                    activeWord === word.dataset.originalIndex || // 通过索引匹配
                    (typeof activeWord === 'object' && 
                     activeWord.dataset && 
                     activeWord.dataset.originalIndex === word.dataset.originalIndex)
                );
                
                if (isActive) {
                    word.classList.add('active-word');
                } else {
                    word.classList.remove('active-word');
                }
            });
        }
        
        // 恢复滚动位置
        contextArea.scrollTop = scrollTop;
        
        // 检查上下文内容是否变化,如果变化且翻译功能开启,才翻译上下文内容
        if (CONFIG.TRANSLATION_ENABLED) {
            const currentContextText = getContextText();
            if (currentContextText !== lastTranslatedText) {
                translateContextText(currentContextText);
            }
        }
    }

    // 获取上下文区域的纯文本
    function getContextText() {
        if (!dictionaryPanel) return '';
        
        const contextArea = dictionaryPanel.querySelector('.lunalens-dict-context');
        if (!contextArea) return '';
        
        // 去除振假名
        return getPlainText(contextArea.innerHTML).trim();
    }

    // 翻译上下文内容
    function translateContextText(text, forceTranslate = false) {
        if (!translationArea || (!CONFIG.TRANSLATION_ENABLED && !forceTranslate)) return;
        
        // 如果未提供文本参数,则获取当前上下文文本
        if (!text) {
            text = getContextText();
        }
        
        if (!text) {
            translationArea.innerHTML = '<div class="lunalens-translator-item">没有可翻译的文本</div>';
            return;
        }
        
        // 避免重复翻译相同的文本
        if (text === lastTranslatedText) {
            return;
        }
        
        // 更新上次翻译的文本
        lastTranslatedText = text;
        
        // 清空翻译区域,显示加载信息
        translationArea.innerHTML = '<div class="lunalens-translator-item">正在获取翻译...</div>';
        
        // 获取翻译器列表并发起请求
        GM_xmlhttpRequest({
            method: 'GET',
            url: `${CONFIG.API_URL}/api/list/translator`,
            timeout: CONFIG.TIMEOUT,
            onload: (response) => {
                try {
                    const translators = JSON.parse(response.responseText);
                    if (Array.isArray(translators) && translators.length > 0) {
                        // 清空翻译容器
                        translationArea.innerHTML = '';
                        
                        // 对每个翻译器发起请求
                        translators.forEach((translator, index) => {
                            // 为每个翻译器创建一个项,先显示加载中
                            const translatorItem = document.createElement('div');
                            translatorItem.className = 'lunalens-translator-item';
                            translatorItem.innerHTML = `加载中...<span class="lunalens-translator-name">${translator.name}</span>`;
                            translationArea.appendChild(translatorItem);
                            
                            // 如果不是最后一个翻译器,添加分隔线
                            if (index < translators.length - 1) {
                                const hr = document.createElement('hr');
                                hr.className = 'lunalens-hr';
                                translationArea.appendChild(hr);
                            }
                            
                            // 发起翻译请求
                            GM_xmlhttpRequest({
                                method: 'GET',
                                url: `${CONFIG.API_URL}/api/translate?text=${encodeURIComponent(text)}&id=${encodeURIComponent(translator.id)}`,
                                timeout: CONFIG.TIMEOUT,
                                onload: (response) => {
                                    try {
                                        const data = JSON.parse(response.responseText);
                                        translatorItem.innerHTML = `${data.result || '翻译失败'}<span class="lunalens-translator-name">${translator.name}</span>`;
                                    } catch (error) {
                                        translatorItem.innerHTML = `翻译结果解析失败<span class="lunalens-translator-name">${translator.name}</span>`;
                                    }
                                },
                                onerror: () => {
                                    translatorItem.innerHTML = `翻译请求失败<span class="lunalens-translator-name">${translator.name}</span>`;
                                },
                                ontimeout: () => {
                                    translatorItem.innerHTML = `翻译请求超时<span class="lunalens-translator-name">${translator.name}</span>`;
                                }
                            });
                        });
                    } else {
                        translationArea.innerHTML = '<div class="lunalens-translator-item">未找到可用的翻译器</div>';
                    }
                } catch (error) {
                    translationArea.innerHTML = '<div class="lunalens-translator-item">获取翻译器列表失败</div>';
                }
            },
            onerror: () => {
                translationArea.innerHTML = '<div class="lunalens-translator-item">获取翻译器列表失败</div>';
            },
            ontimeout: () => {
                translationArea.innerHTML = '<div class="lunalens-translator-item">获取翻译器列表超时</div>';
            }
        });
    }

    // 激活元素
    function activateElement(element) {
        // 取消激活当前元素
        deactivateElement();
        
        // 设置新的激活元素
        activeElement = element;
        // 保存原始内容以便后续恢复
        originalContent = element.innerHTML;
        element.classList.add('lunalens-highlighted');
        
        // 重置上次翻译的文本
        lastTranslatedText = '';
        
        // 创建一个取消标志,用于标识当前处理是否仍然有效
        const requestId = Date.now();
        element.dataset.requestId = requestId;
        
        // 如果TTS功能开启,尝试朗读文本
        if (CONFIG.TTS_AUTO) {
            const plainText = getPlainText(originalContent);
            setTimeout(() => {
                // 使用重构后的TTS朗读功能
                readText(plainText);
            }, 50);
        }
        
        // 处理文本并添加分词标记
        processTextWithTokenization(originalContent, html => {
            // 如果元素已经不是当前激活的元素或者请求ID不匹配,则不更新内容
            if (element !== activeElement || element.dataset.requestId != requestId) {
                return;
            }
            
            element.innerHTML = html;
            
            // 为所有单词添加点击事件
            element.querySelectorAll('.lunalens-word').forEach(word => {
                word.addEventListener('click', e => {
                    e.stopPropagation();
                    
                    // 获取单词文本
                    const wordText = word.dataset.word;
                    
                    // 获取所在句子
                    contextSentence = word.closest('.lunalens-sentence');
                    if (!contextSentence) contextSentence = element;
                    
                    // 给单词添加临时闪烁效果
                    word.classList.add('flash');
                    setTimeout(() => {
                        word.classList.remove('flash');
                    }, 1000);
                    
                    // 首先清空之前的激活状态
                    const contextArea = dictionaryPanel.querySelector('.lunalens-dict-context');
                    if (contextArea) {
                        contextArea.querySelectorAll('.lunalens-word.active-word').forEach(w => {
                            w.classList.remove('active-word');
                        });
                    }
                    activeWordElements = [];
                    
                    // 记录当前活跃词
                    activeWordElements.push(word.dataset.originalIndex || word);
                    
                    // 显示词典面板
                    showPanel();
                    
                    // 更新面板上下文
                    updateContext();
                    
                    // 设置查词框内容
                    const queryInput = dictionaryPanel.querySelector('.lunalens-dict-query-input');
                    queryInput.value = wordText;
                    
                    // 查询单词
                    lookupWord(wordText);
                });
            });
        });
    }

    // 取消激活元素
    function deactivateElement() {
        if (activeElement && originalContent) {
            activeElement.innerHTML = originalContent;
            activeElement.classList.remove('lunalens-highlighted');
            activeElement = null;
            originalContent = null;
            
            // 清除激活单词记录
            activeWordElements = [];
            
            // 清除上次翻译的文本记录
            lastTranslatedText = '';
        }
    }

    // 处理点击事件
    function handleClick(e) {
        // 如果点击发生在词典面板内,不处理
        if (dictionaryPanel && dictionaryPanel.contains(e.target)) {
            return;
        }
        
        if (activeElement && activeElement.contains(e.target)) {
            if (e.target.classList.contains('lunalens-sentence') || 
                e.target.classList.contains('lunalens-word') || 
                e.target.closest('.lunalens-word')) {
                e.preventDefault();
                return;
            }
        } else if (isElementSelectable(e.target)) {
            // 检查内容是否为空或只有空白字符
            const textContent = e.target.textContent.trim();
            if (textContent.length < CONFIG.MIN_CONTENT_LENGTH || textContent.length > CONFIG.MAX_CONTENT_LENGTH) {
                return;
            }
            
            e.preventDefault();
            activateElement(e.target);
        } else if (!e.target.closest('.lunalens-panel')) {
            // 只有当点击不在词典面板内时才停用元素
            deactivateElement();
        }
    }
    
    // 判断元素是否符合选择器设置
    function isElementSelectable(element) {
        if (!element) return false;
        
        const tagName = element.tagName.toLowerCase();
        
        // 处理逗号分隔的配置字符串并返回有效的数组
        function parseConfigList(configString) {
            return configString.split(',').map(item => item.trim()).filter(Boolean);
        }
        
        // 1. 检查标签是否在包含列表中
        const includeTags = parseConfigList(CONFIG.INCLUDE_TAGS);
        if (includeTags.length > 0 && !includeTags.includes(tagName)) {
            return false;
        }
        
        // 2. 检查标签是否在排除列表中
        const excludeTags = parseConfigList(CONFIG.EXCLUDE_TAGS);
        if (excludeTags.length > 0 && excludeTags.includes(tagName)) {
            return false;
        }
        
        // 3. 检查class和id是否在包含列表中
        const includeClassIds = parseConfigList(CONFIG.INCLUDE_CLASS_IDS);
        if (includeClassIds.length > 0) {
            let matched = false;
            for (const selector of includeClassIds) {
                if (selector.startsWith('.') && element.classList.contains(selector.substring(1))) {
                    matched = true;
                    break;
                } else if (selector.startsWith('#') && element.id === selector.substring(1)) {
                    matched = true;
                    break;
                }
            }
            if (!matched) return false;
        }
        
        // 4. 检查class和id是否在排除列表中
        const excludeClassIds = parseConfigList(CONFIG.EXCLUDE_CLASS_IDS);
        if (excludeClassIds.length > 0) {
            for (const selector of excludeClassIds) {
                if (selector.startsWith('.') && element.classList.contains(selector.substring(1))) {
                    return false;
                } else if (selector.startsWith('#') && element.id === selector.substring(1)) {
                    return false;
                }
            }
        }
        
        // 5. 检查是否在停止容器内
        const stopContainers = parseConfigList(CONFIG.STOP_CONTAINERS);
        if (stopContainers.length > 0) {
            for (const selector of stopContainers) {
                let closestContainer = null;
                
                try {
                    closestContainer = element.closest(selector);
                } catch (e) {
                    console.error(`无效的选择器: ${selector}`, e);
                }
                
                if (closestContainer) {
                    // 如果元素本身就是停止容器,允许选择
                    if (closestContainer === element) {
                        return true;
                    }
                    
                    // 如果元素在停止容器内,需要确保它不是深层嵌套的
                    const parentContainer = element.parentElement.closest(selector);
                    if (!parentContainer || parentContainer === closestContainer) {
                        return true;
                    }
                    
                    return false;
                }
            }
        }
        
        return true;
    }

    // 处理iframe
    function handleIframe(iframe) {
        try {
            function setupIframe() {
                const iframeDoc = iframe.contentDocument || iframe.contentWindow.document;
                addStyle(iframeDoc);
                iframeDoc.addEventListener('click', handleClick);
            }

            if (iframe.contentDocument && iframe.contentDocument.readyState === 'complete') {
                setupIframe();
            } else {
                iframe.addEventListener('load', setupIframe);
            }
        } catch (e) {
            console.log('无法访问iframe:', e);
        }
    }

    // 处理所有iframe
    function handleAllIframes() {
        document.querySelectorAll('iframe').forEach(handleIframe);
    }

    // 初始化函数
    function init() {
        addStyle(document);
        document.addEventListener('click', handleClick);
        
        // 创建常驻词典面板
        dictionaryPanel = createDictionaryPanel();
        
        // 处理现有iframe
        handleAllIframes();
        
        // 监听新添加的iframe
        new MutationObserver(handleAllIframes).observe(document.body, {
            childList: true,
            subtree: true
        });
        
        // 加载保存的设置
        loadSettings();
    }

    setTimeout(init, 500);

    // 显示通知
    function showToast(message, isError = false) {
        // 创建通知元素
        const toast = document.createElement('div');
        toast.className = 'lunalens-toast';
        toast.textContent = message;
        
        // 错误消息使用红色背景
        if (isError) {
            toast.style.backgroundColor = 'rgba(220, 53, 69, 0.9)';
        } else {
            toast.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
        }
        
        // 添加到文档中并显示
        document.body.appendChild(toast);
        
        // 强制回流以触发动画
        void toast.offsetWidth;
        toast.style.display = 'block';
        
        // 动画结束后移除元素
        setTimeout(() => {
            toast.style.opacity = '0';
            setTimeout(() => {
                if (toast.parentNode) {
                    toast.parentNode.removeChild(toast);
                }
            }, 300);
        }, 2000);
    }
    
    // 保存设置到本地存储
    function saveSettings() {
        const settings = {
            API_URL: CONFIG.API_URL,
            SENTENCE_DELIMITERS: CONFIG.SENTENCE_DELIMITERS,
            SENTENCE_LENGTH: CONFIG.SENTENCE_LENGTH,
            MIN_CONTENT_LENGTH: CONFIG.MIN_CONTENT_LENGTH,
            MAX_CONTENT_LENGTH: CONFIG.MAX_CONTENT_LENGTH,
            INCLUDE_TAGS: CONFIG.INCLUDE_TAGS,
            EXCLUDE_TAGS: CONFIG.EXCLUDE_TAGS,
            INCLUDE_CLASS_IDS: CONFIG.INCLUDE_CLASS_IDS,
            EXCLUDE_CLASS_IDS: CONFIG.EXCLUDE_CLASS_IDS,
            STOP_CONTAINERS: CONFIG.STOP_CONTAINERS,
            TIMEOUT: CONFIG.TIMEOUT,
            DISPLAY_SENTENCE_MODE: CONFIG.DISPLAY_SENTENCE_MODE,
            TRANSLATION_ENABLED: CONFIG.TRANSLATION_ENABLED,
            TTS_AUTO: CONFIG.TTS_AUTO
        };
        
        try {
            localStorage.setItem('lunalens_settings', JSON.stringify(settings));
        } catch (e) {
            console.error('保存设置失败:', e);
        }
    }
    
    // 从本地存储加载设置
    function loadSettings() {
        try {
            const savedSettings = localStorage.getItem('lunalens_settings');
            if (savedSettings) {
                const settings = JSON.parse(savedSettings);
                
                // 更新CONFIG对象
                Object.keys(settings).forEach(key => {
                    if (typeof CONFIG[key] !== 'undefined') {
                        CONFIG[key] = settings[key];
                    }
                });
                
                // 更新设置表单值
                if (dictionaryPanel) {
                    const panel = dictionaryPanel;
                    
                    // 更新基本设置
                    const updateField = (id, value) => {
                        const field = panel.querySelector(`#${id}`);
                        if (field) field.value = value;
                    };
                    
                    updateField('lunalens-api-url', CONFIG.API_URL);
                    updateField('sentence-delimiters', CONFIG.SENTENCE_DELIMITERS);
                    updateField('sentence-length', CONFIG.SENTENCE_LENGTH);
                    updateField('min-content-length', CONFIG.MIN_CONTENT_LENGTH);
                    updateField('max-content-length', CONFIG.MAX_CONTENT_LENGTH);
                    updateField('include-tags', CONFIG.INCLUDE_TAGS);
                    updateField('exclude-tags', CONFIG.EXCLUDE_TAGS);
                    updateField('include-class-ids', CONFIG.INCLUDE_CLASS_IDS);
                    updateField('exclude-class-ids', CONFIG.EXCLUDE_CLASS_IDS);
                    updateField('stop-containers', CONFIG.STOP_CONTAINERS);
                    updateField('timeout', CONFIG.TIMEOUT);
                    
                    // 更新顶栏按钮状态
                    panel.querySelector('.lunalens-context-toggle').textContent = 
                        CONFIG.BUTTON_TEXT.DISPLAY[CONFIG.DISPLAY_SENTENCE_MODE];
                    
                    panel.querySelector('.lunalens-translation-toggle').textContent = 
                        CONFIG.BUTTON_TEXT.TRANSLATION[CONFIG.TRANSLATION_ENABLED];
                    panel.querySelector('.lunalens-translation-toggle').classList.toggle('active', CONFIG.TRANSLATION_ENABLED);
                    
                    panel.querySelector('.lunalens-auto-tts-toggle').textContent = 
                        CONFIG.BUTTON_TEXT.TTS[CONFIG.TTS_AUTO];
                    panel.querySelector('.lunalens-auto-tts-toggle').classList.toggle('active', CONFIG.TTS_AUTO);
                    
                    // 显示/隐藏翻译区域
                    if (translationArea) {
                        translationArea.style.display = CONFIG.TRANSLATION_ENABLED ? 'block' : 'none';
                    }
                }
            }
        } catch (e) {
            console.error('加载设置失败:', e);
        }
    }
    
    // 重置设置为默认值
    function resetSettings() {
        // 从DEFAULT_CONFIG复制所有属性到CONFIG
        Object.keys(DEFAULT_CONFIG).forEach(key => {
            CONFIG[key] = DEFAULT_CONFIG[key];
        });
        
        // 更新UI上的设置值
        if (dictionaryPanel) {
            const panel = dictionaryPanel;
            
            // 更新基本设置
            const updateField = (id, value) => {
                const field = panel.querySelector(`#${id}`);
                if (field) field.value = value;
            };
            
            updateField('lunalens-api-url', CONFIG.API_URL);
            updateField('sentence-delimiters', CONFIG.SENTENCE_DELIMITERS);
            updateField('sentence-length', CONFIG.SENTENCE_LENGTH);
            updateField('min-content-length', CONFIG.MIN_CONTENT_LENGTH);
            updateField('max-content-length', CONFIG.MAX_CONTENT_LENGTH);
            updateField('include-tags', CONFIG.INCLUDE_TAGS);
            updateField('exclude-tags', CONFIG.EXCLUDE_TAGS);
            updateField('include-class-ids', CONFIG.INCLUDE_CLASS_IDS);
            updateField('exclude-class-ids', CONFIG.EXCLUDE_CLASS_IDS);
            updateField('stop-containers', CONFIG.STOP_CONTAINERS);
            updateField('timeout', CONFIG.TIMEOUT);
            
            // 更新顶栏按钮状态
            panel.querySelector('.lunalens-context-toggle').textContent = 
                CONFIG.BUTTON_TEXT.DISPLAY[CONFIG.DISPLAY_SENTENCE_MODE];
            
            panel.querySelector('.lunalens-translation-toggle').textContent = 
                CONFIG.BUTTON_TEXT.TRANSLATION[CONFIG.TRANSLATION_ENABLED];
            panel.querySelector('.lunalens-translation-toggle').classList.toggle('active', CONFIG.TRANSLATION_ENABLED);
            
            panel.querySelector('.lunalens-auto-tts-toggle').textContent = 
                CONFIG.BUTTON_TEXT.TTS[CONFIG.TTS_AUTO];
            panel.querySelector('.lunalens-auto-tts-toggle').classList.toggle('active', CONFIG.TTS_AUTO);
            
            // 显示/隐藏翻译区域
            if (translationArea) {
                translationArea.style.display = CONFIG.TRANSLATION_ENABLED ? 'block' : 'none';
            }
        }
        
        // 从本地存储中移除保存的设置
        localStorage.removeItem('lunalens_settings');
    }

    // 查词典并显示结果
    function lookupWord(word) {
        if (!word) return;
        if (word === currentWord) return;

        currentWord = word;

        // 获取词典面板
        const panel = document.querySelector('.lunalens-panel');
        if (!panel) return;

        const tabsContainer = panel.querySelector('.lunalens-dict-tabs');
        const entriesContainer = panel.querySelector('.lunalens-dict-entries');
        
        // 清空现有内容
        tabsContainer.innerHTML = '';
        entriesContainer.innerHTML = `<div class="lunalens-dict-loading">正在查询${word}</div>`;
        
        // 使用兼容模式查询
        fetchDictionaryByGM(word, tabsContainer, entriesContainer);
    }

    // 使用GM_xmlhttpRequest并行获取多个词典数据
    function fetchDictionaryByGM(word, tabsContainer, entriesContainer, dictIds = []) {
        // 生成唯一请求ID
        const requestId = Date.now().toString();
        dictionaryPanel.setAttribute('data-request-id', requestId);
        
        // 如果没有提供词典ID列表,则先获取可用词典列表
        if (!dictIds || dictIds.length === 0) {
            GM_xmlhttpRequest({
                method: 'GET',
                url: `${CONFIG.API_URL}/api/list/dictionary`,
                onload: (response) => {
                    // 检查响应是否匹配当前请求
                    if (dictionaryPanel.getAttribute('data-request-id') !== requestId) return;
                    
                    try {
                        const dictList = JSON.parse(response.responseText);
                        if (Array.isArray(dictList) && dictList.length > 0) {
                            // 提取词典ID列表
                            const ids = dictList.map(dict => dict.id);
                            // 递归调用,使用获取的词典ID列表
                            fetchDictionaryByGM(word, tabsContainer, entriesContainer, ids);
                        } else {
                            // 没有找到词典
                            showDictionaryStatus(entriesContainer, '');
                        }
                    } catch (error) {
                        console.error('获取词典列表失败:', error);
                        showDictionaryStatus(entriesContainer, '');
                    }
                },
                onerror: () => {
                    // 检查响应是否匹配当前请求
                    if (dictionaryPanel.getAttribute('data-request-id') !== requestId) return;
                    
                    showDictionaryStatus(entriesContainer, '');
                }
            });
            return;
        }
        
        // 记录未完成的请求数
        let pendingRequests = dictIds.length;
        
        // 添加MDICT内部标签切换函数
        if (entriesContainer.parentNode && !entriesContainer.parentNode.querySelector('script[data-mdict-function]')) {
            const script = document.createElement('script');
            script.setAttribute('data-mdict-function', 'true');
            script.textContent = `
                function onclickbtn_mdict_internal(_id) {
                    tabPanes = document.querySelectorAll('.tab-widget_mdict_internal .tab-pane_mdict_internal');
                    tabButtons = document.querySelectorAll('.tab-widget_mdict_internal .tab-button_mdict_internal');
                    for (i = 0; i < tabButtons.length; i++)
                        tabButtons[i].classList.remove('active');
                    for (i = 0; i < tabPanes.length; i++)
                        tabPanes[i].classList.remove('active');

                    document.getElementById(_id).classList.add('active');

                    tabId = document.getElementById(_id).getAttribute('data-tab');
                    tabPane = document.getElementById(tabId);
                    tabPane.classList.add('active');
                }
            `;
            entriesContainer.parentNode.appendChild(script);
        }
        
        // 并行请求每个词典
        dictIds.forEach(dictId => {
            GM_xmlhttpRequest({
                method: 'GET',
                url: `${CONFIG.API_URL}/api/dictionary?id=${dictId}&word=${encodeURIComponent(word)}`,
                onload: (response) => {
                    // 检查响应是否匹配当前请求
                    if (dictionaryPanel.getAttribute('data-request-id') !== requestId) return;
                    
                    try {
                        const data = JSON.parse(response.responseText);
                        
                        // 隐藏加载提示
                        const loadingIndicator = entriesContainer.querySelector('.lunalens-dict-loading');
                        if (loadingIndicator) loadingIndicator.style.display = 'none';
                        
                        // 添加词典条目
                        addDictionaryEntry(tabsContainer, entriesContainer, data);
                    } catch (error) {
                        console.error(`获取词典 ${dictId} 失败:`, error);
                    }
                    
                    // 减少未完成请求计数
                    pendingRequests--;
                    
                    // 如果所有请求都完成了,但没有词典结果,则显示提示
                    if (pendingRequests === 0 && tabsContainer.children.length === 0) {
                        showDictionaryStatus(entriesContainer, '');
                    }
                },
                onerror: () => {
                    // 检查响应是否匹配当前请求
                    if (dictionaryPanel.getAttribute('data-request-id') !== requestId) return;
                    
                    console.error(`获取词典 ${dictId} 失败`);
                    
                    // 减少未完成请求计数
                    pendingRequests--;
                    
                    // 如果所有请求都完成了,但没有词典结果,则显示提示
                    if (pendingRequests === 0 && tabsContainer.children.length === 0) {
                        showDictionaryStatus(entriesContainer, '');
                    }
                }
            });
        });
    }

    // 显示词典状态信息
    function showDictionaryStatus(container, message) {
        const loadingIndicator = container.querySelector('.lunalens-dict-loading');
        if (loadingIndicator) {
            loadingIndicator.textContent = message;
        } else {
            container.innerHTML = `<div class="lunalens-dict-loading">${message}</div>`;
        }
    }

    // 添加词典条目
    function addDictionaryEntry(tabsContainer, entriesContainer, data, isFirst) {
        // 如果没有词典名称,直接跳过
        if (!data.name) return;
        
        const dictName = data.name;
        const dictId = `dict-${dictName.replace(/\s+/g, '-')}`;
        
        // 检查是否已有该词典结果
        let entryDiv = document.getElementById(dictId);
        
        if (!entryDiv) {
            // 创建新词典条目
            entryDiv = document.createElement('div');
            entryDiv.className = 'lunalens-dict-entry';
            if (isFirst || tabsContainer.children.length === 0) entryDiv.classList.add('active');
            entryDiv.id = dictId;
            entryDiv.setAttribute('data-dict', dictName);
            entryDiv.innerHTML = `<div class="lunalens-dict-content">${data.result || ''}</div>`;
            entriesContainer.appendChild(entryDiv);
            
            // 添加词典标签
            const tab = document.createElement('div');
            tab.className = 'lunalens-dict-tab';
            if (isFirst || tabsContainer.children.length === 0) tab.classList.add('active');
            tab.textContent = dictName;
            tab.setAttribute('data-dict', dictName);
            
            tab.addEventListener('click', function() {
                // 更新标签状态
                document.querySelectorAll('.lunalens-dict-tab').forEach(t => t.classList.remove('active'));
                this.classList.add('active');
                
                // 更新词典显示
                const dictName = this.getAttribute('data-dict');
                document.querySelectorAll('.lunalens-dict-entry').forEach(entry => {
                    if (entry.getAttribute('data-dict') === dictName) {
                        entry.classList.add('active');
                    } else {
                        entry.classList.remove('active');
                    }
                });
            });
            
            tabsContainer.appendChild(tab);
        } else {
            // 更新现有词典内容
            const contentDiv = entryDiv.querySelector('.lunalens-dict-content');
            if (contentDiv) contentDiv.innerHTML = data.result || '';
        }
    }

    // TTS朗读功能
    function readText(text, element = null) {
        if (!text || !text.trim()) return false;

        stopReading();

        // 检测设备类型并使用适当的播放方法
        if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
            // 在移动设备上直接使用Audio元素和原始URL
            playWithDirectUrl(text);
        } else {
            // 在桌面设备上使用ArrayBuffer加音频解码
            fetchAndPlayTTS(text);
        }
        
        return true;
    }
    
    // 停止朗读
    function stopReading() {
        // 取消所有待处理的TTS请求
        pendingTTSRequests.forEach(request => {
            if (request && request.abort) {
                try {
                    request.abort();
                } catch(e) {
                    console.log('取消TTS请求失败:', e);
                }
            }
        });
        pendingTTSRequests = [];
        
        // 停止当前播放的音频
        if (currentAudio) {
            try {
                currentAudio.pause();
                if (currentAudio.src) {
                    URL.revokeObjectURL(currentAudio.src);
                }
                
                // 释放资源
                if (currentAudio.source && currentAudio.context) {
                    try {
                        currentAudio.source.stop();
                        currentAudio.context.close();
                    } catch(e) {}
                }
            } catch(e) {
                console.error('停止播放时出错:', e);
            } finally {
                currentAudio = null;
            }
        }
    }
    
    
    // 直接通过URL播放(适用于移动设备)
    function playWithDirectUrl(text) {

        const audio = new Audio();
        audio.src = `${CONFIG.API_URL}/api/tts?text=${encodeURIComponent(text)}`;
        
        currentAudio = {
            element: audio,
            pause: function() {
                try {
                    this.element.pause();
                } catch(e) {
                    console.error('停止播放失败:', e);
                }
            }
        };
        
        audio.onended = () => {
            currentAudio = null;
        };
        
        audio.onerror = (e) => {
            console.error('音频播放失败:', e);
            currentAudio = null;
        };
        
        audio.play().catch(e => fetchAndPlayTTS(text));
    }

    // 获取并播放TTS(适用于桌面设备)
    function fetchAndPlayTTS(text) {
        const request = GM_xmlhttpRequest({
            method: 'GET',
            url: `${CONFIG.API_URL}/api/tts?text=${encodeURIComponent(text)}`,
            responseType: 'arraybuffer',
            timeout: CONFIG.TIMEOUT,
            onload: response => {
                // 从待处理列表中移除该请求
                const index = pendingTTSRequests.indexOf(request);
                if (index > -1) {
                    pendingTTSRequests.splice(index, 1);
                }
                
                if (response.status >= 200 && response.status < 300) {
                    playAudioBlob(response.response);
                } else {
                    console.error('TTS请求失败! 状态:', response.status);
                }
            },
            onerror: error => {
                // 从待处理列表中移除该请求
                const index = pendingTTSRequests.indexOf(request);
                if (index > -1) {
                    pendingTTSRequests.splice(index, 1);
                }
                console.error('TTS请求失败:', error);
            },
            ontimeout: () => {
                // 从待处理列表中移除该请求
                const index = pendingTTSRequests.indexOf(request);
                if (index > -1) {
                    pendingTTSRequests.splice(index, 1);
                }
                console.error('TTS请求超时');
            }
        });
        
        // 将请求添加到待处理列表
        pendingTTSRequests.push(request);
    }
    
    // 播放音频数据(仅用于桌面设备)
    function playAudioBlob(arrayBuffer) {
        // 如果已经有音频在播放或者系统已停止,则不播放新音频
        if (currentAudio) {
            return;
        }
        
        try {
            const audioContext = new (window.AudioContext || window.webkitAudioContext)();
            
            audioContext.decodeAudioData(arrayBuffer, 
                (buffer) => {
                    const source = audioContext.createBufferSource();
                    source.buffer = buffer;
                    source.connect(audioContext.destination);
                    
                    currentAudio = {
                        source: source,
                        context: audioContext,
                        pause: function() {
                            try {
                                this.source.stop();
                                this.context.close();
                            } catch(e) {}
                        }
                    };
                    
                    source.onended = () => {
                        audioContext.close().catch(() => {});
                        currentAudio = null;
                    };
                    
                    source.start(0);
                },
                () => console.error('音频播放失败')
            );
        } catch (e) {
            console.error('音频播放失败:', e);
            playWithDirectUrl(text);
        }
    }
})();