Greasy Fork

Greasy Fork is available in English.

linux.do 小助手(增强版)

自动浏览、点赞、只看楼主、楼层号、保存帖子到本地、清爽模式、用户信息展示(批量展示)。支持拖动和隐藏控制面板。支持 linux.do 和 idcflare.com

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name        linux.do 小助手(增强版)
// @description 自动浏览、点赞、只看楼主、楼层号、保存帖子到本地、清爽模式、用户信息展示(批量展示)。支持拖动和隐藏控制面板。支持 linux.do 和 idcflare.com
// @namespace    https://example.com/userscripts
// @match       https://linux.do/*
// @match       https://idcflare.com/*
// @grant       none
// @version     1.3.0
// @author      quantumcat & nulluser & enhanced
// @license     MIT
// @icon        https://www.google.com/s2/favicons?domain=linux.do
// ==/UserScript==

// 获取当前站点域名
const CURRENT_DOMAIN = window.location.hostname;
const BASE_URL = `https://${CURRENT_DOMAIN}`;

// 配置项
const CONFIG = {
    scroll: {
        minSpeed: 10,
        maxSpeed: 15,
        minDistance: 2,
        maxDistance: 4,
        checkInterval: 500,
        fastScrollChance: 0.08,
        fastScrollMin: 80,
        fastScrollMax: 200
    },
    time: {
        browseTime: 3600000,
        restTime: 600000,
        minPause: 300,
        maxPause: 500,
        loadWait: 1500,
    },
    article: {
        commentLimit: 1000,
        topicListLimit: 100,
        retryLimit: 3
    },
    levelRequirements: {
        0: { // 0级升1级
            topics_entered: 5,
            posts_read_count: 30,
            time_read: 600 // 10分钟 = 600秒
        },
        1: { // 1级升2级
            days_visited: 15,
            likes_given: 1,
            likes_received: 1,
            post_count: 3,
            topics_entered: 20,
            posts_read_count: 100,
            time_read: 3600 // 60分钟 = 3600秒
        }
    },
    mustRead: {
        posts: [
            {
                id: '1051',
                url: 'https://linux.do/t/topic/1051/'
            },
            {
                id: '5973',
                url: 'https://linux.do/t/topic/5973'
            },
            {
                id: '102770',
                url: 'https://linux.do/t/topic/102770'
            },
            {
                id: '154010',
                url: 'https://linux.do/t/topic/154010'
            },
            {
                id: '149576',
                url: 'https://linux.do/t/topic/149576'
            },
            {
                id: '22118',
                url: 'https://linux.do/t/topic/22118'
            },
        ],
        likesNeeded: 5
    }
};

// 工具函数
const Utils = {
    random: (min, max) => Math.floor(Math.random() * (max - min + 1)) + min,
    sleep: (ms) => new Promise(resolve => setTimeout(resolve, ms)),
    isPageLoaded: () => {
        const loadingElements = document.querySelectorAll('.loading, .infinite-scroll');
        return loadingElements.length === 0;
    },
    isNearBottom: () => {
        const {scrollHeight, clientHeight, scrollTop} = document.documentElement;
        return (scrollTop + clientHeight) >= (scrollHeight - 200);
    },
    debounce: (func, wait) => {
        let timeout;
        return function(...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), wait);
        };
    }
};

// 存储管理
const Storage = {
    get: (key, defaultValue = null) => {
        try {
            const value = localStorage.getItem(key);
            return value ? JSON.parse(value) : defaultValue;
        } catch {
            return defaultValue;
        }
    },
    set: (key, value) => {
        try {
            localStorage.setItem(key, JSON.stringify(value));
            return true;
        } catch (error) {
            console.error('Storage error:', error);
            return false;
        }
    }
};

// 用户信息助手类
class UserInfoHelper {
    constructor() {
        this.userInfoCache = new Map();
        this.pendingRequests = new Map();
        this.TRUST_LEVEL_LABELS = {
            0: 'Lv0',
            1: 'Lv1',
            2: 'Lv2',
            3: 'Lv3',
            4: 'Lv4'
        };
        this.DAY_IN_MS = 24 * 60 * 60 * 1000;
        this.revealInProgress = false;
        this.isEnabled = true; // 用户信息展示是否启用
        this.observer = null;
        
        this.init();
    }
    
    enable() {
        this.isEnabled = true;
        this.init();
    }
    
    disable() {
        this.isEnabled = false;
        if (this.observer) {
            this.observer.disconnect();
            this.observer = null;
        }
    }
    
    init() {
        if (!this.isEnabled) return;
        
        // 如果已有观察器,先断开
        if (this.observer) {
            this.observer.disconnect();
        }
        
        // 使用防抖,避免频繁触发
        const debouncedEnhance = this.debounce(() => {
            if (this.isEnabled) {
                this.enhanceUserInfo();
            }
        }, 300);
        
        // 监听页面变化,自动为新加载的用户添加信息
        this.observer = new MutationObserver(() => {
            if (this.isEnabled) {
                debouncedEnhance();
            }
        });
        
        this.observer.observe(document.body, {
            childList: true,
            subtree: true
        });
        
        // 初始增强
        this.enhanceUserInfo();
    }
    
    debounce(func, wait) {
        let timeout;
        return function(...args) {
            clearTimeout(timeout);
            timeout = setTimeout(() => func.apply(this, args), wait);
        };
    }
    
    isTopicPage() {
        return window.location.pathname.includes('/t/topic/');
    }
    
    async enhanceUserInfo() {
        if (!this.isTopicPage()) return;
        
        const articles = document.querySelectorAll('.topic-post article');
        for (const article of articles) {
            const anchor = article.querySelector('.names a[data-user-card]');
            if (!anchor) continue;
            
            const slug = anchor.getAttribute('data-user-card');
            if (!slug) continue;
            
            const normalizedSlug = slug.trim().toLowerCase();
            
            // 检查是否已经添加过信息
            if (article.querySelector(`.user-reg-info[data-user="${normalizedSlug}"]`)) {
                continue;
            }
            
            // 检查是否是第一楼(楼主)
            const postWrapper = article.closest('.topic-post');
            const postNumber = postWrapper?.getAttribute('data-post-number');
            const isFirstPost = postNumber === '1';
            
            // 第一楼直接显示,其他楼添加按钮
            if (isFirstPost) {
                await this.loadAndDisplayUserInfo(anchor, slug, normalizedSlug);
            } else {
                this.addInfoButton(anchor, slug, normalizedSlug);
            }
        }
    }
    
    addInfoButton(anchor, rawSlug, normalizedSlug) {
        const namesContainer = anchor.closest('.names');
        if (!namesContainer) return;
        
        // 检查是否已有按钮或信息
        if (namesContainer.querySelector(`.user-info-btn[data-user="${normalizedSlug}"]`)) {
            return;
        }
        
        // 如果已经有信息节点,不添加按钮
        if (namesContainer.querySelector(`.user-reg-info[data-user="${normalizedSlug}"]`)) {
            return;
        }
        
        const button = document.createElement('button');
        button.className = 'user-info-btn';
        button.setAttribute('data-user', normalizedSlug);
        button.setAttribute('data-raw-slug', rawSlug);
        button.textContent = '📊';
        button.title = '点击查看用户注册信息';
        button.style.cssText = `
            margin-left: 6px;
            font-size: 14px;
            cursor: pointer;
            background: none;
            border: none;
            padding: 2px 4px;
            opacity: 0.6;
            transition: opacity 0.2s;
            vertical-align: middle;
        `;
        
        button.addEventListener('mouseenter', () => {
            button.style.opacity = '1';
        });
        
        button.addEventListener('mouseleave', () => {
            button.style.opacity = '0.6';
        });
        
        button.addEventListener('click', async (e) => {
            e.preventDefault();
            e.stopPropagation();
            if (button.disabled) return;
            
            button.disabled = true;
            button.textContent = '⏳';
            
            try {
                await this.loadAndDisplayUserInfo(anchor, rawSlug, normalizedSlug);
                // 成功后按钮会被 loadAndDisplayUserInfo 中移除
            } catch (error) {
                console.error('加载用户信息失败:', error);
                button.textContent = '📊';
                button.disabled = false;
            }
        });
        
        anchor.insertAdjacentElement('afterend', button);
        
        // 添加"查看话题"按钮
        this.addTopicsButton(anchor, rawSlug, normalizedSlug);
    }
    
    addTopicsButton(anchor, rawSlug, normalizedSlug) {
        const namesContainer = anchor.closest('.names');
        if (!namesContainer) return;
        
        // 检查是否已有话题按钮
        if (namesContainer.querySelector(`.user-topics-btn[data-user="${normalizedSlug}"]`)) {
            return;
        }
        
        const topicsBtn = document.createElement('a');
        topicsBtn.className = 'user-topics-btn';
        topicsBtn.setAttribute('data-user', normalizedSlug);
        topicsBtn.href = `${BASE_URL}/u/${rawSlug}/activity/topics`;
        topicsBtn.target = '_blank';
        topicsBtn.textContent = '查看话题';
        topicsBtn.title = '查看该用户的话题';
        topicsBtn.style.cssText = `
            margin-left: 6px;
            font-size: 12px;
            cursor: pointer;
            text-decoration: none;
            padding: 2px 6px;
            opacity: 0.7;
            transition: all 0.2s;
            vertical-align: middle;
            display: inline-block;
            color: #667eea;
            background: rgba(102, 126, 234, 0.1);
            border-radius: 4px;
        `;
        
        topicsBtn.addEventListener('mouseenter', () => {
            topicsBtn.style.opacity = '1';
            topicsBtn.style.background = 'rgba(102, 126, 234, 0.2)';
        });
        
        topicsBtn.addEventListener('mouseleave', () => {
            topicsBtn.style.opacity = '0.7';
            topicsBtn.style.background = 'rgba(102, 126, 234, 0.1)';
        });
        
        // 插入到信息按钮后面
        const infoBtn = namesContainer.querySelector(`.user-info-btn[data-user="${normalizedSlug}"]`);
        if (infoBtn) {
            infoBtn.insertAdjacentElement('afterend', topicsBtn);
        } else {
            anchor.insertAdjacentElement('afterend', topicsBtn);
        }
    }
    
    async loadAndDisplayUserInfo(anchor, slug, normalizedSlug) {
        const namesContainer = anchor.closest('.names');
        if (!namesContainer) return;
        
        // 再次检查是否已经存在,避免重复
        const existingInfo = namesContainer.querySelector(`.user-reg-info[data-user="${normalizedSlug}"]`);
        if (existingInfo) {
            console.log(`用户 ${normalizedSlug} 信息已存在,跳过`);
            // 确保按钮被移除
            const button = namesContainer.querySelector(`.user-info-btn[data-user="${normalizedSlug}"]`);
            if (button) button.remove();
            return;
        }
        
        const info = await this.fetchUserInfo(slug, normalizedSlug);
        if (!info) {
            // 获取失败,恢复按钮
            const button = namesContainer.querySelector(`.user-info-btn[data-user="${normalizedSlug}"]`);
            if (button) {
                button.textContent = '📊';
                button.disabled = false;
            }
            return;
        }
        
        const infoNode = this.buildInfoNode(info, normalizedSlug);
        if (!infoNode) {
            // 构建失败,恢复按钮
            const button = namesContainer.querySelector(`.user-info-btn[data-user="${normalizedSlug}"]`);
            if (button) {
                button.textContent = '📊';
                button.disabled = false;
            }
            return;
        }
        
        // 最后一次检查,确保在异步等待期间没有被其他调用添加
        const finalCheck = namesContainer.querySelector(`.user-reg-info[data-user="${normalizedSlug}"]`);
        if (finalCheck) {
            console.log(`用户 ${normalizedSlug} 信息在等待期间已被添加,跳过`);
            // 移除按钮
            const button = namesContainer.querySelector(`.user-info-btn[data-user="${normalizedSlug}"]`);
            if (button) button.remove();
            return;
        }
        
        // 先移除信息按钮
        const button = namesContainer.querySelector(`.user-info-btn[data-user="${normalizedSlug}"]`);
        if (button) button.remove();
        
        // 添加信息节点
        anchor.insertAdjacentElement('afterend', infoNode);
        
        // 确保话题按钮存在(如果还没有添加)
        if (!namesContainer.querySelector(`.user-topics-btn[data-user="${normalizedSlug}"]`)) {
            this.addTopicsButton(anchor, slug, normalizedSlug);
        }
    }
    
    async fetchUserInfo(slug, normalizedSlug) {
        // 检查缓存
        if (this.userInfoCache.has(normalizedSlug)) {
            return this.userInfoCache.get(normalizedSlug);
        }
        
        // 检查是否正在请求
        if (this.pendingRequests.has(normalizedSlug)) {
            return this.pendingRequests.get(normalizedSlug);
        }
        
        // 创建请求
        const requestPromise = this.doFetchUserInfo(slug, normalizedSlug);
        this.pendingRequests.set(normalizedSlug, requestPromise);
        
        try {
            const info = await requestPromise;
            if (info) {
                this.userInfoCache.set(normalizedSlug, info);
            }
            return info;
        } finally {
            this.pendingRequests.delete(normalizedSlug);
        }
    }
    
    async doFetchUserInfo(slug, normalizedSlug) {
        try {
            // 使用两个API并行请求,与原脚本保持一致
            const PROFILE_API_BUILDERS = [
                (s) => `${BASE_URL}/u/${encodeURIComponent(s)}.json`,
                (s) => `${BASE_URL}/users/${encodeURIComponent(s)}.json`,
            ];
            
            const SUMMARY_API_BUILDERS = [
                (s) => `${BASE_URL}/u/${encodeURIComponent(s)}/summary.json`,
                (s) => `${BASE_URL}/users/${encodeURIComponent(s)}/summary.json`,
            ];
            
            const [profileData, summaryData] = await Promise.all([
                this.fetchFirstAvailable(PROFILE_API_BUILDERS, slug),
                this.fetchFirstAvailable(SUMMARY_API_BUILDERS, slug),
            ]);
            
            if (!profileData && !summaryData) {
                return null;
            }
            
            const user = profileData && (profileData.user || profileData);
            const summary = summaryData && (summaryData.user_summary || summaryData.summary || summaryData);
            
            const createdAt = this.pickCreatedAt(user) || (summary && this.pickCreatedAt(summary));
            if (!createdAt) {
                return null;
            }
            
            const topicCount = this.pickFirstNumber(
                user && (user.topic_count ?? user.topicCount),
                summary && (summary.topic_count ?? summary.topics_count),
            );
            
            const totalPostCount = this.pickFirstNumber(
                user && (user.post_count ?? user.postCount),
                summary && (summary.post_count ?? summary.posts_count),
            );
            
            let repliesCount = this.pickFirstNumber(
                summary && (summary.replies_count ?? summary.reply_count),
            );
            if (repliesCount === null && totalPostCount !== null && topicCount !== null) {
                repliesCount = Math.max(0, totalPostCount - topicCount);
            }
            
            const trustLevelRaw = this.pickFirstValue(
                user && (user.trust_level ?? user.trustLevel),
                summary && (summary.trust_level ?? summary.trustLevel),
            );
            const trustLevel = this.normalizeTrustLevel(trustLevelRaw);
            
            const days = this.calcDays(createdAt);
            
            return {
                slug: normalizedSlug,
                createdAt,
                days,
                topicCount: typeof topicCount === 'number' && Number.isFinite(topicCount) ? topicCount : undefined,
                repliesCount: typeof repliesCount === 'number' && Number.isFinite(repliesCount) ? repliesCount : undefined,
                trustLevel
            };
        } catch (error) {
            console.error('获取用户信息失败:', slug, error);
            return null;
        }
    }
    
    async fetchFirstAvailable(builders, slug) {
        for (const builder of builders) {
            const url = builder(slug);
            const data = await this.safeFetchJson(url);
            if (data) {
                return data;
            }
        }
        return null;
    }
    
    async safeFetchJson(url) {
        try {
            const response = await fetch(url, { credentials: 'include' });
            if (!response.ok) {
                return null;
            }
            return await response.json();
        } catch (error) {
            return null;
        }
    }
    
    pickFirstNumber(...values) {
        for (const value of values) {
            const numberValue = Number(value);
            if (!Number.isNaN(numberValue)) {
                return numberValue;
            }
        }
        return null;
    }
    
    pickFirstValue(...values) {
        for (const value of values) {
            if (value !== undefined && value !== null) {
                return value;
            }
        }
        return null;
    }
    
    normalizeTrustLevel(raw) {
        if (raw === undefined || raw === null) {
            return undefined;
        }
        
        if (typeof raw === 'number' && Number.isFinite(raw)) {
            return raw;
        }
        
        if (typeof raw === 'string') {
            const TRUST_LEVEL_ALIAS = {
                newuser: 0,
                basic: 1,
                member: 2,
                regular: 3,
                leader: 4,
            };
            const alias = TRUST_LEVEL_ALIAS[raw.toLowerCase()];
            if (alias !== undefined) {
                return alias;
            }
            const numeric = Number(raw);
            if (!Number.isNaN(numeric)) {
                return numeric;
            }
        }
        
        return undefined;
    }
    
    pickCreatedAt(source) {
        if (!source) {
            return null;
        }
        return (
            source.created_at ||
            source.createdAt ||
            source.registration_date ||
            source.registrationDate ||
            source.joined ||
            source.joinedAt ||
            null
        );
    }
    
    calcDays(createdAt) {
        const createdTime = new Date(createdAt).getTime();
        if (Number.isNaN(createdTime)) {
            return 0;
        }
        const diff = Date.now() - createdTime;
        return Math.max(0, Math.floor(diff / this.DAY_IN_MS));
    }
    
    buildInfoNode(info, normalizedSlug) {
        const segments = [`注册 ${this.formatNumber(info.days)} 天`];
        
        if (typeof info.topicCount === 'number' && Number.isFinite(info.topicCount)) {
            segments.push(`发帖 ${this.formatNumber(info.topicCount)}`);
        }
        
        if (typeof info.repliesCount === 'number' && Number.isFinite(info.repliesCount)) {
            segments.push(`回帖 ${this.formatNumber(info.repliesCount)}`);
        }
        
        if (typeof info.trustLevel === 'number' && Number.isFinite(info.trustLevel)) {
            const FULL_TRUST_LEVEL_LABELS = {
                0: 'Lv0 新手',
                1: 'Lv1 入门',
                2: 'Lv2 成员',
                3: 'Lv3 常驻',
                4: 'Lv4 领袖',
            };
            const label = FULL_TRUST_LEVEL_LABELS[info.trustLevel] || `信任级别 Lv${info.trustLevel}`;
            segments.push(label);
        }
        
        if (!segments.length) {
            return null;
        }
        
        const span = document.createElement('span');
        span.className = 'user-reg-info';
        span.setAttribute('data-user', normalizedSlug);
        span.textContent = ` · ${segments.join(' · ')}`;
        span.style.cssText = `
            margin-left: 6px;
            font-size: 12px;
            color: #1a4c7c;
        `;
        
        return span;
    }
    
    formatNumber(value) {
        return Number(value).toLocaleString('zh-CN');
    }
    
    // 批量展示所有已加载的回复用户信息
    async revealAllVisibleReplies() {
        if (!this.isTopicPage()) return;
        if (this.revealInProgress) return;
        
        this.revealInProgress = true;
        
        try {
            const articles = document.querySelectorAll('.topic-post article');
            
            for (let index = 0; index < articles.length; index++) {
                const article = articles[index];
                
                // 跳过第一楼(楼主)
                const postWrapper = article.closest('.topic-post');
                const postNumber = postWrapper?.getAttribute('data-post-number');
                if (postNumber === '1') continue;
                
                const anchor = article.querySelector('.names a[data-user-card]');
                if (!anchor) continue;
                
                const slug = anchor.getAttribute('data-user-card');
                if (!slug) continue;
                
                const normalizedSlug = slug.trim().toLowerCase();
                const namesContainer = anchor.closest('.names');
                if (!namesContainer) continue;
                
                // 检查是否已经展示过
                const hasInfo = namesContainer.querySelector(`.user-reg-info[data-user="${normalizedSlug}"]`);
                if (hasInfo) {
                    // 移除可能残留的按钮
                    const button = namesContainer.querySelector(`.user-info-btn[data-user="${normalizedSlug}"]`);
                    if (button) button.remove();
                    continue;
                }
                
                // 加载并显示用户信息
                await this.loadAndDisplayUserInfo(anchor, slug, normalizedSlug);
            }
        } catch (error) {
            console.error('批量展示用户信息失败:', error);
        } finally {
            this.revealInProgress = false;
        }
    }
}

class BrowseController {
    constructor() {
        this.isScrolling = false;
        this.scrollInterval = null;
        this.pauseTimeout = null;
        this.trustLevelMonitorInterval = null; // 等级监控定时器

        // 使用 sessionStorage 存储窗口独立的状态
        this.accumulatedTime = this.getSessionStorage('accumulatedTime', 0);
        this.lastActionTime = Date.now();
        this.isTopicPage = window.location.href.includes("/t/topic/");
        this.autoRunning = this.getSessionStorage('autoRunning', false);
        this.topicList = this.getSessionStorage('topicList', []);

        // 使用 localStorage 存储全局共享的状态
        this.firstUseChecked = Storage.get('firstUseChecked', false);
        this.likesCount = Storage.get('likesCount', 0);
        this.selectedPost = Storage.get('selectedPost', null);
        this.autoLikeEnabled = Storage.get('autoLikeEnabled', false);
        this.cleanModeEnabled = Storage.get('cleanModeEnabled', false);
        this.likedTopics = Storage.get('likedTopics', []);
        this.panelMinimized = Storage.get('panelMinimized', false);
        this.panelPosition = Storage.get('panelPosition', { x: null, y: null });
        this.likeResumeTime = Storage.get('likeResumeTime', null);
        this.currentUsername = null; // 当前用户名
        this.lastDetectedUser = null; // 上次检测到的用户名(用于账号切换检测)

        // 检查是否到达恢复点赞的时间
        this.checkLikeResumeTime();
        // 监听点赞限制弹窗
        this.observeLikeLimit();

        this.setupButton();
        this.loadUserTrustLevel(); // 加载用户信任等级
        this.startUserSwitchMonitoring(); // 启动账号切换监控
        this.initFloorNumberDisplay();
        this.setupWindowResizeHandler(); // 设置窗口大小调整处理
        this.applyCleanModeStyles();
        this.initOnlyOwnerView();

        if (!this.firstUseChecked) {
            this.handleFirstUse();
        } else if (this.autoRunning) {
            if (this.isTopicPage) {
                this.startScrolling();
                if (this.autoLikeEnabled) {
                    this.autoLikeTopic();
                }
            } else {
                this.getLatestTopics().then(() => this.navigateNextTopic());
            }
        }

        if (this.autoLikeEnabled && this.isTopicPage) {
            this.autoLikeTopic();
        }
        
        // 初始化用户信息助手 - 默认启用,让每个窗口独立工作
        this.userInfoHelper = new UserInfoHelper();
        
        // 启动等级监控(60秒刷新一次)- 默认启用
        this.startTrustLevelMonitor();
    }

    // 启动等级监控(60秒刷新一次)
    startTrustLevelMonitor() {
        // 如果已经有定时器在运行,先清除
        if (this.trustLevelMonitorInterval) {
            clearInterval(this.trustLevelMonitorInterval);
        }
        
        this.trustLevelMonitorInterval = setInterval(() => {
            console.log('自动刷新等级信息...');
            this.loadUserTrustLevel(false);
        }, 60000); // 60秒
        
        console.log('等级监控已启动(60秒刷新一次)');
    }
    
    // 停止等级监控
    stopTrustLevelMonitor() {
        if (this.trustLevelMonitorInterval) {
            clearInterval(this.trustLevelMonitorInterval);
            this.trustLevelMonitorInterval = null;
            console.log('等级监控已停止');
        }
    }

    // sessionStorage 辅助方法(用于窗口独立状态)
    getSessionStorage(key, defaultValue = null) {
        try {
            const value = sessionStorage.getItem(key);
            return value ? JSON.parse(value) : defaultValue;
        } catch {
            return defaultValue;
        }
    }

    setSessionStorage(key, value) {
        try {
            sessionStorage.setItem(key, JSON.stringify(value));
            return true;
        } catch (error) {
            console.error('SessionStorage error:', error);
            return false;
        }
    }

    addGlobalStyles() {
        const style = document.createElement('style');
        style.textContent = `
            .linuxdo-helper-panel {
                position: fixed;
                right: 20px;
                top: 50%;
                transform: translateY(-50%);
                width: 280px;
                min-width: 280px;
                max-height: calc(100vh - 40px);
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                border-radius: 16px;
                box-shadow: 0 10px 40px rgba(0, 0, 0, 0.3);
                z-index: 99999;
                font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
                overflow-y: auto;
                overflow-x: hidden;
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
                backdrop-filter: blur(10px);
                will-change: transform;
            }

            .linuxdo-helper-panel:hover {
                box-shadow: 0 15px 50px rgba(0, 0, 0, 0.4);
                transform: translateY(-2px);
            }

            .linuxdo-helper-panel.minimized {
                width: 280px;
            }

            .panel-header {
                background: rgba(255, 255, 255, 0.15);
                padding: 12px 16px;
                cursor: move;
                display: flex;
                justify-content: space-between;
                align-items: center;
                user-select: none;
                border-bottom: 1px solid rgba(255, 255, 255, 0.2);
            }

            .panel-header:active {
                cursor: grabbing;
            }

            .panel-title {
                color: white;
                font-weight: 600;
                font-size: 14px;
                text-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
            }

            .panel-controls {
                display: flex;
                gap: 8px;
            }

            .panel-control-btn {
                width: 24px;
                height: 24px;
                border-radius: 6px;
                border: none;
                background: rgba(255, 255, 255, 0.2);
                color: white;
                cursor: pointer;
                font-size: 14px;
                display: flex;
                align-items: center;
                justify-content: center;
                transition: all 0.2s;
                padding: 0;
                line-height: 1;
            }

            .panel-control-btn:hover {
                background: rgba(255, 255, 255, 0.3);
                transform: scale(1.1);
            }

            .panel-control-btn:active {
                transform: scale(0.95);
            }

            .panel-content {
                padding: 12px;
                display: flex;
                flex-direction: column;
                gap: 6px;
                transition: all 0.3s;
                overflow: hidden;
            }

            .panel-content.hidden {
                max-height: 0;
                padding: 0 16px;
            }

            .main-action-btn {
                width: 100%;
                padding: 8px 12px;
                font-size: 13px;
                font-weight: 600;
                background: white;
                color: #667eea;
                border: none;
                border-radius: 8px;
                cursor: pointer;
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
                display: flex;
                align-items: center;
                justify-content: center;
                gap: 5px;
                white-space: nowrap;
                overflow: hidden;
                min-height: 32px;
                line-height: 1.1;
            }
            
            .main-action-btn .btn-text {
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                flex: 1;
                min-width: 0;
            }
            
            .main-action-btn .btn-icon {
                flex-shrink: 0;
                font-size: 14px;
            }

            .main-action-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
            }

            .main-action-btn:active {
                transform: translateY(0);
            }

            .main-action-btn.running {
                background: #ff6b6b;
                color: white;
            }

            .btn-icon {
                font-size: 18px;
            }

            .trust-level-row {
                background: rgba(255, 255, 255, 0.15);
                padding: 8px 12px;
                border-radius: 10px;
                margin-top: 8px;
            }

            .trust-level-header {
                color: white;
                font-size: 13px;
                font-weight: 600;
                margin-bottom: 6px;
                text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
                display: flex;
                justify-content: space-between;
                align-items: center;
            }

            .trust-level-refresh {
                background: rgba(255, 255, 255, 0.2);
                border: none;
                color: white;
                padding: 4px 8px;
                border-radius: 4px;
                cursor: pointer;
                font-size: 11px;
                transition: all 0.2s;
            }

            .trust-level-refresh:hover {
                background: rgba(255, 255, 255, 0.3);
                transform: scale(1.05);
            }

            .trust-level-refresh:disabled {
                opacity: 0.5;
                cursor: not-allowed;
            }

            .trust-level-item {
                display: flex;
                justify-content: space-between;
                align-items: center;
                color: rgba(255, 255, 255, 0.9);
                font-size: 11px;
                margin: 4px 0;
                padding: 3px 0;
            }

            .trust-level-name {
                flex: 1;
            }

            .trust-level-progress {
                display: flex;
                align-items: center;
                gap: 6px;
            }

            .trust-level-bar {
                width: 60px;
                height: 6px;
                background: rgba(255, 255, 255, 0.2);
                border-radius: 3px;
                overflow: hidden;
            }

            .trust-level-bar-fill {
                height: 100%;
                background: linear-gradient(90deg, #48bb78 0%, #68d391 100%);
                transition: width 0.3s;
            }

            .trust-level-bar-fill.completed {
                background: linear-gradient(90deg, #4299e1 0%, #63b3ed 100%);
            }

            .trust-level-value {
                font-size: 10px;
                color: rgba(255, 255, 255, 0.8);
                min-width: 50px;
                text-align: right;
            }

            .trust-level-loading {
                color: rgba(255, 255, 255, 0.7);
                font-size: 11px;
                text-align: center;
                padding: 8px 0;
            }

            .random-floor-btn, .reveal-users-btn {
                width: 100%;
                padding: 7px 12px;
                font-size: 12px;
                font-weight: 600;
                background: rgba(255, 255, 255, 0.95);
                color: #667eea;
                border: none;
                border-radius: 8px;
                cursor: pointer;
                box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
                transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
                display: flex;
                align-items: center;
                justify-content: center;
                gap: 6px;
                white-space: nowrap;
                overflow: hidden;
                text-overflow: ellipsis;
                min-height: 28px;
                line-height: 1.2;
                margin-bottom: 6px;
            }
            
            .reveal-users-btn {
                margin-bottom: 0;
            }
            
            .random-floor-btn .btn-text,
            .reveal-users-btn .btn-text {
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
                flex: 1;
                min-width: 0;
            }
            
            .random-floor-btn .btn-icon,
            .reveal-users-btn .btn-icon {
                flex-shrink: 0;
                font-size: 13px;
            }

            .random-floor-btn:hover, .reveal-users-btn:hover {
                transform: translateY(-2px);
                box-shadow: 0 6px 20px rgba(0, 0, 0, 0.25);
                background: rgba(255, 255, 255, 1);
            }

            .random-floor-btn:active, .reveal-users-btn:active {
                transform: translateY(0);
            }
            
            .reveal-users-btn:disabled {
                opacity: 0.6;
                cursor: not-allowed;
                transform: none !important;
            }

            .toggle-row {
                background: rgba(255, 255, 255, 0.15);
                padding: 5px 10px;
                border-radius: 8px;
                display: flex;
                justify-content: space-between;
                align-items: center;
                transition: all 0.2s;
                min-height: 26px;
            }

            .toggle-row:hover {
                background: rgba(255, 255, 255, 0.22);
            }

            .toggle-label {
                color: white;
                font-size: 12px;
                font-weight: 500;
                text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
            }

            .toggle-switch {
                position: relative;
                width: 36px;
                height: 20px;
                flex-shrink: 0;
            }

            .toggle-switch input {
                opacity: 0;
                width: 0;
                height: 0;
            }

            .toggle-slider {
                position: absolute;
                cursor: pointer;
                top: 0;
                left: 0;
                right: 0;
                bottom: 0;
                background-color: rgba(255, 255, 255, 0.3);
                transition: 0.3s;
                border-radius: 26px;
            }

            .toggle-slider:before {
                position: absolute;
                content: "";
                height: 14px;
                width: 14px;
                left: 3px;
                bottom: 3px;
                background-color: white;
                transition: 0.3s;
                border-radius: 50%;
                box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
            }

            .toggle-switch input:checked + .toggle-slider {
                background-color: rgba(76, 175, 80, 0.8);
            }

            .toggle-switch input:checked + .toggle-slider:before {
                transform: translateX(16px);
            }

            .section-divider {
                height: 1px;
                background: rgba(255, 255, 255, 0.2);
                margin: 6px 0;
            }
            
            .section-title {
                color: rgba(255, 255, 255, 0.9);
                font-size: 12px;
                font-weight: 600;
                margin: 4px 0 4px 0;
                padding: 0 4px;
                text-transform: uppercase;
                letter-spacing: 0.5px;
            }

            @keyframes fadeIn {
                from {
                    opacity: 0;
                    transform: scale(0.8);
                }
                to {
                    opacity: 1;
                    transform: scale(1);
                }
            }

            .linuxdo-helper-panel {
                animation: fadeIn 0.3s ease-out;
            }
        `;
        document.head.appendChild(style);
    }

    setupButton() {
        this.addGlobalStyles();

        // 创建主容器
        this.container = document.createElement("div");
        this.container.className = "linuxdo-helper-panel";
        if (this.panelMinimized) {
            this.container.classList.add('minimized');
        }

        // 如果有保存的位置,使用保存的位置
        if (this.panelPosition.x !== null && this.panelPosition.y !== null) {
            // 使用绝对定位的 left/top 而不是 transform,避免与居中 transform 冲突
            this.container.style.position = 'fixed';
            this.container.style.left = this.panelPosition.x + 'px';
            this.container.style.top = this.panelPosition.y + 'px';
            this.container.style.right = 'auto';
            this.container.style.bottom = 'auto';
            this.container.style.transform = 'none';
        }

        // 创建面板头部
        const header = document.createElement("div");
        header.className = "panel-header";
        header.innerHTML = `
            <span class="panel-title">📚 Linux.do 助手</span>
            <div class="panel-controls">
                <button class="panel-control-btn minimize-btn" title="最小化">─</button>
            </div>
        `;

        // 创建面板内容区
        const content = document.createElement("div");
        content.className = "panel-content";
        if (this.panelMinimized) {
            content.classList.add('hidden');
        }

        // 主按钮
        this.button = document.createElement("button");
        this.button.className = "main-action-btn" + (this.autoRunning ? " running" : "");
        this.button.innerHTML = this.autoRunning
            ? '<span class="btn-icon">⏸</span><span class="btn-text">停止阅读</span>'
            : '<span class="btn-icon">▶</span><span class="btn-text">开始阅读</span>';
        this.button.addEventListener("click", () => this.handleButtonClick());

        // 随机楼层按钮
        this.randomBtn = document.createElement("button");
        this.randomBtn.className = "random-floor-btn";
        this.randomBtn.innerHTML = '<span class="btn-icon">🎲</span><span class="btn-text">随机楼层</span>';
        this.randomBtn.addEventListener("click", () => this.randomJump());
        this.randomBtn.style.display = this.isTopicPage ? 'flex' : 'none';
        this.randomBtn.title = '随机跳转到某个楼层(抽奖用)';
        
        // 批量展示用户信息按钮
        this.revealUsersBtn = document.createElement("button");
        this.revealUsersBtn.className = "reveal-users-btn";
        this.revealUsersBtn.innerHTML = '<span class="btn-icon">📊</span><span class="btn-text">批量展示信息</span>';
        this.revealUsersBtn.addEventListener("click", () => this.handleRevealUsersClick());
        this.revealUsersBtn.style.display = this.isTopicPage ? 'flex' : 'none';
        this.revealUsersBtn.title = '批量展示当前页面所有已加载回复的用户信息';

        // 自动点赞开关
        const autoLikeRow = this.createToggleRow(
            "👍 自动点赞主题",
            this.autoLikeEnabled,
            (checked) => {
                // 检查是否在冷却期
                if (checked && this.likeResumeTime && Date.now() < this.likeResumeTime) {
                    const now = Date.now();
                    const remainingHours = Math.ceil((this.likeResumeTime - now) / (1000 * 60 * 60));
                    const resumeDate = new Date(this.likeResumeTime);
                    this.showNotification(`点赞功能冷却中,将在 ${resumeDate.toLocaleTimeString()} 恢复`);
                    console.log(`点赞冷却中,还需约 ${remainingHours} 小时,无法开启`);
                    
                    // 恢复开关状态为关闭
                    setTimeout(() => {
                        const toggleRows = this.container.querySelectorAll('.toggle-row');
                        for (const row of toggleRows) {
                            const label = row.querySelector('.toggle-label');
                            if (label && label.textContent.includes('自动点赞')) {
                                const input = row.querySelector('input[type="checkbox"]');
                                if (input) {
                                    input.checked = false;
                                }
                                break;
                            }
                        }
                    }, 100);
                    return;
                }
                
                this.autoLikeEnabled = checked;
                Storage.set('autoLikeEnabled', this.autoLikeEnabled);
                console.log(`自动点赞主题: ${this.autoLikeEnabled ? '开启' : '关闭'}`);
                if (this.autoLikeEnabled && this.isTopicPage) {
                    this.autoLikeTopic();
                }
            }
        );

        // 清爽模式开关
        const cleanModeRow = this.createToggleRow(
            "✨ 清爽模式",
            this.cleanModeEnabled,
            (checked) => {
                this.cleanModeEnabled = checked;
                Storage.set('cleanModeEnabled', this.cleanModeEnabled);
                console.log(`清爽模式: ${this.cleanModeEnabled ? '开启' : '关闭'}`);
                this.toggleCleanMode();
            }
        );

        // 清除点赞冷却按钮
        this.clearCooldownBtn = document.createElement("button");
        this.clearCooldownBtn.className = "reveal-users-btn";
        this.clearCooldownBtn.innerHTML = '<span class="btn-icon">🔥</span><span class="btn-text">清除点赞冷却</span>';
        this.clearCooldownBtn.addEventListener("click", () => this.handleClearCooldown());
        this.clearCooldownBtn.title = '清除点赞冷却时间,立即恢复点赞功能';
        this.clearCooldownBtn.style.background = 'linear-gradient(135deg, #f093fb 0%, #f5576c 100%)';

        // 信任等级显示容器
        this.trustLevelContainer = document.createElement("div");
        this.trustLevelContainer.className = "trust-level-row";
        this.trustLevelContainer.innerHTML = '<div class="trust-level-loading">加载等级信息...</div>';

        // 组装面板 - 按功能分类
        // 📖 自动阅读区(包含阅读按钮和相关设置)
        const autoSection = document.createElement("div");
        autoSection.innerHTML = '<div class="section-title">📖 自动阅读</div>';
        content.appendChild(autoSection);
        content.appendChild(this.button);
        content.appendChild(autoLikeRow);
        content.appendChild(this.clearCooldownBtn);
        content.appendChild(cleanModeRow);
        
        // 分隔线1
        this.divider1 = document.createElement("div");
        this.divider1.className = "section-divider";
        content.appendChild(this.divider1);
        
        // 🛠️ 工具功能区(只在文章页显示)
        this.toolSectionContainer = document.createElement("div");
        this.toolSectionContainer.className = "tool-section-container";
        const toolSection = document.createElement("div");
        toolSection.innerHTML = '<div class="section-title">🛠️ 工具功能</div>';
        this.toolSectionContainer.appendChild(toolSection);
        this.toolSectionContainer.appendChild(this.randomBtn);
        this.toolSectionContainer.appendChild(this.revealUsersBtn);
        content.appendChild(this.toolSectionContainer);
        
        // 分隔线2
        this.divider2 = document.createElement("div");
        this.divider2.className = "section-divider";
        content.appendChild(this.divider2);
        
        // 📊 账号信息区
        const accountSection = document.createElement("div");
        accountSection.innerHTML = '<div class="section-title">📊 账号信息</div>';
        content.appendChild(accountSection);
        content.appendChild(this.trustLevelContainer);

        this.container.appendChild(header);
        this.container.appendChild(content);
        document.body.appendChild(this.container);

        // 添加拖动功能
        this.makeDraggable(header);

        // 添加最小化功能
        header.querySelector('.minimize-btn').addEventListener('click', (e) => {
            e.stopPropagation();
            this.toggleMinimize();
        });
    }

    createToggleRow(label, checked, onChange) {
        const row = document.createElement("div");
        row.className = "toggle-row";

        const labelEl = document.createElement("span");
        labelEl.className = "toggle-label";
        labelEl.textContent = label;

        const toggleSwitch = document.createElement("label");
        toggleSwitch.className = "toggle-switch";

        const input = document.createElement("input");
        input.type = "checkbox";
        input.checked = checked;
        input.addEventListener("change", (e) => onChange(e.target.checked));

        const slider = document.createElement("span");
        slider.className = "toggle-slider";

        toggleSwitch.appendChild(input);
        toggleSwitch.appendChild(slider);

        row.appendChild(labelEl);
        row.appendChild(toggleSwitch);

        return row;
    }

    makeDraggable(header) {
        let isDragging = false;
        let currentX;
        let currentY;
        let initialX;
        let initialY;
        let rafId = null;

        // 禁用过渡效果以提高拖动流畅度
        const disableTransition = () => {
            this.container.style.transition = 'none';
        };

        const enableTransition = () => {
            this.container.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)';
        };

        header.addEventListener('mousedown', (e) => {
            if (e.target.classList.contains('panel-control-btn') ||
                e.target.closest('.panel-control-btn')) {
                return;
            }

            isDragging = true;
            disableTransition();

            const rect = this.container.getBoundingClientRect();
            initialX = e.clientX - rect.left;
            initialY = e.clientY - rect.top;

            // 使用捕获阶段,提高响应速度
            document.addEventListener('mousemove', onMouseMove, true);
            document.addEventListener('mouseup', onMouseUp, true);

            // 防止文本选择
            e.preventDefault();
        });

        const updatePosition = () => {
            // 限制在视窗内
            const maxX = window.innerWidth - this.container.offsetWidth;
            const maxY = window.innerHeight - this.container.offsetHeight;

            currentX = Math.max(0, Math.min(currentX, maxX));
            currentY = Math.max(0, Math.min(currentY, maxY));

            // 使用 left/top 定位(避免与居中 transform 冲突)
            this.container.style.position = 'fixed';
            this.container.style.left = currentX + 'px';
            this.container.style.top = currentY + 'px';
            this.container.style.right = 'auto';
            this.container.style.bottom = 'auto';
            this.container.style.transform = 'none';

            // 保存位置供页面调整大小时使用
            this.currentTranslateX = currentX;
            this.currentTranslateY = currentY;
        };

        const onMouseMove = (e) => {
            if (!isDragging) return;

            e.preventDefault();
            e.stopPropagation();

            currentX = e.clientX - initialX;
            currentY = e.clientY - initialY;

            // 使用 requestAnimationFrame 确保流畅渲染
            if (rafId) {
                cancelAnimationFrame(rafId);
            }
            rafId = requestAnimationFrame(updatePosition);
        };

        const onMouseUp = () => {
            if (isDragging) {
                isDragging = false;
                enableTransition();

                // 取消未完成的动画帧
                if (rafId) {
                    cancelAnimationFrame(rafId);
                    rafId = null;
                }

                // 保存最终位置
                this.panelPosition = { x: currentX, y: currentY };
                Storage.set('panelPosition', this.panelPosition);
            }
            document.removeEventListener('mousemove', onMouseMove, true);
            document.removeEventListener('mouseup', onMouseUp, true);
        };
    }

    toggleMinimize() {
        this.panelMinimized = !this.panelMinimized;
        Storage.set('panelMinimized', this.panelMinimized);

        const content = this.container.querySelector('.panel-content');
        if (this.panelMinimized) {
            content.classList.add('hidden');
            this.container.classList.add('minimized');
        } else {
            content.classList.remove('hidden');
            this.container.classList.remove('minimized');
        }
    }

    setupWindowResizeHandler() {
        // 监听窗口大小变化,确保面板始终在可见区域内
        let resizeTimer;
        
        const adjustPosition = () => {
            const rect = this.container.getBoundingClientRect();
            const maxX = window.innerWidth - rect.width;
            const maxY = window.innerHeight - rect.height;

            // 如果面板有自定义位置
            if (this.panelPosition.x !== null && this.panelPosition.y !== null) {
                // 当前位置(从 transform 获取)
                let currentX = this.currentTranslateX || this.panelPosition.x;
                let currentY = this.currentTranslateY || this.panelPosition.y;

                // 限制在视窗内(预留20px边距)
                currentX = Math.max(20, Math.min(currentX, maxX - 20));
                currentY = Math.max(20, Math.min(currentY, maxY - 20));

                // 更新位置
                this.container.style.position = 'fixed';
                this.container.style.left = currentX + 'px';
                this.container.style.top = currentY + 'px';
                this.container.style.transform = 'none';
                this.currentTranslateX = currentX;
                this.currentTranslateY = currentY;

                // 保存新位置
                this.panelPosition = { x: currentX, y: currentY };
                Storage.set('panelPosition', this.panelPosition);
            } else {
                // 默认位置:垂直居中,右侧20px
                // 确保面板高度不超过视口
                const currentRect = this.container.getBoundingClientRect();
                
                // 如果面板太高,调整为顶部对齐并限制最大高度
                if (currentRect.height > window.innerHeight - 40) {
                    this.container.style.top = '20px';
                    this.container.style.transform = 'none';
                    this.container.style.maxHeight = (window.innerHeight - 40) + 'px';
                } else {
                    // 否则保持垂直居中
                    this.container.style.top = '50%';
                    this.container.style.transform = 'translateY(-50%)';
                }
                
                // 确保不超出右边
                if (currentRect.right > window.innerWidth) {
                    this.container.style.right = '0px';
                }
            }
        };
        
        window.addEventListener('resize', () => {
            clearTimeout(resizeTimer);
            resizeTimer = setTimeout(adjustPosition, 100);
        });
        
        // 初始调整一次
        setTimeout(adjustPosition, 500);
    }

    checkLikeResumeTime() {
        if (this.likeResumeTime) {
            const now = Date.now();
            if (now >= this.likeResumeTime) {
                // 时间到了,清除冷却时间
                console.log('点赞冷却时间已过,可以正常使用点赞功能');
                this.likeResumeTime = null;
                Storage.set('likeResumeTime', null);
                this.updateClearCooldownButton();
                // 不自动开启点赞,由用户决定
            } else {
                // 还在冷却期,记录状态但不修改开关
                const remainingHours = Math.ceil((this.likeResumeTime - now) / (1000 * 60 * 60));
                const resumeDate = new Date(this.likeResumeTime);
                console.log(`点赞功能冷却中,将在 ${resumeDate.toLocaleString()} (还需约 ${remainingHours} 小时) 后恢复`);
                console.log(`提示:可以点击"清除点赞冷却"按钮立即恢复点赞功能`);
                this.updateClearCooldownButton();
            }
        } else {
            this.updateClearCooldownButton();
        }
    }
    
    updateClearCooldownButton() {
        if (!this.clearCooldownBtn) return;
        
        if (this.likeResumeTime && Date.now() < this.likeResumeTime) {
            const remainingHours = Math.ceil((this.likeResumeTime - Date.now()) / (1000 * 60 * 60));
            this.clearCooldownBtn.innerHTML = `<span class="btn-icon">🔥</span><span class="btn-text">清除冷却 (${remainingHours}h)</span>`;
            this.clearCooldownBtn.style.display = 'flex';
        } else {
            this.clearCooldownBtn.style.display = 'none';
        }
    }
    
    handleClearCooldown() {
        if (!this.likeResumeTime) {
            this.showNotification('当前没有点赞冷却');
            return;
        }
        
        // 清除冷却时间
        this.likeResumeTime = null;
        Storage.set('likeResumeTime', null);
        
        // 更新按钮显示
        this.updateClearCooldownButton();
        
        // 显示成功提示
        this.showNotification('✅ 点赞冷却已清除,可以正常点赞了!');
        console.log('[清除冷却] 点赞冷却时间已清除');
    }

    observeLikeLimit() {
        // 监听 DOM 变化,检测点赞限制弹窗
        const observer = new MutationObserver((mutations) => {
            for (const mutation of mutations) {
                for (const node of mutation.addedNodes) {
                    if (node.nodeType === 1) {
                        // 检测弹窗内容
                        const text = node.textContent || '';
                        
                        // 只处理点赞限制弹窗,排除回复限制弹窗
                        // 点赞限制关键词:点赞上限、点赞、分享很多爱
                        // 回复限制关键词:回复数量、创建更多新回复
                        const isLikeLimit = (
                            (text.includes('点赞上限') ||
                             text.includes('分享很多爱') ||
                             text.includes('点赞') && text.includes('小时后再次点赞')) &&
                            !text.includes('回复') &&
                            !text.includes('创建更多新回复')
                        );
                        
                        if (isLikeLimit) {
                            this.handleLikeLimit(text);
                            // 自动关闭弹窗
                            setTimeout(() => {
                                const confirmBtn = document.querySelector('.modal-footer .btn-primary, .dialog-footer .btn-primary, button.btn-primary');
                                if (confirmBtn && confirmBtn.textContent.includes('确定')) {
                                    confirmBtn.click();
                                }
                            }, 1000);
                            break;
                        }
                    }
                }
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });
    }

    handleLikeLimit(text) {
        console.log('检测到点赞限制提示:', text);

        let waitMinutes = 0; // 等待时间(分钟)
        
        // 优先匹配 "在 X 分钟后" 格式
        const minuteMatch = text.match(/[在|可以在]\s*(\d+)\s*分钟后/);
        if (minuteMatch) {
            waitMinutes = parseInt(minuteMatch[1]);
            console.log(`从 "X分钟后" 提取到等待时间: ${waitMinutes} 分钟`);
        } else {
            // 匹配 "在 X 小时后" 格式
            const hourMatch = text.match(/[在|可以在]\s*(\d+)\s*小时后/);
            if (hourMatch) {
                waitMinutes = parseInt(hourMatch[1]) * 60;
                console.log(`从 "X小时后" 提取到等待时间: ${hourMatch[1]} 小时 = ${waitMinutes} 分钟`);
            } else {
                // 尝试匹配最后一个数字+单位的组合
                const allMinuteMatches = text.match(/(\d+)\s*分钟/g);
                const allHourMatches = text.match(/(\d+)\s*小时/g);
                
                if (allMinuteMatches && allMinuteMatches.length > 0) {
                    // 取最后一个分钟匹配
                    const lastMatch = allMinuteMatches[allMinuteMatches.length - 1].match(/(\d+)/);
                    if (lastMatch) {
                        waitMinutes = parseInt(lastMatch[1]);
                        console.log(`从最后一个匹配提取到等待时间: ${waitMinutes} 分钟`);
                    }
                } else if (allHourMatches && allHourMatches.length > 0) {
                    // 取最后一个小时匹配
                    const lastMatch = allHourMatches[allHourMatches.length - 1].match(/(\d+)/);
                    if (lastMatch) {
                        waitMinutes = parseInt(lastMatch[1]) * 60;
                        console.log(`从最后一个匹配提取到等待时间: ${lastMatch[1]} 小时 = ${waitMinutes} 分钟`);
                    }
                } else {
                    // 默认10小时
                    waitMinutes = 10 * 60;
                    console.log(`未能提取等待时间,使用默认值: 10 小时 = ${waitMinutes} 分钟`);
                }
            }
        }

        // 计算恢复时间
        const resumeTime = Date.now() + (waitMinutes * 60 * 1000);
        this.likeResumeTime = resumeTime;
        Storage.set('likeResumeTime', resumeTime);

        // 关闭自动点赞
        this.autoLikeEnabled = false;
        Storage.set('autoLikeEnabled', false);

        // 更新UI - 更精确地定位到自动点赞开关
        const toggleRows = this.container.querySelectorAll('.toggle-row');
        for (const row of toggleRows) {
            const label = row.querySelector('.toggle-label');
            if (label && label.textContent.includes('自动点赞')) {
                const input = row.querySelector('input[type="checkbox"]');
                if (input) {
                    input.checked = false;
                }
                break;
            }
        }

        const resumeDate = new Date(resumeTime);
        const displayTime = waitMinutes >= 60
            ? `${Math.floor(waitMinutes / 60)} 小时 ${waitMinutes % 60 > 0 ? (waitMinutes % 60) + ' 分钟' : ''}`.trim()
            : `${waitMinutes} 分钟`;
        
        console.log(`已达到点赞上限,自动关闭点赞功能,将在 ${resumeDate.toLocaleString()} (${displayTime}后) 恢复`);

        // 显示提示 - 使用提取到的实际时间
        this.showNotification(`点赞已达上限,将在 ${displayTime}后自动恢复`);
    }

    showNotification(message) {
        const notification = document.createElement('div');
        notification.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 15px 20px;
            border-radius: 10px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
            z-index: 100000;
            font-size: 14px;
            max-width: 300px;
            animation: slideIn 0.3s ease-out;
        `;
        notification.textContent = message;

        // 添加动画样式
        const style = document.createElement('style');
        style.textContent = `
            @keyframes slideIn {
                from {
                    transform: translateX(400px);
                    opacity: 0;
                }
                to {
                    transform: translateX(0);
                    opacity: 1;
                }
            }
        `;
        document.head.appendChild(style);

        document.body.appendChild(notification);

        // 3秒后自动消失
        setTimeout(() => {
            notification.style.transition = 'all 0.3s';
            notification.style.opacity = '0';
            notification.style.transform = 'translateX(400px)';
            setTimeout(() => notification.remove(), 300);
        }, 3000);
    }

    // 获取当前用户名
    async getCurrentUsername() {
        if (this.currentUsername) return this.currentUsername;

        try {
            // 方法1:从用户菜单获取
            const userMenuBtn = document.querySelector('.header-dropdown-toggle.current-user');
            if (userMenuBtn) {
                const img = userMenuBtn.querySelector('img[alt]');
                if (img && img.alt) {
                    this.currentUsername = img.alt;
                    return this.currentUsername;
                }
            }

            // 方法2:从 API 获取
            const response = await fetch(`${BASE_URL}/session/current.json`);
            if (response.ok) {
                const data = await response.json();
                if (data.current_user && data.current_user.username) {
                    this.currentUsername = data.current_user.username;
                    return this.currentUsername;
                }
            }
        } catch (error) {
            console.error('获取用户名失败:', error);
        }
        return null;
    }

    // 加载用户信任等级
    async loadUserTrustLevel(isManualRefresh = false) {
        const username = await this.getCurrentUsername();
        if (!username) {
            this.trustLevelContainer.innerHTML = '<div class="trust-level-loading">未登录</div>';
            return;
        }

        // 如果不是手动刷新,显示加载状态
        if (isManualRefresh) {
            const refreshBtn = this.trustLevelContainer.querySelector('.trust-level-refresh');
            if (refreshBtn) {
                refreshBtn.textContent = '刷新中...';
                refreshBtn.disabled = true;
            }
        }

        try {
            // 首先尝试从 summary.json 获取(适用于TL0-TL1)
            const summaryResponse = await fetch(`${BASE_URL}/u/${username}/summary.json`);
            if (summaryResponse.ok) {
                const data = await summaryResponse.json();
                // 检查是否能从 summary 获取足够信息
                if (data.user_summary) {
                    this.renderTrustLevel(data, username);
                    return;
                }
            }

            // 如果 summary 不可用或等级较高,尝试从 connect.linux.do 获取详细信息
            if (CURRENT_DOMAIN === 'linux.do') {
                await this.loadTrustLevelFromConnect(username);
            } else {
                throw new Error('无法获取等级数据');
            }
        } catch (error) {
            console.error('加载信任等级失败:', error);
            this.trustLevelContainer.innerHTML = `
                <div class="trust-level-header">
                    📊 信任等级
                    <button class="trust-level-refresh" onclick="window.browseController.loadUserTrustLevel(true)">🔄 刷新</button>
                </div>
                <div class="trust-level-loading">加载失败,请点击刷新重试</div>
            `;
        } finally {
            // 恢复刷新按钮状态
            if (isManualRefresh) {
                setTimeout(() => {
                    const refreshBtn = this.trustLevelContainer.querySelector('.trust-level-refresh');
                    if (refreshBtn) {
                        refreshBtn.textContent = '🔄 刷新';
                        refreshBtn.disabled = false;
                    }
                }, 1000);
            }
        }
    }

    // 从 connect.linux.do 加载等级信息(适用于TL2+)
    async loadTrustLevelFromConnect(username) {
        try {
            const response = await fetch('https://connect.linux.do/');
            if (!response.ok) {
                throw new Error('无法访问 connect.linux.do');
            }

            const html = await response.text();
            const parser = new DOMParser();
            const doc = parser.parseFromString(html, 'text/html');

            // 查找包含"信任级别"的区块
            const trustLevelSection = Array.from(doc.querySelectorAll('div.bg-white.p-6.rounded-lg')).find(div => {
                const h2 = div.querySelector('h2');
                return h2 && h2.textContent.includes('信任级别');
            });

            if (!trustLevelSection) {
                throw new Error('未找到信任级别数据');
            }

            // 解析标题获取目标等级
            const h2 = trustLevelSection.querySelector('h2');
            const titleMatch = h2.textContent.match(/信任级别\s*(\d+)\s*的要求/);
            const targetLevel = titleMatch ? titleMatch[1] : '未知';

            // 解析表格数据
            const tableRows = trustLevelSection.querySelectorAll('table tbody tr');
            const requirements = [];

            tableRows.forEach((row, index) => {
                if (index === 0) return; // 跳过表头

                const cells = row.querySelectorAll('td');
                if (cells.length >= 3) {
                    const name = cells[0].textContent.trim();
                    const current = cells[1].textContent.trim();
                    const required = cells[2].textContent.trim();
                    const isMet = cells[1].classList.contains('text-green-500');

                    requirements.push({ name, current, required, isMet });
                }
            });

            // 渲染高级等级信息
            this.renderAdvancedTrustLevel(username, targetLevel, requirements);

        } catch (error) {
            console.error('从 connect.linux.do 加载失败:', error);
            throw error;
        }
    }

    // 渲染信任等级信息(支持 TL0->TL1 和 TL1->TL2 - 基于 summary.json)
    renderTrustLevel(data, username) {
        const summary = data.user_summary;
        if (!summary) {
            this.trustLevelContainer.innerHTML = '<div class="trust-level-loading">无数据</div>';
            return;
        }

        // 获取当前信任等级
        // 优先从 user_summary 中获取,如果没有则从外层获取
        const currentLevel = summary.trust_level !== undefined ? summary.trust_level :
                           (data.user && data.user.trust_level !== undefined ? data.user.trust_level : 1);
        const targetLevel = currentLevel + 1;
        
        // 根据当前等级获取对应的升级要求
        const levelConfig = CONFIG.levelRequirements[currentLevel];
        
        if (!levelConfig) {
            // 如果没有配置(比如已经是最高等级),使用原来的逻辑
            this.renderDefaultTrustLevel(summary);
            return;
        }

        const requirements = [];
        
        // 根据配置动态构建要求列表
        Object.entries(levelConfig).forEach(([key, requiredValue]) => {
            let currentValue = 0;
            let label = '';
            
            switch (key) {
                case 'topics_entered':
                    currentValue = summary.topics_entered || 0;
                    label = '浏览的话题';
                    break;
                case 'posts_read_count':
                    currentValue = summary.posts_read_count || 0;
                    label = '已读帖子';
                    break;
                case 'time_read':
                    currentValue = Math.floor((summary.time_read || 0) / 60);
                    label = '阅读时长(分)';
                    requiredValue = Math.floor(requiredValue / 60);
                    break;
                case 'days_visited':
                    currentValue = summary.days_visited || 0;
                    label = '访问天数';
                    break;
                case 'likes_given':
                    currentValue = summary.likes_given || 0;
                    label = '给出的赞';
                    break;
                case 'likes_received':
                    currentValue = summary.likes_received || 0;
                    label = '收到的赞';
                    break;
                case 'post_count':
                    currentValue = summary.post_count || 0;
                    label = '帖子数量';
                    break;
            }
            
            if (label) {
                requirements.push({
                    name: label,
                    current: currentValue,
                    required: requiredValue
                });
            }
        });

        // 计算达标数量
        const achievedCount = requirements.filter(req => req.current >= req.required).length;
        const totalCount = requirements.length;
        const allMet = achievedCount === totalCount;

        const levelNames = {
            0: 'Lv0 → Lv1',
            1: 'Lv1 → Lv2',
            2: 'Lv2 → Lv3',
            3: 'Lv3 → Lv4'
        };

        let html = `
            <div class="trust-level-header">
                <span>📊 ${levelNames[currentLevel] || `Lv${currentLevel} → Lv${targetLevel}`}</span>
                <button class="trust-level-refresh" data-action="refresh">🔄 刷新</button>
            </div>
        `;

        requirements.forEach(req => {
            const progress = Math.min((req.current / req.required) * 100, 100);
            const isCompleted = req.current >= req.required;
            const fillClass = isCompleted ? 'completed' : '';

            html += `
                <div class="trust-level-item">
                    <span class="trust-level-name">${req.name}</span>
                    <div class="trust-level-progress">
                        <div class="trust-level-bar">
                            <div class="trust-level-bar-fill ${fillClass}" style="width: ${progress}%"></div>
                        </div>
                        <span class="trust-level-value">${req.current}/${req.required}</span>
                    </div>
                </div>
            `;
        });

        // 在数据下方添加总结信息
        if (allMet) {
            html += `
                <div style="background: rgba(255, 255, 255, 0.25); padding: 6px 8px; border-radius: 6px; margin: 6px 0 0 0;">
                    <div style="color: #fff; font-size: 11px; font-weight: 600; text-align: center;">
                        ✅ 已满足 Lv${targetLevel} 要求
                    </div>
                </div>
            `;
        } else {
            const unmetCount = totalCount - achievedCount;
            html += `
                <div style="background: rgba(255, 255, 255, 0.15); padding: 6px 8px; border-radius: 6px; margin: 6px 0 0 0;">
                    <div style="color: rgba(255, 255, 255, 0.9); font-size: 11px; font-weight: 500; text-align: center;">
                        还需完成 ${unmetCount} 项升级到 Lv${targetLevel}
                    </div>
                </div>
            `;
        }

        this.trustLevelContainer.innerHTML = html;

        // 添加刷新按钮事件监听
        setTimeout(() => {
            const refreshBtn = this.trustLevelContainer.querySelector('.trust-level-refresh');
            if (refreshBtn) {
                refreshBtn.addEventListener('click', () => this.loadUserTrustLevel(true));
            }
        }, 100);
    }

    // 默认渲染方法(用于没有配置的等级)
    renderDefaultTrustLevel(summary) {
        const requirements = [
            { name: '访问天数', current: summary.days_visited, required: 15 },
            { name: '给出的赞', current: summary.likes_given, required: 1 },
            { name: '收到的赞', current: summary.likes_received, required: 1 },
            { name: '帖子数量', current: summary.post_count, required: 3 },
            { name: '进入主题', current: summary.topics_entered, required: 20 },
            { name: '阅读帖子', current: summary.posts_read_count, required: 100 },
            { name: '阅读时长(分)', current: Math.floor(summary.time_read / 60), required: 60 }
        ];

        // 计算达标数量
        const achievedCount = requirements.filter(req => req.current >= req.required).length;
        const totalCount = requirements.length;
        const allMet = achievedCount === totalCount;

        let html = `
            <div class="trust-level-header">
                <span>📊 等级 (L2+)</span>
                <button class="trust-level-refresh" data-action="refresh">🔄 刷新</button>
            </div>
        `;

        // 添加总结信息
        if (allMet) {
            html += `
                <div style="background: rgba(16, 185, 129, 0.2); padding: 6px 8px; border-radius: 6px; margin: 6px 0;">
                    <div style="color: #10b981; font-size: 11px; font-weight: 600; text-align: center;">
                        🎉 所有要求已达标!
                    </div>
                </div>
            `;
        } else {
            const unmetCount = totalCount - achievedCount;
            html += `
                <div style="background: rgba(251, 146, 60, 0.2); padding: 6px 8px; border-radius: 6px; margin: 6px 0;">
                    <div style="color: #ea580c; font-size: 11px; font-weight: 600; text-align: center;">
                        还需完成 ${unmetCount} 项要求
                    </div>
                </div>
            `;
        }

        requirements.forEach(req => {
            const progress = Math.min((req.current / req.required) * 100, 100);
            const isCompleted = req.current >= req.required;
            const fillClass = isCompleted ? 'completed' : '';

            html += `
                <div class="trust-level-item">
                    <span class="trust-level-name">${req.name}</span>
                    <div class="trust-level-progress">
                        <div class="trust-level-bar">
                            <div class="trust-level-bar-fill ${fillClass}" style="width: ${progress}%"></div>
                        </div>
                        <span class="trust-level-value">${req.current}/${req.required}</span>
                    </div>
                </div>
            `;
        });

        this.trustLevelContainer.innerHTML = html;

        setTimeout(() => {
            const refreshBtn = this.trustLevelContainer.querySelector('.trust-level-refresh');
            if (refreshBtn) {
                refreshBtn.addEventListener('click', () => this.loadUserTrustLevel(true));
            }
        }, 100);
    }

    // 渲染高级信任等级信息(从 connect.linux.do 获取的TL2+数据)
    renderAdvancedTrustLevel(username, targetLevel, requirements) {
        const achievedCount = requirements.filter(r => r.isMet).length;
        const totalCount = requirements.length;

        // 计算当前等级
        const currentLevel = parseInt(targetLevel) - 1;
        
        // 等级名称映射(简化显示)
        const levelNames = {
            2: 'Lv1 → Lv2',
            3: 'Lv2 → Lv3',
            4: 'Lv3 → Lv4'
        };

        let html = `
            <div class="trust-level-header">
                <span>📊 ${levelNames[targetLevel] || `Lv${currentLevel} → Lv${targetLevel}`}</span>
                <button class="trust-level-refresh" data-action="refresh">🔄 刷新</button>
            </div>
        `;

        requirements.forEach(req => {
            // 尝试从文本中提取数字
            const currentMatch = req.current.match(/(\d+)/);
            const requiredMatch = req.required.match(/(\d+)/);

            const currentNum = currentMatch ? parseInt(currentMatch[1]) : 0;
            const requiredNum = requiredMatch ? parseInt(requiredMatch[1]) : 1;

            const progress = Math.min((currentNum / requiredNum) * 100, 100);
            const isCompleted = req.isMet;
            const fillClass = isCompleted ? 'completed' : '';

            // 简化标签名称
            let simpleName = req.name
                .replace('已读帖子(所有时间)', '已读帖子')
                .replace('浏览的话题(所有时间)', '浏览话题')
                .replace('获赞:点赞用户数量', '点赞用户数')
                .replace('被禁言(过去 6 个月)', '被禁言')
                .replace('被封禁(过去 6 个月)', '被封禁');

            html += `
                <div class="trust-level-item">
                    <span class="trust-level-name">${simpleName}</span>
                    <div class="trust-level-progress">
                        <div class="trust-level-bar">
                            <div class="trust-level-bar-fill ${fillClass}" style="width: ${progress}%"></div>
                        </div>
                        <span class="trust-level-value">${req.current}/${req.required}</span>
                    </div>
                </div>
            `;
        });

        // 在数据下方添加总结信息
        if (achievedCount === totalCount) {
            html += `
                <div style="background: rgba(255, 255, 255, 0.25); padding: 6px 8px; border-radius: 6px; margin: 6px 0 0 0;">
                    <div style="color: #fff; font-size: 11px; font-weight: 600; text-align: center;">
                        ✅ 已满足 Lv${targetLevel} 要求
                    </div>
                </div>
            `;
        } else {
            const unmetCount = totalCount - achievedCount;
            html += `
                <div style="background: rgba(255, 255, 255, 0.15); padding: 6px 8px; border-radius: 6px; margin: 6px 0 0 0;">
                    <div style="color: rgba(255, 255, 255, 0.9); font-size: 11px; font-weight: 500; text-align: center;">
                        还需完成 ${unmetCount} 项升级到 Lv${targetLevel}
                    </div>
                </div>
            `;
        }

        this.trustLevelContainer.innerHTML = html;
        
        // 添加刷新按钮事件监听
        setTimeout(() => {
            const refreshBtn = this.trustLevelContainer.querySelector('.trust-level-refresh');
            if (refreshBtn) {
                refreshBtn.addEventListener('click', () => this.loadUserTrustLevel(true));
            }
        }, 100);
    }

    // 启动账号切换监控
    startUserSwitchMonitoring() {
        // 初始化当前用户
        this.getCurrentUsername().then(username => {
            this.lastDetectedUser = username;
        });

        // 每5秒检查一次是否切换账号
        setInterval(async () => {
            const currentDetectedUser = await this.getCurrentUsername();
            
            if (currentDetectedUser && this.lastDetectedUser &&
                currentDetectedUser !== this.lastDetectedUser) {
                console.log(`检测到账号切换: ${this.lastDetectedUser} -> ${currentDetectedUser}`);
                this.lastDetectedUser = currentDetectedUser;
                this.currentUsername = currentDetectedUser;
                
                // 延迟一点时间再刷新,确保页面稳定
                setTimeout(() => {
                    console.log('账号切换后重新加载等级信息');
                    this.loadUserTrustLevel(true);
                }, 1000);
            } else if (currentDetectedUser) {
                this.lastDetectedUser = currentDetectedUser;
            }
        }, 5000);
    }

    toggleCleanMode() {
        const sidebarToggle = document.querySelector('button.btn-sidebar-toggle');
        if (sidebarToggle && this.cleanModeEnabled) {
            if (sidebarToggle.getAttribute('aria-expanded') === 'true') {
                console.log('清爽模式启用,收起边栏');
                sidebarToggle.click();
            }
        }
        this.applyCleanModeStyles();
    }

    applyCleanModeStyles() {
        let styleElement = document.getElementById('clean-mode-styles');
        if (styleElement) {
            styleElement.remove();
        }

        if (this.cleanModeEnabled) {
            styleElement = document.createElement('style');
            styleElement.id = 'clean-mode-styles';
            styleElement.textContent = `
                p:contains("希望你喜欢这里。有问题,请提问,或搜索现有帖子。") {
                    display: none !important;
                }
                div#global-notice-alert-global-notice.alert.alert-info.alert-global-notice {
                    display: none !important;
                }
                a[href="https://linux.do/t/topic/482293"] {
                    display: none !important;
                }
                div.link-bottom-line a.badge-category__wrapper {
                    display: none !important;
                }
                td.posters.topic-list-data {
                    display: none !important;
                }
                a.discourse-tag.box[href^="/tag/"] {
                    display: none !important;
                }
            `;
            document.head.appendChild(styleElement);
        }
    }

    initOnlyOwnerView() {
        this.createToggleButton();
        this.observePageChanges();
        this.toggleVisibility();
    }

    toggleVisibility() {
        const displayMode = localStorage.getItem("on_off") || "当前查看全部";
        const userId = document.getElementById("post_1")?.getAttribute('data-user-id');
        if (userId) {
            document.querySelectorAll('article').forEach(article => {
                article.style.display = (displayMode === "当前只看楼主" && article.dataset.userId !== userId) ? 'none' : '';
            });
        }
    }

    createToggleButton() {
        if (document.getElementById("toggleVisibilityBtn")) {
            return;
        }

        const btn = document.createElement("button");
        btn.id = "toggleVisibilityBtn";
        btn.textContent = localStorage.getItem("on_off") || "当前查看全部";
        btn.onclick = () => {
            const newText = btn.textContent === '当前查看全部' ? '当前只看楼主' : '当前查看全部';
            document.getElementsByClassName("start-date")[0]?.click();
            btn.textContent = newText;
            localStorage.setItem("on_off", newText);
            this.toggleVisibility();
        };

        btn.style.backgroundColor = "#333";
        btn.style.color = "#FFF";
        btn.style.border = "none";
        btn.style.padding = "8px 16px";
        btn.style.marginLeft = "10px";
        btn.style.borderRadius = "5px";
        btn.style.cursor = "pointer";

        const saveButton = document.querySelector('.save-to-local-btn');
        if (saveButton) {
            saveButton.parentElement.appendChild(btn);
        } else {
            const firstPostContent = document.querySelector('.boxed.onscreen-post[data-post-id] .cooked');
            if (firstPostContent) {
                firstPostContent.appendChild(btn);
            }
        }
    }

    observePageChanges() {
        const observer = new MutationObserver(() => {
            if (document.querySelector(".timeline-footer-controls") && !document.getElementById("toggleVisibilityBtn")) {
                this.createToggleButton();
            }
            this.toggleVisibility();
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    initFloorNumberDisplay() {
        this.addFloorNumbers();
        this.initMutationObserver();
        this.setupRandomJumpButton();
        this.monitorURLChangeAndUpdateButton();
    }

    addFloorNumbers() {
        document.querySelectorAll('.boxed.onscreen-post').forEach((post) => {
            if (!post.querySelector('.floor-number')) {
                const floorNumber = document.createElement('div');
                floorNumber.className = 'floor-number';
                floorNumber.textContent = '楼层: ' + post.id.split("_")[1];
                floorNumber.style.cssText = 'color: grey; margin-left: 10px;';
                post.querySelector('.topic-meta-data').appendChild(floorNumber);
            }
        });
        this.setupSaveButton();
    }

    initMutationObserver() {
        const observer = new MutationObserver(() => {
            this.addFloorNumbers();
            this.setupSaveButton();
            this.toggleCleanMode();
        });
        observer.observe(document.body, { childList: true, subtree: true });
    }

    randomJump() {
        fetch(window.location.href + '.json')
            .then(response => response.json())
            .then(data => {
                if (data && data.posts_count) {
                    const postId = 1 + Math.floor(Math.random() * data.posts_count);
                    const currentUrl = new URL(window.location.href);
                    const list1 = currentUrl.pathname.split("/");
                    if (list1[list1.length - 2] === "topic") {
                        list1.push(postId);
                    } else if (list1[list1.length - 3] === "topic") {
                        list1[list1.length - 1] = postId;
                    }
                    const newUrl = list1.join("/");
                    window.location.href = newUrl;
                    alert('恭喜楼层【' + postId + '】的用户被抽中!');
                }
            })
            .catch(error => console.error('Error:', error));
    }

    setupRandomJumpButton() {
        // 随机按钮已集成到主面板中,不需要单独创建
    }

    setupSaveButton() {
        const firstPost = document.querySelector('.boxed.onscreen-post[data-post-id]');
        if (firstPost && firstPost.id.includes('post_1')) {
            if (!firstPost.querySelector('.save-to-local-btn')) {
                const saveButton = document.createElement('button');
                saveButton.className = 'save-to-local-btn';
                saveButton.textContent = '💾 保存到本地';
                Object.assign(saveButton.style, {
                    padding: '10px 20px',
                    fontSize: '15px',
                    fontWeight: '600',
                    backgroundColor: '#ff9800',
                    color: 'white',
                    border: 'none',
                    borderRadius: '8px',
                    cursor: 'pointer',
                    marginTop: '10px',
                    boxShadow: '0 4px 12px rgba(255, 152, 0, 0.3)',
                    transition: 'all 0.3s'
                });
                saveButton.addEventListener('mouseover', () => {
                    saveButton.style.transform = 'translateY(-2px)';
                    saveButton.style.boxShadow = '0 6px 20px rgba(255, 152, 0, 0.4)';
                });
                saveButton.addEventListener('mouseout', () => {
                    saveButton.style.transform = 'translateY(0)';
                    saveButton.style.boxShadow = '0 4px 12px rgba(255, 152, 0, 0.3)';
                });
                saveButton.addEventListener('click', () => this.savePostToLocal(firstPost));
                const postContent = firstPost.querySelector('.cooked');
                if (postContent) {
                    postContent.appendChild(saveButton);
                }
            }
        }
    }

    async savePostToLocal(postElement) {
        try {
            const topicTitle = document.querySelector('.fancy-title')?.textContent.trim() || 'Untitled_Topic';
            const postContent = postElement.querySelector('.cooked');
            if (!postContent) {
                alert('无法获取帖子内容!');
                return;
            }

            const contentClone = postContent.cloneNode(true);
            contentClone.querySelector('.save-to-local-btn')?.remove();

            const images = contentClone.querySelectorAll('img');
            for (const img of images) {
                try {
                    const response = await fetch(img.src);
                    const blob = await response.blob();
                    const reader = new FileReader();
                    await new Promise((resolve) => {
                        reader.onload = resolve;
                        reader.readAsDataURL(blob);
                    });
                    img.src = reader.result;
                } catch (error) {
                    console.error('图片加载失败:', img.src, error);
                    img.alt = '[图片加载失败]';
                }
            }

            const htmlContent = `
                <!DOCTYPE html>
                <html lang="zh-CN">
                <head>
                    <meta charset="UTF-8">
                    <meta name="viewport" content="width=device-width, initial-scale=1.0">
                    <title>${topicTitle}</title>
                    <style>
                        body { font-family: Arial, sans-serif; margin: 20px; }
                        .post-content { max-width: 800px; margin: 0 auto; }
                        img { max-width: 100%; height: auto; }
                    </style>
                </head>
                <body>
                    <div class="post-content">
                        <h1>${topicTitle}</h1>
                        ${contentClone.innerHTML}
                    </div>
                </body>
                </html>
            `;

            const blob = new Blob([htmlContent], { type: 'text/html' });
            const url = URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.href = url;
            const fileName = topicTitle
                .replace(/[\\/:*?"<>|]/g, '_')
                .replace(/\s+/g, '_')
                + '.html';
            link.download = fileName;
            link.click();
            URL.revokeObjectURL(url);

            alert('帖子内容已保存到本地!');
        } catch (error) {
            console.error('保存帖子失败:', error);
            alert('保存失败,请查看控制台错误信息。');
        }
    }

    monitorURLChangeAndUpdateButton() {
        let lastURL = location.href;

        // 初始检查一次
        this.updateButtonVisibility();

        setInterval(() => {
            const currentURL = location.href;
            if (currentURL !== lastURL) {
                lastURL = currentURL;
                this.isTopicPage = location.pathname.includes('/t/topic/');
                this.updateButtonVisibility();
                this.toggleCleanMode();
                if (this.autoLikeEnabled && currentURL.includes('/t/topic/')) {
                    this.autoLikeTopic();
                }
            }
        }, 1000);
    }

    updateButtonVisibility() {
        const isTopicPage = location.pathname.includes('/t/topic/');
        
        // 整个工具功能区:只在文章页显示
        if (this.toolSectionContainer) {
            this.toolSectionContainer.style.display = isTopicPage ? 'block' : 'none';
        }
        
        // 工具区上方的分隔线:只在文章页显示
        if (this.divider1) {
            this.divider1.style.display = isTopicPage ? 'block' : 'none';
        }
        
        // 工具区下方的分隔线:只在文章页显示
        if (this.divider2) {
            this.divider2.style.display = isTopicPage ? 'block' : 'none';
        }
        
        console.log(`页面类型: ${isTopicPage ? '文章页' : '非文章页'},工具功能区${isTopicPage ? '显示' : '隐藏'}`);
    }
    
    async handleRevealUsersClick() {
        if (this.userInfoHelper.revealInProgress) return;
        
        // 更新按钮状态
        this.revealUsersBtn.disabled = true;
        this.revealUsersBtn.innerHTML = '<span class="btn-icon">⏳</span><span class="btn-text">加载中...</span>';
        
        try {
            await this.userInfoHelper.revealAllVisibleReplies();
            this.revealUsersBtn.innerHTML = '<span class="btn-icon">✅</span><span class="btn-text">加载完成</span>';
            
            // 2秒后恢复按钮
            setTimeout(() => {
                this.revealUsersBtn.disabled = false;
                this.revealUsersBtn.innerHTML = '<span class="btn-icon">📊</span><span class="btn-text">批量展示信息</span>';
            }, 2000);
        } catch (error) {
            console.error('展示用户信息失败:', error);
            this.revealUsersBtn.disabled = false;
            this.revealUsersBtn.innerHTML = '<span class="btn-icon">❌</span><span class="btn-text">加载失败</span>';
            
            setTimeout(() => {
                this.revealUsersBtn.innerHTML = '<span class="btn-icon">📊</span><span class="btn-text">批量展示信息</span>';
            }, 2000);
        }
    }

    handleButtonClick() {
        if (this.isScrolling || this.autoRunning) {
            // 停止自动阅读
            this.stopScrolling();
            this.autoRunning = false;
            this.setSessionStorage('autoRunning', false);
            this.button.innerHTML = '<span class="btn-icon">▶</span><span class="btn-text">开始阅读</span>';
            this.button.classList.remove('running');
        } else {
            // 开启自动阅读
            this.autoRunning = true;
            this.setSessionStorage('autoRunning', true);
            this.button.innerHTML = '<span class="btn-icon">⏸</span><span class="btn-text">停止阅读</span>';
            this.button.classList.add('running');

            if (!this.firstUseChecked) {
                this.handleFirstUse();
            } else if (this.isTopicPage) {
                this.startScrolling();
                if (this.autoLikeEnabled) {
                    this.autoLikeTopic();
                }
            } else {
                this.getLatestTopics().then(() => this.navigateNextTopic());
            }
        }
    }

    async autoLikeTopic() {
        if (!this.autoLikeEnabled) return;

        // 检查是否在冷却期
        if (this.likeResumeTime && Date.now() < this.likeResumeTime) {
            console.log("点赞功能冷却中,跳过点赞");
            return;
        }

        const match = window.location.pathname.match(/\/t\/topic\/(\d+)/);
        if (!match) {
            console.log("无法获取当前主题ID");
            return;
        }
        const topicId = match[1];

        if (this.likedTopics.includes(topicId)) {
            console.log(`主题 ${topicId} 已经点赞过,跳过点赞操作`);
            return;
        }

        console.log("正在检查是否需要自动点赞主题...");
        await Utils.sleep(2000);

        const likeButton = document.querySelector('div.discourse-reactions-reaction-button button.btn-toggle-reaction-like');
        if (likeButton && !likeButton.classList.contains('has-like') && !likeButton.classList.contains('liked')) {
            likeButton.scrollIntoView({ behavior: 'smooth', block: 'center' });
            await Utils.sleep(1000);
            console.log("找到主题点赞按钮,执行点击操作");
            likeButton.click();

            this.likedTopics.push(topicId);
            Storage.set('likedTopics', this.likedTopics);
            console.log(`已记录点赞主题 ${topicId}`);
        } else {
            console.log("未找到可点赞的主题按钮或已点赞");
            if (likeButton && (likeButton.classList.contains('has-like') || likeButton.classList.contains('liked'))) {
                if (!this.likedTopics.includes(topicId)) {
                    this.likedTopics.push(topicId);
                    Storage.set('likedTopics', this.likedTopics);
                    console.log(`主题 ${topicId} 已点赞,记录到列表`);
                }
            }
        }
    }

    async handleFirstUse() {
        if (!this.autoRunning) return;

        // 只在 linux.do 域名下执行新手教程
        if (CURRENT_DOMAIN !== 'linux.do') {
            console.log('非 linux.do 域名,跳过新手教程');
            Storage.set('firstUseChecked', true);
            this.firstUseChecked = true;
            await this.getLatestTopics();
            await this.navigateNextTopic();
            return;
        }

        if (!this.selectedPost) {
            const randomIndex = Math.floor(Math.random() * CONFIG.mustRead.posts.length);
            this.selectedPost = CONFIG.mustRead.posts[randomIndex];
            Storage.set('selectedPost', this.selectedPost);
            console.log(`随机选择文章: ${this.selectedPost.url}`);
            window.location.href = this.selectedPost.url;
            return;
        }

        const currentUrl = window.location.href;
        if (currentUrl.includes(this.selectedPost.url)) {
            console.log(`当前在选中的文章页面,已点赞数: ${this.likesCount}`);
            while (this.likesCount < CONFIG.mustRead.likesNeeded && this.autoRunning) {
                await this.likeRandomComment();
                if (this.likesCount >= CONFIG.mustRead.likesNeeded) {
                    console.log('完成所需点赞数量,开始正常浏览');
                    Storage.set('firstUseChecked', true);
                    this.firstUseChecked = true;
                    await this.getLatestTopics();
                    await this.navigateNextTopic();
                    break;
                }
                await Utils.sleep(1000);
            }
        } else {
            window.location.href = this.selectedPost.url;
        }
    }

    async likeRandomComment() {
        if (!this.autoRunning) return false;

        // 检查是否在冷却期
        if (this.likeResumeTime && Date.now() < this.likeResumeTime) {
            console.log("点赞功能冷却中,跳过点赞");
            return false;
        }

        const likeButtons = Array.from(document.querySelectorAll('.like-button, .like-count, [data-like-button], .discourse-reactions-reaction-button'))
            .filter(button =>
                button &&
                button.offsetParent !== null &&
                !button.classList.contains('has-like') &&
                !button.classList.contains('liked')
            );

        if (likeButtons.length > 0) {
            const randomButton = likeButtons[Math.floor(Math.random() * likeButtons.length)];
            randomButton.scrollIntoView({ behavior: 'smooth', block: 'center' });
            await Utils.sleep(1000);

            if (!this.autoRunning) return false;
            console.log('找到可点赞的评论,准备点赞');
            randomButton.click();
            this.likesCount++;
            Storage.set('likesCount', this.likesCount);
            await Utils.sleep(1000);
            return true;
        }

        window.scrollBy({
            top: 500,
            behavior: 'smooth'
        });
        await Utils.sleep(1000);
        console.log('当前位置没有找到可点赞的评论,继续往下找');
        return false;
    }

    async getLatestTopics() {
        let page = 1;
        let topicList = [];
        let retryCount = 0;

        while (topicList.length < CONFIG.article.topicListLimit && retryCount < CONFIG.article.retryLimit) {
            try {
                const response = await fetch(`${BASE_URL}/latest.json?no_definitions=true&page=${page}`);
                const data = await response.json();

                if (data?.topic_list?.topics) {
                    const filteredTopics = data.topic_list.topics.filter(topic =>
                        topic.posts_count < CONFIG.article.commentLimit
                    );
                    topicList.push(...filteredTopics);
                    page++;
                } else {
                    break;
                }
            } catch (error) {
                console.error('获取文章列表失败:', error);
                retryCount++;
                await Utils.sleep(1000);
            }
        }

        if (topicList.length > CONFIG.article.topicListLimit) {
            topicList = topicList.slice(0, CONFIG.article.topicListLimit);
        }

        this.topicList = topicList;
        this.setSessionStorage('topicList', topicList);
        console.log(`已获取 ${topicList.length} 篇文章`);
    }

    async getNextTopic() {
        if (this.topicList.length === 0) {
            await this.getLatestTopics();
        }

        if (this.topicList.length > 0) {
            const topic = this.topicList.shift();
            this.setSessionStorage('topicList', this.topicList);
            return topic;
        }

        return null;
    }

    async startScrolling() {
        if (this.isScrolling) return;

        this.isScrolling = true;
        this.button.innerHTML = '<span class="btn-icon">⏸</span><span class="btn-text">停止阅读</span>';
        this.button.classList.add('running');
        this.lastActionTime = Date.now();

        while (this.isScrolling) {
            const speed = Utils.random(CONFIG.scroll.minSpeed, CONFIG.scroll.maxSpeed);
            const distance = Utils.random(CONFIG.scroll.minDistance, CONFIG.scroll.maxDistance);
            const scrollStep = distance * 2.5;

            window.scrollBy({
                top: scrollStep,
                behavior: 'smooth'
            });

            if (Utils.isNearBottom()) {
                await Utils.sleep(800);

                if (Utils.isNearBottom() && Utils.isPageLoaded()) {
                    console.log("已到达页面底部,准备导航到下一篇文章...");
                    await Utils.sleep(1000);
                    await this.navigateNextTopic();
                    break;
                }
            }

            await Utils.sleep(speed);
            this.accumulateTime();

            if (Math.random() < CONFIG.scroll.fastScrollChance) {
                const fastScroll = Utils.random(CONFIG.scroll.fastScrollMin, CONFIG.scroll.fastScrollMax);
                window.scrollBy({
                    top: fastScroll,
                    behavior: 'smooth'
                });
                await Utils.sleep(200);
            }
        }
    }

    async waitForPageLoad() {
        let attempts = 0;
        const maxAttempts = 5;

        while (attempts < maxAttempts) {
            if (Utils.isPageLoaded()) {
                return true;
            }
            await Utils.sleep(300);
            attempts++;
        }

        return false;
    }

    stopScrolling() {
        this.isScrolling = false;
        clearInterval(this.scrollInterval);
        clearTimeout(this.pauseTimeout);
        this.button.innerHTML = '<span class="btn-icon">▶</span><span class="btn-text">开始阅读</span>';
        this.button.classList.remove('running');
    }

    accumulateTime() {
        const now = Date.now();
        this.accumulatedTime += now - this.lastActionTime;
        this.setSessionStorage('accumulatedTime', this.accumulatedTime);
        this.lastActionTime = now;

        if (this.accumulatedTime >= CONFIG.time.browseTime) {
            this.accumulatedTime = 0;
            this.setSessionStorage('accumulatedTime', 0);
            this.pauseForRest();
        }
    }

    async pauseForRest() {
        this.stopScrolling();
        console.log("休息10分钟...");
        await Utils.sleep(CONFIG.time.restTime);
        console.log("休息结束,继续浏览...");
        this.startScrolling();
    }

    async navigateNextTopic() {
        const nextTopic = await this.getNextTopic();
        if (nextTopic) {
            console.log("导航到新文章:", nextTopic.title);
            const url = nextTopic.last_read_post_number
                ? `${BASE_URL}/t/topic/${nextTopic.id}/${nextTopic.last_read_post_number}`
                : `${BASE_URL}/t/topic/${nextTopic.id}`;
            window.location.href = url;
        } else {
            console.log("没有更多文章,返回首页");
            window.location.href = `${BASE_URL}/latest`;
        }
    }

    resetFirstUse() {
        Storage.set('firstUseChecked', false);
        Storage.set('likesCount', 0);
        Storage.set('selectedPost', null);
        this.firstUseChecked = false;
        this.likesCount = 0;
        this.selectedPost = null;
        console.log('已重置首次使用状态');
    }
}

// 初始化
(function() {
    window.browseController = new BrowseController();
})();