// ==UserScript==
// @name 百度网盘不限速下载-千幻云DL
// @description 一款百度网盘不限速解析脚本,复活?可用?不限制?不限速? 支持Motrix、idm、Aria下载器下载,速度快就完事了!
// @version 2.3
// @antifeature membership
// @antifeature ads
// @antifeature tracking
// @license MIT
// @author huan_kong、QHY-Down
// @icon https://www.42kx.com/tc/view.php/95e1f47a9fd0dd02fbd0f7f0044f4640.jpg
// @require https://registry.npmmirror.com/jquery/3.7.1/files/dist/jquery.min.js
// @resource https://registry.npmmirror.com/sweetalert2/11.10.3/files/dist/sweetalert2.min.css
// @require https://registry.npmmirror.com/sweetalert2/11.10.3/files/dist/sweetalert2.all.min.js
// @grant GM_xmlhttpRequest
// @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 pan.baidu.com
// @connect yun.baidu.com
// @connect gitee.com
// @connect jx.oxah.cn
// @namespace https://jx.oxah.cn/
// ==/UserScript==
;(async () => {
const serverUrl = 'https://gitee.com/iappyc/web/raw/master/server'
if (window.location.pathname === '/disk/home') window.location.replace('/disk/main')
async function sendRequest(method, url, data = null) {
return new Promise((resolve, reject) => {
console.log('发起请求:', {
method,
url,
...(['get', 'head'].includes(method) ? {} : { data: JSON.stringify(data), headers: { 'Content-Type': 'application/json' } }),
})
GM_xmlhttpRequest({
method,
url,
...(['get', 'head'].includes(method) ? {} : { data: JSON.stringify(data), headers: { 'Content-Type': 'application/json' } }),
onload: (response) => {
console.log('请求成功:', response)
let returnValue = response.responseText
try {
returnValue = typeof returnValue === 'string' ? JSON.parse(returnValue) : returnValue
} catch (error) {
console.log('JSON 解析失败', returnValue)
resolve(returnValue)
}
if (!returnValue.code || returnValue.code === 200) {
resolve(returnValue)
return
}
Swal.fire({
title: '系统提示',
html: returnValue.message,
})
reject(returnValue.message)
},
onerror: (error) => {
console.log('请求出错:', error)
reject(error)
},
})
})
}
async function init() {
try {
const res = await sendRequest('get', serverUrl)
const SCONFIG = res.config
// for (const imgkey of ['set', 'parse', 'copy', 'bpush', 'wec']) {
// const blob = await sendRequest('GET', SCONFIG[imgkey], undefined, undefined, 'blob')
// SCONFIG[imgkey] = URL.createObjectURL(blob)
// }
return SCONFIG
} catch (error) {
console.log('获取服务器数据失败:', error)
Swal.fire({
title: '系统提示',
html: '连接到服务器失败,请尝试使用国内网络',
})
}
}
function getBdsToken() {
const htmlString = $('html').html()
const regex = /"bdstoken":"(\w+)"/
const match = regex.exec(htmlString)
return match ? match[1] : null
}
async function fetchUserInfo() {
const response = await sendRequest('get', 'https://pan.baidu.com/rest/2.0/membership/user/info?method=query&clienttype=0&app_id=250528')
response.bdstoken = getBdsToken()
return response.user_info
}
function extractShortUrl(link) {
const regex = /https:\/\/pan\.baidu\.com\/s\/([a-zA-Z0-9-_]+)/
const match = regex.exec(link)
return match ? match[1] : null
}
async function shareFiles(selectedIds) {
const response = await $.ajax({
method: 'post',
url: `https://pan.baidu.com/share/set?channel=chunlei&bdstoken=${USERINFO.bdstoken}&clienttype=0&app_id=250528&web=1`,
data: {
period: 1,
pwd: '1111',
eflag_disable: true,
channel_list: '[]',
schannel: 4,
fid_list: JSON.stringify(selectedIds),
},
})
return extractShortUrl(response.link)
}
async function getFileList(surl, parse_password) {
const response = await sendRequest('post', `${SCONFIG.server}/api/v1/user/parse/get_file_list`, {
dir: '/',
surl,
pwd: '1111',
parse_password,
})
return response.data
}
async function getDownloadLinks(randsk, uk, shareid, fs_id, surl, parse_password) {
const response = await sendRequest('post', `${SCONFIG.server}/api/v1/user/parse/get_download_links`, {
randsk,
uk,
shareid,
fs_id,
surl,
dir: '/',
pwd: '1111',
token: 'guest',
parse_password,
rand2: '油猴脚本',
})
return response.data[0]
}
function addElement() {
const alreadyExists = document.getElementById('QHY-Down')
if (alreadyExists) return
const toolbar = document.querySelector('div.wp-s-agile-tool-bar__header')
if (!toolbar) {
setTimeout(addElement, 100)
return
}
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', handleDownloadButton)
}
let downloadLinks = []
let currentLinkIndex = 0
function CopyLink() {
GM_setClipboard(downloadLinks.urls[currentLinkIndex])
Swal.fire({
title: '系统通知',
html: '下载链接已复制',
showConfirmButton: false,
allowOutsideClick: false,
})
setTimeout(showDownloadLinks, 1500)
}
async function SendLink() {
const aria2Config = {
jsonrpc: '2.0',
method: 'aria2.addUri',
id: Date.now(),
params: [
`token:`,
[downloadLinks.urls[currentLinkIndex]],
{
header: [`User-Agent: ${downloadLinks.ua}`],
},
],
}
const data = await $.ajax({
method: 'POST',
url: 'http://127.0.0.1:6800/jsonrpc',
data: JSON.stringify(aria2Config),
contentType: 'application/json',
})
if (data.error) {
Swal.fire({
html: `Aria2推送失败 ${data.error.message ? '原因:' + data.error.message : ''}`,
title: '失败',
showConfirmButton: false,
allowOutsideClick: false,
})
setTimeout(showDownloadLinks, 1500)
} else {
Swal.fire({
title: '成功',
html: 'Aria2推送成功',
showConfirmButton: false,
allowOutsideClick: false,
})
setTimeout(showDownloadLinks, 1500)
}
}
function ChangeLink() {
if (currentLinkIndex < downloadLinks.urls.length - 1) {
currentLinkIndex++
showDownloadLinks()
} else {
Swal.fire({
title: '系统通知',
html: '没有更多下载链接啦',
showConfirmButton: false,
allowOutsideClick: false,
})
setTimeout(showDownloadLinks, 1500)
}
}
async function handleDownloadButton() {
const selectedRawElements = 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',
)
const selectedElements = Array.from(selectedRawElements)
const selectedIds = selectedElements.map((item) => parseFloat(item.getAttribute('data-id')))
if (selectedIds.length === 0) {
Swal.fire({
title: '系统提示',
text: '请先选择需要解析下载的文件',
})
return
}
if (selectedIds.length > 1) {
Swal.fire({
title: '系统提示',
text: '一次暂时只能解析单个文件哦',
})
return
}
if (selectedElements.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.qun} 获取`,
inputPlaceholder: '解析密码是为控制流量,希望理解',
inputAttributes: {
maxlength: 30,
autocapitalize: 'off',
autocorrect: 'off',
},
})
if (!password) {
Swal.fire({
title: '系统提示',
text: '需要输入解析密码解析哦',
})
return
}
Swal.fire({
title: '正在获取下载链接...',
allowOutsideClick: false,
showConfirmButton: false,
})
let surl
try {
Swal.fire({
title: '正在创建分享链接...',
allowOutsideClick: false,
showConfirmButton: false,
})
// 分享文件
surl = await shareFiles(selectedIds)
console.log('SURL:', surl)
} catch (error) {
Swal.fire({
title: '系统提示',
text: '分享文件失败,请稍后再试',
})
return
}
Swal.fire({
title: '正在获取文件信息...',
allowOutsideClick: false,
showConfirmButton: false,
})
const { shareid, uk, randsk } = await getFileList(surl, password)
console.log('FileList获取成功:', shareid, uk, randsk)
Swal.fire({
title: '正在获取下载链接...',
allowOutsideClick: false,
showConfirmButton: false,
})
const links = await getDownloadLinks(randsk, uk, shareid, selectedIds, surl, password)
console.log('DownloadLinks获取成功:', links)
downloadLinks = links
currentLinkIndex = 0
showDownloadLinks()
}
function showDownloadLinks() {
Swal.fire({
title: '下载链接获取成功',
html: `
<div style="border: 1px solid #ddd; padding: 10px; margin-bottom: 10px;">
<a href="${downloadLinks.urls[currentLinkIndex]}" target="_blank">下载链接:${downloadLinks.urls[currentLinkIndex].substring(0, 50)}...</a>
</div>
<div style="border: 1px solid #ddd; padding: 10px; margin-top: 10px;">
当前的UA: ${downloadLinks.ua}
</div>`,
showConfirmButton: false,
allowOutsideClick: false,
footer: `
<div style="display:flex; gap: 10px;">
<button id="CopyLink" class="u-button nd-file-list-toolbar-action-item u-button--primary">复制下载链接</button>
<button id="SendLink" class="u-button nd-file-list-toolbar-action-item u-button--primary">发送到Aria2</button>
<button id="ChangeLink" class="u-button nd-file-list-toolbar-action-item u-button--primary">更换下载链接</button>
</div>`,
})
document.querySelector('#CopyLink').addEventListener('click', CopyLink)
document.querySelector('#SendLink').addEventListener('click', SendLink)
document.querySelector('#ChangeLink').addEventListener('click', ChangeLink)
}
const SCONFIG = await init()
const USERINFO = await fetchUserInfo()
// 最后创建
addElement()
})()