【复活版】百度网盘不限速下载-TT快下

复活版TT快下,加速?

目前为 2024-07-29 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name 【复活版】百度网盘不限速下载-TT快下
  3. // @namespace https://wiki.tttt.ee
  4. // @description 复活版TT快下,加速?
  5. // @version 1.0.2
  6. // @license MIT
  7. // @author MoTeam-Top、TT-down
  8. // @icon https://wiki.tttt.ee/logo.png
  9. // @resource https://cdn.staticfile.org/limonte-sweetalert2/11.7.1/sweetalert2.min.css
  10. // @require https://cdn.jsdelivr.net/npm/sweetalert2@11.12.2/dist/sweetalert2.all.min.js
  11. // @require https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js
  12. // @grant GM_xmlhttpRequest
  13. // @grant GM_addStyle
  14. // @grant GM_setClipboard
  15. // @match *://pan.baidu.com/*
  16. // @match *://yun.baidu.com/*
  17. // @match *://pan.baidu.com/disk/home*
  18. // @match *://yun.baidu.com/disk/home*
  19. // @match *://pan.baidu.com/disk/main*
  20. // @match *://yun.baidu.com/disk/main*
  21. // @match *://pan.baidu.com/s/*
  22. // @match *://yun.baidu.com/s/*
  23. // @match *://pan.baidu.com/share/*
  24. // @match *://yun.baidu.com/share/*
  25. // @connect moiu.cn
  26. // @connect jsdelivr.net
  27. // @connect baidu.com
  28. // @antifeature membership
  29. // @antifeature referral-link
  30. // ==/UserScript==
  31.  
  32. (() => {
  33. // 在页面加载时立即调用GetNotify函数
  34. GetNotify();
  35.  
  36. if (window.location.pathname === "/disk/home") {
  37. window.location.replace("/disk/main");
  38. }
  39.  
  40. AddElement();
  41. let filelistValue = ''; // 新增变量,用于保存从 save 接口返回的 to 值
  42.  
  43. // 添加一些自定义 CSS 来调整按钮样式
  44. const style = document.createElement('style');
  45. style.innerHTML = `
  46. .swal2-cancel-button {
  47. margin-left: 10px;
  48. }
  49. `;
  50. document.head.appendChild(style);
  51.  
  52. function GetNotify() {
  53. GM_xmlhttpRequest({
  54. method: "GET",
  55. url: "https://api.moiu.cn/JavaScript/PaiPai/info_v2",
  56. onload: function(response) {
  57. try {
  58. const jsondata = JSON.parse(response.responseText);
  59. const { code, message, ua, gg, open, url, url_data } = jsondata;
  60.  
  61. // 确保公告是打开状态
  62. if (open === 1 && code === 200) {
  63. const showCancelButton = url_data === 'y';
  64.  
  65. Swal.fire({
  66. icon: "info",
  67. title: gg, // 使用公告标题
  68. text: message, // 使用公告信息
  69. confirmButtonText: "关闭",
  70. showCancelButton: showCancelButton, // 根据 url_data 控制取消按钮的显示
  71. cancelButtonText: "我要租号",
  72. cancelButtonColor: '#007bff', // 自定义取消按钮颜色
  73. customClass: {
  74. cancelButton: 'swal2-cancel-button' // 自定义按钮类名
  75. },
  76. preConfirm: () => {
  77. // 这个函数在点击“关闭”时触发
  78. console.log('关闭按钮被点击');
  79. }
  80. }).then((result) => {
  81. if (result.dismiss === Swal.DismissReason.cancel) {
  82. // 点击“我要租号”按钮的行为
  83. window.open(url, "_blank");
  84. }
  85. });
  86. }
  87. } catch (e) {
  88. console.error("Error fetching announcement:", e);
  89. }
  90. },
  91. });
  92. }
  93.  
  94.  
  95.  
  96.  
  97. // 存储用户信息
  98. let userInfo = {};
  99.  
  100. // 获取用户信息
  101. function fetchUserInfo() {
  102. return new Promise((resolve, reject) => {
  103. GM_xmlhttpRequest({
  104. method: "GET",
  105. url: "https://pan.baidu.com/rest/2.0/membership/user/info?method=query&clienttype=0&app_id=250528",
  106. onload: function(response) {
  107. try {
  108. const data = JSON.parse(response.responseText);
  109. resolve(data.user_info);
  110. } catch (error) {
  111. reject(error);
  112. }
  113. },
  114. onerror: function(error) {
  115. reject(error);
  116. }
  117. });
  118. });
  119. }
  120.  
  121. // 在页面加载完成后请求用户信息
  122. async function getUserInfoOnPageLoad() {
  123. try {
  124. const data = await fetchUserInfo();
  125. userInfo = data;
  126. console.log("User info fetched on page load:", userInfo);
  127. } catch (error) {
  128. console.error("Error fetching user info on page load:", error);
  129. }
  130. }
  131.  
  132. function AddElement() {
  133. if (document.getElementById("TTDown") === null) {
  134. const toolbar = document.querySelector("div.wp-s-agile-tool-bar__header");
  135. if (toolbar) {
  136. const newButton = document.createElement("button");
  137. newButton.id = "TTDown";
  138. newButton.className = "u-button nd-file-list-toolbar-action-item"; // 去掉原有的颜色类名
  139. newButton.style.marginRight = "8px";
  140. newButton.style.backgroundColor = "red"; // 设置背景颜色为红色
  141. newButton.style.color = "white"; // 设置文字颜色为白色以便更好地显示
  142. newButton.innerText = "TTDown";
  143. toolbar.prepend(newButton);
  144.  
  145. const statusButton = document.createElement("button");
  146. statusButton.id = "TTDownStatus";
  147. statusButton.className = "u-button nd-file-list-toolbar-action-item"; // 去掉原有的颜色类名
  148. statusButton.style.marginRight = "8px";
  149. statusButton.style.backgroundColor = "red"; // 设置背景颜色为红色
  150. statusButton.style.color = "white"; // 设置文字颜色为白色以便更好地显示
  151. statusButton.innerText = "TTDown Status";
  152. toolbar.prepend(statusButton);
  153.  
  154. newButton.addEventListener("click", handleTTDownClick);
  155. statusButton.addEventListener("click", handleTTDownStatusClick);
  156. } else {
  157. setTimeout(AddElement, 100);
  158. }
  159. } else {
  160. console.log("TTDown button already added.");
  161. }
  162. }
  163.  
  164. async function getBdsToken() {
  165. var htmlString = $("html").html();
  166. var regex = /"bdstoken":"(\w+)"/;
  167. var match = regex.exec(htmlString);
  168. console.log("bdstoken:", match ? match[1] : null);
  169. return match ? match[1] : null;
  170. }
  171.  
  172. async function shareFiles(bdstoken, selectedIds) {
  173. const bdpassword = "7777";
  174. console.log("Sharing files with bdstoken:", bdstoken, "selectedIds:", selectedIds, "bdpassword:", bdpassword);
  175. return $.post("https://pan.baidu.com/share/set?channel=chunlei&bdstoken=" + bdstoken, {
  176. period: 1,
  177. pwd: bdpassword,
  178. eflag_disable: true,
  179. channel_list: "[]",
  180. schannel: 4,
  181. fid_list: JSON.stringify(selectedIds)
  182. }).then(response => response);
  183. }
  184.  
  185. function extractShortUrl(link) {
  186. const regex = /https:\/\/pan\.baidu\.com\/s\/([a-zA-Z0-9-_]+)/;
  187. const match = regex.exec(link);
  188. console.log("Extracted short URL:", match ? match[1] : null);
  189. return match ? match[1] : null;
  190. }
  191.  
  192. function callWxlistApi(shorturl, password) {
  193. console.log("Calling Wxlist API with shorturl:", shorturl, "password:", password);
  194. const bdpassword = "7777";
  195. return new Promise((resolve, reject) => {
  196. const url = "https://api.moiu.cn/api/List";
  197. const formParams = {
  198. "surl": shorturl,
  199. "dir": "/",
  200. "password": password,
  201. "pwd": bdpassword
  202. };
  203.  
  204. $.ajax({
  205. type: "POST",
  206. url: url,
  207. data: formParams,
  208. success: function(response) {
  209. console.log("Wxlist API response:", response);
  210. resolve(response);
  211. },
  212. error: function(xhr, status, error) {
  213. console.error("Error calling Wxlist API:", xhr, status, error);
  214. reject({
  215. status: xhr.status,
  216. statusText: xhr.statusText
  217. });
  218. }
  219. });
  220. });
  221. }
  222.  
  223. function extractWxlistData(responseBody) {
  224. const data = responseBody.data;
  225. console.log("Extracted data from Wxlist response:", data);
  226. return {
  227. uk: data.uk,
  228. shareid: data.shareid,
  229. randsk: data.randsk,
  230. list: data.list,
  231. fsidlist: data.list.map(item => item.fs_id.toString()),
  232. size: data.list[0]?.size || 0, // 提取第一个列表项的 size 属性
  233. filename: data.list[0]?.server_filename || 0, // 提取第一个列表项的 size 属性
  234. };
  235. }
  236.  
  237. function postToSaveApi(data, password, userid) {
  238. const requestData = {
  239. fsidlist: JSON.stringify(data.list.map(item => item.fs_id)), // 将 fsidlist 转换为 JSON 字符串
  240. sekey: data.randsk,
  241. uk: data.uk,
  242. shareid: data.shareid,
  243. password,
  244. userid,
  245. size: data.size // 将提取到的 size 作为参数提交
  246. };
  247.  
  248. console.log("Prepared request data for Save API:", requestData);
  249.  
  250. return new Promise((resolve, reject) => {
  251. GM_xmlhttpRequest({
  252. method: "POST",
  253. url: "https://api.moiu.cn/JavaScript/PaiPai/save",
  254. headers: {
  255. "Content-Type": "application/json"
  256. },
  257. data: JSON.stringify(requestData),
  258. onload: function(response) {
  259. const responseData = JSON.parse(response.responseText);
  260. console.log("Save API response:", responseData);
  261. if (responseData.code !== 200) {
  262. Swal.fire("错误", responseData.message, "error");
  263. reject({
  264. status: response.status,
  265. statusText: responseData.message
  266. });
  267. } else {
  268. filelistValue = responseData.data[0].to; // 提取 to 值并保存到 filelistValue 变量中
  269. resolve(responseData.data);
  270. }
  271. },
  272. onerror: function(response) {
  273. const errorMessage = JSON.parse(response.responseText).message || '网络错误';
  274. Swal.fire("错误", errorMessage, "error");
  275. console.error("Error posting to Save API:", response);
  276. reject({
  277. status: response.status,
  278. statusText: errorMessage
  279. });
  280. }
  281. });
  282. });
  283. }
  284.  
  285. function postToDlinkApi(to_fs_id, shareid, surl, password, userid, size) {
  286. const requestData = {
  287. fsidlist: JSON.stringify([to_fs_id]), // 将 to_fs_id 转换为 JSON 字符串数组
  288. filelist: filelistValue, // 直接使用保存的 filelistValue 字符串
  289. shareid,
  290. surl,
  291. password,
  292. userid, // 添加 userid 参数
  293. size // 添加 size 参数
  294. };
  295. console.log("Posting to Dlink API with data:", requestData);
  296.  
  297. return new Promise((resolve, reject) => {
  298. GM_xmlhttpRequest({
  299. method: "POST",
  300. url: "https://api.moiu.cn/JavaScript/PaiPai/dlink",
  301. headers: {
  302. "Content-Type": "application/json"
  303. },
  304. data: JSON.stringify(requestData),
  305. onload: function(response) {
  306. const responseData = JSON.parse(response.responseText);
  307. console.log("Dlink API response:", responseData);
  308. if (responseData.code !== 200) {
  309. Swal.fire("错误", responseData.message, "error");
  310. reject({
  311. status: response.status,
  312. statusText: responseData.message
  313. });
  314. } else {
  315. resolve(responseData.data.dlink);
  316. }
  317. },
  318. onerror: function(response) {
  319. const errorMessage = JSON.parse(response.responseText).message || '网络错误';
  320. Swal.fire("错误", errorMessage, "error");
  321. console.error("Error posting to Dlink API:", response);
  322. reject({
  323. status: response.status,
  324. statusText: errorMessage
  325. });
  326. }
  327. });
  328. });
  329. }
  330.  
  331. async function handleTTDownClick() {
  332. console.log("TTDown button clicked.");
  333. 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");
  334. let selectedIds = Array.from(selectedElements).map(item => item.getAttribute("data-id"));
  335.  
  336. console.log("Selected elements:", selectedElements);
  337. console.log("Selected IDs:", selectedIds);
  338.  
  339. if (selectedIds.length === 0) {
  340. Swal.fire({
  341. showConfirmButton: true,
  342. title: '系统提示',
  343. text: '请选择需要下载的文件',
  344. icon: 'error'
  345. });
  346. return;
  347. }
  348.  
  349. if (selectedIds.length > 1) {
  350. Swal.fire({
  351. showConfirmButton: true,
  352. title: '系统提示',
  353. text: '暂时只能下载一个文件',
  354. icon: 'error'
  355. });
  356. return;
  357. }
  358.  
  359. let selectedItems = Array.from(selectedElements);
  360. if (selectedItems.some(item => item.dataset.isdir === "true") || $('tr.selected img[src*="ceH8M5EZYnGhnBKRceGqmaZXPPw2xbO+1x"]').length > 0) {
  361. Swal.fire({
  362. title: '系统提示',
  363. text: '请不要选择文件夹解析,因为还没学会.',
  364. icon: 'error'
  365. });
  366. return;
  367. }
  368.  
  369. const { value: password } = await Swal.fire({
  370. title: '输入密码',
  371. input: 'password',
  372. inputLabel: '使用前请先关注公众号:冰箱喵 获取验证码吧!',
  373. inputPlaceholder: '密码为了控制流量,理解下',
  374. inputAttributes: {
  375. maxlength: 6,
  376. autocapitalize: 'off',
  377. autocorrect: 'off'
  378. }
  379. });
  380.  
  381. if (!password) {
  382. Swal.fire("提示", "需要密码来继续", "info");
  383. return;
  384. }
  385.  
  386. Swal.fire({
  387. title: "正在获取下载链接...",
  388. onBeforeOpen: () => {
  389. Swal.showLoading();
  390. }
  391. });
  392.  
  393. const bdstoken = await getBdsToken();
  394. if (!bdstoken) {
  395. Swal.fire("错误", "无法获取bdstoken", "error");
  396. return;
  397. }
  398.  
  399. // 获取用户信息
  400. if (!userInfo.uk) {
  401. try {
  402. userInfo = await fetchUserInfo();
  403. console.log("Fetched user info in handleTTDownClick:", userInfo);
  404. } catch (error) {
  405. Swal.fire("错误", "无法获取用户信息", "error");
  406. return;
  407. }
  408. }
  409.  
  410. const shareResponse = await shareFiles(bdstoken, selectedIds);
  411. const shorturl = extractShortUrl(shareResponse.link);
  412.  
  413. if (!shorturl) {
  414. Swal.fire("错误", "无法提取shorturl", "error");
  415. return;
  416. }
  417.  
  418. try {
  419. const wxlistResponse = await callWxlistApi(shorturl, password);
  420. const extractedData = extractWxlistData(wxlistResponse);
  421.  
  422. console.log("Extracted Wxlist Data:", extractedData);
  423.  
  424. if (!extractedData.randsk) {
  425. console.error("randsk is undefined in extracted data");
  426. Swal.fire("错误", "无法提取 randsk", "error");
  427. return;
  428. }
  429.  
  430. const saveResponseData = await postToSaveApi(extractedData, password, userInfo.uk);
  431.  
  432. console.log("Save API Response Data:", saveResponseData);
  433.  
  434. const toFsIdList = saveResponseData.map(item => item.to_fs_id);
  435. const dlinkPromises = toFsIdList.map(to_fs_id => postToDlinkApi(to_fs_id, extractedData.shareid, shorturl, password, userInfo.uk, extractedData.size));
  436.  
  437. const downloadLinks = await Promise.all(dlinkPromises);
  438.  
  439.  
  440. const ua = window.userAgent;
  441.  
  442. Swal.fire({
  443. icon: 'success',
  444. title: '下载链接获取成功',
  445. html: downloadLinks.map(link => `
  446. <div style="border: 1px solid #ddd; padding: 10px; margin-bottom: 10px;">
  447. <a href="${link}" target="_blank">下载链接:${link.substring(0, 50)}...</a>
  448. </div>
  449. `).join('') +
  450. `<div style="border: 1px solid #ddd; padding: 10px; margin-top: 10px;">当前下载UA: netdisk;TTdown;svip</div>`,
  451. showCancelButton: true,
  452. cancelButtonText: '取消',
  453. confirmButtonText: '复制链接',
  454. showDenyButton: true,
  455. denyButtonText: '发送到 Aria2',
  456. preConfirm: async () => {
  457. try {
  458. await navigator.clipboard.writeText(downloadLinks.join('\n'));
  459. Swal.fire("已复制", "下载链接已复制到剪贴板", "success");
  460. } catch (err) {
  461. console.error("Failed to copy: ", err);
  462. Swal.fire("复制失败", "无法将链接复制到剪贴板", "error");
  463. }
  464. }
  465. }).then((result) => {
  466. if (result.isDenied) {
  467. sendToAria2(downloadLinks);
  468. }
  469. });
  470.  
  471. } catch (error) {
  472. Swal.fire("错误", error.statusText || "处理过程中出现错误", "error");
  473. console.error("Error:", error);
  474. }
  475. }
  476.  
  477. function sendToAria2(downloadLinks) {
  478. const aria2Config = {
  479. jsonrpc: "2.0",
  480. method: "aria2.addUri",
  481. id: Date.now(),
  482. params: [
  483. `token:`,
  484. downloadLinks,
  485. {
  486. header: ['User-Agent: netdisk;TTdown;svip']
  487. }
  488. ]
  489. };
  490.  
  491. fetch("http://127.0.0.1:16800/jsonrpc", {
  492. method: "POST",
  493. headers: {
  494. "Content-Type": "application/json"
  495. },
  496. body: JSON.stringify(aria2Config)
  497. })
  498. .then(response => response.json())
  499. .then(data => {
  500. if (data.error) {
  501. console.error("Aria2 Error:", data.error.message);
  502. } else {
  503. console.log("Aria2 Download Added:", data.result);
  504. }
  505. })
  506. .catch(fetchError => {
  507. console.error("Fetch Error:", fetchError);
  508. });
  509. }
  510.  
  511. async function handleTTDownStatusClick() {
  512. Swal.fire("检查中...", "正在检查服务器状态,请稍候...", "info");
  513. GM_xmlhttpRequest({
  514. method: "GET",
  515. url: "https://api.moiu.cn/JavaScript/users/status",
  516. onload: function(response) {
  517. try {
  518. const data = JSON.parse(response.responseText);
  519. const { code, message } = data;
  520. console.log("Server status response:", data);
  521. if (code === 200) {
  522. Swal.fire({
  523. icon: "success",
  524. title: "服务器状态",
  525. text: message,
  526. });
  527. } else if (code === 201) {
  528. Swal.fire({
  529. icon: "error",
  530. title: "服务器状态",
  531. text: message,
  532. });
  533. } else {
  534. Swal.fire({
  535. icon: "warning",
  536. title: "服务器状态",
  537. text: "未知状态",
  538. });
  539. }
  540. } catch (error) {
  541. Swal.fire("错误", "处理服务器响应时发生错误", "error");
  542. console.error("Error handling server response:", error);
  543. }
  544. },
  545. onerror: function(error) {
  546. Swal.fire("错误", "无法连接到服务器", "error");
  547. console.error("Error connecting to server:", error);
  548. },
  549. });
  550. }
  551.  
  552. // 在页面加载完成后请求用户信息
  553. getUserInfoOnPageLoad();
  554. // 本代码由KDown原作者XiaoMo授权二次分发,希望管理不要误会!
  555. })();