Enhanced Exhentai Record (Optimized)

增強型 Exhentai 記錄腳本,優化加載進度和閱讀體驗,支持後台加載

Stan na 16-03-2025. Zobacz najnowsza wersja.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

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

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         Enhanced Exhentai Record (Optimized)
// @namespace    http://tampermonkey.net/
// @version      4.1
// @description  增強型 Exhentai 記錄腳本,優化加載進度和閱讀體驗,支持後台加載
// @author       You
// @match        https://exhentai.org/watched*
// @icon         https://www.google.com/s2/favicons?domain=exhentai.org
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    // 配置選項
    const CONFIG = {
        autoHideRecorded: true,      // 自動隱藏已記錄項目
        loadDelay: 800,              // 加載下一頁的延遲(毫秒)
        toastDuration: 3000,         // Toast 顯示時間
        storageKey: 'exhentai_record',// 本地存儲鍵名
        continueInBackground: true   // 切換頁面時繼續加載
    };

    // DOM 元素引用
    let DOM = {
        progressBar: null,
        progressText: null,
        readingProgressBar: null,
        statusArea: null,
        totalCountElem: null,
        pageRecordedElem: null,
        pageUnrecordedElem: null,
        pageHiddenElem: null
    };

    // 統計數據
    const STATS = {
        totalProcessed: 0,
        totalAdded: 0,
        totalFiltered: 0,
        currentPage: 1,
        estimatedTotalPages: 0,
        readingProgress: 0
    };

    // 加載狀態
    const LOADING_STATE = {
        userPaused: false,     // 用戶手動暫停
        backgroundPaused: false, // 因切換到後台而暫停
        processing: false      // 正在處理
    };

    // SVG 圖標定義
    const ICONS = {
        record: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"></path><polyline points="17 21 17 13 7 13 7 21"></polyline><polyline points="7 3 7 8 15 8"></polyline></svg>',
        toggle: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle></svg>',
        download: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="7 10 12 15 17 10"></polyline><line x1="12" y1="15" x2="12" y2="3"></line></svg>',
        upload: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path><polyline points="17 8 12 3 7 8"></polyline><line x1="12" y1="3" x2="12" y2="15"></line></svg>',
        loadAll: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="8 17 12 21 16 17"></polyline><line x1="12" y1="12" x2="12" y2="21"></line><path d="M20.88 18.09A5 5 0 0 0 18 9h-1.26A8 8 0 1 0 3 16.29"></path></svg>',
        info: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"></circle><line x1="12" y1="16" x2="12" y2="12"></line><line x1="12" y1="8" x2="12.01" y2="8"></line></svg>',
        data: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"></path><polyline points="3.27 6.96 12 12.01 20.73 6.96"></polyline><line x1="12" y1="22.08" x2="12" y2="12"></line></svg>',
        check: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 11 12 14 22 4"></polyline><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path></svg>',
        uncheck: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"></rect><line x1="9" y1="9" x2="15" y2="15"></line><line x1="15" y1="9" x2="9" y2="15"></line></svg>',
        hidden: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path><line x1="1" y1="1" x2="23" y2="23"></line></svg>',
        stop: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="18" height="18" rx="2" ry="2"/></svg>',
        pause: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/></svg>',
        play: '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 3 19 12 5 21 5 3"></polygon></svg>'
    };

    // 樣式定義
    const STYLES = `
        /* 主控制面板 */
        .ex-record-toolbar {
            position: sticky;
            top: 0;
            margin: 0 auto;
            padding: 15px;
            background-color: #333;
            border-radius: 5px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            flex-wrap: wrap;
            box-shadow: 0 3px 10px rgba(0,0,0,0.3);
            z-index: 1000;
            margin-bottom: 15px;
            border: 1px solid #444;
            max-width: 95%;
        }

        /* 按鈕樣式 */
        .ex-record-btn {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            margin: 5px;
            padding: 8px 15px;
            background-color: #444;
            color: #eee;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.3s;
            border: none;
            font-weight: bold;
            font-size: 14px;
            min-width: 120px;
            box-shadow: 0 2px 5px rgba(0,0,0,0.2);
        }

        .ex-record-btn svg {
            margin-right: 8px;
        }

        .ex-record-btn:hover {
            background-color: #555;
            transform: translateY(-2px);
            box-shadow: 0 4px 8px rgba(0,0,0,0.3);
        }

        .ex-record-btn:active {
            transform: translateY(0);
            box-shadow: 0 1px 3px rgba(0,0,0,0.2);
        }

        /* 不同類型的按鈕顏色 */
        .ex-record-add {
            background-color: #1a73e8;
        }

        .ex-record-add:hover {
            background-color: #1967d2;
        }

        .ex-record-toggle {
            background-color: #34a853;
        }

        .ex-record-toggle:hover {
            background-color: #2d9247;
        }

        .ex-record-export {
            background-color: #ea4335;
        }

        .ex-record-export:hover {
            background-color: #d33426;
        }

        .ex-record-import {
            background-color: #fbbc05;
            color: #333;
        }

        .ex-record-import:hover {
            background-color: #f0b400;
        }

        .ex-record-stop {
            background-color: #ea4335;
        }

        .ex-record-stop:hover {
            background-color: #d33426;
        }

        /* 信息顯示 */
        .ex-record-info {
            display: inline-flex;
            align-items: center;
            padding: 8px 12px;
            margin: 5px;
            border-radius: 4px;
            background-color: #444;
            color: #eee;
            font-weight: bold;
            border: 1px solid #555;
            box-shadow: 0 1px 3px rgba(0,0,0,0.2);
        }

        .ex-record-info svg {
            margin-right: 8px;
            color: #aaa;
        }

        /* 標記已記錄項目 */
        .ex-record-highlighted {
            background-color: rgba(26, 115, 232, 0.15) !important;
            border-left: 4px solid #1a73e8 !important;
        }

        /* 記錄時間顯示 */
        .ex-record-time {
            font-size: 12px;
            color: #aaa;
            margin-left: 8px;
            display: inline-block;
            padding: 3px 6px;
            background-color: rgba(0, 0, 0, 0.2);
            border-radius: 3px;
        }

        /* Toast 消息 */
        .ex-record-toast {
            position: fixed;
            top: 20px;
            right: 20px;
            padding: 12px 20px;
            background-color: rgba(50, 50, 50, 0.9);
            color: #fff;
            border-radius: 4px;
            z-index: 10000;
            animation: ex-record-fadeInOut 3s ease-in-out forwards;
            box-shadow: 0 4px 10px rgba(0,0,0,0.3);
            border-left: 4px solid #1a73e8;
            max-width: 300px;
        }

        @keyframes ex-record-fadeInOut {
            0% { opacity: 0; transform: translateY(-20px); }
            10% { opacity: 1; transform: translateY(0); }
            80% { opacity: 1; transform: translateY(0); }
            100% { opacity: 0; transform: translateY(-20px); }
        }

        /* 模態對話框 */
        .ex-record-modal {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.7);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 10001;
        }

        .ex-record-modal-content {
            background-color: #333;
            padding: 20px;
            border-radius: 8px;
            width: 80%;
            max-width: 600px;
            box-shadow: 0 5px 15px rgba(0,0,0,0.5);
            color: #eee;
            border: 1px solid #444;
        }

        .ex-record-modal-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 15px;
            border-bottom: 1px solid #444;
            padding-bottom: 10px;
        }

        .ex-record-modal-close {
            background: none;
            border: none;
            font-size: 24px;
            cursor: pointer;
            color: #aaa;
        }

        .ex-record-modal-close:hover {
            color: #fff;
        }

        .ex-record-modal-body {
            margin-bottom: 15px;
        }

        .ex-record-modal textarea {
            width: 100%;
            height: 200px;
            background-color: #222;
            color: #eee;
            border: 1px solid #444;
            padding: 10px;
            border-radius: 4px;
            resize: vertical;
            font-family: monospace;
        }

        .ex-record-modal-footer {
            display: flex;
            justify-content: flex-end;
            gap: 10px;
        }

        .ex-record-modal-btn {
            padding: 8px 15px;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-weight: bold;
            min-width: 80px;
        }

        .ex-record-modal-btn-primary {
            background-color: #1a73e8;
            color: white;
        }

        .ex-record-modal-btn-primary:hover {
            background-color: #1967d2;
        }

        .ex-record-modal-btn-secondary {
            background-color: #444;
            color: #eee;
        }

        .ex-record-modal-btn-secondary:hover {
            background-color: #555;
        }

        /* 控制面板內的區域 */
        .ex-record-toolbar {
            flex-direction: column;
            padding: 12px 15px;
        }

        .ex-record-controls-row {
            display: flex;
            width: 100%;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 8px;
        }

        .ex-record-controls-row:last-child {
            margin-bottom: 0;
        }

        .ex-record-controls-left, .ex-record-controls-center, .ex-record-controls-right {
            display: flex;
            align-items: center;
            flex-wrap: wrap;
        }

        .ex-record-controls-stats {
            flex: 1;
            display: flex;
            flex-wrap: wrap;
            justify-content: flex-start;
        }

        .ex-record-controls-center {
            flex-grow: 1;
            justify-content: center;
            margin: 0 10px;
        }

        .ex-record-controls-buttons {
            flex: 1;
            display: flex;
            justify-content: center;
        }

        .ex-record-controls-data {
            display: flex;
            justify-content: flex-end;
        }

        /* 進度條樣式 */
        .ex-record-progress-container {
            position: fixed;
            bottom: 20px;
            right: 20px;
            width: 300px;
            background-color: #333;
            border-radius: 5px;
            padding: 12px;
            box-shadow: 0 3px 10px rgba(0,0,0,0.3);
            border: 1px solid #444;
            z-index: 1000;
            transition: opacity 0.3s ease;
        }

        .ex-record-progress-container.hidden {
            opacity: 0;
            pointer-events: none;
        }

        .ex-record-progress-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 8px;
        }

        .ex-record-progress-title {
            font-weight: bold;
            color: #eee;
        }

        .ex-record-progress-controls {
            display: flex;
            gap: 5px;
        }

        .ex-record-progress-btn {
            background: none;
            border: none;
            color: #aaa;
            cursor: pointer;
            padding: 0;
            display: flex;
            align-items: center;
            justify-content: center;
            width: 24px;
            height: 24px;
            border-radius: 50%;
            transition: all 0.2s;
        }

        .ex-record-progress-btn:hover {
            background-color: #444;
            color: #fff;
        }

        .ex-record-progress {
            width: 100%;
            height: 6px;
            background-color: #444;
            border-radius: 3px;
            margin: 5px 0;
            overflow: hidden;
        }

        .ex-record-progress-bar {
            height: 100%;
            background-color: #1a73e8;
            width: 0%;
            transition: width 0.3s ease;
        }

        .ex-record-reading-progress {
            width: 100%;
            height: 6px;
            background-color: #444;
            border-radius: 3px;
            margin: 8px 0 5px 0;
            overflow: hidden;
        }

        .ex-record-reading-progress-bar {
            height: 100%;
            background-color: #34a853;
            width: 0%;
            transition: width 0.3s ease;
        }

        .ex-record-progress-stats {
            display: flex;
            justify-content: space-between;
            color: #aaa;
            font-size: 12px;
            margin-top: 5px;
        }

        .ex-record-progress-text {
            color: #eee;
            font-size: 13px;
            margin: 8px 0;
        }

        /* 數據管理下拉選單 */
        .ex-record-controls-right {
            position: relative;
        }

        .ex-record-data-buttons {
            position: absolute;
            right: 0;
            top: 100%;
            background-color: #333;
            border-radius: 4px;
            padding: 5px;
            display: none;
            flex-direction: column;
            z-index: 2000;
            box-shadow: 0 3px 8px rgba(0,0,0,0.3);
            border: 1px solid #444;
            min-width: 120px;
        }

        .ex-record-controls-right:hover .ex-record-data-buttons {
            display: flex;
        }

        .ex-record-data-toggle {
            display: flex;
            align-items: center;
            justify-content: center;
            background-color: #444;
            color: #eee;
            padding: 8px 15px;
            border-radius: 4px;
            cursor: pointer;
            transition: all 0.3s;
            font-weight: bold;
            font-size: 14px;
            border: none;
        }

        .ex-record-data-toggle svg {
            margin-right: 8px;
        }

        .ex-record-data-toggle:hover {
            background-color: #555;
        }
    `;

    // 工具函數
    const Utils = {
        // 從 localStorage 獲取記錄
        getRecords() {
            try {
                const recordStr = localStorage.getItem(CONFIG.storageKey);
                return recordStr ? JSON.parse(recordStr) : {};
            } catch (e) {
                console.error('解析記錄失敗:', e);
                return {};
            }
        },

        // 保存記錄到 localStorage
        saveRecords(records) {
            try {
                localStorage.setItem(CONFIG.storageKey, JSON.stringify(records));
                return true;
            } catch (e) {
                console.error('保存記錄失敗:', e);
                UI.showToast('保存記錄失敗: ' + e.message);
                return false;
            }
        },

        // 格式化時間
        formatDate(dateString) {
            try {
                const date = new Date(dateString);
                const year = date.getFullYear();
                const month = String(date.getMonth() + 1).padStart(2, '0');
                const day = String(date.getDate()).padStart(2, '0');
                const hours = String(date.getHours()).padStart(2, '0');
                const minutes = String(date.getMinutes()).padStart(2, '0');

                return `${year}-${month}-${day} ${hours}:${minutes}`;
            } catch (e) {
                return '未知時間';
            }
        },

        // 獲取表格主體
        getTableBody() {
            const table = document.querySelector('.itg.glte');
            return table && table.tBodies.length > 0 ? table.tBodies[0] : null;
        },

        // 獲取頁面中的所有項目 ID
        getPageItems() {
            const tableBody = this.getTableBody();
            if (!tableBody) return [];

            return Array.from(tableBody.rows)
                .map(row => {
                    const link = row.querySelector('a');
                    if (!link) return null;
                    const url = link.href.split("/").filter(i => i !== '');
                    return url[url.length - 1] + url[url.length - 2];
                })
                .filter(id => id !== null);
        },

        // 從URL獲取項目ID
        getIdFromUrl(url) {
            const parts = url.split("/").filter(i => i !== '');
            return parts[parts.length - 1] + parts[parts.length - 2];
        },

        // 估算總頁數
        estimateTotalPages() {
            // 嘗試從分頁器中獲取頁數
            const pager = document.querySelector('.ptt');
            if (pager) {
                const lastPageLink = Array.from(pager.querySelectorAll('a')).pop();
                if (lastPageLink && lastPageLink.textContent) {
                    const pageNum = parseInt(lastPageLink.textContent);
                    if (!isNaN(pageNum)) {
                        return pageNum;
                    }
                }
            }
            // 如果無法從頁面獲取,返回預設值
            return 10;
        },

        // 獲取當前頁碼
        getCurrentPage() {
            const pager = document.querySelector('.ptt');
            if (pager) {
                const currentPageElement = pager.querySelector('td.ptds');
                if (currentPageElement && currentPageElement.textContent) {
                    const pageNum = parseInt(currentPageElement.textContent);
                    if (!isNaN(pageNum)) {
                        return pageNum;
                    }
                }
            }
            return 1;
        },

        // 動態調整閱讀進度
        updateReadingProgress() {
            // 計算閱讀進度百分比
            const tableBody = this.getTableBody();
            if (!tableBody) return 0;

            const totalItems = tableBody.rows.length;
            if (totalItems === 0) return 0;

            // 通過檢測可見區域來判斷閱讀進度
            const viewportHeight = window.innerHeight;
            const viewportTop = window.scrollY;
            const viewportBottom = viewportTop + viewportHeight;

            let visibleCount = 0;

            Array.from(tableBody.rows).forEach(row => {
                const rect = row.getBoundingClientRect();
                const rowTop = rect.top + viewportTop;
                const rowBottom = rect.bottom + viewportTop;

                // 行完全可見或部分可見
                if ((rowTop >= viewportTop && rowTop <= viewportBottom) ||
                    (rowBottom >= viewportTop && rowBottom <= viewportBottom) ||
                    (rowTop <= viewportTop && rowBottom >= viewportBottom)) {
                    visibleCount++;
                }
                // 已經滾動過的行
                else if (rowBottom < viewportTop) {
                    visibleCount++;
                }
            });

            const progress = Math.min(100, Math.round((visibleCount / totalItems) * 100));

            if (DOM.readingProgressBar) {
                DOM.readingProgressBar.style.width = `${progress}%`;
            }

            return progress;
        },

        // 延時執行函數
        debounce(func, wait) {
            let timeout;
            return function(...args) {
                clearTimeout(timeout);
                timeout = setTimeout(() => func.apply(this, args), wait);
            };
        },

        // 可靠的延時函數,即使在後台也能工作
        reliableDelay(ms) {
            return new Promise(resolve => {
                const startTime = Date.now();
                const checkTime = () => {
                    const elapsedTime = Date.now() - startTime;
                    if (elapsedTime >= ms) {
                        resolve();
                    } else {
                        setTimeout(checkTime, Math.min(100, ms - elapsedTime));
                    }
                };
                setTimeout(checkTime, Math.min(100, ms));
            });
        },

        // 記錄到控制台
        log(message) {
            console.log(`[ExRecord] ${message}`);
        }
    };

    // UI 操作相關
    const UI = {
        // 顯示 Toast 消息
        showToast(message, duration = CONFIG.toastDuration) {
            const toast = document.createElement('div');
            toast.className = 'ex-record-toast';
            toast.textContent = message;
            document.body.appendChild(toast);

            setTimeout(() => {
                if (toast.parentNode) {
                    document.body.removeChild(toast);
                }
            }, duration);
        },

        // 創建進度顯示容器
        createProgressContainer() {
            const container = document.createElement('div');
            container.className = 'ex-record-progress-container';
            container.id = 'ex-record-progress-container';
            container.innerHTML = `
                <div class="ex-record-progress-header">
                    <div class="ex-record-progress-title">加載進度</div>
                    <div class="ex-record-progress-controls">
                        <button class="ex-record-progress-btn" id="ex-record-pause-btn" title="暫停/繼續加載">
                            ${ICONS.pause}
                        </button>
                        <button class="ex-record-progress-btn" id="ex-record-stop-btn" title="停止加載">
                            ${ICONS.stop}
                        </button>
                    </div>
                </div>
                <div class="ex-record-progress-text" id="ex-record-progress-text">準備加載...</div>
                <div class="ex-record-progress">
                    <div class="ex-record-progress-bar" id="ex-record-progress-bar"></div>
                </div>
                <div class="ex-record-progress-stats">
                    <span id="ex-record-progress-page">頁面: 0/0</span>
                    <span id="ex-record-progress-items">已加載: 0</span>
                </div>
                <div class="ex-record-progress-text">閱讀進度</div>
                <div class="ex-record-reading-progress">
                    <div class="ex-record-reading-progress-bar" id="ex-record-reading-progress-bar"></div>
                </div>
                <div class="ex-record-progress-stats">
                    <span id="ex-record-reading-percent">0%</span>
                    <span id="ex-record-new-items">新項目: 0</span>
                </div>
            `;

            document.body.appendChild(container);

            // 獲取DOM引用
            DOM.progressBar = document.getElementById('ex-record-progress-bar');
            DOM.progressText = document.getElementById('ex-record-progress-text');
            DOM.readingProgressBar = document.getElementById('ex-record-reading-progress-bar');

            // 設置暫停/停止按鈕事件
            document.getElementById('ex-record-pause-btn').addEventListener('click', () => {
                this.toggleLoadingPause();
            });

            document.getElementById('ex-record-stop-btn').addEventListener('click', () => {
                this.stopLoading();
            });

            return container;
        },

        // 更新暫停按鈕圖標
        updatePauseButtonIcon(isPaused) {
            const pauseBtn = document.getElementById('ex-record-pause-btn');
            if (pauseBtn) {
                pauseBtn.innerHTML = isPaused ? ICONS.play : ICONS.pause;
                pauseBtn.title = isPaused ? "繼續加載" : "暫停加載";
            }
        },

        // 更新加載進度
        updateProgress(percent, currentPage, totalPages, loadedItems) {
            if (DOM.progressBar) {
                DOM.progressBar.style.width = `${percent}%`;
            }

            // 更新頁面計數
            const pageCountElement = document.getElementById('ex-record-progress-page');
            if (pageCountElement) {
                pageCountElement.textContent = `頁面: ${currentPage}/${totalPages || '?'}`;
            }

            // 更新已加載項目數
            const itemsCountElement = document.getElementById('ex-record-progress-items');
            if (itemsCountElement) {
                itemsCountElement.textContent = `已加載: ${loadedItems}`;
            }

            // 更新新項目數
            const newItemsElement = document.getElementById('ex-record-new-items');
            if (newItemsElement) {
                newItemsElement.textContent = `新項目: ${STATS.totalAdded}`;
            }

            // 更新閱讀百分比
            const readingPercentElement = document.getElementById('ex-record-reading-percent');
            if (readingPercentElement) {
                const readingPercent = Utils.updateReadingProgress();
                STATS.readingProgress = readingPercent;
                readingPercentElement.textContent = `${readingPercent}%`;
            }
        },

        // 更新加載狀態文本
        updateProgressText(text) {
            if (DOM.progressText) {
                DOM.progressText.textContent = text;
            }
        },

        // 顯示/隱藏進度容器
        toggleProgressContainer(show = true) {
            const container = document.getElementById('ex-record-progress-container');
            if (container) {
                container.className = show
                    ? 'ex-record-progress-container'
                    : 'ex-record-progress-container hidden';
            }
        },

        // 暫停/繼續加載
        toggleLoadingPause() {
            const loader = PageLoader;

            if (LOADING_STATE.userPaused) {
                // 如果是用戶暫停,則恢復
                LOADING_STATE.userPaused = false;
                this.updatePauseButtonIcon(false);

                if (!LOADING_STATE.backgroundPaused) {
                    // 如果不是因為背景暫停,則恢復加載
                    loader.processNextItem();
                    this.updateProgressText('繼續加載中...');
                    this.showToast('繼續加載');
                } else {
                    this.updateProgressText('頁面處於後台,將在返回前台時繼續加載');
                    this.showToast('已設置為繼續加載,將在返回前台時恢復');
                }
            } else {
                // 暫停加載
                LOADING_STATE.userPaused = true;
                this.updatePauseButtonIcon(true);
                this.updateProgressText('加載已暫停(用戶手動)');
                this.showToast('加載已暫停');
            }
        },

        // 停止加載
        stopLoading() {
            PageLoader.stopLoading();
            LOADING_STATE.userPaused = false;
            LOADING_STATE.backgroundPaused = false;
            this.updatePauseButtonIcon(false);
            this.updateProgressText('加載已停止');
            this.showToast('加載已停止');

            // 3秒後隱藏進度條
            setTimeout(() => {
                this.toggleProgressContainer(false);
            }, 3000);
        },

        // 創建控制面板
        createControlPanel() {
            const controlPanel = document.createElement('div');
            controlPanel.className = 'ex-record-toolbar';

            // 構建控制面板HTML - 分為上下兩行
            controlPanel.innerHTML = `
                <!-- 第一行:數據統計 -->
                <div class="ex-record-controls-row">
                    <div class="ex-record-controls-stats">
                        <div class="ex-record-info" id="ex-record-total-count">
                            ${ICONS.info}總記錄: 0 筆
                        </div>
                        <div class="ex-record-info" id="ex-record-page-recorded">
                            ${ICONS.check}本頁已記錄: 0 筆
                        </div>
                        <div class="ex-record-info" id="ex-record-page-unrecorded">
                            ${ICONS.uncheck}本頁未記錄: 0 筆
                        </div>
                        <div class="ex-record-info" id="ex-record-page-hidden">
                            ${ICONS.hidden}本頁隱藏: 0 筆
                        </div>
                    </div>
                </div>

                <!-- 第二行:操作按鈕 -->
                <div class="ex-record-controls-row">
                    <!-- 中間按鈕區域 -->
                    <div class="ex-record-controls-buttons">
                        <button class="ex-record-btn ex-record-add" id="ex-record-add-btn">
                            ${ICONS.record}記錄此頁
                        </button>
                        <button class="ex-record-btn ex-record-toggle" id="ex-record-toggle-btn">
                            ${ICONS.toggle}隱藏/顯示
                        </button>
                        <button class="ex-record-btn ex-record-add" id="ex-record-load-all-btn">
                            ${ICONS.loadAll}加載所有頁面
                        </button>
                    </div>

                    <!-- 右側數據管理按鈕 -->
                    <div class="ex-record-controls-data">
                        <div class="ex-record-controls-right">
                            <button class="ex-record-data-toggle" id="ex-record-data-toggle">
                                ${ICONS.data}數據管理
                            </button>
                            <div class="ex-record-data-buttons">
                                <button class="ex-record-btn ex-record-export" id="ex-record-export-btn">
                                    ${ICONS.download}匯出記錄
                                </button>
                                <button class="ex-record-btn ex-record-import" id="ex-record-import-btn">
                                    ${ICONS.upload}匯入記錄
                                </button>
                            </div>
                        </div>
                    </div>
                </div>
            `;

            // 插入到頁面中
            const target = document.querySelector('.searchnav');
            if (target && target.parentNode) {
                target.parentNode.insertBefore(controlPanel, target);
            } else {
                const searchtext = document.querySelector('.searchtext');
                if (searchtext && searchtext.parentNode) {
                    searchtext.parentNode.insertBefore(controlPanel, searchtext.nextSibling);
                } else {
                    document.body.insertBefore(controlPanel, document.body.firstChild);
                }
            }

            // 保存DOM引用
            DOM.totalCountElem = document.getElementById('ex-record-total-count');
            DOM.pageRecordedElem = document.getElementById('ex-record-page-recorded');
            DOM.pageUnrecordedElem = document.getElementById('ex-record-page-unrecorded');
            DOM.pageHiddenElem = document.getElementById('ex-record-page-hidden');

            // 綁定按鈕事件
            document.getElementById('ex-record-add-btn').addEventListener('click', () => Record.recordCurrentPage());
            document.getElementById('ex-record-toggle-btn').addEventListener('click', () => Record.toggleRecordedItems());
            document.getElementById('ex-record-load-all-btn').addEventListener('click', () => PageLoader.loadAllPages());
            document.getElementById('ex-record-export-btn').addEventListener('click', () => DataManager.exportRecords());
            document.getElementById('ex-record-import-btn').addEventListener('click', () => DataManager.importRecords());

            return controlPanel;
        },

        // 更新統計信息顯示
        updateStatsDisplay() {
            const records = Utils.getRecords();
            const recordsCount = Object.keys(records).length;

            // 更新記錄總數
            if (DOM.totalCountElem) {
                DOM.totalCountElem.innerHTML = `${ICONS.info}總記錄: ${recordsCount} 筆`;
            }

            // 計算並更新當前頁面統計
            const pageItems = Utils.getPageItems();
            const pageRecorded = pageItems.filter(id => records[id]).length;
            const pageUnrecorded = pageItems.length - pageRecorded;

            if (DOM.pageRecordedElem) {
                DOM.pageRecordedElem.innerHTML = `${ICONS.check}本頁已記錄: ${pageRecorded} 筆`;
            }

            if (DOM.pageUnrecordedElem) {
                DOM.pageUnrecordedElem.innerHTML = `${ICONS.uncheck}本頁未記錄: ${pageUnrecorded} 筆`;
            }

            // 統計隱藏數量
            let hiddenCount = 0;
            const tableBody = Utils.getTableBody();
            if (tableBody) {
                Array.from(tableBody.rows).forEach(row => {
                    if (row.style.display === "none") {
                        hiddenCount++;
                    }
                });
            }

            if (DOM.pageHiddenElem) {
                DOM.pageHiddenElem.innerHTML = `${ICONS.hidden}本頁隱藏: ${hiddenCount} 筆`;
            }
        },

        // 添加樣式到頁面
        addStyles() {
            const styleElement = document.createElement('style');
            styleElement.textContent = STYLES;
            document.head.appendChild(styleElement);
        },

        // 創建模態對話框
        createModal(title, content, buttons) {
            const modal = document.createElement('div');
            modal.className = 'ex-record-modal';
            modal.innerHTML = `
                <div class="ex-record-modal-content">
                    <div class="ex-record-modal-header">
                        <h3>${title}</h3>
                        <button class="ex-record-modal-close">&times;</button>
                    </div>
                    <div class="ex-record-modal-body">
                        ${content}
                    </div>
                    <div class="ex-record-modal-footer">
                        ${buttons.map(btn => `
                            <button class="ex-record-modal-btn ${btn.primary ? 'ex-record-modal-btn-primary' : 'ex-record-modal-btn-secondary'}"
                                id="${btn.id}">${btn.text}</button>
                        `).join('')}
                    </div>
                </div>
            `;

            document.body.appendChild(modal);

            // 綁定關閉按鈕
            const closeBtn = modal.querySelector('.ex-record-modal-close');
            if (closeBtn) {
                closeBtn.addEventListener('click', () => document.body.removeChild(modal));
            }

            // 返回modal以供後續處理
            return modal;
        }
    };

    // 記錄操作相關
    const Record = {
        // 標記已記錄的項目
        highlightRecorded() {
            const tableBody = Utils.getTableBody();
            if (!tableBody) return;

            const records = Utils.getRecords();

            Array.from(tableBody.rows).forEach(row => {
                const link = row.querySelector('a');
                if (!link) return;

                const url = link.href.split("/").filter(i => i !== '');
                const id = url[url.length - 1] + url[url.length - 2];

                if (records[id]) {
                    row.classList.add('ex-record-highlighted');

                    // 添加記錄時間
                    const titleElement = row.querySelector('.gl4e');
                    if (titleElement && !titleElement.querySelector('.ex-record-time')) {
                        const timeSpan = document.createElement('span');
                        timeSpan.className = 'ex-record-time';
                        // 兼容新舊記錄格式
                        const timestamp = records[id].timestamp || records[id].t || '';
                        timeSpan.textContent = timestamp ? `記錄於: ${Utils.formatDate(timestamp)}` : '已記錄';
                        titleElement.appendChild(timeSpan);
                    }
                } else {
                    row.classList.remove('ex-record-highlighted');

                    // 移除記錄時間
                    const timeSpan = row.querySelector('.ex-record-time');
                    if (timeSpan && timeSpan.parentNode) {
                        timeSpan.parentNode.removeChild(timeSpan);
                    }
                }
            });
        },

        // 切換顯示/隱藏已記錄的項目
        toggleRecordedItems() {
            const tableBody = Utils.getTableBody();
            if (!tableBody) return;

            const records = Utils.getRecords();
            let hiddenCount = 0;
            let shownCount = 0;

            Array.from(tableBody.rows).forEach(row => {
                const link = row.querySelector('a');
                if (!link) return;

                const url = link.href.split("/").filter(i => i !== '');
                const id = url[url.length - 1] + url[url.length - 2];

                if (records[id]) {
                    if (row.style.display === "none") {
                        row.style.display = "table-row";
                        shownCount++;
                    } else {
                        row.style.display = "none";
                        hiddenCount++;
                    }
                }
            });

            if (hiddenCount > 0) {
                UI.showToast(`已隱藏 ${hiddenCount} 筆已記錄的內容`);
            } else if (shownCount > 0) {
                UI.showToast(`已顯示 ${shownCount} 筆已記錄的內容`);
            } else {
                UI.showToast('本頁沒有已記錄的內容');
            }

            UI.updateStatsDisplay();
        },

        // 隱藏已記錄的項目
        hideRecordedItems() {
            const tableBody = Utils.getTableBody();
            if (!tableBody) return 0;

            const records = Utils.getRecords();
            let hiddenCount = 0;

            Array.from(tableBody.rows).forEach(row => {
                const link = row.querySelector('a');
                if (!link) return;

                const url = link.href.split("/").filter(i => i !== '');
                const id = url[url.length - 1] + url[url.length - 2];

                if (records[id]) {
                    row.style.display = "none";
                    hiddenCount++;
                }
            });

            UI.updateStatsDisplay();
            return hiddenCount;
        },

        // 記錄當前頁面的所有項目
        recordCurrentPage() {
            const tableBody = Utils.getTableBody();
            if (!tableBody) return;

            const records = Utils.getRecords();
            const now = new Date().toISOString();
            let newCount = 0;

            Array.from(tableBody.rows).forEach(row => {
                if (row.style.display === "none") return; // 跳過已隱藏的行

                const link = row.querySelector('a');
                if (!link) return;

                const url = link.href.split("/").filter(i => i !== '');
                const id = url[url.length - 1] + url[url.length - 2];

                if (!records[id]) {
                    // 使用簡化的數據結構以節省空間
                    records[id] = { t: now };
                    newCount++;
                }
            });

            if (newCount > 0) {
                if (Utils.saveRecords(records)) {
                    this.highlightRecorded();
                    UI.updateStatsDisplay();
                    UI.showToast(`已記錄 ${newCount} 筆新內容`);
                } else {
                    UI.showToast('記錄失敗:可能超出存儲限制');
                }
            } else {
                UI.showToast('沒有新內容可記錄');
            }
        }
    };

    // 頁面加載器
    const PageLoader = {
        loadQueue: [], // 加載隊列
        isLoading: false, // 是否正在加載
        isStopped: false, // 是否已停止

        // 初始化加載器
        init() {
            STATS.currentPage = Utils.getCurrentPage();
            STATS.estimatedTotalPages = Utils.estimateTotalPages();

            // 設置頁面可見性變化監聽
            this.setupVisibilityHandler();
        },

        // 監聽頁面可見性變化
        setupVisibilityHandler() {
            document.addEventListener('visibilitychange', () => {
                if (document.visibilityState === 'hidden') {
                    // 頁面進入後台
                    Utils.log('頁面進入後台');
                    if (!CONFIG.continueInBackground && !LOADING_STATE.userPaused && this.isLoading) {
                        // 如果不允許在後台加載且沒有用戶手動暫停,則暫停加載
                        LOADING_STATE.backgroundPaused = true;
                        UI.updateProgressText('頁面處於後台,加載已暫停');
                        Utils.log('自動暫停加載');
                    }
                } else if (document.visibilityState === 'visible') {
                    // 頁面回到前台
                    Utils.log('頁面回到前台');
                    if (LOADING_STATE.backgroundPaused && !LOADING_STATE.userPaused) {
                        // 如果因為後台而暫停且沒有用戶手動暫停,則恢復加載
                        LOADING_STATE.backgroundPaused = false;
                        UI.updateProgressText('頁面回到前台,繼續加載...');
                        Utils.log('自動恢復加載');
                        this.processNextItem();
                    }
                }
            });
        },

        // 加載所有頁面
        loadAllPages() {
            if (this.isLoading) {
                UI.showToast('正在加載中,請等待...');
                return;
            }

            // 初始化進度顯示
            UI.toggleProgressContainer(true);
            UI.updateProgressText('準備加載所有頁面...');
            UI.updatePauseButtonIcon(false);

            this.isLoading = true;
            this.isStopped = false;
            this.loadQueue = [];

            // 重設加載狀態
            LOADING_STATE.userPaused = false;
            LOADING_STATE.backgroundPaused = false;
            LOADING_STATE.processing = false;

            // 重設統計
            STATS.totalProcessed = 0;
            STATS.totalAdded = 0;
            STATS.totalFiltered = 0;

            // 查找下一頁鏈接
            const nextPageLink = document.querySelector('#unext');
            if (!nextPageLink || nextPageLink.href === "javascript:void(0)") {
                UI.updateProgressText('已經是最後一頁');
                UI.showToast('已經是最後一頁');
                this.isLoading = false;

                // 3秒後隱藏進度條
                setTimeout(() => {
                    UI.toggleProgressContainer(false);
                }, 3000);

                return;
            }

            // 添加第一個頁面到隊列
            this.addPageToQueue(nextPageLink.href, true);

            // 開始處理隊列
            this.processNextItem();
        },

        // 添加頁面到隊列
        addPageToQueue(pageUrl, recursive = false) {
            this.loadQueue.push({
                type: 'page',
                url: pageUrl,
                recursive: recursive
            });
            Utils.log(`頁面已添加到隊列: ${pageUrl}`);
        },

        // 添加行項目到隊列
        addRowsToQueue(params) {
            this.loadQueue.push({
                type: 'rows',
                ...params
            });
            Utils.log(`${params.rows.length} 行已添加到隊列`);
        },

        // 處理隊列中的下一個項目
        async processNextItem() {
            // 如果已停止或沒有正在加載,則退出
            if (this.isStopped || !this.isLoading) {
                return;
            }

            // 如果用戶暫停或後台暫停,則退出
            if (LOADING_STATE.userPaused || (LOADING_STATE.backgroundPaused && !CONFIG.continueInBackground)) {
                return;
            }

            // 如果正在處理項目,則退出
            if (LOADING_STATE.processing) {
                return;
            }

            // 如果隊列為空,則完成加載
            if (this.loadQueue.length === 0) {
                this.completeLoading();
                return;
            }

            // 獲取隊列中的下一個項目
            const nextItem = this.loadQueue.shift();

            // 設置處理標記
            LOADING_STATE.processing = true;

            try {
                if (nextItem.type === 'page') {
                    // 處理頁面項目
                    await this.processPageItem(nextItem);
                } else if (nextItem.type === 'rows') {
                    // 處理行項目
                    await this.processRowsItem(nextItem);
                }
            } catch (error) {
                console.error('處理項目失敗:', error);
                UI.updateProgressText(`處理失敗: ${error.message}`);
                UI.showToast(`處理失敗: ${error.message}`);
                // 發生錯誤時仍然繼續處理其他項目
                LOADING_STATE.processing = false;
                this.processNextItem();
            }
        },

        // 處理頁面項目
        async processPageItem(item) {
            const { url, recursive } = item;

            STATS.currentPage++;
            UI.updateProgressText(`正在加載第 ${STATS.currentPage} 頁...`);

            try {
                // 獲取頁面內容
                const response = await fetch(url);
                const html = await response.text();

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

                // 獲取下一頁的表格
                const nextPageTableBody = doc.querySelector('.itg.glte tbody');
                if (!nextPageTableBody) {
                    throw new Error('無法解析頁面內容');
                }

                // 獲取下一頁中的行
                const nextPageRows = Array.from(nextPageTableBody.rows);

                // 獲取當前表格
                const tableBody = Utils.getTableBody();
                if (!tableBody) {
                    throw new Error('無法找到當前頁面的表格');
                }

                // 添加行項目到隊列
                this.addRowsToQueue({
                    rows: nextPageRows,
                    tableBody: tableBody,
                    totalToProcess: nextPageRows.length,
                    processed: 0,
                    filtered: 0
                });

                // 檢查是否有下一頁
                const nextPageUrl = this.getNextPageUrlFromDoc(doc);
                if (nextPageUrl && recursive) {
                    this.addPageToQueue(nextPageUrl, true);
                }

                // 處理完成
                LOADING_STATE.processing = false;
                this.processNextItem();
            } catch (error) {
                LOADING_STATE.processing = false;
                throw error;
            }
        },

        // 處理行項目
        async processRowsItem(item) {
            const { rows, tableBody, totalToProcess } = item;
            const records = Utils.getRecords();

            let addedCount = item.processed || 0;
            let filteredCount = item.filtered || 0;

            try {
                // 處理每一行
                for (let i = 0; i < rows.length; i++) {
                    // 檢查是否已停止
                    if (this.isStopped) {
                        LOADING_STATE.processing = false;
                        this.isLoading = false;
                        return;
                    }

                    // 檢查是否暫停
                    if (LOADING_STATE.userPaused || (LOADING_STATE.backgroundPaused && !CONFIG.continueInBackground)) {
                        // 如果暫停,則將剩餘行重新加入隊列
                        const remainingRows = rows.slice(i);
                        this.loadQueue.unshift({
                            type: 'rows',
                            rows: remainingRows,
                            tableBody: tableBody,
                            totalToProcess: totalToProcess,
                            processed: addedCount,
                            filtered: filteredCount
                        });
                        LOADING_STATE.processing = false;
                        return;
                    }

                    const row = rows[i];

                    // 解析 ID
                    const link = row.querySelector('a');
                    if (!link) continue;

                    const id = Utils.getIdFromUrl(link.href);

                    // 檢查是否已記錄
                    const isAlreadyRecorded = records[id];

                    // 複製行並添加到表格
                    const clonedRow = row.cloneNode(true);
                    tableBody.appendChild(clonedRow);
                    addedCount++;
                    STATS.totalProcessed++;
                    STATS.totalAdded++;

                    // 如果是已記錄項目,設置高亮並可能隱藏
                    if (isAlreadyRecorded) {
                        clonedRow.classList.add('ex-record-highlighted');

                        // 添加記錄時間
                        const titleElement = clonedRow.querySelector('.gl4e');
                        if (titleElement && !titleElement.querySelector('.ex-record-time')) {
                            const timeSpan = document.createElement('span');
                            timeSpan.className = 'ex-record-time';
                            const timestamp = records[id].timestamp || records[id].t || '';
                            timeSpan.textContent = timestamp ? `記錄於: ${Utils.formatDate(timestamp)}` : '已記錄';
                            titleElement.appendChild(timeSpan);
                        }

                        // 根據當前狀態決定是否隱藏
                        if (CONFIG.autoHideRecorded) {
                            clonedRow.style.display = 'none';
                            filteredCount++;
                            STATS.totalFiltered++;
                        }
                    }

                    // 更新進度顯示
                    const percent = Math.round((i + 1) / totalToProcess * 100);
                    UI.updateProgress(
                        percent,
                        STATS.currentPage,
                        STATS.estimatedTotalPages,
                        STATS.totalProcessed
                    );

                    // 更新統計顯示
                    UI.updateStatsDisplay();

                    // 適當延遲以避免頁面凍結
                    if (i < rows.length - 1 && i % 10 === 0) {
                        await Utils.reliableDelay(10);
                    }
                }

                // 更新進度文本
                UI.updateProgressText(`第 ${STATS.currentPage} 頁完成,已加載 ${addedCount} 項`);

                // 添加延遲以避免請求過快
                await Utils.reliableDelay(CONFIG.loadDelay);

                // 處理完成
                LOADING_STATE.processing = false;
                this.processNextItem();
            } catch (error) {
                LOADING_STATE.processing = false;
                throw error;
            }
        },

        // 完成加載
        completeLoading() {
            this.isLoading = false;
            UI.updateProgressText(`加載完成,共處理 ${STATS.totalProcessed} 項,新增 ${STATS.totalAdded} 項`);
            UI.showToast(`加載完成,共處理 ${STATS.totalProcessed} 項,新增 ${STATS.totalAdded} 項`);

            // 3秒後隱藏進度條
            setTimeout(() => {
                UI.toggleProgressContainer(false);
            }, 3000);
        },

        // 從文檔中獲取下一頁URL
        getNextPageUrlFromDoc(doc) {
            const nextPageLink = doc.querySelector('#unext');
            if (nextPageLink && nextPageLink.href && nextPageLink.href !== "javascript:void(0)") {
                return nextPageLink.href;
            }
            return null;
        },

        // 停止加載
        stopLoading() {
            this.isStopped = true;
            this.isLoading = false;
            this.loadQueue = [];
            LOADING_STATE.processing = false;
            LOADING_STATE.userPaused = false;
            LOADING_STATE.backgroundPaused = false;
        }
    };

    // 數據管理
    const DataManager = {
        // 匯出記錄
        exportRecords() {
            const records = Utils.getRecords();
            const exportData = JSON.stringify(records, null, 2);

            const modalContent = `
                <p>以下是您的記錄資料,請複製並保存:</p>
                <textarea readonly>${exportData}</textarea>
            `;

            const buttons = [
                { id: 'ex-record-copy-btn', text: '複製', primary: true },
                { id: 'ex-record-modal-close-btn', text: '關閉', primary: false }
            ];

            const modal = UI.createModal('匯出記錄', modalContent, buttons);

            document.getElementById('ex-record-copy-btn').addEventListener('click', () => {
                const textarea = modal.querySelector('textarea');
                if (textarea) {
                    textarea.select();
                    document.execCommand('copy');
                    UI.showToast('已複製到剪貼簿');
                }
            });

            document.getElementById('ex-record-modal-close-btn').addEventListener('click', () => {
                document.body.removeChild(modal);
            });
        },

        // 匯入記錄
        importRecords() {
            const modalContent = `
                <p>請貼上之前匯出的記錄資料:</p>
                <textarea placeholder="在這裡貼上 JSON 格式的記錄資料..."></textarea>
            `;

            const buttons = [
                { id: 'ex-record-import-btn', text: '匯入', primary: true },
                { id: 'ex-record-modal-close-btn', text: '取消', primary: false }
            ];

            const modal = UI.createModal('匯入記錄', modalContent, buttons);

            document.getElementById('ex-record-import-btn').addEventListener('click', () => {
                const textarea = modal.querySelector('textarea');
                if (!textarea) return;

                try {
                    const importData = JSON.parse(textarea.value);
                    const currentRecords = Utils.getRecords();

                    // 合併記錄
                    const mergedRecords = { ...currentRecords, ...importData };

                    if (Utils.saveRecords(mergedRecords)) {
                        Record.highlightRecorded();
                        UI.updateStatsDisplay();
                        UI.showToast(`匯入成功,共 ${Object.keys(mergedRecords).length} 筆記錄`);
                    } else {
                        UI.showToast('匯入失敗:保存記錄時出錯');
                    }

                    document.body.removeChild(modal);
                } catch (error) {
                    UI.showToast(`匯入失敗:${error.message}`);
                }
            });

            document.getElementById('ex-record-modal-close-btn').addEventListener('click', () => {
                document.body.removeChild(modal);
            });
        }
    };

    // 檢查舊數據格式並轉換
    function migrateOldData() {
        const oldRecordStr = localStorage.getItem("record");
        if (oldRecordStr) {
            try {
                const oldIds = oldRecordStr.split(",").filter(id => id.trim() !== '');
                const newRecords = Utils.getRecords();
                const now = new Date().toISOString();

                for (let i = 0; i < oldIds.length; i++) {
                    const id = oldIds[i];
                    if (id && !newRecords[id]) {
                        newRecords[id] = { t: now };
                    }
                }

                Utils.saveRecords(newRecords);
                localStorage.removeItem("record");
                UI.showToast("已轉換舊格式記錄");
            } catch (e) {
                console.error('轉換舊記錄失敗:', e);
            }
        }
    }

    // 初始化函數
    function init() {
        console.log('初始化 Enhanced Exhentai Record 腳本...');

        // 添加樣式
        UI.addStyles();

        // 轉換舊數據
        migrateOldData();

        if (Utils.getTableBody()) {
            // 創建控制面板
            UI.createControlPanel();

            // 創建進度容器
            UI.createProgressContainer();
            UI.toggleProgressContainer(false); // 默認隱藏

            // 標記已記錄的項目
            Record.highlightRecorded();

            // 更新統計信息
            UI.updateStatsDisplay();

            // 初始化頁面加載器
            PageLoader.init();

            // 默認隱藏已記錄的項目
            if (CONFIG.autoHideRecorded) {
                const hiddenCount = Record.hideRecordedItems();
                if (hiddenCount > 0) {
                    UI.showToast(`已隱藏 ${hiddenCount} 筆已記錄的內容`);
                }
            }

            // 添加滾動事件來監控閱讀進度
            window.addEventListener('scroll', Utils.debounce(() => {
                Utils.updateReadingProgress();
            }, 200));
        } else {
            console.log('找不到作品表格,可能不在正確的頁面');
        }
    }

    // 確保頁面載入完成後執行初始化
    if (document.readyState === 'complete' || document.readyState === 'interactive') {
        setTimeout(init, 1000);
    } else {
        document.addEventListener('DOMContentLoaded', () => {
            setTimeout(init, 1000);
        });
    }

    // 確保初始化執行
    setTimeout(() => {
        if (!document.querySelector('.ex-record-toolbar')) {
            init();
        }
    }, 2000);
})();