百度网盘不限速下载-KDown🔥🔥🔥

一款百度云加速程序,加速永无止境,无视黑号

// ==UserScript==
// @name         百度网盘不限速下载-KDown🔥🔥🔥
// @namespace    https://kdown.moiu.net
// @description  一款百度云加速程序,加速永无止境,无视黑号
// @version 1.5.5
// @license      MIT
// @icon https://upload.moiu.net/MoTeam-CDN-img/logo.png
// @resource https://cdn.staticfile.org/limonte-sweetalert2/11.7.1/sweetalert2.min.css
// @require https://cdn.jsdelivr.net/npm/sweetalert2@11.12.2/dist/sweetalert2.all.min.js
// @require https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_setClipboard
// @match        *://pan.baidu.com/disk/home*
// @match        *://yun.baidu.com/disk/home*
// @match        *://pan.baidu.com/disk/main*
// @match        *://yun.baidu.com/disk/main*
// @connect      moiu.cn
// @connect      jsdelivr.net
// @connect      baidu.com
// ==/UserScript==

(() => {
    let aria2Url = localStorage.getItem('aria2Url') || 'http://127.0.0.1:16800/jsonrpc';
    let userAgent = 'netdisk'; // 默认的 UA,在解析接口返回数据后会更新
    let currentLinkIndex = 0;
    let downloadLinks = [];

    GetNotify();

    if (window.location.pathname === "/disk/home") {
        window.location.replace("/disk/main");
    }

    AddElement();

    function GetNotify() {
        GM_xmlhttpRequest({
            method: "GET",
            url: "https://api.moiu.cn/JavaScript/users/info_v2",
            onload: function(response) {
                try {
                    const jsondata = JSON.parse(response.responseText);
                    const { code, message, ua, gg, open } = jsondata;

                    if (open === 1 && code === 200) {
                        Swal.fire({
                            icon: "info",
                            title: gg,
                            text: message,
                            confirmButtonText: "关闭",
                        });
                    }
                } catch (e) {
                    console.error("Error fetching announcement:", e);
                }
            },
        });
    }

    let userInfo = {};

    function fetchUserInfo() {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: "https://pan.baidu.com/rest/2.0/membership/user/info?method=query&clienttype=0&app_id=250528",
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        resolve(data.user_info);
                    } catch (error) {
                        reject(error);
                    }
                },
                onerror: function(error) {
                    reject(error);
                }
            });
        });
    }

    async function getUserInfoOnPageLoad() {
        try {
            const data = await fetchUserInfo();
            userInfo = data;
            console.log("User info fetched on page load:", userInfo);
        } catch (error) {
            console.error("Error fetching user info on page load:", error);
        }
    }

    function AddElement() {
        if (document.getElementById("KDown") === null) {
            const toolbar = document.querySelector("div.wp-s-agile-tool-bar__header");
            if (toolbar) {
                const newButton = document.createElement("button");
                newButton.id = "KDown";
                newButton.className = "u-button nd-file-list-toolbar-action-item u-button--primary";
                newButton.style.marginRight = "8px";
                newButton.innerText = "KDown";
                toolbar.prepend(newButton);

                const statusButton = document.createElement("button");
                statusButton.id = "KDownStatus";
                statusButton.className = "u-button nd-file-list-toolbar-action-item u-button--primary";
                statusButton.style.marginRight = "8px";
                statusButton.innerText = "KDown Status";
                toolbar.prepend(statusButton);

                newButton.addEventListener("click", handleKDownClick);
                statusButton.addEventListener("click", handleKDownStatusClick);
            } else {
                setTimeout(AddElement, 100);
            }
        } else {
            console.log("KDown button already added.");
        }
    }

    async function handleKDownClick() {
        console.log("KDown button clicked.");
        let selectedElements = document.querySelectorAll(".wp-s-pan-table__body-row.mouse-choose-item.selected, .wp-s-file-grid-list__item.text-center.cursor-p.mouse-choose-item.is-checked, .wp-s-file-contain-list__item.text-center.cursor-p.mouse-choose-item.is-checked");
        let selectedIds = Array.from(selectedElements).map(item => item.getAttribute("data-id"));

        console.log("Selected elements:", selectedElements);
        console.log("Selected IDs:", selectedIds);

        if (selectedIds.length === 0) {
            Swal.fire({
                showConfirmButton: true,
                title: '系统提示',
                text: '请选择需要下载的文件',
                icon: 'error'
            });
            return;
        }

        if (selectedIds.length > 1) {
            Swal.fire({
                showConfirmButton: true,
                title: '系统提示',
                text: '暂时只能下载一个文件',
                icon: 'error'
            });
            return;
        }

        let selectedItems = Array.from(selectedElements);
        if (selectedItems.some(item => item.dataset.isdir === "true")) {
            Swal.fire({
                title: '系统提示',
                text: '请不要选择文件夹解析,因为还没学会.',
                icon: 'error'
            });
            return;
        }

        const { value: requestType } = await Swal.fire({
            title: '选择请求类型',
            html: `
                <div>
                    <input type="radio" id="cloud" name="requestType" value="cloud" checked>
                    <label for="cloud">1号接口(无法保证全天稳定,推荐2号接口)</label>
                </div>
                <div>
                    <input type="radio" id="local" name="requestType" value="local">
                    <label for="local">2号接口(稳定,加速需要自带SVIP账号)</label>
                </div>
            `,
            showCancelButton: true,
            cancelButtonText: '取消',
            preConfirm: () => {
                const requestType = document.querySelector('input[name="requestType"]:checked').value;
                return requestType;
            }
        });

        if (!requestType) {
            Swal.fire("提示", "您需要选择一个请求类型来继续", "info");
            return;
        }

        const { value: password } = await Swal.fire({
            title: '输入密码',
            input: 'password',
            inputLabel: '使用前请先获取密码,地址(https://pan.quark.cn/s/11d137f012ef)',
            inputPlaceholder: '这也是为了回老本,没办法,理解下',
            inputAttributes: {
                maxlength: 12,
                autocapitalize: 'off',
                autocorrect: 'off'
            }
        });

        if (!password) {
            Swal.fire("提示", "需要密码来继续", "info");
            return;
        }

        Swal.fire({
            title: "正在获取下载链接...",
            onBeforeOpen: () => {
                Swal.showLoading();
            }
        });

        if (requestType === 'local') {
            try {
                const rootListResponse = await fetchBaiduRootFileList();
                const rootFileList = rootListResponse.list;

                console.log("Baidu root file list response:", rootFileList);

                const myResourceFolderExists = rootFileList.some(file => file.path === "/我的资源");

                if (!myResourceFolderExists) {
                    Swal.fire({
                        title: '错误',
                        text: '似乎你解析的文件没有放在 我的资源 文件夹,或者你根本没创建这个文件夹',
                        icon: 'error'
                    });
                    return;
                }

                let pathLocal;
                let filename;
                try {
                    const listResponse = await fetchBaiduFileList();
                    const fileList = listResponse.list;

                    console.log("Baidu file list response:", fileList);

                    fileList.forEach(file => {
                        if (selectedIds.includes(file.fs_id.toString())) {
                            pathLocal = file.path;
                            filename = file.server_filename;
                        }
                    });

                    if (!pathLocal || !filename) {
                        Swal.fire("错误", "未找到匹配的文件或文件名", "error");
                        return;
                    }

                    console.log("Matched file path:", pathLocal);
                    console.log("Matched file name:", filename);

                    // 生成下载链接的请求
                    const bdstoken = await getBdsToken();
                    if (!bdstoken) {
                        Swal.fire("错误", "无法获取bdstoken", "error");
                        return;
                    }

                    const queryParams = new URLSearchParams({
                        "target": JSON.stringify([pathLocal]),
                        "dlink": 1,
                        "channel": "chunlei",
                        "web": 1,
                        "app_id": 250528,
                        "bdstoken": bdstoken,
                        "logid": "QzBQUQORDY1N0E0QzMzNzEyRDDBNjZDZjc1NzJFQUY6Rkc9MQ%3D%3D",
                        "clienttype": 0
                    });

                    const requestUrl = `https://pan.baidu.com/api/filemetas?${queryParams.toString()}`;

                    // 发起请求以获取下载链接
                    const downloadLinkResponse = await fetch(requestUrl);
                    const downloadLinkData = await downloadLinkResponse.json();

                    if (downloadLinkData.errno === 0) {
                        console.log("Download link data:", downloadLinkData);

                        const downloadLink = downloadLinkData.info[0].dlink;

                        // 显示下载链接
                        Swal.fire({
                            icon: 'success',
                            title: '下载链接获取成功',
                            html: `<a href="${downloadLink}" target="_blank">${downloadLink}</a>`,
                            showCancelButton: true,
                            cancelButtonText: '关闭',
                            confirmButtonText: '复制链接',
                            preConfirm: async () => {
                                try {
                                    await navigator.clipboard.writeText(downloadLink);
                                    Swal.fire({
                                        icon: 'success',
                                        title: '已复制',
                                        text: '下载链接已复制到剪贴板',
                                        showConfirmButton: false,
                                        timer: 1500,
                                    });
                                } catch (err) {
                                    console.error("Failed to copy: ", err);
                                    Swal.fire("复制失败", "无法将链接复制到剪贴板", "error");
                                }
                            },
                            willClose: () => {
                                return false;  // 防止弹窗关闭
                            },
                            allowOutsideClick: false, // 防止外部点击关闭
                            allowEscapeKey: false, // 防止按 ESC 关闭
                            allowEnterKey: false // 防止按回车键关闭
                        });

                    } else {
                        Swal.fire("错误", "无法获取下载链接", "error");
                    }

                } catch (error) {
                    Swal.fire("错误", "无法获取文件列表", "error");
                    console.error("Error fetching file list:", error);
                    return;
                }

            } catch (error) {
                Swal.fire("错误", "无法获取根目录文件列表", "error");
                console.error("Error fetching root directory file list:", error);
                return;
            }
        } else if (requestType === 'cloud') {
            try {
                const bdstoken = await getBdsToken();
                const shareResponse = await shareFiles(bdstoken, selectedIds);
                const shorturl = extractShortUrl(shareResponse.link);

                if (!shorturl) {
                    Swal.fire("错误", "无法提取shorturl", "error");
                    return;
                }

                const wxlistResponse = await callWxlistApi(shorturl, password);
                const extractedData = extractWxlistData(wxlistResponse);

                const parseResponseData = await postToSaveApi(extractedData, password, userInfo.uk, shorturl);
                userAgent = parseResponseData.ua || userAgent; // 从解析接口的 data 中提取 ua
                downloadLinks = [parseResponseData.dlink, ...parseResponseData.urls]; // 获取下载链接

                // 显示下载链接并显示动态获取到的 UA
                showDownloadLink();

            } catch (error) {
                Swal.fire("错误", error.statusText || "处理过程中出现错误", "error");
                console.error("Error:", error);
            }
        }
    }

    function showDownloadLink() {
        Swal.fire({
            icon: 'success',
            title: '下载链接获取成功',
            html: `
            <div style="border: 1px solid #ddd; padding: 10px; margin-bottom: 10px;">
                <a href="${downloadLinks[currentLinkIndex]}" target="_blank">${downloadLinks[currentLinkIndex].substring(0, 50)}...</a>
            </div>
            <div style="border: 1px solid #ddd; padding: 10px; margin-bottom: 10px;">
                <div>当前的 UA:</div>
                <div>${userAgent}</div>
            </div>`,
            showCancelButton: true,
            cancelButtonText: '关闭',
            confirmButtonText: '复制链接',
            showDenyButton: true,
            denyButtonText: '发送到 Aria2',
            footer: `<button id="SetAria2" class="swal2-deny">设置 Aria2 地址</button><button id="ChangeLink" class="swal2-deny">换个下载链接</button>`,
            preConfirm: async () => {
                try {
                    await navigator.clipboard.writeText(downloadLinks[currentLinkIndex]);
                    Swal.fire({
                        icon: 'success',
                        title: '已复制',
                        text: '下载链接已复制到剪贴板',
                        showConfirmButton: false,
                        timer: 1500,
                    });
                } catch (err) {
                    console.error("Failed to copy: ", err);
                    Swal.fire("复制失败", "无法将链接复制到剪贴板", "error");
                }
            },
            willClose: () => {
                return false;  // 防止弹窗关闭
            },
            allowOutsideClick: false, // 防止外部点击关闭
            allowEscapeKey: false, // 防止按 ESC 关闭
            allowEnterKey: false // 防止按回车键关闭
        }).then((result) => {
            if (result.isDenied) {
                sendToAria2([downloadLinks[currentLinkIndex]]);
            }
        });

        document.getElementById("SetAria2").addEventListener("click", setAria2Config);

        document.getElementById("ChangeLink").addEventListener("click", () => {
            if (currentLinkIndex < downloadLinks.length - 1) {
                currentLinkIndex++;
                showDownloadLink();
            }
            if (currentLinkIndex === downloadLinks.length - 1) {
                document.getElementById("ChangeLink").disabled = true;
                document.getElementById("ChangeLink").innerText = "没有更多链接";
            }
        });
    }

    function sendToAria2(downloadLinks) {
        const aria2Config = {
            jsonrpc: "2.0",
            method: "aria2.addUri",
            id: Date.now(),
            params: [
                downloadLinks,
                {
                    header: [`User-Agent: ${userAgent}`] // 使用动态获取到的 UA
                }
            ]
        };

        fetch(aria2Url, {
            method: "POST",
            headers: {
                "Content-Type": "application/json"
            },
            body: JSON.stringify(aria2Config)
        })
        .then(response => response.json())
        .then(data => {
            if (data.error) {
                console.error("Aria2 Error:", data.error.message);
            } else {
                console.log("Aria2 Download Added:", data.result);
            }
        })
        .catch(fetchError => {
            console.error("Fetch Error:", fetchError);
        });
    }

    function setAria2Config() {
        Swal.fire({
            title: '设置 Aria2 地址',
            input: 'text',
            inputLabel: 'Aria2 RPC 地址',
            inputValue: aria2Url,
            showCancelButton: true,
            inputValidator: (value) => {
                if (!value) {
                    return '地址不能为空!';
                }
            }
        }).then((result) => {
            if (result.isConfirmed) {
                aria2Url = result.value;
                localStorage.setItem('aria2Url', aria2Url);
                Swal.fire('成功!', 'Aria2 地址已保存', 'success');
            }
        });
    }

    async function getBdsToken() {
        var htmlString = $("html").html();
        var regex = /"bdstoken":"(\w+)"/;
        var match = regex.exec(htmlString);
        console.log("bdstoken:", match ? match[1] : null);
        return match ? match[1] : null;
    }

    async function shareFiles(bdstoken, selectedIds) {
        const bdpassword = "7777";
        console.log("Sharing files with bdstoken:", bdstoken, "selectedIds:", selectedIds, "bdpassword:", bdpassword);
        return $.post("https://pan.baidu.com/share/set?channel=chunlei&bdstoken=" + bdstoken, {
            period: 1,
            pwd: bdpassword,
            eflag_disable: true,
            channel_list: "[]",
            schannel: 4,
            fid_list: JSON.stringify(selectedIds)
        }).then(response => response);
    }

    function extractShortUrl(link) {
        const regex = /https:\/\/pan\.baidu\.com\/s\/([a-zA-Z0-9-_]+)/;
        const match = regex.exec(link);
        console.log("Extracted short URL:", match ? match[1] : null);
        return match ? match[1] : null;
    }

    function callWxlistApi(shorturl, password) {
        console.log("Calling Wxlist API with shorturl:", shorturl, "password:", password);
        const bdpassword = "7777";
        return new Promise((resolve, reject) => {
            const url = "https://api.moiu.cn/api/List";
            const formParams = {
                "surl": shorturl,
                "dir": "/",
                "password": password,
                "pwd": bdpassword
            };

            $.ajax({
                type: "POST",
                url: url,
                data: formParams,
                success: function(response) {
                    console.log("Wxlist API response:", response);
                    resolve(response);
                },
                error: function(xhr, status, error) {
                    console.error("Error calling Wxlist API:", xhr, status, error);
                    reject({
                        status: xhr.status,
                        statusText: xhr.statusText
                    });
                }
            });
        });
    }

    function extractWxlistData(responseBody) {
        const data = responseBody.data;
        console.log("Extracted data from Wxlist response:", data);
        return {
            uk: data.uk,
            shareid: data.shareid,
            randsk: data.randsk,
            list: data.list,
            fsidlist: data.list.map(item => item.fs_id.toString()),
            size: data.list[0]?.size || 0, // 提取第一个列表项的 size 属性
            filename: data.list[0]?.server_filename || 0, // 提取第一个列表项的 filename 属性
        };
    }

    function postToSaveApi(data, password, userid, shorturl) {
        const requestData = {
            fsidlist: String(data.list[0].fs_id),
            sekey: data.randsk,
            uk: data.uk,
            shareid: data.shareid,
            password,
            surl: shorturl,
            userid,
            size: data.size,
            filename: data.filename  // 添加 filename 参数
        };

        console.log("Prepared request data for Save API:", requestData);

        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "POST",
                url: "https://api.moiu.cn/api/v0/parse",
                headers: {
                    "Content-Type": "application/json"
                },
                data: JSON.stringify(requestData),
                onload: function(response) {
                    const responseData = JSON.parse(response.responseText);
                    console.log("Save API response:", responseData);
                    if (responseData.code !== 200) {
                        Swal.fire("错误", responseData.message, "error");
                        reject({
                            status: response.status,
                            statusText: responseData.message
                        });
                    } else {
                        resolve(responseData.data); // 直接返回data对象
                    }
                },
                onerror: function(response) {
                    const errorMessage = JSON.parse(response.responseText).message || '网络错误';
                    Swal.fire("错误", errorMessage, "error");
                    console.error("Error posting to Save API:", response);
                    reject({
                        status: response.status,
                        statusText: errorMessage
                    });
                }
            });
        });
    }

    async function handleKDownStatusClick() {
        Swal.fire("检查中...", "正在检查服务器状态,请稍候...", "info");
        GM_xmlhttpRequest({
            method: "GET",
            url: "https://api.moiu.cn/api/v0/status",
            onload: function(response) {
                try {
                    const data = JSON.parse(response.responseText);
                    const { code, message } = data;
                    console.log("Server status response:", data);
                    if (code === 200) {
                        Swal.fire({
                            icon: "success",
                            title: "服务器状态",
                            text: message,
                        });
                    } else if (code === 201) {
                        Swal.fire({
                            icon: "error",
                            title: "服务器状态",
                            text: message,
                        });
                    } else {
                        Swal.fire({
                            icon: "warning",
                            title: "服务器状态",
                            text: "未知状态",
                        });
                    }
                } catch (error) {
                    Swal.fire("错误", "处理服务器响应时发生错误", "error");
                    console.error("Error handling server response:", error);
                }
            },
            onerror: function(error) {
                Swal.fire("错误", "无法连接到服务器", "error");
                console.error("Error connecting to server:", error);
            },
        });
    }

    async function fetchBaiduRootFileList() {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: "https://pan.baidu.com/api/list?clienttype=0&app_id=250528&web=1&order=time&desc=1&dir=%2F&num=100&page=1",
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.errno === 0) {
                            resolve(data);
                        } else {
                            reject(new Error("API 返回错误: " + data.errno));
                        }
                    } catch (error) {
                        reject(error);
                    }
                },
                onerror: function(error) {
                    reject(error);
                }
            });
        });
    }

    async function fetchBaiduFileList() {
        return new Promise((resolve, reject) => {
            GM_xmlhttpRequest({
                method: "GET",
                url: "https://pan.baidu.com/api/list?clienttype=0&app_id=250528&web=1&order=time&desc=1&dir=%2F%E6%88%91%E7%9A%84%E8%B5%84%E6%BA%90&num=100&page=1",
                onload: function(response) {
                    try {
                        const data = JSON.parse(response.responseText);
                        if (data.errno === 0) {
                            resolve(data);
                        } else {
                            reject(new Error("API 返回错误: " + data.errno));
                        }
                    } catch (error) {
                        reject(error);
                    }
                },
                onerror: function(error) {
                    reject(error);
                }
            });
        });
    }

    // 在页面加载完成后请求用户信息
    getUserInfoOnPageLoad();
})();