全能搜索引擎切换助手

在搜索结果页面添加智能搜索引擎切换功能,支持多种布局和自定义设置

目前為 2025-02-25 提交的版本,檢視 最新版本

// ==UserScript==
// @name         全能搜索引擎切换助手
// @namespace    http://tampermonkey.net/
// @version      1.6
// @description  在搜索结果页面添加智能搜索引擎切换功能,支持多种布局和自定义设置
// @author       Yuze
// @copyright    2025, Yuze (https://gf.qytechs.cn/users/Yuze Guitar)
// @license      MIT
// @match        *://www.google.com/search*
// @match        *://www.google.co*/search*
// @match        *://www.bing.com/search*
// @match        *://cn.bing.com/search*
// @match        *://www.baidu.com/s*
// @match        *://www.sogou.com/web*
// @match        *://www.so.com/s*
// @match        *://duckduckgo.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @grant        GM_registerMenuCommand
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';
    
    // 记录调试信息
    const DEBUG = true;
    function log(...args) {
        if (DEBUG) {
            console.log('[搜索引擎切换助手]', ...args);
        }
    }
    
    // 错误处理
    function handleError(error, context) {
        console.error(`[搜索引擎切换助手] 错误 (${context}):`, error);
        if (DEBUG) {
            console.trace();
        }
    }

    // 检测操作系统
    const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;
    const modifierKey = isMac ? '⌘' : 'Alt+';
    const modifierKeyCode = isMac ? 'metaKey' : 'altKey';
    
    // 定义搜索引擎
    const defaultEngines = [
        {
            name: 'Google',
            icon: 'https://www.google.com/favicon.ico',
            url: 'https://www.google.com/search?q={query}',
            matchPattern: 'google\\.[^/]+/search',
            queryParam: 'q',
            shortcut: 'G'
        },
        {
            name: 'Bing',
            icon: 'https://www.bing.com/favicon.ico',
            url: 'https://www.bing.com/search?q={query}',
            matchPattern: 'bing\\.com/search',
            queryParam: 'q',
            shortcut: 'B'
        },
        {
            name: '百度',
            icon: 'https://www.baidu.com/favicon.ico',
            url: 'https://www.baidu.com/s?wd={query}',
            matchPattern: 'baidu\\.com/s',
            queryParam: 'wd',
            shortcut: 'D'
        },
        {
            name: 'DuckDuckGo',
            // 内置图标数据,确保在任何环境下都能显示
            icon: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZmlsbD0iI0RFNTgzMyIgZD0iTTEyIDFDNS45MiAxIDEgNS45MiAxIDEyczQuOTIgMTEgMTEgMTEgMTEtNC45MiAxMS0xMVMxOC4wOCAxIDEyIDF6bTMuNTggMTQuMWMwIC4wOS0uMDUuMi0uMTMuMjdsLS45My43Ni0uMDIuMDJhLjM4LjM4IDAgMCAxLS4yOC4xMmgtNS4xM2MtLjIyIDAtLjQtLjE4LS40LS40di0uOTctLjAxYzAtLjIyLjE4LS40LjQtLjRoNS4xNWEuMzguMzggMCAwIDEgLjI2LjEybC4wMS4wMi45My43NmEuMzQuMzQgMCAwIDEgLjEzLjI3eiIvPjwvc3ZnPg==',
            url: 'https://duckduckgo.com/?q={query}',
            matchPattern: 'duckduckgo\\.com',
            queryParam: 'q',
            shortcut: 'K'
        }
    ];
    
    // 添加CSS样式
    function addStyles() {
        try {
            GM_addStyle(`
                /* 主容器 */
                #search-engine-switcher {
                    position: fixed;
                    top: 120px;
                    left: 10px;
                    z-index: 9999;
                    background: #fff;
                    border-radius: 8px;
                    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
                    padding: 10px;
                    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
                    font-size: 14px;
                    display: flex;
                    flex-direction: column;
                    gap: 12px;
                    transition: all 0.3s ease;
                    min-width: 120px;
                    max-width: 180px;
                }
                
                /* 深色模式 */
                @media (prefers-color-scheme: dark) {
                    #search-engine-switcher {
                        background: #333;
                        color: #fff;
                        box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
                    }
                    #search-engine-switcher .engine-btn {
                        color: #eee;
                    }
                    #search-engine-switcher .engine-btn:hover {
                        background: #444;
                    }
                    #search-engine-switcher .collapse-btn {
                        color: #ccc;
                    }
                    #search-engine-switcher.collapsed {
                        background: rgba(51, 51, 51, 0.9);
                    }
                }
                
                /* 折叠状态 - 优化折叠后的外观 */
                #search-engine-switcher.collapsed {
                    padding: 8px 10px;
                    min-width: unset;
                    max-width: unset;
                    width: auto;
                }
                
                #search-engine-switcher.collapsed .engine-container {
                    display: none;
                }
                
                #search-engine-switcher.collapsed .switcher-header {
                    margin: 0;
                    padding: 0;
                }
                
                #search-engine-switcher.collapsed .collapse-btn {
                    transform: rotate(180deg);
                    margin-left: 5px;
                }
                
                #search-engine-switcher.collapsed .switcher-title {
                    margin: 0;
                    font-size: 12px;
                    white-space: nowrap;
                }
                
                /* 头部样式 */
                .switcher-header {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    margin-bottom: 5px;
                }
                
                .switcher-title {
                    font-weight: bold;
                    font-size: 14px;
                    margin: 0;
                    user-select: none;
                }
                
                .settings-btn, .collapse-btn {
                    background: none;
                    border: none;
                    cursor: pointer;
                    padding: 0;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    width: 20px;
                    height: 20px;
                    opacity: 0.7;
                    transition: opacity 0.2s;
                }
                
                .settings-btn:hover, .collapse-btn:hover {
                    opacity: 1;
                }
                
                .header-actions {
                    display: flex;
                    gap: 8px;
                }
                
                /* 搜索引擎按钮容器 */
                .engine-container {
                    display: flex;
                    flex-direction: column;
                    gap: 8px;
                }
                
                /* 搜索引擎按钮 */
                .engine-btn {
                    display: flex;
                    align-items: center;
                    gap: 8px;
                    padding: 6px 8px;
                    border-radius: 6px;
                    border: none;
                    background: none;
                    cursor: pointer;
                    color: #333;
                    font-size: 14px;
                    text-align: left;
                    transition: background 0.2s;
                }
                
                .engine-btn:hover {
                    background: #f0f0f0;
                }
                
                .engine-icon {
                    width: 16px;
                    height: 16px;
                    object-fit: contain;
                }
                
                .shortcut {
                    margin-left: auto;
                    padding: 2px 4px;
                    border-radius: 3px;
                    background: #f0f0f0;
                    color: #666;
                    font-size: 10px;
                }
                
                @media (prefers-color-scheme: dark) {
                    .shortcut {
                        background: #444;
                        color: #ccc;
                    }
                }
                
                /* 设置面板样式 */
                .settings-overlay {
                    position: fixed;
                    top: 0;
                    left: 0;
                    right: 0;
                    bottom: 0;
                    background: rgba(0, 0, 0, 0.5);
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    z-index: 10000;
                }
                
                .settings-container {
                    background: #fff;
                    border-radius: 8px;
                    padding: 20px;
                    width: 90%;
                    max-width: 400px;
                    max-height: 80vh;
                    overflow-y: auto;
                }
                
                @media (prefers-color-scheme: dark) {
                    .settings-container {
                        background: #333;
                        color: #fff;
                    }
                }
                
                .settings-header {
                    font-weight: bold;
                    font-size: 18px;
                    margin-bottom: 15px;
                }
                
                .settings-section {
                    margin-bottom: 20px;
                }
                
                .section-title {
                    font-weight: bold;
                    margin-bottom: 10px;
                }
                
                .checkbox-group {
                    display: flex;
                    flex-direction: column;
                    gap: 10px;
                }
                
                .settings-actions {
                    display: flex;
                    justify-content: flex-end;
                    gap: 10px;
                    margin-top: 20px;
                }
                
                .settings-button {
                    padding: 8px 16px;
                    border-radius: 4px;
                    border: none;
                    cursor: pointer;
                }
                
                .cancel-button {
                    background: #f0f0f0;
                    color: #333;
                }
                
                .save-button {
                    background: #4285f4;
                    color: white;
                }
                
                @media (prefers-color-scheme: dark) {
                    .cancel-button {
                        background: #555;
                        color: #eee;
                    }
                }
                
                /* Mac选项 */
                .mac-options {
                    display: flex;
                    gap: 15px;
                    margin-top: 10px;
                }
                
                .mac-option {
                    display: flex;
                    align-items: center;
                    gap: 5px;
                }
            `);
            log('样式已添加');
        } catch (error) {
            handleError(error, '添加样式');
        }
    }
    
    // 获取启用的搜索引擎
    function getEnabledEngines() {
        try {
            const settings = loadSettings();
            const enabledEngineNames = settings.enabledEngines || defaultEngines.map(e => e.name);
            
            return defaultEngines.filter(engine => 
                enabledEngineNames.includes(engine.name)
            );
        } catch (error) {
            handleError(error, '获取启用的搜索引擎');
            return defaultEngines;
        }
    }
    
    // 加载设置
    function loadSettings() {
        try {
            const defaultSettings = {
                enabledEngines: defaultEngines.map(engine => engine.name),
                collapsed: false,
                keyboardShortcuts: true,
                macModifierType: 'command'
            };
            
            const savedSettings = GM_getValue('searchEngineSettings');
            if (!savedSettings) {
                log('未找到保存的设置,使用默认设置');
                return defaultSettings;
            }
            
            try {
                const parsedSettings = typeof savedSettings === 'string' 
                    ? JSON.parse(savedSettings) 
                    : savedSettings;
                
                log('成功加载设置:', parsedSettings);
                return {...defaultSettings, ...parsedSettings};
            } catch (e) {
                handleError(e, '解析设置');
                return defaultSettings;
            }
        } catch (error) {
            handleError(error, '加载设置');
            return {
                enabledEngines: defaultEngines.map(engine => engine.name),
                collapsed: false,
                keyboardShortcuts: true,
                macModifierType: 'command'
            };
        }
    }
    
    // 保存设置
    function saveSettings(settings) {
        try {
            log('保存设置:', settings);
            GM_setValue('searchEngineSettings', settings);
            return true;
        } catch (error) {
            handleError(error, '保存设置');
            return false;
        }
    }
    
    // 获取当前搜索引擎和查询词
    function getCurrentEngineAndQuery() {
        try {
            const url = window.location.href;
            
            let currentEngine = null;
            let query = '';
            
            // 遍历搜索引擎进行匹配
            for (const engine of defaultEngines) {
                // 创建正则表达式
                const regexPattern = new RegExp(engine.matchPattern, 'i');
                
                if (regexPattern.test(url)) {
                    log(`匹配到搜索引擎: ${engine.name}`);
                    currentEngine = engine;
                    
                    // 提取查询词
                    const urlObj = new URL(url);
                    query = urlObj.searchParams.get(engine.queryParam) || '';
                    
                    // 特殊处理DuckDuckGo
                    if (engine.name === 'DuckDuckGo' && !query) {
                        // 检查URL中是否包含q=参数(可能在hash中)
                        if (url.includes('q=')) {
                            const match = url.match(/[?&#]q=([^&#]*)/);
                            if (match && match[1]) {
                                query = decodeURIComponent(match[1]);
                            }
                        }
                    }
                    
                    break;
                }
            }
            
            if (currentEngine) {
                log(`当前引擎: ${currentEngine.name}, 查询词: ${query}`);
            } else {
                log('未匹配到搜索引擎');
            }
            
            return { currentEngine, query };
        } catch (error) {
            handleError(error, '获取当前搜索引擎和查询词');
            return { currentEngine: null, query: '' };
        }
    }
    
    // 切换到指定搜索引擎
    function switchToEngine(engine, query) {
        try {
            if (!query) {
                log('没有查询词,取消切换');
                return;
            }
            
            // 将查询参数编码并替换到URL中
            const encodedQuery = encodeURIComponent(query);
            const targetUrl = engine.url.replace('{query}', encodedQuery);
            
            log(`切换到 ${engine.name}, URL: ${targetUrl}`);
            
            // 导航到新的URL
            window.location.href = targetUrl;
        } catch (error) {
            handleError(error, '切换搜索引擎');
        }
    }
    
    // 创建搜索引擎切换器UI
    function createSwitcherUI() {
        try {
            // 检查当前页面是否为搜索结果页
            const { currentEngine, query } = getCurrentEngineAndQuery();
            if (!currentEngine || !query) {
                log('未检测到搜索引擎或查询词,不创建UI');
                return;
            }
            
            // 检查是否已存在搜索引擎切换器,如果存在则移除
            let switcher = document.getElementById('search-engine-switcher');
            if (switcher) {
                log('搜索引擎切换器已存在,移除旧的');
                switcher.remove();
            }
            
            // 获取设置
            const settings = loadSettings();
            
            // 获取启用的搜索引擎
            const enabledEngines = getEnabledEngines();
            
            // 创建搜索引擎切换器容器
            switcher = document.createElement('div');
            switcher.id = 'search-engine-switcher';
            if (settings.collapsed) {
                switcher.classList.add('collapsed');
            }
            
            // 创建标题栏
            const header = document.createElement('div');
            header.className = 'switcher-header';
            
            // 创建标题
            const title = document.createElement('div');
            title.className = 'switcher-title';
            title.textContent = '搜索引擎切换';
            header.appendChild(title);
            
            // 创建按钮容器
            const headerActions = document.createElement('div');
            headerActions.className = 'header-actions';
            
            // 创建设置按钮
            const settingsButton = document.createElement('button');
            settingsButton.className = 'settings-btn';
            settingsButton.title = '设置';
            settingsButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>';
            settingsButton.addEventListener('click', function(e) {
                e.stopPropagation();
                showSettingsPanel();
            });
            headerActions.appendChild(settingsButton);
            
            // 创建折叠/展开按钮
            const collapseButton = document.createElement('button');
            collapseButton.className = 'collapse-btn';
            collapseButton.title = settings.collapsed ? '展开' : '折叠';
            collapseButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="18 15 12 9 6 15"></polyline></svg>';
            
            collapseButton.addEventListener('click', function(e) {
                e.stopPropagation();
                // 切换折叠状态
                switcher.classList.toggle('collapsed');
                // 更新设置
                const newSettings = {...settings, collapsed: switcher.classList.contains('collapsed')};
                saveSettings(newSettings);
                // 更新按钮提示
                this.title = newSettings.collapsed ? '展开' : '折叠';
            });
            headerActions.appendChild(collapseButton);
            
            header.appendChild(headerActions);
            switcher.appendChild(header);
            
            // 创建搜索引擎按钮容器
            const engineContainer = document.createElement('div');
            engineContainer.className = 'engine-container';
            
            // 创建每个搜索引擎按钮
            for (const engine of enabledEngines) {
                // 如果是当前搜索引擎,则跳过
                if (currentEngine && engine.name === currentEngine.name) {
                    continue;
                }
                
                // 创建按钮
                const engineBtn = document.createElement('button');
                engineBtn.className = 'engine-btn';
                engineBtn.title = `在${engine.name}中搜索 "${query}"`;
                engineBtn.addEventListener('click', function() {
                    switchToEngine(engine, query);
                });
                
                // 创建图标
                const img = document.createElement('img');
                img.src = engine.icon;
                img.className = 'engine-icon';
                img.alt = engine.name;
                img.onerror = function() {
                    // 如果图标加载失败,使用文字缩写
                    this.outerHTML = `<div style="width:16px;height:16px;display:flex;align-items:center;justify-content:center;background:#f0f0f0;border-radius:3px;font-size:10px;font-weight:bold;">${engine.name.charAt(0)}</div>`;
                };
                engineBtn.appendChild(img);
                
                // 添加搜索引擎名称
                engineBtn.appendChild(document.createTextNode(engine.name));
                
                // 如果启用快捷键,添加提示
                if (settings.keyboardShortcuts) {
                    const shortcutSpan = document.createElement('span');
                    shortcutSpan.className = 'shortcut';
                    shortcutSpan.textContent = `${modifierKey}${engine.shortcut}`;
                    engineBtn.appendChild(shortcutSpan);
                }
                
                engineContainer.appendChild(engineBtn);
            }
            
            // 如果没有其他搜索引擎按钮,添加一个提示
            if (engineContainer.children.length === 0) {
                const noEnginesMsg = document.createElement('div');
                noEnginesMsg.textContent = '没有其他可用的搜索引擎';
                noEnginesMsg.style.padding = '10px 0';
                noEnginesMsg.style.color = '#888';
                noEnginesMsg.style.fontSize = '12px';
                noEnginesMsg.style.textAlign = 'center';
                engineContainer.appendChild(noEnginesMsg);
            }
            
            switcher.appendChild(engineContainer);
            
            // 添加到页面
            document.body.appendChild(switcher);
            
            // 添加点击事件,防止冒泡
            switcher.addEventListener('click', function(e) {
                e.stopPropagation();
            });
            
            log('搜索引擎切换器UI已创建');
        } catch (error) {
            handleError(error, '创建搜索引擎切换器UI');
        }
    }
    
    // 显示设置面板
    function showSettingsPanel() {
        try {
            log('显示设置面板');
            
            // 获取当前设置
            const settings = loadSettings();
            
            // 创建设置覆盖层
            const settingsOverlay = document.createElement('div');
            settingsOverlay.className = 'settings-overlay';
            
            // 创建设置容器
            const settingsContainer = document.createElement('div');
            settingsContainer.className = 'settings-container';
            
            // 创建设置标题
            const settingsHeader = document.createElement('div');
            settingsHeader.className = 'settings-header';
            settingsHeader.textContent = '搜索引擎切换工具设置';
            settingsContainer.appendChild(settingsHeader);
            
            // 创建搜索引擎选择部分
            const enginesSection = document.createElement('div');
            enginesSection.className = 'settings-section';
            
            const enginesTitle = document.createElement('div');
            enginesTitle.className = 'section-title';
            enginesTitle.textContent = '选择要显示的搜索引擎:';
            enginesSection.appendChild(enginesTitle);
            
            const checkboxGroup = document.createElement('div');
            checkboxGroup.className = 'checkbox-group';
            
            // 添加每个搜索引擎的复选框
            defaultEngines.forEach(engine => {
                const label = document.createElement('label');
                
                const checkbox = document.createElement('input');
                checkbox.type = 'checkbox';
                checkbox.name = 'engine';
                checkbox.value = engine.name;
                checkbox.checked = settings.enabledEngines.includes(engine.name);
                label.appendChild(checkbox);
                
                label.appendChild(document.createTextNode(` ${engine.name}`));
                
                checkboxGroup.appendChild(label);
            });
            
            enginesSection.appendChild(checkboxGroup);
            settingsContainer.appendChild(enginesSection);
            
            // 创建快捷键部分
            const shortcutSection = document.createElement('div');
            shortcutSection.className = 'settings-section';
            
            const shortcutTitle = document.createElement('div');
            shortcutTitle.className = 'section-title';
            shortcutTitle.textContent = '快捷键设置:';
            shortcutSection.appendChild(shortcutTitle);
            
            const shortcutCheckbox = document.createElement('label');
            const shortcutInput = document.createElement('input');
            shortcutInput.type = 'checkbox';
            shortcutInput.name = 'keyboardShortcuts';
            shortcutInput.checked = settings.keyboardShortcuts;
            shortcutCheckbox.appendChild(shortcutInput);
            shortcutCheckbox.appendChild(document.createTextNode(' 启用键盘快捷键'));
            shortcutSection.appendChild(shortcutCheckbox);
            
            // Mac特定选项
            if (isMac) {
                const shortcutContent = document.createElement('div');
                shortcutContent.style.marginTop = '10px';
                shortcutContent.style.marginLeft = '20px';
                shortcutContent.style.display = settings.keyboardShortcuts ? 'block' : 'none';
                
                shortcutInput.addEventListener('change', function() {
                    shortcutContent.style.display = this.checked ? 'block' : 'none';
                });
                
                const shortcutDescription = document.createElement('div');
                shortcutDescription.textContent = '选择快捷键修饰键:';
                shortcutContent.appendChild(shortcutDescription);
                
                const macOptions = document.createElement('div');
                macOptions.className = 'mac-options';
                
                // Command选项
                const commandOption = document.createElement('label');
                commandOption.className = 'mac-option';
                
                const commandRadio = document.createElement('input');
                commandRadio.type = 'radio';
                commandRadio.name = 'macModifier';
                commandRadio.value = 'command';
                commandRadio.checked = settings.macModifierType === 'command';
                
                commandOption.appendChild(commandRadio);
                commandOption.appendChild(document.createTextNode(' ⌘ (Command)'));
                
                // Option选项
                const optionOption = document.createElement('label');
                optionOption.className = 'mac-option';
                
                const optionRadio = document.createElement('input');
                optionRadio.type = 'radio';
                optionRadio.name = 'macModifier';
                optionRadio.value = 'option';
                optionRadio.checked = settings.macModifierType === 'option';
                
                optionOption.appendChild(optionRadio);
                optionOption.appendChild(document.createTextNode(' ⌥ (Option)'));
                
                macOptions.appendChild(commandOption);
                macOptions.appendChild(optionOption);
                
                shortcutContent.appendChild(macOptions);
                shortcutSection.appendChild(shortcutContent);
            } else {
                const shortcutDescription = document.createElement('div');
                shortcutDescription.style.marginTop = '10px';
                shortcutDescription.style.marginLeft = '20px';
                shortcutDescription.style.display = settings.keyboardShortcuts ? 'block' : 'none';
                shortcutDescription.textContent = '按下 Alt + 快捷键字母 可快速切换搜索引擎';
                
                shortcutInput.addEventListener('change', function() {
                    shortcutDescription.style.display = this.checked ? 'block' : 'none';
                });
                
                shortcutSection.appendChild(shortcutDescription);
            }
            
            settingsContainer.appendChild(shortcutSection);
            
            // 创建折叠选项
            const collapseSection = document.createElement('div');
            collapseSection.className = 'settings-section';
            
            const collapseCheckbox = document.createElement('label');
            const collapseInput = document.createElement('input');
            collapseInput.type = 'checkbox';
            collapseInput.name = 'collapsed';
            collapseInput.checked = settings.collapsed;
            collapseCheckbox.appendChild(collapseInput);
            collapseCheckbox.appendChild(document.createTextNode(' 默认折叠'));
            
            collapseSection.appendChild(collapseCheckbox);
            settingsContainer.appendChild(collapseSection);
            
            // 创建按钮
            const actions = document.createElement('div');
            actions.className = 'settings-actions';
            
            const cancelButton = document.createElement('button');
            cancelButton.className = 'settings-button cancel-button';
            cancelButton.textContent = '取消';
            cancelButton.addEventListener('click', function() {
                settingsOverlay.remove();
            });
            
            const saveButton = document.createElement('button');
            saveButton.className = 'settings-button save-button';
            saveButton.textContent = '保存';
            saveButton.addEventListener('click', function() {
                // 收集设置
                const newSettings = {
                    enabledEngines: Array.from(
                        settingsContainer.querySelectorAll('input[name="engine"]:checked')
                    ).map(checkbox => checkbox.value),
                    keyboardShortcuts: settingsContainer.querySelector('input[name="keyboardShortcuts"]').checked,
                    collapsed: settingsContainer.querySelector('input[name="collapsed"]').checked
                };
                
                // Mac特定选项
                if (isMac) {
                    const macModifier = settingsContainer.querySelector('input[name="macModifier"]:checked');
                    newSettings.macModifierType = macModifier ? macModifier.value : 'command';
                }
                
                // 保存设置
                const success = saveSettings(newSettings);
                if (success) {
                    settingsOverlay.remove();
                    
                    // 刷新切换器界面
                    const switcher = document.getElementById('search-engine-switcher');
                    if (switcher) {
                        switcher.remove();
                    }
                    setTimeout(createSwitcherUI, 100);
                }
            });
            
            actions.appendChild(cancelButton);
            actions.appendChild(saveButton);
            
            settingsContainer.appendChild(actions);
            
            settingsOverlay.appendChild(settingsContainer);
            document.body.appendChild(settingsOverlay);
            
            // 点击外部区域关闭设置面板
            settingsOverlay.addEventListener('click', function(e) {
                if (e.target === settingsOverlay) {
                    settingsOverlay.remove();
                }
            });
            
            log('设置面板已显示');
        } catch (error) {
            handleError(error, '显示设置面板');
        }
    }
    
    // 设置键盘快捷键
    function setupKeyboardShortcuts() {
        try {
            const settings = loadSettings();
            if (!settings.keyboardShortcuts) {
                log('快捷键功能已禁用');
                return;
            }
            
            const { currentEngine, query } = getCurrentEngineAndQuery();
            if (!query) {
                log('没有查询词,不设置快捷键');
                return;
            }
            
            log('设置键盘快捷键');
            
            document.addEventListener('keydown', function(e) {
                // 检查修饰键是否按下
                let modifierPressed = false;
                
                if (isMac) {
                    if (settings.macModifierType === 'command') {
                        modifierPressed = e.metaKey;
                    } else if (settings.macModifierType === 'option') {
                        modifierPressed = e.altKey;
                    } else {
                        modifierPressed = e.metaKey;
                    }
                } else {
                    modifierPressed = e.altKey;
                }
                
                if (!modifierPressed) return;
                
                // 获取按下的键
                const key = e.key.toUpperCase();
                
                // 查找匹配的搜索引擎
                const targetEngine = getEnabledEngines().find(engine => 
                    engine.shortcut && engine.shortcut.toUpperCase() === key && 
                    (!currentEngine || engine.name !== currentEngine.name)
                );
                
                if (targetEngine) {
                    e.preventDefault();
                    switchToEngine(targetEngine, query);
                }
            });
            
            log('键盘快捷键已设置');
        } catch (error) {
            handleError(error, '设置键盘快捷键');
        }
    }
    
    // 设置DOM变化观察器
    function setupMutationObserver() {
        try {
            log('设置MutationObserver开始');
            // 创建一个观察器实例
            const observer = new MutationObserver(function(mutations) {
                // 检查是否需要重新创建UI
                const switcher = document.getElementById('search-engine-switcher');
                if (!switcher) {
                    log('MutationObserver: UI不存在,重新创建');
                    createSwitcherUI();
                }
            });
            
            // 更频繁地观察DOM变化
            const config = { childList: true, subtree: true };
            observer.observe(document.body, config);
            
            // 定期检查UI是否存在
            setInterval(() => {
                const switcher = document.getElementById('search-engine-switcher');
                if (!switcher) {
                    log('定期检查: UI不存在,重新创建');
                    createSwitcherUI();
                }
            }, 3000);
            
            log('MutationObserver已增强设置');
        } catch (error) {
            handleError(error, '设置MutationObserver');
        }
    }

    // 添加菜单项
    function setupUserMenu() {
        try {
            GM_registerMenuCommand('搜索引擎切换工具设置', showSettingsPanel);
            log('用户菜单已设置');
        } catch (error) {
            handleError(error, '设置用户菜单');
        }
    }

    // 初始化
    function initialize() {
        try {
            log('开始初始化搜索引擎切换助手');
            addStyles();
            setupUserMenu();
            setTimeout(createSwitcherUI, 100);
            setupKeyboardShortcuts();
            setupMutationObserver();
            log('初始化完成');
        } catch (error) {
            handleError(error, '初始化');
        }
    }

    // 立即执行初始化
    initialize();
    
    // 确保DOM加载后执行
    if (document.readyState !== 'complete') {
        document.addEventListener('DOMContentLoaded', function() {
            setTimeout(createSwitcherUI, 300);
        });
    }
    
    // 页面完全加载后再次执行
    window.addEventListener('load', function() {
        setTimeout(createSwitcherUI, 500);
    });
})(); 

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址