noahzark / 福利部落自动保存V2.3.1 美化+路径版

// ==UserScript==
// @name         福利部落自动保存V2.3.1 美化+路径版
// @namespace    https://dfulibl.net/
// @version      2.3.1
// @description  致敬永远的神李恒道!增加从标题解析保存路径
// @author       李恒道
// @license      MIT
// @match        https://www.afulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://www.ifulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://www.fulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://www.afulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://www.fulibl.tokyobl.xyz/wp-content/plugins/erphpdown/download.php*
// @match        https://www.afulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.tokyobl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://www.ifulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://www.ifulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://www.fulibl.club/wp-content/plugins/erphpdown/download.php*
// @match        https://www.fulibl.xyz/wp-content/plugins/erphpdown/download.php*
// @match        https://www.fulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://www.fulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://www.bfulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://www.bfulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://down.tokyobl.xyz/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.tokyobl.com/wp-content/plugins/erphpdown/download.php*
// @match        https://afulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://ifulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://afulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.tokyobl.xyz/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.kasawaa.org/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.kasawaa.org/wp-content/plugins/erphpdown/download.php* 
// @match        https://afulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://ifulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://ifulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.club/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.xyz/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://tokyobl.xyz/wp-content/plugins/erphpdown/download.php*
// @match        https://bfulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://bfulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://tokyobl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://tokyobl.com/wp-content/plugins/erphpdown/download.php*
// @match        https://cfulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://cfulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://cfulibl.com/wp-content/plugins/erphpdown/download.php*
// @match        https://www.cfulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://www.cfulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://www.cfulibl.com/wp-content/plugins/erphpdown/download.php*
// @match        https://efulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://efulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://www.efulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://www.efulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://dfulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://dfulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://www.fulibl.yookaasaa.org/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.yookaasaa.org/wp-content/plugins/erphpdown/download.php*
// @match        https://www.dfulibl.org/wp-content/plugins/erphpdown/download.php*
// @match        https://www.dfulibl.net/wp-content/plugins/erphpdown/download.php*
// @match        https://fulibl.kyotoo.org/wp-content/plugins/erphpdown/download.php*
// @icon         https://www.google.com/s2/favicons?domain=baidu.com
// @require      https://cdn.staticfile.org/jszip/3.5.0/jszip.min.js
// @require      https://cdn.jsdelivr.net/npm/sweetalert2@11
// @require      https://cdn.jsdelivr.net/npm/tampermonkey-toastr@1.0.6
// @grant        unsafeWindow
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant       GM_addStyle
// ==/UserScript==
let zip = new JSZip();
let max_faile_upload_num = 3;
let UA = "netdisk;2.2.51.6;netdisk;10.0.63;PC;android-android;QTP/1.0.32.2"; // 自定义User-Agent
//初始化显示框
let showtextouter = document.createElement("div");
let showtext = document.createElement("div");
showtext.innerHTML = '';
showtextouter.append(showtext)
showtextouter.className = 'card-wrap'
showtext.className = 'card'
document.body.append(showtextouter);
//页面吐司框
function toast_tip(str) {
    toastr.info(str)
}
//页面模态框
function page_tip(title, text, icon) {
    Swal.fire({
        title: title,
        text: text,
        icon: icon,
        confirmButtonText: '确认'
    })
}
//同步GM_xmlhttpRequest
function sync_xhr(config) {
    return new Promise((resolve) => {
        GM_xmlhttpRequest({
            url: config.url,
            responseType: config.responseType,
            data: config.data,
            headers: config.headers,
            method: config.method,
            onload: function (xhr) {
                resolve(xhr)
            }
        });
    })
}
//等待promise
function wati_time(time = 3000) {
    return new Promise((resolve) => {
        setTimeout(() => resolve(), time)
    })
}
//下载链接并利用zip解压搜索链接
async function SaveHrelFile(href) {
    toast_tip('已开始寻找路径...')
    let xhr = await sync_xhr({
        url: href,
        method: "GET"
    })
    toast_tip('寻找路径成功,开始分析...')
    if (xhr.response.indexOf('pan.baidu.com') != -1) {
        page_tip('错误', '该文件非百度秒传,请手动处理!', 'error')
        return;
    }
    console.log('有罪推定', xhr)
    let finalurl = xhr.response.replace("<script type='text/javascript'>window.location='", "").replace("';</script>", '')
    toast_tip('开始下载秒传压缩包')
    xhr = await sync_xhr({
        url: finalurl,
        method: "GET",
        responseType: 'arraybuffer'
    })
    toast_tip('下载完成,开始解压分析')
    try {
        debugger;
        let zipfile = await zip.loadAsync(xhr.response)
        let filelist = Object.keys(zipfile.files)
        if (filelist.length != 0) {
            for (let index = 0; index < filelist.length; index++) {
                let data = await zipfile.file(filelist[index]).async('string')
                let baiduurl = FindBaiDuURL(data)
                if (baiduurl == 'error') {
                    page_tip('错误', '解析文本失败,请手动处理!', 'error')
                }
                ShowHtmlText(data, baiduurl[0])
                for (let index = 0; index < baiduurl.length; index++) {
                    await SaveBaiduFile(baiduurl[index])
                    //await wati_time()
                }
            }
        } else {
            page_tip('错误', '解析文件失败或无文件,请手动处理!', 'error')
        }
    } catch (err) {
        console.log('err', err)
        page_tip('错误', '下载文件失败,请重新尝试!!', 'error')

    }


};
//保存百度文件
async function SaveBaiduFile(url) {
    let token = GM_getValue("bdtoken", '')
    if (token == '') {
        //如果不存在token,则刷新Token
        token = await RefreshToken()
        if (token === false) {
            return;
        }
    }
    console.log('获取当前token', token)
    await getLink(url, token)
}
//原网页函数进行抽离吧
async function getLink(link, token) {
    let bdstoken = ''
    let bdsfield = token
    if (bdsfield == "") {
        page_tip('错误', '未输入bdstoken,请阅读使用教程', 'error')
        return;
    }
    else if (bdsfield.match(/[0-9a-zA-Z]{32}/) == null) {
        if (bdsfield.includes("-6")) {
            page_tip('错误', '未登录百度账号,请登录百度网盘网页版后再次获取', 'error')
        } else {
            page_tip('错误', '未检测到有效bdstoken,请阅读使用教程', 'error')
        }
        return;
    }
    else {
        bdstoken = bdsfield.match(/[0-9a-zA-Z]{32}/)[0];
        console.log('修改了bsdtoken', bdstoken)
    }

    let bdpan = link.match(/bdpan:\/\/(.+)/);
    let pcs = link.match('BaiduPCS-Go');
    let mengji = link.match(/.{32}#.{32}/);
    let bdlink = link.match('bdlink(.+)');
    let pan = link.match(/^pan:\/\//);

    if (mengji) {
        let input = link;
        let md5 = input.match(/^(.{32})#/)[1];
        let slicemd5 = input.match(/#(.{32})#/)[1];
        let file_length = input.match(/#([0-9]+)#/)[1];
        let file_name = input.match(/#[0-9]+#(.+)$/)[1];
        file_name = Trim(file_name);
        await saveFile(md5, slicemd5, file_length, file_name, mengji, token, link);
    }
    else {
        page_tip('错误', '未检测到有效秒传链接', 'error')
    }
}
//保存百度函数
async function saveFile(md5, slicemd5, length, name, method, token, url, randomobfs = false, retry = 0) {
    let urlSearchParams = new URLSearchParams(window.location.search);
    let postid = urlSearchParams.get('postid');
    let pageTitle = document.title.replace("文件下载 - ", "");
    let seriesName = pageTitle;
    if (seriesName.indexOf("@") > -1) {
        seriesName = pageTitle.substring(pageTitle.indexOf("@") + 1, pageTitle.indexOf(" "));
    } else if (seriesName.indexOf("[") > -1) {
        seriesName = pageTitle.substring(0, pageTitle.indexOf("[")).replace(" ", "");
    }
    if (seriesName.indexOf(")") > -1) {
        seriesName = seriesName.substring(0, seriesName.indexOf(")") + 1);
    }
    if (seriesName.indexOf(")") > -1) {
        seriesName = seriesName.substring(0, seriesName.indexOf(")") + 1);
    }
    console.log('saveFile', document.title, md5, slicemd5, length, name, method, 'fulibl-' + postid)
    toast_tip('开始保存文件')
    let saveDir = '%2Fapps%2FCloud%20Sync%2Fnas%2Fseries%2f' + encodeURI(seriesName) + '%2Ffulibl-' + postid + '%2F' + name;
    let post_text = '&rtype=0&path=' + saveDir + '&content-md5=' + randomstring(md5,randomobfs) + '&slice-md5=' + slicemd5.toLowerCase() + '&content-length=' + length
    let xhr = await sync_xhr({
        url: 'https://pan.baidu.com/api/rapidupload?bdstoken=' + token,
        method: "POST",
        data: post_text,
        headers: {
            'Content-Type': 'application/json; charset=UTF-8',
            "User-Agent": UA,
        },

    })
    let json = JSON.parse(xhr.responseText);
    if (json.errno === 0) {
        page_tip('成功', '保存' + name + '文件成功!', 'success')
        let successDive = document.createElement("div");
        div.innerHTML = "<span>已保存至目录:" + decodeURIComponent(saveDir) + "</span>";
        document.querySelector('#erphpdown-download').append(successDive);
    } else if (json.errno === -6) {
        page_tip('错误', '保存文件失败!,百度账号未登录', 'error')
        GM_setValue("bdtoken", '');
    } else if (json.errno === -8) {
        toast_tip(name + '存在同名文件')
    } else if (json.errno === 2) {
        page_tip('错误', '疑似bsdtoken刷新,正在重试!', 'error')
        GM_setValue("bdtoken", '');
        //如果不存在token,则刷新Token
        let token = await RefreshToken()
        if (token === false) {
            return;
        }
        if (retry < max_faile_upload_num) {
            saveFile(md5, slicemd5, length, name, method, token, url, randomobfs, retry + 1)
        }
    }
    else {
        if (json.errno === 404) {
            if (randomobfs === true) {
                page_tip('错误', '错误码404,obfs启动无效', 'error')
            }
            else {
                if (retry < max_faile_upload_num) {
                    await saveFile(md5, slicemd5, length, name, method, token, url, true, retry + 1)
                }
            }
        }
        else {
            page_tip('错误', '保存文件失败!,好可惜!错误码' + json.errno, 'error')

        }

    }
}
//随机字符串
function randomstring(text, status) {
    if (status === false) {
        return text;
    }
    const tempString = []
    for (let i of text) {
        if (!Math.round(Math.random())) {
            tempString.push(i.toLowerCase())
        } else {
            tempString.push(i.toUpperCase())
        }
    }
    return tempString.join('')

}
//编码函数
function atou(str) {
    return decodeURIComponent(escape(window.atob(str)));
}
//trim函数
function Trim(str) {
    return str.replace(/(^\s*)|(\s*$)/g, "");
}
//刷新Token
async function RefreshToken() {
    toast_tip('正在解析百度Token')
    let xhr = await sync_xhr({
        url: 'https://pan.baidu.com/api/gettemplatevariable?fields=[%22bdstoken%22]',
        method: "GET",
    })
    let json = JSON.parse(xhr.responseText);
    if (json.errno === 0) {
        toast_tip('解析百度Token成功')
        GM_setValue("bdtoken", json.result.bdstoken);
        return json.result.bdstoken
    } else if (json.errno === -6) {
        page_tip('错误', '保存文件失败!,百度账号未登录', 'error')
        GM_setValue("bdtoken", '');
    }
    else {
        page_tip('错误', '刷新百度token失败,请检查是否登陆百度账户!错误码:' + json.errno, 'error')
    }
    return false

}
//将提取到的zip内的txt文件显示到页面中
function ShowHtmlText(url, name) {
    if (showtext.innerHTML.indexOf(name) == -1) {
        let textlist = url.split(/[\s\n]/)
        for (let index = 0; index < textlist.length; index++) {
            let temp = textlist[index]
            if (temp != '') {
                let item = document.createElement("div");
                item.innerHTML = temp
                showtext.className = 'btn-class card'
                showtext.append(item)
            }
        }
    }

}
//寻找百度URL链接
function FindBaiDuURL(text) {
    let textlist = text.split(/[\s\n]/)
    let retlist = []
    for (let index = 0; index < textlist.length; index++) {
        let temp = textlist[index]
        if (temp != '') {
            if (temp.indexOf('#') != -1) {
                let listnum = temp.split('#').length
                console.log('listnum', listnum)
                if (listnum == 4) {
                    retlist.push(temp)
                }
            }

        }
    }
    if (retlist.length != 0) {
        return retlist
    }
    return 'error'
}
//按钮点击后遍历页面链接
let div = document.createElement("div");
div.innerHTML = '<button class="btn-class btnhover-class">一键保存</button>';
toast_tip('脚本注入成功!')
div.onclick = async function (event) {
    toast_tip('开始运行,请勿重复点击!')
    let lista = document.querySelectorAll('a')
    let num = 0
    for (let index = 0; index < lista.length; index++) {
        num++
        await SaveHrelFile(lista[index].href)
    }
};
document.querySelector('#erphpdown-download').append(div);
//插入美化css
GM_addStyle('.btn-class {color: #409eff;background-color: rgb(236, 245, 255);border-color: #b3d8ff;border-style: solid;border-width: 1px;padding: 4.9px 8.5px;border-radius: 4.3px;cursor: pointer;}.btnhover-class:hover{background: #409eff;border-color: #409eff;color: #fff;}.card-wrap{display: flex;justify-content: center;}.card{padding: 10.9px;line-height: 22px;cursor: auto;}')