究极美化必应搜索页面(毛玻璃)(原生JS重构版)

美化必应搜索页面 (重构版 - 使用localStorage)

// ==UserScript==
// @name         究极美化必应搜索页面(毛玻璃)(原生JS重构版)
// @namespace    http://tampermonkey.net/
// @version      3.0.3
// @description  美化必应搜索页面 (重构版 - 使用localStorage)
// @author       Onion (重构优化版)
// @match        *://*.cn.bing.com/*
// @match        *://*.bing.com/*
// @match        *://*.baidu.com/*
// @icon         https://gitee.com/onion-big/gitstore/raw/main/js/jpg/beautify.png
// @license      MPL2.0
// @grant        GM_notification
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // ==================== 配置管理模块 ====================
    class ConfigManager {
        constructor() {
            this.storageKey = 'bing_beautify_config';
            this.cacheKey = 'bing_beautify_cache';
            this.defaultConfig = {
                blurLevel: 13,
                opacity1: 83, // 渐变色透明度 (0-100)
                opacity2: 75, // 图片透明度 (0-100)
                backgroundType: 'gradient', // 'gradient' | 'image' | 'custom'
                backgroundImage: this.getDefaultImages()[0],
                customImageBase64: '',
                searchboxStyle: 'transparent' // 'transparent' | 'colorful'
            };
            this.initConfig();
        }

        getDefaultImages() {
            return [
                "https://bing.biturl.top/?resolution=1920&format=image&index=0&mkt=zh-CN",
                "https://bing.com/th?id=OHR.NationalDay2022_ZH-CN3861603311_1920x1080.jpg",
                "https://bing.com/th?id=OHR.BridgeofSighs_ZH-CN5414607871_1920x1080.jpg",
                "https://images4.alphacoders.com/171/171916.jpg",
                "https://images5.alphacoders.com/613/613927.jpg",
                "https://images2.alphacoders.com/606/606275.jpg",
                "https://images2.alphacoders.com/742/742320.png",
                "https://dogefs.s3.ladydaily.com/~/source/wallhaven/full/8o/wallhaven-8o2dpj.png?w=2560&fmt=webp"
            ];
        }

        initConfig() {
            try {
                const stored = localStorage.getItem(this.storageKey);
                this.config = stored ? { ...this.defaultConfig, ...JSON.parse(stored) } : { ...this.defaultConfig };
                this.saveConfig();
            } catch (error) {
                console.error('配置初始化失败:', error);
                this.config = { ...this.defaultConfig };
                this.saveConfig();
            }
        }

        get(key) {
            return this.config[key];
        }

        set(key, value) {
            this.config[key] = value;
            this.saveConfig();
        }

        update(updates) {
            Object.assign(this.config, updates);
            this.saveConfig();
        }

        saveConfig() {
            try {
                localStorage.setItem(this.storageKey, JSON.stringify(this.config));
            } catch (error) {
                console.error('配置保存失败:', error);
            }
        }

        reset() {
            this.config = { ...this.defaultConfig };
            this.saveConfig();
        }

        // 透明度转换:0-100 转为 0-255 的十六进制
        opacityToHex(opacity) {
            const value = Math.round((opacity / 100) * 255);
            return value.toString(16).padStart(2, '0');
        }

        // 十六进制转透明度:0-255 转为 0-100
        hexToOpacity(hex) {
            if (!hex) return 80;
            const value = parseInt(hex, 16);
            return Math.round((value / 255) * 100);
        }

        // 图片缓存管理
        getCachedImage(url) {
            try {
                const cache = JSON.parse(localStorage.getItem(this.cacheKey) || '{}');
                const cached = cache[url];
                
                // 必应每日壁纸需要每日更新
                if (url.includes('bing.biturl.top') && cached) {
                    const today = new Date().toDateString();
                    if (cached.date !== today) {
                        delete cache[url];
                        localStorage.setItem(this.cacheKey, JSON.stringify(cache));
                        return null;
                    }
                }
                
                return cached?.data || null;
            } catch (error) {
                console.error('获取缓存图片失败:', error);
                return null;
            }
        }

        setCachedImage(url, base64Data) {
            try {
                const cache = JSON.parse(localStorage.getItem(this.cacheKey) || '{}');
                cache[url] = {
                    data: base64Data,
                    date: new Date().toDateString(),
                    timestamp: Date.now()
                };
                
                // 清理过期缓存(30天前)
                const expireTime = Date.now() - (30 * 24 * 60 * 60 * 1000);
                Object.keys(cache).forEach(key => {
                    if (cache[key].timestamp < expireTime) {
                        delete cache[key];
                    }
                });
                
                localStorage.setItem(this.cacheKey, JSON.stringify(cache));
            } catch (error) {
                console.error('缓存图片失败:', error);
            }
        }

        // 将图片转换为base64存储
        async convertImageToBase64(imageUrl) {
            try {
                // 先检查缓存
                const cached = this.getCachedImage(imageUrl);
                if (cached) {
                    console.log('使用缓存图片:', imageUrl);
                    return cached;
                }

                console.log('下载并缓存图片:', imageUrl);
                const response = await fetch(imageUrl);
                const blob = await response.blob();
                
                return new Promise((resolve, reject) => {
                    const reader = new FileReader();
                    reader.onloadend = () => {
                        const result = reader.result;
                        // 缓存图片
                        this.setCachedImage(imageUrl, result);
                        resolve(result);
                    };
                    reader.onerror = reject;
                    reader.readAsDataURL(blob);
                });
            } catch (error) {
                console.error('图片转换base64失败:', error);
                return null;
            }
        }
    }

    // ==================== 样式管理模块 ====================
    class StyleManager {
        constructor(config) {
            this.config = config;
            this.injectedStyles = new Set();
        }

        injectGlobalStyles() {
            const css = `
                @keyframes fadeIn {
                    0% { opacity: 0; transform: translateY(-10px); }
                    100% { opacity: 1; transform: translateY(0); }
                }

                /* 设置框样式 - 强制最高优先级 */
                .beautify-settings {
                    position: fixed !important;
                    top: 50% !important;
                    left: 50% !important;
                    transform: translate(-50%, -50%) !important;
                    width: min(520px, 95vw) !important;
                    max-height: 85vh !important;
                    background: rgba(255, 255, 255, 0.98) !important;
                    backdrop-filter: blur(20px) !important;
                    border-radius: 15px !important;
                    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.3) !important;
                    z-index: 999999999 !important;
                    padding: 0 !important;
                    margin: 0 !important;
                    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif !important;
                    display: none !important;
                    animation: fadeIn 0.3s ease-out !important;
                    border: 2px solid rgba(76, 175, 80, 0.3) !important;
                    overflow: hidden !important;
                    pointer-events: auto !important;
                }

                .beautify-settings.show {
                    display: block !important;
                    visibility: visible !important;
                    opacity: 1 !important;
                }

                .beautify-settings-header {
                    display: flex !important;
                    justify-content: space-between !important;
                    align-items: center !important;
                    padding: 15px 20px !important;
                    border-bottom: 1px solid rgba(0, 0, 0, 0.1) !important;
                    cursor: move !important;
                    background: rgba(76, 175, 80, 0.1) !important;
                    border-radius: 15px 15px 0 0 !important;
                    flex-shrink: 0 !important;
                }

                .beautify-settings-title {
                    font-size: 16px !important;
                    font-weight: 600 !important;
                    color: #333 !important;
                    margin: 0 !important;
                    white-space: nowrap !important;
                }

                .beautify-close-btn {
                    background: rgba(255, 0, 0, 0.1) !important;
                    border: none !important;
                    font-size: 20px !important;
                    cursor: pointer !important;
                    color: #666 !important;
                    padding: 5px !important;
                    width: 30px !important;
                    height: 30px !important;
                    display: flex !important;
                    align-items: center !important;
                    justify-content: center !important;
                    border-radius: 50% !important;
                    transition: all 0.2s ease !important;
                    flex-shrink: 0 !important;
                }

                .beautify-close-btn:hover {
                    background: rgba(255, 0, 0, 0.2) !important;
                    color: #ff0000 !important;
                    transform: scale(1.1) !important;
                }

                .beautify-settings-content {
                    padding: 20px !important;
                    max-height: calc(85vh - 120px) !important;
                    overflow-y: auto !important;
                    background: rgba(255, 255, 255, 0.95) !important;
                    border-radius: 0 0 15px 15px !important;
                }

                .beautify-form-group {
                    margin-bottom: 18px !important;
                }

                .beautify-form-group:last-child {
                    margin-bottom: 0 !important;
                }

                .beautify-label {
                    display: block !important;
                    margin-bottom: 8px !important;
                    font-size: 14px !important;
                    font-weight: 500 !important;
                    color: #555 !important;
                    white-space: nowrap !important;
                    overflow: hidden !important;
                    text-overflow: ellipsis !important;
                }

                .beautify-input, .beautify-select {
                    width: 100% !important;
                    padding: 10px 12px !important;
                    border: 2px solid rgba(0, 0, 0, 0.1) !important;
                    border-radius: 8px !important;
                    font-size: 14px !important;
                    background: white !important;
                    transition: border-color 0.2s ease !important;
                    box-sizing: border-box !important;
                }

                .beautify-input:focus, .beautify-select:focus {
                    outline: none !important;
                    border-color: #4CAF50 !important;
                }

                /* 滑块样式 */
                .beautify-slider-container {
                    display: flex !important;
                    align-items: center !important;
                    gap: 10px !important;
                }

                .beautify-slider {
                    flex: 1 !important;
                    height: 6px !important;
                    background: #ddd !important;
                    border-radius: 3px !important;
                    outline: none !important;
                    border: none !important;
                }

                .beautify-slider::-webkit-slider-thumb {
                    appearance: none !important;
                    width: 18px !important;
                    height: 18px !important;
                    background: #4CAF50 !important;
                    border-radius: 50% !important;
                    cursor: pointer !important;
                }

                .beautify-slider::-moz-range-thumb {
                    width: 18px !important;
                    height: 18px !important;
                    background: #4CAF50 !important;
                    border-radius: 50% !important;
                    cursor: pointer !important;
                    border: none !important;
                }

                .beautify-value-display {
                    min-width: 45px !important;
                    text-align: right !important;
                    font-size: 12px !important;
                    color: #666 !important;
                    background: rgba(0, 0, 0, 0.05) !important;
                    padding: 4px 8px !important;
                    border-radius: 4px !important;
                }

                .beautify-button-group {
                    display: flex !important;
                    gap: 10px !important;
                    margin-top: 20px !important;
                    padding-top: 15px !important;
                    border-top: 1px solid rgba(0, 0, 0, 0.1) !important;
                }

                .beautify-btn {
                    flex: 1 !important;
                    padding: 10px 16px !important;
                    border: none !important;
                    border-radius: 8px !important;
                    font-size: 13px !important;
                    font-weight: 500 !important;
                    cursor: pointer !important;
                    transition: all 0.2s ease !important;
                }

                .beautify-btn-primary {
                    background: #4CAF50 !important;
                    color: white !important;
                }

                .beautify-btn-primary:hover {
                    background: #45a049 !important;
                    transform: translateY(-1px) !important;
                }

                .beautify-btn-secondary {
                    background: #f5f5f5 !important;
                    color: #666 !important;
                }

                .beautify-btn-secondary:hover {
                    background: #e5e5e5 !important;
                    transform: translateY(-1px) !important;
                }

                /* 搜索框控制按钮 */
                .beautify-control-buttons {
                    display: flex !important;
                    gap: 5px !important;
                }

                .beautify-control-btn {
                    padding: 8px 12px !important;
                    background: rgba(255, 255, 255, 0.9) !important;
                    border: 1px solid rgba(0, 0, 0, 0.1) !important;
                    border-radius: 6px !important;
                    font-size: 12px !important;
                    cursor: pointer !important;
                    transition: all 0.2s ease !important;
                    color: #444 !important;
                    backdrop-filter: blur(10px) !important;
                }

                .beautify-control-btn:hover {
                    background: rgba(255, 255, 255, 1) !important;
                    transform: translateY(-1px) !important;
                    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important;
                }

                .beautify-control-btn.active {
                    background: #4CAF50 !important;
                    color: white !important;
                }

                /* 透明化处理 */
                .pagereco_CB, .pagereco_CBImageCard, .pagereco_CBTextCard, 
                #tabcontrol_8_156412_navr, #lMapContainer, .b_algoSlug .algoSlug_icon, 
                #b_PagAboveFooter, .tta_incell, .tta_outcell, #tta_output_ta {
                    background: transparent !important;
                    border: none !important;
                }

                /* Header 统一背景 */
                #b_header {
                    border-bottom: none !important;
                    background: transparent !important;
                }

                .b_searchboxForm {
                    background: rgba(255, 255, 255, 0.8) !important;
                    backdrop-filter: blur(10px) !important;
                    border-radius: 25px !important;
                }

                /* 结果框样式 */
                .b_algo, .b_ans {
                    border-radius: 10px !important;
                    backdrop-filter: blur(${this.config.get('blurLevel')}px) !important;
                    margin-bottom: 15px !important;
                    transition: all 0.3s ease !important;
                }

                .b_algo:hover, .b_ans:hover {
                    transform: translateY(-2px) !important;
                    box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1) !important;
                }

                /* 文件上传样式 */
                .beautify-file-upload {
                    position: relative !important;
                    display: inline-block !important;
                    width: 100% !important;
                }

                .beautify-file-input {
                    position: absolute !important;
                    opacity: 0 !important;
                    width: 100% !important;
                    height: 100% !important;
                    cursor: pointer !important;
                }

                .beautify-file-label {
                    display: block !important;
                    padding: 12px 15px !important;
                    border: 2px dashed rgba(0, 0, 0, 0.2) !important;
                    border-radius: 8px !important;
                    text-align: center !important;
                    cursor: pointer !important;
                    transition: all 0.2s ease !important;
                    background: rgba(0, 0, 0, 0.02) !important;
                    font-size: 13px !important;
                }

                .beautify-file-label:hover {
                    border-color: #4CAF50 !important;
                    background: rgba(76, 175, 80, 0.05) !important;
                }

                /* 遮罩层 */
                .beautify-overlay {
                    position: fixed !important;
                    top: 0 !important;
                    left: 0 !important;
                    width: 100vw !important;
                    height: 100vh !important;
                    background: rgba(0, 0, 0, 0.3) !important;
                    z-index: 999999998 !important;
                    display: none !important;
                }

                .beautify-overlay.show {
                    display: block !important;
                }
            `;

            this.injectCSS('global-styles', css);
        }

        injectCSS(id, css) {
            if (this.injectedStyles.has(id)) return;
            
            const style = document.createElement('style');
            style.id = id;
            style.textContent = css;
            (document.head || document.documentElement).appendChild(style);
            this.injectedStyles.add(id);
        }

        updateResultBoxStyles() {
            const opacity1 = this.config.get('opacity1');
            const opacity2 = this.config.get('opacity2');
            
            const opacity = this.config.get('backgroundType') === 'image' ? opacity2 : opacity1;
            const alpha = opacity / 100;
            
            const elements = document.querySelectorAll('.b_algo, .b_ans');
            elements.forEach(el => {
                el.style.backgroundColor = `rgba(255, 255, 255, ${alpha})`;
                el.style.backdropFilter = `blur(${this.config.get('blurLevel')}px)`;
            });
        }

        updateSearchboxStyle() {
            const searchboxForm = document.querySelector('.b_searchboxForm');
            if (!searchboxForm) return;

            const style = this.config.get('searchboxStyle');
            const opacity2 = this.config.get('opacity2') / 100;
            
            if (style === 'transparent') {
                searchboxForm.style.background = `rgba(255, 255, 255, ${opacity2})`;
                searchboxForm.style.backgroundImage = 'none';
            } else if (style === 'colorful') {
                searchboxForm.style.backgroundImage = 'linear-gradient(to right, rgb(255, 221, 238), skyblue)';
                searchboxForm.style.background = 'none';
            }
        }

        async updateHeaderBackground() {
            // 统一header背景
            const header = document.getElementById('b_header');
            if (!header) return;

            const backgroundType = this.config.get('backgroundType');
            let backgroundImage = '';

            switch (backgroundType) {
                case 'gradient':
                    backgroundImage = 'linear-gradient(to right, #FFDDEE, skyblue)';
                    break;
                case 'image':
                    const imageUrl = this.config.get('backgroundImage');
                    const cachedImage = await this.config.convertImageToBase64(imageUrl);
                    backgroundImage = `url(${cachedImage || imageUrl})`;
                    break;
                case 'custom':
                    const base64Image = this.config.get('customImageBase64');
                    if (base64Image) {
                        backgroundImage = `url(${base64Image})`;
                    } else {
                        backgroundImage = 'linear-gradient(to right, #FFDDEE, skyblue)';
                    }
                    break;
            }

            header.style.background = backgroundImage;
            header.style.backgroundSize = 'cover';
            header.style.backgroundPosition = 'center';
            header.style.backgroundAttachment = 'fixed';
        }
    }

    // ==================== 背景管理模块 ====================
    class BackgroundManager {
        constructor(config) {
            this.config = config;
        }

        async applyBackground() {
            const container = document.getElementById('b_content') || document.documentElement;
            const backgroundType = this.config.get('backgroundType');

            // 清除之前的背景设置
            container.style.backgroundImage = '';
            container.style.backgroundColor = '';
            document.documentElement.style.background = '';

            switch (backgroundType) {
                case 'gradient':
                    this.applyGradientBackground(container);
                    break;
                case 'image':
                    await this.applyImageBackground(container);
                    break;
                case 'custom':
                    this.applyCustomBackground(container);
                    break;
            }
        }

        applyGradientBackground(container) {
            container.style.backgroundImage = 'linear-gradient(to right, #FFDDEE, skyblue)';
            container.style.backgroundAttachment = 'fixed';
        }

        async applyImageBackground(container) {
            const imageUrl = this.config.get('backgroundImage');
            
            // 尝试使用缓存的base64图片
            const cachedImage = await this.config.convertImageToBase64(imageUrl);
            if (cachedImage) {
                container.style.background = `url(${cachedImage}) center/cover fixed`;
            } else {
                // 回退到直接URL
                container.style.background = `url(${imageUrl}) center/cover fixed`;
            }
        }

        applyCustomBackground(container) {
            const base64Image = this.config.get('customImageBase64');
            if (base64Image) {
                container.style.background = `url(${base64Image}) center/cover fixed`;
            } else {
                this.applyGradientBackground(container); // 回退到渐变色
            }
        }

        // 为百度设置特殊背景
        applyBaiduBackground() {
            const wrapper = document.getElementById('wrapper_wrapper');
            if (wrapper) {
                const imageUrl = this.config.get('backgroundImage');
                wrapper.style.background = `url(${imageUrl}) center/cover fixed`;
            }
        }
    }

    // ==================== UI管理模块 ====================
    class UIManager {
        constructor(config, styleManager, backgroundManager) {
            this.config = config;
            this.styleManager = styleManager;
            this.backgroundManager = backgroundManager;
            this.settingsPanel = null;
            this.overlay = null;
            this.dragData = { isDragging: false, offset: { x: 0, y: 0 } };
        }

        createControlButtons() {
            const scopebar = document.querySelector('.b_scopebar');
            if (!scopebar || !scopebar.children[0]) return;

            const controlContainer = document.createElement('div');
            controlContainer.className = 'beautify-control-buttons';
            
            const buttons = [
                { text: '透明', action: () => this.setSearchboxStyle('transparent') },
                { text: '炫彩', action: () => this.setSearchboxStyle('colorful') },
                { text: '渐变', action: () => this.setBackgroundType('gradient') },
                { text: '图片', action: () => this.setBackgroundType('image') }
            ];

            buttons.forEach(btn => {
                const button = document.createElement('button');
                button.className = 'beautify-control-btn';
                button.textContent = btn.text;
                button.addEventListener('click', btn.action);
                controlContainer.appendChild(button);
            });

            // 设置按钮
            const settingsBtn = document.createElement('button');
            settingsBtn.className = 'beautify-control-btn';
            settingsBtn.textContent = '⚙️';
            settingsBtn.style.fontSize = '16px';
            settingsBtn.addEventListener('click', () => {
                console.log('设置按钮被点击了');
                this.showSettingsPanel();
            });
            
            const headerNav = document.getElementById('id_h');
            if (headerNav) {
                headerNav.appendChild(settingsBtn);
            } else {
                // 如果找不到id_h,就添加到控制按钮组里
                controlContainer.appendChild(settingsBtn);
            }

            scopebar.children[0].appendChild(controlContainer);
        }

        async setSearchboxStyle(style) {
            this.config.set('searchboxStyle', style);
            this.styleManager.updateSearchboxStyle();
            this.updateActiveButtons();
        }

        async setBackgroundType(type) {
            this.config.set('backgroundType', type);
            await this.backgroundManager.applyBackground();
            await this.styleManager.updateHeaderBackground();
            this.styleManager.updateResultBoxStyles();
            this.updateActiveButtons();
        }

        updateActiveButtons() {
            // 更新按钮激活状态
            document.querySelectorAll('.beautify-control-btn').forEach(btn => {
                btn.classList.remove('active');
            });

            const searchboxStyle = this.config.get('searchboxStyle');
            const backgroundType = this.config.get('backgroundType');
            
            document.querySelectorAll('.beautify-control-btn').forEach(btn => {
                if ((btn.textContent === '透明' && searchboxStyle === 'transparent') ||
                    (btn.textContent === '炫彩' && searchboxStyle === 'colorful') ||
                    (btn.textContent === '渐变' && backgroundType === 'gradient') ||
                    (btn.textContent === '图片' && backgroundType === 'image')) {
                    btn.classList.add('active');
                }
            });
        }

        createOverlay() {
            if (this.overlay) return;
            
            this.overlay = document.createElement('div');
            this.overlay.className = 'beautify-overlay';
            this.overlay.addEventListener('click', () => this.hideSettingsPanel());
            document.body.appendChild(this.overlay);
        }

        createSettingsPanel() {
            console.log('创建设置面板');
            if (this.settingsPanel) {
                console.log('设置面板已存在');
                return;
            }

            // 创建遮罩层
            this.createOverlay();

            const panel = document.createElement('div');
            panel.className = 'beautify-settings';
            panel.innerHTML = `
                <div class="beautify-settings-header">
                    <h3 class="beautify-settings-title">🎨 美化设置</h3>
                    <button class="beautify-close-btn" type="button">×</button>
                </div>
                <div class="beautify-settings-content">
                    <div class="beautify-form-group">
                        <label class="beautify-label">模糊度 (0-100)</label>
                        <div class="beautify-slider-container">
                            <input type="range" class="beautify-input beautify-slider" id="blur-slider" 
                                   min="0" max="100" value="${this.config.get('blurLevel')}">
                            <span class="beautify-value-display" id="blur-value">${this.config.get('blurLevel')}px</span>
                        </div>
                    </div>
                    
                    <div class="beautify-form-group">
                        <label class="beautify-label">渐变色透明度 (0-100)</label>
                        <div class="beautify-slider-container">
                            <input type="range" class="beautify-input beautify-slider" id="opacity1-slider" 
                                   min="0" max="100" value="${this.config.get('opacity1')}">
                            <span class="beautify-value-display" id="opacity1-value">${this.config.get('opacity1')}%</span>
                        </div>
                    </div>
                    
                    <div class="beautify-form-group">
                        <label class="beautify-label">图片背景透明度 (0-100)</label>
                        <div class="beautify-slider-container">
                            <input type="range" class="beautify-input beautify-slider" id="opacity2-slider" 
                                   min="0" max="100" value="${this.config.get('opacity2')}">
                            <span class="beautify-value-display" id="opacity2-value">${this.config.get('opacity2')}%</span>
                        </div>
                    </div>
                    
                    <div class="beautify-form-group">
                        <label class="beautify-label">背景类型</label>
                        <select class="beautify-select" id="background-type">
                            <option value="gradient" ${this.config.get('backgroundType') === 'gradient' ? 'selected' : ''}>渐变色</option>
                            <option value="image" ${this.config.get('backgroundType') === 'image' ? 'selected' : ''}>预设图片</option>
                            <option value="custom" ${this.config.get('backgroundType') === 'custom' ? 'selected' : ''}>自定义图片</option>
                        </select>
                    </div>
                    
                    <div class="beautify-form-group">
                        <label class="beautify-label">预设图片</label>
                        <select class="beautify-select" id="background-image">
                            ${this.createImageOptions()}
                        </select>
                    </div>
                    
                    <div class="beautify-form-group">
                        <label class="beautify-label">上传自定义图片</label>
                        <div class="beautify-file-upload">
                            <input type="file" class="beautify-file-input" id="custom-image" accept="image/*">
                            <label for="custom-image" class="beautify-file-label">
                                📷 点击选择图片文件
                            </label>
                        </div>
                    </div>
                    
                    <div class="beautify-button-group">
                        <button class="beautify-btn beautify-btn-secondary" id="reset-btn">🔄 重置</button>
                        <button class="beautify-btn beautify-btn-primary" id="save-btn">💾 保存</button>
                    </div>
                </div>
            `;

            document.body.appendChild(panel);
            this.settingsPanel = panel;
            console.log('设置面板已添加到DOM');
            this.setupPanelEvents();
        }

        createImageOptions() {
            const images = this.config.getDefaultImages();
            return images.map((url, index) => {
                const selected = url === this.config.get('backgroundImage') ? 'selected' : '';
                const label = index === 0 ? '必应每日壁纸' : `预设图片 ${index}`;
                return `<option value="${url}" ${selected}>${label}</option>`;
            }).join('');
        }

        setupPanelEvents() {
            const panel = this.settingsPanel;
            
            // 关闭按钮
            panel.querySelector('.beautify-close-btn').addEventListener('click', () => {
                this.hideSettingsPanel();
            });

            // 拖拽功能
            const header = panel.querySelector('.beautify-settings-header');
            this.setupDragEvents(header, panel);

            // 模糊度滑块
            const blurSlider = panel.querySelector('#blur-slider');
            const blurValue = panel.querySelector('#blur-value');
            blurSlider.addEventListener('input', (e) => {
                const value = e.target.value;
                blurValue.textContent = `${value}px`;
            });

            // 透明度1滑块
            const opacity1Slider = panel.querySelector('#opacity1-slider');
            const opacity1Value = panel.querySelector('#opacity1-value');
            opacity1Slider.addEventListener('input', (e) => {
                const value = e.target.value;
                opacity1Value.textContent = `${value}%`;
            });

            // 透明度2滑块
            const opacity2Slider = panel.querySelector('#opacity2-slider');
            const opacity2Value = panel.querySelector('#opacity2-value');
            opacity2Slider.addEventListener('input', (e) => {
                const value = e.target.value;
                opacity2Value.textContent = `${value}%`;
            });

            // 自定义图片上传
            panel.querySelector('#custom-image').addEventListener('change', (e) => {
                this.handleImageUpload(e.target.files[0]);
            });

            // 保存按钮
            panel.querySelector('#save-btn').addEventListener('click', () => {
                this.saveSettings();
            });

            // 重置按钮
            panel.querySelector('#reset-btn').addEventListener('click', () => {
                this.resetSettings();
            });
        }

        setupDragEvents(handle, element) {
            handle.addEventListener('mousedown', (e) => {
                this.dragData.isDragging = true;
                this.dragData.offset.x = e.clientX - element.offsetLeft;
                this.dragData.offset.y = e.clientY - element.offsetTop;
                handle.style.cursor = 'grabbing';
            });

            document.addEventListener('mousemove', (e) => {
                if (!this.dragData.isDragging) return;
                
                const x = e.clientX - this.dragData.offset.x;
                const y = e.clientY - this.dragData.offset.y;
                
                element.style.left = `${x}px`;
                element.style.top = `${y}px`;
                element.style.transform = 'none';
            });

            document.addEventListener('mouseup', () => {
                this.dragData.isDragging = false;
                handle.style.cursor = 'move';
            });
        }

        async handleImageUpload(file) {
            if (!file) return;

            try {
                const base64 = await this.fileToBase64(file);
                this.config.set('customImageBase64', base64);
                GM_notification({ text: '图片上传成功!', timeout: 2000 });
            } catch (error) {
                console.error('图片上传失败:', error);
                GM_notification({ text: '图片上传失败,请重试', timeout: 3000 });
            }
        }

        fileToBase64(file) {
            return new Promise((resolve, reject) => {
                const reader = new FileReader();
                reader.onload = () => resolve(reader.result);
                reader.onerror = reject;
                reader.readAsDataURL(file);
            });
        }

        async saveSettings() {
            const panel = this.settingsPanel;
            
            const updates = {
                blurLevel: parseInt(panel.querySelector('#blur-slider').value),
                opacity1: parseInt(panel.querySelector('#opacity1-slider').value),
                opacity2: parseInt(panel.querySelector('#opacity2-slider').value),
                backgroundType: panel.querySelector('#background-type').value,
                backgroundImage: panel.querySelector('#background-image').value
            };

            this.config.update(updates);
            await this.backgroundManager.applyBackground();
            await this.styleManager.updateHeaderBackground();
            this.styleManager.updateResultBoxStyles();
            this.styleManager.updateSearchboxStyle();
            this.updateActiveButtons();
            
            GM_notification({ text: '设置已保存!', timeout: 2000 });
            this.hideSettingsPanel();
        }

        async resetSettings() {
            this.config.reset();
            await this.backgroundManager.applyBackground();
            await this.styleManager.updateHeaderBackground();
            this.styleManager.updateResultBoxStyles();
            this.styleManager.updateSearchboxStyle();
            this.updateActiveButtons();
            
            GM_notification({ text: '设置已重置为默认值!', timeout: 2000 });
            this.hideSettingsPanel();
        }

        showSettingsPanel() {
            console.log('显示设置面板');
            if (!this.settingsPanel) {
                this.createSettingsPanel();
            }
            
            // 强制显示
            this.overlay.classList.add('show');
            this.settingsPanel.classList.add('show');
            this.settingsPanel.style.display = 'block';
            this.settingsPanel.style.visibility = 'visible';
            this.settingsPanel.style.opacity = '1';
            this.settingsPanel.style.zIndex = '999999999';
            
            console.log('设置面板显示状态:', this.settingsPanel.style.display);
        }

        hideSettingsPanel() {
            if (this.settingsPanel) {
                this.settingsPanel.classList.remove('show');
                this.settingsPanel.style.display = 'none';
            }
            if (this.overlay) {
                this.overlay.classList.remove('show');
            }
        }
    }

    // ==================== 增强功能模块 ====================
    class EnhancementManager {
        constructor(config) {
            this.config = config;
        }

        enhanceSearchBox() {
            const searchBox = document.querySelector('.b_searchbox');
            if (!searchBox) return;

            // 搜索框获得焦点时扩展宽度
            searchBox.addEventListener('focus', () => {
                searchBox.style.transition = 'all 0.3s ease';
                searchBox.style.width = '600px';
            });

            // 点击页面其他地方时恢复宽度
            document.addEventListener('click', (e) => {
                if (!e.target.closest('.b_searchboxForm')) {
                    searchBox.style.width = '';
                }
            });
        }

        enhanceResults() {
            // 结果框悬停效果已在CSS中处理
            this.fixResultOverflow();
            this.cleanupFooter();
        }

        fixResultOverflow() {
            // 修复相关搜索框宽度
            const relatedBox = document.querySelector('.b_rrsr .b_vlist2col');
            if (relatedBox?.children[0]?.children[1]) {
                Array.from(relatedBox.children[0].children[1].children)
                    .forEach(item => item.style.width = '45%');
            }

            // 修复其他溢出问题
            const brsv3 = document.getElementById('brsv3');
            if (brsv3?.children[1]) {
                Array.from(brsv3.children[1].children)
                    .forEach(item => item.style.width = '45%');
            }
        }

        cleanupFooter() {
            const footer = document.getElementById('b_footer');
            if (footer) {
                footer.style.background = 'rgba(0, 0, 0, 0.8)';
                footer.style.backdropFilter = 'blur(10px)';
            }

            const mfaSrch = document.getElementById('mfa_srch');
            if (mfaSrch) {
                mfaSrch.style.backdropFilter = 'blur(10px)';
                mfaSrch.style.background = 'transparent';
            }
        }

        setupKeyboardShortcuts() {
            document.addEventListener('keydown', (e) => {
                // Ctrl + / 打开设置
                if (e.ctrlKey && e.code === 'Slash') {
                    e.preventDefault();
                    const settingsBtn = document.querySelector('.beautify-control-btn[textContent="⚙️"]');
                    if (settingsBtn) settingsBtn.click();
                }
            });
        }

        cleanupOtherElements() {
            // 清理其他元素的背景
            const selectors = [
                '.qna_algo', '.slide', '.nws_cwrp', '.mc_vhvc_th', '.na_ccw'
            ];

            selectors.forEach(selector => {
                document.querySelectorAll(selector).forEach(el => {
                    el.style.background = 'transparent';
                    if (el.children[0]) {
                        el.children[0].style.background = 'transparent';
                    }
                });
            });
        }
    }

    // ==================== 主应用类 ====================
    class BingBeautifier {
        constructor() {
            this.config = new ConfigManager();
            this.styleManager = new StyleManager(this.config);
            this.backgroundManager = new BackgroundManager(this.config);
            this.uiManager = new UIManager(this.config, this.styleManager, this.backgroundManager);
            this.enhancementManager = new EnhancementManager(this.config);
        }

        init() {
            console.log('初始化美化脚本');
            // 根据不同域名执行不同逻辑
            if (this.isBingSearch()) {
                this.initBing();
            } else if (this.isBaidu()) {
                this.initBaidu();
            }
        }

        isBingSearch() {
            return window.location.href.includes('bing.com/search');
        }

        isBaidu() {
            return window.location.href.includes('baidu.com');
        }

        async initBing() {
            console.log('初始化必应美化');
            
            // 立即注入基础样式
            this.styleManager.injectGlobalStyles();
            
            // 使用async/await优化异步操作
            const initializeUI = async () => {
                // 应用背景
                await this.backgroundManager.applyBackground();
                
                // 更新header背景
                await this.styleManager.updateHeaderBackground();
                
                // 更新样式
                this.styleManager.updateResultBoxStyles();
                this.styleManager.updateSearchboxStyle();
                
                // 增强功能
                this.enhancementManager.enhanceSearchBox();
                this.enhancementManager.enhanceResults();
                this.enhancementManager.setupKeyboardShortcuts();
                this.enhancementManager.cleanupOtherElements();
            };

            // 检查DOM是否准备好
            const checkAndInit = async () => {
                const scopebar = document.querySelector('.b_scopebar');
                if (scopebar) {
                    // 创建UI控件
                    this.uiManager.createControlButtons();
                    this.uiManager.updateActiveButtons();
                    await initializeUI();
                    console.log('必应搜索美化已应用');
                } else {
                    // 如果DOM还没准备好,稍后再试
                    setTimeout(checkAndInit, 100);
                }
            };

            // 立即执行基础初始化
            await initializeUI();
            
            // 检查并创建UI控件
            checkAndInit();
        }

        initBaidu() {
            // 简单的百度页面美化
            this.backgroundManager.applyBaiduBackground();
            console.log('百度页面美化已应用');
        }
    }

    // ==================== 初始化 ====================
    function main() {
        try {
            const beautifier = new BingBeautifier();
            beautifier.init();
        } catch (error) {
            console.error('美化脚本初始化失败:', error);
        }
    }

    // 等待DOM加载完成
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', main);
    } else {
        main();
    }

    // 错误处理
    window.addEventListener('error', (e) => {
        console.error('脚本运行时错误:', e.error);
    }, true);

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