网站亮暗色转换

实现任意网站的暗色、亮色的转换,支持负片反色模式,支持网站白名单。

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name              网站亮暗色转换
// @version           1.0.4
// @description       实现任意网站的暗色、亮色的转换,支持负片反色模式,支持网站白名单。
// @author            Redlyn
// @license           MIT
// @match             *://*/*
// @require           https://unpkg.com/[email protected]/dist/rule.min.js
// @require           https://unpkg.com/[email protected]/dist/sweetalert2.min.js
// @resource          swalStyle https://unpkg.com/[email protected]/dist/sweetalert2.min.css
// @run-at            document-start
// @grant             GM_getValue
// @grant             GM_setValue
// @grant             GM_registerMenuCommand
// @grant             GM_getResourceText
// @icon              data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNOTMuNSA5NC42YzEwLjYgMCAyMC4zLTMuMyAyOC4yLTktOC4zIDIyLjUtMzAuMiAzOC42LTU2IDM4LjYtMzIuNyAwLTU5LjMtMjUuOC01OS4zLTU3LjdTMzIuOSA4LjcgNjUuNyA4LjdoMi4yQzU0LjYgMTcgNDUuNyAzMS41IDQ1LjcgNDhjMCAyNS43IDIxLjQgNDYuNiA0Ny44IDQ2LjZ6IiBmaWxsPSIjZmZiNTc4Ii8+PHBhdGggZD0iTTEyMS42IDgxLjhjLS44IDAtMS42LjItMi4zLjctNy41IDUuMy0xNi41IDguMS0yNS44IDguMS0yNC4yIDAtNDMuOS0xOS4xLTQzLjktNDIuNyAwLTE0LjcgNy42LTI4LjEgMjAuMy0zNiAxLjEtLjcgMS44LTEuOSAxLjgtMy4yYTMuOCAzLjggMCAwIDAtMy44LTMuOGgtMi4zQzMwLjggNC45IDIuNSAzMi41IDIuNSA2Ni41UzMwLjggMTI4IDY1LjcgMTI4YzI2LjcgMCA1MC43LTE2LjUgNTkuNi00MSAuMS0uNC4yLS45LjItMS4zIDAtMi4xLTEuNy0zLjktMy45LTMuOXptLTU1LjkgMzguNWMtMzAuNSAwLTU1LjQtMjQuMi01NS40LTUzLjkgMC0yNi4yIDE5LjQtNDguNiA0NS43LTUzLjEtOSA5LjQtMTQuMiAyMS44LTE0LjIgMzQuNyAwIDI3LjggMjMuMiA1MC40IDUxLjcgNTAuNCA2LjcgMCAxMy4yLTEuMiAxOS4zLTMuNi0xMCAxNS44LTI3LjggMjUuNS00Ny4xIDI1LjV6bTM1LjYtNDcuOUg3Ny45Yy0xLjYgMC0yLjktMS4zLTIuOS0yLjkgMC0xIC41LTEuOSAxLjMtMi40TDkxLjYgNTdINzcuOWMtMS42IDAtMi45LTEuMy0yLjktMi45czEuMy0yLjkgMi45LTIuOWgyMy40YzEuNiAwIDIuOSAxLjMgMi45IDIuOSAwIDEtLjUgMS45LTEuMyAyLjRMODcuNiA2Ni42aDEzLjdjMS42IDAgMi45IDEuMyAyLjkgMi45cy0xLjMgMi45LTIuOSAyLjl6bTEzLjItMzEuMWgtMTQuNGMtMS42IDAtMi45LTEuMy0yLjktMi45IDAtMSAuNS0xLjkgMS4zLTIuNGw2LjMtNC4xaC00LjdjLTEuNiAwLTIuOS0xLjMtMi45LTIuOXMxLjMtMi45IDIuOS0yLjloMTQuNGMxLjYgMCAyLjkgMS4zIDIuOSAyLjkgMCAxLS41IDEuOS0xLjMgMi40bC02LjMgNC4xaDQuN2MxLjYgMCAyLjkgMS4zIDIuOSAyLjlzLTEuMyAyLjktMi45IDIuOXptNS42LTI3LjVIMTA4Yy0xLjYgMC0yLjktMS4zLTIuOS0yLjkgMC0xIC41LTEuOSAxLjMtMi40bDQuMS0yLjdIMTA4Yy0xLjYgMC0yLjktMS4zLTIuOS0yLjlTMTA2LjQgMCAxMDggMGgxMi4xYzEuNiAwIDIuOSAxLjMgMi45IDIuOSAwIDEtLjUgMS45LTEuMyAyLjRMMTE3LjYgOGgyLjRjMS42IDAgMi45IDEuMyAyLjkgMi45cy0xLjIgMi45LTIuOCAyLjl6IiBmaWxsPSIjNDQ0Ii8+PC9zdmc+
// @namespace https://greasyfork.org/users/1530405
// ==/UserScript==

;(function () {
    'use strict';

    let util = {
        getValue(name) {
            return GM_getValue(name);
        },

        setValue(name, value) {
            GM_setValue(name, value);
        },

        addStyle(id, tag, css) {
            tag = tag || 'style';
            let doc = document, styleDom = doc.getElementById(id);
            if (styleDom) return;
            let style = doc.createElement(tag);
            style.rel = 'stylesheet';
            style.id = id;
            tag === 'style' ? style.innerHTML = css : style.href = css;
            doc.head.appendChild(style);
        },

        hover(ele, fn1, fn2) {
            ele.onmouseenter = function () {
                fn1.call(ele);
            };
            ele.onmouseleave = function () {
                fn2.call(ele);
            };
        },

        addThemeColor(color) {
            let doc = document, meta = doc.getElementsByName('theme-color')[0];
            if (meta) return meta.setAttribute('content', color);
            let metaEle = doc.createElement('meta');
            metaEle.name = 'theme-color';
            metaEle.content = color;
            doc.head.appendChild(metaEle);
        },

        getThemeColor() {
            let meta = document.getElementsByName('theme-color')[0];
            if (meta) {
                return meta.content;
            }
            return '#ffffff';
        },

        removeElementById(eleId) {
            let ele = document.getElementById(eleId);
            ele && ele.parentNode.removeChild(ele);
        },

        hasElementById(eleId) {
            return document.getElementById(eleId);
        },

        filter: '-webkit-filter: url(#dark-mode-filter) !important; filter: url(#dark-mode-filter) !important;',
        reverseFilter: '-webkit-filter: url(#dark-mode-reverse-filter) !important; filter: url(#dark-mode-reverse-filter) !important;',
        firefoxFilter: `filter: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><filter id="dark-mode-filter" color-interpolation-filters="sRGB"><feColorMatrix type="matrix" values="0.283 -0.567 -0.567 0 0.925 -0.567 0.283 -0.567 0 0.925 -0.567 -0.567 0.283 0 0.925 0 0 0 1 0"/></filter></svg>#dark-mode-filter') !important;`,
        firefoxReverseFilter: `filter: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg"><filter id="dark-mode-reverse-filter" color-interpolation-filters="sRGB"><feColorMatrix type="matrix" values="0.333 -0.667 -0.667 0 1 -0.667 0.333 -0.667 0 1 -0.667 -0.667 0.333 0 1 0 0 0 1 0"/></filter></svg>#dark-mode-reverse-filter') !important;`,
        noneFilter: '-webkit-filter: none !important; filter: none !important;',
        // 添加负片反色滤镜
        invertFilter: 'filter: invert(1) hue-rotate(180deg) !important;',
        invertReverseFilter: 'filter: invert(1) hue-rotate(180deg) !important;'
    };

    // 主要功能逻辑
    let main = {
        // 初始化默认值 - 设置初始配置
        initValue() {
            let value = [{
                name: 'button_position',
                value: 'left'
            }, {
                name: 'button_size',
                value: 32
            }, {
                name: 'exclude_list',
                value: ['youku.com', 'v.youku.com', 'www.douyu.com', 'www.iqiyi.com', 'vip.iqiyi.com', 'mail.qq.com', 'live.kuaishou.com']
            }, {
                name: 'origin_theme_color',
                value: '#ffffff'
            }, {
                name: 'site_modes',
                value: {}
            }, {
                name: 'site_original_modes',  // 新增:存储原始检测结果
                value: {}
            }, {
                name: 'enable_invert_mode',
                value: false  // 默认关闭负片反色模式
            }];

            value.forEach((v) => {
                util.getValue(v.name) === undefined && util.setValue(v.name, v.value);
            });
        },

        // 重置为默认值
        resetToDefaults() {
            let defaults = [{
                name: 'button_position',
                value: 'left'
            }, {
                name: 'button_size',
                value: 32
            }, {
                name: 'exclude_list',
                value: ['youku.com', 'v.youku.com', 'www.douyu.com', 'www.iqiyi.com', 'vip.iqiyi.com', 'mail.qq.com', 'live.kuaishou.com']
            }, {
                name: 'origin_theme_color',
                value: '#ffffff'
            }, {
                name: 'site_modes',
                value: {}
            }, {
                name: 'site_original_modes',
                value: {}
            }, {
                name: 'enable_invert_mode',
                value: false
            }];

            defaults.forEach((v) => {
                util.setValue(v.name, v.value);
            });

            // 重新应用当前模式
            if (this.isDarkMode()) {
                this.enableDarkMode();
            } else {
                this.disableDarkMode();
            }

            return true;
        },


        // 获取当前网站模式 - 读取站点模式设置
        getCurrentSiteMode() {
            let siteModes = util.getValue('site_modes') || {};
            let host = location.host;
            return siteModes[host] || 'light';
        },

        // 设置当前网站模式 - 更新站点模式状态
        setCurrentSiteMode(mode) {
            let siteModes = util.getValue('site_modes') || {};
            let host = location.host;
            siteModes[host] = mode;
            util.setValue('site_modes', siteModes);
        },

        // 获取原始网站模式
        getOriginalSiteMode() {
            let siteModes = util.getValue('site_original_modes') || {};
            let host = location.host;
            return siteModes[host] || null;
        },

        // 设置原始网站模式
        setOriginalSiteMode(mode) {
            let siteModes = util.getValue('site_original_modes') || {};
            let host = location.host;
            siteModes[host] = mode;
            util.setValue('site_original_modes', siteModes);
        },

        // 检查是否启用负片反色模式
        isInvertModeEnabled() {
            return util.getValue('enable_invert_mode') === true;
        },

        // 添加额外样式 - 注入自定义CSS规则
        addExtraStyle() {
            try {
                return darkModeRule;
            } catch (e) {
                return '';
            }
        },

        // 创建深色滤镜 - 生成SVG颜色滤镜
        createDarkFilter() {
            if (util.hasElementById('dark-mode-svg')) return;
            let svgDom = '<svg id="dark-mode-svg" style="height: 0; width: 0;"><filter id="dark-mode-filter" x="0" y="0" width="99999" height="99999"><feColorMatrix type="matrix" values="0.283 -0.567 -0.567 0 0.925 -0.567 0.283 -0.567 0 0.925 -0.567 -0.567 0.283 0 0.925 0 0 0 1 0"></feColorMatrix></filter><filter id="dark-mode-reverse-filter" x="0" y="0" width="99999" height="99999"><feColorMatrix type="matrix" values="0.333 -0.667 -0.667 0 1 -0.667 0.333 -0.667 0 1 -0.667 -0.667 0.333 0 1 0 0 0 1 0"></feColorMatrix></filter></svg>';
            let div = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
            div.innerHTML = svgDom;
            let frag = document.createDocumentFragment();
            while (div.firstChild)
                frag.appendChild(div.firstChild);
            document.head.appendChild(frag);
        },

        // 创建深色样式 - 应用深色模式CSS
        createDarkStyle() {
            const isInvertMode = this.isInvertModeEnabled();

            let baseFilter = isInvertMode ?
                util.invertFilter :
            (this.isFirefox() ? util.firefoxFilter : util.filter);

            let reverseFilter = isInvertMode ?
                util.invertReverseFilter :
            (this.isFirefox() ? util.firefoxReverseFilter : util.reverseFilter);

            util.addStyle('dark-mode-style', 'style', `
                @media screen {
                    html {
                        ${baseFilter}
                        scrollbar-color: #454a4d #202324;
                    }

                    img,
                    video,
                    iframe,
                    canvas,
                    :not(object):not(body) > embed,
                    object,
                    svg image,
                    [style*="background:url"],
                    [style*="background-image:url"],
                    [style*="background: url"],
                    [style*="background-image: url"],
                    [background],
                    twitterwidget,
                    .sr-reader,
                    .no-dark-mode,
                    .sr-backdrop {
                        ${reverseFilter}
                    }

                    [style*="background:url"] *,
                    [style*="background-image:url"] *,
                    [style*="background: url"] *,
                    [style*="background-image: url"] *,
                    input,
                    [background] *,
                    img[src^="https://s0.wp.com/latex.php"],
                    twitterwidget .NaturalImage-image {
                        ${util.noneFilter}
                    }

                    /* 排除夜间模式按钮本身 */
                    #darkmode-container,
                    #darkmode-container * {
                        ${util.noneFilter} !important;
                    }

                    html {
                        text-shadow: 0 0 0 !important;
                    }

                    .no-filter,
                    :-webkit-full-screen,
                    :-webkit-full-screen *,
                    :-moz-full-screen,
                    :-moz-full-screen *,
                    :fullscreen,
                    :fullscreen * {
                        ${util.noneFilter}
                    }

                    ::-webkit-scrollbar {
                        background-color: #202324;
                        color: #aba499;
                    }
                    ::-webkit-scrollbar-thumb {
                        background-color: #454a4d;
                    }
                    ::-webkit-scrollbar-thumb:hover {
                        background-color: #575e62;
                    }
                    ::-webkit-scrollbar-thumb:active {
                        background-color: #484e51;
                    }
                    ::-webkit-scrollbar-corner {
                        background-color: #181a1b;
                    }

                    html {
                        background: #fff !important;
                    }

                    ${this.addExtraStyle()}
                }

                @media print {
                    .no-print {
                        display: none !important;
                    }
                }`);
        },

        // 设置主题颜色 - 保存原始主题色
        setThemeColor() {
            util.setValue('origin_theme_color', util.getThemeColor());
        },

        // 启用深色模式 - 激活夜间模式
        enableDarkMode() {
            if (this.isFullScreen()) return;
            if (!this.isInvertModeEnabled()) {
                !this.isFirefox() && this.createDarkFilter();
            }
            this.createDarkStyle();
            util.addThemeColor('#131313');
        },

        // 禁用深色模式 - 恢复亮色模式
        disableDarkMode() {
            util.removeElementById('dark-mode-svg');
            util.removeElementById('dark-mode-style');
            util.addThemeColor(util.getValue('origin_theme_color'));
        },

        // 添加切换按钮 - 创建模式切换UI
        addButton() {
            if (this.isTopWindow()) {
                let buttonSize = util.getValue('button_size');
                let buttonPosition = util.getValue('button_position');
                let svgSize = parseInt(buttonSize * 0.6);
                let buttonWidth = +buttonSize + 2;

                let showMoon = true;
                let currentMode = this.getCurrentSiteMode();
                if (currentMode === this.shouldShow()) {
                    showMoon = true;
                } else {
                    showMoon = false;
                }

                // 根据当前模式设置初始背景颜色
                let backgroundColor = showMoon ? '#000000' : '#ffffff';
                let borderColor = showMoon ? '#333333' : '#f6f6f6';
                if (currentMode === 'light')
                {
                    backgroundColor = showMoon ? '#000000' : '#ffffff';
                    borderColor = showMoon ? '#333333' : '#f6f6f6';
                }
                else
                {
                    backgroundColor = showMoon ? '#ffffff' : '#000000';
                    borderColor = showMoon ? '#f6f6f6' : '#333333';
                }

                let html = `<div class="no-print" id="darkmode-container" style="position: fixed; ${buttonPosition}: -${buttonWidth / 2}px; bottom: 25px; cursor: pointer; z-index: 2147483647; user-select: none;">
            <div id="darkmode-button" style="width: ${buttonSize}px;height: ${buttonSize}px;background: ${backgroundColor};border:1px solid ${borderColor};display: flex;align-items: center;justify-content: center;border-radius: 50%;position: relative;">
                <svg fill="#009fe8" id="svg-moon" style="width: ${svgSize}px;height: ${svgSize}px;margin: 0;padding: 0;transition: transform 0.3s, opacity 0.3s;position: absolute;${showMoon ? 'transform: scale(1);opacity: 1;' : 'transform: scale(0);opacity: 0;'}" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
                    <path d="M587.264 104.96c33.28 57.856 52.224 124.928 52.224 196.608 0 218.112-176.128 394.752-393.728 394.752-29.696 0-58.368-3.584-86.528-9.728C223.744 832.512 369.152 934.4 538.624 934.4c229.376 0 414.72-186.368 414.72-416.256 1.024-212.992-159.744-389.12-366.08-413.184z"></path>
                </svg>
                <svg fill="#009fe8" id="svg-sun" style="width: ${svgSize}px;height: ${svgSize}px;margin: 0;padding: 0;transition: transform 0.3s, opacity 0.3s;position: absolute;${!showMoon ? 'transform: scale(1);opacity: 1;' : 'transform: scale(0);opacity: 0;'}" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
                    <path d="M234.24 512a277.76 277.76 0 1 0 555.52 0 277.76 277.76 0 1 0-555.52 0zM512 187.733a42.667 42.667 0 0 1-42.667-42.666v-102.4a42.667 42.667 0 0 1 85.334 0v102.826A42.667 42.667 0 0 1 512 187.733zm-258.987 107.52a42.667 42.667 0 0 1-29.866-12.373l-72.96-73.387a42.667 42.667 0 0 1 59.306-59.306l73.387 72.96a42.667 42.667 0 0 1 0 59.733 42.667 42.667 0 0 1-29.867 12.373zm-107.52 259.414H42.667a42.667 42.667 0 0 1 0-85.334h102.826a42.667 42.667 0 0 1 0 85.334zm34.134 331.946a42.667 42.667 0 0 1-29.44-72.106l72.96-73.387a42.667 42.667 0 0 1 59.733 59.733l-73.387 73.387a42.667 42.667 0 0 1-29.866 12.373zM512 1024a42.667 42.667 0 0 1-42.667-42.667V878.507a42.667 42.667 0 0 1 85.334 0v102.826A42.667 42.667 0 0 1 512 1024zm332.373-137.387a42.667 42.667 0 0 1-29.866-12.373l-73.387-73.387a42.667 42.667 0 0 1 0-59.733 42.667 42.667 0 0 1 59.733 0l72.96 73.387a42.667 42.667 0 0 1-29.44 72.106zm136.96-331.946H878.507a42.667 42.667 0 0 1 0-85.334h102.826a42.667 42.667 0 0 1 0 85.334zM770.987 295.253a42.667 42.667 0 0 1-29.867-12.373 42.667 42.667 0 0 1 0-59.733l73.387-72.96a42.667 42.667 0 1 1 59.306 59.306l-72.96 73.387a42.667 42.667 0 0 1-29.866 12.373z"></path>
                </svg>
            </div>
        </div>`;

                document.body.insertAdjacentHTML('beforeend', html);

                let containerDOM = document.getElementById('darkmode-container');
                let buttonDOM = document.getElementById('darkmode-button');
                let moonDOM = document.getElementById('svg-moon');
                let sunDOM = document.getElementById('svg-sun');

                util.hover(containerDOM, () => {
                    containerDOM.style[buttonPosition] = '0px';
                    containerDOM.style.transition = `${buttonPosition} 0.3s`
        }, () => {
                    containerDOM.style[buttonPosition] = `-${buttonWidth / 2}px`;
                    containerDOM.style.transition = `${buttonPosition} 0.3s`
        });

                buttonDOM.addEventListener("click", () => {

                    let currentMode = this.getCurrentSiteMode();
                    if (currentMode === 'light') {
                        this.switchToDarkMode(moonDOM, sunDOM);
                    } else {
                        this.switchToLightMode(moonDOM, sunDOM);
                    }
                    if (this.getCurrentSiteMode() === this.shouldShow()) {
                        moonDOM.style.transform = 'scale(1)';
                        moonDOM.style.opacity = '1';
                        sunDOM.style.transform = 'scale(0)';
                        sunDOM.style.opacity = '0';
                    } else {
                        moonDOM.style.transform = 'scale(0)';
                        moonDOM.style.opacity = '0';
                        sunDOM.style.transform = 'scale(1)';
                        sunDOM.style.opacity = '1';
                    }
                });
            }
        },

        // 切换到深色模式 - 更新界面状态
        switchToDarkMode(moonDOM, sunDOM) {
            this.setCurrentSiteMode('dark');
            this.enableDarkMode();
        },

        // 切换到亮色模式 - 更新界面状态
        switchToLightMode(moonDOM, sunDOM) {
            this.setCurrentSiteMode('light');
            this.disableDarkMode();

        },

        // 检测亮色主题 - 分析页面颜色模式
        isLight() {
            let darkTextCount = 0;
            let lightTextCount = 0;
            let totalSamples = 0;

            try {
                // 方法1: 随机采样页面中的文本元素
                const textSelectors = [
                    'p', 'span', 'div', 'a', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
                    'li', 'td', 'th', 'label', 'button'
                ];

                // 从每种选择器中取多个样本
                for (let selector of textSelectors)
                {
                    const elements = document.querySelectorAll(selector);
                    // 每种类型最多取5个样本,避免过度偏向某种元素
                    const maxSamples = Math.min(elements.length, 5);

                    for (let i = 0; i < maxSamples; i++)
                    {
                        try {
                            const el = elements[i];
                            if (!el || !el.offsetParent) continue; // 跳过隐藏元素

                            const color = getComputedStyle(el).color;
                            const rgb = color.match(/\d+/g);
                            if (rgb && rgb.length >= 3)
                            {
                                const luminance = 0.299 * parseInt(rgb[0]) + 0.587 * parseInt(rgb[1]) + 0.114 * parseInt(rgb[2]);
                                totalSamples++;

                                if (luminance > 180) { // 很亮的文本
                                    lightTextCount++;
                                } else if (luminance < 100) { // 很暗的文本
                                    darkTextCount++;
                                }
                                // 中等亮度文本不计入统计
                            }
                        } catch (e) {}
                    }
                }
            } catch (e) {}

            const isDark = lightTextCount > darkTextCount;
            return isDark ? 'dark' : 'light';
        },

        // 判断显示月亮图标 - 确定按钮初始状态
        shouldShow() {
            let host = location.host;

            const knownDarkSites = [
                'github.com',
                'twitter.com',
                'x.com',
                'reddit.com',
                'notion.so',
                'linear.app',
                'figma.com',
                'spotify.com',
                'netflix.com',
                'twitch.tv',
                'discord.com',
                'telegram.org',
                'leetcode.com',
                'stackoverflow.com',
                'gitlab.com',
                'medium.com'
            ];

            const knownLightSites = [
                'bing.com',
                'google.com',
                'baidu.com',
                'zhihu.com',
                'weibo.com',
                'bilibili.com',
                'taobao.com',
                'jd.com',
                'qq.com',
                '163.com',
                'douban.com',
                'apple.com',
                'microsoft.com',
                'wikipedia.org',
                'cnn.com',
                'nytimes.com',
                'facebook.com',
                'instagram.com',
                'linkedin.com',
                'amazon.com',
                'w3schools.com',
                'csdn.net'
            ];

            for (let site of knownDarkSites) {
                if (host.includes(site)) {
                    return 'dark';
                }
            }

            for (let site of knownLightSites) {
                if (host.includes(site)) {
                    return 'light';
                }
            }

            let original = this.getOriginalSiteMode();
            if (original === null)
            {
                original = this.isLight();
                this.setOriginalSiteMode(original);
            }
            return original;
        },

        // 获取颜色亮度 - 计算颜色明度值
        getColorBrightness(color) {
            let rgb = color.match(/\d+/g);
            if (rgb && rgb.length >= 3) {
                return (parseInt(rgb[0]) * 299 + parseInt(rgb[1]) * 587 + parseInt(rgb[2]) * 114) / 1000;
            }
            return 255;
        },

        // 检测网站视觉亮色 - 分析页面背景色
        isSiteVisuallyLight() {
            try {
                let bodyStyle = window.getComputedStyle(document.body);
                let bgColor = bodyStyle.backgroundColor;

                if (bgColor && bgColor !== 'rgba(0, 0, 0, 0)' && bgColor !== 'transparent') {
                    let rgb = bgColor.match(/\d+/g);
                    if (rgb && rgb.length >= 3) {
                        let brightness = (parseInt(rgb[0]) * 299 + parseInt(rgb[1]) * 587 + parseInt(rgb[2]) * 114) / 1000;
                        return brightness >= 128;
                    }
                }

                let htmlStyle = window.getComputedStyle(document.documentElement);
                let htmlBgColor = htmlStyle.backgroundColor;
                if (htmlBgColor && htmlBgColor !== 'rgba(0, 0, 0, 0)' && htmlBgColor !== 'transparent') {
                    let rgb = htmlBgColor.match(/\d+/g);
                    if (rgb && rgb.length >= 3) {
                        let brightness = (parseInt(rgb[0]) * 299 + parseInt(rgb[1]) * 587 + parseInt(rgb[2]) * 114) / 1000;
                        return brightness >= 128;
                    }
                }

                return true;
            } catch (e) {
                return true;
            }
        },

        // 注册菜单命令 - 创建用户脚本菜单
        // 注册菜单命令 - 创建用户脚本菜单
        registerMenuCommand() {
            if (this.isTopWindow()) {
                let whiteList = util.getValue('exclude_list');
                let host = location.host;

                let currentMode = this.getCurrentSiteMode();

                if (whiteList.includes(host)) {
                    GM_registerMenuCommand(`💡 当前网站:❌ 排除`, () => {
                        let index = whiteList.indexOf(host);
                        whiteList.splice(index, 1);
                        util.setValue('exclude_list', whiteList);
                        history.go(0);
                    });
                } else {
                    GM_registerMenuCommand(`💡 当前网站:✔️ 启用`, () => {
                        whiteList.push(host);
                        util.setValue('exclude_list', Array.from(new Set(whiteList)));
                        history.go(0);
                    });
                }

                GM_registerMenuCommand('⚙️ 设置', () => {
                    let style = `
                                .darkmode-popup { font-size: 14px !important; }
                                .darkmode-center { display: flex;align-items: center; }
                                .darkmode-setting-label { display: flex;align-items: center;justify-content: space-between;padding-top: 15px; }
                                .darkmode-setting-label-col { display: flex;align-items: flex-start;;padding-top: 15px;flex-direction:column }
                                .darkmode-setting-radio { width: 16px;height: 16px; }
                                .darkmode-setting-textarea { width: 100%; margin: 14px 0 0; height: 100px; resize: none; border: 1px solid #bbb; box-sizing: border-box; padding: 5px 10px; border-radius: 5px; color: #666; line-height: 1.2; }
                                .darkmode-setting-input { border: 1px solid #bbb; box-sizing: border-box; padding: 5px 10px; border-radius: 5px; width: 100px}
                                .darkmode-setting-switch { display: flex; align-items: center; }
                                .darkmode-switch { position: relative; display: inline-block; width: 50px; height: 24px; margin-left: 10px; }
                                .darkmode-switch input { opacity: 0; width: 0; height: 0; }
                                .darkmode-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 24px; }
                                .darkmode-slider:before { position: absolute; content: ""; height: 16px; width: 16px; left: 4px; bottom: 4px; background-color: white; transition: .4s; border-radius: 50%; }
                                input:checked + .darkmode-slider { background-color: #2196F3; }
                                input:checked + .darkmode-slider:before { transform: translateX(26px); }
                                .darkmode-reset-btn { margin-top: 20px; padding: 8px 16px; background-color: #f8f9fa; border: 1px solid #ddd; border-radius: 4px; cursor: pointer; color: #666; font-size: 14px; }
                                .darkmode-reset-btn:hover { background-color: #e9ecef; }
                            `;
                    util.addStyle('darkmode-style', 'style', style);
                    util.addStyle('swal-pub-style', 'style', GM_getResourceText('swalStyle'));
                    let excludeListStr = util.getValue('exclude_list').join('\n');
                    let isInvertModeEnabled = this.isInvertModeEnabled();

                    let dom = `<div style="font-size: 1em;">
                              <label class="darkmode-setting-label">按钮位置 <div id="S-Dark-Position" class="darkmode-center"><input type="radio" name="buttonPosition" ${util.getValue('button_position') === 'left' ? 'checked' : ''} class="darkmode-setting-radio" value="left">左 <input type="radio" name="buttonPosition" style="margin-left: 30px;" ${util.getValue('button_position') === 'right' ? 'checked' : ''} class="darkmode-setting-radio" value="right">右</div></label>
                              <label class="darkmode-setting-label"><span style="text-align: left;">按钮大小(默认:32)<small id="currentSize">当前:${util.getValue('button_size')}</small></span>
                              <input id="S-Dark-Size" type="range" class="darkmode-setting-range" min="20" max="50" step="2" value="${util.getValue('button_size')}">
                              </label>
                              <label class="darkmode-setting-label">
                                <span>启用负片反色模式</span>
                                <div class="darkmode-setting-switch">
                                  <label class="darkmode-switch">
                                    <input type="checkbox" id="S-Dark-Invert" ${isInvertModeEnabled ? 'checked' : ''}>
                                    <span class="darkmode-slider"></span>
                                  </label>
                                  <small style="margin-left: 10px; color: #666;">${isInvertModeEnabled ? '已启用' : '已关闭'}</small>
                                </div>
                              </label>
                              <label class="darkmode-setting-label-col">排除下列网址 <textarea placeholder="列表中的域名将不开启夜间模式,一行一个,例如:v.youku.com" id="S-Dark-Exclude" class="darkmode-setting-textarea">${excludeListStr}</textarea></label>

                              <div style="text-align: center; margin-top: 20px;">
                                <button id="S-Dark-Reset" class="darkmode-reset-btn" type="button">🔄 重置为默认值</button>
                              </div>
                            </div>`;
                    Swal.fire({
                        title: '夜间模式配置',
                        html: dom,
                        icon: 'info',
                        showCloseButton: true,
                        confirmButtonText: '保存',
                        showCancelButton: true,
                        cancelButtonText: '取消',
                        customClass: {
                            popup: 'darkmode-popup',
                        },
                    }).then((res) => {
                        if (res.isConfirmed) {
                            history.go(0);
                        }
                    });

                    document.getElementById('S-Dark-Position').addEventListener('click', (e) => {
                        e.target.tagName === "INPUT" && util.setValue('button_position', e.target.value);
                    });
                    document.getElementById('S-Dark-Size').addEventListener('change', (e) => {
                        util.setValue('button_size', e.currentTarget.value);
                        document.getElementById('currentSize').innerText = '当前:' + e.currentTarget.value;
                    });
                    document.getElementById('S-Dark-Exclude').addEventListener('change', (e) => {
                        util.setValue('exclude_list', Array.from(new Set(e.currentTarget.value.split('\n').filter(Boolean))));
                    });
                    document.getElementById('S-Dark-Invert').addEventListener('change', (e) => {
                        util.setValue('enable_invert_mode', e.currentTarget.checked);
                        // 更新状态显示
                        const statusText = e.currentTarget.checked ? '已启用' : '已关闭';
                        e.currentTarget.parentElement.parentElement.querySelector('small').innerText = statusText;
                    });

                    // 添加重置按钮事件
                    document.getElementById('S-Dark-Reset').addEventListener('click', () => {
                        Swal.fire({
                            title: '确认重置',
                            text: '这将恢复所有设置为默认值,包括按钮位置、大小、排除列表等。确定要继续吗?',
                            icon: 'warning',
                            showCancelButton: true,
                            confirmButtonText: '确定重置',
                            cancelButtonText: '取消',
                            confirmButtonColor: '#d33',
                        }).then((result) => {
                            if (result.isConfirmed) {
                                if (this.resetToDefaults()) {
                                    Swal.fire({
                                        title: '重置成功',
                                        text: '所有设置已恢复为默认值,页面将重新加载。',
                                        icon: 'success',
                                        confirmButtonText: '确定'
                                    }).then(() => {
                                        history.go(0);
                                    });
                                }
                            }
                        });
                    });
                });
            }
        },

        // 检查顶层窗口 - 验证窗口层级
        isTopWindow() {
            return window.self === window.top;
        },

        // 添加监听器 - 绑定事件处理
        addListener() {
            document.addEventListener("fullscreenchange", (e) => {
                if (this.isFullScreen()) {
                    this.disableDarkMode();
                } else {
                    this.isDarkMode() && this.enableDarkMode();
                }
            });
        },

        // 检查深色模式 - 判断当前模式状态
        isDarkMode() {
            return this.getCurrentSiteMode() === 'dark';
        },

        // 检查排除列表 - 验证站点权限
        isInExcludeList() {
            return util.getValue('exclude_list').includes(location.host);
        },

        // 检查全屏模式 - 检测全屏状态
        isFullScreen() {
            return document.fullscreenElement;
        },

        // 检查Firefox浏览器 - 判断浏览器类型
        isFirefox() {
            return /Firefox/i.test(navigator.userAgent);
        },

        // 首次启用深色模式 - 延迟初始化功能
        firstEnableDarkMode() {
            let retryCount = 0;
            const maxRetries = 5;

            const initDarkMode = () => {
                try {
                    if (this.isDarkMode()) {
                        this.enableDarkMode();
                    }

                    if (document.body && !util.hasElementById('darkmode-container')) {
                        this.addButton();
                    } else if (!document.body && retryCount < maxRetries) {
                        retryCount++;
                        setTimeout(initDarkMode, 200);
                    }
                } catch (error) {
                    console.log('Dark mode initialization error:', error);
                    if (retryCount < maxRetries) {
                        retryCount++;
                        setTimeout(initDarkMode, 200);
                    }
                }
            };

            // 如果文档已经加载完成,直接初始化
            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', () => {
                    setTimeout(initDarkMode, 100);
                });
            } else {
                setTimeout(initDarkMode, 100);
            }

            // 额外的观察器确保在动态内容加载后也能工作
            const headObserver = new MutationObserver(() => {
                if (this.isDarkMode() && !util.hasElementById('dark-mode-style')) {
                    this.enableDarkMode();
                }
            });
            headObserver.observe(document.head, { childList: true, subtree: true });

            // 确保body存在后再添加按钮
            if (!document.body) {
                const bodyObserver = new MutationObserver(() => {
                    if (document.body) {
                        bodyObserver.disconnect();
                        setTimeout(() => {
                            if (!util.hasElementById('darkmode-container')) {
                                this.addButton();
                            }
                        }, 100);
                    }
                });
                bodyObserver.observe(document, { childList: true, subtree: true });
            }
        },

        // 初始化主函数 - 脚本入口点
        init() {
            this.initValue();// 初始化默认配置值
            this.setThemeColor();// 保存原始主题颜色
            this.registerMenuCommand();// 注册用户脚本菜单命令
            if (this.isInExcludeList()) return;// 检查是否在排除列表中
            this.addListener();// 添加事件监听器

            // 确保在页面完全加载后执行
            if (document.readyState === 'loading') {
                document.addEventListener('DOMContentLoaded', () => {
                    this.firstEnableDarkMode();
                });
            } else {
                this.firstEnableDarkMode();
            }
        }


    };
    main.init();
})();