智能护眼模式

根据时间自动调整页面亮度和色温,支持手动调节

// ==UserScript==
// @name         智能护眼模式
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  根据时间自动调整页面亮度和色温,支持手动调节
// @author       Trae AI Assistant
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @license MIT
// ==/UserScript==

(function() {
    'use strict';

    // 默认配置
    const defaultConfig = {
        autoMode: true,
        brightness: 100,
        blueLight: 0,
        contrast: 100,
        nightModeStart: 20, // 晚上8点
        nightModeEnd: 6,    // 早上6点
        nightBrightness: 70,
        nightBlueLight: 50
    };

    // 获取配置
    function getConfig() {
        const saved = GM_getValue('eyeProtectionConfig', JSON.stringify(defaultConfig));
        return JSON.parse(saved);
    }

    // 保存配置
    function saveConfig(config) {
        GM_setValue('eyeProtectionConfig', JSON.stringify(config));
    }

    // 创建控制面板
    function createControlPanel() {
        const panel = document.createElement('div');
        panel.id = 'eye-protection-panel';
        panel.innerHTML = `
            <div class="ep-header">
                <span>👁️ 护眼模式</span>
                <button id="ep-toggle">×</button>
            </div>
            <div class="ep-content">
                <div class="ep-item">
                    <label>
                        <input type="checkbox" id="ep-auto"> 自动模式
                    </label>
                </div>
                <div class="ep-item">
                    <label>亮度: <span id="ep-brightness-val">100</span>%</label>
                    <input type="range" id="ep-brightness" min="20" max="100" value="100">
                </div>
                <div class="ep-item">
                    <label>蓝光过滤: <span id="ep-bluelight-val">0</span>%</label>
                    <input type="range" id="ep-bluelight" min="0" max="80" value="0">
                </div>
                <div class="ep-item">
                    <label>对比度: <span id="ep-contrast-val">100</span>%</label>
                    <input type="range" id="ep-contrast" min="50" max="150" value="100">
                </div>
                <div class="ep-item">
                    <button id="ep-reset">重置</button>
                    <button id="ep-preset-night">夜间模式</button>
                </div>
            </div>
        `;

        // 添加样式
        GM_addStyle(`
            #eye-protection-panel {
                position: fixed;
                top: 50px;
                right: 20px;
                width: 280px;
                background: rgba(255, 255, 255, 0.95);
                border: 1px solid #ddd;
                border-radius: 8px;
                box-shadow: 0 4px 20px rgba(0,0,0,0.1);
                z-index: 10000;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
                backdrop-filter: blur(10px);
                transform: translateX(300px);
                transition: transform 0.3s ease;
            }
            
            #eye-protection-panel.show {
                transform: translateX(0);
            }
            
            .ep-header {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: 12px 16px;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
                border-radius: 8px 8px 0 0;
                font-weight: 500;
            }
            
            #ep-toggle {
                background: none;
                border: none;
                color: white;
                font-size: 18px;
                cursor: pointer;
                padding: 0;
                width: 24px;
                height: 24px;
                display: flex;
                align-items: center;
                justify-content: center;
            }
            
            .ep-content {
                padding: 16px;
            }
            
            .ep-item {
                margin-bottom: 16px;
            }
            
            .ep-item label {
                display: block;
                margin-bottom: 6px;
                font-size: 14px;
                font-weight: 500;
                color: #333;
            }
            
            .ep-item input[type="range"] {
                width: 100%;
                height: 6px;
                border-radius: 3px;
                background: #ddd;
                outline: none;
                -webkit-appearance: none;
            }
            
            .ep-item input[type="range"]::-webkit-slider-thumb {
                -webkit-appearance: none;
                appearance: none;
                width: 18px;
                height: 18px;
                border-radius: 50%;
                background: #667eea;
                cursor: pointer;
                box-shadow: 0 2px 6px rgba(0,0,0,0.2);
            }
            
            .ep-item button {
                padding: 8px 16px;
                margin-right: 8px;
                border: none;
                border-radius: 4px;
                background: #667eea;
                color: white;
                cursor: pointer;
                font-size: 12px;
                transition: background 0.2s;
            }
            
            .ep-item button:hover {
                background: #5a67d8;
            }
            
            #ep-reset {
                background: #718096 !important;
            }
            
            #ep-preset-night {
                background: #553c9a !important;
            }
        `);

        document.body.appendChild(panel);
        return panel;
    }

    // 创建悬浮按钮
    function createFloatingButton() {
        const button = document.createElement('div');
        button.id = 'eye-protection-btn';
        button.innerHTML = '👁️';
        
        GM_addStyle(`
            #eye-protection-btn {
                position: fixed;
                top: 50px;
                right: 20px;
                width: 50px;
                height: 50px;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                border-radius: 50%;
                display: flex;
                align-items: center;
                justify-content: center;
                font-size: 20px;
                cursor: pointer;
                z-index: 9999;
                box-shadow: 0 4px 20px rgba(0,0,0,0.2);
                transition: transform 0.2s, box-shadow 0.2s;
            }
            
            #eye-protection-btn:hover {
                transform: scale(1.1);
                box-shadow: 0 6px 25px rgba(0,0,0,0.3);
            }
        `);
        
        document.body.appendChild(button);
        return button;
    }

    // 应用滤镜效果
    function applyFilters(brightness, blueLight, contrast) {
        const filterId = 'eye-protection-filter';
        let filterElement = document.getElementById(filterId);
        
        if (!filterElement) {
            filterElement = document.createElement('div');
            filterElement.id = filterId;
            document.body.appendChild(filterElement);
        }
        
        // 计算滤镜值
        const brightnessVal = brightness / 100;
        const sepiaVal = blueLight / 100;
        const contrastVal = contrast / 100;
        
        GM_addStyle(`
            html {
                filter: brightness(${brightnessVal}) sepia(${sepiaVal}) contrast(${contrastVal}) !important;
                transition: filter 0.3s ease !important;
            }
        `);
    }

    // 获取当前时间是否为夜间
    function isNightTime(config) {
        const now = new Date().getHours();
        return now >= config.nightModeStart || now < config.nightModeEnd;
    }

    // 自动调整设置
    function autoAdjust(config) {
        if (!config.autoMode) return;
        
        if (isNightTime(config)) {
            applyFilters(config.nightBrightness, config.nightBlueLight, config.contrast);
        } else {
            applyFilters(config.brightness, config.blueLight, config.contrast);
        }
    }

    // 初始化
    function init() {
        const config = getConfig();
        const floatingBtn = createFloatingButton();
        const panel = createControlPanel();
        let panelVisible = false;
        
        // 悬浮按钮点击事件
        floatingBtn.addEventListener('click', () => {
            panelVisible = !panelVisible;
            panel.classList.toggle('show', panelVisible);
        });
        
        // 面板控制事件
        const autoCheckbox = document.getElementById('ep-auto');
        const brightnessSlider = document.getElementById('ep-brightness');
        const bluelightSlider = document.getElementById('ep-bluelight');
        const contrastSlider = document.getElementById('ep-contrast');
        const resetBtn = document.getElementById('ep-reset');
        const nightBtn = document.getElementById('ep-preset-night');
        const toggleBtn = document.getElementById('ep-toggle');
        
        // 初始化界面
        autoCheckbox.checked = config.autoMode;
        brightnessSlider.value = config.brightness;
        bluelightSlider.value = config.blueLight;
        contrastSlider.value = config.contrast;
        
        // 更新数值显示
        function updateValues() {
            document.getElementById('ep-brightness-val').textContent = brightnessSlider.value;
            document.getElementById('ep-bluelight-val').textContent = bluelightSlider.value;
            document.getElementById('ep-contrast-val').textContent = contrastSlider.value;
        }
        updateValues();
        
        // 应用当前设置
        function applyCurrentSettings() {
            const newConfig = {
                ...config,
                autoMode: autoCheckbox.checked,
                brightness: parseInt(brightnessSlider.value),
                blueLight: parseInt(bluelightSlider.value),
                contrast: parseInt(contrastSlider.value)
            };
            
            if (newConfig.autoMode) {
                autoAdjust(newConfig);
            } else {
                applyFilters(newConfig.brightness, newConfig.blueLight, newConfig.contrast);
            }
            
            saveConfig(newConfig);
            Object.assign(config, newConfig);
        }
        
        // 事件绑定
        autoCheckbox.addEventListener('change', applyCurrentSettings);
        
        [brightnessSlider, bluelightSlider, contrastSlider].forEach(slider => {
            slider.addEventListener('input', () => {
                updateValues();
                applyCurrentSettings();
            });
        });
        
        resetBtn.addEventListener('click', () => {
            autoCheckbox.checked = defaultConfig.autoMode;
            brightnessSlider.value = defaultConfig.brightness;
            bluelightSlider.value = defaultConfig.blueLight;
            contrastSlider.value = defaultConfig.contrast;
            updateValues();
            applyCurrentSettings();
        });
        
        nightBtn.addEventListener('click', () => {
            autoCheckbox.checked = false;
            brightnessSlider.value = 70;
            bluelightSlider.value = 50;
            contrastSlider.value = 90;
            updateValues();
            applyCurrentSettings();
        });
        
        toggleBtn.addEventListener('click', () => {
            panelVisible = false;
            panel.classList.remove('show');
        });
        
        // 初始应用设置
        if (config.autoMode) {
            autoAdjust(config);
        } else {
            applyFilters(config.brightness, config.blueLight, config.contrast);
        }
        
        // 定时检查自动模式
        setInterval(() => {
            if (config.autoMode) {
                autoAdjust(config);
            }
        }, 60000); // 每分钟检查一次
    }
    
    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();