社区助手1.0.9

论坛增强功能:AI内容总结、新标签页打开、用户屏蔽、快速预览、自定义CSS等

// ==UserScript==
// @name         社区助手1.0.9
// @namespace    https://boyshelpboys.com/
// @version      1.0.9
// @description  论坛增强功能:AI内容总结、新标签页打开、用户屏蔽、快速预览、自定义CSS等
// @author       全民制作人
// @match        https://*.boyshelpboys.com/*
// @icon         https://boyshelpboys.com/upload/attach/202410/b.svg
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_xmlhttpRequest
// @grant        GM_notification
// @connect      api.siliconflow.cn
// @connect      boyshelpboys.com
// @license      MIT
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';
    
    // 配置
    const CONFIG = {
        apiUrl: 'https://api.siliconflow.cn/v1/chat/completions',
        defaultApiKey: 'sk-jantscvokoclrasijsgfdxuujcbikpebkzosubcjwmjteebu',
        defaultModel: 'THUDM/glm-4-9b-chat',
        checkInterval: 60000,    // 通知检查间隔 (1分钟)
        maxSavedIds: 100,        // 最大保存的帖子ID数量
        maxNotifications: 3,     // 最大同时显示的通知数
        notificationTimeout: 20000 // 通知自动消失时间 (20秒)
    };
    
    // 初始化 CSS
    GM_addStyle(`
        .blocked-post{display:none!important}
        #bhb-panel{position:fixed;right:20px;top:20px;background:#1a1a1a;border:1px solid #333;border-radius:4px;padding:8px;z-index:9999;box-shadow:0 2px 8px rgba(0,0,0,.3);transition:.3s;width:280px;color:#ccc;font-size:12px}
        #bhb-panel.mini{width:24px;height:24px;min-width:24px;padding:0;overflow:hidden;cursor:pointer}
        #bhb-panel.mini #bhb-content{display:none}
        #bhb-panel-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;padding-bottom:4px;border-bottom:1px solid #333}
        .bhb-section{margin-bottom:10px}
        .bhb-section-title{color:#888;font-size:11px;margin-bottom:6px;padding-left:2px}
        .bhb-options-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:6px;margin-bottom:6px}
        .bhb-option{position:relative}
        .bhb-option-content{display:flex;align-items:center;justify-content:space-between;gap:8px}
        .bhb-label{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
        .bhb-checkbox-label{display:flex;align-items:center;gap:4px}
        .bhb-checkbox{margin:0;transform:scale(.9)}
        .bhb-input-section{display:grid;grid-template-columns:repeat(2,1fr);gap:6px}
        .bhb-input-area{display:none;margin-top:8px;background:#1a1a1a;border:1px solid #333;border-radius:4px;padding:8px}
        .bhb-input-area.active{display:block}
        .bhb-textarea{width:100%;height:100px;background:#222;border:1px solid #333;border-radius:2px;color:#ccc;padding:4px;font-size:12px;resize:vertical;margin-bottom:4px}
        .bhb-btn{background:#222;color:#ccc;border:1px solid #333;padding:0 8px;border-radius:2px;cursor:pointer;font-size:12px;text-align:center;white-space:nowrap;line-height:20px;height:20px;display:inline-flex;align-items:center;justify-content:center;width:100%}
        .bhb-btn:hover{background:#2a2a2a;color:#fff}
        .ai-summary-btn{background:#222;color:#ccc;border:1px solid #333;padding:4px 12px;border-radius:12px;cursor:pointer;margin:6px auto;font-size:12px;display:block;transition:all .2s ease}
        .ai-summary-btn:hover{background:#2a2a2a;color:#fff}
        .ai-summary{background:#1a1a1a;border:1px solid #333;border-radius:4px;padding:12px;margin:8px 0;color:#ccc;line-height:1.6;white-space:pre-line}
        .ai-loading{color:#888;text-align:center;padding:8px}
        .ai-summary.hide{display:none}
        #bhb-toggle{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700;color:#ccc;cursor:pointer}
        #bhb-toggle:hover{background:#222}
        #bhb-help-area{position:relative;width:100%;box-sizing:border-box;border-top:1px solid #333;margin-top:8px;z-index:9000}
        .bhb-help-content{max-height:120px;overflow-y:auto}
        #bhb-panel.mini #bhb-toggle{display:flex}
        .bhb-tip{font-size:10px;color:#666;margin-top:2px}
        .auto-pagination-loader{position:fixed;bottom:20px;left:50%;transform:translateX(-50%);background:#1a1a1a;color:#ccc;padding:5px 10px;border-radius:4px;font-size:12px;z-index:999;opacity:0;transition:opacity 0.3s ease;}
        .auto-pagination-loader.show{opacity:1;}
        .bhb-page-marker{text-align:center;width:100%;display:block;padding:5px 0;color:#888;font-size:12px;}
        
        /* 快速预览样式 - 左侧固定 */
        .bhb-preview-container{position:fixed;z-index:10000;width:300px;left:0;top:0;bottom:0;background:#1a1a1a;border-right:1px solid #333;box-shadow:2px 0 10px rgba(0,0,0,.3);padding:0;overflow:hidden;opacity:0;visibility:hidden;transition:all .3s ease;transform:translateX(-100%)}
        .bhb-preview-container.show{opacity:1;visibility:visible;transform:translateX(0)}
        .bhb-preview-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;background:#222;border-bottom:1px solid #333}
        .bhb-preview-title{font-size:14px;font-weight:bold;color:#fff;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex:1}
        .bhb-preview-info{font-size:12px;color:#888;margin-left:10px}
        .bhb-preview-content{padding:12px;overflow-y:auto;color:#ccc;line-height:1.5;font-size:13px;position:absolute;top:40px;bottom:40px;left:0;right:0;scrollbar-width:thin;scrollbar-color:#444 #222}
        .bhb-preview-content::-webkit-scrollbar{width:6px;height:6px}
        .bhb-preview-content::-webkit-scrollbar-track{background:#222}
        .bhb-preview-content::-webkit-scrollbar-thumb{background:#444;border-radius:3px}
        .bhb-preview-content::-webkit-scrollbar-thumb:hover{background:#555}
        .bhb-preview-footer{display:flex;justify-content:space-between;padding:8px 12px;border-top:1px solid #333;background:#222;font-size:12px;color:#888;position:absolute;bottom:0;left:0;right:0}
        .bhb-preview-loading{display:flex;justify-content:center;align-items:center;height:100px;color:#888}
        .bhb-preview-error{color:#ff6b6b;text-align:center;padding:20px}
        .bhb-preview-img{max-width:100%;height:auto;margin:8px 0;border-radius:2px}
        .bhb-preview-close{position:absolute;top:8px;right:8px;width:24px;height:24px;display:flex;align-items:center;justify-content:center;cursor:pointer;color:#888;font-size:18px;border-radius:50%;background:#333;z-index:1}
        .bhb-preview-close:hover{background:#444;color:#fff}
        
        /* 预览高亮样式 */
        .bhb-preview-highlight{background:rgba(255,255,255,0.05);border-radius:2px;transition:background 0.2s ease}
        .bhb-preview-highlight:hover{background:rgba(255,255,255,0.1)}
    `);

    // 工具函数
    const Utils = {
        $: (selector, parent = document) => parent.querySelector(selector),
        $$: (selector, parent = document) => [...parent.querySelectorAll(selector)],
        
        toggleClass: (el, className) => el.classList.toggle(className),
        
        createEl: (tag, props = {}) => {
            const el = document.createElement(tag);
            Object.entries(props).forEach(([k, v]) => {
                if (k === 'className') el.className = v;
                else if (k === 'innerHTML') el.innerHTML = v;
                else if (k === 'textContent') el.textContent = v;
                else if (k === 'onclick') el.onclick = v;
                else el.setAttribute(k, v);
            });
            return el;
        },
        
        // 简化的HTTP请求
        request: (url, options = {}) => new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: options.method || 'GET',
                url,
                headers: options.headers || {},
                data: options.data ? JSON.stringify(options.data) : undefined,
                timeout: options.timeout || 10000,
                onload: r => r.status >= 200 && r.status < 300 ? 
                    resolve(options.isJson ? JSON.parse(r.responseText) : r.responseText) : 
                    reject(new Error(`请求失败: ${r.status}`)),
                onerror: reject,
                ontimeout: () => reject(new Error('请求超时'))
            });
        }),
        
        // 统一的通知发送
        notify: (title, body, url, tag) => {
            if ("Notification" in window && Notification.permission === "granted") {
                const notification = new Notification(title, {
                    body,
                    icon: 'https://boyshelpboys.com/upload/attach/202410/b.svg',
                    tag
                });
                
                if (url) {
                    notification.onclick = () => {
                        window.open(url, '_blank');
                        notification.close();
                    };
                }

                // 设置通知20秒后自动关闭
                setTimeout(() => notification.close(), CONFIG.notificationTimeout);
            } else {
                GM_notification({
                    title,
                    text: body,
                    image: 'https://boyshelpboys.com/upload/attach/202410/b.svg',
                    onclick: url ? () => window.open(url, '_blank') : null,
                    timeout: CONFIG.notificationTimeout
                });
            }
        }
    };

    // 功能实现
    const Features = {
        // 在新标签页打开帖子
        openInNewTab: () => {
            Utils.$$('a.subject[href*="thread-"]').forEach(a => {
                a.target = '_blank';
                a.rel = 'noopener';
            });
        },
        
        // 自动翻页功能 - AJAX实现
        autoPagination: {
            isLoading: false,
            nextPageLink: null,
            container: null,
            pageCount: 1,
            
            // 初始化自动翻页
            init: () => {
                if (!GM_getValue('auto_pagination', false)) return;
                if (location.href.includes('/thread-') && !location.href.includes('/forum-')) return;
                
                // 创建加载提示元素
                const loader = Utils.createEl('div', {
                    className: 'auto-pagination-loader',
                    textContent: '正在加载下一页...'
                });
                document.body.appendChild(loader);
                Features.autoPagination.loaderElement = loader;
                
                // 找到列表容器和下一页链接
                Features.autoPagination.findContainer();
                Features.autoPagination.findNextPageLink();
                
                // 添加滚动监听(使用节流函数)
                let scrollTimer = null;
                window.addEventListener('scroll', () => {
                    if (scrollTimer) clearTimeout(scrollTimer);
                    scrollTimer = setTimeout(Features.autoPagination.checkScroll, 200);
                });
            },
            
            // 查找内容容器
            findContainer: () => {
                // 常见容器选择器
                const selectors = ['.table', '.thread_list', '.threadlist', '#threadlist', 
                                  '.content-list', '.forum_body', 'table.list tbody', '#content'];
                
                // 尝试所有选择器
                for (const selector of selectors) {
                    const container = document.querySelector(selector);
                    if (container && container.children.length > 2) {
                        Features.autoPagination.container = container;
                        return;
                    }
                }
                
                // 未找到,分析帖子链接
                const links = document.querySelectorAll('a[href*="thread-"]');
                if (links.length > 3) {
                    // 找出最可能是列表容器的父元素
                    const parents = {};
                    links.forEach(link => {
                        const parent = link.closest('tr, li, .thread, .item');
                        if (parent && parent.parentElement) {
                            const parentPath = parent.parentElement.tagName.toLowerCase() + 
                                (parent.parentElement.id ? `#${parent.parentElement.id}` : '');
                            parents[parentPath] = (parents[parentPath] || 0) + 1;
                        }
                    });
                    
                    // 选择包含最多帖子链接的容器
                    const bestParent = Object.entries(parents)
                        .sort((a, b) => b[1] - a[1])
                        .shift();
                        
                    if (bestParent && bestParent[1] > 2) {
                        Features.autoPagination.container = document.querySelector(bestParent[0]);
                    }
                }
            },
            
            // 查找下一页链接
            findNextPageLink: () => {
                const pagination = document.querySelector('.pagination');
                if (!pagination) return;
                
                // 常见下一页按钮模式
                const nextLinkSelectors = [
                    // 活动页面后面的链接
                    () => {
                        const active = pagination.querySelector('.active, .current');
                        if (active && active.nextElementSibling) {
                            return active.nextElementSibling.querySelector('a');
                        }
                        return null;
                    },
                    // 下一页文本或符号
                    () => {
                        const links = pagination.querySelectorAll('a');
                        for (const link of links) {
                            const text = link.textContent.trim();
                            if (text === '下一页' || text === '>' || text === '›' || 
                                text === '»' || text === '▶' || 
                                link.title?.includes('下一页') || 
                                link.title?.includes('Next')) {
                                return link;
                            }
                        }
                        return null;
                    },
                    // 当前页数+1
                    () => {
                        const active = pagination.querySelector('.active, .current');
                        if (active) {
                            const currentPage = parseInt(active.textContent.trim());
                            if (currentPage) {
                                const links = pagination.querySelectorAll('a');
                                for (const link of links) {
                                    if (parseInt(link.textContent.trim()) === currentPage + 1) {
                                        return link;
                                    }
                                }
                            }
                        }
                        return null;
                    }
                ];
                
                // 尝试所有选择器
                for (const selector of nextLinkSelectors) {
                    const link = selector();
                    if (link && link.href) {
                        Features.autoPagination.nextPageLink = link;
                        return;
                    }
                }
            },
            
            // 检查滚动位置和加载下一页
            checkScroll: () => {
                if (Features.autoPagination.isLoading || !Features.autoPagination.nextPageLink) return;
                
                const scrollBottom = document.documentElement.scrollHeight - window.scrollY - window.innerHeight;
                if (scrollBottom < 300) {
                    Features.autoPagination.loadNextPage();
                }
            },
            
            // 加载下一页内容
            loadNextPage: () => {
                if (Features.autoPagination.isLoading || !Features.autoPagination.nextPageLink) return;
                
                // 无容器时直接跳转
                if (!Features.autoPagination.container) {
                    location.href = Features.autoPagination.nextPageLink.href;
                    return;
                }
                
                Features.autoPagination.isLoading = true;
                
                // 显示加载提示
                const loader = Features.autoPagination.loaderElement;
                if (loader) {
                    loader.textContent = '正在加载下一页...';
                    loader.classList.add('show');
                }
                
                // 获取下一页内容
                fetch(Features.autoPagination.nextPageLink.href)
                    .then(res => res.text())
                    .then(html => {
                        const doc = new DOMParser().parseFromString(html, 'text/html');
                        
                        // 尝试找到新页面中对应的内容容器
                        const container = Features.autoPagination.container;
                        let selector = container.id ? `#${container.id}` : 
                                      container.className ? `.${container.className.replace(/\s+/g, '.')}` : 
                                      container.tagName.toLowerCase();
                        
                        let newContent = doc.querySelector(selector);
                        
                        // 找不到时尝试其他选择器
                        if (!newContent) {
                            for (const sel of ['.table', '.thread_list', '.threadlist', '#threadlist']) {
                                newContent = doc.querySelector(sel);
                                if (newContent) break;
                            }
                        }
                        
                        if (!newContent) throw new Error('未找到内容');
                        
                        // 提取内容项
                        const isTable = /^(TABLE|TBODY)$/i.test(container.tagName);
                        const items = isTable 
                            ? Array.from(newContent.querySelectorAll('tr')).filter(tr => !tr.classList.contains('header')) 
                            : Array.from(newContent.children);
                        
                        if (items.length < 3) throw new Error('内容项太少');
                        
                        // 创建分页标记
                        const marker = Utils.createEl('div', {
                            className: 'bhb-page-marker',
                            textContent: `第 ${++Features.autoPagination.pageCount} 页`
                        });
                        
                        // 添加新内容
                        if (isTable) {
                            const tbody = container.tagName === 'TABLE' ? container.querySelector('tbody') : container;
                            const row = document.createElement('tr');
                            const cell = document.createElement('td');
                            cell.colSpan = 10;
                            cell.appendChild(marker);
                            row.appendChild(cell);
                            tbody.appendChild(row);
                            
                            items.forEach(item => tbody.appendChild(item.cloneNode(true)));
                        } else {
                            container.appendChild(marker);
                            items.forEach(item => container.appendChild(item.cloneNode(true)));
                        }
                        
                        // 更新URL
                        history.pushState(
                            { page: Features.autoPagination.pageCount }, 
                            document.title, 
                            Features.autoPagination.nextPageLink.href
                        );
                        
                        // 处理新内容
                        if (GM_getValue('newtab', true)) Features.openInNewTab(container);
                        Features.blockUser(container);
                        
                        // 查找新的下一页链接
                        const pagination = doc.querySelector('.pagination');
                        if (pagination) {
                            const active = pagination.querySelector('.active, .current');
                            if (active && active.nextElementSibling) {
                                const nextLink = active.nextElementSibling.querySelector('a');
                                if (nextLink && nextLink.href) {
                                    Features.autoPagination.nextPageLink = {
                                        href: nextLink.href,
                                        textContent: nextLink.textContent
                                    };
                                } else {
                                    Features.autoPagination.nextPageLink = null;
                                }
                            } else {
                                Features.autoPagination.nextPageLink = null;
                            }
                        } else {
                            Features.autoPagination.nextPageLink = null;
                        }
                        
                        // 重置状态
                        Features.autoPagination.isLoading = false;
                        if (loader) loader.classList.remove('show');
                    })
                    .catch(error => {
                        console.error('[BHB] 加载失败:', error);
                        
                        if (confirm('无刷新加载失败,是否直接跳转到下一页?')) {
                            location.href = Features.autoPagination.nextPageLink.href;
                        }
                        
                        Features.autoPagination.isLoading = false;
                        if (loader) {
                            loader.textContent = '加载失败,点击重试';
                            loader.classList.add('show');
                            loader.onclick = Features.autoPagination.loadNextPage;
                            setTimeout(() => loader.classList.remove('show'), 3000);
                        }
                    });
            },
            
            // 清理资源
            cleanup: () => {
                window.removeEventListener('scroll', Features.autoPagination.checkScroll);
                if (Features.autoPagination.loaderElement) Features.autoPagination.loaderElement.remove();
            }
        },
        
        // 屏蔽用户
        blockUser: () => {
            const blockedUsers = GM_getValue('blockedUsers', '')
                .split('\n').map(u => u.trim()).filter(Boolean);
            
            if (blockedUsers.length === 0) return;
            
            Utils.$$('.thread.card.tap, .media.post, .post_reply_item').forEach(post => {
                const userEl = Utils.$('.username a, .username, .reply_item_user a', post);
                if (userEl && blockedUsers.includes(userEl.textContent.trim())) {
                    post.classList.add('blocked-post');
                }
            });
        },
        
        // AI摘要
        aiSummary: {
            // 获取AI摘要
            getSummary: async (text) => {
                const apiKey = GM_getValue('api_key', CONFIG.defaultApiKey);
                
                return Utils.request(CONFIG.apiUrl, {
                    method: 'POST',
                    headers: {
                        'Content-Type': 'application/json',
                        'Authorization': `Bearer ${apiKey}`
                    },
                    data: {
                        model: CONFIG.defaultModel,
                        messages: [
                            {
                                role: 'system',
                                content: '两句话总结帖子的内容'
                            },
                            {
                                role: 'user',
                                content: text
                            }
                        ],
                        stream: false,
                        max_tokens: 512,
                        temperature: 0.7,
                        top_p: 0.7,
                        top_k: 50,
                        frequency_penalty: 0.5,
                        n: 1,
                        response_format: { type: 'text' }
                    },
                    isJson: true
                }).then(result => {
                    if (result.error) throw new Error(result.error.message);
                    return result.choices[0].message.content.trim();
                });
            },
            
            // 添加AI摘要按钮
            addButtons: () => {
                if (!GM_getValue('ai_summary', false) || !location.href.includes('/thread-')) return;
                
                const mainPost = Utils.$('.message.break-all');
                if (!mainPost?.textContent.trim() || mainPost.classList.contains('ai-summary-added') || Utils.$('.ai-summary-btn')) return;
                
                const summaryDiv = Utils.createEl('div', {
                    className: 'ai-summary',
                    innerHTML: '<div class="ai-loading">正在生成AI摘要...</div>'
                });
                
                const summaryBtn = Utils.createEl('button', {
                    className: 'ai-summary-btn',
                    textContent: 'AI总结',
                    onclick: () => Utils.toggleClass(summaryDiv, 'hide')
                });
                
                mainPost.parentNode.insertBefore(summaryDiv, mainPost);
                mainPost.parentNode.insertBefore(summaryBtn, summaryDiv);
                
                Features.aiSummary.getSummary(mainPost.textContent.trim())
                    .then(summary => {
                        summaryDiv.innerHTML = `<div style="color:#fff">${summary}</div>`;
                        mainPost.classList.add('ai-summary-added');
                    })
                    .catch(error => {
                        summaryDiv.innerHTML = `<div style="color:#ff4444">生成摘要失败:${error.message}</div>`;
                        setTimeout(() => {
                            summaryDiv.remove();
                            summaryBtn.remove();
                        }, 3000);
                    });
            }
        },
        
        // 新帖通知
        notification: {
            timer: null,
            
            // 获取最新帖子
            fetchPosts: async () => {
                const html = await Utils.request('https://boyshelpboys.com/');
                const parser = new DOMParser();
                const doc = parser.parseFromString(html, 'text/html');
                
                return Utils.$$('.thread', doc)
                    .map(post => {
                        const id = post.getAttribute('data-tid') || post.id || '';
                        const titleEl = Utils.$('.subject, .title, h3, a[title]', post);
                        const authorEl = Utils.$('.username, .author, .user', post);
                        const url = post.getAttribute('data-href') || 
                                  (Utils.$('a', post)?.getAttribute('href') || '');
                        
                        return {
                            id,
                            title: titleEl ? titleEl.textContent.trim() : '无标题',
                            author: authorEl ? authorEl.textContent.trim() : '匿名',
                            url
                        };
                    })
                    .filter(p => p.id && p.title && p.url);
            },
            
            // 检查新帖子
            check: async () => {
                try {
                    const posts = await Features.notification.fetchPosts();
                    const knownIds = GM_getValue('knownPostsIds', []);
                    
                    // 首次运行,只保存ID
                    if (!knownIds.length) {
                        GM_setValue('knownPostsIds', posts.map(p => p.id));
                        return;
                    }
                    
                    // 找出新帖
                    const newPosts = posts.filter(p => !knownIds.includes(p.id));
                    
                    // 发送通知
                    if (newPosts.length > 0) {
                        // 显示最多CONFIG.maxNotifications个通知
                        newPosts.slice(0, CONFIG.maxNotifications).forEach(post => {
                            Utils.notify(
                                '论坛新帖提醒', 
                                `${post.title}\n作者: ${post.author}`,
                                `https://boyshelpboys.com/${post.url}`,
                                post.id
                            );
                        });
                        
                        // 超过限制显示汇总通知
                        if (newPosts.length > CONFIG.maxNotifications) {
                            Utils.notify(
                                '论坛新帖提醒',
                                `还有 ${newPosts.length - CONFIG.maxNotifications} 个新帖未显示,点击查看`,
                                'https://boyshelpboys.com/'
                            );
                        }
                    }
                    
                    // 更新已知ID列表,保留最新的CONFIG.maxSavedIds个
                    const mergedIds = [...new Set([...posts.map(p => p.id), ...knownIds])].slice(0, CONFIG.maxSavedIds);
                    GM_setValue('knownPostsIds', mergedIds);
                    
                } catch (error) {
                    console.error('检查新帖失败', error);
                }
            },
            
            // 设置通知
            setup: () => {
                if (Features.notification.timer) {
                    clearInterval(Features.notification.timer);
                    Features.notification.timer = null;
                }
                
                if (GM_getValue('notification', false)) {
                    Features.notification.check();
                    Features.notification.timer = setInterval(
                        Features.notification.check,
                        CONFIG.checkInterval
                    );
                }
            }
        },
        
        // 快速预览功能
        quickPreview: {
            previewContainer: null,
            previewTimeout: null,
            previewDelay: 500, // 悬停多久后显示预览
            cache: {},         // 缓存已加载的帖子内容
            currentLink: null, // 当前预览的链接元素
            
            // 创建预览容器
            createContainer: () => {
                if (Features.quickPreview.previewContainer) return;
                
                const container = Utils.createEl('div', {
                    className: 'bhb-preview-container',
                    innerHTML: `
                        <div class="bhb-preview-header">
                            <div class="bhb-preview-title">加载中...</div>
                            <div class="bhb-preview-info"></div>
                        </div>
                        <div class="bhb-preview-content">
                            <div class="bhb-preview-loading">加载中...</div>
                        </div>
                        <div class="bhb-preview-footer">
                            <span>点击链接查看完整内容</span>
                            <span>社区助手提供</span>
                        </div>
                    `
                });
                
                document.body.appendChild(container);
                Features.quickPreview.previewContainer = container;
                
                // 添加点击事件监听器到document
                document.addEventListener('click', (e) => {
                    // 如果点击的是预览容器内部或当前预览的链接,不关闭
                    if (container.contains(e.target) || 
                        (Features.quickPreview.currentLink && 
                         Features.quickPreview.currentLink.contains(e.target))) {
                        return;
                    }
                    
                    // 点击其他地方,关闭预览
                    if (container.classList.contains('show')) {
                        container.classList.remove('show');
                        Features.quickPreview.currentLink = null;
                        
                        // 移除所有高亮
                        Utils.$$('.bhb-preview-highlight').forEach(el => {
                            el.classList.remove('bhb-preview-highlight');
                        });
                    }
                });
                
                // 添加键盘事件监听器 - ESC键关闭预览
                document.addEventListener('keydown', (e) => {
                    if (e.key === 'Escape' && container.classList.contains('show')) {
                        container.classList.remove('show');
                        Features.quickPreview.currentLink = null;
                        
                        // 移除所有高亮
                        Utils.$$('.bhb-preview-highlight').forEach(el => {
                            el.classList.remove('bhb-preview-highlight');
                        });
                    }
                });
            },
            
            // 获取帖子内容
            fetchPostContent: async (url) => {
                // 如果已缓存,直接返回
                if (Features.quickPreview.cache[url]) {
                    return Features.quickPreview.cache[url];
                }
                
                try {
                    const html = await Utils.request(url);
                    const parser = new DOMParser();
                    const doc = parser.parseFromString(html, 'text/html');
                    
                    // 尝试找到主帖内容
                    const mainPost = doc.querySelector('.message.break-all, .post-content, .thread-content');
                    if (!mainPost) throw new Error('无法找到帖子内容');
                    
                    // 获取帖子标题
                    const title = doc.querySelector('h1, .subject, .thread-subject')?.textContent.trim() || '无标题';
                    
                    // 获取作者和时间
                    const author = doc.querySelector('.username, .author')?.textContent.trim() || '匿名';
                    const time = doc.querySelector('.date, .time, .post-time')?.textContent.trim() || '';
                    
                    // 处理内容中的图片
                    const content = mainPost.innerHTML;
                    const processedContent = content
                        .replace(/<img[^>]*src="([^"]+)"[^>]*>/gi, '<img class="bhb-preview-img" src="$1" alt="图片">')
                        .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, ''); // 移除脚本标签
                    
                    const result = {
                        title,
                        author,
                        time,
                        content: processedContent
                    };
                    
                    // 缓存结果
                    Features.quickPreview.cache[url] = result;
                    return result;
                } catch (error) {
                    console.error('获取帖子内容失败', error);
                    throw error;
                }
            },
            
            // 显示预览
            showPreview: (link, event) => {
                if (!GM_getValue('quick_preview', false)) return;
                
                Features.quickPreview.createContainer();
                const container = Features.quickPreview.previewContainer;
                
                // 移除之前的高亮
                if (Features.quickPreview.currentLink && 
                    Features.quickPreview.currentLink !== link) {
                    const parentElement = Features.quickPreview.currentLink.closest('tr, li, .thread, .item');
                    if (parentElement) {
                        parentElement.classList.remove('bhb-preview-highlight');
                    }
                }
                
                // 保存当前预览的链接
                Features.quickPreview.currentLink = link;
                
                // 高亮当前链接所在的行或项目
                const parentElement = link.closest('tr, li, .thread, .item');
                if (parentElement) {
                    parentElement.classList.add('bhb-preview-highlight');
                }
                
                // 清除之前的定时器
                if (Features.quickPreview.previewTimeout) {
                    clearTimeout(Features.quickPreview.previewTimeout);
                }
                
                // 设置新的定时器
                Features.quickPreview.previewTimeout = setTimeout(async () => {
                    try {
                        // 显示加载状态
                        container.querySelector('.bhb-preview-title').textContent = '加载中...';
                        container.querySelector('.bhb-preview-info').textContent = '';
                        container.querySelector('.bhb-preview-content').innerHTML = '<div class="bhb-preview-loading">加载中...</div>';
                        container.classList.add('show');
                        
                        // 获取帖子内容
                        const url = link.href;
                        const postData = await Features.quickPreview.fetchPostContent(url);
                        
                        // 更新预览内容
                        container.querySelector('.bhb-preview-title').textContent = postData.title;
                        container.querySelector('.bhb-preview-info').textContent = `${postData.author} ${postData.time}`;
                        container.querySelector('.bhb-preview-content').innerHTML = postData.content;
                        
                    } catch (error) {
                        container.querySelector('.bhb-preview-content').innerHTML = 
                            `<div class="bhb-preview-error">加载失败: ${error.message}</div>`;
                    }
                }, Features.quickPreview.previewDelay);
            },
            
            // 添加预览事件
            addPreviewEvents: () => {
                if (!GM_getValue('quick_preview', false)) return;
                
                // 针对论坛特定结构的头像选择器
                const avatarSelectors = [
                    '.v_avatar', // 头像容器
                    '.v_avatar img', // 头像图片
                    '.avatar-3', // 具体的头像类名
                    'img.avatar' // 通用头像
                ];
                
                // 为所有头像添加预览事件
                Utils.$$(avatarSelectors.join(', ')).forEach(element => {
                    if (element.classList.contains('bhb-preview-added')) return;
                    
                    // 标记已添加预览事件
                    element.classList.add('bhb-preview-added');
                    
                    // 查找关联的帖子容器
                    let container = element.closest('li.thread, .thread');
                    if (!container) return;
                    
                    // 查找帖子链接或使用容器的data-href属性
                    let link = container.querySelector('a.subject[href*="thread-"]');
                    
                    // 如果找不到链接,尝试从data-href属性获取
                    if (!link && container.hasAttribute('data-href')) {
                        // 创建一个虚拟链接对象
                        link = {
                            href: 'https://boyshelpboys.com/' + container.getAttribute('data-href'),
                            textContent: container.querySelector('.subject')?.textContent || '帖子预览'
                        };
                    }
                    
                    // 如果找不到任何链接,放弃
                    if (!link) return;
                    
                    // 添加鼠标悬停事件
                    element.style.cursor = 'pointer';
                    element.setAttribute('title', '悬停查看帖子预览');
                    
                    element.addEventListener('mouseenter', (e) => {
                        Features.quickPreview.showPreview(link, e);
                    });
                });
                
                // 备选方案:直接处理thread元素
                if (Utils.$$('.bhb-preview-added').length === 0) {
                    Utils.$$('li.thread[data-href*="thread-"]').forEach(thread => {
                        const avatarContainer = thread.querySelector('.v_avatar');
                        if (!avatarContainer || avatarContainer.classList.contains('bhb-preview-added')) return;
                        
                        avatarContainer.classList.add('bhb-preview-added');
                        avatarContainer.style.cursor = 'pointer';
                        avatarContainer.setAttribute('title', '悬停查看帖子预览');
                        
                        const link = {
                            href: 'https://boyshelpboys.com/' + thread.getAttribute('data-href'),
                            textContent: thread.querySelector('.subject')?.textContent || '帖子预览'
                        };
                        
                        avatarContainer.addEventListener('mouseenter', (e) => {
                            Features.quickPreview.showPreview(link, e);
                        });
                    });
                }
            },
            
            // 清理资源
            cleanup: () => {
                if (Features.quickPreview.previewContainer) {
                    Features.quickPreview.previewContainer.remove();
                    Features.quickPreview.previewContainer = null;
                }
                
                if (Features.quickPreview.previewTimeout) {
                    clearTimeout(Features.quickPreview.previewTimeout);
                    Features.quickPreview.previewTimeout = null;
                }
                
                // 移除所有高亮
                Utils.$$('.bhb-preview-highlight').forEach(el => {
                    el.classList.remove('bhb-preview-highlight');
                });
                
                Features.quickPreview.cache = {};
                Features.quickPreview.currentLink = null;
            }
        },
        
        // 控制面板
        panel: {
            create: () => {
                const panel = Utils.createEl('div', {
                    id: 'bhb-panel',
                    innerHTML: `
                        <div id="bhb-content">
                            <div id="bhb-panel-header">
                                <span id="bhb-panel-title">社区助手</span>
                                <span class="bhb-tip">点击收起</span>
                            </div>
                            
                            <div class="bhb-section">
                                <div class="bhb-section-title">功能开关</div>
                                <div class="bhb-options-grid">
                                    <div class="bhb-option">
                                        <label class="bhb-checkbox-label">
                                            <input type="checkbox" id="bhb-newtab" class="bhb-checkbox">
                                            <span class="bhb-label">新标签</span>
                                        </label>
                                    </div>
                                    
                                    <div class="bhb-option">
                                        <label class="bhb-checkbox-label">
                                            <input type="checkbox" id="bhb-notification" class="bhb-checkbox">
                                            <span class="bhb-label">新帖通知</span>
                                        </label>
                                    </div>

                                    <div class="bhb-option">
                                        <label class="bhb-checkbox-label">
                                            <input type="checkbox" id="bhb-auto-pagination" class="bhb-checkbox">
                                            <span class="bhb-label">自动翻页</span>
                                        </label>
                                    </div>

                                    <div class="bhb-option">
                                        <label class="bhb-checkbox-label">
                                            <input type="checkbox" id="bhb-ai-summary" class="bhb-checkbox">
                                            <span class="bhb-label">AI总结</span>
                                        </label>
                                    </div>
                                    
                                    <div class="bhb-option">
                                        <label class="bhb-checkbox-label">
                                            <input type="checkbox" id="bhb-quick-preview" class="bhb-checkbox">
                                            <span class="bhb-label">快速预览</span>
                                        </label>
                                    </div>
                                </div>
                            </div>

                            <div class="bhb-section">
                                <div class="bhb-section-title">高级设置</div>
                                <div class="bhb-input-section">
                                    <div class="bhb-option">
                                        <span class="bhb-btn" id="bhb-toggle-block">屏蔽用户</span>
                                    </div>
                                    <div class="bhb-option">
                                        <span class="bhb-btn" id="bhb-toggle-css">自定义CSS</span>
                                    </div>
                                </div>

                                <div class="bhb-input-area" id="bhb-block-area">
                                    <textarea class="bhb-textarea" id="bhb-blocked-users" placeholder="每行一个用户名">${GM_getValue('blockedUsers', '')}</textarea>
                                    <div style="display:flex;justify-content:flex-end">
                                        <button class="bhb-btn" id="bhb-apply-block" style="width:auto">应用</button>
                                    </div>
                                </div>

                                <div class="bhb-input-area" id="bhb-css-area">
                                    <textarea class="bhb-textarea" id="bhb-css" placeholder="输入CSS代码">${GM_getValue('customCSS', '')}</textarea>
                                    <div style="display:flex;justify-content:flex-end">
                                        <button class="bhb-btn" id="bhb-apply-css" style="width:auto">应用</button>
                                    </div>
                                </div>
                            </div>
                        </div>
                        <div id="bhb-toggle">B</div>
                    `
                });
                document.body.appendChild(panel);
                
                // 创建帮助区域
                const helpArea = Utils.createEl('div', {
                    id: 'bhb-help-area',
                    className: 'bhb-input-area',
                    innerHTML: `
                        <div class="bhb-help-content">
                            <h4 style="margin:4px 0;color:#ddd">BOYS HELP BOYS</h4>
                            <p style="margin:6px 0;line-height:1.4;font-size:12px"> 
                                - 鼠标悬浮到帖子头像即可预览帖子内容<br>


                                <br>
                                使用过程中有任何问题,请联系开发者。
                            </p>
                        </div>
                    `
                });
                panel.appendChild(helpArea);
                Features.panel.setup(panel);
            },
            
            setup: (panel) => {
                // 添加自定义样式元素
                const customStyle = Utils.createEl('style', {
                    id: 'bhb-custom-style',
                    textContent: GM_getValue('customCSS', '')
                });
                document.head.appendChild(customStyle);
                
                // 切换输入区域
                ['block', 'css'].forEach(type => {
                    Utils.$(`#bhb-toggle-${type}`, panel).onclick = () => {
                        const area = Utils.$(`#bhb-${type}-area`, panel);
                        Utils.$$('.bhb-input-area', panel).forEach(a => a !== area && a.classList.remove('active'));
                        Utils.toggleClass(area, 'active');
                    };
                });
                
                // AI总结设置
                const aiSummaryCheckbox = Utils.$('#bhb-ai-summary', panel);
                aiSummaryCheckbox.checked = GM_getValue('ai_summary', false);
                aiSummaryCheckbox.onchange = () => {
                    GM_setValue('ai_summary', aiSummaryCheckbox.checked);
                    if (aiSummaryCheckbox.checked) {
                        Features.aiSummary.addButtons();
                    } else {
                        Utils.$$('.ai-summary, .ai-summary-btn').forEach(el => el.remove());
                        Utils.$$('.ai-summary-added').forEach(el => el.classList.remove('ai-summary-added'));
                    }
                };
                
                // 面板最小化功能
                const togglePanel = () => {
                    Utils.toggleClass(panel, 'mini');
                    GM_setValue('panelMini', panel.classList.contains('mini'));
                };
                
                Utils.$('#bhb-panel-header', panel).onclick = togglePanel;
                
                // 修改B按钮功能为展开帮助说明
                Utils.$('#bhb-toggle', panel).onclick = () => {
                    if (panel.classList.contains('mini')) {
                        // 如果面板是最小化状态,先恢复面板
                        Utils.toggleClass(panel, 'mini');
                        GM_setValue('panelMini', false);
                    } else {
                        // 否则切换帮助区域显示/隐藏
                        const helpArea = Utils.$('#bhb-help-area', panel);
                        Utils.toggleClass(helpArea, 'active');
                    }
                };
                
                if (GM_getValue('panelMini', false)) panel.classList.add('mini');
                
                // 新标签页设置
                const newTabCheckbox = Utils.$('#bhb-newtab', panel);
                newTabCheckbox.checked = GM_getValue('newtab', true);
                newTabCheckbox.onchange = () => {
                    GM_setValue('newtab', newTabCheckbox.checked);
                    newTabCheckbox.checked && Features.openInNewTab();
                };
                
                // 新帖通知设置
                const notificationCheckbox = Utils.$('#bhb-notification', panel);
                notificationCheckbox.checked = GM_getValue('notification', false);
                notificationCheckbox.onchange = async () => {
                    const checked = notificationCheckbox.checked;
                    if (checked && "Notification" in window) {
                        const permission = await Notification.requestPermission();
                        if (permission !== 'granted') {
                            alert('需要开启浏览器通知权限才能接收新帖通知!');
                            notificationCheckbox.checked = false;
                            return;
                        }
                    }
                    GM_setValue('notification', checked);
                    Features.notification.setup();
                };
                
                // 自动翻页设置
                const autoPaginationCheckbox = Utils.$('#bhb-auto-pagination', panel);
                autoPaginationCheckbox.checked = GM_getValue('auto_pagination', false);
                autoPaginationCheckbox.onchange = () => {
                    const checked = autoPaginationCheckbox.checked;
                    GM_setValue('auto_pagination', checked);
                    
                    if (checked) {
                        Features.autoPagination.init();
                    } else {
                        Features.autoPagination.cleanup();
                    }
                };
                
                // 屏蔽用户设置
                Utils.$('#bhb-apply-block', panel).onclick = () => {
                    GM_setValue('blockedUsers', Utils.$('#bhb-blocked-users', panel).value.trim());
                    Features.blockUser();
                };
                
                // 自定义CSS设置
                Utils.$('#bhb-apply-css', panel).onclick = () => {
                    const css = Utils.$('#bhb-css', panel).value.trim();
                    GM_setValue('customCSS', css);
                    customStyle.textContent = css;
                };
                
                // 快速预览设置
                const quickPreviewCheckbox = Utils.$('#bhb-quick-preview', panel);
                quickPreviewCheckbox.checked = GM_getValue('quick_preview', false);
                quickPreviewCheckbox.onchange = () => {
                    GM_setValue('quick_preview', quickPreviewCheckbox.checked);
                    if (quickPreviewCheckbox.checked) {
                        Features.quickPreview.addPreviewEvents();
                    } else {
                        Features.quickPreview.cleanup();
                    }
                };
            }
        }
    };
    
    // 初始化函数
    const init = () => {
        Features.panel.create();
        if (GM_getValue('newtab', true)) Features.openInNewTab();
        Features.blockUser();
        Features.notification.setup();
        Features.autoPagination.init();
        if (GM_getValue('quick_preview', false)) Features.quickPreview.addPreviewEvents();
        
        // 动态内容监听
        const observer = new MutationObserver((() => {
            let timer = null;
            return () => {
                if (timer) return;
                timer = setTimeout(() => {
                    if (GM_getValue('newtab', true)) Features.openInNewTab();
                    Features.blockUser();
                    if (GM_getValue('ai_summary', false)) Features.aiSummary.addButtons();
                    if (GM_getValue('quick_preview', false)) Features.quickPreview.addPreviewEvents();
                    timer = null;
                }, 1000);
            };
        })());
        
        if (document.body) {
            observer.observe(document.body, { childList: true, subtree: true });
            if (GM_getValue('ai_summary', false)) Features.aiSummary.addButtons();
        }
    };
    
    // 等待DOM加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();