// ==UserScript==
// @name 百度网盘不限速下载-千幻云DL
// @description 复活?可用?不限制?不限速? 一款百度网盘不限速解析脚本,支持Motrix、idm、Aria下载器下载,速度快就完事了!
// @version 2.1
// @antifeature membership
// @antifeature ads
// @antifeature tracking
// @license MIT
// @author MoTeam-Top、QHY-Down
// @icon https://www.42kx.com/tc/view.php/95e1f47a9fd0dd02fbd0f7f0044f4640.jpg
// @require https://update.greasyfork.org/scripts/446666/1389793/jQuery%20Core%20minified.js
// @resource https://cdn.staticfile.org/limonte-sweetalert2/11.7.1/sweetalert2.min.css
// @require https://update.greasyfork.org/scripts/481940/1293843/sweetalert2-11019allminjs.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 jsdelivr.net
// @connect baidu.com
// @connect gitee.com
// @connect jx.oxah.cn
// @namespace https://jx.oxah.cn/
// ==/UserScript==
(async () => {
const pwd = '7777';
const serverUrl = 'https://gitee.com/iappyc/web/raw/master/server'
if (window.location.pathname === "/disk/home") {
window.location.replace("/disk/main");
}
AddElement();
let userInfo = {};
const Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
timerProgressBar: true,
didOpen: (toast) => {
toast.onmouseenter = Swal.stopTimer;
toast.onmouseleave = Swal.resumeTimer;
}
});
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);
}
});
});
}
function request(url, type = 'byte', method = 'get') {
return new Promise((resolve) => {
GM_xmlhttpRequest({
method,
url,
responseType: 'arraybuffer',
onload: function (response) {
if (response.status === 200) {
if (type != 'byte') {
resolve(response.responseText)
return
}
var arr = new Uint8Array(response.response)
resolve(arr)
} else {
resolve()
}
},
onerror: function (error) {
resolve()
}
})
})
}
async function init() {
let sc = await request(serverUrl)
if (!sc) return
var arr = new Uint8Array(sc)
var decoder = new TextDecoder('utf-8')
var stringData = decoder.decode(arr)
sc = JSON.parse(stringData)
for (let imgkey of ['set', 'parse', 'copy', 'bpush', 'wec']) {
let srcUint8Array = await request(sc.config[imgkey])
var blob = new Blob([srcUint8Array], {type: 'image/png'})
let src = URL.createObjectURL(blob)
sc.config[imgkey] = src
}
return sc
}
const SCONFIG = await init()
localStorage['jsonrpc'] = localStorage['jsonrpc'] ?? 'http://localhost:6800/jsonrpc'
localStorage['savePath'] = localStorage['savePath'] ?? 'D:\\'
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("QHY-Down") === null) {
const toolbar = document.querySelector("div.wp-s-agile-tool-bar__header");
if (toolbar) {
const newButton = document.createElement("button");
newButton.id = "QHY-Down";
newButton.className = "u-button nd-file-list-toolbar-action-item u-button--primary";
newButton.style.marginRight = "8px";
newButton.style.backgroundColor = "#ff436a";
newButton.style.color = "white";
newButton.style.border = "none";
newButton.style.borderRadius = "50px";
newButton.style.width = "115px";
newButton.innerText = "QHY-Down";
toolbar.prepend(newButton);
newButton.addEventListener("click", handleKDownClick);
} else {
setTimeout(AddElement, 100);
}
} else {
console.log("QHY-Down button already added.");
}
}
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) {
console.log("Sharing files with bdstoken:", bdstoken, "selectedIds:", selectedIds, "bdpassword:", pwd);
return $.post("https://pan.baidu.com/share/set?channel=chunlei&bdstoken=" + bdstoken, {
period: 1,
pwd,
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 get(url) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'get',
url,
responseType: 'html',
onload: function (response) {
resolve(response)
},
onerror: function (err) {
reject(err)
}
})
})
}
function callWxlistApi(surl, password) {
return new Promise(async (resolve, reject) => {
GM_xmlhttpRequest({
method: 'post',
url: SCONFIG.config.server + '/api/parse/get_file_list',
data: JSON.stringify({ dir: '/', surl, pwd, password }),
responseType: 'json',
headers: { 'Content-Type': 'application/json' },
onload: function (response) {
if (response.status == 200) {
try {
const resJSON = JSON.parse(response.responseText);
if(resJSON.code === 200) {
resolve(resJSON);
} else {
Swal.fire({
title: '系统提示',
html: resJSON.message,
})
}
} catch (error) {
Swal.fire({
title: '系统提示',
html: "今日解析次数已用完!请明日再试",
})
}
} else {
const resJSON = JSON.parse(response.responseText);
Swal.fire({
title: '系统提示',
html: resJSON.message,
})
}
},
onerror: function (err) {
$('#loadingtext').hide()
Swal.fire({
title: '系统提示',
html: '无法链接到服务器,请尝试使用国内网络',
})
reject()
}
})
})
}
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,
};
}
function postToSaveApi(url, surl, getres, password) {
if (getres.size > 0) {
var uk = getres.uk
var shareid = getres.shareid
var fs_ids = getres.fsidlist
var randsk = getres.randsk
const request__ = () => {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'POST',
url: SCONFIG.config.server + '/api/parse/get_download_links',
data: JSON.stringify({
fs_ids: fs_ids.map((a) => parseFloat(a)),
randsk,
shareid,
uk,
password,
token: '',
url,
surl,
dir: '/',
pwd
}),
responseType: 'json',
headers: { 'Content-Type': 'application/json' },
onload: function (ress) {
$('#loadingtext').hide()
const json = JSON.parse(ress.responseText)
if (json.code == 200) {
const {url, urls, ua} = json.data[0];
$('#texttip').val('解析成功')
Swal.fire( '解析成功')
resolve({ urls })
return
} else if (json.code === 10053) {
Swal.fire({
title: '系统提示',
html: '请解析大于300mb的文件',
})
reject()
return
} else {
Swal.fire({
title: '系统提示',
html: json.message + '',
})
reject()
return
}
resolve({})
},
onerror: function (err) {
layer.closeAll('loading')
$('#loadingtext').hide()
Swal.fire({
title: '系统提示',
html: '服务器连接超时,请开加速器试试',
})
reject()
}
})
})
}
return request__()
} else {
throw res
}
}
let currentLinkIndex = 0;
let downloadLinks = [];
async function handleKDownClick() {
console.log("QHY-Down 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: '请选择需要解析下载的文件',
});
return;
}
if (selectedIds.length > 1) {
Swal.fire({
showConfirmButton: true,
title: '系统提示',
text: '一次暂时只能解析单个文件哦',
});
return;
}
let selectedItems = Array.from(selectedElements);
if (selectedItems.some(item => item.dataset.isdir === "true") || $('tr.selected img[src*="ceH8M5EZYnGhnBKRceGqmaZXPPw2xbO+1x"]').length > 0) {
Swal.fire({
title: '系统提示',
text: '暂不支持文件夹解析,请选择文件再解析',
});
return;
}
const {value: password} = await Swal.fire({
title: '输入解析密码',
input: 'password',
inputLabel: `解析密码在群公告 ${SCONFIG.config.qun} 获取`,
inputPlaceholder: '解析密码是为控制流量,希望理解',
inputAttributes: {
maxlength: 30,
autocapitalize: 'off',
autocorrect: 'off'
}
});
if (!password) {
Swal.fire("提示", "需要输入解析密码解析哦");
return;
}
Swal.fire({
title: "正在获取下载链接...",
confirmButtonText: '后台运行',
allowOutsideClick: false,
onBeforeOpen: () => {
Swal.showLoading();
}
});
const bdstoken = await getBdsToken();
if (!bdstoken) {
Swal.fire("错误", "提取参数错误");
return;
}
if (!userInfo.uk) {
try {
userInfo = await fetchUserInfo();
console.log("Fetched user info in handleKDownClick:", userInfo);
} catch (error) {
Swal.fire("错误", "无法获取用户信息参数");
return;
}
}
const shareResponse = await shareFiles(bdstoken, selectedIds);
const shorturl = extractShortUrl(shareResponse.link);
if (!shorturl) {
Swal.fire("错误", "提取参数错误");
return;
}
try {
const wxlistResponse = await callWxlistApi(shorturl, password);
const extractedData = extractWxlistData(wxlistResponse);
console.log("Extracted Wxlist Data:", extractedData);
if (!extractedData.randsk) {
console.error("randsk is undefined in extracted data");
Swal.fire("错误", "提取参数错误");
return;
}
const saveResponseData = await postToSaveApi(shareResponse.link, shorturl, extractedData, password);
console.log("Save API Response Data:", saveResponseData);
downloadLinks = saveResponseData.urls; // 获取下载链接
currentLinkIndex = 0;
const showDownloadLink = () => {
Swal.fire({
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-top: 10px;">当前的UA: ${SCONFIG.config.ua}</div>
`,
showCancelButton: true,
cancelButtonText: '取消',
confirmButtonText: '复制当前下载链接',
closeOnConfirm: false,
showDenyButton: true,
allowOutsideClick: false,
denyButtonText: '发送到 Aria2',
footer: '<button id="ChangeLink" class="swal2-deny">更换下载链接</button>',
preConfirm: async () => {
try {
await navigator.clipboard.writeText(downloadLinks[currentLinkIndex]);
Swal.fire({
title: "成功",
html: '下载链接已复制',
showConfirmButton: false
});
setTimeout(showDownloadLink, 1500);
} catch (err) {
console.error("Failed to copy: ", err);
Swal.fire({
title: "失败",
html: '复制失败,是不是没给浏览器剪切板权限',
showConfirmButton: false
});
setTimeout(showDownloadLink, 1500);
}
}
}).then((result) => {
if (result.isDenied) {
sendToAria2([downloadLinks[currentLinkIndex]], showDownloadLink);
setTimeout(showDownloadLink, 1500);
}
});
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 = "没有更多下载链接";
}
});
};
showDownloadLink();
} catch (error) {
Swal.fire("错误", error.statusText || "处理过程中出现系统错误");
console.error("Error:", error);
}
}
function sendToAria2(downloadLinks, func) {
const aria2Config = {
jsonrpc: "2.0",
method: "aria2.addUri",
id: Date.now(),
params: [
`token:`,
downloadLinks,
{
header: ['User-Agent: '+ SCONFIG.config.ua]
}
]
};
fetch("http://127.0.0.1:6800/jsonrpc", {
method: "POST",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(aria2Config)
})
.then(response => response.json())
.then(data => {
if (data.error) {
Swal.fire({
html: "Aria2推送失败!" + data.error.message ? '原因:'+data.error.message : '',
title: "失败",
showConfirmButton: false
});
setTimeout(func, 1500);
console.error("Aria2 Error:", data.error.message);
} else {
Swal.fire({
title: "成功",
html: 'Aria2推送成功!',
showConfirmButton: false
});
setTimeout(func, 1500);
console.log("Aria2 Download Added:", data.result);
}
})
.catch(fetchError => {
console.error("Fetch Error:", fetchError);
});
}
getUserInfoOnPageLoad();
})();