Greasy Fork

Greasy Fork is available in English.

百度贴吧终极增强套件Pro

优化版:解决强制屏蔽水贴失效问题,解决逻辑冲突,优化动态DOM处理,移除排序功能,部分来自(Grok AI)。未经许可,禁止修改或分发。

当前为 2025-02-22 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         百度贴吧终极增强套件Pro
// @namespace    http://tampermonkey.net/
// @version      7.37
// @description  优化版:解决强制屏蔽水贴失效问题,解决逻辑冲突,优化动态DOM处理,移除排序功能,部分来自(Grok AI)。未经许可,禁止修改或分发。
// @author       YourName
// @match        *://tieba.baidu.com/p/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @require      https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js
// @connect      tieba.baidu.com
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 防伪校验
    const SCRIPT_AUTH_TOKEN = 'xAI-Grok3-EnhancedTieba-20250225'; // 更新为新日期
    const checkAuthenticity = () => {
        const meta = GM_info.script;
        if (meta.version !== '7.37' || meta.name !== '百度贴吧终极增强套件Pro' || !meta.description.includes('xAI')) {
            alert('脚本可能被篡改或非正版,请从官方渠道下载!');
            return false;
        }
        GM_setValue('authToken', SCRIPT_AUTH_TOKEN);
        return true;
    };

    const LOG_LEVEL = GM_getValue('logLevel', 'verbose');
    const MAX_LOG_ENTRIES = 100;
    const CONFIG = {
        debugMode: GM_getValue('debugMode', true),
        defaultSettings: {
            filter: {
                hideInvalid: true,
                hideSpam: true,
                spamKeywords: ["顶", "沙发", "签到"],
                whitelist: [],
                blockedElements: [],
                tempBlockedElements: [],
                autoExpandImages: true,
                blockType: 'perm',
                blockAds: true,
                enhanceImages: true,
                linkifyVideos: true,
                darkMode: false,
                showHiddenFloors: false
            },
            panel: {
                width: 320,
                minHeight: 100,
                maxHeight: '90vh',
                position: { x: 20, y: 20 },
                scale: 1.0,
                minimized: true
            },
            logPath: `tieba_enhance_log_${new Date().toISOString().replace(/[:.]/g, '-')}.txt`
        }
    };

    const logBuffer = {
        script: [],
        pageState: [],
        pageBehavior: [],
        userActions: []
    };

    const originalConsole = {
        log: console.log.bind(console),
        warn: console.warn.bind(console),
        error: console.error.bind(console)
    };

    function logWrapper(category, level, ...args) {
        if (!CONFIG.debugMode || (LOG_LEVEL === 'error' && level !== 'ERROR')) return;
        const timestamp = new Date().toISOString();
        const formattedArgs = args.map(arg => {
            try {
                return typeof arg === 'object' ? JSON.stringify(arg) : arg.toString();
            } catch (e) {
                return '[Unserializable Object]';
            }
        }).join(' ');
        const message = `[${timestamp}] [${level}] ${formattedArgs}`;
        logBuffer[category].push(message);
        if (logBuffer[category].length > MAX_LOG_ENTRIES) logBuffer[category].shift();
        originalConsole[level.toLowerCase()](message);
    }

    const customConsole = {
        log: (...args) => logWrapper('script', 'LOG', ...args),
        warn: (...args) => logWrapper('script', 'WARN', ...args),
        error: (...args) => logWrapper('script', 'ERROR', ...args)
    };

    class PerformanceMonitor {
        static instance;
        constructor() {
            this.metrics = {
                memoryUsage: [],
                processSpeed: [],
                networkRequests: []
            };
        }
        static getInstance() {
            if (!PerformanceMonitor.instance) {
                PerformanceMonitor.instance = new PerformanceMonitor();
            }
            return PerformanceMonitor.instance;
        }
        recordMemory() {
            try {
                if ('memory' in performance) {
                    const used = performance.memory.usedJSHeapSize;
                    this.metrics.memoryUsage.push(used);
                    if (this.metrics.memoryUsage.length > 100) this.metrics.memoryUsage.shift();
                    logWrapper('pageState', 'LOG', `Memory recorded: ${Math.round(used / 1024 / 1024)} MB`);
                }
            } catch (e) {
                customConsole.error('Error in recordMemory:', e);
            }
        }
        recordProcessSpeed(time) {
            try {
                this.metrics.processSpeed.push(time);
                if (this.metrics.processSpeed.length > 100) this.metrics.processSpeed.shift();
                logWrapper('pageState', 'LOG', `Process speed recorded: ${time.toFixed(2)} ms`);
            } catch (e) {
                customConsole.error('Error in recordProcessSpeed:', e);
            }
        }
        recordNetwork() {
            try {
                if (performance.getEntriesByType) {
                    const requests = performance.getEntriesByType('resource');
                    requests.forEach(req => {
                        if (!this.metrics.networkRequests.some(r => r.name === req.name)) {
                            this.metrics.networkRequests.push(req);
                            if (this.metrics.networkRequests.length > 100) this.metrics.networkRequests.shift();
                            logWrapper('pageState', 'LOG', `Network request: ${req.name}, Duration: ${req.duration}ms`);
                        }
                    });
                }
            } catch (e) {
                customConsole.error('Error in recordNetwork:', e);
            }
        }
        recordPageTiming() {
            try {
                const timing = performance.timing;
                if (timing.loadEventEnd && timing.navigationStart) {
                    const loadTime = timing.loadEventEnd - timing.navigationStart;
                    logWrapper('pageState', 'LOG', `Page load time: ${loadTime}ms`);
                }
            } catch (e) {
                customConsole.error('Error in recordPageTiming:', e);
            }
        }
    }

    class PostFilter {
        constructor() {
            try {
                this.settings = GM_getValue('settings', CONFIG.defaultSettings.filter);
                customConsole.log('PostFilter settings:', this.settings);
                this.postsCache = new Map();
                this.spamPosts = new Set();
                this.originalOrder = [];
                this.applyStyles();
                this.saveOriginalOrder();
                this.applyFilters();
                this.autoExpandImages();
                this.observeDOMChanges();
                this.startSpamEnforcer();
                this.blockAds();
                this.interceptAjax();
                if (this.settings.linkifyVideos) this.linkifyVideos();
            } catch (e) {
                customConsole.error('Error initializing PostFilter:', e);
            }
        }

        applyStyles() {
            GM_addStyle(`
                .spam-hidden { display: none !important; }
                .invalid-hidden { display: none !important; }
            `);
        }

        saveOriginalOrder() {
            const posts = document.querySelectorAll('.l_post');
            this.originalOrder = Array.from(posts).map(post => {
                const pid = post.dataset.pid || 'unknown';
                const floor = post.dataset.floor || post.querySelector('.tail-info')?.textContent.match(/(\d+)楼/)?.[1] || '0';
                return { pid, floor, element: post.cloneNode(true) };
            });
            customConsole.log('Saved original post order:', this.originalOrder.length, 'Posts:', this.originalOrder.map(p => ({ pid: p.pid, floor: p.floor })));
        }

        applyFilters(nodes = document.querySelectorAll('.l_post')) {
            customConsole.log('Applying filters');
            logWrapper('pageBehavior', 'LOG', 'Applying content filters');
            const startTime = performance.now();
            try {
                nodes.forEach(post => {
                    if (!post || this.postsCache.has(post)) return;
                    const contentEle = post.querySelector('.d_post_content');
                    if (!contentEle) return;

                    const content = contentEle.textContent.trim();
                    const pid = post.dataset.pid || 'unknown';

                    post.style.display = '';
                    post.classList.remove('spam-hidden', 'invalid-hidden');

                    if (this.settings.hideInvalid && !content) {
                        post.classList.add('invalid-hidden');
                        logWrapper('pageBehavior', 'LOG', `Hid invalid post: ${pid}`);
                        if (this.settings.showHiddenFloors) {
                            post.classList.remove('invalid-hidden');
                            logWrapper('pageBehavior', 'LOG', `Restored invalid post: ${pid}`);
                        }
                    } else if (this.settings.hideSpam) {
                        const keywords = this.settings.spamKeywords.map(k => k.trim());
                        const regex = new RegExp(keywords.map(k => k.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('|'), 'i');
                        if (regex.test(content)) {
                            post.classList.add('spam-hidden');
                            post.style.display = 'none';
                            this.spamPosts.add(post);
                            const matchedKeyword = keywords.find(k => content.toLowerCase().includes(k.toLowerCase())) || 'unknown';
                            logWrapper('pageBehavior', 'LOG', `Hid spam post: ${pid}, Keyword: ${matchedKeyword}, Content: ${content.slice(0, 50)}...`);
                        }
                    }

                    this.postsCache.set(post, true);
                });

                const blockedElements = [...(this.settings.blockedElements || []), ...(this.settings.tempBlockedElements || [])];
                blockedElements.forEach(selector => {
                    try {
                        document.querySelectorAll(selector).forEach(el => {
                            if (!this.postsCache.has(el)) {
                                el.classList.add('spam-hidden');
                                el.style.display = 'none';
                                logWrapper('pageBehavior', 'LOG', `Hid blocked element: ${selector}`);
                                this.postsCache.set(el, true);
                            }
                        });
                    } catch (e) {
                        customConsole.warn(`Invalid selector: ${selector}`, e);
                    }
                });

                setTimeout(() => this.enforceSpamHiding(), 100);
            } catch (e) {
                customConsole.error('Error in applyFilters:', e);
            }
            const endTime = performance.now();
            PerformanceMonitor.getInstance().recordProcessSpeed(endTime - startTime);
        }

        startSpamEnforcer() {
            const observer = new MutationObserver(() => {
                if (this.settings.hideSpam) {
                    this.enforceSpamHiding();
                }
            });
            observer.observe(document.body, { childList: true, subtree: true, attributes: true });
            customConsole.log('Spam enforcer started');
        }

        enforceSpamHiding() {
            const allPosts = document.querySelectorAll('.l_post');
            allPosts.forEach(post => {
                if (!post || !this.spamPosts.has(post) || !document.body.contains(post)) return;
                if (post.style.display !== 'none') {
                    post.style.display = 'none';
                    post.classList.add('spam-hidden');
                    const pid = post.dataset.pid || 'unknown';
                    logWrapper('pageBehavior', 'LOG', `Re-enforced spam hiding for post: ${pid}`);
                }
            });
            setTimeout(() => this.enforceSpamHiding(), 500);
        }

        autoExpandImages(nodes = document.querySelectorAll('.replace_tip')) {
            if (!this.settings.autoExpandImages) return;
            customConsole.log('Auto expanding images');
            logWrapper('pageBehavior', 'LOG', 'Starting auto expand images');
            const startTime = performance.now();
            try {
                nodes.forEach(tip => {
                    if (tip.style.display !== 'none' && !tip.dataset.expanded) {
                        const rect = tip.getBoundingClientRect();
                        const clickEvent = new MouseEvent('click', { bubbles: true, cancelable: true, clientX: rect.left, clientY: rect.top });
                        tip.dispatchEvent(clickEvent);
                        tip.dataset.expanded = 'true';
                        const img = tip.closest('.replace_div')?.querySelector('img');
                        logWrapper('pageBehavior', 'LOG', `Expanded image: ${img?.src || 'unknown'}`);
                        logWrapper('userActions', 'LOG', `Simulated click on replace_tip at (${Math.round(rect.left)}, ${Math.round(rect.top)})`);
                        this.postsCache.set(tip, true);
                        if (this.settings.enhanceImages && img) this.enhanceImage(img);
                    }
                });
            } catch (e) {
                customConsole.error('Error in autoExpandImages:', e);
            }
            const endTime = performance.now();
            PerformanceMonitor.getInstance().recordProcessSpeed(endTime - startTime);
        }

        updateFilters() {
            try {
                this.settings = GM_getValue('settings', CONFIG.defaultSettings.filter);
                customConsole.log('Updated settings:', this.settings);
                this.postsCache.clear();
                this.spamPosts.clear();
                this.saveOriginalOrder();
                this.applyFilters();
                this.autoExpandImages();
                this.blockAds();
                this.restoreOriginalOrder(); // 仅恢复原始顺序
                if (this.settings.linkifyVideos) this.linkifyVideos();
            } catch (e) {
                customConsole.error('Error in updateFilters:', e);
            }
        }

        observeDOMChanges() {
            try {
                const observer = new MutationObserver(_.debounce(mutations => {
                    let shouldProcess = false;
                    const newPosts = new Set();
                    mutations.forEach(mutation => {
                        if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                            shouldProcess = true;
                            mutation.addedNodes.forEach(node => {
                                if (node.nodeType === Node.ELEMENT_NODE) {
                                    if (node.matches('.l_post')) newPosts.add(node);
                                    node.querySelectorAll('.l_post').forEach(post => newPosts.add(post));
                                }
                            });
                        }
                    });

                    if (shouldProcess) {
                        customConsole.log('Detected DOM change, reapplying filters');
                        logWrapper('pageBehavior', 'LOG', 'Page content updated, reapplying filters');
                        this.postsCache.clear();
                        this.spamPosts.clear();
                        this.saveOriginalOrder();
                        this.applyFilters(document.querySelectorAll('.l_post'));
                        this.autoExpandImages();
                        this.blockAds();
                        this.restoreOriginalOrder(); // 仅恢复原始顺序
                        if (this.settings.linkifyVideos) this.linkifyVideos();
                    } else if (newPosts.size > 0) {
                        customConsole.log('New posts detected:', newPosts.size);
                        this.applyFilters([...newPosts]);
                        this.autoExpandImages();
                    }
                }, 300));
                observer.observe(document.body, { childList: true, subtree: true });
                customConsole.log('DOM observer initialized');
            } catch (e) {
                customConsole.error('Error in observeDOMChanges:', e);
            }
        }

        interceptAjax() {
            const originalFetch = window.fetch;
            window.fetch = async (url, options) => {
                const response = await originalFetch(url, options);
                if (url.includes('pn=') && url.includes('ajax=1')) {
                    customConsole.log('Detected AJAX page load:', url);
                    setTimeout(() => {
                        this.postsCache.clear();
                        this.spamPosts.clear();
                        this.saveOriginalOrder();
                        this.applyFilters(document.querySelectorAll('.l_post'));
                        this.autoExpandImages();
                        this.blockAds();
                        this.restoreOriginalOrder(); // 仅恢复原始顺序
                    }, 500);
                }
                return response;
            };
            customConsole.log('AJAX interceptor initialized');
        }

        blockAds() {
            if (!this.settings.blockAds) return;
            customConsole.log('Blocking ads');
            logWrapper('pageBehavior', 'LOG', 'Blocking advertisements');
            try {
                const adSelectors = [
                    '.ad_item',
                    '.mediago',
                    '[class*="ad_"]:not([class*="content"])',
                    '.app_download_box',
                    '.right_section .region_bright:not(.content)'
                ];
                adSelectors.forEach(selector => {
                    document.querySelectorAll(selector).forEach(el => {
                        if (!el.closest('.d_post_content') && !el.closest('.l_container')) {
                            el.classList.add('spam-hidden');
                            el.style.display = 'none';
                            logWrapper('pageBehavior', 'LOG', `Hid ad element: ${selector}`);
                            this.postsCache.set(el, true);
                        }
                    });
                });
            } catch (e) {
                customConsole.error('Error in blockAds:', e);
            }
        }

        restoreOriginalOrder() {
            customConsole.log('Restoring original post order');
            logWrapper('pageBehavior', 'LOG', 'Restoring original post order');
            try {
                const container = document.querySelector('.pb_list');
                if (!container || !this.originalOrder.length) return;

                const currentPosts = new Map(Array.from(document.querySelectorAll('.l_post')).map(p => [p.dataset.pid, p]));
                customConsole.log('Current posts:', Array.from(currentPosts.keys()));
                customConsole.log('Original order:', this.originalOrder.map(p => p.pid));

                while (container.firstChild) container.removeChild(container.firstChild);
                this.originalOrder
                    .sort((a, b) => Number(a.floor) - Number(b.floor))
                    .forEach(item => {
                        const existingPost = currentPosts.get(item.pid);
                        if (existingPost) {
                            container.appendChild(existingPost);
                        } else {
                            container.appendChild(item.element.cloneNode(true));
                        }
                    });

                this.applyFilters();
            } catch (e) {
                customConsole.error('Error in restoreOriginalOrder:', e);
            }
        }

        linkifyVideos() {
            customConsole.log('Linking videos');
            logWrapper('pageBehavior', 'LOG', 'Converting video links');
            try {
                const videoRegex = /(?:av\d+|BV\w+)|(?:https?:\/\/(?:www\.)?(youtube\.com|youtu\.be)\/[^\s]+)/gi;
                document.querySelectorAll('.d_post_content').forEach(post => {
                    if (!this.postsCache.has(post)) {
                        post.innerHTML = post.innerHTML.replace(videoRegex, match => {
                            if (match.startsWith('http')) {
                                return `<a href="${match}" target="_blank">${match}</a>`;
                            } else {
                                return `<a href="https://bilibili.com/video/${match}" target="_blank">${match}</a>`;
                            }
                        });
                        this.postsCache.set(post, true);
                    }
                });
            } catch (e) {
                customConsole.error('Error in linkifyVideos:', e);
            }
        }

        enhanceImage(img) {
            if (!img) return;
            customConsole.log('Enhancing image:', img.src);
            try {
                img.style.cursor = 'pointer';
                img.removeEventListener('click', this.handleImageClick);
                img.addEventListener('click', this.handleImageClick.bind(this));
            } catch (e) {
                customConsole.error('Error in enhanceImage:', e);
            }
        }

        handleImageClick() {
            const overlay = document.createElement('div');
            overlay.className = 'image-overlay';
            const largeImg = document.createElement('img');
            largeImg.src = this.src;
            largeImg.className = 'large-image';
            overlay.appendChild(largeImg);
            document.body.appendChild(overlay);
            overlay.addEventListener('click', () => overlay.remove());
            overlay.addEventListener('wheel', (e) => {
                e.preventDefault();
                const scale = e.deltaY > 0 ? 0.9 : 1.1;
                largeImg.style.transform = `scale(${(parseFloat(largeImg.style.transform?.match(/scale\((.*?)\)/)?.[1]) || 1) * scale})`;
            });
        }
    }

    class DynamicPanel {
        constructor() {
            try {
                this.panel = null;
                this.minimizedIcon = null;
                this.isDragging = false;
                this.dragOccurred = false;
                this.lastClickTime = 0;
                this.isResizing = false;
                this.settings = GM_getValue('settings', CONFIG.defaultSettings.filter) || CONFIG.defaultSettings.filter;
                this.panelSettings = GM_getValue('panelSettings', CONFIG.defaultSettings.panel) || CONFIG.defaultSettings.panel;
                if (!this.settings.blockedElements) this.settings.blockedElements = [];
                if (!this.settings.tempBlockedElements) this.settings.tempBlockedElements = [];
                customConsole.log('DynamicPanel settings:', this.panelSettings);
                this.postFilter = new PostFilter();
                this.init();
                this.applyDarkMode(this.settings.darkMode);
            } catch (e) {
                customConsole.error('Error initializing DynamicPanel:', e);
            }
        }

        init() {
            customConsole.log('Initializing DynamicPanel');
            try {
                this.createPanel();
                this.createMinimizedIcon();
                document.body.appendChild(this.panel);
                document.body.appendChild(this.minimizedIcon);
                this.loadContent();
                this.setupPanelInteractions();
                this.minimizePanel();
                if (!this.panelSettings.minimized) {
                    this.restorePanel();
                }
                this.ensureVisibility();
                this.observer = new ResizeObserver(() => this.adjustPanelHeight());
                this.observer.observe(this.panel.querySelector('.panel-content'));
                customConsole.log('Panel initialized, visible:', this.panel.style.display !== 'none');
                this.setupUserActionListeners();
                this.setupCleanup();
                setTimeout(() => this.startPerformanceMonitoring(), 100);
            } catch (e) {
                customConsole.error('Error in init:', e);
            }
        }

        ensureVisibility() {
            try {
                this.panel.style.opacity = '1';
                this.panel.style.visibility = 'visible';
                this.minimizedIcon.style.opacity = '1';
                this.minimizedIcon.style.visibility = 'visible';
                customConsole.log('Ensuring visibility:', {
                    panel: { display: this.panel.style.display },
                    icon: { display: this.minimizedIcon.style.display }
                });
            } catch (e) {
                customConsole.error('Error in ensureVisibility:', e);
            }
        }

        createPanel() {
            customConsole.log('Creating panel');
            try {
                this.panel = document.createElement('div');
                this.panel.id = 'enhanced-panel';
                GM_addStyle(`
                    #enhanced-panel {
                        position: fixed;
                        z-index: 9999;
                        top: ${this.panelSettings.position.y}px;
                        left: ${this.panelSettings.position.x}px;
                        width: ${this.panelSettings.width}px;
                        min-height: ${this.panelSettings.minHeight}px;
                        max-height: ${this.panelSettings.maxHeight};
                        background: rgba(255,255,255,0.98);
                        border-radius: 12px;
                        box-shadow: 0 8px 32px rgba(0,0,0,0.1);
                        transition: all 0.3s ease;
                        transform: scale(${this.panelSettings.scale});
                        contain: strict;
                        display: none;
                        opacity: 1;
                        visibility: visible;
                        height: auto;
                    }
                    #minimized-icon {
                        position: fixed;
                        z-index: 9999;
                        top: ${this.panelSettings.position.y}px;
                        left: ${this.panelSettings.position.x}px;
                        width: 32px;
                        height: 32px;
                        background: #ffffff;
                        border-radius: 50%;
                        box-shadow: 0 4px 16px rgba(0,0,0,0.2);
                        display: block;
                        cursor: pointer;
                        text-align: center;
                        line-height: 32px;
                        font-size: 16px;
                        color: #007bff;
                        overflow: hidden;
                    }
                    .panel-header {
                        padding: 16px;
                        border-bottom: 1px solid #eee;
                        user-select: none;
                        display: flex;
                        justify-content: space-between;
                        align-items: center;
                        cursor: move;
                    }
                    .panel-content {
                        padding: 16px;
                        overflow-y: auto;
                        overscroll-behavior: contain;
                        height: auto;
                        max-height: calc(90vh - 80px);
                    }
                    .resize-handle {
                        position: absolute;
                        bottom: 0;
                        right: 0;
                        width: 20px;
                        height: 20px;
                        cursor: nwse-resize;
                        background: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjAiIGhlaWdodD0iMjAiIHZpZXdCb3g9IjAgMCAyMCAyMCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTUgNUwxNSAxNSIgc3Ryb2tlPSIjOTk5OTk5IiBzdHJva2Utd2lkdGg9IjIiLz48cGF0aCBkPSJNNSAxNUwxNSAxNSIgc3Ryb2tlPSIjOTk5OTk5IiBzdHJva2Utd2lkdGg9IjIiLz48L3N2Zz4=') no-repeat center;
                    }
                    .minimize-btn, .scale-btn {
                        cursor: pointer;
                        padding: 0 8px;
                    }
                    .minimize-btn:hover, .scale-btn:hover {
                        color: #007bff;
                    }
                    .setting-group {
                        display: flex;
                        align-items: center;
                        padding: 10px 0;
                        gap: 10px;
                    }
                    .toggle-switch {
                        position: relative;
                        width: 40px;
                        height: 20px;
                        flex-shrink: 0;
                    }
                    .toggle-switch input {
                        opacity: 0;
                        width: 0;
                        height: 0;
                    }
                    .toggle-slider {
                        position: absolute;
                        top: 0;
                        left: 0;
                        right: 0;
                        bottom: 0;
                        background: #ccc;
                        border-radius: 10px;
                        cursor: pointer;
                        transition: background 0.3s;
                    }
                    .toggle-slider:before {
                        position: absolute;
                        content: "";
                        height: 16px;
                        width: 16px;
                        left: 2px;
                        top: 2px;
                        background: white;
                        border-radius: 50%;
                        transition: transform 0.3s;
                        box-shadow: 0 1px 2px rgba(0,0,0,0.2);
                    }
                    .toggle-switch input:checked + .toggle-slider {
                        background: #34c759;
                    }
                    .toggle-switch input:checked + .toggle-slider:before {
                        transform: translateX(20px);
                    }
                    .setting-label {
                        flex: 1;
                        font-size: 14px;
                        color: #333;
                    }
                    body.dark-mode .setting-label {
                        color: #ddd !important;
                    }
                    select {
                        padding: 4px;
                        border: 1px solid #ddd;
                        border-radius: 4px;
                    }
                    .divider {
                        height: 1px;
                        background: #eee;
                        margin: 16px 0;
                    }
                    .tool-grid {
                        display: grid;
                        grid-template-columns: repeat(2, 1fr);
                        gap: 8px;
                    }
                    .tool-card {
                        padding: 12px;
                        background: #f8f9fa;
                        border: 1px solid #eee;
                        border-radius: 8px;
                        cursor: pointer;
                        transition: all 0.2s;
                    }
                    .tool-card:hover {
                        transform: translateY(-2px);
                        box-shadow: 0 4px 12px rgba(0,0,0,0.1);
                    }
                    .metric-grid {
                        display: grid;
                        gap: 12px;
                    }
                    .progress-bar {
                        height: 4px;
                        background: #e9ecef;
                        border-radius: 2px;
                        overflow: hidden;
                    }
                    .progress-fill {
                        height: 100%;
                        background: #28a745;
                        width: 0%;
                        transition: width 0.3s ease;
                    }
                    .block-modal, .keyword-modal, .log-modal, .search-modal {
                        position: fixed;
                        top: 0;
                        left: 0;
                        right: 0;
                        bottom: 0;
                        background: rgba(0,0,0,0.5);
                        display: flex;
                        justify-content: center;
                        align-items: center;
                        z-index: 10000;
                        pointer-events: auto;
                    }
                    .modal-content {
                        background: white;
                        padding: 20px;
                        border-radius: 8px;
                        width: 400px;
                        max-height: 80vh;
                        overflow-y: auto;
                        pointer-events: auto;
                    }
                    .modal-content p {
                        color: #666;
                        margin: 5px 0 10px;
                        font-size: 12px;
                    }
                    textarea, input[type="text"] {
                        width: 100%;
                        margin: 10px 0;
                        padding: 8px;
                        border: 1px solid #ddd;
                        resize: vertical;
                    }
                    .modal-actions {
                        text-align: right;
                    }
                    .btn-cancel, .btn-save, .btn-block, .btn-undo, .btn-confirm, .btn-search {
                        padding: 6px 12px;
                        margin: 0 5px;
                        border: none;
                        border-radius: 4px;
                        cursor: pointer;
                        pointer-events: auto;
                    }
                    .btn-cancel {
                        background: #eee;
                    }
                    .btn-save, .btn-block, .btn-undo, .btn-confirm, .btn-search {
                        background: #34c759;
                        color: white;
                    }
                    .btn-block.active {
                        background: #ff4444;
                    }
                    .btn-undo {
                        background: #ff9800;
                    }
                    .hover-highlight {
                        outline: 2px solid #ff4444;
                        outline-offset: 2px;
                    }
                    .blocked-item {
                        display: flex;
                        justify-content: space-between;
                        align-items: center;
                        padding: 5px 0;
                        border-bottom: 1px solid #eee;
                    }
                    .blocked-item button {
                        padding: 4px 8px;
                        font-size: 12px;
                    }
                    .cursor-circle {
                        position: fixed;
                        width: 20px;
                        height: 20px;
                        background: rgba(128, 128, 128, 0.5);
                        border-radius: 50%;
                        pointer-events: none;
                        z-index: 10001;
                        transition: transform 0.2s ease;
                    }
                    .cursor-circle.confirm {
                        background: rgba(52, 199, 89, 0.8);
                        transform: scale(1.5);
                        transition: transform 0.3s ease, background 0.3s ease;
                    }
                    body.blocking-mode * {
                        cursor: none !important;
                    }
                    .performance-info {
                        display: none;
                    }
                    .highlight-match {
                        background-color: yellow;
                    }
                    .image-overlay {
                        position: fixed;
                        top: 0;
                        left: 0;
                        width: 100%;
                        height: 100%;
                        background: rgba(0,0,0,0.8);
                        z-index: 10000;
                        display: flex;
                        justify-content: center;
                        align-items: center;
                    }
                    .large-image {
                        max-width: 90%;
                        max-height: 90%;
                        cursor: move;
                    }
                    body.dark-mode,
                    body.dark-mode .wrap1,
                    body.dark-mode .l_container,
                    body.dark-mode .pb_content,
                    body.dark-mode .d_post_content,
                    body.dark-mode .left_section,
                    body.dark-mode .right_section {
                        background: #222 !important;
                        color: #ddd !important;
                    }
                    body.dark-mode #enhanced-panel {
                        background: rgba(50,50,50,0.98) !important;
                        color: #ddd !important;
                    }
                    body.dark-mode a {
                        color: #66b3ff !important;
                    }
                `);
                this.panel.innerHTML = `
                    <div class="panel-header"><span>贴吧增强控制台</span><div class="panel-controls"><span class="minimize-btn">—</span><span class="scale-btn" data-scale="0.8">缩小</span><span class="scale-btn" data-scale="1.0">还原</span></div></div>
                    <div class="panel-content"></div>
                    <div class="resize-handle"></div>
                `;
            } catch (e) {
                customConsole.error('Error in createPanel:', e);
            }
        }

        createMinimizedIcon() {
            customConsole.log('Creating minimized icon');
            try {
                this.minimizedIcon = document.createElement('div');
                this.minimizedIcon.id = 'minimized-icon';
                this.minimizedIcon.textContent = '⚙️';
                this.minimizedIcon.addEventListener('click', e => {
                    const now = Date.now();
                    if (now - this.lastClickTime > 300 && !this.dragOccurred) {
                        customConsole.log('Minimized icon clicked, toggling panel');
                        this.toggleMinimize();
                        this.lastClickTime = now;
                    }
                    this.dragOccurred = false;
                    e.stopPropagation();
                });
            } catch (e) {
                customConsole.error('Error in createMinimizedIcon:', e);
            }
        }

        loadContent() {
            customConsole.log('Loading panel content');
            try {
                this.panel.querySelector('.panel-content').innerHTML = `
                    <div class="filter-controls">
                        <h3>📊 智能过滤设置</h3>
                        <div class="setting-group">
                            <label class="toggle-switch">
                                <input type="checkbox" data-setting="debugMode" ${CONFIG.debugMode ? 'checked' : ''}>
                                <span class="toggle-slider"></span>
                            </label>
                            <span class="setting-label">启用调试模式</span>
                        </div>
                        <div class="setting-group"><label class="toggle-switch"><input type="checkbox" data-setting="hideInvalid" ${this.settings.hideInvalid ? 'checked' : ''}><span class="toggle-slider"></span></label><span class="setting-label">隐藏无效楼层</span></div>
                        <div class="setting-group"><label class="toggle-switch"><input type="checkbox" data-setting="hideSpam" ${this.settings.hideSpam ? 'checked' : ''}><span class="toggle-slider"></span></label><span class="setting-label">屏蔽水贴内容</span><button class="btn-config" data-action="editKeywords">✏️ 编辑关键词</button></div>
                        <div class="setting-group"><label class="toggle-switch"><input type="checkbox" data-setting="autoExpandImages" ${this.settings.autoExpandImages ? 'checked' : ''}><span class="toggle-slider"></span></label><span class="setting-label">自动展开图片</span></div>
                        <div class="setting-group">
                            <button class="btn-block" data-action="toggleBlockMode">🛡️ ${this.isBlockingMode ? '停止选择屏蔽' : '开始选择屏蔽元素'}</button>
                            <select data-setting="blockType">
                                <option value="perm" ${this.settings.blockType === 'perm' ? 'selected' : ''}>永久屏蔽</option>
                                <option value="temp" ${this.settings.blockType === 'temp' ? 'selected' : ''}>临时屏蔽</option>
                            </select>
                        </div>
                        <div class="setting-group"><button class="btn-undo" data-action="showUndoList">🔄 查看并撤回屏蔽</button></div>
                        <div class="setting-group"><label class="toggle-switch"><input type="checkbox" data-setting="blockAds" ${this.settings.blockAds ? 'checked' : ''}><span class="toggle-slider"></span></label><span class="setting-label">自动屏蔽广告</span></div>
                        <div class="setting-group"><label class="toggle-switch"><input type="checkbox" data-setting="enhanceImages" ${this.settings.enhanceImages ? 'checked' : ''}><span class="toggle-slider"></span></label><span class="setting-label">图片交互优化</span></div>
                        <div class="setting-group"><label class="toggle-switch"><input type="checkbox" data-setting="linkifyVideos" ${this.settings.linkifyVideos ? 'checked' : ''}><span class="toggle-slider"></span></label><span class="setting-label">视频链接跳转</span></div>
                        <div class="setting-group"><label class="toggle-switch"><input type="checkbox" data-setting="darkMode" ${this.settings.darkMode ? 'checked' : ''}><span class="toggle-slider"></span></label><span class="setting-label">黑夜模式</span></div>
                        <div class="setting-group"><label class="toggle-switch"><input type="checkbox" data-setting="showHiddenFloors" ${this.settings.showHiddenFloors ? 'checked' : ''}><span class="toggle-slider"></span></label><span class="setting-label">显示隐藏楼层</span></div>
                    </div>
                    <div class="divider"></div>
                    <div class="advanced-tools">
                        <h3>⚙️ 高级工具</h3>
                        <div class="tool-grid">
                            <button class="tool-card" data-action="exportSettings"><div class="icon">📤</div><span>导出配置</span></button>
                            <button class="tool-card" data-action="importSettings"><div class="icon">📥</div><span>导入配置</span></button>
                            <button class="tool-card" data-action="performanceChart"><div class="icon">📈</div><span>性能图表</span></button>
                            <button class="tool-card" data-action="quickSearch"><div class="icon">🔍</div><span>快速检索</span></button>
                            <button class="tool-card" data-action="saveLogs"><div class="icon">💾</div><span>保存日志</span></button>
                        </div>
                    </div>
                    <div class="divider"></div>
                    <div class="performance-info">
                        <h3>💻 系统监控</h3>
                        <div class="metric-grid">
                            <div class="metric-item"><span class="metric-label">内存占用</span><span class="metric-value" id="mem-usage">0 MB</span><div class="progress-bar"><div class="progress-fill" id="mem-progress"></div></div></div>
                            <div class="metric-item"><span class="metric-label">处理速度</span><span class="metric-value" id="process-speed">0 ms</span><div class="sparkline" id="speed-chart"></div></div>
                        </div>
                    </div>
                `;
                this.bindEvents();
                setTimeout(() => this.adjustPanelHeight(), 50);
            } catch (e) {
                customConsole.error('Error in loadContent:', e);
            }
        }

        adjustPanelHeight() {
            try {
                if (this.panelSettings.minimized) return;
                const content = this.panel.querySelector('.panel-content');
                const headerHeight = this.panel.querySelector('.panel-header').offsetHeight;
                const maxHeight = Math.min(content.scrollHeight + headerHeight + 32, window.innerHeight * 0.9);
                this.panel.style.height = `${maxHeight}px`;
                customConsole.log('Adjusted panel height:', maxHeight);
            } catch (e) {
                customConsole.error('Error in adjustPanelHeight:', e);
            }
        }

        bindEvents() {
            customConsole.log('Binding events');
            try {
                this.panel.querySelectorAll('input[type="checkbox"]').forEach(checkbox => {
                    checkbox.addEventListener('change', () => {
                        if (checkbox.dataset.setting === 'debugMode') {
                            CONFIG.debugMode = checkbox.checked;
                            GM_setValue('debugMode', CONFIG.debugMode);
                        } else if (checkbox.dataset.setting === 'darkMode') {
                            this.settings.darkMode = checkbox.checked;
                            GM_setValue('settings', this.settings);
                            this.applyDarkMode(checkbox.checked);
                        } else {
                            this.settings[checkbox.dataset.setting] = checkbox.checked;
                            GM_setValue('settings', this.settings);
                            this.postFilter.updateFilters();
                        }
                        logWrapper('userActions', 'LOG', `Toggled ${checkbox.dataset.setting} to ${checkbox.checked}`);
                        this.adjustPanelHeight();
                    });
                });

                this.panel.querySelector('[data-setting="blockType"]').addEventListener('change', (e) => {
                    this.settings.blockType = e.target.value;
                    GM_setValue('settings', this.settings);
                    logWrapper('userActions', 'LOG', `Set block type to ${this.settings.blockType}`);
                });

                const actions = {
                    editKeywords: () => this.showKeywordEditor(),
                    toggleBlockMode: () => this.toggleBlockMode(),
                    showUndoList: () => this.showUndoList(),
                    exportSettings: () => this.exportConfig(),
                    importSettings: () => this.importConfig(),
                    performanceChart: () => {
                        const perfInfo = this.panel.querySelector('.performance-info');
                        perfInfo.style.display = perfInfo.style.display === 'block' ? 'none' : 'block';
                        logWrapper('userActions', 'LOG', `Toggled performance chart: ${perfInfo.style.display}`);
                        this.adjustPanelHeight();
                        customConsole.log('Toggling performance chart');
                    },
                    quickSearch: () => this.toggleSearch(),
                    saveLogs: () => this.showLogSaveDialog()
                };

                this.panel.querySelectorAll('[data-action]').forEach(btn => {
                    btn.addEventListener('click', () => {
                        actions[btn.dataset.action]();
                        logWrapper('userActions', 'LOG', `Clicked button: ${btn.dataset.action}`);
                    });
                });

                this.panel.querySelector('.minimize-btn').addEventListener('click', e => {
                    this.toggleMinimize();
                    logWrapper('userActions', 'LOG', 'Clicked minimize button');
                    e.stopPropagation();
                });
            } catch (e) {
                customConsole.error('Error in bindEvents:', e);
            }
        }

        setupPanelInteractions() {
            customConsole.log('Setting up panel interactions');
            try {
                const header = this.panel.querySelector('.panel-header');
                const resizeHandle = this.panel.querySelector('.resize-handle');
                let startX, startY, startWidth, startHeight;

                const onDragStart = (e, target) => {
                    this.isDragging = true;
                    this.dragOccurred = false;
                    startX = e.clientX - this.panelSettings.position.x;
                    startY = e.clientY - this.panelSettings.position.y;
                    e.preventDefault();
                };

                const onDragMove = (e) => {
                    if (this.isDragging) {
                        this.dragOccurred = true;
                        const panelWidth = this.panel.offsetWidth;
                        const panelHeight = this.panel.offsetHeight;
                        this.panelSettings.position.x = Math.max(0, Math.min(e.clientX - startX, window.innerWidth - panelWidth));
                        this.panelSettings.position.y = Math.max(0, Math.min(e.clientY - startY, window.innerHeight - panelHeight));
                        const target = this.panelSettings.minimized ? this.minimizedIcon : this.panel;
                        target.style.left = `${this.panelSettings.position.x}px`;
                        target.style.top = `${this.panelSettings.position.y}px`;
                        logWrapper('userActions', 'LOG', `Dragged ${this.panelSettings.minimized ? 'minimized icon' : 'panel'} to (${this.panelSettings.position.x}, ${this.panelSettings.position.y})`);
                    }
                    if (this.isResizing) {
                        const newWidth = startWidth + (e.clientX - startX);
                        const newHeight = startHeight + (e.clientY - startY);
                        this.panelSettings.width = Math.max(200, newWidth);
                        this.panel.style.width = `${this.panelSettings.width}px`;
                        this.panel.style.height = `${Math.max(200, newHeight)}px`;
                        logWrapper('userActions', 'LOG', `Resized panel to ${this.panelSettings.width}x${Math.max(200, newHeight)}`);
                    }
                };

                const onDragEnd = () => {
                    if (this.isDragging || this.isResizing) {
                        GM_setValue('panelSettings', this.panelSettings);
                        this.isDragging = false;
                        this.isResizing = false;
                        this.adjustPanelHeight();
                        setTimeout(() => { this.dragOccurred = false; }, 100);
                        customConsole.log('Drag or resize ended');
                    }
                };

                header.addEventListener('mousedown', e => onDragStart(e, this.panel));
                this.minimizedIcon.addEventListener('mousedown', e => onDragStart(e, this.minimizedIcon));
                document.addEventListener('mousemove', onDragMove);
                document.addEventListener('mouseup', onDragEnd);

                resizeHandle.addEventListener('mousedown', e => {
                    this.isResizing = true;
                    startX = e.clientX;
                    startY = e.clientY;
                    startWidth = this.panelSettings.width;
                    startHeight = parseInt(this.panel.style.height) || this.panel.offsetHeight;
                    e.preventDefault();
                });

                this.panel.querySelectorAll('.scale-btn').forEach(btn => {
                    btn.addEventListener('click', e => {
                        this.panelSettings.scale = parseFloat(btn.dataset.scale);
                        this.panel.style.transform = `scale(${this.panelSettings.scale})`;
                        GM_setValue('panelSettings', this.panelSettings);
                        this.ensureVisibility();
                        this.adjustPanelHeight();
                        logWrapper('userActions', 'LOG', `Scaled panel to ${this.panelSettings.scale}`);
                        e.stopPropagation();
                    });
                });
            } catch (e) {
                customConsole.error('Error in setupPanelInteractions:', e);
            }
        }

        setupUserActionListeners() {
            try {
                document.addEventListener('click', e => {
                    if (!this.panel.contains(e.target) && !this.minimizedIcon.contains(e.target)) {
                        logWrapper('userActions', 'LOG', `Clicked on page at (${e.clientX}, ${e.clientY}), Target: ${e.target.tagName}.${e.target.className || ''}`);
                    }
                });

                document.addEventListener('input', e => {
                    logWrapper('userActions', 'LOG', `Input in ${e.target.tagName}, Value: ${e.target.value}`);
                });

                document.addEventListener('scroll', _.debounce(() => {
                    logWrapper('userActions', 'LOG', `Scrolled to (${window.scrollX}, ${window.scrollY})`);
                }, 200));
            } catch (e) {
                customConsole.error('Error in setupUserActionListeners:', e);
            }
        }

        startPerformanceMonitoring() {
            const perfMonitor = PerformanceMonitor.getInstance();
            const updatePerformance = () => {
                perfMonitor.recordMemory();
                perfMonitor.recordNetwork();
                const memUsage = perfMonitor.metrics.memoryUsage.length > 0 ? Math.round(_.mean(perfMonitor.metrics.memoryUsage) / 1024 / 1024) : 0;
                const processSpeed = perfMonitor.metrics.processSpeed.length > 0 ? _.mean(perfMonitor.metrics.processSpeed).toFixed(2) : 0;
                const memElement = document.getElementById('mem-usage');
                const progElement = document.getElementById('mem-progress');
                const speedElement = document.getElementById('process-speed');
                if (memElement && progElement) {
                    memElement.textContent = `${memUsage} MB`;
                    progElement.style.width = `${Math.min(memUsage / 100 * 100, 100)}%`;
                }
                if (speedElement) {
                    speedElement.textContent = `${processSpeed} ms`;
                }
                requestAnimationFrame(updatePerformance);
            };
            requestAnimationFrame(updatePerformance);
        }

        toggleMinimize() {
            try {
                customConsole.log('Toggling minimize, current state:', this.panelSettings.minimized);
                if (this.panelSettings.minimized) {
                    this.restorePanel();
                } else {
                    this.minimizePanel();
                }
                GM_setValue('panelSettings', this.panelSettings);
                this.ensureVisibility();
                customConsole.log('Toggle minimize completed, minimized:', this.panelSettings.minimized);
            } catch (e) {
                customConsole.error('Error in toggleMinimize:', e);
            }
        }

        minimizePanel() {
            try {
                this.panel.style.display = 'none';
                this.minimizedIcon.style.display = 'block';
                this.minimizedIcon.style.left = `${this.panelSettings.position.x}px`;
                this.minimizedIcon.style.top = `${this.panelSettings.position.y}px`;
                this.panelSettings.minimized = true;
                customConsole.log('Minimized panel');
            } catch (e) {
                customConsole.error('Error in minimizePanel:', e);
            }
        }

        restorePanel() {
            try {
                this.panel.style.display = 'block';
                this.minimizedIcon.style.display = 'none';
                this.panel.style.left = `${this.panelSettings.position.x}px`;
                this.panel.style.top = `${this.panelSettings.position.y}px`;
                this.panel.style.transform = `scale(${this.panelSettings.scale})`;
                this.panelSettings.minimized = false;
                this.adjustPanelHeight();
                customConsole.log('Restored panel');
            } catch (e) {
                customConsole.error('Error in restorePanel:', e);
            }
        }

        toggleBlockMode(event) {
            try {
                this.isBlockingMode = !this.isBlockingMode;
                const blockBtn = this.panel.querySelector('.btn-block');
                blockBtn.textContent = `🛡️ ${this.isBlockingMode ? '停止选择屏蔽' : '开始选择屏蔽元素'}`;
                blockBtn.classList.toggle('active', this.isBlockingMode);

                if (this.isBlockingMode) {
                    document.body.classList.add('blocking-mode');
                    this.createCursorCircle();
                    this.listeners = {
                        move: this.moveCursorCircle.bind(this),
                        click: this.handleBlockClick.bind(this)
                    };
                    document.addEventListener('mousemove', this.listeners.move);
                    document.addEventListener('click', this.listeners.click);
                } else {
                    document.body.classList.remove('blocking-mode');
                    this.removeCursorCircle();
                    if (this.listeners) {
                        document.removeEventListener('mousemove', this.listeners.move);
                        document.removeEventListener('click', this.listeners.click);
                        this.listeners = null;
                    }
                    this.removeHighlight();
                    this.selectedTarget = null;
                }
                customConsole.log('Block mode:', this.isBlockingMode);
                if (event) event.stopPropagation();
                this.adjustPanelHeight();
            } catch (e) {
                customConsole.error('Error in toggleBlockMode:', e);
            }
        }

        createCursorCircle() {
            try {
                this.cursorCircle = document.createElement('div');
                this.cursorCircle.className = 'cursor-circle';
                document.body.appendChild(this.cursorCircle);
            } catch (e) {
                customConsole.error('Error in createCursorCircle:', e);
            }
        }

        moveCursorCircle(event) {
            if (!this.isBlockingMode || !this.cursorCircle) return;
            try {
                this.cursorCircle.style.left = `${event.clientX - 10}px`;
                this.cursorCircle.style.top = `${event.clientY - 10}px`;
                this.highlightElement(event);
            } catch (e) {
                customConsole.error('Error in moveCursorCircle:', e);
            }
        }

        removeCursorCircle() {
            try {
                if (this.cursorCircle && document.body.contains(this.cursorCircle)) {
                    document.body.removeChild(this.cursorCircle);
                }
                this.cursorCircle = null;
            } catch (e) {
                customConsole.error('Error in removeCursorCircle:', e);
            }
        }

        highlightElement(event) {
            if (!this.isBlockingMode) return;
            try {
                this.removeHighlight();
                const target = event.target;
                if (target === this.panel || this.panel.contains(target) ||
                    target.classList.contains('block-modal') || target.closest('.block-modal')) return;
                target.classList.add('hover-highlight');
                customConsole.log('Highlighting:', target.tagName + '.' + (target.className || ''));
            } catch (e) {
                customConsole.error('Error in highlightElement:', e);
            }
        }

        removeHighlight() {
            try {
                const highlighted = document.querySelector('.hover-highlight');
                if (highlighted) highlighted.classList.remove('hover-highlight');
            } catch (e) {
                customConsole.error('Error in removeHighlight:', e);
            }
        }

        handleBlockClick(event) {
            if (!this.isBlockingMode) return;
            try {
                event.preventDefault();
                event.stopPropagation();
                const target = event.target;
                if (target === this.panel || this.panel.contains(target) ||
                    target.classList.contains('block-modal') || target.closest('.block-modal')) return;
                this.selectedTarget = target;
                this.showConfirmDialog(event.clientX, event.clientY);
            } catch (e) {
                customConsole.error('Error in handleBlockClick:', e);
            }
        }

        showConfirmDialog(x, y) {
            try {
                const modal = document.createElement('div');
                modal.className = 'block-modal';
                modal.innerHTML = `
                    <div class="modal-content">
                        <h3>确认屏蔽</h3>
                        <p>确定要屏蔽此元素吗?当前模式:${this.settings.blockType === 'temp' ? '临时' : '永久'}</p>
                        <div class="modal-actions">
                            <button class="btn-cancel">取消</button>
                            <button class="btn-confirm">确定</button>
                        </div>
                    </div>
                `;
                const confirmBtn = modal.querySelector('.btn-confirm');
                const cancelBtn = modal.querySelector('.btn-cancel');
                confirmBtn.addEventListener('click', e => {
                    e.stopPropagation();
                    if (this.selectedTarget) this.blockElement(this.selectedTarget, x, y);
                    document.body.removeChild(modal);
                    logWrapper('userActions', 'LOG', 'Confirmed block element');
                }, { once: true });
                cancelBtn.addEventListener('click', e => {
                    e.stopPropagation();
                    document.body.removeChild(modal);
                    this.toggleBlockMode();
                    logWrapper('userActions', 'LOG', 'Canceled block element');
                }, { once: true });
                document.body.appendChild(modal);
            } catch (e) {
                customConsole.error('Error in showConfirmDialog:', e);
            }
        }

        blockElement(target, x, y) {
            try {
                const selector = this.getUniqueSelector(target);
                const blockList = this.settings.blockType === 'temp' ? this.settings.tempBlockedElements : this.settings.blockedElements;
                if (!blockList.includes(selector)) {
                    blockList.push(selector);
                    GM_setValue('settings', this.settings);
                    this.postFilter.updateFilters();
                    customConsole.log(`Blocked element (${this.settings.blockType}) with selector:`, selector);
                    logWrapper('userActions', 'LOG', `Blocked element (${this.settings.blockType}): ${selector}`);
                }
                target.classList.add('spam-hidden');
                target.style.display = 'none';
                if (this.cursorCircle) {
                    this.cursorCircle.style.left = `${x - 10}px`;
                    this.cursorCircle.style.top = `${y - 10}px`;
                    this.cursorCircle.classList.add('confirm');
                    setTimeout(() => {
                        this.cursorCircle.classList.remove('confirm');
                        this.toggleBlockMode();
                    }, 300);
                } else {
                    this.toggleBlockMode();
                }
                this.adjustPanelHeight();
            } catch (e) {
                customConsole.error('Error in blockElement:', e);
            }
        }

        getUniqueSelector(element) {
            try {
                if (element.id) return `#${element.id}`;
                const path = [];
                let current = element;
                while (current && current.nodeType === Node.ELEMENT_NODE && current !== document.body) {
                    let selector = current.tagName.toLowerCase();
                    if (current.className) selector += `.${current.className.trim().split(/\s+/).join('.')}`;
                    const siblings = Array.from(current.parentNode.children).filter(child => child.tagName === current.tagName);
                    if (siblings.length > 1) selector += `:nth-child(${siblings.indexOf(current) + 1})`;
                    path.unshift(selector);
                    current = current.parentNode;
                }
                return path.join(' > ');
            } catch (e) {
                customConsole.error('Error in getUniqueSelector:', e);
                return '';
            }
        }

        showKeywordEditor() {
            customConsole.log('Showing keyword editor');
            try {
                const modal = document.createElement('div');
                modal.className = 'keyword-modal';
                modal.innerHTML = `
                    <div class="modal-content">
                        <h3>关键词管理</h3>
                        <textarea>${this.settings.spamKeywords.join('\n')}</textarea>
                        <div class="modal-actions">
                            <button class="btn-cancel">取消</button>
                            <button class="btn-save">保存</button>
                        </div>
                    </div>
                `;
                modal.querySelector('.btn-save').addEventListener('click', () => {
                    this.settings.spamKeywords = modal.querySelector('textarea').value.split('\n').map(k => k.trim()).filter(k => k.length > 0);
                    GM_setValue('settings', this.settings);
                    this.postFilter.updateFilters();
                    document.body.removeChild(modal);
                    logWrapper('userActions', 'LOG', `Updated spam keywords: ${this.settings.spamKeywords.join(', ')}`);
                    this.adjustPanelHeight();
                });
                modal.querySelector('.btn-cancel').addEventListener('click', () => {
                    document.body.removeChild(modal);
                    logWrapper('userActions', 'LOG', 'Canceled keyword editor');
                });
                document.body.appendChild(modal);
            } catch (e) {
                customConsole.error('Error in showKeywordEditor:', e);
            }
        }

        showUndoList() {
            customConsole.log('Showing undo list');
            try {
                const modal = document.createElement('div');
                modal.className = 'block-modal';
                const permItems = this.settings.blockedElements.length > 0 ?
                    this.settings.blockedElements.map((sel, i) => `
                        <div class="blocked-item">
                            <span>[永久] ${sel}</span>
                            <button class="btn-undo" data-index="${i}" data-type="perm">撤销</button>
                        </div>
                    `).join('') : '';
                const tempItems = this.settings.tempBlockedElements.length > 0 ?
                    this.settings.tempBlockedElements.map((sel, i) => `
                        <div class="blocked-item">
                            <span>[临时] ${sel}</span>
                            <button class="btn-undo" data-index="${i}" data-type="temp">撤销</button>
                        </div>
                    `).join('') : '';
                const listItems = permItems + tempItems || '<p>暂无屏蔽元素</p>';
                modal.innerHTML = `
                    <div class="modal-content">
                        <h3>屏蔽元素列表</h3>
                        <p>点击“撤销”恢复显示对应元素</p>
                        ${listItems}
                        <div class="modal-actions">
                            <button class="btn-cancel">关闭</button>
                        </div>
                    </div>
                `;
                modal.querySelectorAll('.btn-undo').forEach(btn => {
                    btn.addEventListener('click', () => {
                        const index = parseInt(btn.dataset.index);
                        const type = btn.dataset.type;
                        this.undoBlockElement(index, type);
                        document.body.removeChild(modal);
                        this.showUndoList();
                        logWrapper('userActions', 'LOG', `Undid block (${type}) at index ${index}`);
                    });
                });
                modal.querySelector('.btn-cancel').addEventListener('click', () => {
                    document.body.removeChild(modal);
                    logWrapper('userActions', 'LOG', 'Closed undo list');
                });
                document.body.appendChild(modal);
            } catch (e) {
                customConsole.error('Error in showUndoList:', e);
            }
        }

        undoBlockElement(index, type) {
            try {
                const blockList = type === 'temp' ? this.settings.tempBlockedElements : this.settings.blockedElements;
                if (index < 0 || index >= blockList.length) {
                    customConsole.warn('Invalid undo index:', index);
                    return;
                }
                const selector = blockList[index];
                blockList.splice(index, 1);
                GM_setValue('settings', this.settings);
                this.postFilter.updateFilters();
                document.querySelectorAll(selector).forEach(el => el.classList.remove('spam-hidden'));
                customConsole.log(`Undid block (${type}) for selector:`, selector);
                this.adjustPanelHeight();
            } catch (e) {
                customConsole.error('Error in undoBlockElement:', e);
            }
        }

        exportConfig() {
            customConsole.log('Exporting config');
            try {
                const config = {
                    filter: this.settings,
                    panel: this.panelSettings
                };
                const configJson = JSON.stringify(config, null, 2);
                const blob = new Blob([configJson], { type: 'application/json;charset=utf-8' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = `tieba_enhance_config_${new Date().toISOString().replace(/[:.]/g, '-')}.json`;
                document.body.appendChild(a);
                a.click();
                document.body.removeChild(a);
                URL.revokeObjectURL(url);
                logWrapper('userActions', 'LOG', 'Exported configuration');
            } catch (e) {
                customConsole.error('Error in exportConfig:', e);
            }
        }

        importConfig() {
            customConsole.log('Importing config');
            try {
                const modal = document.createElement('div');
                modal.className = 'keyword-modal';
                modal.innerHTML = `
                    <div class="modal-content">
                        <h3>导入配置</h3>
                        <p>请选择配置文件(JSON格式)</p>
                        <input type="file" accept=".json" id="configFileInput" />
                        <div class="modal-actions">
                            <button class="btn-cancel">取消</button>
                            <button class="btn-save">导入</button>
                        </div>
                    </div>
                `;
                const fileInput = modal.querySelector('#configFileInput');
                modal.querySelector('.btn-save').addEventListener('click', () => {
                    const file = fileInput.files[0];
                    if (file) {
                        const reader = new FileReader();
                        reader.onload = (e) => {
                            try {
                                const importedConfig = JSON.parse(e.target.result);
                                this.settings = { ...CONFIG.defaultSettings.filter, ...importedConfig.filter };
                                this.panelSettings = { ...CONFIG.defaultSettings.panel, ...importedConfig.panel };
                                GM_setValue('settings', this.settings);
                                GM_setValue('panelSettings', this.panelSettings);
                                this.postFilter.updateFilters();
                                this.loadContent();
                                if (this.panelSettings.minimized) {
                                    this.minimizePanel();
                                } else {
                                    this.restorePanel();
                                }
                                this.applyDarkMode(this.settings.darkMode);
                                logWrapper('userActions', 'LOG', 'Imported configuration');
                            } catch (err) {
                                customConsole.error('Invalid config file:', err);
                                alert('配置文件无效,请检查格式');
                            }
                            document.body.removeChild(modal);
                        };
                        reader.readAsText(file);
                    } else {
                        alert('请选择一个配置文件');
                    }
                });
                modal.querySelector('.btn-cancel').addEventListener('click', () => {
                    document.body.removeChild(modal);
                    logWrapper('userActions', 'LOG', 'Canceled config import');
                });
                document.body.appendChild(modal);
            } catch (e) {
                customConsole.error('Error in importConfig:', e);
            }
        }

        toggleSearch() {
            customConsole.log('Toggling quick search');
            try {
                const modal = document.createElement('div');
                modal.className = 'search-modal';
                modal.innerHTML = `
                    <div class="modal-content">
                        <h3>快速检索</h3>
                        <p>输入关键词搜索帖子内容(支持正则表达式)</p>
                        <input type="text" id="searchInput" placeholder="请输入关键词" />
                        <div class="modal-actions">
                            <button class="btn-cancel">关闭</button>
                            <button class="btn-search">搜索</button>
                        </div>
                    </div>
                `;
                const searchInput = modal.querySelector('#searchInput');
                modal.querySelector('.btn-search').addEventListener('click', () => {
                    const keyword = searchInput.value.trim();
                    if (keyword) {
                        this.performSearch(keyword);
                        logWrapper('userActions', 'LOG', `Searched for: ${keyword}`);
                    }
                });
                modal.querySelector('.btn-cancel').addEventListener('click', () => {
                    document.body.removeChild(modal);
                    logWrapper('userActions', 'LOG', 'Closed quick search');
                });
                document.body.appendChild(modal);
                searchInput.focus();
            } catch (e) {
                customConsole.error('Error in toggleSearch:', e);
            }
        }

        performSearch(keyword) {
            try {
                document.querySelectorAll('.highlight-match').forEach(el => {
                    el.classList.remove('highlight-match');
                    el.replaceWith(el.textContent);
                });
                const posts = document.querySelectorAll('.d_post_content');
                let regex;
                try {
                    regex = new RegExp(keyword, 'gi');
                } catch (e) {
                    regex = new RegExp(keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'gi');
                }
                posts.forEach(post => {
                    if (regex.test(post.textContent)) {
                        post.innerHTML = post.innerHTML.replace(regex, match => `<span class="highlight-match">${match}</span>`);
                        post.scrollIntoView({ behavior: 'smooth', block: 'center' });
                    }
                });
            } catch (e) {
                customConsole.error('Error in performSearch:', e);
            }
        }

        showLogSaveDialog() {
            customConsole.log('Showing log save dialog');
            try {
                const modal = document.createElement('div');
                modal.className = 'log-modal';
                modal.innerHTML = `
                    <div class="modal-content">
                        <h3>保存日志</h3>
                        <p>点击“保存”将日志导出为文件(当前最多 ${MAX_LOG_ENTRIES} 条/分类)</p>
                        <div class="modal-actions">
                            <button class="btn-cancel">取消</button>
                            <button class="btn-save">保存</button>
                        </div>
                    </div>
                `;
                modal.querySelector('.btn-save').addEventListener('click', () => {
                    try {
                        customConsole.log('Preparing log content');
                        const fullLog = [
                            '=== 脚本运行日志 ===',
                            ...logBuffer.script,
                            '\n=== 网页运行状态 ===',
                            ...logBuffer.pageState,
                            '\n=== 网页行为 ===',
                            ...logBuffer.pageBehavior,
                            '\n=== 用户操作 ===',
                            ...logBuffer.userActions
                        ].join('\n');

                        customConsole.log('Creating Blob');
                        const blob = new Blob([fullLog], { type: 'text/plain;charset=utf-8' });

                        customConsole.log('Generating download URL');
                        const url = URL.createObjectURL(blob);

                        customConsole.log('Initiating download');
                        const a = document.createElement('a');
                        a.href = url;
                        a.download = CONFIG.defaultSettings.logPath;
                        document.body.appendChild(a);
                        a.click();
                        document.body.removeChild(a);
                        URL.revokeObjectURL(url);

                        customConsole.log('Log file download completed');
                        document.body.removeChild(modal);
                        logWrapper('userActions', 'LOG', 'Saved logs to file');
                    } catch (e) {
                        customConsole.error('Error saving logs:', e);
                        alert('保存日志失败,请检查控制台错误信息');
                    }
                });
                modal.querySelector('.btn-cancel').addEventListener('click', () => {
                    document.body.removeChild(modal);
                    logWrapper('userActions', 'LOG', 'Canceled log save');
                });
                document.body.appendChild(modal);
                this.adjustPanelHeight();
            } catch (e) {
                customConsole.error('Error in showLogSaveDialog:', e);
                alert('打开日志保存对话框失败');
            }
        }

        setupCleanup() {
            try {
                window.addEventListener('beforeunload', () => {
                    this.panel.remove();
                    this.minimizedIcon.remove();
                    this.observer?.disconnect();
                    if (this.listeners) {
                        document.removeEventListener('mousemove', this.listeners.move);
                        document.removeEventListener('click', this.listeners.click);
                    }
                    customConsole.log('Cleaned up resources');
                });
            } catch (e) {
                customConsole.error('Error in setupCleanup:', e);
            }
        }

        applyDarkMode(enable) {
            customConsole.log('Applying dark mode:', enable);
            try {
                if (enable) {
                    document.body.classList.add('dark-mode');
                } else {
                    document.body.classList.remove('dark-mode');
                }
                logWrapper('pageBehavior', 'LOG', `Applying dark mode: ${enable}`);
            } catch (e) {
                customConsole.error('Error in applyDarkMode:', e);
            }
        }
    }

    document.addEventListener('DOMContentLoaded', () => {
        if (!checkAuthenticity()) return; // 防伪校验
        if (GM_getValue('authToken') !== SCRIPT_AUTH_TOKEN) {
            alert('脚本验证失败,请重新安装正版脚本!');
            return;
        }
        customConsole.log('DOM content loaded, initializing');
        const perfMonitor = PerformanceMonitor.getInstance();
        new DynamicPanel();
        perfMonitor.recordPageTiming();
    });

    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        setTimeout(() => {
            if (!checkAuthenticity()) return; // 防伪校验
            if (!document.getElementById('enhanced-panel') && !document.getElementById('minimized-icon')) {
                customConsole.log('Fallback initialization');
                const perfMonitor = PerformanceMonitor.getInstance();
                new DynamicPanel();
            }
        }, 50);
    }
})();