Greasy Fork 支持简体中文。

百度贴吧终极增强套件Pro

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

// ==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);
    }
})();