HDSky 体育沙龙面板

在 HDSky 论坛页面右上角显示控制面板,自动高亮特殊关注用户的回复内容,支持快速翻页和收藏功能,可折叠面板,下拉加载翻页

当前为 2025-11-28 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         HDSky 体育沙龙面板
// @namespace    http://tampermonkey.net/
// @version      5.1
// @description  在 HDSky 论坛页面右上角显示控制面板,自动高亮特殊关注用户的回复内容,支持快速翻页和收藏功能,可折叠面板,下拉加载翻页
// @author       江畔 | LOVE
// @match        https://hdsky.me/*
// @match        https://www.hdsky.me/*
// @icon         https://hdsky.me/favicon.ico
// @grant        GM_setValue
// @grant        GM_getValue
// @charset      UTF-8
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // 配置管理
    const Config = {
        // 获取配置
        get(key, defaultValue) {
            return GM_getValue(key, defaultValue);
        },
        // 设置配置
        set(key, value) {
            GM_setValue(key, value);
        },
        // 获取下拉加载开关状态
        getAutoLoadEnabled() {
            return this.get('autoLoadEnabled', false);
        },
        // 设置下拉加载开关状态
        setAutoLoadEnabled(enabled) {
            this.set('autoLoadEnabled', enabled);
        },
        // 获取面板展开状态
        getPanelExpanded() {
            return this.get('panelExpanded', true); // 默认展开
        },
        // 设置面板展开状态
        setPanelExpanded(expanded) {
            this.set('panelExpanded', expanded);
        },
        // 获取检查有效下注开关状态
        getCheckValidBetEnabled() {
            return this.get('checkValidBetEnabled', false);
        },
        // 设置检查有效下注开关状态
        setCheckValidBetEnabled(enabled) {
            this.set('checkValidBetEnabled', enabled);
        },
        // 获取高亮特殊关注开关状态
        getHighlightFollowEnabled() {
            return this.get('highlightFollowEnabled', true); // 默认开启
        },
        // 设置高亮特殊关注开关状态
        setHighlightFollowEnabled(enabled) {
            this.set('highlightFollowEnabled', enabled);
        }
    };

    // 从存储中获取特殊关注名单
    function getSpecialFollowList() {
        const listStr = Config.get('specialFollowList', '');
        if (!listStr) return [];
        return listStr.split(',').map(name => name.trim()).filter(name => name);
    }

    // 保存特殊关注名单到存储
    function saveSpecialFollowList(list) {
        Config.set('specialFollowList', list.join(','));
    }

    // 从存储中获取收藏列表
    function getBookmarkList() {
        const listStr = Config.get('bookmarkList', '[]');
        try {
            return JSON.parse(listStr);
        } catch (e) {
            return [];
        }
    }

    // 保存收藏列表到存储
    function saveBookmarkList(list) {
        Config.set('bookmarkList', JSON.stringify(list));
    }

    // 用户备注缓存,避免重复解析
    let userNotesCache = null;

    // 获取用户备注映射
    function getUserNotesMap() {
        if (userNotesCache) {
            return userNotesCache;
        }
        const notesStr = Config.get('userNotes', '{}');
        try {
            userNotesCache = JSON.parse(notesStr) || {};
        } catch (e) {
            userNotesCache = {};
        }
        return userNotesCache;
    }

    // 保存用户备注映射
    function saveUserNotesMap(notesMap) {
        userNotesCache = notesMap;
        Config.set('userNotes', JSON.stringify(notesMap));
    }

    // 获取单个用户备注
    function getUserNoteById(userId) {
        const notes = getUserNotesMap();
        return notes[userId] || '';
    }

    // 更新单个用户备注
    function setUserNoteById(userId, note) {
        const notes = getUserNotesMap();
        if (note) {
            notes[userId] = note;
        } else {
            delete notes[userId];
        }
        saveUserNotesMap(notes);
    }

    // 创建控制面板
    function createControlPanel() {
        // 创建容器,包含面板和折叠按钮
        const container = document.createElement('div');
        container.id = 'hdsky-panel-container';
        container.style.cssText = `
            position: fixed;
            top: 80px;
            right: 10px;
            display: flex;
            align-items: flex-start;
            z-index: 10000;
        `;

        // 创建折叠按钮
        const toggleBtn = document.createElement('button');
        toggleBtn.id = 'panel-toggle-btn';
        toggleBtn.innerHTML = '◀';
        toggleBtn.title = '收起面板';
        toggleBtn.style.cssText = `
            background: #e0e0e0;
            color: #666;
            border: none;
            border-radius: 4px 0 0 4px;
            width: 24px;
            height: 40px;
            cursor: pointer;
            font-size: 14px;
            transition: background 0.3s;
            margin-right: -2px;
            z-index: 1;
        `;
        toggleBtn.onmouseover = () => toggleBtn.style.background = '#d0d0d0';
        toggleBtn.onmouseout = () => toggleBtn.style.background = '#e0e0e0';
        toggleBtn.onclick = togglePanel;
        
        const panel = document.createElement('div');
        panel.id = 'hdsky-special-follow-panel';
        panel.style.cssText = `
            background: #fff;
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 15px;
            box-shadow: 0 4px 8px rgba(0,0,0,0.2);
            width: 220px;
            font-family: Arial, sans-serif;
            transition: all 0.3s ease;
        `;

        // 面板标题
        const title = document.createElement('div');
        title.textContent = '体育沙龙面板';
        title.style.cssText = `
            font-size: 16px;
            font-weight: bold;
            margin-bottom: 12px;
            color: #333;
            text-align: center;
            border-bottom: 1px solid #ddd;
            padding-bottom: 8px;
        `;
        panel.appendChild(title);

        // 按钮容器(统一管理所有按钮)
        const buttonContainer = document.createElement('div');
        buttonContainer.style.cssText = `
            display: flex;
            flex-direction: column;
            gap: 10px;
        `;

        // 关注列表按钮
        const followListBtn = document.createElement('button');
        followListBtn.id = 'follow-list-btn';
        followListBtn.textContent = '关注列表';
        followListBtn.style.cssText = `
            padding: 10px 15px;
            background: #2196F3;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            transition: background 0.3s;
            width: 100%;
        `;
        followListBtn.title = '点击编辑特殊关注名单';
        followListBtn.onmouseover = () => followListBtn.style.background = '#0b7dda';
        followListBtn.onmouseout = () => followListBtn.style.background = '#2196F3';
        followListBtn.onclick = handleFollowListClick;
        buttonContainer.appendChild(followListBtn);

        // 下拉加载翻页按钮
        const autoLoadBtn = document.createElement('button');
        autoLoadBtn.id = 'auto-load-btn';
        autoLoadBtn.style.cssText = `
            padding: 10px 15px;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            transition: background 0.3s;
            width: 100%;
        `;
        autoLoadBtn.onclick = toggleAutoLoadFromPanel;
        updateAutoLoadButton(autoLoadBtn); // 在设置基础样式后再更新按钮状态
        buttonContainer.appendChild(autoLoadBtn);

        // 检查有效下注按钮
        const checkValidBetBtn = document.createElement('button');
        checkValidBetBtn.id = 'check-valid-bet-btn';
        checkValidBetBtn.style.cssText = `
            padding: 10px 15px;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            transition: background 0.3s;
            width: 100%;
        `;
        checkValidBetBtn.onclick = toggleCheckValidBet;
        updateCheckValidBetButton(checkValidBetBtn);
        buttonContainer.appendChild(checkValidBetBtn);

        // 高亮特殊关注按钮
        const highlightFollowBtn = document.createElement('button');
        highlightFollowBtn.id = 'highlight-follow-btn';
        highlightFollowBtn.style.cssText = `
            padding: 10px 15px;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            transition: background 0.3s;
            width: 100%;
        `;
        highlightFollowBtn.onclick = toggleHighlightFollow;
        updateHighlightFollowButton(highlightFollowBtn);
        buttonContainer.appendChild(highlightFollowBtn);

        // 收藏功能按钮容器
        const bookmarkContainer = document.createElement('div');
        bookmarkContainer.id = 'bookmark-container';
        bookmarkContainer.style.cssText = `
            display: flex;
            flex-direction: row;
            gap: 10px;
        `;

        // 收藏按钮
        const bookmarkBtn = document.createElement('button');
        bookmarkBtn.textContent = '收藏';
        bookmarkBtn.id = 'bookmark-btn';
        bookmarkBtn.style.cssText = `
            padding: 8px 12px;
            background: #2196F3;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 13px;
            font-weight: bold;
            transition: background 0.3s;
            flex: 1;
        `;
        bookmarkBtn.onmouseover = () => bookmarkBtn.style.background = '#0b7dda';
        bookmarkBtn.onmouseout = () => bookmarkBtn.style.background = '#2196F3';
        bookmarkBtn.onclick = addBookmark;
        bookmarkContainer.appendChild(bookmarkBtn);

        // 收藏夹按钮
        const bookmarkListBtn = document.createElement('button');
        bookmarkListBtn.textContent = '收藏夹';
        bookmarkListBtn.id = 'bookmark-list-btn';
        bookmarkListBtn.style.cssText = `
            padding: 8px 12px;
            background: #2196F3;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 13px;
            font-weight: bold;
            transition: background 0.3s;
            flex: 1;
        `;
        bookmarkListBtn.onmouseover = () => bookmarkListBtn.style.background = '#0b7dda';
        bookmarkListBtn.onmouseout = () => bookmarkListBtn.style.background = '#2196F3';
        bookmarkListBtn.onclick = showBookmarkList;
        bookmarkContainer.appendChild(bookmarkListBtn);

        buttonContainer.appendChild(bookmarkContainer);

        // 数据分析按钮
        const dataAnalysisBtn = document.createElement('button');
        dataAnalysisBtn.id = 'data-analysis-btn';
        dataAnalysisBtn.textContent = '数据分析';
        dataAnalysisBtn.style.cssText = `
            padding: 10px 15px;
            background: #4caf50;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            transition: background 0.3s;
            width: 100%;
        `;
        dataAnalysisBtn.onmouseover = () => dataAnalysisBtn.style.background = '#388e3c';
        dataAnalysisBtn.onmouseout = () => dataAnalysisBtn.style.background = '#4caf50';
        dataAnalysisBtn.onclick = openDataAnalysisDialog;
        buttonContainer.appendChild(dataAnalysisBtn);

        panel.appendChild(buttonContainer);

        // 将按钮和面板添加到容器
        container.appendChild(toggleBtn);
        container.appendChild(panel);

        // 添加到页面
        document.body.appendChild(container);
        
        // 应用保存的面板状态
        const isPanelExpanded = Config.getPanelExpanded();
        if (!isPanelExpanded) {
            // 如果保存的是收起状态,则收起面板
            panel.style.display = 'none';
            toggleBtn.innerHTML = '▶';
            toggleBtn.title = '展开面板';
            toggleBtn.style.borderRadius = '4px';
        }
    }

    // 切换面板显示/隐藏
    function togglePanel() {
        const panel = document.getElementById('hdsky-special-follow-panel');
        const toggleBtn = document.getElementById('panel-toggle-btn');
        
        if (panel.style.display === 'none') {
            // 展开面板
            panel.style.display = 'block';
            toggleBtn.innerHTML = '◀';
            toggleBtn.title = '收起面板';
            toggleBtn.style.borderRadius = '4px 0 0 4px';
            Config.setPanelExpanded(true); // 保存展开状态
        } else {
            // 收起面板
            panel.style.display = 'none';
            toggleBtn.innerHTML = '▶';
            toggleBtn.title = '展开面板';
            toggleBtn.style.borderRadius = '4px';
            Config.setPanelExpanded(false); // 保存收起状态
        }
    }

    // 更新下拉加载按钮的显示
    function updateAutoLoadButton(button) {
        const isEnabled = Config.getAutoLoadEnabled();
        
        button.style.background = '#2196F3'; // 统一使用蓝色
        button.onmouseover = () => button.style.background = '#0b7dda';
        button.onmouseout = () => button.style.background = '#2196F3';
        
        if (isEnabled) {
            button.textContent = '✅ 下拉加载翻页';
            button.title = '点击关闭下拉加载翻页功能';
        } else {
            button.textContent = '❌ 下拉加载翻页';
            button.title = '点击开启下拉加载翻页功能';
        }
    }

    // 从面板切换下拉加载功能
    function toggleAutoLoadFromPanel() {
        const currentState = Config.getAutoLoadEnabled();
        const newState = !currentState;
        Config.setAutoLoadEnabled(newState);
        
        // 更新按钮显示
        const button = document.getElementById('auto-load-btn');
        if (button) {
            updateAutoLoadButton(button);
        }
        
        // 如果是开启,立即初始化功能
        if (newState) {
            autoLoadNextPage();
        } else {
            // 如果是关闭,需要刷新页面以移除事件监听器
            if (confirm('需要刷新页面以完全关闭下拉加载功能,是否立即刷新?')) {
                location.reload();
            }
        }
    }

    // 更新检查有效下注按钮的显示
    function updateCheckValidBetButton(button) {
        const isEnabled = Config.getCheckValidBetEnabled();
        
        button.style.background = '#2196F3'; // 统一使用蓝色
        button.onmouseover = () => button.style.background = '#0b7dda';
        button.onmouseout = () => button.style.background = '#2196F3';
        
        if (isEnabled) {
            button.textContent = '✅ 检查有效下注';
            button.title = '点击关闭检查有效下注功能\n如果超过截止时间或重复下注将禁用回复功能';
        } else {
            button.textContent = '❌ 检查有效下注';
            button.title = '点击开启检查有效下注功能\n如果超过截止时间或重复下注将禁用回复功能';
        }
    }

    // 从面板切换检查有效下注功能
    function toggleCheckValidBet() {
        const currentState = Config.getCheckValidBetEnabled();
        const newState = !currentState;
        Config.setCheckValidBetEnabled(newState);
        
        // 更新按钮显示
        const button = document.getElementById('check-valid-bet-btn');
        if (button) {
            updateCheckValidBetButton(button);
        }
        
        // 如果关闭功能,恢复回复表单
        if (!newState) {
            enableReplyForm();
        } else {
            // 如果开启功能,重新检查并应用
            checkValidBetAndDisableReply();
        }
    }

    // 更新高亮特殊关注按钮的显示
    function updateHighlightFollowButton(button) {
        const isEnabled = Config.getHighlightFollowEnabled();
        
        button.style.background = '#2196F3'; // 统一使用蓝色
        button.onmouseover = () => button.style.background = '#0b7dda';
        button.onmouseout = () => button.style.background = '#2196F3';
        
        if (isEnabled) {
            button.textContent = '✅ 高亮特殊关注';
            button.title = '点击关闭高亮特殊关注功能';
        } else {
            button.textContent = '❌ 高亮特殊关注';
            button.title = '点击开启高亮特殊关注功能';
        }
    }

    // 从面板切换高亮特殊关注功能
    function toggleHighlightFollow() {
        const currentState = Config.getHighlightFollowEnabled();
        const newState = !currentState;
        Config.setHighlightFollowEnabled(newState);
        
        // 更新按钮显示
        const button = document.getElementById('highlight-follow-btn');
        if (button) {
            updateHighlightFollowButton(button);
        }
        
        // 如果关闭功能,清除所有高亮
        if (!newState) {
            clearHighlights();
        } else {
            // 如果开启功能,重新应用高亮
            autoHighlightFollowedPosts();
        }
    }

    // 获取当前用户名
    function getCurrentUsername() {
        const infoBlock = document.getElementById('info_block');
        if (!infoBlock) return null;
        
        // 查找包含用户名的链接(userdetails.php?id=xxx)
        const userLink = infoBlock.querySelector('a[href*="userdetails.php?id"]');
        if (!userLink) return null;
        
        // 提取用户名文本(去除HTML标签)
        const username = userLink.textContent.trim();
        return username || null;
    }

    // 检查给定文档中当前用户是否已经下注(已回帖)
    function hasUserRepliedOnDocument(targetDoc, currentUsername) {
        if (!targetDoc || !currentUsername) return false;
        
        const userLinks = targetDoc.querySelectorAll('a[href*="userdetails.php?id"]');
        
        for (let link of userLinks) {
            if (link.closest('#info_block')) continue;
            const username = link.textContent.trim();
            if (username === currentUsername) {
                const postDiv = link.closest('div[style*="margin-top: 8pt"]');
                if (postDiv) {
                    return true;
                }
            }
        }
        
        return false;
    }
    
    // 获取当前主题所有页面的URL
    function getTopicPageUrls() {
        const urls = new Set();
        
        // 从当前URL中提取topicid和基础URL
        const currentUrlObj = new URL(window.location.href);
        const topicid = currentUrlObj.searchParams.get('topicid');
        if (!topicid) {
            console.log('未找到topicid参数');
            return [];
        }
        
        // 构建基础URL(不包含page参数,保留forumid以匹配当前页面)
        const forumid = currentUrlObj.searchParams.get('forumid');
        const baseParams = new URLSearchParams();
        baseParams.set('action', 'viewtopic');
        if (forumid) {
            baseParams.set('forumid', forumid);
        }
        baseParams.set('topicid', topicid);
        const baseUrl = `${currentUrlObj.origin}${currentUrlObj.pathname}?${baseParams.toString()}`;
        
        // 添加第一页(page=0或没有page参数)
        urls.add(baseUrl);
        
        // 从分页链接中提取所有页码
        const pageNumbers = new Set();
        const currentPageParam = currentUrlObj.searchParams.get('page');
        const currentPage = currentPageParam ? parseInt(currentPageParam, 10) : 0;
        pageNumbers.add(0); // 第一页
        pageNumbers.add(isNaN(currentPage) ? 0 : currentPage); // 当前页
        
        // 查找所有包含page参数的分页链接
        const pageLinks = document.querySelectorAll('a[href*="viewtopic"][href*="topicid="]');
        pageLinks.forEach(link => {
            const href = link.getAttribute('href');
            if (!href) return;
            
            let pageNum = null;
            
            // 先尝试用正则表达式提取(适用于相对路径和绝对路径)
            const match = href.match(/[?&]page=(\d+)/);
            if (match && match[1]) {
                pageNum = parseInt(match[1], 10);
            } else {
                // 如果正则没匹配到,尝试用URL对象解析
                try {
                    const linkUrl = new URL(href, window.location.href);
                    const pageParam = linkUrl.searchParams.get('page');
                    if (pageParam !== null) {
                        pageNum = parseInt(pageParam, 10);
                    }
                } catch (e) {
                    // 解析失败,跳过
                }
            }
            
            if (pageNum !== null && !isNaN(pageNum)) {
                pageNumbers.add(pageNum);
            }
        });
        
        // 构建所有页面的URL
        pageNumbers.forEach(pageNum => {
            if (pageNum === 0) {
                // 第一页:不添加page参数
                urls.add(baseUrl);
            } else {
                // 其他页:添加page参数
                urls.add(`${baseUrl}&page=${pageNum}`);
            }
        });
        
        console.log('找到的分页URL:', Array.from(urls));
        return Array.from(urls);
    }
    
    // 标准化URL用于比较(只保留topicid与page,忽略参数顺序)
    function normalizeUrlForCompare(url) {
        try {
            const urlObj = new URL(url, window.location.origin);
            const topicid = urlObj.searchParams.get('topicid') || '';
            const page = urlObj.searchParams.get('page') || '0';
            const path = urlObj.pathname || '/forums.php';
            return `${urlObj.origin}${path}?topicid=${topicid}&page=${page}`;
        } catch (e) {
            return url.split('#')[0];
        }
    }
    
    // 获取当前主题各分页的文档内容
    async function fetchTopicDocuments() {
        const pageUrls = getTopicPageUrls();
        if (pageUrls.length === 0) {
            return [];
        }
        
        const parser = new DOMParser();
        const currentNormalized = normalizeUrlForCompare(window.location.href);
        const documents = [];
        
        for (let url of pageUrls) {
            const normalizedUrl = normalizeUrlForCompare(url);
            const isCurrentPage = normalizedUrl === currentNormalized;
            
            if (isCurrentPage) {
                documents.unshift({ url, doc: document, isCurrentPage: true });
                continue;
            }
            
            try {
                const response = await fetch(url, {
                    credentials: 'include',
                    headers: { 'Accept': 'text/html' }
                });
                
                if (!response.ok) {
                    console.error('获取分页失败:', url, response.status);
                    continue;
                }
                
                const html = await response.text();
                const doc = parser.parseFromString(html, 'text/html');
                documents.push({ url, doc, isCurrentPage: false });
            } catch (error) {
                console.error('请求分页发生错误:', url, error);
            }
        }
        
        return documents;
    }
    
    // 检查当前用户是否已经在任意分页下注
    async function hasUserReplied() {
        const currentUsername = getCurrentUsername();
        if (!currentUsername) {
            console.log('未获取到当前用户名');
            return false;
        }
        
        const topicDocuments = await fetchTopicDocuments();
        console.log('开始检查分页下注情况,共', topicDocuments.length, '页');
        
        for (let entry of topicDocuments) {
            if (!entry.doc) continue;
            
            if (hasUserRepliedOnDocument(entry.doc, currentUsername)) {
                console.log(`检测到用户在${entry.isCurrentPage ? '当前页' : '其他分页'}已下注:`, currentUsername, entry.url);
                return true;
            } else {
                console.log('该分页未检测到下注:', entry.url);
            }
        }
        
        console.log('所有分页检查完成,未发现重复下注');
        return false;
    }

    // 禁用快速回复表单并显示提示(公共函数)
    function disableReplyForm(message, noticeClass, backgroundColor) {
        // 查找快速回复表单
        const composeForm = document.getElementById('compose');
        if (!composeForm) return false;
        
        // 查找包含快速回复的 table
        const replyTable = composeForm.closest('table');
        if (!replyTable) return false;
        
        // 禁用所有表单元素
        const formElements = composeForm.querySelectorAll('textarea, input[type="submit"], button');
        formElements.forEach(element => {
            element.disabled = true;
            element.style.opacity = '0.5';
            element.style.cursor = 'not-allowed';
        });
        
        // 检查是否已经添加过提示
        if (!replyTable.querySelector('.' + noticeClass)) {
            // 在表单顶部添加提示
            const notice = document.createElement('div');
            notice.className = noticeClass;
            notice.style.cssText = `
                background: ${backgroundColor};
                color: white;
                padding: 10px 15px;
                margin: 10px 0;
                border-radius: 5px;
                text-align: center;
                font-weight: bold;
                font-size: 14px;
            `;
            notice.textContent = message;
            
            // 在"快速回复"标题后插入提示
            const quickReplyTitle = Array.from(replyTable.querySelectorAll('b')).find(b => b.textContent === '快速回复');
            if (quickReplyTitle && quickReplyTitle.parentElement) {
                quickReplyTitle.parentElement.appendChild(notice);
            }
        }
        
        return true;
    }

    // 恢复快速回复表单(移除禁用状态和提示)
    function enableReplyForm() {
        // 查找快速回复表单
        const composeForm = document.getElementById('compose');
        if (!composeForm) return false;
        
        // 查找包含快速回复的 table
        const replyTable = composeForm.closest('table');
        if (!replyTable) return false;
        
        // 恢复所有表单元素
        const formElements = composeForm.querySelectorAll('textarea, input[type="submit"], button');
        formElements.forEach(element => {
            element.disabled = false;
            element.style.opacity = '';
            element.style.cursor = '';
        });
        
        // 移除所有提示信息
        const deadlineNotice = replyTable.querySelector('.deadline-notice');
        if (deadlineNotice) {
            deadlineNotice.remove();
        }
        
        const duplicateBetNotice = replyTable.querySelector('.duplicate-bet-notice');
        if (duplicateBetNotice) {
            duplicateBetNotice.remove();
        }
        
        console.log('已恢复快速回复表单');
        return true;
    }

    // 检查有效下注并禁用回复(合并截止时间和重复下注检查)
    async function checkValidBetAndDisableReply() {
        // 只在开关开启时检查
        if (!Config.getCheckValidBetEnabled()) {
            return;
        }
        
        // 1. 检查截止时间
        const topSpan = document.getElementById('top');
        if (topSpan) {
            const titleText = topSpan.textContent;
            // 匹配格式:截止时间:2025-11-13 21:00
            const deadlineMatch = titleText.match(/截止时间[::]\s*(\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2})/);
            
            if (deadlineMatch) {
                const deadlineStr = deadlineMatch[1];
                // 解析截止时间(北京时间)
                const deadlineDate = new Date(deadlineStr.replace(' ', 'T') + ':00+08:00');
                
                // 获取当前时间
                const now = new Date();
                
                // 如果截止时间已过
                if (now > deadlineDate) {
                    if (disableReplyForm('⚠️ 投注截止时间已过,快速回复已禁用', 'deadline-notice', '#ff5252')) {
                        console.log('截止时间已过,已禁用快速回复面板');
                    }
                    return; // 截止时间已过,不再检查重复下注
                }
            }
        }
        
        // 2. 检查是否已下注(重复下注)
        if (await hasUserReplied()) {
            if (disableReplyForm('⚠️ 您已经下注,禁止重复下注', 'duplicate-bet-notice', '#ff9800')) {
                console.log('检测到重复下注,已禁用快速回复面板');
            }
        }
    }

    const ENABLE_SPECIAL_TILES = false;

    // 全局变量:高亮帖子列表
    let highlightedPosts = [];

    // 添加收藏
    function addBookmark() {
        const currentUrl = window.location.href;
        let currentTitle = document.title || '未命名页面';
        
        // 从标题中提取引号里的内容
        const match = currentTitle.match(/"([^"]+)"/);
        if (match && match[1]) {
            currentTitle = match[1];
        } else {
            // 如果没有引号,则删掉常见的前后缀
            currentTitle = currentTitle.replace(/^HDSky :: 查看主题\s+/i, '');
            currentTitle = currentTitle.replace(/^HDSky :: /i, '');
            currentTitle = currentTitle.replace(/\s*高清视界.*$/i, '');
            currentTitle = currentTitle.replace(/\s*-\s*Powered by.*$/i, '');
        }
        
        // 获取现有收藏列表
        const bookmarks = getBookmarkList();
        
        // 检查是否已经收藏
        const exists = bookmarks.some(b => b.url === currentUrl);
        if (exists) {
            alert('该页面已经在收藏夹中了!');
            return;
        }
        
        // 添加新收藏
        bookmarks.push({
            url: currentUrl,
            title: currentTitle,
            time: new Date().toLocaleString()
        });
        
        // 保存
        saveBookmarkList(bookmarks);
        alert('收藏成功!\n标题:' + currentTitle);
    }

    // 显示收藏夹
    function showBookmarkList() {
        const bookmarks = getBookmarkList();
        
        // 移除旧的收藏夹窗口(如果存在)
        const oldDialog = document.getElementById('bookmark-dialog');
        if (oldDialog) {
            oldDialog.remove();
        }
        
        // 创建遮罩层
        const overlay = document.createElement('div');
        overlay.id = 'bookmark-dialog';
        overlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            z-index: 10003;
            display: flex;
            justify-content: center;
            align-items: center;
        `;
        
        // 创建弹窗
        const dialog = document.createElement('div');
        dialog.style.cssText = `
            background: white;
            border-radius: 10px;
            padding: 20px;
            width: 700px;
            max-width: 95vw;
            max-height: 85vh;
            overflow-y: auto;
            box-shadow: 0 4px 20px rgba(0,0,0,0.3);
        `;
        
        // 标题栏
        const header = document.createElement('div');
        header.style.cssText = `
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 2px solid #2196F3;
            background: transparent;
        `;
        
        const title = document.createElement('h2');
        title.textContent = '我的收藏夹';
        title.style.cssText = `
            margin: 0;
            padding: 0;
            color: #2196F3;
            font-size: 20px;
            background: transparent;
            border: none;
            outline: none;
        `;
        header.appendChild(title);
        
        const closeBtn = document.createElement('button');
        closeBtn.textContent = '✕';
        closeBtn.style.cssText = `
            background: #f44336;
            color: white;
            border: none;
            border-radius: 50%;
            width: 30px;
            height: 30px;
            cursor: pointer;
            font-size: 18px;
            font-weight: bold;
            transition: background 0.3s;
        `;
        closeBtn.onmouseover = () => closeBtn.style.background = '#d32f2f';
        closeBtn.onmouseout = () => closeBtn.style.background = '#f44336';
        closeBtn.onclick = () => overlay.remove();
        header.appendChild(closeBtn);
        
        dialog.appendChild(header);
        
        // 收藏列表
        if (bookmarks.length === 0) {
            const emptyMsg = document.createElement('div');
            emptyMsg.textContent = '收藏夹还是空的,快去收藏喜欢的页面吧!';
            emptyMsg.style.cssText = `
                text-align: center;
                color: #999;
                padding: 40px 20px;
                font-size: 14px;
                background: #f9f9f9;
                border-radius: 5px;
                margin-top: 10px;
            `;
            dialog.appendChild(emptyMsg);
        } else {
            bookmarks.forEach((bookmark, index) => {
                const item = createBookmarkItem(bookmark, index);
                dialog.appendChild(item);
            });
        }
        
        overlay.appendChild(dialog);
        document.body.appendChild(overlay);
        
        // 点击遮罩层关闭
        overlay.onclick = (e) => {
            if (e.target === overlay) {
                overlay.remove();
            }
        };
    }

    // 创建收藏项
    function createBookmarkItem(bookmark, index) {
        const item = document.createElement('div');
        item.style.cssText = `
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 12px;
            margin-bottom: 10px;
            background: #fafafa;
            border: 1px solid #e0e0e0;
            border-radius: 5px;
            transition: all 0.3s;
        `;
        item.onmouseover = () => {
            item.style.background = '#e3f2fd';
            item.style.borderColor = '#2196F3';
            item.style.transform = 'translateX(5px)';
            item.style.boxShadow = '0 2px 8px rgba(33, 150, 243, 0.2)';
        };
        item.onmouseout = () => {
            item.style.background = '#fafafa';
            item.style.borderColor = '#e0e0e0';
            item.style.transform = 'translateX(0)';
            item.style.boxShadow = 'none';
        };
        
        // 左侧内容区
        const content = document.createElement('div');
        content.style.cssText = `
            flex: 1;
            cursor: pointer;
            overflow: hidden;
        `;
        content.onclick = () => window.location.href = bookmark.url;
        
        const titleDiv = document.createElement('div');
        titleDiv.textContent = bookmark.title;
        titleDiv.style.cssText = `
            font-size: 14px;
            font-weight: bold;
            color: #2196F3;
            margin-bottom: 5px;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
        `;
        content.appendChild(titleDiv);
        
        const timeDiv = document.createElement('div');
        timeDiv.textContent = '收藏时间: ' + bookmark.time;
        timeDiv.style.cssText = `
            font-size: 12px;
            color: #999;
        `;
        content.appendChild(timeDiv);
        
        item.appendChild(content);
        
        // 删除按钮
        const deleteBtn = document.createElement('button');
        deleteBtn.textContent = '✕';
        deleteBtn.style.cssText = `
            background: #ff5722;
            color: white;
            border: none;
            border-radius: 50%;
            width: 25px;
            height: 25px;
            cursor: pointer;
            font-size: 14px;
            font-weight: bold;
            transition: background 0.3s;
            margin-left: 10px;
        `;
        deleteBtn.onmouseover = () => deleteBtn.style.background = '#e64a19';
        deleteBtn.onmouseout = () => deleteBtn.style.background = '#ff5722';
        deleteBtn.onclick = (e) => {
            e.stopPropagation();
            if (confirm('确定要删除这个收藏吗?\n' + bookmark.title)) {
                deleteBookmark(index);
                showBookmarkList(); // 刷新列表
            }
        };
        item.appendChild(deleteBtn);
        
        return item;
    }

    // 删除收藏
    function deleteBookmark(index) {
        const bookmarks = getBookmarkList();
        bookmarks.splice(index, 1);
        saveBookmarkList(bookmarks);
    }

    // 处理关注列表点击(编辑)
    function handleFollowListClick() {
        const currentList = getSpecialFollowList();
        const currentStr = currentList.join(',');
        
        const input = prompt('请输入特殊关注名单(用逗号分隔):\n例如: DFBCOLD19,李知恩', currentStr);
        
        if (input !== null) { // 用户点击了确定(包括空字符串)
            const newList = input.split(',').map(name => name.trim()).filter(name => name);
            saveSpecialFollowList(newList);
            
            alert('特殊关注名单已更新!\n当前关注: ' + (newList.length > 0 ? newList.join(', ') : '无'));
            
            // 重新应用高亮
            autoHighlightFollowedPosts();
            renderSpecialFollowTiles();
        }
    }

    // 自动高亮特殊关注用户的帖子(页面加载时调用)
    function autoHighlightFollowedPosts() {
        // 如果开关关闭,清除高亮并退出
        if (!Config.getHighlightFollowEnabled()) {
            clearHighlights();
            return;
        }
        
        const followList = getSpecialFollowList();
        
        // 如果没有关注名单,不执行高亮
        if (followList.length === 0) {
            return;
        }
        
        // 先清除之前的高亮
        clearHighlights();
        
        // 找到所有回复帖子(每个帖子在一个带有 margin-top 和 margin-bottom 的 div 中)
        const allPosts = document.querySelectorAll('div[style*="margin-top: 8pt"]');
        
        // 重置高亮列表
        highlightedPosts = [];
        
        allPosts.forEach(post => {
            // 在帖子中查找用户名链接
            const userLinks = post.querySelectorAll('a[href*="userdetails.php"]');
            let isFollowedUser = false;
            
            userLinks.forEach(link => {
                const username = link.textContent.trim();
                // 检查是否在关注列表中
                if (followList.some(followName => username === followName)) {
                    isFollowedUser = true;
                }
            });
            
            if (isFollowedUser) {
                // 高亮显示关注用户的信息div
                post.style.background = '#fffacd';
                post.style.border = '2px solid #ffd700';
                post.style.borderRadius = '5px';
                post.style.padding = '5px';
                
                // 找到并高亮div内部的table
                const innerTables = post.querySelectorAll('table');
                innerTables.forEach(table => {
                    table.style.background = '#fff8dc';
                    table.style.border = '2px solid #ffb700';
                });
                
                // 标记为已高亮
                post.dataset.highlighted = 'true';
                
                // 找到并高亮紧跟在div后面的回复内容table(class="main")
                let nextElement = post.nextElementSibling;
                if (nextElement && nextElement.tagName === 'TABLE' && nextElement.classList.contains('main')) {
                    nextElement.style.background = '#fff8dc';
                    nextElement.style.border = '2px solid #ffb700';
                    nextElement.style.borderRadius = '5px';
                    // 标记这个table也被高亮了
                    nextElement.dataset.highlightedContent = 'true';
                }
                
                // 添加到高亮列表
                highlightedPosts.push(post);
            }
        });
    }

    // 清除所有高亮
    function clearHighlights() {
        // 找到所有被高亮的帖子div
        const posts = document.querySelectorAll('div[data-highlighted="true"]');
        
        posts.forEach(post => {
            // 清除div的高亮样式
            post.style.background = '';
            post.style.border = '';
            post.style.borderRadius = '';
            post.style.padding = '';
            post.removeAttribute('data-highlighted');
            
            // 清除div内部table的高亮样式
            const tables = post.querySelectorAll('table');
            tables.forEach(table => {
                table.style.background = '';
                table.style.border = '';
            });
        });
        
        // 清除所有被高亮的回复内容table
        const contentTables = document.querySelectorAll('table[data-highlighted-content="true"]');
        contentTables.forEach(table => {
            table.style.background = '';
            table.style.border = '';
            table.style.borderRadius = '';
            table.removeAttribute('data-highlighted-content');
        });
        
        // 重置全局变量
        highlightedPosts = [];
    }

    // 移除特殊关注磁贴容器
    function removeSpecialFollowTiles() {
        const existing = document.getElementById('special-follow-tile-container');
        if (existing) {
            existing.remove();
        }
    }

    // 记录文档中特殊关注用户的回帖信息
    function recordFollowRepliesFromDocument(doc, pageUrl, followSet, collectedMap, isCurrentPage) {
        if (!doc) return;

        const posts = doc.querySelectorAll('div[style*="margin-top: 8pt"]');
        posts.forEach(post => {
            // 查找帖子中的所有用户名链接
            const userLinks = post.querySelectorAll('a[href*="userdetails.php?id"]');
            userLinks.forEach(link => {
                const username = link.textContent.trim();
                if (!username || !followSet.has(username) || collectedMap.has(username)) {
                    return;
                }

                // 查找带有 pid 的元素,用于定位锚点
                let anchorId = '';
                const pidElement = post.querySelector('[id^="pid"]') || post.querySelector('table[id^="pid"]');
                if (pidElement && pidElement.id) {
                    anchorId = pidElement.id;
                } else {
                    const pidLink = post.querySelector('a[href*="#pid"]');
                    if (pidLink) {
                        const hashMatch = pidLink.getAttribute('href').match(/#(pid\d+)/);
                        if (hashMatch && hashMatch[1]) {
                            anchorId = hashMatch[1];
                        }
                    }
                }

                let targetUrl = pageUrl;
                const anchorNoHash = anchorId ? anchorId.replace('#', '') : '';
                if (anchorNoHash) {
                    try {
                        const urlObj = new URL(pageUrl);
                        urlObj.hash = `#${anchorNoHash}`;
                        targetUrl = urlObj.href;
                    } catch (e) {
                        targetUrl = `${pageUrl.split('#')[0]}#${anchorNoHash}`;
                    }
                }

                collectedMap.set(username, {
                    username,
                    targetUrl,
                    anchorId: anchorNoHash,
                    isOnCurrentPage: isCurrentPage && !!(anchorNoHash && document.getElementById(anchorNoHash)),
                    pageUrl
                });
            });
        });
    }

    // 收集特殊关注用户的回帖数据(遍历所有分页)
    async function collectSpecialFollowReplies(followList) {
        const followSet = new Set(followList);
        const collectedMap = new Map();
        
        const topicDocuments = await fetchTopicDocuments();
        for (let entry of topicDocuments) {
            if (!entry.doc) continue;
            
            recordFollowRepliesFromDocument(
                entry.doc,
                entry.url,
                followSet,
                collectedMap,
                entry.isCurrentPage
            );
            
            if (collectedMap.size === followSet.size) {
                break; // 已经找到所有关注用户
            }
        }
        
        return Array.from(collectedMap.values());
    }

    // 点击磁贴时滚动或跳转
    function handleFollowTileClick(tileInfo) {
        if (tileInfo.isOnCurrentPage && tileInfo.anchorId) {
            const target = document.getElementById(tileInfo.anchorId);
            if (target) {
                target.scrollIntoView({ behavior: 'smooth', block: 'start' });
                target.style.boxShadow = '0 0 10px 2px rgba(33,150,243,0.6)';
                setTimeout(() => {
                    target.style.boxShadow = '';
                }, 2000);
                return;
            }
        }

        // 如果不在当前页,跳转到对应链接
        window.location.href = tileInfo.targetUrl;
    }

    // 渲染特殊关注磁贴
    async function renderSpecialFollowTiles() {
        if (!ENABLE_SPECIAL_TILES) {
            removeSpecialFollowTiles();
            return;
        }
        removeSpecialFollowTiles();

        const urlParams = new URLSearchParams(window.location.search);
        if (urlParams.get('action') !== 'viewtopic') {
            return;
        }

        const followList = getSpecialFollowList();
        if (followList.length === 0) {
            return;
        }

        const tileData = await collectSpecialFollowReplies(followList);
        if (tileData.length === 0) {
            return;
        }

        const container = document.createElement('div');
        container.id = 'special-follow-tile-container';
        container.style.cssText = `
            position: fixed;
            right: 10px;
            top: 50%;
            transform: translateY(-50%);
            display: flex;
            flex-direction: column;
            gap: 10px;
            z-index: 10000;
        `;

        tileData.forEach(info => {
            const tile = document.createElement('div');
            tile.className = 'special-follow-tile';
            tile.textContent = info.username;
            tile.style.cssText = `
                background: #fff;
                border: 1px solid #2196F3;
                border-radius: 8px;
                padding: 10px 14px;
                font-size: 13px;
                font-weight: bold;
                color: #2196F3;
                cursor: pointer;
                box-shadow: 0 2px 6px rgba(0,0,0,0.15);
                transition: transform 0.2s, box-shadow 0.2s;
                min-width: 120px;
                text-align: center;
            `;

            tile.onmouseover = () => {
                tile.style.transform = 'translateX(-4px)';
                tile.style.boxShadow = '0 4px 10px rgba(33,150,243,0.3)';
            };
            tile.onmouseout = () => {
                tile.style.transform = 'translateX(0)';
                tile.style.boxShadow = '0 2px 6px rgba(0,0,0,0.15)';
            };

            tile.onclick = () => handleFollowTileClick(info);

            container.appendChild(tile);
        });

        document.body.appendChild(container);
    }

    // 自动加载下一页功能
    let isLoadingNextPage = false;
    const scrollThreshold = 800; // 距离底部多少像素时触发加载

    function autoLoadNextPage() {
        if (!Config.getAutoLoadEnabled()) {
            return;
        }

        // 检查URL中是否包含topicid参数
        const urlParams = new URLSearchParams(window.location.search);
        if (!urlParams.has('topicid')) {
            return;
        }

        let lastScrollTop = 0;
        
        window.addEventListener('scroll', function() {
            const scrollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;
            const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
            const clientHeight = document.documentElement.clientHeight || window.innerHeight;
            
            // 只在向下滚动时触发
            if (scrollTop > lastScrollTop) {
                // 判断是否接近底部
                if (scrollHeight <= clientHeight + scrollTop + scrollThreshold && !isLoadingNextPage) {
                    // 查找下一页链接
                    const nextLinks = document.querySelectorAll('a');
                    let nextPageLink = null;
                    
                    for (let link of nextLinks) {
                        const text = link.textContent.trim();
                        if (text.includes('下一页') || text === '下一页 >>') {
                            nextPageLink = link;
                            break;
                        }
                    }
                    
                    if (nextPageLink && nextPageLink.href) {
                        loadNextPage(nextPageLink.href);
                    }
                }
            }
            
            lastScrollTop = scrollTop;
        }, false);
    }

    function loadNextPage(url) {
        isLoadingNextPage = true;
        
        // 显示加载提示
        const loadingDiv = document.createElement('div');
        loadingDiv.id = 'auto-loading-indicator';
        loadingDiv.style.cssText = `
            position: fixed;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            background: rgba(33, 150, 243, 0.9);
            color: white;
            padding: 12px 24px;
            border-radius: 25px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.3);
            z-index: 9999;
            font-size: 14px;
            font-weight: bold;
        `;
        loadingDiv.textContent = '正在加载下一页...';
        document.body.appendChild(loadingDiv);
        
        // 使用 fetch 加载下一页
        fetch(url)
            .then(response => response.text())
            .then(html => {
                const parser = new DOMParser();
                const doc = parser.parseFromString(html, 'text/html');
                
                // 查找主要内容区域 - 找到所有回复帖子
                const newPosts = doc.querySelectorAll('div[style*="margin-top: 8pt"]');
                
                // 找到当前页面的最后一个帖子
                const currentPosts = document.querySelectorAll('div[style*="margin-top: 8pt"]');
                if (currentPosts.length > 0 && newPosts.length > 0) {
                    const lastPost = currentPosts[currentPosts.length - 1];
                    
                    // 找到最后一个帖子的下一个 table(回复内容)
                    let lastTable = lastPost.nextElementSibling;
                    while (lastTable && lastTable.tagName !== 'TABLE') {
                        lastTable = lastTable.nextElementSibling;
                    }
                    
                    // 确定插入位置:如果有 table 就在 table 后面,否则在 div 后面
                    let insertAfter = lastTable || lastPost;
                    
                    // 将新帖子插入到页面中
                    newPosts.forEach(post => {
                        // 克隆 div(用户信息)
                        const clonedPost = post.cloneNode(true);
                        insertAfter.parentNode.insertBefore(clonedPost, insertAfter.nextSibling);
                        insertAfter = clonedPost;
                        
                        // 查找并克隆紧跟的 table(回复内容)
                        const nextTable = post.nextElementSibling;
                        if (nextTable && nextTable.tagName === 'TABLE' && nextTable.classList.contains('main')) {
                            const clonedTable = nextTable.cloneNode(true);
                            insertAfter.parentNode.insertBefore(clonedTable, insertAfter.nextSibling);
                            insertAfter = clonedTable;
                        }
                    });
                    
                    // 更新页码导航(找到所有 <p align="center"> 中包含"上一页"和"下一页"的元素)
                    const newPagers = doc.querySelectorAll('p[align="center"]');
                    const currentPagers = document.querySelectorAll('p[align="center"]');
                    
                    // 遍历并更新所有分页器
                    let pagerUpdateCount = 0;
                    for (let i = 0; i < currentPagers.length && i < newPagers.length; i++) {
                        const currentPager = currentPagers[i];
                        const newPager = newPagers[i];
                        
                        // 检查是否包含分页链接(包含"上一页"或"下一页")
                        if (currentPager.innerHTML.includes('上一页') || currentPager.innerHTML.includes('下一页')) {
                            currentPager.innerHTML = newPager.innerHTML;
                            pagerUpdateCount++;
                        }
                    }
                    
                    console.log(`已更新 ${pagerUpdateCount} 个分页导航`);
                    
                    // 重新应用高亮
                    autoHighlightFollowedPosts();
                    renderSpecialFollowTiles();
                    enhanceAuthorRemarks();
                    
                    loadingDiv.textContent = '✓ 加载完成';
                    loadingDiv.style.background = 'rgba(76, 175, 80, 0.9)';
                    
                    setTimeout(() => {
                        loadingDiv.remove();
                    }, 2000);
                    
                    // 更新 URL(不刷新页面)
                    history.pushState(null, '', url);
                } else {
                    loadingDiv.textContent = '没有更多内容了';
                    loadingDiv.style.background = 'rgba(255, 152, 0, 0.9)';
                    setTimeout(() => {
                        loadingDiv.remove();
                    }, 2000);
                }
                
                isLoadingNextPage = false;
            })
            .catch(error => {
                console.error('加载下一页失败:', error);
                loadingDiv.textContent = '✗ 加载失败';
                loadingDiv.style.background = 'rgba(244, 67, 54, 0.9)';
                setTimeout(() => {
                    loadingDiv.remove();
                }, 2000);
                isLoadingNextPage = false;
            });
    }


    // 提取收藏夹中所有URL的topicid并打印到控制台
    function printBookmarkTopicIds() {
        const bookmarks = getBookmarkList();
        const topicIds = [];
        
        bookmarks.forEach(bookmark => {
            try {
                const url = new URL(bookmark.url);
                const topicid = url.searchParams.get('topicid');
                if (topicid) {
                    topicIds.push(topicid);
                }
            } catch (e) {
                // 如果URL格式不正确,尝试用正则表达式提取
                const match = bookmark.url.match(/topicid=(\d+)/);
                if (match && match[1]) {
                    topicIds.push(match[1]);
                }
            }
        });
        
        if (topicIds.length > 0) {
            console.log('收藏夹中的topicid列表:');
            console.log(topicIds);
            console.log('topicid列表(逗号分隔):' + topicIds.join(','));
        } else {
            console.log('收藏夹中没有找到包含topicid的URL');
        }
        
        return topicIds;
    }

    // 将函数暴露到全局,方便在控制台中手动调用
    window.printBookmarkTopicIds = printBookmarkTopicIds;

    // 在embedded左侧添加星星标记收藏的帖子
    function highlightTopicIdRows() {
        // 只在URL包含viewforum时生效
        const urlParams = new URLSearchParams(window.location.search);
        if (urlParams.get('action') !== 'viewforum') {
            return;
        }
        
        // 获取收藏夹中的topicid列表
        const bookmarks = getBookmarkList();
        const topicIds = [];
        
        bookmarks.forEach(bookmark => {
            try {
                const url = new URL(bookmark.url);
                const topicid = url.searchParams.get('topicid');
                if (topicid) {
                    topicIds.push(topicid);
                }
            } catch (e) {
                // 如果URL格式不正确,尝试用正则表达式提取
                const match = bookmark.url.match(/topicid=(\d+)/);
                if (match && match[1]) {
                    topicIds.push(match[1]);
                }
            }
        });
        
        if (topicIds.length === 0) {
            return; // 如果没有收藏的topicid,不执行标记
        }
        
        // 查找所有包含topicid链接的embedded元素
        const embeddedTds = document.querySelectorAll('td.embedded');
        
        embeddedTds.forEach(td => {
            // 查找td中所有包含topicid的链接
            const links = td.querySelectorAll('a[href*="topicid"]');
            
            links.forEach(link => {
                // 从链接中提取topicid
                const href = link.getAttribute('href');
                const match = href.match(/topicid[=&](\d+)/);
                
                if (match && match[1]) {
                    const topicid = match[1];
                    
                    // 如果这个topicid在收藏列表中,添加星星
                    if (topicIds.includes(topicid)) {
                        // 检查是否已经添加过星星
                        if (!td.querySelector('.bookmark-star')) {
                            // 创建星星元素
                            const star = document.createElement('span');
                            star.className = 'bookmark-star';
                            star.textContent = '⭐';
                            star.title = '已收藏';
                            star.style.cssText = `
                                margin-right: 5px;
                                font-size: 14px;
                                cursor: pointer;
                            `;
                            
                            // 在embedded的左侧插入星星(在所有内容之前)
                            td.insertBefore(star, td.firstChild);
                        }
                    }
                }
            });
        });
        
        console.log(`已标记 ${document.querySelectorAll('.bookmark-star').length} 个收藏的帖子`);
    }

    // 清理下注文本,移除【数字】或[数字]等前缀
    function sanitizeBetValue(value) {
        if (!value) {
            return '';
        }
        return value
            .replace(/[\[【]\s*[\d.]+\s*[\]】]/g, '')
            .replace(/\s+/g, ' ')
            .trim();
    }

    // 采集帖子下注数据
    function collectBetPostsData() {
        const postTables = document.querySelectorAll('table[id^="pid"]');
        const results = [];
        let maxBetIndex = 0;
        let skipFirstPost = true;

        postTables.forEach(table => {
            if (!table.id || table.id.endsWith('body')) {
                return;
            }
            if (skipFirstPost) {
                skipFirstPost = false;
                return;
            }
            const userLink = table.querySelector('a[href*="userdetails.php?id="]');
            if (!userLink) {
                return;
            }
            const username = (userLink.textContent || '').trim();
            const body = document.getElementById(`${table.id}body`);
            if (!body) {
                return;
            }
            const textContent = body.innerText || '';
            const lines = textContent.split(/\r?\n/).map(line => line.trim()).filter(line => line);
            const betMap = {};
            let betAmount = '';

            lines.forEach(line => {
                const match = line.match(/^(\d+)\.(?:下注球队|下注球隊)[::]\s*(.+)$/);
                if (match) {
                    const index = parseInt(match[1], 10);
                    if (!isNaN(index)) {
                        const sanitized = sanitizeBetValue(match[2]);
                        if (sanitized) {
                            betMap[index] = sanitized;
                        }
                        if (index > maxBetIndex) {
                            maxBetIndex = index;
                        }
                    }
                    return;
                }
                if (!betAmount) {
                    const betMatch = line.match(/下注点数[::]\s*([\d,]+)/);
                    if (betMatch && betMatch[1]) {
                        betAmount = betMatch[1].replace(/,/g, '');
                    }
                }
            });

            if (Object.keys(betMap).length === 0) {
                return;
            }

            results.push({
                username,
                bets: betMap,
                betAmount,
                anchorId: table.id || ''
            });
        });

        return {
            rows: results,
            maxBetIndex
        };
    }

    // 渲染数据分析表格
    function renderDataAnalysisTable(dataRows, maxBetIndex, container, onlyFollow) {
        container.innerHTML = '';
        const followList = new Set(getSpecialFollowList());
        const filteredRows = onlyFollow ? dataRows.filter(row => followList.has(row.username)) : dataRows.slice();

        if (filteredRows.length === 0) {
            const empty = document.createElement('div');
            empty.style.cssText = `
                padding: 40px 20px;
                text-align: center;
                color: #999;
                font-size: 14px;
            `;
            empty.textContent = onlyFollow ? '特殊关注列表中没有匹配的下注记录。' : '当前页面未找到下注记录。';
            container.appendChild(empty);
            return;
        }

        const table = document.createElement('table');
        table.style.cssText = `
            width: 100%;
            border-collapse: separate;
            border-spacing: 0;
            font-size: 13px;
            background: #fff;
            border-radius: 8px;
            overflow: hidden;
        `;

        const thead = document.createElement('thead');
        const headerRow = document.createElement('tr');
        headerRow.style.background = '#f5f5f5';

        const userTh = document.createElement('th');
        userTh.textContent = '用户名';
        userTh.style.cssText = 'border: 1px solid #ddd; padding: 8px; width: 120px;';
        headerRow.appendChild(userTh);

        for (let i = 1; i <= maxBetIndex; i++) {
            const th = document.createElement('th');
            th.textContent = i;
            th.style.cssText = 'border: 1px solid #ddd; padding: 8px;';
            headerRow.appendChild(th);
        }
        const betAmountTh = document.createElement('th');
        betAmountTh.textContent = '下注点数';
        betAmountTh.style.cssText = 'border: 1px solid #ddd; padding: 8px; width: 100px;';
        headerRow.appendChild(betAmountTh);

        thead.appendChild(headerRow);
        table.appendChild(thead);

        const tbody = document.createElement('tbody');

        const columnTopMap = new Map();
        for (let i = 1; i <= maxBetIndex; i++) {
            const freq = new Map();
            filteredRows.forEach(row => {
                const val = (row.bets[i] || '').trim();
                if (!val) return;
                freq.set(val, (freq.get(val) || 0) + 1);
            });
            let topValue = '';
            let topCount = 0;
            freq.forEach((count, val) => {
                if (count > topCount) {
                    topValue = val;
                    topCount = count;
                }
            });
            columnTopMap.set(i, { value: topValue, count: topCount });
        }

        filteredRows.forEach(row => {
            const tr = document.createElement('tr');
            tr.style.background = '#fff';

            const userTd = document.createElement('td');
            userTd.style.cssText = 'border: 1px solid #ddd; padding: 8px; font-weight: bold; color: #2196F3;';
            const anchorLink = document.createElement('a');
            anchorLink.textContent = row.username;
            anchorLink.style.cssText = 'color: #2196F3; text-decoration: none; cursor: pointer;';
            anchorLink.title = '点击跳转到该用户的楼层';
            anchorLink.onclick = () => {
                if (row.anchorId) {
                    const target = document.getElementById(row.anchorId);
                    if (target) {
                        target.scrollIntoView({ behavior: 'smooth', block: 'start' });
                        target.style.boxShadow = '0 0 12px rgba(33,150,243,0.7)';
                        setTimeout(() => target.style.boxShadow = '', 2000);
                    } else {
                        window.location.href = `#${row.anchorId}`;
                    }
                }
                const overlay = document.getElementById('data-analysis-dialog');
                if (overlay) {
                    overlay.remove();
                }
            };
            userTd.appendChild(anchorLink);
            tr.appendChild(userTd);

            for (let i = 1; i <= maxBetIndex; i++) {
                const td = document.createElement('td');
                const value = row.bets[i] || '';
                td.textContent = value;
                td.style.cssText = 'border: 1px solid #eee; padding: 8px;';
                const topInfo = columnTopMap.get(i);
                if (topInfo && topInfo.value && value === topInfo.value) {
                    td.style.background = '#fff7d6';
                    td.style.fontWeight = 'bold';
                    td.style.color = '#e65100';
                }
                tr.appendChild(td);
            }
            const betAmountTd = document.createElement('td');
            betAmountTd.textContent = row.betAmount || '';
            betAmountTd.style.cssText = 'border: 1px solid #ddd; padding: 8px; text-align: right;';
            tr.appendChild(betAmountTd);

            tbody.appendChild(tr);
        });

        table.appendChild(tbody);

        const summaryRow = document.createElement('tr');
        summaryRow.style.background = '#e3f2fd';

        const summaryLabel = document.createElement('td');
        summaryLabel.textContent = '最常见';
        summaryLabel.style.cssText = 'border: 1px solid #ddd; padding: 8px; font-weight: bold;';
        summaryRow.appendChild(summaryLabel);

        for (let i = 1; i <= maxBetIndex; i++) {
            const td = document.createElement('td');
            const info = columnTopMap.get(i);
            if (info && info.value) {
                td.textContent = `${info.value}(${info.count}次)`;
                td.style.fontWeight = 'bold';
                td.style.color = '#0d47a1';
            } else {
                td.textContent = '无数据';
                td.style.color = '#999';
            }
            td.style.cssText = (td.style.cssText || '') + 'border: 1px solid #ddd; padding: 8px;';
            summaryRow.appendChild(td);
        }
        const summaryBetTd = document.createElement('td');
        summaryBetTd.textContent = '—';
        summaryBetTd.style.cssText = 'border: 1px solid #ddd; padding: 8px; text-align: center; color: #777;';
        summaryRow.appendChild(summaryBetTd);

        if (tbody.firstChild) {
            tbody.insertBefore(summaryRow, tbody.firstChild);
        } else {
            tbody.appendChild(summaryRow);
        }

        // 构建最常见下注文本
        const popularLines = [];
        for (let i = 1; i <= maxBetIndex; i++) {
            const info = columnTopMap.get(i);
            if (info && info.value) {
                popularLines.push(`${i}.下注球隊: [0.9]${info.value}`);
            }
        }

        const textAreaWrapper = document.createElement('div');
        textAreaWrapper.style.cssText = 'margin-top: 12px;';

        const textAreaLabel = document.createElement('div');
        textAreaLabel.textContent = '最常见下注组合:';
        textAreaLabel.style.cssText = 'font-weight: bold; margin-bottom: 6px;';
        textAreaWrapper.appendChild(textAreaLabel);

        const summaryTextarea = document.createElement('textarea');
        summaryTextarea.readOnly = true;
        summaryTextarea.style.cssText = `
            width: 98%;
            min-height: 160px;
            border: 1px solid #ccc;
            border-radius: 6px;
            padding: 10px;
            font-size: 13px;
            line-height: 1.5;
            resize: vertical;
        `;

        if (popularLines.length > 0) {
            popularLines.push('', '下注点数:1000000');
            summaryTextarea.value = popularLines.join('\n');
        } else {
            summaryTextarea.value = '暂无可用的最常见下注数据';
        }
        summaryTextarea.style.height = 'auto';
        summaryTextarea.style.height = Math.max(200, summaryTextarea.scrollHeight) + 'px';

        textAreaWrapper.appendChild(summaryTextarea);
        container.appendChild(textAreaWrapper);
        const divider = document.createElement('hr');
        divider.style.cssText = 'border: none; border-top: 1px dashed #ccc; margin: 16px 0;';
        container.appendChild(divider);
        container.appendChild(table);
        return summaryTextarea;
    }

    // 打开数据分析弹窗
    function openDataAnalysisDialog() {
        const { rows, maxBetIndex } = collectBetPostsData();
        if (!rows || rows.length === 0) {
            alert('当前页面未找到下注内容,无法生成数据分析。');
            return;
        }

        const existing = document.getElementById('data-analysis-dialog');
        if (existing) {
            existing.remove();
        }

        const overlay = document.createElement('div');
        overlay.id = 'data-analysis-dialog';
        overlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.5);
            z-index: 10003;
            display: flex;
            justify-content: center;
            align-items: center;
        `;

        const dialog = document.createElement('div');
        dialog.style.cssText = `
            background: white;
            border-radius: 10px;
            padding: 20px;
            width: 1200px;
            max-width: 95vw;
            max-height: 90vh;
            overflow-y: auto;
            box-shadow: 0 4px 20px rgba(0,0,0,0.3);
        `;

        const header = document.createElement('div');
        header.style.cssText = `
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
            padding-bottom: 10px;
            border-bottom: 2px solid #2196F3;
            background: transparent;
        `;

        const title = document.createElement('h2');
        title.textContent = '下注数据分析';
        title.style.cssText = `
            margin: 0;
            padding: 0;
            color: #2196F3;
            font-size: 20px;
            background: transparent;
            border: none;
            outline: none;
        `;
        header.appendChild(title);

        const closeBtn = document.createElement('button');
        closeBtn.textContent = '✕';
        closeBtn.style.cssText = `
            background: #f44336;
            color: white;
            border: none;
            border-radius: 50%;
            width: 30px;
            height: 30px;
            cursor: pointer;
            font-size: 18px;
            font-weight: bold;
            transition: background 0.3s;
        `;
        closeBtn.onmouseover = () => closeBtn.style.background = '#d32f2f';
        closeBtn.onmouseout = () => closeBtn.style.background = '#f44336';
        closeBtn.onclick = () => overlay.remove();
        header.appendChild(closeBtn);

        const controlBar = document.createElement('div');
        controlBar.style.cssText = `
            display: flex;
            justify-content: flex-start;
            gap: 10px;
            align-items: center;
            margin-bottom: 10px;
        `;

        let summaryTextareaRef = null;
        const followBtn = document.createElement('button');
        followBtn.textContent = '只看特殊关注:关闭';
        followBtn.style.cssText = `
            padding: 6px 12px;
            border: 1px solid #2196F3;
            background: #fff;
            color: #2196F3;
            border-radius: 4px;
            cursor: pointer;
            transition: box-shadow 0.2s;
        `;
        const copyAnswerBtn = document.createElement('button');
        copyAnswerBtn.textContent = '复制答案';
        copyAnswerBtn.style.cssText = `
            padding: 6px 12px;
            border: 1px solid #4caf50;
            background: #fff;
            color: #4caf50;
            border-radius: 4px;
            cursor: pointer;
            transition: box-shadow 0.2s;
        `;
        const tableWrapper = document.createElement('div');
        tableWrapper.style.cssText = `
            border: 1px solid #ddd;
            border-radius: 8px;
            padding: 10px;
            background: #fafafa;
            max-height: 70vh;
            overflow: auto;
        `;

        let onlyFollow = Config.get('dataAnalysisOnlyFollow', false);

        const refreshTable = () => {
            followBtn.textContent = `只看特殊关注:${onlyFollow ? '开启' : '关闭'}`;
            followBtn.style.background = onlyFollow ? '#2196F3' : '#fff';
            followBtn.style.color = onlyFollow ? '#fff' : '#2196F3';
            summaryTextareaRef = renderDataAnalysisTable(rows, maxBetIndex, tableWrapper, onlyFollow);
        };

        followBtn.onclick = () => {
            onlyFollow = !onlyFollow;
            Config.set('dataAnalysisOnlyFollow', onlyFollow);
            refreshTable();
        };
        copyAnswerBtn.onclick = () => {
            if (!summaryTextareaRef) return;
            const text = summaryTextareaRef.value;
            navigator.clipboard.writeText(text).then(() => {
                copyAnswerBtn.textContent = '已复制';
                setTimeout(() => copyAnswerBtn.textContent = '复制答案', 1500);
            }).catch(() => {
                alert('复制失败,请手动复制。');
            });
        };
        const addHoverEffect = (btn, baseColor) => {
            btn.onmouseover = () => btn.style.boxShadow = '0 0 8px rgba(0,0,0,0.15)';
            btn.onmouseout = () => btn.style.boxShadow = '';
        };
        addHoverEffect(followBtn);
        addHoverEffect(copyAnswerBtn);

        controlBar.appendChild(followBtn);
        controlBar.appendChild(copyAnswerBtn);

        dialog.appendChild(header);
        dialog.appendChild(controlBar);
        dialog.appendChild(tableWrapper);
        overlay.appendChild(dialog);
        document.body.appendChild(overlay);

        overlay.addEventListener('click', event => {
            if (event.target === overlay) {
                overlay.remove();
            }
        });

        refreshTable();
    }

    // 更新单个帖子行的备注展示(通过按钮文字体现)
    function updateUserNoteDisplayForTd(td, note) {
        const remarkBtn = td.querySelector('.author-remark-btn');
        if (!remarkBtn) {
            return;
        }

        if (note) {
            remarkBtn.textContent = `备注:${note}`;
            remarkBtn.style.fontWeight = 'bold';
        } else {
            remarkBtn.textContent = '备注';
            remarkBtn.style.fontWeight = 'normal';
        }
    }

    // 刷新指定用户的全部备注展示
    function refreshUserNoteDisplayByUserId(userId) {
        const note = getUserNoteById(userId);
        document.querySelectorAll(`td.embedded[data-user-id="${userId}"]`).forEach(td => {
            updateUserNoteDisplayForTd(td, note);
        });
    }

    // 为帖子添加备注按钮与展示
    function enhanceAuthorRemarks() {
        const urlParams = new URLSearchParams(window.location.search);
        if (urlParams.get('action') !== 'viewtopic') {
            return;
        }

        const embeddedTds = document.querySelectorAll('td.embedded');
        embeddedTds.forEach(td => {
            if (td.dataset.remarkBound === '1') {
                return;
            }

            const userLink = td.querySelector('a[href*="userdetails.php?id="]');
            if (!userLink) {
                return;
            }

            const userHref = userLink.getAttribute('href') || '';
            let userId = '';
            try {
                userId = new URL(userHref, window.location.href).searchParams.get('id') || '';
            } catch (e) {
                const match = userHref.match(/id=(\d+)/);
                if (match && match[1]) {
                    userId = match[1];
                }
            }

            if (!userId) {
                return;
            }

            const authorLink = Array.from(td.querySelectorAll('a[href*="authorid="]')).find(link => {
                const href = link.getAttribute('href') || '';
                try {
                    const authorId = new URL(href, window.location.href).searchParams.get('authorid');
                    return authorId === userId;
                } catch (e) {
                    const match = href.match(/authorid=(\d+)/);
                    return match && match[1] === userId;
                }
            });

            if (!authorLink) {
                return;
            }

            td.dataset.remarkBound = '1';
            td.dataset.userId = userId;

            const remarkBtn = document.createElement('button');
            remarkBtn.className = 'author-remark-btn';
            remarkBtn.textContent = '备注';
            remarkBtn.style.cssText = `
                padding: 0 4px;
                border: none;
                background: transparent;
                color: #1e73c1;
                cursor: pointer;
                font-size: 12px;
                text-decoration: none;
                font-weight: normal;
            `;

            remarkBtn.addEventListener('click', event => {
                event.preventDefault();
                event.stopPropagation();
                const username = (userLink.textContent || '').trim();
                const currentNote = getUserNoteById(userId);
                const result = prompt(`请输入对 ${username || '该用户'} 的备注(留空删除):`, currentNote);
                if (result === null) {
                    return;
                }
                const trimmed = result.trim();
                setUserNoteById(userId, trimmed);
                refreshUserNoteDisplayByUserId(userId);
            });

            authorLink.insertAdjacentElement('afterend', remarkBtn);
            const separator = document.createElement('font');
            separator.color = 'gray';
            separator.textContent = '\u00A0\u00A0|\u00A0';
            remarkBtn.parentNode.insertBefore(separator, remarkBtn);
            updateUserNoteDisplayForTd(td, getUserNoteById(userId));
        });
    }

    // 检查指定topicid的帖子是否已下注(检查所有分页),同时收集特殊关注用户
    async function checkTopicBetStatus(topicid) {
        const currentUsername = getCurrentUsername();
        if (!currentUsername) {
            return { hasBet: false, followUsers: [] };
        }

        const followList = getSpecialFollowList();
        const followSet = new Set(followList);
        const foundUsers = new Set();
        let hasBet = false;

        // 构建基础URL
        const baseUrl = `${window.location.origin}/forums.php?action=viewtopic&topicid=${topicid}`;
        
        // 先检查第一页
        try {
            const response = await fetch(baseUrl, { 
                credentials: 'include',
                headers: { 'Accept': 'text/html' }
            });
            
            if (!response.ok) {
                return { hasBet: false, followUsers: [] };
            }
            
            const html = await response.text();
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');
            
            // 检查第一页是否已下注
            if (hasUserRepliedOnDocument(doc, currentUsername)) {
                hasBet = true;
            }
            
            // 收集第一页中的特殊关注用户
            if (followSet.size > 0) {
                const userLinks = doc.querySelectorAll('a[href*="userdetails.php?id"]');
                userLinks.forEach(link => {
                    if (link.closest('#info_block')) return; // 跳过当前用户信息
                    const username = link.textContent.trim();
                    if (followSet.has(username)) {
                        foundUsers.add(username);
                    }
                });
            }
            
            // 从第一页获取所有分页链接
            const pageNumbers = new Set();
            pageNumbers.add(0); // 第一页
            
            const pageLinks = doc.querySelectorAll('a[href*="viewtopic"][href*="topicid="]');
            pageLinks.forEach(link => {
                const href = link.getAttribute('href');
                if (!href) return;
                
                const match = href.match(/[?&]page=(\d+)/);
                if (match && match[1]) {
                    const pageNum = parseInt(match[1], 10);
                    if (!isNaN(pageNum)) {
                        pageNumbers.add(pageNum);
                    }
                }
            });
            
            // 检查其他分页
            for (let pageNum of pageNumbers) {
                if (pageNum === 0) continue; // 第一页已经检查过了
                
                const pageUrl = `${baseUrl}&page=${pageNum}`;
                try {
                    const pageResponse = await fetch(pageUrl, { 
                        credentials: 'include',
                        headers: { 'Accept': 'text/html' }
                    });
                    
                    if (pageResponse.ok) {
                        const pageHtml = await pageResponse.text();
                        const pageDoc = parser.parseFromString(pageHtml, 'text/html');
                        
                        // 检查该分页是否已下注
                        if (!hasBet && hasUserRepliedOnDocument(pageDoc, currentUsername)) {
                            hasBet = true;
                        }
                        
                        // 收集该分页中的特殊关注用户
                        if (followSet.size > 0) {
                            const pageUserLinks = pageDoc.querySelectorAll('a[href*="userdetails.php?id"]');
                            pageUserLinks.forEach(link => {
                                if (link.closest('#info_block')) return;
                                const username = link.textContent.trim();
                                if (followSet.has(username)) {
                                    foundUsers.add(username);
                                }
                            });
                        }
                    }
                } catch (e) {
                    // 忽略单个分页的错误,继续检查其他分页
                }
            }
        } catch (error) {
            console.error(`检查topicid ${topicid} 时发生错误:`, error);
        }
        
        return { 
            hasBet, 
            followUsers: Array.from(foundUsers) 
        };
    }

    // 在论坛列表页面标记每个帖子是否已下注
    async function markTopicBetStatus() {
        // 只在viewforum页面生效
        const urlParams = new URLSearchParams(window.location.search);
        if (urlParams.get('action') !== 'viewforum') {
            return;
        }

        const currentUsername = getCurrentUsername();
        if (!currentUsername) {
            console.log('未获取到当前用户名,无法检查下注状态');
            return;
        }

        // 查找所有帖子链接(主题链接,不是分页链接)
        // 主题链接通常包含forumid参数,或者不包含page参数
        const topicLinks = document.querySelectorAll('td.embedded a[href*="viewtopic"][href*="topicid="]');
        const topicMap = new Map(); // 用于去重,key是topicid,value是链接元素

        topicLinks.forEach(link => {
            const href = link.getAttribute('href');
            if (!href) return;

            // 只处理主题链接(不包含page参数,且不是分页链接)
            // 分页链接通常格式是:?action=viewtopic&topicid=xxx&page=0
            // 主题链接通常格式是:?action=viewtopic&forumid=xx&topicid=xxx 或 ?action=viewtopic&topicid=xxx(没有page参数)
            if (href.includes('page=') || href.includes('page=p')) {
                return; // 跳过分页链接
            }

            // 提取topicid
            const match = href.match(/topicid=(\d+)/);
            if (match && match[1]) {
                const topicid = match[1];
                
                // 每个topicid只保留第一个链接(避免重复检查)
                if (!topicMap.has(topicid)) {
                    topicMap.set(topicid, link);
                }
            }
        });

        console.log(`找到 ${topicMap.size} 个帖子,开始检查下注状态...`);

        // 对每个帖子检查是否已下注
        for (let [topicid, link] of topicMap) {
            // 检查是否已经添加过标记
            const parent = link.closest('td.embedded');
            if (!parent) continue;
            
            if (parent.querySelector('.bet-status-mark')) {
                continue; // 已经标记过,跳过
            }

            // 异步检查下注状态和特殊关注用户
            checkTopicBetStatus(topicid).then(({ hasBet, followUsers }) => {
                // 检查标记是否已存在(防止重复添加)
                if (parent.querySelector('.bet-status-mark')) {
                    return;
                }

                // 创建标记元素
                const mark = document.createElement('span');
                mark.className = 'bet-status-mark';
                mark.textContent = hasBet ? '【已下注】' : '【未下注】';
                mark.style.cssText = `
                    margin-left: 8px;
                    font-size: 12px;
                    font-weight: bold;
                    color: ${hasBet ? '#4caf50' : '#ff9800'};
                `;
                mark.title = hasBet ? '您已在此帖子下注' : '您尚未在此帖子下注';

                // 在链接后面插入标记
                // 如果链接后面有其他元素(如分页链接),插入到链接和分页链接之间
                link.parentNode.insertBefore(mark, link.nextSibling);
                
                // 如果有特殊关注用户回复,显示用户名列表
                if (followUsers && followUsers.length > 0) {
                    const followMark = document.createElement('span');
                    followMark.className = 'follow-users-mark';
                    followMark.textContent = ` [${followUsers.join(',')}]`;
                    followMark.style.cssText = `
                        margin-left: 4px;
                        font-size: 12px;
                        color: #2196F3;
                        font-weight: bold;
                    `;
                    followMark.title = '在此帖子回复过的特殊关注用户';
                    mark.parentNode.insertBefore(followMark, mark.nextSibling);
                }
            }).catch(err => {
                console.error(`检查topicid ${topicid} 下注状态失败:`, err);
            });
        }
    }

    // 初始化
    function init() {
        // 等待页面加载完成
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', () => {
                createControlPanel();
                autoHighlightFollowedPosts();
                autoLoadNextPage();
                checkValidBetAndDisableReply().catch(err => {
                    console.error('检查有效下注时发生错误:', err);
                }); // 检查有效下注(截止时间和重复下注)
                printBookmarkTopicIds(); // 打印收藏夹中的topicid列表
                highlightTopicIdRows(); // 高亮包含topicid的行
                markTopicBetStatus(); // 标记论坛列表页面每个帖子的下注状态
                renderSpecialFollowTiles(); // 渲染特殊关注磁贴
                enhanceAuthorRemarks(); // 添加备注按钮与展示
            });
        } else {
            createControlPanel();
            autoHighlightFollowedPosts();
            autoLoadNextPage();
            checkValidBetAndDisableReply().catch(err => {
                console.error('检查有效下注时发生错误:', err);
            }); // 检查有效下注(截止时间和重复下注)
            printBookmarkTopicIds(); // 打印收藏夹中的topicid列表
            highlightTopicIdRows(); // 高亮包含topicid的行
            markTopicBetStatus(); // 标记论坛列表页面每个帖子的下注状态
            renderSpecialFollowTiles(); // 渲染特殊关注磁贴
            enhanceAuthorRemarks(); // 添加备注按钮与展示
        }
    }

    // 启动脚本
    init();
})();