⭐网页瞬间加载/跳过进度条直接加载网页(附重定向链接优化)⭐

任何链接内容跳过进度条秒加载,并优化删除重定向链接(解决95%的重定向问题,如知乎,微博等),所有参数可高度自定义

スクリプトをインストール?
作者が勧める他のスクリプト

🌙 高级定制网页护眼模式🌙も気に入るかもしれません。

スクリプトをインストール
このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         ⭐网页瞬间加载/跳过进度条直接加载网页(附重定向链接优化)⭐ 
// @namespace    fenda
// @version      1.0.15
// @description  任何链接内容跳过进度条秒加载,并优化删除重定向链接(解决95%的重定向问题,如知乎,微博等),所有参数可高度自定义
// @icon         data:image/png;base64,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
// @author       fenda
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @run-at       document-end
// @license      MPL-2.0
// ==/UserScript==

(function() {
    'use strict';

    /**
     * 添加一个新的样式标签到文档的头部,如果已有同名ID的标签则不执行添加。
     * 
     * @param {string} styleId - 样式标签的ID,用于检查是否已经存在具有相同ID的样式。
     * @param {string} cssRules - 要添加的CSS规则的字符串表示,用于设置style标签的内容。
     */
    function addStyle(styleId, cssRules) {
        if (!document.getElementById(styleId)) {
            const style = document.createElement('style');
            style.id = styleId;
            style.setAttribute('type', 'text/css');
            style.innerHTML = cssRules;
            document.head.appendChild(style);
        }
    }

    function createElementWithStylesAndAttributes(tag, styles, attributes) {
        let element = document.createElement(tag);
        if (styles) {
            Object.assign(element.style, styles);
        }
        if (attributes) {
            for (const key in attributes) {
                if (attributes.hasOwnProperty(key)) {
                    if (key in element) {
                        element[key] = attributes[key];
                    } else {
                        element.setAttribute(key, attributes[key]);
                    }
                }
            }
        }
        return element;
    }

    /* ------------------------------- 以下是脚本的设置面板函数 ------------------------------- */

    /**
     * 主动画循环。
     */
    function animate() {
        if (loadingPanel.style.display === 'block') {
            stats.update();
        }
        requestAnimationFrame(animate);
    }
    /**
     * 检查是否有更新。
     */
    function checkForUpdates() {
        var lastCheckedTime = GM_getValue('lastCheckedTime', 0);
        var currentTime = Date.now();

        if (currentTime - lastCheckedTime >= 3600000) {
            GM_setValue('lastCheckedTime', currentTime);
            var updateURL = "https://update.greasyfork.org/scripts/493851/%E2%AD%90%E7%BD%91%E9%A1%B5%E7%9E%AC%E9%97%B4%E5%8A%A0%E8%BD%BD%E8%B7%B3%E8%BF%87%E8%BF%9B%E5%BA%A6%E6%9D%A1%E7%9B%B4%E6%8E%A5%E5%8A%A0%E8%BD%BD%E7%BD%91%E9%A1%B5%E2%AD%90.meta.js";

            fetch(updateURL).then(function(response) {
                response.text().then(function(text) {
                    var latestVersion = text.match(/@version\s+([^\n]+)/)[1];
                    if (latestVersion) {
                        GM_setValue('latestVersion', latestVersion);
                    }
                });
            }).catch(function(error) {
                console.error('An error occurred while checking for updates:', error);
            });
        }
    }

    /**
     * 创建特性列表项。
     *
     * @param {Array} features - 特性描述列表。
     * @returns {Array} - 转换为HTML元素列表的数组。
     */
    function createFeatureListItems(features) {
        return features.map(feature => {
            let parts = feature.split(',').map(part => part.trim());
            let listItem = createElementWithStylesAndAttributes('div', { width: '85px', height: '32px', lineHeight: '32px', backgroundColor: '#E0E5EC', margin: '3px 0', borderRadius: '5px', boxShadow: 'inset 2px 2px 4px #BECBD8, inset -2px -2px 4px #FFFFFF', textAlign: 'center', userSelect: 'none', whiteSpace: 'nowrap', fontSize: '14px', }, { innerText: parts[0] });
            let featureContainer = createElementWithStylesAndAttributes('div', { display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: 'calc(100% - 6px)', marginTop: '3px', marginLeft: '3px', marginRight: '3px', boxSizing: 'border-box' });
            featureContainer.appendChild(listItem);
            if (parts.includes('information')) {
                function parseMarkdown(mdText) {
                    let htmlText = mdText;
                    htmlText = htmlText.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>"); // 加粗
                    htmlText = htmlText.replace(/\*(.*?)\*/g, "<em>$1</em>"); // 斜体
                    htmlText = htmlText.replace(/##(.*?)\n/g, "<h2>$1</h2>"); // 标题
                    htmlText = htmlText.replace(/\n/g, "<br>"); // 换行
                    htmlText = htmlText.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank">$1</a>'); // 链接
                    return htmlText;
                }
                let infoIcon = createElementWithStylesAndAttributes("div", { position: 'relative', cursor: 'pointer', display: 'flex', alignItems: 'left', justifyContent: 'center' }, { innerHTML: `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>` });
                let infoBox = createElementWithStylesAndAttributes("div", { width: "300px", height: "auto", overflow: "auto", display: "none", position: "absolute", transform: "translateX(-50%)", backgroundColor: "#E0E5EC", borderRadius: "12px", boxShadow: "2px 2px 4px #AEBEC7, -2px -2px 4px #FFFFFF", zIndex: "2000" });
                let parsedContent = parseMarkdown(parts[4]);
                let infoText = createElementWithStylesAndAttributes("div", { padding: "10px", margin: "0", fontSize: "15px", fontWeight: "bold", textAlign: "left", textShadow: "2px 2px 3px rgba(0, 0, 0, 0.2)", color: "#4B5563" }, { innerHTML: parsedContent });

                infoBox.appendChild(infoText);
                document.body.appendChild(infoBox);
                document.addEventListener('mousemove', function(e) {
                    const mouseX = e.pageX;
                    const mouseY = e.pageY;
                    const offsetX = 20;
                    const offsetY = 20;
                    infoBox.style.left = `${mouseX + offsetX}px`;
                    infoBox.style.top = `${mouseY + offsetY}px`;
                });
                featureContainer.appendChild(infoIcon);
                infoIcon.addEventListener('mouseover', function() {
                    infoBox.style.display = 'block';
                });
                infoIcon.addEventListener('mouseout', function() {
                    infoBox.style.display = 'none';
                });
            }
            if (parts.includes('styleSelector')) {
                addStyle("neumorphic-checkbox-style", `
                    .neumorphic-checkbox { -webkit-appearance: none; appearance: none; background-color: #e0e5ec; margin: 0; font: inherit; color: currentColor; width: 30px; height: 30px; border: 2px solid #d1d9e6; border-radius: 4px; transform: translateY(-0.075em); display: grid; place-content: center; }
                    .neumorphic-checkbox { background-color: #ff3b3b; /* red for false */ }
                    .neumorphic-checkbox:checked { background-color: #3bff3b; /* green for true */ border-color: #28a745; box-shadow: inset 3px 3px 5px #b8c4d8, inset -3px -3px 5px #ffffff; }
                    .neumorphic-checkbox + span { vertical-align: middle; }
                `);

                let Selector = GM_getValue(parts[6]);
                let styleSelectorCheckbox = createElementWithStylesAndAttributes("input", {}, {
                    type: "checkbox",
                    checked: Selector || false,
                    className: "neumorphic-checkbox"
                });

                styleSelectorCheckbox.addEventListener("change", function() {
                    GM_setValue(parts[6], styleSelectorCheckbox.checked);

                    // 将背景颜色设置为红色或绿色取决于复选框的状态
                    styleSelectorCheckbox.style.backgroundColor = styleSelectorCheckbox.checked ? '#3bff3b' : '#ff3b3b';
                });

                // 设置初始背景颜色
                styleSelectorCheckbox.style.backgroundColor = Selector ? '#3bff3b' : '#ff3b3b';

                let checkboxContainer = createElementWithStylesAndAttributes("label", { display: 'flex', alignItems: 'center', justifyContent: 'space-between' });
                checkboxContainer.appendChild(styleSelectorCheckbox);
                featureContainer.appendChild(checkboxContainer);
            };

            if (parts.includes('settingButton')) {

                const settingButtonContainer = createElementWithStylesAndAttributes('div', { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '80px', height: '32px', margin: '5px 0' });

                const settingButton = createElementWithStylesAndAttributes('div', { cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', width: '24px', height: '24px', }, { innerHTML: `<svg xmlns="http://www.w3.org/2000/svg" height="1.5em" fill="currentColor" viewBox="0 0 512 512"><path d="M 188 37 Q 192 20 205 10 L 205 10 Q 218 0 235 0 L 277 0 Q 294 0 307 10 Q 320 20 324 37 L 332 71 L 333 71 L 363 53 Q 378 44 394 46 Q 410 48 422 60 L 452 90 Q 464 102 466 118 Q 468 134 459 149 L 441 179 L 441 180 L 475 188 Q 492 192 502 205 Q 512 218 512 235 L 512 277 Q 512 294 502 307 Q 492 320 475 324 L 441 332 L 441 333 L 459 363 Q 468 378 466 394 Q 464 410 452 422 L 422 452 Q 410 464 394 466 Q 378 468 363 459 L 333 441 L 332 441 L 324 475 Q 319 492 307 502 Q 294 512 277 512 L 235 512 Q 218 512 205 502 Q 192 492 188 475 L 180 441 L 179 441 L 149 459 Q 134 468 118 466 Q 102 464 90 452 L 60 422 Q 48 410 46 394 Q 44 378 53 363 L 72 333 L 71 332 L 37 324 Q 20 320 10 307 Q 0 294 0 277 L 0 235 Q 0 218 10 205 Q 20 192 37 188 L 71 180 L 71 179 L 53 149 Q 44 134 46 118 Q 48 102 60 90 L 90 60 Q 102 48 118 46 Q 134 44 149 53 L 179 72 L 180 71 L 188 37 L 188 37 Z M 277 48 L 235 48 L 224 95 Q 220 107 208 112 Q 198 115 188 120 Q 176 125 165 119 L 124 94 L 94 124 L 119 165 Q 126 176 120 188 Q 115 198 112 208 Q 107 220 95 224 L 48 235 L 48 277 L 95 288 Q 107 292 112 304 Q 115 314 120 324 Q 125 336 119 347 L 94 388 L 124 418 L 165 393 Q 176 387 188 392 Q 198 397 208 400 Q 220 405 224 417 L 235 464 L 277 464 L 288 417 Q 292 405 304 400 Q 314 397 324 392 Q 336 387 347 393 L 388 418 L 418 388 L 393 347 Q 387 336 392 324 Q 397 314 400 304 Q 405 292 417 288 L 464 277 L 464 235 L 417 224 Q 405 220 400 208 Q 397 198 392 188 Q 387 176 393 165 L 418 124 L 388 94 L 347 119 Q 336 126 324 120 Q 314 115 304 112 Q 292 107 288 95 L 277 48 L 277 48 Z M 292 163 L 260 355 Q 255 373 237 372 Q 219 367 220 349 L 252 157 Q 257 139 275 140 Q 293 145 292 163 L 292 163 Z M 198 230 L 172 256 L 198 282 Q 210 296 198 310 Q 184 322 170 310 L 130 270 Q 118 256 130 242 L 170 202 Q 184 190 198 202 Q 210 216 198 230 L 198 230 Z M 342 202 L 382 242 Q 394 256 382 270 L 342 310 Q 328 322 314 310 Q 302 296 314 282 L 340 256 L 314 230 Q 302 216 314 202 Q 328 190 342 202 L 342 202 Z" /></svg>` });


                settingButton.addEventListener('click', function() {
                    document.body.style.overflow = 'hidden';
                    const settingParametersPanel = createElementWithStylesAndAttributes('div', { display: 'none', position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', flexDirection: 'column', background: '#E0E5EC', border: '1px solid #BECBD8', borderRadius: '10px', boxShadow: '2px 2px 8px #BECBD8, -2px -2px 8px #FFFFFF', width: '300px', height: '300px', zIndex: '1500' });
                    const settingTitle = createElementWithStylesAndAttributes('div', { fontSize: '16px', fontWeight: 'bold', margin: '10px 0', textAlign: 'center' }, { innerHTML: '重定向调试菜单' });
                    const settingOptions = createElementWithStylesAndAttributes('div', { userSelect: 'none', fontSize: '14px', padding: '10px', textAlign: 'left', whiteSpace: 'nowrap', display: 'flex', flexDirection: 'column', justifyContent: 'space-between', position: 'relative' });
                    const siteLinksOption = createElementWithStylesAndAttributes('div', { cursor: 'pointer', fontSize: '14px', padding: '10px', textAlign: 'left', whiteSpace: 'nowrap', borderBottom: '1px solid #BECBD8' }, { innerHTML: '本站链接' });
                    const parametersOption = createElementWithStylesAndAttributes('div', { cursor: 'pointer', fontSize: '14px', padding: '10px', textAlign: 'left', whiteSpace: 'nowrap' }, { innerHTML: '参数设置' });
                    let count = 1;
                    let preloadedLinks = GM_getValue('preloadedLinks', []);
                    const settingInputBox = createElementWithStylesAndAttributes('div', { fontSize: '13px', id: 'redirectConversionLinks', padding: '10px', flex: '1 1', height: '230px', resize: 'none', borderRadius: '10px', boxShadow: 'inset 2px 2px 4px #a3b1c6, inset -2px -2px 4px #ffffff', overflow: 'auto' }, { innerHTML: preloadedLinks.map(linkData => { return `<div class="styledPanel"> <strong>${count++}.</strong> <br>原链接:${linkData.url} <br>优化后:${linkData.optimizedUrl || linkData.url} <br>重定向参数: ${linkData.redirectParameter} </div> `; }).join('') });
                    addStyle('customDisplayStyles', ` .styledPanel { width: 100%; margin: 5px 0; padding: 10px; box-shadow: 0 0 10px rgba(0, 0, 0, 0.1); white-space: pre-line; /* 允许长单词换行 */ word-wrap: break-word; } `);
                    const settingOptionsContainer = createElementWithStylesAndAttributes('div', { display: 'flex', flexDirection: 'row', overflow: 'hidden', alignItems: 'top', marginRight: '15px' });
                    const settingCloseButton = createElementWithStylesAndAttributes('div', { cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', width: '24px', height: '24px', position: 'absolute', top: '0', right: '0', margin: '10px 0 20px 10px' }, { innerHTML: `<svg xmlns="http://www.w3.org/2000/svg" height="1em" fill="currentColor" viewBox="0 0 334 334"><path d="M 320 48 Q 334 31 320 14 Q 303 0 286 14 L 167 133 L 48 14 Q 31 0 14 14 Q 0 31 14 48 L 133 167 L 14 286 Q 0 303 14 320 Q 31 334 48 320 L 167 201 L 286 320 Q 303 334 320 320 Q 334 303 320 286 L 201 167 L 320 48 L 320 48 Z" /></svg>` });
                    settingOptionsContainer.appendChild(settingOptions);
                    settingOptionsContainer.appendChild(settingInputBox);
                    settingParametersPanel.appendChild(settingTitle);
                    settingParametersPanel.appendChild(settingOptionsContainer);
                    settingParametersPanel.appendChild(settingCloseButton);
                    document.body.appendChild(settingParametersPanel);
                    settingCloseButton.addEventListener('click', function() {
                        const newQueryItemsText = document.getElementById('queryItemsList').value.split(',');
                        console.log(newQueryItemsText);
                        if (newQueryItemsText) {
                            GM_setValue('queryItemsList', newQueryItemsText);
                            showAlert("重定向参数保存成功");
                            console.log(GM_getValue('queryItemsList'));
                        } else {
                            showAlert("请确保输入参数后再保存!");
                        }
                        settingParametersPanel.style.display = 'none';
                        document.body.style.overflow = 'auto';
                    });
                    const originalContent = settingInputBox.innerHTML;
                    siteLinksOption.addEventListener('click', function() {
                        settingInputBox.innerHTML = originalContent;
                    });
                    parametersOption.addEventListener('click', function() {
                        settingInputBox.innerHTML = '';
                        console.log(GM_getValue('queryItemsList'));
                        const joinQueryItems = GM_getValue('queryItemsList').join(',');
                        settingInputBox.innerHTML = `<textarea id="queryItemsList" class="styledPanel" style="height: calc(100% - 20px); width: calc(100%-10px); overflow: auto ;">${joinQueryItems}</textarea>`;
                    });
                    settingParametersPanel.style.display = 'flex';
                    settingOptions.appendChild(siteLinksOption);
                    settingOptions.appendChild(parametersOption);
                });



                settingButtonContainer.appendChild(settingButton);
                featureContainer.appendChild(settingButtonContainer);
            }
            parts.slice(1).forEach((componentType, idx) => {
                let component;
                let defaultValue;
                switch (componentType) {
                    case 'numberPicker':
                        defaultValue = GM_getValue(parts[idx + 2]);
                        component = createUIComponent('numberPicker', { value: defaultValue, min: 0, max: 100, step: 1, key: parts[idx + 2] });
                        break;
                    case 'inputBox':
                        defaultValue = GM_getValue(parts[idx + 2]);
                        component = createUIComponent('inputBox', { type: 'text', value: defaultValue, key: parts[idx + 2] });
                        break;
                    case 'selector':
                        defaultValue = GM_getValue(parts[idx + 2]);
                        component = createUIComponent('selector', { options: optionsArray, key: parts[idx + 2] });
                        break;
                    case 'switch':
                        defaultValue = GM_getValue(parts[idx + 2]);
                        component = createUIComponent('switch', { checked: defaultValue, key: parts[idx + 2] });
                        break;
                    case 'shortcutKeySetting':
                        defaultValue = GM_getValue(parts[idx + 2]);
                        component = createUIComponent('shortcutKeySetting', { value: defaultValue, key: parts[idx + 2] });
                        break;
                    default:
                        break;
                }
                if (component) {
                    featureContainer.appendChild(component);
                }
            });



            return featureContainer;
        });
    }

    /**
     * 创建并初始化特色功能面板。
     *
     * @param {string} id - 该面板的HTML元素ID。
     * @param {number} translateX - 初始移动位置的距离。
     * @returns {HTMLElement} - 创建的特色功能面板元素。
     */
    function createShowcaseFeaturesPanel(id, translateX) {
        let showcaseFeatures = createElementWithStylesAndAttributes('div', { position: "absolute", width: "250px", height: "270px", borderRadius: "15px", display: "flex", alignItems: "flex-start", flexDirection: "column", justifyContent: "flex-start", background: "#E0E5EC", boxShadow: "2px 2px 8px #BECBD8, -2px -2px 8px #FFFFFF", transition: "transform 0.5s ease", transform: `translateX(${translateX}px)`, overflow: "hidden" });
        showcaseFeatures.id = id;
        return showcaseFeatures;
    }

    /**
     * 创建不同的UI组件。
     *
     * @param {string} type - 组件类型。
     * @param {Object} options - 用于创建组件的选项。
     * @param {string} [options.value] - 组件的当前值。
     * @param {Object} options.min - 组件的最小值。
     * @param {Object} options.max - 组件的最大值。
     * @param {Object} options.step - 组件的步长值。
     * @param {Array} options.options - 下拉选项。
     * @param {boolean} options.checked - 开关的选中状态。
     * @returns {HTMLElement} - 相应类型的行内UI组件。
     */
    function createUIComponent(type, options, ) {

        if (type === 'switch') {
            addStyle('optimized-switch-style', `
                .optimizedswitchcontainer input[type="checkbox"] {  width: 0; height: 0; opacity: 0; }
                .optimizedswitchcontainer { position: relative; display: inline-block; width: 34px; height: 14px; }
                .optimizedswitchslider { position: absolute; cursor: pointer; top: 0; bottom: 0; left: 0; right: 0; background-color: #ccc; transition: .4s; }
                .optimizedswitchslider:before { position: absolute; content: ""; height: 20px; width: 20px; left: 0; bottom: -3px; background-color: white; transition: .4s; box-shadow: 0 2px 5px rgba(0,0,0,0.3); }
                .optimizedswitchcontainer input:checked + .optimizedswitchslider { background-color: #00FF00; }
                .optimizedswitchcontainer input:focus + .optimizedswitchslider { box-shadow: 0 0 1px #2196F3; }
                .optimizedswitchcontainer input:checked + .optimizedswitchslider:before { transform: translateX(18px); }
            `);
            let switchContainer = createElementWithStylesAndAttributes("label", {}, {
                className: "optimizedswitchcontainer"
            });

            let switchInput = createElementWithStylesAndAttributes("input", {}, {
                type: "checkbox",
                checked: options.checked || false,
            });

            switchInput.addEventListener("change", function() {
                GM_setValue(options.key, this.checked);
            });

            let switchSlider = createElementWithStylesAndAttributes("span", {}, {
                className: "optimizedswitchslider"
            });

            switchContainer.appendChild(switchInput);
            switchContainer.appendChild(switchSlider);

            return switchContainer;
        } else if (type === 'inputBox') {
            addStyle("neumorphic-style",
                `.neu-display-box { font-size: 14px; background: #e0e5ec; border-radius: 10px; box-shadow: 2px 2px 4px #a3b1c6, -2px -2px 4px #ffffff; transition: all 0.3s; display: flex; justify-content: center; align-items: center; cursor: pointer; width: 80px; height: 30px; overflow: hidden; white-space: nowrap; }
                .neu-input-modal { width: 200px;height: 300px; display: none; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #e0e5ec; border-radius: 10px; box-shadow: 2px 2px 4px #a3b1c6, -2px -2px 4px #ffffff; width: 280px; box-sizing: border-box; justify-content: center; align-items: center; flex-direction: column;z-index: 1500; }
                .neu-text-input, .button-row button { border: none; background: none; outline: none; }
                .neu-text-input { padding: 10px;width: 250px; height: 200px; resize: none; margin-bottom: 10px; border-radius: 10px; box-shadow: inset 2px 2px 4px #a3b1c6, inset -2px -2px 4px #ffffff; }
                .button-row { display: flex; justify-content: space-between; width: calc(100% - 34px); }
                .button-row button { width: 95px; cursor: pointer; background: #e0e5ec; border-radius: 5px;  box-shadow: 2px 2px 4px #a3b1c6, -2px -2px 4px #ffffff; }
                .button-row button:hover { box-shadow: inset 2px 2px 4px #a3b1c6, inset -2px -2px 4px #ffffff; }
            `);

            let modal = createElementWithStylesAndAttributes("div", {}, {
                className: "neu-input-modal",
            });

            let textInput = createElementWithStylesAndAttributes("textarea", {}, {
                className: "neu-text-input",
                value: GM_getValue(options.key) || "",
            });

            let valueDisplay = options.value.join(',').length > 5 ? options.value.join(',').substring(0, 5) + '...' : options.value.join(',') || "点击输入";
            let displayBox = createElementWithStylesAndAttributes("div", { id: "displayBox" }, {
                className: "neu-display-box",
                innerHTML: valueDisplay,
                onclick: function() {
                    modal.style.display = 'flex';
                    textInput.focus();
                    var textLength = textInput.value.length;
                    textInput.setSelectionRange(textLength, textLength);
                }
            });

            let buttonRow = createElementWithStylesAndAttributes("div", {}, {
                className: "button-row",
            });


            let saveButton = createElementWithStylesAndAttributes("button", {}, {
                innerHTML: '保存',
                onclick: function() {
                    modal.style.display = 'none';
                    let userInput = textInput.value.trim();
                    let userDomains = userInput ? userInput.split(',') : [];
                    GM_setValue(options.key, userDomains);
                    updateDomainLists();
                    displayBox.textContent = userDomains.join(',').length > 5 ? userDomains.join(',').substring(0, 5) + '...' : userDomains.join(',') || "点击输入";
                    showAlert('域名已保存!');
                }
            });


            let addDomainButton = createElementWithStylesAndAttributes("button", {}, {
                innerHTML: '添加当前域名到输入框',
                onclick: function() {
                    var domain = window.location.hostname;
                    var domainList = GM_getValue(options.key, []);
                    if (!domainList.includes(domain)) {
                        domainList.push(domain);
                        GM_setValue(options.key, domainList);
                        updateDomainLists();
                        modal.style.display = 'none';
                        textInput.value = domainList.join(',');
                        displayBox.textContent = domainList.join(',').length > 5 ? domainList.join(',').substring(0, 5) + '...' : domainList.join(',');
                        showAlert('域名已保存!');
                    } else {
                        showAlert('域名已存在!');
                    }
                }
            });

            buttonRow.appendChild(saveButton);
            buttonRow.appendChild(addDomainButton);

            modal.appendChild(textInput);
            modal.appendChild(buttonRow);

            document.body.appendChild(modal);

            return displayBox;
        } else if (type === 'selector') {
            addStyle("neumorphic-selector-modal-style",
                `.neu-selector-display {  font-size: 14px; line-height: 32px;height: 32px; width: 80px; background: #e0e5ec; border-radius: 10px; box-shadow: 2px 2px 4px #a3b1c6, -2px -2px 4px #ffffff;cursor: pointer; user-select: none; position: relative; text-align: center; }
                .neu-selector-modal { display: none; position: absolute; background: #e0e5ec; box-shadow: 2px 2px 4px #a3b1c6, -2px -2px 4px #ffffff; border-radius: 10px; z-index: 1000; flex-direction: column; }
                .neu-selector-modal-open { display: flex; }
                .neu-selector-option { font-size: 18px;margin-bottom: 2px;white-space: nowrap; cursor: pointer; user-select: none; text-align: center; width: 70px; box-sizing: border-box; }
                .neu-selector-option:hover { background-color: #d1d9e6; }
            `);

            let selectorDisplay = createElementWithStylesAndAttributes("div", {}, {
                className: "neu-selector-display"
            });

            let modal = createElementWithStylesAndAttributes("div", {}, {
                className: "neu-selector-modal"
            });

            let container = document.createElement("div");
            container.style.position = "relative";

            function selectOption(option) {
                GM_setValue(options.key, option);
                selectorDisplay.textContent = GM_getValue(options.key);
                modal.className = "neu-selector-modal";
            }

            optionsArray.forEach((option) => {
                let optionElement = createElementWithStylesAndAttributes("div", {}, {
                    className: "neu-selector-option",
                    textContent: option,
                    onclick: () => selectOption(option)
                });
                modal.appendChild(optionElement);
            });

            selectorDisplay.addEventListener("click", function(event) {
                event.stopPropagation();
                modal.className = modal.className.includes("neu-selector-modal-open") ? "neu-selector-modal" : "neu-selector-modal neu-selector-modal-open";
                let modalRect = modal.getBoundingClientRect();
                modal.style.left = `-${selectorDisplay.offsetWidth}px`;
                modal.style.top = `${(selectorDisplay.offsetHeight - modalRect.height) / 2}px`;
            });
            document.addEventListener("click", function() {
                modal.className = "neu-selector-modal";
            });
            container.appendChild(selectorDisplay);
            container.appendChild(modal);
            selectorDisplay.textContent = GM_getValue(options.key);

            return container;
        } else if (type === 'shortcutKeySetting') {
            addStyle("shortcutKeySetting-style", `
                .shortcutKeySetting-displayBox { width: 80px; height: 32px; overflow:auto ;background: #e0e5ec; border-radius: 5px; box-shadow: inset 2px 2px 4px #BECBD8, inset -2px -2px 4px #FFFFFF; border: none;  margin: 5px 0; flex: 1; text-align: center; outline: none; width: 80px; }
                .shortcutKeySetting-button { width: 60px; height: 32px; margin-left: 10px; background: #e0e5ec; border-radius: 10px; box-shadow: 2px 2px 4px #a3b1c6, -2px -2px 4px #ffffff; border: none; cursor: pointer; user-select: none; }
                .shortcutKeySetting-container { display: flex; justify-content: space-between; align-items: center; box-sizing: border-box;  }
            `);

            let container = createElementWithStylesAndAttributes('div', {}, {
                className: "shortcutKeySetting-container"
            });

            let shortcutKeyValue = GM_getValue(options.key);
            let displayPlaceholder = shortcutKeyValue ? shortcutKeyValue.toUpperCase() : '快捷键';

            let displayBox = createElementWithStylesAndAttributes('input', {}, {
                type: 'text',
                readOnly: true,
                placeholder: displayPlaceholder,
                className: "shortcutKeySetting-displayBox"
            });

            let setButton = createElementWithStylesAndAttributes('button', {}, {
                innerText: '设定',
                className: "shortcutKeySetting-button"
            });

            setButton.addEventListener('click', function() {
                displayBox.value = '按下任意键...';
                displayBox.disabled = false;
                let keySequence = [];

                let keyDownEvent = function(event) {
                    event.preventDefault();
                    let key = event.key.toLowerCase();
                    if (!keySequence.includes(key)) {
                        keySequence.push(key);
                        displayBox.value = keySequence.join('+').toUpperCase();
                        GM_setValue(options.key, keySequence.join('+'));
                        console.log(GM_getValue(options.key));
                    }
                };

                let keyUpEvent = function() {
                    document.removeEventListener('keydown', keyDownEvent);
                    displayBox.disabled = true;
                    document.removeEventListener('keyup', keyUpEvent);
                };

                document.addEventListener('keydown', keyDownEvent);
                document.addEventListener('keyup', keyUpEvent);
            });

            container.appendChild(displayBox);
            container.appendChild(setButton);

            return container;
        } else if (type === 'numberPicker') {
            addStyle("neumorphic-numberPicker-style",
                `.neu-numberPicker-container { max-width: 121px;width: 100%; height: 32px; display: flex; align-items: center; justify-content: space-between; background: #e0e5ec; border-radius: 10px; box-shadow: 2px 2px 4px #a3b1c6, -2px -2px 4px #ffffff; }
                 .neu-numberPicker-button { background: #e0e5ec; border: none; border-radius: 100%; box-shadow: 2px 2px 4px #a3b1c6, -2px -2px 4px #ffffff; width: 30px; height: 30px; cursor: pointer; font-size: 15px; display: flex; align-items: center; justify-content: center; user-select: none; min-width: 30px;}
                 .neu-numberPicker-button:active {box-shadow: inset 2px 2px 4px #a3b1c6, inset -2px -2px 4px #ffffff; }
                 .neu-numberPicker-value {width: 40px; text-align: center; font-size: 16px; background: transparent; border: none; outline: none; margin: 0 auto;  
            }`);

            let container = createElementWithStylesAndAttributes("div", {}, {
                className: "neu-numberPicker-container"
            });

            let intervalId = null;

            const updateValue = (increment) => {
                let currentValue = parseInt(valueDisplay.value, 10) || 0;
                let newValue = increment ? currentValue + 1 : currentValue - 1;
                if (newValue < 1) {
                    newValue = 1; // 最小值限制
                    showAlert('亲,“1”难道还不够小嘛');
                }
                valueDisplay.value = newValue;
                GM_setValue(options.key, valueDisplay.value);
            };

            const createContinuousButton = (innerHTML, increment) => {
                let button = createElementWithStylesAndAttributes("button", {}, {
                    innerHTML: innerHTML,
                    className: "neu-numberPicker-button"
                });

                button.addEventListener("mousedown", function() {
                    updateValue(increment);
                    intervalId = setInterval(() => updateValue(increment), 200);
                });

                ['mouseup', 'mouseleave'].forEach(event => {
                    button.addEventListener(event, function() {
                        clearInterval(intervalId);
                    });
                });

                return button;
            };

            let currentValue = GM_getValue(options.key, 0);

            let valueDisplay = createElementWithStylesAndAttributes("input", {}, {
                type: "text",
                value: currentValue,
                className: "neu-numberPicker-value",
                oninput: function() {
                    this.value = this.value.replace(/[^0-9]/g, '');
                    GM_setValue(options.key, this.value);
                }
            });

            let minusButton = createContinuousButton('➖', false);
            let plusButton = createContinuousButton('➕', true);

            container.appendChild(minusButton);
            container.appendChild(valueDisplay);
            container.appendChild(plusButton);

            return container;
        } else {
            throw new Error('不支持的UI组件类型');
        }
    }

    /**
     * 创建显示版本信息的元素,并添加到页面中。
     *
     * @returns {HTMLElement} - 包含版本信息和更新日志按钮的元素。
     */
    function createVersionInfoElement() {
        const versionInfo = createElementWithStylesAndAttributes('div', {
            position: 'relative',
            left: '20px',
            width: 'auto',
            bottom: `5px`,
            fontSize: '10px',
            color: '#666',
            display: 'flex',
            marginTop: '10px',
        });

        const currentVersion = '1.0.15';
        versionInfo.innerHTML = `<strong>当前版本:${currentVersion}(最新版本:${GM_getValue('latestVersion', '1.0.15')})</strong>`;

        const updateLogButton = document.createElement('button');
        updateLogButton.innerHTML = '更新日志';
        updateLogButton.style.cssText = 'display: flex; flex-direction: row; flex-wrap: wrap; position: relative; right: 0px; background-color: #e0e5ec; border: none; border-radius: 10px; cursor: pointer;';

        if (updateLogButton) {
            updateLogButton.onclick = fetchAndDisplayVersionHistory;
        }

        versionInfo.appendChild(updateLogButton);

        return versionInfo;
    }

    /**
     * 显示版本历史面板。
     *
     * @param {string} versionHistory - 版本历史内容的HTML字符串。
     */
    function displayVersionHistoryPanel(versionHistory) {
        let versionHistoryPanel = document.getElementById('versionHistoryPanel');
        if (!versionHistoryPanel) {
            versionHistoryPanel = document.createElement('div');
            versionHistoryPanel.id = 'versionHistoryPanel';
            document.body.appendChild(versionHistoryPanel);
        } else {

            versionHistoryPanel.style.display = 'block';
        }
        versionHistoryPanel.innerHTML = `
            <div id="versionHistoryContent" style="padding: 10px; position: relative; width: 300px; height: 300px; overflow: auto; position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); background: #e0e5ec; box-shadow: 0 4px 8px 0 rgba(0,0,0,0.4), 0 6px 20px 0 rgba(0,0,0,0.19); border-radius: 15px; box-sizing: border-box; z-index: 10000; display: block; font-family: Arial, sans-serif;">
                <button id="closeVersionHistory" style="position: absolute; top: 10px; right: 10px; background: none; border: none; cursor: pointer;">
                    <svg xmlns="http://www.w3.org/2000/svg" height="24" fill="currentColor" viewBox="0 0 334 334"><path d="M 320 48 Q 334 31 320 14 Q 303 0 286 14 L 167 133 L 48 14 Q 31 0 14 14 Q 0 31 14 48 L 133 167 L 14 286 Q 0 303 14 320 Q 31 334 48 320 L 167 201 L 286 320 Q 303 334 320 320 Q 334 303 320 286 L 201 167 L 320 48 L 320 48 Z" /></svg>
                </button>
                <h2 style="text-align: center; font-size: 20px; font-weight: bold; color: #333; margin-bottom: 20px; text-shadow: 1px 1px 2px #888;">更新日志</h2>
                ${versionHistory}
            </div>
        `;

        document.getElementById('closeVersionHistory').addEventListener('click', function() {
            versionHistoryPanel.style.display = 'none';
        });
    }

    /**
     * 通过Greasy Fork网站获取版本历史信息并显示在自定义面板中。
     */
    async function fetchAndDisplayVersionHistory() {
        const url = 'https://greasyfork.org/zh-CN/scripts/493851-%E7%BD%91%E9%A1%B5%E7%9E%AC%E9%97%B4%E5%8A%A0%E8%BD%BD-%E8%B7%B3%E8%BF%87%E8%BF%9B%E5%BA%A6%E6%9D%A1%E7%9B%B4%E6%8E%A5%E5%8A%A0%E8%BD%BD%E7%BD%91%E9%A1%B5/versions';

        try {
            const response = await fetch(url);
            const text = await response.text();
            const parser = new DOMParser();
            const doc = parser.parseFromString(text, 'text/html');
            const versionHistory = doc.querySelector('.history_versions');
            if (versionHistory) {
                displayVersionHistoryPanel(versionHistory.innerHTML);
            } else {
                throw new Error('无法找到更新历史信息的元素');
            }
        } catch (error) {
            console.error('Failed to fetch version history', error);
            showAlert('无法获取更新历史,请稍后重试。');
        }
    }

    /**
     * 初始化默认设置并存储。
     */
    function initializeDefaultSettings() {
        const defaultSettings = {
            backToThePreviousPage: "shift+r",
            blacklistDomains: [],
            blackSelector: true,
            concurrentLoadingNumber: 5,
            forward: "shift+f",
            goToTheCorrespondingPage: "shift+e",
            lazyLoadImages: false,
            loadedStyle: "下划线",
            manipulatorBall: true,
            mobileGestures: true,
            previewHoverWindow: false,
            redirectOptimization: true,
            setShortcuts: "shift+s",
            asynchronousResources: true,
            whitelistDomains: [],
            whiteSelector: false,
            maxContentSize: 5,
            maxStorageItems: 100,
            dataCleanupInterval: 1,
            is_loadedStyle: true,
            monitorRefresh: 2,
        };

        Object.keys(defaultSettings).forEach((key) => {
            let currentValue = GM_getValue(key);
            if (currentValue === undefined || currentValue === null) {
                GM_setValue(key, defaultSettings[key]);
            }
        });
    }

    function replaceDownloadLink() {
        if (/lanz/.test(window.location.hostname)) {
            let downloadLinks = document.querySelectorAll('a');
            downloadLinks.forEach(link => {
                if (link.textContent.includes('立即下载')) {
                    let scripts = document.querySelectorAll('script');
                    scripts.forEach(script => {
                        let match = script.textContent.match(/var link = '(.*?)';/);
                        if (match) {
                            let newLink = window.location.hostname + '/' + match[1] + "##";
                            console.log(newLink);
                            link.href = '//' + newLink;
                        }
                    });
                } else if (/下载\(\s*[\d\.]+\s*K\s*\)/.test(link.textContent)) {
                    let scripts = document.querySelectorAll('script');
                    let vkjxld, hyggid;

                    scripts.forEach(script => {
                        let match_vk = script.textContent.match(/var vkjxld = '(.*?)';/);
                        let match_hy = script.textContent.match(/var hyggid = '(.*?)';/);

                        if (match_vk) {
                            vkjxld = match_vk[1];
                        }

                        if (match_hy) {
                            hyggid = match_hy[1];
                        }
                    });

                    if (vkjxld && hyggid) {
                        let newLink = vkjxld + hyggid;
                        console.log(newLink);
                        link.href = newLink;
                    }
                }
            });
        }
    }



    /**
     * 设置当前激活的面板,并对动画进行处理。
     *
     * @param {string} activePanelId - 要激活的面板ID。
     */
    function setActivePanel(activePanelId) {
        if (isAnimating) return;
        isAnimating = true;
        updateActiveIndicator(activePanelId);

        const panelIds = ['panel1', 'panel2', 'panel3']; // 面板ID列表按顺序
        const currentActiveIndex = panelIds.indexOf(currentActivePanelId);
        const targetActiveIndex = panelIds.indexOf(activePanelId);
        const direction = targetActiveIndex > currentActiveIndex ? -1 : 1; // 目标在右边则向左(-1), 否则向右(1)

        // 根据目标和当前激活的面板,计算出移动距离
        let moveDistance = direction * Math.abs(targetActiveIndex - currentActiveIndex) * 290; // 每个面板间隔250px宽度

        // 创建移动函数,面板根据方向和距离移动
        const animatePanel = (panelId, distance) => {
            const panel = document.getElementById(panelId);
            let currentTranslateX = parseFloat(panel.style.transform.replace('translateX(', '').replace('px)', '')) || 0;
            panel.style.transform = `translateX(${currentTranslateX + distance}px)`;
        };

        panelIds.forEach(id => {
            animatePanel(id, moveDistance);
        });

        // 动画结束后,重置面板位置并只显示目标面板
        setTimeout(() => {
            panelIds.forEach(id => {
                const panel = document.getElementById(id);
                panel.style.transform = `translateX(${(panelIds.indexOf(id) - targetActiveIndex) * 270}px)`;
            });
            currentActivePanelId = activePanelId;
            isAnimating = false;
        }, 500);
    }

    /**
     * 在屏幕上显示一段提示信息。
     *
     * @param {string} message - 需要展示的消息。
     */
    function showAlert(message) {
        let alertBox = createElementWithStylesAndAttributes("div", { width: "300px", position: "fixed", bottom: "10px", left: "50%", transform: "translateX(-50%)", backgroundColor: "#E0E5EC", borderRadius: "5px", boxShadow: "2px 2px 2px #AEBEC7, -2px -2px 2px #FFFFFF", zIndex: "2000" });
        let alertText = createElementWithStylesAndAttributes("div", { margin: "0", fontSize: "16px", fontWeight: "bold", textAlign: "center", textShadow: "2px 2px 3px rgba(0, 0, 0, 0.2)", color: "#4B5563" }, { innerText: message });
        alertBox.appendChild(alertText);
        document.body.appendChild(alertBox);

        setTimeout(function() {
            alertBox.style.opacity = "1";
        }, 10);

        setTimeout(function() {
            alertBox.style.opacity = "0";
            alertBox.addEventListener('transitionend', function() {
                document.body.removeChild(alertBox);
            }, { once: true });
        }, 1500);
    }

    /**
     * 性能分析工具的主要类。
     */
    var Stats = function() {
        var currentMode = 0;
        var container = createElementWithStylesAndAttributes('div', { position: 'fixed', bottom: '10px', right: '10px', left: '10px', cursor: 'pointer', opacity: '0.9', zIndex: '10000' });
        container.addEventListener('click', function(event) {
            event.preventDefault();
            showPanel(++currentMode % container.children.length);
        }, false);
        // 初始化性能监视计时
        var startTime = (performance || Date).now(),
            prevTime = startTime;
        var frames = 0;
        // 创建并添加面板
        var fpsPanel = addPanel(new Stats.Panel('FPS', '#0ff', '#002'));
        var msPanel = addPanel(new Stats.Panel('MS', '#0f0', '#020'));
        var memPanel;
        // 判断performance.memory是否可用以监视内存使用
        if (self.performance && self.performance.memory) {
            memPanel = addPanel(new Stats.Panel('MB', '#f08', '#201'));
        }

        showPanel(0);

        function addPanel(panel) {
            container.appendChild(panel.dom);
            return panel;
        }

        function showPanel(mode) {
            for (var i = 0; i < container.children.length; i++) {
                container.children[i].style.display = i === mode ? 'block' : 'none';
            }
            currentMode = mode;
        }
        return {
            dom: container,
            addPanel: addPanel,
            showPanel: showPanel,
            begin: function() {
                startTime = (performance || Date).now();
            },
            end: function() {
                frames++;
                var time = (performance || Date).now();
                msPanel.update(time - startTime, 200);

                if (time > prevTime + GM_getValue('monitorRefresh', 2) * 1000) {
                    fpsPanel.update((frames * 1000) / (time - prevTime), 100);
                    prevTime = time;
                    frames = 0;
                    if (memPanel) {
                        var memory = performance.memory;
                        memPanel.update(memory.usedJSHeapSize / 1048576, memory.jsHeapSizeLimit / 1048576);
                    }
                }
                return time;
            },
            update: function() {
                startTime = this.end();
            }
        };
    };

    /**
     * Stats中的Panel类,用来展示性能数据。
     *
     * @param {string} name - 面板显示的标题。
     * @param {string} fg - 前景色。
     * @param {string} bg - 背景色。
     */
    Stats.Panel = function(name, fg, bg) {
        var min = Infinity,
            max = 0;
        var round = Math.round;
        var pixelRatio = round(window.devicePixelRatio || 1);
        var width = 80 * pixelRatio,
            height = 48 * pixelRatio;
        var textPadding = 3 * pixelRatio,
            textHeight = 2 * pixelRatio;
        var graphX = 3 * pixelRatio,
            graphY = 15 * pixelRatio;
        var graphWidth = 74 * pixelRatio,
            graphHeight = 30 * pixelRatio;
        var canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = height;
        canvas.style.cssText = 'width:80px;height:48px';
        var context = canvas.getContext('2d');
        context.font = 'bold ' + (9 * pixelRatio) + 'px Helvetica,Arial,sans-serif';
        context.textBaseline = 'top';
        context.fillStyle = bg;
        context.fillRect(0, 0, width, height);
        context.fillStyle = fg;
        context.fillText(name, textPadding, textHeight);
        context.fillRect(graphX, graphY, graphWidth, graphHeight);
        context.fillStyle = bg;
        context.globalAlpha = 0.9;
        context.fillRect(graphX, graphY, graphWidth, graphHeight);

        return {
            dom: canvas,
            update: function(value, maxValue) {
                min = Math.min(min, value);
                max = Math.max(max, value);
                context.fillStyle = bg;
                context.globalAlpha = 1;
                context.fillRect(0, 0, width, graphY);
                context.fillStyle = fg;
                context.fillText(round(value) + ' ' + name + ' (' + round(min) + '-' + round(max) + ')', textPadding, textHeight);
                context.drawImage(canvas, graphX + pixelRatio, graphY, graphWidth - pixelRatio, graphHeight, graphX, graphY, graphWidth - pixelRatio, graphHeight);
                context.fillRect(graphX + graphWidth - pixelRatio, graphY, pixelRatio, graphHeight);
                context.fillStyle = bg;
                context.globalAlpha = 0.9;
                context.fillRect(graphX + graphWidth - pixelRatio, graphY, pixelRatio, round((1 - value / maxValue) * graphHeight));
            }

        };
    };

    /**
     * 更新当前激活面板的指示器样式。
     *
     * @param {string} activePanelId - 当前激活的面板ID。
     */
    function updateActiveIndicator(activePanelId) {
        // 首先重置所有按钮的样式
        [settingsParameters, additionalFeatures, shortcutKeys].forEach(button => {
            button.style.fontSize = "20px";
            button.style.textShadow = "none";
        });

        // 根据当前激活的面板ID,将对应按钮的字体放大并添加立体效果
        if (activePanelId === 'panel1') {
            settingsParameters.style.fontSize = "24px";
            settingsParameters.style.textShadow = "1px 1px #888888";
        } else if (activePanelId === 'panel2') {
            additionalFeatures.style.fontSize = "24px";
            additionalFeatures.style.textShadow = "1px 1px #888888";
        } else if (activePanelId === 'panel3') {
            shortcutKeys.style.fontSize = "24px";
            shortcutKeys.style.textShadow = "1px 1px #888888";
        }
    }

    /*-------------以下为重定向优化的具体实现函数-------------*/

    /**
     * 重定向优化的主要参数,每个参数代表重定向的查询参数名称(基本涵盖95%的重定向链接)。
     */
    const queryItems = [
        'url', 'target', 'href', 'tid', 'u', 'goto', 'link',
        'remoteUrl', 'to', 'redirect', 'iv', 'safecheck', 'black',
        'sinaurl', 'newredirectconfirmcgi', 'view', 'go.shtml', 'link',
        'linkout', 'link2', 'go-wild', 'id', 'jump', 'jump.php', 'web',
        'security', 'r', 'redirect_link', 'youtube.com/redirect',
    ];



    if (typeof GM_getValue === 'function') {
        var queryItemsList = GM_getValue('queryItemsList', []);
        var queryItemsLists = [...new Set([...queryItemsList, ...queryItems])];
        GM_setValue('queryItemsList', queryItemsLists);

    }

    /**
     * 额外的重定向判断条件。
     * @param {string} urlObj 
     * @param {HTMLAnchorElement} linkElement 
     * @returns 
     */
    function extractTargetUrl(urlObj, linkElement) {
        if (urlObj.pathname.includes('jump.php')) {
            extractFromJumpPhp(urlObj, linkElement);
            return;
        }

        for (const item of queryItemsList) {
            try {
                const target = urlObj.searchParams.get(item);

                if (target && isValidHttpUrl(decodeURIComponent(target))) {
                    updateLink(target, linkElement, item);
                    return;
                }
            } catch (e) {
                console.error('URI 解码错误:', e);
            }
        }
    }

    /**
     * 单独对jump.php的处理。
     * @param {string} urlObj 
     * @param {HTMLAnchorElement} linkElement 
     */
    function extractFromJumpPhp(urlObj, linkElement) {
        const fullUrl = urlObj.href;
        const targetUrl = fullUrl.substring(fullUrl.indexOf('jump.php?') + 9);
        updateLink(targetUrl, linkElement);
    }

    let preloadedLinks = [];

    /**
     * 对链接优化的主要函数
     * @param {string} target 
     * @param {HTMLAnchorElement} linkElement 
     * @param {string} item
     */
    function updateLink(target, linkElement, item) {
        const originalHref = linkElement.href;
        const linkName = linkElement.textContent || linkElement.innerText;
        try {
            const targetUrl = decodeURIComponent(target);
            if (isValidHttpUrl(targetUrl)) {
                linkElement.href = targetUrl;
                console.log('优化的重定向链接:', originalHref, 'to:', targetUrl);
                preloadedLinks.push({ redirectParameter: item, name: linkName, url: originalHref, optimizedUrl: targetUrl });
                GM_setValue('preloadedLinks', preloadedLinks);
            }
        } catch (e) {
            console.error('URI 解码错误:', e);
        }
    }

    function isValidHttpUrl(string) {
        try {
            const url = new URL(string);
            return url.protocol === "http:" || url.protocol === "https:";
        } catch (_) {
            return false;
        }
    }

    function optimizeRedirects() {
        document.querySelectorAll('a[href]').forEach(link => {
            if (link.dataset.optimized) return;
            try {
                const urlObj = new URL(link.href);
                extractTargetUrl(urlObj, link);
                link.dataset.optimized = true;
            } catch (e) {
                console.error('错误处理链接:', link.href, '; Error:', e);
            }
        });
    }
    /**
     * 初始化重定向链接
     */
    function init() {
        if (GM_getValue('redirectOptimization')) {
            window.addEventListener('load', () => {
                optimizeRedirects();
                replaceDownloadLink();
                setInterval(replaceDownloadLink, 200); // 每0.5秒执行一次
            });
            const observer = new MutationObserver(() => {
                optimizeRedirects();
                replaceDownloadLink();
            });
            observer.observe(document.body, { childList: true, subtree: true });
            window.addEventListener('beforeunload', () => observer.disconnect());
        }
    }

    init();

    /* ----------------------------- 以下为预加载链接的具体代码实现 ---------------------------- */

    /**
     * 为链接添加视觉提醒,指示其已被预加载。
     *
     * @param {HTMLElement} element - 链接元素。
     */
    function addAVisualLinkReminder(element) {
        var href = element.href;
        try {
            var linkURL = new URL(href);
            var currentOrigin = window.location.origin;
            if (linkURL.origin === currentOrigin) {
                if (element.dataset.preloaded && GM_getValue('is_loadedStyle')) {
                    switch (GM_getValue('loadedStyle', "下划线")) {
                        case '下划线':
                            element.style.textDecoration = 'underline';
                            element.style.textDecorationSkipInk = 'none';
                            break;
                        case '高亮':
                            element.style.backgroundColor = 'yellow';
                            break;
                        case '品红':
                            element.style.color = '#FF00FF';
                            break;
                        case '加粗':
                            element.style.fontWeight = 'bold';
                            break;
                        case '边框':
                            element.style.border = '2px solid red';
                            element.style.borderRadius = '4px';
                            break;
                        default:
                            break;
                    }
                }
            }
        } catch (e) {
            console.error('Error adding visual link reminder:', e);
        }
    }

    /**
     * 添加可拖动的图标到页面上。
     */
    function addDraggableIcon() {
        var svgHTML = '<svg id="draggableIcon" style="position: fixed; top: 50%; right: -20px; transform: translateY(-50%); cursor: pointer; z-index: 9999999;" width="50" height="50" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path fill="currentColor" d="M3.464 20.536C4.93 22 7.286 22 12 22c4.714 0 7.071 0 8.535-1.465C22 19.072 22 16.714 22 12s0-7.071-1.465-8.536C19.072 2 16.714 2 12 2S4.929 2 3.464 3.464C2 4.93 2 7.286 2 12c0 4.714 0 7.071 1.464 8.535" opacity=".5"/><path fill="currentColor" d="M12.03 9.53a.75.75 0 0 0-1.06-1.06l-3 3a.75.75 0 0 0 0 1.06l3 3a.75.75 0 1 0 1.06-1.06L9.56 12z"/><path fill="currentColor" d="M16.03 9.53a.75.75 0 0 0-1.06-1.06l-3 3a.75.75 0 0 0 0 1.06l3 3a.75.75 0 1 0 1.06-1.06L13.56 12z"/></svg>',
            div = document.createElement('div');
        div.innerHTML = svgHTML;
        document.body.appendChild(div.firstChild);

        function onDrag(e, move) {
            var startX = ('touches' in e ? e.touches[0] : e).clientX - dragIcon.getBoundingClientRect().left,
                startY = ('touches' in e ? e.touches[0] : e).clientY - dragIcon.getBoundingClientRect().top;

            function dragging(ev) {
                var clientX = ('touches' in ev ? ev.touches[0] : ev).clientX,
                    clientY = ('touches' in ev ? ev.touches[0] : ev).clientY;
                dragIcon.style.left = clientX - startX + 'px';
                dragIcon.style.top = clientY - startY + 'px';
            }

            function endDrag() {
                document.removeEventListener(move ? 'mousemove' : 'touchmove', dragging);
                document.removeEventListener(move ? 'mouseup' : 'touchend', endDrag);
                document.body.style.overflow = '';
                dragIcon.style.transition = '';
                GM_setValue('iconPosition', { left: dragIcon.style.left, top: dragIcon.style.top });
            }
            document.addEventListener(move ? 'mousemove' : 'touchmove', dragging);
            document.addEventListener(move ? 'mouseup' : 'touchend', endDrag);
            document.body.style.overflow = 'hidden';
            dragIcon.style.transition = 'none';
            if (!move) {
                dragIcon.dataset.pressTimer = setTimeout(endDrag, 500);
            }
        }

        var dragIcon = document.getElementById('draggableIcon');
        dragIcon.style.display = 'none';
        var savedPosition = GM_getValue('iconPosition');
        savedPosition && (dragIcon.style.left = savedPosition.left, dragIcon.style.top = savedPosition.top);

        dragIcon.ontouchstart = function(e) {
            onDrag(e, false);
        };
        dragIcon.ontouchend = function() {
            clearTimeout(dragIcon.dataset.pressTimer);
        };
        dragIcon.onmousedown = function(e) {
            e.preventDefault();
            onDrag(e, true);
        };
    }

    /**
     * 将一个链接添加到预加载队列中。
     *
     * @param {string} url - 链接的地址。
     * @param {HTMLElement} element - 对应的链接元素。
     */
    function addToPreloadQueue(url, element) {
        // 增加了对集合中存在性的检查
        if (isInViewport(element) && !preloadSet.has(url)) {
            preloadSet.add(url);
            preloadQueue.push({ url: url, element: element });
        }
    }

    /**
     * 将二进制大对象(blob)转换为Base64编码的字符串。
     *
     * @param {Blob} blob - 需要转换的blob对象。
     * @returns {Promise<string>} - 包含Base64编码字符串的Promise。
     */
    function blobToBase64(blob) {
        return new Promise((resolve, reject) => {
            const reader = new FileReader();
            reader.onloadend = () => resolve(reader.result);
            reader.onerror = e => reject(e);
            reader.readAsDataURL(blob);
        });
    }

    /**
     * 取消一个指定链接的预加载。
     *
     * @param {string} url - 需要取消预加载的链接URL。
     */
    function cancelPreload(url) {
        if (abortControllers[url]) {
            abortControllers[url].abort();
            delete abortControllers[url]; // 删除abortController实例的引用以防内存泄露
            console.log("Preload cancelled for link out of viewport:", url);
            currentPreloads--; // 更新计数
            preloadNext(); // 尝试开始下一个预加载
        }
        // 从预加载队列中移除链接
        preloadQueue = preloadQueue.filter(item => item.url !== url);
        preloadSet.delete(url); // 从预加载集合中移除链接
    }

    /**
     * 检查预加载的锚点链接并添加相应的视觉提醒。
     */
    function checkAndAddBulletsForPreloadedLinks() {
        var links = document.querySelectorAll('a');
        links.forEach(function(link) {
            if (link.dataset.preloaded) {
                addAVisualLinkReminder(link);
            }
        });
    }

    /**
     * 清理预加载队列,移出不符合条件的链接。
     */
    function cleanPreloadQueue() {
        // 清理已经预加载或者不在视口内的链接
        preloadQueue = preloadQueue.filter(item => {
            if (!(isInViewport(document.querySelector(`a[href="${item.url}"]`)) && !document.querySelector(`a[href="${item.url}"]`).dataset.preloaded)) {
                preloadSet.delete(item.url); // 如果不满足条件,则从集合中删除
                return false;
            }
            return true;
        });
    }

    /**
     * 清理已经超时或已经中止的AbortController实例。
     */
    function cleanAbortControllers() {
        // 获取当前时间
        var now = Date.now();

        // 遍历abortControllers对象的属性
        for (var url in abortControllers) {
            // 如果请求已经很久没有响应,那么我们认为它可能已经失效,需要删除控制器
            // 或如果请求已经被中止,亦应删除
            var controller = abortControllers[url];
            if ((controller.timestamp && now - controller.timestamp > 30000) || controller.signal.aborted) { // 30秒或已中止
                delete abortControllers[url];
            }
        }
    }

    /**
     * 防抖函数,用于延迟执行并防止函数在短时间内多次触发。
     *
     * @param {Function} func - 需要防抖的函数。
     * @param {number} wait - 延迟执行的时间,单位为毫秒。
     * @param {boolean} immediate - 是否立即执行。
     * @returns 防抖处理后的函数。
     */
    function debounce(func, wait, immediate) {
        var timeout, called = false;
        return function() {
            var context = this,
                args = arguments;
            var later = function() {
                timeout = null;
                if (!immediate && !called) func.apply(context, args);
                called = false; // 重置调用标志
            };
            var callNow = immediate && !timeout;
            if (callNow) {
                func.apply(context, args);
                called = true; // 立即执行时,设置调用标志
            }
            clearTimeout(timeout);
            timeout = setTimeout(later, wait);
        };
    }

    /**
     * 从IndexedDB数据库中删除旧内容。
     */
    function deleteOldContentFromDB() {
        const now = Date.now();
        const transaction = db.transaction([dbStoreName], 'readwrite');
        const store = transaction.objectStore(dbStoreName);

        var contentRequest = store.getAll();

        contentRequest.onsuccess = function() {
            var contents = contentRequest.result;
            // 如有必要,根据最后访问时间进行排序
            contents.sort((a, b) => b.timestamp - a.timestamp);

            // 判断记录是否超出最大存储量或者是否过期,然后执行删除
            contents.forEach((content, index) => {
                if (now - content.timestamp > dataCleanupInterval || index >= maxStorageItems) { // 检查每一项是否过期或超出容量限制
                    store.delete(content.url);
                }
            });
        };

        contentRequest.onerror = function(event) {
            console.error("Error fetching contents from IndexedDB", event.target.error);
        };
    }

    /**
     * 显示预加载的内容。
     *
     * @param {string} base64Content - 预加载内容的Base64编码。
     * @param {string} url - 内容对应的链接地址。
     */
    function displayPreloadedContent(base64Content, url) {
        if (base64Content.startsWith('data:')) {
            var binary = atob(base64Content.split(',')[1]);
            var array = new Uint8Array(binary.length);
            for (var i = 0; i < binary.length; i++) {
                array[i] = binary.charCodeAt(i);
            }
            var documentEncoding = document.characterSet || 'UTF-8';
            var blobContent = new Blob([array], { type: `text/html;charset=${documentEncoding}` });

            var reader = new FileReader();
            reader.onload = function() {
                var existingFullPageDiv = document.getElementById('fullPageDiv');
                if (existingFullPageDiv) {
                    existingFullPageDiv.parentNode.removeChild(existingFullPageDiv);
                    existingFullPageDiv.remove();
                }

                var fullPageDiv = document.createElement('div');
                fullPageDiv.id = 'fullPageDiv';
                fullPageDiv.style.cssText = `
                    position: fixed;
                    top: 0;
                    left: 0;
                    width: 100%;
                    height: 100%;
                    overflow: auto;
                    z-index: 1000;
                    background: white;
                `;
                fullPageDiv.innerHTML = reader.result;
                toggleDragIconVisibility(true);
                document.body.style.overflow = 'hidden';
                document.body.appendChild(fullPageDiv);
                if (GM_getValue('asynchronousResources')) {
                    var iframe = document.createElement('iframe');
                    iframe.style.cssText = ' top: 0; left: 0; width: 100%; height: 100%; display: block; visibility: hidden;';
                    iframe.src = url;
                    document.body.appendChild(iframe);

                    fullPageDiv.onscroll = function() {
                        if (iframe.contentWindow) {
                            iframe.contentWindow.scrollTo(0, fullPageDiv.scrollY);
                            iframe.contentWindow.scrollTo(0, fullPageDiv.scrollTop);
                        }
                    };

                    iframe.onload = function() {
                        iframe.contentWindow.onscroll = function() {
                            var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
                            fullPageDiv.innerHTML = iframeDocument.documentElement.outerHTML; // 更新内容
                        };
                    }
                }
            };
            reader.readAsText(blobContent, documentEncoding);
        }
    }


    /**
     * 初始化IndexedDB数据库。
     *
     * @param {Function} success - 数据库就绪后执行的回调函数。
     */
    function initDB(success) {
        if (!dbReady) {
            openDB(success);
        } else if (typeof success === 'function') {
            success();
        }
    }

    /**
     * 判断一个元素是否在视口内。
     *
     * @param {HTMLElement} element - 需要判断的HTML元素。
     * @returns {boolean} - 元素是否在视口内。
     */
    function isInViewport(element) {
        var rect = element.getBoundingClientRect();
        var inViewport = (
            rect.top >= 0 &&
            rect.left >= 0 &&
            rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
            rect.right <= (window.innerWidth || document.documentElement.clientWidth)
        );

        if (!inViewport && element.dataset.preloaded) {
            cancelPreload(element.href); // 如果链接不在视窗中并且已被标记为预加载,取消它的预加载
            element.dataset.preloaded = false; // 移除预加载标记
        }

        return inViewport;
    }

    /**
     * 判断当前设备是否为移动设备。
     *
     * @returns {boolean} - 是否为移动设备。
     */
    function isMobileDevice() {
        return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
    }

    /**
     * 使用MutationObserver监听DOM变化。
     */
    function observeDOMChanges() {
        var handledLinks = new Set(); // 用于储存处理过的链接

        var config = { childList: true, subtree: true };
        var callback = function(mutationsList, observer) {
            requestAnimationFrame(function() {
                mutationsList.forEach(debounce(function(mutation) {
                    if (mutation.type == 'childList' && mutation.addedNodes.length) {
                        mutation.addedNodes.forEach(function(node) {
                            if (node.nodeType === 1 && node.matches('a[href]')) {
                                var href = node.getAttribute('href');
                                if (!preloadSet.has(href) && !handledLinks.has(href)) {
                                    preloadLink(href, node);
                                    handledLinks.add(href); // 将链接添加到 handledLinks 中进行标记
                                    preloadSet.add(href); // 将链接添加到 preloadSet 中
                                }
                            }
                        });
                    }
                }, 250));
                preloadVisibleLinks();
            });
        };

        var observer = new MutationObserver(callback);
        observer.observe(document.body, config);
    }

    /**
     * 打开IndexedDB数据库。
     *
     * @param {Function} callback - 数据库打开成功的回调函数。
     */
    function openDB(callback) {
        if (dbInitializationPromise) { // 如果存在初始化的Promise,直接返回它并添加回调
            dbInitializationPromise.then(callback).catch(err => console.error('IndexedDB init error:', err));
            return;
        }

        // 新建一个Promise来处理初始化过程
        dbInitializationPromise = new Promise((resolve, reject) => {
            var request = indexedDB.open(dbName, dbVersion);

            request.onupgradeneeded = function(event) {
                var db = event.target.result;
                if (!db.objectStoreNames.contains(dbStoreName)) {
                    db.createObjectStore(dbStoreName, { keyPath: 'url' });
                }
            };

            request.onsuccess = function(event) {
                db = event.target.result;
                dbReady = true;
                console.log('IndexedDB database opened successfully');
                db.onerror = function(event) {
                    console.error("Database error: " + event.target.error.message);
                };
                resolve(db);
            };

            request.onerror = function(event) {
                console.error('IndexedDB database open error:', event.target.errorCode);
                dbInitializationPromise = null; // 如果Promise失败,我们重置这个变量
                reject(event.target.error);
            };
        });

        // 调用传入的回调函数
        dbInitializationPromise.then(callback).catch(err => console.error('IndexedDB init error:', err));
    }

    /**
     * 将一个链接的属性值视为适当。
     *
     * @param {string} url - 链接的URL地址。
     * @returns {string} - 适当的属性值。
     */
    function appropriateAsAttributeValue(url) {
        if (url.endsWith('.css')) {
            return 'style';
        } else if (url.endsWith('.js')) {
            return 'script';
        } else if (url.match(/(.jpg|.jpeg|.png|.gif)$/)) {
            return 'image';
        } else if (url.endsWith('.json')) {
            return 'fetch';
        } else {
            return 'fetch';
        }
    }

    /**
     * 预加载指定的链接。
     *
     * @param {string} url - 需要预加载的链接URL。
     * @param {HTMLElement} element - 对应的链接元素。
     */
    function preloadLink(url, element) {
        try {
            var linkURL = new URL(url);

            if (linkURL.protocol !== 'http:' && linkURL.protocol !== 'https:') {
                console.log('Not preloading: Non-HTTP link:', url);
                return;
            }
            if (isBlacklistModeEnabled && blacklistDomains.includes(linkURL.hostname)) {
                console.log('Not preloading: Blacklisted domain:', linkURL.hostname);
                return;
            }
            // 跳过与当前页面相同或者跨域的URL
            if (linkURL.hostname !== window.location.hostname || linkURL.href === window.location.href) {
                console.warn('Not preloading: Same page or cross-origin link:', url);
                return;
            }
            if (preloadSet.has(url) || element.dataset.preloaded) {
                console.log('Not preloading: Already preloaded or enqueued for preload:', url);
                return;
            }

            if (currentPreloads < maxConcurrentPreloads) {
                currentPreloads++;
                let options = {
                    cache: "force-cache", // 使用force-cache可以帮助减少不必要的网络请求
                    as: appropriateAsAttributeValue(url), // 根据不同的链接类型,为 'as' 属性设置适当的值
                    credentials: "include",
                    headers: new Headers(window.headers)
                };

                if (element.rel && (element.rel.includes('noreferrer') || element.rel.includes('noopener'))) {
                    options.referrerPolicy = 'no-referrer';
                }

                // 创建一个新的abortController实例,并将signal传给fetch
                var controller = new AbortController();
                controller.timestamp = Date.now();
                var signal = controller.signal;
                options.signal = signal; // 将signal添加到fetch选项中
                abortControllers[url] = controller;

                fetch(linkURL.href, options).then(function(response) {
                    if (!response.ok) {
                        throw new Error('HTTP error, status = ' + response.status);
                    }
                    return response.blob();
                }).then(function(blob) {
                    saveContentToDB(url, blob);
                    addAVisualLinkReminder(element);
                }).catch(function(error) {
                    console.error('Preload failed for ', url, ':', error.message);
                }).finally(function() {
                    currentPreloads--;
                    preloadNext();
                    delete abortControllers[url];
                });
            } else {
                addToPreloadQueue(url, element);
                return;
            }
        } catch (e) {
            console.error('Error preloading link:', e.message);
        }
    }

    /**
     * 继续预加载队列中的下一个链接。
     */
    function preloadNext() {
        if (preloadQueue.length > 0 && currentPreloads < maxConcurrentPreloads) {
            var nextPreload = preloadQueue.shift();
            preloadLink(nextPreload.url, nextPreload.element);
            delete abortControllers[nextPreload.url];
        }
    }

    /**
     * 预加载所有可见的链接。
     */
    function preloadVisibleLinks() {
        if (!isMobileDevice()) {
            return;
        }
        var links = document.querySelectorAll('a');

        var visibleLinks = Array.from(links).filter(function(link) {
            var href = link.href;
            return isInViewport(link) && !link.dataset.preloaded && (shouldPreloadMapping[href] !== false);
        });

        visibleLinks.sort(function(a, b) {
            var aRect = a.getBoundingClientRect();
            var bRect = b.getBoundingClientRect();
            return (window.innerHeight - aRect.bottom) - (window.innerHeight - bRect.bottom);
        });

        var preloadLimit = Math.min(visibleLinks.length, maxConcurrentPreloads - currentPreloads);

        for (var i = 0; i < preloadLimit; i++) {
            (function(linkElement) {
                var href = linkElement.href;
                if (shouldPreloadMapping[href] === undefined) {
                    // 如果该链接的预加载状态尚未决定,则发起检查
                    shouldPreload(linkElement.href).then(function(should) {
                        shouldPreloadMapping[href] = should;
                        if (should && isInViewport(linkElement)) {
                            preloadLink(linkElement.href, linkElement);
                            linkElement.dataset.preloaded = true;
                        }
                    });
                } else if (shouldPreloadMapping[href]) {
                    // 如果已经确定需要预加载,则直接预加载,无需重复检查
                    preloadLink(linkElement.href, linkElement);
                    linkElement.dataset.preloaded = true;
                }
            })(visibleLinks[i]);
        }
    }

    /**
     * 处理数据库写入队列。
     */
    function processDBWriteQueue() {
        if (dbWriteInProgress || dbWriteQueue.length === 0) {
            return;
        }

        dbWriteInProgress = true;
        var item = dbWriteQueue.shift();

        blobToBase64(item.blob).then(base64data => {
            var transaction = db.transaction([dbStoreName], 'readwrite');
            var objectStore = transaction.objectStore(dbStoreName);

            // 处理事务完成
            return new Promise((resolve, reject) => {
                var request = objectStore.put({ url: item.url, htmlContent: base64data, timestamp: Date.now() });
                request.onsuccess = () => resolve();
                request.onerror = () => reject(request.error);
            });
        }).then(() => {
            console.log('Page content saved to IndexedDB for', item.url);
            dbWriteInProgress = false;
            processDBWriteQueue(); // 递归处理队列中的下一项
        }).catch(error => {
            console.error('IndexedDB save operation failed for', item.url, error);
            dbWriteQueue.unshift(item); // 发生错误时重新将项目放入队列
            dbWriteInProgress = false;
            setTimeout(processDBWriteQueue, 1000); // 延迟重试
        });
    }

    /**
     * 从数据库中读取内容。
     *
     * @param {string} url - 内容的URL。
     * @param {Function} callback - 读取到内容后的回调函数。
     */
    function readContentFromDB(url, callback) {
        var transaction = db.transaction([dbStoreName], 'readonly');
        var objectStore = transaction.objectStore(dbStoreName);
        var request = objectStore.get(url);

        request.onsuccess = function(event) {
            callback(event.target.result);
        };

        request.onerror = function(event) {
            console.error('IndexedDB read failed for', url);
            callback(null);
        };
    }

    /**
     * 将内容保存到IndexedDB数据库中。
     *
     * @param {string} url - 内容的URL。
     * @param {Blob} blob - 包含要保存内容的Blob对象。
     */
    function saveContentToDB(url, blob) {
        if (!dbReady) {
            console.error('IndexedDB is not ready for writing data.');
            return;
        }

        if (blob.size > maxContentSize) {
            console.log('Content size exceeds the maxContentSize limit. Not saving to IndexedDB');
            return;
        }

        dbWriteQueue.push({ url, blob });

        if (!dbWriteInProgress) {
            processDBWriteQueue();
        }
    }


    /**
     * 安排下一次数据库内容清理。
     */
    function scheduleNextCleanup() {
        // 删除旧内容后,再次调用此函数以依据当前间隔设定继续调度
        setTimeout(function() {
            deleteOldContentFromDB();
            scheduleNextCleanup();
        }, dataCleanupInterval);
    }

    /**
     * 设置鼠标悬停预加载行为。
     */
    function setupMouseHoverPreload() {
        document.addEventListener('mouseover', function(event) {
            var target = event.target.closest('a');
            if (target && !target.dataset.preloaded) {

                // 判断链接是否指向图片,如果是,就不进行预加载处理
                var href = target.getAttribute('href');

                // 更新正则表达式来匹配 Greasy Fork 的特定图片链接模式
                if (href.match(/\.(jpeg|jpg|gif|png|webp)$/i) ||
                    href.includes("active_storage/blobs/redirect")) {
                    console.log('Skip preloading for image link', href);
                    return; // 如果链接指向图片,直接返回,不设置预加载
                }

                // 鼠标悬停65毫秒以上就启动预加载
                target.dataset.hoverTimeout = setTimeout(function() {
                    shouldPreload(target.href).then(function(shouldPreloadResult) {
                        if (shouldPreloadResult && !target.dataset.preloaded) {
                            preloadLink(target.href, target);
                            target.dataset.preloaded = true; // 设置链接已预加载
                            addAVisualLinkReminder(target); // 添加小圆球指示器
                        }
                    });
                }, 65);
            }
        });

        document.addEventListener('mouseout', function(event) {
            var target = event.target.closest('a');
            if (target && target.dataset.hoverTimeout) {
                // 当鼠标移开时清除定时器
                clearTimeout(target.dataset.hoverTimeout);
                target.dataset.hoverTimeout = null;
            }
        });
    }

    /**
     * 判断一个链接是否应该被预加载。
     *
     * @param {string} url - 需要判断的链接URL。
     * @returns {Promise<boolean>} - 是否应该预加载该链接。
     */
    function shouldPreload(url) {
        if (!(url instanceof URL)) {
            var linkURL = new URL(url);
        }

        if (signoutLinks.some(link => linkURL.pathname.includes(link))) {
            console.log('Not preloading: Signout link:', url);
            return Promise.resolve(false);
        }

        var domain = new URL(url).hostname;

        if (isWhitelistModeEnabled && !whitelistDomains.includes(domain)) {
            return Promise.resolve(false);
        }

        if (isBlacklistModeEnabled && blacklistDomains.includes(domain)) {
            return Promise.resolve(false);
        }
        return fetch(url, { method: 'GET', mode: 'no-cors' })
            .then(function(response) {
                return response.text();
            })
            .then(function(html) {
                // 检查页面是否包含跳转脚本
                var redirectRegex = /window\.location\.href\s*=\s*['"]([^'"]+)['"]/;
                var match = redirectRegex.exec(html);
                if (match && match[1]) {
                    // 页面有跳转,打印消息并返回 false
                    console.log('The page has a redirect script. Skipping preload for:', url);
                    return false;
                }
                // 页面没有跳转,返回 true
                return true;
            })
            .catch(function(error) {
                console.error('Error fetching page for preload check:', error);
                return false;
            });
    }

    /**
     * 切换可拖动图标的显示状态。
     *
     * @param {boolean} show - 是否显示图标。
     */
    function toggleDragIconVisibility(show) {
        var dragIcon = document.getElementById('draggableIcon');
        if (dragIcon) {
            dragIcon.style.display = show ? 'block' : 'none';
        }
    }

    /**
     * 开始预加载链接。
     */
    function startLinkPreloading() {
        initDB(preloadVisibleLinks);
    }

    /**
     * 处理回退导航。
     */
    function handleBackNavigation() {
        if (currentPreviewIndex > 0) {
            currentPreviewIndex -= 1;
            var prevURL = clickedLinks[currentPreviewIndex];

            readContentFromDB(prevURL, function(data) {
                if (data) {
                    displayPreloadedContent(data.htmlContent, prevURL);
                } else {
                    location.href = prevURL;
                }
            });
        } else {
            var fullPageDiv = document.getElementById('fullPageDiv');

            if (fullPageDiv) {
                fullPageDiv.remove();
                toggleDragIconVisibility(false);
                document.body.style.overflow = '';
            }

            clickedLinks = [];
            currentPreviewIndex = -1;
        }
    }

    /**
     * 处理前进导航。
     */
    function handleForwardNavigation() {
        if (currentPreviewIndex < clickedLinks.length - 1) {
            currentPreviewIndex += 1;
            var nextURL = clickedLinks[currentPreviewIndex];

            readContentFromDB(nextURL, function(data) {
                if (data) {
                    displayPreloadedContent(data.htmlContent, nextURL);
                } else {
                    location.href = nextURL;
                }
            });
        }
    }

    /**
     * 导航到URL。
     */
    function navigateToURL() {
        if (clickedLinks.length > 0 && currentPreviewIndex >= 0) {
            var currentURL = clickedLinks[currentPreviewIndex];
            window.location.href = currentURL;
        }
    }

    /*-------------以下为设置面板的具体代码初始化代码-------------*/

    initializeDefaultSettings();
    checkForUpdates();
    var indexedDB = window.indexedDB || window.mozIndexedDB || window.webkitIndexedDB || window.msIndexedDB;
    var dbVersion = 1;
    var dbName = 'preloadedPagesDB';
    var dbStoreName = 'preloadedPages';

    var maxConcurrentPreloads = GM_getValue('concurrentLoadingNumber', 5);
    var dataCleanupInterval = GM_getValue('dataCleanupInterval', 1) * 3600000;
    var maxContentSize = GM_getValue('maxContentSize', 5) * 1024 * 1024;
    var maxStorageItems = GM_getValue('maxStorageItems', 100);
    var isWhitelistModeEnabled = GM_getValue('whiteSelector', false);
    var isBlacklistModeEnabled = GM_getValue('blackSelector', true);
    var defaultBlacklistDomains = [
        'www.bilibili.com',
        'www.bing.com',
        'www.huya.com',
        'www.vimeo.com',
        'www.tiktok.com',
        'www.twitch.tv',
        'www.youtube.com',
        'www.dailymotion.com',
        'www.liveleak.com',
        'www.metacafe.com',
        'www.youku.com',
        'www.iqiyi.com',
        'www.netflix.com',
        'www.hulu.com',
        'www.primevideo.com'
    ];
    const signoutLinks = [
        '/sign_out', // 一般的 sign out 链接
        '/logout', // 常见的登出链接
        '/signoff', // 另一个常见的退出链接
        '/signout', // 没有下划线的 signout 链接
        '/logoff', // log off 形式的退出链接
        '/exit', // exit 链接
        '/user/logout', // 用户目录下的 logout 链接
        '/account/signout', // 帐户目录下的 signout 链接
        '/users/sign_out', // 复数形式 users 的 sign out 链接
        '/session/logout', // session 目录下的 logout 链接
        '/auth/logout', // 认证目录下的 logout 链接
        '/disconnect', // disconnect 形式的退出链接
        '/member/signout', // 会员目录下的 signout 链接
        '/user/sign_out', // 单个用户的 sign out 链接
        '/users/logout', // 复数形式 users 的 logout 链接
        '/sessions/signout', // sessions 目录下的 signout 链接
        '/api/logout', // API 目录下的 logout 链接
        '/app/logout', // APP 目录下的 logout 链接
        '/dashboard/logout', // 仪表盘目录下的 logout 链接
        '/home/logout', // 主页目录下的 logout 链接
        '/profile/logout', // 个人资料目录下的 logout 链接
        '/log_out', // 带下划线的 log out 链接
        '/signoff_user', // 带下划线的 sign off user 链接
    ];

    if (typeof GM_getValue === 'function') {
        var storedBlacklistDomains = GM_getValue('blacklistDomains', []);
        var blacklistDomains = [...new Set([...storedBlacklistDomains, ...defaultBlacklistDomains])]; //将检索到的黑名单与默认黑名单合并,确保没有重复项
        GM_setValue('blacklistDomains', blacklistDomains);

        var whitelistDomains = GM_getValue('whitelistDomains', []);
    }

    function updateDomainLists() {
        blacklistDomains = GM_getValue('blacklistDomains', []);
        whitelistDomains = GM_getValue('whitelistDomains', []);
    }

    var currentPreloads = 0;
    var preloadQueue = [];
    var preloadSet = new Set();
    var abortControllers = {};
    var db;
    var dbReady = false;
    var clickedLinks = [];
    var currentPreviewIndex = -1;
    var dbWriteQueue = [];
    var dbWriteInProgress = false;
    var shouldPreloadMapping = {};
    let touchStartX = 0;
    let touchStartY = 0;
    let iconVisible = false;
    const svgBack = '<svg id="sliderBIcon" style="position: fixed; top: 50%; left: 100%; transform: translateY(-50%); cursor: pointer; z-index: 9999999;" width="100" height="50" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M14.53 7.53a.75.75 0 0 0-1.06-1.06l-5 5a.75.75 0 0 0 0 1.06l5 5a.75.75 0 1 0 1.06-1.06L10.06 12l4.47-4.47Z"/><path fill-rule="evenodd" d="M12 1.25C6.063 1.25 1.25 6.063 1.25 12S6.063 22.75 12 22.75 22.75 17.937 22.75 12 17.937 1.25 12 1.25ZM2.75 12a9.25 9.25 0 1 1 18.5 0 9.25 9.25 0 0 1-18.5 0Z"/></svg>';
    const svgForward = '<svg id="sliderFIcon" style="position: fixed; top: 50%; right: 100%; transform: translateY(-50%); cursor: pointer; z-index: 9999999;" width="100" height="50" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M10.53 6.47a.75.75 0 1 0-1.06 1.06L13.94 12l-4.47 4.47a.75.75 0 1 0 1.06 1.06l5-5a.75.75 0 0 0 0-1.06l-5-5Z"/><path fill-rule="evenodd" d="M12 1.25C6.063 1.25 1.25 6.063 1.25 12S6.063 22.75 12 22.75 22.75 17.937 22.75 12 17.937 1.25 12 1.25ZM2.75 12a9.25 9.25 0 1 1 18.5 0 9.25 9.25 0 0 1-18.5 0Z"/></svg>';
    const divBack = document.createElement('div');
    const divForward = document.createElement('div');
    divBack.innerHTML = svgBack;
    divForward.innerHTML = svgForward;
    document.body.appendChild(divBack);
    document.body.appendChild(divForward);
    var dbInitializationPromise = null;

    let currentActivePanelId = 'panel1';
    let isAnimating = false;
    let loadingPanel = createElementWithStylesAndAttributes('div', { position: "fixed", width: "305px", height: "auto", top: "50%", left: "50%", transform: "translate(-50%, -50%)", zIndex: "1001", backgroundColor: "#E0E5EC", borderRadius: "15px", boxShadow: "2px 2px 8px #BECBD8, -2px -2px 8px #FFFFFF", display: "none", flexDirection: "column" }, { className: 'loadingPanel customFontStyle' });
    let showcaseFeaturesPanel = createElementWithStylesAndAttributes('div', { position: "relative", width: "275px", height: "300px", borderRadius: "15px", display: "flex", alignItems: "center", justifyContent: "center", margin: "10px auto", overflowY: "hidden", overflowX: "hidden", flexWrap: "wrap", background: "#E0E5EC", boxShadow: "inset 9px 9px 16px #BABEC6, inset -9px -9px 16px #FFFFFF" }, { className: "showcaseFeaturesPanel" });
    const versionInfoElement = createVersionInfoElement();
    let font_style = `.customFontStyle *:not([class*='icon']):not(.fa):not(.fas):not(i) { font-family: 'PingFang SC', 'Heiti SC', 'myfont', 'Microsoft YaHei', 'Source Han Sans SC', 'Noto Sans CJK SC', 'HanHei SC', 'sans-serif' ,'icomoon','Icons' ,'brand-icons' ,'FontAwesome','Material Icons','Material Icons Extended','Glyphicons Halflings' !important; text-shadow: 1px 1px 10px #c3c3c3 !important; font-weight: bold !important; }`;
    const parameterFunction = [
        "并发加载数,numberPicker,concurrentLoadingNumber,information,⑴设计原则: 限制同时加载的页面数量,防止某些网页限制了并发数网站限制如:吾爱破解论坛。\n⑵功能: 应对网页限制策略",
        "最大内存项,numberPicker,maxContentSize,information,单位:(MB)\n⑴设计原则: 防止单个预加载页面占用过多内存资源,避免浏览器崩溃或响应缓慢。\n⑵功能: 允许用户设定每个页面预加载内容的内存使用上限,优化资源管理。",
        "最大储存项,numberPicker,maxStorageItems,information,⑴设计原则: 限制缓存预加载内容的数量,以防数据库溢出或过度占用存储空间。\n⑵功能: 用户可自定义预加载内容储存数量上限,以维护存储空间的有效利用。",
        "加载完样式,selector,loadedStyle,information,开关关闭则无提示样式\n⑴设计原则: 增强用户界面友好性,通过视觉反馈让用户明确知晓哪些内容已经被预加载。\n⑵功能: 提供多种可选样式(如下划线、高亮等),用户可以根据个人偏好设置预加载成功后元素的显示方式。,styleSelector,is_loadedStyle",
        "黑名单列表,inputBox,blacklistDomains,information,⑴设计原则: 考虑到不同网页对动态内容加载的特殊要求,通过设定黑名单避免兼容性问题。\n⑵功能: 用户可以指定脚本不适用的网页域名,防止在这些网页上执行可能导致冲突的操作。,styleSelector,blackSelector",
        "白名单列表,inputBox,whitelistDomains,information,⑴设计原则: 为了专注资源和优化特定网站的加载速度,通过白名单机制确保仅在指定域名上启用功能。\n⑵功能: 用户可设定脚本只在特定的网站或页面上运行,从而提高脚本的运行效率和兼容性。,styleSelector,whiteSelector",
    ];

    const additionalFeaturesFunction = [
        "清理间隔项,numberPicker,dataCleanupInterval,information,单位:(小时)\n⑴设计原则: 通过定期清理过期或不常用的缓存数据,减少对存储资源的占用率,防止存储溢出和数据膨胀。⑵功能: 网页长时间不用则自动清理内存缓存,节省存储空间。",
        "异步の资源,switch,asynchronousResources,information,建议电脑开启\n⑴设计原则: 对于异步加载的资源进行实时更新,比如:动态加载的图片等。\n⑵功能: 在本模式下,可以加载出一些异步资源,如果你关闭,那么久不会异步加载资源,但是加载会更流畅。",
        "图片懒加载,switch,lazyLoadImages,information,未完善状态,由于效果并不是特别明显,暂且搁置\n⑴设计原则: 一种提高网页加载速度的技术,通过延迟加载图片,只加载当前可见区域的图片,提高页面加载速度。\n⑵功能: 当用户滚动页面时,提前加载屏幕外一个屏幕距离的图片,提升页面整体加载速度。",
        "重定向优化,switch,redirectOptimization,information,⑴设计原则: 无疑重定向链接是重要的,但它有很多问题如:SEO影响、性能影响、重定循环(恶意钓鱼)等。\n⑵基于此,本选项提供删除重定向的功能,默认的重定向参数已经涵盖95%的重定向链接,你可以快捷方便地自己添加参数,settingButton",
        "监控器刷新,numberPicker,monitorRefresh,information,单位:(秒)\n下方性能监控器点击可切换监控内容\n⑴设计原则: 决定下方的网页性能监控的刷新间隔,保证性能\n⑵功能: 设定刷新监控的间隔时间"
    ];

    const shortcutKeysFunction = [
        "跳转对应页,shortcutKeySetting,goToTheCorrespondingPage",
        "返回上一页,shortcutKeySetting,backToThePreviousPage",
        "设置快捷键,shortcutKeySetting,setShortcuts",
        "前进快捷键,shortcutKeySetting,forward",
        "手势指示器,switch,mobileGestures,information,⑴移动端手势:本插件提供便捷操作方式,如左向右滑动后退,右向左滑动前进。且会显示一个指示器,关闭此选项后,手势操作仍然有效,但不再显示指示器占用屏幕空间",
        "启用操作球,switch,manipulatorBall,information,操作球显示在屏幕右方且仅在预加载页面显示。\n⑴手机用户默认开启手势\n⑵电脑用户默认启用操作球"
    ];

    const optionsArray = ['下划线', '无样式', '高亮', '品红', '加粗', '边框'];
    const title = createElementWithStylesAndAttributes('h1', { color: "#4B5563", textAlign: "center", marginBottom: "10px", marginTop: "10px", fontSize: "24px", fontWeight: "bold", textShadow: "2px 2px 3px rgba(0, 0, 0, 0.2)", userSelect: "none" }, { className: 'title', innerText: '网页瞬间加载' });
    const closeSetting = createElementWithStylesAndAttributes('span', { cursor: 'pointer', marginLeft: '30px', width: '11px', height: '11px', display: 'inline-block', verticalAlign: 'middle' }, { innerHTML: `<svg xmlns="http://www.w3.org/2000/svg" height="1em" fill="currentColor" viewBox="0 0 334 334"><path d="M 320 48 Q 334 31 320 14 Q 303 0 286 14 L 167 133 L 48 14 Q 31 0 14 14 Q 0 31 14 48 L 133 167 L 14 286 Q 0 303 14 320 Q 31 334 48 320 L 167 201 L 286 320 Q 303 334 320 320 Q 334 303 320 286 L 201 167 L 320 48 L 320 48 Z" /></svg>` });
    const settingsParameters = createElementWithStylesAndAttributes('div', { color: "#4B5563", textAlign: "center", marginBottom: "10px", fontSize: "24px", textShadow: "1px 1px #888888", fontWeight: "bold", cursor: "pointer", userSelect: "none" }, { className: 'settingsParameters', innerText: '参数' });
    const additionalFeatures = createElementWithStylesAndAttributes('div', { color: "#4B5563", textAlign: "center", marginBottom: "10px", fontSize: "20px", fontWeight: "bold", cursor: "pointer", userSelect: "none" }, { className: 'additionalFeatures', innerText: '高级' });
    const shortcutKeys = createElementWithStylesAndAttributes('div', { color: "#4B5563", textAlign: "center", marginBottom: "10px", fontSize: "20px", fontWeight: "bold", cursor: "pointer", userSelect: "none" }, { className: 'shortcutKeys', innerText: '操作' });
    const selectTheContainer = createElementWithStylesAndAttributes('div', { display: "flex", justifyContent: "space-around" }, {});
    const showcaseFeaturesPanel1 = createShowcaseFeaturesPanel('panel1', 0);
    const showcaseFeaturesPanel2 = createShowcaseFeaturesPanel('panel2', 280);
    const showcaseFeaturesPanel3 = createShowcaseFeaturesPanel('panel3', 560);

    createFeatureListItems(parameterFunction).forEach(featureElement => {
        showcaseFeaturesPanel1.appendChild(featureElement);
    });
    createFeatureListItems(additionalFeaturesFunction).forEach(featureElement => {
        showcaseFeaturesPanel2.appendChild(featureElement);
    });
    createFeatureListItems(shortcutKeysFunction).forEach(featureElement => {
        showcaseFeaturesPanel3.appendChild(featureElement);
    });

    settingsParameters.addEventListener('click', () => setActivePanel('panel1'));
    additionalFeatures.addEventListener('click', () => setActivePanel('panel2'));
    shortcutKeys.addEventListener('click', () => setActivePanel('panel3'));
    closeSetting.addEventListener('click', () => { loadingPanel.style.display = 'none'; });

    addStyle('custom-font-style', font_style);

    var stats = new Stats();
    stats.dom.style.cssText = 'position: absolute; display: block; bottom: 10px; left: 10px; ';
    showcaseFeaturesPanel2.appendChild(stats.dom);
    stats.showPanel(0);


    settingsParameters.addEventListener('click', () => setActivePanel('panel1'));
    additionalFeatures.addEventListener('click', () => setActivePanel('panel2'));
    shortcutKeys.addEventListener('click', () => setActivePanel('panel3'));
    loadingPanel.appendChild(title);
    title.appendChild(closeSetting);
    selectTheContainer.appendChild(settingsParameters);
    selectTheContainer.appendChild(additionalFeatures);
    selectTheContainer.appendChild(shortcutKeys);
    loadingPanel.appendChild(selectTheContainer);
    loadingPanel.appendChild(showcaseFeaturesPanel);
    loadingPanel.appendChild(versionInfoElement);
    showcaseFeaturesPanel.appendChild(showcaseFeaturesPanel1);
    showcaseFeaturesPanel.appendChild(showcaseFeaturesPanel2);
    showcaseFeaturesPanel.appendChild(showcaseFeaturesPanel3);
    document.body.appendChild(loadingPanel);


    GM_registerMenuCommand('显示/隐藏 参数与功能设置菜单', function() {
        loadingPanel.style.display = loadingPanel.style.display === 'none' ? 'block' : 'none';
    });
    animate();


    document.addEventListener('touchstart', function(e) {
        touchStartX = e.changedTouches[0].screenX;
        touchStartY = e.changedTouches[0].screenY;
    });

    if (GM_getValue('mobileGestures', true)) {
        document.addEventListener('touchmove', function(e) {
            let touchMoveX = e.changedTouches[0].screenX;
            let touchMoveY = e.changedTouches[0].screenY;
            let moveRightDistance = touchMoveX - touchStartX;
            let moveLeftDistance = touchStartX - touchMoveX;
            let moveYDistance = Math.abs(touchMoveY - touchStartY);
            if (moveYDistance > 100) {
                iconVisible = false;
                divForward.firstChild.style.right = '100%';
                divBack.firstChild.style.left = '100%';
                return;
            }
            if (moveRightDistance > 50 && !iconVisible) {
                iconVisible = true;
                divBack.firstChild.style.left = '-20px';
            } else if (moveRightDistance <= 50 && iconVisible) {
                iconVisible = false;
                divBack.firstChild.style.left = '100%';
            }
            if (iconVisible && moveRightDistance <= 100) {
                divBack.firstChild.style.left = `${0.8 * (moveRightDistance - 50)}px`;
            } else if (moveRightDistance > 100) {
                divBack.firstChild.style.left = '-20px';
            }

            if (moveLeftDistance > 50 && !iconVisible) {
                iconVisible = true;
                divForward.firstChild.style.right = '-20px';
            } else if (moveLeftDistance <= 50 && iconVisible) {
                iconVisible = false;
                divForward.firstChild.style.right = '100%';
            }
            if (iconVisible && moveLeftDistance <= 100) {
                divForward.firstChild.style.right = `${0.8 * (moveLeftDistance - 50)}px`;
            } else if (moveLeftDistance > 100) {
                divForward.firstChild.style.right = '-20px';
            }
        });
    }

    document.addEventListener('touchend', function(e) {
        let touchEndX = e.changedTouches[0].screenX;
        let touchEndY = e.changedTouches[0].screenY;
        let touchDistance = touchEndX - touchStartX;
        let touchYDistance = Math.abs(touchEndY - touchStartY);

        if (touchYDistance > 100) {
            return;
        }
        if (touchDistance > 150) {
            handleBackNavigation();
        }
        if (touchDistance < -150) {
            handleForwardNavigation();
        }

        iconVisible = false;
        divBack.firstChild.style.left = '100%';
        divForward.firstChild.style.right = '100%';
    });

    document.addEventListener('keydown', function(e) {
        var returnShortcutKeyString = GM_getValue('backToThePreviousPage', 'shift+r').toLowerCase();
        var returnShortcutKeys = returnShortcutKeyString.split('+').map(key => key.toLowerCase());

        var directShortcutKeyString = GM_getValue('goToTheCorrespondingPage', 'shift+e').toLowerCase();
        var directShortcutKeys = directShortcutKeyString.split('+').map(key => key.toLowerCase());

        var forwardShortcutKey = GM_getValue('forward', 'shift+f').toLowerCase();
        var forwardShortcutKeys = forwardShortcutKey.split('+').map(key => key.toLowerCase());
        var loadingShortcutKey = GM_getValue('setShortcuts', 'shift+s').toLowerCase();
        var loadingShortcutKeys = loadingShortcutKey.split('+').map(key => key.toLowerCase());
        var keyPressed = {
            'alt': e.altKey,
            'shift': e.shiftKey,
            'control': e.ctrlKey,
            'meta': e.metaKey // 对于 Mac 的 Command 键
        };
        keyPressed[e.key.toLowerCase()] = true;

        var returnKeysPressed = returnShortcutKeys.every(key => keyPressed[key]);
        var directKeysPressed = directShortcutKeys.every(key => keyPressed[key]);
        var forwardKeysPressed = forwardShortcutKeys.every(key => keyPressed[key]);
        var loadingKeysPressed = loadingShortcutKeys.every(key => keyPressed[key]);
        if (returnKeysPressed) {
            handleBackNavigation(); // 对应的操作函数
        }
        if (directKeysPressed) {
            navigateToURL(); // 对应的操作函数
        }
        if (forwardKeysPressed) {
            handleForwardNavigation(); // 对应的操作函数
        }
        if (loadingKeysPressed) {
            loadingPanel.style.display = loadingPanel.style.display === 'none' ? 'block' : 'none';
        }
    });

    var debouncedScrollHandler = debounce(function() {
        cleanPreloadQueue();
        cleanAbortControllers();
        preloadVisibleLinks();
        checkAndAddBulletsForPreloadedLinks();
    }, 10);

    var debouncedScrollHandlerPC = debounce(function() {
        cleanPreloadQueue();
        cleanAbortControllers();
        checkAndAddBulletsForPreloadedLinks();
    }, 10);


    document.addEventListener('click', function(event) {
        var target = event.target.closest('a');
        if (target && target.href) {
            event.preventDefault();
            if (event.ctrlKey && !event.shiftKey) {
                // 用户按下了Ctrl键并点击了链接 - 在后台新标签页中打开
                window.open(target.href);
            } else if (event.shiftKey) {
                // 用户按下了Shift键并点击了链接 - 在前台新标签页中打开
                window.open(target.href, '_blank');
            } else {
                // 正常点击 - 不打开新标签页,遵循预加载逻辑以下或直接导航到链接地址
                if (!clickedLinks.includes(target.href)) {
                    clickedLinks.push(target.href);
                }
                currentPreviewIndex = clickedLinks.indexOf(target.href);

                if (target.dataset.preloaded) {
                    readContentFromDB(target.href, function(data) {
                        if (data) {
                            displayPreloadedContent(data.htmlContent, target.href);
                        } else {
                            location.href = target.href;
                        }
                    });
                } else {
                    location.href = target.href;
                }
            }
        }
    });

    observeDOMChanges();
    openDB();
    startLinkPreloading();
    initDB(function() {
        deleteOldContentFromDB();
        scheduleNextCleanup();
    });
    if (isMobileDevice()) {
        GM_setValue('mobileGestures', false);
        window.addEventListener('touchend', debouncedScrollHandler);
        if (GM_getValue('manipulatorBall')) {
            addDraggableIcon();
            document.getElementById('draggableIcon').onclick = handleBackNavigation;
        }
    } else {
        window.addEventListener('scroll', debouncedScrollHandlerPC);
        setupMouseHoverPreload();
        if (GM_getValue('manipulatorBall', true)) {
            addDraggableIcon();
            document.getElementById('draggableIcon').onclick = handleBackNavigation;
        }
    }


})();