YUC.Wiki 番剧标记助手

在YUC.Wiki上标记番剧为已阅或删除状态,支持显示/隐藏标记番剧,一键复制动画名称

// ==UserScript==
// @name         YUC.Wiki 番剧标记助手
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  在YUC.Wiki上标记番剧为已阅或删除状态,支持显示/隐藏标记番剧,一键复制动画名称
// @author       Cylirix
// @match        https://yuc.wiki/*
// @exclude      https://yuc.wiki/new/*
// @exclude      https://yuc.wiki/
// @license      MIT license
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand

// ==/UserScript==


(function() {
    'use strict';

    // 配置存储键名
    const STORAGE_KEY = 'YUC_ANIME_TRACKER_STATE';
    const SETTINGS_KEY = 'YUC_TRACKER_SETTINGS';
    const DETAILS_STATE_KEY = 'YUC_DETAILS_STATE';

    // PASS状态基础滤镜
    const BASE_PASS_FILTER = 'sepia(100%) hue-rotate(-50deg) saturate(500%) brightness(0.7)';

    // 默认设置
    const defaultSettings = {
        readOpacity: 0.5,
        buttonOpacity: 1.0,
        showRead: true,
        showPass: true,
        panelOpen: false,
        effectsEnabled: true,
        passOpacity: 0.3,
        hoverPanelOpen: false,
        keepPanelOpen: false
    };

    // 加载设置
    function loadSettings() {
        const saved = GM_getValue(SETTINGS_KEY, JSON.stringify(defaultSettings));
        return {...defaultSettings, ...JSON.parse(saved)};
    }

    // 保存设置
    function saveSettings(settings) {
        GM_setValue(SETTINGS_KEY, JSON.stringify(settings));
    }

    // 加载动画状态
    function loadAnimeState() {
        const saved = GM_getValue(STORAGE_KEY, '{}');
        return JSON.parse(saved);
    }

    // 保存动画状态
    function saveAnimeState(state) {
        GM_setValue(STORAGE_KEY, JSON.stringify(state));
    }

    // 加载详情展开状态
    function loadDetailsState() {
        const saved = GM_getValue(DETAILS_STATE_KEY, '{}');
        return JSON.parse(saved);
    }

    // 保存详情展开状态
    function saveDetailsState(state) {
        GM_setValue(DETAILS_STATE_KEY, JSON.stringify(state));
    }

    // 统计当前页面状态数量
    function countStates() {
        let readCount = 0;
        let passCount = 0;

        document.querySelectorAll('.anime-item').forEach(item => {
            const title = item.querySelector('.anime-title').textContent;
            const state = animeState[title];
            if (state === 'read') readCount++;
            else if (state === 'pass') passCount++;
        });

        return { readCount, passCount };
    }

    // 更新设置面板中的数量显示
    function updateCountDisplay() {
        const counts = countStates();

        if (readCounter) {
            readCounter.textContent = `(${counts.readCount})`;
        }
        if (passCounter) {
            passCounter.textContent = `(${counts.passCount})`;
        }
    }

    // 创建控制面板
    function createControlPanel() {
        let panel = document.getElementById('anime-tracker-control');
        if (!panel) {
            panel = document.createElement('div');
            panel.id = 'anime-tracker-control';
            panel.style.cssText = `
                position: fixed;
                bottom: 118px; /* 在悬浮球上方**px处 */
                right: 20px;
                background: rgba(255, 255, 255, 0.55); /* 设置区域透明度 */
                padding: 18px;
                border-radius: 20px;
                box-shadow: 0 0 15px rgba(0,0,0,0.2);
                z-index: 9999;
                font-family: 'Microsoft YaHei', sans-serif;
                max-width: 300px;
                border: 1px solid #ddd;
                transition: transform 0.3s ease;
                transform: translateY(${settings.hoverPanelOpen ? '0' : '20px'});
            `;

            // 标题栏
            const header = document.createElement('div');
            header.style.display = 'flex';
            header.style.justifyContent = 'space-between';
            header.style.alignItems = 'center';
            header.style.marginBottom = '8px';
            const title = document.createElement('h3');
            title.textContent = 'YUC.WIKI 番剧标记助手';//设置面板标题
            title.style.margin = '0';
            title.style.fontSize = '16px';
            const closeBtn = document.createElement('button');
            closeBtn.textContent = '×';
            closeBtn.style.cssText = `
                background: none;
                border: none;
                font-size: 20px;
                cursor: pointer;
                color: #999;
                padding: 0;
                line-height: 1;
            `;
            closeBtn.addEventListener('click', () => {
                settings.panelOpen = false;
                settings.hoverPanelOpen = false;
                saveSettings(settings);
                panel.style.display = 'none';
                toggleFloatingBall(true);
            });
            header.appendChild(title);
            header.appendChild(closeBtn);
            panel.appendChild(header);

            // 已阅透明度控制
            const opacityRow = document.createElement('div');
            opacityRow.style.display = 'flex';
            opacityRow.style.alignItems = 'center';
            opacityRow.style.marginBottom = '12px';
            const opacityLabel = document.createElement('label');
            opacityLabel.textContent = '已阅(状态)透明度:';
            opacityLabel.style.marginRight = '8px';
            opacityLabel.style.flex = '0 0 auto';
            opacityLabel.style.fontSize = '14px';
            const opacitySlider = document.createElement('input');
            opacitySlider.type = 'range';
            opacitySlider.min = '0.1';
            opacitySlider.max = '1.0';
            opacitySlider.step = '0.05';
            opacitySlider.value = settings.readOpacity;
            opacitySlider.style.flex = '1';
            opacitySlider.style.height = '16px';
            const opacityValue = document.createElement('div');
            opacityValue.textContent = Math.round(settings.readOpacity * 100) + '%';
            opacityValue.style.flex = '0 0 40px';
            opacityValue.style.textAlign = 'right';
            opacityValue.style.paddingLeft = '8px';
            opacityValue.style.fontSize = '14px';
            opacitySlider.addEventListener('input', () => {
                settings.readOpacity = parseFloat(opacitySlider.value);
                opacityValue.textContent = Math.round(settings.readOpacity * 100) + '%';
                applyStates();
                updateCountDisplay();
            });
            opacityRow.appendChild(opacityLabel);
            opacityRow.appendChild(opacitySlider);
            opacityRow.appendChild(opacityValue);
            panel.appendChild(opacityRow);

            // 删除透明度控制
            const passOpacityRow = document.createElement('div');
            passOpacityRow.style.display = 'flex';
            passOpacityRow.style.alignItems = 'center';
            passOpacityRow.style.marginBottom = '12px';
            const passOpacityLabel = document.createElement('label');
            passOpacityLabel.textContent = '删除(状态)透明度:';
            passOpacityLabel.style.marginRight = '8px';
            passOpacityLabel.style.flex = '0 0 auto';
            passOpacityLabel.style.fontSize = '14px';
            const passOpacitySlider = document.createElement('input');
            passOpacitySlider.type = 'range';
            passOpacitySlider.min = '0';
            passOpacitySlider.max = '1';
            passOpacitySlider.step = '0.05';
            passOpacitySlider.value = settings.passOpacity;
            passOpacitySlider.style.flex = '1';
            passOpacitySlider.style.height = '16px';
            const passOpacityValue = document.createElement('div');
            passOpacityValue.textContent = Math.round(settings.passOpacity * 100) + '%';
            passOpacityValue.style.flex = '0 0 40px';
            passOpacityValue.style.textAlign = 'right';
            passOpacityValue.style.paddingLeft = '8px';
            passOpacityValue.style.fontSize = '14px';
            passOpacitySlider.addEventListener('input', () => {
                settings.passOpacity = parseFloat(passOpacitySlider.value);
                passOpacityValue.textContent = Math.round(settings.passOpacity * 100) + '%';
                applyStates();
                updateCountDisplay();
            });
            passOpacityRow.appendChild(passOpacityLabel);
            passOpacityRow.appendChild(passOpacitySlider);
            passOpacityRow.appendChild(passOpacityValue);
            panel.appendChild(passOpacityRow);

            // 按钮可视度控制
            const buttonOpacityRow = document.createElement('div');
            buttonOpacityRow.style.display = 'flex';
            buttonOpacityRow.style.alignItems = 'center';
            buttonOpacityRow.style.marginBottom = '12px';
            const buttonOpacityLabel = document.createElement('label');
            buttonOpacityLabel.textContent = '按钮透明度:';
            buttonOpacityLabel.style.marginRight = '45px';
            buttonOpacityLabel.style.flex = '0 0 auto';
            buttonOpacityLabel.style.fontSize = '14px';
            const buttonOpacitySlider = document.createElement('input');
            buttonOpacitySlider.type = 'range';
            buttonOpacitySlider.min = '0.0';
            buttonOpacitySlider.max = '1.0';
            buttonOpacitySlider.step = '0.05';
            buttonOpacitySlider.value = settings.buttonOpacity;
            buttonOpacitySlider.style.flex = '1';
            buttonOpacitySlider.style.height = '16px';
            const buttonOpacityValue = document.createElement('div');
            buttonOpacityValue.textContent = Math.round(settings.buttonOpacity * 100) + '%';
            buttonOpacityValue.style.flex = '0 0 40px';
            buttonOpacityValue.style.textAlign = 'right';
            buttonOpacityValue.style.paddingLeft = '8px';
            buttonOpacityValue.style.fontSize = '14px';
            buttonOpacitySlider.addEventListener('input', () => {
                settings.buttonOpacity = parseFloat(buttonOpacitySlider.value);
                buttonOpacityValue.textContent = Math.round(settings.buttonOpacity * 100) + '%';
                applyButtonOpacity();
            });
            buttonOpacityRow.appendChild(buttonOpacityLabel);
            buttonOpacityRow.appendChild(buttonOpacitySlider);
            buttonOpacityRow.appendChild(buttonOpacityValue);
            panel.appendChild(buttonOpacityRow);

            // 显示已阅和显示删除放在同一行
            const showReadPassRow = document.createElement('div');
            showReadPassRow.style.display = 'flex';
            showReadPassRow.style.justifyContent = 'space-between';
            showReadPassRow.style.marginBottom = '12px';

            // 显示已阅开关
            const showReadContainer = document.createElement('div');
            showReadContainer.style.display = 'flex';
            showReadContainer.style.alignItems = 'center';
            showReadContainer.style.flex = '1';
            showReadContainer.style.marginRight = '10px';
            const showReadLabel = document.createElement('label');
            showReadLabel.textContent = '显示已阅:';
            showReadLabel.style.marginRight = '8px';
            showReadLabel.style.flex = '0 0 auto';
            showReadLabel.style.fontSize = '14px';
            const showReadToggle = document.createElement('div');
            showReadToggle.className = 'toggle-switch';
            showReadToggle.style.cssText = `
                width: 40px;
                height: 20px;
                background-color: ${settings.showRead ? '#4CAF50' : '#cccccc'};
                border-radius: 10px;
                position: relative;
                cursor: pointer;
                transition: background-color 0.3s;
            `;
            const showReadSlider = document.createElement('div');
            showReadSlider.style.cssText = `
                position: absolute;
                top: 2px;
                left: ${settings.showRead ? '22px' : '2px'};
                width: 16px;
                height: 16px;
                background-color: white;
                border-radius: 50%;
                transition: left 0.3s;
            `;
            showReadToggle.appendChild(showReadSlider);
            showReadToggle.addEventListener('click', () => {
                settings.showRead = !settings.showRead;
                showReadToggle.style.backgroundColor = settings.showRead ? '#4CAF50' : '#cccccc';
                showReadSlider.style.left = settings.showRead ? '22px' : '2px';
                saveSettings(settings);
                applyStates();
                updateCountDisplay();
            });
            showReadContainer.appendChild(showReadLabel);
            showReadContainer.appendChild(showReadToggle);

            // 数量计数器
            readCounter = document.createElement('span');
            readCounter.className = 'counter';
            readCounter.textContent = '(0)';
            readCounter.style.marginLeft = '8px';
            readCounter.style.fontSize = '14px';
            showReadContainer.appendChild(readCounter);

            // 显示删除开关
            const showPassContainer = document.createElement('div');
            showPassContainer.style.display = 'flex';
            showPassContainer.style.alignItems = 'center';
            showPassContainer.style.flex = '1';
            const showPassLabel = document.createElement('label');
            showPassLabel.textContent = '显示删除:';
            showPassLabel.style.marginRight = '8px';
            showPassLabel.style.flex = '0 0 auto';
            showPassLabel.style.fontSize = '14px';
            const showPassToggle = document.createElement('div');
            showPassToggle.className = 'toggle-switch';
            showPassToggle.style.cssText = `
                width: 40px;
                height: 20px;
                background-color: ${settings.showPass ? '#4CAF50' : '#cccccc'};
                border-radius: 10px;
                position: relative;
                cursor: pointer;
                transition: background-color 0.3s;
            `;
            const showPassSlider = document.createElement('div');
            showPassSlider.style.cssText = `
                position: absolute;
                top: 2px;
                left: ${settings.showPass ? '22px' : '2px'};
                width: 16px;
                height: 16px;
                background-color: white;
                border-radius: 50%;
                transition: left 0.3s;
            `;
            showPassToggle.appendChild(showPassSlider);
            showPassToggle.addEventListener('click', () => {
                settings.showPass = !settings.showPass;
                showPassToggle.style.backgroundColor = settings.showPass ? '#4CAF50' : '#cccccc';
                showPassSlider.style.left = settings.showPass ? '22px' : '2px';
                saveSettings(settings);
                applyStates();
                updateCountDisplay();
            });
            showPassContainer.appendChild(showPassLabel);
            showPassContainer.appendChild(showPassToggle);

            // 数量计数器
            passCounter = document.createElement('span');
            passCounter.className = 'counter';
            passCounter.textContent = '(0)';
            passCounter.style.marginLeft = '8px';
            passCounter.style.fontSize = '14px';
            showPassContainer.appendChild(passCounter);

            showReadPassRow.appendChild(showReadContainer);
            showReadPassRow.appendChild(showPassContainer);
            panel.appendChild(showReadPassRow);

            // 全局效果和保持菜单放在同一行
            const effectsKeepRow = document.createElement('div');
            effectsKeepRow.style.display = 'flex';
            effectsKeepRow.style.justifyContent = 'space-between';
            effectsKeepRow.style.marginBottom = '12px';

            // 全局效果开关
            const effectsContainer = document.createElement('div');
            effectsContainer.style.display = 'flex';
            effectsContainer.style.alignItems = 'center';
            effectsContainer.style.flex = '1';
            effectsContainer.style.marginRight = '10px';
            const effectsLabel = document.createElement('label');
            effectsLabel.textContent = '全局效果:';
            effectsLabel.style.marginRight = '8px';
            effectsLabel.style.flex = '0 0 auto';
            effectsLabel.style.fontSize = '14px';
            const effectsToggle = document.createElement('div');
            effectsToggle.className = 'toggle-switch';
            effectsToggle.style.cssText = `
                width: 40px;
                height: 20px;
                background-color: ${settings.effectsEnabled ? '#4CAF50' : '#cccccc'};
                border-radius: 10px;
                position: relative;
                cursor: pointer;
                transition: background-color 0.3s;
            `;
            const toggleSlider = document.createElement('div');
            toggleSlider.style.cssText = `
                position: absolute;
                top: 2px;
                left: ${settings.effectsEnabled ? '22px' : '2px'};
                width: 16px;
                height: 16px;
                background-color: white;
                border-radius: 50%;
                transition: left 0.3s;
            `;
            effectsToggle.appendChild(toggleSlider);
            effectsToggle.addEventListener('click', () => {
                settings.effectsEnabled = !settings.effectsEnabled;
                effectsToggle.style.backgroundColor = settings.effectsEnabled ? '#4CAF50' : '#cccccc';
                toggleSlider.style.left = settings.effectsEnabled ? '22px' : '2px';
                saveSettings(settings);
                applyStates();
            });
            effectsContainer.appendChild(effectsLabel);
            effectsContainer.appendChild(effectsToggle);

            // 保持菜单打开开关
            const keepOpenContainer = document.createElement('div');
            keepOpenContainer.style.display = 'flex';
            keepOpenContainer.style.alignItems = 'center';
            keepOpenContainer.style.flex = '1';
            const keepOpenLabel = document.createElement('label');
            keepOpenLabel.textContent = '保持菜单:';
            keepOpenLabel.style.marginRight = '8px';
            keepOpenLabel.style.flex = '0 0 auto';
            keepOpenLabel.style.fontSize = '14px';
            const keepOpenToggle = document.createElement('div');
            keepOpenToggle.className = 'toggle-switch';
            keepOpenToggle.style.cssText = `
                width: 40px;
                height: 20px;
                background-color: ${settings.keepPanelOpen ? '#4CAF50' : '#cccccc'};
                border-radius: 10px;
                position: relative;
                cursor: pointer;
                transition: background-color 0.3s;
            `;
            const keepOpenSlider = document.createElement('div');
            keepOpenSlider.style.cssText = `
                position: absolute;
                top: 2px;
                left: ${settings.keepPanelOpen ? '22px' : '2px'};
                width: 16px;
                height: 16px;
                background-color: white;
                border-radius: 50%;
                transition: left 0.3s;
            `;
            keepOpenToggle.appendChild(keepOpenSlider);
            keepOpenToggle.addEventListener('click', () => {
                settings.keepPanelOpen = !settings.keepPanelOpen;
                keepOpenToggle.style.backgroundColor = settings.keepPanelOpen ? '#4CAF50' : '#cccccc';
                keepOpenSlider.style.left = settings.keepPanelOpen ? '22px' : '2px';
                saveSettings(settings);
            });
            keepOpenContainer.appendChild(keepOpenLabel);
            keepOpenContainer.appendChild(keepOpenToggle);

            effectsKeepRow.appendChild(effectsContainer);
            effectsKeepRow.appendChild(keepOpenContainer);
            panel.appendChild(effectsKeepRow);

            // 重置按钮容器
            const resetButtonsContainer = document.createElement('div');
            resetButtonsContainer.style.cssText = `
                display: flex;
                gap: 20px;
                margin-top: 12px;
            `;

            // 仅重置当前页面标记按钮
            const resetCurrentBtn = document.createElement('button');
            resetCurrentBtn.textContent = '重置当前页标记';
            resetCurrentBtn.style.cssText = `
                flex: 1;
                padding: 6px;
                background-color: #ff9800;
                color: white;
                border: none;
                border-radius: 10px;
                cursor: pointer;
                font-weight: bold;
                font-size: 14px;
            `;
            resetCurrentBtn.addEventListener('click', () => {
                if (confirm('确定要重置当前页面的番剧标记吗?')) {
                    // 获取当前页面所有标题
                    const currentPageTitles = [];
                    document.querySelectorAll('.anime-item').forEach(item => {
                        const title = item.querySelector('.anime-title').textContent;
                        currentPageTitles.push(title);
                    });

                    // 从状态中移除当前页面的标记
                    const newState = {...animeState};
                    currentPageTitles.forEach(title => {
                        delete newState[title];
                    });

                    // 保存新状态并刷新
                    saveAnimeState(newState);
                    location.reload();
                }
            });
            resetButtonsContainer.appendChild(resetCurrentBtn);

            // 重置所有标记按钮
            const resetAllBtn = document.createElement('button');
            resetAllBtn.textContent = '重置所有标记';
            resetAllBtn.style.cssText = `
                flex: 1;
                padding: 6px;
                background-color: #f44336;
                color: white;
                border: none;
                border-radius: 10px;
                cursor: pointer;
                font-weight: bold;
                font-size: 14px;
            `;
            resetAllBtn.addEventListener('click', () => {
                if (confirm('确定要重置所有番剧标记吗?')) {
                    GM_setValue(STORAGE_KEY, '{}');
                    location.reload();
                }
            });
            resetButtonsContainer.appendChild(resetAllBtn);

            panel.appendChild(resetButtonsContainer);

            document.body.appendChild(panel);
        }

        panel.style.display = settings.panelOpen || settings.hoverPanelOpen ? 'block' : 'none';
        toggleFloatingBall(true);
        updateCountDisplay();
    }

    // 创建悬浮球
    function createFloatingBall() {
        let ball = document.getElementById('anime-tracker-ball');
        if (!ball) {
            ball = document.createElement('div');
            ball.id = 'anime-tracker-ball';
            ball.textContent = '⚙️';
            ball.style.cssText = `
                position: fixed;
                bottom: 60px;
                right: 24px;
                width: 36px;
                height: 36px;
                background: rgba(255, 255, 255, 0.95);
                border-radius: 50%;
                box-shadow: 0 0 10px rgba(0,0,0,0.2);
                display: flex;
                align-items: center;
                justify-content: center;
                font-size: 18px;
                cursor: pointer;
                z-index: 9998;
                transition: transform 0.3s ease;

                /* 新增的禁止选中和拖动的样式 */
                user-select: none;
                -webkit-user-select: none; /* Safari/Chrome */
                -moz-user-select: none; /* Firefox */
                -ms-user-select: none; /* IE/Edge */
                -webkit-touch-callout: none; /* iOS Safari */

                /* 防止点击时出现高亮 */
                -webkit-tap-highlight-color: transparent;
                outline: none;

                /* 防止拖动鼠标时选择文本 */
                -webkit-user-drag: none;
                -khtml-user-drag: none;
                -moz-user-drag: none;
                -o-user-drag: none;
                user-drag: none;
            `;
            ball.addEventListener('mouseenter', () => {
                settings.hoverPanelOpen = true;
                saveSettings(settings);
                createControlPanel();
            });
            // 修改点击事件:切换菜单开关状态
            ball.addEventListener('click', () => {
                settings.panelOpen = !settings.panelOpen;
                settings.hoverPanelOpen = false; // 确保关闭悬浮状态
                saveSettings(settings);
                createControlPanel();
            });
            document.body.appendChild(ball);
        }
                // 添加额外的焦点处理以防止键盘选中
        ball.addEventListener('focus', () => {
            ball.blur();
        });
    }


    function toggleFloatingBall(show) {
        const ball = document.getElementById('anime-tracker-ball');
        if (ball) ball.style.display = show ? 'flex' : 'none';
    }

    // 应用按钮透明度
    function applyButtonOpacity() {
        saveSettings(settings);
        const shouldShow = settings.buttonOpacity > 0;
        document.querySelectorAll('.btn-container').forEach(container => {
            container.style.display = shouldShow ? 'flex' : 'none';
            container.style.opacity = settings.buttonOpacity;
        });
    }

    // 应用状态到动画条目
    function applyStates() {
        saveSettings(settings);

        // 应用每个番剧项的样式
        document.querySelectorAll('.anime-item').forEach(item => {
            const title = item.querySelector('.anime-title').textContent;
            const state = animeState[title] || 'none';

            // 重置样式
            const elementsToStyle = [
                '.div_date, .div_date_', 'table',
                '.date_title, .date_title_, .date_title1, .date_title2',
                '.copyright',
                '.div_sp', '.sp_title, .sp_title_'
            ];

            elementsToStyle.forEach(sel => {
                const el = item.querySelector(sel);
                if (el) {
                    el.style.opacity = '';
                    el.style.filter = '';
                    el.style.position = '';
                    el.style.zIndex = '';
                    el.querySelectorAll('.pass-overlay').forEach(o => o.remove());
                }
            });
            item.style.display = '';

            // 应用效果(如果全局效果启用)
            if (settings.effectsEnabled) {
                if (state === 'read') {
                    if (settings.showRead) {
                        elementsToStyle.forEach(sel => {
                            const el = item.querySelector(sel);
                            if (el) {
                                el.style.opacity = settings.readOpacity;
                                el.style.filter = 'grayscale(100%)';
                            }
                        });
                    } else {
                        item.style.display = 'none';
                    }
                } else if (state === 'pass') {
                    if (settings.showPass) {
                        elementsToStyle.forEach(sel => {
                            const el = item.querySelector(sel);
                            if (el) {
                                // 使用删除透明度设置
                                el.style.filter = BASE_PASS_FILTER;
                                el.style.opacity = settings.passOpacity;
                            }
                        });
                    } else {
                        item.style.display = 'none';
                    }
                }
            }

            // 应用按钮透明度
            applyButtonOpacity();
        });

        // 更新星期标题显示状态
        updateWeekHeaders();

        // 确保复制按钮在所有状态下都显示
        setupCopyButtons();
    }

    // 更新星期标题显示状态
    function updateWeekHeaders() {
        // 找到所有星期标题行
        const weekHeaders = document.querySelectorAll('table > tr > td.date2');

        weekHeaders.forEach(header => {
            const tableRow = header.closest('tr');
            const table = tableRow.closest('table');
            const container = table.closest('div');

            // 检查该星期分组下是否有可见的番剧
            let hasVisibleItems = false;
            let next = container.nextElementSibling;

            while (next && !next.querySelector('td.date2')) {
                if (next.style.display !== 'none' && window.getComputedStyle(next).display !== 'none') {
                    hasVisibleItems = true;
                    break;
                }
                next = next.nextElementSibling;
            }

            // 如果没有可见番剧,隐藏星期标题行并添加占位符
            if (!hasVisibleItems) {
                table.style.display = 'none';

                // 添加占位符
                if (!table.nextElementSibling || !table.nextElementSibling.classList.contains('week-placeholder')) {
                    const placeholder = document.createElement('div');
                    placeholder.className = 'week-placeholder';
                    placeholder.style.height = '30px'; // 占位高度
                    table.parentNode.insertBefore(placeholder, table.nextSibling);
                }
            } else {
                table.style.display = '';

                // 移除占位符
                if (table.nextElementSibling && table.nextElementSibling.classList.contains('week-placeholder')) {
                    table.nextElementSibling.remove();
                }
            }
        });
    }

    // 获取动画标题文本
    function getAnimeTitle(item) {
        // 尝试多种选择器以适应不同页面
        const titleSelectors = [
            '.date_title', '.date_title_', '.date_title1', '.date_title2',
            '.sp_title', '.sp_title_', '.date_title2'
        ];

        for (const selector of titleSelectors) {
            const titleEl = item.querySelector(selector);
            if (titleEl) {
                return titleEl.textContent.replace(/\n/g, ' ').trim();
            }
        }

        // 作为备选方案,尝试查找包含标题文本的元素
        const possibleElements = item.querySelectorAll('td[class*="title"], div[class*="title"]');
        for (const el of possibleElements) {
            if (el.textContent.trim().length > 5) { // 假设标题至少5个字符
                return el.textContent.replace(/\n/g, ' ').trim();
            }
        }

        console.warn('无法找到标题元素:', item);
        return 'Unknown';
    }

    // 设置动画条目和标记按钮
    function setupAnimeItems() {
        // 尝试多种选择器以适应不同页面
        const animeItems = document.querySelectorAll('div[style*="float:left"]:not(.anime-item)');
        if (!animeItems.length) return;

        animeItems.forEach(item => {
            const title = getAnimeTitle(item);
            if (title === 'Unknown') {
                console.warn('跳过未知标题的条目:', item);
                return;
            }

            item.classList.add('anime-item');
            const titleSpan = document.createElement('span');
            titleSpan.className = 'anime-title';
            titleSpan.textContent = title;
            titleSpan.style.display = 'none';
            item.appendChild(titleSpan);

            // 检查是否已经添加过按钮
            if (item.querySelector('.btn-container')) return;

            const btnContainer = document.createElement('div');
            btnContainer.className = 'btn-container';
            btnContainer.style.cssText = `
                display: flex;
                justify-content: center;
                gap: 6px;
                margin-top: 4px;
                position: relative;
                z-index: 2;
                opacity: ${settings.buttonOpacity};
            `;
            const readBtn = document.createElement('button');
            readBtn.textContent = '已阅';
            readBtn.style.cssText = `
                padding: 2px 6px;
                border-radius: 4px;
                border: 1px solid #4CAF50;
                background-color: rgba(76,175,80,0.2);
                color: #4CAF50;
                cursor: pointer;
                font-size: 13px;
                transition: all 0.2s;
                min-width: 50px;
            `;
            const passBtn = document.createElement('button');
            passBtn.textContent = '删除';
            passBtn.style.cssText = `
                padding: 2px 6px;
                border-radius: 5px;
                border: 1px solid #f44336;
                background-color: rgba(244,67,54,0.2);
                color: #f44336;
                cursor: pointer;
                font-size: 13px;
                min-width: 50px;
            `;

            // 仅已阅按钮添加hover效果
            readBtn.addEventListener('mouseover', () => {
                readBtn.style.backgroundColor = 'rgba(76,175,80,0.4)';
            });
            readBtn.addEventListener('mouseout', () => {
                readBtn.style.backgroundColor = 'rgba(76,175,80,0.2)';
            });

            readBtn.addEventListener('click', e => {
                e.stopPropagation();
                animeState[title] = animeState[title] === 'read' ? 'none' : 'read';
                applyStates();
                saveAnimeState(animeState);
                updateCountDisplay();
            });
            passBtn.addEventListener('click', e => {
                e.stopPropagation();
                animeState[title] = animeState[title] === 'pass' ? 'none' : 'pass';
                applyStates();
                saveAnimeState(animeState);
                updateCountDisplay();
            });

            btnContainer.appendChild(readBtn);
            btnContainer.appendChild(passBtn);

            // 尝试多种插入位置以适应不同页面
            const table = item.querySelector('table');
            if (table) {
                table.parentNode.insertBefore(btnContainer, table.nextSibling);
            } else {
                const img = item.querySelector('.div_sp');
                if (img) {
                    img.parentNode.insertBefore(btnContainer, img.nextSibling);
                } else {
                    item.appendChild(btnContainer);
                }
            }
        });

        // 初始加载时设置复制按钮
        setupCopyButtons();
    }

    // 设置复制按钮(在文字区域内)
    function setupCopyButtons() {
        const animeItems = document.querySelectorAll('.anime-item');
        if (!animeItems.length) return;

        animeItems.forEach(item => {
            const title = item.querySelector('.anime-title').textContent;

            // 尝试多种选择器以适应不同页面
            const titleSelectors = [
                '.date_title', '.date_title_', '.date_title1, .date_title2',
                '.sp_title', '.sp_title_'
            ];

            let titleEl = null;
            for (const selector of titleSelectors) {
                titleEl = item.querySelector(selector);
                if (titleEl) break;
            }

            if (!titleEl) {
                // 作为备选方案,尝试查找包含标题文本的元素
                const possibleElements = item.querySelectorAll('td[class*="title"], div[class*="title"]');
                for (const el of possibleElements) {
                    if (el.textContent.trim().length > 5) { // 假设标题至少5个字符
                        titleEl = el;
                        break;
                    }
                }
            }

            if (!titleEl) {
                console.warn('无法找到标题元素用于复制按钮:', item);
                return;
            }

            // 移除已有的复制按钮
            const existingCopyBtn = item.querySelector('.copy-btn');
            if (existingCopyBtn) existingCopyBtn.remove();

            // 创建复制按钮放在标题元素内
            const copyBtn = document.createElement('button');
            copyBtn.className = 'copy-btn';
            copyBtn.textContent = '复制';
            copyBtn.title = '复制标题';
            copyBtn.style.cssText = `
                position: absolute;
                top: 2px;
                right: 4px;
                padding: 2px 6px;
                font-size: 11px;
                background: rgba(0,0,0,0.6);
                color: #fff;
                border: none;
                border-radius: 3px;
                opacity: 0;
                cursor: pointer;
                transition: opacity 0.2s;
                z-index: 99999; /* 最高层级 */
                pointer-events: auto;
                filter: none !important; /* 确保不受父元素滤镜影响 */
            `;

            // 确保标题元素有相对定位
            titleEl.style.position = 'relative';
            titleEl.appendChild(copyBtn);

            // 悬浮显示/隐藏
            titleEl.addEventListener('mouseenter', () => {
                copyBtn.style.opacity = '1';
            });
            titleEl.addEventListener('mouseleave', () => {
                copyBtn.style.opacity = '0';
            });

            copyBtn.addEventListener('click', e => {
                e.stopPropagation();
                navigator.clipboard.writeText(title).then(() => {
                    const old = copyBtn.textContent;
                    copyBtn.textContent = '已复制!';
                    copyBtn.style.background = '#4CAF50';
                    setTimeout(() => {
                        copyBtn.textContent = old;
                        copyBtn.style.background = 'rgba(0,0,0,0.6)';
                    }, 1000);
                });
            });
        });
    }

    // 设置详情折叠状态保存
    function setupDetails() {
        const detailsEls = document.querySelectorAll('details');
        const detailsState = loadDetailsState();
        detailsEls.forEach((d, i) => {
            const key = `details_${i}`;
            if (detailsState[key] !== undefined) d.open = detailsState[key];
            d.addEventListener('toggle', () => {
                detailsState[key] = d.open;
                saveDetailsState(detailsState);
            });
        });
    }

    // 点击空白处关闭设置面板(修复版)
    function setupPanelCloseOnOutsideClick() {
        document.addEventListener('click', (e) => {
            const panel = document.getElementById('anime-tracker-control');
            const ball = document.getElementById('anime-tracker-ball');

            if (!panel || panel.style.display !== 'block') return;

            // 检查点击是否在面板或悬浮球内部
            const isPanelClick = panel.contains(e.target);
            const isBallClick = ball && ball.contains(e.target);

            // 如果开启了"保持菜单"设置,则不关闭面板
            if (settings.keepPanelOpen) return;

            // 修复点:无论何种方式打开,点击外部都关闭面板
            if (!isPanelClick && !isBallClick) {
                // 重置所有打开状态
                settings.hoverPanelOpen = false;
                settings.panelOpen = false;
                saveSettings(settings);
                panel.style.display = 'none';
                toggleFloatingBall(true);
            }
        });
    }


    // 初始化
    const settings = loadSettings();
    const animeState = loadAnimeState();
    let readCounter = null;
    let passCounter = null;

    function addNavSettingButton() {
        const nav = document.querySelector('#nav');
        if (nav) {
            const btn = document.createElement('a');
            btn.textContent = '标记设置';
            btn.href = '#';
            btn.style.marginLeft = '15px';
            btn.style.cursor = 'pointer';
            btn.style.fontSize = '14px';
            btn.addEventListener('click', e => {
                e.preventDefault();
                settings.panelOpen = true;
                settings.hoverPanelOpen = false;
                saveSettings(settings);
                createControlPanel();
            });
            nav.appendChild(btn);
        }
    }

    function init() {
        // 排除特定页面
        if (window.location.href.includes('/new/')) return;

        addNavSettingButton();
        setupAnimeItems();
        applyStates();
        setupDetails();
        createControlPanel();
        createFloatingBall();
        toggleFloatingBall(true);
        setupPanelCloseOnOutsideClick();
    }

    window.addEventListener('load', init);
    if (document.readyState === 'complete') {
        setTimeout(init, 500);
    }
})();