NodeSeek Enhance

【NodeSeek增强脚本】全面增强 NodeSeek/DeepFlood 论坛体验。核心功能:自动签到(支持随机/固定鸡腿)、无缝翻页(帖子列表和评论自动加载)、快捷回复(浮动编辑器)、代码高亮(支持亮色/暗色主题)、图片滑动查看。内容管理:屏蔽用户/帖子/分类(支持关键词和正则)、帖子排序(按回复数/查看数/已访问置底)、隐藏元素(页脚/分类标签/帖子信息/推荐轮播/用户统计面板)。界面优化:紧凑模式(1-4列多栏布局,自定义间距/字体/头像大小)、自定义背景图(支持URL/本地上传)、Header/Frame透明度(支持模糊和饱和度)、字体排版自定义(标题/Tag/元数据/内容)、已访问链接标记(可隐藏/置底)、默认头像替换(自动识别系统头像)。增强功能:用户卡片扩展(显示@我/私信/回复通知)、等级标签显示(楼主等级和统计信息)、浏览历史记录(下拉菜单快速访问)、键盘快捷键(左右箭头翻页、Ctrl+Enter提交)、强制新标签页打开帖子、自动跳转外部链接、平滑滚动、即时页面预加载。设置管理:可视化设置面板(集成到导航栏)、设置导入导出、一键恢复默认样式。支持深色模式自动适配。

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

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

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         NodeSeek Enhance
// @namespace    http://www.nodeseek.com/
// @version      1.3
// @description  【NodeSeek增强脚本】全面增强 NodeSeek/DeepFlood 论坛体验。核心功能:自动签到(支持随机/固定鸡腿)、无缝翻页(帖子列表和评论自动加载)、快捷回复(浮动编辑器)、代码高亮(支持亮色/暗色主题)、图片滑动查看。内容管理:屏蔽用户/帖子/分类(支持关键词和正则)、帖子排序(按回复数/查看数/已访问置底)、隐藏元素(页脚/分类标签/帖子信息/推荐轮播/用户统计面板)。界面优化:紧凑模式(1-4列多栏布局,自定义间距/字体/头像大小)、自定义背景图(支持URL/本地上传)、Header/Frame透明度(支持模糊和饱和度)、字体排版自定义(标题/Tag/元数据/内容)、已访问链接标记(可隐藏/置底)、默认头像替换(自动识别系统头像)。增强功能:用户卡片扩展(显示@我/私信/回复通知)、等级标签显示(楼主等级和统计信息)、浏览历史记录(下拉菜单快速访问)、键盘快捷键(左右箭头翻页、Ctrl+Enter提交)、强制新标签页打开帖子、自动跳转外部链接、平滑滚动、即时页面预加载。设置管理:可视化设置面板(集成到导航栏)、设置导入导出、一键恢复默认样式。支持深色模式自动适配。
// @author       bbb
// @match        *://www.nodeseek.com/*
// @match        *://www.deepflood.com/*
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAACz0lEQVR4Ae3B32tVdQAA8M85u7aVHObmzJVD0+ssiphstLEM62CBlCBEIAYhUoGGD/kiRUo+9CIEElFZgZJFSApBVhCUX2WFrVQKf5Qy26SgdK4pN7eZu+cbtyfJ/gLx83HD9SAhlEyXupiPhUSTeonRfNw1ws2aRJeN5jHcolFhJJ9M8Zj99piDTnv12SjzfzIb9dmrC7Pttt8ykjDVLsu8ZZ1GH1oqeDofJLtJh4fMEw3Y72jlCuEO2+W+sNJFr3vOZ1YIi8NIGA29hDWhGgZDJ2Rt2ZvZSBazmMUsZsPZ1qwVQmcYDNWwhtAbRsNIWJx6WLPDfgxNVkm9nR8hm+XduLba7F9RtcXztmUzyY/YJrUqNPvBYc0eSS3CwXxMl4WG7CarsyEuvU2HOkRNujSw3PosxR6DFurKxx3E/akFohPo0aDfEO61os5LdrtLVWG1TzxokifdiSH9GnTjuGhBqsWE39GOo3kVi8wsmeVW00SJ200zA9r0kFcdQzv+MKElVW/S+L5EE86pmUth3BV/SzCOCUjMVXMWzfsSYybVl1SlSlESkagpuOI1nzshFX1gyAF1UKhJEKOkJFVNXVBv+pJoBK1qBkh86z1/SaR+9o5zEgoDaloxsiSart6F1Bkl83ESHWEKvvEbqZJETaokgSH9hCk6cBLtSs6kDqEb/cZ0K+MnO0X/VdhRGUBZjzH9uA+HUl+a0BvmO+J7bVZSKWz1kehqhfe9oWalNoccDmW9JnyV+toxsy3PK3aY9Gx4gMp567ziV4WawpCXra+MEhZ5xqTtecVycxzXlxA22OK4ZYbt9LjvrM5PkNUp6zVPdNpBv1QKwt126Paxp8zwqXu8kG8pYZdHlT2Rvxo2aVG2ObyYn65UnXLKVULZZrP02ZRfCms1OmAXCSHRYqrLzuZFaDFV6s/8omuERs0Kl/LzITVTvTHDeXTD9eAftAsSYhXYOWUAAAAASUVORK5CYII=
// @require      https://s4.zstatic.net/ajax/libs/layui/2.9.9/layui.min.js
// @resource     highlightStyle https://s4.zstatic.net/ajax/libs/highlight.js/11.9.0/styles/atom-one-light.min.css
// @resource     highlightStyle_dark https://s4.zstatic.net/ajax/libs/highlight.js/11.9.0/styles/atom-one-dark.min.css
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_notification
// @grant        GM_getResourceURL
// @grant        GM_addElement
// @grant        GM_addStyle
// @grant        GM_openInTab
// @grant        unsafeWindow
// @run-at       document-start
// @license      GPL-3.0 License
// ==/UserScript==

(function () {
    'use strict';

    const { version, author, name, icon } = GM_info.script;

    const BASE_URL = location.origin;

    const SITE_MAP = {
        "www.nodeseek.com": { code: "ns", name: "NodeSeek", url: "https://www.nodeseek.com/" },
        "www.deepflood.com": { code: "df", name: "DeepFlood", url: "https://www.deepflood.com/" }
    };

    const DEFAULT_COMPACT_MODE = Object.freeze({
        enabled: true,
        columns: 1,
        padding: "6px 10px",
        avatarSize: 26,
        titleFontSize: 13,
        infoFontSize: 10,
        marginBottom: 2
    });

    const COMPACT_MODE_STYLE_ID = 'nsx-compact-mode-style';
    const CUSTOM_BACKGROUND_STYLE_ID = 'nsx-custom-background-style';
    const VISITED_LINK_STYLE_ID = 'nsx-visited-links-style';
    const HEADER_OPACITY_STYLE_ID = 'nsx-header-opacity-style';
    const FRAME_OPACITY_STYLE_ID = 'nsx-frame-opacity-style';
    const TYPOGRAPHY_STYLE_IDS = {
        title: 'nsx-typography-title-style',
        tag: 'nsx-typography-tag-style',
        meta: 'nsx-typography-meta-style',
        content: 'nsx-typography-content-style'
    };

    const escapeCssValue = (value = '') => `${value}`.replace(/"/g, '\\"');

    const INITIAL_OVERLAY_CLASS = 'nsx-initial-hide';
    const INITIAL_OVERLAY_DURATION_DEFAULT = 1200;
    let initialOverlayTimer = null;

    const toggleRootClass = (className, enabled = true) => {
        const root = document.documentElement;
        root.classList.toggle(className, enabled);
        const body = document.body;
        if (body) {
            body.classList.toggle(className, enabled);
            return;
        }
        if (!enabled) return;
        const applyToBody = () => {
            if (document.body) {
                document.body.classList.toggle(className, enabled);
                return true;
            }
            return false;
        };
        if (typeof MutationObserver === 'function') {
            const observer = new MutationObserver((mutations, obs) => {
                if (applyToBody()) {
                    obs.disconnect();
                }
            });
            observer.observe(root, { childList: true });
        } else {
            const onReady = () => {
                applyToBody();
                document.removeEventListener('DOMContentLoaded', onReady);
            };
            document.addEventListener('DOMContentLoaded', onReady, { once: true });
        }
    };

    const addCompactPendingClass = () => {
        const apply = () => {
            document.documentElement.classList.add('nsx-compact-mode-pending');
            document.documentElement.classList.add('nsx-body-hidden');
            document.body?.classList.add('nsx-compact-mode-pending');
            document.body?.classList.add('nsx-body-hidden');
        };
        if (document.body) {
            apply();
        } else {
            document.addEventListener('DOMContentLoaded', apply, { once: true });
        }
    };

    const removeCompactPendingClass = () => {
        document.documentElement.classList.remove('nsx-compact-mode-pending');
        document.documentElement.classList.remove('nsx-body-hidden');
        document.body?.classList.remove('nsx-compact-mode-pending');
        document.body?.classList.remove('nsx-body-hidden');
    };

    const getOverlayStoredSettings = () => {
        const stored = getStoredSettings();
        const overlay = stored && stored.loading_overlay ? stored.loading_overlay : {};
        return {
            enabled: overlay.enabled !== false,
            duration: parseInt(overlay.duration, 10) || INITIAL_OVERLAY_DURATION_DEFAULT
        };
    };

    const createInitialOverlay = (() => {
        let cssInjected = false;
        return (_forceDuration = null, forceEnabled = null) => {
            const storedSettings = getOverlayStoredSettings();
            const enabled = forceEnabled !== null ? forceEnabled : storedSettings.enabled;
            if (!enabled) return;
            if (!cssInjected) {
                GM_addStyle(`
                    html.${INITIAL_OVERLAY_CLASS} body {
                        opacity: 0 !important;
                        transition: opacity 0.4s ease;
                    }
                `);
                cssInjected = true;
            }
            document.documentElement.classList.add(INITIAL_OVERLAY_CLASS);
        };
    })();

    const removeInitialOverlay = () => {
        document.documentElement.classList.remove(INITIAL_OVERLAY_CLASS);
        initialOverlayTimer && clearTimeout(initialOverlayTimer);
    };

    const scheduleRemoveInitialOverlay = (() => {
        let loadHandlerRegistered = false;
        let pendingDuration = INITIAL_OVERLAY_DURATION_DEFAULT;
        let overlayEnabled = true;

        const reveal = () => {
            removeInitialOverlay();
            removeCompactPendingClass();
        };

        const runRemoval = () => {
            initialOverlayTimer && clearTimeout(initialOverlayTimer);
            if (!overlayEnabled) {
                reveal();
                return;
            }
            initialOverlayTimer = setTimeout(() => {
                if (typeof requestAnimationFrame === 'function') {
                    requestAnimationFrame(reveal);
                } else {
                    reveal();
                }
            }, pendingDuration);
        };

        return (duration = INITIAL_OVERLAY_DURATION_DEFAULT, enabled = true) => {
            const delay = Number.isFinite(duration) ? duration : parseInt(duration, 10);
            pendingDuration = Number.isFinite(delay) && delay >= 0 ? delay : INITIAL_OVERLAY_DURATION_DEFAULT;
            overlayEnabled = enabled !== false;

            if (!overlayEnabled) {
                reveal();
                return;
            }

            if (document.readyState === 'complete') {
                runRemoval();
                return;
            }

            if (!loadHandlerRegistered) {
                loadHandlerRegistered = true;
                window.addEventListener('load', runRemoval, { once: true });
            }
        };
    })();

    const ensureStyleElement = (id) => {
        let style = document.getElementById(id);
        if (!style) {
            style = document.createElement('style');
            style.id = id;
            (document.head || document.documentElement).appendChild(style);
        }
        return style;
    };

    const applyCustomBackgroundStyle = (config) => {
        if (!config) {
            const existing = document.getElementById(CUSTOM_BACKGROUND_STYLE_ID);
            if (existing) existing.remove();
            return;
        }
        const style = ensureStyleElement(CUSTOM_BACKGROUND_STYLE_ID);
        style.textContent = `
            body {
                background-image: url("${escapeCssValue(config.url)}") !important;
                background-repeat: ${config.repeat} !important;
                background-position: ${config.position} !important;
                background-size: ${config.size} !important;
                background-attachment: ${config.attachment} !important;
            }
        `;
    };

    const applyVisitedLinkStyle = (config) => {
        if (!config) {
            const existing = document.getElementById(VISITED_LINK_STYLE_ID);
            if (existing) existing.remove();
            return;
        }
        const { lightLink, lightVisited, darkLink, darkVisited } = config;
        const style = ensureStyleElement(VISITED_LINK_STYLE_ID);
        const lightVars = [];
        if (lightLink) lightVars.push(`    --link-color: ${lightLink};`);
        lightVars.push(`    --link-visited-color: ${lightVisited};`);
        const darkVars = [];
        if (darkLink) darkVars.push(`    --link-color: ${darkLink};`);
        darkVars.push(`    --link-visited-color: ${darkVisited};`);
        style.textContent = `
:root {
${lightVars.join('\n')}
}
body.dark-layout {
${darkVars.join('\n')}
}
.post-list .post-title a:visited {
    color: var(--link-visited-color);
}
`;
    };

    const applyHeaderOpacityCSS = (config) => {
        const style = ensureStyleElement(HEADER_OPACITY_STYLE_ID);
        if (!config) {
            style.textContent = '';
            return;
        }
        const clamped = Math.min(1, Math.max(0, config.value ?? 0.92));
        const darkValue = Math.min(1, Math.max(0, clamped - 0.1));
        const blurEnabled = config.blur_enabled !== false;
        const saturateEnabled = config.saturate_enabled !== false;
        const blur = blurEnabled ? Math.max(0, parseFloat(config.blur) || 0) : 0;
        const saturate = saturateEnabled ? Math.max(0, parseFloat(config.saturate) || 0) : 0;
        const blurCSS = blurEnabled ? ` blur(${blur}px)` : '';
        const saturateCSS = saturateEnabled ? ` saturate(${saturate}%)` : '';
        const effectCSS = (blurEnabled || saturateEnabled)
            ? `    backdrop-filter:${saturateCSS || ''}${blurCSS || ''};
    -webkit-backdrop-filter:${saturateCSS || ''}${blurCSS || ''};
`
            : '';
        style.textContent = `
html.nsx-header-opacity body > header,
html.nsx-header-opacity body > header #nsk-head {
    background-color: rgba(255,255,255, ${clamped}) !important;
${effectCSS}}
html.nsx-header-opacity body.dark-layout > header,
html.nsx-header-opacity body.dark-layout > header #nsk-head {
    background-color: rgba(20,20,20, ${darkValue}) !important;
${effectCSS}}
`;
    };
const applyFrameOpacityCSS = (config) => {
        const style = ensureStyleElement(FRAME_OPACITY_STYLE_ID);
        if (!config) {
            style.textContent = '';
            return;
        }
        const clamped = Math.min(1, Math.max(0, config.value ?? 0.95));
        const darkValue = Math.min(1, Math.max(0, clamped - 0.1));
        const blurEnabled = config.blur_enabled !== false;
        const saturateEnabled = config.saturate_enabled !== false;
        const blur = blurEnabled ? Math.max(0, parseFloat(config.blur) || 0) : 0;
        const saturate = saturateEnabled ? Math.max(0, parseFloat(config.saturate) || 0) : 0;
        const blurCSS = blurEnabled ? ` blur(${blur}px)` : '';
        const saturateCSS = saturateEnabled ? ` saturate(${saturate}%)` : '';
        const effectCSS = (blurEnabled || saturateEnabled)
            ? `    backdrop-filter:${saturateCSS || ''}${blurCSS || ''};
    -webkit-backdrop-filter:${saturateCSS || ''}${blurCSS || ''};
`
            : '';
        style.textContent = `
html.nsx-frame-opacity #nsk-body,
html.nsx-frame-opacity .nsk-body,
html.nsx-frame-opacity #nsk-frame,
html.nsx-frame-opacity .nsk-frame {
    background-color: rgba(255,255,255, ${clamped}) !important;
${effectCSS}}
html.nsx-frame-opacity body.dark-layout #nsk-body,
html.nsx-frame-opacity body.dark-layout .nsk-body,
html.nsx-frame-opacity body.dark-layout #nsk-frame,
html.nsx-frame-opacity body.dark-layout .nsk-frame {
    background-color: rgba(20,20,20, ${darkValue}) !important;
${effectCSS}}
`;
    };
        const buildTypographyCSS = (type, config) => {
            const selectors = {
                title: '.post-list .post-title a, .post-title a',
                tag: '.post-list .post-category, .post-category, .post-list .nsk-badge',
                meta: '.post-list .post-info, .post-info, .post-meta-info, .content-info',
                content: '.post-content, .post-content *:not(svg):not(path)'
            };
            const selector = selectors[type];
            if (!selector) return '';
            const declarations = [];
            const normalize = (val) => typeof val === 'string' ? val.trim() : '';
            const fontFamily = normalize(config.fontFamily);
            const fontSize = normalize(config.fontSize);
            const color = normalize(config.color);
            const fontStyle = normalize(config.fontStyle);
            const letterSpacing = normalize(config.letterSpacing);
            const ligatures = normalize(config.ligatures);
            if (fontFamily) declarations.push(`font-family: ${fontFamily} !important;`);
            if (fontSize) declarations.push(`font-size: ${fontSize} !important;`);
            if (color) declarations.push(`color: ${color} !important;`);
            if (fontStyle) declarations.push(`font-style: ${fontStyle} !important;`);
            if (letterSpacing) declarations.push(`letter-spacing: ${letterSpacing} !important;`);
            if (ligatures) declarations.push(`font-variant-ligatures: ${ligatures} !important;`);
            if (declarations.length === 0) return '';
            return `
${selector} {
    ${declarations.join('\n    ')}
}
`;
        };
const applyTypographyStyle = (type, config) => {
        const styleId = TYPOGRAPHY_STYLE_IDS[type];
        if (!styleId) return;
        if (!config || config.enabled === false) {
            const existing = document.getElementById(styleId);
            if (existing) existing.remove();
            return;
        }
        const css = buildTypographyCSS(type, config);
        if (!css.trim()) {
            document.getElementById(styleId)?.remove();
            return;
        }
        const style = ensureStyleElement(styleId);
        style.textContent = css;
    };

    const normalizeCompactConfig = (config = {}) => ({
        enabled: config.enabled !== false,
        columns: parseInt(config.columns, 10) || DEFAULT_COMPACT_MODE.columns,
        padding: config.padding || DEFAULT_COMPACT_MODE.padding,
        avatarSize: parseInt(config.avatarSize, 10) || DEFAULT_COMPACT_MODE.avatarSize,
        titleFontSize: parseInt(config.titleFontSize, 10) || DEFAULT_COMPACT_MODE.titleFontSize,
        infoFontSize: parseInt(config.infoFontSize, 10) || DEFAULT_COMPACT_MODE.infoFontSize,
        marginBottom: parseInt(config.marginBottom, 10) || DEFAULT_COMPACT_MODE.marginBottom
    });

    const buildCompactModeCSS = (config) => {
        const normalized = normalizeCompactConfig(config);
        const columns = normalized.columns;
        const padding = normalized.padding;
        const avatarSize = normalized.avatarSize;
        const titleFontSize = normalized.titleFontSize;
        const infoFontSize = normalized.infoFontSize;
        const marginBottom = normalized.marginBottom;
        const containerWidth = columns > 1 ? `${1080 + (columns - 1) * 400}px` : '1080px';
        const containerWidthNum = columns > 1 ? 1080 + (columns - 1) * 400 : 1080;
        const gridGapX = Math.max(8, marginBottom * 2);
        const iconSize = Math.max(12, infoFontSize - 2);

        return `
            /* 紧凑模式 - 多列布局 */
            html.nsx-compact-mode .nsk-container {
                width: ${containerWidth} !important;
                max-width: 98% !important;
            }
            html.nsx-compact-mode #nsk-body-left {
                flex: 1 !important;
                min-width: 0 !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list {
                display: grid !important;
                grid-template-columns: repeat(${columns}, 1fr) !important;
                gap: ${marginBottom}px ${gridGapX}px !important;
                padding: 4px 0 !important;
            }
            html.nsx-compact-mode #nsk-head {
                position: relative !important;
            }
            html.nsx-compact-mode #nsk-head .search-box {
                position: absolute !important;
                left: 50% !important;
                transform: translateX(-50%) !important;
                margin-left: 0 !important;
                flex: 0 1 170px !important;
                max-width: 290px !important;
                z-index: 2 !important;
                pointer-events: auto !important;
                transition: none !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item {
                padding: ${padding} !important;
                margin-bottom: ${marginBottom}px !important;
                border-bottom: 1px solid rgba(0,0,0,.05) !important;
                display: flex !important;
                flex-direction: row !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .post-title {
                font-size: ${titleFontSize}px !important;
                line-height: 1.35 !important;
                margin-bottom: 3px !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .post-title a {
                font-size: inherit !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .post-info {
                font-size: ${infoFontSize}px !important;
                line-height: 1.25 !important;
                margin-top: 2px !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .avatar-wrapper,
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .avatar-normal {
                width: ${avatarSize}px !important;
                height: ${avatarSize}px !important;
                margin-right: 6px !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .post-list-content {
                margin-left: 6px !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .nsk-badge,
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .role-tag {
                font-size: ${infoFontSize}px !important;
                padding: 1px 4px !important;
                margin: 0 2px !important;
                line-height: 1.1 !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .content-info,
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .post-meta-info {
                margin-top: 1px !important;
                gap: 3px !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .content-info > span,
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .post-meta-info > span {
                margin-right: 4px !important;
            }
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item svg,
            html.nsx-compact-mode #nsk-body-left .post-list .post-list-item .iconpark-icon {
                width: ${iconSize}px !important;
                height: ${iconSize}px !important;
            }
            html.nsx-compact-mode .nsx-user-stats {
                font-size: ${infoFontSize - 1}px !important;
                margin-top: 1px !important;
                gap: 3px !important;
            }
            html.nsx-compact-mode .nsx-user-stats span {
                font-size: inherit !important;
            }
            @media screen and (max-width: 1400px) {
                html.nsx-compact-mode .nsk-container {
                    width: auto !important;
                    max-width: 98% !important;
                }
                html.nsx-compact-mode #nsk-body-left .post-list {
                    grid-template-columns: repeat(${Math.min(columns, 3)}, 1fr) !important;
                }
            }
            @media screen and (max-width: 1200px) {
                html.nsx-compact-mode #nsk-body-left .post-list {
                    grid-template-columns: repeat(${Math.min(columns, 2)}, 1fr) !important;
                }
            }
            @media screen and (max-width: 800px) {
                html.nsx-compact-mode #nsk-body-left .post-list {
                    grid-template-columns: 1fr !important;
                }
                html.nsx-compact-mode #nsk-head .search-box {
                    position: static !important;
                    transform: none !important;
                    left: auto !important;
                    margin-left: auto !important;
                    flex: 0 1 auto !important;
                    transition: none !important;
                }
            }
            html.nsx-compact-mode #nsk-body-left .post-list .blocked-post,
            html.nsx-compact-mode #nsk-body-left .post-list-item.blocked-post {
                display: none !important;
            }
            
            /* 紧凑模式下调整快速导航按钮位置,根据容器宽度动态计算 */
            html.nsx-compact-mode #fast-nav-button-group {
                right: calc(50% - ${Math.floor(containerWidthNum / 2)}px + 20px) !important;
            }
            
            /* 响应式调整 */
            @media screen and (max-width: 1400px) {
                html.nsx-compact-mode #fast-nav-button-group {
                    right: calc(50% - ${Math.floor(Math.min(containerWidthNum, 1480) / 2)}px + 20px) !important;
                }
            }
            @media screen and (max-width: 1200px) {
                html.nsx-compact-mode #fast-nav-button-group {
                    right: calc(50% - ${Math.floor(Math.min(containerWidthNum, 1280) / 2)}px + 20px) !important;
                }
            }
            @media screen and (max-width: 800px) {
                html.nsx-compact-mode #fast-nav-button-group {
                    right: 30px !important;
                }
            }
        `;
    };

    const applyCompactModeStyleFromConfig = (config, options = {}) => {
        const { delayReveal = false } = options;
        if (!config) {
            const existing = document.getElementById(COMPACT_MODE_STYLE_ID);
            if (existing) existing.remove();
            removeCompactPendingClass();
            return;
        }
        const style = ensureStyleElement(COMPACT_MODE_STYLE_ID);
        style.textContent = buildCompactModeCSS(config);
        if (!delayReveal) {
            requestAnimationFrame(removeCompactPendingClass);
        }
    };

    const injectBaseUtilityStyles = (() => {
        let injected = false;
        return () => {
            if (injected) return;
            injected = true;
            GM_addStyle(`
                html.nsx-hide-footer footer {
                    display: none !important;
                }
                html.nsx-hide-post-category .post-category,
                html.nsx-hide-post-category a.info-item.post-category {
                    display: none !important;
                }
                html.nsx-hide-post-info .post-info {
                    display: none !important;
                }
                html.nsx-hide-topic-carousel .topic-carousel-wrapper {
                    display: none !important;
                }
                html.nsx-body-hidden,
                body.nsx-body-hidden {
                    visibility: hidden !important;
                }
                .nsx-right-panel-highlight {
                    background-color: #ffeb3b !important;
                    color: #000 !important;
                    padding: 1px 2px !important;
                    border-radius: 2px !important;
                    font-weight: inherit !important;
                    text-decoration: inherit !important;
                    display: inline !important;
                }
                body.dark-layout .nsx-right-panel-highlight {
                    background-color: #f57f17 !important;
                    color: #fff !important;
                }
                /* 确保在链接中也能正确显示 */
                a .nsx-right-panel-highlight,
                .post-title .nsx-right-panel-highlight,
                .post-title a .nsx-right-panel-highlight,
                mark.nsx-right-panel-highlight {
                    background-color: #ffeb3b !important;
                    color: #000 !important;
                    padding: 1px 2px !important;
                    border-radius: 2px !important;
                    display: inline !important;
                }
                body.dark-layout a .nsx-right-panel-highlight,
                body.dark-layout .post-title .nsx-right-panel-highlight,
                body.dark-layout .post-title a .nsx-right-panel-highlight,
                body.dark-layout mark.nsx-right-panel-highlight {
                    background-color: #f57f17 !important;
                    color: #fff !important;
                }
                .nsx-highlight-input-panel textarea {
                    font-family: inherit;
                    width: 100%;
                    box-sizing: border-box;
                }
                .nsx-highlight-input-panel label {
                    user-select: none;
                }
                .nsx-highlight-input-panel code {
                    background-color: rgba(0, 0, 0, 0.05);
                    border-radius: 3px;
                    padding: 2px 4px;
                    font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
                    font-size: 11px;
                    color: #e83e8c;
                }
                body.dark-layout .nsx-highlight-input-panel code {
                    background-color: rgba(255, 255, 255, 0.1);
                    color: #ff6b9d;
                }
            `);
        };
    })();

    // 早期注入紧凑模式样式,避免页面闪烁
    // 在脚本最开始就读取配置并注入样式
    const getStoredSettings = () => {
        try {
            const stored = GM_getValue('settings');
            return stored || null;
        } catch (e) {
            return null;
        }
    };

    const getCompactModeConfig = () => {
        const stored = getStoredSettings();
        if (!stored) return normalizeCompactConfig({ ...DEFAULT_COMPACT_MODE });
        const compactMode = stored.compact_mode ?? {};
        if (compactMode.enabled === false) return null;
        return normalizeCompactConfig({ ...DEFAULT_COMPACT_MODE, ...compactMode });
    };

    const getVisitedLinksStoredConfig = () => {
        const stored = getStoredSettings();
        if (!stored) return null;
        const cfg = stored.visited_links || {};
        if (cfg.enabled === false) return null;
        return {
            lightLink: (cfg.link_color || '').trim(),
            lightVisited: (cfg.visited_color || '').trim() || '#afb9c1',
            darkLink: (cfg.dark_link_color || '').trim(),
            darkVisited: (cfg.dark_visited_color || '').trim() || cfg.visited_color || '#393f4e'
        };
    };

    const getCustomBackgroundStoredConfig = () => {
        const stored = getStoredSettings();
        if (!stored) return null;
        const cfg = stored.custom_background || {};
        if (cfg.enabled === false || !cfg.url) return null;
        return {
            url: cfg.url,
            repeat: cfg.repeat || 'repeat',
            position: cfg.position || 'center',
            size: cfg.size || 'cover',
            attachment: cfg.attachment || 'scroll'
        };
    };

    const getHeaderOpacityStoredConfig = () => {
        const stored = getStoredSettings();
        if (!stored) return null;
        return stored.header_opacity || null;
    };

    const getFrameOpacityStoredConfig = () => {
        const stored = getStoredSettings();
        if (!stored) return null;
        return stored.frame_opacity || null;
    };

    const applyEarlyVisibilityClasses = () => {
        const stored = getStoredSettings();
        if (!stored) return;
        if (stored.hide_footer?.enabled) toggleRootClass('nsx-hide-footer', true);
        if (stored.hide_post_category?.enabled) toggleRootClass('nsx-hide-post-category', true);
        if (stored.hide_post_info?.enabled) toggleRootClass('nsx-hide-post-info', true);
        if (stored.hide_topic_carousel?.enabled) toggleRootClass('nsx-hide-topic-carousel', true);
        if (stored.remove_promotions?.enabled) toggleRootClass('nsx-remove-promotions', true);
        if (stored.visited_links?.hide_visited) toggleRootClass('nsx-hide-visited', true);
    };

    const applyEarlyVisitedLinksStyle = () => {
        const config = getVisitedLinksStoredConfig();
        if (!config) return;
        applyVisitedLinkStyle(config);
    };

    const applyEarlyCustomBackgroundStyle = () => {
        const config = getCustomBackgroundStoredConfig();
        if (!config) return;
        applyCustomBackgroundStyle(config);
    };

    const applyEarlyHeaderOpacityStyle = () => {
        const config = getHeaderOpacityStoredConfig();
        if (!config || config.enabled !== true) return;
        toggleRootClass('nsx-header-opacity', true);
        applyHeaderOpacityCSS(config);
    };

    const applyEarlyFrameOpacityStyle = () => {
        const config = getFrameOpacityStoredConfig();
        if (!config || config.enabled !== true) return;
        toggleRootClass('nsx-frame-opacity', true);
        applyFrameOpacityCSS(config);
    };

    // 立即注入早期样式
    injectBaseUtilityStyles();

    const injectEarlyCompactModeStyle = () => {
        const overlaySettings = getOverlayStoredSettings();
        const overlayEnabled = overlaySettings.enabled;
        if (overlayEnabled) {
            createInitialOverlay(null, true);
        } else {
            removeInitialOverlay();
        }
        const config = getCompactModeConfig();
        if (!config) {
            removeCompactPendingClass();
            return;
        }
        addCompactPendingClass();
        toggleRootClass('nsx-compact-mode', true);
        applyCompactModeStyleFromConfig(config, { delayReveal: overlayEnabled });
        if (overlayEnabled) {
            scheduleRemoveInitialOverlay(overlaySettings.duration, true);
        }
    };

    // 立即执行
    injectEarlyCompactModeStyle();
    applyEarlyVisibilityClasses();
    applyEarlyVisitedLinksStyle();
    applyEarlyCustomBackgroundStyle();
    applyEarlyHeaderOpacityStyle();
    applyEarlyFrameOpacityStyle();

    const onDocumentReady = (fn) => {
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', fn, { once: true });
        } else {
            fn();
        }
    };

    class BroadcastManager {
        static instances = new Map();

        constructor(channelName = "nsx_channel") {
            if (BroadcastManager.instances.has(channelName)) {
                return BroadcastManager.instances.get(channelName);
            }

            this.channelName = channelName;
            this.myId = `${Date.now()}-${Math.random()}`;
            this.receivers = [];
            this.ch = new BroadcastChannel(channelName);
            this.KEY = `only_last_tab_${channelName}`;

            // 广播接收
            this.ch.onmessage = e => this.receivers.forEach(fn => fn(e.data));

            // 主控权管理
            localStorage.setItem(this.KEY, this.myId);
            this.updateActive();

            // 事件监听
            addEventListener("storage", e => {
                if (e.key === this.KEY) {
                    e.newValue || localStorage.setItem(this.KEY, this.myId);
                    this.updateActive();
                }
            });

            addEventListener("beforeunload", () => {
                this.active && localStorage.removeItem(this.KEY);
            });

            BroadcastManager.instances.set(channelName, this);
        }

        updateActive() {
            this.active = localStorage.getItem(this.KEY) === this.myId;
        }

        registerReceiver(fn) {
            this.receivers.push(fn);
        }

        broadcast(data) {
            const message = { sender: this.myId, data };
            this.ch.postMessage(message);
            this.receivers.forEach(fn => fn(message));
        }

        startTask(taskFn, interval) {
            setInterval(async () => {
                if (this.active) {
                    try {
                        this.broadcast(await taskFn());
                    } catch (err) {
                        // console.error(`[Tab ${this.myId}] 任务出错:`, err);
                    }
                }
            }, interval);
        }
    }

    const util = {
        clog:(c) => {
            // console.group(`%c %c [${name}]-v${version} by ${author}`, `background:url(${icon}) center/12px no-repeat;padding:3px`, "");
            // console.log(c);
            // console.groupEnd();
        },
        getValue: (name, defaultValue) => GM_getValue(name, defaultValue),
        setValue: (name, value) => GM_setValue(name, value),
        sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
        addStyle(id, tag, css) {
            tag = tag || 'style';
            let doc = document, styleDom = doc.head.querySelector(`#${id}`);
            if (styleDom) return;
            let style = doc.createElement(tag);
            style.rel = 'stylesheet';
            style.id = id;
            tag === 'style' ? style.innerHTML = css : style.href = css;
            doc.head.appendChild(style);
        },
        removeStyle(id,tag){
            tag = tag || 'style';
            let doc = document, styleDom = doc.head.querySelector(`#${id}`);
            if (styleDom) { doc.head.removeChild(styleDom) };
        },
        getAttrsByPrefix(element, prefix) {
            return Array.from(element.attributes).reduce((acc, { name, value }) => {
                if (name.startsWith(prefix)) acc[name] = value;
                return acc;
            }, {});
        },
        data(element, key, value) {
            if (arguments.length < 2) return undefined;
            if (value !== undefined) element.dataset[key] = value;
            return element.dataset[key];
        },
        async post(url, data, headers, responseType = 'json') {
            return this.fetchData(url, 'POST', data, headers, responseType);
        },
        async get(url, headers, responseType = 'json') {
            return this.fetchData(url, 'GET', null, headers, responseType);
        },
        async fetchData(url, method='GET', data=null, headers={}, responseType='json') {
            const options = {
                method,
                headers: { 'Content-Type':'application/json',...headers},
                body: data ? JSON.stringify(data) : undefined
            };
            const response = await fetch(url.startsWith("http") ? url : BASE_URL + url, options);
            const result = await response[responseType]().catch(() => null);
            return response.ok ? result : Promise.reject(result);
        },
        getCurrentDate() {
            const localTimezoneOffset = (new Date()).getTimezoneOffset();
            const beijingOffset = 8 * 60;
            const beijingTime = new Date(Date.now() + (localTimezoneOffset + beijingOffset) * 60 * 1000);
            const timeNow = `${beijingTime.getFullYear()}/${(beijingTime.getMonth() + 1)}/${beijingTime.getDate()}`;
            return timeNow;
        },
        createElement(tagName, options = {}, childrens = [], doc = document, namespace = null) {
            if (Array.isArray(options)) {
                if (childrens.length !== 0) {
                    throw new Error("If options is an array, childrens should not be provided.");
                }
                childrens = options;
                options = {};
            }

            const { staticClass = '', dynamicClass = '', attrs = {}, on = {} } = options;

            const ele = namespace ? doc.createElementNS(namespace, tagName) : doc.createElement(tagName);

            if (staticClass) {
                staticClass.split(' ').forEach(cls => ele.classList.add(cls.trim()));
            }
            if (dynamicClass) {
                dynamicClass.split(' ').forEach(cls => ele.classList.add(cls.trim()));
            }

            Object.entries(attrs).forEach(([key, value]) => {
                if (key === 'style' && typeof value === 'object') {
                    Object.entries(value).forEach(([styleKey, styleValue]) => {
                        ele.style[styleKey] = styleValue;
                    });
                } else {
                    if (value !== undefined) ele.setAttribute(key, value);
                }
            });

            Object.entries(on).forEach(([event, handler]) => {
                ele.addEventListener(event, handler);
            });

            childrens.forEach(child => {
                if (typeof child === 'string') {
                    child = doc.createTextNode(child);
                }
                ele.appendChild(child);
            });

            return ele;
        },
        b64DecodeUnicode(str) {
            // Going backwards: from bytestream, to percent-encoding, to original string.
            return decodeURIComponent(atob(str).split('').map(function (c) {
                return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
            }).join(''));
        }
    };

    const opts = {
        curSite : SITE_MAP[location.host] || null,
        post: {
            pathPattern: /^\/(categories\/|page|award|search|$)/,
            scrollThreshold: 1500,
            nextPagerSelector: '.nsk-pager a.pager-next',
            postListSelector: 'ul.post-list:not(.topic-carousel-panel)',
            topPagerSelector: 'div.nsk-pager.pager-top',
            bottomPagerSelector: 'div.nsk-pager.pager-bottom',
        },
        comment: {
            pathPattern: /^\/post-/,
            scrollThreshold: 690,
            nextPagerSelector: '.nsk-pager a.pager-next',
            postListSelector: 'ul.comments',
            topPagerSelector: 'div.nsk-pager.post-top-pager',
            bottomPagerSelector: 'div.nsk-pager.post-bottom-pager',
        },
        settings:{
            "version": version,
            "sign_in": {"ns":{ "enabled": false, "method": 0, "last_date": "", "ignore_date": "" },"df":{ "enabled": false, "method": 0, "last_date": "", "ignore_date": "" }},
            "signin_tips": { "enabled": true },
            "re_signin": { "enabled": true },
            "auto_jump_external_links": { "enabled": true },
            "loading_post": { "enabled": true },
            "loading_comment": { "enabled": true },
            "quick_comment": { "enabled": true },
            "open_post_in_new_tab": { "enabled": false },
            "block_members": { "enabled": true },
            "block_posts": { "enabled": true,"keywords":[] },
            "block_categories": { "enabled": false, "categories": [] },
            "level_tag": { "enabled": true, "low_lv_alarm":false, "low_lv_max_days":30 },
            "show_all_users_stats": { "enabled": false, "position": "below" },
            "code_highlight": { "enabled": true },
            "image_slide":{ "enabled":true },
            "visited_links":{ "enabled": true, "link_color":"","visited_color":"","dark_link_color":"","dark_visited_color":"", "hide_visited": false },
            "user_card_ext": { "enabled":true },
            "compact_mode": {
                ...DEFAULT_COMPACT_MODE
            },
            "custom_background": {
                "enabled": false,
                "url": "",
                "repeat": "repeat",
                "position": "center",
                "size": "cover",
                "attachment": "scroll"
            },
            "merge_category_to_nav": {
                "enabled": false
            },
            "remove_promotions": {
                "enabled": false
            },
            "header_opacity": {
                "enabled": false,
                "value": 0.92,
                "effect": true,
                "blur": 16,
                "saturate": 180
            },
            "frame_opacity": {
                "enabled": false,
                "value": 0.95,
                "blur_enabled": true,
                "saturate_enabled": true,
                "blur": 12,
                "saturate": 180
            },
            "default_avatar": {
                "enabled": false,
                "url": "",
                "auto_detect": true
            },
            "loading_overlay": {
                "enabled": true,
                "duration": INITIAL_OVERLAY_DURATION_DEFAULT
            },
            "typography": {
                "title": {
                    "enabled": false,
                    "fontFamily": "",
                    "fontSize": "",
                    "color": "",
                    "fontStyle": "",
                    "letterSpacing": "",
                    "ligatures": ""
                },
                "tag": {
                    "enabled": false,
                    "fontFamily": "",
                    "fontSize": "",
                    "color": "",
                    "fontStyle": "",
                    "letterSpacing": "",
                    "ligatures": ""
                },
                "meta": {
                    "enabled": false,
                    "fontFamily": "",
                    "fontSize": "",
                    "color": "",
                    "fontStyle": "",
                    "letterSpacing": "",
                    "ligatures": ""
                },
                "content": {
                    "enabled": false,
                    "fontFamily": "",
                    "fontSize": "",
                    "color": "",
                    "fontStyle": "",
                    "letterSpacing": "",
                    "ligatures": ""
                }
            },
            "hide_user_stats_panel": {
                "enabled": false
            },
            "hide_footer": {
                "enabled": false
            },
            "hide_post_category": {
                "enabled": false
            },
            "hide_post_info": {
                "enabled": false
            },
            "hide_topic_carousel": {
                "enabled": false
            },
            "post_sort": {
                "enabled": false,
                "mode": "none",
                "visited_to_bottom": false
            },
            "right_panel_highlight": {
                "enabled": false,
                "keywords": []
            }
        }
    };
    onDocumentReady(() => {
        layui.use(function () {
        const layer = layui.layer;
        const dropdown = layui.dropdown;
        const message = {
            info: (text) => message.__msg(text, { "background-color": "#4D82D6" }),
            success: (text) => message.__msg(text, { "background-color": "#57BF57" }),
            warning: (text) => message.__msg(text, { "background-color": "#D6A14D" }),
            error: (text) => message.__msg(text, { "background-color": "#E1715B" }),
            __msg: (text, style) => { let index = layer.msg(text, { offset: 't', area: ['100%', 'auto'], anim: 'slideDown' }); layer.style(index, Object.assign({ opacity: 0.9 }, style)); }
        };

        const Config = {
            // 初始化配置数据
            initializeConfig() {
                const defaultConfig = opts.settings;
                if (!util.getValue('settings')) {
                    util.setValue('settings', defaultConfig);
                    return;
                }
                if(this.getConfig('version')===version) return;
                // 从存储中获取当前配置
                let storedConfig = util.getValue('settings');

                // 递归地删除不在默认配置中的项
                const cleanDefaults = (stored, defaults) => {
                    Object.keys(stored).forEach(key => {
                        if (defaults[key] === undefined) {
                            delete stored[key]; // 如果默认配置中没有这个键,删除它
                        } else if (typeof stored[key] === 'object' && stored[key] !== null && !(stored[key] instanceof Array)) {
                            cleanDefaults(stored[key], defaults[key]); // 递归检查
                        }
                    });
                };

                // 递归地将默认配置中的新项合并到存储的配置中
                const mergeDefaults = (stored, defaults) => {
                    Object.keys(defaults).forEach(key => {
                        if (typeof defaults[key] === 'object' && defaults[key] !== null && !(defaults[key] instanceof Array)) {
                            if (!stored[key]) stored[key] = {};
                            mergeDefaults(stored[key], defaults[key]);
                        } else {
                            if (stored[key] === undefined) {
                                stored[key] = defaults[key];
                            }
                        }
                    });
                };

                mergeDefaults(storedConfig, defaultConfig);
                //...这里将旧设置项的值迁移到新设置项
                cleanDefaults(storedConfig, defaultConfig);
                storedConfig.version = version;
                util.setValue('settings',storedConfig);
            },updateConfig(path, value) {
                let config = util.getValue('settings');
                if (!config) {
                    config = opts.settings;
                    util.setValue('settings', config);
                }
                let keys = path.split('.');
                let lastKey = keys.pop();
                let lastObj = keys.reduce((obj, key) => {
                    if (!obj[key]) {
                        obj[key] = {};
                    }
                    return obj[key];
                }, config);
                lastObj[lastKey] = value;
                util.setValue('settings', config);
            },            getConfig(path) {
                let config = GM_getValue('settings');
                if (!config) return undefined;
                let keys = path.split('.');
                let result = keys.reduce((obj, key) => {
                    if (obj === null || obj === undefined) return undefined;
                    return obj[key];
                }, config);
                return result;
            }
        };

        const getRuntimeOverlaySettings = () => ({
            enabled: Config.getConfig('loading_overlay.enabled') !== false,
            duration: parseInt(Config.getConfig('loading_overlay.duration'), 10) || INITIAL_OVERLAY_DURATION_DEFAULT
        });

        const FeatureFlags={
            isEnabled(featureName) {
                if (Config.getConfig(featureName)) {
                    return Config.getConfig(`${featureName}.enabled`);
                } else {
                    // console.error(`Feature '${featureName}' does not exist.`);
                    return false;
                }
            }
        };

        const main = {
            loginStatus: false,
            blockKeywordRules: [],
            blockedCategorySet: new Set(),
            rightPanelHighlightRules: [],
            rightPanelHighlightObserver: null,
            avatarObserver: null,
            avatarDefaultCache: new Map(),
            //检查是否登陆
            checkLogin() {
                if (unsafeWindow.__config__ && unsafeWindow.__config__.user) {
                    this.loginStatus = true;
                    util.clog(`当前登录用户 ${unsafeWindow.__config__.user.member_name} (ID ${unsafeWindow.__config__.user.member_id})`);
                }
            },
            // 自动签到
            autoSignIn(rand) {
                if(!FeatureFlags.isEnabled(`sign_in.${opts.curSite.code}`)) return;

                if (!this.loginStatus) return
                if (Config.getConfig(`sign_in.${opts.curSite.code}.enabled`) !== true) return;

                rand = rand || (Config.getConfig(`sign_in.${opts.curSite.code}.method`) === 1);

                let timeNow = util.getCurrentDate(),
                    timeOld = Config.getConfig(`sign_in.${opts.curSite.code}.last_date`);
                if (!timeOld || timeOld != timeNow) { // 是新的一天
                    Config.updateConfig(`sign_in.${opts.curSite.code}.last_date`, timeNow);
                    this.signInRequest(rand);
                }
            },
            // 重新签到
            reSignIn() {
                if (!this.loginStatus) return;
                if (Config.getConfig(`sign_in.${opts.curSite.code}.enabled`) !== true) {
                    unsafeWindow.mscAlert('提示', '自动签到已关闭,不支持重新签到!');
                    return;
                }

                Config.updateConfig(`sign_in.${opts.curSite.code}.last_date`, '1753/1/1');
                location.reload();
            },
            addSignTips() {
                if(!FeatureFlags.isEnabled('signin_tips')) return;

                if (!this.loginStatus) return
                if (Config.getConfig(`sign_in.${opts.curSite.code}.enabled`) === true) return;

                const timeNow = util.getCurrentDate();
                const timeIgnore = Config.getConfig(`sign_in.${opts.curSite.code}.ignore_date`);
                const timeOld = Config.getConfig(`sign_in.${opts.curSite.code}.last_date`);

                if (timeNow === timeIgnore || timeNow === timeOld) return;

                const _this = this;
                let tip = util.createElement("div", { staticClass: 'nsplus-tip' });
                let tip_p = util.createElement('p');
                tip_p.innerHTML = '今天你还没有签到哦!&emsp;【<a class="sign_in_btn" data-rand="true" href="javascript:;">随机抽个鸡腿</a>】&emsp;【<a class="sign_in_btn" data-rand="false" href="javascript:;">只要5个鸡腿</a>】&emsp;【<a id="sign_in_ignore" href="javascript:;">今天不再提示</a>】';
                tip.appendChild(tip_p);
                tip.querySelectorAll('.sign_in_btn').forEach(function (item) {
                    item.addEventListener("click", function (e) {
                        const rand = util.data(this, 'rand');
                        _this.signInRequest(rand);
                        tip.remove();
                        Config.updateConfig(`sign_in.${opts.curSite.code}.last_date`, timeNow);
                    })
                });
                tip.querySelector('#sign_in_ignore').addEventListener("click", function (e) {
                    tip.remove();
                    Config.updateConfig(`sign_in.${opts.curSite.code}.ignore_date`, timeNow);
                });

                document.querySelector('header').append(tip);
            },
            async signInRequest(rand) {
                await util.post('/api/attendance?random=' + (rand || false), {}, { "Content-Type": "application/json" }).then(json => {
                    if (json.success) {
                        message.success(`签到成功!今天午饭+${json.gain}个鸡腿; 积攒了${json.current}个鸡腿了`);
                    }
                    else {
                        message.info(json.message);
                    }
                }).catch(error => {
                    message.info(error.message || "发生未知错误");
                    util.clog(error);
                });
                util.clog(`[${name}] 签到完成`);
            },
            is_show_quick_comment: false,
            quickComment() {
                if (!this.loginStatus || !opts.comment.pathPattern.test(location.pathname)) return;
                if (Config.getConfig('loading_comment.enabled') === false) return;

                const _this = this;


                const onClick = (e) => {
                    if (_this.is_show_quick_comment) {
                        return;
                    }
                    e.preventDefault();

                    const mdEditor = document.querySelector('.md-editor');
                    const clientHeight = document.documentElement.clientHeight, clientWidth = document.documentElement.clientWidth;
                    const mdHeight = mdEditor.clientHeight, mdWidth = mdEditor.clientWidth;
                    const top = (clientHeight / 2) - (mdHeight / 2), left = (clientWidth / 2) - (mdWidth / 2);
                    mdEditor.style.cssText = `position: fixed; top: ${top}px; left: ${left}px; margin: 30px 0px; width: 100%; max-width: ${mdWidth}px; z-index: 999;`;
                    const moveEl = mdEditor.querySelector('.tab-select.window_header');
                    moveEl.style.cursor = "move";
                    moveEl.addEventListener('mousedown', startDrag);
                    addEditorCloseButton();
                    _this.is_show_quick_comment = true;
                };
                const commentDiv = document.querySelector('#fast-nav-button-group #back-to-parent').cloneNode(true);
                commentDiv.id = 'back-to-comment';
                commentDiv.innerHTML = '<svg class="iconpark-icon" style="width: 24px; height: 24px;"><use href="#comments"></use></svg>';
                commentDiv.addEventListener("click", onClick);
                document.querySelector('#back-to-parent').before(commentDiv);
                document.querySelectorAll('.nsk-post .comment-menu,.comment-container .comments').forEach(x=>x.addEventListener("click",(event) =>{ if(!["引用", "回复", "编辑"].includes(event.target.textContent)) return; onClick(event);},true));//使用冒泡法给按钮引用、回复添加事件

                function addEditorCloseButton() {
                    const fullScreenToolbar = document.querySelector('#editor-body .window_header > :last-child');
                    const cloneToolbar = fullScreenToolbar.cloneNode(true);
                    cloneToolbar.setAttribute('title', '关闭');
                    cloneToolbar.querySelector('span').classList.replace('i-icon-full-screen-one', 'i-icon-close');
                    cloneToolbar.querySelector('span').innerHTML = '<svg width="16" height="16" viewBox="0 0 48 48" fill="none"><path d="M8 8L40 40" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path><path d="M8 40L40 8" stroke="currentColor" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"></path></svg>';
                    cloneToolbar.addEventListener("click", function (e) {
                        const mdEditor = document.querySelector('.md-editor');
                        mdEditor.style = "";
                        const moveEl = mdEditor.querySelector('.tab-select.window_header');
                        moveEl.style.cursor = "";
                        moveEl.removeEventListener('mousedown', startDrag);

                        this.remove();
                        _this.is_show_quick_comment = false;
                    });
                    fullScreenToolbar.after(cloneToolbar);
                }
                function startDrag(event) {
                    if (event.button !== 0) return;

                    const draggableElement = document.querySelector('.md-editor');
                    const parentMarginTop = parseInt(window.getComputedStyle(draggableElement).marginTop);
                    const initialX = event.clientX - draggableElement.offsetLeft;
                    const initialY = event.clientY - draggableElement.offsetTop + parentMarginTop;
                    document.onmousemove = function (event) {
                        const newX = event.clientX - initialX;
                        const newY = event.clientY - initialY;
                        draggableElement.style.left = newX + 'px';
                        draggableElement.style.top = newY + 'px';
                    };
                    document.onmouseup = function () {
                        document.onmousemove = null;
                        document.onmouseup = null;
                    };
                }
            },
            // 切换官方打开链接设置
            async switchOpenPostInNewTab(stateName, states){
                try {
                    unsafeWindow.indexedDB.open('ns-preference-db').onsuccess = e => {
                        const db = e.target.result;
                        const store = db.transaction('ns-preference-store', 'readwrite').objectStore('ns-preference-store');
                        store.get('configuration').onsuccess = e => {
                            const cfg = e.target.result || { openPostInNewPage: false };
                            cfg.openPostInNewPage = !cfg.openPostInNewPage;
                            store.put(cfg, 'configuration');
                            Config.updateConfig(`${stateName}.enabled`, cfg.openPostInNewPage);
                            unsafeWindow.mscAlert(`已${cfg.openPostInNewPage?'开启':'关闭'}新标签页打开链接`);
                        };
                    };
                } catch (error) {
                    // console.error(error);
                }
            },
            // 强制新标签页打开帖子链接
            enforceNewTabForPosts() {
                // 使用事件委托监听所有链接点击
                const clickHandler = function(e) {
                    // 检查配置是否启用(每次检查以确保实时性,但只在启用时才进行后续处理)
                    if (!Config.getConfig('open_post_in_new_tab.enabled')) return;

                    const link = e.target.closest('a');
                    if (!link || !link.href) return;

                    // 检查是否是帖子链接
                    const href = link.href;
                    const isPostLink = /\/post-\d+/.test(href) && href.startsWith(BASE_URL);

                    // 排除特殊链接(如跳转链接、锚点、已有target的链接等)
                    if (link.hasAttribute('data-no-instant') ||
                        link.href.includes('/jump?to=') ||
                        link.href.startsWith('#') ||
                        link.target === '_blank') {
                        return;
                    }

                    // 如果是帖子链接,强制在新标签页打开
                    if (isPostLink) {
                        e.preventDefault();
                        e.stopPropagation();
                        window.open(link.href, '_blank');
                    }
                };
                document.addEventListener('click', clickHandler, true); // 使用捕获阶段确保优先执行
            },
            //自动点击跳转页链接
            autoJump() {
                document.querySelectorAll('a[href*="/jump?to="]').forEach(link => {
                    try {
                        const urlObj = new URL(link.href);
                        const encodedUrl = urlObj.searchParams.get('to');
                        if (encodedUrl) {
                            const decodedUrl = decodeURIComponent(encodedUrl);
                            link.href = decodedUrl;
                        }
                    } catch (e) {
                        // console.error('处理链接时出错:', e);
                    }
                });
                if (!/^\/jump/.test(location.pathname)) return;
                document.querySelector('.btn').click();
            },
            refreshBlockKeywordRules() {
                const stored = Config.getConfig('block_posts.keywords');
                const list = Array.isArray(stored) ? stored : [];
                this.blockKeywordRules = list.map(rule => {
                    if (!rule) return null;
                    if (typeof rule === 'string') {
                        const value = rule.trim();
                        if (!value) return null;
                        return { type: 'text', value, lower: value.toLowerCase() };
                    }
                    const type = rule.type || 'text';
                    if (type === 'regex') {
                        const pattern = rule.value || rule.pattern || '';
                        if (!pattern) return null;
                        const flags = rule.flags || '';
                        try {
                            const regex = new RegExp(pattern, flags || 'i');
                            return { type: 'regex', regex, value: pattern, flags };
                        } catch (err) {
                            // console.warn('[NodeSeek X] 无效的正则规则:', pattern, err);
                            return null;
                        }
                    }
                    const value = (rule.value || '').trim();
                    if (!value) return null;
                    return { type: 'text', value, lower: value.toLowerCase() };
                }).filter(Boolean);
            },
            getBlockKeywordInputValue() {
                const stored = Config.getConfig('block_posts.keywords');
                if (!Array.isArray(stored) || stored.length === 0) return '';
                return stored.map(rule => {
                    if (!rule) return '';
                    if (typeof rule === 'string') return rule;
                    if (rule.type === 'regex') {
                        const flags = rule.flags || '';
                        return `/${rule.value || ''}/${flags}`;
                    }
                    return rule.value || '';
                }).filter(Boolean).join('\n');
            },
            parseBlockKeywordInput(inputValue) {
                if (!inputValue) return [];
                return inputValue.split(/\r?\n/).map(line => line.trim()).filter(Boolean).map(line => {
                    if (line.startsWith('/') && line.lastIndexOf('/') > 0) {
                        const lastSlash = line.lastIndexOf('/');
                        const pattern = line.slice(1, lastSlash);
                        const flags = line.slice(lastSlash + 1);
                        try {
                            new RegExp(pattern, flags || 'i');
                            return { type: 'regex', value: pattern, flags };
                        } catch (err) {
                            // console.warn('[NodeSeek X] 忽略无效正则:', line, err);
                            return null;
                        }
                    }
                    return { type: 'text', value: line };
                }).filter(Boolean);
            },
            shouldBlockTitle(title) {
                if (!this.blockKeywordRules || this.blockKeywordRules.length === 0) return false;
                const lowerTitle = title.toLowerCase();
                return this.blockKeywordRules.some(rule => {
                    if (rule.type === 'regex') {
                        try {
                            return rule.regex.test(title);
                        } catch (err) {
                            // console.warn('[NodeSeek X] 正则匹配失败:', rule, err);
                            return false;
                        }
                    }
                    return lowerTitle.includes(rule.lower);
                });
            },
            blockPost(ele) {
                if (Config.getConfig('block_posts.enabled') === false) return;
                if (!this.blockKeywordRules || this.blockKeywordRules.length === 0) return;
                ele = ele || document;
                ele.querySelectorAll('.post-title a[href], .post-list-item a.post-title').forEach(item => {
                    const title = (item.textContent || '').trim();
                    if (!title || !this.shouldBlockTitle(title)) return;
                    const li = item.closest('.post-list-item');
                    if (li) {
                        li.classList.add('blocked-post');
                    } else {
                        const fallback = item.closest('li, article, .post-card, .post-item, .post, .post-list-content') || item.parentElement;
                        fallback?.classList.add('blocked-post');
                    }
                });
            },
            refreshBlockedCategories() {
                const stored = Config.getConfig('block_categories.categories');
                const list = Array.isArray(stored) ? stored : [];
                this.blockedCategorySet = new Set(list.map(item => (item || '').trim().toLowerCase()).filter(Boolean));
            },
            getBlockedCategoryInputValue() {
                const stored = Config.getConfig('block_categories.categories');
                if (!Array.isArray(stored) || stored.length === 0) return '';
                return stored.join('\n');
            },
            parseBlockedCategoryInput(inputValue) {
                if (!inputValue) return [];
                return inputValue.split(/\r?\n/).map(line => line.trim()).filter(Boolean);
            },
            blockPostsByCategory(ele) {
                if (Config.getConfig('block_categories.enabled') === false) return;
                if (!this.blockedCategorySet || this.blockedCategorySet.size === 0) return;
                ele = ele || document;
                ele.querySelectorAll('.post-list-item').forEach(item => {
                    if (item.classList.contains('blocked-post')) return;
                    const categoryAnchor = item.querySelector('.post-category');
                    if (!categoryAnchor) return;
                    const text = (categoryAnchor.textContent || '').trim().toLowerCase();
                    if (this.blockedCategorySet.has(text)) {
                        item.classList.add('blocked-post');
                    }
                });
            },
            togglePromotions() {
                const enabled = Config.getConfig('remove_promotions.enabled') === true;
                toggleRootClass('nsx-remove-promotions', enabled);
            },
            async isDefaultAvatar(img) {
                const config = Config.getConfig('default_avatar');
                if (!config || config.auto_detect === false) return true;
                const src = img.currentSrc || img.src;
                if (this.avatarDefaultCache.has(src)) {
                    return this.avatarDefaultCache.get(src);
                }
                try {
                    const response = await fetch(src, { credentials: 'include', headers: { 'Accept': 'text/html' } });
                    if (!response.ok) throw new Error(response.status);
                    const text = await response.text();
                    const isDefault = /vue-color-avatar/i.test(text);
                    this.avatarDefaultCache.set(src, isDefault);
                    return isDefault;
                } catch (err) {
                    // console.warn('[NodeSeek X] avatar detect failed', err);
                    this.avatarDefaultCache.set(src, false);
                    return false;
                }
            },
            replaceDefaultAvatars(target = document) {
                const config = Config.getConfig('default_avatar');
                if (!config || config.enabled !== true) {
                    target.querySelectorAll('img.avatar-normal[data-nsx-original-avatar]').forEach(img => {
                        img.src = img.dataset.nsxOriginalAvatar;
                        delete img.dataset.nsxOriginalAvatar;
                        delete img.dataset.nsxAvatarProcessed;
                    });
                    return;
                }
                const fallbackUrl = (config.url || '').trim();
                if (!fallbackUrl) return;
                const autoDetect = config.auto_detect !== false;
                const process = (img) => {
                    if (img.dataset.nsxAvatarProcessed) return;
                    const finalize = (shouldReplace) => {
                        if (shouldReplace) {
                            if (!img.dataset.nsxOriginalAvatar) {
                                img.dataset.nsxOriginalAvatar = img.src;
                            }
                            img.src = fallbackUrl;
                            img.dataset.nsxAvatarProcessed = '1';
                        } else {
                            img.dataset.nsxAvatarProcessed = 'checked';
                        }
                    };
                    const runDetect = () => {
                        if (!autoDetect) {
                            finalize(true);
                            return;
                        }
                        this.isDefaultAvatar(img).then(isDefault => finalize(isDefault));
                    };
                    if (img.complete && img.naturalWidth) {
                        runDetect();
                    } else {
                        img.addEventListener('load', runDetect, { once: true });
                    }
                };
                target.querySelectorAll('img.avatar-normal').forEach(process);
            },
            startAvatarObserver() {
                if (this.avatarObserver) this.avatarObserver.disconnect();
                if (!document.body) return;
                this.avatarObserver = new MutationObserver(mutations => {
                    mutations.forEach(mutation => {
                        mutation.addedNodes.forEach(node => {
                            if (node.nodeType !== 1) return;
                            if (node.matches && node.matches('img.avatar-normal')) {
                                this.replaceDefaultAvatars(node);
                            } else if (node.querySelector) {
                                this.replaceDefaultAvatars(node);
                            }
                        });
                    });
                });
                this.avatarObserver.observe(document.body, { childList: true, subtree: true });
            },
            updateHeaderOpacityStyle() {
                const config = Config.getConfig('header_opacity');
                if (!config || config.enabled !== true) {
                    toggleRootClass('nsx-header-opacity', false);
                    document.getElementById(HEADER_OPACITY_STYLE_ID)?.remove();
                    return;
                }
                toggleRootClass('nsx-header-opacity', true);
                applyHeaderOpacityCSS(config);
            },
            updateFrameOpacityStyle() {
                const config = Config.getConfig('frame_opacity');
                if (!config || config.enabled !== true) {
                    toggleRootClass('nsx-frame-opacity', false);
                    document.getElementById(FRAME_OPACITY_STYLE_ID)?.remove();
                    return;
                }
                toggleRootClass('nsx-frame-opacity', true);
                applyFrameOpacityCSS(config);
            },
            blockPostsByViewLevel(ele) {
                ele = ele || document;
                let level=0;
                if (this.loginStatus) level = unsafeWindow.__config__.user.rank;
                [...ele.querySelectorAll('.post-list-item use[href="#lock"]')].forEach(el => {
                    const n = +el.closest('span')?.textContent.match(/\d+/)?.[0] || 0;
                    if (n > level) el.closest('.post-list-item')?.classList.add('blocked-post');
                });
            },
            //屏蔽用户
            blockMemberDOMInsert() {
                if (!this.loginStatus) return;

                const _this = this;
                
                // 调整用户卡片位置,确保不会超出页面底部
                const adjustUserCardPosition = (userCard) => {
                    if (!userCard) return;
                    const rect = userCard.getBoundingClientRect();
                    const viewportHeight = window.innerHeight;
                    const cardBottom = rect.bottom;
                    
                    // 如果卡片底部超出视口,调整位置
                    if (cardBottom > viewportHeight - 20) {
                        const currentTop = parseInt(userCard.style.top) || rect.top;
                        const cardHeight = rect.height;
                        const newTop = viewportHeight - cardHeight - 20;
                        
                        // 确保新位置不会太高(至少距离顶部100px)
                        if (newTop < 100) {
                            userCard.style.top = '100px';
                            userCard.style.maxHeight = `${viewportHeight - 120}px`;
                            userCard.style.overflowY = 'auto';
                        } else {
                            userCard.style.top = `${newTop}px`;
                        }
                    }
                };
                
                Array.from(document.querySelectorAll(".post-list .post-list-item,.content-item")).forEach((function (t, n) {
                    const r = t.querySelector('.avatar-normal');
                    if (!r) return;
                    r.addEventListener("click", (function (n) {
                        n.preventDefault();
                        let intervalId = setInterval(() => {
                            const userCard = document.querySelector('div.user-card.hover-user-card');
                            const pmButton = document.querySelector('div.user-card.hover-user-card a.btn');
                            if (userCard && pmButton) {
                                clearInterval(intervalId);
                                
                                // 调整用户卡片位置
                                adjustUserCardPosition(userCard);
                                
                                // 监听窗口大小变化和滚动,动态调整位置
                                const adjustHandler = () => adjustUserCardPosition(userCard);
                                window.addEventListener('resize', adjustHandler);
                                window.addEventListener('scroll', adjustHandler);
                                
                                // 当用户卡片消失时,移除监听器
                                const observer = new MutationObserver(() => {
                                    if (!document.contains(userCard)) {
                                        window.removeEventListener('resize', adjustHandler);
                                        window.removeEventListener('scroll', adjustHandler);
                                        observer.disconnect();
                                    }
                                });
                                observer.observe(document.body, { childList: true, subtree: true });
                                
                                const dataVAttrs = util.getAttrsByPrefix(userCard, 'data-v');
                                const userName = userCard.querySelector('a.Username').textContent;
                                dataVAttrs.style = "float:left; background-color:rgba(0,0,0,.3)";
                                const blockBtn = util.createElement("a", {
                                    staticClass: "btn", attrs: dataVAttrs, on: {
                                        click: function (e) {
                                            e.preventDefault();
                                            unsafeWindow.mscConfirm(`确定要屏蔽"${userName}"吗?`, '你可以在本站的 设置=>屏蔽用户 中解除屏蔽', function () { blockMember(userName); })
                                        }
                                    }
                                }, ["屏蔽"]);
                                pmButton.after(blockBtn);
                                
                                // 添加屏蔽按钮后,再次调整位置(因为按钮可能增加了卡片高度)
                                setTimeout(() => adjustUserCardPosition(userCard), 100);
                            }
                        }, 50);
                        // 添加超时保护,5秒后自动清理
                        setTimeout(() => clearInterval(intervalId), 5000);
                    }))
                }))
                function blockMember(userName) {
                    util.post("/api/block-list/add", { "block_member_name": userName }, { "Content-Type": "application/json" }).then(function (data) {
                        if (data.success) {
                            let msg = '屏蔽用户【' + userName + '】成功!';
                            unsafeWindow.mscAlert(msg);
                            util.clog(msg);
                        } else {
                            let msg = '屏蔽用户【' + userName + '】失败!' + data.message;
                            unsafeWindow.mscAlert(msg);
                            util.clog(msg);
                        }
                    }).catch(function (err) {
                        util.clog(err);
                    });
                }
            },
            addImageSlide() {
                if (!opts.comment.pathPattern.test(location.pathname)) return;

                const posts = document.querySelectorAll('article.post-content');
                posts.forEach(function (post, i) {
                    const images = post.querySelectorAll('img:not(.sticker)');
                    if (images.length === 0) return;

                    images.forEach(function (image, i) {
                        const newImg = image.cloneNode(true);
                        image.parentNode.replaceChild(newImg, image);
                        newImg.addEventListener('click', function (e) {
                            e.preventDefault();
                            const imgArr = Array.from(post.querySelectorAll('img:not(.sticker)'));
                            const clickedIndex = imgArr.indexOf(this);
                            const photoData = imgArr.map((img, i) => ({ alt: img.alt, pid: i + 1, src: img.src }));
                            layer.photos({ photos: { "title": "图片预览", "start": clickedIndex, "data": photoData } });
                        }, true);
                    });
                });
            },
            addLevelTag() {//添加等级标签
                if (!this.loginStatus) return;
                if (!opts.comment.pathPattern.test(location.pathname)) return;
                let _this=this;
                this.getUserInfo(unsafeWindow.__config__.postData.op.uid).then((user) => {
                    let warningInfo = '';
                    const daysDiff = Math.floor((new Date() - new Date(user.created_at)) / (1000 * 60 * 60 * 24));
                    if (daysDiff < 30) {
                        warningInfo = `⚠️`;
                    }
                    // console.log(user);
                    let rank = _this.getRankByCoin(user.coin);
                    const span = util.createElement("span", { staticClass: `nsk-badge role-tag user-level user-lv${rank}` }, [util.createElement("span", [`${warningInfo}Lv ${rank}`])]);

                    const authorLink = document.querySelector('#nsk-body .nsk-post .nsk-content-meta-info .author-info>a');
                    if (authorLink != null) {
                        authorLink.after(span);
                    }

                    // 在 content-info 中添加用户统计信息
                    const contentInfo = document.querySelector('#nsk-body .nsk-post .nsk-content-meta-info .content-info');
                    const mainPost = document.querySelector('#nsk-body .nsk-post');
                    if (contentInfo) {
                        // 检查是否已添加过统计信息,避免重复
                        if (contentInfo.querySelector('.nsx-user-stats')) return;

                        // 获取位置设置
                        const position = Config.getConfig('show_all_users_stats.position') || 'below';

                        // 创建统计信息容器
                        const statsContainer = util.createElement("div", {
                            staticClass: "nsx-user-stats",
                            attrs: { 
                                style: position === 'right' 
                                    ? "display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 0.9em; margin-left: 8px;" 
                                    : "margin-top: 4px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 0.9em;" 
                            }
                        }, [
                            util.createElement("span", { attrs: { title: "注册天数", style: "color: #2ea44f;" } }, [`📅 注册 ${daysDiff} 天`]),
                            util.createElement("span", { attrs: { style: "color: var(--text-tertiary-color, #ccc);" } }, ["·"]),
                            util.createElement("span", { attrs: { title: "鸡腿数量", style: "color: #ff9800;" } }, [`🍗 ${user.coin || 0}`]),
                            util.createElement("span", { attrs: { style: "color: var(--text-tertiary-color, #ccc);" } }, ["·"]),
                            util.createElement("span", { attrs: { title: "帖子数", style: "color: #2196f3;" } }, [`📝 帖子 ${user.nPost || 0}`]),
                            util.createElement("span", { attrs: { style: "color: var(--text-tertiary-color, #ccc);" } }, ["·"]),
                            util.createElement("span", { attrs: { title: "评论数", style: "color: #9c27b0;" } }, [`💬 评论 ${user.nComment || 0}`])
                        ]);

                        // 根据位置设置插入
                        if (position === 'right' && mainPost) {
                            // 插入到作者名字右边
                            const authorLink = mainPost.querySelector('.nsk-content-meta-info .author-info a');
                            if (authorLink) {
                                authorLink.after(statsContainer);
                            } else {
                                // 如果找不到作者链接,回退到下方
                                contentInfo.appendChild(statsContainer);
                            }
                        } else {
                            // 默认插入到下方
                            contentInfo.appendChild(statsContainer);
                        }
                    }
                });
            },
            getUserInfo(uid) {
                return new Promise((resolve, reject) => {
                    util.get(`/api/account/getInfo/${uid}`, {}, 'json').then((data) => {
                        if (!data.success) {
                            util.clog(data);
                            return;
                        }
                        resolve(data.detail);
                    }).catch((err) => reject(err));
                })
            },
            // 为所有用户显示统计信息
            showAllUsersStats() {
                if (!this.loginStatus) return;
                
                const _this = this;
                // 缓存用户数据,避免重复请求(Map<uid, userData>)
                if (!_this.userDataCache) {
                    _this.userDataCache = new Map();
                }
                // 记录正在请求的 UID,避免重复请求(Set<uid>)
                if (!_this.pendingUserRequests) {
                    _this.pendingUserRequests = new Set();
                }
                // 记录等待用户数据的楼层(Map<uid, Array<contentInfo>>)
                if (!_this.pendingContentItems) {
                    _this.pendingContentItems = new Map();
                }
                
                // 创建用户统计信息的辅助函数
                const createUserStats = (user, contentInfo, item) => {
                    if (!user || !contentInfo) return;
                    
                    // 获取位置设置
                    const position = Config.getConfig('show_all_users_stats.position') || 'below';
                    
                    // 检查是否已添加过统计信息
                    const existingStats = contentInfo.querySelector('.nsx-user-stats');
                    if (existingStats) {
                        // 如果位置设置改变,需要移除旧的并重新添加
                        existingStats.remove();
                    }
                    
                    // 计算注册天数
                    let daysDiff = 0;
                    if (user.created_at) {
                        const registerDate = new Date(user.created_at);
                        const now = new Date();
                        if (!isNaN(registerDate.getTime())) {
                            daysDiff = Math.floor((now - registerDate) / (1000 * 60 * 60 * 24));
                        }
                    }
                    // 如果计算失败,显示为 0 天
                    if (isNaN(daysDiff) || daysDiff < 0) {
                        daysDiff = 0;
                    }
                    
                    // 创建统计信息容器
                    const statsContainer = util.createElement("div", {
                        staticClass: "nsx-user-stats",
                        attrs: { 
                            style: position === 'right' 
                                ? "display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 0.9em; margin-left: 8px;" 
                                : "margin-top: 4px; display: flex; flex-wrap: wrap; gap: 8px; align-items: center; font-size: 0.9em;" 
                        }
                    }, [
                        util.createElement("span", { attrs: { title: "注册天数", style: "color: #2ea44f;" } }, [`📅 注册 ${daysDiff} 天`]),
                        util.createElement("span", { attrs: { style: "color: var(--text-tertiary-color, #ccc);" } }, ["·"]),
                        util.createElement("span", { attrs: { title: "鸡腿数量", style: "color: #ff9800;" } }, [`🍗 ${user.coin || 0}`]),
                        util.createElement("span", { attrs: { style: "color: var(--text-tertiary-color, #ccc);" } }, ["·"]),
                        util.createElement("span", { attrs: { title: "帖子数", style: "color: #2196f3;" } }, [`📝 帖子 ${user.nPost || 0}`]),
                        util.createElement("span", { attrs: { style: "color: var(--text-tertiary-color, #ccc);" } }, ["·"]),
                        util.createElement("span", { attrs: { title: "评论数", style: "color: #9c27b0;" } }, [`💬 评论 ${user.nComment || 0}`])
                    ]);
                    
                    // 根据位置设置插入
                    if (position === 'right' && item) {
                        // 插入到作者名字右边
                        const authorLink = item.querySelector('.nsk-content-meta-info .author-info a');
                        if (authorLink) {
                            authorLink.after(statsContainer);
                        } else {
                            // 如果找不到作者链接,回退到下方
                            contentInfo.appendChild(statsContainer);
                        }
                    } else {
                        // 默认插入到下方
                        contentInfo.appendChild(statsContainer);
                    }
                };
                
                // 处理单个内容项(帖子或评论)
                const processContentItem = (item) => {
                    // 排除主帖,主帖的统计信息由 addLevelTag 处理
                    // 检查 item 是否在主帖内(#nsk-body .nsk-post)
                    const mainPost = document.querySelector('#nsk-body .nsk-post');
                    if (mainPost && mainPost.contains(item)) {
                        return;
                    }
                    
                    // 查找 content-info 元素
                    const contentInfo = item.querySelector('.nsk-content-meta-info .content-info');
                    if (!contentInfo) return;
                    
                    // 如果已经有统计信息,跳过
                    if (contentInfo.querySelector('.nsx-user-stats')) return;
                    
                    // 尝试从头像获取 UID
                    const avatar = item.querySelector('.avatar-normal');
                    let uid = null;
                    
                    if (avatar) {
                        // 尝试从 data-uid 属性获取
                        uid = avatar.getAttribute('data-uid');
                        // 如果没找到,尝试从头像 URL 提取(/avatar/12345.png)
                        if (!uid && avatar.src) {
                            const match = avatar.src.match(/\/avatar\/(\d+)\.png/);
                            if (match) {
                                uid = match[1];
                            }
                        }
                    }
                    
                    // 如果还是没找到,尝试从作者链接获取
                    if (!uid) {
                        const authorLink = item.querySelector('.nsk-content-meta-info .author-info a');
                        if (authorLink && authorLink.href) {
                            const match = authorLink.href.match(/\/space\/(\d+)/);
                            if (match) {
                                uid = match[1];
                            }
                        }
                    }
                    
                    if (!uid) return;
                    
                    // 如果用户数据已经在缓存中,直接使用
                    if (_this.userDataCache.has(uid)) {
                        const user = _this.userDataCache.get(uid);
                        createUserStats(user, contentInfo, item);
                        return;
                    }
                    
                    // 如果正在请求该用户的数据,将当前楼层加入等待列表
                    if (_this.pendingUserRequests.has(uid)) {
                        if (!_this.pendingContentItems.has(uid)) {
                            _this.pendingContentItems.set(uid, []);
                        }
                        _this.pendingContentItems.get(uid).push({ contentInfo, item });
                        return;
                    }
                    
                    // 标记为正在请求
                    _this.pendingUserRequests.add(uid);
                    
                    // 获取用户信息
                    _this.getUserInfo(uid).then((user) => {
                        // 缓存用户数据
                        _this.userDataCache.set(uid, user);
                        
                        // 为当前楼层显示统计信息
                        createUserStats(user, contentInfo, item);
                        
                        // 为所有等待该用户数据的楼层显示统计信息
                        if (_this.pendingContentItems.has(uid)) {
                            const pendingItems = _this.pendingContentItems.get(uid);
                            pendingItems.forEach(({ contentInfo: pendingContentInfo, item: pendingItem }) => {
                                createUserStats(user, pendingContentInfo, pendingItem);
                            });
                            _this.pendingContentItems.delete(uid);
                        }
                        
                        // 移除请求标记
                        _this.pendingUserRequests.delete(uid);
                    }).catch((err) => {
                        // 忽略错误,移除请求标记
                        _this.pendingUserRequests.delete(uid);
                        _this.pendingContentItems.delete(uid);
                    });
                };
                
                // 处理所有内容项
                const processAllItems = () => {
                    // 处理所有评论(包括主帖,但主帖的统计信息由 addLevelTag 处理,这里会跳过)
                    const contentItems = document.querySelectorAll('.content-item');
                    contentItems.forEach(item => {
                        processContentItem(item);
                    });
                };
                
                // 初始处理
                processAllItems();
                
                // 监听动态加载的内容
                if (!_this.allUsersStatsObserver) {
                    _this.allUsersStatsObserver = new MutationObserver((mutations) => {
                        mutations.forEach((mutation) => {
                            mutation.addedNodes.forEach((node) => {
                                if (node.nodeType === 1) { // Element node
                                    // 检查是否是新的内容项
                                    if (node.matches && node.matches('.content-item')) {
                                        processContentItem(node);
                                    }
                                    // 检查子元素中是否有新的内容项
                                    const newItems = node.querySelectorAll ? node.querySelectorAll('.content-item') : [];
                                    newItems.forEach(item => processContentItem(item));
                                }
                            });
                        });
                    });
                    
                    const commentsContainer = document.querySelector('.comments, .comment-container');
                    if (commentsContainer) {
                        _this.allUsersStatsObserver.observe(commentsContainer, {
                            childList: true,
                            subtree: true
                        });
                    }
                }
            },
            // 隐藏所有用户统计信息
            hideAllUsersStats() {
                // 移除所有用户统计信息(除了楼主的,因为那是 level_tag 功能的一部分)
                document.querySelectorAll('.nsx-user-stats').forEach(stats => {
                    // 只移除非楼主区域的统计信息
                    const isMainPost = stats.closest('#nsk-body .nsk-post');
                    if (!isMainPost) {
                        stats.remove();
                    }
                });
                
                // 断开观察器
                if (this.allUsersStatsObserver) {
                    this.allUsersStatsObserver.disconnect();
                    this.allUsersStatsObserver = null;
                }
            },
            getRankByCoin(coin){
                // 处理无效值:负数、NaN、undefined 都返回 0
                if (!coin || coin < 0) {
                    return 0;
                }
                // 计算等级:使用平方根公式,最大等级为6
                const level = Math.floor(Math.sqrt(coin) / 10);
                return Math.min(6, level);
            },
            fakeLevel(){
                let coin = unsafeWindow.__config__.user.coin;
                if(coin < 4900) return;//不足7级直接返回
                let rank = this.getRankByCoin(coin);
                const userCard = document.querySelector(".user-card .user-stat");
                userCard.querySelector('use[href="#level"]').closest('svg').nextElementSibling.innerText='等级 Lv '+ rank;
            },
            userCardEx() {
                if (!this.loginStatus) return;
                if (!(opts.post.pathPattern.test(location.pathname)|| opts.comment.pathPattern.test(location.pathname))) return;

                const bn = new BroadcastManager("notification_sync");

                const updateNotificationElement = (element, href, iconHref, text, count) => {
                    element.querySelector("a").setAttribute("href", `${href}`);
                    element.querySelector("a > svg > use").setAttribute("href", `${iconHref}`);
                    element.querySelector("a > :nth-child(2)").textContent = `${text} `;
                    element.querySelector("a > :last-child").textContent = count;
                    const countEl = element.querySelector("a > :last-child");
                    countEl.classList.toggle("notify-count", count > 0);

                    // 通知(只在主控标签页且有新消息时发送)
                    if (count > 0 && bn.active) {
                        GM_notification({
                            text: `你有 ${count} 条新 ${text === '我' ? '@' : text},点击查看`,
                            tag: 'notice_count',
                            onclick: e => (e.preventDefault(), GM_openInTab(`${BASE_URL}${href}`, {active: true}))
                        });
                    }

                    return element;
                };

                const userCard = document.querySelector(".user-card .user-stat");
                const lastElement = userCard.querySelector(".stat-block:first-child > :last-child");

                const atMeElement = lastElement.cloneNode(true);
                const msgElement = lastElement.cloneNode(true);

                lastElement.after(atMeElement);
                userCard.querySelector(".stat-block:last-child").append(msgElement);

                // 初始化通知显示
                const updateAllCounts = (counts) => {
                    updateNotificationElement(atMeElement, "/notification#/atMe", "#at-sign", "我", counts.atMe);
                    updateNotificationElement(msgElement, "/notification#/message?mode=list", "#envelope-one", "私信", counts.message);
                    updateNotificationElement(lastElement, "/notification#/reply", "#remind-6nce9p47", "回复", counts.reply);
                };

                // 注册数据接收器
                bn.registerReceiver(({ sender, data }) => {
                    if (data.type === 'unreadCount' && data.counts) {
                        // console.log(`接收到来自 ${sender} 的广播数据:${JSON.stringify(data.counts)}`, new Date(data.timestamp).toLocaleString());
                        updateAllCounts(data.counts);
                    }
                });

                // 首次加载
                bn.broadcast({ type: 'unreadCount', counts: unsafeWindow.__config__.user.unViewedCount, timestamp: Date.now() });

                let interval = 5000;
                // 启动定时任务(只在主控标签页执行)
                bn.startTask(async () => {
                    const response = await fetch("/api/notification/unread-count", { credentials: "include" });

                    if (!response.ok) throw new Error(response.status);

                    const data = await response.json();
                    if (data.success && data.unreadCount) {
                        // console.log(`${bn.myId} 发送一条广播数据:${JSON.stringify(data.unreadCount)}`);
                        return {
                            type: 'unreadCount',
                            counts: data.unreadCount,
                            timestamp: Date.now()
                        };
                    }
                    throw new Error('Invalid response');
                }, interval);
            },
            // 自动翻页
            autoLoading() {
                if (Config.getConfig('loading_post.enabled') === false && Config.getConfig('loading_comment.enabled') === false) return;
                let opt = {};
                if (opts.post.pathPattern.test(location.pathname)) { opt = opts.post; }
                else if (opts.comment.pathPattern.test(location.pathname)) { opt = opts.comment; }
                else { return; }
                let is_requesting = false;
                let _this = this;
                this.windowScroll(function (direction, e) {
                    if (direction === 'down') { // 下滑才准备翻页
                        let scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
                        if (document.documentElement.scrollHeight <= document.documentElement.clientHeight + scrollTop + opt.scrollThreshold && !is_requesting) {
                            if (!document.querySelector(opt.nextPagerSelector)) return;
                            let nextUrl = document.querySelector(opt.nextPagerSelector).attributes.href.value;
                            is_requesting = true;

                            // 显示加载遮罩(无缝翻页时)
                            const overlay = document.getElementById('nsx-loading-overlay');
                            if (overlay) overlay.classList.add('show');

                            util.get(nextUrl, {}, 'text').then(function (data) {
                                let doc = new DOMParser().parseFromString(data, "text/html");
                                _this.blockPost(doc);//过滤帖子
                                _this.blockPostsByViewLevel(doc);
                                _this.blockPostsByCategory(doc);
                                if (opts.comment.pathPattern.test(location.pathname)){
                                    // 取加载页的评论数据追加到原评论数据
                                    let el = doc.getElementById('temp-script')
                                    let jsonText = el.textContent;
                                    if (jsonText) {
                                        let conf = JSON.parse(util.b64DecodeUnicode(jsonText))
                                        unsafeWindow.__config__.postData.comments.push(...conf.postData.comments);
                                    }
                                }
                                if (name === 'block_posts') {
                                    const keywordsBox = layero[0].querySelector('#block_post_keywords_box');
                                    if (keywordsBox) keywordsBox.style.display = data.elem.checked ? '' : 'none';
                                    if (data.elem.checked) {
                                        _this.refreshBlockKeywordRules();
                                        _this.blockPost();
                                    }
                                }
                                document.querySelector(opt.postListSelector).append(...doc.querySelector(opt.postListSelector).childNodes);
                                document.querySelector(opt.topPagerSelector).innerHTML = doc.querySelector(opt.topPagerSelector).innerHTML;
                                document.querySelector(opt.bottomPagerSelector).innerHTML = doc.querySelector(opt.bottomPagerSelector).innerHTML;
                                history.pushState(null, null, nextUrl);
                                _this.replaceDefaultAvatars(doc);

                                // 确保新加载的内容也应用紧凑模式样式
                                if (Config.getConfig('compact_mode.enabled') !== false) {
                                    _this.updateCompactModeStyle();
                                }

                                // 确保新加载的内容也应用隐藏设置
                                _this.togglePostCategory();
                                _this.togglePostInfo();

                                // 应用关键词高亮
                                if (Config.getConfig('right_panel_highlight.enabled') === true) {
                                    _this.applyRightPanelHighlight();
                                }

                                // 应用排序
                                _this.sortPostList();

                                // 如果启用了显示所有用户统计,为新加载的内容添加统计信息
                                if (Config.getConfig('show_all_users_stats.enabled') === true) {
                                    setTimeout(() => {
                                        _this.showAllUsersStats();
                                    }, 300);
                                }

                                // 隐藏加载遮罩
                                const overlay = document.getElementById('nsx-loading-overlay');
                                if (overlay) overlay.classList.remove('show');

                                // 评论菜单条
                                if (opts.comment.pathPattern.test(location.pathname)){
                                    const vue = document.querySelector('.comment-menu').__vue__;
                                    Array.from(document.querySelectorAll(".content-item")).forEach(function (t,e) {
                                        const n = t.querySelector(".comment-menu-mount");
                                        if(!n) return;
                                        const o = new vue.$root.constructor(vue.$options);
                                        o.setIndex(e);
                                        o.$mount(n);
                                    });
                                    
                                    // 如果启用了显示所有用户统计,为新加载的评论添加统计信息
                                    if (Config.getConfig('show_all_users_stats.enabled') === true) {
                                        setTimeout(() => {
                                            _this.showAllUsersStats();
                                        }, 500);
                                    }
                                }
                                is_requesting = false;
                            }).catch(function (err) {
                                // 出错时也隐藏遮罩
                                const overlay = document.getElementById('nsx-loading-overlay');
                                if (overlay) overlay.classList.remove('show');
                                is_requesting = false;
                                util.clog(err);
                            });
                        }
                    }
                });
            },
            // 滚动条事件
            windowScroll(fn1) {
                let beforeScrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop,
                    fn = fn1 || function () { };
                setTimeout(function () { // 延时执行,避免刚载入到页面就触发翻页事件
                    window.addEventListener('scroll', function (e) {
                        const afterScrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop,
                              delta = afterScrollTop - beforeScrollTop;
                        if (delta == 0) return false;
                        fn(delta > 0 ? 'down' : 'up', e);
                        beforeScrollTop = afterScrollTop;
                    }, false);
                }, 1000)
            },
            // 平滑滚动
            smoothScroll(){
                const scroll = (selector, top = 0) => {
                    const btn = document.querySelector(selector);
                    if (btn) {
                        // 移除现有事件监听器
                        btn.onclick = null;
                        btn.removeAttribute('onclick');
                        // 添加新的事件处理器
                        btn.addEventListener('click', e => {
                            e.preventDefault();
                            e.stopImmediatePropagation();
                            if(e.target.querySelector('use[href="#down"]')){
                                top = Math.max(document.documentElement.scrollHeight, document.body.scrollHeight);
                            }
                            window.scrollTo({ top, behavior: 'smooth' });
                        }, true);
                    }
                };
                scroll('#back-to-top', 0);
                scroll('#back-to-bottom', Math.max(document.documentElement.scrollHeight, document.body.scrollHeight));
            },
            history: ()=>{
                const STORAGE_KEY = 'nsx_browsing_history';
                const PAGE_SIZE = 10;
                let saveLimit = 'all';
                let sortedCache = null; // 缓存排序后的数据

                const POST_URL_PATTERN = /\/post-(\d+)-\d+.*$/;
                const getCurrentTime = () => layui.util.toDateString(new Date(),"yyyy-MM-ddTHH:mm:ss.SSS");

                const getBrowsingHistory = () => {
                    return JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
                };

                const saveBrowsingHistory = (history) => {
                    if (saveLimit !== 'all') {
                        history = history.slice(-saveLimit);
                    }
                    // 保存时排序,并清除缓存
                    sortedCache = null;
                    localStorage.setItem(STORAGE_KEY, JSON.stringify(history));
                };

                const addOrUpdateHistory = (url, title) => {
                    const match = url.match(POST_URL_PATTERN);
                    if (!match) return; // 只保存匹配的帖子记录

                    const normalizedUrl = `/post-${match[1]}-1`; // 只判断第1页,即不区分页码
                    const history = getBrowsingHistory();
                    const index = history.findIndex(item => item.url === normalizedUrl);
                    const entry = { url: normalizedUrl, title, time: getCurrentTime() };
                    if (index > -1) {
                        history[index] = entry;
                    }
                    else {
                        history.push(entry);
                    }
                    saveBrowsingHistory(history);
                };

                const getHistory = (page = 1) => {
                    // 使用缓存或重新排序
                    if (!sortedCache) {
                    const history = getBrowsingHistory();
                        sortedCache = history.sort((a, b) => new Date(b.time) - new Date(a.time));
                    }
                    if(page===0) return sortedCache;
                    return sortedCache.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE);
                };

                const showHistory = (page = 1) => {
                    const history = getBrowsingHistory();
                    const totalPages = Math.ceil(history.length / PAGE_SIZE);
                    const pageHistory = getHistory(page);
                    // console.clear();
                    // console.log(`浏览历史 - 第 ${page} 页,共 ${totalPages} 页`);
                    pageHistory.forEach((item, i) => {
                        // console.log(`${(page - 1) * PAGE_SIZE + i + 1}. [${item.time}] ${item.title} - ${item.url}`);
                    });
                    if (page < totalPages) {
                        // console.log(`输入 showHistory(${page + 1}) 查看下一页`);
                    }
                };

                const setSaveLimit = (limit) => {
                    if (typeof limit === 'number' && limit > 0 || limit === 'all') {
                        saveLimit = limit;
                        // console.log(`保存限制已设置为:${limit === 'all' ? '全部' : `最近 ${limit} 条`}`);
                    }
                    else {
                        // console.error('无效的保存限制。请输入正整数或 "all"');
                    }
                };

                const injectDom=()=>{
                    const svg = util.createElement("svg", { staticClass: "iconpark-icon", attrs: { "style": "width: 17px;height: 17px;" }},[ util.createElement("use",{ attrs: { "href": "#history"} }, [], document, "http://www.w3.org/2000/svg") ], document, "http://www.w3.org/2000/svg");
                    const originalSwitcher = document.querySelector('#nsk-head .color-theme-switcher');
                    if (originalSwitcher) {
                        const svgWrap = originalSwitcher.cloneNode();
                        svgWrap.classList.replace('color-theme-switcher', 'history-dropdown-on');
                        svgWrap.setAttribute('lay-options', '{trigger:"hover"}');

                        // 判断是否为移动端(li 元素)并移除 SVG 的 style 属性
                        if (originalSwitcher.tagName.toLowerCase() === 'li') {
                            svg.removeAttribute('style');
                        }

                        svgWrap.appendChild(svg);
                        originalSwitcher.insertAdjacentElement('beforebegin', svgWrap);
                    }

                    const history=getHistory(0);
                    const maxLength=20;
                    // 按天分组
                    const grouped = history.reduce((result, item, i) => {
                        const date = item.time.split("T")[0];
                        if (!result[date]) {
                            result[date] = [];
                        }
                        const truncatedTitle = item.title.length > maxLength
                        ? item.title.slice(0, maxLength) + "..."
                        : item.title;
                        result[date].push({
                            id: 1000+i+1,
                            title: `${truncatedTitle}(${layui.util.toDateString(item.time,'HH:mm')})`,
                            href: item.url,
                            time: item.time
                        });
                        return result;
                    }, {});

                    // 转换为目标结构
                    const result = Object.entries(grouped).map(([day, items], index) => ({
                        id: index + 1,
                        title: day,
                        type: "group",
                        child: items // 将子项包裹在数组中
                    }));

                    // console.log(result);

                    dropdown.render({
                        elem: '.history-dropdown-on',
                        // trigger: 'click' // trigger 已配置在元素 `lay-options` 属性上
                        data: result,
                        style: 'width: 370px; height: 200px;'
                    });
                };

                addOrUpdateHistory(window.location.href, document.title);
                injectDom();
            },
            initInstantPage:() => {
                const prefetchedUrls = new Set(); // 用于存储已经尝试预加载的 URL
                let prefetcher = document.createElement('link');
                prefetcher.rel = 'prefetch';

                document.body.addEventListener('mouseover', (event) => {
                    const target = event.target.closest('a');

                    if (!target || !target.href || target.hasAttribute('data-no-instant')) {
                        return;
                    }

                    const href = target.href;

                    if (!href.startsWith(`${BASE_URL}/post-`)) {
                        return;
                    }

                    if (prefetchedUrls.has(href)) {
                        // console.log('跳过已预加载链接:', href);
                        return;
                    }

                    setTimeout(() => {
                        if (target.matches(':hover')) {
                            prefetcher.href = href;
                            document.head.appendChild(prefetcher);
                            prefetchedUrls.add(href);
                            // console.log('预加载链接已启动:', href);
                        }
                    }, 65); // 65毫秒延迟
                });
            },
            // 在导航栏添加设置按钮
            addSettingsButton() {
                const header = document.querySelector('#nsk-head');
                if (!header) return;

                const colorSwitcher = header.querySelector('.color-theme-switcher');
                if (!colorSwitcher) return;

                // 检查是否已存在设置按钮
                if (header.querySelector('.nsx-settings-btn')) return;

                const settingsBtn = colorSwitcher.cloneNode(true);
                settingsBtn.classList.remove('color-theme-switcher');
                settingsBtn.classList.add('nsx-settings-btn');
                settingsBtn.setAttribute('title', 'NodeSeek X 设置');
                settingsBtn.querySelector('use').setAttribute('href', '#setting');
                settingsBtn.addEventListener('click', (e) => {
                    e.preventDefault();
                    this.advancedSettings();
                });

                colorSwitcher.insertAdjacentElement('beforebegin', settingsBtn);
            },
            moveSearchBoxToCenter() {
                // 搜索框定位逻辑已提前通过紧凑模式样式处理,避免运行时闪烁
            },
            advancedSettings() {
                const _this = this;
                const layerWidth = layui.device().mobile ? '100%' : '700px';
                const siteCode = opts.curSite ? opts.curSite.code : 'ns';

                // 生成设置内容
            const generateSettingsContent = () => {
                const blockPostsEnabled = (Config.getConfig('block_posts.enabled') ?? true) !== false;
                const blockCategoriesEnabled = Config.getConfig('block_categories.enabled') === true;
                const blockPostKeywordsValue = (_this.getBlockKeywordInputValue() || '')
                    .replace(/&/g, '&amp;')
                    .replace(/</g, '&lt;')
                    .replace(/>/g, '&gt;');
                const blockCategoriesValue = (_this.getBlockedCategoryInputValue() || '')
                    .replace(/&/g, '&amp;')
                    .replace(/</g, '&lt;')
                    .replace(/>/g, '&gt;');
                const signInMethod = Config.getConfig(`sign_in.${siteCode}.method`) ?? 0;
                const signInEnabled = Config.getConfig(`sign_in.${siteCode}.enabled`) === true;
                const typographyTitle = Config.getConfig('typography.title') || {};
                const typographyTag = Config.getConfig('typography.tag') || {};
                const typographyMeta = Config.getConfig('typography.meta') || {};
                const typographyContent = Config.getConfig('typography.content') || {};
                const escape = (val) => (val || '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');

                return `
<div class="layui-row" style="display:flex;height:100%">
  <div class="layui-panel layui-col-xs3 layui-col-sm3 layui-col-md3" id="nsx-settings-menu">
    <ul class="layui-menu" lay-filter="nsx-settings-menu">
      <li class="layui-menu-item-checked"><div class="layui-menu-body-title"><a href="javascript:void(0)" data-target="basic">基本设置</a></div></li>
      <li><div class="layui-menu-body-title"><a href="javascript:void(0)" data-target="enhance">增强功能</a></div></li>
      <li><div class="layui-menu-body-title"><a href="javascript:void(0)" data-target="display">显示设置</a></div></li>
      <li><div class="layui-menu-body-title"><a href="javascript:void(0)" data-target="config">配置</a></div></li>
    </ul>
  </div>
  <div class="layui-col-xs9 layui-col-sm9 layui-col-md9" style="overflow-y: auto; padding: 15px;" id="nsx-settings-content">
    <fieldset id="basic" class="layui-elem-field layui-field-title">
      <legend>基本设置</legend>
    </fieldset>
    <div class="layui-form" lay-filter="nsx-settings-form" style="padding: 20px 0;">
      <div class="layui-form-item">
        <label class="layui-form-label">自动签到</label>
        <div class="layui-input-block">
          <input type="radio" name="sign_in_method" value="0" title="关闭" lay-filter="sign_in_method" ${signInEnabled !== true ? 'checked' : ''}>
          <input type="radio" name="sign_in_method" value="1" title="随机🍗" lay-filter="sign_in_method" ${signInEnabled && signInMethod === 1 ? 'checked' : ''}>
          <input type="radio" name="sign_in_method" value="2" title="5个🍗" lay-filter="sign_in_method" ${signInEnabled && (signInMethod === 0 || signInMethod === undefined) ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">移除推广</label>
        <div class="layui-input-block">
          <input type="checkbox" name="remove_promotions" lay-skin="switch" lay-filter="remove_promotions" lay-text="开启|关闭" ${Config.getConfig('remove_promotions.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">隐藏页面中的推广位(.promotation-item)。</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">默认头像</label>
        <div class="layui-input-block">
          <input type="checkbox" name="default_avatar" lay-skin="switch" lay-filter="default_avatar" lay-text="开启|关闭" ${Config.getConfig('default_avatar.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">识别系统随机头像并替换为自定义图片。</div>
        </div>
      </div>
      <div class="layui-form-item" id="default_avatar_box" style="${Config.getConfig('default_avatar.enabled') === true ? '' : 'display: none;'}">
        <label class="layui-form-label">头像设置</label>
        <div class="layui-input-block">
          <input type="text" name="default_avatar_url" value="${escape(Config.getConfig('default_avatar.url') || '')}" placeholder="替换用的头像 URL" class="layui-input" style="margin-bottom: 8px;">
          <div style="margin-bottom: 6px;">
            <input type="checkbox" name="default_avatar_auto" lay-skin="primary" lay-filter="default_avatar_auto" title="自动识别默认头像" ${Config.getConfig('default_avatar.auto_detect') === false ? '' : 'checked'}>
          </div>
          <div class="layui-form-mid layui-word-aux">若禁用自动识别则所有未自定义头像的用户都会替换为上面的 URL。</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">加载遮罩</label>
        <div class="layui-input-block">
          <input type="checkbox" name="loading_overlay" lay-skin="switch" lay-filter="loading_overlay" lay-text="开启|关闭" ${(Config.getConfig('loading_overlay.enabled') ?? true) !== false ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">控制开屏时的模糊加载页。</div>
        </div>
      </div>
      <div class="layui-form-item" id="loading_overlay_box" style="${(Config.getConfig('loading_overlay.enabled') ?? true) !== false ? '' : 'display:none;'}">
        <label class="layui-form-label">显示时长</label>
        <div class="layui-input-block">
          <input type="range" name="loading_overlay_duration" min="300" max="3000" step="100" value="${Config.getConfig('loading_overlay.duration') ?? INITIAL_OVERLAY_DURATION_DEFAULT}" style="width:200px;">
          <span class="layui-form-mid" id="loading_overlay_duration_display">${(Config.getConfig('loading_overlay.duration') ?? INITIAL_OVERLAY_DURATION_DEFAULT)}ms</span>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">签到提示</label>
        <div class="layui-input-block">
          <input type="checkbox" name="signin_tips" lay-skin="switch" lay-filter="signin_tips" lay-text="开启|关闭" ${(Config.getConfig('signin_tips.enabled') ?? true) !== false ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">自动跳转外部链接</label>
        <div class="layui-input-block">
          <input type="checkbox" name="auto_jump_external_links" lay-skin="switch" lay-filter="auto_jump_external_links" lay-text="开启|关闭" ${(Config.getConfig('auto_jump_external_links.enabled') ?? true) !== false ? 'checked' : ''}>
        </div>
      </div>
    </div>

    <fieldset id="enhance" class="layui-elem-field layui-field-title">
      <legend>增强功能</legend>
    </fieldset>
    <div class="layui-form" lay-filter="nsx-settings-form" style="padding: 20px 0;">
      <div class="layui-form-item">
        <label class="layui-form-label">下拉加载翻页</label>
        <div class="layui-input-block">
          <input type="checkbox" name="loading_post" lay-skin="switch" lay-filter="loading_post" lay-text="开启|关闭" ${(Config.getConfig('loading_post.enabled') ?? true) !== false ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">自动加载帖子和评论</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">新标签页打开帖子</label>
        <div class="layui-input-block">
          <input type="checkbox" name="open_post_in_new_tab" lay-skin="switch" lay-filter="open_post_in_new_tab" lay-text="开启|关闭" ${Config.getConfig('open_post_in_new_tab.enabled') === true ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">快捷评论</label>
        <div class="layui-input-block">
          <input type="checkbox" name="quick_comment" lay-skin="switch" lay-filter="quick_comment" lay-text="开启|关闭" ${(Config.getConfig('quick_comment.enabled') ?? true) !== false ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">屏蔽用户</label>
        <div class="layui-input-block">
          <input type="checkbox" name="block_members" lay-skin="switch" lay-filter="block_members" lay-text="开启|关闭" ${(Config.getConfig('block_members.enabled') ?? true) !== false ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">屏蔽帖子</label>
        <div class="layui-input-block">
          <input type="checkbox" name="block_posts" lay-skin="switch" lay-filter="block_posts" lay-text="开启|关闭" ${blockPostsEnabled ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item" id="block_post_keywords_box" style="${blockPostsEnabled ? '' : 'display: none;'}">
        <label class="layui-form-label">标题关键词</label>
        <div class="layui-input-block">
          <textarea name="block_post_keywords" class="layui-textarea" placeholder="一行一个关键词;使用 /正则/flags 形式可启用正则匹配">${blockPostKeywordsValue}</textarea>
          <div class="layui-form-mid layui-word-aux">示例:<code>羊了个羊</code>、<code>/^\\[广告\\]/i</code>。匹配命中时会直接隐藏该帖子。</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">屏蔽分类</label>
        <div class="layui-input-block">
          <input type="checkbox" name="block_categories" lay-skin="switch" lay-filter="block_categories" lay-text="开启|关闭" ${blockCategoriesEnabled ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item" id="block_categories_box" style="${blockCategoriesEnabled ? '' : 'display: none;'}">
        <label class="layui-form-label">分类列表</label>
        <div class="layui-input-block">
          <textarea name="block_categories_list" class="layui-textarea" placeholder="一行一个分类名称,如:日常、技术、交易">${blockCategoriesValue}</textarea>
          <div class="layui-form-mid layui-word-aux">与帖子上显示的分类文字一致即可,例如“日常”“技术”“情报”“测评”等。</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">用户卡片扩展</label>
        <div class="layui-input-block">
          <input type="checkbox" name="user_card_ext" lay-skin="switch" lay-filter="user_card_ext" lay-text="开启|关闭" ${(Config.getConfig('user_card_ext.enabled') ?? true) !== false ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">显示所有用户统计</label>
        <div class="layui-input-block">
          <input type="checkbox" name="show_all_users_stats" lay-skin="switch" lay-filter="show_all_users_stats" lay-text="开启|关闭" ${Config.getConfig('show_all_users_stats.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">在帖子内所有用户(包括评论者)的元数据区域显示注册天数、鸡腿数量、帖子数、评论数等统计信息</div>
        </div>
      </div>
      <div class="layui-form-item" id="show_all_users_stats_position_box" style="${Config.getConfig('show_all_users_stats.enabled') === true ? '' : 'display: none;'}">
        <label class="layui-form-label">显示位置</label>
        <div class="layui-input-block">
          <input type="radio" name="show_all_users_stats_position" value="below" title="下方" lay-filter="show_all_users_stats_position" ${(Config.getConfig('show_all_users_stats.position') || 'below') === 'below' ? 'checked' : ''}>
          <input type="radio" name="show_all_users_stats_position" value="right" title="作者名字右边" lay-filter="show_all_users_stats_position" ${Config.getConfig('show_all_users_stats.position') === 'right' ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">选择统计信息的显示位置</div>
        </div>
      </div>
    </div>

    <fieldset id="display" class="layui-elem-field layui-field-title">
      <legend>显示设置</legend>
    </fieldset>
    <div class="layui-form" lay-filter="nsx-settings-form" style="padding: 20px 0;">
      <div class="layui-form-item">
        <label class="layui-form-label">等级标签</label>
        <div class="layui-input-block">
          <input type="checkbox" name="level_tag" lay-skin="switch" lay-filter="level_tag" lay-text="开启|关闭" ${(Config.getConfig('level_tag.enabled') ?? true) !== false ? 'checked' : ''}>
  </div>
</div>
      <div class="layui-form-item">
        <label class="layui-form-label">代码高亮</label>
        <div class="layui-input-block">
          <input type="checkbox" name="code_highlight" lay-skin="switch" lay-filter="code_highlight" lay-text="开启|关闭" ${(Config.getConfig('code_highlight.enabled') ?? true) !== false ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">图片滑动查看</label>
        <div class="layui-input-block">
          <input type="checkbox" name="image_slide" lay-skin="switch" lay-filter="image_slide" lay-text="开启|关闭" ${(Config.getConfig('image_slide.enabled') ?? true) !== false ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">已访问链接标记</label>
        <div class="layui-input-block">
          <input type="checkbox" name="visited_links" lay-skin="switch" lay-filter="visited_links" lay-text="开启|关闭" ${(Config.getConfig('visited_links.enabled') ?? true) !== false ? 'checked' : ''}>
        </div>
        <div class="layui-input-block" style="margin-top: 10px;">
          <input type="checkbox" name="hide_visited_links" lay-skin="primary" lay-filter="hide_visited_links" title="隐藏已访问帖子" ${Config.getConfig('visited_links.hide_visited') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">启用后,点击过的帖子会直接在列表中隐藏。</div>
        </div>
        <div class="layui-input-block" style="margin-top: 10px;">
          <input type="checkbox" name="visited_to_bottom" lay-skin="primary" lay-filter="visited_to_bottom" title="已访问帖子置底" ${Config.getConfig('post_sort.visited_to_bottom') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">启用后,已访问的帖子会排在列表最后。</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">帖子排序</label>
        <div class="layui-input-block">
          <input type="radio" name="post_sort_mode" value="none" title="不排序" lay-filter="post_sort_mode" ${(Config.getConfig('post_sort.mode') || 'none') === 'none' ? 'checked' : ''}>
          <input type="radio" name="post_sort_mode" value="comments" title="按回复数" lay-filter="post_sort_mode" ${Config.getConfig('post_sort.mode') === 'comments' ? 'checked' : ''}>
          <input type="radio" name="post_sort_mode" value="views" title="按查看数" lay-filter="post_sort_mode" ${Config.getConfig('post_sort.mode') === 'views' ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">对帖子列表进行排序,按回复数或查看数从高到低排列</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">紧凑模式</label>
        <div class="layui-input-block">
          <input type="checkbox" name="compact_mode" lay-skin="switch" lay-filter="compact_mode" lay-text="开启|关闭" ${(Config.getConfig('compact_mode.enabled') ?? true) !== false ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">增大信息密度,一页显示更多帖子</div>
        </div>
      </div>
      <div class="layui-form-item" id="compact_mode_options" style="${(Config.getConfig('compact_mode.enabled') ?? true) !== false ? '' : 'display: none;'}">
        <label class="layui-form-label">列数</label>
        <div class="layui-input-block">
          <input type="radio" name="compact_columns" value="1" title="1列" lay-filter="compact_columns" ${(Config.getConfig('compact_mode.columns') ?? 1) === 1 ? 'checked' : ''}>
          <input type="radio" name="compact_columns" value="2" title="2列" lay-filter="compact_columns" ${(Config.getConfig('compact_mode.columns') ?? 1) === 2 ? 'checked' : ''}>
          <input type="radio" name="compact_columns" value="3" title="3列" lay-filter="compact_columns" ${(Config.getConfig('compact_mode.columns') ?? 1) === 3 ? 'checked' : ''}>
          <input type="radio" name="compact_columns" value="4" title="4列" lay-filter="compact_columns" ${(Config.getConfig('compact_mode.columns') ?? 1) === 4 ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item" id="compact_mode_custom_options" style="${(Config.getConfig('compact_mode.enabled') ?? true) !== false ? '' : 'display: none;'}">
        <label class="layui-form-label">自定义设置</label>
        <div class="layui-input-block">
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">内边距 (px):</label>
            <input type="text" name="compact_padding" value="${Config.getConfig('compact_mode.padding') || '6px 10px'}" placeholder="如: 6px 10px" style="width: 150px; display: inline-block;">
          </div>
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">头像大小 (px):</label>
            <input type="number" name="compact_avatarSize" value="${Config.getConfig('compact_mode.avatarSize') || 26}" min="16" max="40" style="width: 150px; display: inline-block;">
          </div>
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">标题字体 (px):</label>
            <input type="number" name="compact_titleFontSize" value="${Config.getConfig('compact_mode.titleFontSize') || 13}" min="10" max="16" style="width: 150px; display: inline-block;">
          </div>
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">信息字体 (px):</label>
            <input type="number" name="compact_infoFontSize" value="${Config.getConfig('compact_mode.infoFontSize') || 10}" min="8" max="12" style="width: 150px; display: inline-block;">
          </div>
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">间距 (px):</label>
            <input type="number" name="compact_marginBottom" value="${Config.getConfig('compact_mode.marginBottom') || 2}" min="0" max="10" style="width: 150px; display: inline-block;">
          </div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">自定义背景图</label>
        <div class="layui-input-block">
          <input type="checkbox" name="custom_background" lay-skin="switch" lay-filter="custom_background" lay-text="开启|关闭" ${Config.getConfig('custom_background.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">自定义页面背景图片</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">Header透明</label>
        <div class="layui-input-block">
          <input type="checkbox" name="header_opacity" lay-skin="switch" lay-filter="header_opacity" lay-text="开启|关闭" ${Config.getConfig('header_opacity.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">调节顶栏透明度,美化视觉。</div>
        </div>
      </div>
      <div class="layui-form-item" id="header_opacity_box" style="${Config.getConfig('header_opacity.enabled') === true ? '' : 'display: none;'}">
        <label class="layui-form-label">透明度</label>
        <div class="layui-input-block">
          <input type="range" name="header_opacity_value" min="0" max="1" step="0.01" value="${Config.getConfig('header_opacity.value') ?? 0.92}" style="width: 200px;">
          <span class="layui-form-mid" id="header_opacity_value_display">${(Config.getConfig('header_opacity.value') ?? 0.92).toFixed(2)}</span>
        </div>
        <div class="layui-input-block" style="margin-top:10px;">
          <input type="checkbox" name="header_opacity_blur_toggle" lay-skin="primary" lay-filter="header_opacity_blur_toggle" title="开启模糊" ${(Config.getConfig('header_opacity.blur_enabled') ?? true) !== false ? 'checked' : ''}>
          <input type="number" name="header_opacity_blur" class="layui-input" style="width:100px;display:inline-block;margin-left:10px;" placeholder="blur(px)" value="${Config.getConfig('header_opacity.blur') ?? 16}">
        </div>
        <div class="layui-input-block" style="margin-top:10px;">
          <input type="checkbox" name="header_opacity_saturate_toggle" lay-skin="primary" lay-filter="header_opacity_saturate_toggle" title="开启饱和度" ${(Config.getConfig('header_opacity.saturate_enabled') ?? true) !== false ? 'checked' : ''}>
          <input type="number" name="header_opacity_saturate" class="layui-input" style="width:120px;display:inline-block;margin-left:10px;" placeholder="saturate(%)" value="${Config.getConfig('header_opacity.saturate') ?? 180}">
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">框体透明</label>
        <div class="layui-input-block">
          <input type="checkbox" name="frame_opacity" lay-skin="switch" lay-filter="frame_opacity" lay-text="开启|关闭" ${Config.getConfig('frame_opacity.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">调节 #nsk-frame 等主体容器透明度。</div>
        </div>
      </div>
      <div class="layui-form-item" id="frame_opacity_box" style="${Config.getConfig('frame_opacity.enabled') === true ? '' : 'display: none;'}">
        <label class="layui-form-label">透明度</label>
        <div class="layui-input-block">
          <input type="range" name="frame_opacity_value" min="0" max="1" step="0.01" value="${Config.getConfig('frame_opacity.value') ?? 0.95}" style="width: 200px;">
          <span class="layui-form-mid" id="frame_opacity_value_display">${(Config.getConfig('frame_opacity.value') ?? 0.95).toFixed(2)}</span>
        </div>
        <div class="layui-input-block" style="margin-top:10px;">
          <input type="checkbox" name="frame_opacity_blur_toggle" lay-skin="primary" lay-filter="frame_opacity_blur_toggle" title="开启模糊" ${(Config.getConfig('frame_opacity.blur_enabled') ?? true) !== false ? 'checked' : ''}>
          <input type="number" name="frame_opacity_blur" class="layui-input" style="width:100px;display:inline-block;margin-left:10px;" placeholder="blur(px)" value="${Config.getConfig('frame_opacity.blur') ?? 12}">
        </div>
        <div class="layui-input-block" style="margin-top:10px;">
          <input type="checkbox" name="frame_opacity_saturate_toggle" lay-skin="primary" lay-filter="frame_opacity_saturate_toggle" title="开启饱和度" ${(Config.getConfig('frame_opacity.saturate_enabled') ?? true) !== false ? 'checked' : ''}>
          <input type="number" name="frame_opacity_saturate" class="layui-input" style="width:120px;display:inline-block;margin-left:10px;" placeholder="saturate(%)" value="${Config.getConfig('frame_opacity.saturate') ?? 180}">
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">标题字体</label>
        <div class="layui-input-block">
          <input type="checkbox" name="typography_title" lay-skin="switch" lay-filter="typography_title" lay-text="开启|关闭" ${typographyTitle.enabled ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item" id="typography_title_box">
        <label class="layui-form-label">设置</label>
        <div class="layui-input-block">
          <input type="text" name="typography_title_fontFamily" placeholder="font-family" value="${escape(typographyTitle.fontFamily)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_title_fontSize" placeholder="font-size (如 16px)" value="${escape(typographyTitle.fontSize)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_title_color" placeholder="color (如 #333)" value="${escape(typographyTitle.color)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_title_fontStyle" placeholder="font-style" value="${escape(typographyTitle.fontStyle)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_title_letterSpacing" placeholder="letter-spacing" value="${escape(typographyTitle.letterSpacing)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_title_ligatures" placeholder="font-variant-ligatures" value="${escape(typographyTitle.ligatures)}" class="layui-input">
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">Tag 字体</label>
        <div class="layui-input-block">
          <input type="checkbox" name="typography_tag" lay-skin="switch" lay-filter="typography_tag" lay-text="开启|关闭" ${typographyTag.enabled ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item" id="typography_tag_box">
        <label class="layui-form-label">设置</label>
        <div class="layui-input-block">
          <input type="text" name="typography_tag_fontFamily" placeholder="font-family" value="${escape(typographyTag.fontFamily)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_tag_fontSize" placeholder="font-size" value="${escape(typographyTag.fontSize)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_tag_color" placeholder="color" value="${escape(typographyTag.color)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_tag_fontStyle" placeholder="font-style" value="${escape(typographyTag.fontStyle)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_tag_letterSpacing" placeholder="letter-spacing" value="${escape(typographyTag.letterSpacing)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_tag_ligatures" placeholder="font-variant-ligatures" value="${escape(typographyTag.ligatures)}" class="layui-input">
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">Meta 字体</label>
        <div class="layui-input-block">
          <input type="checkbox" name="typography_meta" lay-skin="switch" lay-filter="typography_meta" lay-text="开启|关闭" ${typographyMeta.enabled ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item" id="typography_meta_box">
        <label class="layui-form-label">设置</label>
        <div class="layui-input-block">
          <input type="text" name="typography_meta_fontFamily" placeholder="font-family" value="${escape(typographyMeta.fontFamily)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_meta_fontSize" placeholder="font-size" value="${escape(typographyMeta.fontSize)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_meta_color" placeholder="color" value="${escape(typographyMeta.color)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_meta_fontStyle" placeholder="font-style" value="${escape(typographyMeta.fontStyle)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_meta_letterSpacing" placeholder="letter-spacing" value="${escape(typographyMeta.letterSpacing)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_meta_ligatures" placeholder="font-variant-ligatures" value="${escape(typographyMeta.ligatures)}" class="layui-input">
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">内容字体</label>
        <div class="layui-input-block">
          <input type="checkbox" name="typography_content" lay-skin="switch" lay-filter="typography_content" lay-text="开启|关闭" ${typographyContent.enabled ? 'checked' : ''}>
        </div>
      </div>
      <div class="layui-form-item" id="typography_content_box">
        <label class="layui-form-label">设置</label>
        <div class="layui-input-block">
          <input type="text" name="typography_content_fontFamily" placeholder="font-family" value="${escape(typographyContent.fontFamily)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_content_fontSize" placeholder="font-size" value="${escape(typographyContent.fontSize)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_content_color" placeholder="color" value="${escape(typographyContent.color)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_content_fontStyle" placeholder="font-style" value="${escape(typographyContent.fontStyle)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_content_letterSpacing" placeholder="letter-spacing" value="${escape(typographyContent.letterSpacing)}" class="layui-input" style="margin-bottom:6px;">
          <input type="text" name="typography_content_ligatures" placeholder="font-variant-ligatures" value="${escape(typographyContent.ligatures)}" class="layui-input">
        </div>
      </div>
      <div class="layui-form-item" id="custom_background_options" style="${Config.getConfig('custom_background.enabled') === true ? '' : 'display: none;'}">
        <label class="layui-form-label">背景图设置</label>
        <div class="layui-input-block">
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">上传图片:</label>
            <input type="file" id="custom_bg_upload" accept="image/*" style="display: none;">
            <button type="button" id="custom_bg_upload_btn" class="layui-btn layui-btn-sm" style="margin-right: 10px;">选择图片</button>
            <button type="button" id="custom_bg_clear_btn" class="layui-btn layui-btn-sm layui-btn-danger" style="display: ${Config.getConfig('custom_background.url') ? 'inline-block' : 'none'};">清除图片</button>
            <div id="custom_bg_preview" style="margin-top: 10px; ${Config.getConfig('custom_background.url') && Config.getConfig('custom_background.url').startsWith('data:') ? '' : 'display: none;'}">
              <img id="custom_bg_preview_img" src="${Config.getConfig('custom_background.url') || ''}" style="max-width: 300px; max-height: 200px; border: 1px solid #ddd; border-radius: 4px; display: block;">
            </div>
          </div>
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">或输入URL:</label>
            <input type="text" name="custom_bg_url" value="${Config.getConfig('custom_background.url') && !Config.getConfig('custom_background.url').startsWith('data:') ? Config.getConfig('custom_background.url') : ''}" placeholder="输入图片URL" style="width: 400px; display: inline-block;">
          </div>
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">重复方式:</label>
            <select name="custom_bg_repeat" style="width: 150px; display: inline-block;">
              <option value="repeat" ${(Config.getConfig('custom_background.repeat') || 'repeat') === 'repeat' ? 'selected' : ''}>重复</option>
              <option value="no-repeat" ${Config.getConfig('custom_background.repeat') === 'no-repeat' ? 'selected' : ''}>不重复</option>
              <option value="repeat-x" ${Config.getConfig('custom_background.repeat') === 'repeat-x' ? 'selected' : ''}>横向重复</option>
              <option value="repeat-y" ${Config.getConfig('custom_background.repeat') === 'repeat-y' ? 'selected' : ''}>纵向重复</option>
            </select>
          </div>
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">位置:</label>
            <input type="text" name="custom_bg_position" value="${Config.getConfig('custom_background.position') || 'center'}" placeholder="如: center, top left, 50% 50%" style="width: 200px; display: inline-block;">
          </div>
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">大小:</label>
            <input type="text" name="custom_bg_size" value="${Config.getConfig('custom_background.size') || 'cover'}" placeholder="如: auto, cover, contain, 100% 100%" style="width: 200px; display: inline-block;">
          </div>
          <div style="margin-bottom: 10px;">
            <label style="display: inline-block; width: 120px;">滚动方式:</label>
            <select name="custom_bg_attachment" style="width: 150px; display: inline-block;">
              <option value="scroll" ${(Config.getConfig('custom_background.attachment') || 'scroll') === 'scroll' ? 'selected' : ''}>随页面滚动</option>
              <option value="fixed" ${Config.getConfig('custom_background.attachment') === 'fixed' ? 'selected' : ''}>固定背景</option>
            </select>
          </div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">合并分类到导航栏</label>
        <div class="layui-input-block">
          <input type="checkbox" name="merge_category_to_nav" lay-skin="switch" lay-filter="merge_category_to_nav" lay-text="开启|关闭" ${Config.getConfig('merge_category_to_nav.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">将分类面板合并到导航栏,节省空间。多列模式下自动启用</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">隐藏用户统计面板</label>
        <div class="layui-input-block">
          <input type="checkbox" name="hide_user_stats_panel" lay-skin="switch" lay-filter="hide_user_stats_panel" lay-text="开启|关闭" ${Config.getConfig('hide_user_stats_panel.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">隐藏右侧面板中的"用户数目"和"欢迎新用户"面板</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">隐藏页脚</label>
        <div class="layui-input-block">
          <input type="checkbox" name="hide_footer" lay-skin="switch" lay-filter="hide_footer" lay-text="开启|关闭" ${Config.getConfig('hide_footer.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">隐藏页面底部的 footer 区域</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">隐藏分类标签</label>
        <div class="layui-input-block">
          <input type="checkbox" name="hide_post_category" lay-skin="switch" lay-filter="hide_post_category" lay-text="开启|关闭" ${Config.getConfig('hide_post_category.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">隐藏帖子列表中的分类标签(如"日常"、"技术"等)</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">隐藏帖子信息</label>
        <div class="layui-input-block">
          <input type="checkbox" name="hide_post_info" lay-skin="switch" lay-filter="hide_post_info" lay-text="开启|关闭" ${Config.getConfig('hide_post_info.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">隐藏帖子列表中的作者、浏览量、评论数等信息</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">隐藏推荐轮播</label>
        <div class="layui-input-block">
          <input type="checkbox" name="hide_topic_carousel" lay-skin="switch" lay-filter="hide_topic_carousel" lay-text="开启|关闭" ${Config.getConfig('hide_topic_carousel.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">隐藏页面顶部的推荐帖子轮播图</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">右侧面板关键词高亮</label>
        <div class="layui-input-block">
          <input type="checkbox" name="right_panel_highlight" lay-skin="switch" lay-filter="right_panel_highlight" lay-text="开启|关闭" ${Config.getConfig('right_panel_highlight.enabled') === true ? 'checked' : ''}>
          <div class="layui-form-mid layui-word-aux">在右侧面板显示关键词输入框,可在帖子标题和右侧面板中高亮显示关键词</div>
        </div>
      </div>
    </div>

    <fieldset id="config" class="layui-elem-field layui-field-title">
      <legend>配置</legend>
    </fieldset>
    <div style="padding: 20px 0;">
      <div class="layui-form-item">
        <label class="layui-form-label">导出设置</label>
        <div class="layui-input-block">
          <button type="button" class="layui-btn layui-btn-sm" id="nsx-export-settings">导出到剪贴板</button>
          <div class="layui-form-mid layui-word-aux">复制当前全部设置,方便备份或同步。</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">导入设置</label>
        <div class="layui-input-block">
          <textarea id="nsx-import-settings" class="layui-textarea" placeholder="粘贴之前导出的配置 JSON"></textarea>
          <div class="layui-form-mid layui-word-aux">导入前会自动校验格式,并覆盖现有设置。</div>
          <button type="button" class="layui-btn layui-btn-danger layui-btn-sm" id="nsx-import-apply" style="margin-top:10px;">导入并应用</button>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">默认样式</label>
        <div class="layui-input-block">
          <button type="button" class="layui-btn layui-btn-sm layui-btn-normal" id="nsx-reset-to-default">一键设置默认样式</button>
          <div class="layui-form-mid layui-word-aux">将设置恢复为推荐的默认样式配置(不会覆盖version字段)。</div>
        </div>
      </div>
      <div class="layui-form-item">
        <label class="layui-form-label">键盘快捷键</label>
        <div class="layui-input-block">
          <div style="background-color: var(--bg-sub-color, #f5f5f5); border-radius: 4px; padding: 15px; margin-top: 10px;">
            <div style="font-weight: bold; margin-bottom: 12px; color: var(--text-color, #333);">当前可用的快捷键:</div>
            <table style="width: 100%; border-collapse: collapse;">
              <tbody>
                <tr style="border-bottom: 1px solid rgba(0,0,0,.1);">
                  <td style="padding: 8px 12px; font-weight: 500; color: var(--text-color, #333); width: 40%;">
                    <kbd style="background-color: var(--bg-main-color, #fff); border: 1px solid rgba(0,0,0,.2); border-radius: 3px; box-shadow: 0 1px 0 rgba(0,0,0,.2); padding: 3px 8px; font-family: monospace; font-size: 12px; color: var(--text-color, #333);">←</kbd>
                    <span style="margin-left: 5px;">或</span>
                    <kbd style="background-color: var(--bg-main-color, #fff); border: 1px solid rgba(0,0,0,.2); border-radius: 3px; box-shadow: 0 1px 0 rgba(0,0,0,.2); padding: 3px 8px; font-family: monospace; font-size: 12px; color: var(--text-color, #333);">ArrowLeft</kbd>
                  </td>
                  <td style="padding: 8px 12px; color: var(--text-color, #666);">跳转到上一页</td>
                </tr>
                <tr style="border-bottom: 1px solid rgba(0,0,0,.1);">
                  <td style="padding: 8px 12px; font-weight: 500; color: var(--text-color, #333);">
                    <kbd style="background-color: var(--bg-main-color, #fff); border: 1px solid rgba(0,0,0,.2); border-radius: 3px; box-shadow: 0 1px 0 rgba(0,0,0,.2); padding: 3px 8px; font-family: monospace; font-size: 12px; color: var(--text-color, #333);">→</kbd>
                    <span style="margin-left: 5px;">或</span>
                    <kbd style="background-color: var(--bg-main-color, #fff); border: 1px solid rgba(0,0,0,.2); border-radius: 3px; box-shadow: 0 1px 0 rgba(0,0,0,.2); padding: 3px 8px; font-family: monospace; font-size: 12px; color: var(--text-color, #333);">ArrowRight</kbd>
                  </td>
                  <td style="padding: 8px 12px; color: var(--text-color, #666);">跳转到下一页</td>
                </tr>
                <tr>
                  <td style="padding: 8px 12px; font-weight: 500; color: var(--text-color, #333);">
                    <kbd style="background-color: var(--bg-main-color, #fff); border: 1px solid rgba(0,0,0,.2); border-radius: 3px; box-shadow: 0 1px 0 rgba(0,0,0,.2); padding: 3px 8px; font-family: monospace; font-size: 12px; color: var(--text-color, #333);">Ctrl</kbd>
                    <span style="margin: 0 3px;">+</span>
                    <kbd style="background-color: var(--bg-main-color, #fff); border: 1px solid rgba(0,0,0,.2); border-radius: 3px; box-shadow: 0 1px 0 rgba(0,0,0,.2); padding: 3px 8px; font-family: monospace; font-size: 12px; color: var(--text-color, #333);">Enter</kbd>
                  </td>
                  <td style="padding: 8px 12px; color: var(--text-color, #666);">提交回复(在回复编辑器中)</td>
                </tr>
              </tbody>
            </table>
            <div style="margin-top: 12px; font-size: 12px; color: var(--text-color, #999); line-height: 1.6;">
              <div>💡 <strong>提示:</strong></div>
              <div style="margin-left: 20px; margin-top: 4px;">
                • 翻页快捷键仅在非输入框状态下生效<br>
                • 提交快捷键仅在回复编辑器中生效<br>
                • 快捷键不会与网站原有功能冲突
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>`;
                };

                layer.open({
                    type: 1,
                    offset: 'r',
                    anim: 'slideLeft',
                    area: [layerWidth, '100%'],
                    scrollbar: false,
                    shade: 0.1,
                    shadeClose: true,
                    btn: ["保存设置", "取消"],
                    btnAlign: 'r',
                    title: '<i class="layui-icon layui-icon-set"></i> NodeSeek X 设置',
                    id: 'nsx-settings-layer',
                    content: generateSettingsContent(),
                    success: function(layero, index) {
                        // 初始化表单
                        layui.form.render();

                        // 菜单导航事件处理
                        const menuLinks = layero[0].querySelectorAll('#nsx-settings-menu a');
                        menuLinks.forEach(function(link) {
                            link.addEventListener('click', function(e) {
                                e.preventDefault();
                                e.stopPropagation();
                                e.stopImmediatePropagation();
                                const targetId = this.getAttribute('data-target');
                                const target = layero[0].querySelector('#' + targetId);
                                if (target) {
                                    layero[0].querySelectorAll('#nsx-settings-menu li').forEach(li => li.classList.remove('layui-menu-item-checked'));
                                    this.closest('li').classList.add('layui-menu-item-checked');
                                    const contentArea = layero[0].querySelector('#nsx-settings-content');
                                    if (contentArea) {
                                        contentArea.scrollTo({
                                            top: target.offsetTop - 20,
                                            behavior: 'smooth'
                                        });
                                    }
                                }
                                return false;
                            });
                        });

                        // 滚动时高亮菜单
                        const docContent = layero[0].querySelector('#nsx-settings-content');
                        if (docContent) {
                            docContent.addEventListener('scroll', function() {
                                const scrollPos = docContent.scrollTop;
                                layero[0].querySelectorAll('#nsx-settings-content fieldset').forEach(function(el) {
                                    const topPos = el.offsetTop - 30;
      if (scrollPos >= topPos) {
                                        const id = el.getAttribute('id');
                                        layero[0].querySelectorAll('#nsx-settings-menu li').forEach(li => li.classList.remove('layui-menu-item-checked'));
                                        const navItem = layero[0].querySelector('#nsx-settings-menu a[data-target="' + id + '"]');
                                        if (navItem) {
                                            navItem.closest('li').classList.add('layui-menu-item-checked');
                                        }
                                    }
                                });
                            });
                        }

                        // 处理签到方式切换
                        layui.form.on('radio(sign_in_method)', function(data) {
                            const value = parseInt(data.value, 10);
                            if (value === 0) {
                                Config.updateConfig(`sign_in.${siteCode}.enabled`, false);
                                return;
                            }
                            Config.updateConfig(`sign_in.${siteCode}.enabled`, true);
                            if (value === 1) {
                                // 随机抽鸡腿
                                Config.updateConfig(`sign_in.${siteCode}.method`, 1);
                            } else if (value === 2) {
                                // 固定 5 个鸡腿
                                Config.updateConfig(`sign_in.${siteCode}.method`, 0);
                            }
                        });

                        // 处理所有开关
                        const switchNames = [
                            'signin_tips', 'auto_jump_external_links', 'loading_post',
                            'open_post_in_new_tab', 'quick_comment', 'block_members',
                            'block_posts', 'block_categories', 'remove_promotions', 'default_avatar', 'user_card_ext', 'level_tag', 'code_highlight',
                            'image_slide', 'visited_links', 'compact_mode', 'custom_background', 'header_opacity', 'frame_opacity',
                            'typography_title', 'typography_tag', 'typography_meta', 'typography_content',
                            'loading_overlay',
                            'merge_category_to_nav', 'hide_user_stats_panel', 'hide_footer',
                            'hide_post_category', 'hide_post_info', 'hide_topic_carousel', 'right_panel_highlight', 'show_all_users_stats'
                        ];

                        switchNames.forEach(name => {
                            layui.form.on('switch(' + name + ')', function(data) {
                                Config.updateConfig(`${name}.enabled`, data.elem.checked);
                                // 紧凑模式实时切换,无需刷新
                                if (name === 'compact_mode') {
                                    const optionsDiv = layero[0].querySelector('#compact_mode_options');
                                    const customDiv = layero[0].querySelector('#compact_mode_custom_options');
                                    if (optionsDiv) optionsDiv.style.display = data.elem.checked ? '' : 'none';
                                    if (customDiv) customDiv.style.display = data.elem.checked ? '' : 'none';
                                    _this.updateCompactModeStyle();
                                }
                                if (name === 'block_posts') {
                                    const keywordsBox = layero[0].querySelector('#block_post_keywords_box');
                                    if (keywordsBox) keywordsBox.style.display = data.elem.checked ? '' : 'none';
                                    if (data.elem.checked) {
                                        _this.refreshBlockKeywordRules();
                                        _this.blockPost();
                                    }
                                }
                                if (name === 'block_categories') {
                                    const categoriesBox = layero[0].querySelector('#block_categories_box');
                                    if (categoriesBox) categoriesBox.style.display = data.elem.checked ? '' : 'none';
                                    if (data.elem.checked) {
                                        _this.refreshBlockedCategories();
                                        _this.blockPostsByCategory();
                                    }
                                }
                                if (name === 'remove_promotions') {
                                    _this.togglePromotions();
                                }
                                if (name === 'default_avatar') {
                                    const box = layero[0].querySelector('#default_avatar_box');
                                    if (box) box.style.display = data.elem.checked ? '' : 'none';
                                    _this.replaceDefaultAvatars();
                                }
                                if (name === 'loading_overlay') {
                                    const box = layero[0].querySelector('#loading_overlay_box');
                                    if (box) box.style.display = data.elem.checked ? '' : 'none';
                                    if (!data.elem.checked) {
                                        removeInitialOverlay();
                                    }
                                }
                                if (name === 'header_opacity') {
                                    const box = layero[0].querySelector('#header_opacity_box');
                                    if (box) box.style.display = data.elem.checked ? '' : 'none';
                                    _this.updateHeaderOpacityStyle();
                                }
                                if (name === 'frame_opacity') {
                                    const box = layero[0].querySelector('#frame_opacity_box');
                                    if (box) box.style.display = data.elem.checked ? '' : 'none';
                                    _this.updateFrameOpacityStyle();
                                }
                                if (name === 'typography_title' || name === 'typography_tag' || name === 'typography_meta' || name === 'typography_content') {
                                    const type = name.split('_')[1];
                                    Config.updateConfig(`typography.${type}.enabled`, data.elem.checked);
                                    _this.updateTypography(type);
                                }
                                // 自定义背景图实时切换
                                if (name === 'custom_background') {
                                    const optionsDiv = layero[0].querySelector('#custom_background_options');
                                    if (data.elem.checked) {
                                        if (optionsDiv) optionsDiv.style.display = '';
                                        _this.updateCustomBackground();
                                    } else {
                                        if (optionsDiv) optionsDiv.style.display = 'none';
                                        _this.updateCustomBackground();
                                    }
                                }
                                if (name === 'visited_links') {
                                    _this.updateVisitedLinkStyle();
                                }
                                if (name === 'show_all_users_stats') {
                                    const positionBox = document.getElementById('show_all_users_stats_position_box');
                                    if (positionBox) {
                                        positionBox.style.display = data.elem.checked ? '' : 'none';
                                    }
                                    if (data.elem.checked) {
                                        _this.showAllUsersStats();
                                    } else {
                                        _this.hideAllUsersStats();
                                    }
                                }
                                // 合并分类到导航栏实时切换
                                if (name === 'merge_category_to_nav') {
                                    _this.mergeCategoryToNav();
                                }
                                // 隐藏用户统计面板实时切换
                                if (name === 'hide_user_stats_panel') {
                                    _this.toggleUserStatsPanel();
                                }
                                // 隐藏页脚实时切换
                                if (name === 'hide_footer') {
                                    _this.toggleFooter();
                                }
                                // 隐藏分类标签实时切换
                                if (name === 'hide_post_category') {
                                    _this.togglePostCategory();
                                }
                                // 隐藏帖子信息实时切换
                                if (name === 'hide_post_info') {
                                    _this.togglePostInfo();
                                }
                                // 隐藏推荐轮播实时切换
                                if (name === 'hide_topic_carousel') {
                                    _this.toggleTopicCarousel();
                                }
                                // 右侧面板关键词高亮实时切换
                                if (name === 'right_panel_highlight') {
                                    if (data.elem.checked) {
                                        // 显示右侧面板输入框
                                        _this.addRightPanelHighlightInput();
                                        _this.applyRightPanelHighlight();
                                        _this.startRightPanelHighlightObserver();
                                    } else {
                                        // 隐藏右侧面板输入框并移除高亮
                                        const inputPanel = document.querySelector('.nsx-highlight-input-panel');
                                        if (inputPanel) {
                                            inputPanel.remove();
                                        }
                                        _this.applyRightPanelHighlight(); // 移除高亮
                                        if (_this.rightPanelHighlightObserver) {
                                            _this.rightPanelHighlightObserver.disconnect();
                                            _this.rightPanelHighlightObserver = null;
                                        }
                                    }
                                }
                            });
                        });

                        const blockKeywordTextarea = layero[0].querySelector('textarea[name="block_post_keywords"]');
                        if (blockKeywordTextarea) {
                            let keywordTimer = null;
                            const persistKeywords = () => {
                                const parsed = _this.parseBlockKeywordInput(blockKeywordTextarea.value);
                                Config.updateConfig('block_posts.keywords', parsed);
                                _this.refreshBlockKeywordRules();
                                _this.blockPost();
                            };
                            const schedulePersist = () => {
                                clearTimeout(keywordTimer);
                                keywordTimer = setTimeout(persistKeywords, 400);
                            };
                            blockKeywordTextarea.addEventListener('input', schedulePersist);
                            blockKeywordTextarea.addEventListener('blur', schedulePersist);
                        }

                        const blockCategoriesTextarea = layero[0].querySelector('textarea[name="block_categories_list"]');
                        if (blockCategoriesTextarea) {
                            let categoryTimer = null;
                            const persistCategories = () => {
                                const parsed = _this.parseBlockedCategoryInput(blockCategoriesTextarea.value);
                                Config.updateConfig('block_categories.categories', parsed);
                                _this.refreshBlockedCategories();
                                _this.blockPostsByCategory();
                            };
                            const scheduleCategoriesPersist = () => {
                                clearTimeout(categoryTimer);
                                categoryTimer = setTimeout(persistCategories, 400);
                            };
                            blockCategoriesTextarea.addEventListener('input', scheduleCategoriesPersist);
                            blockCategoriesTextarea.addEventListener('blur', scheduleCategoriesPersist);
                        }

                        const headerOpacityRange = layero[0].querySelector('input[name="header_opacity_value"]');
                        if (headerOpacityRange) {
                            headerOpacityRange.addEventListener('input', function() {
                                const parsed = parseFloat(this.value);
                                const value = Number.isNaN(parsed) ? 0.92 : parsed;
                                const display = layero[0].querySelector('#header_opacity_value_display');
                                if (display) display.textContent = value.toFixed(2);
                                Config.updateConfig('header_opacity.value', value);
                                _this.updateHeaderOpacityStyle();
                            });
                        }

                        layui.form.on('checkbox(header_opacity_blur_toggle)', function(data) {
                            Config.updateConfig('header_opacity.blur_enabled', data.elem.checked);
                            _this.updateHeaderOpacityStyle();
                        });

                        const headerBlurInput = layero[0].querySelector('input[name="header_opacity_blur"]');
                        if (headerBlurInput) {
                            const handler = () => {
                                Config.updateConfig('header_opacity.blur', headerBlurInput.value);
                                _this.updateHeaderOpacityStyle();
                            };
                            headerBlurInput.addEventListener('input', handler);
                            headerBlurInput.addEventListener('blur', handler);
                        }

                        const headerSaturateInput = layero[0].querySelector('input[name="header_opacity_saturate"]');
                        if (headerSaturateInput) {
                            const handler = () => {
                                Config.updateConfig('header_opacity.saturate', headerSaturateInput.value);
                                _this.updateHeaderOpacityStyle();
                            };
                            headerSaturateInput.addEventListener('input', handler);
                            headerSaturateInput.addEventListener('blur', handler);
                        }

                        const frameOpacityRange = layero[0].querySelector('input[name="frame_opacity_value"]');
                        if (frameOpacityRange) {
                            frameOpacityRange.addEventListener('input', function() {
                                const parsed = parseFloat(this.value);
                                const value = Number.isNaN(parsed) ? 0.95 : parsed;
                                const display = layero[0].querySelector('#frame_opacity_value_display');
                                if (display) display.textContent = value.toFixed(2);
                                Config.updateConfig('frame_opacity.value', value);
                                _this.updateFrameOpacityStyle();
                            });
                        }

                        layui.form.on('checkbox(frame_opacity_blur_toggle)', function(data) {
                            Config.updateConfig('frame_opacity.blur_enabled', data.elem.checked);
                            _this.updateFrameOpacityStyle();
                        });

                        layui.form.on('checkbox(header_opacity_saturate_toggle)', function(data) {
                            Config.updateConfig('header_opacity.saturate_enabled', data.elem.checked);
                            _this.updateHeaderOpacityStyle();
                        });

                        layui.form.on('checkbox(frame_opacity_saturate_toggle)', function(data) {
                            Config.updateConfig('frame_opacity.saturate_enabled', data.elem.checked);
                            _this.updateFrameOpacityStyle();
                        });

                        const frameBlurInput = layero[0].querySelector('input[name="frame_opacity_blur"]');
                        if (frameBlurInput) {
                            const handler = () => {
                                Config.updateConfig('frame_opacity.blur', frameBlurInput.value);
                                _this.updateFrameOpacityStyle();
                            };
                            frameBlurInput.addEventListener('input', handler);
                            frameBlurInput.addEventListener('blur', handler);
                        }

                        const frameSaturateInput = layero[0].querySelector('input[name="frame_opacity_saturate"]');
                        if (frameSaturateInput) {
                            const handler = () => {
                                Config.updateConfig('frame_opacity.saturate', frameSaturateInput.value);
                                _this.updateFrameOpacityStyle();
                            };
                            frameSaturateInput.addEventListener('input', handler);
                            frameSaturateInput.addEventListener('blur', handler);
                        }

                        const loadingOverlayRange = layero[0].querySelector('input[name="loading_overlay_duration"]');
                        if (loadingOverlayRange) {
                            const handler = () => {
                                const value = parseInt(loadingOverlayRange.value, 10) || INITIAL_OVERLAY_DURATION_DEFAULT;
                                const display = layero[0].querySelector('#loading_overlay_duration_display');
                                if (display) display.textContent = `${value}ms`;
                                Config.updateConfig('loading_overlay.duration', value);
                            };
                            loadingOverlayRange.addEventListener('input', handler);
                            loadingOverlayRange.addEventListener('blur', handler);
                        }

                        const defaultAvatarUrlInput = layero[0].querySelector('input[name="default_avatar_url"]');
                        if (defaultAvatarUrlInput) {
                            const handler = () => {
                                Config.updateConfig('default_avatar.url', defaultAvatarUrlInput.value.trim());
                                _this.replaceDefaultAvatars();
                            };
                            defaultAvatarUrlInput.addEventListener('input', handler);
                            defaultAvatarUrlInput.addEventListener('blur', handler);
                        }
                        layui.form.on('checkbox(default_avatar_auto)', function(data) {
                            Config.updateConfig('default_avatar.auto_detect', data.elem.checked);
                            _this.replaceDefaultAvatars();
                        });

                        const exportBtn = layero[0].querySelector('#nsx-export-settings');
                        if (exportBtn) {
                            exportBtn.addEventListener('click', () => {
                                const settings = util.getValue('settings') || {};
                                const json = JSON.stringify(settings, null, 2);
                                navigator.clipboard.writeText(json).then(() => {
                                    message.success('设置已复制到剪贴板');
                                }).catch(err => {
                                    // console.error(err);
                                    message.error('复制失败,请手动复制文本域内容');
                                });
                            });
                        }

                        const importBtn = layero[0].querySelector('#nsx-import-apply');
                        const importTextarea = layero[0].querySelector('#nsx-import-settings');
                        if (importBtn && importTextarea) {
                            importBtn.addEventListener('click', () => {
                                const text = importTextarea.value.trim();
                                if (!text) {
                                    message.warning('请先粘贴配置 JSON');
                                    return;
                                }
                                try {
                                    const parsed = JSON.parse(text);
                                    // 合并默认配置,确保所有配置项都存在
                                    const defaultConfig = opts.settings;
                                    const mergeDefaults = (stored, defaults) => {
                                        Object.keys(defaults).forEach(key => {
                                            if (typeof defaults[key] === 'object' && defaults[key] !== null && !(defaults[key] instanceof Array)) {
                                                if (!stored[key]) stored[key] = {};
                                                mergeDefaults(stored[key], defaults[key]);
                                            } else {
                                                if (stored[key] === undefined) {
                                                    stored[key] = defaults[key];
                                                }
                                            }
                                        });
                                    };
                                    mergeDefaults(parsed, defaultConfig);
                                    // 保留version字段
                                    const currentSettings = util.getValue('settings') || {};
                                    parsed.version = currentSettings.version || version;
                                    util.setValue('settings', parsed);
                                    message.success('配置导入成功,正在刷新...');
                                    setTimeout(() => location.reload(), 800);
                                } catch (err) {
                                    // console.error(err);
                                    message.error('导入失败:JSON 格式不正确');
                                }
                            });
                        }

                        // 一键设置默认样式
                        const resetToDefaultBtn = layero[0].querySelector('#nsx-reset-to-default');
                        if (resetToDefaultBtn) {
                            resetToDefaultBtn.addEventListener('click', () => {
                                const defaultConfig = {
                                    "sign_in": {
                                        "ns": {
                                            "enabled": true,
                                            "method": 0,
                                            "last_date": "",
                                            "ignore_date": ""
                                        },
                                        "df": {
                                            "enabled": true,
                                            "method": 0,
                                            "last_date": "",
                                            "ignore_date": ""
                                        }
                                    },
                                    "signin_tips": {
                                        "enabled": true
                                    },
                                    "re_signin": {
                                        "enabled": true
                                    },
                                    "auto_jump_external_links": {
                                        "enabled": true
                                    },
                                    "loading_post": {
                                        "enabled": false
                                    },
                                    "loading_comment": {
                                        "enabled": false
                                    },
                                    "quick_comment": {
                                        "enabled": true
                                    },
                                    "open_post_in_new_tab": {
                                        "enabled": false
                                    },
                                    "block_members": {
                                        "enabled": true
                                    },
                                    "block_posts": {
                                        "enabled": true,
                                        "keywords": []
                                    },
                                    "block_categories": {
                                        "enabled": false,
                                        "categories": []
                                    },
                                    "level_tag": {
                                        "enabled": true,
                                        "low_lv_alarm": false,
                                        "low_lv_max_days": 30
                                    },
                                    "code_highlight": {
                                        "enabled": true
                                    },
                                    "image_slide": {
                                        "enabled": true
                                    },
                                    "visited_links": {
                                        "enabled": true,
                                        "link_color": "",
                                        "visited_color": "",
                                        "dark_link_color": "",
                                        "dark_visited_color": "",
                                        "hide_visited": false
                                    },
                                    "user_card_ext": {
                                        "enabled": true
                                    },
                                    "compact_mode": {
                                        "enabled": true,
                                        "columns": 4,
                                        "padding": "6px 10px",
                                        "avatarSize": 26,
                                        "titleFontSize": 13,
                                        "infoFontSize": 10,
                                        "marginBottom": 2
                                    },
                                    "custom_background": {
                                        "enabled": false,
                                        "url": "",
                                        "repeat": "repeat",
                                        "position": "center",
                                        "size": "cover",
                                        "attachment": "scroll"
                                    },
                                    "merge_category_to_nav": {
                                        "enabled": true
                                    },
                                    "remove_promotions": {
                                        "enabled": true
                                    },
                                    "header_opacity": {
                                        "enabled": true,
                                        "value": 0.18,
                                        "effect": true,
                                        "blur": 16,
                                        "saturate": 180,
                                        "blur_enabled": false,
                                        "saturate_enabled": false
                                    },
                                    "frame_opacity": {
                                        "enabled": false,
                                        "value": 1,
                                        "blur_enabled": false,
                                        "saturate_enabled": false,
                                        "blur": 12,
                                        "saturate": 180
                                    },
                                    "default_avatar": {
                                        "enabled": true,
                                        "url": "/avatar/14049.png",
                                        "auto_detect": true
                                    },
                                    "loading_overlay": {
                                        "enabled": false,
                                        "duration": 300
                                    },
                                    "typography": {
                                        "title": {
                                            "enabled": false,
                                            "fontFamily": "",
                                            "fontSize": "",
                                            "color": "",
                                            "fontStyle": "",
                                            "letterSpacing": "",
                                            "ligatures": ""
                                        },
                                        "tag": {
                                            "enabled": false,
                                            "fontFamily": "",
                                            "fontSize": "",
                                            "color": "",
                                            "fontStyle": "",
                                            "letterSpacing": "",
                                            "ligatures": ""
                                        },
                                        "meta": {
                                            "enabled": false,
                                            "fontFamily": "",
                                            "fontSize": "",
                                            "color": "",
                                            "fontStyle": "",
                                            "letterSpacing": "",
                                            "ligatures": ""
                                        },
                                        "content": {
                                            "enabled": false,
                                            "fontFamily": "",
                                            "fontSize": "",
                                            "color": "",
                                            "fontStyle": "",
                                            "letterSpacing": "",
                                            "ligatures": ""
                                        }
                                    },
                                    "hide_user_stats_panel": {
                                        "enabled": true
                                    },
                                    "hide_footer": {
                                        "enabled": true
                                    },
                                    "hide_post_category": {
                                        "enabled": true
                                    },
                                    "hide_post_info": {
                                        "enabled": false
                                    },
                                    "hide_topic_carousel": {
                                        "enabled": true
                                    },
                                    "post_sort": {
                                        "enabled": false,
                                        "mode": "none",
                                        "visited_to_bottom": true
                                    },
                                    "show_all_users_stats": {
                                        "enabled": false,
                                        "position": "below"
                                    },
                                    "right_panel_highlight": {
                                        "enabled": false,
                                        "keywords": []
                                    }
                                };

                                // 保留当前的version
                                const currentSettings = util.getValue('settings') || {};
                                defaultConfig.version = currentSettings.version || version;

                                // 确认对话框
                                unsafeWindow.mscConfirm('确定要恢复默认样式吗?', '这将覆盖您当前的所有设置(除了版本号),是否继续?', function() {
                                    util.setValue('settings', defaultConfig);
                                    message.success('默认样式已应用,正在刷新页面...');
                                    setTimeout(() => location.reload(), 800);
                                });
                            });
                        }

                        const typographyFields = ['fontFamily','fontSize','color','fontStyle','letterSpacing','ligatures'];
                        const typographyTypes = ['title','tag','meta','content'];
                        typographyTypes.forEach(type => {
                            typographyFields.forEach(field => {
                                const input = layero[0].querySelector(`input[name="typography_${type}_${field}"]`);
                                if (input) {
                                    const handler = () => {
                                        Config.updateConfig(`typography.${type}.${field}`, input.value);
                                        _this.updateTypography(type);
                                    };
                                    input.addEventListener('input', handler);
                                    input.addEventListener('blur', handler);
                                }
                            });
                        });

                        // 紧凑模式列数切换
                        layui.form.on('radio(compact_columns)', function(data) {
                            const columns = parseInt(data.value);
                            Config.updateConfig('compact_mode.columns', columns);
                            _this.updateCompactModeStyle();
                            // 如果列数 >= 2,自动启用合并分类到导航栏
                            if (columns >= 2) {
                                Config.updateConfig('merge_category_to_nav.enabled', true);
                                // 更新开关状态
                                const switchElem = layero[0].querySelector('input[name="merge_category_to_nav"]');
                                if (switchElem && !switchElem.checked) {
                                    switchElem.checked = true;
                                    layui.form.render('checkbox');
                                }
                                _this.mergeCategoryToNav();
                            }
                        });

                        // 帖子排序模式切换
                        layui.form.on('radio(post_sort_mode)', function(data) {
                            const mode = data.value;
                            Config.updateConfig('post_sort.mode', mode);
                            Config.updateConfig('post_sort.enabled', mode !== 'none');
                            _this.sortPostList();
                        });

                        // 用户统计信息位置切换
                        layui.form.on('radio(show_all_users_stats_position)', function(data) {
                            const position = data.value;
                            Config.updateConfig('show_all_users_stats.position', position);
                            // 如果功能已启用,重新渲染所有统计信息
                            if (Config.getConfig('show_all_users_stats.enabled') === true) {
                                _this.hideAllUsersStats();
                                setTimeout(() => {
                                    _this.showAllUsersStats();
                                }, 100);
                            }
                        });

                        // 已访问帖子置底切换
                        layui.form.on('checkbox(visited_to_bottom)', function(data) {
                            Config.updateConfig('post_sort.visited_to_bottom', data.elem.checked);
                            _this.sortPostList();
                        });

                        // 紧凑模式自定义数值变化
                        const compactInputs = ['compact_padding', 'compact_avatarSize', 'compact_titleFontSize', 'compact_infoFontSize', 'compact_marginBottom'];
                        compactInputs.forEach(inputName => {
                            const input = layero[0].querySelector(`input[name="${inputName}"]`);
                            if (input) {
                                input.addEventListener('input', function() {
                                    let value = this.value;
                                    if (inputName === 'compact_padding') {
                                        Config.updateConfig('compact_mode.padding', value);
                                    } else if (inputName === 'compact_avatarSize') {
                                        Config.updateConfig('compact_mode.avatarSize', parseInt(value));
                                    } else if (inputName === 'compact_titleFontSize') {
                                        Config.updateConfig('compact_mode.titleFontSize', parseInt(value));
                                    } else if (inputName === 'compact_infoFontSize') {
                                        Config.updateConfig('compact_mode.infoFontSize', parseInt(value));
                                    } else if (inputName === 'compact_marginBottom') {
                                        Config.updateConfig('compact_mode.marginBottom', parseInt(value));
                                    }
                                    _this.updateCompactModeStyle();
                                });
                            }
                        });

                        // 自定义背景图文件上传
                        const uploadBtn = layero[0].querySelector('#custom_bg_upload_btn');
                        const fileInput = layero[0].querySelector('#custom_bg_upload');
                        const clearBtn = layero[0].querySelector('#custom_bg_clear_btn');
                        const previewDiv = layero[0].querySelector('#custom_bg_preview');
                        const previewImg = layero[0].querySelector('#custom_bg_preview_img');
                        const urlInput = layero[0].querySelector('input[name="custom_bg_url"]');

                        if (uploadBtn && fileInput) {
                            uploadBtn.addEventListener('click', () => {
                                fileInput.click();
                            });

                            fileInput.addEventListener('change', function(e) {
                                const file = e.target.files[0];
                                if (!file) return;

                                // 检查文件类型
                                if (!file.type.startsWith('image/')) {
                                    message.warning('请选择图片文件');
                                    return;
                                }

                                // 提示:大图片可能会因为GM存储限制而保存失败
                                if (file.size > 5 * 1024 * 1024) {
                                    const proceed = confirm(`图片较大(${(file.size / 1024 / 1024).toFixed(2)}MB),转换为base64后可能超过GM存储限制(通常5-10MB),是否继续?\n\n建议:使用小于3MB的图片以获得最佳体验。`);
                                    if (!proceed) {
                                        fileInput.value = '';
                                        return;
                                    }
                                }

                                const reader = new FileReader();
                                reader.onload = function(e) {
                                    const base64 = e.target.result;

                                    // 尝试保存,如果失败会抛出错误
                                    try {
                                        Config.updateConfig('custom_background.url', base64);
                                    } catch (err) {
                                        message.error('图片数据过大,无法保存。请使用较小的图片(建议小于3MB)。');
                                        fileInput.value = '';
                                        return;
                                    }

                                    // 更新预览
                                    if (previewImg) {
                                        previewImg.src = base64;
                                    }
                                    if (previewDiv) {
                                        previewDiv.style.display = 'block';
                                    }
                                    if (clearBtn) {
                                        clearBtn.style.display = 'inline-block';
                                    }
                                    if (urlInput) {
                                        urlInput.value = '';
                                    }

                                    // 立即应用
                                    if (Config.getConfig('custom_background.enabled')) {
                                        _this.updateCustomBackground();
                                    }

                                    message.success('图片上传成功');
                                };
                                reader.onerror = function() {
                                    message.error('图片读取失败');
                                };
                                reader.readAsDataURL(file);
                            });
                        }

                        // 清除图片
                        if (clearBtn) {
                            clearBtn.addEventListener('click', function() {
                                Config.updateConfig('custom_background.url', '');
                                if (previewDiv) {
                                    previewDiv.style.display = 'none';
                                }
                                if (previewImg) {
                                    previewImg.src = '';
                                }
                                if (fileInput) {
                                    fileInput.value = '';
                                }
                                if (urlInput) {
                                    urlInput.value = '';
                                }
                                this.style.display = 'none';

                                if (Config.getConfig('custom_background.enabled')) {
                                    _this.updateCustomBackground();
                                }

                                message.success('图片已清除');
                            });
                        }

                        // 自定义背景图设置变化
                        const bgInputs = ['custom_bg_url', 'custom_bg_position', 'custom_bg_size'];
                        bgInputs.forEach(inputName => {
                            const input = layero[0].querySelector(`input[name="${inputName}"]`);
                            if (input) {
                                input.addEventListener('input', function() {
                                    let value = this.value;
                                    if (inputName === 'custom_bg_url') {
                                        // 如果输入了URL,清除base64预览
                                        if (value && !value.startsWith('data:')) {
                                            Config.updateConfig('custom_background.url', value);
                                            if (previewDiv) {
                                                previewDiv.style.display = 'none';
                                            }
                                            if (clearBtn) {
                                                clearBtn.style.display = 'inline-block';
                                            }
                                        }
                                    } else if (inputName === 'custom_bg_position') {
                                        Config.updateConfig('custom_background.position', value);
                                    } else if (inputName === 'custom_bg_size') {
                                        Config.updateConfig('custom_background.size', value);
                                    }
                                    if (Config.getConfig('custom_background.enabled')) {
                                        _this.updateCustomBackground();
                                    }
                                });
                            }
                        });

                        // 自定义背景图下拉框变化
                        const bgSelects = ['custom_bg_repeat', 'custom_bg_attachment'];
                        bgSelects.forEach(selectName => {
                            const select = layero[0].querySelector(`select[name="${selectName}"]`);
                            if (select) {
                                select.addEventListener('change', function() {
                                    let value = this.value;
                                    if (selectName === 'custom_bg_repeat') {
                                        Config.updateConfig('custom_background.repeat', value);
                                    } else if (selectName === 'custom_bg_attachment') {
                                        Config.updateConfig('custom_background.attachment', value);
                                    }
                                    if (Config.getConfig('custom_background.enabled')) {
                                        _this.updateCustomBackground();
                                    }
                                });
                            }
                        });
                    },
                    yes: function(index, layero) {
                        // 同步下拉加载设置
                        const loadingPost = layero.find('input[name="loading_post"]').prop('checked');
                        Config.updateConfig('loading_post.enabled', loadingPost);
                        Config.updateConfig('loading_comment.enabled', loadingPost);

                        // 保存紧凑模式设置
                        const compactColumns = layero.find('input[name="compact_columns"]:checked').val();
                        if (compactColumns) {
                            Config.updateConfig('compact_mode.columns', parseInt(compactColumns));
                        }
                        const compactPadding = layero.find('input[name="compact_padding"]').val();
                        if (compactPadding) {
                            Config.updateConfig('compact_mode.padding', compactPadding);
                        }
                        const compactAvatarSize = layero.find('input[name="compact_avatarSize"]').val();
                        if (compactAvatarSize) {
                            Config.updateConfig('compact_mode.avatarSize', parseInt(compactAvatarSize));
                        }
                        const compactTitleFontSize = layero.find('input[name="compact_titleFontSize"]').val();
                        if (compactTitleFontSize) {
                            Config.updateConfig('compact_mode.titleFontSize', parseInt(compactTitleFontSize));
                        }
                        const compactInfoFontSize = layero.find('input[name="compact_infoFontSize"]').val();
                        if (compactInfoFontSize) {
                            Config.updateConfig('compact_mode.infoFontSize', parseInt(compactInfoFontSize));
                        }
                        const compactMarginBottom = layero.find('input[name="compact_marginBottom"]').val();
                        if (compactMarginBottom) {
                            Config.updateConfig('compact_mode.marginBottom', parseInt(compactMarginBottom));
                        }

                        // 保存自定义背景图设置
                        const customBgUrl = layero.find('input[name="custom_bg_url"]').val();
                        // 如果URL输入框有值,使用输入框的值;否则保留已保存的base64数据
                        if (customBgUrl && customBgUrl.trim() !== '') {
                            Config.updateConfig('custom_background.url', customBgUrl.trim());
                        } else {
                            // 如果URL输入框为空,检查是否已有base64数据,如果有则保留
                            const currentUrl = Config.getConfig('custom_background.url');
                            if (currentUrl && currentUrl.startsWith('data:')) {
                                // 保留已上传的base64数据,不做任何操作
                            } else if (customBgUrl === '') {
                                // 如果用户清空了URL输入框,且没有base64数据,则清空配置
                                Config.updateConfig('custom_background.url', '');
                            }
                        }
                        const customBgRepeat = layero.find('select[name="custom_bg_repeat"]').val();
                        if (customBgRepeat) {
                            Config.updateConfig('custom_background.repeat', customBgRepeat);
                        }
                        const customBgPosition = layero.find('input[name="custom_bg_position"]').val();
                        if (customBgPosition !== undefined) {
                            Config.updateConfig('custom_background.position', customBgPosition);
                        }
                        const customBgSize = layero.find('input[name="custom_bg_size"]').val();
                        if (customBgSize !== undefined) {
                            Config.updateConfig('custom_background.size', customBgSize);
                        }
                        const customBgAttachment = layero.find('select[name="custom_bg_attachment"]').val();
                        if (customBgAttachment) {
                            Config.updateConfig('custom_background.attachment', customBgAttachment);
                        }

                        // 更新紧凑模式样式
                        main.updateCompactModeStyle();

                        // 更新自定义背景图
                        main.updateCustomBackground();

                        // 同步新标签页设置到 IndexedDB
                        const openInNewTab = layero.find('input[name="open_post_in_new_tab"]').prop('checked');
                        if (openInNewTab !== Config.getConfig('open_post_in_new_tab.enabled')) {
                            _this.switchOpenPostInNewTab('open_post_in_new_tab', []);
                        }

                        // 保存用户统计信息位置设置
                        const statsPosition = layero.find('input[name="show_all_users_stats_position"]:checked').val();
                        if (statsPosition) {
                            Config.updateConfig('show_all_users_stats.position', statsPosition);
                        }

                        message.success('设置已保存');
                        layer.close(index);
                    }
                });
            },
            addCodeHighlight() {
                const codes = document.querySelectorAll(".post-content pre code");
                if (codes) {
                    codes.forEach(function (code) {
                        const copyBtn = util.createElement("span", { staticClass: "copy-code", attrs: { title: "复制代码" }, on: { click: copyCode } }, [util.createElement("svg", { staticClass: 'iconpark-icon' }, [util.createElement("use", { attrs: { href: "#copy" } }, [], document, "http://www.w3.org/2000/svg")], document, "http://www.w3.org/2000/svg")]);
                        code.after(copyBtn);
                    });
                }
                function copyCode(e) {
                    const pre = this.closest('pre');
                    const selection = window.getSelection();
                    const range = document.createRange();
                    range.selectNodeContents(pre.querySelector("code"));
                    selection.removeAllRanges();
                    selection.addRange(range);
                    document.execCommand('copy');
                    selection.removeAllRanges();
                    updateCopyButton(this);
                    layer.tips(`复制成功`, this, { tips: 4, time: 1000 })
                }
                function updateCopyButton(ele) {
                    ele.querySelector("use").setAttribute("href", "#check");
                    util.sleep(1000).then(() => ele.querySelector("use").setAttribute("href", "#copy"));
                }
            },

            updateCompactModeStyle() {
                const enabled = Config.getConfig('compact_mode.enabled');
                if (enabled === false) {
                toggleRootClass('nsx-compact-mode', false);
                applyCompactModeStyleFromConfig(null);
                removeCompactPendingClass();
                removeInitialOverlay();
                // 禁用紧凑模式时,也需要更新分类合并
                this.mergeCategoryToNav();
                return;
            }
            const config = normalizeCompactConfig({
                columns: Config.getConfig('compact_mode.columns'),
                padding: Config.getConfig('compact_mode.padding'),
                avatarSize: Config.getConfig('compact_mode.avatarSize'),
                titleFontSize: Config.getConfig('compact_mode.titleFontSize'),
                infoFontSize: Config.getConfig('compact_mode.infoFontSize'),
                marginBottom: Config.getConfig('compact_mode.marginBottom')
            });
            // 先添加类名,再调用 mergeCategoryToNav,确保能正确判断状态
            toggleRootClass('nsx-compact-mode', true);
            if (config.columns >= 2 && !Config.getConfig('merge_category_to_nav.enabled')) {
                Config.updateConfig('merge_category_to_nav.enabled', true);
            }
            // 更新分类合并(需要知道当前的紧凑模式状态)
            this.mergeCategoryToNav();
            applyCompactModeStyleFromConfig(config);
            const overlaySettings = getRuntimeOverlaySettings();
            scheduleRemoveInitialOverlay(overlaySettings.duration, overlaySettings.enabled);
            },

            updateCustomBackground() {
                const config = Config.getConfig('custom_background');
                if (!config || config.enabled === false || !config.url) {
                    applyCustomBackgroundStyle(null);
                    return;
                }
                applyCustomBackgroundStyle({
                    url: config.url,
                    repeat: config.repeat || 'repeat',
                    position: config.position || 'center',
                    size: config.size || 'cover',
                    attachment: config.attachment || 'scroll'
                });
            },
            updateVisitedLinkStyle() {
                const cfg = Config.getConfig('visited_links');
                if (!cfg || cfg.enabled === false) {
                    applyVisitedLinkStyle(null);
                    toggleRootClass('nsx-hide-visited', false);
                    return;
                }
                const normalized = {
                    lightLink: (cfg.link_color || '').trim(),
                    lightVisited: (cfg.visited_color || '').trim() || '#afb9c1',
                    darkLink: (cfg.dark_link_color || '').trim(),
                    darkVisited: (cfg.dark_visited_color || '').trim() || cfg.visited_color || '#393f4e'
                };
                applyVisitedLinkStyle(normalized);
                toggleRootClass('nsx-hide-visited', cfg.hide_visited === true);
            },
            updateTypography(type) {
                const cfg = Config.getConfig(`typography.${type}`);
                applyTypographyStyle(type, cfg);
            },
            updateAllTypography() {
                ['title', 'tag', 'meta', 'content'].forEach(type => this.updateTypography(type));
            },
            toggleUserStatsPanel() {
                const enabled = Config.getConfig('hide_user_stats_panel.enabled');
                const rightPanel = document.querySelector('#nsk-right-panel-container');

                if (!rightPanel) return;

                // 查找包含"用户数目"或"欢迎新用户"的面板
                const panels = rightPanel.querySelectorAll('.nsk-panel');
                panels.forEach(panel => {
                    const h4 = panel.querySelector('h4');
                    if (h4) {
                        const text = h4.textContent || '';
                        // 检查是否包含"用户数目"或"欢迎新用户"
                        if (text.includes('用户数目') || text.includes('欢迎新用户') || text.includes('📈') || text.includes('🎉')) {
                            panel.style.display = enabled ? 'none' : '';
                        }
                    }
                });
            },
            // 在右侧面板添加关键词高亮输入框
            addRightPanelHighlightInput() {
                const enabled = Config.getConfig('right_panel_highlight.enabled');
                if (enabled !== true) {
                    // 如果开关关闭,移除输入框
                    const existingPanel = document.querySelector('.nsx-highlight-input-panel');
                    if (existingPanel) {
                        existingPanel.remove();
                    }
                    return;
                }

                const rightPanel = document.querySelector('#nsk-right-panel-container');
                if (!rightPanel) return;

                // 检查是否已存在
                if (rightPanel.querySelector('.nsx-highlight-input-panel')) return;

                // 创建面板
                const panel = document.createElement('div');
                panel.className = 'nsk-panel nsx-highlight-input-panel';
                panel.innerHTML = `
                    <h4 aria-level="2">
                        <span style="font-weight: bold;">🔍 关键词高亮</span>
                    </h4>
                    <div style="margin-top: 8px;">
                        <textarea 
                            id="nsx-right-panel-keywords-input" 
                            class="layui-textarea" 
                            style="min-height: 60px; font-size: 12px; resize: vertical;"
                            placeholder="一行一个关键词,支持正则表达式(使用 /正则/flags 格式)&#10;例如:VPS、服务器、/\\d+GB/i"
                        ></textarea>
                        <div id="nsx-highlight-help-text" style="margin-top: 5px; font-size: 11px; color: #888; display: block;">
                            <div style="margin-bottom: 4px;"><strong>使用说明:</strong></div>
                            <div style="margin-left: 8px; line-height: 1.6;">
                                • 每行输入一个关键词,使用<strong>换行符</strong>分隔<br>
                                • 支持普通文本匹配(不区分大小写)<br>
                                • 支持正则表达式:使用 <code>/正则/flags</code> 格式<br>
                                • 示例:<code>VPS</code>、<code>服务器</code>、<code>/\\d+GB/i</code>
                            </div>
                        </div>
                        <div id="nsx-highlight-status-text" style="margin-top: 5px; font-size: 11px; color: #888; display: none;">
                            输入关键词后会自动保存并高亮显示(需在设置中启用)
                        </div>
                    </div>
                `;

                // 插入到右侧面板顶部
                const firstPanel = rightPanel.querySelector('.nsk-panel');
                if (firstPanel) {
                    rightPanel.insertBefore(panel, firstPanel);
                } else {
                    rightPanel.appendChild(panel);
                }

                // 获取元素
                const textarea = panel.querySelector('#nsx-right-panel-keywords-input');
                const helpText = panel.querySelector('#nsx-highlight-help-text');
                const statusText = panel.querySelector('#nsx-highlight-status-text');

                // 加载当前配置
                const currentKeywords = this.getRightPanelHighlightKeywords();
                if (textarea) textarea.value = currentKeywords;
                
                // 根据输入框内容显示/隐藏帮助文本
                const updateHelpVisibility = () => {
                    if (!textarea || !helpText || !statusText) return;
                    const hasContent = textarea.value.trim().length > 0;
                    helpText.style.display = hasContent ? 'none' : 'block';
                    statusText.style.display = hasContent ? 'block' : 'none';
                };
                
                // 初始状态
                updateHelpVisibility();

                // 输入框事件处理
                if (textarea) {
                    let timer = null;
                    const saveKeywords = () => {
                        const value = textarea.value.trim();
                        updateHelpVisibility(); // 更新帮助文本显示状态
                        const parsed = this.parseRightPanelHighlightKeywords(value);
                        // console.log('[NodeSeek X] 解析的关键词:', parsed);
                        Config.updateConfig('right_panel_highlight.keywords', parsed);
                        this.refreshRightPanelHighlightRules();
                        // console.log('[NodeSeek X] 刷新后的规则:', this.rightPanelHighlightRules);
                        // 如果功能已启用,立即应用高亮
                        if (Config.getConfig('right_panel_highlight.enabled') === true) {
                            // console.log('[NodeSeek X] 关键词已保存,规则数量:', this.rightPanelHighlightRules.length);
                            this.applyRightPanelHighlight();
                        }
                    };
                    textarea.addEventListener('input', () => {
                        updateHelpVisibility(); // 实时更新帮助文本显示状态
                        clearTimeout(timer);
                        timer = setTimeout(saveKeywords, 500);
                    });
                    textarea.addEventListener('blur', saveKeywords);
                }
            },
            toggleFooter() {
                const enabled = Config.getConfig('hide_footer.enabled');
                toggleRootClass('nsx-hide-footer', enabled === true);
            },
            togglePostCategory() {
                const enabled = Config.getConfig('hide_post_category.enabled');
                toggleRootClass('nsx-hide-post-category', enabled === true);
            },
            togglePostInfo() {
                const enabled = Config.getConfig('hide_post_info.enabled');
                toggleRootClass('nsx-hide-post-info', enabled === true);
            },
            toggleTopicCarousel() {
                const enabled = Config.getConfig('hide_topic_carousel.enabled');
                toggleRootClass('nsx-hide-topic-carousel', enabled === true);
            },
            // 获取右侧面板高亮关键词输入值
            getRightPanelHighlightKeywords() {
                const stored = Config.getConfig('right_panel_highlight.keywords');
                if (!Array.isArray(stored) || stored.length === 0) return '';
                return stored.map(rule => {
                    if (!rule) return '';
                    if (typeof rule === 'string') return rule;
                    if (rule.type === 'regex') {
                        const flags = rule.flags || '';
                        return `/${rule.value || ''}/${flags}`;
                    }
                    return rule.value || '';
                }).filter(Boolean).join('\n');
            },
            // 解析右侧面板高亮关键词输入
            parseRightPanelHighlightKeywords(inputValue) {
                if (!inputValue) return [];
                return inputValue.split(/\r?\n/).map(line => line.trim()).filter(Boolean).map(line => {
                    if (line.startsWith('/') && line.lastIndexOf('/') > 0) {
                        const lastSlash = line.lastIndexOf('/');
                        const pattern = line.slice(1, lastSlash);
                        const flags = line.slice(lastSlash + 1);
                        try {
                            new RegExp(pattern, flags || 'i');
                            return { type: 'regex', value: pattern, flags };
                        } catch (err) {
                            // console.warn('[NodeSeek X] 忽略无效正则:', line, err);
                            return null;
                        }
                    }
                    return { type: 'text', value: line };
                }).filter(Boolean);
            },
            // 刷新右侧面板高亮关键词规则
            refreshRightPanelHighlightRules() {
                const stored = Config.getConfig('right_panel_highlight.keywords');
                const list = Array.isArray(stored) ? stored : [];
                this.rightPanelHighlightRules = list.map(rule => {
                    if (!rule) return null;
                    if (typeof rule === 'string') {
                        const value = rule.trim();
                        if (!value) return null;
                        return { type: 'text', value, lower: value.toLowerCase() };
                    }
                    const type = rule.type || 'text';
                    if (type === 'regex') {
                        const pattern = rule.value || rule.pattern || '';
                        if (!pattern) return null;
                        const flags = rule.flags || '';
                        try {
                            const regex = new RegExp(pattern, flags || 'i');
                            return { type: 'regex', regex, value: pattern, flags };
                        } catch (err) {
                            // console.warn('[NodeSeek X] 无效的正则规则:', pattern, err);
                            return null;
                        }
                    }
                    const value = (rule.value || '').trim();
                    if (!value) return null;
                    return { type: 'text', value, lower: value.toLowerCase() };
                }).filter(Boolean);
            },
            // 高亮文本节点中的关键词
            highlightTextNode(textNode, rules) {
                if (!rules || rules.length === 0) return;
                if (!textNode || textNode.nodeType !== Node.TEXT_NODE) return;
                
                const text = textNode.textContent;
                if (!text || text.trim().length === 0) return;
                
                // 检查是否已经高亮过(避免重复处理)
                // 如果父元素已经包含高亮标记,说明已经处理过
                if (textNode.parentElement && textNode.parentElement.querySelector('.nsx-right-panel-highlight')) {
                    return;
                }
                
                const fragments = [];
                let lastIndex = 0;
                
                // 收集所有匹配位置
                const matches = [];
                rules.forEach(rule => {
                    if (rule.type === 'regex') {
                        try {
                            const regex = new RegExp(rule.regex.source, rule.regex.flags + 'g');
                            let match;
                            while ((match = regex.exec(text)) !== null) {
                                matches.push({
                                    start: match.index,
                                    end: match.index + match[0].length,
                                    text: match[0]
                                });
                            }
                        } catch (err) {
                            // console.warn('[NodeSeek X] 正则匹配失败:', rule, err);
                        }
                    } else {
                        // 普通文本匹配(不区分大小写)
                        const lowerText = text.toLowerCase();
                        const lowerKeyword = rule.lower;
                        if (!lowerKeyword) return;
                        
                        let index = 0;
                        while ((index = lowerText.indexOf(lowerKeyword, index)) !== -1) {
                            matches.push({
                                start: index,
                                end: index + rule.value.length,
                                text: text.substring(index, index + rule.value.length)
                            });
                            index += rule.value.length;
                        }
                    }
                });
                
                // 按位置排序并合并重叠
                matches.sort((a, b) => a.start - b.start);
                const mergedMatches = [];
                matches.forEach(match => {
                    if (mergedMatches.length === 0) {
                        mergedMatches.push(match);
                    } else {
                        const last = mergedMatches[mergedMatches.length - 1];
                        if (match.start <= last.end) {
                            // 重叠,合并
                            last.end = Math.max(last.end, match.end);
                            last.text = text.substring(last.start, last.end);
                        } else {
                            mergedMatches.push(match);
                        }
                    }
                });
                
                if (mergedMatches.length === 0) return;
                
                // 创建高亮片段
                mergedMatches.forEach(match => {
                    // 添加匹配前的文本
                    if (match.start > lastIndex) {
                        fragments.push(document.createTextNode(text.substring(lastIndex, match.start)));
                    }
                    // 添加高亮的文本
                    const mark = document.createElement('mark');
                    mark.className = 'nsx-right-panel-highlight';
                    mark.textContent = match.text;
                    fragments.push(mark);
                    lastIndex = match.end;
                });
                
                // 添加剩余的文本
                if (lastIndex < text.length) {
                    fragments.push(document.createTextNode(text.substring(lastIndex)));
                }
                
                if (fragments.length > 1) {
                    // 替换文本节点
                    const parent = textNode.parentNode;
                    const markCount = fragments.filter(f => f.tagName === 'MARK').length;
                    fragments.forEach(fragment => {
                        parent.insertBefore(fragment, textNode);
                    });
                    parent.removeChild(textNode);
                    if (markCount > 0) {
                        // console.log('[NodeSeek X] 已高亮文本节点,创建了', markCount, '个高亮标记,文本:', text.substring(0, 50), '匹配的关键词:', mergedMatches.map(m => m.text).join(', '));
                    }
                }
            },
            // 应用右侧面板关键词高亮
            applyRightPanelHighlight() {
                const enabled = Config.getConfig('right_panel_highlight.enabled');
                if (enabled !== true) {
                    // 移除所有高亮
                    this.removeAllHighlights();
                    return;
                }
                
                this.refreshRightPanelHighlightRules();
                // console.log('[NodeSeek X] 应用高亮,规则数量:', this.rightPanelHighlightRules ? this.rightPanelHighlightRules.length : 0);
                
                if (!this.rightPanelHighlightRules || this.rightPanelHighlightRules.length === 0) {
                    this.removeAllHighlights();
                    return;
                }
                
                // 先移除已存在的高亮标记(避免重复)
                this.removeAllHighlights();
                
                // 处理右侧面板
                const rightPanel = document.querySelector('#nsk-right-panel-container');
                if (rightPanel) {
                    // console.log('[NodeSeek X] 处理右侧面板');
                    this.highlightInContainer(rightPanel);
                }
                
                // 处理帖子列表 - 使用配置的选择器
                let postList = document.querySelector(opts.post.postListSelector);
                if (!postList) {
                    // 备用选择器
                    postList = document.querySelector('#nsk-body-left .post-list');
                }
                if (!postList) {
                    postList = document.querySelector('.post-list:not(.topic-carousel-panel)');
                }
                if (!postList) {
                    postList = document.querySelector('#nsk-body-left');
                }
                if (postList) {
                    // console.log('[NodeSeek X] 处理帖子列表,容器:', postList.className || postList.id || postList.tagName, '选择器:', opts.post.postListSelector);
                    this.highlightInContainer(postList);
                } else {
                    // console.warn('[NodeSeek X] 未找到帖子列表容器,尝试的选择器:', opts.post.postListSelector, '#nsk-body-left .post-list', '.post-list:not(.topic-carousel-panel)');
                }
            },
            // 移除所有高亮标记
            removeAllHighlights() {
                const containers = [
                    document.querySelector('#nsk-right-panel-container'),
                    document.querySelector(opts.post.postListSelector),
                    document.querySelector('#nsk-body-left .post-list'),
                    document.querySelector('.post-list:not(.topic-carousel-panel)')
                ].filter(Boolean);
                
                containers.forEach(container => {
                    if (!container) return;
                    container.querySelectorAll('.nsx-right-panel-highlight').forEach(mark => {
                        const parent = mark.parentNode;
                        parent.replaceChild(document.createTextNode(mark.textContent), mark);
                        parent.normalize();
                    });
                    container.querySelectorAll('.nsx-highlight-processed').forEach(el => {
                        el.classList.remove('nsx-highlight-processed');
                    });
                });
            },
            // 在指定容器中应用高亮
            highlightInContainer(container) {
                if (!container) {
                    // console.warn('[NodeSeek X] highlightInContainer: 容器为空');
                    return;
                }
                
                // console.log('[NodeSeek X] highlightInContainer: 开始处理容器', container.tagName, container.className || container.id);
                
                // 遍历所有文本节点
                const walker = document.createTreeWalker(
                    container,
                    NodeFilter.SHOW_TEXT,
                    {
                        acceptNode: (node) => {
                            // 排除已处理的节点和某些特殊元素
                            if (node.parentElement && (
                                node.parentElement.tagName === 'SCRIPT' ||
                                node.parentElement.tagName === 'STYLE' ||
                                node.parentElement.classList.contains('nsx-highlight-input-panel')
                            )) {
                                return NodeFilter.FILTER_REJECT;
                            }
                            // 如果父元素已经包含高亮标记,跳过(避免重复处理)
                            // 注意:这里检查的是父元素是否包含高亮标记,而不是当前节点
                            const parent = node.parentElement;
                            if (parent && parent.querySelector && parent.querySelector('.nsx-right-panel-highlight')) {
                                // 如果父元素已经包含高亮标记,说明已经处理过,跳过
                                return NodeFilter.FILTER_REJECT;
                            }
                            // 特别处理帖子标题:确保处理 .post-title 内的文本节点
                            const isInPostTitle = parent && (
                                parent.classList.contains('post-title') ||
                                parent.closest('.post-title')
                            );
                            if (isInPostTitle && node.textContent.trim()) {
                                // console.log('[NodeSeek X] 找到帖子标题文本节点:', node.textContent.substring(0, 50), '父元素:', parent.tagName, parent.className);
                            }
                            return NodeFilter.FILTER_ACCEPT;
                        }
                    }
                );
                
                const textNodes = [];
                let node;
                while (node = walker.nextNode()) {
                    textNodes.push(node);
                }
                
                // console.log('[NodeSeek X] 找到文本节点数量:', textNodes.length, '规则数量:', this.rightPanelHighlightRules.length);
                
                if (textNodes.length === 0) {
                    // console.warn('[NodeSeek X] highlightInContainer: 未找到任何文本节点');
                    return;
                }
                
                // 处理文本节点(从后往前,避免位置偏移)
                let processedCount = 0;
                for (let i = textNodes.length - 1; i >= 0; i--) {
                    const beforeLength = textNodes[i].textContent.length;
                    this.highlightTextNode(textNodes[i], this.rightPanelHighlightRules);
                    // 检查是否被处理了(如果被处理,文本节点会被替换)
                    if (textNodes[i].parentNode && textNodes[i].parentNode.querySelector('.nsx-right-panel-highlight')) {
                        processedCount++;
                    }
                }
                // console.log('[NodeSeek X] 处理完成,处理了', processedCount, '个文本节点');
            },
            // 启动右侧面板高亮观察器
            startRightPanelHighlightObserver() {
                const enabled = Config.getConfig('right_panel_highlight.enabled');
                if (enabled !== true) {
                    if (this.rightPanelHighlightObserver) {
                        this.rightPanelHighlightObserver.disconnect();
                        this.rightPanelHighlightObserver = null;
                    }
                    return;
                }
                
                if (this.rightPanelHighlightObserver) {
                    this.rightPanelHighlightObserver.disconnect();
                }
                
                const _this = this;
                const containers = [
                    document.querySelector('#nsk-right-panel-container'),
                    document.querySelector('#nsk-body-left .post-list')
                ].filter(Boolean);
                
                if (containers.length === 0) return;
                
                this.rightPanelHighlightObserver = new MutationObserver(() => {
                    // 延迟应用高亮,避免频繁触发
                    setTimeout(() => {
                        _this.applyRightPanelHighlight();
                    }, 100);
                });
                
                // 观察所有容器
                containers.forEach(container => {
                    this.rightPanelHighlightObserver.observe(container, {
                        childList: true,
                        subtree: true,
                        characterData: true
                    });
                });
            },
            mergeCategoryToNav() {
                const enabled = Config.getConfig('merge_category_to_nav.enabled');
                const navMenu = document.querySelector('#nsk-head .nav-menu');
                const categoryPanel = document.querySelector('#nsk-right-panel-container .category-list');
                const leftCategoryPanel = document.querySelector('#nsk-left-panel-container .category-list');

                if (!navMenu) return;

                // 移除旧的合并样式
                const oldStyle = document.getElementById('nsx-merge-category-style');
                if (oldStyle) oldStyle.remove();

                // 移除已存在的合并分类列表(可能在 nav-menu 中,也可能在 header 中)
                const existingMerged = document.querySelector('#nsk-head .nsx-merged-categories, header ~ .nsx-merged-categories-wrapper');
                if (existingMerged) {
                    existingMerged.remove();
                }

                if (!enabled) {
                    // 恢复右侧面板显示
                    if (categoryPanel) {
                        categoryPanel.style.display = '';
                    }
                    if (leftCategoryPanel) {
                        leftCategoryPanel.style.display = '';
                    }
                    return;
                }

                // 隐藏右侧和左侧的分类面板
                if (categoryPanel) {
                    categoryPanel.style.display = 'none';
                }
                if (leftCategoryPanel) {
                    leftCategoryPanel.style.display = 'none';
                }

                // 获取分类列表(优先使用右侧面板)
                const categoryList = categoryPanel || leftCategoryPanel;
                if (!categoryList) return;

                const categoryItems = categoryList.querySelectorAll('ul li');
                if (categoryItems.length === 0) return;

                // 获取导航栏中已有的链接URL集合(用于去重)
                const existingNavLinks = new Set();
                navMenu.querySelectorAll('li a').forEach(link => {
                    const href = link.getAttribute('href');
                    if (href) {
                        // 标准化URL,移除查询参数和锚点
                        const normalizedHref = href.split('?')[0].split('#')[0];
                        existingNavLinks.add(normalizedHref);
                    }
                });
                // 也检查已存在的合并分类链接
                const header = document.querySelector('#nsk-head');
                if (header) {
                    const existingMerged = header.querySelector('.nsx-merged-categories');
                    if (existingMerged) {
                        existingMerged.querySelectorAll('a').forEach(link => {
                            const href = link.getAttribute('href');
                            if (href) {
                                const normalizedHref = href.split('?')[0].split('#')[0];
                                existingNavLinks.add(normalizedHref);
                            }
                        });
                    }
                }

                // 创建合并后的分类菜单
                const mergedCategories = document.createElement('div');
                mergedCategories.className = 'nsx-merged-categories';
                // 检查是否是紧凑模式,如果不是,设置 flex-wrap: nowrap 防止换行
                const isCompactMode = document.documentElement.classList.contains('nsx-compact-mode');
                const compactColumns = Config.getConfig('compact_mode.columns') || 1;
                // 只有在紧凑模式且列数>=2时才允许换行,否则单行显示
                if (isCompactMode && compactColumns >= 2) {
                    // 紧凑模式多列:允许换行
                    mergedCategories.style.cssText = 'display: flex; align-items: center; margin-left: 10px; gap: 5px; flex-wrap: wrap;';
                } else {
                    // 单列模式或紧凑模式单列:不换行,隐藏超出部分
                    mergedCategories.style.cssText = 'display: flex; align-items: center; margin-left: 10px; gap: 5px; flex-wrap: nowrap; overflow: hidden;';
                }

                categoryItems.forEach((item) => {
                    const link = item.querySelector('a');
                    if (!link) return;

                    // 检查是否已存在于导航栏中
                    const href = link.getAttribute('href');
                    if (href) {
                        const normalizedHref = href.split('?')[0].split('#')[0];
                        if (existingNavLinks.has(normalizedHref)) {
                            // 如果导航栏中已有此链接,跳过(保留导航栏中的带图标版本)
                            return;
                        }
                    }

                    const clonedLink = link.cloneNode(true);
                    clonedLink.style.cssText = 'display: flex; align-items: center; padding: 4px 8px; border-radius: 4px; transition: background-color 0.2s, color 0.2s; white-space: nowrap;';

                    // 保持当前分类的样式
                    if (item.classList.contains('current-category')) {
                        clonedLink.style.backgroundColor = '#f1f3f5';
                        clonedLink.style.color = '#0dbc79';
                    }

                    // 添加悬停效果
                    clonedLink.addEventListener('mouseenter', function() {
                        if (!item.classList.contains('current-category')) {
                            this.style.backgroundColor = '#f1f3f5';
                            this.style.color = '#0dbc79';
                        }
                    });
                    clonedLink.addEventListener('mouseleave', function() {
                        if (!item.classList.contains('current-category')) {
                            this.style.backgroundColor = '';
                            this.style.color = '';
                        }
                    });

                    mergedCategories.appendChild(clonedLink);
                });

                // 只有当有新的分类链接时才添加到导航栏
                if (mergedCategories.children.length > 0) {
                    // 将合并的分类链接添加到 header 中,搜索框之后
                    const header = document.querySelector('#nsk-head');
                    const searchBox = header ? header.querySelector('.search-box') : null;
                    if (searchBox && searchBox.nextSibling) {
                        header.insertBefore(mergedCategories, searchBox.nextSibling);
                    } else if (searchBox) {
                        searchBox.insertAdjacentElement('afterend', mergedCategories);
                    } else {
                        // 如果没有搜索框,添加到 nav-menu 后面
                        navMenu.insertAdjacentElement('afterend', mergedCategories);
                    }
                }

                // 添加样式
                const style = document.createElement('style');
                style.id = 'nsx-merge-category-style';
                style.textContent = `
                    /* 增加导航栏宽度,确保能容纳所有内容 */
                    #nsk-head {
                        max-width: 100% !important;
                        width: 100% !important;
                        overflow: visible !important;
                    }
                    /* 导航栏内的分类链接 */
                    #nsk-head .nsx-merged-categories {
                        display: flex;
                        align-items: center;
                        flex-wrap: nowrap;
                        gap: 5px;
                        margin-left: 10px;
                        flex-shrink: 0;
                        overflow: hidden;
                    }
                    /* 单列模式下,分类链接从搜索框右边开始,限制最大宽度避免覆盖设置按钮 */
                    html:not(.nsx-compact-mode) #nsk-head .nsx-merged-categories {
                        position: absolute;
                        left: calc(50% + 180px);
                        right: 120px;
                        top: 50%;
                        transform: translateY(-50%);
                        max-width: calc(50% - 300px);
                        z-index: 0;
                    }
                    /* 紧凑模式多列:分类链接在搜索框右侧 */
                    html.nsx-compact-mode #nsk-head .nsx-merged-categories {
                        position: absolute;
                        left: calc(50% + 150px);
                        top: 50%;
                        transform: translateY(-50%);
                        max-width: calc(50% - 150px);
                        z-index: 0;
                    }
                    @media screen and (max-width: 1200px) {
                        html:not(.nsx-compact-mode) #nsk-head .nsx-merged-categories {
                            left: calc(50% + 150px) !important;
                            right: 120px !important;
                            max-width: calc(50% - 270px) !important;
                        }
                        html.nsx-compact-mode #nsk-head .nsx-merged-categories {
                            left: calc(50% + 150px) !important;
                            right: 120px !important;
                            max-width: calc(50% - 270px) !important;
                        }
                    }
                    @media screen and (max-width: 800px) {
                        #nsk-head .nsx-merged-categories {
                            position: static !important;
                            transform: none !important;
                            left: auto !important;
                            right: auto !important;
                            max-width: 100% !important;
                            margin-left: 0 !important;
                            margin-top: 5px !important;
                        }
                    }
                    .nsx-merged-categories a {
                        font-size: 13px;
                        text-decoration: none;
                        color: var(--link-color);
                        display: flex;
                        align-items: center;
                        padding: 4px 8px;
                        border-radius: 4px;
                        transition: background-color 0.2s, color 0.2s;
                        white-space: nowrap;
                        flex-shrink: 0;
                    }
                    .nsx-merged-categories a:hover {
                        color: var(--link-hover-color);
                    }
                    .nsx-merged-categories .iconpark-icon {
                        width: 14px;
                        height: 14px;
                        margin-right: 4px;
                    }
                `;
                document.head.appendChild(style);
            },
            addPluginStyle() {
                let style = `
            .nsplus-tip { background-color: rgba(255, 217, 0, 0.8); border: 0px solid black;  padding: 3px; text-align: center;animation: blink 5s cubic-bezier(.68,.05,.46,.96) infinite;}
            /* @keyframes blink{ 0%{background-color: red;} 25%{background-color: yellow;} 50%{background-color: blue;} 75%{background-color: green;} 100%{background-color: red;} } */
            .nsplus-tip p,.nsplus-tip p a { color: #f00 }
            .nsplus-tip p a:hover {color: #0ff}
            #back-to-comment{display:flex;}
            #fast-nav-button-group .nav-item-btn:nth-last-child(4){bottom:120px;}

            header div.history-dropdown-on { color: var(--link-hover-color); cursor: pointer; padding: 0 5px; position: absolute; right: 50px}
            header div.nsx-settings-btn { 
                color: var(--link-hover-color); 
                cursor: pointer; 
                padding: 0 5px; 
                position: absolute; 
                right: 70px; 
                transition: color 0.3s;
                z-index: 10 !important;
                pointer-events: auto !important;
            }
            header div.nsx-settings-btn:hover { color: var(--link-color);}

            /* 导航栏链接美化 - 添加悬浮效果 */
            #nsk-head .nav-menu a {
                padding: 4px 8px;
                border-radius: 4px;
                transition: background-color 0.2s, color 0.2s;
                text-decoration: none;
            }
            #nsk-head .nav-menu a:hover {
                color: var(--link-hover-color);
                background-color: rgba(0, 0, 0, 0.05);
            }
            body.dark-layout #nsk-head .nav-menu a:hover {
                background-color: rgba(255, 255, 255, 0.1);
            }

            .user-card .close,
            .hover-user-card .close,
            .closeBtn,
            .closeBtn * {
                cursor: pointer !important;
            }
            /* 单列模式下,确保用户卡片不会超出页面底部 */
            html:not(.nsx-compact-mode) .hover-user-card,
            html.nsx-compact-mode[data-compact-columns="1"] .hover-user-card {
                max-height: calc(100vh - 100px) !important;
                overflow-y: auto !important;
                max-width: calc(100vw - 40px) !important;
            }
            /* 如果用户卡片底部超出视口,调整位置 */
            html:not(.nsx-compact-mode) .hover-user-card[style*="top"] {
                max-height: calc(100vh - 100px) !important;
            }
            html.nsx-compact-mode[data-compact-columns="1"] .hover-user-card[style*="top"] {
                max-height: calc(100vh - 100px) !important;
            }

            .blocked-post { display: none !important; }
            html.nsx-remove-promotions .promotation-item {
                display: none !important;
            }

            /* 紧凑模式样式由 updateCompactModeStyle() 动态生成 */

            /* 设置面板快捷键列表样式 */
            #nsx-settings-layer .layui-form-item table kbd {
                background-color: var(--bg-main-color, #fff) !important;
                border: 1px solid rgba(0,0,0,.2) !important;
                border-radius: 3px !important;
                box-shadow: 0 1px 0 rgba(0,0,0,.2) !important;
                padding: 3px 8px !important;
                font-family: monospace !important;
                font-size: 12px !important;
                color: var(--text-color, #333) !important;
                display: inline-block !important;
                margin: 0 2px !important;
            }
            body.dark-layout #nsx-settings-layer .layui-form-item table kbd {
                background-color: var(--bg-sub-color, #3b3b3b) !important;
                border-color: rgba(255,255,255,.2) !important;
                color: var(--text-color, #aaa) !important;
            }
            #nsx-settings-layer .layui-form-item table td {
                color: var(--text-color, #333) !important;
            }
            body.dark-layout #nsx-settings-layer .layui-form-item table td {
                color: var(--text-color, #aaa) !important;
            }
            #nsx-settings-layer .layui-form-item table {
                background-color: transparent !important;
            }

            /* 用户统计信息颜色样式 - 鲜艳配色 */
            .nsx-user-stats span {
                font-weight: 500;
            }
            .nsx-user-stats span[title="注册天数"] {
                color: #2ea44f !important;
            }
            .nsx-user-stats span[title="鸡腿数量"] {
                color: #ff9800 !important;
            }
            .nsx-user-stats span[title="帖子数"] {
                color: #2196f3 !important;
            }
            .nsx-user-stats span[title="评论数"] {
                color: #9c27b0 !important;
            }
            /* 深色模式下的鲜艳配色 */
            body.dark-layout .nsx-user-stats span[title="注册天数"] {
                color: #45ca6b !important;
            }
            body.dark-layout .nsx-user-stats span[title="鸡腿数量"] {
                color: #ffb74d !important;
            }
            body.dark-layout .nsx-user-stats span[title="帖子数"] {
                color: #64b5f6 !important;
            }
            body.dark-layout .nsx-user-stats span[title="评论数"] {
                color: #ba68c8 !important;
            }

            /* Lv0 - Lv2: 灰到橙 */
            .role-tag.user-level.user-lv0 {background-color: #c7c2c2; border: 1px solid #c7c2c2; color: #fafafa;}
            .role-tag.user-level.user-lv1 {background-color: #ffb74d; border: 1px solid #ffb74d; color: #fafafa;}
            .role-tag.user-level.user-lv2 {background-color: #ff9400; border: 1px solid #ff9400; color: #fafafa;}
            /* Lv3 - Lv4: 红到深红 */
            .role-tag.user-level.user-lv3 {background-color: #ff5252; border: 1px solid #ff5252; color: #fafafa;}
            .role-tag.user-level.user-lv4 {background-color: #e53935; border: 1px solid #e53935; color: #fafafa;}
            /* Lv5 - Lv6: 紫到深紫 */
            .role-tag.user-level.user-lv5 {background-color: #ab47bc; border: 1px solid #ab47bc; color: #fafafa;}
            .role-tag.user-level.user-lv6 {background-color: #8e24aa; border: 1px solid #8e24aa; color: #fafafa;}
            /* Lv7 - Lv8: 蓝到深蓝 */
            .role-tag.user-level.user-lv7 {background-color: #42a5f5; border: 1px solid #42a5f5; color: #fafafa;}
            .role-tag.user-level.user-lv8 {background-color: #1e88e5; border: 1px solid #1e88e5; color: #fafafa;}
            /* Lv9 - Lv10: 绿到深绿 */
            .role-tag.user-level.user-lv9 {background-color: #66bb6a; border: 1px solid #66bb6a; color: #fafafa;}
            .role-tag.user-level.user-lv10 {background-color: #2e7d32; border: 1px solid #2e7d32; color: #fafafa;}
            /* Lv11 - Lv12: 金橙到深金橙 */
            .role-tag.user-level.user-lv11 {background-color: #ffca28; border: 1px solid #ffca28; color: #fafafa;}
            .role-tag.user-level.user-lv12 {background-color: #ffb300; border: 1px solid #ffb300; color: #fafafa;}
            /* Lv13 - Lv14: 紫金到深紫金 */
            .role-tag.user-level.user-lv13 {background-color: #b388ff; border: 1px solid #b388ff; color: #fafafa;}
            .role-tag.user-level.user-lv14 {background-color: #7c4dff; border: 1px solid #7c4dff; color: #fafafa;}
            /* Lv15: 黑金至尊 */
            .role-tag.user-level.user-lv15 {background-color: #000000; border: 1px solid #000000; color: #ffd700;}

            .post-content pre { position: relative; }
            .post-content pre span.copy-code { position: absolute; right: .5em; top: .5em; cursor: pointer;color: #c1c7cd;  }
            .post-content pre .iconpark-icon {width:16px;height:16px;margin:3px;}
            .post-content pre .iconpark-icon:hover {color:var(--link-hover-color)}
            .dark-layout .post-content pre code.hljs { padding: 1em !important; }

            html.nsx-hide-visited .post-list .post-title a:visited,
            html.nsx-hide-visited .post-list-item .post-title a:visited {
                display: none !important;
            }
`;
                if (document.head) {
                    util.addStyle('nsplus-style', 'style', style);
                    util.addStyle('layui-style', 'link', 'https://s.cfn.pp.ua/layui/2.9.9/css/layui.css');
                    util.addStyle('hightlight-style', 'link', GM_getResourceURL("highlightStyle"));
                }
            },
            addPluginScript() {
                GM_addElement(document.body, 'script', {
                    src: 'https://s4.zstatic.net/ajax/libs/highlight.js/11.9.0/highlight.min.js'
                });
                GM_addElement(document.body, 'script', {
                    textContent: 'window.onload = function(){hljs.highlightAll();}'
                });
                GM_addElement(document.body, "script", { textContent: `!function(e){var t,n,d,o,i,a,r='<svg><symbol id="envelope-one" viewBox="0 0 48 48" fill="none"><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="M36 16V8H4v24h8" data-follow-stroke="currentColor"/><path stroke-linejoin="round" stroke-width="4" stroke="currentColor" d="M12 40h32V16H12v24Z" data-follow-stroke="currentColor"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="m12 16 16 12 16-12" data-follow-stroke="currentColor"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="M32 16H12v15" data-follow-stroke="currentColor"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="M44 31V16H24" data-follow-stroke="currentColor"/></symbol><symbol id="at-sign" viewBox="0 0 48 48" fill="none"><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="M44 24c0-11.046-8.954-20-20-20S4 12.954 4 24s8.954 20 20 20v0c4.989 0 9.55-1.827 13.054-4.847" data-follow-stroke="currentColor"/><path stroke-linejoin="round" stroke-width="4" stroke="currentColor" d="M24 32a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z" data-follow-stroke="currentColor"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="M32 24a6 6 0 0 0 6 6v0a6 6 0 0 0 6-6m-12 1v-9" data-follow-stroke="currentColor"/></symbol><symbol id="copy" viewBox="0 0 48 48" fill="none"><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="M13 12.432v-4.62A2.813 2.813 0 0 1 15.813 5h24.374A2.813 2.813 0 0 1 43 7.813v24.375A2.813 2.813 0 0 1 40.187 35h-4.67" data-follow-stroke="currentColor"/><path stroke-linejoin="round" stroke-width="4" stroke="currentColor" d="M32.188 13H7.811A2.813 2.813 0 0 0 5 15.813v24.374A2.813 2.813 0 0 0 7.813 43h24.375A2.813 2.813 0 0 0 35 40.187V15.814A2.813 2.813 0 0 0 32.187 13Z" data-follow-stroke="currentColor"/></symbol><symbol id="history" viewBox="0 0 48 48" fill="none"><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="M5.818 6.727V14h7.273" data-follow-stroke="currentColor"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="M4 24c0 11.046 8.954 20 20 20v0c11.046 0 20-8.954 20-20S35.046 4 24 4c-7.402 0-13.865 4.021-17.323 9.998" data-follow-stroke="currentColor"/><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="m24.005 12-.001 12.009 8.48 8.48" data-follow-stroke="currentColor"/></symbol><symbol id="setting" viewBox="0 0 48 48" fill="none"><path stroke-linejoin="round" stroke-linecap="round" stroke-width="4" stroke="currentColor" d="M36.34 14.34L38.86 12 34 7.14l-2.34 2.52c-.8-.3-1.66-.52-2.56-.66L28 6H20l-1.1 3.2c-.9.14-1.76.36-2.56.66L14 7.14 9.14 12l2.52 2.34c-.3.8-.52 1.66-.66 2.56L6 20v8l3.2 1.1c.14.9.36 1.76.66 2.56L7.14 34 12 38.86l2.34-2.52c.8.3 1.66.52 2.56.66L20 42h8l1.1-3.2c.9-.14 1.76-.36 2.56-.66L34 38.86 38.86 34l-2.52-2.34c.3-.8.52-1.66.66-2.56L42 28v-8l-3.2-1.1c-.14-.9-.36-1.76-.66-2.56ZM24 32a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z" data-follow-stroke="currentColor"/></symbol></svg>';function c(){i||(i=!0,d())}t=function(){var e,t,n;(n=document.createElement("div")).innerHTML=r,r=null,(t=n.getElementsByTagName("svg")[0])&&(t.setAttribute("aria-hidden","true"),t.style.position="absolute",t.style.width=0,t.style.height=0,t.style.overflow="hidden",e=t,(n=document.body).firstChild?(t=n.firstChild).parentNode.insertBefore(e,t):n.appendChild(e))},document.addEventListener?["complete","loaded","interactive"].indexOf(document.readyState)>-1?setTimeout(t,0):(n=function(){document.removeEventListener("DOMContentLoaded",n,!1),t()},document.addEventListener("DOMContentLoaded",n,!1)):document.attachEvent&&(d=t,o=e.document,i=!1,(a=function(){try{o.documentElement.doScroll("left")}catch(e){return void setTimeout(a,50)}c()})(),o.onreadystatechange=function(){"complete"==o.readyState&&(o.onreadystatechange=null,c())})}(window);` });
            },
            darkMode(){
                // 选择要监视的目标元素(body元素)
                const targetNode = document.querySelector('body');
                // 进入页面时判断是否是深色模式
                if(targetNode.classList.contains('dark-layout')){
                    util.addStyle('layuicss-theme-dark','link','https://s.cfn.pp.ua/layui/theme-dark/2.9.7/css/layui-theme-dark.css');
                    util.removeStyle('hightlight-style');
                    util.addStyle('hightlight-style', 'link', GM_getResourceURL("highlightStyle_dark"));
                }

                // 配置MutationObserver的选项
                const observerConfig = {
                    attributes: true, // 监视属性变化
                    attributeFilter: ['class'], // 只监视类属性
                };

                // 创建一个新的MutationObserver,并指定触发变化时的回调函数
                const observer = new MutationObserver((mutationsList, observer) => {
                    for(let mutation of mutationsList) {
                        if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                            if(targetNode.classList.contains('dark-layout')){
                                util.addStyle('layuicss-theme-dark','link','https://s.cfn.pp.ua/layui/theme-dark/2.9.7/css/layui-theme-dark.css');
                                util.removeStyle('hightlight-style');
                                util.addStyle('hightlight-style', 'link', GM_getResourceURL("highlightStyle_dark"));
                            }else{
                                util.removeStyle('layuicss-theme-dark');
                                util.removeStyle('hightlight-style');
                                util.addStyle('hightlight-style', 'link', GM_getResourceURL("highlightStyle"));
                            }
                        }
                    }
                });

                // 使用给定的配置选项开始观察目标节点
                observer.observe(targetNode, observerConfig);
            },
            // 键盘快捷键翻页
            initKeyboardNavigation() {
                document.addEventListener('keydown', (e) => {
                    // 如果用户在输入框中(input, textarea, contenteditable),不触发快捷键
                    const activeElement = document.activeElement;
                    const isInputFocused = activeElement && (
                        activeElement.tagName === 'INPUT' ||
                        activeElement.tagName === 'TEXTAREA' ||
                        activeElement.isContentEditable ||
                        activeElement.closest('.CodeMirror') // CodeMirror 编辑器
                    );

                    if (isInputFocused) return;

                    // 左箭头键:前一页
                    if (e.key === 'ArrowLeft' || e.key === '←') {
                        e.preventDefault();
                        this.navigateToPage('prev');
                    }
                    // 右箭头键:后一页
                    else if (e.key === 'ArrowRight' || e.key === '→') {
                        e.preventDefault();
                        this.navigateToPage('next');
                    }
                });
            },
            // 导航到上一页或下一页
            navigateToPage(direction) {
                // 查找所有分页器(可能有顶部和底部两个)
                const pagers = document.querySelectorAll('div[role="navigation"][aria-label="pagination"]');

                if (pagers.length === 0) return;

                // 优先使用第一个可见的分页器
                let targetPager = null;
                for (const pager of pagers) {
                    const rect = pager.getBoundingClientRect();
                    if (rect.width > 0 && rect.height > 0) {
                        targetPager = pager;
                        break;
                    }
                }

                if (!targetPager) targetPager = pagers[0];

                let targetLink = null;

                if (direction === 'prev') {
                    // 查找前一页按钮
                    const prevBtn = targetPager.querySelector('.pager-prev');
                    if (prevBtn) {
                        // 检查是否可用(不是 disabled)
                        const isDisabled = prevBtn.getAttribute('aria-disabled') === 'true' ||
                                          prevBtn.classList.contains('disabled') ||
                                          prevBtn.hasAttribute('disabled');

                        if (!isDisabled) {
                            // 如果按钮本身是链接
                            if (prevBtn.tagName === 'A' && prevBtn.href) {
                                targetLink = prevBtn;
                            } else {
                                // 尝试查找内部的链接或父级链接
                                const link = prevBtn.querySelector('a') || prevBtn.closest('a');
                                if (link && link.href) {
                                    targetLink = link;
                                }
                            }
                        }
                    }
                } else if (direction === 'next') {
                    // 查找后一页按钮
                    const nextBtn = targetPager.querySelector('.pager-next');
                    if (nextBtn) {
                        // 检查是否可用(不是 disabled)
                        const isDisabled = nextBtn.getAttribute('aria-disabled') === 'true' ||
                                          nextBtn.classList.contains('disabled') ||
                                          nextBtn.hasAttribute('disabled');

                        if (!isDisabled) {
                            // 如果按钮本身是链接
                            if (nextBtn.tagName === 'A' && nextBtn.href) {
                                targetLink = nextBtn;
                            } else {
                                // 尝试查找内部的链接或父级链接
                                const link = nextBtn.querySelector('a') || nextBtn.closest('a');
                                if (link && link.href) {
                                    targetLink = link;
                                }
                            }
                        }
                    }
                }

                if (targetLink && targetLink.href) {
                    // 显示加载遮罩
                    const overlay = document.getElementById('nsx-loading-overlay');
                    if (overlay) overlay.classList.add('show');

                    window.location.href = targetLink.href;
                }
            },
            // 排序帖子列表
            sortPostList() {
                const postList = document.querySelector(opts.post.postListSelector);
                if (!postList) return;

                const sortMode = Config.getConfig('post_sort.mode') || 'none';
                const visitedToBottom = Config.getConfig('post_sort.visited_to_bottom') === true;

                // 如果没有启用排序且不需要置底,直接返回
                if (sortMode === 'none' && !visitedToBottom) return;

                const items = Array.from(postList.querySelectorAll('.post-list-item'));
                if (items.length === 0) return;

                // 获取已访问的链接集合(从 localStorage)
                const visitedLinks = new Set();
                if (visitedToBottom) {
                    try {
                        const visited = localStorage.getItem('nsx_visited_posts');
                        if (visited) {
                            const visitedArray = JSON.parse(visited);
                            visitedArray.forEach(url => visitedLinks.add(url));
                        }
                    } catch (e) {
                        // console.warn('[NodeSeek X] 读取访问记录失败:', e);
                    }
                }

                // 提取数据并排序
                const itemsWithData = items.map(item => {
                    const titleLink = item.querySelector('.post-title a');
                    const href = titleLink ? titleLink.href : '';
                    // 检查是否已访问:优先使用 localStorage,其次使用 :visited 伪类
                    let isVisited = false;
                    if (visitedToBottom && href) {
                        // 标准化 URL(移除查询参数和锚点)
                        const normalizedUrl = href.split('?')[0].split('#')[0];
                        isVisited = visitedLinks.has(normalizedUrl);
                    }
                    // 如果 localStorage 中没有,尝试使用 :visited 伪类(作为后备)
                    if (!isVisited && titleLink) {
                        try {
                            // 注意:浏览器安全限制,无法直接读取 :visited 状态
                            // 但可以通过计算样式来检测(虽然不总是可靠)
                            const computedStyle = window.getComputedStyle(titleLink);
                            // 如果链接颜色与未访问链接不同,可能是已访问
                            // 这里我们主要依赖 localStorage
                        } catch (e) {
                            // 忽略错误
                        }
                    }

                    // 提取回复数
                    let comments = 0;
                    const commentsEl = item.querySelector('.info-comments-count span[title]');
                    if (commentsEl) {
                        const title = commentsEl.getAttribute('title') || '';
                        const match = title.match(/(\d+)\s*comments?/i);
                        if (match) {
                            comments = parseInt(match[1], 10) || 0;
                        } else {
                            // 如果没有title,尝试从文本内容提取
                            const text = commentsEl.textContent.trim();
                            const numMatch = text.match(/\d+/);
                            if (numMatch) {
                                comments = parseInt(numMatch[0], 10) || 0;
                            }
                        }
                    }

                    // 提取查看数
                    let views = 0;
                    const viewsEl = item.querySelector('.info-views span[title]');
                    if (viewsEl) {
                        const title = viewsEl.getAttribute('title') || '';
                        const match = title.match(/(\d+)\s*views?/i);
                        if (match) {
                            views = parseInt(match[1], 10) || 0;
                        } else {
                            // 如果没有title,尝试从文本内容提取
                            const text = viewsEl.textContent.trim();
                            const numMatch = text.match(/\d+/);
                            if (numMatch) {
                                views = parseInt(numMatch[0], 10) || 0;
                            }
                        }
                    }

                    return {
                        item,
                        href,
                        isVisited,
                        comments,
                        views
                    };
                });

                // 排序
                itemsWithData.sort((a, b) => {
                    // 如果启用已访问置底,先按访问状态排序
                    if (visitedToBottom) {
                        if (a.isVisited && !b.isVisited) return 1;
                        if (!a.isVisited && b.isVisited) return -1;
                    }

                    // 然后按排序模式排序
                    if (sortMode === 'comments') {
                        return b.comments - a.comments;
                    } else if (sortMode === 'views') {
                        return b.views - a.views;
                    }

                    // 如果只是置底,保持原有顺序(在已访问置底后)
                    return 0;
                });

                // 重新插入排序后的元素
                itemsWithData.forEach(({ item }) => {
                    postList.appendChild(item);
                });
            },
            // 记录帖子访问
            recordPostVisit(url) {
                if (!url) return;
                try {
                    const normalizedUrl = url.split('?')[0].split('#')[0];
                    const visited = localStorage.getItem('nsx_visited_posts');
                    let visitedArray = visited ? JSON.parse(visited) : [];

                    // 如果不存在,添加到数组
                    if (!visitedArray.includes(normalizedUrl)) {
                        visitedArray.push(normalizedUrl);
                        // 限制数组大小,避免占用过多存储空间(保留最近1000条)
                        if (visitedArray.length > 1000) {
                            visitedArray = visitedArray.slice(-1000);
                        }
                        localStorage.setItem('nsx_visited_posts', JSON.stringify(visitedArray));
                    }
                } catch (e) {
                    // console.warn('[NodeSeek X] 记录访问失败:', e);
                }
            },
            // 初始化帖子访问监听,用于自动重新排序
            initPostVisitListener() {
                const visitedToBottom = Config.getConfig('post_sort.visited_to_bottom') === true;
                if (!visitedToBottom) return;

                const _this = this;

                // 监听帖子链接点击
                document.addEventListener('click', (e) => {
                    const link = e.target.closest('a');
                    if (!link || !link.href) return;

                    // 检查是否是帖子链接
                    const href = link.href;
                    const isPostLink = /\/post-\d+/.test(href) && href.startsWith(BASE_URL);

                    if (isPostLink) {
                        // 立即记录访问
                        _this.recordPostVisit(href);
                        // 延迟重新排序,确保记录已保存
                        setTimeout(() => {
                            _this.sortPostList();
                        }, 50);
                    }
                }, true);

                // 监听页面可见性变化(从新标签页返回时重新排序)
                document.addEventListener('visibilitychange', () => {
                    if (!document.hidden) {
                        // 页面重新可见时,延迟重新排序
                        setTimeout(() => {
                            _this.sortPostList();
                        }, 200);
                    }
                });

                // 监听焦点变化(切换标签页返回时)
                window.addEventListener('focus', () => {
                    setTimeout(() => {
                        _this.sortPostList();
                    }, 200);
                });
            },
            init() {
                Config.initializeConfig();
                this.addPluginStyle();
                this.checkLogin();
                this.refreshBlockKeywordRules();
                this.refreshBlockedCategories();
                this.refreshRightPanelHighlightRules();
                // 应用紧凑模式(类名已在早期添加,这里只需要更新样式)
                this.updateCompactModeStyle();
                const codeMirrorElement = document.querySelector('.CodeMirror');
                if (codeMirrorElement) {
                    const codeMirrorInstance = codeMirrorElement.CodeMirror;
                    if (codeMirrorInstance) {
                        let btnSubmit = document.querySelector('.md-editor button.submit.btn.focus-visible');
                        btnSubmit.innerText=btnSubmit.innerText+'(Ctrl+Enter)';
                        codeMirrorInstance.addKeyMap({"Ctrl-Enter":function(cm){ btnSubmit.click();}});
                    }
                }
                this.autoSignIn();//自动签到
                this.addSignTips();//签到提示
                this.enforceNewTabForPosts();//强制新标签页打开帖子
                this.autoJump();//自动点击跳转页
                this.autoLoading();//无缝加载帖子和评论
                this.blockMemberDOMInsert();//屏蔽用户
                this.blockPost();//屏蔽帖子
                this.blockPostsByCategory();
                this.blockPostsByViewLevel();
                this.quickComment();//快捷评论
                this.addLevelTag();//添加等级标签
                this.userCardEx();//用户卡片扩展
                //this.fakeLevel();
                this.addPluginScript();
                this.addCodeHighlight();
                this.addImageSlide();
                this.darkMode();
                this.history();
                this.initInstantPage();
                this.smoothScroll();
                this.addSettingsButton();
                this.updateCustomBackground();
                this.updateVisitedLinkStyle();
                this.updateAllTypography();
                this.togglePromotions();
                this.updateHeaderOpacityStyle();
                this.updateFrameOpacityStyle();
                this.replaceDefaultAvatars();
                this.startAvatarObserver();
                this.moveSearchBoxToCenter();
                this.mergeCategoryToNav();
                this.toggleUserStatsPanel();
                this.toggleFooter(); // 应用页脚隐藏设置
                this.togglePostCategory(); // 应用分类标签隐藏设置
                this.togglePostInfo(); // 应用帖子信息隐藏设置
                this.toggleTopicCarousel(); // 应用推荐轮播隐藏设置
                this.addRightPanelHighlightInput(); // 在右侧面板添加关键词输入框
                // 延迟应用高亮,确保DOM完全加载
                setTimeout(() => {
                    this.applyRightPanelHighlight();
                }, 200);
                this.startRightPanelHighlightObserver(); // 启动右侧面板高亮观察器
                this.initKeyboardNavigation(); // 初始化键盘快捷键
                this.initPostVisitListener(); // 初始化访问监听,用于自动重新排序

                // 延迟执行排序,确保DOM完全加载
                // 使用多种方式确保排序能执行
                setTimeout(() => {
                    this.sortPostList();
                    // 同时重新应用高亮
                    this.applyRightPanelHighlight();
                }, 100);

                // 如果页面还在加载,等待load事件
                if (document.readyState === 'loading') {
                    window.addEventListener('load', () => {
                        setTimeout(() => {
                            this.sortPostList();
                            // 同时重新应用高亮
                            this.applyRightPanelHighlight();
                        }, 200);
                    }, { once: true });
                }

                // 使用MutationObserver监听帖子列表的出现
                const postListObserver = new MutationObserver(() => {
                    const postList = document.querySelector(opts.post.postListSelector);
                    if (postList && postList.children.length > 0) {
                        setTimeout(() => {
                            this.sortPostList();
                            // 同时重新应用高亮
                            this.applyRightPanelHighlight();
                        }, 100);
                        postListObserver.disconnect();
                    }
                });

                // 如果帖子列表还不存在,开始观察
                const postList = document.querySelector(opts.post.postListSelector);
                if (!postList || postList.children.length === 0) {
                    if (document.body) {
                        postListObserver.observe(document.body, {
                            childList: true,
                            subtree: true
                        });
                        // 5秒后自动停止观察
                        setTimeout(() => postListObserver.disconnect(), 5000);
                    }
                } else {
                    // 如果帖子列表已经存在,立即应用高亮
                    setTimeout(() => {
                        this.applyRightPanelHighlight();
                    }, 300);
                }

                // 如果启用了显示所有用户统计,则执行
                if (Config.getConfig('show_all_users_stats.enabled') === true) {
                    setTimeout(() => {
                        this.showAllUsersStats();
                    }, 500);
                }
            }
        };
        main.init();
        });
    });
})();
                        layui.form.on('checkbox(hide_visited_links)', function(data) {
                            Config.updateConfig('visited_links.hide_visited', data.elem.checked);
                            _this.updateVisitedLinkStyle();
                        });