Web Reading Tools

Enhanced Features: Press F8 to show/hide buttons. Provides Eye-care Mode, Dark Mode, Chinese Conversion, TOC navigation, Font Switching and more.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name               网页阅读助手
// @name:zh-CN         网页阅读助手
// @name:en            Web Reading Tools
// @description        增强功能:按 F8 显示/隐藏按钮,提供护眼模式、黑夜模式、繁简转换、目录导航、字体转换等功能。
// @description:zh-CN  增强功能:按 F8 显示/隐藏按钮,提供护眼模式、黑夜模式、繁简转换、目录导航、字体转换等功能
// @description:en     Enhanced Features: Press F8 to show/hide buttons. Provides Eye-care Mode, Dark Mode, Chinese Conversion, TOC navigation, Font Switching and more.
// @namespace          https://www.runningcheese.com/bookmarklets
// @author             RunningCheese
// @version            1.0
// @icon               data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1NzYiIGhlaWdodD0iNTEyIiB2aWV3Qm94PSIwIDAgNTc2IDUxMiI+Cgk8cGF0aCBmaWxsPSIjMDA3RkU5IiBkPSJNNTQyLjIyIDMyLjA1Yy01NC44IDMuMTEtMTYzLjcyIDE0LjQzLTIzMC45NiA1NS41OWMtNC42NCAyLjg0LTcuMjcgNy44OS03LjI3IDEzLjE3djM2My44N2MwIDExLjU1IDEyLjYzIDE4Ljg1IDIzLjI4IDEzLjQ5YzY5LjE4LTM0LjgyIDE2OS4yMy00NC4zMiAyMTguNy00Ni45MmMxNi44OS0uODkgMzAuMDItMTQuNDMgMzAuMDItMzAuNjZWNjIuNzVjLjAxLTE3LjcxLTE1LjM1LTMxLjc0LTMzLjc3LTMwLjdNMjY0LjczIDg3LjY0QzE5Ny41IDQ2LjQ4IDg4LjU4IDM1LjE3IDMzLjc4IDMyLjA1QzE1LjM2IDMxLjAxIDAgNDUuMDQgMCA2Mi43NVY0MDAuNmMwIDE2LjI0IDEzLjEzIDI5Ljc4IDMwLjAyIDMwLjY2YzQ5LjQ5IDIuNiAxNDkuNTkgMTIuMTEgMjE4Ljc3IDQ2Ljk1YzEwLjYyIDUuMzUgMjMuMjEtMS45NCAyMy4yMS0xMy40NlYxMDAuNjNjMC01LjI5LTIuNjItMTAuMTQtNy4yNy0xMi45OSIgLz4KPC9zdmc+
// @match              *://*/*
// @grant              GM_getValue
// @grant              GM_setValue
// @grant              GM_registerMenuCommand
// @grant              GM_unregisterMenuCommand
// @license            MIT
// ==/UserScript==

(function() {
    'use strict';

    let ttPolicy;
    if (window.trustedTypes && window.trustedTypes.createPolicy) {
        try {
            ttPolicy = window.trustedTypes.createPolicy('web-assistant-' + Math.random().toString(36).substring(2, 9), {
                createHTML: (string) => string
            });
        } catch (e) {
            ttPolicy = { createHTML: (string) => string };
        }
    } else {
        ttPolicy = { createHTML: (string) => string };
    }

    // 简化的元素创建工具
    const elements = {
        createAs(nodeType, config, appendTo) {
            const element = document.createElement(nodeType);
            if (config) {
                Object.entries(config).forEach(([key, value]) => {
                    if (key === 'innerHTML') {
                        element.innerHTML = ttPolicy.createHTML(value);
                    } else {
                        element[key] = value;
                    }
                });
            }
            if (appendTo) appendTo.appendChild(element);
            return element;
        },
        getAs(selector) {
            return document.body.querySelector(selector);
        }
    };


    // 添加CSS样式
    const style = elements.createAs('style', {
        textContent: `
            .web-icon-btn {
                display: inline-flex;
                align-items: center;
                justify-content: center;
                width: 40px;
                height: 40px;
                border-radius: 50%;
                cursor: pointer;
                transition: background-color 0.3s, transform 0.2s;
                background-color: #fff;
                color: #555;
                box-shadow: 0 4px 10px rgba(0, 0, 0, 0.12);
                text-decoration: none;
            }

            .web-icon-btn:hover {
                background-color: #d0d0d0;
                transform: scale(1.1);
            }

            .web-icon-btn svg {
                width: 20px;
                height: 20px;
                fill: #555;
            }
        `
    }, document.head);

    // 网页助手主体
    const webViewer = {
        buttonAdded: false,
        buttonCheckInterval: null,
        visible: false,
        menuCommandIds: [],
        buttonConfigs: [
            { id: 'web-bookmarklet-btn', key: 'autoRunBtn1', label: '护眼模式' },
            { id: 'web-bookmarklet-btn-2', key: 'autoRunBtn2', label: '黑夜模式' },
            { id: 'web-bookmarklet-btn-3', key: 'autoRunBtn3', label: '繁简转换' },
            { id: 'web-bookmarklet-btn-4', key: 'autoRunBtn4', label: '目录导航' },
            { id: 'web-bookmarklet-btn-5', key: 'autoRunBtn5', label: '网页字体' },
        ],

        runButtonAction(id) {
            switch (id) {
                case 'web-bookmarklet-btn':
                    this.runEyesCareMode();
                    break;
                case 'web-bookmarklet-btn-2':
                    this.runDarkMode();
                    break;
                case 'web-bookmarklet-btn-3':
                    this.runCharConvert();
                    break;
                case 'web-bookmarklet-btn-4':
                    this.runTOC();
                    break;
                case 'web-bookmarklet-btn-5':
                    this.runFontChange();
                    break;
            }
        },

        // 运行“护眼模式”功能
        runEyesCareMode() {
            var night = function(w) {
                (function(d) {
                    var css = 'html{filter: brightness(0.9);}';
                    var s = d.getElementsByTagName('style');
                    for (var i = 0, si; si = s[i]; i++) {
                        if (si.innerHTML == css) {
                            si.parentNode.removeChild(si);
                            return;
                        }
                    }
                    var heads = d.getElementsByTagName('head');
                    if (heads.length) {
                        var node = d.createElement('style');
                        node.type = 'text/css';
                        node.appendChild(d.createTextNode(css));
                        heads[0].appendChild(node);
                    }
                })(w.document);
                for (var i = 0, f; f = w.frames[i]; i++) {
                    try { arguments.callee(f); } catch (e) {}
                }
            };
            night(window);
        },

        // 运行“黑夜模式”功能
        runDarkMode() {
            var d = document.documentElement;
            if (d.hasAttribute('data-dark-mode')) {
                var e = document.querySelectorAll('[data-original-style]');
                e.forEach(function(n) {
                    n.style.cssText = n.getAttribute('data-original-style') || '';
                    n.removeAttribute('data-original-style');
                });
                d.removeAttribute('data-dark-mode');
            } else {
                d.setAttribute('data-dark-mode', 'true');
                function R(c) {
                    var r = c[0], g = c[1], b = c[2], M = Math.max(Math.max(r, g), b), m = Math.min(Math.min(r, g), b), s = M + m, f = M - m, l = s / 2, h = 0, S = 0;
                    if (M != m) {
                        S = l <= .5 ? f / s : f / (2 - s);
                        var Rd = r / 6 / f, Gd = g / 6 / f, Bd = b / 6 / f;
                        h = r == M ? Gd - Bd : g == M ? 1 / 3 + Bd - Rd : 2 / 3 + Rd - Gd;
                        if (h < 0) h += 1;
                        if (h > 1) h -= 1;
                    }
                    return [h, S, l];
                }
                function C(n, p) {
                    var r = getComputedStyle(n, null).getPropertyValue(p);
                    if (/rgb\((\d+),\s(\d+),\s(\d+)\)/.exec(r)) return [parseInt(RegExp.$1, 10) / 255, parseInt(RegExp.$2, 10) / 255, parseInt(RegExp.$3, 10) / 255];
                    return r;
                }
                function H(h) {
                    if (h[2] < .1) return 'hsl(220,20%,15%)';
                    return 'hsl(' + Math.round(h[0] * 360) + ',' + Math.round(h[1] * 100) + '%,' + Math.round(h[2] * 100) + '%)';
                }
                function I(n) {
                    return n.tagName === 'BUTTON' || n.tagName === 'INPUT' || n.classList.contains('icon') || n.classList.contains('btn') || n.getAttribute('role') === 'button' || /\b(icon|btn|button)\b/i.test(n.className);
                }
                var P = ['color', 'background-color', 'border-left-color', 'border-right-color', 'border-top-color', 'border-bottom-color'],
                    P2 = ['color', 'backgroundColor', 'borderLeftColor', 'borderRightColor', 'borderTopColor', 'borderBottomColor'];
                if (typeof C(d, 'background-color') == 'string') d.style.backgroundColor = 'white';
                (function L(n) {
                    if (n.nodeType == Node.ELEMENT_NODE) {
                        if (!n.hasAttribute('data-original-style')) n.setAttribute('data-original-style', n.style.cssText);
                        for (var i = 0, x; x = n.childNodes[i]; ++i) L(x);
                        if (!I(n))
                            for (i = 0; x = P[i]; ++i) {
                                var c = C(n, x);
                                if (typeof c != 'string') {
                                    var h = R(c);
                                    h[2] = 1 - h[2];
                                    n.style[P2[i]] = H(h);
                                }
                            }
                    }
                })(d);
            }
        },

        // 运行“目录导航”功能
        runTOC() {
            var toc = function() {
                var selectors = ["article", "section", "main", "content", "#article", ".article", "#main", ".main", "#content", ".content", "#post", ".post", "body"];
                var headingSelector = "h1, h2, h3, h4, h5, h6";
                var shadow;
                var buildList = function() {
                    var headings = [];
                    var index = 0;
                    for (var s = 0; s < selectors.length; s++) {
                        if (document.querySelectorAll(selectors[s]).length) {
                            document.querySelectorAll(selectors[s]).forEach(function(container) {
                                container.querySelectorAll(headingSelector).forEach(function(el) {
                                    if (el.innerText.trim()) {
                                        headings.push(el);
                                        if (el.id) {
                                            el.dataset.headerMark = el.id;
                                        } else {
                                            el.dataset.headerMark = "toc_index_" + index++;
                                            el.id = el.dataset.headerMark;
                                        }
                                    }
                                });
                            });
                            break;
                        }
                    }
                    var html = "";
                    if (headings.length) {
                        var prevLevel = +headings[0].tagName.replace(/H/g, "");
                        var indent = 0;
                        headings.forEach(function(el) {
                            var level = +el.tagName.replace(/H/g, "");
                            indent = indent + level - prevLevel;
                            indent = indent < 0 ? 0 : indent;
                            prevLevel = level;
                            var span = document.createElement("span");
                            span.innerText = el.innerText;
                            html += '<li class="toc_menu_item toc_header_level_' + indent + '"><a href="#' + el.dataset.headerMark + '">' + span.innerHTML + '</a></li>';
                        });
                    } else {
                        html += '<li class="toc_menu_item">[空]</li>';
                    }
                    return html;
                };
                (function() {
                    var host = document.createElement("div");
                    shadow = host.attachShadow({ mode: "open" });
                    host.id = "toc_menu_root";
                    shadow.innerHTML = '<style>#toc_menu_root{position:fixed;top:50%;right:20%;transform:translateY(-50%);width:220px;max-height:80vh;z-index:2147483647;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:#fff;border-radius:8px;box-shadow:0 4px 12px rgba(0,0,0,0.25);}#toc_menu_root>#toc_header{padding:8px 10px;cursor:move;font-size:14px;border-radius:8px 8px 0 0;border-bottom:1px solid #eee;color:#333;display:flex;justify-content:space-between;align-items:center;}#toc_header_text{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1;}#close_button{cursor:pointer;margin-left:8px;color:#999;width:20px;height:20px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:all 0.2s ease;flex-shrink:0;}#close_button:hover{background:#dadada;color:#333;}#toc_menu_root>ul#toc_menu_list{box-sizing:border-box!important;margin:0;padding:4px;max-height:calc(80vh - 32px);overflow:auto;background:#fff;border-radius:0 0 8px 8px;}#toc_menu_root>ul#toc_menu_list>li{list-style:none!important;margin:0;padding:0 10px;height:32px;font-size:14px;transition:all 0.2s ease;border-radius:6px;cursor:pointer;}#toc_menu_root>ul#toc_menu_list>li.toc_menu_item>a{display:flex;align-items:center;color:#333;text-decoration:none;font-size:14px;height:100%;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}#toc_menu_root>ul#toc_menu_list>li:hover{background:#dadada;}#toc_menu_root>ul#toc_menu_list>li.toc_menu_item>a:hover{color:#333;}#toc_menu_root>ul#toc_menu_list>li.toc_header_level_1{padding-left:1.2em;}#toc_menu_root>ul#toc_menu_list>li.toc_header_level_2{padding-left:2em;}#toc_menu_root>ul#toc_menu_list>li.toc_header_level_3{padding-left:2.8em;}</style><div id="toc_menu_root"><div id="toc_header"><span id="toc_header_text">▼ 目录导航</span><span id="close_button">✕</span></div><ul id="toc_menu_list"></ul></div>';
                    document.querySelector("html").appendChild(host);
                    var menuRoot = shadow.querySelector("#toc_menu_root");
                    var menuList = shadow.querySelector("#toc_menu_list");
                    var header = shadow.querySelector("#toc_header");
                    menuList.innerHTML = buildList();
                    var isDragging = false;
                    var offsetX, offsetY;
                    header.addEventListener("mousedown", function(e) {
                        if (e.target.id === "close_button") return;
                        isDragging = true;
                        offsetX = e.clientX - e.currentTarget.getBoundingClientRect().left;
                        offsetY = e.clientY - e.currentTarget.getBoundingClientRect().top;
                    });
                    document.addEventListener("mousemove", function(e) {
                        if (!isDragging) return;
                        var x = e.clientX - offsetX;
                        var y = e.clientY - offsetY;
                        e.preventDefault();
                        menuRoot.style.left = x + "px";
                        menuRoot.style.top = y + "px";
                        menuRoot.style.right = "auto";
                        menuRoot.style.transform = "none";
                    });
                    document.addEventListener("mouseup", function() {
                        isDragging = false;
                    });
                    shadow.querySelector("#close_button").addEventListener("click", function() {
                        host.remove();
                    });
                    document.addEventListener("keydown", function(evt) {
                        if (evt.key === "Escape") {
                            host.remove();
                        }
                    });
                })();
            };
            toc();
        },

        // 显示提示消息
        showToast(message) {
            const toast = elements.createAs("div", {
                style: `
                    position: fixed;
                    top: 12%;
                    left: 50%;
                    transform: translate(-50%, -50%);
                    background-color: #ff2442;
                    color: white;
                    padding: 15px 20px;
                    border-radius: 8px;
                    font-size: 14px;
                    font-weight: bold;
                    z-index: 1000000000;
                    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
                `,
                textContent: message
            }, document.body);

            setTimeout(() => {
                if (document.body.contains(toast)) {
                    document.body.removeChild(toast);
                }
            }, 3000);
        },

        // 添加按钮到页面浮动容器
        addButtons() {
            let buttonContainer = elements.getAs('#web-helper-buttons');

            if (!buttonContainer) {
                buttonContainer = elements.createAs('div', {
                    id: 'web-helper-buttons',
                    style: `
                        position: fixed;
                        top: 50%;
                        right: 30px;
                        transform: translateY(-50%);
                        display: flex;
                        flex-direction: column;
                        align-items: center;
                        gap: 15px;
                        z-index: 999999;
                    `
                }, document.body);
            }

            buttonContainer.style.display = this.visible ? 'flex' : 'none';

            // 创建小书签按钮
            if (!elements.getAs('#web-bookmarklet-btn')) {
                elements.createAs('a', {
                    id: 'web-bookmarklet-btn',
                    href: 'javascript:void(0);',
                    className: 'web-icon-btn',
                    title: '护眼模式',
                    innerHTML: '<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512"><path fill="#555" fill-rule="evenodd" d="M277.333 405.333v85.333h-42.667v-85.333zm99.346-58.824l60.34 60.34l-30.17 30.17l-60.34-60.34zm-241.359 0l30.17 30.17l-60.34 60.34l-30.17-30.17zM256 139.353c64.422 0 116.647 52.224 116.647 116.647c0 64.422-52.225 116.647-116.647 116.647A116.427 116.427 0 0 1 139.352 256c0-64.423 52.225-116.647 116.648-116.647m0 42.666c-40.859 0-73.981 33.123-73.981 74.062a73.76 73.76 0 0 0 21.603 52.296c13.867 13.867 32.685 21.64 52.378 21.603zm234.666 52.647v42.667h-85.333v-42.667zm-384 0v42.667H21.333v-42.667zM105.15 74.98l60.34 60.34l-30.17 30.17l-60.34-60.34zm301.7 0l30.169 30.17l-60.34 60.34l-30.17-30.17zM277.332 21.333v85.333h-42.667V21.333z" /></svg>',
                    onclick: () => {
                        webViewer.runEyesCareMode();
                    }
                }, buttonContainer);
            }

            if (!elements.getAs('#web-bookmarklet-btn-2')) {
                elements.createAs('a', {
                    id: 'web-bookmarklet-btn-2',
                    href: 'javascript:void(0);',
                    className: 'web-icon-btn',
                    title: '黑夜模式',
                    innerHTML: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="#555" d="M11 21q-3.35 0-5.675-2.325T3 13t2.325-5.675T11 5q.125 0 .25.012t.25.013q-.725.8-1.112 1.825T10 9q0 2.5 1.75 4.25T16 15q.775 0 1.513-.187t1.387-.563q-.45 2.95-2.7 4.85T11 21m2.8-10L17 2h2l3.2 9h-1.9l-.7-2h-3.2l-.7 2zm3.05-3.35h2.3L18 4z" /></svg>',
                    onclick: () => {
                        webViewer.runDarkMode();
                    }
                }, buttonContainer);
            }

            if (!elements.getAs('#web-bookmarklet-btn-3')) {
                elements.createAs('a', {
                    id: 'web-bookmarklet-btn-3',
                    href: 'javascript:void(0);',
                    className: 'web-icon-btn',
                    title: '繁简转换',
                    innerHTML: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-translate" viewBox="0 0 16 16"><path d="M4.545 6.714 4.11 8H3l1.862-5h1.284L8 8H6.833l-.435-1.286H4.545zm1.634-.736L5.5 3.956h-.049l-.679 2.022H6.18z"/><path d="M0 2a2 2 0 0 1 2-2h7a2 2 0 0 1 2 2v3h3a2 2 0 0 1 2 2v7a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2v-3H2a2 2 0 0 1-2-2V2zm2-1a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h7a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H2zm7.138 9.995c.193.301.402.583.63.846-.748.575-1.673 1.001-2.768 1.292.178.217.451.635.555.867 1.125-.359 2.08-.844 2.886-1.494.777.665 1.739 1.165 2.93 1.472.133-.254.414-.673.629-.89-1.125-.253-2.057-.694-2.82-1.284.681-.747 1.222-1.651 1.621-2.757H14V8h-3v1.047h.765c-.318.844-.74 1.546-1.272 2.13a6.066 6.066 0 0 1-.415-.492 1.988 1.988 0 0 1-.94.31z"/></svg>',
                    onclick: () => {
                        webViewer.runCharConvert();
                    }
                }, buttonContainer);
            }

            if (!elements.getAs('#web-bookmarklet-btn-4')) {
                elements.createAs('a', {
                    id: 'web-bookmarklet-btn-4',
                    href: 'javascript:void(0);',
                    className: 'web-icon-btn',
                    title: '目录导航',
                    innerHTML: '<svg xmlns="http://www.w3.org/2000/svg" width="640" height="640" viewBox="0 0 640 640"><path fill="#555" d="M64 136c0-13.2 10.7-24 24-24h48c13.3 0 24 10.7 24 24v104h24c13.3 0 24 10.7 24 24s-10.7 24-24 24H88c-13.3 0-24-10.7-24-24s10.7-24 24-24h24v-80H88c-13.3 0-24-10.7-24-24m30.4 229.2c11.4-8.6 25.3-13.2 39.6-13.2h4.9c33.7 0 61.1 27.4 61.1 61.1c0 19.6-9.4 37.9-25.2 49.4l-24 17.5H184c13.3 0 24 10.7 24 24s-10.7 24-24 24H93.3C77.1 528 64 514.9 64 498.7c0-9.4 4.5-18.2 12.1-23.7l70.5-51.3c3.4-2.5 5.4-6.4 5.4-10.6c0-7.2-5.9-13.1-13.1-13.1H134c-3.9 0-7.7 1.3-10.8 3.6l-20.8 15.6c-10.6 8-25.6 5.8-33.6-4.8s-5.8-25.6 4.8-33.6zM288 128h256c17.7 0 32 14.3 32 32s-14.3 32-32 32H288c-17.7 0-32-14.3-32-32s14.3-32 32-32m0 160h256c17.7 0 32 14.3 32 32s-14.3 32-32 32H288c-17.7 0-32-14.3-32-32s14.3-32 32-32m0 160h256c17.7 0 32 14.3 32 32s-14.3 32-32 32H288c-17.7 0-32-14.3-32-32s14.3-32 32-32" /></svg>',
                    onclick: () => {
                        webViewer.runTOC();
                    }
                }, buttonContainer);
            }

            if (!elements.getAs('#web-bookmarklet-btn-5')) {
                elements.createAs('a', {
                    id: 'web-bookmarklet-btn-5',
                    href: 'javascript:void(0);',
                    className: 'web-icon-btn',
                    title: '网页字体',
                    innerHTML: '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="#555" d="M7 2a1 1 0 0 1 .94.658l2.882 7.926l-1.11 2.798L9.209 12H4.792l-.852 2.342a1 1 0 0 1-1.88-.684l4.001-11A1 1 0 0 1 7.001 2m-1.48 8h2.962L7 5.926zm9.848-3.472a1 1 0 0 0-1.86 0L8.151 20.022h-.15a1 1 0 1 0 0 2H11a1 1 0 0 0 0-2h-.697L11.106 18h6.653l.8 2.023H18a1 1 0 0 0 0 2h3.009a1 1 0 0 0 0-2h-.298zM16.967 16H11.9l2.537-6.39z" /></svg>',
                    onclick: () => {
                        webViewer.runFontChange();
                    }
                }, buttonContainer);
            }

            this.buttonAdded = true;
        },

        runCharConvert() {
            javascript:(function(){var s = document.getElementById('tongwenlet_script');if(s != null){document.body.removeChild(s);s = document.createElement('script');s.language = 'javascript';s.type = 'text/javascript';if(window.lastTongwenType === 'cn'){s.src = 'https://gcore.jsdelivr.net/gh/runningcheese/Awesome-Bookmarklets/libs/bookmarklet_tw.js';window.lastTongwenType = 'tw';}else{s.src = 'https://gcore.jsdelivr.net/gh/runningcheese/Awesome-Bookmarklets/libs/bookmarklet_cn.js';window.lastTongwenType = 'cn';}}else{s = document.createElement('script');s.language = 'javascript';s.type = 'text/javascript';s.src = 'https://gcore.jsdelivr.net/gh/runningcheese/Awesome-Bookmarklets/libs/bookmarklet_cn.js';window.lastTongwenType = 'cn';}s.id = 'tongwenlet_script';document.body.appendChild(s);})();
        },

        runFontChange() {
            javascript:(function(){const e=document.createElement('div');e.style.cssText='position:fixed;top:20%;right:20%;transform:translate(-50%,0);background:#fff;border:none;border-radius:8px;padding:4px;width:200px;box-shadow:0 4px 12px rgba(0,0,0,0.25);z-index:999999;cursor:move;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif';let t=0,n=0,o=0,i=0,s=!1;e.onmousedown=l=>{s=!0;t=l.clientX;n=l.clientY;o=e.offsetLeft;i=e.offsetTop;e.style.transform='translateX(-50%)'};document.onmousemove=l=>{if(!s)return;const d=l.clientX-t,r=l.clientY-n;e.style.left=o+d+'px';e.style.top=i+r+'px'};document.onmouseup=()=>s=!1;let lastEscTime=0;document.addEventListener('keydown',function(evt){if(evt.key==='Escape'){const now=Date.now();if(now-lastEscTime<=300){e.remove()}lastEscTime=now}});const l=[{title:'▼ 修改网页字体 ×',isTitle:true},{title:'1、衬线字体',code:` document.body.style.fontFamily = "Georgia,Times,Times New Roman,serif";const allElements = document.querySelectorAll('*');allElements.forEach(el =>{if(el !== e && !e.contains(el)){el.style.fontFamily = "Georgia,Times,Times New Roman,serif";}});`},{title:'2、无衬线字体',code:` document.body.style.fontFamily = "Arial,Helvetica,sans-serif";const allElements = document.querySelectorAll('*');allElements.forEach(el =>{if(el !== e && !e.contains(el)){el.style.fontFamily = "Arial,Helvetica,sans-serif";}});`},{title:'3、思源宋体',code:` document.body.style.fontFamily = "Source Han Serif SC,Source Han Serif CN,Source Han Serif,serif";const allElements = document.querySelectorAll('*');allElements.forEach(el =>{if(el !== e && !e.contains(el)){el.style.fontFamily = "Source Han Serif SC,Source Han Serif CN,Source Han Serif,serif";}});`},{title:'4、思源黑体',code:` document.body.style.fontFamily = "Source Han Sans SC,Source Han Sans CN,Source Han Sans,sans-serif";const allElements = document.querySelectorAll('*');allElements.forEach(el =>{if(el !== e && !e.contains(el)){el.style.fontFamily = "Source Han Sans SC,Source Han Sans CN,Source Han Sans,sans-serif";}});`},{title:'5、Seravek 字体',code:` document.body.style.fontFamily = "Seravek,-apple-system,BlinkMacSystemFont,sans-serif";const allElements = document.querySelectorAll('*');allElements.forEach(el =>{if(el !== e && !e.contains(el)){el.style.fontFamily = "Seravek,-apple-system,BlinkMacSystemFont,sans-serif";}});`},{title:'6、苹方字体',code:` document.body.style.fontFamily = "PingFang SC,PingFang TC,PingFang HK,sans-serif";const allElements = document.querySelectorAll('*');allElements.forEach(el =>{if(el !== e && !e.contains(el)){el.style.fontFamily = "PingFang SC,PingFang TC,PingFang HK,sans-serif";}});`},{title:'7、等宽字体',code:` document.body.style.fontFamily = "Menlo,Monaco,Consolas,'Courier New',monospace";const allElements = document.querySelectorAll('*');allElements.forEach(el =>{if(el !== e && !e.contains(el)){el.style.fontFamily = "Menlo,Monaco,Consolas,'Courier New',monospace";}});`},{title:'8、楷体',code:` document.body.style.fontFamily = "KaiTi,楷体,STKaiti,华文楷体,serif";const allElements = document.querySelectorAll('*');allElements.forEach(el =>{if(el !== e && !e.contains(el)){el.style.fontFamily = "KaiTi,楷体,STKaiti,华文楷体,serif";}});`},{title:'9、宋体',code:` document.body.style.fontFamily = "SimSun,宋体,STSong,华文宋体,serif";const allElements = document.querySelectorAll('*');allElements.forEach(el =>{if(el !== e && !e.contains(el)){el.style.fontFamily = "SimSun,宋体,STSong,华文宋体,serif";}});`},{title:'10、恢复默认',code:` document.body.style.fontFamily = "";const allElements = document.querySelectorAll('*');allElements.forEach(el =>{if(el !== e && !e.contains(el)){el.style.fontFamily = "";}});`}];l.forEach((t,idx)=>{const n=document.createElement('div');n.style.cssText=t.isTitle?'display:flex;justify-content:space-between;align-items:center;padding:4px 10px;font-size:14px;color:#333;border-bottom:1px solid #eee;margin-bottom:2px':'cursor:pointer;padding:0px 10px;height:32px;transition:all 0.2s ease;border-radius:6px;font-size:14px;color:#333;display:flex;align-items:center';if(t.isTitle){const o=document.createElement('span');o.textContent='✕';o.style.cssText='cursor:pointer;color:#999;width:20px;height:20px;display:flex;align-items:center;justify-content:center;border-radius:50%;transition:all 0.2s ease';o.onmouseover=()=>o.style.backgroundColor='#dadada';o.onmouseout=()=>o.style.backgroundColor='';o.onclick=()=>e.remove();n.textContent=t.title.replace(' ×','');n.appendChild(o)}else{n.textContent=t.title;n.onmouseover=()=>n.style.backgroundColor='#dadada';n.onmouseout=()=>n.style.backgroundColor='';if(t.url||t.code){n.onclick=o=>{o.preventDefault();if(t.url){window.open(t.url+encodeURIComponent(window.getSelection().toString()||''))}else if(t.code){eval(t.code);}}}}e.appendChild(n)});document.body.appendChild(e)})();
            this.showToast('已切换阅读字体');
        },

        // 启动按钮检查
        startButtonCheck() {
            if (this.buttonCheckInterval) {
                clearInterval(this.buttonCheckInterval);
            }

            this.buttonCheckInterval = setInterval(() => {
                this.addButtons();
            }, 1500);
        },

        // 切换按钮显示/隐藏
        toggleVisibility() {
            this.visible = !this.visible;
            const container = elements.getAs('#web-helper-buttons');
            if (container) {
                container.style.display = this.visible ? 'flex' : 'none';
            } else if (this.visible) {
                this.addButtons();
            }
        },

        // 切换是否自动运行
        toggleAutoRun(key, label) {
            const newState = !GM_getValue(key, false);
            GM_setValue(key, newState);
            this.showToast((newState ? '已开启' : '已关闭') + '自动运行' + label);
            this.registerMenu();
        },

        // 注册脚本菜单命令
        registerMenu() {
            this.menuCommandIds.forEach(id => {
                try { GM_unregisterMenuCommand(id); } catch (e) {}
            });
            this.menuCommandIds = [];

            this.buttonConfigs.forEach(config => {
                const enabled = GM_getValue(config.key, false);
                const id = GM_registerMenuCommand(
                    config.label + ' ' + (enabled ? '✅' : '❌'),
                    () => { this.toggleAutoRun(config.key, config.label); }
                );
                this.menuCommandIds.push(id);
            });
        },

        // 初始化
        init() {
            this.addButtons();
            this.startButtonCheck();

            this.buttonConfigs.forEach(config => {
                if (GM_getValue(config.key, false)) {
                    this.runButtonAction(config.id);
                }
            });
            this.registerMenu();
            console.log('网页助手初始化成功');

            // F8 切换按钮显示/隐藏
            document.addEventListener('keydown', (e) => {
                if (e.key === 'F8') {
                    e.preventDefault();
                    this.toggleVisibility();
                }
            });

            // 监听页面变化
            let lastUrl = location.href;
            new MutationObserver(() => {
                if (lastUrl !== location.href) {
                    lastUrl = location.href;
                    // 延迟处理,等待页面元素加载
                    setTimeout(() => {
                        this.addButtons();
                    }, 800);
                }
            }).observe(document.body, {
                childList: true,
                subtree: true
            });
        }
    };

    webViewer.init();
})();