115Rename2025

115网盘视频整理工具:1.根据番号查询并重命名文件 2.支持javbus/avmoo查询 3.演员归档自动分类 4.可设置归档根目录 5.支持中文字幕和无码标记 6.支持文件夹归档 7.增强用户体验的通知提示 8.性能优化 9.评分同步 10.支持批量处理

// ==UserScript==
// @name            115Rename2025
// @namespace           http://tampermonkey.net/
// @version             1.4.1
// @description         115网盘视频整理工具:1.根据番号查询并重命名文件 2.支持javbus/avmoo查询 3.演员归档自动分类 4.可设置归档根目录 5.支持中文字幕和无码标记 6.支持文件夹归档 7.增强用户体验的通知提示 8.性能优化 9.评分同步 10.支持批量处理
// @author              db117 wusuowei111 Chunluren 
// @include             https://115.com/*
// @icon      	 https://115.com/favicon.ico
// @domain              javbus.com
// @domain              avmoo.host
// @domain              avsox.host
// @domain              javdb.com
// @domain              fc2ppvdb.com
// @connect             javdb.com
// @connect             fc2ppvdb.com
// @grant               GM_notification
// @grant               GM_xmlhttpRequest
// @grant               GM_setValue
// @grant               GM_getValue
// @license             MIT
// ==/UserScript==

/*
 * 更新日志:
 * v1.4.1 (2024-05-xx):
 * 1. 实现多网站轮询查询功能,优先javbus,失败后查询javdb (取代原有4个改名按钮)
 * 2. 新增FC2-PPV格式支持,针对FC2视频自动到fc2ppvdb.com查询
 * 3. 改进番号提取逻辑,支持更多格式:
 *    - FC2-PPV、PPV-xxxxx等FC2系列格式
 *    - 带空格的番号格式,如"SONE- 101- UC" → "SONE-101"
 *    - 日期格式番号,如"041117_510"等
 * 4. 自动过滤文件名中的常见后缀(UC、C、U、字幕等)
 * 5. 针对不同网站查询失败情况提供更友好的错误提示
 * 6. 增强域名前缀清理,支持hhd800.com@等格式
 */

(function () {
    // 添加一个独特的标识符,确保元素唯一
    const rootInfoId = 'archive-root-info-' + Date.now();
    
    // 在执行任何操作前,先清除可能存在的所有归档根目录信息元素
    function cleanupExistingRootInfo() {
        try {
            // 清除主文档中的元素
            const mainDocElements = document.querySelectorAll('[id^="archive-root-info"]');
            if (mainDocElements.length > 0) {
                console.log(`清理主文档中发现的${mainDocElements.length}个归档根目录信息元素`);
                mainDocElements.forEach(element => element.remove());
            }
            
            // 尝试清除所有iframe中的元素
            const iframes = document.querySelectorAll('iframe');
            iframes.forEach(iframe => {
                try {
                    if (iframe.contentDocument) {
                        const iframeElements = iframe.contentDocument.querySelectorAll('[id^="archive-root-info"]');
                        if (iframeElements.length > 0) {
                            console.log(`清理iframe中发现的${iframeElements.length}个归档根目录信息元素`);
                            iframeElements.forEach(element => element.remove());
                        }
                    }
                } catch (e) {
                    // 跨域iframe可能会抛出异常,忽略
                    console.log("无法访问iframe内容,可能是跨域限制");
                }
            });
        } catch (e) {
            console.error("清理归档根目录信息元素时出错:", e);
        }
    }
    
    // 立即执行清理
    cleanupExistingRootInfo();
    
    // 添加样式,使用更明确的选择器
    const notificationStyle = `
    <style>
        /* 归档根目录信息样式 */
        [id^="archive-root-info"] {
            position: fixed;
            top: 20px;
            right: 20px;
            max-width: 300px;
            background-color: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 12px 20px;
            border-radius: 4px;
            z-index: 9998;
            font-size: 14px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            border-left: 4px solid #1890ff;
        }
        
        /* 临时通知样式 */
        .custom-notification {
            position: fixed;
            top: 80px; /* 位于根目录通知下方 */
            right: 20px;
            max-width: 300px;
            background-color: rgba(0, 0, 0, 0.8);
            color: white;
            padding: 12px 20px;
            border-radius: 4px;
            z-index: 9999;
            font-size: 14px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
            transition: all 0.3s ease;
            opacity: 0;
            transform: translateY(-10px);
        }
        .custom-notification.success {
            border-left: 4px solid #52c41a;
        }
        .custom-notification.error {
            border-left: 4px solid #f5222d;
        }
        .custom-notification.info {
            border-left: 4px solid #1890ff;
        }
        .custom-notification.show {
            opacity: 1;
            transform: translateY(0);
        }
    </style>`;
    
    // 添加样式到页面
    $('head').append(notificationStyle);
    
    // 默认使用根目录ID
    const ROOT_DIR_CID = "0"; // 115网盘根目录的ID为"0"
    // 尝试从存储中获取根目录ID,如果不存在则为null(表示未设置)
    let archiveRootCid = GM_getValue("archiveRootCid", null);
    let archiveRootName = GM_getValue("archiveRootName", null);
    
    // 简单的页面内通知函数
    window.showPageNotification = function(message, type = 'info', duration = 3000) {
        // 为不同类型通知设置不同的默认持续时间
        if (duration === 3000) {
            if (type === 'success') duration = 3000;      // 成功通知更短
            else if (type === 'error') duration = 5000;   // 错误通知更长
            else if (type === 'info') duration = 3000;    // 信息通知标准
        }
        
        const notificationId = 'custom-notification-' + Date.now();
        const notificationHtml = `<div id="${notificationId}" class="custom-notification ${type}">${message}</div>`;
        
        // 添加通知到页面
        $('body').append(notificationHtml);
        
        // 显示通知
        setTimeout(() => {
            $(`#${notificationId}`).addClass('show');
        }, 10);
        
        // 自动关闭
        setTimeout(() => {
            $(`#${notificationId}`).removeClass('show');
            setTimeout(() => {
                $(`#${notificationId}`).remove();
            }, 300);
        }, duration);
    };
    
    // 简单函数:显示归档根目录信息
    function showArchiveRootInfo() {
        // 确保清理可能存在的其他实例
        cleanupExistingRootInfo();
        
        // 根据是否设置了根目录,显示不同的信息
        let rootDirMessage;
        if (archiveRootCid && archiveRootName) {
            rootDirMessage = `当前归档根目录: "${archiveRootName}"`;
        } else {
            rootDirMessage = "当前无归档根目录,将使用115网盘根目录";
        }
        
        // 创建信息元素,使用带时间戳的ID确保唯一性
        const infoElement = $(`<div id="${rootInfoId}" class="archive-root-info">${rootDirMessage}</div>`);
        
        // 确保只添加到主文档,不添加到iframe
        if (window.self === window.top) {
            $('body').append(infoElement);
            console.log("在主文档中显示归档根目录信息: " + rootDirMessage);
        }
    }
    
    // 设置延迟计时器
    let rootInfoTimer = null;
    
    // 只在主窗口(非iframe)中显示一次
    function initializeRootInfo() {
        // 只在主窗口中初始化,避免在iframe中创建
        if (window.self !== window.top) {
            console.log("处于iframe中,跳过显示归档根目录信息");
            return;
        }
        
        // 清除可能存在的计时器
        if (rootInfoTimer) {
            clearTimeout(rootInfoTimer);
        }
        
        // 设置新的计时器
        rootInfoTimer = setTimeout(function() {
            showArchiveRootInfo();
            rootInfoTimer = null;  // 清除引用
        }, 2000);
    }
    
    // 在页面完全加载后显示
    $(window).on('load', function() {
        initializeRootInfo();
    });
    
    // 如果window.load事件已触发,直接初始化
    if (document.readyState === 'complete') {
        initializeRootInfo();
    }
    
    // 不再在document.ready时创建,避免重复
    
    // 按钮
    let rename_list = `
            <li id="rename_list">
                <a id="rename_all_multi" class="mark" href="javascript:;">改名(多网站轮询)</a>
                <a id="rename_all_multi_date" class="mark" href="javascript:;">改名(多网站轮询)_时间</a>
                <a id="archive_to_folder" class="mark" href="javascript:;">归档至文件夹</a>
                <a id="set_archive_root" class="mark" href="javascript:;">设置为归档根目录</a>
                <a id="get_javdb_rating" class="mark" href="javascript:;">获取javdb评分</a>
            </li>
        `;
    /**
     * 添加按钮的定时任务
     */
    let interval = setInterval(buttonInterval, 1000);

    // javbus
    let javbusBase = "https://www.javbus.com/";
    // 直接访问番号页面 (使用番号直接访问)
    let javbusDirectAccess = javbusBase;
    // 无码页面基础URL
    let javbusUncensoredBase = javbusBase + "uncensored/";

    // javdb
    let javdbBase = "https://javdb.com/";
    let javdbSearchBase = "https://javdb.com/search?q=";
    let javdbDirectAccess = "https://javdb.com/";

    // fc2ppvdb
    let fc2ppvdbBase = "https://fc2ppvdb.com/articles/";

    // avmoo
    // 有码
    let avmooSearch = "https://avmoo.host/cn/search/";
    // 无码
    let avmooUncensoredSearch = "https://avsox.host/cn/search/";
    'use strict';

    /**
     * 添加按钮定时任务(检测到可以添加时添加按钮)
     */
    function buttonInterval() {
        let open_dir = $("div#js_float_content li[val='open_dir']");
        if (open_dir.length !== 0 && $("li#rename_list").length === 0) {
            open_dir.before(rename_list);
            $("a#rename_all_multi").click(
                function () {
                    rename(rename_multi, false);
                });
            $("a#rename_all_multi_date").click(
                function () {
                    rename(rename_multi, true);
                });
            $("a#archive_to_folder").click(
                function () {
                    archiveToActorFolder();
                });
            $("a#set_archive_root").click(
                function () {
                    setArchiveRoot();
                });
            $("a#get_javdb_rating").click(
                function () {
                    getJavdbRating();
                });
            
            // 根据是否设置了根目录,显示不同的日志
            if (archiveRootCid) {
                console.log("添加按钮,当前归档根目录: " + archiveRootName + " (CID: " + archiveRootCid + ")");
            } else {
                console.log("添加按钮,未设置归档根目录,将使用115网盘根目录");
            }
            
            // 按钮添加时不再创建根目录信息,依赖页面加载时的创建
            console.log("按钮已添加,根目录信息状态: " + (window.rootInfoDisplayed ? "已显示" : "未显示"));
            
            // 结束定时任务
            clearInterval(interval);
        }
    }

    /**
     * 设置归档根目录
     * 获取选中的文件夹信息并保存为归档根目录
     */
    function setArchiveRoot() {
        // 获取选中的文件夹
        let selectedFolder = $("iframe[rel='wangpan']")
            .contents()
            .find("li.selected");
        
        // 检查是否只选择了一个文件夹
        if (selectedFolder.length !== 1) {
            GM_notification(getDetails("请只选择一个文件夹", "设置失败"));
            showPageNotification("请只选择一个文件夹", 'error', 3000);
            console.log("设置归档根目录失败:选择了 " + selectedFolder.length + " 个项目,请只选择一个文件夹");
            return;
        }
        
        let $item = $(selectedFolder[0]);
        // 检查是否是文件夹
        let file_type = $item.attr("file_type");
        if (file_type !== "0") {
            GM_notification(getDetails("请选择文件夹类型", "设置失败"));
            showPageNotification("请选择文件夹类型", 'error', 3000);
            console.log("设置归档根目录失败:选中的不是文件夹");
            return;
        }
        
        // 获取文件夹ID和名称
        let cid = $item.attr("cate_id");
        let name = $item.attr("title");
        
        if (cid) {
            // 保存到GM存储中
            GM_setValue("archiveRootCid", cid);
            GM_setValue("archiveRootName", name);
            
            // 更新当前变量
            archiveRootCid = cid;
            archiveRootName = name;
            
            // 更新归档根目录显示
            cleanupExistingRootInfo();
            showArchiveRootInfo();
            
            GM_notification(getDetails(name, "归档根目录设置成功"));
            showPageNotification(`归档根目录设置成功: "${name}"`, 'success', 5000);
            console.log("归档根目录设置成功: " + name + " (CID: " + cid + ")");
        } else {
            GM_notification(getDetails("无法获取文件夹ID", "设置失败"));
            showPageNotification("无法获取文件夹ID", 'error', 3000);
            console.log("设置归档根目录失败:无法获取文件夹ID");
        }
    }

    /**
     * 执行改名方法
     * @param call       回调函数
     * @param addDate   是否添加时间
     */
    function rename(call, addDate) {
        // 获取选中的文件数量
        let selectedCount = $("iframe[rel='wangpan']").contents().find("li.selected").length;
        showPageNotification(`开始处理 ${selectedCount} 个文件...`, 'info', 3000);
        
        // 记录成功处理的数量
        let successCount = 0;
        
        // 获取所有已选择的文件
        let list = $("iframe[rel='wangpan']")
            .contents()
            .find("li.selected")
            .each(function (index, v) {
                let $item = $(v);
                // 原文件名称
                let file_name = $item.attr("title");
                // 文件类型
                let file_type = $item.attr("file_type");
                
                console.log("处理文件: " + file_name);

                // 文件id
                let fid;
                // 后缀名
                let suffix;
                if (file_type === "0") {
                    // 文件夹
                    fid = $item.attr("cate_id");
                } else {
                    // 文件
                    fid = $item.attr("file_id");
                    // 处理后缀
                    let lastIndexOf = file_name.lastIndexOf('.');
                    if (lastIndexOf !== -1) {
                        suffix = file_name.substr(lastIndexOf, file_name.length);
                    }
                }

                if (fid && file_name) {
                    // 先检查是否是FC2或PPV格式的文件
                    let isFC2 = /FC2/i.test(file_name) || /PPV[-_\s]?\d{5,7}/i.test(file_name);
                    if (isFC2) {
                        console.log("检测到可能的FC2格式文件: " + file_name);
                        // 尝试直接从文件名提取FC2编号
                        let fc2Number = extractFC2Number(file_name);
                        if (fc2Number) {
                            console.log("直接从文件名提取FC2编号: " + fc2Number);
                            let fc2Code = "FC2-PPV-" + fc2Number;
                            call(fid, fc2Code, suffix, false, false, addDate, function() {
                                successCount++;
                                if (successCount === selectedCount) {
                                    showPageNotification(`所有 ${successCount} 个文件处理完成`, 'success', 5000);
                                }
                            });
                            return;
                        } else if (/PPV[-_\s]?(\d{5,7})/i.test(file_name)) {
                            // 特殊处理PPV-XXXXX格式
                            let ppvMatch = file_name.match(/PPV[-_\s]?(\d{5,7})/i);
                            if (ppvMatch && ppvMatch[1]) {
                                console.log("从PPV格式提取FC2编号: " + ppvMatch[1]);
                                let fc2Code = "FC2-PPV-" + ppvMatch[1];
                                call(fid, fc2Code, suffix, false, false, addDate, function() {
                                    successCount++;
                                    if (successCount === selectedCount) {
                                        showPageNotification(`所有 ${successCount} 个文件处理完成`, 'success', 5000);
                                    }
                                });
                                return;
                            }
                        }
                    }
                    
                    // 不是FC2格式或者提取FC2编号失败,尝试常规番号提取
                    let fh = getVideoCode(file_name);
                    if (fh) {
                        // 校验是否是中文字幕
                        let chineseCaptions = checkChineseCaptions(fh, file_name);
                        let Uncensored = checkUncensored(fh, file_name);
                        // 执行查询
                        call(fid, fh, suffix, chineseCaptions, Uncensored, addDate, function() {
                            // 成功回调
                            successCount++;
                            // 如果所有文件都处理完毕,显示总结通知
                            if (successCount === selectedCount) {
                                showPageNotification(`所有 ${successCount} 个文件处理完成`, 'success', 5000);
                            }
                        });
                    } else {
                        console.log("无法从文件名中提取到番号: " + file_name);
                    }
                }
            });
    }
    
    /**
     * 提取FC2编号
     * @param title 文件名或番号
     * @returns {string|null} FC2编号,如果不是FC2格式则返回null
     */
    function extractFC2Number(title) {
        // 格式1: FC2-PPV-1234567
        let match = title.match(/FC2[-\s]?PPV[-\s]?(\d{5,7})/i);
        if (match && match[1]) {
            return match[1];
        }
        
        // 格式2: FC2PPV_1234567 或 FC2PPV-1234567
        match = title.match(/FC2PPV[_-]?(\d{5,7})/i);
        if (match && match[1]) {
            return match[1];
        }
        
        // 格式3: 单纯的FC2 1234567
        match = title.match(/FC2\s+(\d{5,7})/i);
        if (match && match[1]) {
            return match[1];
        }
        
        // 格式4: 单纯的PPV-1234567
        match = title.match(/PPV[-_\s]?(\d{5,7})/i);
        if (match && match[1]) {
            return match[1];
        }
        
        return null;
    }
    
    /**
     * 多网站轮询查询重命名
     * 先尝试javbus,然后javdb,对于FC2-PPV格式尝试fc2ppvdb
     */
    function rename_multi(fid, fh, suffix, chineseCaptions, Uncensored, addDate, callback) {
        console.log("开始多网站轮询查询: " + fh);
        
        // 检查番号是否为FC2格式
        let isFC2 = /FC2/i.test(fh) || /^PPV-\d{5,7}$/i.test(fh);
        
        if (isFC2) {
            // 提取FC2编号
            let fc2Number;
            if (/FC2/i.test(fh)) {
                fc2Number = extractFC2Number(fh);
            } else if (/^PPV-(\d{5,7})$/i.test(fh)) {
                // 处理PPV-XXXXX格式
                let ppvMatch = fh.match(/^PPV-(\d{5,7})$/i);
                fc2Number = ppvMatch ? ppvMatch[1] : null;
            }
            
            if (fc2Number) {
                console.log("检测到FC2格式,提取编号: " + fc2Number);
                requestFC2(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback);
                return;
            }
        }
        
        // 首先尝试javbus
        requestMultiSource(fid, fh, suffix, chineseCaptions, Uncensored, addDate, callback, "javbus");
    }
    
    /**
     * 多来源查询处理
     * @param fid 文件ID
     * @param fh 番号
     * @param suffix 后缀
     * @param chineseCaptions 是否有中文字幕
     * @param Uncensored 是否无码
     * @param addDate 是否添加日期
     * @param callback 回调函数
     * @param source 当前尝试的来源
     */
    function requestMultiSource(fid, fh, suffix, chineseCaptions, Uncensored, addDate, callback, source) {
        if (source === "javbus") {
            console.log("尝试使用javbus查询: " + fh);
            // 使用javbus查询,如果失败则尝试javdb
            requestJavbus(fid, fh, suffix, chineseCaptions, Uncensored, addDate, javbusDirectAccess, function() {
                // 成功回调
                if (typeof callback === 'function') {
                    callback();
                }
            }, 0, function() {
                // 失败回调,尝试javdb
                console.log("javbus查询失败,尝试javdb: " + fh);
                requestMultiSource(fid, fh, suffix, chineseCaptions, Uncensored, addDate, callback, "javdb");
            });
        } else if (source === "javdb") {
            console.log("尝试使用javdb查询: " + fh);
            requestJavdb(fid, fh, suffix, chineseCaptions, Uncensored, addDate, callback);
        } else {
            // 所有来源都失败
            console.log("所有来源查询失败: " + fh);
            GM_notification(getDetails(fh, "所有来源查询失败"));
            showPageNotification(`无法在所有网站找到"${fh}"的信息`, 'error', 3000);
            if (typeof callback === 'function') {
                callback(); // 确保回调函数被执行
            }
        }
    }

    /**
     * 请求javbus,并请求115进行改名
     * @param fid               文件id
     * @param fh                番号
     * @param suffix            后缀
     * @param chineseCaptions   是否有中文字幕
     * @param Uncensored        是否无码
     * @param url               请求地址
     * @param addDate           是否添加时间
     * @param callback          成功回调
     * @param uncensoredAttempt 是否已尝试过无码查询
     * @param failCallback      失败回调
     */
    function requestJavbus(fid, fh, suffix, chineseCaptions, Uncensored, addDate, url, callback, uncensoredAttempt = 0, failCallback) {
        GM_xmlhttpRequest({
            method: "GET",
            url: url + fh,
            onload: xhr => {
                // 匹配标题
                let response = $(xhr.responseText);

                // 尝试不同方式获取标题
                let title = null;
                
                // 方法1: 从详情页面的标题获取
                let h3Title = response.find("h3");
                if (h3Title.length > 0) {
                    title = h3Title.text().trim();
                    // 删除番号部分(如果有),保留后面的标题
                    if (title.toUpperCase().indexOf(fh.toUpperCase()) === 0) {
                        title = title.substring(fh.length).trim();
                    }
                    console.log("从h3获取标题: " + title);
                }
                
                // 方法2: 如果方法1没有获取到标题,尝试从img标签获取
                if (!title || title.length === 0) {
                    title = response.find("div.photo-frame img").attr("title");
                    console.log("从img标签title属性获取标题: " + title);
                }
                
                // 方法3: 如果前两种方法都失败,尝试获取页面标题
                if (!title || title.length === 0) {
                    title = response.find("title").text().trim();
                    // 清理标题中可能的额外信息
                    if (title.indexOf(" - JavBus") > 0) {
                        title = title.substring(0, title.indexOf(" - JavBus")).trim();
                    }
                    if (title.toUpperCase().indexOf(fh.toUpperCase()) === 0) {
                        title = title.substring(fh.length).trim();
                    }
                    console.log("从页面title获取标题: " + title);
                }

                // 时间
                let date = response.find("div.photo-info date:last").html();
                
                // 如果无法通过 date:last 获取日期,尝试其他方法
                if (!date) {
                    console.log("未找到日期,尝试其他方法获取");
                    
                    // 方法1: 查找带有日期标识的元素
                    let dateLabel = response.find("p.header:contains('発売日:')").next("p");
                    if (dateLabel.length > 0) {
                        date = dateLabel.text().trim();
                        console.log("从日期标签获取到日期: " + date);
                    }
                    
                    // 方法2: 查找所有日期格式的文本
                    if (!date) {
                        let allText = response.text();
                        let dateMatch = allText.match(/\d{4}-\d{2}-\d{2}/);
                        if (dateMatch) {
                            date = dateMatch[0];
                            console.log("从页面文本匹配到日期: " + date);
                        }
                    }
                } else {
                    console.log("找到日期: " + date);
                }

                if (title && title.length > 0) {
                    console.log("最终使用标题: " + title);
                    // 构建新名称
                    let newName = buildNewName(fh, suffix, chineseCaptions, Uncensored, title);

                    // 添加时间
                    if (addDate && date) {
                        // 标准化日期格式为YYYY-MM-DD
                        if (date.match(/\d{4}-\d{2}-\d{2}/)) {
                            // 已经是标准格式
                            newName = date + "_" + newName;
                        } else if (date.match(/\d{4}\/\d{2}\/\d{2}/)) {
                            // 转换斜杠格式为连字符格式
                            newName = date.replace(/\//g, "-") + "_" + newName;
                        } else {
                            // 其他格式,尝试提取数字
                            let numbers = date.match(/\d+/g);
                            if (numbers && numbers.length >= 3) {
                                let year = numbers[0].length === 4 ? numbers[0] : "20" + numbers[0];
                                let month = numbers[1].padStart(2, "0");
                                let day = numbers[2].padStart(2, "0");
                                let formattedDate = `${year}-${month}-${day}`;
                                console.log("格式化日期: " + date + " -> " + formattedDate);
                                newName = formattedDate + "_" + newName;
                            } else {
                                // 无法格式化,使用原始日期
                        newName = date + "_" + newName;
                            }
                        }
                        console.log("添加日期后的文件名: " + newName);
                    }

                    if (newName) {
                        // 修改名称
                        send_115(fid, newName, fh, callback);
                    }
                } else if (url !== javbusUncensoredBase && uncensoredAttempt === 0) {
                    // 如果当前不是无码站点且未尝试过无码查询,则尝试一次无码查询
                    console.log("未找到标题,尝试一次无码页面查询: " + fh);
                    requestJavbus(fid, fh, suffix, chineseCaptions, Uncensored, addDate, javbusUncensoredBase, callback, 1, failCallback);
                } else {
                    // 已经尝试过无码查询或当前就是无码查询,尝试下一个来源
                    console.log("javbus查询尝试完毕,无法获取标题: " + fh);
                    
                    if (typeof failCallback === 'function') {
                        failCallback(); // 执行失败回调,尝试下一个来源
                    } else if (typeof callback === 'function') {
                        callback(); // 确保回调函数被执行
                    }
                }
            },
            onerror: xhr => {
                console.log("javbus请求失败: ", xhr);
                
                if (typeof failCallback === 'function') {
                    failCallback(); // 执行失败回调,尝试下一个来源
                } else if (typeof callback === 'function') {
                    callback(); // 确保回调函数被执行
                }
            }
        })
    }

    /**
     * 请求FC2PPV DB获取标题信息
     */
    function requestFC2(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback) {
        console.log("请求FC2PPV DB: " + fc2Number);
        
        // 构建查询URL
        const fc2Url = fc2ppvdbBase + fc2Number;
        console.log("FC2查询URL: " + fc2Url);
        
        // 显示查询进度通知
        showPageNotification(`正在从FC2PPVDB查询: ${fc2Number}`, 'info', 2000);
        
        GM_xmlhttpRequest({
            method: "GET",
            url: fc2Url,
            timeout: 10000, // 10秒超时
            onload: xhr => {
                try {
                    if (xhr.status !== 200) {
                        console.log(`FC2PPV DB请求返回非200状态码: ${xhr.status}`);
                        handleFC2Error(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback, "查询返回非200状态码");
                        return;
                    }
                    
                    let response = $(xhr.responseText);
                    
                    // 查找标题元素
                    let title = null;
                    let articleLink = response.find('a[href*="adult.contents.fc2.com"]');
                    
                    if (articleLink.length > 0) {
                        title = articleLink.text().trim();
                        console.log("从FC2PPV DB获取到标题: " + title);
                    }
                    
                    // 如果没有找到标题,尝试其他方法
                    if (!title || title.length === 0) {
                        // 尝试找到页面标题
                        title = response.find("title").text().trim();
                        if (title.includes(" - FC2PPVDB")) {
                            title = title.replace(" - FC2PPVDB", "").trim();
                        }
                        console.log("从页面标题获取标题: " + title);
                    }
                    
                    // 如果仍然没有找到标题,尝试找到任何链接或标题类元素
                    if (!title || title.length === 0) {
                        let possibleElements = response.find("h1, h2, h3, a.title");
                        if (possibleElements.length > 0) {
                            title = possibleElements.first().text().trim();
                            console.log("从其他元素获取到标题: " + title);
                        }
                    }
                    
                    // 仔细检查页面内容是否包含没有找到项目的提示
                    let pageText = response.text();
                    if (pageText.includes("No articles found") || pageText.includes("没有找到相关项目") || pageText.includes("Not Found")) {
                        console.log("FC2PPV DB页面显示未找到内容");
                        handleFC2Error(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback, "未找到该FC2编号的内容");
                        return;
                    }
                    
                    // 查找日期信息
                    let date = null;
                    let dateElement = response.find("time");
                    if (dateElement.length > 0) {
                        date = dateElement.attr("datetime") || dateElement.text().trim();
                        console.log("找到日期信息: " + date);
                        
                        // 尝试格式化日期
                        if (date) {
                            let dateMatch = date.match(/(\d{4})[/-](\d{1,2})[/-](\d{1,2})/);
                            if (dateMatch) {
                                date = `${dateMatch[1]}-${dateMatch[2].padStart(2, '0')}-${dateMatch[3].padStart(2, '0')}`;
                                console.log("格式化日期: " + date);
                            }
                        }
                    }
                    
                    if (title && title.length > 0) {
                        // 构建标准FC2番号格式
                        let standardFC2 = "FC2-PPV-" + fc2Number;
                        console.log("标准化FC2番号: " + standardFC2);
                        
                        // 构建新名称
                        let newName = buildNewName(standardFC2, suffix, chineseCaptions, Uncensored, title);
                        
                        // 添加时间
                        if (addDate && date) {
                            newName = date + "_" + newName;
                            console.log("添加日期后的文件名: " + newName);
                        }
                        
                        if (newName) {
                            // 修改名称
                            send_115(fid, newName, standardFC2, callback);
                            return;
                        } else {
                            // 找到标题但构建名称失败
                            console.log("构建名称失败");
                            handleFC2Error(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback, "构建文件名失败");
                        }
                    } else {
                        // 没有找到标题
                        console.log("FC2PPV DB未找到标题");
                        handleFC2Error(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback, "未找到标题信息");
                    }
                } catch (e) {
                    console.log("处理FC2PPV DB响应出错: ", e);
                    handleFC2Error(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback, "处理响应出错: " + e.message);
                }
            },
            onerror: xhr => {
                console.log("FC2PPV DB请求失败: ", xhr);
                // 检查是否是因为@connect权限问题
                let errorMsg = xhr.error || xhr.toString();
                if (errorMsg.includes("@connect") || errorMsg.includes("Refused to connect")) {
                    handleFC2Error(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback, 
                                  "fc2ppvdb.com不在@connect列表中,请更新脚本或在Tampermonkey设置中添加该域名", true);
                } else {
                    handleFC2Error(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback, "请求失败");
                }
            },
            ontimeout: () => {
                console.log("FC2PPV DB请求超时");
                handleFC2Error(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback, "请求超时");
            }
        });
    }
    
    /**
     * 处理FC2查询错误
     * 对于FC2文件,如果查询失败,不再尝试其他网站
     */
    function handleFC2Error(fid, fh, suffix, chineseCaptions, Uncensored, addDate, fc2Number, callback, errorMsg, isConnectError = false) {
        let standardFC2 = "FC2-PPV-" + fc2Number;
        
        // 如果是@connect错误,给出特殊提示
        if (isConnectError) {
            let notificationMsg = `${standardFC2}: ${errorMsg}`;
            console.log(notificationMsg);
            GM_notification(getDetails(notificationMsg, "FC2查询失败-权限问题"));
            showPageNotification(notificationMsg, 'error', 8000);
            
            // 显示详细说明
            let connectHelp = "请在Tampermonkey脚本设置中添加@connect和@domain: fc2ppvdb.com,或更新脚本版本。";
            console.log(connectHelp);
            showPageNotification(connectHelp, 'info', 10000);
            
            if (typeof callback === 'function') {
                callback(); // 确保回调函数被执行
            }
            return;
        }
        
        // 普通错误处理
        let notificationMsg = `${standardFC2}: ${errorMsg}`;
        console.log(notificationMsg);
        GM_notification(getDetails(standardFC2, "FC2查询失败"));
        showPageNotification(notificationMsg, 'error', 5000);
        
        // 对于FC2文件,查询失败就不再尝试其他网站,直接返回
        if (typeof callback === 'function') {
            callback(); // 确保回调函数被执行
        }
    }
    
    /**
     * 请求javdb获取标题信息
     */
    function requestJavdb(fid, fh, suffix, chineseCaptions, Uncensored, addDate, callback) {
        console.log("请求JavDB: " + fh);
        
        // 构建搜索URL
        const searchUrl = javdbSearchBase + fh;
        
        GM_xmlhttpRequest({
            method: "GET",
            url: searchUrl,
            onload: xhr => {
                try {
                    // 解析搜索结果页面
                let response = $(xhr.responseText);
                    
                    // 查找第一个搜索结果
                    let firstResult = response.find('.movie-list .item').first();
                    if (firstResult.length > 0) {
                        // 获取详情页链接
                        let detailLink = firstResult.find('a.box').attr('href');
                        if (detailLink) {
                            // 确保链接是完整的URL
                            if (detailLink.startsWith('/')) {
                                detailLink = javdbDirectAccess + detailLink.substring(1);
                            }
                            
                            console.log("获取到详情页链接: " + detailLink);
                            
                            // 请求详情页
                            GM_xmlhttpRequest({
                                method: "GET",
                                url: detailLink,
                                onload: detailXhr => {
                                    try {
                                        let detailResponse = $(detailXhr.responseText);
                                        
                                        // 获取标题
                                        let title = null;
                                        
                                        // 方法1: 从h2标签获取
                                        let h2Title = detailResponse.find('h2.title');
                                        if (h2Title.length > 0) {
                                            title = h2Title.text().trim();
                                            console.log("从h2获取标题: " + title);
                                        }
                                        
                                        // 方法2: 从页面标题获取
                                        if (!title || title.length === 0) {
                                            title = detailResponse.find('title').text().trim();
                                            if (title.includes(" - JavDB")) {
                                                title = title.replace(" - JavDB", "").trim();
                                            }
                                            console.log("从页面标题获取标题: " + title);
                                        }
                                        
                                        // 获取日期
                                        let date = null;
                                        
                                        // 方法1: 查找含有发行日期的元素
                                        let dateElements = detailResponse.find('.panel-block .value');
                                        dateElements.each(function() {
                                            let text = $(this).text().trim();
                                            let dateMatch = text.match(/(\d{4}-\d{2}-\d{2})/);
                                            if (dateMatch) {
                                                date = dateMatch[0];
                                                console.log("找到日期信息: " + date);
                                                return false; // 找到日期后停止循环
                                            }
                                        });
                                        
                                        // 方法2: 在整个页面文本中查找日期格式
                                        if (!date) {
                                            let pageText = detailResponse.text();
                                            let dateMatch = pageText.match(/(\d{4}-\d{2}-\d{2})/);
                                            if (dateMatch) {
                                                date = dateMatch[0];
                                                console.log("从页面文本中匹配到日期: " + date);
                                            }
                                        }
                                        
                                        if (title && title.length > 0) {
                                            // 处理标题中可能存在的番号前缀
                                            if (title.toUpperCase().indexOf(fh.toUpperCase()) === 0) {
                                                title = title.substring(fh.length).trim();
                                                console.log("移除番号前缀后的标题: " + title);
                                            }
                                            
                        // 构建新名称
                                            let newName = buildNewName(fh, suffix, chineseCaptions, Uncensored, title);

                        // 添加时间
                        if (addDate && date) {
                            newName = date + "_" + newName;
                                                console.log("添加日期后的文件名: " + newName);
                        }

                        if (newName) {
                            // 修改名称
                                                send_115(fid, newName, fh, callback);
                                                return;
                                            }
                                        }
                                        
                                        // 如果找不到有效信息,通知失败
                                        console.log("JavDB详情页没有找到有效信息");
                                        GM_notification(getDetails(fh, "JavDB未找到有效信息"));
                                        if (typeof callback === 'function') {
                                            callback();
                                        }
                                        
                                    } catch (e) {
                                        console.log("处理JavDB详情页响应出错: ", e);
                                        GM_notification(getDetails(fh, "处理JavDB详情页出错"));
                                        if (typeof callback === 'function') {
                                            callback();
                                        }
                                    }
                                },
                                onerror: err => {
                                    console.log("JavDB详情页请求失败: ", err);
                                    GM_notification(getDetails(fh, "JavDB详情页请求失败"));
                                    if (typeof callback === 'function') {
                                        callback();
                                    }
                                }
                            });
                        } else {
                            console.log("未找到详情页链接");
                            GM_notification(getDetails(fh, "JavDB未找到详情页链接"));
                            if (typeof callback === 'function') {
                                callback();
                            }
                        }
                    } else {
                        console.log("JavDB搜索结果为空");
                        GM_notification(getDetails(fh, "JavDB搜索结果为空"));
                        if (typeof callback === 'function') {
                            callback();
                        }
                    }
                    
                } catch (e) {
                    console.log("处理JavDB搜索响应出错: ", e);
                    GM_notification(getDetails(fh, "处理JavDB搜索结果出错"));
                    if (typeof callback === 'function') {
                        callback();
                    }
                }
            },
            onerror: xhr => {
                console.log("JavDB搜索请求失败: ", xhr);
                GM_notification(getDetails(fh, "JavDB搜索请求失败"));
                if (typeof callback === 'function') {
                    callback();
                }
            }
        });
    }

    /**
     * 构建新名称
     * @param fh                番号
     * @param suffix            后缀
     * @param chineseCaptions   是否有中文字幕
     * @param title             番号标题
     * @returns {string}        新名称
     */
    function buildNewName(fh, suffix, chineseCaptions, Uncensored, title) {
        if (title) {
            let newName = String(fh);
            // 有中文字幕
            if (chineseCaptions) {
                newName = newName + "【中文字幕】";
            }
            // 有无码
            if (Uncensored) {
                newName = newName + "【无码】";
            }
            // 拼接标题
            newName = newName + " " + title;
            if (suffix) {
                // 文件保存后缀名
                newName = newName + suffix;
            }
            return newName;
        }
    }

    /**
     * 请求115接口
     * @param id 文件id
     * @param name 要修改的名称
     * @param fh 番号
     * @param callback 成功回调
     */
    function send_115(id, name, fh, callback) {
        let file_name = stringStandard(name);
        $.post("https://webapi.115.com/files/edit", {
                fid: id,
                file_name: file_name
            },
            function (data, status) {
                let result = JSON.parse(data);
                if (!result.state) {
                    GM_notification(getDetails(fh, "修改失败"));
                    showPageNotification(`${fh} 修改失败: ${result.error}`, 'error', 3000);
                    console.log("请求115接口异常: " + unescape(result.error
                        .replace(/\\(u[0-9a-fA-F]{4})/gm, '%$1')));
                } else {
                    GM_notification(getDetails(fh, "修改成功"));
                    showPageNotification(`${fh} 修改成功`, 'success', 2000);
                    console.log("修改文件名称,fh:" + fh, "name:" + file_name);
                    if (typeof callback === 'function') {
                        callback();
                    }
                }
            }
        );
    }

    /**
     * 通知参数
     * @param text 内容
     * @param title 标题
     * @returns {{text: *, title: *, timeout: number}}
     */
    function getDetails(text, title) {
        return {
            text: text,
            title: title,
            timeout: 1000
        };
    }

    /**
     * 115名称不接受(\/:*?\"<>|)
     * @param name
     */
    function stringStandard(name) {
        return name.replace(/\\/g, "")
            .replace(/\//g, " ")
            .replace(/:/g, " ")
            .replace(/\?/g, " ")
            .replace(/"/g, " ")
            .replace(/</g, " ")
            .replace(/>/g, " ")
            .replace(/\|/g, "")
            .replace(/\*/g, " ");
    }

    /**
     * 校验是否为中文字幕
     * @param fh    番号
     * @param title 标题
     */
    function checkChineseCaptions(fh, title) {
        if (title.indexOf("中文") !== -1) {
            return true;
        }
        let regExp = new RegExp(fh + "[_-](UC|C)");
        let match = title.toUpperCase().match(regExp);
        if (match) {
            return true;
        }
    }
    /**
     * 校验是否为无码
     * @param fh    番号
     * @param title 标题
     */
	function checkUncensored(fh, title) {
         if (title.indexOf("无码") !== -1) {
            return true;
        }
		let regExp = new RegExp(fh + "[_-](UC|U)");
		let match = title.toUpperCase().match(regExp);
		if (match) {
			return true; // 如果标题中包含 "-U" 或 "_U",则返回 true,表示为无码
		}
		return false; // 默认情况下,返回 false,表示不是无码
	}
    /**
     * 获取番号
     * @param title         源标题
     * @returns {string}    提取的番号
     */
    function getVideoCode(title) {
        // 排除明显的非番号格式,如单纯的文件格式或编码格式
        const nonAvCodes = ["MP4", "MKV", "AVI", "RMVB", "WMV", "MOV", "FLV", 
                            "X264", "X265", "HEVC", "H264", "H265", "AAC", "MP3"];
        
        // 常见的后缀,需要在提取番号时移除
        const commonSuffixes = ["UC", "C", "U", "字幕"];
        
        // 处理域名前缀
        title = title.replace(/^[a-zA-Z0-9-]+\.(com|net|org|info|xyz|cc|me|tv|io)@/i, "");
        
        title = title.toUpperCase().replace("SIS001", "")
            .replace("1080P", "")
            .replace("720P", "");

        console.log("处理文件名: " + title);
        
        // 预处理:移除末尾的常见后缀
        let cleanTitle = title;
        for (let suffix of commonSuffixes) {
            let suffixPattern = new RegExp(`[-\\s_]*${suffix}\\s*$`, 'i');
            cleanTitle = cleanTitle.replace(suffixPattern, '');
        }
        
        // 移除多余的空格,简化后续处理
        cleanTitle = cleanTitle.replace(/\s+/g, ' ').trim();
        
        if (cleanTitle !== title) {
            console.log("预处理后的文件名: " + cleanTitle);
        }
        
        // 优先检查FC2格式
        // FC2-PPV-1234567 或其他FC2变种格式
        let fc2Match = cleanTitle.match(/FC2[-\s]?PPV[-\s]?(\d{5,7})/i) || 
                       cleanTitle.match(/FC2PPV[_-]?(\d{5,7})/i) ||
                       cleanTitle.match(/FC2\s+(\d{5,7})/i);
                        
        if (fc2Match && fc2Match[1]) {
            let fc2Code = "FC2-PPV-" + fc2Match[1];
            console.log("找到FC2番号: " + fc2Code);
            return fc2Code;
        }

        // 改进常规AV番号格式匹配,允许模式中有空格
        // SONE- 101 -> SONE-101
        let t = cleanTitle.match(/([A-Z]{2,6})[-\s_]*(\d{2,5})/);
        if (t && t[1] && t[2]) {
            let code = t[1] + "-" + t[2];
            console.log("从带空格格式中提取番号: " + code);
            return code;
        }
        
        // 尝试传统匹配方式
        t = cleanTitle.match(/[A-Z]{2,6}[-_]?\d{2,5}/);
        
        if (!t) {
            // 日期+编号格式,如041117_510
            t = cleanTitle.match(/\d{6}_\d{3}/);
            if (t) {
                let code = t.toString();
                // 验证日期格式是否合理
                let month = parseInt(code.substring(0, 2));
                let day = parseInt(code.substring(2, 4));
                let year = parseInt(code.substring(4, 6));
                
                // 检查日期是否在合理范围内
                if (month >= 1 && month <= 12 && day >= 1 && day <= 31 && year >= 0 && year <= 99) {
                    console.log("找到日期格式番号: " + code);
                    return code;
                }
            }
        }
        
        if (!t) {
            // 一本道格式
            t = cleanTitle.match(/1PONDO[-_]\d{6}[-_]\d{2,4}/);
            if (t) {
                t = t.toString().replace("1PONDO_", "")
                    .replace("1PONDO-", "");
            }
        }
        
        if (!t) {
            // HEYZO格式
            t = cleanTitle.match(/HEYZO[-_]?\d{4}/);
        }
        
        if (!t) {
            // 加勒比格式
            t = cleanTitle.match(/CARIB[-_]\d{6}[-_]\d{3}/);
            if (t) {
                t = t.toString().replace("CARIB-", "")
                    .replace("CARIB_", "");
            }
        }
        
        if (!t) {
            // 东京热格式
            t = cleanTitle.match(/N[-_]\d{4}/);
        }
        
        if (!t) {
            // FC2格式 (补充检查,以防前面的优先检查没有匹配到)
            t = cleanTitle.match(/FC2[-_]?(PPV)?[-_]?\d{6,7}/i);
            if (t) {
                // 提取FC2编号
                let fc2NumMatch = t.toString().match(/\d{6,7}/);
                if (fc2NumMatch) {
                    let fc2Code = "FC2-PPV-" + fc2NumMatch[0];
                    console.log("第二次检查找到FC2番号: " + fc2Code);
                    return fc2Code;
                }
            }
        }
        
        if (!t) {
            // T28系列
            t = cleanTitle.match(/T28[-_]\d{3,4}/);
        }
        
        if (!t) {
            // 通用格式:2-5个字母后跟3-5个数字
            t = cleanTitle.match(/[A-Z]{2,5}[-_]?\d{3,5}/);
        }
        
        if (!t) {
            // 日期类型番号,如210622-001
            t = cleanTitle.match(/\d{6}[-_]\d{2,4}/);
        }
        
        // 非常宽松的匹配逻辑,只在上面都匹配不到时使用
        if (!t) {
            // 任意字母+数字组合
            t = cleanTitle.match(/[A-Z]+\d{3,5}/);
        }
        
        // 处理提取到的番号
        if (t) {
            let code = t.toString();
            
            // 检查是否为已知的非番号字符串
            if (nonAvCodes.includes(code)) {
                console.log("跳过文件格式或编码格式: " + code);
                return null;
            }
            
            // 检查番号长度是否合理(4-15字符之间)
            if (code.length < 4) {
                console.log("提取的番号过短 (" + code.length + " 字符),不是有效番号: " + code);
                return null;
            }
            
            if (code.length > 15) {
                console.log("提取的番号过长 (" + code.length + " 字符),不是有效番号: " + code);
                return null;
            }
            
            // 额外检查:番号必须同时包含字母和数字(日期格式除外)
            if (!/\d{6}_\d{3}/.test(code) && (!/[A-Z]/i.test(code) || !/\d/.test(code))) {
                console.log("提取的番号格式不正确 (缺少字母或数字): " + code);
                return null;
            }
            
            // 格式化番号,确保查询成功率
            // 1. 移除下划线,替换为连字符
            code = code.replace(/_/g, "-");
            
            // 2. 如果番号中没有连字符但同时包含字母和数字,在字母和数字之间添加连字符
            // 例如: STARS265 -> STARS-265
            if (!code.includes("-")) {
                let letterPartMatch = code.match(/^([A-Z]+)/);
                let numberPartMatch = code.match(/(\d+)$/);
                
                if (letterPartMatch && numberPartMatch) {
                    let letterPart = letterPartMatch[1];
                    let numberPart = numberPartMatch[1];
                    
                    // 重新构建番号,确保字母和数字之间有连字符
                    if (code === letterPart + numberPart) {
                        let newCode = letterPart + "-" + numberPart;
                        console.log("格式化番号: " + code + " -> " + newCode);
                        code = newCode;
                    }
                }
            }
            
            console.log("找到番号: " + code + " (用于查询的URL: " + javbusBase + code + ")");
            return code;
        }
        
        // 没有匹配到任何番号格式
        console.log("未找到任何番号格式: " + title);
        return null;
    }
    
    /**
     * 执行归档到演员文件夹的功能
     */
    function archiveToActorFolder() {
        // 获取选中的文件数量
        let selectedCount = $("iframe[rel='wangpan']").contents().find("li.selected").length;
        let processedCount = 0;
        let successCount = 0;
        
        // 不再显示额外的归档根目录提示
        showPageNotification(`开始处理 ${selectedCount} 个项目...`, 'info', 3000);
        
        // 获取所有已选择的文件
        $("iframe[rel='wangpan']")
            .contents()
            .find("li.selected")
            .each(function (index, v) {
                let $item = $(v);
                // 原文件名称
                let file_name = $item.attr("title");
                // 文件类型
                let file_type = $item.attr("file_type");
                
                // 根据类型获取正确的ID
                let fid;
                if (file_type === "0") {
                    // 文件夹
                    fid = $item.attr("cate_id");
                    console.log("处理文件夹: " + file_name + ", ID: " + fid);
                    
                    // 从文件夹名称中提取番号
                    let fh = getVideoCode(file_name);
                    if (fh) {
                        console.log("从文件夹名称中提取到番号: " + fh);
                        // 使用与文件相同的逻辑处理文件夹
                        requestJavbusForActor(fid, fh, function() {
                            processedCount++;
                            successCount++;
                            checkAllCompleted();
                        }, function() {
                            processedCount++;
                            checkAllCompleted();
                        });
                    } else {
                        console.log("无法从文件夹名称中提取番号: " + file_name);
                        showPageNotification(`无法从"${file_name}"提取番号`, 'error', 3000);
                        processedCount++;
                        checkAllCompleted();
                    }
                } else {
                    // 文件
                    fid = $item.attr("file_id");
                    
                    if (fid && file_name) {
                        let fh = getVideoCode(file_name);
                        if (fh) {
                            // 执行查询演员并归档
                            requestJavbusForActor(fid, fh, function() {
                                processedCount++;
                                successCount++;
                                checkAllCompleted();
                            }, function() {
                                processedCount++;
                                checkAllCompleted();
                            });
                        } else {
                            console.log("无法从文件名称中提取番号: " + file_name);
                            showPageNotification(`无法从"${file_name}"提取番号`, 'error', 3000);
                            processedCount++;
                            checkAllCompleted();
                        }
                    } else {
                        processedCount++;
                        checkAllCompleted();
                    }
                }
            });
            
        // 检查是否所有文件都处理完毕
        function checkAllCompleted() {
            if (processedCount === selectedCount) {
                if (successCount > 0) {
                    showPageNotification(`处理完成: ${successCount}/${selectedCount} 个项目成功处理`, 'success', 5000);
                } else {
                    showPageNotification(`处理完成: 没有成功处理的项目`, 'info', 5000);
                }
            }
        }
    }

    /**
     * 请求javbus获取演员信息并归档
     * @param fid 文件id
     * @param fh  番号
     * @param successCallback 成功回调
     * @param failCallback 失败回调
     */
    function requestJavbusForActor(fid, fh, successCallback, failCallback) {
        console.log("开始查询番号演员信息: " + fh);
        GM_xmlhttpRequest({
            method: "GET",
            url: javbusDirectAccess + fh,
            onload: xhr => {
                // 分析返回的HTML内容
                let response = $(xhr.responseText);
                console.log("获取到javbus页面内容,开始查找演员信息");
                
                // 打印页面中的演员相关HTML,用于调试
                let actorElements = response.find("span.genre");
                console.log("找到潜在演员元素数量: " + actorElements.length);
                
                // 查找所有演员元素
                let actresses = [];
                actorElements.each(function() {
                    let anchor = $(this).find("a[href*='/star/']");
                    if (anchor.length > 0) {
                        let actorName = anchor.text().trim();
                        let actorLink = anchor.attr("href");
                        console.log("找到演员: " + actorName + ", 链接: " + actorLink);
                        actresses.push({ name: actorName, link: actorLink });
                    }
                });
                
                if (actresses.length > 0) {
                    // 取第一个演员
                    let firstActress = actresses[0];
                    console.log("选择首位演员: " + firstActress.name + " 进行归档");
                    
                    // 查找或创建文件夹,然后移动文件
                    findOrCreateFolderAndMove(fid, firstActress.name, successCallback, failCallback);
                } else {
                    console.log("在有码页面未找到演员信息,尝试查询无码页面");
                    
                    if (javbusDirectAccess !== javbusUncensoredBase) {
                        // 尝试查询无码
                        GM_xmlhttpRequest({
                            method: "GET",
                            url: javbusUncensoredBase + fh,
                            onload: xhrUnc => {
                                let responseUnc = $(xhrUnc.responseText);
                                console.log("获取到javbus无码页面内容,开始查找演员信息");
                                
                                // 打印页面中的演员相关HTML,用于调试
                                let actorElementsUnc = responseUnc.find("span.genre");
                                console.log("找到潜在演员元素数量(无码): " + actorElementsUnc.length);
                                
                                // 查找所有演员元素
                                let actressesUnc = [];
                                actorElementsUnc.each(function() {
                                    let anchor = $(this).find("a[href*='/star/']");
                                    if (anchor.length > 0) {
                                        let actorName = anchor.text().trim();
                                        let actorLink = anchor.attr("href");
                                        console.log("找到演员(无码): " + actorName + ", 链接: " + actorLink);
                                        actressesUnc.push({ name: actorName, link: actorLink });
                                    }
                                });
                                
                                if (actressesUnc.length > 0) {
                                    // 取第一个演员
                                    let firstActressUnc = actressesUnc[0];
                                    console.log("选择首位演员(无码): " + firstActressUnc.name + " 进行归档");
                                    
                                    // 查找或创建文件夹,然后移动文件
                                    findOrCreateFolderAndMove(fid, firstActressUnc.name, successCallback, failCallback);
                                } else {
                                    console.log("HTML内容: " + xhrUnc.responseText.substring(0, 500) + "...");
                                    GM_notification(getDetails(fh, "未找到演员信息"));
                                    console.log("在有码和无码页面均未找到演员信息: " + fh);
                                }
                            }
                        });
                    } else {
                        console.log("HTML内容: " + xhr.responseText.substring(0, 500) + "...");
                        GM_notification(getDetails(fh, "未找到演员信息"));
                        console.log("在有码页面未找到演员信息: " + fh);
                    }
                }
            },
            onerror: err => {
                console.log("请求javbus页面失败: ", err);
                GM_notification(getDetails(fh, "请求javbus页面失败"));
                showPageNotification(`请求javbus页面失败: ${fh}`, 'error', 3000);
                if (typeof failCallback === 'function') {
                    failCallback();
                }
            }
        });
    }
    
    /**
     * 查找或创建文件夹,然后移动文件
     * @param fid       文件id
     * @param actorName 演员名称
     * @param successCallback 成功回调
     * @param failCallback 失败回调
     */
    function findOrCreateFolderAndMove(fid, actorName, successCallback, failCallback) {
        console.log("开始查找或创建文件夹: " + actorName);
        
        // 使用保存的归档根目录ID,如果未设置则使用根目录
        let cid = archiveRootCid || ROOT_DIR_CID;
        let dirName = archiveRootName || "根目录";
        
        console.log("使用归档目录: " + dirName + " (CID: " + cid + ")");
        
        // 清理演员名称,确保不会因为特殊字符导致查询问题
        actorName = stringStandard(actorName);
        console.log("处理后的演员名称: " + actorName);
        
        // 首先检查目标文件夹下是否直接存在同名文件夹(列出所有子文件夹)
        $.get("https://webapi.115.com/files", {
            aid: 1,
            cid: cid,
            limit: 1000, // 获取足够多的文件/文件夹
            offset: 0,
            show_dir: 1,  // 只显示文件夹
            format: "json"
        }, function(listData) {
            let listResult = typeof listData === 'string' ? JSON.parse(listData) : listData;
            console.log("直接获取目录下的所有文件夹,开始查找匹配项");
            
            let folderFound = false;
            let targetCid = null;
            
            // 检查是否有匹配的文件夹
            if (listResult.state && listResult.data && listResult.data.length > 0) {
                console.log("发现 " + listResult.data.length + " 个文件/文件夹");
                
                // 遍历所有项目,查找匹配的文件夹 (使用some而不是forEach,可以在找到匹配项后立即中断)
                listResult.data.some(function(item) {
                    // 仅检查文件夹类型 - 115API中文件夹信息在'n'字段,不是'name'
                    // 文件夹类型可能通过'is_dir'或'm'为0或者存在'cid'而没有'fid'来判断
                    let isFolder = item.is_dir || (item.m === 0 && item.cid && !item.fid);
                    let folderName = item.n || item.name;
                    
                    if (isFolder && folderName === actorName) {
                        folderFound = true;
                        targetCid = item.cid;
                        console.log("找到完全匹配的文件夹(直接列表): " + folderName + ", ID: " + item.cid);
                        return true; // 找到匹配项,中断循环
                    }
                    return false; // 继续循环
                });
            }
            
            if (folderFound && targetCid) {
                // 文件夹存在,直接移动文件
                console.log("使用现有文件夹: " + actorName + ", ID: " + targetCid);
                moveFileToFolder(fid, targetCid, actorName, successCallback, failCallback);
            } else {
                // 如果直接列表没找到,再尝试搜索
                console.log("直接列表未找到,尝试使用搜索API查找: " + actorName);
                
                $.get("https://webapi.115.com/files/search", {
                    search_value: actorName,
                    format: "json",
                    aid: "1", // 搜索范围为115网盘
                    cid: cid, // 使用固定目录
                    file_type: "0", // 只搜索文件夹
                    limit: 1000
                }, function(data) {
                    let result = typeof data === 'string' ? JSON.parse(data) : data;
                    console.log("搜索文件夹结果,开始查找匹配项");
                    
                    let searchFolderFound = false;
                    let searchTargetCid = null;
                    
                    // 检查搜索结果
                    if (result.state && result.data && result.data.count > 0) {
                        console.log("找到 " + result.data.count + " 个可能的文件夹");
                        // 遍历搜索结果,查找完全匹配的文件夹 (使用some而不是forEach)
                        result.data.list.some(function(item) {
                            if (item.name === actorName && item.file_type === "0") {
                                searchFolderFound = true;
                                searchTargetCid = item.cid;
                                console.log("找到完全匹配的文件夹(搜索): " + item.name + ", ID: " + item.cid);
                                return true; // 找到匹配项,中断循环
                            }
                            return false; // 继续循环
                        });
                    }
                    
                    if (searchFolderFound && searchTargetCid) {
                        // 搜索找到了文件夹,使用它
                        console.log("搜索发现现有文件夹: " + actorName + ", ID: " + searchTargetCid);
                        moveFileToFolder(fid, searchTargetCid, actorName, successCallback, failCallback);
                    } else {
                        // 最后确认,再次检查目标文件夹是否存在
                        console.log("最终确认,检查文件夹是否存在: " + actorName);
                        
                        $.get("https://webapi.115.com/files", {
                            aid: 1,
                            cid: cid,
                            limit: 1000,
                            offset: 0,
                            show_dir: 1,
                            format: "json"
                        }, function(finalCheckData) {
                            let finalCheck = typeof finalCheckData === 'string' ? JSON.parse(finalCheckData) : finalCheckData;
                            
                            let finalFolderFound = false;
                            let finalTargetCid = null;
                            
                            // 最后一次检查文件夹是否存在
                            if (finalCheck.state && finalCheck.data && finalCheck.data.length > 0) {
                                // 使用some代替forEach
                                finalCheck.data.some(function(item) {
                                    // 同样更新此处的文件夹检测逻辑
                                    let isFolder = item.is_dir || (item.m === 0 && item.cid && !item.fid);
                                    let folderName = item.n || item.name;
                                    
                                    if (isFolder && folderName === actorName) {
                                        finalFolderFound = true;
                                        finalTargetCid = item.cid;
                                        console.log("最终确认找到文件夹: " + folderName + ", ID: " + item.cid);
                                        return true; // 找到匹配项,中断循环
                                    }
                                    return false; // 继续循环
                                });
                            }
                            
                            if (finalFolderFound && finalTargetCid) {
                                console.log("最终确认发现文件夹,使用它: " + actorName);
                                moveFileToFolder(fid, finalTargetCid, actorName, successCallback, failCallback);
                            } else {
                                // 文件夹确实不存在,创建新文件夹
                                console.log("多次确认后,确定需要创建新文件夹: " + actorName);
                                $.post("https://webapi.115.com/files/add", {
                                    pid: cid,
                                    cname: actorName
                                }, function(createData) {
                                    let createResult = typeof createData === 'string' ? JSON.parse(createData) : createData;
                                    console.log("创建文件夹结果: ", createResult);
                                    
                                    if (createResult.state) {
                                        // 获取新创建的文件夹cid
                                        let newFolderCid = createResult.cid;
                                        console.log("新文件夹创建成功,ID: " + newFolderCid);
                                        moveFileToFolder(fid, newFolderCid, actorName, successCallback, failCallback);
                                    } else {
                                        console.log("创建文件夹失败,响应码: " + createResult.errno + ", 错误: " + createResult.error);
                                        if (createResult.errno === 20004) {
                                            // 如果是"文件夹已存在"错误,尝试再次获取文件夹列表
                                            console.log("文件夹已存在错误,尝试最后一次查找");
                                            
                                            // 短暂延迟后再次尝试
                                            setTimeout(function() {
                                                $.get("https://webapi.115.com/files", {
                                                    aid: 1,
                                                    cid: cid,
                                                    limit: 1000,
                                                    offset: 0,
                                                    show_dir: 1,
                                                    format: "json"
                                                }, function(lastData) {
                                                    let lastCheck = typeof lastData === 'string' ? JSON.parse(lastData) : lastData;
                                                    
                                                    let foundFolder = null;
                                                    
                                                    if (lastCheck.state && lastCheck.data && lastCheck.data.length > 0) {
                                                        // 使用some代替forEach
                                                        lastCheck.data.some(function(item) {
                                                            // 同样更新此处的文件夹检测逻辑
                                                            let isFolder = item.is_dir || (item.m === 0 && item.cid && !item.fid);
                                                            let folderName = item.n || item.name;
                                                            
                                                            if (isFolder && folderName === actorName) {
                                                                foundFolder = item;
                                                                return true; // 找到匹配项,中断循环
                                                            }
                                                            return false; // 继续循环
                                                        });
                                                    }
                                                    
                                                    if (foundFolder) {
                                                        console.log("最后尝试成功找到文件夹: " + foundFolder.name + ", ID: " + foundFolder.cid);
                                                        moveFileToFolder(fid, foundFolder.cid, actorName, successCallback, failCallback);
                                                    } else {
                                                        GM_notification(getDetails(actorName, "无法找到或创建文件夹"));
                                                        console.log("所有尝试均失败,无法找到或创建文件夹: " + actorName);
                                                    }
                                                });
                                            }, 1000);
                                        } else {
                                            GM_notification(getDetails(actorName, "创建文件夹失败"));
                                            console.log("创建文件夹失败:", createResult);
                                        }
                                    }
                                }).fail(function(xhr) {
                                    console.log("创建文件夹请求失败: ", xhr.status, xhr.statusText);
                                    GM_notification(getDetails(actorName, "创建文件夹请求失败"));
                                });
                            }
                        }).fail(function(err) {
                            console.log("最终确认请求失败: ", err);
                            GM_notification(getDetails(actorName, "最终确认请求失败"));
                        });
                    }
                }).fail(function(err) {
                    console.log("搜索文件夹请求失败: ", err);
                    GM_notification(getDetails(actorName, "搜索文件夹失败"));
                });
            }
        }).fail(function(err) {
            console.log("列出文件夹请求失败: ", err);
            GM_notification(getDetails(actorName, "列出文件夹失败"));
        });
    }
    
    /**
     * 移动文件到指定文件夹
     * @param fid       文件id
     * @param targetCid 目标文件夹id
     * @param actorName 演员名称(用于通知)
     * @param successCallback 成功回调
     * @param failCallback 失败回调
     */
    function moveFileToFolder(fid, targetCid, actorName, successCallback, failCallback) {
        console.log("开始移动文件: " + fid + " 到文件夹: " + actorName + " (" + targetCid + ")");
        
        $.post("https://webapi.115.com/files/move", {
            pid: targetCid,
            fid: fid
        }, function(data) {
            let result = typeof data === 'string' ? JSON.parse(data) : data;
            console.log("移动文件结果: ", result);
            
            if (result.state) {
                GM_notification(getDetails(actorName, "归档成功"));
                showPageNotification(`文件成功归档到 ${actorName}`, 'success', 2000);
                console.log("文件已成功移动到: " + actorName);
                if (typeof successCallback === 'function') {
                    successCallback();
                }
            } else {
                // 检查是否是临时错误(如"尚未完成,请稍后再试")
                let errorMsg = result.error || '未知错误';
                let isTemporaryError = errorMsg.includes('尚未完成') || 
                                      errorMsg.includes('请稍后再试') || 
                                      errorMsg.includes('队列已满');
                
                if (isTemporaryError) {
                    // 对于临时错误,只记录日志,不显示任何通知
                    console.log("移动文件处理中(临时状态):", errorMsg);
                    // 移除临时错误的通知
                    // showPageNotification(`归档到 ${actorName} 处理中: ${errorMsg}`, 'info', 3000);
                    
                    // 仍然调用成功回调,因为这类错误通常会在后台继续处理最终成功
                    if (typeof successCallback === 'function') {
                        successCallback();
                    }
                } else {
                    // 真正的错误才显示失败通知
                    GM_notification(getDetails(actorName, "归档失败"));
                    showPageNotification(`归档到 ${actorName} 失败: ${errorMsg}`, 'error', 3000);
                    console.log("移动文件失败:", result);
                    if (typeof failCallback === 'function') {
                        failCallback();
                    }
                }
            }
        }).fail(function(err) {
            console.log("移动文件请求失败: ", err);
            GM_notification(getDetails(actorName, "移动文件失败"));
            showPageNotification(`移动文件请求失败: ${err.statusText || '网络错误'}`, 'error', 3000);
            if (typeof failCallback === 'function') {
                failCallback();
            }
        });
    }

    /**
     * 获取javdb评分并更新115文件评分
     */
    function getJavdbRating() {
        // 获取选中的文件数量
        let selectedCount = $("iframe[rel='wangpan']").contents().find("li.selected").length;
        let processedCount = 0;
        let successCount = 0;
        
        showPageNotification(`开始处理 ${selectedCount} 个项目的评分...`, 'info', 3000);
        
        // 获取所有已选择的文件/文件夹
        $("iframe[rel='wangpan']")
            .contents()
            .find("li.selected")
            .each(function (index, v) {
                let $item = $(v);
                // 原文件名称
                let file_name = $item.attr("title");
                // 文件类型
                let file_type = $item.attr("file_type");
                
                // 根据类型获取正确的ID
                let fid;
                if (file_type === "0") {
                    // 文件夹
                    fid = $item.attr("cate_id");
                    console.log("处理文件夹评分: " + file_name + ", ID: " + fid);
                } else {
                    // 文件
                    fid = $item.attr("file_id");
                    console.log("处理文件评分: " + file_name + ", ID: " + fid);
                }

                if (fid && file_name) {
                    let fh = getVideoCode(file_name);
                    if (fh) {
                        // 执行查询评分
                        requestJavdbRating(fid, fh, file_name, function(success) {
                            processedCount++;
                            if (success) successCount++;
                            checkAllCompleted();
                        });
                    } else {
                        console.log("无法从名称中提取番号: " + file_name);
                        showPageNotification(`无法从"${file_name}"提取番号`, 'error', 3000);
                        processedCount++;
                        checkAllCompleted();
                    }
                } else {
                    processedCount++;
                    checkAllCompleted();
                }
            });
            
        // 检查是否所有文件都处理完毕
        function checkAllCompleted() {
            if (processedCount === selectedCount) {
                if (successCount > 0) {
                    showPageNotification(`评分处理完成: ${successCount}/${selectedCount} 个项目成功更新`, 'success', 5000);
                } else {
                    showPageNotification(`评分处理完成: 没有成功处理的项目`, 'info', 5000);
                }
            }
        }
    }
    
    /**
     * 请求javdb获取评分并更新115评分
     * @param fid 文件id
     * @param fh  番号
     * @param file_name 文件名
     * @param callback 回调函数,参数为是否成功
     */
    function requestJavdbRating(fid, fh, file_name, callback) {
        console.log("开始查询番号评分信息: " + fh);
        
        // 使用符合JavDB格式的搜索URL
        const searchUrl = javdbSearchBase + fh + "&f=all";
        console.log("使用搜索URL: " + searchUrl);
        
        GM_xmlhttpRequest({
            method: "GET",
            url: searchUrl,
            timeout: 10000, // 设置10秒超时
            onload: xhr => {
                let status = xhr.status;
                let responseText = xhr.responseText;
                
                if (status === 200) {
                    console.log("成功获取搜索页面,开始解析结果");
                    
                    try {
                        // 解析页面
                        const parser = new DOMParser();
                        const doc = parser.parseFromString(responseText, "text/html");
                        
                        // 获取电影列表中的第一个项目
                        const firstItem = doc.querySelector('.movie-list .item');
                        if (firstItem) {
                            console.log("找到搜索结果的第一项");
                            
                            // 直接从item元素的score属性获取评分
                            const scoreAttr = firstItem.getAttribute('score');
                            if (scoreAttr) {
                                const rating = parseFloat(scoreAttr);
                                const userNum = firstItem.getAttribute('usernum') || '未知';
                                
                                if (!isNaN(rating)) {
                                    console.log(`获取到"${fh}"的评分: ${rating}分 (${userNum}人评价)`);
                                    
                                    // JavDB实际是5分满分制,115也是5分满分制,无需除以2转换
                                    let star115 = Math.round(rating);
                                    console.log(`转换评分: ${rating},四舍五入为 ${star115}星`);
                                    update115Rating(fid, star115, fh, file_name, callback);
                                    return;
                                } else {
                                    console.log("评分格式不正确: " + scoreAttr);
                                }
                            } else {
                                console.log("未找到评分属性");
                                
                                // 尝试从评分文本中获取
                                const ratingElement = firstItem.querySelector('.score .value');
                                if (ratingElement) {
                                    const ratingText = ratingElement.textContent.trim();
                                    console.log("找到评分元素文本: " + ratingText);
                                    
                                    // 提取数字部分
                                    let ratingMatch = ratingText.match(/(\d+\.\d+)分/);
                                    if (ratingMatch && ratingMatch[1]) {
                                        const rating = parseFloat(ratingMatch[1]);
                                        console.log(`从评分文本提取到评分: ${rating}`);
                                        
                                        // JavDB实际是5分满分制,115也是5分满分制,无需除以2转换
                                        let star115 = Math.round(rating);
                                        console.log(`转换评分: ${rating},四舍五入为 ${star115}星`);
                                        update115Rating(fid, star115, fh, file_name, callback);
                                        return;
                                    }
                                }
                            }
                            
                            // 如果没有在搜索结果中找到评分,获取详情页
                            const detailLink = firstItem.querySelector('a.box');
                            if (detailLink) {
                                const href = detailLink.getAttribute('href');
                                if (href) {
                                    const detailUrl = javdbBase + href.substring(1); // 去掉开头的斜杠
                                    console.log("获取到详情页链接: " + detailUrl);
                                    
                                    // 访问详情页获取评分
                                    GM_xmlhttpRequest({
                                        method: "GET",
                                        url: detailUrl,
                                        timeout: 10000,
                                        onload: detailXhr => {
                                            if (detailXhr.status === 200) {
                                                processJavdbRating(fid, fh, detailXhr.responseText, file_name, callback);
                                            } else {
                                                console.log("无法获取详情页: " + fh);
                                                showPageNotification(`无法获取"${fh}"的详情页`, 'error', 3000);
                                                callback(false);
                                            }
                                        },
                                        onerror: err => {
                                            console.log("请求详情页失败: ", err);
                                            let errorMsg = "未知错误";
                                            if (err.error) {
                                                errorMsg = err.error.substring(0, 100);
                                            }
                                            showPageNotification(`请求"${fh}"详情页失败: ${errorMsg}`, 'error', 3000);
                                            callback(false);
                                        },
                                        ontimeout: () => {
                                            console.log("请求详情页超时");
                                            showPageNotification(`请求"${fh}"详情页超时`, 'error', 3000);
                                            callback(false);
                                        }
                                    });
                                    return;
                                }
                            }
                        } else {
                            // 尝试找到任何电影列表项目
                            const anyMovieItem = doc.querySelector('.movie-list .item, div[class*="movie-list"] .item, div[id="waterfall"] .item');
                            if (anyMovieItem) {
                                console.log("找到替代的搜索结果项");
                                
                                // 直接从item元素的score属性获取评分
                                const scoreAttr = anyMovieItem.getAttribute('score');
                                if (scoreAttr) {
                                    const rating = parseFloat(scoreAttr);
                                    const userNum = anyMovieItem.getAttribute('usernum') || '未知';
                                    
                                    if (!isNaN(rating)) {
                                        console.log(`获取到"${fh}"的评分: ${rating}分 (${userNum}人评价)`);
                                        
                                        // JavDB实际是5分满分制,115也是5分满分制,无需除以2转换
                                        let star115 = Math.round(rating);
                                        console.log(`转换评分: ${rating},四舍五入为 ${star115}星`);
                                        update115Rating(fid, star115, fh, file_name, callback);
                                        return;
                                    }
                                }
                            }
                            
                            console.log("未找到搜索结果");
                            showPageNotification(`"${fh}"在JavDB中未找到搜索结果`, 'error', 3000);
                            callback(false);
                        }
                    } catch (e) {
                        console.log("解析搜索页面出错: ", e);
                        showPageNotification(`解析"${fh}"的搜索页面出错`, 'error', 3000);
                        callback(false);
                    }
                } else {
                    console.log("搜索请求失败: " + status);
                    showPageNotification(`搜索"${fh}"失败,状态码: ${status}`, 'error', 3000);
                    callback(false);
                }
            },
            onerror: err => {
                console.log("请求javdb页面失败: ", err);
                let errorMsg = "未知错误";
                if (err.error) {
                    // 如果错误中包含域名不在@connect列表,给出明确提示
                    if (err.error.indexOf("This domain is not a part of the @connect list") !== -1) {
                        errorMsg = "JavDB域名未在@connect列表中,请更新脚本或添加域名到@connect";
                        showPageNotification("需要在脚本设置中允许访问JavDB,请检查@connect设置", 'error', 5000);
                    } else {
                        errorMsg = err.error.substring(0, 100);
                    }
                }
                
                console.log("请求错误详情: ", errorMsg);
                showPageNotification(`请求"${fh}"的JavDB页面失败: ${errorMsg}`, 'error', 3000);
                callback(false);
            },
            ontimeout: () => {
                console.log("请求javdb页面超时");
                showPageNotification(`请求"${fh}"的JavDB页面超时`, 'error', 3000);
                callback(false);
            }
        });
    }
    
    /**
     * 处理JavDB页面内容,提取评分并更新115
     * @param fid 文件id
     * @param fh 番号
     * @param responseText 页面内容
     * @param file_name 文件名
     * @param callback 回调函数
     */
    function processJavdbRating(fid, fh, responseText, file_name, callback) {
        try {
            const parser = new DOMParser();
            const doc = parser.parseFromString(responseText, "text/html");
            
            // 尝试多种选择器来定位评分元素
            let ratingText = null;
            let ratingElement = null;
            
            // 方法1: 查找评分区域
            ratingElement = doc.querySelector('.panel-block .value');
            if (ratingElement) {
                ratingText = ratingElement.textContent.trim();
                console.log("方法1找到评分: " + ratingText);
            }
            
            // 方法2: 查找带有"分"字的元素
            if (!ratingText) {
                const allElements = doc.querySelectorAll('*');
                for (const element of allElements) {
                    const text = element.textContent.trim();
                    if (text.match(/\d+\.\d+分/) && text.indexOf('評價') > 0) {
                        ratingText = text;
                        console.log("方法2找到评分: " + ratingText);
                        break;
                    }
                }
            }
            
            // 方法3: 直接在HTML中查找评分模式
            if (!ratingText) {
                const ratingMatch = responseText.match(/(\d+\.\d+)分, 由(\d+)人評價/);
                if (ratingMatch && ratingMatch[1]) {
                    ratingText = ratingMatch[0];
                    console.log("方法3找到评分: " + ratingText);
                }
            }
            
            if (ratingText) {
                // 从评分文本中提取数字
                const ratingMatch = ratingText.match(/(\d+\.\d+)分/);
                if (ratingMatch && ratingMatch[1]) {
                    const rating = parseFloat(ratingMatch[1]);
                    
                    if (!isNaN(rating)) {
                        console.log(`获取到"${fh}"的评分: ${rating}`);
                        
                        // JavDB实际是5分满分制,115也是5分满分制,无需除以2转换
                        let star115 = Math.round(rating);
                        console.log(`转换评分: ${rating},四舍五入为 ${star115}星`);
                        update115Rating(fid, star115, fh, file_name, callback);
                        return;
                    }
                }
            }
            
            // 如果所有方法都失败
            console.log("页面内容中未找到有效评分信息");
            showPageNotification(`未能解析"${fh}"的评分信息`, 'error', 3000);
            callback(false);
            
        } catch (e) {
            console.log("处理评分页面出错: ", e);
            showPageNotification(`处理"${fh}"的评分页面出错`, 'error', 3000);
            callback(false);
        }
    }
    
    /**
     * 更新115文件评分
     * @param fid 文件id
     * @param star 评分(1-5)
     * @param fh 番号(用于通知)
     * @param file_name 文件名(用于日志)
     * @param callback 回调函数
     */
    function update115Rating(fid, star, fh, file_name, callback) {
        console.log(`开始更新评分: 文件ID=${fid}, 番号=${fh}, 评分=${star}星`);

        // 确保星级在1-5之间
        star = Math.max(1, Math.min(5, star));
        
        // 使用有效的评分API (备用API 1)
        $.ajax({
            url: "https://webapi.115.com/files/score",
            type: "POST",
            data: {
                file_id: fid,
                score: star
            },
            dataType: "json",
            success: function(result) {
                console.log("评分API响应:", JSON.stringify(result));
                
                if (result && result.state) {
                    console.log(`成功更新评分: ${fh}, 文件: ${file_name}, 评分: ${star}星`);
                    showPageNotification(`"${fh}"评分更新为${star}星`, 'success', 2000);
                    callback(true);
                } else {
                    // 尝试备用API
                    console.log(`第一个API评分失败: ${fh}, 错误信息:`, result);
                    console.log(`尝试备用API...`);
                    
                    // 尝试备用API (备用API 2)
                    $.ajax({
                        url: "https://webapi.115.com/files/edit_property",
                        type: "POST",
                        data: {
                            file_id: fid,
                            property: "score",
                            value: star
                        },
                        dataType: "json",
                        success: function(backupResult) {
                            console.log("备用API响应:", JSON.stringify(backupResult));
                            
                            if (backupResult && backupResult.state) {
                                console.log(`备用API成功更新评分: ${fh}`);
                                showPageNotification(`"${fh}"评分更新为${star}星`, 'success', 2000);
                                callback(true);
                            } else {
                                console.log("所有评分API尝试都失败");
                                showPageNotification(`"${fh}"评分更新失败,请尝试手动评分`, 'error', 3000);
                                callback(false);
                            }
                        },
                        error: function() {
                            console.log("备用API请求失败");
                            showPageNotification(`"${fh}"评分更新失败,请尝试手动评分`, 'error', 3000);
                            callback(false);
                        }
                    });
                }
            },
            error: function(xhr) {
                console.log(`评分API请求失败: ${xhr.status}, ${xhr.statusText}`);
                
                // 尝试备用API
                $.ajax({
                    url: "https://webapi.115.com/files/edit_property",
                    type: "POST",
                    data: {
                        file_id: fid,
                        property: "score",
                        value: star
                    },
                    dataType: "json",
                    success: function(backupResult) {
                        console.log("备用API响应:", JSON.stringify(backupResult));
                        
                        if (backupResult && backupResult.state) {
                            console.log(`备用API成功更新评分: ${fh}`);
                            showPageNotification(`"${fh}"评分更新为${star}星`, 'success', 2000);
                            callback(true);
                        } else {
                            console.log("所有评分API尝试都失败");
                            showPageNotification(`"${fh}"评分更新失败,请尝试手动评分`, 'error', 3000);
                            callback(false);
                        }
                    },
                    error: function() {
                        console.log("备用API请求失败");
                        showPageNotification(`"${fh}"评分更新失败,请尝试手动评分`, 'error', 3000);
                        callback(false);
                    }
                });
            }
        });
    }
})();