Greasy Fork is available in English.

神速Down

一个纯净好用的百度网盘下载助手,绝无多余附加功能。免SVIP会员,免安装浏览器扩展,无视黑号,只要你有个IDM或Aria2,就能享受极速下载的快感!

2023/11/19時点のページです。最新版はこちら。

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         神速Down
// @namespace    http://sswpdd.xyz/
// @version      3.2.1
// @antifeature  membership
// @description  一个纯净好用的百度网盘下载助手,绝无多余附加功能。免SVIP会员,免安装浏览器扩展,无视黑号,只要你有个IDM或Aria2,就能享受极速下载的快感!
// @author       SSDown
// @icon         http://sswpdd.xyz/ewm.jpg
// @match        *://pan.baidu.com/*
// @match        *://yun.baidu.com/*
// @require      https://lib.baomitu.com/jquery/3.6.0/jquery.js
// @require      https://lib.baomitu.com/sweetalert/2.1.2/sweetalert.min.js
// @require      https://lib.baomitu.com/clipboard.js/2.0.6/clipboard.min.js
// @run-at       document-idle
// @grant        unsafeWindow
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @grant        GM_listValues
// @grant        GM_openInTab
// @grant        GM_notification
// @grant        GM_xmlhttpRequest
// @connect      localhost
// @connect      127.0.0.1
// @connect      baidu.com
// @connect      sswpdd.xyz
// ==/UserScript==

(function () {
    'use strict';

    let globalData = {
        scriptVersion: '2.1.0',
        domain: '',
        domainB: '',
        param: '',
        downloading: 0,
        sending: 0,
        storageNamePrefix: 'SSD_storageName', // 本地储存名称前缀
    }

    let getAppSettingData = function () {
        return {
            scriptVersion: globalData.scriptVersion,
            param: globalData.param,
            storageNamePrefix: globalData.storageNamePrefix,
            getDownloadUrl: `/bd/api.php`,
        }
    }

    let tmpData = {
        response: '',
        pwd: '',
        fs_id: '',
        token: '',
    }

    let configDefault = {
        savePath: 'D:\\SSDown',
        jsonRpc: 'http://localhost:6800/jsonrpc',
        token: '',
        mine: '',
        code: '',
    };
    let getConfig = function () {
        // 上次使用 > 应用配置 > 代码默认
        return {
            savePath: getStorage.getLastUse('savePath') || getStorage.getAppConfig('savePath') || configDefault.savePath,
            jsonRpc: getStorage.getLastUse('jsonRpc') || getStorage.getAppConfig('jsonRpc') || configDefault.jsonRpc,
            token: getStorage.getLastUse('token') || getStorage.getAppConfig('token') || configDefault.token,
            mine: getStorage.getLastUse('mine') || getStorage.getAppConfig('mine') || configDefault.mine,
            code: getStorage.getLastUse('code') || configDefault.code,
        }
    }
    let getStorage = {
        getAppConfig: (key) => {
            return GM_getValue(getAppSettingData().storageNamePrefix + '_app_' + key) || '';
        },
        setAppConfig: (key, value) => {
            GM_setValue(getAppSettingData().storageNamePrefix + '_app_' + key, value || '');
        },
        getLastUse: (key) => {
            return GM_getValue(getAppSettingData().storageNamePrefix + '_last_' + key) || '';
        },
        setLastUse: (key, value) => {
            GM_setValue(getAppSettingData().storageNamePrefix + '_last_' + key, value || '');
        },
        getCommonValue: (key) => {
            return GM_getValue(getAppSettingData().storageNamePrefix + '_common_' + key) || '';
        },
        setCommonValue: (key, value) => {
            GM_setValue(getAppSettingData().storageNamePrefix + '_common_' + key, value || '');
        }
    }

    let uInfo = {};

    let isOldHomePage = function () {
        let url = location.href;
        if (url.indexOf(".baidu.com/disk/home") > 0) {
            return true;
        } else {
            return false;
        }
    };

    let isNewHomePage = function () {
        let url = location.href;
        if (url.indexOf(".baidu.com/disk/main") > 0) {
            return true;
        } else {
            return false;
        }
    };

    let isSharePage = function () {
        let path = location.pathname.replace('/disk/', '');
        if (/^\/(s|share)\//.test(path)) {
            return true;
        } else {
            return false;
        }
    }

    let getSelectedFileList = function () {
        let pageType = getPageType();
        if (pageType === 'old') {
            return require('system-core:context/context.js').instanceForSystem.list.getSelected();
        }
        if (pageType === 'new') {
            let mainList = document.querySelector('.nd-main-list');
            if (!mainList) mainList = document.querySelector('.nd-new-main-list');//20220524 新版
            return mainList.__vue__.selectedList;
        }
    };

    let getFileListStat = function (fileList) {
        let fileStat = {
            file_num: 0,
            dir_num: 0
        };
        fileList.forEach(function (item) {
            if (item.isdir == 0) {
                fileStat.file_num++;
            } else {
                fileStat.dir_num++;
            }
        });
        return fileStat;
    };

    let initButtonEvent = function () {
        console.log('initButtonEvent初始化按钮事件');
        let pageType = getPageType();
        let yunData = getYunData();
        if (!yunData && pageType != 'new') {
            showLogin();
            return;
        }
        //暂时限制只能在管理页面中使用
        if (pageType === 'share') {
            showTipErrorSwal('必须先转存到自己网盘中,然后进入网盘进行下载!');
            console.log('必须先转存到自己网盘中');
            showShareSave();
        } else {
            let fileList = getSelectedFileList();
            let fileStat = getFileListStat(fileList);
            if (fileList.length) {
                if (fileStat.file_num > 1 || fileStat.dir_num > 0) {
                    showTipError('请选择一个文件进行下载(暂时不支持文件夹和多文件批量下载)')
                }
                if (fileStat.dir_num == 0 && fileStat.file_num == 1) {
                    showDownloadDialog(fileList, fileStat);
                    setShareCompleteState();
                    //自动下载
                    // getJquery()("#dialogBtnGetUrl").click();
                }
            } else {
                showTipErrorSwal('请选择一个文件进行下载');
            }
        }
    };

    let getYunData = function () {
        return unsafeWindow.yunData;
    };

    let showTipErrorSwal = function (err) {
        showSwal(err, {icon: 'error'});
    }
    let showTipError = function (err) {
        // showSwal(err,{icon: 'error'});
        alert(err);
    }
    let showTipInfo = function (info) {
        //getJquery()("#dialogOpTips").show().html(info);
        getJquery()("#dialogRemark").html(info);
    }
    let showTipInfoAria = function (info) {
        //getJquery()("#dialogOpTipsAria").show().html(info);
        getJquery()("#dialogBtnAria").contents().last()[0].textContent = info;

    }
    let showTipInfoIdm = function (info) {
       // getJquery()("#dialogOpTipsIdm").show().html(info);
       getJquery()("#dialogBtnIdm").contents().last()[0].textContent = info;
    }

    let showSwal = function (content, option) {
        divTips.innerHTML = content;
        option.content = divTips;
        if (!option.hasOwnProperty('button')) {
            option.button = '好! 我 知 道 了'
        }
        swal(option);
    }

    let getJquery = function () {
        // return require("base:widget/libs/jquerypacket.js");
        return $;
    };
    let showLogin = function () {
        require("base:widget/libs/jquerypacket.js")("[node-type='header-login-btn']").click();
    };
    let showShareSave = function () {
        require("base:widget/libs/jquerypacket.js")("[node-type='shareSave']").click();
    };

    let popup = function() {
    let t = getJquery()("#popup");
        if (t.css("display") == "none") {
            t.show();
        } else {
            t.hide();
        }
}


    //下载面板
    let showDownloadDialog = function (fileList, fileStat) {
        let theFile = fileList[0];
        console.log(theFile);
        let content = `
<div id="downloadDialog">
    <div id="dialogTop">
     已选中的文件 ${CutString(theFile.server_filename, 35)}
    </div>
    <div id="dialogMiddle">
<div id="dialogLeft">
            <div id="dialogQr">
                <img id="dialogQrImg" src="http://sswpdd.xyz/ewm.jpg">
            </div>
            <p class="title">扫一扫不失联</p>
            <div class="sub_title">发送</div><div><em class="emwz">免费白嫖</em></div><br<div class="emwtl" style="
    color: initial;
    font-size: 20px;
    caret-color:transparent;
">四个字获取暗号/无套路</br<div>
    <div id="gearIcon">
        <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAh9JREFUWEfFl9FRxDAMRHWdQCVAJUAlQCUclUAn0AnMy3gzwmfJTpyZy89dEltaSauVc7IrX6cr+7ctAJ7M7NHM3szsKwB+b2YvZvZR1vz0AhwBgON3M8MYjrk/FyBycFPAvZZ3AOHZc7kPcfQAfJoZxjBM5FzcAwgH/gIMDpUd1rBWz5vZyACQSqJ9KEZaUchBlGqBVcYubGQAFCUAZq5vV7JNAIieLNzOeDez34wLIyWYBbA7AyD35NubCHGpGUiUATbhnE0tgqntPAnp/dbalIgtAHIO+VqCo/dkBIdqR/5HbNeeC13wAHx/RwIiQwDz3eGFKCqbSgFQsgXYVYoxAFkwjPOor+FF7dxzA+HCVqQdBImc02FLeZUBXrA56wpJcsQLgCiQngQTyFJiORzpeYSJdT35TtuupIs1SPvZA8DBEbrgSxm17ipOdQmy9KpMUXeMlkBl+lcCGc9I6IkazQdNzygQnRf4XYL3KVeb4ChqJRERoP5gwh6N32ivOITflaSZEGX9zLtaiLjv7aH3cb5eM1JMGu9K65GRSIpVugvndQlqxo6008iA2jWMMHzUgQRiijObDiQp8pHQa9Fp7TlCeHpYdh9I1FbRYIFc/jwQnQUoQXiwyTKAA003/x0weiyXKGXTsztYREZ9aGCM/2q7ZaaXZ3CGdzxDsDJd6OpAXVfNcX79x0e9TsQV6w/5NOuRbOp9b7ZPGR/Z/AfzOqohK4HohwAAAABJRU5ErkJggg==" alt="Settings">
    </div>

<div id="popup" class="hidden">
        <div id="closeButton">X</div>
        <div class="content">

            <div id="dialogDivSavePath">
            <span> 保存路径:</span><input type="text" id="dialogTxtSavePath" value="D:\SSDown" style="width: 170px;"><br>
                        <span id="dialogAriaConfigClick">配置Aria2/Motrix&gt;&gt;</span>
                        <div id="dialogAriaConfig">
                            <input type="text" id="dialogAriaRPC" value="http://localhost:6800/jsonrpc" title="RPC地址" placeholder="RPC地址" style="width: 100%;">
                            <input type="text" id="dialogAriaToken" value="" title="token" placeholder="token" style="width: 77px;">
                            <br>
                            <input type="checkbox" id="dialogAriaMine" value="checked">
                            <span>使用自己的Aria2/Motrix(如不懂,勿勾选)</span>
			      <span class="bcsp">Motrix默认地址:</span><span>http://localhost:16800/jsonrpc </span>
			      <br>
			      <span class="bcsp">Aria2默认地址:</span><span>&nbsp;&nbsp;http://localhost:6800/jsonrpc </span>
                        </div>
                    </div>
        </div>
    </div>

        </div>
        <div id="dialogRight">
            <div id="dialogContent">
                <div id="tipp">

  <div class="block1">
<p class="titleidmair">IDM</p>
<p class="sub_titledown">选项 -&gt; 下载 -&gt; 手动添加任务时使用的用户代理(UA)-&gt; 填入 LogStatistic。在 IDM 新建任务,粘贴链接即可下载。</p>

<a id=""  class="btnInterfaceidmyc" style="display: inline;"></a>

<a id="dialogBtnIdm" data-clipboard-text="" class="btnInterface">复制链接</a>
</div>

 <hr class="hrfg">

<div class="block2"><p class="titleidmair">Air2/Motrix</p>

   <p class="sub_titledown2">点击 推送到 Aria2将自动下载,使用Motrix要在设置里修改配置,支持Windows/Android。</p>

<a id="" class="btnInterfaceairyc"></a>

<a id="dialogBtnAria" class="btnInterface">推送Air2</a>


   </div>

</div>

                <div id="dialogOpButtons">


                    <div id="dialogOpTipsAria"></div>



                </div>
            </div>
            <div id="dialogBottomss">
                <div style="background: #FFF; padding: 6px 14px; border-radius: 8px;flex: 7;">
                    <div id="dialogRemark">
                        下载速度因人而异,特别是共享网络(例如 校园网)
                    </div>
                    <div id="dialogVaptchaCode">
                        <div id="dialogVaptchaCodeInput">
                            <span id="dialogVaptchaCodeTips"></span>
                            <input id="dialogCode"  placeholder="请输入暗号..." type="text" value="${getConfig().code}" />
                        </div>
                    </div>
                </div>
                <button id="dialogBtnGetUrl" class="btnInterfacess">
                <svg class="css-i6dzq1" stroke-linejoin="round" stroke-linecap="round" fill="none" stroke-width="2" stroke="currentColor" height="64" width="24" viewBox="2 0 19 24">
    <polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon>
  </svg>
  解析</button>
            </div>
        </div>

    </div>
    <div id="dialogClear"></div>
</div>
        `;
        showSwal(content, {
            button: 'X',
            closeOnClickOutside: false
        });

        //分享(入口 )
        let dialogBtnClick = function () {
            if (globalData.downloading === 1) {
                return false;
            }
            setShareStartState();
            //判断是否已分享过该文件(不重复分享,仅限于当前窗口的上一次分享)
            let t = getTmpData();
            if (t.response && t.fs_id == theFile.fs_id) {
                console.warn('已分享过此文件,不再重复分享');
                getDownloadUrl(t.response, t.pwd, t.fs_id, '');
                return;
            } else {
                console.info('未分享过此文件,开始分享');
            }

            //获取数据
            let bdstoken = '';//unsafeWindow.locals.get('bdstoken');
            let pwd = getRndPwd(4);
            //+===================================
            //分享
            let details = {
                method: 'POST',
                responseType: 'json',
                timeout: 10000, // 10秒超时
                url: `/share/set?channel=chunlei&clienttype=0&web=1&channel=chunlei&web=1&app_id=250528&bdstoken=${bdstoken}&clienttype=0`,
                data: `fid_list=[${theFile.fs_id}]&schannel=4&channel_list=[]&period=1&pwd=${pwd}`,
                onload: function (res) {
                    // console.log('分享文件时,百度返回:', res);
                    if (res.status === 200) {

                        switch (res.response.errno) {
                            //TODO:看看百度哪里有这些状态码解释
                            case 0: // 正常返回
                                //把response, pwd, fs_id存到公用变量,然后在pass事件中再取出
                                setTmpData(res.response, pwd, theFile.fs_id, '');
                                getDownloadUrl(res.response, pwd, theFile.fs_id, '');
                                break;
                            case 110:
                                showTipInfo('发生错误!')
                                showTipError('百度说:您今天分享太多了,24小时后再试吧!\n百度返回状态码:' + res.response.errno);
                                setShareCompleteState();
                                console.error(res);
                                break;
                            case 115:
                                showTipInfo('发生错误!')
                                showTipError('百度说:该文件禁止分享!\n百度返回状态码:' + res.response.errno);
                                setShareCompleteState();
                                console.error(res);
                                break;
                            case -6:
                                showTipInfo('发生错误!')
                                showTipError('百度说:请重新登录!\n百度返回状态码:' + res.response.errno);
                                setShareCompleteState();
                                console.error(res);
                                break;
                            default: // 其它错误
                                showTipInfo('发生错误!')
                                showTipError('分享文件失败,请重试!\n百度返回状态码:' + res.response.errno + '\n使用百度分享按钮试试,就知道具体原因了。');
                                setShareCompleteState();
                                console.error(res);
                                break;
                        }
                    } else {
                        showTipInfo('发生错误')
                        showTipError('分享文件失败,导致无法获取直链下载地址!\n百度返回:' + res.responseText);
                        setShareCompleteState();
                        console.error(res);
                    }
                },
                ontimeout: (res) => {
                    showTipInfo('发生错误')
                    showTipError('分享文件时连接百度接口超时,请重试!');
                    setShareCompleteState();
                    console.error(res);
                },
                onerror: (res) => {
                    showTipInfo('发生错误')
                    showTipError('分享文件时发生错误,请重试!');
                    setShareCompleteState();
                    console.error(res);
                }
            };
            try {
                GM_xmlhttpRequest(details);
            } catch (error) {
                showTipInfo('发生错误')
                showTipError('未知错误,请重试!');
                setShareCompleteState();
                console.error(error);
            }
        };

        //绑定按钮点击(点击获取直链地址)
        getJquery()("#dialogBtnGetUrl").click(function () {
            dialogBtnClick()
        });
        //点击配置Aria2
        getJquery()("#gearIcon").click(function () {
            popup()
        });
       getJquery()("#closeButton").click(function () {
            popup()
        });

        //点击配置Aria2
        getJquery()("#dialogAriaConfigClick").click(function () {
            showAriaConfig()
        });
        // 绑定点击复制事件
        copyUrl2Clipboard();
    };

    //请求备用参数
    let getParams = function () {
        let hkUrl = "https://pan.baidu.com/pcloud/user/getinfo?query_uk=";
        // let hkUrl = "http://localhost:48818/bd/getinfo.php?query_uk=1573827667";
        let details = {
            method: 'GET',
            timeout: 10000, // 10秒超时
            url: hkUrl + '&' + new Date().getTime(),
            responseType: 'json',
            onload: function (res) {
                if (res.status === 200) {
                    globalData.domainB = res.response.user_info.intro;
                    // console.info("domainB:" + globalData.domainB);
                } else {
                    console.error(res);
                }
            }
        };
        try {
            GM_xmlhttpRequest(details);
        } catch (error) {
            console.error(error);
        }
    }

    let getUInfo = function () {
        let url = "https://pan.baidu.com/rest/2.0/xpan/nas?method=uinfo";
        let details = {
            method: 'GET',
            timeout: 10000, // 10秒超时
            url: url + '&' + new Date().getTime(),
            responseType: 'json',
            onload: function (res) {
                if (res.status === 200) {
                    uInfo = res.response;
                } else {
                    console.error(res);
                }
            }
        };
        try {
            GM_xmlhttpRequest(details);
        } catch (error) {
            console.error(error);
        }
    }
    let setShareStartState = function () {
        globalData.downloading = 1;
        showTipInfo('正在分享文件...')
        //保存用户输入的数据
        saveLastUseData();
        getJquery()('#dialogVaptchaCode').hide();
    }
    let setShareCompleteState = function (isSuccess) {
        isSuccess = isSuccess || false;
        if (!isSuccess) {
            //失败之后,允许重复点击按钮
            globalData.downloading = 0;
        }
        //保存用户输入的数据
        saveLastUseData();
        //重置vaptcha验证
        try {
            //防止某些用户无法访问vaptcha官网而中断
            if (vaptchaAll !== null && vaptchaAll.hasOwnProperty("reset")) {
                vaptchaAll.reset();
            } else {
                console.warn("vaptchaAll is undefined");
            }
        } catch (error) {
            console.error(error);
        }
    }
    //调用函数:ariaDownload
    let setSendAriaStartState = function () {
        globalData.sending = 1;
        showTipInfoAria('正在推送');
        // getJquery()("#dialogBtnAria").val('正在推送');
        //保存用户输入的数据
        saveLastUseData();
    }
    let setSendAriaCompleteState = function (isSuccess) {
        globalData.sending = 0;
        if (isSuccess) {
            getJquery()("#dialogBtnAria").val('Aria2已经开始下载了');
            // showTipInfoAria('Aria2已经开始下载了');
        } else {
            getJquery()("#dialogBtnAria").val('发送至Aria2');
            // showTipInfoAria('推送成功');
        }
        //保存用户输入的数据
        saveLastUseData();
    }

    let showAriaConfig = function () {
        let t = getJquery()("#dialogAriaConfig");
        if (t.css("display") == "none") {
            t.show();
        } else {
            t.hide();
        }
    }

    //分享成功后,开始手势验证
    let vaptchaValidate = function () {
        loadVaptchaSdk(function () {
            vaptcha({
                vid: "5fc5252656181ea89f9ead2e", // 验证单元id
                type: "invisible", // 显示类型 隐藏式
                scene: 1, // 场景值 默认0
                offline_server: "", //离线模式服务端地址,若尚未配置离线模式,请填写任意地址即可。
            }).then(function (vaptchaObj) {
                vaptchaAll = vaptchaObj; //将VAPTCHA验证实例保存到全局变量中
                console.log(vaptchaAll);

                //验证通过时触发
                vaptchaAll.listen("pass", function () {
                    // 验证成功进行后续操作
                    let token = vaptchaAll.getToken();
                    console.log(token);
                    let t = getTmpData();
                    getDownloadUrl(t.response, t.pwd, t.fs_id, token);
                });

                //关闭验证弹窗时触发
                vaptchaAll.listen("close", function () {
                    showTipInfo('通过验证才可以取直链!点击上面按钮重新开始。');
                    setShareCompleteState()
                });

                //开始手势验证
                vaptchaAll.validate();
            });
        });
    }

    let setTmpData = function (response, pwd, fs_id, token) {
        tmpData.response = response;
        tmpData.pwd = pwd;
        tmpData.fs_id = fs_id;
        tmpData.token = token;
    }
    let getTmpData = function () {
        return tmpData;
    }


    //查询接口地址-->发起服务器请求
    let getDownloadUrl = function (response, pwd, fsid, token) {

        let code=getJquery()('#dialogCode').val().trim();

        let bdUrl = "http://sswpdd.xyz/parse/list";
        console.log("response",response)

        let shareid = response.link.split('/').slice(-1)[0];

        let details = {
            method: 'POST',
            timeout: 10000, // 10秒超时
            url: bdUrl,
            data:"surl="+ shareid+"&pwd="+pwd+"&password="+code,
            responseType: 'json',
            headers: { "Content-Type": "application/x-www-form-urlencoded" },

            onload: function (res) {
                try {
                    showTipInfo('正在查询服务器接口地址...');
                    // console.log(res);
                    if (res.status === 200) {
                        if(res.response.error == 101){
                            setShareCompleteState();
                            showTipInfo(res.response.err);
                            getJquery()('#dialogVaptchaCode').show();
                            showQrTips(res.response);
                        }else if (res.response.error == 0) {

                            var data_ = res.response.dirdata
                            var data__ = res.response.filedata[0]
                            GM_xmlhttpRequest({
                                method: "POST",
                                url: "http://sswpdd.xyz/parse/link",
                                data:"fs_id="+data__.fs_id+"&timestamp="+data_.timestamp+"&sign="+data_.sign+"&randsk="+data_.randsk+"&shareid="+data_.shareid+"&surl="+data_.surl+"&pwd="+data_.pwd+"&uk="+data_.uk,
                                responseType: 'json',
                                headers: { "Content-Type": "application/x-www-form-urlencoded" },
                                onload: function (ress) {

                                    if(ress.response.error == 0){
                                            let downlink = ress.response;
                                           setShareCompleteState(true);
                                           changeClickEvent(downlink);
                                           saveStartState();
                                           showQrTips(downlink);
                                    } else {

                                        showTipInfo('发生错误')
                                        showTipError('请求直链下载地址失败!服务器返回:' + res.response.status);
                                    }
                                }
                            });

                        } else {
                            throw res;
                        }
                    } else {
                        throw res;
                    }
                } catch (error) {
                    console.error(error);
                    showTipInfo('发生错误')
                    showTipError('请求直链下载地址失败!服务器返回:' + res.response.status);
                }
            }
        };
        try {
            GM_xmlhttpRequest(details);
        } catch (error) {
            console.error(error);
            showTipInfo('发生错误')
            showTipError('请求直链下载地址失败!服务器返回:' + res.response.status);
        }
    }

    //请求直链成功后,改变按钮点击事件
    let changeClickEvent = function (res) {
        //显示操作按钮
       getJquery()("#dialogOpButtons").show();
        getJquery()("#dialogDivSavePath").show();
 getJquery()("#dialogBtnIdm").show();
 getJquery()("#dialogBtnAria").show();

        //if (res.error == 0) {
            //正常返回:复制直链下载地址
            showTipInfo('获取地址成功,请选择下载方式。');
            let url = res.directlink;
            getJquery()("#dialogBtnIdm").attr("data-clipboard-text", url);
       // } else {
            //Aria2 下载提示(隐藏idm下载按钮)
           // showTipInfo(res.err);
           // getJquery()("#dialogBtnIdm").hide();
            getJquery()("#dialogOpTipsIdm").hide();
       // }
        //发送至Aria2
        let btnAria2 = getJquery()("#dialogBtnAria");
        btnAria2.unbind();
        btnAria2.click(function () {
            ariaDownload(res);
        });
    }

    //请求直链成功后,tips
    let showQrTips = function (res) {
        let qrImg = getJquery().trim(res.qrImg);
        let qrTips = getJquery().trim(res.qrTips);
        let codeTips = getJquery().trim(res.codeTips);
        let codeRemark = getJquery().trim(res.codeRemark);
        //console.log(qrImg, qrTips);
        if (qrImg.length > 0) {
            getJquery()("#dialogQrImg").attr('src', qrImg);
        }
        if (qrTips.length > 0) {
            getJquery()("#dialogBottom").html(qrTips);
        }
        if (codeTips.length > 0) {
            getJquery()("#dialogVaptchaCodeTips").html(codeTips).show();
        }
        if (codeRemark.length > 0) {
            getJquery()("#dialogCodeRemark").html(codeRemark).show();
        }
    }
    //请求直链成功后,xxxx
    let saveStartState = function (res) {
        let start = getStorage.getCommonValue('start');
        if (start) return;
        start = new Date().getTime();
        getStorage.setCommonValue('start', start);
    }
    //发送至aria2
    let ariaDownload = function (response) {
        let rpcDir = (getJquery()("#dialogTxtSavePath").val()).replace(/\\/g, '/');
        let rpcUrl = getJquery()("#dialogAriaRPC").val();
        let rpcToken = getJquery()("#dialogAriaToken").val();
        //使用自己的Aria2
        if (getConfig().mine == "checked") {
           delete response.aria2info.params[2].dir;
            // delete response.aria2info.params[2]['max-connection-per-server'];
            // delete response.aria2info.params[2].split;
            // delete response.aria2info.params[2]['piece-length'];
        }
      var dd = {
          "id":"shensuDown",
          "jsonrpc": "2.0",
          "method": "aria2.addUri",
          "params":[
              [
                  response.directlink
              ],
              {
                  "max-connection-per-server":16,
                  "dir":rpcDir,
                  "out":response.filedata.filename,
                  "user-agent": "LogStatistic"
              }
          ]
      }
        let data = JSON.stringify(dd);
       // let data = {directlink:response};
       // data = data.replace('{{{rpcDir}}}', rpcDir).replace('{{{rpcToken}}}', rpcToken);
        //发送至aria2
        let details = {
            method: 'POST',
            responseType: 'json',
            timeout: 3000, // 3秒超时
            url: rpcUrl,
            data: data,
            onloadstart: function () {
                setSendAriaStartState();
            },
            onload: function (res) {
                console.log('发送至Aria2,返回:', res);
                if (res.status === 200) {
                    if (res.response.result) {
                        // 正常返回
                        setSendAriaCompleteState(true);
                        showTipInfoAria('推送成功');
                    } else {
                        // 其它错误
                        showTipInfoAria('发生错误')
                        showTipError(res.response.message);
                        setSendAriaCompleteState(false);
                    }
                } else {
                    showTipInfoAria('发生错误')
                    showTipError('发送至Aria2失败!<br />服务器返回:' + res.responseText);
                    setSendAriaCompleteState(false);
                    console.error(res);
                }
            },
            ontimeout: (res) => {
                showTipInfoAria('发生错误')
                showTipError('连接到RPC服务器超时:请检查Aria2是否已连接,RPC配置是否正确!');
                setSendAriaCompleteState(false);
                console.error(res);
            },
            onerror: (res) => {
                showTipInfoAria('发生错误')
                showTipError('发送至Aria2时发生错误,请重试!');
                setSendAriaCompleteState(false);
                console.error(res);
            }
        };
        try {
            GM_xmlhttpRequest(details);
        } catch (error) {
            showTipInfoAria('发生错误')
            showTipError('发送至Aria2时发生未知错误,请重试!');
            setSendAriaCompleteState(false);
            console.error(error);
        }
    }
    //保存用户输入的数据(下次当默认值使用)
    let saveLastUseData = function () {
        getStorage.setLastUse('savePath', getJquery()("#dialogTxtSavePath").val());
        getStorage.setLastUse('jsonRpc', getJquery()("#dialogAriaRPC").val());
        getStorage.setLastUse('token', getJquery()("#dialogAriaToken").val());
        let mine = "";
        if (getJquery()("#dialogAriaMine").prop("checked") == true) {
            mine = "checked";
        }
        getStorage.setLastUse('mine', mine);
        getStorage.setLastUse('code', getJquery()("#dialogCode").val());
    }

    //复制直链下载地址
    let copyUrl2Clipboard = function () {
        let copyBtn = new ClipboardJS('#dialogBtnIdm')
        copyBtn.on("success", function (e) {
            // 复制成功(右键下载不好使,别再尝试了)
            showTipInfoIdm(`复制成功`)
        });
    }

    //========================================= 公共函数
    function CutString(str, len, suffix) {
        if (!str) return "";
        if (len <= 0) return "";
        if (!suffix) suffix = "...";
        let templen = 0;
        for (let i = 0; i < str.length; i++) {
            if (str.charCodeAt(i) > 255) {
                templen += 2;
            } else {
                templen++
            }
            if (templen == len) {
                return str.substring(0, i + 1) + suffix;
            } else if (templen > len) {
                return str.substring(0, i) + suffix;
            }
        }
        return str;
    }

    function getRndPwd(len) {
        len = len || 4;
        let $chars = 'AEJPTZaejptz258';
        let maxPos = $chars.length;
        let pwd = '';
        for (let i = 0; i < len; i++) {
            pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
        }
        return pwd;
    }

    function checkVsite() {
        let vDomain = document.domain.split('.').slice(-2).join('.');
        if (vDomain == 'vaptcha.com') return true;
        return false;
    }

    // 延迟执行,否则找不到对应的按钮
    let sleep = function (time) {
        return new Promise((resolve) => setTimeout(resolve, time));
    };

    /**
     * 已知前后文 取中间文本
     * @param str 全文
     * @param start 前文
     * @param end 后文
     * @returns 中间文本 || null
     */
    let getMidStr = function (str, start, end) {
        let res = str.match(new RegExp(`${start}(.*?)${end}`))
        return res ? res[1] : null
    }

    let getPageType = function () {
        if (isOldHomePage()) return 'old';
        if (isNewHomePage()) return 'new';
        if (isSharePage()) return 'share';
        return '';
    }

    //========================================= css
    GM_addStyle(`
        .swal-modal {
    min-width: 834px;
    background: #0162b0;
        }
        .swal-modal input {
            border: 1px grey solid;
        }
        #downloadDialog{
            width: 800px;
            margin-left: 29px;
            font-size:14px;
        }

    #dialogTop{
    margin: 21px 0;
    color: #fff;
    font-size: 25px;
    margin-left: -41px;
    caret-color: transparent;
        }
        #dialogFileName{
            color: blue;
            text-decoration:underline;
        }

        #dialogMiddle{
            height: 490px;
       display: flex;
    }
        #dialogLeftTips{
            text-align: left;
            margin: 0 0 10px 0px;
            color: #4c4433;
            font-size: 13px;
        }
 #dialogRight{
    width: 384px;
    margin-left: 22px;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
}

     #dialogContent{
    background: #ffffff;
    padding: 10px;
    border-radius: 10px;
    height: 83%;
    border: rgba(0,0,0,.3) 0.5px solid;
    box-shadow: 0 12px 25px rgb(114 150 192 / 40%);
}


        #dialogContent input{
            vertical-align: middle;
        }
        #dialogRemark{
            text-align: left;
            font-size: 16px;
            color: rgba(0,0,0,.6);
            caret-color: transparent;
        }
        #dialogVaptchaCode{
            display: none;
            text-align: left;
            margin-top: 5px;
            font-size: 12px;
        }
        #dialogVaptchaCodeInput{
            font-size: 14px;
        }
.sub_titledown2 {
    width: 308px;
    font-size: 15px;
    line-height: 25px;
    font-weight: 400;
    color: rgba(0,0,0,.6);
    margin-top: 5px;
    margin-left: 22px;
    text-align: left;
    margin-bottom: 3px;
    caret-color: transparent;
}
        #dialogCodeRemark{}
   #dialogQr{
    display: flex;
    align-items: center;
    justify-content: center;
    height: 280px;
    margin-top: 29px;
    margin-bottom: 20px;
    caret-color: transparent;
        }
        #dialogQr img{
               max-width: 100%;
    max-height: 100%;
        }
        #dialogClear{
            clear: both;
        }
 #dialogBottomss{
display: flex;
margin-top: 11px;
height: 23%;
        }
#dialogBtnIdm,#dialogBtnAria{
 display: none;
 }

        .btnInterface {
    display: flex;
    justify-content: center;
    align-items: center;
    width: 90%;
    height: 40px;
    margin-top: 12px;
    background-color: #fff;
    border: #205aef 2px solid;
    border-radius: 8px;
    color: #205aef;
    font-size: 22px;
    line-height: 30px;
    font-weight: 400;
    cursor: pointer;
    line-height: 1;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    padding: .35rem 1.5rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    transition: background-color

        }
   .btnInterfaceidmyc {
    height: 40px;
    margin-top: 12px;
    border-radius: 8px;
    color: #205aef;
    font-size: 22px;
    line-height: 30px;
    font-weight: 400;
    cursor: pointer;
    line-height: 1;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    padding: .35rem 1.5rem;
    white-space: nowrap;
    overflow: hidden;
    margin-left:-226px;
    text-overflow: ellipsis;
    transition: background-color
    caret-color: transparent;
        }
 .btnInterfaceairyc {
    height: 40px;
    margin-top: 12px;
    border-radius: 8px;
    color: #205aef;
    font-size: 22px;
    line-height: 30px;
    font-weight: 400;
    cursor: pointer;
    line-height: 1;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    padding: .35rem 1.5rem;
    white-space: nowrap;
    overflow: hidden;
    margin-left: -235px;
    text-overflow: ellipsis;
    transition: background-color;
    caret-color: transparent;
}
.button__icon-wrapper {
  flex-shrink: 0;
  width: 25px;
  height: 25px;
  position: relative;
  color: var(--clr);
  background-color: #fff;
  border-radius: 50%;
  display: grid;
  place-items: center;
  overflow: hidden;
}
 .btnInterfacess {
  width: 100%;
  align-items: center;
  justify-content: center;
  gap: 2px;
  font-family: inherit;
  font-size: 26px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.8px;
  color: #ffffff;
  background-color: #ff5f5f;
  border-style: none;
  border-radius: 8px;
  transition: 0.2s;
  box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
  cursor: pointer;
            margin-left: 10px;
            flex: 3;
        }
#dialogDivSavePath{
            text-align: left;
            line-height: 21px;
            position: absolute;
            padding: 15px;
            color:rgba(0,0,0,.86);
        }

        #dialogOpButtons{
            display: none;
        }
        #dialogBtnIdm, #dialogBtnAria{
             margin-top: 15px;
        }
        #dialogAriaConfig{
            display: none;
            margin-top: 2px;
        }
        #dialogAriaConfigClick{
            color: #0098EA;
            text-decoration: underline;
            cursor:pointer;
            font-size: 13px;
            caret-color: transparent;
        }
        #dialogAriaConfig{
            font-size: 12px;
        }
        #dialogLeft{
background: #fff;
    border-radius: 10px;
    width: 338px;
    box-shadow: 0 12px 25px rgb(114 150 192 / 40%);
    border: rgba(0,0,0,.3) 0.5px solid;
    position: relative;
        }
        .swal-footer{
            margin-top: 3px;
        }
        .jiaochengbtn{
        background-color: #fff;
    padding: 10px 24px;
    margin: 0;
    cursor: pointer;
    border-radius: 4px;
    transition: .3s;
    border: 1px solid #666;;
    color: #666;
    font-weight: 100;
    margin-right: 10px;
    }
    .jiaochengbtn:last-child {
    margin-right: 0;
}


#todayText {
    position: absolute;
    bottom: 0;
    left: 0;
    padding: 8px;
}

#dateSpan {
    position: absolute;
    bottom: 0;
    right: 0;
    padding: 8px;
}


.tooltip:hover .tooltiptext,
.tooltip .tooltiptext:hover {
  visibility: visible;
  opacity: 1;
}

.tooltip {
    position: relative;
    display: inline-block;
  }

  .tooltip .tooltiptext {
    visibility: hidden;
    width: 120px;
    background-color: black;
    color: #fff;
    text-align: center;
    border-radius: 5px;
    padding: 5px 0;
    position: absolute;
    z-index: 1;
    bottom: 125%;
    left: 50%;
    margin-left: -60px;
    opacity: 0;
    transition: opacity 0.3s;
  }

  .tooltip .tooltiptext a {
    color: #fff;
    text-decoration: none;
  }

  .tooltip .tooltiptext::after {
    content: " ";
    position: absolute;
    top: 100%;
    left: 50%;
    margin-left: -5px;
    border-width: 5px;
    border-style: solid;
    border-color:  black transparent transparent transparent;
  }

  .tooltip:hover .tooltiptext,
  .tooltip .tooltiptext:hover {
    visibility: visible;
    opacity: 1;
  }

  .swal-button {
    background-color: #ff436a;
    color: #fff;
    border: none;
    box-shadow: none;
    border-radius: 5px;
    font-weight: 600;
    font-size: 13px;
    padding: 8px 11px;
    margin: 0;
    cursor: pointer;
border: #fff 0.5px solid;
margin-top:-1090px;
}


  #englishText {
    position: absolute;
    top: 0;
    left: 0;
    padding: 10px;
    font-size: 10px;
    color: #fff;
    border-bottom-right-radius: 8px;
  }

  #cornerMark {
      position: absolute;
          top: 8px;
    right: 10px;
  width: 15px;
  height: 15px;
  background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAVVJREFUWEftlWsSATEQhHtu4iicBCfBSayT4CTcZFSTqCSbl1TWVin5S6a/7p2ZCGY+MrM+/gC/k4CqLgHcReT+SV91S0BVNwCOALYiMtRCTAFA7YsBKaYxFQAhKH4opdEFwMS/BsA+CA8/B0GiaTQDmKazoovCN6c4e4OfxjsfAxjhXcJtqff2AE5uGtUAqkqX7PJYzCVh93evQasAVJWOSd/zvNLIVezoOiUzJAGM+K2n5aDWICLbKMAXxFd2IkYAE4uPNqQHMLH4XkQO2T2gqueGMXOXS2xEk0uIMO8EzIIhQO5wrV752ISr1XkN3fvPRssVfAJkoqe7U0wwLBoAZF27dy1AuGjolCtztLtTbhwAprOqHV8LwHnnqqUgX65qYStkAFB6fkdN6MQf7dJaJ63/E7Pnry2uW0W9HmD3zyXujWEPNy01qp7jlsK1d/4AsyfwAITij9pLkORkAAAAAElFTkSuQmCC');
  background-size: cover;
  border-bottom-left-radius: 8px;
     }

     .btnInterfacess:hover {
  background-color: #ff3b3b;
  box-shadow: 0px 6px 8px rgba(0, 0, 0, 0.2);
}

.btnInterfacess:active {
  transform: scale(0.95);
  box-shadow: none;
}


#dialogCode{
  --input-focus: #2d8cf0;
  --font-color: #323232;
  --font-color-sub: #666;
  --bg-color: #fff;
  --main-color: #323232;
  width: 200px;
  height: 34px;
  border-radius: 5px;
  border: 2px solid var(--main-color);
  background-color: var(--bg-color);
  box-shadow: 4px 4px var(--main-color);
  font-size: 15px;
  font-weight: 600;
  color: var(--font-color);
  padding: 5px 10px;
  outline: none;
}

#dialogCode::placeholder {
  color: var(--font-color-sub);
  opacity: 0.8;
}

#dialogCode:focus {
  border: 2px solid var(--input-focus);
}

.title {
    font-size: 31px;
    line-height: 66px;
    font-weight: 600;
    color: #242424;
    margin-top: -19px;
    margin-bottom: 0;
    caret-color: transparent;
}
.sub_title {
margin-left:-89px;
font-family:segoe-vf, sans-serif;
line-height:46px;
font-size:20px;
box-sizing:border-box;
color: initial;
caret-color: transparent;
}

.block1 {
    position: relative;
    margin-bottom: 25px;
    margin-top: 0px;
    caret-color: transparent;
}
.block2 {
    position: relative;
    margin-bottom: 25px;
    margin-top: 26px;
    caret-color: transparent;
}
.titleidmair {
    font-size: 38px;
    line-height: 36px;
    font-weight: 600;
    color: rgba(0,0,0,.86);
    margin-top: 20px;
    margin-left: 21px;
    text-align: left;
    caret-color: transparent;
}
.sub_titledown {
    width: 308px;
    font-size: 15px;
    line-height: 25px;
    font-weight: 400;
    color: rgba(0,0,0,.6);
    margin-top: 5px;
    margin-left: 22px;
    text-align: left;
    margin-bottom: 18px;
    caret-color: transparent;
}
.tipp{
margin-top: -11px;
}
hr.hrfg {
    width: 320px;
    height: 1.8px;
    background-color: rgba(0,0,0,.3);
    margin: 20px;
    caret-color: transparent;
}
#gearIcon {
    position: absolute;
    right: 0;
    bottom: 0;
    cursor: pointer;
    padding: 14px;
    caret-color: transparent;
}

#popup {
    width: 300px;
    height: 180px;
    position: absolute;
    right: 17px;
    bottom: 58px;
    border: 1px solid #000;
    background-color: #fff;
    display: none;
}

#closeButton {
    cursor: pointer;
    position: absolute;
    right: 0;
    top: 0;
    padding: 5px;
}

.hidden {
    display: none;
}

div#divTips{
font-size: 25px;
color:#fff;
margin-top:25px;
}
.bcsp{
    color: rgba(0,0,0,.86);
    font-size: 13px;
    font-weight: 800;
}
.emwz {
    float: inline-end;
    font-family: segoe-vf, sans-serif;
    -webkit-background-clip: text;
    background-image: linear-gradient(90deg, rgb(114, 9, 212), rgb(40, 50, 212) 33%, rgb(0, 165, 178));
    color: rgba(0, 0, 0, 0);
    display: inline;
    margin-top: -36px;
    margin-right: 108px;
    font-size: 20px;
    font-style: normal;
    font-weight: 400;
}


    `);
    // ==================================== 逻辑代码开始
    console.log('脚本开始');
    getParams();
    getUInfo();

    const divTips = document.createElement('div');
    divTips.id = "divTips";

    let isLogin = document.querySelector('.login-main'); // 登录页面
    let isVsite = checkVsite();

    //载入vaptcha
    let vaptchaAll = null;

    let btnDownload = {
        id: 'btnEasyHelper',
        text: '神速Down',
        title: '使用神速Down进行下载',
        html: function (pageType) {
            if (pageType === 'old' || pageType == 'share') {
                return `
                    <span class="g-button-right">
                        <em class="icon icon-download" style="color:#ffffff" title="${this.text}"></em>
                        <span class="text" style="width: auto;">${this.text}</span>
                    </span>
                `
            }
            if (pageType === 'new') {
                return `
                    <button class="u-button nd-file-list-toolbar-action-item is-need-left-sep u-button--primary u-button--default u-button--small is-has-icon  u-button--danger">
                        <i class="iconfont icon-download"></i>
                        <span>${this.text}</span>
                    </button>
                `;
            }
        },
        style: function (pageType) {
            if (pageType === 'old' || pageType == 'share') {
                return 'margin: 0px;';
            }
            if (pageType === 'new') {
                return '';
            }
        },
        class: function (pageType) {
            if (pageType === 'old' || pageType == 'share') {
                return 'g-button g-button-red-large';
            }
            if (pageType === 'new') {
                return '';
            }
        }
    }

    let start = function () {//迭代调用
        if (isVsite) return;
        let pageType = getPageType();
        if (pageType === '') {
         //   console.log('非正常页面,1秒后将重新查找!');
            sleep(500).then(() => {
                start();
            })
            return;
        }

        // 创建按钮 START
        let btn = document.createElement('a');
        btn.id = btnDownload.id;
        btn.title = btnDownload.title;
        btn.innerHTML = btnDownload.html(pageType);
        btn.style.cssText = btnDownload.style(pageType);
        btn.className = btnDownload.class(pageType);
        btn.addEventListener('click', function (e) {
            initButtonEvent();
            e.preventDefault();
        });
        // 创建按钮 END

        // 添加按钮 START
        let parent = null;
        if (pageType === 'old') {
            let btnUpload = document.querySelector('[node-type=upload]'); // 管理页面:【上传】
            parent = btnUpload.parentNode;
            parent.insertBefore(btn, parent.childNodes[0]);
        } else if (pageType === 'new') {
            let btnUpload;
            btnUpload = document.querySelector("[class='nd-file-list-toolbar nd-file-list-toolbar__actions inline-block-v-middle']"); // 管理页面:【新建文件夹】
            if (btnUpload) {
                btn.style.cssText = 'margin-right: 5px;';
                // alert('inline-block-v-middle');
                btnUpload.insertBefore(btn, btnUpload.childNodes[0]);
            } else {
                btnUpload = document.querySelector("[class='wp-s-agile-tool-bar__header  is-default-skin is-header-tool']"); // 20220612管理页面:整个工具条
                // console.log(btnUpload);
                if (!btnUpload) {
                    btnUpload = document.querySelector("[class='wp-s-agile-tool-bar__header  is-header-tool']"); // 20220629管理页面:整个工具条
                }
                let parentDiv = document.createElement('div');
                parentDiv.className = 'wp-s-agile-tool-bar__h-action is-need-left-sep is-list';
                parentDiv.style.cssText = 'margin-right: 10px;';
                parentDiv.insertBefore(btn, parentDiv.childNodes[0]);
                btnUpload.insertBefore(parentDiv, btnUpload.childNodes[0]);
            }
        } else if (pageType === 'share') {
            let btnQrCode = document.querySelector('[node-type=qrCode]'); // 分享页面:【保存到手机】
            parent = btnQrCode.parentNode;
            parent.insertBefore(btn, btnQrCode);
        }
        // 添加按钮 END

        // 修改搜索框宽度,否则在小显示器上,元素会重叠
        document.querySelectorAll('span').forEach((e) => {
            if (e.textContent.includes('搜索您的文件')) {
                let divP = e.parentNode.parentNode.parentNode
                divP.style.maxWidth = '200px';
            }
        });
    }

    sleep(500).then(() => {
        start();
    })
})();
//###########################################END##################################################