Greasy Fork is available in English.
复活版TT快下,加速?
// ==UserScript==// @name 【复活版】百度网盘不限速下载-TT快下// @namespace https://wiki.tttt.ee// @description 复活版TT快下,加速?// @version 1.2.2// @license MIT// @author MoTeam-Top、TT-down// @icon https://wiki.tttt.ee/logo.png// @resource https://cdn.staticfile.org/limonte-sweetalert2/11.7.1/sweetalert2.min.css// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert2.all.min.js// @require https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js// @grant GM_xmlhttpRequest// @grant GM_addStyle// @grant GM_setClipboard// @match *://pan.baidu.com/*// @match *://yun.baidu.com/*// @match *://pan.baidu.com/disk/home*// @match *://yun.baidu.com/disk/home*// @match *://pan.baidu.com/disk/main*// @match *://yun.baidu.com/disk/main*// @match *://pan.baidu.com/s/*// @match *://yun.baidu.com/s/*// @match *://pan.baidu.com/share/*// @match *://yun.baidu.com/share/*// @connect moiu.cn// @connect jsdelivr.net// @connect baidu.com// @connect tttt.ee// @antifeature membership// @antifeature referral-link// ==/UserScript==(async () => {// 在页面加载时立即调用GetNotify函数GetNotify();if (window.location.pathname === "/disk/home") {window.location.replace("/disk/main");}AddElement();let filelistValue = ''; // 新增变量,用于保存从 save 接口返回的 to 值// 添加一些自定义 CSS 来调整按钮样式const style = document.createElement('style');style.innerHTML = `.swal2-cancel-button {margin-left: 10px;}`;document.head.appendChild(style);function GetNotify() {GM_xmlhttpRequest({method: "GET",url: "https://api.moiu.cn/JavaScript/PaiPai/info_v2",onload: function(response) {try {const jsondata = JSON.parse(response.responseText);const { code, message, ua, gg, open, url, url_data } = jsondata;// 确保公告是打开状态if (open === 1 && code === 200) {const showCancelButton = url_data === 'y';Swal.fire({icon: "info",title: gg, // 使用公告标题text: message, // 使用公告信息confirmButtonText: "关闭",showCancelButton: showCancelButton, // 根据 url_data 控制取消按钮的显示cancelButtonText: "我要租号",cancelButtonColor: '#007bff', // 自定义取消按钮颜色customClass: {cancelButton: 'swal2-cancel-button' // 自定义按钮类名},preConfirm: () => {// 这个函数在点击“关闭”时触发console.log('关闭按钮被点击');}}).then((r###lt) => {if (r###lt.dismiss === Swal.DismissReason.cancel) {// 点击“我要租号”按钮的行为window.open(url, "_blank");}});}} catch (e) {console.error("Error fetching announcement:", e);}},});}// 存储用户信息let userInfo = {};// 获取用户信息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);}});});}// 在页面加载完成后请求用户信息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("TTDown") === null) {const toolbar = document.querySelector("div.wp-s-agile-tool-bar__header");if (toolbar) {const newButton = document.createElement("button");newButton.id = "TTDown";newButton.className = "u-button nd-file-list-toolbar-action-item"; // 去掉原有的颜色类名newButton.style.marginRight = "8px";newButton.style.backgroundColor = "red"; // 设置背景颜色为红色newButton.style.color = "white"; // 设置文字颜色为白色以便更好地显示newButton.innerText = "TTDown";toolbar.prepend(newButton);const statusButton = document.createElement("button");statusButton.id = "TTDownStatus";statusButton.className = "u-button nd-file-list-toolbar-action-item"; // 去掉原有的颜色类名statusButton.style.marginRight = "8px";statusButton.style.backgroundColor = "red"; // 设置背景颜色为红色statusButton.style.color = "white"; // 设置文字颜色为白色以便更好地显示statusButton.innerText = "TTDown Status";toolbar.prepend(statusButton);newButton.addEventListener("click", handleTTDownClick);statusButton.addEventListener("click", handleTTDownStatusClick);} else {setTimeout(AddElement, 100);}} else {console.log("TTDown 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) {const bdpassword = "7777";console.log("Sharing files with bdstoken:", bdstoken, "selectedIds:", selectedIds, "bdpassword:", bdpassword);return $.post("https://pan.baidu.com/share/set?channel=chunlei&bdstoken=" + bdstoken, {period: 1,pwd: bdpassword,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 callWxlistApi(shorturl, password) {console.log("Calling Wxlist API with shorturl:", shorturl, "password:", password);const bdpassword = "7777";return new Promise((resolve, reject) => {const url = "https://api.moiu.cn/api/List";const formParams = {"surl": shorturl,"dir": "/","password": password,"pwd": bdpassword};$.ajax({type: "POST",url: url,data: formParams,success: function(response) {console.log("Wxlist API response:", response);resolve(response);},error: function(xhr, status, error) {console.error("Error calling Wxlist API:", xhr, status, error);reject({status: xhr.status,statusText: xhr.statusText});}});});}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, // 提取第一个列表项的 size 属性filename: data.list[0]?.server_filename || 0, // 提取第一个列表项的 size 属性};}function postToSaveApi(data, password, userid, shorturl) {const requestData = {fsidlist: data.list[0].fs_id.toString(), // 确保是字符串sekey: data.randsk,uk: data.uk,surl: shorturl,shareid: data.shareid,password: password,userid: userid,size: data.size.toString(), // 确保是字符串filename: data.filename};console.log("Prepared request data for Save API:", requestData);return new Promise((resolve, reject) => {GM_xmlhttpRequest({method: "POST",url: "https://api.tttt.ee/parse.php",headers: {"Content-Type": "application/json"},data: JSON.stringify(requestData),onload: function(response) {const responseData = JSON.parse(response.responseText);console.log("Save API response:", responseData);if (responseData.code !== 200) {Swal.fire("错误", responseData.message, "error");reject({status: response.status,statusText: responseData.message});} else {resolve(responseData.data); // 直接返回data对象}},onerror: function(response) {const errorMessage = JSON.parse(response.responseText).message || '网络错误';Swal.fire("错误", errorMessage, "error");console.error("Error posting to Save API:", response);reject({status: response.status,statusText: errorMessage});}});});}let currentLinkIndex = 0;let downloadLinks = [];async function handleTTDownClick() {console.log("TTDown 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: '请选择需要下载的文件',icon: 'error'});return;}if (selectedIds.length > 1) {Swal.fire({showConfirmButton: true,title: '系统提示',text: '暂时只能下载一个文件',icon: 'error'});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: '请不要选择文件夹解析,因为还没学会.',icon: 'error'});return;}const { value: requestType } = await Swal.fire({title: '选择请求类型',html: `<div><input type="radio" id="cloud" name="requestType" value="cloud" checked><label for="cloud">1号接口(全天稳定无法保证,有时可能加速正常)</label></div><div><input type="radio" id="local" name="requestType" value="local"><label for="local">2号接口(稳定,加速需要自带SVIP账号)</label></div>`,showCancelButton: true,cancelButtonText: '取消',preConfirm: () => {const requestType = document.querySelector('input[name="requestType"]:checked').value;return requestType;}});if (!requestType) {Swal.fire("提示", "您需要选择一个请求类型来继续", "info");return;}const { value: password } = await Swal.fire({title: '输入密码',input: 'password',inputLabel: '使用前请先关注公众号:冰箱喵 获取验证码吧!',inputPlaceholder: '密码为了控制流量,理解下',inputAttributes: {maxlength: 6,autocapitalize: 'off',autocorrect: 'off'}});if (!password) {Swal.fire("提示", "需要密码来继续", "info");return;}Swal.fire({title: "正在获取下载链接...",onBeforeOpen: () => {Swal.showLoading();}});if (requestType === 'local') {try {const rootListResponse = await fetchBaiduRootFileList();const rootFileList = rootListResponse.list;console.log("Baidu root file list response:", rootFileList);const myResourceFolderExists = rootFileList.some(file => file.path === "/我的资源");if (!myResourceFolderExists) {Swal.fire({title: '错误',text: '似乎你解析的文件没有放在 我的资源 文件夹,或者你根本没创建这个文件夹',icon: 'error'});return;}let pathLocal;let filename;try {const listResponse = await fetchBaiduFileList();const fileList = listResponse.list;console.log("Baidu file list response:", fileList);fileList.forEach(file => {if (selectedIds.includes(file.fs_id.toString())) {pathLocal = file.path;filename = file.server_filename;}});if (!pathLocal || !filename) {Swal.fire("错误", "未找到匹配的文件或文件名", "error");return;}console.log("Matched file path:", pathLocal);console.log("Matched file name:", filename);// 生成下载链接的请求const bdstoken = await getBdsToken();if (!bdstoken) {Swal.fire("错误", "无法获取bdstoken", "error");return;}const queryParams = new URLSearchParams({"target": JSON.stringify([pathLocal]),"dlink": 1,"channel": "chunlei","web": 1,"app_id": 250528,"bdstoken": bdstoken,"logid": "QzBQUQORDY1N0E0QzMzNzEyRDDBNjZDZjc1NzJFQUY6Rkc9MQ%3D%3D","clienttype": 0});const requestUrl = `https://pan.baidu.com/api/filemetas?${queryParams.toString()}`;// 发起请求以获取下载链接const downloadLinkResponse = await fetch(requestUrl);const downloadLinkData = await downloadLinkResponse.json();if (downloadLinkData.errno === 0) {console.log("Download link data:", downloadLinkData);const downloadLink = downloadLinkData.info[0].dlink;// 发送请求到 parse 接口const parseResponse = await postToSaveApi({ filename, dlink: downloadLink }, password, userInfo.uk, shorturl);console.log("Parse API Response Data:", parseResponse);Swal.fire({icon: 'success',title: '下载链接获取成功',html: `<a href="${downloadLink}" target="_blank">${downloadLink}</a>`,showCancelButton: true,cancelButtonText: '关闭',confirmButtonText: '复制链接',preConfirm: async () => {try {await navigator.clipboard.writeText(downloadLink);Swal.fire("已复制", "下载链接已复制到剪贴板", "success");} catch (err) {console.error("Failed to copy: ", err);Swal.fire("复制失败", "无法将链接复制到剪贴板", "error");}}});} else {Swal.fire("错误", "无法获取下载链接", "error");}} catch (error) {Swal.fire("错误", "无法获取文件列表", "error");console.error("Error fetching file list:", error);return;}} catch (error) {Swal.fire("错误", "无法获取根目录文件列表", "error");console.error("Error fetching root directory file list:", error);return;}} else {const bdstoken = await getBdsToken();if (!bdstoken) {Swal.fire("错误", "无法获取bdstoken", "error");return;}const shareResponse = await shareFiles(bdstoken, selectedIds);const shorturl = extractShortUrl(shareResponse.link);if (!shorturl) {Swal.fire("错误", "无法提取shorturl", "error");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("错误", "无法提取 randsk", "error");return;}const saveResponseData = await postToSaveApi(extractedData, password, userInfo.uk, shorturl);console.log("Save API Response Data:", saveResponseData);downloadLinks = [saveResponseData.dlink, ...saveResponseData.urls]; // 获取 dlink 和其他链接currentLinkIndex = 0;const showDownloadLink = () => {Swal.fire({icon: 'success',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: netdisk;P2SP;2.2.61.31;netdisk;10.0.183;android-android;ttdown</div>`,showCancelButton: true,cancelButtonText: '取消',confirmButtonText: '复制当前链接',showDenyButton: true,denyButtonText: '发送到 Aria2',footer: '<button id="ChangeLink" class="swal2-deny">换个下载链接</button>',preConfirm: async () => {try {await navigator.clipboard.writeText(downloadLinks[currentLinkIndex]);Swal.fire("已复制", "下载链接已复制到剪贴板", "success");} catch (err) {console.error("Failed to copy: ", err);Swal.fire("复制失败", "无法将链接复制到剪贴板", "error");}}}).then((r###lt) => {if (r###lt.isDenied) {sendToAria2([downloadLinks[currentLinkIndex]]);}});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 || "处理过程中出现错误", "error");console.error("Error:", error);}}}function sendToAria2(downloadLinks) {const aria2Config = {jsonrpc: "2.0",method: "aria2.addUri",id: Date.now(),params: [`token:`,downloadLinks,{header: ['User-Agent: netdisk;TTdown;svip']}]};fetch("http://127.0.0.1:16800/jsonrpc", {method: "POST",headers: {"Content-Type": "application/json"},body: JSON.stringify(aria2Config)}).then(response => response.json()).then(data => {if (data.error) {console.error("Aria2 Error:", data.error.message);} else {console.log("Aria2 Download Added:", data.r###lt);}}).catch(fetchError => {console.error("Fetch Error:", fetchError);});}async function handleTTDownStatusClick() {Swal.fire("检查中...", "正在检查服务器状态,请稍候...", "info");GM_xmlhttpRequest({method: "GET",url: "https://api.moiu.cn/JavaScript/users/status",onload: function(response) {try {const data = JSON.parse(response.responseText);const { code, message } = data;console.log("Server status response:", data);if (code === 200) {Swal.fire({icon: "success",title: "服务器状态",text: message,});} else if (code === 201) {Swal.fire({icon: "error",title: "服务器状态",text: message,});} else {Swal.fire({icon: "warning",title: "服务器状态",text: "未知状态",});}} catch (error) {Swal.fire("错误", "处理服务器响应时发生错误", "error");console.error("Error handling server response:", error);}},onerror: function(error) {Swal.fire("错误", "无法连接到服务器", "error");console.error("Error connecting to server:", error);},});}// 获取百度网盘根目录文件列表async function fetchBaiduRootFileList() {return new Promise((resolve, reject) => {GM_xmlhttpRequest({method: "GET",url: "https://pan.baidu.com/api/list?clienttype=0&app_id=250528&web=1&order=time&desc=1&dir=%2F&num=100&page=1",onload: function(response) {try {const data = JSON.parse(response.responseText);if (data.errno === 0) {resolve(data);} else {reject(new Error("API 返回错误: " + data.errno));}} catch (error) {reject(error);}},onerror: function(error) {reject(error);}});});}// 获取百度网盘文件列表async function fetchBaiduFileList() {return new Promise((resolve, reject) => {GM_xmlhttpRequest({method: "GET",url: "https://pan.baidu.com/api/list?clienttype=0&app_id=250528&web=1&order=time&desc=1&dir=%2F%E6%88%91%E7%9A%84%E8%B5%84%E6%BA%90&num=100&page=1",onload: function(response) {try {const data = JSON.parse(response.responseText);if (data.errno === 0) {resolve(data);} else {reject(new Error("API 返回错误: " + data.errno));}} catch (error) {reject(error);}},onerror: function(error) {reject(error);}});});}// 在页面加载完成后请求用户信息getUserInfoOnPageLoad();})();