Greasy Fork 还支持 简体中文。

Fab Helper (优化版)

Fab Helper 优化版 - 减少API请求,提高性能,增强稳定性,修复限速刷新

安裝腳本?
作者推薦腳本

您可能也會喜歡 FAB Free Asset Getter Latest

安裝腳本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Fab Helper (优化版)
// @name:zh-CN   Fab Helper (优化版)
// @name:en      Fab Helper (Optimized)
// @namespace    https://www.fab.com/
// @version      3.3.0-20250831165136
// @description  Fab Helper 优化版 - 减少API请求,提高性能,增强稳定性,修复限速刷新
// @description:zh-CN  Fab Helper 优化版 - 减少API请求,提高性能,增强稳定性,修复限速刷新
// @description:en  Fab Helper Optimized - Reduced API requests, improved performance, enhanced stability, fixed rate limit refresh
// @author       RunKing
// @match        https://www.fab.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=fab.com
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_addValueChangeListener
// @grant        GM_removeValueChangeListener
// @grant        GM_openInTab
// @connect      fab.com
// @connect      www.fab.com
// @run-at       document-idle
// ==/UserScript==

(function () {
    'use strict';

    // --- 模块一: 配置与常量 ---
    const Config = {
        SCRIPT_NAME: 'Fab Helper (优化版)',
        DB_VERSION: 3,
        DB_NAME: 'fab_helper_db',
        MAX_WORKERS: 5, // Maximum number of concurrent worker tabs
        MAX_CONCURRENT_WORKERS: 7, // 最大并发工作标签页数量
        WORKER_TIMEOUT: 30000, // 工作标签页超时时间
        UI_CONTAINER_ID: 'fab-helper-container',
        UI_LOG_ID: 'fab-helper-log',
        DB_KEYS: {
            DONE: 'fab_done_v8',
            FAILED: 'fab_failed_v8',
            TODO: 'fab_todo_v1', // 用于永久存储待办列表
            HIDE: 'fab_hide_v8',
            AUTO_ADD: 'fab_autoAdd_v8', // 自动添加设置键
            REMEMBER_POS: 'fab_rememberPos_v8',
            LAST_CURSOR: 'fab_lastCursor_v8', // Store only the cursor string
            WORKER_DONE: 'fab_worker_done_v8', // This is the ONLY key workers use to report back.
            APP_STATUS: 'fab_app_status_v1', // For tracking 429 rate limiting
            STATUS_HISTORY: 'fab_status_history_v1', // 状态历史记录持久化
            AUTO_RESUME: 'fab_auto_resume_v1', // 自动恢复功能设置
            IS_EXECUTING: 'fab_is_executing_v1', // 执行状态保存
            AUTO_REFRESH_EMPTY: 'fab_auto_refresh_empty_v1', // 无商品可见时自动刷新
            // 其他键值用于会话或主标签页持久化
        },
        SELECTORS: {
            card: 'div.fabkit-Stack-root.nTa5u2sc, div.AssetCard-root',
            cardLink: 'a[href*="/listings/"]',
            addButton: 'button[aria-label*="Add to"], button[aria-label*="添加至"], button[aria-label*="cart"]',
            rootElement: '#root',
            successBanner: 'div[class*="Toast-root"]',
            freeStatus: '.csZFzinF',
            ownedStatus: '.cUUvxo_s'
        },
        TEXTS: {
            en: {
                // 基础UI
                hide: 'Hide Done', show: 'Show Done', sync: 'Sync State', execute: 'Start Tasks', executing: 'Executing...', stopExecute: 'Stop',
                added: 'Done', failed: 'Failed', todo: 'To-Do', hidden: 'Hidden', visible: 'Visible',
                clearLog: 'Clear Log', copyLog: 'Copy Log', copied: 'Copied!',
                tab_dashboard: 'Dashboard', tab_settings: 'Settings', tab_debug: 'Debug',

                // 应用标题和标签
                app_title: 'Fab Helper',
                free_label: 'Free',
                operation_log: '📝 Operation Log',
                position_indicator: '📍 ',

                // 按钮文本
                clear_all_data: '🗑️ Clear All Data',
                debug_mode: 'Debug Mode',
                page_diagnosis: 'Page Diagnosis',
                copy_btn: 'Copy',
                clear_btn: 'Clear',
                copied_success: 'Copied!',

                // 状态文本
                status_history: 'Status Cycle History',
                script_startup: 'Script Startup',
                normal_period: 'Normal Operation',
                rate_limited_period: 'Rate Limited',
                current_normal: 'Current: Normal',
                current_rate_limited: 'Current: Rate Limited',
                no_history: 'No history records to display.',
                no_saved_position: 'No saved position',

                // 状态历史详细信息
                time_label: 'Time',
                info_label: 'Info',
                ended_at: 'Ended at',
                duration_label: 'Duration',
                requests_label: 'Requests',
                requests_unit: 'times',
                unknown_duration: 'Unknown',

                // 日志消息
                log_init: 'Assistant is online!',
                log_db_loaded: 'Reading archive...',
                log_exec_no_tasks: 'To-Do list is empty.',
                log_verify_success: 'Verified and added to library!',
                log_verify_fail: "Couldn't add. Will retry later.",
                log_429_error: 'Request limit hit! Taking a 15s break...',
                log_recon_reset: 'Recon progress has been reset. Next scan will start from the beginning.',
                log_recon_active: 'Cannot reset progress while recon is active.',
                log_no_failed_tasks: 'No failed tasks to retry.',
                log_requeuing_tasks: 'Re-queuing {0} failed tasks...',
                log_detail_page: 'This is a detail or worker page. Halting main script execution.',
                log_copy_failed: 'Failed to copy log:',
                log_auto_add_enabled: '"Auto add" is enabled. Will process all tasks in the current "To-Do" queue.',
                log_auto_add_toggle: 'Infinite scroll auto add tasks {0}.',
                log_remember_pos_toggle: 'Remember waterfall browsing position {0}.',
                log_auto_resume_toggle: '429 auto resume function {0}.',
                log_auto_resume_start: '🔄 429 auto resume activated! Will refresh page in {0} seconds to attempt recovery...',
                log_auto_resume_detect: '🔄 Detected 429 error, will auto refresh page in {0} seconds to attempt recovery...',

                // 调试日志消息
                debug_save_cursor: 'Saving new recovery point: {0}',
                debug_prepare_hide: 'Preparing to hide {0} cards, will use longer delay...',
                debug_unprocessed_cards: 'Detected {0} unprocessed or inconsistent cards, re-executing hide logic',
                debug_new_content_loading: 'Detected new content loading, waiting for API requests to complete...',
                debug_process_new_content: 'Starting to process newly loaded content...',
                debug_unprocessed_cards_simple: 'Detected unprocessed cards, re-executing hide logic',
                debug_hide_completed: 'Completed hiding all {0} cards',
                debug_visible_after_hide: '👁️ Actual visible items after hiding: {0}, hidden items: {1}',
                debug_filter_owned: 'Filtered out {0} owned items and {1} items already in todo list.',
                debug_api_wait_complete: 'API wait completed, starting to process {0} cards...',
                debug_api_stopped: 'API activity stopped for {0}ms, continuing to process cards.',
                debug_wait_api_response: 'Starting to wait for API response, will process {0} cards after API activity stops...',
                debug_api_wait_in_progress: 'API wait process already in progress, adding current {0} cards to wait queue.',
                debug_cached_items: 'Cached {0} item data',
                debug_no_cards_to_check: 'No cards need to be checked',

                // Fab DOM Refresh 相关
                fab_dom_api_complete: 'API query completed, confirmed {0} owned items.',
                fab_dom_checking_status: 'Checking status of {0} items...',
                fab_dom_add_to_waitlist: 'Added {0} item IDs to wait list, current wait list size: {0}',
                fab_dom_unknown_status: '{0} items have unknown status, waiting for native web requests to update',

                // 状态监控
                status_monitor_all_hidden: 'Detected all items hidden in normal state ({0} items)',

                // 空搜索结果
                empty_search_initial: 'Page just loaded, might be initial request, not triggering rate limit',

                // 游标相关
                cursor_patched_url: 'Patched URL',
                cursor_injecting: 'Injecting cursor. Original',
                page_patcher_match: '-> ✅ MATCH! URL will be patched',

                // 自动刷新相关
                auto_refresh_countdown: '⏱️ Auto refresh countdown: {0} seconds...',
                rate_limit_success_request: 'Successful request during rate limit +1, current consecutive: {0}/{1}, source: {2}',
                rate_limit_no_visible_continue: '🔄 No visible items on page and in rate limit state, will continue auto refresh.',
                rate_limit_no_visible_suggest: '🔄 In rate limit state with no visible items, suggest refreshing page',
                status_check_summary: '📊 Status check - Actually visible: {0}, Total cards: {1}, Hidden items: {2}',
                refresh_plan_exists: 'Refresh plan already in progress, not scheduling new refresh (429 auto recovery)',
                page_content_rate_limit_detected: '[Page Content Detection] Detected page showing rate limit error message!',
                last_moment_check_cancelled: '⚠️ Last moment check: refresh conditions not met, auto refresh cancelled.',
                refresh_cancelled_visible_items: '⏹️ Detected {0} visible items on page before refresh, auto refresh cancelled.',

                // 限速检测来源
                rate_limit_source_page_content: 'Page Content Detection',
                rate_limit_source_global_call: 'Global Call',

                // 日志标签
                log_tag_auto_add: 'Auto Add',

                // 自动添加相关消息
                auto_add_api_timeout: 'API wait timeout, waited {0}ms, will continue processing cards.',
                auto_add_api_error: 'Error while waiting for API: {0}',
                auto_add_new_tasks: 'Added {0} new tasks to queue.',

                // HTTP状态检测
                http_status_check_performance_api: 'Using Performance API check, no longer sending HEAD requests',

                // 页面状态检测
                page_status_hidden_no_visible: '👁️ Detected {0} hidden items on page, but no visible items',
                page_status_suggest_refresh: '🔄 Detected {0} hidden items on page, but no visible items, suggest refreshing page',

                // 限速状态相关
                rate_limit_already_active: 'Already in rate limit state, source: {0}, ignoring new rate limit trigger: {1}',
                xhr_detected_429: '[XHR] Detected 429 status code: {0}',

                // 状态历史消息
                history_cleared_new_session: 'History cleared, new session started',
                status_history_cleared: 'Status history cleared.',
                duplicate_normal_status_detected: 'Detected duplicate normal status record, source: {0}',
                execution_status_changed: 'Detected execution status change: {0}',
                status_executing: 'Executing',
                status_stopped: 'Stopped',

                // 状态历史UI文本
                status_duration_label: 'Duration: ',
                status_requests_label: 'Requests: ',
                status_ended_at_label: 'Ended at: ',
                status_started_at_label: 'Started at: ',
                status_ongoing_label: 'Ongoing: ',
                status_unknown_time: 'Unknown time',
                status_unknown_duration: 'Unknown',

                // 启动时状态检测
                startup_rate_limited: 'Script started in rate limited state. Rate limit has lasted at least {0}s, source: {1}',
                status_unknown_source: 'Unknown',

                // 请求成功来源
                request_source_search_response: 'Search Response Success',
                request_source_xhr_search: 'XHR Search Success',
                request_source_xhr_item: 'XHR Item Request',
                consecutive_success_exit: 'Consecutive {0} successful requests ({1})',
                search_response_parse_failed: 'Search response parsing failed: {0}',

                // 缓存清理和Fab DOM相关
                cache_cleanup_complete: '[Cache] Cleanup complete, current cache size: items={0}, owned status={1}, prices={2}',
                fab_dom_no_new_owned: '[Fab DOM Refresh] API query completed, no new owned items found.',

                // 状态报告UI标签
                status_time_label: 'Time',
                status_info_label: 'Info',

                // 隐性限速检测和API监控
                implicit_rate_limit_detection: '[Implicit Rate Limit Detection]',
                scroll_api_monitoring: '[Scroll API Monitoring]',
                task_execution_time: 'Task execution time: {0} seconds',
                detected_rate_limit_error: 'Detected rate limit error info: {0}',
                detected_possible_rate_limit_empty: 'Detected possible rate limit situation (empty result): {0}',
                detected_possible_rate_limit_scroll: 'Detected possible rate limit situation: no card count increase after {0} consecutive scrolls.',
                detected_api_429_status: 'Detected API request status code 429: {0}',
                detected_api_rate_limit_content: 'Detected API response content contains rate limit info: {0}',

                // 限速来源标识
                source_implicit_rate_limit: 'Implicit Rate Limit Detection',
                source_scroll_api_monitoring: 'Scroll API Monitoring',

                // 设置项
                setting_auto_refresh: 'Auto refresh when no items visible',
                setting_auto_add_scroll: 'Auto add tasks on infinite scroll',
                setting_remember_position: 'Remember waterfall browsing position',
                setting_auto_resume_429: 'Auto resume after 429 errors',
                setting_debug_tooltip: 'Enable detailed logging for troubleshooting',

                // 状态文本
                status_enabled: 'enabled',
                status_disabled: 'disabled',

                // 确认对话框
                confirm_clear_data: 'Are you sure you want to clear all locally stored script data (completed, failed, to-do lists)? This action cannot be undone!',
                confirm_open_failed: 'Are you sure you want to open {0} failed items in new tabs?',
                confirm_clear_history: 'Are you sure you want to clear all status history records?',

                // 错误提示
                error_api_refresh: 'API refresh failed. Please check console for error details and confirm you are logged in.',

                // 工具提示
                tooltip_open_failed: 'Click to open all failed items',
                tooltip_executing_progress: 'Executing: {0}/{1} ({2}%)',
                tooltip_executing: 'Executing',
                tooltip_start_tasks: 'Click to start executing tasks',

                // 其他
                goto_page_label: 'Page:',
                goto_page_btn: 'Go',
                page_reset: 'Page: 1',
                untitled: 'Untitled',
                cursor_mode: 'Cursor Mode',
                using_native_requests: 'Using native web requests, waiting: {0}',
                worker_closed: 'Worker tab closed before completion'
            },
            zh: {
                // 基础UI
                hide: '隐藏已得', show: '显示已得', sync: '同步状态', execute: '一键开刷', executing: '执行中...', stopExecute: '停止',
                added: '已入库', failed: '失败', todo: '待办', hidden: '已隐藏', visible: '可见',
                clearLog: '清空日志', copyLog: '复制日志', copied: '已复制!',
                tab_dashboard: '仪表盘', tab_settings: '设定', tab_debug: '调试',

                // 应用标题和标签
                app_title: 'Fab Helper',
                free_label: '免费',
                operation_log: '📝 操作日志',
                position_indicator: '📍 ',

                // 按钮文本
                clear_all_data: '🗑️ 清空所有存档',
                debug_mode: '调试模式',
                page_diagnosis: '页面诊断',
                copy_btn: '复制',
                clear_btn: '清空',
                copied_success: '已复制!',

                // 状态文本
                status_history: '状态周期历史记录',
                script_startup: '脚本启动',
                normal_period: '正常运行期',
                rate_limited_period: '限速期',
                current_normal: '当前: 正常运行',
                current_rate_limited: '当前: 限速中',
                no_history: '没有可显示的历史记录。',
                no_saved_position: '无保存位置',

                // 状态历史详细信息
                time_label: '时间',
                info_label: '信息',
                ended_at: '结束于',
                duration_label: '持续',
                requests_label: '请求',
                requests_unit: '次',
                unknown_duration: '未知',

                // 日志消息
                log_init: '助手已上线!',
                log_db_loaded: '正在读取存档...',
                log_exec_no_tasks: '"待办"清单是空的。',
                log_verify_success: '搞定!已成功入库。',
                log_verify_fail: '哎呀,这个没加上。稍后会自动重试!',
                log_429_error: '请求太快被服务器限速了!休息15秒后自动重试...',
                log_recon_reset: '重置进度已完成。下次扫描将从头开始。',
                log_recon_active: '扫描正在进行中,无法重置进度。',
                log_no_failed_tasks: '没有失败的任务需要重试。',
                log_requeuing_tasks: '正在重新排队 {0} 个失败任务...',
                log_detail_page: '这是详情页或工作标签页。停止主脚本执行。',
                log_copy_failed: '复制日志失败:',
                log_auto_add_enabled: '"自动添加"已开启。将直接处理当前"待办"队列中的所有任务。',
                log_auto_add_toggle: '无限滚动自动添加任务已{0}。',
                log_remember_pos_toggle: '记住瀑布流浏览位置功能已{0}。',
                log_auto_resume_toggle: '429后自动恢复功能已{0}。',
                log_auto_resume_start: '🔄 429自动恢复启动!将在{0}秒后刷新页面尝试恢复...',
                log_auto_resume_detect: '🔄 检测到429错误,将在{0}秒后自动刷新页面尝试恢复...',

                // 调试日志消息
                debug_save_cursor: '保存新的恢复点: {0}',
                debug_prepare_hide: '准备隐藏 {0} 张卡片,将使用更长的延迟...',
                debug_unprocessed_cards: '检测到 {0} 个未处理或状态不一致的卡片,重新执行隐藏逻辑',
                debug_new_content_loading: '检测到新内容加载,等待API请求完成...',
                debug_process_new_content: '开始处理新加载的内容...',
                debug_unprocessed_cards_simple: '检测到未处理的卡片,重新执行隐藏逻辑',
                debug_hide_completed: '已完成所有 {0} 张卡片的隐藏',
                debug_visible_after_hide: '👁️ 隐藏后实际可见商品数: {0},隐藏商品数: {1}',
                debug_filter_owned: '过滤掉 {0} 个已入库商品和 {1} 个已在待办列表中的商品。',
                debug_api_wait_complete: 'API等待完成,开始处理 {0} 张卡片...',
                debug_api_stopped: 'API活动已停止 {0}ms,继续处理卡片。',
                debug_wait_api_response: '开始等待API响应,将在API活动停止后处理 {0} 张卡片...',
                debug_api_wait_in_progress: '已有API等待过程在进行,将当前 {0} 张卡片加入等待队列。',
                debug_cached_items: '已缓存 {0} 个商品数据',
                debug_no_cards_to_check: '没有需要检查的卡片',

                // Fab DOM Refresh 相关
                fab_dom_api_complete: 'API查询完成,共确认 {0} 个已拥有的项目。',
                fab_dom_checking_status: '正在检查 {0} 个项目的状态...',
                fab_dom_add_to_waitlist: '添加 {0} 个商品ID到等待列表,当前等待列表大小: {0}',
                fab_dom_unknown_status: '有 {0} 个商品状态未知,等待网页原生请求更新',

                // 状态监控
                status_monitor_all_hidden: '检测到正常状态下所有商品都被隐藏 ({0}个)',

                // 空搜索结果
                empty_search_initial: '页面刚刚加载,可能是初始请求,不触发限速',

                // 游标相关
                cursor_patched_url: 'Patched URL',
                cursor_injecting: 'Injecting cursor. Original',
                page_patcher_match: '-> ✅ MATCH! URL will be patched',

                // 自动刷新相关
                auto_refresh_countdown: '⏱️ 自动刷新倒计时: {0} 秒...',
                rate_limit_success_request: '限速状态下成功请求 +1,当前连续成功: {0}/{1},来源: {2}',
                rate_limit_no_visible_continue: '🔄 页面上没有可见商品且处于限速状态,将继续自动刷新。',
                rate_limit_no_visible_suggest: '🔄 处于限速状态且没有可见商品,建议刷新页面',
                status_check_summary: '📊 状态检查 - 实际可见: {0}, 总卡片: {1}, 隐藏商品数: {2}',
                refresh_plan_exists: '已有刷新计划正在进行中,不再安排新的刷新 (429自动恢复)',
                page_content_rate_limit_detected: '[页面内容检测] 检测到页面显示限速错误信息!',
                last_moment_check_cancelled: '⚠️ 最后一刻检查:刷新条件不满足,自动刷新已取消。',
                refresh_cancelled_visible_items: '⏹️ 刷新前检测到页面上有 {0} 个可见商品,已取消自动刷新。',

                // 限速检测来源
                rate_limit_source_page_content: '页面内容检测',
                rate_limit_source_global_call: '全局调用',

                // 日志标签
                log_tag_auto_add: '自动添加',

                // 自动添加相关消息
                auto_add_api_timeout: 'API等待超时,已等待 {0}ms,将继续处理卡片。',
                auto_add_api_error: '等待API时出错: {0}',
                auto_add_new_tasks: '新增 {0} 个任务到队列。',

                // HTTP状态检测
                http_status_check_performance_api: '使用Performance API检查,不再发送HEAD请求',

                // 页面状态检测
                page_status_hidden_no_visible: '👁️ 检测到页面上有 {0} 个隐藏商品,但没有可见商品',
                page_status_suggest_refresh: '🔄 检测到页面上有 {0} 个隐藏商品,但没有可见商品,建议刷新页面',

                // 限速状态相关
                rate_limit_already_active: '已处于限速状态,来源: {0},忽略新的限速触发: {1}',
                xhr_detected_429: '[XHR] 检测到429状态码: {0}',

                // 状态历史消息
                history_cleared_new_session: '历史记录已清空,新会话开始',
                status_history_cleared: '状态历史记录已清空。',
                duplicate_normal_status_detected: '检测到重复的正常状态记录,来源: {0}',
                execution_status_changed: '检测到执行状态变化:{0}',
                status_executing: '执行中',
                status_stopped: '已停止',

                // 状态历史UI文本
                status_duration_label: '持续时间: ',
                status_requests_label: '期间请求数: ',
                status_ended_at_label: '结束于: ',
                status_started_at_label: '开始于: ',
                status_ongoing_label: '已持续: ',
                status_unknown_time: '未知时间',
                status_unknown_duration: '未知',

                // 启动时状态检测
                startup_rate_limited: '脚本启动时处于限速状态。限速已持续至少 {0}s,来源: {1}',
                status_unknown_source: '未知',

                // 请求成功来源
                request_source_search_response: '搜索响应成功',
                request_source_xhr_search: 'XHR搜索成功',
                request_source_xhr_item: 'XHR商品请求',
                consecutive_success_exit: '连续{0}次成功请求 ({1})',
                search_response_parse_failed: '搜索响应解析失败: {0}',

                // 缓存清理和Fab DOM相关
                cache_cleanup_complete: '[Cache] 清理完成,当前缓存大小: 商品={0}, 拥有状态={1}, 价格={2}',
                fab_dom_no_new_owned: '[Fab DOM Refresh] API查询完成,没有发现新的已拥有项目。',

                // 状态报告UI标签
                status_time_label: '时间',
                status_info_label: '信息',

                // 隐性限速检测和API监控
                implicit_rate_limit_detection: '[隐性限速检测]',
                scroll_api_monitoring: '[滚动API监控]',
                task_execution_time: '任务执行时间: {0}秒',
                detected_rate_limit_error: '检测到限速错误信息: {0}',
                detected_possible_rate_limit_empty: '检测到可能的限速情况(空结果): {0}',
                detected_possible_rate_limit_scroll: '检测到可能的限速情况:连续{0}次滚动后卡片数量未增加。',
                detected_api_429_status: '检测到API请求状态码为429: {0}',
                detected_api_rate_limit_content: '检测到API响应内容包含限速信息: {0}',

                // 限速来源标识
                source_implicit_rate_limit: '隐性限速检测',
                source_scroll_api_monitoring: '滚动API监控',

                // 设置项
                setting_auto_refresh: '无商品可见时自动刷新',
                setting_auto_add_scroll: '无限滚动时自动添加任务',
                setting_remember_position: '记住瀑布流浏览位置',
                setting_auto_resume_429: '429后自动恢复并继续',
                setting_debug_tooltip: '启用详细日志记录,用于排查问题',

                // 状态文本
                status_enabled: '开启',
                status_disabled: '关闭',

                // 确认对话框
                confirm_clear_data: '您确定要清空所有本地存储的脚本数据(已完成、失败、待办列表)吗?此操作不可逆!',
                confirm_open_failed: '您确定要在新标签页中打开 {0} 个失败的项目吗?',
                confirm_clear_history: '您确定要清空所有状态历史记录吗?',

                // 错误提示
                error_api_refresh: 'API 刷新失败。请检查控制台中的错误信息,并确认您已登录。',

                // 工具提示
                tooltip_open_failed: '点击打开所有失败的项目',
                tooltip_executing_progress: '执行中: {0}/{1} ({2}%)',
                tooltip_executing: '执行中',
                tooltip_start_tasks: '点击开始执行任务',

                // 其他
                goto_page_label: '页码:',
                goto_page_btn: '跳转',
                page_reset: 'Page: 1',
                untitled: 'Untitled',
                cursor_mode: 'Cursor Mode',
                using_native_requests: '使用网页原生请求,等待中: {0}',
                worker_closed: '工作标签页在完成前关闭'
            }
        },
        // Centralized keyword sets, based STRICTLY on the rules in FAB_HELPER_RULES.md
        OWNED_SUCCESS_CRITERIA: {
            // Check for an H2 tag with the specific success text.
            h2Text: ['已保存在我的库中', 'Saved in My Library'],
            // Check for buttons/links with these texts.
            buttonTexts: ['在我的库中查看', 'View in My Library'],
            // Check for the temporary success popup (snackbar).
            snackbarText: ['产品已添加至您的库中', 'Product added to your library'],
        },
        ACQUISITION_TEXT_SET: new Set(['添加到我的库', 'Add to my library']),

        // Kept for backward compatibility with recon logic.
        SAVED_TEXT_SET: new Set(['已保存在我的库中', 'Saved in My Library', '在我的库中', 'In My Library']),
        FREE_TEXT_SET: new Set(['免费', 'Free', '起始价格 免费']),
        // 添加一个实例ID,用于防止多实例运行
        INSTANCE_ID: 'fab_instance_id_' + Math.random().toString(36).substring(2, 15),
    };

    // --- 模块二: 全局状态管理 ---
const State = {
    db: {
        todo: [],   // 待办任务列表
        done: [],   // 已完成任务列表
        failed: [], // 失败任务列表
    },
    hideSaved: false, // 是否隐藏已保存项目
    autoAddOnScroll: false, // 是否在滚动时自动添加任务
    rememberScrollPosition: false, // 是否记住滚动位置
    autoResumeAfter429: false, // 是否在429后自动恢复
    autoRefreshEmptyPage: true, // 新增:无商品可见时自动刷新(默认开启)
    debugMode: false, // 是否启用调试模式
    lang: 'zh', // 当前语言,默认中文,会在detectLanguage中更新
    isExecuting: false, // 是否正在执行任务
    isRefreshScheduled: false, // 新增:标记是否已经安排了页面刷新
        isWorkerTab: false, // 是否是工作标签页
        isReconning: false, // 是否正在进行API扫描
        lastReconUrl: '', // 最后一次API扫描的URL
        totalTasks: 0, // API扫描的总任务数
        completedTasks: 0, // API扫描的已完成任务数
        isDispatchingTasks: false, // 新增:标记是否正在派发任务
        savedCursor: null, // Holds the loaded cursor for hijacking
        // --- NEW: State for 429 monitoring ---
        appStatus: 'NORMAL', // 'NORMAL' or 'RATE_LIMITED'
        rateLimitStartTime: null,
        normalStartTime: Date.now(),
        successfulSearchCount: 0,
        statusHistory: [], // Holds the history of NORMAL/RATE_LIMITED periods
        autoResumeAfter429: false, // The new setting for the feature
        // --- 限速恢复相关状态 ---
        consecutiveSuccessCount: 0, // 连续成功请求计数
        requiredSuccessCount: 3, // 退出限速需要的连续成功请求数
        lastLimitSource: '', // 最后一次限速的来源
        isCheckingRateLimit: false, // 是否正在检查限速状态
        // --- End New State ---
        showAdvanced: false,
        activeWorkers: 0,
        runningWorkers: {}, // NEW: To track active workers for the watchdog { workerId: { task, startTime } }
        lastKnownHref: null, // To detect SPA navigation
        hiddenThisPageCount: 0,
        executionTotalTasks: 0, // For execution progress
        executionCompletedTasks: 0, // For execution progress
        executionFailedTasks: 0, // For execution progress
        watchdogTimer: null,
        // UI-related state
        UI: {
            container: null,
            logPanel: null,
            tabs: {}, // For tab buttons
            tabContents: {}, // For tab content panels
            progressContainer: null,
            progressText: null,
            progressBarFill: null,
            progressBar: null,
            statusTodo: null,
            statusDone: null,
            statusFailed: null,
            statusHidden: null,
            execBtn: null,
            hideBtn: null,
            syncBtn: null,
            statusVisible: null,
            debugContent: null,
            settingsVisible: false,
            historyVisible: false,
            historyTab: 'all',
            statusBarContainer: null,
            statusItems: {},
            savedPositionDisplay: null, // 新增:保存位置显示元素的引用
            // 排序选择器已移除
        },
        valueChangeListeners: [],
        sessionCompleted: new Set(), // Phase15: URLs completed this session
        isLogCollapsed: localStorage.getItem('fab_helper_log_collapsed') === 'true' || false, // 日志面板折叠状态
        hasRunDomPart: false,
        observerDebounceTimer: null,
        isObserverRunning: false, // New flag for the robust launcher
        lastKnownCardCount: 0,
        workerTaskId: null, // 新增:当前工作标签页的任务ID
        // 添加排序相关的状态
        sortOptions: {
            'relevance': { name: '相关度', value: '-relevance' },
            'rating': { name: '评分', value: '-rating' },
            'newest': { name: '最新', value: '-created_at' },
            'oldest': { name: '最旧', value: 'created_at' },
            'price_asc': { name: '价格 (从低到高)', value: 'price' },
            'price_desc': { name: '价格 (从高到低)', value: '-price' },
            'title_asc': { name: '标题 A-Z', value: 'title' },
            'title_desc': { name: '标题 Z-A', value: '-title' }
        },
        currentSortOption: 'title_desc', // 默认排序方式
    };

    // --- 模块三: 页面状态诊断工具 ---
    const PageDiagnostics = {
        // 诊断商品详情页面状态
        diagnoseDetailPage: () => {
            const report = {
                timestamp: new Date().toISOString(),
                url: window.location.href,
                pageTitle: document.title,
                buttons: [],
                licenseOptions: [],
                priceInfo: {},
                ownedStatus: {},
                dynamicContent: {}
            };

            // 检测所有按钮
            const buttons = document.querySelectorAll('button');
            buttons.forEach((btn, index) => {
                const text = btn.textContent?.trim();
                const isVisible = btn.offsetParent !== null;
                const isDisabled = btn.disabled;
                const classes = btn.className;

                if (text) {
                    report.buttons.push({
                        index,
                        text,
                        isVisible,
                        isDisabled,
                        classes,
                        hasClickHandler: btn.onclick !== null
                    });
                }
            });

            // 检测许可选择相关元素
            const licenseElements = document.querySelectorAll('[class*="license"], [class*="License"], [role="option"]');
            licenseElements.forEach((elem, index) => {
                const text = elem.textContent?.trim();
                const isVisible = elem.offsetParent !== null;

                if (text) {
                    report.licenseOptions.push({
                        index,
                        text,
                        isVisible,
                        tagName: elem.tagName,
                        classes: elem.className,
                        role: elem.getAttribute('role')
                    });
                }
            });

            // 检测价格信息
            const priceElements = document.querySelectorAll('[class*="price"], [class*="Price"]');
            priceElements.forEach((elem, index) => {
                const text = elem.textContent?.trim();
                if (text) {
                    report.priceInfo[`price_${index}`] = {
                        text,
                        isVisible: elem.offsetParent !== null,
                        classes: elem.className
                    };
                }
            });

            // 检测拥有状态相关元素
            const ownedElements = document.querySelectorAll('h2, [class*="owned"], [class*="library"]');
            ownedElements.forEach((elem, index) => {
                const text = elem.textContent?.trim();
                if (text && (text.includes('库') || text.includes('Library') || text.includes('拥有') || text.includes('Owned'))) {
                    report.ownedStatus[`owned_${index}`] = {
                        text,
                        isVisible: elem.offsetParent !== null,
                        tagName: elem.tagName,
                        classes: elem.className
                    };
                }
            });

            return report;
        },

        // 输出诊断报告到日志
        logDiagnosticReport: (report) => {
            console.log('=== 页面状态诊断报告 ===');
            console.log(`页面: ${report.url}`);
            console.log(`标题: ${report.pageTitle}`);

            console.log(`--- 按钮信息 (${report.buttons.length}个) ---`);
            report.buttons.forEach(btn => {
                if (btn.isVisible) {
                    console.log(`按钮: "${btn.text}" (可见: ${btn.isVisible}, 禁用: ${btn.isDisabled})`);
                }
            });

            console.log(`--- 许可选项 (${report.licenseOptions.length}个) ---`);
            report.licenseOptions.forEach(opt => {
                if (opt.isVisible) {
                    console.log(`许可: "${opt.text}" (可见: ${opt.isVisible}, 角色: ${opt.role})`);
                }
            });

            console.log(`--- 价格信息 ---`);
            Object.entries(report.priceInfo).forEach(([, price]) => {
                if (price.isVisible) {
                    console.log(`价格: "${price.text}"`);
                }
            });

            console.log(`--- 拥有状态 ---`);
            Object.entries(report.ownedStatus).forEach(([, status]) => {
                if (status.isVisible) {
                    console.log(`状态: "${status.text}"`);
                }
            });

            console.log('=== 诊断报告结束 ===');
        }
    };

    // --- 模块四: 日志与工具函数 ---
    const Utils = {
        logger: (type, ...args) => {
            // 支持debug级别日志
            if (type === 'debug') {
                // 默认不在控制台显示debug级别日志,除非启用了调试模式
                if (State.debugMode) {
                    // 调试模式下在控制台输出日志,使用console.log而不是console.debug以确保可见性
                    console.log(`${Config.SCRIPT_NAME} [DEBUG]`, ...args);
                }
                // 无论是否调试模式,都记录到日志面板
                if (State.UI.logPanel) {
                    const logEntry = document.createElement('div');
                    logEntry.style.cssText = 'padding: 2px 4px; border-bottom: 1px solid #444; font-size: 11px; color: #888;';
                    const timestamp = new Date().toLocaleTimeString();
                    logEntry.innerHTML = `<span style="color: #888;">[${timestamp}]</span> <span style="color: #8a8;">[DEBUG]</span> ${args.join(' ')}`;
                    State.UI.logPanel.prepend(logEntry);
                    while (State.UI.logPanel.children.length > 100) {
                        State.UI.logPanel.removeChild(State.UI.logPanel.lastChild);
                    }
                }
                return;
            }

            // 在工作标签页中,只记录关键日志
            if (State.isWorkerTab) {
                if (type === 'error' || args.some(arg => typeof arg === 'string' && arg.includes('Worker'))) {
                    console[type](`${Config.SCRIPT_NAME} [Worker]`, ...args);
                }
                return;
            }

            console[type](`${Config.SCRIPT_NAME}`, ...args);
            // The actual logging to screen will be handled by the UI module
            // to keep modules decoupled.
            if (State.UI.logPanel) {
                const logEntry = document.createElement('div');
                logEntry.style.cssText = 'padding: 2px 4px; border-bottom: 1px solid #444; font-size: 11px;';
                const timestamp = new Date().toLocaleTimeString();
                logEntry.innerHTML = `<span style="color: #888;">[${timestamp}]</span> ${args.join(' ')}`;
                State.UI.logPanel.prepend(logEntry);
                while (State.UI.logPanel.children.length > 100) {
                    State.UI.logPanel.removeChild(State.UI.logPanel.lastChild);
                }
            }
        },
        getText: (key, ...args) => {
            let text = (Config.TEXTS[State.lang]?.[key]) || (Config.TEXTS['en']?.[key]) || key;

            // 支持两种格式的参数替换
            if (args.length > 0) {
                // 如果第一个参数是对象,使用 %placeholder% 格式
                if (typeof args[0] === 'object' && args[0] !== null) {
                    const replacements = args[0];
                    for (const placeholder in replacements) {
                        text = text.replace(`%${placeholder}%`, replacements[placeholder]);
                    }
                } else {
                    // 否则使用 {0}, {1}, {2} 格式
                    args.forEach((arg, index) => {
                        text = text.replace(new RegExp(`\\{${index}\\}`, 'g'), arg);
                    });
                }
            }

            return text;
        },
        detectLanguage: () => {
            const oldLang = State.lang;
            State.lang = window.location.href.includes('/zh-cn/') ? 'zh' : 'en';
            Utils.logger('info', `语言检测: 地址=${window.location.href}, 检测到语言=${State.lang}${oldLang !== State.lang ? ` (从${oldLang}切换)` : ''}`);

            // 如果语言发生了变化且UI已经创建,更新UI
            if (oldLang !== State.lang && State.UI.container) {
                Utils.logger('info', `语言已切换到${State.lang},正在更新界面...`);
                UI.update();
            }
        },
        waitForElement: (selector, timeout = 5000) => {
            return new Promise((resolve, reject) => {
                const interval = setInterval(() => {
                    const element = document.querySelector(selector);
                    if (element) {
                        clearInterval(interval);
                        resolve(element);
                    }
                }, 100);
                setTimeout(() => {
                    clearInterval(interval);
                    reject(new Error(`Timeout waiting for selector: ${selector}`));
                }, timeout);
            });
        },
        waitForButtonEnabled: (button, timeout = 5000) => {
            return new Promise((resolve, reject) => {
                const interval = setInterval(() => {
                    if (button && !button.disabled) {
                        clearInterval(interval);
                        resolve();
                    }
                }, 100);
                setTimeout(() => {
                    clearInterval(interval);
                    reject(new Error('Timeout waiting for button to be enabled.'));
                }, timeout);
            });
        },
        // This function is now for UI display purposes only.
        getDisplayPageFromUrl: (url) => {
            if (!url) return '1';
            try {
                const urlParams = new URLSearchParams(new URL(url).search);
                const cursor = urlParams.get('cursor');
                if (!cursor) return '1';

                // Try to decode offset-based cursors for a nice page number display.
                if (cursor.startsWith('bz')) {
                    const decoded = atob(cursor);
                    const offsetMatch = decoded.match(/o=(\d+)/);
                    if (offsetMatch && offsetMatch[1]) {
                        const offset = parseInt(offsetMatch[1], 10);
                        const pageSize = 24;
                        const pageNum = Math.round((offset / pageSize) + 1);
                        return pageNum.toString();
                    }
                }
                // For timestamp-based cursors, we can't calculate a page number.
                return 'Cursor Mode';
            } catch (e) {
                return '...';
            }
        },
        getCookie: (name) => {
            const value = `; ${document.cookie}`;
            const parts = value.split(`; ${name}=`);
            if (parts.length === 2) return parts.pop().split(';').shift();
            return null;
        },
        // Simulates a more forceful click by dispatching mouse events, which can succeed
        // where a simple .click() is ignored by a framework's event handling.
        deepClick: (element) => {
            if (!element) return;
            // A small delay to ensure the browser's event loop is clear and any framework
            // event listeners on the element have had a chance to attach.
            setTimeout(() => {
            const pageWindow = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;

            Utils.logger('info', `Performing deep click on element: <${element.tagName.toLowerCase()} class="${element.className}">`);

                // Add pointerdown for modern frameworks
                const pointerDownEvent = new PointerEvent('pointerdown', { view: pageWindow, bubbles: true, cancelable: true });
            const mouseDownEvent = new MouseEvent('mousedown', { view: pageWindow, bubbles: true, cancelable: true });
            const mouseUpEvent = new MouseEvent('mouseup', { view: pageWindow, bubbles: true, cancelable: true });

                element.dispatchEvent(pointerDownEvent);
            element.dispatchEvent(mouseDownEvent);
            element.dispatchEvent(mouseUpEvent);
            // Also trigger the standard click for maximum compatibility.
            element.click();
            }, 50); // 50ms delay
        },
        cleanup: () => {
            if (State.watchdogTimer) {
                clearInterval(State.watchdogTimer);
                State.watchdogTimer = null;
            }
            State.valueChangeListeners.forEach(id => {
                try {
                    GM_removeValueChangeListener(id);
                } catch (e) { /* Ignore errors */ }
            });
            State.valueChangeListeners = [];
        },
        // 添加游标解码函数
        decodeCursor: (cursor) => {
            if (!cursor) return '无保存位置';
            try {
                // Base64解码
                const decoded = atob(cursor);

                // 游标通常格式为: o=1&p=Item+Name 或 p=Item+Name
                // 主要提取p参数的值,通常包含项目名称
                let match;
                if (decoded.includes('&p=')) {
                    match = decoded.match(/&p=([^&]+)/);
                } else if (decoded.startsWith('p=')) {
                    match = decoded.match(/p=([^&]+)/);
                }

                if (match && match[1]) {
                    // 解码URI组件并替换+为空格
                    const itemName = decodeURIComponent(match[1].replace(/\+/g, ' '));
                    return `位置: "${itemName}"`;
                }

                return `位置: (已保存,但无法读取名称)`;
            } catch (e) {
                Utils.logger('error', `游标解码失败: ${e.message}`);
                return '位置: (格式无法解析)';
            }
        },
        // 账号验证函数
        checkAuthentication: () => {
            const csrfToken = Utils.getCookie('fab_csrftoken');
            if (!csrfToken) {
                Utils.logger('error', '账号失效:未找到 CSRF token,请重新登录');
                // 停止执行状态
                if (State.isExecuting) {
                    State.isExecuting = false;
                    GM_setValue(Config.DB_KEYS.IS_EXECUTING, false);
                }
                // 更新UI显示
                if (State.UI.startStopButton) {
                    State.UI.startStopButton.textContent = Utils.getText('start_execution');
                    State.UI.startStopButton.disabled = true;
                }
                // 显示警告信息
                alert('账号失效:请重新登录后再使用脚本');
                return false;
            }
            return true;
        },
    };

    // --- DOM Creation Helpers (moved outside for broader scope) ---
    // 移除createOwnedElement函数,不再手动添加"已保存在我的库中"标记

    // createFreeElement函数已移除,不再使用

    // --- 新增: 数据缓存系统 ---
    const DataCache = {
        // 商品数据缓存 - 键为商品ID,值为商品数据
        listings: new Map(),

        // 拥有状态缓存 - 键为商品ID,值为拥有状态对象
        ownedStatus: new Map(),

        // 价格缓存 - 键为报价ID,值为价格信息对象
        prices: new Map(),

        // 等待网页原生请求更新的UID列表
        waitingList: new Set(),

        // 缓存时间戳 - 用于判断缓存是否过期
        timestamps: {
            listings: new Map(),
            ownedStatus: new Map(),
            prices: new Map()
        },

        // 缓存有效期(毫秒)
        TTL: 5 * 60 * 1000, // 5分钟

        // 检查缓存是否有效
        isValid: function(type, key) {
            const timestamp = this.timestamps[type].get(key);
            return timestamp && (Date.now() - timestamp < this.TTL);
        },

        // 保存商品数据到缓存
        saveListings: function(items) {
            if (!Array.isArray(items)) return;

            const now = Date.now();
            items.forEach(item => {
                if (item && item.uid) {
                    this.listings.set(item.uid, item);
                    this.timestamps.listings.set(item.uid, now);
                }
            });
        },

        // 添加到等待列表
        addToWaitingList: function(uids) {
            if (!uids || !Array.isArray(uids)) return;
            uids.forEach(uid => this.waitingList.add(uid));
            Utils.logger('debug', `[Cache] ${Utils.getText('fab_dom_add_to_waitlist', uids.length, this.waitingList.size)}`);
        },

        // 检查并从等待列表中移除
        checkWaitingList: function() {
            if (this.waitingList.size === 0) return;

            // 检查等待列表中的UID是否已经有了拥有状态
            let removedCount = 0;
            for (const uid of this.waitingList) {
                if (this.ownedStatus.has(uid)) {
                    this.waitingList.delete(uid);
                    removedCount++;
                }
            }

            if (removedCount > 0) {
                Utils.logger('info', `[Cache] 从等待列表中移除了 ${removedCount} 个已更新的商品ID,剩余: ${this.waitingList.size}`);
            }
        },

        // 保存拥有状态到缓存
        saveOwnedStatus: function(states) {
            if (!Array.isArray(states)) return;

            const now = Date.now();
            states.forEach(state => {
                if (state && state.uid) {
                    this.ownedStatus.set(state.uid, {
                        acquired: !!state.acquired,
                        lastUpdatedAt: state.lastUpdatedAt || new Date().toISOString(),
                        uid: state.uid
                    });
                    this.timestamps.ownedStatus.set(state.uid, now);

                    // 如果在等待列表中,从等待列表移除
                    if (this.waitingList.has(state.uid)) {
                        this.waitingList.delete(state.uid);
                    }
                }
            });

            // 如果有更新,检查等待列表
            if (states.length > 0) {
                this.checkWaitingList();
            }
        },

        // 保存价格信息到缓存
        savePrices: function(offers) {
            if (!Array.isArray(offers)) return;

            const now = Date.now();
            offers.forEach(offer => {
                if (offer && offer.offerId) {
                    this.prices.set(offer.offerId, {
                        offerId: offer.offerId,
                        price: offer.price || 0,
                        currencyCode: offer.currencyCode || 'USD'
                    });
                    this.timestamps.prices.set(offer.offerId, now);
                }
            });
        },

        // 获取商品数据,如果缓存有效则使用缓存
        getListings: function(uids) {
            const result = [];
            const missing = [];

            uids.forEach(uid => {
                if (this.isValid('listings', uid)) {
                    result.push(this.listings.get(uid));
                } else {
                    missing.push(uid);
                }
            });

            return { result, missing };
        },

        // 获取拥有状态,如果缓存有效则使用缓存
        getOwnedStatus: function(uids) {
            const result = [];
            const missing = [];

            uids.forEach(uid => {
                if (this.isValid('ownedStatus', uid)) {
                    result.push(this.ownedStatus.get(uid));
                } else {
                    missing.push(uid);
                }
            });

            return { result, missing };
        },

        // 获取价格信息,如果缓存有效则使用缓存
        getPrices: function(offerIds) {
            const result = [];
            const missing = [];

            offerIds.forEach(offerId => {
                if (this.isValid('prices', offerId)) {
                    result.push(this.prices.get(offerId));
                } else {
                    missing.push(offerId);
                }
            });

            return { result, missing };
        },

        // 清理过期缓存
        cleanupExpired: function() {
            try {
                const now = Date.now();
                const cacheTypes = ['listings', 'ownedStatus', 'prices'];

                // 统一清理所有类型的缓存
                for (const type of cacheTypes) {
                    for (const [key, timestamp] of this.timestamps[type].entries()) {
                        if (now - timestamp > this.TTL) {
                            this[type].delete(key);
                            this.timestamps[type].delete(key);
                        }
                    }
                }

                if (State.debugMode) {
                    Utils.logger('debug', Utils.getText('cache_cleanup_complete', this.listings.size, this.ownedStatus.size, this.prices.size));
                }
            } catch (e) {
                Utils.logger('error', `缓存清理失败: ${e.message}`);
            }
        }
    };

    // --- 模块四: 异步网络请求 ---
    const API = {
        gmFetch: (options) => {
            return new Promise((resolve, reject) => {
                GM_xmlhttpRequest({
                    anonymous: false, // Default to false to ensure cookies are sent
                    ...options,
                    onload: (response) => resolve(response),
                    onerror: (error) => reject(new Error(`GM_xmlhttpRequest error: ${error.statusText || 'Unknown Error'}`)),
                    ontimeout: () => reject(new Error('Request timed out.')),
                    onabort: () => reject(new Error('Request aborted.'))
                });
            });
        },

        // 接口响应数据提取函数
        extractStateData: (rawData, source = '') => {
            // 记录原始数据格式
            const dataType = Array.isArray(rawData) ? 'Array' : typeof rawData;
            if (State.debugMode) {
                Utils.logger('debug', `[${source}] 接口返回数据类型: ${dataType}`);
            }

            // 如果是数组,直接返回
            if (Array.isArray(rawData)) {
                return rawData;
            }

            // 如果是对象,尝试提取可能的数组字段
            if (rawData && typeof rawData === 'object') {
                // 记录对象的顶级键
                const keys = Object.keys(rawData);
                if (State.debugMode) {
                    Utils.logger('debug', `[${source}] 接口返回对象键: ${keys.join(', ')}`);
                }

                // 尝试常见的数组字段名
                const possibleArrayFields = ['data', 'results', 'items', 'listings', 'states'];
                for (const field of possibleArrayFields) {
                    if (rawData[field] && Array.isArray(rawData[field])) {
                        Utils.logger('info', `[${source}] 在字段 "${field}" 中找到数组数据`);
                        return rawData[field];
                    }
                }

                // 如果没有找到预定义字段,查找任何数组类型的字段
                for (const key of keys) {
                    if (Array.isArray(rawData[key])) {
                        Utils.logger('info', `[${source}] 在字段 "${key}" 中找到数组数据`);
                        return rawData[key];
                    }
                }

                // 如果对象中有uid和acquired字段,可能是单个项目
                if (rawData.uid && 'acquired' in rawData) {
                    Utils.logger('info', `[${source}] 返回的是单个项目数据,转换为数组`);
                    return [rawData];
                }
            }

            // 如果无法提取,记录详细信息并返回空数组
            Utils.logger('warn', `[${source}] 无法从API响应中提取数组数据`);
            if (State.debugMode) {
                try {
                    const preview = JSON.stringify(rawData).substring(0, 200);
                    Utils.logger('debug', `[${source}] API响应预览: ${preview}...`);
                } catch (e) {
                    Utils.logger('debug', `[${source}] 无法序列化API响应: ${e.message}`);
                }
            }
            return [];
        },

        // 优化后的商品拥有状态检查函数 - 只使用缓存和网页原生请求的数据
        checkItemsOwnership: async function(uids) {
            if (!uids || uids.length === 0) return [];

            try {
                // 从缓存中获取已知的拥有状态
                const { result: cachedResults, missing: missingUids } = DataCache.getOwnedStatus(uids);

                // 如果有缺失的UID,记录但不主动请求
                if (missingUids.length > 0) {
                    Utils.logger('debug', Utils.getText('fab_dom_unknown_status', missingUids.length));
                    // 将这些UID添加到等待列表,等待网页原生请求更新
                    DataCache.addToWaitingList(missingUids);
                }

                // 只返回缓存中已有的结果
                return cachedResults;
            } catch (e) {
                Utils.logger('error', `检查拥有状态失败: ${e.message}`);
                return []; // 出错时返回空数组
            }
        },

        // 优化后的价格验证函数
        checkItemsPrices: async function(offerIds) {
            if (!offerIds || offerIds.length === 0) return [];

            try {
                // 从缓存中获取已知的价格信息
                const { result: cachedResults, missing: missingOfferIds } = DataCache.getPrices(offerIds);

                // 如果所有报价都有缓存,直接返回
                if (missingOfferIds.length === 0) {
                    if (State.debugMode) {
                Utils.logger('info', `使用缓存的价格数据,避免API请求`);
            }
                    return cachedResults;
                }

                // 对缺失的报价ID发送API请求
                if (State.debugMode) {
                Utils.logger('info', `对 ${missingOfferIds.length} 个缺失的报价ID发送API请求`);
            }

                const csrfToken = Utils.getCookie('fab_csrftoken');
                if (!csrfToken) {
                    Utils.checkAuthentication();
                    throw new Error("CSRF token not found");
                }

                const pricesUrl = new URL('https://www.fab.com/i/listings/prices-infos');
                missingOfferIds.forEach(offerId => pricesUrl.searchParams.append('offer_ids', offerId));

                const response = await this.gmFetch({
                    method: 'GET',
                    url: pricesUrl.href,
                    headers: { 'x-csrftoken': csrfToken, 'x-requested-with': 'XMLHttpRequest' }
                });

                try {
                    const pricesData = JSON.parse(response.responseText);

                    // 提取并缓存价格信息
                    if (pricesData.offers && Array.isArray(pricesData.offers)) {
                        DataCache.savePrices(pricesData.offers);

                        // 合并缓存结果和API结果
                        return [...cachedResults, ...pricesData.offers];
                    }
                } catch (e) {
                    Utils.logger('error', `[优化] 解析价格API响应失败: ${e.message}`);
                }

                // 出错时返回缓存结果
                return cachedResults;
            } catch (e) {
                Utils.logger('error', `[优化] 获取价格信息失败: ${e.message}`);
                return []; // 出错时返回空数组
            }
        }
        // ... Other API-related functions will go here ...
    };


    // --- 模块五: 数据库交互 ---
    const Database = {
        load: async () => {
            // 从存储中加载待办列表
            State.db.todo = await GM_getValue(Config.DB_KEYS.TODO, []);
            State.db.done = await GM_getValue(Config.DB_KEYS.DONE, []);
            State.db.failed = await GM_getValue(Config.DB_KEYS.FAILED, []);
            State.hideSaved = await GM_getValue(Config.DB_KEYS.HIDE, false);
            State.autoAddOnScroll = await GM_getValue(Config.DB_KEYS.AUTO_ADD, false); // Load the setting
            State.rememberScrollPosition = await GM_getValue(Config.DB_KEYS.REMEMBER_POS, false);
            State.autoResumeAfter429 = await GM_getValue(Config.DB_KEYS.AUTO_RESUME, false);
            State.autoRefreshEmptyPage = await GM_getValue(Config.DB_KEYS.AUTO_REFRESH_EMPTY, true); // 加载无商品自动刷新设置
            State.debugMode = await GM_getValue('fab_helper_debug_mode', false); // 加载调试模式设置
            State.currentSortOption = await GM_getValue('fab_helper_sort_option', 'title_desc'); // 加载排序设置
            State.isExecuting = await GM_getValue(Config.DB_KEYS.IS_EXECUTING, false); // Load the execution state

            const persistedStatus = await GM_getValue(Config.DB_KEYS.APP_STATUS);
            if (persistedStatus && persistedStatus.status === 'RATE_LIMITED') {
                State.appStatus = 'RATE_LIMITED';
                State.rateLimitStartTime = persistedStatus.startTime;
                // 添加空值检查,防止persistedStatus.startTime为null
                const previousDuration = persistedStatus && persistedStatus.startTime ?
                    ((Date.now() - persistedStatus.startTime) / 1000).toFixed(2) : '0.00';
                Utils.logger('warn', `Script starting in RATE_LIMITED state. 429 period has lasted at least ${previousDuration}s.`);
            }
            State.statusHistory = await GM_getValue(Config.DB_KEYS.STATUS_HISTORY, []);

            Utils.logger('info', Utils.getText('log_db_loaded'), `(Session) To-Do: ${State.db.todo.length}, Done: ${State.db.done.length}, Failed: ${State.db.failed.length}`);
        },
        // 添加保存待办列表的方法
        saveTodo: () => GM_setValue(Config.DB_KEYS.TODO, State.db.todo),
        saveDone: () => GM_setValue(Config.DB_KEYS.DONE, State.db.done),
        saveFailed: () => GM_setValue(Config.DB_KEYS.FAILED, State.db.failed),
        saveHidePref: () => GM_setValue(Config.DB_KEYS.HIDE, State.hideSaved),
        saveAutoAddPref: () => GM_setValue(Config.DB_KEYS.AUTO_ADD, State.autoAddOnScroll), // Save the setting
        saveRememberPosPref: () => GM_setValue(Config.DB_KEYS.REMEMBER_POS, State.rememberScrollPosition),
        saveAutoResumePref: () => GM_setValue(Config.DB_KEYS.AUTO_RESUME, State.autoResumeAfter429),
        saveAutoRefreshEmptyPref: () => GM_setValue(Config.DB_KEYS.AUTO_REFRESH_EMPTY, State.autoRefreshEmptyPage), // 保存无商品自动刷新设置
        saveExecutingState: () => GM_setValue(Config.DB_KEYS.IS_EXECUTING, State.isExecuting), // Save the execution state

        resetAllData: async () => {
            if (window.confirm(Utils.getText('confirm_clear_data'))) {
                // 清除待办列表
                await GM_deleteValue(Config.DB_KEYS.TODO);
                await GM_deleteValue(Config.DB_KEYS.DONE);
                await GM_deleteValue(Config.DB_KEYS.FAILED);
                State.db.todo = [];
                State.db.done = [];
                State.db.failed = [];
                Utils.logger('info', '所有脚本数据已重置。');
                UI.removeAllOverlays();
                UI.update();
            }
        },

        isDone: (url) => {
            if (!url) return false;
            return State.db.done.includes(url.split('?')[0]);
        },
        isFailed: (url) => {
            if (!url) return false;
            const cleanUrl = url.split('?')[0];
            return State.db.failed.some(task => task.url === cleanUrl);
        },
        isTodo: (url) => {
             if (!url) return false;
            const cleanUrl = url.split('?')[0];
            return State.db.todo.some(task => task.url === cleanUrl);
        },
        markAsDone: async (task) => {
            if (!task || !task.uid) {
                Utils.logger('error', '标记任务完成失败,收到无效任务:', JSON.stringify(task));
                return;
            }

            // 从待办列表中移除任务
            const initialTodoCount = State.db.todo.length;

            State.db.todo = State.db.todo.filter(t => t.uid !== task.uid);

            // 如果待办列表发生了变化,保存到存储
            if (State.db.todo.length !== initialTodoCount) {
                Database.saveTodo();
            }

            if (State.db.todo.length === initialTodoCount && initialTodoCount > 0) {
                    Utils.logger('warn', '任务未能从待办列表中移除,可能已被其他操作处理');
            }

            let changed = false;

            // The 'done' list can still use URLs for simplicity, as it's for display/hiding.
            const cleanUrl = task.url.split('?')[0];
            if (!Database.isDone(cleanUrl)) {
                State.db.done.push(cleanUrl);
                changed = true;
            }

            if (changed) {
                await Database.saveDone();
            }
        },
        markAsFailed: async (task) => {
            if (!task || !task.uid) {
                Utils.logger('error', '标记任务失败,收到无效任务:', JSON.stringify(task));
                return;
            }

            // Remove from todo
            const initialTodoCount = State.db.todo.length;
            State.db.todo = State.db.todo.filter(t => t.uid !== task.uid);
            let changed = State.db.todo.length < initialTodoCount;

            // Add to failed, ensuring no duplicates by UID
            if (!State.db.failed.some(f => f.uid === task.uid)) {
                State.db.failed.push(task); // Store the whole task object for potential retry
                changed = true;
            }

            if (changed) {
                await Database.saveFailed();
            }
        },
    };



    // 集中处理限速状态的函数
    const RateLimitManager = {
        // 添加防止重复日志的变量
        _lastLogTime: 0,
        _lastLogType: null,
        _duplicateLogCount: 0,

        // 检查是否与最后一条记录重复
        isDuplicateRecord: function(newEntry) {
            if (State.statusHistory.length === 0) return false;

            const lastEntry = State.statusHistory[State.statusHistory.length - 1];

            // 检查类型是否相同
            if (lastEntry.type !== newEntry.type) return false;

            // 检查时间是否过于接近(10秒内)
            const lastTime = new Date(lastEntry.endTime).getTime();
            const newTime = new Date(newEntry.endTime).getTime();
            const timeDiff = Math.abs(newTime - lastTime);

            if (timeDiff < 10000) { // 10秒内
                // 如果是相同类型且时间很接近,检查持续时间是否相似
                const durationDiff = Math.abs((lastEntry.duration || 0) - (newEntry.duration || 0));
                if (durationDiff < 5) { // 持续时间差异小于5秒
                    return true;
                }
            }

            return false;
        },

        // 添加记录到历史,带去重检查
        addToHistory: async function(entry) {
            // 检查是否重复
            if (this.isDuplicateRecord(entry)) {
                Utils.logger('debug', `检测到重复的状态记录,跳过: ${entry.type} - ${entry.endTime}`);
                return false;
            }

            // 添加到历史记录
            State.statusHistory.push(entry);

            // 限制历史记录数量,保留最近50条
            if (State.statusHistory.length > 50) {
                State.statusHistory = State.statusHistory.slice(-50);
            }

            // 保存到存储
            await GM_setValue(Config.DB_KEYS.STATUS_HISTORY, State.statusHistory);
            return true;
        },

        // 进入限速状态
        enterRateLimitedState: async function(source = '未知来源') {
            // 如果已经处于限速状态,不需要重复处理
            if (State.appStatus === 'RATE_LIMITED') {
                Utils.logger('info', Utils.getText('rate_limit_already_active', State.lastLimitSource, source));
                return false;
            }

            // 重置连续成功计数
            State.consecutiveSuccessCount = 0;
            State.lastLimitSource = source;

            // 记录正常运行期的统计信息
            // 添加空值检查,防止normalStartTime为null
            const normalDuration = State.normalStartTime ? ((Date.now() - State.normalStartTime) / 1000).toFixed(2) : '0.00';

            // 创建正常运行期的记录
            const logEntry = {
                type: 'NORMAL',
                duration: parseFloat(normalDuration),
                requests: State.successfulSearchCount,
                endTime: new Date().toISOString()
            };

            // 使用新的去重方法添加到历史记录
            const wasAdded = await this.addToHistory(logEntry);

            if (wasAdded) {
                Utils.logger('error', `🚨 RATE LIMIT DETECTED from [${source}]! Normal operation lasted ${normalDuration}s with ${State.successfulSearchCount} successful search requests.`);
            } else {
                Utils.logger('debug', Utils.getText('duplicate_normal_status_detected', source));
            }

            // 切换到限速状态
            State.appStatus = 'RATE_LIMITED';
            State.rateLimitStartTime = Date.now();

            // 保存状态到存储
            await GM_setValue(Config.DB_KEYS.APP_STATUS, {
                status: 'RATE_LIMITED',
                startTime: State.rateLimitStartTime,
                source: source
            });

            // 更新UI
            UI.updateDebugTab();
            UI.update();

            // 重新计算实际可见的商品数量,确保与DOM状态同步
            const totalCards = document.querySelectorAll(Config.SELECTORS.card).length;
            const hiddenCards = document.querySelectorAll(`${Config.SELECTORS.card}[style*="display: none"]`).length;
            const actualVisibleCards = totalCards - hiddenCards;

            // 更新UI显示的可见商品数量,确保UI与实际DOM状态一致
            const visibleCountElement = document.getElementById('fab-status-visible');
            if (visibleCountElement) {
                visibleCountElement.textContent = actualVisibleCards.toString();
            }

            // 更新全局状态
            State.hiddenThisPageCount = hiddenCards;

            // 检查是否有待办任务、活动工作线程,或者可见的商品数量不为0
            if (State.db.todo.length > 0 || State.activeWorkers > 0 || actualVisibleCards > 0) {
                if (actualVisibleCards > 0) {
                    Utils.logger('info', `检测到页面上有 ${actualVisibleCards} 个可见商品,暂不自动刷新页面。`);
                    Utils.logger('info', '当仍有可见商品时不触发自动刷新,以避免中断浏览。');
                } else {
                    Utils.logger('info', `检测到有 ${State.db.todo.length} 个待办任务和 ${State.activeWorkers} 个活动工作线程,暂不自动刷新页面。`);
                    Utils.logger('info', '请手动完成或取消这些任务后再刷新页面。');
                }

                // 显示明显提示
                Utils.logger('warn', '⚠️ 处于限速状态,但不满足自动刷新条件,请在需要时手动刷新页面。');
            } else {
                // 无任务情况下,开始随机刷新
                // 缩短延迟时间为5-7秒,使恢复更快
                const randomDelay = 5000 + Math.random() * 2000;
                if (State.autoResumeAfter429) {
                    // 添加空值检查,防止randomDelay为null
                    Utils.logger('info', Utils.getText('log_auto_resume_start', randomDelay ? (randomDelay/1000).toFixed(1) : '未知'));
                } else {
                    // 添加空值检查,防止randomDelay为null
                    Utils.logger('info', Utils.getText('log_auto_resume_detect', randomDelay ? (randomDelay/1000).toFixed(1) : '未知'));
                }
                countdownRefresh(randomDelay, '429自动恢复');
            }

            return true;
        },

        // 记录成功请求
        recordSuccessfulRequest: async function(source = '未知来源', hasResults = true) {
            // 无论在什么状态下,总是增加成功请求计数 - 修复统计问题
            if (hasResults) {
                State.successfulSearchCount++;
                UI.updateDebugTab();
            }

            // 只有在限速状态下才需要记录连续成功
            if (State.appStatus !== 'RATE_LIMITED') {
                return;
            }

            // 如果请求没有返回有效结果,不计入连续成功
            if (!hasResults) {
                Utils.logger('info', `请求成功但没有返回有效结果,不计入连续成功计数。来源: ${source}`);
                State.consecutiveSuccessCount = 0;
                return;
            }

            // 增加连续成功计数
            State.consecutiveSuccessCount++;

            Utils.logger('info', Utils.getText('rate_limit_success_request', State.consecutiveSuccessCount, State.requiredSuccessCount, source));

            // 如果达到所需的连续成功数,退出限速状态
            if (State.consecutiveSuccessCount >= State.requiredSuccessCount) {
                await this.exitRateLimitedState(Utils.getText('consecutive_success_exit', State.consecutiveSuccessCount, source));
            }
        },

        // 退出限速状态
        exitRateLimitedState: async function(source = '未知来源') {
            // 如果当前不是限速状态,不需要处理
            if (State.appStatus !== 'RATE_LIMITED') {
                Utils.logger('info', `当前不是限速状态,忽略退出限速请求: ${source}`);
                return false;
            }

            // 记录限速期的统计信息
            // 添加空值检查,防止rateLimitStartTime为null
            const rateLimitDuration = State.rateLimitStartTime ? ((Date.now() - State.rateLimitStartTime) / 1000).toFixed(2) : '0.00';

            // 创建限速期的记录
            const logEntry = {
                type: 'RATE_LIMITED',
                duration: parseFloat(rateLimitDuration),
                endTime: new Date().toISOString(),
                source: source
            };

            // 使用新的去重方法添加到历史记录
            const wasAdded = await this.addToHistory(logEntry);

            if (wasAdded) {
                Utils.logger('info', `✅ Rate limit appears to be lifted from [${source}]. The 429 period lasted ${rateLimitDuration}s.`);
            } else {
                Utils.logger('debug', `检测到重复的限速状态记录,来源: ${source}`);
            }

            // 恢复到正常状态
            State.appStatus = 'NORMAL';
            State.rateLimitStartTime = null;
            State.normalStartTime = Date.now();
            // 不重置请求计数,保留累计值,这样每个正常期的请求数会累加起来
            // State.successfulSearchCount = 0;
            State.consecutiveSuccessCount = 0;

            // 删除存储的限速状态
            await GM_deleteValue(Config.DB_KEYS.APP_STATUS);

            // 更新UI
            UI.updateDebugTab();
            UI.update();

            // 如果有待办任务,继续执行
            if (State.db.todo.length > 0 && !State.isExecuting) {
                Utils.logger('info', `发现 ${State.db.todo.length} 个待办任务,自动恢复执行...`);
                State.isExecuting = true;
                Database.saveExecutingState();
                TaskRunner.executeBatch();
            }

            return true;
        },

        // 检查限速状态
        checkRateLimitStatus: async function() {
            // 如果已经在检查中,避免重复检查
            if (State.isCheckingRateLimit) {
                Utils.logger('info', '已有限速状态检查正在进行,跳过本次检查');
                return false;
            }

            State.isCheckingRateLimit = true;

            try {
                Utils.logger('info', '开始检查限速状态...');

                // 首先检查页面内容是否包含限速信息
                const pageText = document.body.innerText || '';
                if (pageText.includes('Too many requests') ||
                    pageText.includes('rate limit') ||
                    pageText.match(/\{\s*"detail"\s*:\s*"Too many requests"\s*\}/i)) {

                    Utils.logger('warn', '页面内容包含限速信息,确认仍处于限速状态');
                    await this.enterRateLimitedState('页面内容检测');
                    return false;
                }

                // 使用Performance API检查最近的网络请求,而不是主动发送API请求
                Utils.logger('debug', '使用Performance API检查最近的网络请求,不再主动发送API请求');

                if (window.performance && window.performance.getEntriesByType) {
                    const recentRequests = window.performance.getEntriesByType('resource')
                        .filter(r => r.name.includes('/i/listings/search') || r.name.includes('/i/users/me/listings-states'))
                        .filter(r => Date.now() - r.startTime < 10000); // 最近10秒内的请求

                    // 如果有最近的请求,检查它们的状态
                    if (recentRequests.length > 0) {
                        // 检查是否有429状态码的请求
                        const has429 = recentRequests.some(r => r.responseStatus === 429);
                        if (has429) {
                            Utils.logger('info', `检测到最近10秒内有429状态码的请求,判断为限速状态`);
                            await this.enterRateLimitedState('Performance API检测429');
                            return false;
                        }

                        // 检查是否有成功的请求
                        const hasSuccess = recentRequests.some(r => r.responseStatus >= 200 && r.responseStatus < 300);
                        if (hasSuccess) {
                            Utils.logger('info', `检测到最近10秒内有成功的API请求,判断为正常状态`);
                            await this.recordSuccessfulRequest('Performance API检测成功', true);
                            return true;
                        }
                    }
                }

                // 如果没有足够的信息判断,保持当前状态
                Utils.logger('info', `没有足够的信息判断限速状态,保持当前状态`);
                return State.appStatus === 'NORMAL';
            } catch (e) {
                Utils.logger('error', `限速状态检查失败: ${e.message}`);
                return false;
            } finally {
                State.isCheckingRateLimit = false;
            }
        }
    };

    const PagePatcher = {
        _patchHasBeenApplied: false,
        _lastSeenCursor: null,
        // REMOVED: This state variable was the source of the bug.
        // _secondToLastSeenCursor: null,

        // --- NEW: State for request debouncing ---
        _debounceXhrTimer: null,
        _pendingXhr: null,

        async init() {
            // 初始化时,从存储中加载上次保存的cursor
            try {
                const savedCursor = await GM_getValue(Config.DB_KEYS.LAST_CURSOR);
                if (savedCursor) {
                    State.savedCursor = savedCursor;
                    this._lastSeenCursor = savedCursor;
                    Utils.logger('info', `[Cursor] Initialized. Loaded saved cursor: ${savedCursor.substring(0, 30)}...`);
                } else {
                    Utils.logger('info', `[Cursor] Initialized. No saved cursor found.`);
                }
            } catch (e) {
                Utils.logger('warn', '[Cursor] Failed to restore cursor state:', e);
            }

            // 应用拦截器
            this.applyPatches();
            Utils.logger('info', '[Cursor] Network interceptors applied.');

            // 监听URL变化,检测排序方式变更
            this.setupSortMonitor();
        },

        // 添加监听URL变化的方法,检测排序方式变更
        setupSortMonitor() {
            // 初始检查当前URL中的排序参数
            this.checkCurrentSortFromUrl();

            // 使用MutationObserver监听URL变化
            if (typeof MutationObserver !== 'undefined') {
                // 监听body变化,因为SPA应用可能不会触发popstate事件
                const bodyObserver = new MutationObserver(() => {
                    // 如果URL发生变化,检查排序参数和语言
                    if (window.location.href !== this._lastCheckedUrl) {
                        this._lastCheckedUrl = window.location.href;
                        this.checkCurrentSortFromUrl();
                        // 重新检测语言
                        Utils.detectLanguage();
                    }
                });

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

                // 保存引用以便后续可以断开
                this._bodyObserver = bodyObserver;
            }

            // 监听popstate事件(浏览器前进/后退按钮)
            window.addEventListener('popstate', () => {
                this.checkCurrentSortFromUrl();
                Utils.detectLanguage();
            });

            // 监听hashchange事件
            window.addEventListener('hashchange', () => {
                this.checkCurrentSortFromUrl();
                Utils.detectLanguage();
            });

            // 保存当前URL作为初始状态
            this._lastCheckedUrl = window.location.href;
        },

        // 从URL中检查当前排序方式并更新设置
        checkCurrentSortFromUrl() {
            try {
                const url = new URL(window.location.href);
                const sortParam = url.searchParams.get('sort_by');

                if (!sortParam) return; // 如果URL中没有排序参数,不做任何更改

                // 查找匹配的排序选项
                let matchedOption = null;
                for (const [key, option] of Object.entries(State.sortOptions)) {
                    if (option.value === sortParam) {
                        matchedOption = key;
                        break;
                    }
                }

                // 如果找到匹配的排序选项,且与当前选项不同,则更新
                if (matchedOption && matchedOption !== State.currentSortOption) {
                    const previousSort = State.currentSortOption;
                    State.currentSortOption = matchedOption;
                    GM_setValue('fab_helper_sort_option', State.currentSortOption);

                                         // 排序选择器UI已移除,不需要更新

                    Utils.logger('info', `检测到URL排序参数变更,排序方式已从"${State.sortOptions[previousSort].name}"更改为"${State.sortOptions[State.currentSortOption].name}"`);

                    // 清除已保存的浏览位置
                    State.savedCursor = null;
                    GM_deleteValue(Config.DB_KEYS.LAST_CURSOR);
                    if (State.UI.savedPositionDisplay) {
                        State.UI.savedPositionDisplay.textContent = Utils.getText('no_saved_position');
                    }
                    Utils.logger('info', '由于排序方式变更,已清除保存的浏览位置');
                }
            } catch (e) {
                Utils.logger('warn', `检查URL排序参数时出错: ${e.message}`);
            }
        },

        async handleSearchResponse(request) {
            if (request.status === 429) {
                // 使用统一的限速管理器处理限速情况
                await RateLimitManager.enterRateLimitedState('搜索响应429');
            } else if (request.status >= 200 && request.status < 300) {
                try {
                    // 检查响应是否包含有效数据
                    const responseText = request.responseText;
                    if (responseText) {
                        const data = JSON.parse(responseText);
                        const hasResults = data && data.results && data.results.length > 0;

                        // 记录成功请求,并传递是否有结果的信息
                        await RateLimitManager.recordSuccessfulRequest(Utils.getText('request_source_search_response'), hasResults);
                    }
                } catch (e) {
                    Utils.logger('warn', Utils.getText('search_response_parse_failed', e.message));
                }
            }
        },

        isDebounceableSearch(url) {
            return typeof url === 'string' && url.includes('/i/listings/search') && !url.includes('aggregate_on=') && !url.includes('count=0');
        },

        shouldPatchUrl(url) {
            if (typeof url !== 'string') return false;
            if (this._patchHasBeenApplied) return false;
            if (!State.rememberScrollPosition || !State.savedCursor) return false;
            if (!url.includes('/i/listings/search')) return false;
            if (url.includes('aggregate_on=') || url.includes('count=0') || url.includes('in=wishlist')) return false;
            // 同时支持sort_by=title和sort_by=-title的URL
            Utils.logger('info', `[PagePatcher] -> ✅ MATCH! URL will be patched: ${url}`);
            return true;
        },

        getPatchedUrl(originalUrl) {
            if (State.savedCursor) {
                const urlObj = new URL(originalUrl, window.location.origin);
                urlObj.searchParams.set('cursor', State.savedCursor);
                // 确保不改变原始URL中的sort_by参数,如果存在的话
                // 这样可以支持sort_by=-title(降序)和sort_by=title(升序)
                const modifiedUrl = urlObj.pathname + urlObj.search;
                // NEW: Logging for injection
                Utils.logger('info', `[Cursor] Injecting cursor. Original: ${originalUrl}`);
                Utils.logger('info', `[Cursor] Patched URL: ${modifiedUrl}`);
                this._patchHasBeenApplied = true; // This should be set here
                return modifiedUrl;
            }
                    return originalUrl;
        },

        saveLatestCursorFromUrl(url) {
            // 改进实现,确保不会保存过早的浏览位置
            try {
                if (typeof url !== 'string' || !url.includes('/i/listings/search') || !url.includes('cursor=')) return;
                const urlObj = new URL(url, window.location.origin);
                const newCursor = urlObj.searchParams.get('cursor');

                // 如果是有效的cursor且与上次的不同
                if (newCursor && newCursor !== this._lastSeenCursor) {
                    // 解码cursor,检查是否是有效的浏览位置
                    let isValidPosition = true;
                    let decodedCursor = '';

                    try {
                        decodedCursor = atob(newCursor);

                        // 1. 检查特定的过滤关键词列表
                        const filterKeywords = [
                            "Nude+Tennis+Racket",
                            "Nordic+Beach+Boulder",
                            "Nordic+Beach+Rock"
                        ];

                        // 检查是否包含任何需要过滤的关键词
                        if (filterKeywords.some(keyword => decodedCursor.includes(keyword))) {
                            Utils.logger('info', `[Cursor] 跳过已知位置的保存: ${decodedCursor}`);
                            isValidPosition = false;
                        }

                        // 2. 检查是否是已经滚动过的前面位置(直接检测首字母)
                        if (isValidPosition && this._lastSeenCursor) {
                            try {
                                // 从解码的cursor中提取物品名称
                                let newItemName = '';
                                let lastItemName = '';

                                // 提取当前cursor中的物品名
                                if (decodedCursor.includes("p=")) {
                                    const match = decodedCursor.match(/p=([^&]+)/);
                                    if (match && match[1]) {
                                        newItemName = decodeURIComponent(match[1].replace(/\+/g, ' '));
                                    }
                                }

                                // 提取上次保存cursor中的物品名
                                const lastDecoded = atob(this._lastSeenCursor);
                                if (lastDecoded.includes("p=")) {
                                    const match = lastDecoded.match(/p=([^&]+)/);
                                    if (match && match[1]) {
                                        lastItemName = decodeURIComponent(match[1].replace(/\+/g, ' '));
                                    }
                                }

                                // 提取首字母或首个单词进行比较
                                if (newItemName && lastItemName) {
                                    // 获取首个单词或首字母
                                    const getFirstWord = (text) => {
                                        // 优先获取前三个字母,如果不足三个则获取全部
                                        return text.trim().substring(0, 3);
                                    };

                                    const newFirstWord = getFirstWord(newItemName);
                                    const lastFirstWord = getFirstWord(lastItemName);

                                    // 检查URL中的排序参数
                                    const sortParam = urlObj.searchParams.get('sort_by') || '';
                                    const isReverseSort = sortParam.startsWith('-');

                                    // 根据排序方向决定比较逻辑
                                    // 如果是按标题排序:
                                    // - 升序排列(title):如果新位置的首字母在字母表中排在当前位置前面,说明是回退了
                                    // - 降序排列(-title):如果新位置的首字母在字母表中排在当前位置后面,说明是回退了
                                    if ((isReverseSort && sortParam.includes('title') && newFirstWord > lastFirstWord) ||
                                        (!isReverseSort && sortParam.includes('title') && newFirstWord < lastFirstWord)) {
                                        Utils.logger('info', `[Cursor] 跳过回退位置: ${newItemName} (当前位置: ${lastItemName}), 排序: ${isReverseSort ? '降序' : '升序'}`);
                                        isValidPosition = false;
                                    }
                                }
                            } catch (compareError) {
                                // 比较错误,继续正常流程
                            }
                        }
                    } catch (decodeError) {
                        // 解码错误,继续正常流程
                    }

                    // 只有是有效位置才保存
                    if (isValidPosition) {
                        this._lastSeenCursor = newCursor;
                        State.savedCursor = newCursor; // 立即更新状态

                        // 持久化保存cursor供下次页面加载使用
                        GM_setValue(Config.DB_KEYS.LAST_CURSOR, newCursor);

                        // 日志记录保存操作
                        if (State.debugMode) {
                            Utils.logger('debug', `[Cursor] ${Utils.getText('debug_save_cursor', newCursor.substring(0, 30) + '...')}`);
                        }

                        // 更新UI中的位置显示
                        if (State.UI.savedPositionDisplay) {
                            State.UI.savedPositionDisplay.textContent = Utils.decodeCursor(newCursor);
                        }
                    }
                }
            } catch (e) {
                Utils.logger('warn', `[Cursor] 保存cursor时出错:`, e);
            }
        },

        applyPatches() {
            const self = this;
            const originalXhrOpen = XMLHttpRequest.prototype.open;
            const originalXhrSend = XMLHttpRequest.prototype.send;
            const DEBOUNCE_DELAY_MS = 350; // Centralize debounce delay

            const listenerAwareSend = function(...args) {
                const request = this;
                // 为所有请求添加监听器
                const onLoad = () => {
                    request.removeEventListener("load", onLoad);

                    // 记录所有网络活动
                    if (typeof window.recordNetworkActivity === 'function') {
                        window.recordNetworkActivity();
                    }

                    // 只统计商品相关的请求,保持原有逻辑
                    if (request.status >= 200 && request.status < 300 &&
                        request._url && self.isDebounceableSearch(request._url)) {
                        // 只记录商品卡片相关请求
                        window.recordNetworkRequest(Utils.getText('request_source_xhr_item'), true);
                    }

                    // 对所有请求检查429错误
                    if (request.status === 429 || request.status === '429' || request.status.toString() === '429') {
                        Utils.logger('warn', Utils.getText('xhr_detected_429', request.responseURL || request._url));
                        // 调用handleRateLimit函数处理限速情况
                        RateLimitManager.enterRateLimitedState(request.responseURL || request._url || 'XHR响应429');
                        return;
                    }

                    // 检查其他可能的限速情况(返回空结果或错误信息)
                    if (request.status >= 200 && request.status < 300) {
                        try {
                            const responseText = request.responseText;
                            if (responseText) {
                                // 先检查原始文本是否包含限速相关的关键词
                                if (responseText.includes("Too many requests") ||
                                    responseText.includes("rate limit") ||
                                    responseText.match(/\{\s*"detail"\s*:\s*"Too many requests"\s*\}/i)) {
                                    Utils.logger('warn', `[XHR限速检测] 检测到限速情况,原始响应: ${responseText}`);
                                    RateLimitManager.enterRateLimitedState('XHR响应内容限速');
                                    return;
                                }

                                // 尝试解析JSON
                                try {
                                    const data = JSON.parse(responseText);

                                    // 检查是否返回了空结果或错误信息
                                    if (data.detail && (data.detail.includes("Too many requests") || data.detail.includes("rate limit"))) {
                                        Utils.logger('warn', `${Utils.getText('implicit_rate_limit_detection')} ${Utils.getText('detected_rate_limit_error', JSON.stringify(data))}`);
                                        RateLimitManager.enterRateLimitedState('XHR响应限速错误');
                                        return;
                                    }

                                    // 检查是否返回了空结果
                                    if (data.results && data.results.length === 0 && self.isDebounceableSearch(request._url)) {
                                        // 情况1: 到达列表末尾的正常情况(next为null但previous不为null)
                                        const isEndOfList = data.next === null && data.previous !== null && data.cursors && data.cursors.next === null && data.cursors.previous !== null;

                                        // 情况2: 完全空的结果集,但可能是正常的搜索结果为空
                                        const isEmptySearch = data.next === null && data.previous === null && data.cursors && data.cursors.next === null && data.cursors.previous === null;

                                        // 获取当前URL的参数
                                        const urlObj = new URL(request._url, window.location.origin);
                                        const params = urlObj.searchParams;

                                        // 检查是否有特殊的搜索参数(如果有特殊过滤条件,空结果可能是正常的)
                                        const hasSpecialFilters = params.has('query') || params.has('category') || params.has('subcategory') || params.has('tag');

                                        if (isEndOfList) {
                                            Utils.logger('info', `[列表末尾] 检测到已到达列表末尾,这是正常情况,不触发限速: ${JSON.stringify(data).substring(0, 200)}...`);
                                            // 记录成功请求,虽然没有结果,但这是正常情况
                                            RateLimitManager.recordSuccessfulRequest('XHR列表末尾', true);
                                            return;
                                        } else if (isEmptySearch && hasSpecialFilters) {
                                            Utils.logger('info', `[空搜索结果] 检测到搜索结果为空,但包含特殊过滤条件,这可能是正常情况: ${JSON.stringify(data).substring(0, 200)}...`);
                                            // 记录成功请求,虽然没有结果,但这可能是正常情况
                                            RateLimitManager.recordSuccessfulRequest('XHR空搜索结果', true);
                                            return;
                                        } else if (isEmptySearch && State.appStatus === 'RATE_LIMITED') {
                                            // 如果已经处于限速状态,不要重复触发
                                            Utils.logger('info', `[空搜索结果] 已处于限速状态,不重复触发: ${JSON.stringify(data).substring(0, 200)}...`);
                                            return;
                                        } else if (isEmptySearch && document.readyState !== 'complete') {
                                            // 如果页面尚未完全加载,可能是初始请求,不要立即触发限速
                                            Utils.logger('info', `[空搜索结果] 页面尚未完全加载,可能是初始请求,不触发限速: ${JSON.stringify(data).substring(0, 200)}...`);
                                            return;
                                        } else if (isEmptySearch && Date.now() - (window.pageLoadTime || 0) < 5000) {
                                            // 如果页面刚刚加载不到5秒,可能是初始请求,不要立即触发限速
                                            Utils.logger('info', `[空搜索结果] ${Utils.getText('empty_search_initial')}: ${JSON.stringify(data).substring(0, 200)}...`);
                                            return;
                                        } else {
                                            Utils.logger('warn', `${Utils.getText('implicit_rate_limit_detection')} ${Utils.getText('detected_possible_rate_limit_empty', JSON.stringify(data).substring(0, 200) + '...')}`);
                                            RateLimitManager.enterRateLimitedState('XHR响应空结果');
                                            return;
                                        }
                                    }

                                    // 如果是搜索请求且有结果,记录成功请求
                                    if (self.isDebounceableSearch(request._url) && data.results && data.results.length > 0) {
                                        RateLimitManager.recordSuccessfulRequest(Utils.getText('request_source_xhr_search'), true);
                                    }
                                } catch (jsonError) {
                                    // JSON解析错误,忽略
                                }
                            }
                        } catch (e) {
                            // 解析错误,忽略
                        }
                    }

                    // 处理搜索请求的特殊逻辑(429检测等)
                    if (self.isDebounceableSearch(request._url)) {
                        self.handleSearchResponse(request);
                    }
                };
                request.addEventListener("load", onLoad);

                return originalXhrSend.apply(request, args);
            };

            XMLHttpRequest.prototype.open = function(method, url, ...args) {
                let modifiedUrl = url;
                // Priority 1: Handle the "remember position" patch, which should not be debounced.
                if (self.shouldPatchUrl(url)) {
                    modifiedUrl = self.getPatchedUrl(url);
                    this._isDebouncedSearch = false; // Explicitly mark it as NOT debounced
                }
                // Priority 2: Tag all other infinite scroll requests to be debounced.
                else if (self.isDebounceableSearch(url)) {
                    self.saveLatestCursorFromUrl(url); // FIX: Ensure we save the cursor before debouncing.
                    this._isDebouncedSearch = true;
                }
                // Priority 3: All other requests just save the cursor.
                else {
                    self.saveLatestCursorFromUrl(url);
                }
                this._url = modifiedUrl;
                // We still call the original open, but the send will be intercepted.
                return originalXhrOpen.apply(this, [method, modifiedUrl, ...args]);
            };

            XMLHttpRequest.prototype.send = function(...args) {
                // If this is not a request we need to debounce, send it immediately.
                if (!this._isDebouncedSearch) {
                    // Still use the wrapper to catch responses for non-debounced search requests
                    return listenerAwareSend.apply(this, args);
                }

                // NEW: Use [Debounce] tag for clarity
                if (State.debugMode) {
                    Utils.logger('debug', `[Debounce] 🚦 Intercepted scroll request. Applying ${DEBOUNCE_DELAY_MS}ms delay...`);
                }

                // If there's a previously pending request, abort it.
                if (self._pendingXhr) {
                    self._pendingXhr.abort();
                    Utils.logger('info', `[Debounce] 🗑️ Discarded previous pending request.`);
                }
                // Clear any existing timer.
                clearTimeout(self._debounceXhrTimer);

                // Store the current request as the latest one.
                self._pendingXhr = this;

                // Set a timer to send the latest request after a period of inactivity.
                self._debounceXhrTimer = setTimeout(() => {
                    if (State.debugMode) {
                        Utils.logger('debug', `[Debounce] ▶️ Sending latest scroll request: ${this._url}`);
                    }
                    listenerAwareSend.apply(self._pendingXhr, args);
                    self._pendingXhr = null; // Clear after sending
                }, DEBOUNCE_DELAY_MS);
            };

            const originalFetch = window.fetch;
            window.fetch = function(input, init) {
                let url = (typeof input === 'string') ? input : input.url;
                let modifiedInput = input;
                if (self.shouldPatchUrl(url)) {
                    const modifiedUrl = self.getPatchedUrl(url);
                        if (typeof input === 'string') {
                            modifiedInput = modifiedUrl;
                        } else {
                            modifiedInput = new Request(modifiedUrl, input);
                        }
                    } else {
                    self.saveLatestCursorFromUrl(url);
                    }

                // 拦截响应以检测429错误
                return originalFetch.apply(this, [modifiedInput, init])
                    .then(async response => {
                        // 记录所有网络活动
                        if (typeof window.recordNetworkActivity === 'function') {
                            window.recordNetworkActivity();
                        }

                        // 只统计商品相关的请求
                        if (response.status >= 200 && response.status < 300 &&
                            typeof url === 'string' && self.isDebounceableSearch(url)) {
                            window.recordNetworkRequest('Fetch商品请求', true);
                        }

                        // 检查429错误
                        if (response.status === 429 || response.status === '429' || response.status.toString() === '429') {
                            // 克隆响应以避免"已消费"错误
                            // 克隆响应以避免"已消费"错误(但这里不需要使用)
                            response.clone();
                            Utils.logger('warn', `[Fetch] 检测到429状态码: ${response.url}`);
                            // 使用RateLimitManager处理限速情况
                            RateLimitManager.enterRateLimitedState('Fetch响应429').catch(e =>
                                Utils.logger('error', `处理限速时出错: ${e.message}`)
                            );
                        }

                        // 检查其他可能的限速情况(返回空结果或错误信息)
                        if (response.status >= 200 && response.status < 300) {
                            try {
                                // 克隆响应以避免"已消费"错误
                                const clonedResponse = response.clone();

                                // 先检查原始文本
                                const text = await clonedResponse.text();
                                if (text.includes("Too many requests") ||
                                    text.includes("rate limit") ||
                                    text.match(/\{\s*"detail"\s*:\s*"Too many requests"\s*\}/i)) {
                                    Utils.logger('warn', `[Fetch限速检测] 检测到限速情况,原始响应: ${text.substring(0, 100)}...`);
                                    RateLimitManager.enterRateLimitedState('Fetch响应内容限速').catch(e =>
                                        Utils.logger('error', `处理限速时出错: ${e.message}`)
                                    );
                                    return response;
                                }

                                        // 尝试解析JSON - 增强版
        try {
            const data = JSON.parse(text);

            // 检查明确的限速信息
            if (data.detail && (data.detail.includes("Too many requests") || data.detail.includes("rate limit"))) {
                Utils.logger('warn', `[限速检测] 检测到API限速响应`);
                RateLimitManager.enterRateLimitedState('API限速响应').catch(e =>
                    Utils.logger('error', `处理限速时出错: ${e.message}`)
                );
                return;
            }

            // 检查是否返回了空结果
            const responseUrl = response.url || '';
            if (data.results && data.results.length === 0 && responseUrl.includes('/i/listings/search')) {
                // 情况1: 到达列表末尾的正常情况(next为null但previous不为null)
                const isEndOfList = data.next === null && data.previous !== null && data.cursors && data.cursors.next === null && data.cursors.previous !== null;

                // 情况2: 完全空的结果集,但可能是正常的搜索结果为空
                const isEmptySearch = data.next === null && data.previous === null && data.cursors && data.cursors.next === null && data.cursors.previous === null;

                // 获取当前URL的参数
                const urlObj = new URL(responseUrl, window.location.origin);
                const params = urlObj.searchParams;

                // 检查是否有特殊的搜索参数(如果有特殊过滤条件,空结果可能是正常的)
                const hasSpecialFilters = params.has('query') || params.has('category') || params.has('subcategory') || params.has('tag');

                if (isEndOfList) {
                    Utils.logger('info', `[Fetch列表末尾] 检测到已到达列表末尾,这是正常情况,不触发限速: ${JSON.stringify(data).substring(0, 200)}...`);
                    // 记录成功请求,虽然没有结果,但这是正常情况
                    RateLimitManager.recordSuccessfulRequest('Fetch列表末尾', true);
                } else if (isEmptySearch && hasSpecialFilters) {
                    Utils.logger('info', `[Fetch空搜索结果] 检测到搜索结果为空,但包含特殊过滤条件,这可能是正常情况: ${JSON.stringify(data).substring(0, 200)}...`);
                    // 记录成功请求,虽然没有结果,但这可能是正常情况
                    RateLimitManager.recordSuccessfulRequest('Fetch空搜索结果', true);
                } else if (isEmptySearch && State.appStatus === 'RATE_LIMITED') {
                    // 如果已经处于限速状态,不要重复触发
                    Utils.logger('info', `[Fetch空搜索结果] 已处于限速状态,不重复触发: ${JSON.stringify(data).substring(0, 200)}...`);
                } else if (isEmptySearch && document.readyState !== 'complete') {
                    // 如果页面尚未完全加载,可能是初始请求,不要立即触发限速
                    Utils.logger('info', `[Fetch空搜索结果] 页面尚未完全加载,可能是初始请求,不触发限速: ${JSON.stringify(data).substring(0, 200)}...`);
                } else if (isEmptySearch && Date.now() - (window.pageLoadTime || 0) < 5000) {
                    // 如果页面刚刚加载不到5秒,可能是初始请求,不要立即触发限速
                    Utils.logger('info', `[Fetch空搜索结果] 页面刚刚加载,可能是初始请求,不触发限速: ${JSON.stringify(data).substring(0, 200)}...`);
                } else {
                    Utils.logger('warn', `[Fetch隐性限速] 检测到可能的限速情况(空结果): ${JSON.stringify(data).substring(0, 200)}...`);
                    RateLimitManager.enterRateLimitedState('Fetch响应空结果').catch(e =>
                        Utils.logger('error', `处理限速时出错: ${e.message}`)
                    );
                }
            }
        } catch (jsonError) {
            // JSON解析错误,忽略
            Utils.logger('debug', `JSON解析错误: ${jsonError.message}`);
            // 添加更多调试信息,帮助诊断问题
            if (responseText && responseText.length > 0) {
                Utils.logger('debug', `响应长度: ${responseText.length}, 前100个字符: ${responseText.substring(0, 100)}`);
            }
        }
                            } catch (e) {
                                // 解析错误,忽略
                            }
                        }

                        return response;
                });
            };
        }
    };


    // --- 模块七: 任务运行器与事件处理 (Task Runner & Event Handlers) ---
    const TaskRunner = {
        isCardFinished: (card) => {
            const link = card.querySelector(Config.SELECTORS.cardLink);
            // If there's no link, we can't get a URL to check against the DB.
            // In this case, rely only on visual cues.
            const url = link ? link.href.split('?')[0] : null;

            // 如果没有链接,无法获取UID,则只能依赖视觉提示
            if (!link) {
                // 检查是否有"已拥有"样式标记(绿色对勾图标)
                const icons = card.querySelectorAll('i.fabkit-Icon--intent-success, i.edsicon-check-circle-filled');
                if (icons.length > 0) return true;

                // 检查是否有"已保存"文本
                const text = card.textContent || '';
                return text.includes("已保存在我的库中") ||
                       text.includes("已保存") ||
                       text.includes("Saved to My Library") ||
                       text.includes("In your library");
            }

            // 从链接中提取UID
            const uidMatch = link.href.match(/listings\/([a-f0-9-]+)/);
            if (!uidMatch || !uidMatch[1]) {
                return false;
            }

            const uid = uidMatch[1];

            // 优先使用缓存的API数据判断
            if (DataCache.ownedStatus.has(uid)) {
                const status = DataCache.ownedStatus.get(uid);
                if (status && status.acquired) {
                    return true;
                }
            }

            // 如果缓存中没有,则检查网页元素
            if (card.querySelector(Config.SELECTORS.ownedStatus) !== null) {
                // 找到了,将状态保存到缓存
                if (uid) {
                    DataCache.saveOwnedStatus([{
                        uid: uid,
                        acquired: true,
                        lastUpdatedAt: new Date().toISOString()
                    }]);
                }
                return true;
            }

            // 最后检查本地数据库
            if (url) {
                if (Database.isDone(url)) return true;
                if (Database.isFailed(url)) return true; // A failed item is also considered "finished" for skipping/hiding purposes.
                if (State.sessionCompleted.has(url)) return true;
            }

            return false;
        },
        // --- Toggles ---
        // This is the new main execution function, triggered by the "一键开刷" button.
        toggleExecution: () => {
            // 检查账号状态
            if (!Utils.checkAuthentication()) {
                return;
            }
            
            if (State.isExecuting) {
                // If it's running, stop it.
                State.isExecuting = false;
                // 保存执行状态
                Database.saveExecutingState();
                State.runningWorkers = {};
                State.activeWorkers = 0;
                State.executionTotalTasks = 0;
                State.executionCompletedTasks = 0;
                State.executionFailedTasks = 0;
                Utils.logger('info', '执行已由用户手动停止。');
                UI.update();
                return;
            }

            // NEW: Divert logic if auto-add is on. The observer populates the list,
            // so the button should just act as a "start" signal.
            if (State.autoAddOnScroll) {
                Utils.logger('info', Utils.getText('log_auto_add_enabled'));

                // 先检查当前页面上的卡片状态,更新数据库
                TaskRunner.checkVisibleCardsStatus().then(() => {
                    // 然后开始执行任务
                    TaskRunner.startExecution(); // This will use the existing todo list
                });
                return;
            }


            // --- BEHAVIOR CHANGE: From Accumulate to Overwrite Mode ---
            // As per user request for waterfall pages, clear the existing To-Do list before every scan.
            // This part now only runs when auto-add is OFF.
            State.db.todo = [];
            Utils.logger('info', '待办列表已清空。现在将扫描并仅添加当前可见的项目。');

            Utils.logger('info', '正在扫描已加载完成的商品...');
                const cards = document.querySelectorAll(Config.SELECTORS.card);
                const newlyAddedList = [];
                let alreadyInQueueCount = 0;
                let ownedCount = 0;
            let skippedCount = 0;

            const isCardSettled = (card) => {
                return card.querySelector(`${Config.SELECTORS.freeStatus}, ${Config.SELECTORS.ownedStatus}`) !== null;
            };

                cards.forEach(card => {
                // 正确的修复:直接检查元素的 display 样式。如果它是 'none',就意味着它被隐藏了,应该跳过。
                if (card.style.display === 'none') {
                    return;
                }

                if (!isCardSettled(card)) {
                    skippedCount++;
                    return; // Skip unsettled cards
                }

                // UNIFIED LOGIC: Use the new single source of truth to check if the card is finished.
                if (TaskRunner.isCardFinished(card)) {
                        ownedCount++;
                        return;
                    }

                const link = card.querySelector(Config.SELECTORS.cardLink);
                const url = link ? link.href.split('?')[0] : null;
                if (!url) return; // Should be caught by isCardFinished, but good for safety.

                // The only check unique to adding is whether it's already in the 'todo' queue.
                    const isTodo = Database.isTodo(url);
                if (isTodo) {
                        alreadyInQueueCount++;
                        return;
                    }

                    const name = card.querySelector('a[aria-label*="创作的"]')?.textContent.trim() || card.querySelector('a[href*="/listings/"]')?.textContent.trim() || Utils.getText('untitled');
                    newlyAddedList.push({ name, url, type: 'detail', uid: url.split('/').pop() });
                });

            if (skippedCount > 0) {
                Utils.logger('info', `已跳过 ${skippedCount} 个状态未加载的商品。`);
            }

                if (newlyAddedList.length > 0) {
                    State.db.todo.push(...newlyAddedList);
                    Utils.logger('info', `已将 ${newlyAddedList.length} 个新商品加入待办队列。`);
                }

                const actionableCount = State.db.todo.length;
                if (actionableCount > 0) {
                    if (newlyAddedList.length === 0 && alreadyInQueueCount > 0) {
                         Utils.logger('info', `本页的 ${alreadyInQueueCount} 个可领取商品已全部在待办或失败队列中。`);
                }

                    // 先检查当前页面上的卡片状态,更新数据库
                    TaskRunner.checkVisibleCardsStatus().then(() => {
                        // 然后开始执行任务
                    TaskRunner.startExecution();
                    });
            } else {
                 Utils.logger('info', `本页没有可领取的新商品 (已拥有: ${ownedCount} 个, 已跳过: ${skippedCount} 个)。`);
            UI.update();
            }
        },

        // This function starts the execution loop without scanning.
        startExecution: () => {
            // Case 1: Execution is already running. We just need to update the total task count.
            if (State.isExecuting) {
                const newTotal = State.db.todo.length;
                if (newTotal > State.executionTotalTasks) {
                    Utils.logger('info', `任务执行中,新任务已添加。总任务数更新为: ${newTotal}`);
                    State.executionTotalTasks = newTotal;
                    UI.update(); // Update the UI to reflect the new total.
                } else {
                    Utils.logger('info', '执行器已在运行中,新任务已加入队列等待处理。');
                }
                // IMPORTANT: Do not start a new execution loop. The current one will pick up the new tasks.
                return;
            }

            // Case 2: Starting a new execution from an idle state.
            if (State.db.todo.length === 0) {
                Utils.logger('debug', Utils.getText('log_exec_no_tasks'));
                return;
            }
            Utils.logger('info', `队列中有 ${State.db.todo.length} 个任务,即将开始执行...`);
            State.isExecuting = true;
            // 保存执行状态
            Database.saveExecutingState();
            State.executionTotalTasks = State.db.todo.length;
            State.executionCompletedTasks = 0;
            State.executionFailedTasks = 0;

            // 立即更新UI,确保按钮状态与执行状态一致
            UI.update();

            TaskRunner.executeBatch();
        },

        // 执行按钮的点击处理函数
        toggleExecution: () => {
            // 检查账号状态
            if (!Utils.checkAuthentication()) {
                return;
            }
            
            if (State.isExecuting) {
                TaskRunner.stop();
            } else {
                // 检查待办清单是否为空,如果为空则先扫描页面
                if (State.db.todo.length === 0) {
                    Utils.logger('info', '待办清单为空,正在扫描当前页面...');
                    // 使用主扫描函数,这会清空待办并添加新发现的商品
                    const cards = document.querySelectorAll(Config.SELECTORS.card);
                    const newlyAddedList = [];
                    let alreadyInQueueCount = 0;
                    let ownedCount = 0;
                    let skippedCount = 0;

                    const isCardSettled = (card) => {
                        return card.querySelector(`${Config.SELECTORS.freeStatus}, ${Config.SELECTORS.ownedStatus}`) !== null;
                    };

                    cards.forEach(card => {
                        // 检查元素是否被隐藏
                        if (card.style.display === 'none') {
                            return;
                        }

                        if (!isCardSettled(card)) {
                            skippedCount++;
                            return; // 跳过未加载完成的卡片
                        }

                        // 使用统一逻辑检查卡片是否已处理
                        if (TaskRunner.isCardFinished(card)) {
                            ownedCount++;
                            return;
                        }

                        const link = card.querySelector(Config.SELECTORS.cardLink);
                        const url = link ? link.href.split('?')[0] : null;
                        if (!url) return;

                        // 检查是否已在待办队列
                        const isTodo = Database.isTodo(url);
                        if (isTodo) {
                            alreadyInQueueCount++;
                            return;
                        }

                        const name = card.querySelector('a[aria-label*="创作的"]')?.textContent.trim() || card.querySelector('a[href*="/listings/"]')?.textContent.trim() || Utils.getText('untitled');
                        newlyAddedList.push({ name, url, type: 'detail', uid: url.split('/').pop() });
                    });

                    if (skippedCount > 0) {
                        Utils.logger('info', `已跳过 ${skippedCount} 个状态未加载的商品。`);
                    }

                    if (newlyAddedList.length > 0) {
                        State.db.todo.push(...newlyAddedList);
                        Utils.logger('info', `已将 ${newlyAddedList.length} 个新商品加入待办队列。`);
                        // 保存待办列表到存储
                        Database.saveTodo();
                    } else {
                        Utils.logger('info', `本页没有可领取的新商品 (已拥有: ${ownedCount} 个, 已跳过: ${skippedCount} 个)。`);
                    }
                }

                // 然后开始执行
                TaskRunner.startExecution();
            }

            // 立即更新UI,确保按钮状态与执行状态一致
            UI.update();
        },
        toggleHideSaved: async () => {
            State.hideSaved = !State.hideSaved;
            await Database.saveHidePref();
            TaskRunner.runHideOrShow();

            // 如果关闭了隐藏功能,确保更新可见商品计数
            if (!State.hideSaved) {
                // 重新计算实际可见的商品数量
                const actualVisibleCount = document.querySelectorAll(`${Config.SELECTORS.card}:not([style*="display: none"])`).length;
                Utils.logger('info', `👁️ 显示模式已切换,当前页面有 ${actualVisibleCount} 个可见商品`);
            }

            UI.update();
        },

        toggleAutoAdd: async () => {
            if (State.isTogglingSetting) return;
            State.isTogglingSetting = true;

            State.autoAddOnScroll = !State.autoAddOnScroll;
            await Database.saveAutoAddPref();
            Utils.logger('info', Utils.getText('log_auto_add_toggle', State.autoAddOnScroll ? Utils.getText('status_enabled') : Utils.getText('status_disabled')));
            // No need to call UI.update() as the visual state is handled by the component itself.

            setTimeout(() => { State.isTogglingSetting = false; }, 200);
        },

        toggleAutoResume: async () => {
            if (State.isTogglingSetting) return;
            State.isTogglingSetting = true;

            State.autoResumeAfter429 = !State.autoResumeAfter429;
            await Database.saveAutoResumePref();
            Utils.logger('info', Utils.getText('log_auto_resume_toggle', State.autoResumeAfter429 ? Utils.getText('status_enabled') : Utils.getText('status_disabled')));

            setTimeout(() => { State.isTogglingSetting = false; }, 200);
        },

        toggleRememberPosition: async () => {
            if (State.isTogglingSetting) return;
            State.isTogglingSetting = true;

            State.rememberScrollPosition = !State.rememberScrollPosition;
            await Database.saveRememberPosPref();
            Utils.logger('info', Utils.getText('log_remember_pos_toggle', State.rememberScrollPosition ? Utils.getText('status_enabled') : Utils.getText('status_disabled')));

            if (!State.rememberScrollPosition) {
                await GM_deleteValue(Config.DB_KEYS.LAST_CURSOR);
                // 重置PagePatcher中的状态
                PagePatcher._patchHasBeenApplied = false;
                PagePatcher._lastSeenCursor = null;
                State.savedCursor = null;
                Utils.logger('info', '已清除已保存的浏览位置。');

                // 更新UI中的位置显示
                if (State.UI.savedPositionDisplay) {
                    State.UI.savedPositionDisplay.textContent = Utils.decodeCursor(null);
                }
            } else if (State.UI.savedPositionDisplay) {
                // 如果开启功能,更新显示当前保存的位置
                State.UI.savedPositionDisplay.textContent = Utils.decodeCursor(State.savedCursor);
            }

            setTimeout(() => { State.isTogglingSetting = false; }, 200);
        },

        // 停止执行任务
        stop: () => {
            if (!State.isExecuting) return;

            State.isExecuting = false;
            // 保存执行状态
            Database.saveExecutingState();
            // 保存待办列表
            Database.saveTodo();

            // 清理任务和工作线程
            GM_deleteValue(Config.DB_KEYS.TASK);
            State.runningWorkers = {};
            State.activeWorkers = 0;
            State.executionTotalTasks = 0;
            State.executionCompletedTasks = 0;
            State.executionFailedTasks = 0;

            Utils.logger('info', '执行已由用户手动停止。');

            // 立即更新UI,确保按钮状态与执行状态一致
            UI.update();
        },

        runRecoveryProbe: async () => {
            const randomDelay = Math.floor(Math.random() * (30000 - 15000 + 1) + 15000); // 15-30 seconds
            Utils.logger('info', `[Auto-Recovery] In recovery mode. Probing connection in ${(randomDelay / 1000).toFixed(1)} seconds...`);

            setTimeout(async () => {
                Utils.logger('info', `[Auto-Recovery] Probing connection...`);
                try {
                    const csrfToken = Utils.getCookie('fab_csrftoken');
                    if (!csrfToken) {
                        Utils.checkAuthentication();
                        throw new Error("CSRF token not found for probe.");
                    }
                    // Use a lightweight, known-good endpoint for the probe
                    const probeResponse = await API.gmFetch({
                        method: 'GET',
                        url: 'https://www.fab.com/i/users/context',
                        headers: { 'x-csrftoken': csrfToken, 'x-requested-with': 'XMLHttpRequest' }
                    });

                    if (probeResponse.status === 429) {
                        throw new Error("Probe failed with 429. Still rate-limited.");
                    } else if (probeResponse.status >= 200 && probeResponse.status < 300) {
                        // SUCCESS!
                        // Manually create a fake request object to reuse the recovery logic in handleSearchResponse
                        await PagePatcher.handleSearchResponse({ status: 200 });
                        Utils.logger('info', `[Auto-Recovery] ✅ Connection restored! Auto-resuming operations...`);
                        TaskRunner.toggleExecution(); // Auto-start the process!
                    } else {
                        throw new Error(`Probe failed with unexpected status: ${probeResponse.status}`);
                    }
                } catch (e) {
                    Utils.logger('error', `[Auto-Recovery] ❌ ${e.message}. Scheduling next refresh...`);
                    setTimeout(() => location.reload(), 2000); // Wait 2s before next refresh
                }
            }, randomDelay);
        },

        resetReconProgress: async () => {
            if (State.isReconning) {
                Utils.logger('warn', Utils.getText('log_recon_active'));
                return;
            }
            await GM_deleteValue(Config.DB_KEYS.NEXT_URL);
            if (State.UI.reconProgressDisplay) {
                State.UI.reconProgressDisplay.textContent = Utils.getText('page_reset');
            }
            Utils.logger('info', Utils.getText('log_recon_reset'));
        },

        refreshVisibleStates: async () => {
            const API_ENDPOINT = 'https://www.fab.com/i/users/me/listings-states';
            const API_CHUNK_SIZE = 24; // Server-side limit

            const isElementInViewport = (el) => {
                if (!el) return false;
                const rect = el.getBoundingClientRect();
                return rect.top < window.innerHeight && rect.bottom > 0 && rect.left < window.innerWidth && rect.right > 0;
            };

            try {
                const csrfToken = Utils.getCookie('fab_csrftoken');
                if (!csrfToken) {
                    Utils.checkAuthentication();
                    throw new Error('CSRF token not found. Are you logged in?');
                }

                // Step 1: Gather all unique UIDs to check
                // 只收集可见的未入库商品
                const uidsFromVisibleCards = new Set([...document.querySelectorAll(Config.SELECTORS.card)]
                    .filter(isElementInViewport)
                    .filter(card => {
                        // 过滤掉已经确认入库的商品
                        const link = card.querySelector(Config.SELECTORS.cardLink);
                        if (!link) return false;
                        const url = link.href.split('?')[0];
                        return !Database.isDone(url);
                    })
                    .map(card => card.querySelector(Config.SELECTORS.cardLink)?.href.match(/listings\/([a-f0-9-]+)/)?.[1])
                    .filter(Boolean));

                // 收集已经入库失败的商品
                const uidsFromFailedList = new Set(State.db.failed.map(task => task.uid));

                // 合并两类商品ID
                const allUidsToCheck = Array.from(new Set([...uidsFromVisibleCards, ...uidsFromFailedList]));

                if (allUidsToCheck.length === 0) {
                    Utils.logger('info', '[Fab DOM Refresh] 没有未入库的可见商品或入库失败的商品需要检查。');
                    return;
                }
                Utils.logger('info', `[Fab DOM Refresh] 正在分批检查 ${uidsFromVisibleCards.size} 个未入库的可见商品和 ${uidsFromFailedList.size} 个入库失败的商品...`);

                // Step 2: Process UIDs in chunks
                const ownedUids = new Set();
                for (let i = 0; i < allUidsToCheck.length; i += API_CHUNK_SIZE) {
                    const chunk = allUidsToCheck.slice(i, i + API_CHUNK_SIZE);
                const apiUrl = new URL(API_ENDPOINT);
                    chunk.forEach(uid => apiUrl.searchParams.append('listing_ids', uid));

                    Utils.logger('info', `[Fab DOM Refresh] 正在处理批次 ${Math.floor(i / API_CHUNK_SIZE) + 1}... (${chunk.length}个项目)`);

                                    const response = await fetch(apiUrl.href, {
                        headers: { 'accept': 'application/json, text/plain, */*', 'x-csrftoken': csrfToken, 'x-requested-with': 'XMLHttpRequest' }
                    });

                    if (!response.ok) {
                         Utils.logger('warn', `批次处理失败,状态码: ${response.status}。将跳过此批次。`);
                         continue; // Skip to next chunk
                    }

                    const rawData = await response.json();

                    // 使用API.extractStateData处理可能的不同格式的响应
                    const data = API.extractStateData(rawData, 'RefreshStates');

                    if (!data || !Array.isArray(data)) {
                        Utils.logger('warn', `API返回的数据格式异常: ${JSON.stringify(rawData).substring(0, 200)}...`);
                        continue; // Skip to next chunk if data format is unexpected
                    }

                    data.filter(item => item.acquired).forEach(item => ownedUids.add(item.uid));

                    // Add a small delay between chunks to be safe
                    if (allUidsToCheck.length > i + API_CHUNK_SIZE) {
                       await new Promise(r => setTimeout(r, 250));
                    }
                }

                Utils.logger('info', `[Fab DOM Refresh] ${Utils.getText('fab_dom_api_complete', ownedUids.size)}`);

                // Step 3: Update database based on all results
                let dbUpdated = false;
                const langPath = State.lang === 'zh' ? '/zh-cn' : '';
                if (ownedUids.size > 0) {
                    const initialFailedCount = State.db.failed.length;
                    State.db.failed = State.db.failed.filter(failedTask => !ownedUids.has(failedTask.uid));

                    if (State.db.failed.length < initialFailedCount) {
                        dbUpdated = true;
                        ownedUids.forEach(uid => {
                            const url = `${window.location.origin}${langPath}/listings/${uid}`;
                            if (!Database.isDone(url)) {
                                State.db.done.push(url);
                            }
                        });
                        Utils.logger('info', `[Fab DB Sync] 从"失败"列表中清除了 ${initialFailedCount - State.db.failed.length} 个已手动完成的商品。`);
                    }
                }

                // Step 3.5: Remove non-free items from the Failed list
                try {
                    const failedTasksSnapshot = [...State.db.failed];
                    Utils.logger('info', `[Fab DB Sync] 开始检查失败列表中的 ${failedTasksSnapshot.length} 个商品的价格状态...`);

                    if (failedTasksSnapshot.length > 0) {
                        // Map failed UID -> offerId (from cached listings)
                        const uidToOfferId = new Map();
                        let foundOfferIds = 0;
                        const missingCacheUids = [];

                        failedTasksSnapshot.forEach(task => {
                            const listing = DataCache.listings.get(task.uid);
                            const offerId = listing?.startingPrice?.offerId;
                            if (offerId) {
                                uidToOfferId.set(task.uid, offerId);
                                foundOfferIds++;
                            } else {
                                missingCacheUids.push(task.uid);
                                Utils.logger('debug', `[Fab DB Sync] 商品 ${task.uid} 没有找到缓存的商品信息或价格ID`);
                            }
                        });

                        Utils.logger('info', `[Fab DB Sync] 在 ${failedTasksSnapshot.length} 个失败商品中找到了 ${foundOfferIds} 个有价格ID的商品`);

                        // 对于没有缓存数据的商品,尝试重新获取信息
                        if (missingCacheUids.length > 0) {
                            Utils.logger('info', `[Fab DB Sync] 尝试为 ${missingCacheUids.length} 个缺失缓存的商品重新获取信息...`);

                            try {
                                const csrfToken = Utils.getCookie('fab_csrftoken');
                                if (csrfToken) {
                                    // 分批查询商品信息
                                    const SEARCH_CHUNK_SIZE = 5; // 每次查询5个商品
                                    for (let i = 0; i < missingCacheUids.length; i += SEARCH_CHUNK_SIZE) {
                                        const chunk = missingCacheUids.slice(i, i + SEARCH_CHUNK_SIZE);

                                        for (const uid of chunk) {
                                            try {
                                                const searchUrl = `https://www.fab.com/i/listings/search?q=${uid}`;
                                                const response = await fetch(searchUrl, {
                                                    headers: {
                                                        'accept': 'application/json, text/plain, */*',
                                                        'x-csrftoken': csrfToken,
                                                        'x-requested-with': 'XMLHttpRequest'
                                                    }
                                                });

                                                if (response.ok) {
                                                    const searchData = await response.json();
                                                    if (searchData.results && searchData.results.length > 0) {
                                                        // 找到匹配的商品
                                                        const matchedItem = searchData.results.find(item => item.uid === uid);
                                                        if (matchedItem && matchedItem.startingPrice?.offerId) {
                                                            // 缓存商品信息
                                                            DataCache.saveListings([matchedItem]);
                                                            // 添加到offerId映射
                                                            uidToOfferId.set(uid, matchedItem.startingPrice.offerId);
                                                            foundOfferIds++;
                                                            Utils.logger('debug', `[Fab DB Sync] 成功获取商品 ${uid} 的价格ID: ${matchedItem.startingPrice.offerId}`);
                                                        }
                                                    }
                                                }

                                                // 添加延迟避免请求过快
                                                await new Promise(r => setTimeout(r, 200));
                                            } catch (e) {
                                                Utils.logger('debug', `[Fab DB Sync] 获取商品 ${uid} 信息失败: ${e.message}`);
                                            }
                                        }
                                    }

                                    Utils.logger('info', `[Fab DB Sync] 重新获取完成,现在总共有 ${foundOfferIds} 个商品有价格ID`);
                                }
                            } catch (e) {
                                Utils.logger('warn', `[Fab DB Sync] 重新获取商品信息时出错: ${e.message}`);
                            }
                        }

                        const offerIds = Array.from(uidToOfferId.values());
                        if (offerIds.length > 0) {
                            const CHUNK = 50;
                            const nonFreeOfferIds = new Set();

                            Utils.logger('info', `[Fab DB Sync] 开始检查 ${offerIds.length} 个商品的价格...`);

                            for (let i = 0; i < offerIds.length; i += CHUNK) {
                                const chunk = offerIds.slice(i, i + CHUNK);
                                Utils.logger('info', `[Fab DB Sync] 检查价格批次 ${Math.floor(i / CHUNK) + 1},包含 ${chunk.length} 个商品...`);

                                const prices = await API.checkItemsPrices(chunk);
                                Utils.logger('info', `[Fab DB Sync] 价格API返回了 ${prices.length} 个结果`);

                                prices.forEach(offer => {
                                    if (offer && typeof offer.price === 'number' && offer.price > 0) {
                                        nonFreeOfferIds.add(offer.offerId);
                                        Utils.logger('debug', `[Fab DB Sync] 发现付费商品: ${offer.offerId}, 价格: ${offer.price}`);
                                    } else if (offer) {
                                        Utils.logger('debug', `[Fab DB Sync] 发现免费商品: ${offer.offerId}, 价格: ${offer.price}`);
                                    }
                                });

                                // Gentle pacing to be safe
                                if (offerIds.length > i + CHUNK) {
                                    await new Promise(r => setTimeout(r, 150));
                                }
                            }

                            Utils.logger('info', `[Fab DB Sync] 价格检查完成,发现 ${nonFreeOfferIds.size} 个付费商品`);

                            if (nonFreeOfferIds.size > 0) {
                                const before = State.db.failed.length;
                                const removedItems = [];

                                State.db.failed = State.db.failed.filter(task => {
                                    const offerId = uidToOfferId.get(task.uid);
                                    const shouldRemove = offerId && nonFreeOfferIds.has(offerId);
                                    if (shouldRemove) {
                                        removedItems.push(`${task.name || task.uid} (${offerId})`);
                                    }
                                    // Remove only when we are sure it's not free (price > 0)
                                    return !offerId || !nonFreeOfferIds.has(offerId);
                                });

                                const removed = before - State.db.failed.length;
                                if (removed > 0) {
                                    dbUpdated = true;
                                    Utils.logger('info', `[Fab DB Sync] 从"失败"列表中移除了 ${removed} 个非免费商品:`);
                                    removedItems.forEach(item => Utils.logger('info', `  - ${item}`));
                                } else {
                                    Utils.logger('info', `[Fab DB Sync] 没有找到需要移除的付费商品`);
                                }
                            } else {
                                Utils.logger('info', `[Fab DB Sync] 没有发现付费商品,失败列表保持不变`);
                            }
                        } else {
                            Utils.logger('info', `[Fab DB Sync] 失败列表中的商品都没有找到价格ID,跳过价格检查`);
                        }
                    }
                } catch (e) {
                    Utils.logger('warn', `[Fab DB Sync] 检查失败项价格失败: ${e.message}`);
                }


                // Step 4: Update UI for visible cards
                const uidToCardMap = new Map([...document.querySelectorAll(Config.SELECTORS.card)]
                     .filter(isElementInViewport)
                     .map(card => {
                         const uid = card.querySelector(Config.SELECTORS.cardLink)?.href.match(/listings\/([a-f0-9-]+)/)?.[1];
                         return uid ? [uid, card] : null;
                     }).filter(Boolean));

                let updatedCount = 0;
                uidToCardMap.forEach((card, uid) => {
                    const isOwned = ownedUids.has(uid);

                    // 不再手动修改DOM元素,只更新计数
                    if (isOwned) {
                        updatedCount++;
                    }
                });

                if (dbUpdated) {
                    await Database.saveFailed();
                    await Database.saveDone();
                }

                Utils.logger('debug', `[Fab DOM Refresh] Complete. Updated ${updatedCount} visible card states.`);

                TaskRunner.runHideOrShow();

            } catch (e) {
                Utils.logger('error', '[Fab DOM Refresh] An error occurred:', e);
                alert(Utils.getText('error_api_refresh'));
            }
        },

        retryFailedTasks: async () => {
            if (State.db.failed.length === 0) {
                Utils.logger('info', Utils.getText('log_no_failed_tasks'));
                return;
            }
            const count = State.db.failed.length;
            Utils.logger('info', Utils.getText('log_requeuing_tasks', count));
            State.db.todo.push(...State.db.failed); // Append failed tasks to the end of the todo list
            State.db.failed = []; // Clear the failed list
            await Database.saveFailed();
            Utils.logger('info', `${count} tasks moved from Failed to To-Do list.`);
            UI.update(); // Force immediate UI update
        },

        // --- Core Logic Functions ---
        reconWithApi: async () => {
            if (!State.isReconning) return;

            try {
                // 不再主动发送API请求,而是使用网页原生请求的数据
                Utils.logger('info', `[优化] 不再主动发送API请求,而是使用网页原生请求的数据`);
                Utils.logger('info', `[优化] 当前等待列表中有 ${DataCache.waitingList.size} 个商品ID等待更新`);

                // 更新UI显示
                if (State.UI.reconProgressDisplay) {
                    State.UI.reconProgressDisplay.textContent = Utils.getText('using_native_requests', DataCache.waitingList.size);
                }

                // 结束扫描
                State.isReconning = false;
                await GM_deleteValue(Config.DB_KEYS.NEXT_URL);
                Utils.logger('info', Utils.getText('log_recon_end'));
                UI.update();
                return;




            } catch (error) {
                Utils.logger('error', `API扫描出错: ${error.message}`);
                if (error.message && error.message.includes('429')) {
                    Utils.logger('warn', '检测到429错误,可能是请求过于频繁。将暂停扫描。');
                    State.isReconning = false;
                }
                UI.update();
            }
        },

        // This is the watchdog timer that patrols for stalled workers.
        runWatchdog: () => {
            if (State.watchdogTimer) clearInterval(State.watchdogTimer); // Clear any existing timer

            State.watchdogTimer = setInterval(async () => {
                // 如果当前实例不是活跃实例,不执行监控
                if (!InstanceManager.isActive) return;

                if (!State.isExecuting || Object.keys(State.runningWorkers).length === 0) {
                    clearInterval(State.watchdogTimer);
                    State.watchdogTimer = null;
                    return;
                }

                const now = Date.now();
                const STALL_TIMEOUT = Config.WORKER_TIMEOUT; // 使用配置的超时时间
                const stalledWorkers = [];

                // 先收集所有超时的工作标签页,避免在循环中修改对象
                for (const workerId in State.runningWorkers) {
                    const workerInfo = State.runningWorkers[workerId];

                    // 只处理由当前实例创建的工作标签页
                    if (workerInfo.instanceId !== Config.INSTANCE_ID) continue;

                    if (now - workerInfo.startTime > STALL_TIMEOUT) {
                        stalledWorkers.push({
                            workerId,
                            task: workerInfo.task
                        });
                    }
                }

                // 如果有超时的工作标签页,处理它们
                if (stalledWorkers.length > 0) {
                    Utils.logger('warn', `发现 ${stalledWorkers.length} 个超时的工作标签页,正在清理...`);

                    // 逐个处理超时的工作标签页
                    for (const stalledWorker of stalledWorkers) {
                        const { workerId, task } = stalledWorker;

                        Utils.logger('error', `🚨 WATCHDOG: Worker [${workerId.substring(0,12)}] has stalled!`);

                        // 1. Remove from To-Do
                        State.db.todo = State.db.todo.filter(t => t.uid !== task.uid);
                        await Database.saveTodo();

                        // 2. Add to Failed
                        if (!State.db.failed.some(f => f.uid === task.uid)) {
                            State.db.failed.push(task);
                            await Database.saveFailed();
                        }
                        State.executionFailedTasks++;

                        // 3. Clean up worker
                        delete State.runningWorkers[workerId];
                        State.activeWorkers--;

                        // 删除任务数据
                        await GM_deleteValue(workerId);
                    }

                    Utils.logger('info', `已清理 ${stalledWorkers.length} 个超时的工作标签页。剩余活动工作标签页: ${State.activeWorkers}`);

                    // 4. Update UI
                    UI.update();

                    // 5. 延迟一段时间后继续派发任务
                    setTimeout(() => {
                        if (State.isExecuting && State.activeWorkers < Config.MAX_CONCURRENT_WORKERS && State.db.todo.length > 0) {
                        TaskRunner.executeBatch();
                    }
                    }, 2000);
                }
            }, 5000); // Check every 5 seconds
        },

        executeBatch: async () => {
            // 检查账号状态
            if (!Utils.checkAuthentication()) {
                return;
            }
            
            // 只有主页面才需要检查是否是活跃实例
            if (!State.isWorkerTab && !InstanceManager.isActive) {
                Utils.logger('warn', '当前实例不是活跃实例,不执行任务。');
                return;
            }

            if (!State.isExecuting) return;

            // 防止重复执行
            if (State.isDispatchingTasks) {
                Utils.logger('info', '正在派发任务中,请稍候...');
                return;
            }

            // 设置派发任务标志
            State.isDispatchingTasks = true;

            try {
            // Stop condition for the entire execution process
            if (State.db.todo.length === 0 && State.activeWorkers === 0) {
                Utils.logger('info', '✅ 🎉 All tasks have been completed!');
                State.isExecuting = false;
                    // 保存执行状态
                    Database.saveExecutingState();
                    // 保存待办列表(虽然为空,但仍需保存以更新存储)
                    Database.saveTodo();
                if (State.watchdogTimer) {
                    clearInterval(State.watchdogTimer);
                    State.watchdogTimer = null;
                }

                    // 关闭所有可能残留的工作标签页
                    TaskRunner.closeAllWorkerTabs();

                UI.update();
                    State.isDispatchingTasks = false;
                    return;
                }

                // 如果处于限速状态,记录日志但继续执行任务
                if (State.appStatus === 'RATE_LIMITED') {
                    Utils.logger('info', '当前处于限速状态,但仍将继续执行待办任务...');
                }

                // 限制最大活动工作标签页数量
                if (State.activeWorkers >= Config.MAX_CONCURRENT_WORKERS) {
                    Utils.logger('info', `已达到最大并发工作标签页数量 (${Config.MAX_CONCURRENT_WORKERS}),等待现有任务完成...`);
                    State.isDispatchingTasks = false;
                return;
            }

            // --- DISPATCHER FOR DETAIL TASKS ---
                // 创建一个当前正在执行的任务UID集合,用于防止重复派发
                const inFlightUIDs = new Set(Object.values(State.runningWorkers).map(w => w.task.uid));

                // 创建一个副本,避免在迭代过程中修改原数组
                const todoList = [...State.db.todo];
                let dispatchedCount = 0;

                // 创建一个集合,记录本次派发的任务UID
                const dispatchedUIDs = new Set();

                for (const task of todoList) {
                    if (State.activeWorkers >= Config.MAX_CONCURRENT_WORKERS) break;

                    // 如果任务已经在执行中,跳过
                    if (inFlightUIDs.has(task.uid) || dispatchedUIDs.has(task.uid)) {
                        Utils.logger('info', `任务 ${task.name} 已在执行中,跳过。`);
                        continue;
                    }

                    // 如果任务已经在完成列表中,从待办列表移除并跳过
                    if (Database.isDone(task.url)) {
                        Utils.logger('info', `任务 ${task.name} 已完成,从待办列表中移除。`);
                        State.db.todo = State.db.todo.filter(t => t.uid !== task.uid);
                        Database.saveTodo();
                        continue;
                    }

                    // 记录本次派发的任务
                    dispatchedUIDs.add(task.uid);

                State.activeWorkers++;
                    dispatchedCount++;
                const workerId = `worker_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
                    State.runningWorkers[workerId] = {
                        task,
                        startTime: Date.now(),
                        instanceId: Config.INSTANCE_ID // 记录创建此工作标签页的实例ID
                    };

                Utils.logger('info', `🚀 Dispatching Worker [${workerId.substring(0, 12)}...] for: ${task.name}`);

                    await GM_setValue(workerId, {
                        task,
                        instanceId: Config.INSTANCE_ID // 在任务数据中也记录实例ID
                    });

                const workerUrl = new URL(task.url);
                workerUrl.searchParams.set('workerId', workerId);

                    // 使用active:false确保标签页在后台打开,并使用insert:true确保标签页在当前标签页之后打开
                    GM_openInTab(workerUrl.href, { active: false, insert: true });

                    // 等待一小段时间再派发下一个任务,避免浏览器同时打开太多标签页
                    await new Promise(resolve => setTimeout(resolve, 500));
                }

                if (dispatchedCount > 0) {
                    Utils.logger('info', `本批次派发了 ${dispatchedCount} 个任务。`);
                }

                if (!State.watchdogTimer && State.activeWorkers > 0) {
                    TaskRunner.runWatchdog();
                }

            UI.update();
            } finally {
                // 无论如何都要重置派发任务标志
                State.isDispatchingTasks = false;
            }
        },

        // 添加一个方法来关闭所有工作标签页
        closeAllWorkerTabs: () => {
            // 目前没有直接的方法可以关闭由GM_openInTab打开的标签页
            // 但我们可以清理相关的状态
            const workerIds = Object.keys(State.runningWorkers);
            if (workerIds.length > 0) {
                Utils.logger('info', `正在清理 ${workerIds.length} 个工作标签页的状态...`);

                for (const workerId of workerIds) {
                    GM_deleteValue(workerId);
                }

                State.runningWorkers = {};
                State.activeWorkers = 0;
                Utils.logger('info', '已清理所有工作标签页的状态。');
            }
        },

        processDetailPage: async () => {
            // 检查账号状态
            if (!Utils.checkAuthentication()) {
                return;
            }
            
            const urlParams = new URLSearchParams(window.location.search);
            const workerId = urlParams.get('workerId');

            // If there's no workerId, this is not a worker tab, so we do nothing.
            if (!workerId) return;

            // 标记当前标签页为工作标签页,避免执行主脚本逻辑
            State.isWorkerTab = true;
            State.workerTaskId = workerId;

            // 记录工作标签页的启动时间
            const startTime = Date.now();
            let hasReported = false;
            let closeAttempted = false;

            // 设置一个定时器,确保工作标签页最终会关闭
            const forceCloseTimer = setTimeout(() => {
                if (!closeAttempted) {
                    console.log('强制关闭工作标签页');
                    try {
                        window.close();
                    } catch (e) {
                        console.error('关闭工作标签页失败:', e);
                    }
                }
            }, 60000); // 60秒后强制关闭

            try {
                // This is a safety check. If the main tab stops execution, it might delete the task.
                const payload = await GM_getValue(workerId);
                if (!payload || !payload.task) {
                    Utils.logger('info', '任务数据已被清理,工作标签页将关闭。');
                    closeWorkerTab();
                    return;
                }

                // 检查创建此工作标签页的实例ID是否与当前活跃实例一致
                const activeInstance = await GM_getValue('fab_active_instance', null);
                if (activeInstance && activeInstance.id !== payload.instanceId) {
                    Utils.logger('warn', `此工作标签页由实例 [${payload.instanceId}] 创建,但当前活跃实例是 [${activeInstance.id}]。将关闭此标签页。`);
                    await GM_deleteValue(workerId); // 清理任务数据
                    closeWorkerTab();
                    return;
                }

                const currentTask = payload.task;
                const logBuffer = [`[${workerId.substring(0, 12)}] Started: ${currentTask.name}`];
                let success = false;

                try {
                    // 等待页面加载完成
                    await new Promise(resolve => setTimeout(resolve, 3000));

                    // 执行页面状态诊断
                    logBuffer.push(`=== 页面状态诊断开始 ===`);
                    const diagnosticReport = PageDiagnostics.diagnoseDetailPage();

                    // 记录关键信息到日志缓冲区
                    logBuffer.push(`页面标题: ${diagnosticReport.pageTitle}`);
                    logBuffer.push(`可见按钮数量: ${diagnosticReport.buttons.filter(btn => btn.isVisible).length}`);

                    // 记录所有可见按钮
                    diagnosticReport.buttons.forEach(btn => {
                        if (btn.isVisible) {
                            logBuffer.push(`按钮: "${btn.text}" (禁用: ${btn.isDisabled})`);
                        }
                    });

                    // 记录价格信息
                    Object.entries(diagnosticReport.priceInfo).forEach(([, price]) => {
                        if (price.isVisible) {
                            logBuffer.push(`价格显示: "${price.text}"`);
                        }
                    });

                    // 记录许可选项
                    diagnosticReport.licenseOptions.forEach(opt => {
                        if (opt.isVisible) {
                            logBuffer.push(`许可选项: "${opt.text}"`);
                        }
                    });

                    logBuffer.push(`=== 页面状态诊断结束 ===`);
                    // API-First Ownership Check...
                    try {
                        const csrfToken = Utils.getCookie('fab_csrftoken');
                        if (!csrfToken) {
                            Utils.checkAuthentication();
                            throw new Error("CSRF token not found for API check.");
                        }
                        const statesUrl = new URL('https://www.fab.com/i/users/me/listings-states');
                        statesUrl.searchParams.append('listing_ids', currentTask.uid);
                        const response = await API.gmFetch({
                            method: 'GET',
                            url: statesUrl.href,
                            headers: { 'x-csrftoken': csrfToken, 'x-requested-with': 'XMLHttpRequest' }
                        });

                        let statesData;
                        try {
                            statesData = JSON.parse(response.responseText);
                            if (!Array.isArray(statesData)) {
                                logBuffer.push('API返回的数据不是数组格式,这可能是API变更导致的');
                                // 尝试提取数组数据
                                statesData = API.extractStateData(statesData, 'SingleItemCheck');
                            }
                        } catch (e) {
                            logBuffer.push(`解析API响应失败: ${e.message}`);
                            statesData = [];
                        }

                        const isOwned = Array.isArray(statesData) && statesData.some(s => s && s.uid === currentTask.uid && s.acquired);
                        if (isOwned) {
                            logBuffer.push(`API check confirms item is already owned.`);
                            success = true;
                        } else {
                            logBuffer.push(`API check confirms item is not owned. Proceeding to UI interaction.`);
                        }
                    } catch (apiError) {
                        logBuffer.push(`API ownership check failed: ${apiError.message}. Falling back to UI-based check.`);
                    }

                    if (!success) {
                        try {
                            const isItemOwned = () => {
                                const criteria = Config.OWNED_SUCCESS_CRITERIA;
                                const snackbar = document.querySelector('.fabkit-Snackbar-root, div[class*="Toast-root"]');
                                if (snackbar && criteria.snackbarText.some(text => snackbar.textContent.includes(text))) return { owned: true, reason: `Snackbar text "${snackbar.textContent}"` };
                                const successHeader = document.querySelector('h2');
                                if (successHeader && criteria.h2Text.some(text => successHeader.textContent.includes(text))) return { owned: true, reason: `H2 text "${successHeader.textContent}"` };
                                const allButtons = [...document.querySelectorAll('button, a.fabkit-Button-root')];
                                const ownedButton = allButtons.find(btn => criteria.buttonTexts.some(keyword => btn.textContent.includes(keyword)));
                                if (ownedButton) return { owned: true, reason: `Button text "${ownedButton.textContent}"` };
                                return { owned: false };
                            };

                            const initialState = isItemOwned();
                            if (initialState.owned) {
                                logBuffer.push(`Item already owned on page load (UI Fallback PASS: ${initialState.reason}).`);
                                success = true;
                            } else {
                                // 检查是否需要选择许可证
                                const licenseButton = [...document.querySelectorAll('button')].find(btn =>
                                    btn.textContent.includes('选择许可') ||
                                    btn.textContent.includes('Select license')
                                );

                                if (licenseButton) {
                                    logBuffer.push(`Multi-license item detected. Setting up observer for dropdown.`);
                                    try {
                                        await new Promise((resolve, reject) => {
                                            const observer = new MutationObserver((mutationsList) => {
                                                for (const mutation of mutationsList) {
                                                    if (mutation.addedNodes.length > 0) {
                                                        for (const node of mutation.addedNodes) {
                                                            if (node.nodeType !== 1) continue;
                                                            // 查找"免费"或"个人"选项
                                                            const freeTextElement = Array.from(node.querySelectorAll('span, div')).find(el =>
                                                                Array.from(el.childNodes).some(cn => {
                                                                    if (cn.nodeType !== 3) return false;
                                                                    const text = cn.textContent.trim();
                                                                    return [...Config.FREE_TEXT_SET].some(freeWord => text === freeWord) ||
                                                                           text === '个人' || text === 'Personal';
                                                                })
                                                            );

                                                            if (freeTextElement) {
                                                                const clickableParent = freeTextElement.closest('[role="option"], button, label, input[type="radio"]');
                                                                if (clickableParent) {
                                                                    logBuffer.push(`Found free/personal license option, clicking it.`);
                                                                    Utils.deepClick(clickableParent);
                                                                    observer.disconnect();
                                                                    resolve();
                                                                    return;
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            });

                                            observer.observe(document.body, { childList: true, subtree: true });
                                            logBuffer.push(`Clicking license button to open dropdown.`);
                                            Utils.deepClick(licenseButton); // First click attempt

                                            // 有时第一次点击可能不成功,1.5秒后再试一次
                                            setTimeout(() => {
                                                logBuffer.push(`Second attempt to click license button.`);
                                                Utils.deepClick(licenseButton);
                                            }, 1500);

                                            // 如果5秒内没有出现下拉菜单,则超时
                                            setTimeout(() => {
                                                observer.disconnect();
                                                reject(new Error('Timeout (5s): The free/personal option did not appear.'));
                                            }, 5000);
                                        });

                                        // 许可选择后等待UI更新
                                        logBuffer.push(`License selected, waiting for UI update.`);
                                        await new Promise(r => setTimeout(r, 1000));

                                        // 重新检查是否已拥有
                                        if (isItemOwned().owned) {
                                            logBuffer.push(`Item became owned after license selection.`);
                                            success = true;
                                        }
                                    } catch (licenseError) {
                                        logBuffer.push(`License selection failed: ${licenseError.message}`);
                                    }
                                }

                                // 如果许可选择后仍未成功,或者不需要选择许可,尝试点击添加按钮
                                if (!success) {
                                    // 首先尝试找标准的添加按钮
                                    let actionButton = [...document.querySelectorAll('button')].find(btn =>
                                        [...Config.ACQUISITION_TEXT_SET].some(keyword => btn.textContent.includes(keyword))
                                    );

                                    // 如果没有标准添加按钮,检查是否是限时免费商品
                                    if (!actionButton) {
                                        // 查找包含"免费/Free"和"-100%"的按钮(限时免费商品的许可按钮)
                                        actionButton = [...document.querySelectorAll('button')].find(btn => {
                                            const text = btn.textContent;
                                            const hasFreeText = [...Config.FREE_TEXT_SET].some(freeWord => text.includes(freeWord));
                                            const hasDiscount = text.includes('-100%');
                                            const hasPersonal = text.includes('个人') || text.includes('Personal');
                                            return hasFreeText && hasDiscount && hasPersonal;
                                        });

                                        if (actionButton) {
                                            logBuffer.push(`Found limited-time free license button: "${actionButton.textContent.trim()}"`);
                                        }
                                    }

                                    if (actionButton) {
                                        logBuffer.push(`Found add button, clicking it.`);
                                        Utils.deepClick(actionButton);

                                        // 等待添加操作完成
                                        try {
                                            await new Promise((resolve, reject) => {
                                                const timeout = 25000; // 25秒超时
                                                const interval = setInterval(() => {
                                                    const currentState = isItemOwned();
                                                    if (currentState.owned) {
                                                        logBuffer.push(`Item became owned after clicking add button: ${currentState.reason}`);
                                                        success = true;
                                                        clearInterval(interval);
                                                        resolve();
                                                    }
                                                }, 500); // 每500ms检查一次

                                                setTimeout(() => {
                                                    clearInterval(interval);
                                                    reject(new Error(`Timeout waiting for page to enter an 'owned' state.`));
                                                }, timeout);
                                            });
                                        } catch (timeoutError) {
                                            logBuffer.push(`Timeout waiting for ownership: ${timeoutError.message}`);
                                        }
                                    } else {
                                        logBuffer.push(`Could not find an add button.`);
                                    }
                                }
                            }
                        } catch (uiError) {
                            logBuffer.push(`UI interaction failed: ${uiError.message}`);
                        }
                    }
                } catch (error) {
                    logBuffer.push(`A critical error occurred: ${error.message}`);
                    success = false;
                } finally {
                    try {
                        // 标记为已报告
                        hasReported = true;

                        // 报告任务结果
                        await GM_setValue(Config.DB_KEYS.WORKER_DONE, {
                            workerId: workerId,
                            success: success,
                            logs: logBuffer,
                            task: currentTask,
                            instanceId: payload.instanceId,
                            executionTime: Date.now() - startTime
                        });
                    } catch (error) {
                        console.error('Error setting worker done value:', error);
                    }

                    try {
                        await GM_deleteValue(workerId); // 清理任务数据
                    } catch (error) {
                        console.error('Error deleting worker value:', error);
                    }

                    // 确保工作标签页在报告完成后关闭
                    closeWorkerTab();
                }
            } catch (error) {
                Utils.logger('error', `Worker tab error: ${error.message}`);
                closeWorkerTab();
            }

            // 关闭工作标签页的函数
            function closeWorkerTab() {
                closeAttempted = true;
                clearTimeout(forceCloseTimer);

                // 如果尚未报告结果,尝试报告失败
                if (!hasReported && workerId) {
                    try {
                        GM_setValue(Config.DB_KEYS.WORKER_DONE, {
                            workerId: workerId,
                            success: false,
                            logs: [Utils.getText('worker_closed')],
                            task: payload?.task,
                            instanceId: payload?.instanceId,
                            executionTime: Date.now() - startTime
                        });
                    } catch (e) {
                        // 忽略错误
                    }
                }

                try {
                    window.close();
                } catch (error) {
                    Utils.logger('error', `关闭工作标签页失败: ${error.message}`);
                    // 如果关闭失败,尝试其他方法
                    try {
                        window.location.href = 'about:blank';
                    } catch (e) {
                        Utils.logger('error', `重定向失败: ${e.message}`);
                    }
                }
            }
        },

        // 删除这个未使用的函数
        // This function is now fully obsolete.
        // advanceDetailTask: async () => {},

            runHideOrShow: () => {
        // 无论是否在限速状态下,都应该执行隐藏功能
        State.hiddenThisPageCount = 0;
        const cards = document.querySelectorAll(Config.SELECTORS.card);

        // 添加一个计数器,用于跟踪实际隐藏的卡片数量
        let actuallyHidden = 0;

        // 首先检查是否有未加载完成的卡片
        let hasUnsettledCards = false;
        const unsettledCards = [];

        // 检查卡片是否已加载完成的函数
        const isCardSettled = (card) => {
            // 检查卡片是否有价格、免费标签或已拥有标签
            return card.querySelector(`${Config.SELECTORS.freeStatus}, ${Config.SELECTORS.ownedStatus}`) !== null;
        };

        // 检查是否有未加载完成的卡片
        cards.forEach(card => {
            if (!isCardSettled(card)) {
                hasUnsettledCards = true;
                unsettledCards.push(card);
            }
        });

        // 如果有未加载完成的卡片,延迟执行隐藏操作
        if (hasUnsettledCards && unsettledCards.length > 0) {
            Utils.logger('info', `检测到 ${unsettledCards.length} 张卡片尚未加载完成,延迟隐藏操作...`);

            // 设置一个较长的延迟,等待卡片加载完成
            setTimeout(() => {
                Utils.logger('info', `延迟后重新执行隐藏操作,确保卡片已加载完成`);
                TaskRunner.runHideOrShow();
            }, 2000); // 延迟2秒

            return; // 直接返回,等待下次执行
        }

        // 首先收集所有需要隐藏的卡片
        const cardsToHide = [];

        // 添加一个数据属性来标记已处理的卡片,避免重复处理
        cards.forEach(card => {
            // 检查卡片是否已经被处理过
            const isProcessed = card.getAttribute('data-fab-processed') === 'true';

            // 如果卡片已经被处理且已经隐藏,则不需要再次处理
            if (isProcessed && card.style.display === 'none') {
                State.hiddenThisPageCount++;
                return;
            }

            const isFinished = TaskRunner.isCardFinished(card);
            if (State.hideSaved && isFinished) {
                cardsToHide.push(card);
                State.hiddenThisPageCount++;

                // 标记卡片为已处理
                card.setAttribute('data-fab-processed', 'true');
            } else {
                // 如果不需要隐藏,也标记为已处理
                card.setAttribute('data-fab-processed', 'true');
            }
        });

        // 如果有需要隐藏的卡片,使用更长的初始延迟和更慢的隐藏速度
        if (cardsToHide.length > 0) {
            if (State.debugMode) {
                Utils.logger('debug', Utils.getText('debug_prepare_hide', cardsToHide.length));
            }

            // 随机打乱卡片顺序,使隐藏更加随机
            cardsToHide.sort(() => Math.random() - 0.5);

            // 分批次隐藏卡片,每批次最多10张(减少批次大小)
            const batchSize = 10;
            const batches = Math.ceil(cardsToHide.length / batchSize);

            // 设置一个初始延迟,确保页面有足够时间加载
            const initialDelay = 1000; // 1秒的初始延迟

            for (let i = 0; i < batches; i++) {
                const start = i * batchSize;
                const end = Math.min(start + batchSize, cardsToHide.length);
                const currentBatch = cardsToHide.slice(start, end);

                // 为每个批次设置一个更长的延迟,增加延迟时间
                const batchDelay = initialDelay + i * 300 + Math.random() * 300;

                setTimeout(() => {
                    currentBatch.forEach((card, index) => {
                        // 为每张卡片设置一个更长的随机延迟
                        const cardDelay = index * 50 + Math.random() * 100;

                        setTimeout(() => {
                            card.style.display = 'none';
                            actuallyHidden++;

                            // 当所有卡片都隐藏后,更新UI
                            if (actuallyHidden === cardsToHide.length) {
                                if (State.debugMode) {
                                    Utils.logger('debug', Utils.getText('debug_hide_completed', actuallyHidden));
                                }
                                // 延迟更新UI,确保DOM已经完全更新
                                setTimeout(() => {
                                    UI.update();
                                    // 隐藏完成后检查可见性并决定是否刷新
                                    TaskRunner.checkVisibilityAndRefresh();
                                }, 300);
                            }
                        }, cardDelay);
                    });
                }, batchDelay);
            }
        }

        // 确保所有不应该隐藏的卡片都是可见的
        if (State.hideSaved) {
            // 找出所有不应该隐藏的卡片
            const visibleCards = Array.from(cards).filter(card => {
                // 不隐藏未完成的卡片
                return !TaskRunner.isCardFinished(card);
            });

            // 显示这些卡片(如果它们之前被隐藏了)
            visibleCards.forEach(card => {
                card.style.display = '';
            });

            // 只有在没有需要隐藏的卡片时才立即更新UI和检查可见性
            if (cardsToHide.length === 0) {
                UI.update();
                TaskRunner.checkVisibilityAndRefresh();
            }
        } else {
            // 如果没有隐藏功能,正常显示所有卡片并更新UI
            cards.forEach(card => {
                card.style.display = '';
            });
            UI.update();
        }
    },

    // 新增:检查可见性并决定是否刷新的方法
    checkVisibilityAndRefresh: () => {
        // 计算实际可见的商品数量
        const cards = document.querySelectorAll(Config.SELECTORS.card);

        // 重新检查所有卡片,确保隐藏状态正确
        let needsReprocessing = false;
        cards.forEach(card => {
            const isProcessed = card.getAttribute('data-fab-processed') === 'true';
            if (!isProcessed) {
                needsReprocessing = true;
            }
        });

        // 如果发现未处理的卡片,重新执行隐藏逻辑
        if (needsReprocessing) {
            if (State.debugMode) {
                Utils.logger('debug', Utils.getText('debug_unprocessed_cards_simple'));
            }
            setTimeout(() => {
                TaskRunner.runHideOrShow();
            }, 100);
            return;
        }

        // 使用更准确的方式检查元素是否可见
        const visibleCards = Array.from(cards).filter(card => {
            // 检查元素自身的display属性
            if (card.style.display === 'none') return false;

            // 检查是否被CSS规则隐藏
            const computedStyle = window.getComputedStyle(card);
            return computedStyle.display !== 'none' && computedStyle.visibility !== 'hidden';
        }).length;

        // 更新真实的可见商品数量
        if (State.debugMode) {
            Utils.logger('debug', Utils.getText('debug_visible_after_hide', visibleCards, State.hiddenThisPageCount));
        }

        // 更新UI上显示的可见商品数
        const visibleCountElement = document.getElementById('fab-status-visible');
        if (visibleCountElement) {
            visibleCountElement.textContent = visibleCards.toString();
        }

        if (visibleCards === 0) {
            // 无可见商品,根据状态决定是否刷新
            if (State.appStatus === 'RATE_LIMITED' && State.autoRefreshEmptyPage) {
                // 如果已经安排了刷新,不要重复安排
                if (State.isRefreshScheduled) {
                    Utils.logger('info', Utils.getText('refresh_plan_exists').replace('(429自动恢复)', '(无商品可见)'));
                    return;
                }

                Utils.logger('info', '🔄 所有商品都已隐藏且处于限速状态,将在2秒后刷新页面...');

                // 标记已安排刷新
                State.isRefreshScheduled = true;

                setTimeout(() => {
                    // 再次检查实际可见的商品数量
                    const currentVisibleCards = Array.from(document.querySelectorAll(Config.SELECTORS.card))
                        .filter(card => card.style.display !== 'none').length;

                    // 检查是否有待办任务或活动工作线程
                    if (State.db.todo.length > 0 || State.activeWorkers > 0) {
                        Utils.logger('info', `⏹️ 刷新取消,检测到 ${State.db.todo.length} 个待办任务和 ${State.activeWorkers} 个活动工作线程`);
                        State.isRefreshScheduled = false; // 重置刷新标记
                        return;
                    }

                    if (currentVisibleCards === 0 && State.appStatus === 'RATE_LIMITED' && State.autoRefreshEmptyPage) {
                        Utils.logger('info', '🔄 执行刷新...');
                        // 使用更可靠的刷新方式
                        window.location.href = window.location.href;
                    } else {
                        Utils.logger('info', `⏹️ 刷新取消,检测到 ${currentVisibleCards} 个可见商品`);
                        State.isRefreshScheduled = false; // 重置刷新标记
                    }
                }, 2000);
            } else if (State.appStatus === 'NORMAL' && State.hiddenThisPageCount > 0) {
                // 正常状态下也没有可见商品,可能是全部隐藏了
                // 只记录日志,不提示刷新,也不执行刷新
                Utils.logger('info', Utils.getText('page_status_hidden_no_visible', State.hiddenThisPageCount));
            }
        }
    },

        // 添加一个方法来检查并确保待办任务被执行
        ensureTasksAreExecuted: () => {
            // 如果没有待办任务,不需要执行
            if (State.db.todo.length === 0) return;

            // 如果已经在执行中,不需要重新启动
            if (State.isExecuting) {
                // 如果有待办任务但没有活动工作线程,可能是执行卡住了,尝试重新执行
                if (State.activeWorkers === 0) {
                    Utils.logger('info', '检测到有待办任务但没有活动工作线程,尝试重新执行...');
                    TaskRunner.executeBatch();
                }
                return;
            }

            // 如果有待办任务但没有执行,自动开始执行
            Utils.logger('info', `检测到有 ${State.db.todo.length} 个待办任务但未执行,自动开始执行...`);
            TaskRunner.startExecution();
        },

        // 添加一个方法来批量检查当前页面上所有可见卡片的状态
        checkVisibleCardsStatus: async () => {
            try {
                // 获取所有可见卡片
                const visibleCards = [...document.querySelectorAll(Config.SELECTORS.card)];

                // 如果没有可见卡片,直接返回
                if (visibleCards.length === 0) {
                    Utils.logger('info', '[Fab DOM Refresh] 没有可见的卡片需要刷新');
                    return;
                }

                // 首先检查是否有未加载完成的卡片
                let hasUnsettledCards = false;
                const unsettledCards = [];

                // 检查卡片是否已加载完成的函数
                const isCardSettled = (card) => {
                    // 检查卡片是否有价格、免费标签或已拥有标签
                    return card.querySelector(`${Config.SELECTORS.freeStatus}, ${Config.SELECTORS.ownedStatus}`) !== null;
                };

                // 检查是否有未加载完成的卡片
                visibleCards.forEach(card => {
                    if (!isCardSettled(card)) {
                        hasUnsettledCards = true;
                        unsettledCards.push(card);
                    }
                });

                // 如果有未加载完成的卡片,等待一段时间后再检查
                if (hasUnsettledCards && unsettledCards.length > 0) {
                    Utils.logger('info', `[Fab DOM Refresh] 检测到 ${unsettledCards.length} 张卡片尚未加载完成,等待加载...`);

                    // 等待一段时间后再次检查
                    await new Promise(resolve => setTimeout(resolve, 3000));

                    // 重新获取所有可见卡片
                    return TaskRunner.checkVisibleCardsStatus();
                }

                // 提取卡片的UID和DOM元素
                const allItems = [];
                let confirmedOwned = 0;

                visibleCards.forEach(card => {
                    const link = card.querySelector(Config.SELECTORS.cardLink);
                    const uidMatch = link?.href.match(/listings\/([a-f0-9-]+)/);

                    if (uidMatch && uidMatch[1]) {
                        const uid = uidMatch[1];
                        const url = link.href.split('?')[0]; // 移除查询参数

                        // 检查是否已经在已完成列表中
                        if (State.db.done.includes(url)) {
                            // 已经知道是已拥有的,不需要再次检查
                            return;
                        }

                        allItems.push({ uid, url, element: card });
                    }
                });

                // 如果没有需要检查的项目,直接返回
                if (allItems.length === 0) {
                    Utils.logger('debug', `[Fab DOM Refresh] ${Utils.getText('debug_no_cards_to_check')}`);
                    return;
                }

                Utils.logger('info', `[Fab DOM Refresh] ${Utils.getText('fab_dom_checking_status', allItems.length)}`);

                // 提取所有需要检查的商品ID
                const uids = allItems.map(item => item.uid);

                // 使用优化后的API函数检查拥有状态
                const statesData = await API.checkItemsOwnership(uids);

                // 创建已拥有商品ID的集合,便于快速查找
                const ownedUids = new Set(
                    statesData
                        .filter(state => state && state.acquired)
                        .map(state => state.uid)
                );

                // 处理结果
                for (const item of allItems) {
                    if (ownedUids.has(item.uid)) {
                        // 如果不在已完成列表中,添加
                        if (!State.db.done.includes(item.url)) {
                            State.db.done.push(item.url);
                            confirmedOwned++;

                            // 不再手动添加"已保存"标记,网页会自动更新
                        }

                        // 从失败列表中移除
                        State.db.failed = State.db.failed.filter(f => f.uid !== item.uid);

                        // 从待办列表中移除
                        State.db.todo = State.db.todo.filter(t => t.uid !== item.uid);
                    }
                }

                // 保存更改
                if (confirmedOwned > 0) {
                    await Database.saveDone();
                    await Database.saveFailed();
                    Utils.logger('info', `[Fab DOM Refresh] ${Utils.getText('fab_dom_api_complete', confirmedOwned)}`);

                    // 不立即执行隐藏,而是在调用方决定何时执行
                    Utils.logger('info', `[Fab DOM Refresh] Complete. Updated ${confirmedOwned} visible card states.`);
                } else {
                    Utils.logger('info', Utils.getText('fab_dom_no_new_owned'));
                }
            } catch (error) {
                Utils.logger('error', `[Fab DOM Refresh] 检查项目状态时出错: ${error.message}`);

                // 如果是429错误,进入限速状态并退出
                if (error.message && error.message.includes('429')) {
                    RateLimitManager.enterRateLimitedState('[Fab DOM Refresh] 429错误');
                }
            }
        },

                scanAndAddTasks: async (cards) => {
            // This function should ONLY ever run if auto-add is enabled.
            if (!State.autoAddOnScroll) return;

            // 创建一个状态追踪对象
            if (!window._apiWaitStatus) {
                window._apiWaitStatus = {
                    isWaiting: false,
                    pendingCards: [],
                    lastApiActivity: 0,
                    apiCheckInterval: null
                };
            }

            // 如果已经有等待过程在进行,将当前卡片加入队列
            if (window._apiWaitStatus.isWaiting) {
                window._apiWaitStatus.pendingCards = [...window._apiWaitStatus.pendingCards, ...cards];
                Utils.logger('info', `[${Utils.getText('log_tag_auto_add')}] ${Utils.getText('debug_api_wait_in_progress', cards.length)}`);
                return;
            }

            // 标记开始等待API
            window._apiWaitStatus.isWaiting = true;
            window._apiWaitStatus.pendingCards = [...cards];
            window._apiWaitStatus.lastApiActivity = Date.now();

            if (State.debugMode) {
                Utils.logger('debug', `[${Utils.getText('log_tag_auto_add')}] ${Utils.getText('debug_wait_api_response', cards.length)}`);
            }

            // 创建一个函数来检测API活动
            const waitForApiCompletion = () => {
                return new Promise((resolve) => {
                    // 清除之前的检查间隔
                    if (window._apiWaitStatus.apiCheckInterval) {
                        clearInterval(window._apiWaitStatus.apiCheckInterval);
                    }

                    // 设置一个最大等待时间(10秒)
                    const maxWaitTime = 10000;
                    const startTime = Date.now();

                    // 监听网络请求
                    const originalFetch = window.fetch;
                    window.fetch = function(...args) {
                        // 只关注商品状态相关的API请求
                        const url = args[0]?.toString() || '';
                        if (url.includes('/listings-states') || url.includes('/listings/search')) {
                            window._apiWaitStatus.lastApiActivity = Date.now();
                            Utils.logger('debug', `[API监控] 检测到API活动: ${url.substring(0, 50)}...`);
                        }
                        return originalFetch.apply(this, args);
                    };

                    // 检查API活动的间隔
                    window._apiWaitStatus.apiCheckInterval = setInterval(() => {
                        const now = Date.now();
                        const timeSinceLastActivity = now - window._apiWaitStatus.lastApiActivity;
                        const totalWaitTime = now - startTime;

                        // 如果超过最大等待时间,或者API活动停止超过2秒,则认为API已完成
                        if (totalWaitTime > maxWaitTime || timeSinceLastActivity > 2000) {
                            clearInterval(window._apiWaitStatus.apiCheckInterval);

                            // 恢复原始的fetch函数
                            window.fetch = originalFetch;

                            if (totalWaitTime > maxWaitTime) {
                                Utils.logger('warn', `[${Utils.getText('log_tag_auto_add')}] ${Utils.getText('auto_add_api_timeout', totalWaitTime)}`);
                            } else {
                                Utils.logger('debug', `[${Utils.getText('log_tag_auto_add')}] ${Utils.getText('debug_api_stopped', timeSinceLastActivity)}`);
                            }

                            resolve();
                        }
                    }, 200); // 每200ms检查一次
                });
            };

            // 等待API完成
            try {
                await waitForApiCompletion();
            } catch (error) {
                Utils.logger('error', `[${Utils.getText('log_tag_auto_add')}] ${Utils.getText('auto_add_api_error', error.message)}`);
            }

            // 处理卡片
            const cardsToProcess = [...window._apiWaitStatus.pendingCards];
            window._apiWaitStatus.pendingCards = [];
            window._apiWaitStatus.isWaiting = false;

            if (State.debugMode) {
                Utils.logger('debug', `[${Utils.getText('log_tag_auto_add')}] ${Utils.getText('debug_api_wait_complete', cardsToProcess.length)}`);
            }

            // 现在处理卡片
            const newlyAddedList = [];
            let skippedAlreadyOwned = 0;
            let skippedInTodo = 0;

            cardsToProcess.forEach(card => {
                const link = card.querySelector(Config.SELECTORS.cardLink);
                const url = link ? link.href.split('?')[0] : null;
                if (!url) return;

                // 1. 检查是否已经入库或在待办列表中
                // 更严格的检查,确保已入库的商品不会被添加到待办列表

                // 检查URL是否在完成列表中
                if (Database.isDone(url)) {
                    skippedAlreadyOwned++;
                    return;
                }

                // 检查URL是否在待办列表中
                if (Database.isTodo(url)) {
                    skippedInTodo++;
                    return;
                }

                // 检查卡片是否有"已保存"标记
                const text = card.textContent || '';
                if (text.includes("已保存在我的库中") ||
                    text.includes("已保存") ||
                    text.includes("Saved to My Library") ||
                    text.includes("In your library")) {
                    skippedAlreadyOwned++;
                    return;
                }

                // 检查卡片是否有成功图标
                const icons = card.querySelectorAll('i.fabkit-Icon--intent-success, i.edsicon-check-circle-filled');
                if (icons.length > 0) {
                    skippedAlreadyOwned++;
                    return;
                }

                // 从链接中提取UID并检查缓存
                const uidMatch = url.match(/listings\/([a-f0-9-]+)/);
                if (uidMatch && uidMatch[1]) {
                    const uid = uidMatch[1];
                    // 检查缓存中是否标记为已拥有
                    if (DataCache.ownedStatus.has(uid)) {
                        const status = DataCache.ownedStatus.get(uid);
                        if (status && status.acquired) {
                            skippedAlreadyOwned++;
                            return;
                        }
                    }
                }

                // 2. Must be visibly "Free". This is the most critical filter.
                const isFree = card.querySelector(Config.SELECTORS.freeStatus) !== null;
                if (!isFree) {
                    return;
                }

                // If it passes all checks, it's a valid new task.
                const name = card.querySelector('a[aria-label*="创作的"], a[aria-label*="by "]')?.textContent.trim() || card.querySelector('a[href*="/listings/"]')?.textContent.trim() || Utils.getText('untitled');
                newlyAddedList.push({ name, url, type: 'detail', uid: url.split('/').pop() });
            });

            if (newlyAddedList.length > 0 || skippedAlreadyOwned > 0 || skippedInTodo > 0) {
                if (newlyAddedList.length > 0) {
                    State.db.todo.push(...newlyAddedList);
                    Utils.logger('info', `[${Utils.getText('log_tag_auto_add')}] ${Utils.getText('auto_add_new_tasks', newlyAddedList.length)}`);

                    // 保存待办列表到存储
                    Database.saveTodo();
                }

                // 添加详细的过滤信息日志
                if (skippedAlreadyOwned > 0 || skippedInTodo > 0) {
                    Utils.logger('debug', `[${Utils.getText('log_tag_auto_add')}] ${Utils.getText('debug_filter_owned', skippedAlreadyOwned, skippedInTodo)}`);
                }

                // 如果已经在执行,只更新总数
                if (State.isExecuting) {
                    State.executionTotalTasks = State.db.todo.length;
                    // 确保任务继续执行
                    TaskRunner.executeBatch();
                } else if (State.autoAddOnScroll) {
                    // 如果启用了自动添加但尚未开始执行,自动开始执行
                    TaskRunner.startExecution();
                }

                UI.update();
            }
        },

        async handleRateLimit(url) {
            // 使用统一的限速管理器进入限速状态
            await RateLimitManager.enterRateLimitedState(url || '网络请求');
        },

        reportTaskDone: async (task, success) => {
            try {
                // 报告任务完成
                await GM_setValue(Config.DB_KEYS.WORKER_DONE, {
                    workerId: `worker_task_${task.uid}`,
                    success: success,
                    logs: [`任务${success ? '成功' : '失败'}: ${task.name || task.uid}`],
                    task: task,
                    instanceId: Config.INSTANCE_ID,
                    executionTime: 0
                });
                Utils.logger('info', `工作标签页报告任务${success ? '成功' : '失败'}: ${task.name || task.uid}`);
            } catch (error) {
                Utils.logger('error', `报告任务状态时出错: ${error.message}`);
            }
        },

        toggleAutoRefreshEmpty: async () => {
            if (State.isTogglingSetting) return;
            State.isTogglingSetting = true;

            State.autoRefreshEmptyPage = !State.autoRefreshEmptyPage;
            await Database.saveAutoRefreshEmptyPref();
            Utils.logger('info', `无商品可见时自动刷新功能已${State.autoRefreshEmptyPage ? '开启' : '关闭'}。`);

            setTimeout(() => { State.isTogglingSetting = false; }, 200);
        },
    };


    // --- 模块八: 用户界面 (User Interface) ---
    const UI = {
        create: () => {
            // New, more robust rule: A detail page is identified by the presence of a main "acquisition" button,
            // not by its URL, which can be inconsistent.
            const acquisitionButton = [...document.querySelectorAll('button')].find(btn =>
                [...Config.ACQUISITION_TEXT_SET].some(keyword => btn.textContent.includes(keyword))
            );

            // The "Download" button is another strong signal.
            const downloadTexts = ['下载', 'Download'];
            const downloadButton = [...document.querySelectorAll('a[href*="/download/"], button')].find(btn =>
                downloadTexts.some(text => btn.textContent.includes(text))
            );

            if (acquisitionButton || downloadButton) {
                 const urlParams = new URLSearchParams(window.location.search);
                if (urlParams.has('workerId')) return false; // Explicitly return false for worker

                Utils.logger('info', "On a detail page (detected by action buttons), skipping UI creation.");
                return false; // Explicitly return false to halt further execution
            }

            if (document.getElementById(Config.UI_CONTAINER_ID)) return true; // Already created

            // --- Style Injection ---
            const styles = `
                :root {
                    --bg-color: rgba(28, 28, 30, 0.9);
                    --border-color: rgba(255, 255, 255, 0.15);
                    --text-color-primary: #f5f5f7;
                    --text-color-secondary: #a0a0a5;
                    --radius-l: 12px;
                    --radius-m: 8px;
                    --radius-s: 6px;
                    --blue: #007aff; --pink: #ff2d55; --green: #34c759;
                    --orange: #ff9500; --gray: #8e8e93; --dark-gray: #3a3a3c;
                    --blue-bg: rgba(0, 122, 255, 0.2);
                }
                #${Config.UI_CONTAINER_ID} {
                    position: fixed;
                    bottom: 20px;
                    right: 20px;
                    z-index: 9999;
                    background: var(--bg-color);
                    backdrop-filter: blur(15px) saturate(1.8);
                    -webkit-backdrop-filter: blur(15px) saturate(1.8);
                    border: 1px solid var(--border-color);
                    border-radius: var(--radius-l);
                    color: var(--text-color-primary);
                    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
                    width: 300px;
                    font-size: 14px;
                    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
                }
                /* FINAL FIX: Apply a robust box model to all elements within the container */
                #${Config.UI_CONTAINER_ID} *, #${Config.UI_CONTAINER_ID} *::before, #${Config.UI_CONTAINER_ID} *::after {
                    box-sizing: border-box;
                }
                .fab-helper-tabs {
                    display: flex;
                    border-bottom: 1px solid var(--border-color);
                }
                .fab-helper-tabs button {
                    flex: 1;
                    padding: 10px 0;
                    font-size: 14px;
                    font-weight: 500;
                    cursor: pointer;
                    background: transparent;
                    border: none;
                    color: var(--text-color-secondary);
                    transition: color 0.2s, border-bottom 0.2s;
                    border-bottom: 2px solid transparent;
                    /* --- FIX: Center align tab text --- */
                    display: flex;
                    justify-content: center;
                    align-items: center;
                }
                .fab-helper-tabs button.active {
                    color: var(--text-color-primary);
                    border-bottom: 2px solid var(--blue);
                }
                .fab-helper-tab-content {
                    padding: 12px;
                }
                .fab-helper-status-bar {
                    display: flex;
                    flex-wrap: wrap;
                    gap: 6px;
                    /* REMOVED: No longer needed at the bottom of the log */
                    /* margin-bottom: 12px; */
                }
                .fab-helper-status-item {
                    background: var(--dark-gray);
                    padding: 8px 6px;
                    border-radius: var(--radius-m);
                    font-size: 12px;
                    color: var(--text-color-secondary);
                    display: flex;
                    flex-direction: column;
                    justify-content: center;
                    align-items: center;
                    gap: 2px;
                    min-width: 0;
                    flex-grow: 1;
                    /* This formula is now correct thanks to box-sizing: border-box */
                    flex-basis: calc((100% - 12px) / 3); /* (100% width - 2*6px gap) / 3 columns */
                }
                .fab-helper-status-label {
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    gap: 4px;
                    white-space: nowrap;
                    /* REMOVED: No longer needed with a wrapping layout */
                }
                .fab-helper-status-item span {
                    display: block;
                    font-size: 18px;
                    font-weight: 600;
                    color: #fff;
                    margin-top: 0;
                }
                .fab-helper-execute-btn {
                    width: 100%;
                    border: none;
                    border-radius: var(--radius-m);
                    padding: 12px 14px;
                    font-size: 16px;
                    font-weight: 600;
                    cursor: pointer;
                    transition: all 0.2s ease;
                    color: #fff;
                    background: var(--blue);
                    margin-bottom: 12px;
                    /* --- FIX: Center align button content --- */
                    display: flex;
                    justify-content: center;
                    align-items: center;
                    gap: 8px; /* Add space between icon and text */
                }
                .fab-helper-execute-btn.executing {
                    background: var(--pink);
                }
                .fab-helper-actions {
                    display: flex;
                    gap: 8px;
                }
                .fab-helper-actions button {
                    flex: 1; /* RESTORED: Distribute space equally */
                    min-width: 0; /* ADDED BACK: Crucial for flex shrinking */
                    display: flex;
                    align-items: center;
                    justify-content: center;
                    gap: 5px;
                    background: var(--dark-gray);
                    border: none;
                    border-radius: var(--radius-m);
                    color: var(--text-color-primary);
                    padding: 8px 6px; /* CRITICAL FIX: Reduced horizontal padding */
                    cursor: pointer;
                    transition: background-color 0.2s;
                    white-space: nowrap;
                    font-size: 13.5px;
                    font-weight: normal;
                }
                .fab-helper-actions button:hover {
                    background: #4a4a4c;
                }
                .fab-log-container {
                    padding: 0 12px 12px 12px;
                    /* FIX: Swapped border and margin from top to bottom */
                    border-bottom: 1px solid var(--border-color);
                    margin-bottom: 12px;
                }
                .fab-log-header {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    margin-bottom: 8px;
                    margin-top: 8px;
                }
                .fab-log-header span {
                    font-size: 14px;
                    font-weight: 500;
                    color: var(--text-color-secondary);
                }
                .fab-log-controls button {
                    background: transparent;
                    border: none;
                    color: var(--text-color-secondary);
                    cursor: pointer;
                    padding: 4px;
                    font-size: 18px;
                    line-height: 1;
                }
                #${Config.UI_LOG_ID} {
                    background: rgba(10,10,10,0.85);
                    color: #ddd;
                    font-size: 11px;
                    line-height: 1.4;
                    padding: 8px;
                    border-radius: var(--radius-m);
                    max-height: 150px;
                    overflow-y: auto;
                    min-height: 50px;
                    display: flex;
                    flex-direction: column-reverse;
                    box-shadow: inset 0 1px 4px rgba(0,0,0,0.2);
                    scrollbar-width: thin;
                    scrollbar-color: rgba(255,255,255,0.3) rgba(0,0,0,0.2);
                }

                /* 自定义滚动条样式 */
                #${Config.UI_LOG_ID}::-webkit-scrollbar {
                    width: 8px;
                    height: 8px;
                }
                #${Config.UI_LOG_ID}::-webkit-scrollbar-track {
                    background: rgba(0,0,0,0.2);
                    border-radius: 4px;
                }
                #${Config.UI_LOG_ID}::-webkit-scrollbar-thumb {
                    background: rgba(255,255,255,0.3);
                    border-radius: 4px;
                }
                #${Config.UI_LOG_ID}::-webkit-scrollbar-thumb:hover {
                    background: rgba(255,255,255,0.5);
                }

                /* 添加状态周期历史记录的滚动条样式 */
                #${Config.UI_DEBUG_HISTORY_ID},
                .fab-debug-history-container {
                    scrollbar-width: thin;
                    scrollbar-color: rgba(255,255,255,0.3) rgba(0,0,0,0.2);
                }

                #${Config.UI_DEBUG_HISTORY_ID}::-webkit-scrollbar,
                .fab-debug-history-container::-webkit-scrollbar {
                    width: 8px;
                    height: 8px;
                }

                #${Config.UI_DEBUG_HISTORY_ID}::-webkit-scrollbar-track,
                .fab-debug-history-container::-webkit-scrollbar-track {
                    background: rgba(0,0,0,0.2);
                    border-radius: 4px;
                }

                #${Config.UI_DEBUG_HISTORY_ID}::-webkit-scrollbar-thumb,
                .fab-debug-history-container::-webkit-scrollbar-thumb {
                    background: rgba(255,255,255,0.3);
                    border-radius: 4px;
                }

                #${Config.UI_DEBUG_HISTORY_ID}::-webkit-scrollbar-thumb:hover,
                .fab-debug-history-container::-webkit-scrollbar-thumb:hover {
                    background: rgba(255,255,255,0.5);
                }
                @keyframes fab-pulse {
                    0% { box-shadow: 0 0 0 0 rgba(0, 122, 255, 0.7); }
                    70% { box-shadow: 0 0 0 10px rgba(0, 122, 255, 0); }
                    100% { box-shadow: 0 0 0 0 rgba(0, 122, 255, 0); }
                }
                .fab-helper-pulse {
                    animation: fab-pulse 2s infinite;
                }
                .fab-setting-row {
                    display: flex;
                    justify-content: space-between;
                    align-items: center;
                    padding: 10px 0;
                    border-bottom: 1px solid var(--border-color);
                }
                .fab-setting-row:last-child {
                    border-bottom: none;
                }
                .fab-setting-label {
                    font-size: 14px;
                }
                .fab-toggle-switch {
                    position: relative;
                    display: inline-block;
                    width: 44px;
                    height: 24px;
                }
                .fab-toggle-switch input {
                    opacity: 0;
                    width: 0;
                    height: 0;
                }
                .fab-toggle-slider {
                    position: absolute;
                    cursor: pointer;
                    top: 0;
                    left: 0;
                    right: 0;
                    bottom: 0;
                    background-color: var(--dark-gray);
                    transition: .4s;
                    border-radius: 24px;
                }
                .fab-toggle-slider:before {
                    position: absolute;
                    content: "";
                    height: 20px;
                    width: 20px;
                    left: 2px;
                    bottom: 2px;
                    background-color: white;
                    transition: .4s;
                    border-radius: 50%;
                }
                input:checked + .fab-toggle-slider {
                    background-color: var(--blue);
                }
                input:checked + .fab-toggle-slider:before {
                    transform: translateX(20px);
                }
            `;
            const styleSheet = document.createElement("style");
            // styleSheet.type = "text/css"; // 不再需要设置type属性
            styleSheet.innerText = styles;
            document.head.appendChild(styleSheet);

            const container = document.createElement('div');
            container.id = Config.UI_CONTAINER_ID;
            State.UI.container = container;

            // --- Header with Version ---
            const header = document.createElement('div');
            header.style.cssText = 'padding: 8px 12px; border-bottom: 1px solid var(--border-color); display: flex; justify-content: space-between; align-items: center;';
            const title = document.createElement('span');
            title.textContent = Utils.getText('app_title');
            title.style.fontWeight = '600';
            const version = document.createElement('span');
            version.textContent = `v${GM_info.script.version}`;
            version.style.cssText = 'font-size: 12px; color: var(--text-color-secondary); background: var(--dark-gray); padding: 2px 5px; border-radius: var(--radius-s);';
            header.append(title, version);
            container.appendChild(header);

            // --- Tab Controls ---
            const tabContainer = document.createElement('div');
            tabContainer.className = 'fab-helper-tabs';
            const tabs = ['dashboard', 'settings', 'debug'];
            tabs.forEach(tabName => {
                const btn = document.createElement('button');
                btn.textContent = Utils.getText(`tab_${tabName}`);
                btn.onclick = () => UI.switchTab(tabName);
                // 设置仪表盘标签为默认激活状态
                if (tabName === 'dashboard') {
                    btn.classList.add('active');
                }
                tabContainer.appendChild(btn);
                State.UI.tabs[tabName] = btn;
            });

            container.appendChild(tabContainer);

            // --- Dashboard Tab ---
            const dashboardContent = document.createElement('div');
            dashboardContent.className = 'fab-helper-tab-content';
            // 仪表盘标签页默认显示
            dashboardContent.style.display = 'block';
            State.UI.tabContents.dashboard = dashboardContent;

            const statusBar = document.createElement('div');
            statusBar.className = 'fab-helper-status-bar';

            const createStatusItem = (id, label, icon) => {
                const item = document.createElement('div');
                item.className = 'fab-helper-status-item';
                item.innerHTML = `<div class="fab-helper-status-label">${icon} ${label}</div><span id="${id}">0</span>`;
                return item;
            };
            State.UI.statusVisible = createStatusItem('fab-status-visible', Utils.getText('visible'), '👁️');
            State.UI.statusTodo = createStatusItem('fab-status-todo', Utils.getText('todo'), '📥');
            State.UI.statusDone = createStatusItem('fab-status-done', Utils.getText('added'), '✅');
            State.UI.statusFailed = createStatusItem('fab-status-failed', Utils.getText('failed'), '❌');
            State.UI.statusFailed.style.cursor = 'pointer';
            State.UI.statusFailed.title = Utils.getText('tooltip_open_failed');
            State.UI.statusFailed.onclick = () => {
                if (State.db.failed.length === 0) {
                    Utils.logger('info', '失败列表为空,无需操作。');
                    return;
                }
                if (window.confirm(Utils.getText('confirm_open_failed', State.db.failed.length))) {
                    Utils.logger('info', `正在打开 ${State.db.failed.length} 个失败项目...`);
                    State.db.failed.forEach(task => {
                        GM_openInTab(task.url, { active: false });
                    });
                }
            };
            State.UI.statusHidden = createStatusItem('fab-status-hidden', Utils.getText('hidden'), '🙈');
            statusBar.append(State.UI.statusTodo, State.UI.statusDone, State.UI.statusFailed, State.UI.statusVisible, State.UI.statusHidden);

            State.UI.execBtn = document.createElement('button');
            State.UI.execBtn.className = 'fab-helper-execute-btn';
            State.UI.execBtn.onclick = TaskRunner.toggleExecution;

            // 根据State.isExecuting设置按钮初始状态
            if (State.isExecuting) {
                State.UI.execBtn.innerHTML = `<span>${Utils.getText('executing')}</span>`;
                State.UI.execBtn.classList.add('executing');
            } else {
                State.UI.execBtn.textContent = Utils.getText('execute');
                State.UI.execBtn.classList.remove('executing');
            }

            const actionButtons = document.createElement('div');
            actionButtons.className = 'fab-helper-actions';

            State.UI.syncBtn = document.createElement('button');
            State.UI.syncBtn.textContent = '🔄 ' + Utils.getText('sync');
            State.UI.syncBtn.onclick = TaskRunner.refreshVisibleStates;

            State.UI.hideBtn = document.createElement('button');
            State.UI.hideBtn.onclick = TaskRunner.toggleHideSaved;

            actionButtons.append(State.UI.syncBtn, State.UI.hideBtn);

            // --- Log Panel (created before other elements to be appended first) ---
            const logContainer = document.createElement('div');
            logContainer.className = 'fab-log-container';

            const logHeader = document.createElement('div');
            logHeader.className = 'fab-log-header';
            const logTitle = document.createElement('span');
            logTitle.textContent = Utils.getText('operation_log');
            const logControls = document.createElement('div');
            logControls.className = 'fab-log-controls';

            const copyLogBtn = document.createElement('button');
            copyLogBtn.innerHTML = '📄';
            copyLogBtn.title = Utils.getText('copyLog');
            copyLogBtn.onclick = () => {
                navigator.clipboard.writeText(State.UI.logPanel.innerText).then(() => {
                    const originalText = copyLogBtn.textContent;
                    copyLogBtn.textContent = '✅';
                    setTimeout(() => { copyLogBtn.textContent = originalText; }, 1500);
                }).catch(err => Utils.logger('error', 'Failed to copy log:', err));
            };

            const clearLogBtn = document.createElement('button');
            clearLogBtn.innerHTML = '🗑️';
            clearLogBtn.title = Utils.getText('clearLog');
            clearLogBtn.onclick = () => { State.UI.logPanel.innerHTML = ''; };

            logControls.append(copyLogBtn, clearLogBtn);
            logHeader.append(logTitle, logControls);

            State.UI.logPanel = document.createElement('div');
            State.UI.logPanel.id = Config.UI_LOG_ID;

            logContainer.append(logHeader, State.UI.logPanel);

            // 添加当前保存的浏览位置显示
            const positionContainer = document.createElement('div');
            positionContainer.className = 'fab-helper-position-container';
            positionContainer.style.cssText = 'margin: 8px 0; padding: 6px 8px; background-color: rgba(0,0,0,0.05); border-radius: 4px; font-size: 13px;';

            const positionIcon = document.createElement('span');
            positionIcon.textContent = Utils.getText('position_indicator');
            positionIcon.style.marginRight = '4px';

            const positionInfo = document.createElement('span');
            positionInfo.textContent = Utils.decodeCursor(State.savedCursor);

            // 保存引用以便后续更新
            State.UI.savedPositionDisplay = positionInfo;

            positionContainer.appendChild(positionIcon);
            positionContainer.appendChild(positionInfo);

            // Reorder elements for the new layout: Log first, then position, status, then buttons
            dashboardContent.append(logContainer, positionContainer, statusBar, State.UI.execBtn, actionButtons);

            container.appendChild(dashboardContent);

            // --- Settings Tab ---
            const settingsContent = document.createElement('div');
            settingsContent.className = 'fab-helper-tab-content';

            const createSettingRow = (labelText, stateKey) => {
                const row = document.createElement('div');
                row.className = 'fab-setting-row';

                const label = document.createElement('span');
                label.className = 'fab-setting-label';
                label.textContent = labelText;

                const switchContainer = document.createElement('label');
                switchContainer.className = 'fab-toggle-switch';

                const input = document.createElement('input');
                input.type = 'checkbox';
                input.checked = State[stateKey];
                input.onchange = (e) => {
                    // Stop the event from doing anything weird, just in case.
                    e.stopPropagation();
                    e.preventDefault();

                    if(stateKey === 'autoAddOnScroll') {
                        TaskRunner.toggleAutoAdd();
                    } else if (stateKey === 'rememberScrollPosition') {
                        TaskRunner.toggleRememberPosition();
                    } else if (stateKey === 'autoResumeAfter429') {
                        TaskRunner.toggleAutoResume();
                    } else if (stateKey === 'autoRefreshEmptyPage') {
                        TaskRunner.toggleAutoRefreshEmpty();
                    }
                    // Manually sync the visual state of the checkbox since we prevented default action
                    e.target.checked = State[stateKey];
                };

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

                switchContainer.append(input, slider);
                row.append(label, switchContainer);

                // 所有设置行都使用相同的布局
                row.appendChild(label);
                row.appendChild(switchContainer);

                return row;
            };

            const autoAddSetting = createSettingRow(Utils.getText('setting_auto_add_scroll'), 'autoAddOnScroll');
            settingsContent.appendChild(autoAddSetting);

            const rememberPosSetting = createSettingRow(Utils.getText('setting_remember_position'), 'rememberScrollPosition');
            settingsContent.appendChild(rememberPosSetting);

            const autoResumeSetting = createSettingRow(Utils.getText('setting_auto_resume_429'), 'autoResumeAfter429');
            settingsContent.appendChild(autoResumeSetting);

            const autoRefreshEmptySetting = createSettingRow(Utils.getText('setting_auto_refresh'), 'autoRefreshEmptyPage');
            settingsContent.appendChild(autoRefreshEmptySetting);

            const resetButton = document.createElement('button');
            resetButton.textContent = Utils.getText('clear_all_data');
            resetButton.style.cssText = 'width: 100%; margin-top: 15px; background-color: var(--pink); color: white; padding: 10px; border-radius: var(--radius-m); border: none; cursor: pointer;';
            resetButton.onclick = Database.resetAllData;
            settingsContent.appendChild(resetButton);

            // 添加调试模式切换按钮 - 使用自定义行而不是createSettingRow
            const debugModeRow = document.createElement('div');
            debugModeRow.className = 'fab-setting-row';
            debugModeRow.title = Utils.getText('setting_debug_tooltip');

            const debugLabel = document.createElement('span');
            debugLabel.className = 'fab-setting-label';
            debugLabel.textContent = Utils.getText('debug_mode');
            debugLabel.style.color = '#ff9800';

            const switchContainer = document.createElement('label');
            switchContainer.className = 'fab-toggle-switch';

            const input = document.createElement('input');
            input.type = 'checkbox';
            input.checked = State.debugMode;
            input.onchange = (e) => {
                State.debugMode = e.target.checked;
                debugModeRow.classList.toggle('active', State.debugMode);
                Utils.logger('info', `调试模式已${State.debugMode ? '开启' : '关闭'}。${State.debugMode ? '将显示详细日志信息' : ''}`);
                GM_setValue('fab_helper_debug_mode', State.debugMode);
            };

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

            switchContainer.append(input, slider);
            debugModeRow.append(debugLabel, switchContainer);
            debugModeRow.classList.toggle('active', State.debugMode);
            settingsContent.appendChild(debugModeRow);

                            // 排序选择已移除,改为自动从URL获取

              State.UI.tabContents.settings = settingsContent;
              container.appendChild(settingsContent);

            // 确保设置标签页默认隐藏
            settingsContent.style.display = 'none';

            // --- 调试标签页 ---
            const debugContent = document.createElement('div');
            debugContent.className = 'fab-helper-tab-content';
            // 确保调试标签页默认隐藏
            debugContent.style.display = 'none';
            // 初始化调试内容容器
            State.UI.debugContent = debugContent;

            const debugHeader = document.createElement('div');
            debugHeader.style.cssText = 'display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;';

            const debugTitle = document.createElement('h4');
            debugTitle.textContent = Utils.getText('status_history');
            debugTitle.style.margin = '0';

            const debugControls = document.createElement('div');
            debugControls.style.cssText = 'display: flex; gap: 8px;';

            const copyHistoryBtn = document.createElement('button');
            copyHistoryBtn.textContent = Utils.getText('copy_btn');
            copyHistoryBtn.title = '复制详细历史记录';
            copyHistoryBtn.style.cssText = 'background: var(--dark-gray); border: 1px solid var(--border-color); color: var(--text-color-secondary); padding: 4px 8px; border-radius: var(--radius-m); cursor: pointer;';
            copyHistoryBtn.onclick = () => {
                if (State.statusHistory.length === 0) {
                    Utils.logger('info', '没有历史记录可供复制。');
                    return;
                }
                const formatEntry = (entry) => {
                    const date = new Date(entry.endTime).toLocaleString();

                    if (entry.type === 'STARTUP') {
                        return `🚀 ${Utils.getText('script_startup')}\n  - ${Utils.getText('time_label')}: ${date}\n  - ${Utils.getText('info_label')}: ${entry.message || ''}`;
                    } else {
                        const type = entry.type === 'NORMAL' ? `✅ ${Utils.getText('normal_period')}` : `🚨 ${Utils.getText('rate_limited_period')}`;
                        // 添加空值检查,防止toFixed错误
                        let details = `${Utils.getText('duration_label')}: ${entry.duration !== undefined && entry.duration !== null ? entry.duration.toFixed(2) : Utils.getText('unknown_duration')}s`;
                        if (entry.requests !== undefined) {
                            details += `, ${Utils.getText('requests_label')}: ${entry.requests}${Utils.getText('requests_unit')}`;
                        }
                        return `${type}\n  - ${Utils.getText('ended_at')}: ${date}\n  - ${details}`;
                    }
                };
                const fullLog = State.statusHistory.map(formatEntry).join('\n\n');
                navigator.clipboard.writeText(fullLog).then(() => {
                    const originalText = copyHistoryBtn.textContent;
                    copyHistoryBtn.textContent = Utils.getText('copied_success');
                    setTimeout(() => { copyHistoryBtn.textContent = originalText; }, 2000);
                }).catch(err => Utils.logger('error', Utils.getText('log_copy_failed'), err));
            };

            const clearHistoryBtn = document.createElement('button');
            clearHistoryBtn.textContent = Utils.getText('clear_btn');
            clearHistoryBtn.title = '清空历史记录';
            clearHistoryBtn.style.cssText = 'background: var(--dark-gray); border: 1px solid var(--border-color); color: var(--text-color-secondary); padding: 4px 8px; border-radius: var(--radius-m); cursor: pointer;';
            clearHistoryBtn.onclick = async () => {
                if (window.confirm(Utils.getText('confirm_clear_history'))) {
                    State.statusHistory = [];
                    await GM_deleteValue(Config.DB_KEYS.STATUS_HISTORY);

                    // 添加一个新的"当前会话"记录
                    const currentSessionEntry = {
                        type: 'STARTUP',
                        duration: 0,
                        endTime: new Date().toISOString(),
                        message: Utils.getText('history_cleared_new_session')
                    };
                    await RateLimitManager.addToHistory(currentSessionEntry);

                    UI.updateDebugTab();
                    Utils.logger('info', Utils.getText('status_history_cleared'));
                }
            };

            // 添加页面诊断按钮
            const diagnosisBtn = document.createElement('button');
            diagnosisBtn.textContent = Utils.getText('page_diagnosis');
            diagnosisBtn.className = 'fab-helper-btn';
            diagnosisBtn.style.cssText = 'margin-left: 10px; background: #2196F3; color: white;';
            diagnosisBtn.onclick = () => {
                try {
                    const report = PageDiagnostics.diagnoseDetailPage();
                    PageDiagnostics.logDiagnosticReport(report);
                    Utils.logger('info', '页面诊断完成,请查看控制台输出');
                } catch (error) {
                    Utils.logger('error', `页面诊断失败: ${error.message}`);
                }
            };

            debugControls.append(copyHistoryBtn, clearHistoryBtn, diagnosisBtn);
            debugHeader.append(debugTitle, debugControls);

            const historyListContainer = document.createElement('div');
            historyListContainer.style.cssText = 'max-height: 250px; overflow-y: auto; background: rgba(10,10,10,0.85); color: #ddd; padding: 8px; border-radius: var(--radius-m);';
            historyListContainer.className = 'fab-debug-history-container';
            // 将historyListContainer保存为State.UI.historyContainer,而不是debugContent
            State.UI.historyContainer = historyListContainer;

            debugContent.append(debugHeader, historyListContainer);
            State.UI.tabContents.debug = debugContent;
            // 确保调试标签页默认隐藏
            debugContent.style.display = 'none';
            container.appendChild(debugContent);

            document.body.appendChild(container);

            // --- BUG FIX: Explicitly return true on successful creation ---
            return true;
        },

        update: () => {
            if (!State.UI.container) return;

            // --- Update Static Text Elements (for language switching) ---
            // 更新应用标题
            const titleElement = State.UI.container.querySelector('span[style*="font-weight: 600"]');
            if (titleElement) {
                titleElement.textContent = Utils.getText('app_title');
            }

            // 更新标签页文本
            const tabs = ['dashboard', 'settings', 'debug'];
            tabs.forEach((tabName) => {
                const tabButton = State.UI.tabs[tabName];
                if (tabButton) {
                    tabButton.textContent = Utils.getText(`tab_${tabName}`);
                }
            });

            // 更新同步按钮文本
            if (State.UI.syncBtn) {
                State.UI.syncBtn.textContent = '🔄 ' + Utils.getText('sync');
            }

            // --- Update Status Numbers ---
            const todoCount = State.db.todo.length;
            const doneCount = State.db.done.length;
            const failedCount = State.db.failed.length;
            const visibleCount = document.querySelectorAll(Config.SELECTORS.card).length - State.hiddenThisPageCount;

            State.UI.statusTodo.querySelector('span').textContent = todoCount;
            State.UI.statusDone.querySelector('span').textContent = doneCount;
            State.UI.statusFailed.querySelector('span').textContent = failedCount;
            State.UI.statusHidden.querySelector('span').textContent = State.hiddenThisPageCount;
            State.UI.statusVisible.querySelector('span').textContent = visibleCount;

            // --- Update Button States ---
            // 确保按钮状态与State.isExecuting一致
            if (State.isExecuting) {
                State.UI.execBtn.innerHTML = `<span>${Utils.getText('executing')}</span>`;
                State.UI.execBtn.classList.add('executing');
                // 添加提示信息,显示当前执行状态
                if (State.executionTotalTasks > 0) {
                    const progress = State.executionCompletedTasks + State.executionFailedTasks;
                    const percentage = Math.round((progress / State.executionTotalTasks) * 100);
                    State.UI.execBtn.title = Utils.getText('tooltip_executing_progress', progress, State.executionTotalTasks, percentage);
                } else {
                    State.UI.execBtn.title = Utils.getText('tooltip_executing');
                }
            } else {
                State.UI.execBtn.textContent = Utils.getText('execute');
                State.UI.execBtn.classList.remove('executing');
                State.UI.execBtn.title = Utils.getText('tooltip_start_tasks');
            }

            State.UI.hideBtn.textContent = (State.hideSaved ? '🙈 ' : '👁️ ') + (State.hideSaved ? Utils.getText('show') : Utils.getText('hide'));
        },
        removeAllOverlays: () => {
            document.querySelectorAll(Config.SELECTORS.card).forEach(card => {
                const overlay = card.querySelector('.fab-helper-overlay');
                if (overlay) overlay.remove();
                card.style.opacity = '1';
            });
        },
        switchTab: (tabName) => {
            for (const name in State.UI.tabs) {
                State.UI.tabs[name].classList.toggle('active', name === tabName);
                State.UI.tabContents[name].style.display = name === tabName ? 'block' : 'none';
            }
        },
        updateDebugTab: () => {
            // 使用historyContainer而不是debugContent
            if (!State.UI.historyContainer) return;
            State.UI.historyContainer.innerHTML = ''; // Clear previous entries

            // 创建历史记录项
            const createHistoryItem = (entry) => {
                const item = document.createElement('div');
                item.style.cssText = 'padding: 8px; border-bottom: 1px solid var(--border-color);';

                const header = document.createElement('div');
                header.style.cssText = 'display: flex; align-items: center; gap: 8px; margin-bottom: 4px;';

                let icon, color, titleText;

                if (entry.type === 'STARTUP') {
                    icon = '🚀';
                    color = 'var(--blue)';
                    titleText = Utils.getText('script_startup');
                } else if (entry.type === 'NORMAL') {
                    icon = '✅';
                    color = 'var(--green)';
                    titleText = Utils.getText('normal_period');
                } else { // RATE_LIMITED
                    icon = '🚨';
                    color = 'var(--orange)';
                    titleText = Utils.getText('rate_limited_period');
                }

                header.innerHTML = `<span style="font-size: 18px;">${icon}</span> <strong style="color: ${color};">${titleText}</strong>`;

                const details = document.createElement('div');
                details.style.cssText = 'font-size: 12px; color: var(--text-color-secondary); padding-left: 26px;';

                let detailsHtml = '';

                if (entry.type === 'STARTUP') {
                    detailsHtml = `<div>${Utils.getText('status_time_label')}: ${new Date(entry.endTime).toLocaleString()}</div>`;
                    if (entry.message) {
                        detailsHtml += `<div>${Utils.getText('status_info_label')}: <strong>${entry.message}</strong></div>`;
                    }
                } else {
                    // 添加空值检查,防止toFixed错误
                    const duration = entry.duration !== undefined && entry.duration !== null ?
                        entry.duration.toFixed(2) : Utils.getText('status_unknown_duration');
                    detailsHtml = `<div>${Utils.getText('status_duration_label')}<strong>${duration}s</strong></div>`;
                    if (entry.requests !== undefined) {
                        detailsHtml += `<div>${Utils.getText('status_requests_label')}<strong>${entry.requests}</strong></div>`;
                    }
                    // 添加空值检查,防止日期错误
                    const endTime = entry.endTime ? new Date(entry.endTime).toLocaleString() : Utils.getText('status_unknown_time');
                    detailsHtml += `<div>${Utils.getText('status_ended_at_label')}${endTime}</div>`;
                }

                details.innerHTML = detailsHtml;

                item.append(header, details);
                return item;
            };

            // 创建当前状态项(即使没有历史记录也会显示)
            const createCurrentStatusItem = () => {
                if(State.appStatus === 'NORMAL' || State.appStatus === 'RATE_LIMITED') {
                    const item = document.createElement('div');
                    item.style.cssText = 'padding: 8px; border-bottom: 1px solid var(--border-color); background: var(--blue-bg);';

                    const header = document.createElement('div');
                    header.style.cssText = 'display: flex; align-items: center; gap: 8px; margin-bottom: 4px;';

                    const icon = State.appStatus === 'NORMAL' ? '✅' : '🚨';
                    const color = State.appStatus === 'NORMAL' ? 'var(--green)' : 'var(--orange)';
                    const titleText = State.appStatus === 'NORMAL' ? Utils.getText('current_normal') : Utils.getText('current_rate_limited');

                    header.innerHTML = `<span style="font-size: 18px;">${icon}</span> <strong style="color: ${color};">${titleText}</strong>`;

                    const details = document.createElement('div');
                    details.style.cssText = 'font-size: 12px; color: var(--text-color-secondary); padding-left: 26px;';

                    const startTime = State.appStatus === 'NORMAL' ? State.normalStartTime : State.rateLimitStartTime;
                    // 添加空值检查,防止startTime为null或undefined
                    const duration = startTime ? ((Date.now() - startTime) / 1000).toFixed(2) : Utils.getText('status_unknown_duration');

                    let detailsHtml = `<div>${Utils.getText('status_ongoing_label')}<strong>${duration}s</strong></div>`;
                    if (State.appStatus === 'NORMAL') {
                         detailsHtml += `<div>${Utils.getText('status_requests_label')}<strong>${State.successfulSearchCount}</strong></div>`;
                    }
                     // 添加空值检查,防止startTime为null
                     const startTimeDisplay = startTime ? new Date(startTime).toLocaleString() : Utils.getText('status_unknown_time');
                     detailsHtml += `<div>${Utils.getText('status_started_at_label')}${startTimeDisplay}</div>`;
                    details.innerHTML = detailsHtml;

                    item.append(header, details);
                    State.UI.historyContainer.appendChild(item);
                }
            };

            // 添加当前状态项(始终显示)
            createCurrentStatusItem();

            // 如果没有历史记录,显示提示信息
            if (State.statusHistory.length === 0) {
                const emptyMessage = document.createElement('div');
                emptyMessage.style.cssText = 'color: #888; text-align: center; padding: 20px;';
                emptyMessage.textContent = Utils.getText('no_history');
                State.UI.historyContainer.appendChild(emptyMessage);
                return;
            }

            // 显示历史记录(如果有)
            const reversedHistory = [...State.statusHistory].reverse();
            reversedHistory.forEach(entry => State.UI.historyContainer.appendChild(createHistoryItem(entry)));
        },
    };


    // --- 模块九: 主程序与初始化 (Main & Initialization) ---
    const InstanceManager = {
        isActive: false,
        lastPingTime: 0,
        pingInterval: null,

        // 初始化实例管理
        init: async function() {
            try {
                // 检查当前页面是否是搜索页面
                const isSearchPage = window.location.href.includes('/search') ||
                                    window.location.pathname === '/' ||
                                    window.location.pathname === '/zh-cn/' ||
                                    window.location.pathname === '/en/';

                // 如果是搜索页面,总是成为活跃实例
                if (isSearchPage) {
                    this.isActive = true;
                    await this.registerAsActive();
                    Utils.logger('info', `当前是搜索页面,实例 [${Config.INSTANCE_ID}] 已激活。`);

                    // 启动ping机制,每3秒更新一次活跃状态
                    this.pingInterval = setInterval(() => this.ping(), 3000);
                    return true;
                }

                // 如果是工作标签页,检查是否有活跃实例
                const activeInstance = await GM_getValue('fab_active_instance', null);
                const currentTime = Date.now();

                if (activeInstance && (currentTime - activeInstance.lastPing < 10000)) {
                    // 如果有活跃实例且在10秒内有ping,则当前实例不活跃
                    Utils.logger('info', `检测到活跃的脚本实例 [${activeInstance.id}],当前工作标签页将与之协作。`);
                    this.isActive = false;
                    return true; // 工作标签页也返回true,因为它需要执行自己的任务
                } else {
                    // 没有活跃实例或实例超时,当前实例成为活跃实例
                    this.isActive = true;
                    await this.registerAsActive();
                    Utils.logger('info', `没有检测到活跃实例,当前实例 [${Config.INSTANCE_ID}] 已激活。`);

                    // 启动ping机制,每3秒更新一次活跃状态
                    this.pingInterval = setInterval(() => this.ping(), 3000);
                    return true;
                }
            } catch (error) {
                Utils.logger('error', `实例管理初始化失败: ${error.message}`);
                // 出错时默认为活跃,避免脚本不工作
                this.isActive = true;
                return true;
            }
        },

        // 注册为活跃实例
        registerAsActive: async function() {
            await GM_setValue('fab_active_instance', {
                id: Config.INSTANCE_ID,
                lastPing: Date.now()
            });
        },

        // 定期更新活跃状态
        ping: async function() {
            if (!this.isActive) return;

            this.lastPingTime = Date.now();
            await this.registerAsActive();
        },

        // 检查是否可以接管
        checkTakeover: async function() {
            if (this.isActive) return;

            try {
                const activeInstance = await GM_getValue('fab_active_instance', null);
                const currentTime = Date.now();

                if (!activeInstance || (currentTime - activeInstance.lastPing > 10000)) {
                    // 如果没有活跃实例或实例超时,接管
                    this.isActive = true;
                    await this.registerAsActive();
                    Utils.logger('info', `之前的实例不再活跃,当前实例 [${Config.INSTANCE_ID}] 已接管。`);

                    // 启动ping机制
                    this.pingInterval = setInterval(() => this.ping(), 3000);

                    // 刷新页面以确保正确加载
                    location.reload();
                    } else {
                    // 继续等待
                    setTimeout(() => this.checkTakeover(), 5000);
                    }
            } catch (error) {
                Utils.logger('error', `接管检查失败: ${error.message}`);
                // 5秒后重试
                setTimeout(() => this.checkTakeover(), 5000);
            }
        },

        // 清理实例
        cleanup: function() {
            if (this.pingInterval) {
                clearInterval(this.pingInterval);
                this.pingInterval = null;
            }
        }
    };

    async function main() {
        // 记录页面加载时间
        window.pageLoadTime = Date.now();

        Utils.logger('info', '脚本开始运行...');
        Utils.detectLanguage();

        // 检查账号状态
        if (!Utils.checkAuthentication()) {
            Utils.logger('error', '账号未登录,脚本停止执行');
            return;
        }

        // 检查是否是工作标签页
        const urlParams = new URLSearchParams(window.location.search);
        const workerId = urlParams.get('workerId');
        if (workerId) {
            // 如果是工作标签页,只执行工作标签页的逻辑,不执行主脚本逻辑
            State.isWorkerTab = true;
            State.workerTaskId = workerId;

            // 初始化实例管理,但不检查返回值,工作标签页总是需要执行自己的任务
            await InstanceManager.init();
            Utils.logger('info', `工作标签页初始化完成,开始处理任务...`);
            await TaskRunner.processDetailPage();
            return;
        }

        // 初始化实例管理
        await InstanceManager.init();

        // 主页面总是继续执行,不需要检查isActiveInstance
        await Database.load();

        // 确保执行状态与存储状态一致
        const storedExecutingState = await GM_getValue(Config.DB_KEYS.IS_EXECUTING, false);
        if (State.isExecuting !== storedExecutingState) {
            Utils.logger('info', `执行状态不一致,从存储中恢复:${storedExecutingState ? '执行中' : '已停止'}`);
            State.isExecuting = storedExecutingState;
        }

        // 从存储中恢复限速状态
        const persistedStatus = await GM_getValue(Config.DB_KEYS.APP_STATUS);
        if (persistedStatus && persistedStatus.status === 'RATE_LIMITED') {
            State.appStatus = 'RATE_LIMITED';
            State.rateLimitStartTime = persistedStatus.startTime;
            // 添加空值检查,防止persistedStatus.startTime为null
            const previousDuration = persistedStatus && persistedStatus.startTime ?
                ((Date.now() - persistedStatus.startTime) / 1000).toFixed(2) : '0.00';
            Utils.logger('warn', Utils.getText('startup_rate_limited', previousDuration, persistedStatus.source || Utils.getText('status_unknown_source')));
        }

        // 初始化请求拦截器
        setupRequestInterceptors();

        await PagePatcher.init();

        // 检查是否有临时保存的待办任务(从429恢复)
        const tempTasks = await GM_getValue('temp_todo_tasks', null);
        if (tempTasks && tempTasks.length > 0) {
            Utils.logger('info', `从429恢复:找到 ${tempTasks.length} 个临时保存的待办任务,正在恢复...`);
            State.db.todo = tempTasks;
            await GM_deleteValue('temp_todo_tasks'); // 清除临时存储
        }

        // 添加工作标签页完成任务的监听器
        State.valueChangeListeners.push(GM_addValueChangeListener(Config.DB_KEYS.WORKER_DONE, async (key, oldValue, newValue) => {
            if (!newValue) return; // 如果值被删除,忽略此事件

            try {
                // 删除值,防止重复处理
                await GM_deleteValue(Config.DB_KEYS.WORKER_DONE);

                const { workerId, success, task, logs, instanceId, executionTime } = newValue;

                // 检查是否由当前实例处理
                if (instanceId !== Config.INSTANCE_ID) {
                    Utils.logger('info', `收到来自其他实例 [${instanceId}] 的工作报告,当前实例 [${Config.INSTANCE_ID}] 将忽略。`);
             return;
        }

                if (!workerId || !task) {
                    Utils.logger('error', '收到无效的工作报告。缺少workerId或task。');
                    return;
                }

                // 记录执行时间(如果有)
                if (executionTime) {
                    // 添加空值检查,防止executionTime为null
                    Utils.logger('info', Utils.getText('task_execution_time', executionTime ? (executionTime / 1000).toFixed(2) : Utils.getText('status_unknown_duration')));
                }

                // 移除此工作标签页的记录
                if (State.runningWorkers[workerId]) {
                    delete State.runningWorkers[workerId];
                    State.activeWorkers--;
                }

                // 记录工作标签页的日志
                if (logs && logs.length) {
                    logs.forEach(log => Utils.logger('info', log));
                }

                // 处理任务结果
                if (success) {
                    Utils.logger('info', `✅ 任务完成: ${task.name}`);

                    // 从待办列表中移除此任务
                    const initialTodoCount = State.db.todo.length;
                    State.db.todo = State.db.todo.filter(t => t.uid !== task.uid);

                    // 检查是否实际移除了任务
                    if (State.db.todo.length < initialTodoCount) {
                        Utils.logger('info', `已从待办列表中移除任务 ${task.name}`);
                    } else {
                        Utils.logger('warn', `任务 ${task.name} 不在待办列表中,可能已被其他工作标签页处理。`);
                            }

                    // 保存待办列表
                    await Database.saveTodo();

                    // 如果尚未在完成列表中,则添加
                    if (!State.db.done.includes(task.url)) {
                        State.db.done.push(task.url);
                        await Database.saveDone();
                    }

                    // 更新会话状态
                    State.sessionCompleted.add(task.url);

                    // 更新执行统计
                    State.executionCompletedTasks++;
                } else {
                    Utils.logger('warn', `❌ 任务失败: ${task.name}`);

                    // 从待办列表中移除此任务
                    State.db.todo = State.db.todo.filter(t => t.uid !== task.uid);

                    // 保存待办列表
                    await Database.saveTodo();

                    // 添加到失败列表(如果尚未存在)
                    if (!State.db.failed.some(f => f.uid === task.uid)) {
                        State.db.failed.push(task);
                        await Database.saveFailed();
                    }

                    // 更新执行统计
                    State.executionFailedTasks++;
                }

                // 更新UI
                UI.update();

                // 如果还有待办任务,继续执行
                if (State.isExecuting && State.activeWorkers < Config.MAX_CONCURRENT_WORKERS && State.db.todo.length > 0) {
                    // 延迟一小段时间再派发新任务,避免同时打开太多标签页
                    setTimeout(() => TaskRunner.executeBatch(), 1000);
                            }

                // 如果所有任务都已完成,停止执行
                if (State.isExecuting && State.db.todo.length === 0 && State.activeWorkers === 0) {
                    Utils.logger('info', '所有任务已完成。');
                    State.isExecuting = false;
                    // 保存执行状态
                    Database.saveExecutingState();
                    // 保存待办列表(虽然为空,但仍需保存以更新存储)
                    await Database.saveTodo();

                    // 如果处于限速状态且待办任务为0,触发页面刷新
                    if (State.appStatus === 'RATE_LIMITED') {
                        Utils.logger('info', '所有任务已完成,且处于限速状态,将刷新页面尝试恢复...');
                        const randomDelay = 3000 + Math.random() * 5000;
                        countdownRefresh(randomDelay, '任务完成后限速恢复');
                    }

            UI.update();
                }

                // 更新隐藏状态
            TaskRunner.runHideOrShow();
            } catch (error) {
                Utils.logger('error', `处理工作报告时出错: ${error.message}`);
            }
        }));

        // 添加执行状态变化监听器,确保UI状态与存储状态一致
        State.valueChangeListeners.push(GM_addValueChangeListener(Config.DB_KEYS.IS_EXECUTING, (key, oldValue, newValue) => {
            // 如果当前不是工作标签页,且存储状态与当前状态不一致,则更新当前状态
            if (!State.isWorkerTab && State.isExecuting !== newValue) {
                Utils.logger('info', Utils.getText('execution_status_changed', newValue ? Utils.getText('status_executing') : Utils.getText('status_stopped')));
                State.isExecuting = newValue;
            UI.update();
            }
        }));

        // --- ROBUST LAUNCHER ---
        // This interval is launched from the clean userscript context and is less likely to be interfered with.
        // It will persistently try to launch the DOM-dependent part of the script.
        // 使用一个全局变量来防止多次初始化
        window._fabHelperLauncherActive = window._fabHelperLauncherActive || false;

        if (!window._fabHelperLauncherActive) {
            window._fabHelperLauncherActive = true;

            const launcherInterval = setInterval(() => {
                if (document.readyState === 'interactive' || document.readyState === 'complete') {
                    if (!State.hasRunDomPart) {
                        Utils.logger('info', '[Launcher] DOM is ready. Running main script logic...');
                        runDomDependentPart();
                    }
                    if (State.hasRunDomPart) {
                        clearInterval(launcherInterval);
                        window._fabHelperLauncherActive = false;
                        Utils.logger('debug', '[Launcher] Main logic has been launched or skipped. Launcher is now idle.');
                    }
                }
            }, 500); // 增加间隔到500ms,减少频繁检查
        } else {
            Utils.logger('info', '[Launcher] Another launcher is already active. Skipping initialization.');
        }

        // 添加无活动超时刷新功能
        let lastNetworkActivityTime = Date.now();

        // 记录网络活动的函数
        // 记录网络活动时间
        window.recordNetworkActivity = function() {
            lastNetworkActivityTime = Date.now();
        };

        // 记录网络请求
        window.recordNetworkRequest = function(source, isSuccess) {
            // 记录网络活动
            window.recordNetworkActivity();
        };

        // 定期检查是否长时间无活动
        setInterval(() => {
            // 只有在限速状态下才考虑无活动刷新
            if (State.appStatus === 'RATE_LIMITED') {
                const inactiveTime = Date.now() - lastNetworkActivityTime;
                // 如果超过30秒没有网络活动,强制刷新
                if (inactiveTime > 30000) {
                    Utils.logger('warn', `⚠️ 检测到在限速状态下 ${Math.floor(inactiveTime/1000)} 秒无网络活动,即将强制刷新页面...`);
                    // 使用延迟以便用户能看到日志
                    setTimeout(() => {
                        window.location.reload();
                    }, 1500);
                }
            }
        }, 5000); // 每5秒检查一次
    }

        async function runDomDependentPart() {
        if (State.hasRunDomPart) return;

        // 如果是工作标签页,不执行主脚本的DOM相关逻辑
        if (State.isWorkerTab) {
            State.hasRunDomPart = true; // 标记为已运行,避免重复检查
            return;
        }

        // The new, correct worker detection logic.
        const urlParams = new URLSearchParams(window.location.search);
        if (urlParams.has('workerId')) {
            // 这里不需要再调用processDetailPage,因为main函数中已经处理了
            Utils.logger('info', `工作标签页DOM部分初始化,跳过UI创建`);
            State.hasRunDomPart = true; // Mark as run to stop the launcher
            return;
        }

        // --- NEW FLOW: Create the UI FIRST for immediate user feedback ---
        const uiCreated = UI.create();

        if (!uiCreated) {
            Utils.logger('info', Utils.getText('log_detail_page'));
            State.hasRunDomPart = true; // Mark as run to stop the launcher
            return;
        }

        // 初始化完成后,确保UI状态与执行状态一致
            UI.update();

        // 确保UI创建后立即更新调试标签页
        UI.update();
        UI.updateDebugTab();
        UI.switchTab('dashboard'); // 设置初始标签页

        State.hasRunDomPart = true; // Mark as run *after* successful UI creation

        // --- Dead on Arrival Check for initial 429 page load ---
        // 使enterRateLimitedState函数全局可访问,以便其他部分可以调用
        window.enterRateLimitedState = function(source = Utils.getText('rate_limit_source_global_call')) {
            // 使用统一的限速管理器进入限速状态
            RateLimitManager.enterRateLimitedState(source);
        };

        // 添加全局函数用于记录所有网络请求 - 简化版
        window.recordNetworkRequest = function(source = '网络请求', hasResults = true) {
            // 只记录成功请求,不再进行复杂的计数
            if (hasResults) {
                RateLimitManager.recordSuccessfulRequest(source, hasResults);
            }
        };

        // 添加页面内容检测功能,定期检查页面是否显示了限速错误信息
        setInterval(() => {
            // 如果已经处于限速状态,不需要检查
            if (State.appStatus === 'NORMAL') {
                // 检查页面内容是否包含限速错误信息
                const pageText = document.body.innerText || '';
                if (pageText.includes('Too many requests') ||
                    pageText.includes('rate limit') ||
                    pageText.match(/\{\s*"detail"\s*:\s*"Too many requests"\s*\}/i)) {

                    Utils.logger('warn', Utils.getText('page_content_rate_limit_detected'));
                    RateLimitManager.enterRateLimitedState(Utils.getText('rate_limit_source_page_content'));
                }
            }
        }, 5000); // 每5秒检查一次

        const checkIsErrorPage = (title, text) => {
            const isCloudflareTitle = title.includes('Cloudflare') || title.includes('Attention Required');
            const is429Text = text.includes('429') ||
                              text.includes('Too Many Requests') ||
                              text.includes('Too many requests') ||
                              text.match(/\{\s*"detail"\s*:\s*"Too many requests"\s*\}/i);
            if (isCloudflareTitle || is429Text) {
                Utils.logger('warn', `[页面加载] 检测到429错误页面: ${document.location.href}`);
                window.enterRateLimitedState('页面内容429检测');
                return true;
            }
            return false;
        };

        // 如果检测到错误页面,不要立即返回,而是继续尝试恢复
        const isErrorPage = checkIsErrorPage(document.title, document.body.innerText || '');
        // 不要在这里return,让代码继续执行到自动恢复部分

        // The auto-resume logic is preserved - always try to recover from 429
        if (State.appStatus === 'RATE_LIMITED') {
            Utils.logger('info', '[Auto-Resume] 页面在限速状态下加载。正在进行恢复探测...');

            // 使用统一的限速状态检查
            const isRecovered = await RateLimitManager.checkRateLimitStatus();

            if (isRecovered) {
                Utils.logger('info', '✅ 恢复探测成功!限速已解除,继续正常操作。');

                // 如果有待办任务,继续执行
                if (State.db.todo.length > 0 && !State.isExecuting) {
                    Utils.logger('info', `发现 ${State.db.todo.length} 个待办任务,自动恢复执行...`);
                    State.isExecuting = true;
                    Database.saveExecutingState();
                    TaskRunner.executeBatch();
                }
            } else {
                // 仍然处于限速状态,继续随机刷新
                Utils.logger('warn', '恢复探测失败。仍处于限速状态,将继续随机刷新...');

                // 如果有活动任务,等待它们完成
                if (State.activeWorkers > 0) {
                    Utils.logger('info', `仍有 ${State.activeWorkers} 个任务在执行中,等待它们完成后再刷新...`);
                } else if (State.db.todo.length > 0) {
                    // 如果有待办任务但没有活动任务,尝试继续执行
                    Utils.logger('info', `有 ${State.db.todo.length} 个待办任务等待执行,将尝试继续执行...`);
                    if (!State.isExecuting) {
                        State.isExecuting = true;
                        Database.saveExecutingState();
                        TaskRunner.executeBatch();
                    }
                } else {
                    // 没有任务,直接刷新
                    const randomDelay = 5000 + Math.random() * 10000;
                    countdownRefresh(randomDelay, '恢复探测失败');
                }
            }
        }

        // --- Observer setup is now directly inside runDomDependentPart ---
        const containerSelectors = [
            'main', '#main', '.AssetGrid-root', '.fabkit-responsive-grid-container'
        ];
        let targetNode = null;
        for (const selector of containerSelectors) {
            targetNode = document.querySelector(selector);
            if (targetNode) break;
        }
        if (!targetNode) targetNode = document.body;

        const observer = new MutationObserver((mutationsList) => {
            const hasNewContent = mutationsList.some(mutation =>
                [...mutation.addedNodes].some(node =>
                    node.nodeType === 1 && (node.matches(Config.SELECTORS.card) || node.querySelector(Config.SELECTORS.card))
                )
            );
            if (hasNewContent) {
                // 不再立即执行隐藏,而是等待一段时间,确保API请求完成

                // 延迟进行处理
                clearTimeout(State.observerDebounceTimer);
                State.observerDebounceTimer = setTimeout(() => {
                    if (State.debugMode) {
                        Utils.logger('debug', `[Observer] ${Utils.getText('debug_new_content_loading')}`);
                    }

                    // 首先等待一段较长的时间,确保API请求有足够时间完成
                    setTimeout(() => {
                        if (State.debugMode) {
                            Utils.logger('debug', `[Observer] ${Utils.getText('debug_process_new_content')}`);
                        }

                        // 执行一次状态检查,尝试更新卡片状态
                        TaskRunner.checkVisibleCardsStatus().then(() => {
                            // 状态检查后再次执行隐藏,确保新状态被应用
                            // 使用更长的延迟执行隐藏,确保DOM和API状态已完全更新
                            setTimeout(() => {
                                if (State.hideSaved) {
                                    TaskRunner.runHideOrShow();
                                }
                            }, 1000);

                            // 只在非限速状态下执行自动添加任务功能
                            if (State.appStatus === 'NORMAL' || State.autoAddOnScroll) {
                                // 异步调用scanAndAddTasks,但也增加延迟
                                setTimeout(() => {
                                    TaskRunner.scanAndAddTasks(document.querySelectorAll(Config.SELECTORS.card))
                                        .catch(error => Utils.logger('error', `自动添加任务失败: ${error.message}`));
                                }, 500);
                            }
                        }).catch(() => {
                            // 即使状态检查失败也执行隐藏,但延迟更长
                            setTimeout(() => {
                                if (State.hideSaved) {
                                    TaskRunner.runHideOrShow();
                                }
                            }, 1500);
                        });
                    }, 2000); // 等待2秒,确保API请求完成
                }, 500); // 增加防抖延迟
            }
        });

        observer.observe(targetNode, {
            childList: true,
            subtree: true
        });
        Utils.logger('debug', `✅ Core DOM observer is now active on <${targetNode.tagName.toLowerCase()}>.`);

        // 初始化时运行一次隐藏逻辑,确保页面加载时已有的内容能被正确处理
            TaskRunner.runHideOrShow();

            // 添加定期检查功能,确保所有卡片都被正确处理
            setInterval(() => {
                // 如果没有开启隐藏功能,不需要检查
                if (!State.hideSaved) return;

                // 检查是否有未处理的卡片
                const cards = document.querySelectorAll(Config.SELECTORS.card);
                let unprocessedCount = 0;

                cards.forEach(card => {
                    const isProcessed = card.getAttribute('data-fab-processed') === 'true';
                    if (!isProcessed) {
                        unprocessedCount++;
                    } else {
                        // 检查已处理的卡片是否状态正确
                        const isFinished = TaskRunner.isCardFinished(card);
                        const shouldBeHidden = isFinished && State.hideSaved;
                        const isHidden = card.style.display === 'none';

                        // 如果状态不一致,重置处理标记
                        if (shouldBeHidden !== isHidden) {
                            card.removeAttribute('data-fab-processed');
                            unprocessedCount++;
                        }
                    }
                });

                // 如果有未处理的卡片,重新执行隐藏逻辑
                if (unprocessedCount > 0) {
                    if (State.debugMode) {
                        Utils.logger('debug', Utils.getText('debug_unprocessed_cards', unprocessedCount));
                    }
                    TaskRunner.runHideOrShow();
                }
            }, 3000); // 每3秒检查一次

        // 添加定期检查功能,每10秒检查一次待办列表中的任务是否已经完成
        setInterval(() => {
            // 如果待办列表为空,不需要检查
            if (State.db.todo.length === 0) return;

            // 检查待办列表中的每个任务,看是否已经在"完成"列表中
            const initialTodoCount = State.db.todo.length;
            State.db.todo = State.db.todo.filter(task => {
                const url = task.url.split('?')[0];
                // 如果任务已经在"完成"列表中,则从待办列表中移除
                return !State.db.done.includes(url);
            });

            // 如果待办列表的数量发生了变化,更新UI
            if (State.db.todo.length < initialTodoCount) {
                Utils.logger('info', `[自动清理] 从待办列表中移除了 ${initialTodoCount - State.db.todo.length} 个已完成的任务。`);
                UI.update();
            }
        }, 10000);

        // 添加定期检查功能,检测是否请求不出新商品(隐性限速)
        let lastCardCount = document.querySelectorAll(Config.SELECTORS.card).length;
        let noNewCardsCounter = 0;
        let lastScrollY = window.scrollY;

        setInterval(() => {
            // 如果已经处于限速状态,不需要检查
            if (State.appStatus !== 'NORMAL') return;

            // 获取当前卡片数量
            const currentCardCount = document.querySelectorAll(Config.SELECTORS.card).length;

            // 如果滚动了但卡片数量没有增加,可能是隐性限速
            if (window.scrollY > lastScrollY + 100 && currentCardCount === lastCardCount) {
                noNewCardsCounter++;

                // 如果连续3次检查都没有新卡片,认为是隐性限速
                if (noNewCardsCounter >= 3) {
                    Utils.logger('warn', `${Utils.getText('implicit_rate_limit_detection')} ${Utils.getText('detected_possible_rate_limit_scroll', noNewCardsCounter)}`);
                    try {
                        // 使用RateLimitManager处理限速
                        RateLimitManager.enterRateLimitedState(Utils.getText('source_implicit_rate_limit'));
                    } catch (error) {
                        Utils.logger('error', `处理限速出错: ${error.message}`);
                        // 备选方案:直接刷新页面
                        const randomDelay = 5000 + Math.random() * 10000;
                        countdownRefresh(randomDelay, Utils.getText('source_implicit_rate_limit'));
                    }
                    noNewCardsCounter = 0;
                }
            } else if (currentCardCount > lastCardCount) {
                // 有新卡片,重置计数器
                noNewCardsCounter = 0;
            }

            // 更新上次卡片数量和滚动位置
            lastCardCount = currentCardCount;
            lastScrollY = window.scrollY;
        }, 5000); // 每5秒检查一次

        // 添加页面内容检测功能,定期检查页面是否显示了限速错误信息
        setInterval(() => {
            // 如果已经处于限速状态,不需要检查
            if (State.appStatus !== 'NORMAL') return;

            // 检查页面内容是否包含限速错误信息
            const pageText = document.body.innerText || '';
            const jsonPattern = /\{\s*"detail"\s*:\s*"Too many requests"\s*\}/i;

            if (pageText.match(jsonPattern) ||
                pageText.includes('Too many requests') ||
                pageText.includes('rate limit')) {

                Utils.logger('warn', Utils.getText('page_content_rate_limit_detected'));
                try {
                    // 直接使用全局函数,避免使用PagePatcher.handleRateLimit
                    if (typeof window.enterRateLimitedState === 'function') {
                        window.enterRateLimitedState();
                } else {
                        // 最后的备选方案:直接刷新页面
                        const randomDelay = 5000 + Math.random() * 10000;
                        countdownRefresh(randomDelay, '页面内容检测');
                }
                } catch (error) {
                    Utils.logger('error', `处理限速出错: ${error.message}`);
                    // 最后的备选方案:直接刷新页面
                    const randomDelay = 5000 + Math.random() * 10000;
                    countdownRefresh(randomDelay, '错误恢复');
                }
            }
        }, 3000); // 每3秒检查一次

        // 添加HTTP状态码检测功能,定期检查当前页面的HTTP状态码
        const checkHttpStatus = async () => {
            try {
                // 如果已经处于限速状态,不需要检查
                if (State.appStatus !== 'NORMAL') return;

                // 使用window.performance API检查最近的页面请求
                if (window.performance && window.performance.getEntriesByType) {
                    const navigationEntries = window.performance.getEntriesByType('navigation');
                    if (navigationEntries && navigationEntries.length > 0) {
                        const lastNavigation = navigationEntries[0];
                        if (lastNavigation.responseStatus === 429) {
                            Utils.logger('warn', `[HTTP状态检测] 检测到导航请求状态码为429!`);
                            if (typeof window.enterRateLimitedState === 'function') {
                                window.enterRateLimitedState();
                            } else {
                                const randomDelay = 5000 + Math.random() * 10000;
                                countdownRefresh(randomDelay, 'HTTP状态检测');
                            }
                            return;
                        }
                    }
                }

                // 不再发送HEAD请求,只使用Performance API
                Utils.logger('debug', `[HTTP状态检测] ${Utils.getText('http_status_check_performance_api')}`);

                // 检查页面内容是否包含限速信息
                const pageText = document.body.innerText || '';
                if (pageText.includes('Too many requests') ||
                    pageText.includes('rate limit') ||
                    pageText.match(/\{\s*"detail"\s*:\s*"Too many requests"\s*\}/i)) {

                    Utils.logger('warn', `[HTTP状态检测] 页面内容包含限速信息,判断为429状态`);
                    try {
                        // 直接使用全局函数,避免使用PagePatcher.handleRateLimit
                        if (typeof window.enterRateLimitedState === 'function') {
                            window.enterRateLimitedState();
                        } else {
                            // 最后的备选方案:直接刷新页面
                            const randomDelay = 5000 + Math.random() * 10000;
                            countdownRefresh(randomDelay, 'HTTP状态检测');
                        }
                    } catch (error) {
                        Utils.logger('error', `处理限速出错: ${error.message}`);
                        // 最后的备选方案:直接刷新页面
                        const randomDelay = 5000 + Math.random() * 10000;
                        countdownRefresh(randomDelay, '错误恢复');
                    }
                }
            } catch (error) {
                // 忽略错误
            }
        };

        // 每10秒检查一次HTTP状态码
        setInterval(checkHttpStatus, 10000);

        // 添加状态监控,定期检查页面状态
        const checkPageStatus = async () => {
            try {
                // 重新计算实际可见的商品数量,确保与DOM状态同步
                const totalCards = document.querySelectorAll(Config.SELECTORS.card).length;

                // 使用更准确的方式检查元素是否可见
                const visibleCards = Array.from(document.querySelectorAll(Config.SELECTORS.card)).filter(card => {
                    // 检查元素自身的display属性
                    if (card.style.display === 'none') return false;

                    // 检查是否被CSS规则隐藏
                    const computedStyle = window.getComputedStyle(card);
                    return computedStyle.display !== 'none' && computedStyle.visibility !== 'hidden';
                });

                const actualVisibleCards = visibleCards.length;
                const hiddenCards = totalCards - actualVisibleCards;

                // 更新UI显示的可见商品数量,确保UI与实际DOM状态一致
                const visibleCountElement = document.getElementById('fab-status-visible');
                if (visibleCountElement) {
                    visibleCountElement.textContent = actualVisibleCards.toString();
                }

                // 更新全局状态
                State.hiddenThisPageCount = hiddenCards;

                // 如果处于限速状态且没有可见商品,考虑刷新
                // 只有在明确开启了自动刷新功能时才触发
                if (State.appStatus === 'RATE_LIMITED' && actualVisibleCards === 0 && State.autoRefreshEmptyPage) {
                    // 如果已经有倒计时在运行,不要干扰它
                    if (window._pendingZeroVisibleRefresh || currentCountdownInterval || currentRefreshTimeout) {
                        return;
                    }

                    Utils.logger('info', `[状态监控] 检测到限速状态下没有可见商品且自动刷新已开启,准备刷新页面`);
                    const randomDelay = 3000 + Math.random() * 2000; // 3-5秒的短延迟
                    countdownRefresh(randomDelay, '限速状态无可见商品');
                    return;
                }

                // 移除正常状态下因隐藏商品而自动刷新的逻辑
                // 如果处于正常状态且所有商品都被隐藏,只记录日志,不触发刷新
                if (State.appStatus === 'NORMAL' && actualVisibleCards === 0 && hiddenCards > 25) {
                    Utils.logger('info', `[状态监控] ${Utils.getText('status_monitor_all_hidden', hiddenCards)}`);
                    return;
                }

                // 使用window.performance API检查最近的API请求
                if (window.performance && window.performance.getEntriesByType) {
                    const recentRequests = window.performance.getEntriesByType('resource')
                        .filter(r => r.name.includes('/i/listings/search') || r.name.includes('/i/users/me/listings-states'))
                        .filter(r => Date.now() - r.startTime < 15000); // 最近15秒内的请求

                    // 检查是否有429状态码的请求
                    const has429 = recentRequests.some(r => r.responseStatus === 429);
                    if (has429 && State.appStatus === 'NORMAL') {
                        Utils.logger('warn', `[状态监控] 检测到最近15秒内有429状态码的请求,进入限速状态`);
                        if (typeof window.enterRateLimitedState === 'function') {
                            window.enterRateLimitedState('性能API检测429');
                        }
                        return;
                    }

                    // 检查是否有成功的请求
                    const hasSuccess = recentRequests.some(r => r.responseStatus >= 200 && r.responseStatus < 300);
                    if (hasSuccess && State.appStatus === 'RATE_LIMITED' && State.consecutiveSuccessCount >= 2) {
                        Utils.logger('info', `[状态监控] 检测到最近15秒内有成功的API请求,尝试退出限速状态`);
                        if (typeof RateLimitManager.exitRateLimitedState === 'function') {
                            RateLimitManager.exitRateLimitedState('性能API检测成功');
                        }
                    }
                }
            } catch (error) {
                Utils.logger('error', `页面状态检查出错: ${error.message}`);
            }
        };

        // 每10秒检查一次页面状态
        setInterval(checkPageStatus, 10000);

        // 添加定期检查功能,确保待办任务能被执行
        setInterval(() => {
            // 如果没有待办任务,不需要检查
            if (State.db.todo.length === 0) return;

            // 确保任务被执行
            TaskRunner.ensureTasksAreExecuted();
        }, 5000); // 每5秒检查一次

        // 添加专门针对滚动加载API请求的拦截器
        const originalXMLHttpRequestSend = XMLHttpRequest.prototype.send;
        XMLHttpRequest.prototype.send = function(...args) {
            const xhr = this;

            // 添加额外的事件监听器,专门用于检测429错误
            xhr.addEventListener('load', function() {
                // 只检查listings/search相关的请求
                if (xhr._url && xhr._url.includes('/i/listings/search')) {
                    // 检查状态码
                    if (xhr.status === 429 || xhr.status === '429' || xhr.status.toString() === '429') {
                        Utils.logger('warn', `${Utils.getText('scroll_api_monitoring')} ${Utils.getText('detected_api_429_status', xhr._url)}`);
                        try {
                            // 直接使用全局函数,避免使用PagePatcher.handleRateLimit
                            if (typeof window.enterRateLimitedState === 'function') {
                                window.enterRateLimitedState();
                            } else {
                                // 最后的备选方案:直接刷新页面
                                const randomDelay = 5000 + Math.random() * 10000;
                                countdownRefresh(randomDelay, Utils.getText('source_scroll_api_monitoring'));
                            }
                        } catch (error) {
                            Utils.logger('error', `处理限速出错: ${error.message}`);
                            // 最后的备选方案:直接刷新页面
                            const randomDelay = 5000 + Math.random() * 10000;
                            countdownRefresh(randomDelay, '错误恢复');
                        }
                        return;
                    }

                    // 检查响应内容
                    try {
                        const responseText = xhr.responseText;
                        if (responseText && (
                            responseText.includes('Too many requests') ||
                            responseText.match(/\{\s*"detail"\s*:\s*"Too many requests"\s*\}/i)
                        )) {
                            Utils.logger('warn', `${Utils.getText('scroll_api_monitoring')} ${Utils.getText('detected_api_rate_limit_content', responseText)}`);
                            try {
                                // 直接使用全局函数,避免使用PagePatcher.handleRateLimit
                                if (typeof window.enterRateLimitedState === 'function') {
                                    window.enterRateLimitedState();
                                } else {
                                    // 最后的备选方案:直接刷新页面
                                    const randomDelay = 5000 + Math.random() * 10000;
                                    countdownRefresh(randomDelay, Utils.getText('source_scroll_api_monitoring'));
                                }
                            } catch (error) {
                                Utils.logger('error', `处理限速出错: ${error.message}`);
                                // 最后的备选方案:直接刷新页面
                                const randomDelay = 5000 + Math.random() * 10000;
                                countdownRefresh(randomDelay, '错误恢复');
                            }
                            return;
                        }
                    } catch (e) {
                        // 忽略错误
                    }
                }
            });

            return originalXMLHttpRequestSend.apply(this, args);
        };
    }

    main();

    // 添加一个通用的倒计时刷新函数
    // 使用一个全局变量来跟踪当前的倒计时,避免多个倒计时同时运行
    let currentCountdownInterval = null;
    let currentRefreshTimeout = null;

    const countdownRefresh = (delay, reason = '备选方案') => {
        // 如果已经安排了刷新,不要重复安排
        if (State.isRefreshScheduled) {
            Utils.logger('info', Utils.getText('refresh_plan_exists').replace('(429自动恢复)', `(${reason})`));
            return;
        }

        // 标记已安排刷新
        State.isRefreshScheduled = true;

        // 如果已经有倒计时在运行,先清除它
        if (currentCountdownInterval) {
            clearInterval(currentCountdownInterval);
            currentCountdownInterval = null;
        }
        if (currentRefreshTimeout) {
            clearTimeout(currentRefreshTimeout);
            currentRefreshTimeout = null;
        }

        // 添加空值检查,防止delay为null
        const seconds = delay ? (delay/1000).toFixed(1) : '未知';

        // 添加明显的倒计时日志
        Utils.logger('info', `🔄 ${reason}启动!将在 ${seconds} 秒后刷新页面尝试恢复...`);

        // 每秒更新倒计时日志
        let remainingSeconds = Math.ceil(delay/1000);
        currentCountdownInterval = setInterval(() => {
            remainingSeconds--;
            if (remainingSeconds <= 0) {
                clearInterval(currentCountdownInterval);
                currentCountdownInterval = null;
                                    Utils.logger('info', `⏱️ 倒计时结束,正在刷新页面...`);
                } else {
                    Utils.logger('info', Utils.getText('auto_refresh_countdown', remainingSeconds));

                    // 如果用户手动取消了刷新标记
                    if (!State.isRefreshScheduled) {
                        Utils.logger('info', `⏹️ 检测到刷新已被取消,停止倒计时`);
                        clearInterval(currentCountdownInterval);
                        currentCountdownInterval = null;

                        if (currentRefreshTimeout) {
                            clearTimeout(currentRefreshTimeout);
                            currentRefreshTimeout = null;
                        }
                        return;
                    }

                // 每3秒重新检查一次条件
                if (remainingSeconds % 3 === 0) {
                    // 尝试使用优化后的API函数检查限速状态
                    checkRateLimitStatus().then(isNotLimited => {
                        if (isNotLimited) {
                            Utils.logger('info', `⏱️ 检测到API限速已解除,取消刷新...`);
                            clearInterval(currentCountdownInterval);
                            currentCountdownInterval = null;

                            if (currentRefreshTimeout) {
                                clearTimeout(currentRefreshTimeout);
                                currentRefreshTimeout = null;
                            }

                            // 重置刷新标记
                            State.isRefreshScheduled = false;

                            // 恢复正常状态
                            if (State.appStatus === 'RATE_LIMITED') {
                                RateLimitManager.exitRateLimitedState();
                            }

                            return;
                        }

                        // 如果是429限速状态,则检查可见商品是否为0
                        if (State.appStatus === 'RATE_LIMITED') {
                            // 使用UI上显示的可见商品数量作为判断依据
                            const actualVisibleCount = parseInt(document.getElementById('fab-status-visible')?.textContent || '0');

                            // 只检查是否有待办任务或活动工作线程
                            if (State.db.todo.length > 0 || State.activeWorkers > 0) {
                                clearInterval(currentCountdownInterval);
                                clearTimeout(currentRefreshTimeout);
                                currentCountdownInterval = null;
                                currentRefreshTimeout = null;
                                // 重置刷新标记
                                State.isRefreshScheduled = false;
                                Utils.logger('info', `⏹️ 检测到有 ${State.db.todo.length} 个待办任务和 ${State.activeWorkers} 个活动工作线程,已取消自动刷新。`);
                                Utils.logger('warn', '⚠️ 刷新条件已变化,自动刷新已取消。');
                                return;
                            }

                            // 如果没有实际可见的商品,继续刷新
                            if (actualVisibleCount === 0) {
                                Utils.logger('info', Utils.getText('rate_limit_no_visible_continue'));
                            } else {
                                Utils.logger('info', `⏹️ 虽然处于限速状态,但页面上有 ${actualVisibleCount} 个可见商品,暂不刷新。`);
                                clearInterval(currentCountdownInterval);
                                clearTimeout(currentRefreshTimeout);
                                currentCountdownInterval = null;
                                currentRefreshTimeout = null;
                                return;
                            }
                        } else {
                            // 正常状态下,如果有可见商品、待办任务或活动工作线程,则取消刷新
                            // 使用UI上显示的可见商品数量
                            const visibleCount = parseInt(document.getElementById('fab-status-visible')?.textContent || '0');

                            if (State.db.todo.length > 0 || State.activeWorkers > 0 || visibleCount > 0) {
                                clearInterval(currentCountdownInterval);
                                clearTimeout(currentRefreshTimeout);
                                currentCountdownInterval = null;
                                currentRefreshTimeout = null;
                                // 重置刷新标记
                                State.isRefreshScheduled = false;

                                if (visibleCount > 0) {
                                    Utils.logger('info', `⏹️ 检测到页面上有 ${visibleCount} 个可见商品,已取消自动刷新。`);
                                } else {
                                    Utils.logger('info', `⏹️ 检测到有 ${State.db.todo.length} 个待办任务和 ${State.activeWorkers} 个活动工作线程,已取消自动刷新。`);
                                }
                                Utils.logger('warn', '⚠️ 刷新条件已变化,自动刷新已取消。');
                                return;
                            }
                        }
                    }).catch(e => {
                        if (State.debugMode) {
                            Utils.logger('debug', `检查限速状态出错: ${e.message}`);
                        }
                    });
                }
            }
        }, 1000);

        // 设置刷新定时器
        currentRefreshTimeout = setTimeout(() => {
            // 最后一次检查条件,确保在刷新前条件仍然满足
            // 使用UI上显示的可见商品数量
            const visibleCount = parseInt(document.getElementById('fab-status-visible')?.textContent || '0');

            // 如果是429限速状态,检查实际可见商品
            if (State.appStatus === 'RATE_LIMITED') {
                // 使用UI上显示的可见商品数量
                const actualVisibleCount = parseInt(document.getElementById('fab-status-visible')?.textContent || '0');

                // 只检查是否有待办任务或活动工作线程
                if (State.db.todo.length > 0 || State.activeWorkers > 0) {
                    Utils.logger('info', `⏹️ 刷新前检测到有 ${State.db.todo.length} 个待办任务和 ${State.activeWorkers} 个活动工作线程,已取消自动刷新。`);
                    Utils.logger('warn', '⚠️ 最后一刻检查:刷新条件不满足,自动刷新已取消。');
                    State.isRefreshScheduled = false; // 重置刷新标记
                    return;
                }

                // 如果没有实际可见的商品,执行刷新
                if (actualVisibleCount === 0) {
                    Utils.logger('info', `🔄 页面上没有可见商品且处于限速状态,将执行自动刷新。`);
                    // 使用更可靠的刷新方式
                    window.location.href = window.location.href;
                } else {
                    Utils.logger('info', `⏹️ 虽然处于限速状态,但页面上有 ${actualVisibleCount} 个可见商品,取消自动刷新。`);
                    State.isRefreshScheduled = false; // 重置刷新标记
                    return;
                }
            } else {
                // 正常状态下的检查
                if (State.db.todo.length > 0 || State.activeWorkers > 0 || visibleCount > 0) {
                    if (visibleCount > 0) {
                        Utils.logger('info', `⏹️ 刷新前检测到页面上有 ${visibleCount} 个可见商品,已取消自动刷新。`);
                    } else {
                        Utils.logger('info', `⏹️ 刷新前检测到有 ${State.db.todo.length} 个待办任务和 ${State.activeWorkers} 个活动工作线程,已取消自动刷新。`);
                    }
                    Utils.logger('warn', '⚠️ 最后一刻检查:刷新条件不满足,自动刷新已取消。');
                    State.isRefreshScheduled = false; // 重置刷新标记
                } else {
                    // 所有条件都满足,执行刷新
                    // 使用更可靠的刷新方式
                    window.location.href = window.location.href;
                }
            }
        }, delay);
    };

    // 优化后的限速状态检查函数 - 完全依赖网站自身请求流量
    async function checkRateLimitStatus() {
        try {
            // 重新计算实际可见的商品数量,确保与DOM状态同步
            const totalCards = document.querySelectorAll(Config.SELECTORS.card).length;
            const hiddenCards = document.querySelectorAll(`${Config.SELECTORS.card}[style*="display: none"]`).length;
            const actualVisibleCards = totalCards - hiddenCards;

            // 更新UI显示的可见商品数量,确保UI与实际DOM状态一致
            const visibleCountElement = document.getElementById('fab-status-visible');
            if (visibleCountElement) {
                visibleCountElement.textContent = actualVisibleCards.toString();
            }

            // 使用实际DOM状态更新全局状态
            State.hiddenThisPageCount = hiddenCards;

            Utils.logger('info', Utils.getText('status_check_summary', actualVisibleCards, totalCards, hiddenCards));

            // 如果处于限速状态且没有可见商品,直接返回false触发刷新
            if (State.appStatus === 'RATE_LIMITED' && actualVisibleCards === 0) {
                Utils.logger('info', Utils.getText('rate_limit_no_visible_suggest'));
                return false;
            }

            // 即使在正常状态下,如果所有商品都被隐藏且隐藏的商品数量超过25个,也建议刷新
            if (actualVisibleCards === 0 && hiddenCards > 25) {
                Utils.logger('info', Utils.getText('page_status_suggest_refresh', hiddenCards));
                return false;
            }

            // 使用window.performance API检查最近的网络请求
            if (window.performance && window.performance.getEntriesByType) {
                const recentRequests = window.performance.getEntriesByType('resource')
                    .filter(r => r.name.includes('/i/listings/search') || r.name.includes('/i/users/me/listings-states'))
                    .filter(r => Date.now() - r.startTime < 10000); // 最近10秒内的请求

                // 如果有最近的请求,检查它们的状态
                if (recentRequests.length > 0) {
                    // 检查是否有429状态码的请求
                    const has429 = recentRequests.some(r => r.responseStatus === 429);
                    if (has429) {
                        Utils.logger('info', `📊 检测到最近10秒内有429状态码的请求,判断为限速状态`);
                        return false;
                    }

                    // 检查是否有成功的请求
                    const hasSuccess = recentRequests.some(r => r.responseStatus >= 200 && r.responseStatus < 300);
                    if (hasSuccess) {
                        Utils.logger('info', `📊 检测到最近10秒内有成功的API请求,判断为正常状态`);
                        return true;
                    }
                }

                // 如果没有最近的请求或者没有明确的成功/失败状态,保持当前状态
                return State.appStatus === 'NORMAL';
            }

            // 如果无法使用Performance API,根据当前状态返回
            // 在限速状态下返回false,表示需要刷新
            // 在正常状态下返回true,表示不需要刷新
            return State.appStatus === 'NORMAL';
        } catch (error) {
            Utils.logger('error', `检查限速状态出错: ${error.message}`);
            // 出错时保守处理,认为仍然处于限速状态
            return false;
        }
    }

    // 在页面卸载时清理实例
    window.addEventListener('beforeunload', () => {
        InstanceManager.cleanup();
        Utils.cleanup();
    });

    // 添加请求拦截器设置函数
    function setupRequestInterceptors() {
        try {
            // 设置XHR拦截器
            setupXHRInterceptor();

            // 设置Fetch拦截器
            setupFetchInterceptor();

            // 设置定期清理过期缓存的定时器
            setInterval(() => DataCache.cleanupExpired(), 60000); // 每分钟清理一次

            Utils.logger('info', '请求拦截和缓存系统已初始化');
        } catch (e) {
            Utils.logger('error', `初始化请求拦截器失败: ${e.message}`);
        }
    }

    // 设置XHR拦截器
    function setupXHRInterceptor() {
        const originalOpen = XMLHttpRequest.prototype.open;
        const originalSend = XMLHttpRequest.prototype.send;

        XMLHttpRequest.prototype.open = function(...args) {
            this._url = args[1]; // 保存URL以便后续使用
            return originalOpen.apply(this, args);
        };

        XMLHttpRequest.prototype.send = function(...args) {
            const xhr = this;

            // 只拦截相关API请求
            if (xhr._url && typeof xhr._url === 'string') {
                // 添加加载完成事件监听器
                xhr.addEventListener('load', function() {
                    if (xhr.readyState === 4 && xhr.status === 200) {
                        try {
                            const responseData = JSON.parse(xhr.responseText);

                            // 处理商品列表搜索响应
                            if (xhr._url.includes('/i/listings/search') && responseData.results && Array.isArray(responseData.results)) {
                                DataCache.saveListings(responseData.results);
                                if (State.debugMode) {
                                    Utils.logger('debug', `[Cache] ${Utils.getText('debug_cached_items', responseData.results.length)}`);
                                }
                            }
                            // 处理拥有状态响应
                            else if (xhr._url.includes('/i/users/me/listings-states')) {
                                if (Array.isArray(responseData)) {
                                    DataCache.saveOwnedStatus(responseData);
                                } else {
                                    const extractedData = API.extractStateData(responseData, 'XHRInterceptor');
                                    if (Array.isArray(extractedData) && extractedData.length > 0) {
                                        DataCache.saveOwnedStatus(extractedData);
                                    }
                                }
                            }
                            // 处理价格信息响应
                            else if (xhr._url.includes('/i/listings/prices-infos') && responseData.offers && Array.isArray(responseData.offers)) {
                                DataCache.savePrices(responseData.offers);
                            }
                        } catch (e) {
                            // 解析错误时只在调试模式下记录
                            if (State.debugMode) {
                                Utils.logger('debug', `[Cache] 解析响应失败: ${e.message}`);
                            }
                        }
                    }
                });
            }

            return originalSend.apply(this, args);
        };

        if (State.debugMode) {
            Utils.logger('debug', '[优化] XHR拦截器已设置');
        }
    }

    // 设置Fetch拦截器
    function setupFetchInterceptor() {
        const originalFetch = window.fetch;

        window.fetch = async function(...args) {
            const url = args[0]?.toString() || '';

            // 只拦截相关API请求
            if (url.includes('/i/listings/search') ||
                url.includes('/i/users/me/listings-states') ||
                url.includes('/i/listings/prices-infos')) {

                try {
                    // 执行原始fetch请求
                    const response = await originalFetch.apply(this, args);

                    // 如果请求成功,处理响应数据
                    if (response.ok) {
                        // 克隆响应以避免消耗原始响应
                        const clonedResponse = response.clone();

                        // 异步处理响应数据
                        clonedResponse.json().then(data => {
                            // 处理商品列表搜索响应 - 简化版
                            if (url.includes('/i/listings/search') && data.results && Array.isArray(data.results)) {
                                DataCache.saveListings(data.results);
                            }
                            // 处理拥有状态响应
                            else if (url.includes('/i/users/me/listings-states')) {
                                if (Array.isArray(data)) {
                                    Utils.logger('info', `[网页请求] 捕获到拥有状态API响应,包含 ${data.length} 个商品状态`);
                                    DataCache.saveOwnedStatus(data);
                                } else {
                                    const extractedData = API.extractStateData(data, 'FetchInterceptor');
                                    if (Array.isArray(extractedData) && extractedData.length > 0) {
                                        Utils.logger('info', `[网页请求] 捕获到拥有状态API响应,提取出 ${extractedData.length} 个商品状态`);
                                        DataCache.saveOwnedStatus(extractedData);
                                    }
                                }
                            }
                            // 处理价格信息响应
                            else if (url.includes('/i/listings/prices-infos') && data.offers && Array.isArray(data.offers)) {
                                DataCache.savePrices(data.offers);
                            }
                        }).catch((e) => {
                            // 解析错误时只在调试模式下记录
                            if (State.debugMode) {
                                Utils.logger('debug', `[Cache] Fetch: 解析响应失败: ${e.message}`);
                            }
                        });
                    }

                    // 返回原始响应
                    return response;
                } catch (e) {
                    // 请求错误,继续使用原始fetch
                    Utils.logger('error', `[Cache] Fetch拦截器错误: ${e.message}`);
                    return originalFetch.apply(this, args);
                }
            }

            // 非相关API请求,直接使用原始fetch
            return originalFetch.apply(this, args);
        };

        if (State.debugMode) {
            Utils.logger('debug', '[优化] Fetch拦截器已设置');
        }
    }

    // 添加一个函数,确保UI在刷新后能正确重新加载
    function ensureUILoaded() {
        // 检查UI是否已加载
        if (!document.getElementById(Config.UI_CONTAINER_ID)) {
            // 如果UI未加载,尝试重新初始化
            Utils.logger('warn', '检测到UI未加载,尝试重新初始化...');

            // 延迟执行,确保页面已完全加载
            setTimeout(() => {
                try {
                    // 重新执行初始化逻辑
                    runDomDependentPart();
                } catch (error) {
                    Utils.logger('error', `UI重新初始化失败: ${error.message}`);
                }
            }, 1000);
        }
    }

    // 添加页面加载完成后的检查
    window.addEventListener('load', () => {
        // 延迟检查,确保所有脚本都有机会执行
        setTimeout(ensureUILoaded, 2000);
    });

    // 添加可见性变化检查,处理标签页切换回来的情况
    document.addEventListener('visibilitychange', () => {
        if (document.visibilityState === 'visible') {
            // 页面变为可见时检查UI
            setTimeout(ensureUILoaded, 500);
        }
    });

})();