Linux.do 稍后再看

为 Linux.do 论坛添加稍后再看功能

// ==UserScript==
// @name         Linux.do 稍后再看
// @namespace    http://tampermonkey.net/
// @version      2.5
// @description  为 Linux.do 论坛添加稍后再看功能
// @author       HeYeYe
// @match        https://linux.do/*
// @exclude      https://linux.do/a/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @run-at       document-end
// @license      MIT License
// ==/UserScript==

(function() {
    'use strict';

    // 添加样式
    GM_addStyle(`
        /* 浮动管理面板 */
        #read-later-container {
            position: fixed;
            top: 50%;
            right: 20px;
            transform: translateY(-50%);
            z-index: 10000;
            user-select: none;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        }

        /* 主管理按钮 */
        #read-later-btn {
            width: 50px;
            height: 50px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border: none;
            border-radius: 25px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            transition: all 0.3s ease;
            color: white;
            font-size: 20px;
            position: relative;
        }

        #read-later-btn:hover {
            transform: scale(1.1);
            box-shadow: 0 6px 20px rgba(0,0,0,0.2);
        }

        /* 数量徽章 */
        .read-later-badge {
            position: absolute;
            top: -5px;
            right: -5px;
            background: #ff4757;
            color: white;
            border-radius: 10px;
            padding: 2px 6px;
            font-size: 11px;
            font-weight: bold;
            min-width: 16px;
            height: 16px;
            display: flex;
            align-items: center;
            justify-content: center;
            box-shadow: 0 2px 4px rgba(0,0,0,0.2);
        }

        /* 管理面板 */
        #read-later-panel {
            position: absolute;
            right: 60px;
            top: 0;
            width: 350px;
            background: white;
            border-radius: 12px;
            box-shadow: 0 8px 32px rgba(0,0,0,0.1);
            border: 1px solid #e1e8ed;
            display: none;
            overflow: hidden;
            max-height: 500px;
        }

        #read-later-panel.show {
            display: block;
            animation: slideIn 0.3s ease;
        }

        @keyframes slideIn {
            from { opacity: 0; transform: translateX(20px); }
            to { opacity: 1; transform: translateX(0); }
        }

        /* 面板头部 */
        .panel-header {
            padding: 15px 20px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            font-weight: 600;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .panel-close {
            background: none;
            border: none;
            color: white;
            font-size: 18px;
            cursor: pointer;
            padding: 0;
            width: 24px;
            height: 24px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 50%;
        }

        .panel-close:hover {
            background: rgba(255,255,255,0.2);
        }

        /* 列表区域 */
        .read-later-list {
            max-height: 350px;
            overflow-y: auto;
        }

        .list-item {
            padding: 12px 20px;
            border-bottom: 1px solid #f0f0f0;
            cursor: pointer;
            transition: background 0.2s;
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
        }

        .list-item:hover {
            background: #f8f9fa;
        }

        .list-item:last-child {
            border-bottom: none;
        }

        .item-content {
            flex: 1;
            min-width: 0;
        }

        .item-title {
            font-size: 13px;
            font-weight: 500;
            color: #333;
            margin: 0 0 4px 0;
            line-height: 1.3;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
        }

        .item-meta {
            font-size: 11px;
            color: #999;
            margin: 0;
            display: flex;
            gap: 10px;
        }

        .item-actions {
            margin-left: 10px;
            display: flex;
            gap: 5px;
        }

        .action-btn {
            width: 20px;
            height: 20px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 12px;
            display: flex;
            align-items: center;
            justify-content: center;
            transition: all 0.2s;
        }

        .delete-btn {
            background: #ff4757;
            color: white;
        }

        .delete-btn:hover {
            background: #ff3742;
            transform: scale(1.1);
        }

        /* 空状态 */
        .empty-state {
            padding: 40px 20px;
            text-align: center;
            color: #999;
            font-size: 14px;
        }

        /* 清空按钮 */
        .clear-all-btn {
            padding: 10px 20px;
            background: #ff4757;
            color: white;
            border: none;
            font-size: 12px;
            cursor: pointer;
            width: 100%;
            transition: background 0.2s;
        }

        .clear-all-btn:hover {
            background: #ff3742;
        }

        /* 隐藏按钮 */
        .hide-btn {
            position: absolute;
            top: -8px;
            right: -8px;
            width: 20px;
            height: 20px;
            background: #ff4757;
            color: white;
            border: none;
            border-radius: 50%;
            font-size: 12px;
            cursor: pointer;
            display: none;
            align-items: center;
            justify-content: center;
        }

        #read-later-container:hover .hide-btn {
            display: flex;
        }

        /* 恢复按钮(隐藏状态下) */
        .restore-btn {
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 40px;
            height: 40px;
            background: #667eea;
            color: white;
            border: none;
            border-radius: 50%;
            font-size: 16px;
            cursor: pointer;
            z-index: 10000;
            display: none;
            align-items: center;
            justify-content: center;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
        }

        .restore-btn:hover {
            transform: scale(1.1);
        }

        /* 拖拽时的样式 */
        .dragging {
            transition: none !important;
            opacity: 0.8;
        }

        /* 滚动条美化 */
        .read-later-list::-webkit-scrollbar {
            width: 6px;
        }

        .read-later-list::-webkit-scrollbar-track {
            background: #f1f1f1;
        }

        .read-later-list::-webkit-scrollbar-thumb {
            background: #c1c1c1;
            border-radius: 3px;
        }

        .read-later-list::-webkit-scrollbar-thumb:hover {
            background: #a1a1a1;
        }

        /* 列表页面的添加按钮样式 */
        .read-later-add-btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 20px;
            height: 20px;
            margin-left: 8px;
            background: #667eea;
            color: white;
            border: none;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            transition: all 0.2s ease;
            opacity: 0;
            transform: scale(0.8);
            vertical-align: middle;
        }

        .read-later-add-btn:hover {
            background: #5a6fd8;
            transform: scale(1);
        }

        .read-later-add-btn.added {
            background: #4CAF50;
            opacity: 1;
            transform: scale(1);
        }

        .read-later-add-btn.added:hover {
            background: #45a049;
        }

        /* 帖子项悬停时显示按钮 */
        .topic-list-item:hover .read-later-add-btn,
        .topic-list-body tr:hover .read-later-add-btn,
        .latest-topic-list-item:hover .read-later-add-btn,
        .topic-body:hover .read-later-add-btn {
            opacity: 1;
            transform: scale(1);
        }

        /* 已添加的按钮始终显示 */
        .read-later-add-btn.added {
            opacity: 1 !important;
            transform: scale(1) !important;
        }

        /* 当前帖子页面提示 */
        .current-topic-indicator {
            display: inline-flex;
            align-items: center;
            margin-left: 10px;
            padding: 4px 8px;
            background: #e8f5e8;
            color: #4CAF50;
            border-radius: 4px;
            font-size: 12px;
            font-weight: 500;
        }

        /* 同步相关样式 */
        .sync-status {
            padding: 8px 20px;
            background: #f8f9fa;
            border-bottom: 1px solid #e9ecef;
            font-size: 11px;
            color: #666;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .sync-status.syncing {
            background: #fff3cd;
            color: #856404;
        }

        .sync-status.error {
            background: #f8d7da;
            color: #721c24;
        }

        .sync-status.success {
            background: #d4edda;
            color: #155724;
        }

        .sync-btn {
            background: none;
            border: 1px solid #ccc;
            padding: 2px 8px;
            border-radius: 3px;
            font-size: 10px;
            cursor: pointer;
            transition: all 0.2s;
        }

        .sync-btn:hover {
            background: #f0f0f0;
        }

        .sync-btn:disabled {
            opacity: 0.5;
            cursor: not-allowed;
        }

        /* 设置面板样式 */
        .settings-panel {
            position: absolute;
            right: 60px;
            top: 0;
            width: 400px;
            background: white;
            border-radius: 12px;
            box-shadow: 0 8px 32px rgba(0,0,0,0.1);
            border: 1px solid #e1e8ed;
            display: none;
            overflow: visible; /* 改为 visible 允许下拉菜单溢出 */
            max-height: 600px;
        }

        .settings-panel.show {
            display: block;
            animation: slideIn 0.3s ease;
            overflow: visible; /* 确保显示时也允许溢出 */
        }

        .settings-form {
            padding: 20px;
            overflow: visible; /* 表单容器也允许溢出 */
        }

        .form-group {
            margin-bottom: 15px;
        }

        .form-label {
            display: block;
            margin-bottom: 5px;
            font-size: 13px;
            font-weight: 500;
            color: #333;
        }

        .form-input {
            width: 100%;
            padding: 8px 12px;
            border: 1px solid #ddd;
            border-radius: 6px;
            font-size: 13px;
            box-sizing: border-box;
        }

        .form-input:focus {
            outline: none;
            border-color: #667eea;
            box-shadow: 0 0 0 2px rgba(102, 126, 234, 0.1);
        }

        .form-textarea {
            min-height: 60px;
            resize: vertical;
            font-family: monospace;
        }

        .form-checkbox {
            margin-right: 8px;
        }

        .form-help {
            font-size: 11px;
            color: #666;
            margin-top: 4px;
            line-height: 1.4;
        }

        .form-actions {
            display: flex;
            gap: 10px;
            padding-top: 15px;
            border-top: 1px solid #eee;
        }

        .btn-primary {
            background: #667eea;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 6px;
            font-size: 13px;
            cursor: pointer;
            transition: background 0.2s;
        }

        .btn-primary:hover {
            background: #5a6fd8;
        }

        .btn-secondary {
            background: #6c757d;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 6px;
            font-size: 13px;
            cursor: pointer;
            transition: background 0.2s;
        }

        .btn-secondary:hover {
            background: #545b62;
        }

        .btn-danger {
            background: #dc3545;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 6px;
            font-size: 13px;
            cursor: pointer;
            transition: background 0.2s;
        }

        .btn-danger:hover {
            background: #c82333;
        }

        /* 设置按钮 */
        .settings-btn {
            position: absolute;
            top: -8px;
            left: -8px;
            width: 20px;
            height: 20px;
            background: #667eea;
            color: white;
            border: none;
            border-radius: 50%;
            font-size: 12px;
            cursor: pointer;
            display: none;
            align-items: center;
            justify-content: center;
        }

        #read-later-container:hover .settings-btn {
            display: flex;
        }

        /* 帖子计数显示 */
        .topic-count-info {
            padding: 10px 20px;
            background: #f8f9fa;
            border-bottom: 1px solid #e9ecef;
            font-size: 12px;
            color: #666;
            text-align: center;
        }

        /* Gist ID 输入组合样式 */
        .gist-input-group {
            position: relative;
            display: flex;
            gap: 5px;
            align-items: stretch;
        }

        .gist-input-group .form-input {
            flex: 1;
            margin: 0;
        }

        .gist-select-btn {
            background: #667eea;
            color: white;
            border: none;
            padding: 0 12px;
            border-radius: 6px;
            font-size: 12px;
            cursor: pointer;
            white-space: nowrap;
            transition: background 0.2s;
            height: 34px;
            min-width: 60px;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .gist-select-btn:hover {
            background: #5a6fd8;
        }

        .gist-select-btn:disabled {
            background: #ccc;
            cursor: not-allowed;
        }

        /* Gist 下拉菜单样式 */
        .gist-dropdown {
            position: absolute;
            top: calc(100% + 4px);  /* 调整距离,更贴近输入框 */
            left: 0;
            right: 0;
            background: white;
            border: 2px solid #667eea;
            border-radius: 6px;
            box-shadow: 0 8px 24px rgba(0,0,0,0.2);
            z-index: 99999;
            max-height: 250px;
            overflow-y: auto;
            display: none;
        }

        .gist-dropdown.show {
            display: block !important;
            visibility: visible !important;
            opacity: 1 !important;
        }

        /* 导出功能样式 */
        .export-section {
            padding: 15px 20px;
            border-top: 1px solid #e9ecef;
            background: #f8f9fa;
        }

        .export-title {
            font-size: 13px;
            font-weight: 600;
            color: #333;
            margin-bottom: 10px;
        }

        .export-options {
            display: flex;
            gap: 8px;
            margin-bottom: 10px;
        }

        .export-format-btn {
            padding: 6px 12px;
            border: 1px solid #ddd;
            background: white;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            transition: all 0.2s;
            color: #666;
        }

        .export-format-btn:hover {
            border-color: #667eea;
            color: #667eea;
        }

        .export-format-btn.active {
            background: #667eea;
            border-color: #667eea;
            color: white;
        }

        .export-actions {
            display: flex;
            gap: 8px;
        }

        .export-btn {
            flex: 1;
            padding: 8px 12px;
            background: #28a745;
            color: white;
            border: none;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            transition: background 0.2s;
        }

        .export-btn:hover {
            background: #218838;
        }

        .export-btn:disabled {
            background: #ccc;
            cursor: not-allowed;
        }

        .export-copy-btn {
            padding: 8px 12px;
            background: #17a2b8;
            color: white;
            border: none;
            border-radius: 4px;
            font-size: 12px;
            cursor: pointer;
            transition: background 0.2s;
        }

        .export-copy-btn:hover {
            background: #138496;
        }

        .export-info {
            font-size: 11px;
            color: #666;
            margin-top: 8px;
            line-height: 1.4;
        }

        .gist-dropdown-item {
            padding: 10px 12px;
            border-bottom: 1px solid #f0f0f0;
            cursor: pointer;
            transition: background 0.2s;
        }

        .gist-dropdown-item:hover {
            background: #f8f9fa;
        }

        .gist-dropdown-item:last-child {
            border-bottom: none;
        }

        .gist-item-id {
            font-family: monospace;
            font-size: 11px;
            color: #666;
            margin-bottom: 2px;
            word-break: break-all;
        }

        .gist-item-desc {
            font-size: 12px;
            color: #333;
            margin-bottom: 2px;
            line-height: 1.3;
        }

        .gist-item-date {
            font-size: 10px;
            color: #999;
        }

        .gist-dropdown-empty,
        .gist-dropdown-loading,
        .gist-dropdown-error {
            padding: 20px;
            text-align: center;
            font-size: 12px;
            line-height: 1.4;
        }

        .gist-dropdown-loading {
            color: #666;
        }

        .gist-dropdown-error {
            color: #ff4757;
        }

        .gist-dropdown-empty {
            color: #999;
        }
    `);

    // 全局变量
    let readLaterList = [];
    let isDragging = false;
    let dragOffset = { x: 0, y: 0 };
    let observer = null;
    let selectedExportFormat = 'markdown'; // 默认导出格式
    let lastDataChecksum = ''; // 用于检测数据变化
    let crossTabSyncInterval = null; // 跨标签页同步定时器
    let syncConfig = {
        enabled: false,
        token: '',
        gistId: '',
        lastSync: 0,
        autoSync: true,
        syncInterval: 5 * 60 * 1000 // 5分钟自动同步
    };

    // 初始化
    function init() {
        loadReadLaterList();
        loadSyncConfig();
        createFloatingButton();
        startObserving();

        // 启动跨标签页数据同步
        startCrossTabSync();

        // 初始扫描页面
        setTimeout(scanAndAddButtons, 1000);

        // 启动自动同步
        startAutoSync();

        // 监听页面变化(SPA路由)
        let currentUrl = window.location.href;
        setInterval(() => {
            if (window.location.href !== currentUrl) {
                currentUrl = window.location.href;
                setTimeout(scanAndAddButtons, 1000);
            }
        }, 2000);

        // 页面关闭前清理
        window.addEventListener('beforeunload', () => {
            if (crossTabSyncInterval) {
                clearInterval(crossTabSyncInterval);
            }
        });
    }

    // 加载稍后再看列表
    function loadReadLaterList() {
        const saved = GM_getValue('readLaterList', '[]');
        try {
            readLaterList = JSON.parse(saved);
            // 计算数据校验和
            lastDataChecksum = calculateChecksum(readLaterList);
            console.log('[稍后再看] 数据加载完成,校验和:', lastDataChecksum.substring(0, 8));
        } catch (e) {
            readLaterList = [];
            lastDataChecksum = '';
        }
    }

    // 计算数据校验和(简单的字符串哈希)
    function calculateChecksum(data) {
        const str = JSON.stringify(data);
        let hash = 0;
        for (let i = 0; i < str.length; i++) {
            const char = str.charCodeAt(i);
            hash = ((hash << 5) - hash) + char;
            hash = hash & hash; // 转换为32位整数
        }
        return hash.toString(36);
    }

    // 启动跨标签页数据同步
    function startCrossTabSync() {
        console.log('[稍后再看] 启动跨标签页数据同步');

        // 定期检查数据是否被其他标签页修改
        crossTabSyncInterval = setInterval(() => {
            checkCrossTabDataChanges();
        }, 1000); // 每秒检查一次
    }

    // 检查跨标签页数据变化
    function checkCrossTabDataChanges() {
        try {
            const saved = GM_getValue('readLaterList', '[]');
            const savedData = JSON.parse(saved);
            const currentChecksum = calculateChecksum(savedData);

            // 如果校验和不同,说明数据被其他标签页修改了
            if (currentChecksum !== lastDataChecksum) {
                console.log('[稍后再看] 检测到其他标签页的数据变化');
                console.log('[稍后再看] 旧校验和:', lastDataChecksum.substring(0, 8));
                console.log('[稍后再看] 新校验和:', currentChecksum.substring(0, 8));

                // 更新本地数据
                const oldCount = readLaterList.length;
                readLaterList = savedData;
                lastDataChecksum = currentChecksum;

                // 更新UI
                updateBadge();
                updateAllButtonStates();

                // 如果管理面板打开,更新内容
                const panel = document.getElementById('read-later-panel');
                if (panel && panel.classList.contains('show')) {
                    updatePanelContent();
                }

                const newCount = readLaterList.length;
                console.log('[稍后再看] 跨标签页同步完成:', oldCount, '→', newCount);

                // 显示提示(可选)
                if (Math.abs(newCount - oldCount) > 0) {
                    showToast(`数据已同步:${newCount} 个帖子`);
                }
            }
        } catch (error) {
            console.error('[稍后再看] 跨标签页数据检查失败:', error);
        }
    }

    // 保存稍后再看列表 - 添加修改时间记录
    function saveReadLaterList() {
        GM_setValue('readLaterList', JSON.stringify(readLaterList));

        // 记录本地修改时间
        const now = Date.now();
        GM_setValue('lastLocalModified', now);
        console.log('[稍后再看] 本地数据已保存,修改时间:', new Date(now).toLocaleString());

        // 如果启用了同步,标记需要同步
        if (syncConfig.enabled && syncConfig.autoSync) {
            GM_setValue('needSync', 'true');
        }
    }

    // 加载同步配置
    function loadSyncConfig() {
        const saved = GM_getValue('syncConfig', '{}');
        try {
            const savedConfig = JSON.parse(saved);
            syncConfig = { ...syncConfig, ...savedConfig };
        } catch (e) {
            console.error('[稍后再看] 加载同步配置失败:', e);
        }
    }

    // 保存同步配置
    function saveSyncConfig() {
        GM_setValue('syncConfig', JSON.stringify(syncConfig));
    }

    // 开始观察页面变化
    function startObserving() {
        // 停止之前的观察者
        if (observer) {
            observer.disconnect();
        }

        observer = new MutationObserver((mutations) => {
            let shouldScan = false;
            let hasRemovals = false;

            mutations.forEach((mutation) => {
                // 检查是否有新内容添加
                if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
                    for (let node of mutation.addedNodes) {
                        if (node.nodeType === 1) { // Element node
                            if (node.matches && (
                                node.matches('.topic-list-item') ||
                                node.matches('.latest-topic-list-item') ||
                                node.matches('.topic-list-body tr') ||
                                node.querySelector('.topic-list-item, .latest-topic-list-item, .topic-list-body tr')
                            )) {
                                shouldScan = true;
                                console.log(`[稍后再看] 检测到新增帖子元素:`, node);
                                break;
                            }
                        }
                    }
                }

                // 检查是否有按钮被移除
                if (mutation.type === 'childList' && mutation.removedNodes.length > 0) {
                    for (let node of mutation.removedNodes) {
                        if (node.nodeType === 1 && (
                            node.matches && node.matches('.read-later-add-btn') ||
                            node.querySelector && node.querySelector('.read-later-add-btn')
                        )) {
                            hasRemovals = true;
                            console.warn(`[稍后再看] 检测到按钮被移除:`, node);
                            break;
                        }
                    }
                }
            });

            if (hasRemovals) {
                console.warn(`[稍后再看] 按钮被外部移除,将重新扫描`);
                shouldScan = true;
            }

            if (shouldScan) {
                // 延迟执行,避免频繁触发
                clearTimeout(window.readLaterScanTimeout);
                window.readLaterScanTimeout = setTimeout(() => {
                    console.log(`[稍后再看] 触发重新扫描`);
                    scanAndAddButtons();
                }, 500);
            }
        });

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

        // console.log(`[稍后再看] 开始监听页面变化`);
    }

    // 扫描页面并添加按钮
    function scanAndAddButtons() {
        // console.log(`[稍后再看] 开始扫描页面...`);

        // 检查现有按钮数量
        const existingButtons = document.querySelectorAll('.read-later-add-btn');
        console.log(`[稍后再看] 发现 ${existingButtons.length} 个现有按钮`);

        // 获取所有帖子链接
        const topicSelectors = [
            // 首页帖子列表
            '.topic-list-item .main-link a.title',
            '.latest-topic-list-item .main-link a.title',
            // 表格形式的帖子列表
            '.topic-list-body tr .main-link a.title',
            // 搜索结果页面
            '.fps-result .topic .title a',
            // 分类页面
            '.category-list .topic-list .main-link a.title',
            // 用户页面的帖子
            '.user-stream .item .title a'
        ];

        let totalLinks = 0;
        let processedLinks = 0;
        let addedCount = 0;

        topicSelectors.forEach(selector => {
            const links = document.querySelectorAll(selector);
            totalLinks += links.length;

            links.forEach(link => {
                if (link.dataset.readLaterProcessed) {
                    processedLinks++;
                    // 检查是否还有对应的按钮
                    const existingBtn = link.parentNode?.querySelector('.read-later-add-btn');
                    if (!existingBtn) {
                        console.log(`[稍后再看] 发现丢失的按钮,重新添加: ${link.textContent.trim()}`);
                        addButtonToLink(link);
                        addedCount++;
                    }
                } else {
                    addButtonToLink(link);
                    link.dataset.readLaterProcessed = 'true';
                    addedCount++;
                }
            });
        });

        console.log(`[稍后再看] 扫描完成 - 总链接: ${totalLinks}, 已处理: ${processedLinks}, 新添加: ${addedCount}`);

        // 验证按钮是否真的存在
        setTimeout(() => {
            const finalButtons = document.querySelectorAll('.read-later-add-btn');
            console.log(`[稍后再看] 验证结果: ${finalButtons.length} 个按钮最终存在于页面中`);
            if (finalButtons.length !== addedCount + (existingButtons.length - processedLinks)) {
                console.warn(`[稍后再看] 警告: 按钮数量不匹配,可能被其他脚本或页面更新清除了`);
            }
        }, 100);
    }

    // 为链接添加按钮
    function addButtonToLink(link) {
        try {
            // 检查是否已经有按钮了
            const existingBtn = link.parentNode?.querySelector('.read-later-add-btn');
            if (existingBtn) {
                console.log(`[稍后再看] 链接已有按钮,跳过: ${link.textContent.trim()}`);
                return;
            }

            // 解析链接获取帖子信息
            const topicInfo = parseTopicLink(link);
            if (!topicInfo) {
                console.warn(`[稍后再看] 无法解析链接: ${link.href}`);
                return;
            }

            // 检查是否已添加
            const isAdded = readLaterList.some(item => item.id === topicInfo.id);

            // 创建按钮
            const button = document.createElement('button');
            button.className = 'read-later-add-btn' + (isAdded ? ' added' : '');
            button.innerHTML = isAdded ? '✓' : '+';
            button.title = isAdded ? '已在稍后再看中' : '添加到稍后再看';
            button.dataset.topicId = topicInfo.id;

            // 添加调试属性
            button.dataset.debugTitle = topicInfo.title;

            // 绑定点击事件
            button.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();
                // console.log(`[稍后再看] 按钮被点击: ${topicInfo.title}`);
                toggleReadLater(topicInfo, button);
            });

            // 插入按钮到标题后面
            if (link.parentNode) {
                link.parentNode.insertBefore(button, link.nextSibling);
                // console.log(`[稍后再看] 成功添加按钮: ${topicInfo.title} (ID: ${topicInfo.id})`);

                // 验证按钮是否真的被添加了
                setTimeout(() => {
                    const verifyBtn = link.parentNode?.querySelector('.read-later-add-btn');
                    if (!verifyBtn) {
                        console.error(`[稍后再看] 按钮添加后立即消失: ${topicInfo.title}`);
                        console.error(`[稍后再看] 父元素:`, link.parentNode);
                    }
                }, 10);
            } else {
                console.error(`[稍后再看] 无法找到父元素来插入按钮: ${topicInfo.title}`);
            }
        } catch (error) {
            console.error('[稍后再看] 添加按钮失败:', error);
            console.error('[稍后再看] 链接信息:', {
                href: link.href,
                text: link.textContent.trim(),
                parentNode: link.parentNode
            });
        }
    }

    // 解析帖子链接
    function parseTopicLink(link) {
        const href = link.href;
        const title = link.textContent.trim();

        // 匹配 /t/slug/id 格式
        const match = href.match(/\/t\/([^\/]+)\/(\d+)/);
        if (!match) return null;

        const slug = match[1];
        const id = match[2];

        return {
            id: id,
            title: title,
            url: href,
            slug: slug,
            addedAt: new Date().toISOString()
        };
    }

    // 切换稍后再看状态
    function toggleReadLater(topicInfo, button) {
        const isAdded = readLaterList.some(item => item.id === topicInfo.id);

        if (isAdded) {
            // 移除
            readLaterList = readLaterList.filter(item => item.id !== topicInfo.id);
            button.classList.remove('added');
            button.innerHTML = '+';
            button.title = '添加到稍后再看';
            showToast('已从稍后再看中移除');
        } else {
            // 添加
            readLaterList.unshift(topicInfo);
            button.classList.add('added');
            button.innerHTML = '✓';
            button.title = '已在稍后再看中';
            showToast('已添加到稍后再看');
        }

        saveReadLaterList();
        updateBadge();

        // 如果管理面板打开,更新内容
        const panel = document.getElementById('read-later-panel');
        if (panel && panel.classList.contains('show')) {
            updatePanelContent();
        }
    }

    // 从稍后再看中移除
    function removeFromReadLater(id) {
        readLaterList = readLaterList.filter(item => item.id !== id);
        saveReadLaterList();
        updateBadge();

        // 更新页面上对应的按钮状态
        const button = document.querySelector(`[data-topic-id="${id}"]`);
        if (button) {
            button.classList.remove('added');
            button.innerHTML = '+';
            button.title = '添加到稍后再看';
        }

        showToast('已从稍后再看中移除');
    }

    // 清空列表
    function clearAllReadLater() {
        if (readLaterList.length === 0) return;

        if (confirm('确定要清空所有稍后再看的帖子吗?')) {
            readLaterList = [];
            saveReadLaterList();
            updateBadge();

            // 更新所有按钮状态
            document.querySelectorAll('.read-later-add-btn.added').forEach(btn => {
                btn.classList.remove('added');
                btn.innerHTML = '+';
                btn.title = '添加到稍后再看';
            });

            updatePanelContent();
            showToast('已清空稍后再看列表');
        }
    }

    // 显示提示消息
    function showToast(message) {
        const toast = document.createElement('div');
        toast.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            background: rgba(0,0,0,0.8);
            color: white;
            padding: 12px 20px;
            border-radius: 6px;
            font-size: 14px;
            z-index: 10001;
            transition: all 0.3s ease;
        `;
        toast.textContent = message;
        document.body.appendChild(toast);

        setTimeout(() => {
            toast.style.opacity = '0';
            toast.style.transform = 'translateY(-20px)';
            setTimeout(() => {
                if (toast.parentNode) {
                    document.body.removeChild(toast);
                }
            }, 300);
        }, 2000);
    }

    // 切换设置面板
    function toggleSettingsPanel() {
        const settingsPanel = document.getElementById('settings-panel');
        const mainPanel = document.getElementById('read-later-panel');

        // 关闭主面板
        closePanel(mainPanel);

        const isShow = settingsPanel.classList.contains('show');
        if (isShow) {
            closePanel(settingsPanel);
        } else {
            updateSettingsPanel();
            settingsPanel.classList.add('show');
        }
    }

    // 关闭面板的统一函数
    function closePanel(panel) {
        if (panel && panel.classList.contains('show')) {
            panel.classList.remove('show');
            // 关闭 Gist 下拉菜单(如果存在)
            const dropdown = document.getElementById('gist-dropdown');
            if (dropdown) {
                dropdown.classList.remove('show');
            }
        }
    }

    // 关闭所有面板的函数
    function closeAllPanels() {
        const mainPanel = document.getElementById('read-later-panel');
        const settingsPanel = document.getElementById('settings-panel');

        closePanel(mainPanel);
        closePanel(settingsPanel);
    }

    // 创建浮动按钮
    function createFloatingButton() {
        // 主容器
        const container = document.createElement('div');
        container.id = 'read-later-container';

        // 主按钮
        const button = document.createElement('button');
        button.id = 'read-later-btn';
        button.innerHTML = '📚';
        button.title = '稍后再看管理';

        // 数量徽章
        const badge = document.createElement('span');
        badge.className = 'read-later-badge';
        badge.textContent = '0';
        button.appendChild(badge);

        // 操作面板
        const panel = document.createElement('div');
        panel.id = 'read-later-panel';

        // 设置面板
        const settingsPanel = document.createElement('div');
        settingsPanel.className = 'settings-panel';
        settingsPanel.id = 'settings-panel';

        // 隐藏按钮
        const hideBtn = document.createElement('button');
        hideBtn.className = 'hide-btn';
        hideBtn.innerHTML = '×';
        hideBtn.title = '隐藏';

        // 设置按钮
        const settingsBtn = document.createElement('button');
        settingsBtn.className = 'settings-btn';
        settingsBtn.innerHTML = '⚙';
        settingsBtn.title = '同步设置';

        container.appendChild(button);
        container.appendChild(panel);
        container.appendChild(settingsPanel);
        container.appendChild(hideBtn);
        container.appendChild(settingsBtn);
        document.body.appendChild(container);

        // 创建恢复按钮
        const restoreBtn = document.createElement('button');
        restoreBtn.className = 'restore-btn';
        restoreBtn.innerHTML = '📚';
        restoreBtn.title = '显示稍后再看';
        document.body.appendChild(restoreBtn);

        // 绑定事件
        button.addEventListener('click', togglePanel);
        hideBtn.addEventListener('click', hideContainer);
        restoreBtn.addEventListener('click', showContainer);
        settingsBtn.addEventListener('click', toggleSettingsPanel);

        // 拖拽功能
        makeDraggable(container);

        // 初始化UI
        updateBadge();

        // 修复后的点击外部关闭面板逻辑
        document.addEventListener('click', (e) => {
            // 检查点击是否在容器内
            if (!container.contains(e.target)) {
                // 点击在容器外部,关闭所有面板
                closeAllPanels();
            }
        });

        // 阻止容器内的点击冒泡到document
        container.addEventListener('click', (e) => {
            e.stopPropagation();
        });
    }

    // 更新徽章数量
    function updateBadge() {
        const badge = document.querySelector('.read-later-badge');
        if (badge) {
            const count = readLaterList.length;
            badge.textContent = count > 99 ? '99+' : count.toString();
            badge.style.display = count > 0 ? 'flex' : 'none';
        }
    }

    // 切换面板显示
    function togglePanel() {
        const panel = document.getElementById('read-later-panel');
        const settingsPanel = document.getElementById('settings-panel');
        const isShow = panel.classList.contains('show');

        // 先关闭设置面板
        closePanel(settingsPanel);

        if (isShow) {
            closePanel(panel);
        } else {
            updatePanelContent();
            panel.classList.add('show');
            // 加载用户的面板大小偏好
            loadPanelSize();
        }
    }

    // 隐藏容器
    function hideContainer() {
        const container = document.getElementById('read-later-container');
        const restoreBtn = document.querySelector('.restore-btn');
        container.style.display = 'none';
        restoreBtn.style.display = 'flex';
    }

    // 显示容器
    function showContainer() {
        const container = document.getElementById('read-later-container');
        const restoreBtn = document.querySelector('.restore-btn');
        container.style.display = 'block';
        restoreBtn.style.display = 'none';
    }

    // 更新面板内容
    function updatePanelContent() {
        const panel = document.getElementById('read-later-panel');
        const currentTopicInfo = getCurrentTopicInfo();

        panel.innerHTML = `
            <div class="panel-content">
                <div class="panel-header">
                    <span>稍后再看管理</span>
                    <div class="panel-resize-controls">
                        <button class="resize-btn" data-size="compact" title="紧凑">S</button>
                        <button class="resize-btn" data-size="normal" title="正常">M</button>
                        <button class="resize-btn" data-size="large" title="大尺寸">L</button>
                    </div>
                    <button class="panel-close">×</button>
                </div>

                ${getSyncStatusHTML()}

                <div class="topic-count-info">
                    共 ${readLaterList.length} 个帖子
                    ${currentTopicInfo ? '<span class="current-topic-indicator">当前帖子已在列表中</span>' : ''}
                </div>

                <div class="read-later-list">
                    ${readLaterList.length > 0 ?
                        readLaterList.map(item => `
                            <div class="list-item" data-id="${item.id}">
                                <div class="item-content">
                                    <h5 class="item-title">${item.title}</h5>
                                    <p class="item-meta">
                                        <span>${formatTime(item.addedAt)}</span>
                                        <span>ID: ${item.id}</span>
                                    </p>
                                </div>
                                <div class="item-actions">
                                    <button class="action-btn delete-btn" data-action="delete" data-id="${item.id}">×</button>
                                </div>
                            </div>
                        `).join('')
                        : '<div class="empty-state">暂无稍后再看的帖子<br>在帖子列表页面点击 + 按钮添加</div>'
                    }
                </div>

                ${readLaterList.length > 0 ? `
                    <div class="export-section">
                        <div class="export-title">📤 导出数据</div>
                        <div class="export-options">
                            <button class="export-format-btn ${selectedExportFormat === 'markdown' ? 'active' : ''}" data-format="markdown">MD</button>
                            <button class="export-format-btn ${selectedExportFormat === 'html' ? 'active' : ''}" data-format="html">HTML</button>
                            <button class="export-format-btn ${selectedExportFormat === 'json' ? 'active' : ''}" data-format="json">JSON</button>
                        </div>
                        <div class="export-actions">
                            <button class="export-btn" id="export-download-btn">📥 下载</button>
                            <button class="export-copy-btn" id="export-copy-btn">📋 复制</button>
                        </div>
                        <div class="export-info">
                            格式: <strong>${selectedExportFormat.toUpperCase()}</strong> • ${readLaterList.length} 个帖子
                        </div>
                    </div>
                    <button class="clear-all-btn">🗑️ 清空所有</button>
                ` : ''}
            </div>
        `;

        // 设置面板样式,但不强制 display 属性
        const currentStyle = panel.style.cssText;
        panel.style.cssText = `
            position: absolute !important;
            right: 60px !important;
            top: 0 !important;
            width: 450px !important;
            background: white !important;
            border-radius: 12px !important;
            box-shadow: 0 8px 32px rgba(0,0,0,0.1) !important;
            border: 1px solid #e1e8ed !important;
            overflow: visible !important;
            max-height: none !important;
            height: auto !important;
            z-index: 10000 !important;
        `;

        // 重新绑定事件
        bindPanelEvents(panel);
    }

    // 调整面板大小
    function resizePanel(size) {
        const panel = document.getElementById('read-later-panel');

        // 移除所有大小类
        panel.classList.remove('panel-compact', 'panel-normal', 'panel-large');

        // 添加新的大小类
        panel.classList.add(`panel-${size}`);

        // 保存用户偏好
        GM_setValue('panelSize', size);

        // 显示提示
        const sizeNames = {
            compact: '紧凑模式',
            normal: '正常模式',
            large: '大尺寸模式'
        };
        showToast(`已切换到${sizeNames[size]}`);
    }

    // 加载面板大小偏好
    function loadPanelSize() {
        const savedSize = GM_getValue('panelSize', 'normal');
        const panel = document.getElementById('read-later-panel');
        if (panel) {
            panel.classList.add(`panel-${savedSize}`);
        }
    }

    // 绑定面板事件
    function bindPanelEvents(panel) {
        const closeBtn = panel.querySelector('.panel-close');
        const clearAllBtn = panel.querySelector('.clear-all-btn');
        const listItems = panel.querySelectorAll('.list-item');
        const deleteButtons = panel.querySelectorAll('.delete-btn');
        const syncBtns = panel.querySelectorAll('.sync-btn');

        // 大小调整按钮
        const resizeBtns = panel.querySelectorAll('.resize-btn');

        // 导出相关元素
        const exportFormatBtns = panel.querySelectorAll('.export-format-btn');
        const exportDownloadBtn = panel.querySelector('#export-download-btn');
        const exportCopyBtn = panel.querySelector('#export-copy-btn');

        // 关闭按钮事件
        closeBtn?.addEventListener('click', (e) => {
            e.preventDefault();
            e.stopPropagation();
            closePanel(panel);
        });

        clearAllBtn?.addEventListener('click', clearAllReadLater);

        // 绑定大小调整按钮事件
        resizeBtns.forEach(btn => {
            btn.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();
                const size = btn.dataset.size;
                resizePanel(size);
            });
        });

        // 处理同步按钮点击
        syncBtns.forEach(btn => {
            btn.addEventListener('click', (e) => {
                const action = btn.dataset.action;
                if (action === 'sync') {
                    handleSyncAction();
                } else if (action === 'settings') {
                    toggleSettingsPanel();
                }
            });
        });

        // 列表项点击事件
        listItems.forEach(item => {
            item.addEventListener('click', (e) => {
                if (e.target.closest('.item-actions')) return;
                const id = item.dataset.id;
                const post = readLaterList.find(p => p.id === id);
                if (post) {
                    window.open(post.url, '_blank');
                }
            });
        });

        // 删除按钮事件
        deleteButtons.forEach(btn => {
            btn.addEventListener('click', (e) => {
                e.stopPropagation();
                const id = btn.dataset.id;
                removeFromReadLater(id);
                updatePanelContent();
            });
        });

        // 导出格式选择事件
        exportFormatBtns.forEach(btn => {
            btn.addEventListener('click', (e) => {
                e.stopPropagation();
                const format = btn.dataset.format;
                selectedExportFormat = format;

                // 更新按钮状态
                exportFormatBtns.forEach(b => b.classList.remove('active'));
                btn.classList.add('active');

                // 更新信息显示
                const infoDiv = panel.querySelector('.export-info');
                if (infoDiv) {
                    infoDiv.innerHTML = `格式: <strong>${format.toUpperCase()}</strong> • ${readLaterList.length} 个帖子`;
                }
            });
        });

        // 下载文件事件
        exportDownloadBtn?.addEventListener('click', (e) => {
            e.stopPropagation();
            exportToFile(selectedExportFormat);
        });

        // 复制内容事件
        exportCopyBtn?.addEventListener('click', (e) => {
            e.stopPropagation();
            copyExportContent(selectedExportFormat);
        });
    }

    // 调整面板大小函数
    function resizePanel(size) {
        const panel = document.getElementById('read-later-panel');

        if (!panel) {
            console.error('[稍后再看] 找不到面板元素');
            return;
        }

        // 移除所有大小类
        panel.classList.remove('panel-compact', 'panel-normal', 'panel-large');

        // 根据大小设置不同的宽度
        let width, listHeight;
        switch (size) {
            case 'compact':
                width = '320px';
                listHeight = '250px';
                break;
            case 'large':
                width = '500px';
                listHeight = '450px';
                break;
            default: // normal
                width = '380px';
                listHeight = '350px';
        }

        // 直接设置样式
        panel.style.width = width;

        // 调整列表高度
        const listElement = panel.querySelector('.read-later-list');
        if (listElement) {
            listElement.style.maxHeight = listHeight;
        }

        // 保存用户偏好
        GM_setValue('panelSize', size);

        // 显示提示
        const sizeNames = {
            compact: '紧凑模式',
            normal: '正常模式',
            large: '大尺寸模式'
        };
        showToast(`已切换到${sizeNames[size]} (${width})`);
    }

    // 获取同步状态HTML
    function getSyncStatusHTML() {
        if (!syncConfig.enabled) {
            return `
                <div class="sync-status">
                    <span>未启用同步</span>
                    <button class="sync-btn" data-action="settings">设置</button>
                </div>
            `;
        }

        const lastSyncText = syncConfig.lastSync ?
            `上次同步: ${formatTime(new Date(syncConfig.lastSync).toISOString())}` :
            '未同步';

        const needSync = GM_getValue('needSync', 'false') === 'true';
        const statusClass = needSync ? 'error' : 'success';
        const statusText = needSync ? '需要同步' : '已同步';

        return `
            <div class="sync-status ${statusClass}">
                <span>${statusText} • ${lastSyncText}</span>
                <button class="sync-btn" data-action="sync">立即同步</button>
            </div>
        `;
    }

    // 处理同步操作
    async function handleSyncAction() {
        const syncBtn = document.querySelector('.sync-btn[data-action="sync"]');
        if (!syncBtn) return;

        try {
            syncBtn.disabled = true;
            syncBtn.textContent = '同步中...';

            await performSync();

            syncBtn.textContent = '同步成功';
            setTimeout(() => {
                updatePanelContent();
            }, 1000);
        } catch (error) {
            console.error('[稍后再看] 同步失败:', error);
            syncBtn.textContent = '同步失败';
            showToast('同步失败: ' + error.message);
            setTimeout(() => {
                updatePanelContent();
            }, 2000);
        }
    }

    // 获取当前帖子信息(如果在帖子页面)
    function getCurrentTopicInfo() {
        const topicMatch = window.location.pathname.match(/^\/t\/([^\/]+)\/(\d+)/);
        if (!topicMatch) return null;

        const topicId = topicMatch[2];
        return readLaterList.find(item => item.id === topicId);
    }

    // 使元素可拖拽
    function makeDraggable(element) {
        let pos = GM_getValue('buttonPosition', null);
        if (pos) {
            try {
                pos = JSON.parse(pos);
                element.style.top = pos.top;
                element.style.right = pos.right;
                element.style.transform = 'none';
            } catch (e) {
                // 使用默认位置
            }
        }

        element.addEventListener('mousedown', startDrag);
        document.addEventListener('mousemove', drag);
        document.addEventListener('mouseup', stopDrag);

        function startDrag(e) {
            if (e.target.closest('#read-later-panel') || e.target.closest('.hide-btn') || e.target.closest('.settings-panel')) {
                return;
            }

            isDragging = true;
            element.classList.add('dragging');

            const rect = element.getBoundingClientRect();
            dragOffset.x = e.clientX - rect.left;
            dragOffset.y = e.clientY - rect.top;

            e.preventDefault();
        }

        function drag(e) {
            if (!isDragging) return;

            const x = e.clientX - dragOffset.x;
            const y = e.clientY - dragOffset.y;

            // 边界检测
            const maxX = window.innerWidth - element.offsetWidth;
            const maxY = window.innerHeight - element.offsetHeight;

            const newX = Math.max(0, Math.min(x, maxX));
            const newY = Math.max(0, Math.min(y, maxY));

            element.style.left = newX + 'px';
            element.style.top = newY + 'px';
            element.style.right = 'auto';
            element.style.transform = 'none';
        }

        function stopDrag() {
            if (!isDragging) return;

            isDragging = false;
            element.classList.remove('dragging');

            // 保存位置
            const style = window.getComputedStyle(element);
            GM_setValue('buttonPosition', JSON.stringify({
                top: style.top,
                right: style.right
            }));
        }
    }

    // 格式化时间
    function formatTime(isoString) {
        const date = new Date(isoString);
        const now = new Date();
        const diff = now - date;

        const minutes = Math.floor(diff / 60000);
        const hours = Math.floor(diff / 3600000);
        const days = Math.floor(diff / 86400000);

        if (minutes < 1) return '刚刚';
        if (minutes < 60) return `${minutes}分钟前`;
        if (hours < 24) return `${hours}小时前`;
        if (days < 7) return `${days}天前`;

        return date.toLocaleDateString('zh-CN');
    }

    // ===== 导出功能 =====

    // 生成导出内容
    function generateExportContent(format) {
        const timestamp = new Date().toLocaleString('zh-CN');
        const count = readLaterList.length;

        switch (format) {
            case 'markdown':
                return generateMarkdown(timestamp, count);
            case 'html':
                return generateHTML(timestamp, count);
            case 'json':
                return generateJSON(timestamp, count);
            default:
                return '';
        }
    }

    // 生成 Markdown 格式
    function generateMarkdown(timestamp, count) {
        const header = `# Linux.do 稍后再看列表

> 导出时间: ${timestamp}
> 帖子数量: ${count}

---

`;

        const content = readLaterList.map((item, index) => {
            const addedDate = new Date(item.addedAt).toLocaleDateString('zh-CN');
            return `## ${index + 1}. ${item.title}

- **链接**: [${item.title}](${item.url})
- **帖子ID**: ${item.id}
- **添加时间**: ${addedDate}
- **URL**: \`${item.url}\`

`;
        }).join('');

        const footer = `---

*由 Linux.do 稍后再看脚本导出*`;

        return header + content + footer;
    }

    // 生成 HTML 格式
    function generateHTML(timestamp, count) {
        const header = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Linux.do 稍后再看列表</title>
    <style>
        body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; max-width: 800px; margin: 0 auto; padding: 20px; background: #f8f9fa; }
        .container { background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
        h1 { color: #333; border-bottom: 3px solid #667eea; padding-bottom: 10px; }
        .meta { background: #e9ecef; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
        .item { margin-bottom: 25px; padding: 20px; border: 1px solid #dee2e6; border-radius: 5px; background: #f8f9fa; }
        .item h3 { margin: 0 0 10px 0; color: #495057; }
        .item a { color: #667eea; text-decoration: none; font-weight: 500; }
        .item a:hover { text-decoration: underline; }
        .details { font-size: 14px; color: #6c757d; margin-top: 10px; }
        .details span { margin-right: 15px; }
        .footer { text-align: center; margin-top: 30px; color: #6c757d; font-size: 14px; }
    </style>
</head>
<body>
    <div class="container">
        <h1>📚 Linux.do 稍后再看列表</h1>
        <div class="meta">
            <strong>导出时间:</strong> ${timestamp}<br>
            <strong>帖子数量:</strong> ${count}
        </div>
`;

        const content = readLaterList.map((item, index) => {
            const addedDate = new Date(item.addedAt).toLocaleDateString('zh-CN');
            return `        <div class="item">
            <h3>${index + 1}. <a href="${item.url}" target="_blank">${item.title}</a></h3>
            <div class="details">
                <span><strong>帖子ID:</strong> ${item.id}</span>
                <span><strong>添加时间:</strong> ${addedDate}</span>
            </div>
        </div>
`;
        }).join('');

        const footer = `        <div class="footer">
            <em>由 Linux.do 稍后再看脚本导出</em>
        </div>
    </div>
</body>
</html>`;

        return header + content + footer;
    }

    // 生成 JSON 格式
    function generateJSON(timestamp, count) {
        const exportData = {
            metadata: {
                title: 'Linux.do 稍后再看列表',
                exportTime: timestamp,
                exportTimestamp: Date.now(),
                count: count,
                version: '2.3',
                source: 'Linux.do 稍后再看脚本'
            },
            data: readLaterList.map(item => ({
                id: item.id,
                title: item.title,
                url: item.url,
                slug: item.slug,
                addedAt: item.addedAt,
                addedTimestamp: new Date(item.addedAt).getTime()
            }))
        };

        return JSON.stringify(exportData, null, 2);
    }

    // 导出到文件
    function exportToFile(format) {
        try {
            const content = generateExportContent(format);
            const timestamp = new Date().toISOString().slice(0, 19).replace(/:/g, '-');

            let filename, mimeType;
            switch (format) {
                case 'markdown':
                    filename = `linux-do-readlater-${timestamp}.md`;
                    mimeType = 'text/markdown';
                    break;
                case 'html':
                    filename = `linux-do-readlater-${timestamp}.html`;
                    mimeType = 'text/html';
                    break;
                case 'json':
                    filename = `linux-do-readlater-${timestamp}.json`;
                    mimeType = 'application/json';
                    break;
                default:
                    throw new Error('不支持的导出格式');
            }

            // 创建下载链接
            const blob = new Blob([content], { type: mimeType + ';charset=utf-8' });
            const url = URL.createObjectURL(blob);

            const a = document.createElement('a');
            a.href = url;
            a.download = filename;
            a.style.display = 'none';

            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);

            // 清理 URL
            setTimeout(() => URL.revokeObjectURL(url), 1000);

            showToast(`已导出 ${format.toUpperCase()} 文件: ${filename}`);
        } catch (error) {
            console.error('[稍后再看] 导出文件失败:', error);
            showToast('导出文件失败: ' + error.message);
        }
    }

    // 复制导出内容到剪贴板
    async function copyExportContent(format) {
        try {
            const content = generateExportContent(format);

            if (navigator.clipboard && navigator.clipboard.writeText) {
                await navigator.clipboard.writeText(content);
                showToast(`已复制 ${format.toUpperCase()} 内容到剪贴板`);
            } else {
                // 降级方案:使用 textarea
                const textarea = document.createElement('textarea');
                textarea.value = content;
                textarea.style.position = 'fixed';
                textarea.style.opacity = '0';
                document.body.appendChild(textarea);
                textarea.select();
                document.execCommand('copy');
                document.body.removeChild(textarea);
                showToast(`已复制 ${format.toUpperCase()} 内容到剪贴板(兼容模式)`);
            }
        } catch (error) {
            console.error('[稍后再看] 复制内容失败:', error);
            showToast('复制失败: ' + error.message);
        }
    }

    // ===== 同步功能 =====

    // 更新设置面板 - 修复版本,添加 Gist 选择功能
    function updateSettingsPanel() {
        const panel = document.getElementById('settings-panel');

        panel.innerHTML = `
            <div class="panel-header">
                <span>同步设置</span>
                <button class="panel-close">×</button>
            </div>

            <div class="settings-form">
                <div class="form-group">
                    <label class="form-label">
                        <input type="checkbox" class="form-checkbox" id="sync-enabled" ${syncConfig.enabled ? 'checked' : ''}>
                        启用跨设备同步
                    </label>
                    <div class="form-help">通过 GitHub Gist 在不同设备间同步稍后再看列表</div>
                </div>

                <div class="form-group">
                    <label class="form-label" for="github-token">GitHub Token</label>
                    <input type="password" class="form-input" id="github-token" placeholder="ghp_xxxxxxxxxxxx" value="${syncConfig.token}">
                    <div class="form-help">
                        需要创建一个有 gist 权限的 GitHub Token<br>
                        <a href="https://github.com/settings/tokens/new?scopes=gist" target="_blank">点击创建 Token</a>
                    </div>
                </div>

                <div class="form-group">
                    <label class="form-label" for="gist-id">Gist ID</label>
                    <div class="gist-input-group">
                        <input type="text" class="form-input" id="gist-id" placeholder="请输入已存在的 Gist ID 或留空创建新的" value="${syncConfig.gistId}">
                        <button type="button" class="gist-select-btn" id="gist-select-btn">选择</button>
                    </div>
                    <div class="gist-dropdown" id="gist-dropdown"></div>
                    <div class="form-help">
                        <strong style="color: #ff6b6b;">重要:</strong>如果这是第二台设备,请从第一台设备复制 Gist ID 到这里!<br>
                        Gist ID 可以在 GitHub Gist URL 中找到:https://gist.github.com/<strong>YOUR_GIST_ID</strong><br>
                        ${syncConfig.gistId ? `<span style="color: #4CAF50;">当前 Gist ID: ${syncConfig.gistId}</span>` : '<span style="color: #ff9800;">未设置 Gist ID,将创建新的</span>'}
                    </div>
                </div>

                <div class="form-group">
                    <label class="form-label">
                        <input type="checkbox" class="form-checkbox" id="auto-sync" ${syncConfig.autoSync ? 'checked' : ''}>
                        自动同步
                    </label>
                    <div class="form-help">每5分钟自动与云端同步数据</div>
                </div>

                <div class="form-actions">
                    <button class="btn-primary" id="save-settings">保存设置</button>
                    <button class="btn-secondary" id="test-sync">测试连接</button>
                    <button class="btn-danger" id="reset-sync">重置同步</button>
                </div>

                <div id="sync-test-result" style="margin-top: 15px; font-size: 12px;"></div>
            </div>
        `;

        // 绑定事件
        const closeBtn = panel.querySelector('.panel-close');
        const saveBtn = panel.querySelector('#save-settings');
        const testBtn = panel.querySelector('#test-sync');
        const resetBtn = panel.querySelector('#reset-sync');
        const gistSelectBtn = panel.querySelector('#gist-select-btn');

        closeBtn.addEventListener('click', () => closePanel(panel));
        saveBtn.addEventListener('click', saveSettings);
        testBtn.addEventListener('click', testSync);
        resetBtn.addEventListener('click', resetSync);
        gistSelectBtn.addEventListener('click', toggleGistDropdown);
    }

    // 切换 Gist 下拉菜单
    async function toggleGistDropdown() {
        const dropdown = document.getElementById('gist-dropdown');
        const selectBtn = document.getElementById('gist-select-btn');
        const tokenInput = document.getElementById('github-token');

        const token = tokenInput.value.trim();
        if (!token) {
            showToast('请先填入 GitHub Token');
            return;
        }

        const isShow = dropdown.classList.contains('show');
        if (isShow) {
            dropdown.classList.remove('show');
            return;
        }

        // 显示加载状态
        console.log('[稍后再看] 开始加载 Gist 列表');
        dropdown.innerHTML = '<div class="gist-dropdown-loading">正在加载 Gist 列表...</div>';
        dropdown.classList.add('show');

        // 强制显示下拉菜单
        dropdown.style.display = 'block';
        dropdown.style.visibility = 'visible';
        dropdown.style.opacity = '1';

        selectBtn.disabled = true;
        selectBtn.textContent = '加载中...';

        try {
            const gists = await fetchUserGists(token);
            console.log('[稍后再看] 获取到 Gist 列表:', gists.length, '个');
            displayGistDropdown(gists);
        } catch (error) {
            console.error('[稍后再看] 获取 Gist 列表失败:', error);
            dropdown.innerHTML = `<div class="gist-dropdown-error">加载失败: ${error.message}<br><small>请检查 Token 是否正确</small></div>`;

            // 显示错误 5 秒后自动关闭
            setTimeout(() => {
                dropdown.classList.remove('show');
                dropdown.style.display = '';
                dropdown.style.visibility = '';
                dropdown.style.opacity = '';
            }, 5000);
        } finally {
            selectBtn.disabled = false;
            selectBtn.textContent = '选择';
        }
    }

    // 获取用户的 Gist 列表
    async function fetchUserGists(token) {
        try {
            const response = await fetch('https://api.github.com/gists?per_page=50', {
                headers: {
                    'Authorization': `token ${token}`,
                    'Accept': 'application/vnd.github.v3+json'
                }
            });

            if (!response.ok) {
                const errorText = await response.text();
                console.error('[稍后再看] GitHub API 错误响应:', errorText);

                if (response.status === 401) {
                    throw new Error('GitHub Token 无效或已过期');
                } else if (response.status === 403) {
                    throw new Error('GitHub Token 权限不足,需要 gist 权限');
                } else {
                    throw new Error(`GitHub API 错误: ${response.status}`);
                }
            }

            const allGists = await response.json();
            console.log('[稍后再看] 获取到所有 Gist:', allGists.length, '个');

            // 筛选出稍后再看相关的 Gist
            const readLaterGists = allGists.filter(gist => {
                const hasReadLaterFile = gist.files && gist.files['readlater.json'];
                const hasReadLaterDesc = gist.description && (
                    gist.description.includes('稍后再看') ||
                    gist.description.includes('Linux.do')
                );
                return hasReadLaterFile || hasReadLaterDesc;
            });

            console.log('[稍后再看] 筛选后的相关 Gist:', readLaterGists.length, '个');

            return readLaterGists;
        } catch (error) {
            console.error('[稍后再看] fetchUserGists 错误:', error);
            throw error;
        }
    }

    // 显示 Gist 下拉菜单
    function displayGistDropdown(gists) {
        const dropdown = document.getElementById('gist-dropdown');
        console.log('[稍后再看] 显示下拉菜单,Gist 数量:', gists.length);

        if (gists.length === 0) {
            dropdown.innerHTML = `
                <div class="gist-dropdown-empty">
                    未找到稍后再看相关的 Gist<br>
                    <small>保存设置时将自动创建新的</small><br>
                    <button class="btn-secondary" style="margin-top: 8px; font-size: 11px; padding: 4px 8px;" onclick="document.getElementById('gist-dropdown').classList.remove('show')">关闭</button>
                </div>
            `;
            return;
        }

        const gistItems = gists.map(gist => {
            const createDate = new Date(gist.created_at).toLocaleDateString('zh-CN');
            const description = gist.description || '无描述';
            const truncatedDesc = description.length > 50 ? description.substring(0, 50) + '...' : description;

            return `
                <div class="gist-dropdown-item" data-gist-id="${gist.id}" title="点击选择此 Gist">
                    <div class="gist-item-id">${gist.id}</div>
                    <div class="gist-item-desc">${truncatedDesc}</div>
                    <div class="gist-item-date">创建于 ${createDate}</div>
                </div>
            `;
        }).join('');

        dropdown.innerHTML = gistItems;

        // 确保下拉菜单可见
        dropdown.classList.add('show');
        dropdown.style.cssText = `
            display: block !important;
            visibility: visible !important;
            opacity: 1 !important;
            position: absolute !important;
            z-index: 99999 !important;
            background: white !important;
            border: 2px solid #667eea !important;
            border-radius: 6px !important;
            box-shadow: 0 8px 24px rgba(0,0,0,0.3) !important;
            max-height: 250px !important;
            overflow-y: auto !important;
            top: calc(100% + 2px) !important;
            left: 0 !important;
            right: 0 !important;
        `;

        // 绑定点击事件
        dropdown.querySelectorAll('.gist-dropdown-item').forEach((item, index) => {
            item.addEventListener('click', (e) => {
                e.preventDefault();
                e.stopPropagation();
                console.log('[稍后再看] 选择 Gist:', item.dataset.gistId);
                const gistId = item.dataset.gistId;
                const gistInput = document.getElementById('gist-id');
                gistInput.value = gistId;

                // 关闭下拉菜单
                dropdown.classList.remove('show');
                dropdown.style.cssText = '';

                showToast(`已选择 Gist: ${gistId.substring(0, 8)}...`);
            });
        });
    }

    // 保存设置
    function saveSettings() {
        const enabled = document.getElementById('sync-enabled').checked;
        const token = document.getElementById('github-token').value.trim();
        const gistId = document.getElementById('gist-id').value.trim();
        const autoSync = document.getElementById('auto-sync').checked;

        if (enabled && !token) {
            alert('请填入 GitHub Token');
            return;
        }

        // 验证 Gist ID 格式(如果填写了的话)
        if (gistId && !/^[a-f0-9]{32}$/.test(gistId)) {
            alert('Gist ID 格式不正确,应该是32位的十六进制字符串');
            return;
        }

        syncConfig.enabled = enabled;
        syncConfig.token = token;
        syncConfig.gistId = gistId;
        syncConfig.autoSync = autoSync;

        saveSyncConfig();
        showToast('设置已保存');

        // 重启自动同步
        startAutoSync();

        // 关闭面板和下拉菜单
        closeAllPanels();
    }

    // 测试同步连接
    async function testSync() {
        const resultDiv = document.getElementById('sync-test-result');
        const testBtn = document.getElementById('test-sync');

        const token = document.getElementById('github-token').value.trim();
        if (!token) {
            resultDiv.innerHTML = '<span style="color: red;">请先填入 GitHub Token</span>';
            return;
        }

        try {
            testBtn.disabled = true;
            testBtn.textContent = '测试中...';
            resultDiv.innerHTML = '<span style="color: blue;">正在测试连接...</span>';

            // 测试 GitHub API 连接
            const response = await fetch('https://api.github.com/user', {
                headers: {
                    'Authorization': `token ${token}`,
                    'Accept': 'application/vnd.github.v3+json'
                }
            });

            if (response.ok) {
                const user = await response.json();
                resultDiv.innerHTML = `<span style="color: green;">✓ 连接成功!用户: ${user.login}</span>`;
            } else {
                throw new Error(`GitHub API 错误: ${response.status}`);
            }
        } catch (error) {
            console.error('[稍后再看] 测试同步失败:', error);
            resultDiv.innerHTML = `<span style="color: red;">✗ 连接失败: ${error.message}</span>`;
        } finally {
            testBtn.disabled = false;
            testBtn.textContent = '测试连接';
        }
    }

    // 重置同步
    function resetSync() {
        if (confirm('确定要重置所有同步设置吗?这将清除 Token 和 Gist ID,但不会删除本地数据。')) {
            syncConfig = {
                enabled: false,
                token: '',
                gistId: '',
                lastSync: 0,
                autoSync: true,
                syncInterval: 5 * 60 * 1000
            };
            saveSyncConfig();
            GM_setValue('needSync', 'false');
            showToast('同步设置已重置');
            updateSettingsPanel();
        }
    }

    // 执行同步 - 修复删除同步问题
    async function performSync() {
        if (!syncConfig.enabled || !syncConfig.token) {
            throw new Error('同步未启用或缺少 Token');
        }

        console.log('[稍后再看] 开始同步...');

        try {
            // 如果没有 Gist ID,先尝试查找现有的 Gist
            if (!syncConfig.gistId) {
                const existingGist = await findExistingGist();
                if (existingGist) {
                    syncConfig.gistId = existingGist.id;
                    saveSyncConfig();
                    console.log('[稍后再看] 找到现有 Gist:', existingGist.id);
                    showToast(`找到现有 Gist: ${existingGist.id.substring(0, 8)}...`);
                } else {
                    await createGist();
                    showToast('创建了新的同步 Gist');
                }
            }

            // 获取远程数据
            const remoteData = await getRemoteData();

            // 合并数据
            const mergedData = mergeData(readLaterList, remoteData);

            // 检查是否有变化
            const hasChanges = JSON.stringify(mergedData) !== JSON.stringify(readLaterList);

            if (hasChanges) {
                console.log('[稍后再看] 检测到数据变化,更新本地数据');
                readLaterList = mergedData;
                // 不调用 saveReadLaterList(),避免更新修改时间
                GM_setValue('readLaterList', JSON.stringify(readLaterList));
                updateBadge();

                // 更新页面上的按钮状态
                setTimeout(updateAllButtonStates, 100);
            }

            // 总是上传当前数据到远程(确保远程是最新的)
            await uploadData(readLaterList);

            // 更新同步状态
            syncConfig.lastSync = Date.now();
            saveSyncConfig();
            GM_setValue('needSync', 'false');

            // 记录远程同步时间
            GM_setValue('lastRemoteSync', Date.now());

            console.log('[稍后再看] 同步完成');
            return true;
        } catch (error) {
            console.error('[稍后再看] 同步失败:', error);
            throw error;
        }
    }

    // 查找现有的稍后再看 Gist
    async function findExistingGist() {
        try {
            const response = await fetch('https://api.github.com/gists', {
                headers: {
                    'Authorization': `token ${syncConfig.token}`,
                    'Accept': 'application/vnd.github.v3+json'
                }
            });

            if (!response.ok) {
                return null;
            }

            const gists = await response.json();
            const readLaterGist = gists.find(gist =>
                gist.files['readlater.json'] && (
                    gist.description?.includes('稍后再看') ||
                    gist.description?.includes('Linux.do')
                )
            );

            return readLaterGist || null;
        } catch (error) {
            console.error('[稍后再看] 查找现有 Gist 失败:', error);
            return null;
        }
    }

    // 创建新的 Gist
    async function createGist() {
        try {
            const response = await fetch('https://api.github.com/gists', {
                method: 'POST',
                headers: {
                    'Authorization': `token ${syncConfig.token}`,
                    'Accept': 'application/vnd.github.v3+json',
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                    description: `Linux.do 稍后再看数据 - 创建于 ${new Date().toLocaleString()} - 设备: ${navigator.platform}`,
                    public: false,
                    files: {
                        'readlater.json': {
                            content: JSON.stringify({
                                version: '1.0',
                                data: readLaterList,
                                lastModified: Date.now(),
                                device: navigator.userAgent,
                                createdAt: new Date().toISOString()
                            }, null, 2)
                        }
                    }
                })
            });

            if (!response.ok) {
                throw new Error(`创建 Gist 失败: ${response.status}`);
            }

            const gist = await response.json();
            syncConfig.gistId = gist.id;
            saveSyncConfig();

            // 更新 README
            try {
                await fetch(`https://api.github.com/gists/${gist.id}`, {
                    method: 'PATCH',
                    headers: {
                        'Authorization': `token ${syncConfig.token}`,
                        'Accept': 'application/vnd.github.v3+json',
                        'Content-Type': 'application/json'
                    },
                    body: JSON.stringify({
                        files: {
                            'README.md': {
                                content: `# Linux.do 稍后再看数据

这个 Gist 存储了您在 Linux.do 论坛的稍后再看列表。

**重要提示:**
- 如果您要在多个设备间同步,请将此 Gist ID 复制到其他设备的设置中
- **Gist ID: \`${gist.id}\`**
- 请勿手动修改 readlater.json 文件内容

创建时间: ${new Date().toLocaleString()}
设备信息: ${navigator.platform}

## 如何在其他设备使用

1. 在其他设备安装相同的脚本
2. 打开同步设置
3. 填入相同的 GitHub Token
4. 在 "Gist ID" 字段填入: \`${gist.id}\`
5. 保存设置即可开始同步
`
                            }
                        }
                    })
                });
            } catch (error) {
                console.error('[稍后再看] 更新 README 失败:', error);
            }

        } catch (error) {
            console.error('[稍后再看] 创建 Gist 失败:', error);
            throw error;
        }
    }

    // 获取远程数据
    async function getRemoteData() {
        const response = await fetch(`https://api.github.com/gists/${syncConfig.gistId}`, {
            headers: {
                'Authorization': `token ${syncConfig.token}`,
                'Accept': 'application/vnd.github.v3+json'
            }
        });

        if (!response.ok) {
            if (response.status === 404) {
                console.log('[稍后再看] Gist 不存在,将创建新的');
                syncConfig.gistId = '';
                saveSyncConfig();
                return [];
            }
            throw new Error(`获取远程数据失败: ${response.status}`);
        }

        const gist = await response.json();
        const fileContent = gist.files['readlater.json']?.content;

        if (!fileContent) {
            return [];
        }

        try {
            const data = JSON.parse(fileContent);
            return data.data || [];
        } catch (error) {
            console.error('[稍后再看] 解析远程数据失败:', error);
            return [];
        }
    }

    // 上传数据到远程 - 包含时间戳
    async function uploadData(data) {
        const now = Date.now();
        const response = await fetch(`https://api.github.com/gists/${syncConfig.gistId}`, {
            method: 'PATCH',
            headers: {
                'Authorization': `token ${syncConfig.token}`,
                'Accept': 'application/vnd.github.v3+json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                files: {
                    'readlater.json': {
                        content: JSON.stringify({
                            version: '1.0',
                            data: data,
                            lastModified: now,
                            device: navigator.userAgent,
                            count: data.length,
                            uploadTime: new Date(now).toISOString()
                        }, null, 2)
                    }
                }
            })
        });

        if (!response.ok) {
            throw new Error(`上传数据失败: ${response.status}`);
        }

        console.log('[稍后再看] 数据已上传到远程,时间:', new Date(now).toLocaleString());
    }

    // 合并本地和远程数据 - 修复删除同步问题
    function mergeData(localData, remoteData) {
        // 获取本地和远程的最后修改时间
        const localLastModified = GM_getValue('lastLocalModified', 0);
        const remoteLastModified = GM_getValue('lastRemoteSync', 0);

        console.log('[稍后再看] 合并数据 - 本地修改时间:', new Date(localLastModified).toLocaleString());
        console.log('[稍后再看] 合并数据 - 远程同步时间:', new Date(remoteLastModified).toLocaleString());
        console.log('[稍后再看] 本地数据:', localData.length, '项');
        console.log('[稍后再看] 远程数据:', remoteData.length, '项');

        // 如果本地数据更新,以本地为准
        if (localLastModified > remoteLastModified) {
            console.log('[稍后再看] 本地数据较新,以本地为准');
            return [...localData];
        }

        // 如果远程数据更新,以远程为准
        if (remoteLastModified > localLastModified) {
            console.log('[稍后再看] 远程数据较新,以远程为准');
            return [...remoteData];
        }

        // 如果时间相同,进行智能合并
        console.log('[稍后再看] 时间相同,进行智能合并');

        const localIds = new Set(localData.map(item => item.id));
        const remoteIds = new Set(remoteData.map(item => item.id));

        // 创建合并后的数据集合
        const mergedMap = new Map();

        // 添加本地数据
        localData.forEach(item => {
            mergedMap.set(item.id, { ...item, source: 'local' });
        });

        // 添加远程独有的数据
        remoteData.forEach(remoteItem => {
            if (!localIds.has(remoteItem.id)) {
                mergedMap.set(remoteItem.id, { ...remoteItem, source: 'remote' });
            }
        });

        // 转换为数组并按添加时间排序
        const merged = Array.from(mergedMap.values()).map(item => {
            // 移除临时的 source 属性
            const { source, ...cleanItem } = item;
            return cleanItem;
        });

        merged.sort((a, b) => new Date(b.addedAt) - new Date(a.addedAt));

        console.log('[稍后再看] 合并完成,最终数据:', merged.length, '项');
        return merged;
    }

    // 更新所有按钮状态
    function updateAllButtonStates() {
        document.querySelectorAll('.read-later-add-btn').forEach(btn => {
            const topicId = btn.dataset.topicId;
            const isAdded = readLaterList.some(item => item.id === topicId);

            if (isAdded && !btn.classList.contains('added')) {
                btn.classList.add('added');
                btn.innerHTML = '✓';
                btn.title = '已在稍后再看中';
            } else if (!isAdded && btn.classList.contains('added')) {
                btn.classList.remove('added');
                btn.innerHTML = '+';
                btn.title = '添加到稍后再看';
            }
        });
    }

    // 启动自动同步
    function startAutoSync() {
        // 清除现有的定时器
        if (window.readLaterSyncInterval) {
            clearInterval(window.readLaterSyncInterval);
        }

        if (!syncConfig.enabled || !syncConfig.autoSync) {
            return;
        }

        // 设置定时同步
        window.readLaterSyncInterval = setInterval(async () => {
            const needSync = GM_getValue('needSync', 'false') === 'true';
            if (needSync) {
                try {
                    await performSync();
                    console.log('[稍后再看] 自动同步完成');
                } catch (error) {
                    console.error('[稍后再看] 自动同步失败:', error);
                }
            }
        }, syncConfig.syncInterval);

        console.log('[稍后再看] 自动同步已启动,间隔:', syncConfig.syncInterval / 1000, '秒');
    }

    // 启动脚本
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();