智能护眼模式

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

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==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();
    }
})();