// ==UserScript==
// @name 百度网盘直链满速下载助手(智狐版本)
// @namespace http://zhihupe.com/
// @version 0.2.2
// @antifeature zhihu 为防止接口被盗!该脚本需要输入验证码之后才能使用完整功能,感谢理解
// @description 【12月28日 满速下载体验】本脚本是基于超级会员解析,然后获取高速下载直链,下载速度基本可以跑满你的带宽!一共支持三种下载方式,同时支持Windows,Mac,Linux,Android等多平台,每一种都能给你一种高速下载的体验!
// @match https://pan.baidu.com/*
// @icon https://www.zhihupe.com/favicon.ico
// @require https://cdn.staticfile.org/limonte-sweetalert2/11.1.9/sweetalert2.all.min.js
// @require https://cdn.staticfile.org/jquery/3.6.0/jquery.min.js
// @require https://cdn.jsdelivr.net/npm/[email protected]/crypto-js.min.js
// @match *.baidu.com/*
// @grant GM_xmlhttpRequest
// @grant GM_openInTab
// @grant GM_addStyle
// @grant GM_setClipboard
// @grant unsafeWindow
// @connect pan.cyvyc.cn
// @license AGPL
// ==/UserScript==
var Page = "";
function getPwd(len) {
len = len || 4;
let $char = 'abcdefhijkmnprstwxyz123456789';
let l = $char.length;
let pwd = '';
for (let i = 0; i < len; i++) {
pwd += $char.charAt(Math.floor(Math.random() * l));
}
return pwd;
}
function getList() {
try {
return require('system-core:context/context.js').instanceForSystem.list.getSelected();
} catch (e) {
return document.querySelector('.nd-main-layout').__vue__.$children[2].selectedList;
}
}
function getSelectedfileList() {
let list = getList();
if (list && list.length === 1) {
if (list[0].isdir === 1) {
return zhihu.message.error('提示:请打开文件夹后勾选文件!');
}
return list[0];
}else if(list.length > 1){
return zhihu.message.error('提示:不要同时勾选多个文件');
}else{
return zhihu.message.error('提示:请先勾选要下载的文件!');
}
}
function Toast(msg, duration = 3000) {
var m = document.createElement('div');
m.innerHTML = msg;
m.style.cssText = "max-width:60%;min-width: 150px;padding:0 14px;height: 40px;color: rgb(255, 255, 255);line-height: 40px;text-align: center;border-radius: 4px;position: fixed;top: 50%;left: 50%;transform: translate(-50%, -50%);z-index: 999999;background: rgba(0, 0, 0,.7);font-size: 16px;";
document.body.appendChild(m);
setTimeout(() => {
var d = 0.5;
m.style.webkitTransition = '-webkit-transform ' + d + 's ease-in, opacity ' + d + 's ease-in';
m.style.opacity = '0';
setTimeout(() => { document.body.removeChild(m) }, d * 1000);
}, duration);
}
addbtn();
function getPage(){
let url = location.href;
if (url.indexOf(".baidu.com/disk/main") > 0) {
Page = "main"
} else if (url.indexOf(".baidu.com/disk/home") > 0) {
Page = "home"
}
}
async function addbtn() {
await sleep(1500);
getPage();
console.log(Page)
if (Page === 'home'){
let button = `<span class="g-dropdown-button" style="display: inline-block;" id="zhihuDown">
<a class="g-button g-button-blue blue-upload upload-wrapper" title="智狐下载助手" >
<span class="g-button-right">
<em class="icon icon-download" title="智狐下载助手"></em>
<span class="text" style="width: 80px;">智狐下载助手</span>
</span>
</a>
</span>
`;
$('#layoutMain div:has(span.g-new-create)>span.g-dropdown-button:first').before(button);
}
if (Page === 'main'){
let button = `<a id="zhihuDown" class="nd-upload-button upload-wrapper"><button
style="width: 140px;margin-right: 10px;" class="u-btn nd-file-list-toolbar-action-item u-btn--primary u-btn--default u-btn--small is-round is-has-icon">
<i class="iconfont icon-download"></i><span>智狐下载助手
</span>
</button>
</a>
`;
$('.nd-main-layout__body div:has(a.nd-upload-button)>a.nd-upload-button:first').before(button);
}
$('#zhihuDown').on('click', async e => {
let file = getSelectedfileList(),
pwd = getPwd(4);
if (!file)
return;
if (Page === 'home'){
zhihu.message.success('正在获取百度分享链接...');
}
if (Page === 'main'){
zhihu.message.error('请使用旧版页面下载');
}
let surl = await getShortUrl(file.fs_id, pwd);
if (!surl) {
return zhihu.message.error('百度分享链接获取失败');
}
showMain(surl, pwd, file.server_filename)
console.log(surl,pwd);
});
}
function getShortUrl(fs_id, pwd) {
let bdstoken = unsafeWindow.locals.dump('bdstoken');
return fetch(`https://pan.baidu.com/share/set?channel=chunlei&clienttype=0&web=1&channel=chunlei&web=1&app_id=250528&bdstoken=${bdstoken}&clienttype=0`, {
"headers": {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9",
"content-type": "text/plain;charset=UTF-8",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "none"
},
"referrerPolicy": "no-referrer-when-downgrade",
"body": `fid_list=[${fs_id}]&schannel=4&channel_list=[]&period=1&pwd=` + pwd,
"method": "POST",
"mode": "cors",
"credentials": "include"
}).then(r => r.json()).then(r => r.shorturl.replace(/^.+\//, '')).catch(e => null);
}
function getFileInfo(surl, pwd, passwordCode, website) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'POST',
data: `surl=${surl}&pwd=${pwd}&Password=` + passwordCode,
url: website,
headers: {
"content-type": "application/x-www-form-urlencoded",
},
onload: res => {
if (res.status != 200)
return reject(res);
resolve(res.responseText);
console.log(res.responseText)
},
onerror: err => reject(err)
});
}).then(r => {
let m = r.match(/javascript:confirmdl\((.+)\);/);
console.log(m);
if (m) return m[1];
return Promise.reject($(r).find('div.alert.alert-danger').text().trim() || `获取下载信息失败`);
});
}
function getParam(str) {
function fetch_token(fs_id, timestamp, sign, randsk, share_id, uk, bdstoken, filesize) {
let base64 = btoa(fs_id + sign + uk);
let base642 = btoa("nbest" + base64 + fs_id + "Yuan_Tuo" + share_id + sign + base64 + "baiduwp-php-donate");
let md5 = CryptoJS.MD5(base642 + timestamp + base64).toString()
return md5;
}
function urlEncode(obj) {
return Array.isArray(obj) ? obj.map(o => urlEncode(o)).join('&') : Object.keys(obj).map(key => key + '=' + obj[key]).join('&');
}
let arr = str.replace(/'/g,'').split(',');
arr.push(fetch_token(...arr));
return urlEncode(['fs_id', 'time', 'sign', 'randsk', 'share_id', 'uk', 'bdstoken', 'filesize', 'token'].reduce((t, v, i) => (t[v] = arr[i]) && t, {}));
}
function getLinkCommon(str, website) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'POST',
data: getParam(str),
url: website + "/?download",
headers: {
"content-type": "application/x-www-form-urlencoded",
},
onload: res => {
if (res.status != 200)
return reject(res);
resolve(res.responseText);
},
onerror: err => reject(err)
});
}).then(r => {
let link = $(r).find('#https').attr('href');
if (link)
return link;
return Promise.reject($(r).find('div.alert.alert-danger').text().trim() || '获取直链失败');
});
}
function sleep(time) {
return new Promise(resolve => setTimeout(resolve, time));
}
let toast = Swal.mixin({
toast: true,
showConfirmButton: false,
timer: 3500,
timerProgressBar: false,
didOpen: (toast) => {
toast.addEventListener('mouseenter', Swal.stopTimer);
toast.addEventListener('mouseleave', Swal.resumeTimer);
}
});
let zhihu = {
message: {
success(text) {
toast.fire({title: text, icon: 'success'});
},
error(text) {
toast.fire({title: text, icon: 'error'});
},
warning(text) {
toast.fire({title: text, icon: 'warning'});
},
info(text) {
toast.fire({title: text, icon: 'info'});
},
question(text) {
toast.fire({title: text, icon: 'question'});
}
}
}
function showMain(surl, pwd, fileName) {
let defaultpassword = "";
if (localStorage.password && (Date.now() - +localStorage.passwordTime) < 172800) {
defaultpassword = localStorage.password;
} else {
localStorage.password = "";
}
let html = `<div style="background-color: #fff;">
<div style="height: 63px;line-height: 63px;padding-left: 15px;">
<span id="title" style="color: 545454;font-size: 18px;font-weight: bold;text-align: left;">正在获取 ${fileName} 的直链</span>
</div>
<div style="background:#F5F6FA;padding: 15px;display: flex;box-sizing: border-box;">
<div style="width: 50%;margin-left: 5px;">
<div style="font-size: 14px;color:#06A7FF;text-align: center;margin:5px 15px 25px 0;" id="tip"></div>
<div style="margin-bottom: 20px;text-align: left;">
<span style="font-size: 12px;">方式一:IDM用户代理(UA)必须设置为:Hometown Cloud</span>
<div style="display: flex;height: 40px;line-height: 40px;margin-top: 20px;">
<div id="copyIDM"></div>
<a href="https://www.zhihupe.com/html/w10/13168.html" style="color: #09AAFF;font-size: 14px;text-decoration: none;">软件下载及教程</a>
</div>
</div>
<div style="margin-bottom: 20px;text-align: left;">
<span style="font-size: 12px;">方式二:Aria2/Motrix 无需配置,请看下方使用教程</span>
<div style="display: flex;height: 40px;line-height: 40px;margin-top: 20px;">
<div id="sendAria"></div>
<a href="https://www.zhihupe.com/html/w10/13167.html" style="color: #09AAFF;font-size: 14px;text-decoration: none;"">软件下载及教程</a>
</div>
</div>
<div style="font-size: 14px;color: #FF0000;margin-bottom: 10px;text-align: left;">为防止接口被滥用,需要输入验证码</div>
<div style="display: flex;justify-content: space-between;height: 40px;line-height: 40px;">
<input name="passwordCode" id="passwordCode"
value="${defaultpassword}" placeholder="请输入验证码" style="box-sizing: border-box; width: 150px;height: 100%;padding:0 10px ; border: 1px solid #D4D7DE;border-radius: 8px;" />
<div id="dowmBtn" style="margin-right: 15px; font-size: 14px;height: 100%;width: 125px;background: #09AAFF;border-radius: 20px;text-align: center;color: #fff;">点击获取直链</div>
</div>
</div>
<div style="width: 50%;display: flex;flex-direction:column;">
<img style="width: 130px;height: 130px;margin: 20px auto;border-radius: 5px;" src="http://cdn.wezhicms.com/uploads/allimg/20211215/1-21121500044Q94.jpg">
<span style="font-size: 14px;color: #666;text-align: center;">微信扫描上方二维码获取验证码</span>
<h1 style="text-align: center; font-size: 18px;font-weight: bold;margin: 20px 0;">解析步骤</h1>
<div style="font-size: 14px;color: #000;margin-left:15px;text-align: left;">
<div style="line-height: 3;">1.关注公众号【智狐百宝箱】</div>
<div style="line-height: 3;">2.回复‘解析’获取验证码</div>
<div style="line-height: 3;">3.将验证码输入左边输入框中,点击获取高速直链!</div>
</div>
</div>
</div>
<div style="font-size: 12px;color: #878C9C;line-height: 18px;text-align: center;height: 35px;padding-top: 15px;background-color: #F5F6FA; border-top: 1px solid #F0F0F2;"><span style="color:red;padding-right:5px">每晚23点到凌晨30分维护服务器,脚本暂停使用</span>大家有问题点击下方的交流反馈进行反应,脚本的问题也会第一时间交流区公布</div>
</div>`;
Swal.fire({
html:html,
width: 780,
allowOutsideClick: false,
showCancelButton: true,
confirmButtonText: '交流反馈',
cancelButtonText: '关闭',
reverseButtons: true
}).then(r => {
if (r.isConfirmed)
GM_openInTab('https://www.zhihupe.com/ask/list_21_9.html');
});
$('#dowmBtn').off().on("click", function () {
let passwordCode = $("#passwordCode").val();
if (passwordCode) {
if(passwordCode === "WHyATwCB"){
if (passwordCode != localStorage.password) {
localStorage.password = passwordCode;
localStorage.passwordTime = Date.now();
}
let password = "pan6666";
getLink(password);
$("#tip").html("正在获取链接,请稍等!");
}else{alert("验证码错误")}
$("#tip").html("正在获取链接,请稍等!");
} else {
alert("请输入验证码")
}
});
function getLink(passwordCode) {
(async () => {
let exception = null;
try {
let str = await getFileInfo(surl, pwd, passwordCode, website);
console.log(surl, pwd, passwordCode, website);
return await getLinkCommon(str, website);
} catch (e) {
exception = e;
}
throw exception;
})().then(link => {
$("#tip").html("高速链接获取成功!!!");
$("#title").html(`获取 ${fileName} 的高速直链成功`);
$("#copyIDM").html(`<div style="margin-right: 15px; font-size: 14px;height: 100%;width: 175px;background: #09AAFF;border-radius: 20px;text-align: center;color: #fff;">复制IDM链接到剪贴板</div>`)
$('#copyIDM').off().on('click', e => {
GM_setClipboard(link);
Toast('已复制IDM链接到剪贴板');
});
$("#sendAria").html(`<div style="margin-right: 15px; font-size: 14px;height: 100%;width: 175px;background: #09AAFF;border-radius: 20px;text-align: center;color: #fff;">发送到Aria2(motix)</div>`);
$('#sendAria').off().on('click', e => showAria(link, fileName));
}).catch(e => {
$("#title").html(`获取 ${fileName} 的高速直链失败`)
$("#tip").html(`获取高速链接<span style="font-weight:800;color:red">失败!!!</span>,原因是${e}`)
});
}
}
function showAria(url, filename) {
Swal.fire({
title: '发送到 Aria2 Json-RPC',
html: `<div style="width:95%;text-align:left;">
<label>RPC地址:</label>
<input id="wsurl" class="swal2-input" style="width:100%;margin:10px 0;" value="${localStorage.wsurl || ''}">
<div style="width:100%;margin:10px 0;"><small style="text-align:left;">推送aria2默认配置:<b>ws://localhost:6800/jsonrpc</b><br>推送Motrix默认配置:<b>ws://localhost:16800/jsonrpc</b></small></div>
<label>Token:</label>
<input id="token" class="swal2-input" style="width:100%;margin:10px 0;" value="${localStorage.wsToken || ''}">
<div style="width:100%;margin:10px 0;"><small style="text-align:left;">没有token的话,留空</small></div>
</div>`,
allowOutsideClick: false,
focusConfirm: false,
confirmButtonText: '发送',
showCancelButton: true,
cancelButtonText: '取消',
reverseButtons: true,
preConfirm: () => {
let wsurl = $('#wsurl').val();
if (!wsurl) {
Swal.showValidationMessage('RPC地址必填');
return;
}
}
}).then(r => r.isConfirmed && addUri(url, filename));
}
function addUri(url, filename) {
var wsurl = localStorage.wsurl = $('#wsurl').val();
var uris = [url.replace('https:', 'http:'), url];
var token = localStorage.wsToken = $('#token').val();
var options = {
"max-connection-per-server": "16",
"user-agent": "pan7568"
};
if (filename != "") {
options.out = filename;
}
let json = {
"id": "baiduwp-php",
"jsonrpc": '2.0',
"method": 'aria2.addUri',
"params": [uris, options],
};
if (token != "") {
json.params.unshift("token:" + token);
}
let patt = /^wss?\:\/\/(((([A-Za-z0-9]+[A-Za-z0-9\-]+[A-Za-z0-9]+)|([A-Za-z0-9]+))(\.(([A-Za-z0-9]+[A-Za-z0-9\-]+[A-Za-z0-9]+)|([A-Za-z0-9]+)))*(\.[A-Za-z0-9]{2,10}))|(localhost)|((([01]?\d?\d)|(2[0-4]\d)|(25[0-5]))(\.([01]?\d?\d)|(2[0-4]\d)|(25[0-5])){3})|((\[[A-Za-z0-9:]{2,39}\])|([A-Za-z0-9:]{2,39})))(\:\d{1,5})?(\/.*)?$/;
if (!patt.test(wsurl)) {
Swal.fire('地址错误', 'WebSocket 地址不符合验证规则,请检查是否填写正确!', 'error');
return;
}
var ws = new WebSocket(wsurl);
ws.onerror = event => {
console.log(event);
Swal.fire('连接错误', 'Aria2 连接错误,请打开控制台查看详情!', 'error');
};
ws.onopen = () => {
ws.send(JSON.stringify(json));
}
ws.onmessage = event => {
console.log(event);
let received_msg = JSON.parse(event.data);
if (received_msg.error !== undefined) {
if (received_msg.error.code === 1)
Swal.fire('通过RPC连接失败', '请打开控制台查看详细错误信息,返回信息:' + received_msg.error.message, 'error');
}
switch (received_msg.method) {
case "aria2.onDownloadStart":
Swal.fire('Aria2 发送成功', 'Aria2 已经开始下载!' + filename, 'success');
localStorage.setItem('aria2wsurl', wsurl); // add aria2 config to SessionStorage
if (token != "" && token != null)
localStorage.setItem('aria2token', token);
break;
case "aria2.onDownloadError": ;
Swal.fire('下载错误', 'Aria2 下载错误!', 'error');
break;
case "aria2.onDownloadComplete":
Swal.fire('下载完成', 'Aria2 下载完成!', 'success');
break;
default:
break;
}
};
}
const website = "http://pan.cyvyc.cn/";