Sleazy Fork is available in English.

JavDB列表页显示是否已看

在演员列表页,显示每部影片是否已看,就难得点进去看了

// ==UserScript==
// @name         JavDB列表页显示是否已看
// @namespace    http://tampermonkey.net/
// @version      2025-01-19-2010
// @description  在演员列表页,显示每部影片是否已看,就难得点进去看了
// @author       Ryen
// @match        https://javdb.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=javdb.com
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @license      GPL-3.0-only
// ==/UserScript==

// 添加调试开关
const DEBUG = false;

const fadeDuration = 500; // 消息渐变持续时间
const displayDuration = 3000; // 消息显示持续时间
const maxMessages = 3; // 最大显示消息数量
let counter = 0; // 初始化计数器
let lastItemCount = 0; // 存储上一次的电影项目数量

let storedIds = new Set(); // 使用 Set 存储唯一 ID

const styleMap = {
    '我看過這部影片': 'tag is-success is-light',
    '我想看這部影片': 'tag is-info is-light',
    '未看过': 'tag is-gray',
};

// 在这里定义 hideWatchedVideos
let hideWatchedVideos = GM_getValue('hideWatchedVideos', false);
console.log('初始化 hideWatchedVideos:', hideWatchedVideos);

const indicatorTexts = ['我看過這部影片', '我想看這部影片'];

const validUrlPatterns = [
    /https:\/\/javdb\.com\/users\/want_watch_videos.*/,
    /https:\/\/javdb\.com\/users\/watched_videos.*/,
    /https:\/\/javdb\.com\/users\/list_detail.*/,
    /https:\/\/javdb\.com\/lists.*/
];

// 消息容器
const messageContainer = document.createElement('div');
messageContainer.style.position = 'fixed';
messageContainer.style.bottom = '20px';
messageContainer.style.right = '20px';
messageContainer.style.zIndex = '9999';
messageContainer.style.pointerEvents = 'none';
messageContainer.style.maxWidth = '500px';
messageContainer.style.display = 'flex';
messageContainer.style.flexDirection = 'column';
document.body.appendChild(messageContainer);

// 渐入效果
function fadeIn(el) {
    el.style.opacity = 0;
    el.style.display = 'block';

    const startTime = performance.now();
    function animate(time) {
        const elapsed = time - startTime;
        el.style.opacity = Math.min((elapsed / fadeDuration), 1);
        if (elapsed < fadeDuration) {
            requestAnimationFrame(animate);
        }
    }
    requestAnimationFrame(animate);
}

// 渐出效果
function fadeOut(el) {
    const startTime = performance.now();
    function animate(time) {
        const elapsed = time - startTime;
        el.style.opacity = 1 - Math.min((elapsed / fadeDuration), 1);
        if (elapsed < fadeDuration) {
            requestAnimationFrame(animate);
        } else {
            el.remove();
        }
    }
    requestAnimationFrame(animate);
}

// 显示信息
function logToScreen(message, bgColor = 'rgba(169, 169, 169, 0.8)', textColor = 'white') {

    const messageBox = document.createElement('div');
    messageBox.style.padding = '10px';
    messageBox.style.borderRadius = '5px';
    messageBox.style.backgroundColor = bgColor;
    messageBox.style.color = textColor;
    messageBox.style.fontSize = '12px';
    messageBox.style.marginBottom = '10px';
    messageBox.style.pointerEvents = 'none';
    messageBox.style.wordWrap = 'break-word';
    messageBox.style.maxWidth = '100%';

    messageBox.innerHTML = message;
    messageContainer.appendChild(messageBox);


    fadeIn(messageBox);


    setTimeout(() => {
        fadeOut(messageBox);
    }, displayDuration);


    if (messageContainer.childElementCount > maxMessages) {
        fadeOut(messageContainer.firstChild);
    }
}
async function sleep(ms) {
    return new Promise((resolve) => setTimeout(resolve, ms));
}



// 创建调试日志函数
function debugLog(...args) {
    if (DEBUG) {
        console.log(...args);
    }
}

(function () {
    'use strict';
    debugLog('开始初始化面板...');

    let panelVisible = false;
    const circlePosition = { left: -40, top: 60 };
    let lastUploadTime = "";

    // 面板样式优化
    const panel = document.createElement('div');
    debugLog('创建面板元素');
    panel.style.position = 'fixed';
    panel.style.border = 'none';
    panel.style.backgroundColor = 'rgba(255, 255, 255, 0.98)';
    panel.style.padding = '20px';
    panel.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.15)';
    panel.style.maxWidth = '320px';
    panel.style.width = '90vw';
    panel.style.maxHeight = '90vh';
    panel.style.overflowY = 'auto';
    panel.style.overflowX = 'hidden';
    panel.style.borderRadius = '12px';
    panel.style.display = 'none';
    panel.style.zIndex = 10001;
    panel.style.fontFamily = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';

    // 确保面板被添加到文档中
    document.body.appendChild(panel);
    debugLog('面板已添加到文档中');

    // 添加滚动条样式
    panel.style.scrollbarWidth = 'thin'; // Firefox
    panel.style.scrollbarColor = '#ccc transparent'; // Firefox
    // Webkit浏览器的滚动条样式
    const styleSheet = document.createElement('style');
    styleSheet.textContent = `
        #${panel.id}::-webkit-scrollbar {
            width: 6px;
        }
        #${panel.id}::-webkit-scrollbar-track {
            background: transparent;
        }
        #${panel.id}::-webkit-scrollbar-thumb {
            background-color: #ccc;
            border-radius: 3px;
        }
    `;
    document.head.appendChild(styleSheet);

    // 修改面板位置计算
    function updatePanelPosition(panel, top) {
        debugLog('更新面板位置');
        const windowHeight = window.innerHeight;
        const panelHeight = panel.offsetHeight;
        debugLog('窗口高度:', windowHeight, '面板高度:', panelHeight);

        let finalTop = top;

        if (top + panelHeight > windowHeight - 20) {
            finalTop = Math.max(20, windowHeight - panelHeight - 20);
        }

        finalTop = Math.max(20, finalTop);

        panel.style.top = `${finalTop}px`;
        panel.style.left = '10px';
        debugLog('面板最终位置:', finalTop);
    }

    // 创建标题
    const title = document.createElement('div');
    title.textContent = '番号数据上传与搜索';
    title.style.fontWeight = '600';
    title.style.fontSize = '16px';
    title.style.marginBottom = '15px';
    title.style.color = '#333';
    title.style.borderBottom = '1px solid #eee';
    title.style.paddingBottom = '10px';
    debugLog('创建标题');

    // 帮助符号
    const titleHelpIcon = document.createElement('span');
    titleHelpIcon.textContent = 'ℹ️';
    titleHelpIcon.style.cursor = 'pointer';
    titleHelpIcon.style.marginLeft = '10px';
    titleHelpIcon.title = '目前只过滤"看过",更新脚本数据会被清空';
    title.appendChild(titleHelpIcon);

    // 文件上传按钮样式优化
    const uploadButton = document.createElement('input');
    uploadButton.type = 'file';
    uploadButton.accept = '.json';
    uploadButton.style.marginBottom = '15px';
    uploadButton.style.width = '100%';
    uploadButton.style.padding = '8px';
    uploadButton.style.border = '1px solid #ddd';
    uploadButton.style.borderRadius = '6px';

    // 创建一个容器来包含上传按钮和帮助图标
    const uploadContainer = document.createElement('div');
    uploadContainer.style.position = 'relative';
    uploadContainer.style.marginBottom = '15px';
    uploadContainer.style.display = 'flex'; // 使用flex布局
    uploadContainer.style.alignItems = 'center'; // 垂直居中
    uploadContainer.style.gap = '8px'; // 元素之间的间距
    uploadContainer.style.width = '100%';
    panel.appendChild(uploadContainer);

    // 创建一个包装上传按钮的容器
    const uploadButtonWrapper = document.createElement('div');
    uploadButtonWrapper.style.flex = '1'; // 占据剩余空间
    uploadButtonWrapper.style.minWidth = '0'; // 防止内容溢出
    uploadContainer.appendChild(uploadButtonWrapper);
    uploadButtonWrapper.appendChild(uploadButton);

    // 帮助符号
    const uploadHelpIcon = document.createElement('span');
    uploadHelpIcon.textContent = 'ℹ️'; // 图标
    uploadHelpIcon.style.cursor = 'pointer';
    uploadHelpIcon.style.flexShrink = '0'; // 防止图标被压缩
    uploadHelpIcon.style.padding = '4px'; // 增加点击区域
    uploadHelpIcon.title = '前往"看过"页面进行导出文件';
    uploadContainer.appendChild(uploadHelpIcon);

    // 开关按钮样式优化和事件处理
    const toggleHideButton = document.createElement('button');
    toggleHideButton.textContent = hideWatchedVideos ? '当前:隐藏已看番号' : '当前:显示已看标记';
    toggleHideButton.style.marginTop = '10px';
    toggleHideButton.style.marginBottom = '15px';
    toggleHideButton.style.display = 'block';
    toggleHideButton.style.width = '100%';
    toggleHideButton.style.padding = '8px 12px';
    toggleHideButton.style.backgroundColor = hideWatchedVideos ? '#ff4757' : '#2ed573';
    toggleHideButton.style.color = 'white';
    toggleHideButton.style.border = 'none';
    toggleHideButton.style.borderRadius = '6px';
    toggleHideButton.style.cursor = 'pointer';
    toggleHideButton.style.transition = 'all 0.3s ease';

    // 添加按钮悬停效果
    toggleHideButton.addEventListener('mouseover', function () {
        this.style.opacity = '0.9';
    });
    toggleHideButton.addEventListener('mouseout', function () {
        this.style.opacity = '1';
    });

    // 添加开关按钮点击事件
    toggleHideButton.addEventListener('click', function () {
        debugLog('开关按钮被点击');
        hideWatchedVideos = !hideWatchedVideos;
        debugLog('切换 hideWatchedVideos 为:', hideWatchedVideos);

        // 更新按钮文本和颜色
        this.textContent = hideWatchedVideos ? '当前:隐藏已看番号' : '当前:显示已看标记';
        this.style.backgroundColor = hideWatchedVideos ? '#ff4757' : '#2ed573';

        // 保存设置
        GM_setValue('hideWatchedVideos', hideWatchedVideos);

        if (!hideWatchedVideos) {
            // 如果切换到显示模式,自动刷新页面
            debugLog('切换到显示模式,准备刷新页面');
            location.reload();
        } else {
            // 如果切换到隐藏模式,直接处理当前页面
            processLoadedItems();
        }
    });

    // 添加开关按钮到面板
    panel.appendChild(toggleHideButton);

    // 创建按钮容器
    const buttonContainer = document.createElement('div');
    buttonContainer.style.display = 'flex';
    buttonContainer.style.gap = '10px';
    buttonContainer.style.marginTop = '15px';
    buttonContainer.style.marginBottom = '15px';
    debugLog('创建按钮容器');

    // 导出按钮样式优化
    const exportButton = document.createElement('button');
    exportButton.textContent = '导出存储番号';
    exportButton.style.flex = '1';
    exportButton.style.padding = '8px 12px';
    exportButton.style.backgroundColor = '#1e90ff';
    exportButton.style.color = 'white';
    exportButton.style.border = 'none';
    exportButton.style.borderRadius = '6px';
    exportButton.style.cursor = 'pointer';
    exportButton.style.transition = 'all 0.3s ease';
    debugLog('创建导出按钮');

    // 清除按钮样式优化
    const clearButton = document.createElement('button');
    clearButton.textContent = '清除存储番号';
    clearButton.style.flex = '1';
    clearButton.style.padding = '8px 12px';
    clearButton.style.backgroundColor = '#ff6b81';
    clearButton.style.color = 'white';
    clearButton.style.border = 'none';
    clearButton.style.borderRadius = '6px';
    clearButton.style.cursor = 'pointer';
    clearButton.style.transition = 'all 0.3s ease';
    debugLog('创建清除按钮');

    // 定义导出函数
    function handleExport(e) {
        e.preventDefault();
        e.stopPropagation();

        debugLog('点击导出按钮');
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
        const data = Array.from(storedIds).map(id => ({ id }));
        const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `unique_ids_${timestamp}.json`;

        setTimeout(() => {
            URL.revokeObjectURL(url);
        }, 100);

        a.click();
        debugLog('导出完成:', `unique_ids_${timestamp}.json`);
        return false;
    }

    // 定义清除函数
    function handleClear(e) {
        e.preventDefault();
        e.stopPropagation();

        debugLog('开始清除数据...');
        if (confirm('确定要清除所有存储的番号吗?')) {
            try {
                // 清除内存中的数据
                storedIds = new Set();

                // 清除所有 GM 存储
                const allKeys = GM_listValues ? GM_listValues() : ['storedIds', 'lastUploadTime', 'watchedVideos', 'wantWatchVideos', 'hideWatchedVideos'];
                allKeys.forEach(key => {
                    debugLog('清除 GM 存储:', key);
                    GM_deleteValue(key);
                });

                // 清除所有相关的 localStorage
                const localStorageKeys = ['allVideosInfo', 'exportState'];
                localStorageKeys.forEach(key => {
                    debugLog('清除 localStorage:', key);
                    localStorage.removeItem(key);
                });

                // 重新初始化必要的值
                GM_setValue('storedIds', []);
                GM_setValue('lastUploadTime', '');
                lastUploadTime = '';

                // 更新显示
                idCountDisplay.textContent = `已存储 0 个番号`;
                uploadTimeDisplay.textContent = '';

                debugLog('数据清除完成');
                debugLog('当前 storedIds size:', storedIds.size);
                debugLog('当前 GM storage:', GM_getValue('storedIds', []).length);

                // 强制刷新页面
                alert('已清除所有存储的番号,页面将刷新');
                window.location.href = window.location.href;
            } catch (error) {
                console.error('清除数据时出错:', error);
                alert('清除数据时出错,请查看控制台');
            }
        }
        return false;
    }

    // 添加按钮事件监听器
    exportButton.addEventListener('click', handleExport);
    clearButton.addEventListener('click', handleClear);

    // 添加按钮悬停效果
    [exportButton, clearButton].forEach(button => {
        button.addEventListener('mouseover', function() {
            this.style.opacity = '0.9';
            this.style.transform = 'translateY(-1px)';
        });
        button.addEventListener('mouseout', function() {
            this.style.opacity = '1';
            this.style.transform = 'translateY(0)';
        });
    });

    // 将按钮添加到按钮容器
    buttonContainer.appendChild(exportButton);
    buttonContainer.appendChild(clearButton);
    debugLog('按钮已添加到容器');

    // 创建搜索框和结果容器
    const searchContainer = document.createElement('div');
    searchContainer.style.marginBottom = '15px';

    const searchBox = document.createElement('input');
    searchBox.type = 'text';
    searchBox.placeholder = '搜索存储的番号';
    searchBox.style.width = '100%';
    searchBox.style.padding = '8px 12px';
    searchBox.style.border = '1px solid #ddd';
    searchBox.style.borderRadius = '6px';
    searchBox.style.marginBottom = '10px';
    searchBox.style.boxSizing = 'border-box';

    // 创建搜索结果容器
    const resultContainer = document.createElement('div');
    resultContainer.style.maxHeight = '200px';
    resultContainer.style.overflowY = 'auto';
    resultContainer.style.border = '1px solid #eee';
    resultContainer.style.borderRadius = '6px';
    resultContainer.style.padding = '10px';
    resultContainer.style.display = 'none';
    resultContainer.style.backgroundColor = '#f9f9f9';

    // 搜索处理函数
    function handleSearch() {
        const searchTerm = searchBox.value.trim().toLowerCase();
        const storedIdsArray = Array.from(storedIds);

        if (searchTerm === '') {
            resultContainer.style.display = 'none';
            return;
        }

        const results = storedIdsArray.filter(id =>
            id.toLowerCase().includes(searchTerm)
        );

        resultContainer.innerHTML = '';

        if (results.length > 0) {
            results.forEach(id => {
                const resultItem = document.createElement('div');
                resultItem.textContent = id;
                resultItem.style.padding = '5px';
                resultItem.style.borderBottom = '1px solid #eee';
                resultItem.style.cursor = 'pointer';

                resultItem.addEventListener('mouseover', () => {
                    resultItem.style.backgroundColor = '#eee';
                });

                resultItem.addEventListener('mouseout', () => {
                    resultItem.style.backgroundColor = 'transparent';
                });

                resultContainer.appendChild(resultItem);
            });
            resultContainer.style.display = 'block';
        } else {
            const noResult = document.createElement('div');
            noResult.textContent = '未找到匹配的番号';
            noResult.style.padding = '5px';
            noResult.style.color = '#666';
            resultContainer.appendChild(noResult);
            resultContainer.style.display = 'block';
        }
    }

    // 添加搜索事件监听
    searchBox.addEventListener('input', handleSearch);

    // 添加点击外部关闭搜索结果的功能
    document.addEventListener('click', (e) => {
        if (!searchContainer.contains(e.target)) {
            resultContainer.style.display = 'none';
        }
    });

    // 将搜索框和结果容器添加到搜索容器
    searchContainer.appendChild(searchBox);
    searchContainer.appendChild(resultContainer);

    // 创建ID计数显示
    const idCountDisplay = document.createElement('div');
    idCountDisplay.style.marginTop = '15px';
    idCountDisplay.style.color = '#666';
    idCountDisplay.style.fontSize = '13px';
    idCountDisplay.style.textAlign = 'center';
    idCountDisplay.textContent = `已存储 ${storedIds.size} 个番号`;
    debugLog('创建ID计数显示');

    // 创建上传时间显示
    const uploadTimeDisplay = document.createElement('div');
    uploadTimeDisplay.style.marginTop = '5px';
    uploadTimeDisplay.style.color = '#666';
    uploadTimeDisplay.style.fontSize = '13px';
    uploadTimeDisplay.style.textAlign = 'center';
    uploadTimeDisplay.textContent = lastUploadTime ? `上次上传时间:${lastUploadTime}` : '';
    debugLog('创建上传时间显示');

    // 按照正确的顺序添加所有元素到面板
    debugLog('开始添加元素到面板');
    panel.appendChild(title);
    panel.appendChild(uploadContainer);
    panel.appendChild(toggleHideButton);
    panel.appendChild(buttonContainer);
    panel.appendChild(searchContainer);
    panel.appendChild(idCountDisplay);
    panel.appendChild(uploadTimeDisplay);
    debugLog('所有元素已添加到面板');

    // 打印面板内容
    debugLog('面板子元素数量:', panel.children.length);
    debugLog('面板内容:', panel.innerHTML);

    // 加载存储的 ID 和上传时间
    const rawData = GM_getValue('myIds');
    const savedUploadTime = GM_getValue('lastUploadTime');
    if (rawData) {
        storedIds = new Set(rawData); // 如果之前存过数据,加载到 Set
        updateIdCountDisplay(); // 更新 ID 计数显示
    }
    if (savedUploadTime) {
        lastUploadTime = savedUploadTime; // 恢复最新上传时间
        uploadTimeDisplay.textContent = `上次上传时间:${lastUploadTime}`;
    }

    // 处理文件上传
    uploadButton.addEventListener('change', handleFileUpload);

    const circle = createCircle(circlePosition.left, circlePosition.top);

    function handleFileUpload(event) {
        const file = event.target.files[0];
        if (!file) {
            return;
        }

        const reader = new FileReader();
        reader.onload = function (e) {
            try {
                const jsonData = JSON.parse(e.target.result);

                jsonData.forEach(item => {
                    if (item.id) {
                        storedIds.add(item.id);
                    }
                });

                GM_setValue('myIds', Array.from(storedIds));


                lastUploadTime = new Date().toLocaleString();
                GM_setValue('lastUploadTime', lastUploadTime);
                uploadTimeDisplay.textContent = `最新上传时间: ${lastUploadTime}`;

                alert('数据已保存');
                updateIdCountDisplay(); // 更新 ID 计数显示
            } catch (error) {
                console.error('解析 JSON 失败:', error);
                alert('解析 JSON 失败');
            }
        };

        reader.readAsText(file);
    }

    function updateIdCountDisplay() {
        idCountDisplay.textContent = `已看番号总数: ${storedIds.size}`;
    }

    function createCircle(left, top) {
        debugLog('创建圆形按钮...');
        const existingCircle = document.getElementById('unique-circle');
        if (existingCircle) {
            debugLog('移除已存在的圆形按钮');
            existingCircle.remove();
        }

        const circle = document.createElement('div');
        circle.id = 'unique-circle';
        circle.style.position = 'fixed';
        circle.style.width = '60px';
        circle.style.height = '60px';
        circle.style.borderRadius = '50%';
        circle.style.backgroundColor = '#ed0085';
        circle.style.cursor = 'pointer';
        circle.style.zIndex = 10000;
        circle.style.left = `${left}px`;
        circle.style.top = `${top}px`;
        circle.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
        circle.style.transition = 'all 0.3s ease';
        document.body.appendChild(circle);

        // 创建内部文字容器
        const label = document.createElement('div');
        label.textContent = '番';
        label.style.fontSize = '20px';
        label.style.color = 'white';
        label.style.textAlign = 'center';
        label.style.lineHeight = '60px';
        label.style.fontWeight = 'bold';
        label.style.textShadow = '1px 1px 2px rgba(0, 0, 0, 0.2)';
        circle.appendChild(label);

        // 悬停效果
        circle.addEventListener('mouseenter', function () {
            circle.style.transition = 'all 0.3s ease';
            circle.style.left = '0px';
            circle.style.backgroundColor = '#ed0085';
            circle.style.transform = 'scale(1.05)';
            circle.style.boxShadow = '0 6px 12px rgba(0, 0, 0, 0.3)';
        });

        circle.addEventListener('mouseleave', function () {
            circle.style.transition = 'all 0.3s ease';
            circle.style.left = '-40px';
            circle.style.backgroundColor = 'rgba(237, 0, 133, 0.7)';
            circle.style.transform = 'scale(1)';
            circle.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.2)';
        });

        // 点击效果
        circle.addEventListener('mousedown', function() {
            circle.style.transform = 'scale(0.95)';
        });

        circle.addEventListener('mouseup', function() {
            circle.style.transform = 'scale(1.05)';
        });

        // 修改圆形按钮点击事件处理
        circle.addEventListener('click', function(e) {
            e.stopPropagation(); // 阻止事件冒泡
            debugLog('圆形按钮被点击');
            panel.style.display = 'block';
            panelVisible = true;
            debugLog('面板显示状态:', panelVisible);

            setTimeout(() => {
                updatePanelPosition(panel, parseInt(circle.style.top));
            }, 0);

            setupMouseLeave(panel);
        });

        return circle;
    }

    // 修改 setupMouseLeave 函数
    function setupMouseLeave(panel) {
        let timeoutId = null;

        panel.addEventListener('mouseenter', () => {
            debugLog('鼠标进入面板');
            if (timeoutId) {
                clearTimeout(timeoutId);
                timeoutId = null;
            }
        });

        panel.addEventListener('mouseleave', (e) => {
            debugLog('鼠标离开面板');
            if (!panel.contains(e.relatedTarget)) {
                timeoutId = setTimeout(() => {
                    debugLog('关闭面板');
                    panel.style.display = 'none';
                    panelVisible = false;
                }, 1000);
            }
        });

        document.addEventListener('click', (e) => {
            if (!panel.contains(e.target) && e.target.id !== 'unique-circle') {
                debugLog('点击面板外部,关闭面板');
                panel.style.display = 'none';
                panelVisible = false;
            }
        });
    }

    // 添加调试信息
    const observer = new MutationObserver((mutations) => {
        mutations.forEach((mutation) => {
            if (mutation.type === 'attributes' && mutation.attributeName === 'style') {
                debugLog('面板样式变化:', panel.style.cssText);
            }
        });
    });

    observer.observe(panel, { attributes: true });
})();


(function () {

    const url = window.location.href;


    const validUrlPatterns = [
        /https:\/\/javdb\.com\/users\/want_watch_videos.*/,
        /https:\/\/javdb\.com\/users\/watched_videos.*/,
        /https:\/\/javdb\.com\/users\/list_detail.*/,
        /https:\/\/javdb\.com\/lists.*/
    ];


    const isValidUrl = validUrlPatterns.some(pattern => pattern.test(url));
    if (!isValidUrl) {
        return;
    }



    let allVideosInfo = JSON.parse(localStorage.getItem('allVideosInfo')) || [];
    let exportState = {
        allowExport: false,
        currentPage: 1,
        maxPage: null
    };
    let exportButton = null;

    function getVideosInfo() {
        const videoElements = document.querySelectorAll('.item');
        return Array.from(videoElements).map((element) => {
            const title = element.querySelector('.video-title').textContent.trim();
            const [id, ...titleWords] = title.split(' ');
            const releaseDate = element.querySelector('.meta').textContent.replace(/[^0-9-]/g, '');
            return { id, releaseDate };
        });
    }

    function scrapeAllPages() {

        if ((exportState.maxPage && exportState.currentPage > exportState.maxPage) ||
            !document.querySelector('.pagination-next')) {
            exportVideosInfo();
            return;
        }

        const videosInfo = getVideosInfo();
        allVideosInfo = allVideosInfo.concat(videosInfo);


        exportState.currentPage++;
        localStorage.setItem('exportState', JSON.stringify(exportState));
        localStorage.setItem('allVideosInfo', JSON.stringify(allVideosInfo));

        const nextPageButton = document.querySelector('.pagination-next');
        if (nextPageButton) {
            nextPageButton.click();
            setTimeout(() => scrapeAllPages(), 2000);
        } else {
            exportVideosInfo();
        }
    }

    function exportVideosInfo() {
        exportState.allowExport = false;
        exportState.currentPage = 1;
        exportState.maxPage = null;

        localStorage.setItem('exportState', JSON.stringify(exportState));

        allVideosInfo.sort((a, b) => a.id.localeCompare(b.id));
        const json = JSON.stringify(allVideosInfo);
        const jsonBlob = new Blob([json], { type: 'application/json' });
        const jsonUrl = URL.createObjectURL(jsonBlob);
        const downloadLink = document.createElement('a');

        // 获取当前时间戳
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);

        let fileName = '';
        if (url.includes('/watched_videos')) {
            fileName = 'watched-videos';
        } else if (url.includes('/want_watch_videos')) {
            fileName = 'want-watch-videos';
        } else if (url.includes('/list_detail')) {
            const breadcrumb = document.getElementsByClassName('breadcrumb')[0];
            const li = breadcrumb.parentNode.querySelectorAll('li');
            fileName = li[1].innerText;
        } else if (url.includes('/lists')) {
            fileName = document.querySelector('.actor-section-name').innerText;
        }

        downloadLink.href = jsonUrl;
        downloadLink.download = `${fileName}_${timestamp}.json`;
        document.body.appendChild(downloadLink);
        downloadLink.click();
        document.body.removeChild(downloadLink);
        URL.revokeObjectURL(jsonUrl);

        localStorage.removeItem('allVideosInfo');
        localStorage.removeItem('exportState');

        exportButton.textContent = '导出完毕';
        exportButton.disabled = false;
    }

    function startExport() {

        const allImages = document.querySelectorAll('img');
        allImages.forEach((image) => image.remove());


        const maxPageInput = document.getElementById('maxPageInput');
        exportState.maxPage = maxPageInput.value ? parseInt(maxPageInput.value) : null;
        exportState.allowExport = true;
        exportState.currentPage = 1;


        localStorage.setItem('exportState', JSON.stringify(exportState));


        exportButton.textContent = '导出中...';
        exportButton.disabled = true;


        allVideosInfo = [];


        scrapeAllPages();
    }

    function createExportButton() {

        const maxPageInput = document.createElement('input');
        maxPageInput.type = 'number';
        maxPageInput.id = 'maxPageInput';
        maxPageInput.placeholder = '往后获取多少页数';
        maxPageInput.style.marginRight = '10px';

        exportButton = document.createElement('button');
        exportButton.textContent = '导出 json';
        exportButton.className = 'button is-small';
        exportButton.addEventListener('click', startExport);

        const exportContainer = document.createElement('div');
        exportContainer.style.display = 'flex';
        exportContainer.style.alignItems = 'center';
        exportContainer.appendChild(maxPageInput);
        exportContainer.appendChild(exportButton);

        if (url.includes('/list_detail')) {
            document.querySelector('.breadcrumb').querySelector('ul').appendChild(exportContainer);
        } else {
            document.querySelector('.toolbar').appendChild(exportContainer);
        }
    }


    function checkExportState() {
        const savedExportState = localStorage.getItem('exportState');
        if (savedExportState) {
            exportState = JSON.parse(savedExportState);
            const savedVideosInfo = localStorage.getItem('allVideosInfo');

            if (exportState.allowExport) {
                if (savedVideosInfo) {
                    allVideosInfo = JSON.parse(savedVideosInfo);
                }

                exportButton.textContent = '导出中...';
                exportButton.disabled = true;

                scrapeAllPages();
            }
        }
    }

    if (url.includes('/watched_videos')
        || url.includes('/want_watch_videos')
        || url.includes('/list_detail')
        || url.includes('/lists')
    ) {
        createExportButton();
        checkExportState();
    }
})();

// 修改 modifyItemAtCurrentPage 函数
function modifyItemAtCurrentPage(itemToModify, textIndicator) {
    debugLog('处理项目:', textIndicator);
    if (textIndicator === '我看過這部影片' && hideWatchedVideos) {
        debugLog('准备隐藏已看番号');
        const itemContainer = itemToModify.closest('.item');
        if (itemContainer) {
            debugLog('找到要隐藏的番号块,开始隐藏动画');
            itemContainer.style.transition = 'opacity 0.3s';
            itemContainer.style.opacity = '0';
            setTimeout(() => {
                itemContainer.remove();
                debugLog('番号块已移除');
            }, 300);
        }
        return;
    }

    let tags = itemToModify.closest('.item').querySelector('.tags.has-addons');
    let tagClass = styleMap[textIndicator];

    // 检查是否已经存在相同的标记
    let existingTags = Array.from(tags.querySelectorAll('span')); // 获取所有已存在的标签
    let tagExists = existingTags.some(tag => tag.textContent === textIndicator); // 检查是否有相同内容的标签

    // 如果不存在对应的标签,则添加新的标签
    if (!tagExists) {
        let newTag = document.createElement('span');
        newTag.className = tagClass;
        newTag.textContent = textIndicator;
        tags.appendChild(newTag);
    } else {
        debugLog(`标签 "${textIndicator}" 已经存在于该项目中,未重复添加.`);
    }
}

async function processLoadedItems() {
    debugLog('开始处理页面项目');
    debugLog('当前 hideWatchedVideos 状态:', hideWatchedVideos);

    const url = window.location.href;
    debugLog('当前URL:', url);

    const isValidUrl = validUrlPatterns.some(pattern => pattern.test(url));
    if (isValidUrl) {
        debugLog('URL匹配特殊模式,跳过处理');
        return;
    }

    let items = Array.from(document.querySelectorAll('.movie-list .item a'));
    debugLog('找到项目数量:', items.length);

    // 从每个 item 的 <a> 中找到对应的 <strong> 内容
    let titles = items.map(item => {
        // 在当前 item 中查找 <strong> 元素,并获取其文本内容
        let strongElement = item.querySelector('div.video-title > strong');
        return strongElement ? strongElement.textContent.trim() : null; // 如果存在则返回内容,否则返回 null
    }).filter(title => title !== null); // 过滤掉 null 值

    // 输出获取到的标题
    //console.log('获取到的标题:', titles);
    if (titles.length > 0) {
        //logToScreen(`获取到的标题:${titles.join(', ')}`, 'rgba(0, 255, 255, 0.8)', 'white');

        // 对比 titles 和 storedIds,修改样式
        titles.forEach(title => {
            // 查找对应条目
            let itemToModify = items.find(item => {
                let strongElement = item.querySelector('div.video-title > strong');
                return strongElement && strongElement.textContent.trim() === title;
            });

            if (itemToModify) {
                if (storedIds.has(title)) {
                    debugLog(`匹配到已看影片: ${title}`);
                    modifyItemAtCurrentPage(itemToModify, '我看過這部影片');
                    logToScreen(`我看過這部影片: ${title}`, 'rgba(76, 175, 80, 0.8)', 'white');
                } else {
                    // console.log(`未看过: ${title}`);
                    modifyItemAtCurrentPage(itemToModify, '未看过');
                    // logToScreen(`未看过: ${title}`);
                }
            }
        });
    } else {
        logToScreen('未找到任何标题', 'rgba(255, 0, 0, 0.8)', 'white');
    }
}

// 定时检查新加载的项目
setInterval(() => {
    let items = document.querySelectorAll('.movie-list .item a');
    let currentItemCount = items.length;

    if (currentItemCount > lastItemCount) {
        debugLog(`发现新增项目:${currentItemCount - lastItemCount}`);
        logToScreen(`发现新增项目:${currentItemCount - lastItemCount}`, 'rgba(0, 255, 255, 0.8)', 'white');
        processLoadedItems(); // 处理新加载的项目
        lastItemCount = currentItemCount; // 更新上一次的项目计数
    }
}, 1000);

// 初始化时获取当前项目的数量
lastItemCount = document.querySelectorAll('.movie-list .item a').length;
processLoadedItems(); // 初始化已有元素

// 监听窗口大小变化
window.addEventListener('resize', () => {
    if (panelVisible) {
        updatePanelPosition(panel, parseInt(panel.style.top));
    }
});