(改)网盘直链下载助手

一个基于 JavaScript 的网盘文件下载地址获取工具,支持 百度网盘/阿里云盘/天翼云盘/迅雷云盘/夸克网盘/移动网盘 六大网盘 | 基于【网盘直链下载助手】修改自6.2.7版本 | 开源 - 自用 - 去广 | 改界面 - 添功能 - 修Bug | 不仅能够精简网盘界面 还支持修改网盘界面主题颜色!

当前为 2024-10-14 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name (改)网盘直链下载助手
  3. // @namespace https://github.com/syhyz1990/baiduyun
  4. // @version 1.0.9.5
  5. // @author Hmjz100、油小猴
  6. // @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNMTAzLjYgMTA3LjRjMy41LTIuMiA4LjktNi4xIDEzLjgtMTIuNXM3LjMtMTIuNSA4LjUtMTYuNWMuNS0xLjcgMi4yLTcuNSAyLjItMTQuNyAwLTEwLjEtMy4zLTI1LjEtMTUuNC0zNi44LTE0LjUtMTQtMzIuMS0xNC4zLTM1LjctMTQuMy04IDAtMTUuNyAxLjktMjIuNiA1LjJDNDQgMjMgMzUuNyAzMS40IDMwLjggNDEuN2MtMS4zIDIuOC00IDQuNy03LjEgNS00IC4zLTcuNSA0LjQtOC45IDkuNi0uNSAxLjktMS42IDMuNS0zLjEgNC43QzQuNCA2Ni44IDAgNzUuNyAwIDg1YzAgNi44IDIuMyAxMy4xIDYuMSAxOC4yIDUuNSA3LjQgMTQuMiAxMi4yIDI0IDEyLjJoNDcuMWM0LjQgMCAxMS0uNSAxOC4zLTMuNSAzLjItMS40IDUuOS0zIDguMS00LjV6IiBmaWxsPSIjQTA5OUYwIi8+PHBhdGggZD0iTTExOS44IDY0LjNjLjEtMTcuMS0xMC40LTI4LTEyLjUtMzAuMUM5NSAyMi4xIDc5LjkgMjEuOCA3Ni45IDIxLjhjLTE3LjYgMC0zMy4zIDEwLjUtMzkuOSAyNi43LS42IDEuMy0xLjggMi4zLTMuNCAyLjNoLS40Yy01LjggMC0xMC42IDQuOC0xMC42IDEwLjd2LjVjMCAxLjQtLjggMi42LTEuOSAzLjNDMTMuNCA2OSA4LjggNzYuOCA4LjggODVjMCAxMi4yIDkuOSAyMi4zIDIyLjIgMjIuM2g0NS4yYzMuNi0uMSAxNy42LS45IDI5LjYtMTIgMi45LTIuOCAxMy45LTEzLjcgMTQtMzF6IiBmaWxsPSIjNTc0QUI4Ii8+PHBhdGggZD0iTTExMC44IDU3LjRsLjIgMy4zYzAgMS4zLTEuMSAyLjQtMi4zIDIuNC0xLjMgMC0yLjMtMS4xLTIuMy0yLjRsLS4xLTIuOHYtLjNjMC0xLjIuOS0yLjIgMi4xLTIuM2guM2MuNyAwIDEuMy4zIDEuNy43LS4yLjEuMy41LjQgMS40em0tMy4zLTEwLjNjMCAxLjItMSAyLjMtMi4yIDIuM2gtLjFjLS44IDAtMS42LS41LTItMS4yLTQuNi04LjMtMTMuMy0xMy41LTIyLjgtMTMuNS0xLjIgMC0yLjMtMS0yLjMtMi4ydi0uMWMwLTEuMiAxLTIuMyAyLjItMi4zaC4xYTMwLjM3IDMwLjM3IDAgMCAxIDE1LjggNC40YzQuNiAyLjggOC40IDYuOCAxMS4xIDExLjUuMS4zLjIuNy4yIDEuMXpNODguMyA3My44TDczLjUgOTMuMmMtMS41IDEuOS0zLjUgMy4xLTUuNyAzLjVoLS4yYy0uNC4xLS44LjEtMS4yLjEtLjYgMC0xLjEtLjEtMS42LS4yLTIuMi0uNC00LjItMS43LTUuNi0zLjVMNDQuMyA3My45Yy0yLTIuNi0yLjUtNS40LTEuNC03LjcuMS0uMS4xLS4yLjItLjIgMS4yLTIgMy41LTMuMiA2LjQtMy4yaDYuNnYtNS43YzAtNi44IDQuNy0xMiAxMC45LTEyIDQuOCAwIDguNSAyLjYgMTAuMyA3LjIuNSAxLjMtLjIgMi43LTEuNSAzLjJzLTIuOC0uMS0zLjMtMS40Yy0xLjEtMi43LTIuOS00LTUuNS00LTMuNSAwLTYgMy02IDd2OC4xYzAgLjUtLjIgMS0uNiAxLjQtLjYuNy0xLjcgMS4xLTIuNiAxLjFoLTguNGMtMS4zIDAtMiAuNC0yLjEuNy0uMi40IDAgMS4zLjkgMi40TDYzLjEgOTBjLjkgMS4yIDIuMSAxLjggMy4zIDEuOHMyLjMtLjYgMy4xLTEuN2wxNC44LTE5LjNjLjktMS4xIDEuMS0yIC45LTIuNC0uMi0uMy0uOS0uNy0yLjEtLjdoLTcuNmMtLjkgMC0xLjctLjUtMi4xLTEuMi0uMy0uNC0uNC0uOC0uNC0xLjMgMC0xLjQgMS4xLTIuNSAyLjUtMi41aDcuNmMzLjEgMCA1LjUgMS4zIDYuNiAzLjVsLjMuN2MuNyAyLjEuMSA0LjYtMS43IDYuOXoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=
  7. // @description 一个基于 JavaScript 的网盘文件下载地址获取工具,支持 百度网盘/阿里云盘/天翼云盘/迅雷云盘/夸克网盘/移动网盘 六大网盘 | 基于【网盘直链下载助手】修改自6.2.7版本 | 开源 - 自用 - 去广 | 改界面 - 添功能 - 修Bug | 不仅能够精简网盘界面 还支持修改网盘界面主题颜色!
  8. // @license AGPL-3.0-or-later
  9. // @homepage https://github.com/hmjz100/Online-disk-direct-link-download-assistant/
  10. // @support https://github.com/hmjz100/Online-disk-direct-link-download-assistant/issues
  11. // @supportURL https://github.com/hmjz100/Online-disk-direct-link-download-assistant/issues
  12. // @require https://unpkg.com/jquery@3.6.0/dist/jquery.min.js
  13. // @require https://unpkg.com/sweetalert2@11/dist/sweetalert2.min.js
  14. // @require https://unpkg.com/js-md5@0.7.3/build/md5.min.js
  15. // @resource Swal https://unpkg.com/sweetalert2@11/dist/sweetalert2.min.css
  16. // @resource SwalDark https://unpkg.com/@sweetalert2/theme-dark@5/dark.min.css
  17. // @run-at document-body
  18. // @match *://pan.baidu.com/disk/home*
  19. // @match *://yun.baidu.com/disk/home*
  20. // @match *://pan.baidu.com/disk/timeline*
  21. // @match *://yun.baidu.com/disk/timeline*
  22. // @match *://pan.baidu.com/disk/main*
  23. // @match *://yun.baidu.com/disk/main*
  24. // @match *://pan.baidu.com/youth/pan/main*
  25. // @match *://yun.baidu.com/youth/pan/main*
  26. // @match *://pan.baidu.com/disk/base*
  27. // @match *://yun.baidu.com/disk/base*
  28. // @match *://pan.baidu.com/pfile/*
  29. // @match *://yun.baidu.com/pfile/*
  30. // @match *://pan.baidu.com/s/*
  31. // @match *://pan.baidu.com/aipan/*
  32. // @match *://yun.baidu.com/s/*
  33. // @match *://yun.baidu.com/aipan/*
  34. // @match *://pan.baidu.com/share/*
  35. // @match *://yun.baidu.com/share/*
  36. // @match *://openapi.baidu.com/*
  37. // @match *://www.aliyundrive.com/s/*
  38. // @match *://www.aliyundrive.com/drive*
  39. // @match *://www.alipan.com/s/*
  40. // @match *://www.alipan.com/drive*
  41. // @match *://cloud.189.cn/web/*
  42. // @match *://pan.xunlei.com/*
  43. // @match *://pan.quark.cn/*
  44. // @match *://yun.139.com/*
  45. // @match *://caiyun.139.com/*
  46. // @match *://*.youxiaohou.com/*
  47. // @connect baidu.com
  48. // @connect baidupcs.com
  49. // @connect aliyundrive.com
  50. // @connect aliyundrive.net
  51. // @connect alipan.com
  52. // @connect alicloudccp.com
  53. // @connect 189.cn
  54. // @connect xunlei.com
  55. // @connect quark.cn
  56. // @connect youxiaohou.com
  57. // @connect gf.qytechs.cn
  58. // @connect gcore.jsdelivr.net
  59. // @connect localhost
  60. // @connect *
  61. // @grant unsafeWindow
  62. // @grant window.close
  63. // @grant GM_xmlhttpRequest
  64. // @grant GM.xmlhttpRequest
  65. // @grant GM_setClipboard
  66. // @grant GM_setValue
  67. // @grant GM_getValue
  68. // @grant GM_deleteValue
  69. // @grant GM_openInTab
  70. // @grant GM_info
  71. // @grant GM_registerMenuCommand
  72. // @grant GM_cookie
  73. // @grant GM_getResourceText
  74. // @compatible Chrome
  75. // @compatible Edge
  76. // @compatible Firefox
  77. // @compatible Safari
  78. // @compatible Opera
  79. // ==/UserScript==
  80.  
  81. (function Panlinker() {
  82. 'use strict';
  83.  
  84. /*
  85. 防止代码因其他原因被执行多次
  86. 这段代码出自 Via轻插件,作者谷花泰
  87. */
  88. const key = encodeURIComponent('(改)网盘直链下载助手:主代码');
  89. if (window[key]) return;
  90. window[key] = true;
  91.  
  92. /*
  93. 网盘直链下载助手
  94. 以下代码均改自 网盘直链下载助手,作者油小猴
  95. */
  96. /* 全局参数 */
  97. let pt = '', selectList = [], params = {}, mode = '', width = '', pan = {}, color = '',
  98. doc = $(document), progress = {}, request = {}, ins = {}, idm = {}, colored = false,
  99. scriptInfo = GM_info.script,
  100. realauthor = scriptInfo.author,
  101. realname = scriptInfo.name,
  102. realversion = scriptInfo.version,
  103. manageHandler = GM_info.scriptHandler,
  104. manageVersion = GM_info.version;
  105.  
  106.  
  107. /* 设置选项 */
  108. // Shell类型(用于curl下载)
  109. let terminalType = {
  110. wc: "Microsoft Windows 命令提示符",
  111. wp: "Microsoft Windows PowerShell",
  112. lt: "Linux 终端",
  113. ls: "Linux Shell",
  114. mt: "Apple MacOS 终端",
  115. };
  116.  
  117. // 使用油小猴服务器
  118. let monkeyServer = {
  119. v1: "使用 [用油小猴服务器 V1 接口]",
  120. v2: "使用 [用油小猴服务器 V2 接口]",
  121. no: "不使用 [用 jsdelivr 连接本项目 Github 仓库]"
  122. };
  123.  
  124. // 更换 百度网盘新界面/阿里云盘/迅雷云盘/移动云盘 主题颜色
  125. let assistantTheme = {
  126. yes: "更换主题颜色",
  127. no: "不更换主题颜色"
  128. };
  129.  
  130. /* Sweet Alert 2 */
  131. // 自定义元素 Class 名(于 showMainDialog() 中)
  132. let customClass = {
  133. popup: 'pl-popup',
  134. header: 'pl-header',
  135. title: 'pl-title',
  136. closeButton: 'pl-close',
  137. content: 'pl-content',
  138. input: 'pl-input',
  139. footer: 'pl-footer'
  140. };
  141.  
  142. // Toast 提示配置
  143. let toast = Swal.mixin({
  144. toast: true,
  145. position: 'top-end',
  146. showConfirmButton: false,
  147. timer: 3500,
  148. timerProgressBar: true,
  149. showCloseButton: true,
  150. didOpen: function (toast) {
  151. toast.addEventListener('mouseenter', Swal.stopTimer);
  152. toast.addEventListener('mouseleave', Swal.resumeTimer);
  153. }
  154. });
  155.  
  156. // Toast 简易调用
  157. let message = {
  158. success: function (text) {
  159. toast.fire({ title: text, icon: 'success' });
  160. },
  161. error: function (text) {
  162. toast.fire({ title: text, icon: 'error' });
  163. },
  164. warning: function (text) {
  165. toast.fire({ title: text, icon: 'warning' });
  166. },
  167. info: function (text) {
  168. toast.fire({ title: text, icon: 'info' });
  169. },
  170. question: function (text) {
  171. toast.fire({ title: text, icon: 'question' });
  172. }
  173. };
  174.  
  175. /* 基础函数 */
  176. let base = {
  177. // 创建 GreaseMonkey 菜单
  178. registerMenuCommand() {
  179. GM_registerMenuCommand('⚙️ 设置', function () {
  180. base.showSetting();
  181. });
  182. GM_registerMenuCommand('🍃️ 美化', function () {
  183. base.showBeautify();
  184. });
  185. GM_registerMenuCommand('📃 更新', function () {
  186. base.showUpdateLog();
  187. });
  188. GM_registerMenuCommand('🛠️ 调试', function () {
  189. base.showDebug();
  190. });
  191. },
  192.  
  193. // 取消注册(不可用)
  194. unRegisterInit(value) {
  195. message.warning("正在注入设置项目...");
  196. base.setValue('setting_init_code', value);
  197. base.setValue('setting_init_license', value);
  198. history.go(0)
  199. },
  200.  
  201. /*-- 对象类型判断
  202. 示例:
  203. isType([]) // 输出"array"
  204. isType(123) // 输出"number"
  205. isType(null) // 输出"null"
  206. isType(new Date()) // 输出"date"
  207. */
  208. isType(obj) {
  209. return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
  210. },
  211.  
  212.  
  213. // 获取本地保存的数值(仅用于 Greasemonkey)
  214. getValue(name) {
  215. return GM_getValue(name);
  216. },
  217.  
  218. // 增改本地保存的数值(仅用于 Greasemonkey)
  219. setValue(name, value) {
  220. GM_setValue(name, value);
  221. },
  222.  
  223. // 删除本地保存的数值(仅用于 Greasemonkey)
  224. deleteValue(name) {
  225. GM_deleteValue(name);
  226. },
  227.  
  228. // 获取本地保存的数值
  229. getStorage(key) {
  230. try {
  231. return JSON.parse(localStorage.getItem(key));
  232. } catch (e) {
  233. return localStorage.getItem(key);
  234. }
  235. },
  236.  
  237. // 修改本地保存的数值
  238. setStorage(key, value) {
  239. if (this.isType(value) === 'object' || this.isType(value) === 'array') {
  240. return localStorage.setItem(key, JSON.stringify(value));
  241. }
  242. return localStorage.setItem(key, value);
  243. },
  244.  
  245. // 设置剪贴板
  246. setClipboard(text) {
  247. GM_setClipboard(text, 'text');
  248. },
  249.  
  250. // 加密成base64(先转换成URL编码)
  251. encode(str) {
  252. return btoa(unescape(encodeURIComponent(str)));
  253. },
  254.  
  255. // 从base64解密
  256. decode(str) {
  257. return decodeURIComponent(escape(atob(str)));
  258. },
  259.  
  260. // 数字补零
  261. repairTimer(i) {
  262. if (i >= 0 && i <= 9) {
  263. return "0" + i;
  264. } else {
  265. return i;
  266. }
  267. },
  268.  
  269. // 接受文件名并返回大写扩展名
  270. getExtension(name) {
  271. const reg = /(?!\.)\w+$/;
  272. if (reg.test(name)) {
  273. let match = name.match(reg);
  274. return match[0].toUpperCase();
  275. }
  276. return '';
  277. },
  278.  
  279. // 文件大小转换(以字节为单位)
  280. sizeFormat(value) {
  281. if (value === +value) {
  282. let unit = ["字节(B)", "千字节(KB)", "兆字节(MB)", "吉字节(GB)", "太字节(TB)", "拍字节(PB)", "艾字节(EB)", "泽字节(ZB)", "尧字节(YB)"];
  283. if (value === 0) {
  284. return "0字节(B)";
  285. } else {
  286. let index = Math.floor(Math.log(value) / Math.log(1024));
  287. let size = value / Math.pow(1024, index);
  288. size = size.toFixed(1);
  289. return size + unit[index];
  290. }
  291. }
  292. return '';
  293. },
  294.  
  295. // 根据数组中的每个文件名进行排序,使用 localeCompare 方法来比较中文字符串的顺序。
  296. sortByName(arr) {
  297. const handle = function () {
  298. return (a, b) => {
  299. const p1 = a.filename ? a.filename : a.server_filename;
  300. const p2 = b.filename ? b.filename : b.server_filename;
  301. return p1.localeCompare(p2, "zh-CN");
  302. };
  303. };
  304. arr.sort(handle());
  305. },
  306.  
  307. // 替换特殊字符为下划线
  308. fixFilename(name) {
  309. let replace = /[!?&|`"'*\/:<>\\]/g
  310. return name.replace(replace, '_');
  311. },
  312.  
  313. // 传递 Document Cookie
  314. getCookie(name) {
  315. let cname = name + "=";
  316. let ca = document.cookie.split(';');
  317. for (let i = 0; i < ca.length; i++) {
  318. let c = ca[i].trim();
  319. if (c.indexOf(cname) == 0) return c.substring(cname.length, c.length);
  320. }
  321. return "";
  322. },
  323.  
  324. // 接受Blob对象和文件名,然后创建临时链接指向blob对象,之后创建a标签指向临时链接和设置文件名,最后模拟点击a标签实现下载和释放临时链接
  325. blobDownload(blob, filename) {
  326. if (blob instanceof Blob) {
  327. const url = URL.createObjectURL(blob);
  328. const a = document.createElement('a');
  329. a.href = url;
  330. a.download = filename;
  331. a.click();
  332. URL.revokeObjectURL(url);
  333. }
  334. },
  335.  
  336. xmlHttpRequest(option) {
  337. // 检查 GM_xmlhttpRequest 是否可用,并使用可用的请求方式
  338. let request = (typeof GM_xmlhttpRequest !== "undefined") ? GM_xmlhttpRequest : GM.xmlHttpRequest;
  339. // 调用请求函数并传入 option
  340. if (request && typeof request === 'function') {
  341. return request(option);
  342. }
  343. },
  344.  
  345. /* 请求 */
  346. // 使用 Post 发送请求
  347. post(url, data, headers, type, maxRetries = 3, currentRetry = 0) {
  348. if (this.isType(data) === 'object') {
  349. data = JSON.stringify(data);
  350. }
  351. return new Promise((resolve, reject) => {
  352. const sendRequest = function () {
  353. base.xmlHttpRequest({
  354. method: "POST", url, headers, data,
  355. responseType: type || 'json',
  356. onloadstart() {
  357. console.log('【(改)网盘直链下载助手】Post(start)\n请求地址:' + url + '\n请求头部:', headers);
  358. },
  359. onload: function (res) {
  360. // 尝试格式化请求结果以方便调试
  361. if (res.response) {
  362. try {
  363. res.decodedResponse = JSON.parse(res.response);
  364. } catch (e) { }
  365. try {
  366. res.decodedResponse = JSON.parse(base.decode(res.response));
  367. } catch (e) { }
  368. }
  369. if (res.responseText) {
  370. try {
  371. res.decodedResponseText = JSON.stringify(res.responseText);
  372. } catch (e) { }
  373. try {
  374. res.decodedResponseText = JSON.stringify(base.decode(res.responseText));
  375. } catch (e) { }
  376. }
  377. console.log('【(改)网盘直链下载助手】Post(load)\n请求地址:' + url + '\n请求头部:', headers, '\n请求数据:' + JSON.stringify(data) + '\n请求结果:', res);
  378. type === 'blob' ? resolve(res) : resolve(res.response || res.responseText);
  379. },
  380. onerror: function (err) {
  381. if (currentRetry < maxRetries) {
  382. currentRetry++;
  383. console.error(`【(改)网盘直链下载助手】Post(error)\n请求出现错误,可能是网络问题\n5秒后将重试 (错误次数:${currentRetry}/${maxRetries})...`, err);
  384. setTimeout(function () {
  385. console.log(`【(改)网盘直链下载助手】Post(error)\n重新尝试请求...`);
  386. sendRequest(); // 重新发送请求
  387. }, 5000)
  388. } else {
  389. reject('【(改)网盘直链下载助手】Post(error)\n请求出现错误,可能是网络问题\n无法继续请求,达到最大错误次数。', err); // 达到最大重试次数,拒绝 Promise
  390. }
  391. },
  392. });
  393. };
  394. sendRequest(); // 初始请求
  395. });
  396. },
  397.  
  398. // 使用 Get 发送请求
  399. get(url, headers, type, extra, maxRetries = 3, currentRetry = 0) {
  400. return new Promise((resolve, reject) => {
  401. const sendRequest = function () {
  402. let requestObj = base.xmlHttpRequest({
  403. method: "GET", url, headers,
  404. responseType: type || 'json',
  405. onload: function (res) {
  406. if (res.status === 204) {
  407. console.log('【(改)网盘直链下载助手】Get(load)\n\x1B[31m该请求已被某个下载工具捕获。' + (res.statusText ? ("\n\x1B[0m工具提示:\x1B[31m" + res.statusText) : "") + '\x1B[0m\n请求地址:' + url + '\n请求头部:', headers, '\n请求结果:', res);
  408. requestObj.abort();
  409. idm[extra.index] = true;
  410. return;
  411. }
  412. if (type === 'blob') {
  413. console.log('【(改)网盘直链下载助手】Get(load) Blob\n请求地址:' + url + '\n请求头部:', headers, '\n请求结果:', res);
  414. res.status === 200 && base.blobDownload(res.response, extra.filename);
  415. resolve(res);
  416. } else {
  417. // 尝试格式化请求结果以方便调试
  418. if (res.response) {
  419. try {
  420. res.decodedResponse = JSON.parse(res.response);
  421. } catch (e) { }
  422. try {
  423. res.decodedResponse = JSON.parse(base.decode(res.response));
  424. } catch (e) { }
  425. }
  426. if (res.responseText) {
  427. try {
  428. res.decodedResponseText = JSON.stringify(res.responseText);
  429. } catch (e) { }
  430. try {
  431. res.decodedResponseText = JSON.stringify(base.decode(res.responseText));
  432. } catch (e) { }
  433. }
  434. console.log('【(改)网盘直链下载助手】Get(load)\n请求地址:' + url + '\n请求头部:', headers, '\n请求结果:', res);
  435. resolve(res.response || res.responseText);
  436. }
  437. },
  438. onprogress: function (res) {
  439. if (res.status === 204) {
  440. console.log('【(改)网盘直链下载助手】Get(progress)\n\x1B[31m该请求已被某个下载工具捕获。' + (res.statusText ? ("\n\x1B[0m工具提示:\x1B[31m" + res.statusText) : "") + '\x1B[0m\n请求地址:' + url + '\n请求头部:', headers, '\n请求结果:', res);
  441. requestObj.abort();
  442. idm[extra.index] = true;
  443. return;
  444. }
  445. if (extra && extra.filename && extra.index) {
  446. res.total > 0 ? progress[extra.index] = (res.loaded * 100 / res.total).toFixed(2) : progress[extra.index] = 0.00;
  447. console.log('【(改)网盘直链下载助手】Get(progress)\n\x1B[31m该请求正在进行中。' + (progress[extra.index] ? ("\n\x1B[0m下载进度:\x1B[31m" + progress[extra.index]) : "") + '\x1B[0m');
  448. }
  449. },
  450. onloadstart(res) {
  451. if (res.status === 204) {
  452. console.log('【(改)网盘直链下载助手】Get(start)\n\x1B[31m该请求已被某个下载工具捕获。' + (res.statusText ? ("\n\x1B[0m工具提示:\x1B[31m" + res.statusText) : "") + '\x1B[0m\n请求地址:' + url + '\n请求头部:', headers, '\n请求结果:', res);
  453. requestObj.abort();
  454. idm[extra.index] = true;
  455. return;
  456. }
  457. console.log('【(改)网盘直链下载助手】Get(start)\n请求地址:' + url + '\n请求头部:', headers);
  458. if (extra && extra.filename && extra.index) request[extra.index] = requestObj;
  459. },
  460. onerror: function (err) {
  461. if (currentRetry < maxRetries) {
  462. currentRetry++;
  463. console.error(`【(改)网盘直链下载助手】Get(error)\n请求出现错误,可能是网络问题\n5秒后将重试 (错误次数:${currentRetry}/${maxRetries})...`, err);
  464. setTimeout(function () {
  465. console.log(`【(改)网盘直链下载助手】Get(error)\n重新尝试请求...`);
  466. sendRequest(); // 重新发送请求
  467. }, 5000)
  468. } else {
  469. reject('【(改)网盘直链下载助手】Get(error)\n请求出现错误,可能是网络问题\n无法继续请求,达到最大错误次数。', err); // 达到最大重试次数,拒绝 Promise
  470. }
  471. },
  472. });
  473. };
  474.  
  475. sendRequest(); // 初始请求
  476. });
  477. },
  478.  
  479. // 使用 Get 发送请求获取跳转后的链接
  480. getFinalUrl(url, headers, maxRetries = 3, currentRetry = 0) {
  481. return new Promise((resolve, reject) => {
  482. const sendRequest = function () {
  483. let requestObj = base.xmlHttpRequest({
  484. method: "GET", url, headers,
  485. onloadstart() {
  486. console.log('【(改)网盘直链下载助手】Get(start) FinalUrl\n请求地址:' + url + '\n请求头部:', headers);
  487. },
  488. onload: function (res) {
  489. console.log('【(改)网盘直链下载助手】Get(load) FinalUrl\n请求地址:' + url + '\n请求头部:', headers, '\n返回结果:', res);
  490. resolve(res.finalUrl)
  491. },
  492. onerror: function (err) {
  493. if (currentRetry < maxRetries) {
  494. currentRetry++;
  495. console.error(`【(改)网盘直链下载助手】Get(error) FinalUrl\n请求出现错误,可能是网络问题\n5秒后将重试 (错误次数:${currentRetry}/${maxRetries})...`);
  496. setTimeout(function () {
  497. console.log(`【(改)网盘直链下载助手】Get(error) FinalUrl\n重新尝试请求...`);
  498. sendRequest(); // 重新发送请求
  499. }, 5000)
  500. } else {
  501. reject('【(改)网盘直链下载助手】Get(error) FinalUrl\n请求出现错误,可能是网络问题\n无法继续请求,达到最大错误次数。', err); // 达到最大重试次数,拒绝 Promise
  502. }
  503. },
  504. });
  505. };
  506. sendRequest(); // 初始请求
  507. });
  508. },
  509.  
  510. // RPC测试
  511. async rpcTest(domain, port, path, token) {
  512. return new Promise((resolve, reject) => {
  513. let rpc = { domain, port, path, token };
  514. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  515. let rpcData = {
  516. id: new Date().getTime(),
  517. jsonrpc: '2.0',
  518. method: 'system.listMethods',
  519. params: [`token:${rpc.token}`],
  520. };
  521. base.xmlHttpRequest({
  522. method: "POST", url, headers: {}, data: JSON.stringify(rpcData),
  523. responseType: 'json',
  524. onloadstart() {
  525. console.log('【(改)网盘直链下载助手】Post(start) RPCTest\n请求地址:' + url + '\n请求内容:', rpcData);
  526. },
  527. onload: function (res) {
  528. console.log('【(改)网盘直链下载助手】Post(load) RPCTest\n请求地址:' + url + '\n请求结果:', res);
  529. if (res.response) {
  530. resolve("success");
  531. } else {
  532. resolve("fail");
  533. }
  534. },
  535. onerror: function (err) {
  536. console.error('【(改)网盘直链下载助手】Post(error) RPCTest\n请求失败', err);
  537. resolve("fail");
  538. },
  539. });
  540. });
  541. },
  542.  
  543. _resetData() {
  544. progress = {};
  545. $.each(request, function (key) {
  546. (request[key]).abort();
  547. });
  548. $.each(ins, function (key) {
  549. clearInterval(ins[key]);
  550. });
  551. idm = {};
  552. ins = {};
  553. request = {};
  554. },
  555.  
  556. // 将对象转换为 URL 加密
  557. stringify(obj) {
  558. let str = '';
  559. for (let key in obj) {
  560. if (obj.hasOwnProperty(key)) {
  561. let value = obj[key];
  562. if (Array.isArray(value)) {
  563. for (let i = 0; i < value.length; i++) {
  564. str += encodeURIComponent(key) + '=' + encodeURIComponent(value[i]) + '&';
  565. }
  566. } else {
  567. str += encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&';
  568. }
  569. }
  570. }
  571. return str.slice(0, -1); // 去掉末尾的 "&"
  572. },
  573.  
  574. // 动态添加样式
  575. addStyle(id, tag, css, element, position = "append") {
  576. tag = tag || 'style';
  577. element = element || 'body';
  578. let styleDom = document.getElementById(id);
  579. if (styleDom) styleDom.remove();
  580. let style = document.createElement(tag);
  581. style.rel = 'stylesheet';
  582. style.id = id;
  583. tag === 'style' ? style.innerHTML = css : style.href = css;
  584. if (position === "before") {
  585. $(element).before($(style));
  586. } else if (position === "after") {
  587. $(element).after($(style));
  588. } else if (position === "prepend") {
  589. $(element).prepend($(style));
  590. } else {
  591. $(element).append($(style));
  592. }
  593. },
  594.  
  595. hexToRgba(hex) {
  596. // 去掉 # 号
  597. hex = hex.replace(/^#/, '');
  598. // 如果是四位十六进制颜色值,转换为八位
  599. if (hex.length === 4) {
  600. hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3];
  601. }
  602. // 解析 RGB 分量
  603. let r = parseInt(hex.substring(0, 2), 16);
  604. let g = parseInt(hex.substring(2, 4), 16);
  605. let b = parseInt(hex.substring(4, 6), 16);
  606. let a = '';
  607. // 如果是八位十六进制颜色值,解析 alpha 通道
  608. if (hex.length === 8) {
  609. let a = 1;
  610. a = parseInt(hex.substring(6, 8), 16) / 255; // 将 alpha 值转换为 0 到 1 之间的小数
  611. a = ',' + a
  612. }
  613. // 返回 rgba 格式字符串
  614. return r + ', ' + g + ', ' + b + a;
  615. },
  616.  
  617. replaceColors(cssText, baseURI, type, colorMap) {
  618. if (!cssText) return '';
  619. let colorList = ['#09AAFF', '#cc3235', '#518c17', '#ed944b', '#f969a5', '#bca280', '#574AB8', '#b673ab', '#1d2327', '#18a497', '#637dff', '#0d53ff', '#3181f9', '#f8d800', '#0396ff', '#32ccbc', '#f6416c', '#2271b1', '#59524c', '#ff679a', '#f44236', '#fec107', '#8bc24a', '#2594ed', '#9c28b1']
  620. colorList.forEach(function (oldColor) {
  621. cssText = cssText.replace(new RegExp(base.hexToRgba(oldColor), 'ig'), base.hexToRgba(color));
  622. cssText = cssText.replace(new RegExp(oldColor, 'ig'), color);
  623. });
  624. if (type === 'other') {
  625. // 遍历颜色映射数组,将旧颜色替换为新颜色,并添加过渡效果
  626. colorMap.forEach(function (colorPair) {
  627. let oldColor = colorPair[0];
  628. let newColor = colorPair[1];
  629. // 判断新颜色是否为 color
  630. cssText = cssText.replace(new RegExp(oldColor, 'ig'), newColor);
  631. });
  632. return cssText;
  633. }
  634. if (colorMap) {
  635. // 遍历颜色映射数组,将旧颜色替换为新颜色,并添加过渡效果
  636. colorMap.forEach(function (colorPair) {
  637. let oldColor = colorPair[0];
  638. let newColor = colorPair[1];
  639. // 判断新颜色是否为 color
  640. if (oldColor.includes("#")) {
  641. cssText = cssText.replace(new RegExp(oldColor + '(.*?)}', 'ig'), newColor + '$1; ' + 'transition: all 0.1s ease;}');
  642. } else {
  643. cssText = cssText.replace(new RegExp(oldColor, 'ig'), newColor);
  644. }
  645. });
  646. };
  647. if (baseURI) {
  648. // 替换相对路径资源为绝对路径
  649. cssText = cssText.replace(/url\(\s*(['"]?)([^'"]*?)\1\s*\)/ig, function (match, quote, url) {
  650. // 如果 URL 是相对路径,则将其转换为绝对路径
  651. if (url && !/^(data:|https?:|\/\/)/i.test(url)) {
  652. try {
  653. let absoluteURL = new URL(url, baseURI).href;
  654. return 'url(' + absoluteURL + ')';
  655. } catch (e) {
  656. return match; // 如果URL无效,保留原始的匹配
  657. }
  658. }
  659. return match; // 保留已经是绝对路径的情况
  660. });
  661. }
  662. return cssText;
  663. },
  664.  
  665. setColors(colorMap, type) {
  666. let cssText
  667. document.querySelectorAll('[id^="Panlinker-ColorUI-"]').forEach(function (tag) {
  668. if (!tag.parentElement) return;
  669. // 替换颜色并添加样式
  670. if (
  671. tag.innerText === base.replaceColors(tag.innerText, '', type, colorMap)
  672. ) return;
  673. cssText = base.replaceColors(tag.innerText, '', type, colorMap);
  674. tag.innerText = cssText;
  675. console.log(`【(改)网盘直链下载助手】UI\n修改 Panlinker-ColorUI <style> 元素 样式\n元素:`, tag);
  676. });
  677. let count = 0;
  678. if (!colored) {
  679. base.waitForKeyElements('link[rel="stylesheet"]', function (tag) {
  680. if (!tag.parent() || !tag.attr('href')) return;
  681. let href = tag.attr('href')
  682. fetch(href)
  683. .then(response => response.text())
  684. .then(responseText => {
  685. let id = 'Panlinker-ColorUI-' + href
  686. // 替换颜色并添加样式
  687. cssText = base.replaceColors(responseText, href, type, colorMap);
  688. if (responseText === base.replaceColors(responseText, '', type, colorMap)) return;
  689. base.addStyle(id, 'style', cssText, tag[0], "after");
  690. let newStyle = document.querySelector(`[id="${id}"]`)
  691. console.log(`【(改)网盘直链下载助手】UI\n<link> 元素 <style> 元素 样式\n元素:`, tag[0], `\n样式:`, newStyle);
  692. });
  693. })
  694. base.waitForKeyElements('style:not([id^="Panlinker-"],[id^="swal-pub"],[class^="darkreader"])', function (tag) {
  695. if (!tag.parent()) return;
  696. let id = tag[0].id;
  697. let text = tag.text()
  698. // 替换颜色并添加样式
  699. if (text === base.replaceColors(text, '', type, colorMap)) return;
  700. id = id ? id : `Panlinker-ColorUI-${count++}`
  701. cssText = base.replaceColors(text, '', type, colorMap);
  702. base.addStyle(id, 'style', cssText, tag[0], "after");
  703. let newStyle = document.querySelector(`[id="${id}"]`)
  704. console.log(`【(改)网盘直链下载助手】UI\n修改 <style> 元素 样式\n元素:`, newStyle);
  705. })
  706. base.waitForKeyElements('svg', function (element) {
  707. element.find('*').each(function () {
  708. let fill = $(this).attr('fill');
  709. let stroke = $(this).attr('stroke');
  710. if (fill) {
  711. let newFill = base.replaceColors(fill, '', type, colorMap);
  712. if (newFill !== fill) {
  713. $(this).attr('fill', newFill);
  714. console.log(`【(改)网盘直链下载助手】UI\n修改 <svg> 元素 样式\n元素:`, $(this)[0]);
  715. }
  716. }
  717. if (stroke) {
  718. let newStroke = base.replaceColors(stroke, '', type, colorMap);
  719. if (newStroke !== stroke) {
  720. $(this).attr('stroke', newStroke);
  721. console.log(`【(改)网盘直链下载助手】UI\n修改 <svg> 元素 样式\n元素:`, $(this)[0]);
  722. }
  723. }
  724. });
  725. });
  726. colored = true;
  727. }
  728. },
  729.  
  730. // 延迟
  731. sleep(time) {
  732. return new Promise(resolve => setTimeout(resolve, time));
  733. },
  734.  
  735. // 获取大版本
  736. getMajorVersion(version) {
  737. const [major] = (version || '').split('.');
  738. return /^\d+$/.test(major) ? major : null;
  739. },
  740.  
  741. // 查找 React 组件实例
  742. findReact(dom, traverseUp = 0) {
  743. const key = Object.keys(dom).find(key => {
  744. return key.startsWith("__reactFiber$")
  745. || key.startsWith("__reactInternalInstance$");
  746. });
  747. const domFiber = dom[key];
  748. if (domFiber == null) return null;
  749.  
  750. if (domFiber._currentElement) {
  751. let compFiber = domFiber._currentElement._owner;
  752. for (let i = 0; i < traverseUp; i++) {
  753. compFiber = compFiber._currentElement._owner;
  754. }
  755. return compFiber._instance;
  756. }
  757.  
  758. const GetCompFiber = fiber => {
  759. let parentFiber = fiber.return;
  760. while (typeof parentFiber.type == "string") {
  761. parentFiber = parentFiber.return;
  762. }
  763. return parentFiber;
  764. };
  765. let compFiber = GetCompFiber(domFiber);
  766. for (let i = 0; i < traverseUp; i++) {
  767. compFiber = GetCompFiber(compFiber);
  768. }
  769. return compFiber.stateNode || compFiber;
  770. },
  771.  
  772. // 初始化设置项目
  773. initDefaultConfig() {
  774. let value = [
  775. // RPC 设置
  776. {
  777. name: 'setting_rpc_domain',
  778. value: 'http://localhost'
  779. }, {
  780. name: 'setting_rpc_port',
  781. value: '16800'
  782. }, {
  783. name: 'setting_rpc_path',
  784. value: '/jsonrpc'
  785. }, {
  786. name: 'setting_rpc_token',
  787. value: ''
  788. }, {
  789. name: 'setting_rpc_dir',
  790. value: 'D:\\Downloads\\'
  791. },
  792. // 杂项
  793. {
  794. name: 'setting_terminal_type',
  795. value: 'wc'
  796. }, {
  797. name: 'setting_theme_color',
  798. value: '#574AB8'
  799. }, {
  800. name: 'setting_init_code',
  801. value: ''
  802. }, {
  803. name: 'setting_init_license',
  804. value: ''
  805. },
  806. // 额外
  807. {
  808. name: 'setting_server_main',
  809. value: 'v2'
  810. }, {
  811. name: 'setting_theme_baidu',
  812. value: 'no'
  813. }, {
  814. name: 'setting_theme_ali',
  815. value: 'no'
  816. }, {
  817. name: 'setting_theme_tianyi',
  818. value: 'no'
  819. }, {
  820. name: 'setting_theme_xunlei',
  821. value: 'no'
  822. }, {
  823. name: 'setting_theme_quark',
  824. value: 'no'
  825. }, {
  826. name: 'setting_theme_yidong',
  827. value: 'no'
  828. }];
  829.  
  830. value.forEach(function (v) {
  831. // 没有对应的项目就添加上项目
  832. if (!base.getValue(v.name)) base.setValue(v.name, v.value);
  833. });
  834. },
  835.  
  836. // 设置界面
  837. showSetting() {
  838. let dom = ''
  839. dom += `<div style="text-align: center;">带星号的设置项目将在网页刷新后生效</div>`
  840. dom += `<label class="pl-setting-label"><div class="pl-label">RPC主机</div><input type="text" placeholder="主机地址,需带上http(s)://,但不需要写端口与路径" class="swal2-input pl-input listener-rpc-domain" value="${base.getValue('setting_rpc_domain')}"></label>`;
  841. dom += `<label class="pl-setting-label"><div class="pl-label">RPC端口</div><input type="text" placeholder="端口号,例如:Motrix下载器为16800" class="swal2-input pl-input listener-rpc-port" value="${base.getValue('setting_rpc_port')}"></label>`;
  842. dom += `<label class="pl-setting-label"><div class="pl-label">RPC路径</div><input type="text" placeholder="路径,默认为/jsonrpc" class="swal2-input pl-input listener-rpc-path" value="${base.getValue('setting_rpc_path')}"></label>`;
  843. dom += `<label class="pl-setting-label"><div class="pl-label">RPC密钥</div><input type="text" placeholder="无密钥无需填写" class="swal2-input pl-input listener-rpc-token" value="${base.getValue('setting_rpc_token')}"></label>`;
  844. dom += `<label class="pl-setting-label"><div class="pl-label">RPC保存</div><input type="text" placeholder="文件下载后保存路径,例如:D:\\Downloads\\" class="swal2-input pl-input listener-rpc-dir" value="${base.getValue('setting_rpc_dir')}"></label>`;
  845. dom += `<label class="pl-setting-label"><div class="pl-label">当前RPC</div><div><span id="pl-rpcDomain">${base.getValue('setting_rpc_domain')}</span>:<span id="pl-rpcPort">${base.getValue('setting_rpc_port')}</span><span id="pl-rpcPath">${base.getValue('setting_rpc_path')}</span><button type="button" class="pl-button-mini swal2-confirm swal2-styled listener-rpc-test">测试</button></div></label>`;
  846. dom += `<label class="pl-setting-label" style="padding-top:0;flex-direction:row-reverse;text-align:right;"><span><a href="https://www.youxiaohou.com/zh-cn/motrix.html#使用指南" target="_blank" class="pl-a" data-no-instant="1">RPC配置说明</a>,适用于RPC下载👆</span></label>`;
  847.  
  848. dom += `<label class="pl-setting-label"><div class="pl-label">终端类型</div><select class="swal2-select pl-input listener-terminal">`;
  849. Object.keys(terminalType).forEach(k => {
  850. dom += `<option value="${k}" ${base.getValue('setting_terminal_type') === k ? 'selected' : ''}>${terminalType[k]}</option>`;
  851. });
  852. dom += `</select></label>`;
  853. dom += `<label class="pl-setting-label" style="padding-top:0;flex-direction:row-reverse;text-align:right;"><span><a href="https://www.youxiaohou.com/zh-cn/curl.html" target="_blank" class="pl-a" data-no-instant="1">cURL使用教程</a>,适用于cURL下载👆</span></label>`;
  854.  
  855. dom += `<label class="pl-setting-label"><div class="pl-label">使用油小猴服务器*</div><select class="swal2-select pl-input listener-youxiaohou-server">`;
  856. Object.keys(monkeyServer).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_server_main') === value ? 'selected' : ''}>${monkeyServer[value]}</option>`; });
  857. dom += `</select></label>`;
  858.  
  859. dom += `<button type="button" style="margin-top: 30px;" class="pl-button-mini swal2-deny swal2-styled listener-register">熄灭已经点亮的按钮*</button>`
  860.  
  861. dom = '<div>' + dom + '</div>';
  862.  
  863. Swal.fire({
  864. title: '助手设置',
  865. html: dom,
  866. icon: 'info',
  867. iconHtml: '⚙︎',
  868. allowOutsideClick: false,
  869. showCloseButton: true,
  870. showConfirmButton: false,
  871. heightAuto: false,
  872. scrollbarPadding: false,
  873. footer: pan.footer,
  874. });
  875. doc.on('click', '.listener-register', async function (e) {
  876. base.unRegisterInit(111111);
  877. });
  878. doc.on('click', '.listener-rpc-test', async function (e) {
  879. e.preventDefault();
  880. let domain = base.getValue('setting_rpc_domain'),
  881. port = base.getValue('setting_rpc_port'),
  882. path = base.getValue('setting_rpc_path'),
  883. token = base.getValue('setting_rpc_token');
  884. if (e.target.innerHTML !== "测试") return;
  885. e.target.innerHTML = "等待";
  886. e.target.style.opacity = 0.9;
  887. let result = await base.rpcTest(domain, port, path, token);
  888. if (result === "success") {
  889. e.target.innerHTML = "成功";
  890. e.target.style.backgroundColor = "#52c41a";
  891. } else {
  892. e.target.innerHTML = "失败";
  893. e.target.style.backgroundColor = "#cb1616";
  894. }
  895. e.target.style.opacity = "";
  896. setTimeout(function () {
  897. e.target.innerHTML = "测试";
  898. e.target.style.backgroundColor = "";
  899. }, 3000)
  900. });
  901. doc.on('input', '.listener-rpc-domain', async function (e) {
  902. base.setValue('setting_rpc_domain', e.target.value);
  903. document.getElementById("pl-rpcDomain").innerHTML = e.target.value;
  904. });
  905. doc.on('input', '.listener-rpc-port', async function (e) {
  906. base.setValue('setting_rpc_port', e.target.value);
  907. document.getElementById("pl-rpcPort").innerHTML = e.target.value;
  908. });
  909. doc.on('input', '.listener-rpc-path', async function (e) {
  910. base.setValue('setting_rpc_path', e.target.value);
  911. document.getElementById("pl-rpcPath").innerHTML = e.target.value;
  912. });
  913. doc.on('input', '.listener-rpc-token', async function (e) {
  914. base.setValue('setting_rpc_token', e.target.value);
  915. });
  916. doc.on('input', '.listener-rpc-dir', async function (e) {
  917. base.setValue('setting_rpc_dir', e.target.value);
  918. });
  919. doc.on('change', '.listener-terminal', async function (e) {
  920. base.setValue('setting_terminal_type', e.target.value);
  921. });
  922. doc.on('change', '.listener-youxiaohou-server', async function (e) {
  923. base.setValue('setting_server_main', e.target.value);
  924. });
  925. },
  926.  
  927. // 美化界面
  928. showBeautify() {
  929. let dom = '',
  930. btn = '',
  931. colorList = ['#09AAFF', '#cc3235', '#518c17', '#ed944b', '#f969a5', '#bca280', '#b673ab', '#574AB8', '#1d2327', '#18a497', '#637dff', '#0d53ff', '#3181f9', '#f8d800', '#0396ff', '#32ccbc', '#f6416c', '#2271b1', '#59524c', '#ff679a', '#f44236', '#fec107', '#8bc24a', '#2594ed', '#9c28b1'],
  932. colorNameList = ['度盘<br/>经典蓝', '度盘<br/>平安红', '度盘<br/>盎然绿', '度盘<br/>周年橙', '度盘<br/>幸会粉', '度盘<br/>午后棕', '度盘<br/>物语紫', '度盘<br/>星空紫', 'OpenAI<br/>默认黑', 'OpenAI<br/>默认青', '里度<br/>霞光紫', '夸克<br/>极简蓝', '移动<br/>彩云蓝', '果核<br/>柠檬黄', '果核<br/>默认蓝', '果核<br/>碧波绿', '果核<br/>玫瑰红', '文派<br/>默认蓝', '文派<br/>咖啡灰', '哔哩<br/>少女粉', '哔哩<br/>高能红', '哔哩<br/>咸蛋黄', '哔哩<br/>早苗绿', '哔哩<br/>宝石蓝', '哔哩<br/>罗兰紫'];
  933. dom += `<div style="text-align: center;">带星号的美化项目将在网页刷新后生效</div>`
  934.  
  935. colorList.forEach((v, i) => {
  936. btn += `<div style="background: ${v};border: 1px solid ${v}" class="pl-color-box ${v === base.getValue('setting_theme_color') ? 'listener-color' : 'listener-color'}">
  937. <div data-color="${v}" class="pl-mask">${colorNameList[i]} ${v === base.getValue('setting_theme_color') ? '<span id="pl-thisColor">(当前)</span>' : ''}</div>
  938. </div>`;
  939. });
  940.  
  941. dom += `<label class="pl-setting-label"><div class="pl-label">主题颜色</div> <div class="pl-color">${btn}</div></label>`;
  942.  
  943. dom += `<label class="pl-setting-label"><div class="pl-label">[百度网盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-baidu-theme">`;
  944. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_theme_baidu') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  945. dom += `</select></label>`;
  946. dom += `<label class="pl-setting-label" style="padding-top:0;flex-direction:row-reverse;text-align:right;"><span>旧版页面会美化,新版页面则是更换主题色👆</span></label>`;
  947.  
  948. dom += `<label class="pl-setting-label"><div class="pl-label">[阿里云盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-ali-theme">`;
  949. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_theme_ali') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  950. dom += `</select></label>`;
  951.  
  952. dom += `<label class="pl-setting-label"><div class="pl-label">[天翼云盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-tianyi-theme">`;
  953. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_theme_tianyi') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  954. dom += `</select></label>`;
  955.  
  956. dom += `<label class="pl-setting-label"><div class="pl-label">[迅雷云盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-xunlei-theme">`;
  957. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_theme_xunlei') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  958. dom += `</select></label>`;
  959.  
  960. dom += `<label class="pl-setting-label"><div class="pl-label">[夸克网盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-quark-theme">`;
  961. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_theme_quark') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  962. dom += `</select></label>`;
  963.  
  964. dom += `<label class="pl-setting-label"><div class="pl-label">[移动云盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-yidong-theme">`;
  965. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_theme_yidong') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  966. dom += `</select></label>`;
  967.  
  968. dom = '<div>' + dom + '</div>';
  969.  
  970. Swal.fire({
  971. title: '助手美化',
  972. html: dom,
  973. icon: 'success',
  974. iconHtml: '🍃︎',
  975. allowOutsideClick: false,
  976. showCloseButton: true,
  977. showConfirmButton: false,
  978. heightAuto: false,
  979. scrollbarPadding: false,
  980. footer: '<div style="text-align: center;">感谢您使用本脚本,给我们一个<a href="https://github.com/hmjz100/Online-disk-direct-link-download-assistant" target="_blank" class="pl-a" data-no-instant="1">Star</a>吧~</div>',
  981. });
  982. doc.on('click', '.listener-color', async function (e) {
  983. if (e.target.dataset.color) {
  984. if (document.getElementById("pl-thisColor")) {
  985. document.getElementById("pl-thisColor").remove();
  986. }
  987. e.target.innerHTML += '<span id="pl-thisColor">(当前)</span>';
  988. base.setValue('setting_theme_color', e.target.dataset.color);
  989. base.addPanLinkerStyle();
  990. }
  991. });
  992. doc.on('change', '.listener-baidu-theme', async function (e) {
  993. base.setValue('setting_theme_baidu', e.target.value);
  994. });
  995. doc.on('change', '.listener-ali-theme', async function (e) {
  996. base.setValue('setting_theme_ali', e.target.value);
  997. });
  998. doc.on('change', '.listener-tianyi-theme', async function (e) {
  999. base.setValue('setting_theme_tianyi', e.target.value);
  1000. });
  1001. doc.on('change', '.listener-xunlei-theme', async function (e) {
  1002. base.setValue('setting_theme_xunlei', e.target.value);
  1003. });
  1004. doc.on('change', '.listener-quark-theme', async function (e) {
  1005. base.setValue('setting_theme_quark', e.target.value);
  1006. });
  1007. doc.on('change', '.listener-yidong-theme', async function (e) {
  1008. base.setValue('setting_theme_yidong', e.target.value);
  1009. });
  1010. },
  1011.  
  1012. // 调试信息界面
  1013. showDebug() {
  1014. let debugInfo = '';
  1015. let server = '';
  1016. if (base.getValue('setting_server_main') === 'v1') {
  1017. server = `https://api.youxiaohou.com/config/?ver=${version}&a=${author}`;
  1018. } else if (base.getValue('setting_server_main') === 'v2') {
  1019. server = `https://api.youxiaohou.com/config/v2/?ver=${version}&a=${author}`;
  1020. } else if (base.getValue('setting_server_main') === "no") {
  1021. server = `https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/config.json?version=${realversion}`;
  1022. } else {
  1023. server = `https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/config.json?version=${realversion}`;
  1024. base.setValue('setting_server_main', 'v2');
  1025. }
  1026. debugInfo += `<span>以下内容均为脚本自检信息<br/>本页面仅作为调试使用<span>`;
  1027. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[外置]<br/>管理器名称</div>${manageHandler ? manageHandler : "无法获取"}</label>`;
  1028. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[外置]<br/>管理器版本</div>${manageVersion ? manageVersion : "无法获取"}</label>`;
  1029. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[内置]<br/>信息服务器</div>[${base.getValue('setting_server_main')}]${server ? server : "无法获取"}</label>`;
  1030. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[内置]<br/>脚本名称</div>${realname ? realname : "无法获取"}</label>`;
  1031. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[内置]<br/>脚本版本</div>${realversion ? realversion : "无法获取"}</label>`;
  1032. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[内置]<br/>脚本作者</div>${realauthor ? realauthor : "无法获取"}</label>`;
  1033. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[上报]<br/>脚本版本</div>${version ? version : "无法获取"}</label>`;
  1034. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[上报]<br/>脚本作者</div>${author ? author : "无法获取"}</label>`;
  1035.  
  1036. if (pan.num) {
  1037. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>初始化暗号</div>${pan.num ? pan.num : "无法获取"}</label>`;
  1038. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>初始化协议</div>${pan.license ? pan.license : "无法获取"}</label>`;
  1039. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>UA代理</div><code>${pan.ua ? pan.ua : "此网站暂无"}</code></label>`;
  1040. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>公众号码</div>${pan.img ? `${pan.img}<img src="${pan.img}"></img>` : "无法获取"}</label>`;
  1041. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>万能助手</div>${pan.assistant ? pan.assistant : "此网站暂无"}</label>`;
  1042. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>网盘CDN</div>${pan.mirror ? pan.mirror : "此网站暂无"}</label>`;
  1043. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>RPC管理</div>${pan.d ? pan.d : "无法获取"}</label>`;
  1044. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>IDM介绍</div>${pan.idm ? pan.idm : "此网盘暂无"}</label>`;
  1045. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>提示文本</div><code>${JSON.stringify(pan.init) ? JSON.stringify(pan.init) : "无法获取"}</code></label>`;
  1046. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>网盘接口</div><code>${JSON.stringify(pan.pcs) ? JSON.stringify(pan.pcs) : "无法获取"}</code></label>`;
  1047. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>Toast页脚</div>${pan.footer ? pan.footer : "此网站暂无"}</label>`;
  1048. } else {
  1049. debugInfo += `<label>上报的服务器请求未完成,部分信息未能显示</label>`;
  1050. }
  1051.  
  1052.  
  1053. debugInfo = '<div>' + debugInfo + '</div>';
  1054.  
  1055. Swal.fire({
  1056. icon: 'info',
  1057. title: '调试信息',
  1058. html: debugInfo,
  1059. allowOutsideClick: false,
  1060. showCloseButton: true,
  1061. heightAuto: false,
  1062. scrollbarPadding: false,
  1063. confirmButtonText: '关闭'
  1064. });
  1065. },
  1066.  
  1067. // 更新日志界面
  1068. showUpdateLog() {
  1069. Swal.fire({
  1070. icon: 'info',
  1071. title: '更新日志',
  1072. html: `<div style="text-align: left;">
  1073. V1.0.9.5<br/>1、修复因代码逻辑错误而无法获取链接的 Bug。<br/><br/>
  1074. V1.0.9.4<br/>1、修复因百度网盘 AccessToken 过期导致无法获取链接的 Bug。<br/><br/>
  1075. V1.0.9.3<br/>1、若网盘不支持在分享中下载,将仅显示保存网盘按钮;<br/>2、优化下载界面,支持选择 Iframe Blob 的方式来下载文件,增加按钮的提示文本;<br/>3、优化 CSS 样式,统一了 SweetAlert2 按钮样式,同时适配了 Dark Reader 插件,界面更协调;<br/>4、支持修改油小猴网站主题色;<br/>5、原有主题相关设置现已移动至助手美化页面中。<br/><br/>
  1076. V1.0.9.2<br/>1、修复使用API下载时有可能会导致IDM无限弹窗的Bug。<br/><br/>
  1077. V1.0.9.1<br/>1、修复在百度网盘旧版下脚本无法删除元素的Bug。<br/><br/>
  1078. V1.0.9<br/>1、跟进官方V6.2.7,修复因无法进行百度授权而导致获取直链报错 9019 Bug。<br/><br/>
  1079. V1.0.8.9<br/>1、跟进官方V6.2.3,优化保存到网盘提示,修复阿里云盘、移动云盘失效的问题;<br/>2、优化修改网盘主题的代码,减少对页面的破坏。<br/><br/>
  1080. V1.0.8.8<br/>1、修复下载菜单字体过小的Bug。<br/><br/>
  1081. V1.0.8.7<br/>1、修复在阿里云盘分享页面下点击“未点亮”按钮时没有任何反应的Bug;<br/>2、更新并优化网盘界面精简规则;<br/>3、支持更换 百度网盘、阿里云盘、迅雷云盘、夸克网盘、移动云盘 界面的主题颜色。<br/><br/>
  1082. V1.0.8.6<br/>1、新增移动云盘会员中心页面,可在网盘中点击“会员中心”按钮查看(但无法使用第三方支付)。<br/><br/>
  1083. V1.0.8.5<br/>1、跟进官方V6.1.6,修复迅雷网盘分享页面无法选中文件,修复移动云盘无法判断页面。<br/><br/>
  1084. V1.0.8.4<br/>1、修复因重复绑定按钮而导致命令重复执行的Bug;<br/>2、优化调试信息界面排版;<br/>3、移除对百度网盘手机网页版的支持。<br/><br/>
  1085. V1.0.8.3<br/>1、适配阿里云盘新域名alipan.com。<br/><br/>
  1086. V1.0.8.2<br/>1、更换新图标。<br/><br/>
  1087. V1.0.8.1<br/>1、修复因重复绑定按钮而导致RPC下载会发送多条下载请求的Bug;<br/>2、选择不使用油小猴服务器时,“用ghproxy连接Github仓库”更换为“用jsdelivr连接Github仓库”;<br/>3、跟进官方V6.1.4版本,修复移动网盘无法获取链接,支持阿里云盘新域名alipan.com。<br/><br/>
  1088. V1.0.8<br/>1、修复迅雷网盘无法勾选文件。<br/><br/>
  1089. V1.0.7.9<br/>1、更新精简网盘元素匹配规则,防止因通知横条而导致不能点到“API下载”以下的按钮。<br/><br/>
  1090. V1.0.7.8<br/>1、跟进官方V6.1.2,加入V2接口。<br/>2、修复百度网盘下载时因为获取不到accessToken而一直转圈。<br/><br/>
  1091. V1.0.7.7<br/>1、修复百度网盘的按钮会因为主题不同而被改变颜色的Bug;<br/>2、更新夸克网盘按钮与界面。<br/><br/>
  1092. V1.0.7.6<br/>1、修复“注入”功能;<br/>2、黑暗模式支持随设置热切换。<br/><br/>
  1093. V1.0.7.5<br/>1、修复阿里云盘下载逻辑;<br/>2、精简代码;<br/>3、支持深色模式;<br/>4、修改部分提示文本;<br/>5、修改部分CSS;<br/>6、设置可测试RPC连接。<br/><br/>
  1094. V1.0.7.4<br/>1、优化下载逻辑;<br/>2、修复阿里云盘无法使用API下载。<br/><br/>
  1095. V1.0.7.3<br/>1、如果出现网络请求错误时支持自动重新请求;<br/>2、可选择是否使用油小猴服务器。<br/><br/>
  1096. V1.0.7.2<br/>1、修复使用RPC下载时会重复发送链接的Bug。<br/><br/>
  1097. V1.0.7.1<br/>1、[实验功能,不影响正常使用]支持百度网盘手机网页版,勾选文件后可在顶栏找到“下载助手”按钮。<br/><br/>
  1098. V1.0.7<br/>1、重构夸克网盘、阿里云盘按钮。<br/><br/>
  1099. V1.0.6.9<br/>1、下载窗口加入关闭按钮。<br/><br/>
  1100. V1.0.6.8<br/>1、修复夸克网盘按钮错位。<br/><br/>
  1101. V1.0.6.7<br/>1、将百度网盘界面修改为主题色,可在设置选择是否修改;<br/>2、增加主题色名称,更改部分内容颜色;<br/>3、移动云盘API下载支持批量复制;<br/>4、优化控制台输出结果;<br/>5、百度网盘API下载不使用IDM时可以显示剩余时间;<br/>6、“取消点亮按钮”按钮的位置现已移动到设置页面。<br/>7homo特有的彩蛋又回来力(喜)。<br/><br/>
  1102. V1.0.6.6<br/>1、修复暗号错误。<br/><br/>
  1103. V1.0.6.5<br/>1、修复即使输入正确暗号也不能成功点亮按钮的服务器错误。<br/><br/>
  1104. V1.0.6.4<br/>1、跟进官方V6.1.1版本,修复阿里云盘获取下载链接时的问题。<br/><br/>
  1105. V1.0.6.3<br/>1、照顾小屏幕用户,将始终显示复制全部链接的按钮;<br/>2、增加取消下载时的动画。<br/><br/>
  1106. V1.0.6.2<br/>1、修复部分界面错位,实现CSS内置;<br/>2、百度网盘界面将变得更加简洁。<br/><br/>
  1107. V1.0.6.1<br/>1、新增百度云盘API下载支持复制链接;<br/>2、为了照顾手机浏览器用户,增大项目之间间隙,新增隐藏IDM提示选项,可在助手设置中启用;<br/>3、修改CSS,界面会出现更多的主题色;<br/>4、支持在游小猴官网查看暗号;<br/>5、修复部分语法错误。<br/><br/>
  1108. V1.0.6<br/>1、修复了打开阿里云盘分享连接时因下载移动端广告导致只能点击API下载;<br/>2、跟进官方6.0.4版本,修复夸克网盘获取下载链接失效、支持移动云盘。<br/><br/>
  1109. V1.0.5.5<br/>1、感谢<a href="https://github.com/Night-stars-1">Night-stars-1</a>的帮助,修复因为原作者服务器导致的初始化暗号识别错误;<br/>2、修改一些文本以及提供给服务器的信息。<br/><br/>
  1110. V1.0.5.4<br/>1、小修小改css,让主题色出现在更多地方;<br/>2、修改下载链接获取失败的提示;<br/>3、增加更多的主题色,可在助手设置查看;<br/>4homo彩蛋被删去力(悲)。<br/><br/>
  1111. V1.0.5.3<br/>1、修啦修啦,阿里云盘可以摸到下载菜单了。<br/><br/>
  1112. V1.0.5.2<br/>1、增加脚本信息菜单(没有用);<br/>2、优化阿里云盘显示svg图片;<br/>3、修改弹窗按钮颜色。<br/><br/>
  1113. V1.0.5.1<br/>1、修复在切换按钮主题后夸克网盘不能正常显示按钮。<br/><br/>
  1114. V1.0.5<br/>1、跟进官方V5.0.4版本;<br/>2、小改动,照着官方版本更正文件名称检测;<br/>3、保留彩蛋,但必须舍弃官方暗号。<br/><br/>
  1115. V1.0.4<br/>大改!<br/>1、修复了原作者留下的夸克网盘切换文件夹就多一个“下载助手”按钮的大BUG;<br/>2、终于来了,在下载菜单增加“助手设置”“更新日志”按钮;<br/>【再也不用点进油猴管理再进设置了(保留油猴管理内设置)】<br/>3、修改阿里云盘和夸克网盘下载助手按钮样式;<br/>4、增加“取消点亮按钮”油猴菜单;<br/>5、修改部分css,使其与选择的主题更贴切。<br/><br/>
  1116. V1.0.3<br/>1、增加一个小彩蛋; 提示:<br/>homo(需在未点亮按钮状态触发)<br/>【需要重新恢复按钮为未点亮状态请进入 已安装脚本->编辑->开发者->重置到出厂->确定】<br/>2、修改/增加默认主题色。<br/><br/>
  1117. V1.0.2<br/>1、修改并加宽界面,调整部分css,使Sweetalert2界面更美观,更与原版相近;<br/>2、修改部分提示文字,使文字更容易复制。 <br/><br/>
  1118. V1.0.1<br/>1、去除更新提示;<br/>2、更新Sweetalert211版本;<br/>3、部分CDN节点更换为jsdelivr。<br/><br/>
  1119. V1.0.0<br/>1、增加“注入”功能(bushi);<br/>2、去除广告。
  1120. </div>`,
  1121. allowOutsideClick: false,
  1122. showCloseButton: false,
  1123. heightAuto: false,
  1124. scrollbarPadding: false,
  1125. confirmButtonText: '我已阅',
  1126. });
  1127. },
  1128.  
  1129. // 创建浮动标签
  1130. createTip() {
  1131. // 添加提示框到 body
  1132. $('body').append('<div class="pl-tooltip"></div>');
  1133.  
  1134. // 监听所有带有 .listener-tip 类的元素的鼠标移动事件
  1135. $(document).on('mousemove', '.listener-tip', function (e) {
  1136. // 获取提示文字
  1137. let tip = e.currentTarget.dataset.title || `${e.currentTarget.innerText} <span style="margin-left: 10px;color: ${color}">${e.currentTarget.dataset.size}</span>`;
  1138.  
  1139. // 设置提示框的位置并使用 fadeIn() 渐变显示
  1140. $('.pl-tooltip').html(tip).css({
  1141. 'left': e.pageX + 10 + 'px',
  1142. 'top': e.pageY + 20 + 'px' // 增加一些间距
  1143. }).show();
  1144. });
  1145.  
  1146. $(document).on('mouseleave', '.listener-tip, pl-tooltip', function (e) {
  1147. $('.pl-tooltip').hide();
  1148. });
  1149. },
  1150.  
  1151.  
  1152. // 创建加载弹窗
  1153. createLoading() {
  1154. return $('<div class="pl-loading"><div class="pl-loading-box"><div><div></div><div></div></div></div></div>');
  1155. },
  1156.  
  1157. // 创建下载用的隐藏 iframe
  1158. createDownloadIframe() {
  1159. let $div = $('<div style="padding:0;margin:0;display:block"></div>');
  1160. let $iframe = $('<iframe src="javascript:;" id="downloadIframe" style="display:none"></iframe>');
  1161. $div.append($iframe);
  1162. $('body').append($div);
  1163. },
  1164.  
  1165. // 获取镜像列表
  1166. getMirrorList(link, mirror, thread = 2) {
  1167. let host = new URL(link).host;
  1168. let mirrors = [];
  1169. for (let i = 0; i < mirror.length; i++) {
  1170. for (let j = 0; j < thread; j++) {
  1171. let item = link.replace(host, mirror[i]) + '&'.repeat(j);
  1172. mirrors.push(item);
  1173. }
  1174. }
  1175. return mirrors.join('\n');
  1176. },
  1177.  
  1178. // 监听元素出现并执行回调
  1179. listenElement(element, callback) {
  1180. let checkInterval = 1000; // 检查元素的间隔时间(毫秒)
  1181. let wasElementFound = false; // 用于跟踪元素是否之前已经找到
  1182.  
  1183. function checkElement() {
  1184. if (document.querySelector(element)) {
  1185. wasElementFound = true;
  1186. callback();
  1187. } else if (wasElementFound) {
  1188. wasElementFound = false; // 元素消失后重置标志
  1189. }
  1190.  
  1191. setTimeout(checkElement, checkInterval);
  1192. }
  1193. checkElement();
  1194. },
  1195.  
  1196. // 创建基础样式
  1197. addPanLinkerStyle() {
  1198. color = base.getValue('setting_theme_color');
  1199.  
  1200. let swalcss = `
  1201. .swal2-styled{transition: all 0.2s ease;}
  1202. .swal2-loader{display:none;align-items:center;justify-content:center;width:2.2em;height:2.2em;margin:0 1.875em;-webkit-animation:swal2-rotate-loading 1.5s linear 0s infinite normal;animation:swal2-rotate-loading 1.5s linear 0s infinite normal;border-width:.25em;border-style:solid;border-radius:100%;border-color:${color} transparent }
  1203. .swal2-styled.swal2-confirm{border:0;border-radius:.25em;background:initial;background-color:${color};color:#fff;font-size:1em}
  1204. .swal2-styled.swal2-confirm:hover,.swal2-styled.swal2-deny:hover{opacity:0.8;background-image:none!important}
  1205. .swal2-styled.swal2-confirm:focus{box-shadow:0 0 0 3px ${color}80}
  1206. .swal2-styled.swal2-deny:focus{box-shadow:0 0 0 3px #dc374180}
  1207. .swal2-timer-progress-bar-container{position:absolute;right:0;bottom:0;left:0;grid-column:auto;overflow:hidden;border-bottom-right-radius:5px;border-bottom-left-radius:5px}
  1208. .swal2-timer-progress-bar{width:100%;height:.25em;background:${color}33 }
  1209. .swal2-progress-steps .swal2-progress-step{z-index:20;flex-shrink:0;width:2em;height:2em;border-radius:2em;background:${color};color:#fff;line-height:2em;text-align:center}
  1210. .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step{background:${color} }
  1211. .swal2-progress-steps .swal2-progress-step-line{z-index:10;flex-shrink:0;width:2.5em;height:.4em;margin:0 -1px;background:${color}}
  1212. .swal2-popup {padding:1.25em 0 1.25em;flex-direction:column}
  1213. .swal2-close {position:absolute;top:1px;right:1px;transition: all 0.2s ease;}
  1214. div:where(.swal2-container) .swal2-html-container{padding: 1.3em 1.3em 0.3em;}
  1215. div:where(.swal2-container) button:where(.swal2-close):hover {color:${color}!important;font-size:60px!important}
  1216. div:where(.swal2-icon) .swal2-icon-content {font-family: sans-serif;}
  1217. `;
  1218.  
  1219. // 先监听颜色方案变化 Panlinker-SweetAlert2-Default
  1220. window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
  1221. if (e.matches) {
  1222. // 切换到暗色主题
  1223. base.addStyle('swal-pub-style', 'style', GM_getResourceText('SwalDark'));
  1224. } else {
  1225. // 切换到浅色主题
  1226. base.addStyle('swal-pub-style', 'style', GM_getResourceText('Swal'));
  1227. }
  1228. base.addStyle('Panlinker-SweetAlert2-User', 'style', swalcss);
  1229. });
  1230. // 再修改主题 Panlinker-SweetAlert2-Default
  1231. if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  1232. // 切换到暗色主题
  1233. base.addStyle('swal-pub-style', 'style', GM_getResourceText('SwalDark'));
  1234. } else {
  1235. // 切换到浅色主题
  1236. base.addStyle('swal-pub-style', 'style', GM_getResourceText('Swal'));
  1237. }
  1238. base.addStyle('Panlinker-SweetAlert2-User', 'style', swalcss);
  1239.  
  1240. let uicss = `
  1241. ::-webkit-scrollbar {
  1242. width: 8px;
  1243. height: 8px;
  1244. transition: all 0.2s ease;
  1245. }
  1246.  
  1247. ::-webkit-scrollbar-track {
  1248. border-radius: 10px;
  1249. background: #fff;
  1250. }
  1251.  
  1252. ::-webkit-scrollbar-thumb,
  1253. ::-webkit-scrollbar-thumb:hover {
  1254. border-radius: 10px;
  1255. }
  1256.  
  1257. ::-webkit-scrollbar-thumb {
  1258. background-color: ${color}90 !important
  1259. }
  1260.  
  1261. ::-webkit-scrollbar-thumb:hover {
  1262. background-color: ${color}D0 !important
  1263. }
  1264.  
  1265. .swal2-popup {
  1266. font-size: 16px
  1267. }
  1268.  
  1269. .pl-a {
  1270. color: ${color};
  1271. }
  1272.  
  1273. .pl-a:hover {
  1274. color: ${color}90;
  1275. }
  1276.  
  1277. .pl-popup {
  1278. font-size: 12px;
  1279. width: 90%;
  1280. }
  1281.  
  1282. .pl-popup a:not(.pl-btn-primary) {
  1283. color: ${color};
  1284. }
  1285.  
  1286. .pl-popup a:hover:not(.pl-btn-primary) {
  1287. color: ${color}90;
  1288. }
  1289.  
  1290. .pl-header {
  1291. padding: 0;
  1292. align-items: flex-start;
  1293. border-bottom: 1px solid #eee;
  1294. margin: 0 0 10px;
  1295. padding: 0 0 5px;
  1296. }
  1297.  
  1298. .pl-title {
  1299. font-size: 16px;
  1300. line-height: 1;
  1301. white-space: nowrap;
  1302. text-overflow: ellipsis;
  1303. }
  1304.  
  1305. .pl-content {
  1306. padding: 0;
  1307. font-size: 12px;
  1308. }
  1309.  
  1310. .pl-main {
  1311. background-color:${color}15;
  1312. overflow: auto;
  1313. border-radius: 10px;
  1314. max-height:calc(${document.documentElement.clientHeight}px - 250px);
  1315. }
  1316.  
  1317. .pl-footer {
  1318. font-size: 15px;
  1319. margin-top: 10px;
  1320. padding-top: 5px;
  1321. color: #f56c6c;
  1322. text-align: center;
  1323. display: flex !important;
  1324. align-items: center;
  1325. justify-content: center;
  1326. }
  1327.  
  1328. .pl-item {
  1329. display: flex;
  1330. align-items: center;
  1331. line-height: 22px;
  1332. height: 50px;
  1333. background-color: ${color}30;
  1334. border-radius: 5px;
  1335. margin: 8px 6px;
  1336. }
  1337.  
  1338. .pl-item-name {
  1339. flex: 0 0 170px;
  1340. text-align: left;
  1341. margin: 6px;
  1342. overflow: hidden;
  1343. white-space: nowrap;
  1344. text-overflow: ellipsis;
  1345. cursor: default;
  1346. height: 30px;
  1347. }
  1348.  
  1349. .pl-item-link {
  1350. flex: 1;
  1351. text-align: left;
  1352. white-space: nowrap;
  1353. text-overflow: ellipsis;
  1354. cursor: pointer;
  1355. overflow: hidden;
  1356. }
  1357.  
  1358. .pl-item-tip {
  1359. display: flex;
  1360. justify-content: space-between;
  1361. flex: 1;
  1362. }
  1363.  
  1364. .pl-ext {
  1365. display: inline-block;
  1366. width: 44px;
  1367. background: #999;
  1368. color: #fff;
  1369. height: 16px;
  1370. line-height: 16px;
  1371. font-size: 12px;
  1372. border-radius: 3px;
  1373. }
  1374.  
  1375. .pl-retry {
  1376. padding: 3px 10px;
  1377. background: #cc3235;
  1378. color: #fff;
  1379. border-radius: 3px;
  1380. cursor: pointer;
  1381. }
  1382.  
  1383. .pl-browserdownload {
  1384. padding: 3px 10px;
  1385. background: ${color};
  1386. color: #fff;
  1387. border-radius: 3px;
  1388. cursor: pointer;
  1389. }
  1390.  
  1391. .pl-item-progress {
  1392. display: flex;
  1393. flex: 1;
  1394. align-items: center
  1395. }
  1396.  
  1397. .pl-progress {
  1398. display: inline-block;
  1399. vertical-align: middle;
  1400. width: 100%;
  1401. box-sizing: border-box;
  1402. line-height: 1;
  1403. position: relative;
  1404. height: 20px;
  1405. margin: 0 6px;
  1406. flex: 1
  1407. }
  1408.  
  1409. .pl-progress-outer {
  1410. height: 20px;
  1411. border-radius: 100px;
  1412. background-color: #c1c1c1a1;
  1413. overflow: hidden;
  1414. position: relative;
  1415. vertical-align: middle;
  1416. }
  1417.  
  1418. .pl-progress-inner {
  1419. position: absolute;
  1420. left: 0;
  1421. top: 0;
  1422. background-color: ${color};
  1423. border-radius: 100px;
  1424. line-height: 1;
  1425. white-space: nowrap;
  1426. transition: width .6s ease;
  1427. height: 20px;
  1428. display: inline-flex;
  1429. text-align: center;
  1430. align-items: center
  1431. }
  1432.  
  1433. .pl-progress-inner-text {
  1434. display: inline-block;
  1435. vertical-align: middle;
  1436. cursor: default;
  1437. color: #ffffff;
  1438. font-size: 12px;
  1439. margin: 0 5px;
  1440. height: 20px;
  1441. width: 100%;
  1442. }
  1443.  
  1444. .pl-progress-tip {
  1445. flex: 1;
  1446. text-align: right
  1447. }
  1448.  
  1449. .pl-progress-how {
  1450. flex: 0 0 100px;
  1451. background: #ddd;
  1452. border-radius: 3px;
  1453. margin-left: 10px;
  1454. cursor: pointer;
  1455. text-align: center;
  1456. color: #000;
  1457. }
  1458.  
  1459. .pl-progress-inner-text:after {
  1460. display: inline-block;
  1461. content: "";
  1462. height: 100%;
  1463. vertical-align: middle;
  1464. }
  1465.  
  1466. .pl-btn-primary {
  1467. background: ${color};
  1468. border: 0;
  1469. border-radius: 4px;
  1470. color: #ffffff;
  1471. cursor: pointer;
  1472. font-size: 12px;
  1473. outline: none;
  1474. display: flex;
  1475. align-items: center;
  1476. justify-content: center;
  1477. margin: 6px 6px;
  1478. padding: 0.625em 1.1em;
  1479. transition: 0.3s opacity;
  1480. }
  1481.  
  1482. .pl-btn-primary:hover {
  1483. opacity: 0.8;
  1484. transition: 0.3s opacity;
  1485. }
  1486.  
  1487. .pl-btn-primary:focus{
  1488. box-shadow:0 0 0 3px ${color}80;
  1489. }
  1490.  
  1491. .pl-btn-success {
  1492. background: #55af28;
  1493. }
  1494.  
  1495. .pl-btn-success:focus{
  1496. box-shadow:0 0 0 3px #55af2880;
  1497. }
  1498.  
  1499. .pl-btn-info {
  1500. background: #606266;
  1501. }
  1502.  
  1503. .pl-btn-info:focus{
  1504. box-shadow:0 0 0 3px #60626680;
  1505. }
  1506.  
  1507. .pl-btn-warning {
  1508. background: #da9328;
  1509. }
  1510.  
  1511. .pl-btn-warning:focus{
  1512. box-shadow:0 0 0 3px #da932880;
  1513. }
  1514.  
  1515. .pl-btn-danger {
  1516. background: #cc3235;
  1517. }
  1518.  
  1519. .pl-btn-danger:focus{
  1520. box-shadow:0 0 0 3px #cc323580;
  1521. }
  1522.  
  1523. .pl-btn-opacity {
  1524. animation: easeOpacity 1.2s 2;
  1525. animation-fill-mode: forwards
  1526. }
  1527.  
  1528. .pl-button-mini {
  1529. padding: 5px 10px;
  1530. }
  1531.  
  1532. .pl-dropdown-menu-item {
  1533. height: 30px;
  1534. display: flex;
  1535. align-items: center;
  1536. justify-content: center;
  1537. cursor: pointer;
  1538. color: ${color};
  1539. transition: all 0.2s ease;
  1540. }
  1541.  
  1542. .pl-dropdown-menu-item:hover {
  1543. background-color: ${color}15;
  1544. }
  1545.  
  1546. .pl-button-mode {
  1547. padding: 0px;
  1548. padding-left: 0px !important;
  1549. color: ${color} !important;
  1550. transition: all 0.2s ease;
  1551. }
  1552.  
  1553. .pl-button-mode:hover {
  1554. background-color: ${color}33 !important;
  1555. }
  1556.  
  1557. .g-button-menu.pl-button-mode {
  1558. padding: 0px !important;
  1559. }
  1560.  
  1561. .pl-button,
  1562. .pl-dropdown-menu {
  1563. transition: all 0.2s ease;
  1564. }
  1565.  
  1566. .pl-button .pl-dropdown-menu {
  1567. display: none;
  1568. }
  1569.  
  1570. .pl-button:hover .pl-dropdown-menu {
  1571. display: block;
  1572. }
  1573.  
  1574. .pl-button-init {
  1575. opacity: 0.5;
  1576. animation: easeInitOpacity 1.2s 3;
  1577. animation-fill-mode: forwards
  1578. }
  1579.  
  1580. @keyframes easeInitOpacity {
  1581. from {
  1582. opacity: 0.5;
  1583. }
  1584.  
  1585. 50% {
  1586. opacity: 1
  1587. }
  1588.  
  1589. to {
  1590. opacity: 0.5;
  1591. }
  1592. }
  1593.  
  1594. @keyframes easeOpacity {
  1595. from {
  1596. opacity: 1;
  1597. }
  1598.  
  1599. 50% {
  1600. opacity: 0.35
  1601. }
  1602.  
  1603. to {
  1604. opacity: 1;
  1605. }
  1606. }
  1607.  
  1608. .baidu-button {
  1609. background: ${color} !important;
  1610. border-color: ${color} !important;
  1611. border: 1px solid ${color} !important;
  1612. display: inline-flex;
  1613. }
  1614.  
  1615. .baidu-button:hover {
  1616. background: ${color}b0 !important;
  1617. border-color: ${color} !important;
  1618. }
  1619.  
  1620. header[style="display: none;"]~.pl-button {
  1621. display: inline-block;
  1622. position: fixed;
  1623. top: 0.6em;
  1624. left: 65%;
  1625. z-index: 99999;
  1626. }
  1627.  
  1628. .ali-button {
  1629. background: ${color};
  1630. border: 0 solid transparent;
  1631. font-size: 14px;
  1632. margin-left: 20px;
  1633. padding: 8px 16px;
  1634. position: relative;
  1635. height: 32px;
  1636. border-radius: 100px;
  1637. display: flex;
  1638. align-items: center;
  1639. justify-content: center;
  1640. color: var(--basic_white);
  1641. cursor: pointer;
  1642. transition: all .3s ease;
  1643. }
  1644.  
  1645. .ali-button:hover {
  1646. background: ${color}D0
  1647. }
  1648.  
  1649. .ali-btn-icon {
  1650. vertical-align: -0.2em;
  1651. }
  1652.  
  1653. .tianyi-button {
  1654. margin-right: 20px;
  1655. padding: 4px 12px;
  1656. border-radius: 4px;
  1657. color: #fff;
  1658. font-size: 12px;
  1659. border: 1px solid ${color};
  1660. background: ${color};
  1661. cursor: pointer;
  1662. position: relative;
  1663. }
  1664.  
  1665. .tianyi-button:hover {
  1666. border-color: ${color}b0;
  1667. background: ${color}b0;
  1668. }
  1669.  
  1670. .yidong-button {
  1671. float: left;
  1672. position: relative;
  1673. margin: 20px 24px 20px 0;
  1674. width: 110px;
  1675. height: 36px;
  1676. background: ${color};
  1677. border-radius: 2px;
  1678. font-size: 14px;
  1679. color: #fff;
  1680. line-height: 39px;
  1681. text-align: center;
  1682. cursor: pointer;
  1683. }
  1684.  
  1685. .yidong-share-button {
  1686. display: inline-block;
  1687. position: relative;
  1688. font-size: 14px;
  1689. line-height: 36px;
  1690. height: 36px;
  1691. text-align: center;
  1692. color: #fff;
  1693. border: 1px solid ${color};
  1694. border-radius: 2px;
  1695. padding: 0 24px;
  1696. background: ${color};
  1697. }
  1698.  
  1699. .yidong-share-button:hover {
  1700. background: ${color}b0;
  1701. }
  1702.  
  1703. .yidong-button:hover {
  1704. background: ${color}b0;
  1705. }
  1706.  
  1707. .yidong-btn {
  1708. background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAGNQTFRFAAAA////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////mkUNoAAAACF0Uk5TAAbHPP9AMRtr9PwrV8zqXfmNgDODHTLD4iJxhGJJ8Z269m0aDgAAAMZJREFUeJzd0ssOgyAQBVDUK74rWq0PFP3/ryxqTMdGqJtuvGHD5CTDTGDs3nFc17kEPcC7BH3At/Tjvk5AYbBU+NcrwghL4uQDk3gtRSF1KWCCQEpghkd+3jp/ICNQoDANU0AQCJQmWAJ3h8+q3mFdvSywQdttsGvRWGAPLReoHXrbG6WWAzBoJ+3DaCnWI39NLbcvszvLeuTB2fYoqbNBNo7sGjzk31BhMsEJitxmiKk8zSQwE8gFjBGcNuCzOmdqPrib5A2JRQ7qK9g+hQAAAABJRU5ErkJggg==);
  1709. height: 20px;
  1710. line-height: 20px;
  1711. display: inline-block;
  1712. background-repeat: no-repeat;
  1713. background-size: 20px 20px;
  1714. text-indent: 25px;
  1715. }
  1716.  
  1717. .xunlei-button {
  1718. display: inline-flex;
  1719. align-items: center;
  1720. justify-content: center;
  1721. border: 0 solid transparent;
  1722. border-radius: 5px;
  1723. box-shadow: 0 0 0 0 transparent;
  1724. width: fit-content;
  1725. white-space: nowrap;
  1726. flex-shrink: 0;
  1727. font-size: 14px;
  1728. line-height: 1.5;
  1729. outline: 0;
  1730. touch-action: manipulation;
  1731. transition: background .3s ease, color .3s ease, border .3s ease, box-shadow .3s ease;
  1732. color: #fff;
  1733. background: ${color};
  1734. margin-left: 12px;
  1735. padding: 0px 12px;
  1736. position: relative;
  1737. cursor: pointer;
  1738. height: 36px;
  1739. }
  1740.  
  1741. .xunlei-button:hover {
  1742. background: ${color}b0;
  1743. }
  1744.  
  1745. .quark-button {
  1746. background: ${color} !important;
  1747. background-color:${color} !important;
  1748. }
  1749.  
  1750. .quark-button:hover {
  1751. background: ${color}b0 !important;
  1752. background-color:${color}b0 !important;
  1753. }
  1754.  
  1755. .quark-btn-icon {
  1756. width: 20px;
  1757. height: 20px;
  1758. vertical-align: -0.3em;
  1759. }
  1760.  
  1761. .element-clicked {
  1762. opacity: 0.5;
  1763. }
  1764.  
  1765. .pl-extra {
  1766. margin-top: 10px;
  1767. background-color:${color}15;
  1768. border-radius: 10px;
  1769. display: flex
  1770. }
  1771.  
  1772. .pl-extra button {
  1773. flex: 1
  1774. }
  1775.  
  1776. .pointer {
  1777. cursor: pointer
  1778. }
  1779.  
  1780. .pl-setting-label {
  1781. display: flex;
  1782. align-items: center;
  1783. justify-content: space-between;
  1784. padding-top: 10px;
  1785. }
  1786.  
  1787. .pl-label {
  1788. flex: 0 0 100px;
  1789. text-align: left;
  1790. }
  1791.  
  1792. .pl-input {
  1793. flex: 1;
  1794. padding: 8px 10px !important;
  1795. border: 1px solid #c2c2c2;
  1796. border-radius: 5px;
  1797. font-size: 14px !important;
  1798. min-width: 300px;
  1799. margin: 0;
  1800. darktheme
  1801. }
  1802.  
  1803. .init-input {
  1804. width: 400px;
  1805. margin: 1em 1em 3px;
  1806. font-size: 20px;
  1807. text-align: center;
  1808. font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif;
  1809. font-weight: 300;
  1810. }
  1811.  
  1812. .pl-color {
  1813. flex: 1;
  1814. display: flex;
  1815. flex-wrap: wrap
  1816. }
  1817.  
  1818. .pl-color-box {
  1819. width: 55px;
  1820. height: 55px;
  1821. margin: 10px 10px 0 0;
  1822. box-sizing: border-box;
  1823. border: 1px solid #fff;
  1824. cursor: pointer
  1825. }
  1826.  
  1827. .pl-mask {
  1828. width: 53px;
  1829. height: 53px;
  1830. opacity: 0;
  1831. transition: opacity 0.3s;
  1832. color: #fff;
  1833. font-size: 13px;
  1834. display: flex;
  1835. align-items: center;
  1836. justify-content: center;
  1837. flex-direction: column;
  1838. }
  1839.  
  1840. .pl-color-box:hover .pl-mask {
  1841. opacity: 1;
  1842. }
  1843.  
  1844. .pl-close:focus {
  1845. outline: 0;
  1846. box-shadow: none;
  1847. }
  1848.  
  1849. .tag-danger {
  1850. color: #cc3235;
  1851. margin: 0 5px;
  1852. }
  1853.  
  1854. .pl-tooltip {
  1855. position: absolute;
  1856. color: #ffffff;
  1857. max-width: 600px;
  1858. font-size: 12px;
  1859. padding: 5px 10px;
  1860. background: #333;
  1861. border-radius: 5px;
  1862. z-index: 110000;
  1863. line-height: 1.3;
  1864. display: none;
  1865. word-break: break-all;
  1866. }
  1867.  
  1868. @keyframes load {
  1869. 0% {
  1870. transform: rotate(0deg)
  1871. }
  1872.  
  1873. 100% {
  1874. transform: rotate(360deg)
  1875. }
  1876. }
  1877.  
  1878. .pl-loading-box>div>div {
  1879. position: absolute;
  1880. border-radius: 50%;
  1881. }
  1882.  
  1883. .pl-loading-box>div>div:nth-child(1) {
  1884. top: 9px;
  1885. left: 9px;
  1886. width: 82px;
  1887. height: 82px;
  1888. background: #ffffff;
  1889. }
  1890.  
  1891. .pl-loading-box>div>div:nth-child(2) {
  1892. top: 14px;
  1893. left: 38px;
  1894. width: 25px;
  1895. height: 25px;
  1896. background: #666666;
  1897. animation: load 1s linear infinite;
  1898. transform-origin: 12px 36px;
  1899. }
  1900.  
  1901. .pl-loading {
  1902. width: 16px;
  1903. height: 16px;
  1904. display: inline-block;
  1905. overflow: hidden;
  1906. background: none;
  1907. }
  1908.  
  1909. .pl-loading-box {
  1910. width: 100%;
  1911. height: 100%;
  1912. position: relative;
  1913. transform: translateZ(0) scale(0.16);
  1914. backface-visibility: hidden;
  1915. transform-origin: 0 0;
  1916. }
  1917.  
  1918. .pl-loading-box div {
  1919. box-sizing: content-box;
  1920. }
  1921.  
  1922. .pl-dropdown-menu {
  1923. position: absolute;
  1924. padding: 5px 0;
  1925. color: ${color};
  1926. background: themecolor;
  1927. z-index: 999;
  1928. width: 110px;
  1929. border-radius: 5px;
  1930. box-shadow: 0 1px 6px ${color}33;
  1931. -webkit-box-shadow: 0 1px 6px ${color}33;
  1932. text-align: center;
  1933. border: none;
  1934. transition: all 0.2s ease;
  1935. }
  1936.  
  1937. .pl-button-save {
  1938. background-color: ${color} !important;
  1939. color:#fff !important;
  1940. }
  1941.  
  1942. .pl-button-save:hover {
  1943. background-color: ${color}D0 !important;
  1944. color:#fff !important;
  1945. }
  1946.  
  1947. .swal2-container {
  1948. z-index: 100000;
  1949. }
  1950.  
  1951. body.swal2-height-auto {
  1952. height: inherit;
  1953. }
  1954.  
  1955. svg.icon-rpc-devices {
  1956. width: 13px;
  1957. height: 13px;
  1958. }
  1959.  
  1960. [class^="swal2-"], [class*="pl-btn"] {
  1961. transition:all 0.3s ease;
  1962. }
  1963.  
  1964. /* 适配(改)百度网盘会员青春版 */
  1965. a.downloadSubtitle, button.downloadSubtitle {
  1966. transition:all 0.3s ease;
  1967. background-color: ${color};
  1968. }
  1969.  
  1970. a.downloadSubtitle:hover, button.downloadSubtitle:hover {
  1971. background-color: ${color}D0;
  1972. }
  1973.  
  1974. a.downloadSubtitle:disabled, button.downloadSubtitle:disabled {
  1975. background-color: ${color}D0;
  1976. }
  1977.  
  1978. @media (prefers-color-scheme: dark) [data-theme=system] * {
  1979. color-scheme: dark;
  1980. }
  1981.  
  1982. /* RGB! */
  1983. @keyframes hue-rotate {
  1984. 0% {
  1985. filter: hue-rotate()
  1986. }
  1987.  
  1988. to {
  1989. filter: hue-rotate(-360deg)
  1990. }
  1991. }
  1992.  
  1993. /* Webkit, Opera, IE9, Chrome*/
  1994. ::selection {
  1995. background-color: ${color} !important;
  1996. background: ${color} !important;
  1997. color: white !important;
  1998. }
  1999.  
  2000. /* Mozilla Firefox */
  2001. ::-moz-selection {
  2002. background-color: ${color} !important;
  2003. background: ${color} !important;
  2004. color: white !important;
  2005. }
  2006.  
  2007. /* 百度网盘 */
  2008. :not([class*="rwl-exempt"]) ::selection {
  2009. background-color: ${color} !important;
  2010. background: ${color} !important;
  2011. color: white !important;
  2012. }
  2013. `;
  2014. // 先监听颜色方案变化
  2015. window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
  2016. if (e.matches) {
  2017. // 切换到暗色主题
  2018. let dark = uicss.replace("themecolor", "#19191a").replace("darktheme", "color-scheme: dark;");
  2019. base.addStyle('Panlinker-UI', 'style', dark);
  2020. } else {
  2021. // 切换到浅色主题
  2022. let light = uicss.replace("themecolor", "#fff").replace("darktheme", "");
  2023. base.addStyle('Panlinker-UI', 'style', light);
  2024. }
  2025. });
  2026. // 再修改主题
  2027. if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  2028. let dark = uicss.replace("themecolor", "#19191a").replace("darktheme", "color-scheme: dark;");
  2029. base.addStyle('Panlinker-UI', 'style', dark);
  2030. } else {
  2031. // 切换到浅色主题
  2032. let light = uicss.replace("themecolor", "#fff").replace("darktheme", "");
  2033. base.addStyle('Panlinker-UI', 'style', light);
  2034. }
  2035.  
  2036. if (/(pan|yun).baidu.com/.test(location.host) && location.pathname !== '/disk/home' && base.getValue('setting_theme_baidu') === 'yes') {
  2037. base.setColors([
  2038. ['#717fff', `${color}`],
  2039. ['#717FFF', `${color}`],
  2040. ['#06a8ff', `${color}`],
  2041. ['#06A8FF', `${color}`],
  2042. ['#06a7ff', `${color}`],
  2043. ['#06A7FF', `${color}`],
  2044. ['#dcdfe6', `${color}`],
  2045. ['#DCDFE6', `${color}`],
  2046. ['#0095ff', `${color}`],
  2047. ['#0095FF', `${color}`],
  2048. ['#09aaff', `${color}`],
  2049. ['#09AAFF', `${color}`],
  2050. ['#0ca6ff', `${color}`],
  2051. ['#0CA6FF', `${color}`],
  2052. ['#5040ff', `${color}`],
  2053. ['#5040FF', `${color}`],
  2054. ['#454d5a', `${color}`],
  2055. ['#454D5A', `${color}`],
  2056. ['#a2abbd', `${color}`],
  2057. ['#A2ABBD', `${color}`],
  2058. ['#030b1a', `${color}`],
  2059. ['#030B1A', `${color}`],
  2060. ['#afb3bf', `${color}`],
  2061. ['#AFB3BF', `${color}`],
  2062. ['#ff436a', `${color}`],
  2063. ['#FF436A', `${color}`],
  2064. ['#03081a', `${color}`],
  2065. ['#03081A', `${color}`],
  2066. ['#2974b6', `${color}`],
  2067. ['#2974B6', `${color}`],
  2068. ['#0596e6', `${color}`],
  2069. ['#0596E6', `${color}`],
  2070.  
  2071. ['#C3EAFF', `${color}`],
  2072. ['#c0d9fe', `${color}50`],
  2073. ['#0098EA', `${color}D0`],
  2074.  
  2075. ['#38b9ff', `${color}D0`],
  2076. ['#38B9FF', `${color}D0`],
  2077. ['#42d8ff', `${color}D0`],
  2078. ['#42D8FF', `${color}D0`],
  2079. ['#a48dff', `${color}D0`],
  2080. ['#A48DFF', `${color}D0`],
  2081. ['#6b79f2', `${color}D0`],
  2082. ['#6B79F2', `${color}D0`],
  2083.  
  2084. ['#9c86f2', `${color}90`],
  2085. ['#9C86F2', `${color}90`],
  2086. ['#83d3ff', `${color}90`],
  2087. ['#83D3FF', `${color}90`],
  2088. ['#C4D8F4', `${color}90`],
  2089.  
  2090. ['#fafafc', `${color}20`],
  2091. ['#FAFAFC', `${color}20`],
  2092. ['#f5fbff', `${color}20`],
  2093. ['#F5FBFF', `${color}20`],
  2094. ['#b4e5ff', `${color}20`],
  2095. ['#B4E5FF', `${color}20`],
  2096. ['#f0faff', `${color}20`],
  2097. ['#F0FAFF', `${color}20`],
  2098. ['#c4d8f4', `${color}20`],
  2099.  
  2100. ['#f1f3f8', `${color}15`],
  2101. ['#F1F3F8', `${color}15`],
  2102.  
  2103. ['#f2faff', `${color}10`],
  2104. ['#F2FAFF', `${color}10`],
  2105. ['#eef9fe', `${color}10`],
  2106. ['#EEF9FE', `${color}10`],
  2107. ['#f7f9fc', `${color}10`],
  2108. ['#F7F9FC', `${color}10`],
  2109. ['#f5f6fa', `${color}10`],
  2110. ['#F5F6FA', `${color}10`],
  2111. ['#b4e5ff', `${color}10`],
  2112. ['#B4E5FF', `${color}10`],
  2113. ['#e6f6ff', `${color}10`],
  2114. ['#E6F6FF', `${color}10`],
  2115.  
  2116. ['0,149,255', base.hexToRgba(color)],
  2117. ['30, 175, 255', base.hexToRgba(color)],
  2118. ['6,167,255,.1', base.hexToRgba(`${color}15`)],
  2119. ['6,167,255,.23', base.hexToRgba(`${color}3b`)],
  2120. ['164,141,255,.2', base.hexToRgba(`${color}30`)],
  2121. ['196,182,255,.2', base.hexToRgba(`${color}20`)],
  2122. ['113,127,255,.2', base.hexToRgba(`${color}40`)],
  2123. ['3,8,26,.6', base.hexToRgba(`${color}D0`)],
  2124. ['255,32,102,.4', base.hexToRgba(`${color}66`)],
  2125. ['72,166,248,.7', base.hexToRgba(`${color}66`)],
  2126. ]);
  2127. };
  2128. if (/(pan|yun).baidu.com/.test(location.host) && base.getValue('setting_theme_baidu') === 'yes') {
  2129. base.addStyle('Panlinker-UI-Baidu', 'style', `
  2130. #layoutMain,
  2131. .DxdbeCb {
  2132. border-radius: 10px;
  2133. border-bottom-left-radius: 0;
  2134. border-bottom-right-radius: 0;
  2135. background: #ffffffA0 !important
  2136. }
  2137. .KPDwCE,
  2138. .DxdbeCb .OFaPaO .tanwePYr,
  2139. .xGLMIab .fufHyA:hover,
  2140. .module-search-timeline .form-box {
  2141. background: #ffffffA0 !important;
  2142. }
  2143. .KPDwCE .JDeHdxb,
  2144. .NHcGw .AuPKyz,
  2145. .xGLMIab .tvPMvPb,
  2146. .xGLMIab .FcQMwt,
  2147. .cazEfA .yfHIsP,
  2148. .hscjZ4QL .bbxnZ0Bq .ehnyLxWZ span,
  2149. .module-topToolBar,
  2150. .module-timeline-view .timeline-title-curday {
  2151. background: transparent !important;
  2152. border-bottom: 0;
  2153. }
  2154. .MdLxwM {
  2155. background :#fff !important;
  2156. }
  2157. .aside-absolute-container .QGOvsxb .remainingSpaceUi_span {
  2158. /*background: ${color} !important;*/
  2159. background: #8af248 !important;
  2160. border-radius: 10px 0 0 10px;
  2161. border-right: #fff 1px solid;
  2162. border-bottom: #fff 1px solid;
  2163. }
  2164. .xtJbHcb .CDaavKb .KQcHyA {
  2165. background: rgb(244,207,0) !important;
  2166. padding: 8px 15px;
  2167. }
  2168. .xtJbHcb .web-header-nav-new-version-inner {
  2169. background: ${color} !important;
  2170. padding: 8px 15px;
  2171. line-height: 15px;
  2172. width: auto;
  2173. height: auto;
  2174. }
  2175. a {
  2176. transition: all 0.2s ease !important;
  2177. }
  2178. #bd-main .bd-left {
  2179. margin: auto !important;
  2180. }
  2181. .verify-input input {
  2182. padding-left: 0 !important;
  2183. text-align: center !important;
  2184. }
  2185. .verify-input input:focus {
  2186. border: 2px solid ${color} !important;
  2187. }
  2188. [data-theme=light] .vp-video-page-card .vp-video-page-card__video-detail {
  2189. color: #030b1a;
  2190. }
  2191. `, 'body');
  2192. base.setColors([
  2193. ['#717fff', `${color}`],
  2194. ['#717FFF', `${color}`],
  2195. ['#06a8ff', `${color}`],
  2196. ['#06A8FF', `${color}`],
  2197. ['#06a7ff', `${color}`],
  2198. ['#06A7FF', `${color}`],
  2199. ['#dcdfe6', `${color}`],
  2200. ['#DCDFE6', `${color}`],
  2201. ['#0095ff', `${color}`],
  2202. ['#0095FF', `${color}`],
  2203. ['#09aaff', `${color}`],
  2204. ['#09AAFF', `${color}`],
  2205. ['#0ca6ff', `${color}`],
  2206. ['#0CA6FF', `${color}`],
  2207. ['#5040ff', `${color}`],
  2208. ['#5040FF', `${color}`],
  2209. ['#454d5a', `${color}`],
  2210. ['#454D5A', `${color}`],
  2211. ['#a2abbd', `${color}`],
  2212. ['#A2ABBD', `${color}`],
  2213. ['#030b1a', `${color}`],
  2214. ['#030B1A', `${color}`],
  2215. ['#afb3bf', `${color}`],
  2216. ['#AFB3BF', `${color}`],
  2217. ['#ff436a', `${color}`],
  2218. ['#FF436A', `${color}`],
  2219. ['#03081a', `${color}`],
  2220. ['#03081A', `${color}`],
  2221. ['#2974b6', `${color}`],
  2222. ['#2974B6', `${color}`],
  2223. ['#0596e6', `${color}`],
  2224. ['#0596E6', `${color}`],
  2225.  
  2226. ['#C3EAFF', `${color}`],
  2227. ['#c0d9fe', `${color}50`],
  2228. ['#0098EA', `${color}D0`],
  2229.  
  2230. ['#38b9ff', `${color}D0`],
  2231. ['#38B9FF', `${color}D0`],
  2232. ['#42d8ff', `${color}D0`],
  2233. ['#42D8FF', `${color}D0`],
  2234. ['#a48dff', `${color}D0`],
  2235. ['#A48DFF', `${color}D0`],
  2236. ['#6b79f2', `${color}D0`],
  2237. ['#6B79F2', `${color}D0`],
  2238.  
  2239. ['#9c86f2', `${color}90`],
  2240. ['#9C86F2', `${color}90`],
  2241. ['#83d3ff', `${color}90`],
  2242. ['#83D3FF', `${color}90`],
  2243. ['#C4D8F4', `${color}90`],
  2244.  
  2245. ['#fafafc', `${color}20`],
  2246. ['#FAFAFC', `${color}20`],
  2247. ['#f5fbff', `${color}20`],
  2248. ['#F5FBFF', `${color}20`],
  2249. ['#b4e5ff', `${color}20`],
  2250. ['#B4E5FF', `${color}20`],
  2251. ['#f0faff', `${color}20`],
  2252. ['#F0FAFF', `${color}20`],
  2253. ['#c4d8f4', `${color}20`],
  2254.  
  2255. ['#f1f3f8', `${color}15`],
  2256. ['#F1F3F8', `${color}15`],
  2257.  
  2258. ['#f2faff', `${color}10`],
  2259. ['#F2FAFF', `${color}10`],
  2260. ['#eef9fe', `${color}10`],
  2261. ['#EEF9FE', `${color}10`],
  2262. ['#f7f9fc', `${color}10`],
  2263. ['#F7F9FC', `${color}10`],
  2264. ['#f5f6fa', `${color}10`],
  2265. ['#F5F6FA', `${color}10`],
  2266. ['#b4e5ff', `${color}10`],
  2267. ['#B4E5FF', `${color}10`],
  2268. ['#e6f6ff', `${color}10`],
  2269. ['#E6F6FF', `${color}10`],
  2270.  
  2271. ['0,149,255', base.hexToRgba(color)],
  2272. ['30, 175, 255', base.hexToRgba(color)],
  2273. ['6,167,255,.1', base.hexToRgba(`${color}15`)],
  2274. ['6,167,255,.23', base.hexToRgba(`${color}3b`)],
  2275. ['164,141,255,.2', base.hexToRgba(`${color}30`)],
  2276. ['196,182,255,.2', base.hexToRgba(`${color}20`)],
  2277. ['113,127,255,.2', base.hexToRgba(`${color}40`)],
  2278. ['3,8,26,.6', base.hexToRgba(`${color}D0`)],
  2279. ['255,32,102,.4', base.hexToRgba(`${color}66`)],
  2280. ['72,166,248,.7', base.hexToRgba(`${color}66`)],
  2281. ], "other");
  2282. };
  2283. if (/www.(aliyundrive|alipan).com/.test(location.host) && base.getValue('setting_theme_ali') === 'yes') {
  2284. base.setColors([
  2285. ['#3763ff', `${color}`],
  2286. ['#8664ff', `${color}D0`],
  2287. ['99, 125, 255', base.hexToRgba(color)],
  2288. ['132, 133, 141', base.hexToRgba(color)],
  2289. ['112, 136, 255', base.hexToRgba(color)],
  2290. ['97, 122, 250', base.hexToRgba(color)],
  2291. ['68, 109, 255', base.hexToRgba(color)],
  2292. ['82, 110, 250', base.hexToRgba(`${color}20`)],
  2293. ['122, 144, 255', base.hexToRgba(`${color}D0`)],
  2294. ['138, 157, 255', base.hexToRgba(`${color}D0`)],
  2295. ['49, 49, 54', base.hexToRgba(color)],
  2296. ]);
  2297. };
  2298. if (/cloud.189.cn/.test(location.host) && base.getValue('setting_theme_tianyi') === 'yes') {
  2299. base.setColors([
  2300. ['#2b89ea', `${color}`],
  2301. ['#1874d3', `${color}F0`],
  2302. ['#1890ff', `${color}`],
  2303. ['#388fc9', `${color}`],
  2304. ['#0087ff', `${color}`],
  2305. ['#255697', `${color}`],
  2306. ['#3ea6ff', `${color}80`],
  2307. ['#1d52f2', `${color}`],
  2308. ['#3699ff', `${color}D0`],
  2309. ['#f4f9fe', `${color}10`],
  2310. ['#eaf5ff', `${color}20`],
  2311. ], "other");
  2312. }
  2313. if (/pan.xunlei.com/.test(location.host) && base.getValue('setting_theme_xunlei') === 'yes') {
  2314. base.setColors([
  2315. ['#3f85ff', `${color}`],
  2316. ['63,133,255,.1', base.hexToRgba(`${color}20`)],
  2317. ['#2670ea', `${color}D0`],
  2318. ['#619bff', `${color}D0`],
  2319. ['#ecf3ff', `${color}10`],
  2320. ['#f6faff', `${color}10`],
  2321. ['#1a2845', `${color}20`],
  2322. ['#eee', `${color}20`],
  2323. ], "other");
  2324. base.addStyle('Panlinker-UI-Xunlei', 'style', `
  2325. .web-header {
  2326. background: linear-gradient(0deg,${color}D0,${color})
  2327. }
  2328. `);
  2329. };
  2330. if (/pan.quark.cn/.test(location.host) && base.getValue('setting_theme_quark') === 'yes') {
  2331. base.setColors([
  2332. ['#0d53ff', `${color}`],
  2333. ['#e6f1ff', `${color}20`],
  2334. ['#f0faff', `${color}20`],
  2335. ['#7da3ff', `${color}D0`],
  2336. ['#ddd', `${color}D0`],
  2337. ['17,17,17,.9', base.hexToRgba(`${color}D0`)],
  2338. ['40,40,255,.04', base.hexToRgba(`${color}20`)],
  2339. ['#f7f7ff', 'transparent'],
  2340. ['238,247,255,0', base.hexToRgba(`${color}00`)],
  2341. ]);
  2342. base.addStyle('Panlinker-UI-Quark', 'style', `
  2343. .file-list .hover-oper .hover-transparent-bg {
  2344. background: transparent !important;
  2345. }
  2346. `);
  2347. };
  2348. if (/(yun|caiyun).139.com/.test(location.host) && base.getValue('setting_theme_yidong') === 'yes') {
  2349. base.setColors([
  2350. ['#3181f9', `${color}`],
  2351. ['#5a9afa', `${color}`],
  2352. ['#98c0fc', `${color}D0`],
  2353. ['#2d76e5', `${color}D0`],
  2354. ['49,129,249,.08', base.hexToRgba(`${color}20`)],
  2355. ]);
  2356. };
  2357. if (/.*.youxiaohou.com/.test(location.host)) {
  2358. base.setColors([
  2359. ['#00aefe', `${color}`],
  2360. ['#4e6e8e', `${color}`],
  2361. ['#009fe8', `${color}`],
  2362. ['#008fd1', `${color}`],
  2363. ['#05b0ff', `${color}D0`],
  2364. ], "other");
  2365. base.addStyle('Panlinker-UI-Youxiaohou', 'style', `
  2366. a[aria-label="View source on GitHub"] svg[style^="fill"] {
  2367. fill: ${color} !important;
  2368. }
  2369. `);
  2370. };
  2371. },
  2372.  
  2373. // 暗号界面
  2374. async initDialog() {
  2375. let secret = ""
  2376. if (base.getValue('setting_server_main') === 'v1') {
  2377. secret = "当前暗号是‘" + pan.num + "’";
  2378. } else if (base.getValue('setting_server_main') === 'v2') {
  2379. secret = "当前开源协议是‘" + pan.license + "’,暗号是‘" + pan.num + "’";
  2380. } else if (base.getValue('setting_server_main') === "no") {
  2381. secret = "当前暗号是‘" + pan.num + "’";
  2382. } else {
  2383. base.setValue('setting_server_main', 'v2');
  2384. secret = '<span style="color:red">检测到当前配置不正确,已自动修复<br/>请在刷新页面后再继续输入</span>';
  2385. }
  2386. let dialog = await Swal.fire({
  2387. title: `请阅读完以下全文再继续`,
  2388. allowOutsideClick: false,
  2389. showCloseButton: true,
  2390. showDenyButton: true,
  2391. confirmButtonText: '确定',
  2392. heightAuto: false,
  2393. scrollbarPadding: false,
  2394. html: `<div><img style="width: 250px;margin-bottom: 10px;" src="${pan.img}" alt="${pan.img}">
  2395. <input class="swal2-input init-input" id="init" type="text" placeholder="${pan.init[1]}"></div>
  2396. <div><span>服务器说道: ${pan.init[0]}”;</span></div>
  2397. <div><span>脚本说道: ${secret}”。</span></div>
  2398. <div>↓</div>
  2399. <div><span>但史丹利不知道的是,他可以按下<span style="color:red;font-style:italic;vertical-align:unset;">红色按钮</span>来点亮按钮</span></div>
  2400. <div><span>或者有仪式感地 输入以上暗号/开源协议 点亮</span></div>
  2401. <div><span>输入一些<span style="font-style:italic;vertical-align:unset;">恶臭的数字</span>以及<span style="font-style:italic;vertical-align:unset;">特殊的时间戳</span>甚至有彩蛋</span></div>
  2402. <div>↓</div>
  2403. <div><span><a target="_blank" href="https://www.youxiaohou.com" style="vertical-align:unset;">原作者</a>开发很辛苦,所以请有能力的你请支持下他的公众号</span></div>
  2404. <div><span>实在不行的话,那就来给这个改版点个<a href="https://github.com/hmjz100/Online-disk-direct-link-download-assistant/" style="vertical-align:unset;">Star</a>吧...</span></div>
  2405. <div><span>点亮后不仅能精简网盘界面 还能改变众多网盘主题色哦!</span></div>
  2406. `,
  2407. denyButtonText: '我就不输入,点我“注入”直接点亮'
  2408. });
  2409. if (dialog.isDenied) {
  2410. console.log("【(改)网盘直链下载助手】\n正在注入点亮按钮设置项目...");
  2411. message.warning("正在注入设置项目...");
  2412. setTimeout(function () {
  2413. base.setValue('setting_init_code', pan.num);
  2414. base.setValue('setting_init_license', pan.license);
  2415. message.success("注入成功了!");
  2416. setTimeout(function () {
  2417. message.success(pan.init[2]);
  2418. setTimeout(function () {
  2419. location.reload();
  2420. }, 1500);
  2421. }, 1500);
  2422. }, 2500);
  2423. };
  2424. if (dialog.isConfirmed) {
  2425. if (pan.num === $('#init').val() || pan.license === $('#init').val()) {
  2426. console.log("【(改)网盘直链下载助手】\n暗号或协议正确")
  2427. message.success(pan.init[2]);
  2428. setTimeout(function () {
  2429. base.setValue('setting_init_code', pan.num);
  2430. base.setValue('setting_init_license', pan.license);
  2431. location.reload();
  2432. }, 3000)
  2433. } else if ($('#init').val() === '114514' || $('#init').val() === '1919810' || $('#init').val() === '1145141919810') {
  2434. /*---
  2435. homo彩蛋又回来力(喜)
  2436. imageUrl: 'https://pic4.zhimg.com/80/v2-1b97a088e156c015108dec663bba8b04.jpg',
  2437. imageUrl: 'https://lh1.hetaousercontent.com/img/7d4c1c0b4adb0e95.jpg',
  2438. */
  2439. await Swal.fire({
  2440. icon: 'error',
  2441. title: '1145141919810',
  2442. html: '<span>homo特有的数字当然不行啦<br/>哼哼哼啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊</span>',
  2443. timer: 4000,
  2444. imageUrl: 'https://pic1.zhimg.com/v2-1b97a088e156c015108dec663bba8b04.avis',
  2445. allowOutsideClick: false,
  2446. timerProgressBar: true,
  2447. showConfirmButton: false,
  2448. showDenyButton: true,
  2449. heightAuto: false,
  2450. scrollbarPadding: false,
  2451. denyButtonText: '哼哼哼啊啊啊啊啊啊啊啊啊啊',
  2452. });
  2453. message.info("成就:你触发了一个homo特有的彩蛋!");
  2454. setTimeout(function () {
  2455. Swal.fire({
  2456. title: '1145141919810',
  2457. text: 'homo特有的数字当然不行啦...吗?',
  2458. icon: 'question',
  2459. imageUrl: 'https://lh1.hetaousercontent.com/img/7d4c1c0b4adb0e95.jpg',
  2460. showConfirmButton: false,
  2461. allowOutsideClick: false,
  2462. });
  2463. setTimeout(function () {
  2464. base.setValue('setting_init_code', pan.num);
  2465. base.setValue('setting_init_license', pan.license);
  2466. message.success("成就:哼哼哼啊啊啊啊啊啊啊啊地注入成功(喜)");
  2467. location.reload();
  2468. }, 3000)
  2469. }, 4000)
  2470. } else if ($('#init').val() === '1562118175') {
  2471. await Swal.fire({
  2472. icon: 'error',
  2473. title: "What's your problem?",
  2474. html: '<span>那天AI开发者大会上,有人给AI‘泼冷水’。<br/>我们想说,AI前进的道路上会有各种各样想象不到的事情发生,但我们添加会员制的决心不会改变。</span>',
  2475. timer: 5000,
  2476. imageUrl: 'https://pic1.zhimg.com/v2-5fef2a8993a3fff57c6381dfb3a0f577.avis',
  2477. allowOutsideClick: false,
  2478. timerProgressBar: true,
  2479. showConfirmButton: false,
  2480. showDenyButton: true,
  2481. heightAuto: false,
  2482. scrollbarPadding: false,
  2483. denyButtonText: '怡宝',
  2484. });
  2485. message.info("成就:你触发了宏彦获水彩蛋!");
  2486. setTimeout(function () {
  2487. base.setValue('setting_init_code', pan.num);
  2488. base.setValue('setting_init_license', pan.license);
  2489. message.success("成就:你靠一瓶怡宝注入成功");
  2490. location.reload();
  2491. }, 4000)
  2492. } else {
  2493. console.log("【(改)网盘直链下载助手】\n暗号错误")
  2494. await Swal.fire({
  2495. imageUrl: pan.img,
  2496. title: pan.init[3],
  2497. heightAuto: false,
  2498. scrollbarPadding: false,
  2499. html: `<div><span>${pan.init[4]}<br/>你可以在返回后选择“注入”立即点亮按钮,<br/>或者在输入框键入以下暗号:“${pan.num}”。</span></div>`,
  2500. confirmButtonText: '重新输入',
  2501. });
  2502. await this.initDialog();
  2503. return;
  2504. };
  2505. }
  2506. },
  2507. /*--- waitForKeyElements(): 一个实用函数,用于 Greasemonkey 脚本,
  2508. 它可以检测和处理AJAX加载的内容。
  2509. 使用示例:
  2510. base.waitForKeyElements (
  2511. "div.comments"
  2512. , commentCallbackFunction
  2513. );
  2514. // 页面特定的函数,用于在找到节点时执行我们想要的操作。
  2515. function commentCallbackFunction (jNode) {
  2516. jNode.text ("waitForKeyElements() 更改了这段注释。");
  2517. }
  2518. 重要提示:这个函数需要你的脚本加载了jQuery。
  2519. */
  2520. waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector) {
  2521. let targetNodes, btargetsFound;
  2522.  
  2523. if (typeof iframeSelector == "undefined")
  2524. targetNodes = $(selectorTxt);
  2525. else
  2526. targetNodes = $(iframeSelector).contents()
  2527. .find(selectorTxt);
  2528.  
  2529. if (targetNodes && targetNodes.length > 0) {
  2530. btargetsFound = true;
  2531. targetNodes.each(function () {
  2532. let jThis = $(this);
  2533. let alreadyFound = jThis.data('alreadyFound') || false;
  2534.  
  2535. if (!alreadyFound) {
  2536. //--- 调用载荷函数。
  2537. let cancelFound = actionFunction(jThis);
  2538. if (cancelFound) {
  2539. btargetsFound = false;
  2540. } else {
  2541. jThis.data('alreadyFound', true);
  2542. }
  2543. }
  2544. });
  2545. } else {
  2546. btargetsFound = false;
  2547. }
  2548.  
  2549. //--- 获取这个选择器的定时器控制变量。
  2550. let controlObj = base.waitForKeyElements.controlObj || {};
  2551. let controlKey = selectorTxt.replace(/[^\w]/g, "_");
  2552. let timeControl = controlObj[controlKey];
  2553.  
  2554. //--- 现在根据情况设置或清除定时器。
  2555. if (btargetsFound && bWaitOnce && timeControl) {
  2556. //--- 唯一需要清除定时器的情况。
  2557. clearInterval(timeControl);
  2558. delete controlObj[controlKey]
  2559. } else {
  2560. //--- 如果需要的话,设置一个定时器。
  2561. if (!timeControl) {
  2562. timeControl = setInterval(function () {
  2563. base.waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector);
  2564. }, 1000);
  2565. controlObj[controlKey] = timeControl;
  2566. }
  2567. }
  2568. base.waitForKeyElements.controlObj = controlObj;
  2569. },
  2570. };
  2571. // 用于油小猴服务器检测的脚本信息,防止服务器返回更新信息
  2572. let author = base.getValue('setting_script_author'),
  2573. version = base.getValue('setting_script_version')
  2574.  
  2575. //百度网盘
  2576. let baidu = {
  2577.  
  2578. _getExtra() {
  2579. let seKey = decodeURIComponent(base.getCookie('BDCLND'));
  2580. return '{' + '"sekey":"' + seKey + '"' + "}";
  2581. },
  2582.  
  2583. _getSurl() {
  2584. let reg = /(?<=s\/|surl=)([a-zA-Z0-9_-]+)/g;
  2585. if (reg.test(location.href)) {
  2586. return location.href.match(reg)[0];
  2587. }
  2588. return '';
  2589. },
  2590.  
  2591. _getFidList() {
  2592. let fidlist = [];
  2593. for (const v of selectList) {
  2594. if (+v.isdir !== 1) {
  2595. fidlist.push(v.fs_id);
  2596. }
  2597. }
  2598. return '[' + fidlist + ']';
  2599. },
  2600.  
  2601. setBDUSS() {
  2602. try {
  2603. GM_cookie('list', { name: 'BDUSS' }, (cookies, error) => {
  2604. if (!error) {
  2605. let BDUSS = cookies?.[0]?.value;
  2606. if (BDUSS) {
  2607. base.setStorage("baiduyunPlugin_BDUSS", { BDUSS });
  2608. }
  2609. }
  2610. });
  2611. } catch (e) {
  2612. console.error("【(改)网盘直链下载助手】\nsetBDUSS\n错误信息:", e)
  2613. try {
  2614. let BDUSS = document.cookie.match(/BDUSS=(.*?)(;|$)/);
  2615. base.setStorage("baiduyunPlugin_BDUSS", { BDUSS: BDUSS });
  2616. } catch (e) {
  2617. console.error("【(改)网盘直链下载助手】\nsetBDUSS\n错误信息:", e)
  2618. }
  2619. }
  2620. },
  2621.  
  2622. getBDUSS() {
  2623. let baiduyunPlugin_BDUSS = base.getStorage('baiduyunPlugin_BDUSS') ? base.getStorage('baiduyunPlugin_BDUSS') : '{"baiduyunPlugin_BDUSS":""}';
  2624. return baiduyunPlugin_BDUSS.BDUSS || '';
  2625. },
  2626.  
  2627. convertLinkToAria(link, filename, ua) {
  2628. let BDUSS = this.getBDUSS();
  2629. if (!!BDUSS) {
  2630. filename = base.fixFilename(filename);
  2631. return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "User-Agent: ${ua}" --header "Cookie: BDUSS=${BDUSS}"`);
  2632. }
  2633. return {
  2634. link: pan.assistant,
  2635. text: pan.init[5]
  2636. };
  2637. },
  2638.  
  2639. convertLinkToBC(link, filename, ua) {
  2640. let BDUSS = this.getBDUSS();
  2641. if (!!BDUSS) {
  2642. let cookie = `BDUSS=${BDUSS}`;
  2643. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&cookie=${encodeURIComponent(cookie)}&user_agent=${encodeURIComponent(ua)}ZZ`;
  2644. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  2645. }
  2646. return {
  2647. link: pan.assistant,
  2648. text: pan.init[5]
  2649. };
  2650. },
  2651.  
  2652. convertLinkToCurl(link, filename, ua) {
  2653. let BDUSS = this.getBDUSS();
  2654. if (!!BDUSS) {
  2655. let terminal = base.getValue('setting_terminal_type');
  2656. filename = base.fixFilename(filename);
  2657. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}" -A "${ua}" -b "BDUSS=${BDUSS}"`);
  2658. }
  2659. return {
  2660. link: pan.assistant,
  2661. text: pan.init[5]
  2662. };
  2663. },
  2664.  
  2665. addPageListener() {
  2666. /*
  2667. 防止代码因其他原因被执行多次
  2668. 这段代码出自 Via轻插件,作者谷花泰
  2669. */
  2670. const key = encodeURIComponent('(改)网盘直链下载助手:百度网盘');
  2671. if (window[key]) return;
  2672. window[key] = true;
  2673.  
  2674. function _factory(e) {
  2675. let target = $(e.target);
  2676. let item = target.parents('.pl-item');
  2677. let link = item.find('.pl-item-link.blob');
  2678. let directLink = item.find('.pl-item-link.browser');
  2679. let progress = item.find('.pl-item-progress');
  2680. let tip = item.find('.pl-item-tip');
  2681. let copy = item.find('.pl-item-copy');
  2682. let howidm = item.find('.pl-progress-how');
  2683. let back = item.find('.pl-progress-back');
  2684. let stop = item.find('.pl-progress-stop');
  2685. return {
  2686. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  2687. };
  2688. }
  2689.  
  2690. function _reset(i) {
  2691. ins[i] && clearInterval(ins[i]);
  2692. request[i] && request[i].abort();
  2693. progress[i] = 0;
  2694. idm[i] = false;
  2695. }
  2696.  
  2697. doc.on('mouseenter mouseleave click', '.pl-button.g-dropdown-button', function (e) {
  2698. if (e.type === 'mouseleave') {
  2699. $(e.currentTarget).removeClass('button-open');
  2700. } else {
  2701. $(e.currentTarget).addClass('button-open');
  2702. $(e.currentTarget).find('.pl-dropdown-menu').show();
  2703. }
  2704. });
  2705. doc.on('mouseleave', '.pl-button.g-dropdown-button .pl-dropdown-menu', function (e) {
  2706. $(e.currentTarget).hide();
  2707. });
  2708.  
  2709. doc.on('click', '.pl-button-mode', function (e) {
  2710. mode = e.target.dataset.mode;
  2711. if (!mode) return;
  2712. Swal.fire({
  2713. heightAuto: false,
  2714. scrollbarPadding: false,
  2715. showConfirmButton: false,
  2716. html: `链接获取中`,
  2717. willOpen: function () {
  2718. Swal.showLoading();
  2719. }
  2720. });
  2721. baidu.getPCSLink();
  2722. });
  2723. doc.on('click', '.pl-button-save', async function (e) {
  2724. e.preventDefault();
  2725. selectList = baidu.getSelectedList();
  2726. if (selectList.length === 0) {
  2727. return message.error('提示:<br/>请勾选要保存到网盘的文件哦~');
  2728. }
  2729. message.info('提示:<br/>因网盘限制,请保存到自己网盘后再去下载哦~');
  2730. await base.sleep(500);
  2731. document.querySelector('.tools-share-save-hb').click();
  2732. });
  2733. doc.on('click', '.listener-link-api.browser', async function (e) {
  2734. e.preventDefault();
  2735. let dataset = e.currentTarget.dataset;
  2736. let href = dataset.link;
  2737. $('#downloadIframe').attr('src', href);
  2738. });
  2739. doc.on('click', '.listener-link-api.blob', async function (e) {
  2740. e.preventDefault();
  2741. let o = _factory(e);
  2742. let $width = o.item.find('.pl-progress-inner');
  2743. let $text = o.item.find('.pl-progress-inner-text');
  2744. let filename = o.link[0].dataset.filename;
  2745. let index = o.link[0].dataset.index;
  2746. _reset(index);
  2747. base.get(o.link[0].dataset.link, { "User-Agent": pan.ua }, 'blob', { filename, index });
  2748. let startTime = Date.now(); // 记录下载开始时间
  2749. let prevLoaded = 0; // 上一次的已下载数据量
  2750. let prevTime = startTime; // 上一次的时间
  2751. let size = Number(o.link[0].dataset.size);
  2752. ins[index] = setInterval(function () {
  2753. let prog = +progress[index] || 0;
  2754. let isIDM = idm[index] || false;
  2755.  
  2756. if (isIDM) {
  2757. // 处理IDM的代码
  2758. o.tip.hide();
  2759. o.progress.hide();
  2760. o.copy.show();
  2761. o.directLink.show()
  2762. o.link.text('链接已被IDM捕获~请查看IDM下载窗口哦!').animate({ opacity: '0.5' }, "slow").show();
  2763. clearInterval(ins[index]);
  2764. setTimeout(function () {
  2765. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  2766. }, 2000)
  2767. idm[index] = false;
  2768. } else {
  2769. // 处理普通下载的情况...
  2770. let currentTime = Date.now();
  2771. let elapsedTime = currentTime - startTime;
  2772. let totalProgress = prog / 100;
  2773. let totalElapsedSeconds = elapsedTime / 1000;
  2774. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  2775. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  2776.  
  2777. // 将剩余时间转换为天、时、分、秒
  2778. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  2779. remainingTimeSeconds %= (60 * 60 * 24);
  2780.  
  2781. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  2782. remainingTimeSeconds %= (60 * 60);
  2783.  
  2784. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  2785. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  2786.  
  2787. // 计算下载速度
  2788. let loaded = prog * size / 100; // 已下载数据量
  2789. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  2790. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  2791. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  2792.  
  2793. // 更新上一次的数据
  2794. prevLoaded = loaded;
  2795. prevTime = currentTime;
  2796.  
  2797. // 更改界面
  2798. o.link.hide();
  2799. o.directLink.hide();
  2800. o.tip.hide();
  2801. o.stop.show();
  2802. o.copy.hide();
  2803. o.progress.show();
  2804.  
  2805. // 更新进度条
  2806. $width.css('width', prog + '%');
  2807.  
  2808. // 更新进度条文本
  2809. let timeText = '';
  2810. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  2811. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  2812. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  2813. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  2814. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  2815. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  2816. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  2817. timeText = remainingSeconds + '秒';
  2818. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  2819. timeText = '即将完成';
  2820. } else {
  2821. timeText = '计算中...';
  2822. }
  2823.  
  2824. let speedText = '';
  2825. speedText = base.sizeFormat(downloadSpeed)
  2826. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  2827.  
  2828. if (prog === 100) {
  2829. setTimeout(function () {
  2830. clearInterval(ins[index]);
  2831. progress[index] = 0;
  2832. o.item.find('.pl-progress-stop').hide();
  2833. o.howidm.hide();
  2834. $text.text('下载完成~ 浏览器下载框应该弹出来了哦~');
  2835. o.back.show()
  2836. setTimeout(function () {
  2837. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  2838. }, 3000)
  2839. }, 1000)
  2840. }
  2841. }
  2842. }, 500);
  2843. });
  2844. doc.on('click', '.listener-retry', async function (e) {
  2845. let o = _factory(e);
  2846. o.tip.hide();
  2847. o.link.show();
  2848. o.directLink.show();
  2849. });
  2850. doc.on('click', '.listener-how', async function (e) {
  2851. let o = _factory(e);
  2852. let index = o.link[0].dataset.index;
  2853. if (request[index]) {
  2854. request[index].abort();
  2855. clearInterval(ins[index]);
  2856. o.progress.hide();
  2857. o.tip.show();
  2858. }
  2859.  
  2860. });
  2861. doc.on('click', '.listener-stop', async function (e) {
  2862. let o = _factory(e);
  2863. let index = o.link[0].dataset.index;
  2864. if (request[index]) {
  2865. request[index].abort();
  2866. clearInterval(ins[index]);
  2867. o.item.find('.pl-progress-inner-text').text('正在取消...');
  2868. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  2869. setTimeout(function () {
  2870. o.tip.hide();
  2871. o.back.hide();
  2872. o.link.show();
  2873. o.directLink.show();
  2874. o.copy.show();
  2875. o.progress.hide();
  2876. o.stop.hide();
  2877. }, 1050)
  2878. }
  2879. });
  2880. doc.on('click', '.listener-back', async function (e) {
  2881. let o = _factory(e);
  2882. o.progress.hide();
  2883. o.tip.hide();
  2884. o.link.show();
  2885. o.directLink.show();
  2886. o.copy.show();
  2887. o.stop.hide();
  2888. o.back.hide();
  2889. });
  2890. doc.on('click', '.listener-download-all', function (e) {
  2891. $('.pl-item-link.blob').each(function () {
  2892. if ($(this).css('display') !== 'none') {
  2893. $(this).click();
  2894. }
  2895. });
  2896. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  2897. setTimeout(function () {
  2898. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  2899. }, 2000)
  2900. });
  2901. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  2902. e.preventDefault();
  2903. if (!e.target.dataset.link) {
  2904. $(e.target).removeClass('listener-copy-all').addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  2905. } else {
  2906. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  2907. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  2908. setTimeout(
  2909. function () {
  2910. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  2911. }, 2000
  2912. )
  2913. }
  2914. });
  2915. doc.on('click', '.listener-link-rpc', async function (e) {
  2916. e.preventDefault();
  2917. let target = $(e.currentTarget);
  2918.  
  2919. target.find('.icon-rpc-devices').remove();
  2920. target.find('.pl-loading').remove();
  2921. target.prepend(base.createLoading());
  2922.  
  2923. let res = await baidu.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  2924. if (res === 'success') {
  2925. $('.listener-rpc-task').show();
  2926. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  2927. } else if (res === 'assistant') {
  2928. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  2929. } else {
  2930. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  2931. }
  2932. });
  2933. doc.on('click', '.listener-send-rpc', function (e) {
  2934. $('.listener-link-rpc').click();
  2935. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  2936. });
  2937. doc.on('click', '.listener-open-setting', function () {
  2938. base.showSetting();
  2939. });
  2940. doc.on('click', '.listener-open-updatelog', function () {
  2941. base.showUpdateLog();
  2942. });
  2943. doc.on('click', '.listener-open-beautify', function () {
  2944. base.showBeautify();
  2945. });
  2946. doc.on('click', '.listener-rpc-task', function (e) {
  2947. e.preventDefault();
  2948. let rpc = JSON.stringify({
  2949. domain: base.getValue('setting_rpc_domain'),
  2950. port: base.getValue('setting_rpc_port'),
  2951. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  2952. GM_openInTab(url, { active: true });
  2953. });
  2954. document.documentElement.addEventListener('mouseup', function (e) {
  2955. if (e.target.nodeName === 'A' && ~e.target.className.indexOf('pl-a')) {
  2956. e.stopPropagation();
  2957. }
  2958. }, true);
  2959. },
  2960.  
  2961. removeAD() {
  2962. base.waitForKeyElements(".wp-s-header-user__vip-center", function (tag) {
  2963. tag.remove();
  2964. });
  2965. base.waitForKeyElements(".wp-s-header-user__create-team-content", function (tag) {
  2966. tag.remove();
  2967. });
  2968. base.waitForKeyElements(".app-user-vip-center-box.vip-center-type-2", function (tag) {
  2969. tag.remove();
  2970. }, true);
  2971. base.waitForKeyElements(".wp-s-header__vip-btn-tip", function (tag) {
  2972. tag.fadeOut();
  2973. }, true);
  2974. base.waitForKeyElements(".app-user-vip-center-tip", function (tag) {
  2975. tag.fadeOut();
  2976. }, true);
  2977. base.waitForKeyElements("#web-header-text-s-45", function (tag) {
  2978. tag.fadeOut();
  2979. }, true);
  2980. base.waitForKeyElements(".wp-s-header__vip-btn", function (tag) {
  2981. tag[0].innerText = "会员中心";
  2982. }, true);
  2983. base.waitForKeyElements(".KQcHyA", function (tag) {
  2984. tag[0].innerText = "会员中心";
  2985. }, true);
  2986. base.waitForKeyElements(".gOIbzPb", function (tag) {
  2987. tag.fadeOut();
  2988. }, true);
  2989. base.waitForKeyElements(".wp-s-header-user__create-team-title", function (tag) {
  2990. tag.fadeOut();
  2991. }, true);
  2992. base.waitForKeyElements(".web-header-ad-item", function (tag) {
  2993. tag.fadeOut();
  2994. });
  2995. base.waitForKeyElements(".wp-s-header__game-entry", function (tag) {
  2996. tag.fadeOut();
  2997. }, true)
  2998. base.waitForKeyElements(".bd-aside-ad", function (tag) {
  2999. tag.fadeOut();
  3000. }, true)
  3001. base.waitForKeyElements(".btn-img-tips", function (tag) {
  3002. tag.fadeOut();
  3003. }, true)
  3004. base.waitForKeyElements(".nd-operate-guidance", function (tag) {
  3005. tag.fadeOut();
  3006. }, true)
  3007. base.waitForKeyElements(".module-operation-content", function (tag) {
  3008. tag[0].fadeOut();
  3009. document.querySelector(".module-canvas").click();
  3010. }, true)
  3011. base.waitForKeyElements("[class*='module-'][class*='-box'], [class*='module-'][class*='-mask']", function (tag) {
  3012. tag[0].fadeOut();
  3013. tag.find(".close-mask").click();
  3014. }, true)
  3015. base.waitForKeyElements(".newIcon", function (tag) {
  3016. tag.fadeOut();
  3017. }, true);
  3018. base.waitForKeyElements(".u-badge__content.is-dot", function (tag) {
  3019. tag.fadeOut();
  3020. }, true);
  3021. base.waitForKeyElements(".wp-side-options.g-clearfix", function (tag) {
  3022. tag.fadeOut();
  3023. }, true);
  3024. base.waitForKeyElements(".wp-s-header-user__drop-channel", function (tag) {
  3025. tag.fadeOut();
  3026. }, true);
  3027. base.waitForKeyElements(".app-download", function (tag) {
  3028. tag.fadeOut();
  3029. }, true);
  3030. base.waitForKeyElements('.g-button[title*="手机"]', function (tag) {
  3031. tag.fadeOut();
  3032. }, true)
  3033. base.waitForKeyElements('.yike-entrance', function (tag) {
  3034. tag.remove();
  3035. })
  3036. base.waitForKeyElements("p.wp-s-aside-nav__main-item-text", function (tag) {
  3037. if (tag[0].innerHTML.match(/(插件|相册|笔记)/) && tag[0].closest('a') && tag[0].closest('a').getAttribute('target') !== "_blank") {
  3038. $(tag[0].closest('a')).fadeOut();
  3039. } else {
  3040. tag[0].innerHTML = tag[0].innerHTML.replace("百度", "");
  3041. }
  3042. }, true);
  3043. base.waitForKeyElements('dd[node-type="header-link"]', function (tag) {
  3044. tag.children().each(function () {
  3045. let tag = $(this);
  3046. if (!tag.attr("node-type")) return;
  3047. let type = tag.attr("node-type");
  3048. if (
  3049. type !== "disk-home" &&
  3050. type !== "mbox-homepage" &&
  3051. type !== "find-apps"
  3052. ) {
  3053. tag.fadeOut();
  3054. }
  3055. });
  3056. }, true);
  3057. base.waitForKeyElements(".__yunguanjia", function (tag) {
  3058. tag[0].innerHTML = `
  3059. <div class="yunguanjia-list __yunguanjia row g-clearfix _item sel">
  3060. <span type="radio" class="radio-box _radioInput __yunguanjiaRadio">
  3061. <span class="device-name">添加我的电脑</span>
  3062. </span>
  3063. <div class="__yunguanjiaTips radio-tips" style="display: block;">
  3064. 用电脑下载并登录(不可用)最新百度网盘客户端,即自动完成添加。
  3065. <a href="//pan.baidu.com/download" target="_blank">下载百度网盘客户端</a>
  3066. <br/>
  3067. <a>(改)网盘直链下载助手</a> 修复该选项
  3068. </div>
  3069. </div>`;
  3070. }, true)
  3071. // 美化分享页面
  3072. if (pt === 'share') {
  3073. base.waitForKeyElements(`iframe[src^="/buy/ad"]`, function (tag) {
  3074. tag.fadeOut();
  3075. }, true)
  3076. base.waitForKeyElements(`.theme-white.init-new`, function (tag) {
  3077. tag[0].style.background = '#DCEFFE url(https://nd-static.bdstatic.com/m-static/disk-share/widget/pageModule/init-new/image/init-bg_1708266.png) no-repeat center center'
  3078. }, true)
  3079. base.waitForKeyElements(`#layoutApp`, function (tag) {
  3080. tag[0].style.background = '#DCEFFE url(https://nd-static.bdstatic.com/m-static/disk-share/widget/pageModule/init-new/image/init-bg_1708266.png) no-repeat center center'
  3081. document.body.style.background = '#DCEFFE url(https://nd-static.bdstatic.com/m-static/disk-share/widget/pageModule/init-new/image/init-bg_1708266.png) no-repeat center center'
  3082. }, true)
  3083. base.waitForKeyElements(`#bd-main .bd-left`, function (tag) {
  3084. tag[0].style.background = '#ffffffC0';
  3085. tag[0].style.borderRadius = '10px';
  3086.  
  3087. }, true)
  3088. base.waitForKeyElements(`.KPDwCE`, function (tag) {
  3089. tag[0].style.setProperty('background', 'transparent');
  3090. }, true)
  3091. base.waitForKeyElements('.share-list .KPDwCE .AuPKyz', function (tag) {
  3092. tag[0].style.setProperty('background', 'transparent');
  3093. }, true)
  3094. }
  3095. },
  3096.  
  3097. addButton() {
  3098. if (!pt) return;
  3099. let $toolWrap;
  3100. let $button = $(`
  3101. <div class="g-dropdown-button pointer pl-button">
  3102. <div class="baidu-button g-button g-button-blue"><span class="g-button-right"><em class="icon icon-download" style="color:#fff;"></em><span class="text" style="width: 60px;">下载助手</span></span></div>
  3103. <div class="menu" style="color: ${color};border-color: ${color};width:auto;z-index:41;">
  3104. <div class="g-button-menu pl-button-mode" data-mode="api">API下载</div>
  3105. <div class="g-button-menu pl-button-mode" data-mode="aria">Aria下载</div>
  3106. <div class="g-button-menu pl-button-mode" data-mode="rpc">RPC下载</div>
  3107. <div class="g-button-menu pl-button-mode" data-mode="curl">cURL下载</div>
  3108. <div class="g-button-menu pl-button-mode" data-mode="bc">BC下载</div>
  3109. <div class="g-button-menu pl-button-mode listener-open-setting">助手设置</div>
  3110. <div class="g-button-menu pl-button-mode listener-open-beautify">助手美化</div>
  3111. <div class="g-button-menu pl-button-mode listener-open-updatelog">更新日志</div>
  3112. </div>
  3113. </div>
  3114. `);
  3115. if (pt === 'home') $toolWrap = pan.btn.home;
  3116. if (pt === 'main') {
  3117. $toolWrap = pan.btn.main;
  3118. $button = $(`
  3119. <div class="wp-s-agile-tool-bar__h-group pl-button">
  3120. <div class="wp-s-agile-tool-bar__h-action is-need-left-sep is-main">
  3121. <button type="button" class="u-button nd-file-list-toolbar-action-item u-button--primary u-button--small is-round is-has-icon pl-button baidu-button">
  3122. <i class="u-icon u-icon-download"></i>
  3123. <span>下载助手</span>
  3124. </button>
  3125. <ul class="dropdown-list nd-common-float-menu pl-dropdown-menu">
  3126. <li class="sub cursor-p pl-button-mode" data-mode="api">API下载</li>
  3127. <li class="sub cursor-p pl-button-mode" data-mode="aria">Aria下载</li>
  3128. <li class="sub cursor-p pl-button-mode" data-mode="rpc">RPC下载</li>
  3129. <li class="sub cursor-p pl-button-mode" data-mode="curl">cURL下载</li>
  3130. <li class="sub cursor-p pl-button-mode" data-mode="bc">BC下载</li>
  3131. <li class="sub cursor-p pl-button-mode listener-open-setting">助手设置</li>
  3132. <li class="sub cursor-p pl-button-mode listener-open-beautify">助手美化</li>
  3133. <li class="sub cursor-p pl-button-mode listener-open-updatelog">更新日志</li>
  3134. </ul>
  3135. </div>
  3136. </div>`);
  3137. }
  3138. if (pt === 'youth') {
  3139. $toolWrap = pan.btn.main;
  3140. $button = $(`
  3141. <div class="wp-s-agile-tool-bar__h-group pl-button">
  3142. <div class="wp-s-agile-tool-bar__h-action is-need-left-sep is-main">
  3143. <button type="button" class="u-button nd-file-list-toolbar-action-item u-button--primary u-button--small is-round is-has-icon pl-button baidu-button" style="font-size:14px;font-weight:700">
  3144. <i class="u-icon u-icon-more"></i>
  3145. <span>网盘助手</span>
  3146. </button>
  3147. <ul class="dropdown-list nd-common-float-menu pl-dropdown-menu">
  3148. <li class="sub cursor-p pl-button-mode listener-open-setting">助手设置</li>
  3149. <li class="sub cursor-p pl-button-mode listener-open-beautify">助手美化</li>
  3150. <li class="sub cursor-p pl-button-mode listener-open-updatelog">更新日志</li>
  3151. </ul>
  3152. </div>
  3153. </div>`);
  3154. }
  3155. if (pt === 'share') {
  3156. $toolWrap = pan.btn.share;
  3157. $button = $(`
  3158. <div class="g-dropdown-button pointer pl-button">
  3159. <div class="baidu-button g-button g-button-blue"><span class="g-button-right"><em class="icon icon-download" style="color:#fff;"></em><span class="text" style="width: 60px;">下载助手</span></span></div>
  3160. <div class="menu" style="color: ${color};border-color: ${color};width:auto;z-index:41;">
  3161. <div class="g-button-menu pl-button-mode pl-button-save"><em class="icon icon-save-disk" title="保存到网盘"></em><span style="margin-left: 3px;">保存后下载</span></div>
  3162. <div class="g-button-menu pl-button-mode listener-open-setting">助手设置</div>
  3163. <div class="g-button-menu pl-button-mode listener-open-beautify">助手美化</div>
  3164. <div class="g-button-menu pl-button-mode listener-open-updatelog">更新日志</div>
  3165. </div>
  3166. </div>
  3167. `);
  3168. base.listenElement($toolWrap, function () {
  3169. $toolWrap = $($toolWrap);
  3170. $('.pl-button').length === 0 && $toolWrap.append($button);
  3171. })
  3172. } else {
  3173. base.listenElement($toolWrap, function () {
  3174. $toolWrap = $($toolWrap);
  3175. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  3176. })
  3177. }
  3178. this.setBDUSS();
  3179. base.createDownloadIframe();
  3180. },
  3181.  
  3182. addInitButton() {
  3183. if (!pt) return;
  3184. let $toolWrap;
  3185. let $button = $(`<div class="g-dropdown-button pointer pl-button-init" style="opacity:0.5"><div style="color:#fff;" class="g-button g-button-blue"><span class="g-button-right"><em class="icon icon-download" style="color:#fff;"></em><span class="text" style="width: 60px;">点我点亮</span></span></div></div>`);
  3186. if (pt === 'home') {
  3187. $toolWrap = pan.btn.home;
  3188. }
  3189. if (pt === 'main' || pt === 'youth') {
  3190. $toolWrap = pan.btn.main;
  3191. $button = $(`
  3192. <div class="wp-s-agile-tool-bar__h-group pl-button-init">
  3193. <div class="wp-s-agile-tool-bar__h-action is-need-left-sep is-main">
  3194. <button type="button" class="u-button nd-file-list-toolbar-action-item u-button--primary u-button--small is-round is-has-icon pl-button baidu-button" style="font-size:14px;font-weight:700">
  3195. <i class="u-icon u-icon-download"></i>
  3196. <span>点我点亮</span>
  3197. </button>
  3198. </div>
  3199. </div>`);
  3200. }
  3201. if (pt === 'share') $toolWrap = pan.btn.share;
  3202. $button.click(function () { base.initDialog() });
  3203. base.listenElement($toolWrap, function () {
  3204. $toolWrap = $($toolWrap);
  3205. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  3206. })
  3207. },
  3208.  
  3209. async getToken() {
  3210. function openTab() {
  3211. message.info('提示:<br/>稍后请在新标签页中授权助手~');
  3212. base.deleteValue('baidu_access_token');
  3213. setTimeout(() => {
  3214. GM_openInTab(pan.pcs[3], { active: true, insert: true, setParent: true })
  3215. }, 3500);
  3216. }
  3217.  
  3218. const waitForToken = new Promise((resolve) => { // 确保 return Promise
  3219. let attempts = 0;
  3220. const interval = setInterval(function () {
  3221. const token = base.getValue('baidu_access_token');
  3222. if (!!token) {
  3223. clearInterval(interval);
  3224. resolve(token); // 成功获取 token 后 resolve
  3225. }
  3226. attempts++;
  3227. if (attempts > 120) { // 超时后清除 interval,并 resolve 空值
  3228. clearInterval(interval);
  3229. resolve(''); // 超时处理
  3230. }
  3231. }, 1000); // 每秒检查一次
  3232. });
  3233.  
  3234. // 否则进行 URL 请求
  3235. let res = await base.getFinalUrl(pan.pcs[3]);
  3236.  
  3237. if (!res.includes('authorize') && !res.includes('access_token=')) {
  3238. openTab();
  3239. return waitForToken;
  3240. }
  3241.  
  3242. // 如果是 Tampermonkey 环境,打开新标签并等待获取 token
  3243. if (manageHandler === 'Tampermonkey' && base.getMajorVersion(manageVersion) >= 5) {
  3244. openTab();
  3245. return waitForToken;
  3246. }
  3247.  
  3248. if (res.includes('authorize')) {
  3249. let html = await base.get(pan.pcs[3], {}, 'text');
  3250.  
  3251. // 使用正则表达式提取所需字段
  3252. let bdstoken = html.match(/name="bdstoken"\s+value="([^"]+)"/)?.[1];
  3253. let client_id = html.match(/name="client_id"\s+value="([^"]+)"/)?.[1];
  3254.  
  3255. let data = {
  3256. grant_permissions_arr: 'netdisk',
  3257. bdstoken: bdstoken,
  3258. client_id: client_id,
  3259. response_type: "token",
  3260. display: "page",
  3261. grant_permissions: "basic,netdisk"
  3262. };
  3263.  
  3264. // 发送 POST 请求进行授权
  3265. await base.post(pan.pcs[3], base.stringify(data), {
  3266. 'Content-Type': 'application/x-www-form-urlencoded',
  3267. });
  3268.  
  3269. // 再次获取授权后的 URL
  3270. let res2 = await base.getFinalUrl(pan.pcs[3]);
  3271. let accessToken = res2.match(/access_token=([^&]+)/)?.[1];
  3272. accessToken && base.setValue('baidu_access_token', accessToken);
  3273. return accessToken;
  3274. }
  3275.  
  3276. // 如果已有 access_token,则直接返回
  3277. let accessToken = res.match(/access_token=([^&]+)/)?.[1];
  3278. accessToken && base.setValue('baidu_access_token', accessToken);
  3279. return accessToken;
  3280. },
  3281.  
  3282. async getPCSLink() {
  3283. selectList = this.getSelectedList();
  3284. let url, res, accessToken, BDUSS = this.getBDUSS(), fidList = this._getFidList();
  3285.  
  3286. if (pt === 'home' || pt === 'main') {
  3287. if (selectList.length === 0) {
  3288. return message.error('提示:<br/>先勾选要下载的文件哦~');
  3289. }
  3290. if (fidList.length === 2) {
  3291. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  3292. }
  3293. fidList = encodeURIComponent(fidList);
  3294. accessToken = base.getValue('baidu_access_token') || await baidu.getToken();
  3295. if (!!BDUSS && !!accessToken) {
  3296. url = `${pan.pcs[0]}&fsids=${fidList}&access_token=${accessToken}`;
  3297. res = await base.get(url, { "User-Agent": pan.ua, "cookie": `BDUSS=${BDUSS}` });
  3298. }
  3299. } else {
  3300. return message.error('提示:<br/>页面错误~');
  3301. }
  3302. if (res?.list?.[0] && (res?.errno === 0 || res?.errmsg === "succ")) {
  3303. let html = this.generateDom(res.list);
  3304. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  3305. } else if (res?.errno === 112) {
  3306. return message.error('提示:<br/>页面过期了,刷新重试下吧~<br/>代码:' + res.errno);
  3307. } else if (res?.errno === 9019) {
  3308. base.deleteValue('baidu_access_token');
  3309. return message.error('提示:<br/>AccessToken 已过期,刷新网页后再获取一次吧~<br/>代码:' + res.errno);
  3310. } else {
  3311. base.deleteValue('baidu_access_token');
  3312. if (res?.errno) {
  3313. return message.error('提示:<br/>获取下载链接失败,刷新网页后再试试吧~<br/>代码:' + res.errno);
  3314. } else {
  3315. return message.error('提示:<br/>获取下载链接失败,刷新网页后再试试吧~');
  3316. }
  3317. }
  3318. },
  3319.  
  3320. generateDom(list) {
  3321. let content = '<div class="pl-main">';
  3322. let alinkAllText = '';
  3323. base.sortByName(list);
  3324. list.forEach((v, i) => {
  3325. if (v.isdir === 1) return;
  3326. let filename = v.server_filename || v.filename;
  3327. let ext = base.getExtension(filename);
  3328. let size = base.sizeFormat(v.size);
  3329. let dlink = v.dlink + '&access_token=' + base.getValue('baidu_access_token');
  3330. if (mode === 'api') {
  3331. alinkAllText += dlink + '\r\n';
  3332. content += `<div class="pl-item">
  3333. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3334. <button class="pl-item-link listener-tip pl-btn-primary listener-link-api blob" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载有可能会被 IDM 捕获下载链接" data-filename="${filename}" data-size="${v.size}" data-link="${dlink}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  3335. <button class="pl-item-link listener-tip pl-btn-primary pl-btn-info listener-link-api browser" data-title="不建议使用本功能,若使用后长时间没有弹出下载提示则代表请求失败,请换用“增强下载”<br/>基于浏览器直接打开链接来下载文件,适用于较为古老但支持 iframe 的浏览器,点击“直接下载”后需等待下载提示弹出才能点击下个“直接下载”,否则只会下载后者,此方式下载有可能会被 IDM 捕获下载链接" data-filename="${filename}" data-link="${dlink}">直接下载(基于浏览器链接)</button>
  3336. <button class="pl-item-copy listener-tip pl-btn-primary pl-btn-warning listener-copy-all" href="${dlink}" data-title="不建议使用本功能,在本网盘单独复制链接并粘贴下载可能会导致服务器回报 403 错误" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  3337. <div class="pl-item-tip" style="display: none"><span>若没有弹出IDM下载框,找到IDM <b>选项</b> -> <b>文件类型</b> -> <b>第一个框</b> 中添加后缀 <span class="pl-ext">${ext}</span>,<a href="${pan.idm}" target="_blank" class="pl-a">详见此处</a></span> <span class="listener-back">返回</span></div>
  3338. <div class="pl-item-progress" style="display: none">
  3339. <div class="pl-progress">
  3340. <div class="pl-progress-outer"></div>
  3341. <div class="pl-progress-inner" style="width:5%">
  3342. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  3343. </div>
  3344. </div>
  3345. <span class="pl-btn-primary pl-btn-danger pl-progress-stop listener-stop">取消下载</span>
  3346. `;
  3347. content += `<span class="pl-progress-tip" style="display: none" >未发现IDM,使用自带浏览器下载</span>
  3348. <span class="pl-btn-primary pl-btn-info pl-progress-back listener-back" style="display: none">返回</span>
  3349. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  3350. `;
  3351. content += `</div></div>`
  3352. }
  3353. if (mode === 'aria') {
  3354. let alink = this.convertLinkToAria(dlink, filename, pan.ua);
  3355. if (typeof (alink) === 'object') {
  3356. content += `<div class="pl-item">
  3357. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3358. <a class="pl-item-link pl-a" target="_blank" href="${alink.link}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink.link}">${decodeURIComponent(alink.text)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  3359. } else {
  3360. alinkAllText += alink + '\r\n';
  3361. content += `<div class="pl-item">
  3362. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3363. <a class="pl-item-link pl-a listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  3364. }
  3365. }
  3366. if (mode === 'rpc') {
  3367. content += `<div class="pl-item">
  3368. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3369. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><svg class="icon-rpc-devices" viewBox="-10 0 1034 1024"><g transform="matrix(1 0 0 -1 0 960)"><path fill="currentColor" d="M832 -64h-640q-53 0 -90.5 37.5t-37.5 90.5v768q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-768q0 -53 -37.5 -90.5t-90.5 -37.5zM832 768q0 27 -18.5 45.5t-45.5 18.5h-512q-27 0 -45.5 -18.5t-18.5 -45.5v-320h640v320v0zM832 320h-640v-192q0 -27 18.5 -45.5t45.5 -18.5h512q27 0 45.5 18.5t18.5 45.5v192v0zM512 128q-27 0 -45.5 18.5t-18.5 45.5t18.5 45.5t45.5 18.5t45.5 -18.5t18.5 -45.5t-18.5 -45.5t-45.5 -18.5z" /></g></svg><span style="margin-left: 5px;">将 ${filename} 推送到 RPC 下载器</span></button></div>`;
  3370. }
  3371. if (mode === 'curl') {
  3372. let alink = this.convertLinkToCurl(dlink, filename, pan.ua);
  3373. if (typeof (alink) === 'object') {
  3374. content += `<div class="pl-item">
  3375. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3376. <a class="pl-item-link pl-a" target="_blank" href="${alink.link}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink.link}">${decodeURIComponent(alink.text)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  3377. } else {
  3378. alinkAllText += alink + '\r\n';
  3379. content += `<div class="pl-item">
  3380. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3381. <a class="pl-item-link pl-a listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  3382. }
  3383. }
  3384. if (mode === 'bc') {
  3385. let alink = this.convertLinkToBC(dlink, filename, pan.ua);
  3386. if (typeof (alink) === 'object') {
  3387. alinkAllText += decodeURIComponent(alink.text) + '\r\n';
  3388. content += `<div class="pl-item">
  3389. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3390. <a class="pl-item-link pl-a" href="${decodeURIComponent(alink.link)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink.text)}<br/>下载 ${filename}</a> </div>`;
  3391. } else {
  3392. alinkAllText += alink + '\r\n';
  3393. content += `<div class="pl-item">
  3394. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3395. <a class="pl-item-link pl-a" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a> </div>`;
  3396. }
  3397. }
  3398. });
  3399.  
  3400. content += '</div>';
  3401.  
  3402. if (mode === 'api')
  3403. content += `<div class="pl-extra"><button class="pl-btn-primary listener-tip listener-download-all" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载有可能会被 IDM 捕获下载链接">全部增强下载</button><button class="pl-btn-primary listener-tip listener-copy-all" data-link="${alinkAllText}" data-title="不建议使用本功能,在本网盘单独复制链接并粘贴下载可能会导致服务器回报 403 错误">复制全部链接</button></div>`;
  3404. if (mode === 'aria')
  3405. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  3406. if (mode === 'rpc') {
  3407. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  3408. content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">修改 RPC 参数(${rpc})</button><button class="pl-btn-primary pl-btn-success pl-btn-opacity listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  3409. }
  3410. if (mode === 'curl') {
  3411. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">修改终端类型(${terminalType[base.getValue('setting_terminal_type')]})</button></div>`;
  3412. }
  3413. if (mode === 'bc') {
  3414. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  3415. }
  3416. return content;
  3417. },
  3418.  
  3419. async sendLinkToRPC(filename, link) {
  3420. let rpc = {
  3421. domain: base.getValue('setting_rpc_domain'),
  3422. port: base.getValue('setting_rpc_port'),
  3423. path: base.getValue('setting_rpc_path'),
  3424. token: base.getValue('setting_rpc_token'),
  3425. dir: base.getValue('setting_rpc_dir'),
  3426. };
  3427. let BDUSS = this.getBDUSS();
  3428. if (!BDUSS) return 'assistant';
  3429.  
  3430. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  3431. let rpcData = {
  3432. id: new Date().getTime(),
  3433. jsonrpc: '2.0',
  3434. method: 'aria2.addUri',
  3435. params: [`token:${rpc.token}`, [link], {
  3436. dir: rpc.dir,
  3437. out: filename,
  3438. header: [`User-Agent: ${pan.ua}`, `Cookie: BDUSS=${BDUSS}`]
  3439. }]
  3440. };
  3441. try {
  3442. let res = await base.post(url, rpcData, { "User-Agent": pan.ua }, '');
  3443. if (res.result) return 'success';
  3444. return 'fail';
  3445. } catch (e) {
  3446. return 'fail';
  3447. }
  3448. },
  3449.  
  3450. getSelectedList() {
  3451. let List, selectList
  3452. try {
  3453. List = require("system-core:context/context.js").instanceForSystem.list;
  3454. selectList = List.getSelected();
  3455. /*if (!selectList.length) {
  3456. selectList = List.getCurrentList();
  3457. }*/
  3458. return selectList;
  3459. } catch (e) { }
  3460. try {
  3461. List = unsafeWindow.document.querySelector('.wp-s-core-pan');
  3462. if (List && List.__vue__.selectedList) {
  3463. selectList = List.__vue__.selectedList;
  3464. return selectList;
  3465. }
  3466. } catch (e) { }
  3467. try {
  3468. List = unsafeWindow.document.querySelector('.file-list');
  3469. if (List && List.__vue__.allFileList) {
  3470. selectList = List.__vue__.allFileList.filter(function (item) { return !!item.selected; });
  3471. return selectList;
  3472. }
  3473. } catch (e) { }
  3474. },
  3475.  
  3476. getLogid() {
  3477. let ut = require("system-core:context/context.js").instanceForSystem.tools.baseService;
  3478. return ut.base64Encode(base.getCookie("BAIDUID"));
  3479. },
  3480.  
  3481. getShareData() {
  3482. let res = locals.dump();
  3483. params.shareType = 'secret';
  3484. params.sign = '';
  3485. params.timestamp = '';
  3486. params.bdstoken = res.bdstoken.value;
  3487. params.channel = 'chunlei';
  3488. params.clienttype = 0;
  3489. params.web = 1;
  3490. params.app_id = 250528;
  3491. params.encrypt = 0;
  3492. params.product = 'share';
  3493. params.logid = this.getLogid();
  3494. params.primaryid = res.shareid.value;
  3495. params.uk = res.share_uk.value;
  3496. params.shareType === 'secret' && (params.extra = this._getExtra());
  3497. params.surl = this._getSurl();
  3498. },
  3499.  
  3500. detectPage() {
  3501. let path = location.pathname;
  3502. if (/^\/disk\/home/.test(path)) return 'home';
  3503. if (/^\/disk\/main/.test(path)) return 'main';
  3504. if (/^\/youth\/pan\/main/.test(path)) return 'youth';
  3505. if (/^\/(s|share)\//.test(path)) return 'share';
  3506. return '';
  3507. },
  3508.  
  3509. showMainDialog(title, html, footer) {
  3510. Swal.fire({
  3511. title,
  3512. html,
  3513. footer,
  3514. allowOutsideClick: false,
  3515. showCloseButton: true,
  3516. heightAuto: false,
  3517. scrollbarPadding: false,
  3518. position: 'center',
  3519. width, // 确认 width 已正确定义
  3520. padding: '15px 20px 5px',
  3521. customClass, // 确认 customClass 已正确定义
  3522. confirmButtonText: '关闭',
  3523. willClose: function () {
  3524. base._resetData();
  3525. }
  3526. }).then(function () {
  3527. base._resetData();
  3528. });
  3529. },
  3530.  
  3531. async initAuthorize() {
  3532. base.registerMenuCommand();
  3533. Swal.fire({
  3534. heightAuto: false,
  3535. scrollbarPadding: false,
  3536. showConfirmButton: false,
  3537. allowOutsideClick: false,
  3538. allowEscapeKey: false,
  3539. allowEnterKey: false,
  3540. html: `请稍后`,
  3541. willOpen: function () {
  3542. Swal.showLoading();
  3543. },
  3544. });
  3545. if (base.getValue('setting_server_main') === 'v1') {
  3546. let res = await base.post(`https://api.youxiaohou.com/config/?ver=${version}&a=${author}`, {}, {}, 'text');
  3547. pan = JSON.parse(base.decode(res));
  3548. } else if (base.getValue('setting_server_main') === 'v2') {
  3549. let res = await base.post(`https://api.youxiaohou.com/config/v2/?ver=${version}&a=${author}`, {}, {}, 'text');
  3550. pan = JSON.parse(base.decode(res));
  3551. } else if (base.getValue('setting_server_main') === "no") {
  3552. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/config.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  3553. pan = JSON.parse(res);
  3554. } else {
  3555. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/config.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  3556. pan = JSON.parse(res);
  3557. base.setValue('setting_server_main', 'v2');
  3558. }
  3559. Object.freeze && Object.freeze(pan);
  3560. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('setting_init_license')) {
  3561. let url = new URL(location.href)
  3562. let auth = new URL(pan.pcs[3])
  3563. // https://openapi.baidu.com/oauth/2.0/authorize?response_type=code&client_id=&scope=basic,netdisk,mobile&display=page&redirect_uri=
  3564. if (
  3565. /openapi.baidu.com\/oauth\/2.0\/authorize/.test(location.href) &&
  3566. (location.href.includes('basic+netdisk') || location.href.includes('basic,netdisk')) &&
  3567. (
  3568. url.searchParams.get("client_id") === auth.searchParams.get("client_id")/* ||
  3569. url.searchParams.get("client_id") === 'L6g70tBRRIXLsY0Z3HwKqlRE' || // pcstest_oauth
  3570. url.searchParams.get("client_id") === 'fSds3K4w43rw37tOqlQmTa2kDwaczK4U' || // 小度智能词典笔专业版
  3571. url.searchParams.get("client_id") === 'TFwtw8uwHxpdkvVqVKdIlx1XqXUnr1zG' || // 印象笔记
  3572. url.searchParams.get("client_id") === '9dgBV9yesuBVOXaxls7aVHbLBLqU8yyg' || // WPS文档
  3573. url.searchParams.get("client_id") === 'l9DdBOG4RYroMscmzK5OChdaGelgd92M' || // 小猴云印PC版
  3574. url.searchParams.get("client_id") === 'IlLqBbU3GjQ0t46TRwFateTprHWl39zF' // 百度手机助手 */
  3575. )
  3576. ) {
  3577. let dialog = await Swal.fire({
  3578. icon: 'info',
  3579. title: `提示`,
  3580. html: '你好呀,为了获取百度网盘文件的下载直链<br/>我们需要您的授权来使 “下载助手” 读取您的网盘数据<br/><br/>由于使用了别的应用ID,所以授权的应用名称会有不同<br/>获取到的数据仅用于生成直链,请放心授权ヾ(≧▽≦*)o',
  3581. showConfirmButton: true,
  3582. showDenyButton: true,
  3583. allowOutsideClick: false,
  3584. allowEscapeKey: false,
  3585. allowEnterKey: false,
  3586. confirmButtonText: '授权',
  3587. denyButtonText: '再想想',
  3588. position: 'center'
  3589. });
  3590. if (dialog.isConfirmed) {
  3591. base.waitForKeyElements("button#auth-allow", function (element) {
  3592. element[0].click();
  3593. })
  3594. return;
  3595. }
  3596. if (dialog.isDenied) {
  3597. return await Swal.fire({
  3598. icon: 'question',
  3599. title: `好吧(* ̄3 ̄)╭`,
  3600. html: '那就再想一想<br/>想好了就按下 “授权” 按钮吧~',
  3601. timer: 180000,
  3602. toast: true,
  3603. timerProgressBar: true,
  3604. showConfirmButton: false,
  3605. showDenyButton: false,
  3606. position: 'bottom-end',
  3607. })
  3608. }
  3609. } else if (/openapi.baidu.com\/oauth\/2.0\/login_success/.test(location.href)) {
  3610. let int = setInterval(async function () {
  3611. if (location.href.includes('access_token') && (location.href.includes('basic+netdisk') || location.href.includes('basic,netdisk'))) {
  3612. clearInterval(int)
  3613. let token = location.href.match(/access_token=(.*?)&/)[1];
  3614. base.setValue('baidu_access_token', token);
  3615. let dialog = await Swal.fire({
  3616. icon: 'success',
  3617. title: `成功啦`,
  3618. html: '你已 成功授权/授权过 脚本读取您的网盘数据~<br/>等待 <span id="second">3</span> 秒之后将关闭此页面',
  3619. timer: 3000,
  3620. timerProgressBar: true,
  3621. showConfirmButton: true,
  3622. showDenyButton: false,
  3623. allowOutsideClick: false,
  3624. allowEscapeKey: false,
  3625. allowEnterKey: false,
  3626. confirmButtonText: '关闭页面',
  3627. position: 'center',
  3628. willOpen: function () {
  3629. let sec = 3.1;
  3630. setInterval(() => {
  3631. sec -= 0.1;
  3632. document.getElementById("second").innerText = sec.toFixed(1);
  3633. }, 100);
  3634. setTimeout(() => {
  3635. window.close()
  3636. }, 3100);
  3637. },
  3638. });
  3639. if (dialog.isConfirmed) {
  3640. window.close()
  3641. return;
  3642. }
  3643. } else {
  3644. clearInterval(int)
  3645. Swal.close()
  3646. }
  3647. }, 1)
  3648. } else {
  3649. Swal.close()
  3650. }
  3651. } else {
  3652. Swal.close()
  3653. }
  3654. },
  3655.  
  3656. async initPanLinker() {
  3657. pt = this.detectPage();
  3658. base.createTip();
  3659. base.registerMenuCommand();
  3660. if (base.getValue('setting_server_main') === 'v1') {
  3661. let res = await base.post(`https://api.youxiaohou.com/config/?ver=${version}&a=${author}`, {}, {}, 'text');
  3662. pan = JSON.parse(base.decode(res));
  3663. } else if (base.getValue('setting_server_main') === 'v2') {
  3664. let res = await base.post(`https://api.youxiaohou.com/config/v2/?ver=${version}&a=${author}`, {}, {}, 'text');
  3665. pan = JSON.parse(base.decode(res));
  3666. } else if (base.getValue('setting_server_main') === "no") {
  3667. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/config.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  3668. pan = JSON.parse(res);
  3669. } else {
  3670. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/config.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  3671. pan = JSON.parse(res);
  3672. base.setValue('setting_server_main', 'v2');
  3673. }
  3674. Object.freeze && Object.freeze(pan);
  3675. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('setting_init_license')) {
  3676. this.addButton();
  3677. this.addPageListener();
  3678. } else {
  3679. this.addInitButton();
  3680. }
  3681. },
  3682. };
  3683.  
  3684. //阿里云盘
  3685. let ali = {
  3686.  
  3687. convertLinkToAria(link, filename, ua) {
  3688. filename = base.fixFilename(filename);
  3689. return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "Referer: https://${location.host}/"`);
  3690. },
  3691.  
  3692. convertLinkToBC(link, filename, ua) {
  3693. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&refer=${encodeURIComponent(`https://${location.host}/`)}ZZ`;
  3694. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  3695. },
  3696.  
  3697. convertLinkToCurl(link, filename, ua) {
  3698. let terminal = base.getValue('setting_terminal_type');
  3699. filename = base.fixFilename(filename);
  3700. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}" -e "https://${location.host}/"`);
  3701. },
  3702.  
  3703. addPageListener() {
  3704. /*
  3705. 防止代码因其他原因被执行多次
  3706. 这段代码出自 Via轻插件,作者谷花泰
  3707. */
  3708. const key = encodeURIComponent('(改)网盘直链下载助手:阿里云盘');
  3709. if (window[key]) return;
  3710. window[key] = true;
  3711.  
  3712. function _factory(e) {
  3713. let target = $(e.target);
  3714. let item = target.parents('.pl-item');
  3715. let link = item.find('.pl-item-link.blob');
  3716. let directLink = item.find('.pl-item-link.browser');
  3717. let progress = item.find('.pl-item-progress');
  3718. let tip = item.find('.pl-item-tip');
  3719. let copy = item.find('.pl-item-copy');
  3720. let howidm = item.find('.pl-progress-how');
  3721. let back = item.find('.pl-progress-back');
  3722. let stop = item.find('.pl-progress-stop');
  3723. return {
  3724. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  3725. };
  3726. }
  3727.  
  3728. function _reset(i) {
  3729. ins[i] && clearInterval(ins[i]);
  3730. request[i] && request[i].abort();
  3731. progress[i] = 0;
  3732. idm[i] = false;
  3733. }
  3734. doc.on('click', '.pl-button-mode', function (e) {
  3735. mode = e.target.dataset.mode;
  3736. if (!mode) return;
  3737. Swal.fire({
  3738. heightAuto: false,
  3739. scrollbarPadding: false,
  3740. showConfirmButton: false,
  3741. html: `链接获取中`,
  3742. willOpen: function () {
  3743. Swal.showLoading();
  3744. }
  3745. });
  3746. ali.getPCSLink();
  3747. });
  3748. doc.on('click', '.listener-link-api.browser', async function (e) {
  3749. e.preventDefault();
  3750. let dataset = e.currentTarget.dataset;
  3751. let href = dataset.link;
  3752. $('#downloadIframe').attr('src', href);
  3753. });
  3754. doc.on('click', '.listener-link-api.blob', async function (e) {
  3755. e.preventDefault();
  3756. let o = _factory(e);
  3757. let $width = o.item.find('.pl-progress-inner');
  3758. let $text = o.item.find('.pl-progress-inner-text');
  3759. let filename = o.link[0].dataset.filename;
  3760. let index = o.link[0].dataset.index;
  3761. _reset(index);
  3762. let dataset = e.currentTarget.dataset;
  3763. let href = dataset.link;
  3764. //let url = await this.getRealLink(dataset.did, dataset.fid);
  3765. //if (url) href = url;
  3766. base.get(href, { "Referer": `https://${location.host}/` }, 'blob', { filename, index });
  3767. let startTime = Date.now(); // 记录下载开始时间
  3768. let prevLoaded = 0; // 上一次的已下载数据量
  3769. let prevTime = startTime; // 上一次的时间
  3770. let size = Number(o.link[0].dataset.size);
  3771. ins[index] = setInterval(function () {
  3772. let prog = +progress[index] || 0;
  3773. // 处理普通下载的情况...
  3774. let currentTime = Date.now();
  3775. let elapsedTime = currentTime - startTime;
  3776. let totalProgress = prog / 100;
  3777. let totalElapsedSeconds = elapsedTime / 1000;
  3778. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  3779. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  3780.  
  3781. // 将剩余时间转换为天、时、分、秒
  3782. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  3783. remainingTimeSeconds %= (60 * 60 * 24);
  3784.  
  3785. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  3786. remainingTimeSeconds %= (60 * 60);
  3787.  
  3788. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  3789. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  3790.  
  3791. // 计算下载速度
  3792. let loaded = prog * size / 100; // 已下载数据量
  3793. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  3794. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  3795. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  3796.  
  3797. // 更新上一次的数据
  3798. prevLoaded = loaded;
  3799. prevTime = currentTime;
  3800.  
  3801. // 更改界面
  3802. o.link.hide();
  3803. o.directLink.hide();
  3804. o.tip.hide();
  3805. o.stop.show();
  3806. o.copy.hide();
  3807. o.progress.show();
  3808.  
  3809. // 更新进度条
  3810. $width.css('width', prog + '%');
  3811.  
  3812. // 更新进度条文本
  3813. let timeText = '';
  3814. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  3815. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  3816. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  3817. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  3818. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  3819. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  3820. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  3821. timeText = remainingSeconds + '秒';
  3822. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  3823. timeText = '即将完成';
  3824. } else {
  3825. timeText = '计算中...';
  3826. }
  3827.  
  3828. let speedText = '';
  3829. speedText = base.sizeFormat(downloadSpeed)
  3830.  
  3831. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  3832.  
  3833. if (prog === 100) {
  3834. setTimeout(function () {
  3835. clearInterval(ins[index]);
  3836. progress[index] = 0;
  3837. o.item.find('.pl-progress-stop').hide();
  3838. o.howidm.hide();
  3839. $text.text('下载完成~ 浏览器下载框应该弹出来了哦~');
  3840. o.back.show()
  3841. setTimeout(function () {
  3842. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  3843. }, 3000)
  3844. }, 1000)
  3845. }
  3846. }, 500);
  3847. });
  3848. doc.on('click', '.listener-retry', async function (e) {
  3849. let o = _factory(e);
  3850. o.tip.hide();
  3851. o.link.show();
  3852. o.directLink.show();
  3853. });
  3854. doc.on('click', '.listener-how', async function (e) {
  3855. let o = _factory(e);
  3856. let index = o.link[0].dataset.index;
  3857. if (request[index]) {
  3858. request[index].abort();
  3859. clearInterval(ins[index]);
  3860. o.progress.hide();
  3861. o.tip.show();
  3862. }
  3863.  
  3864. });
  3865. doc.on('click', '.listener-stop', async function (e) {
  3866. let o = _factory(e);
  3867. let index = o.link[0].dataset.index;
  3868. if (request[index]) {
  3869. request[index].abort();
  3870. clearInterval(ins[index]);
  3871. o.item.find('.pl-progress-inner-text').text('正在取消...');
  3872. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  3873. setTimeout(function () {
  3874. o.tip.hide();
  3875. o.back.hide();
  3876. o.link.show();
  3877. o.directLink.show();
  3878. o.copy.show();
  3879. o.progress.hide();
  3880. o.stop.hide();
  3881. }, 1050)
  3882. }
  3883. });
  3884. doc.on('click', '.listener-back', async function (e) {
  3885. let o = _factory(e);
  3886. o.progress.hide();
  3887. o.tip.hide();
  3888. o.link.show();
  3889. o.directLink.show();
  3890. o.copy.show();
  3891. o.stop.hide();
  3892. o.back.hide();
  3893. });
  3894. doc.on('click', '.listener-copy-filename', async function (e) {
  3895. base.setClipboard(e.target.dataset.filename);
  3896. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  3897. setTimeout(function () {
  3898. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  3899. }, 2000)
  3900. });
  3901. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  3902. e.preventDefault();
  3903. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  3904. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  3905. setTimeout(function () {
  3906. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  3907. }, 2000)
  3908. });
  3909. doc.on('click', '.listener-link-rpc', async function (e) {
  3910. e.preventDefault();
  3911. let target = $(e.currentTarget);
  3912.  
  3913. target.find('.icon-rpc-devices').remove();
  3914. target.find('.pl-loading').remove();
  3915. target.prepend(base.createLoading());
  3916.  
  3917. let res = await ali.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  3918. if (res === 'success') {
  3919. $('.listener-rpc-task').show();
  3920. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  3921. } else if (res === 'assistant') {
  3922. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  3923. } else {
  3924. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  3925. }
  3926. });
  3927. doc.on('click', '.listener-send-rpc', function (e) {
  3928. $('.listener-link-rpc').click();
  3929. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  3930. });
  3931. doc.on('click', '.listener-download-all.blob', function (e) {
  3932. $('.pl-item-link.blob').each(function () {
  3933. if ($(this).css('display') !== 'none') {
  3934. $(this).click();
  3935. }
  3936. });
  3937. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  3938. setTimeout(function () {
  3939. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  3940. }, 2000)
  3941. });
  3942. doc.on('click', '.listener-open-setting', function () {
  3943. base.showSetting();
  3944. });
  3945. doc.on('click', '.listener-open-updatelog', function () {
  3946. base.showUpdateLog();
  3947. });
  3948. doc.on('click', '.listener-open-beautify', function () {
  3949. base.showBeautify();
  3950. });
  3951. doc.on('click', '.listener-rpc-task', function () {
  3952. let rpc = JSON.stringify({
  3953. domain: base.getValue('setting_rpc_domain'),
  3954. port: base.getValue('setting_rpc_port'),
  3955. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  3956. GM_openInTab(url, { active: true });
  3957. });
  3958. document.documentElement.addEventListener('mouseup', function (e) {
  3959. if (e.target.nodeName === 'A' && ~e.target.className.indexOf('pl-a')) {
  3960. e.stopPropagation();
  3961. }
  3962. }, true);
  3963. },
  3964.  
  3965. async getRealLink(d, f) {
  3966. let authorization = `${base.getStorage('token').token_type} ${base.getStorage('token').access_token}`;
  3967. let res = await base.post(pan.pcs[1], {
  3968. drive_id: d,
  3969. file_id: f
  3970. }, {
  3971. authorization,
  3972. "content-type": "application/json;charset=utf-8",
  3973. "referer": "https://www.aliyundrive.com/",
  3974. "x-canary": "client=windows,app=adrive,version=v6.0.0"
  3975. });
  3976. if (res.code === 'AccessTokenInvalid') {
  3977. return message.error('提示:<br/>Token过期了,请刷新网页后再试');
  3978. }
  3979. if (res.url) {
  3980. return res.url;
  3981. }
  3982. return '';
  3983. },
  3984.  
  3985. removeAD() {
  3986. base.waitForKeyElements('[class*="share-list-banner"]', function (tag) {
  3987. tag.fadeOut();
  3988. }, true);
  3989. base.waitForKeyElements('[class*="to-app"]', function (tag) {
  3990. tag.fadeOut();
  3991. }, true);
  3992. base.waitForKeyElements('[class*="btn-mobile-save"]', function (tag) {
  3993. tag.fadeOut();
  3994. });
  3995. base.waitForKeyElements('div[class*="text"]', function (tag) {
  3996. if (tag[0].innerHTML.match("SVIP"))
  3997. tag.fadeOut();
  3998. }, true);
  3999. base.waitForKeyElements('[class*="SplashScreenImg--close"]', function (tag) {
  4000. tag[0].click();
  4001. }, true);
  4002. base.waitForKeyElements('[class*="container"]', function (tag) {
  4003. tag.find('[class^="icon-close"]').click();
  4004. }, true);
  4005. base.waitForKeyElements('[class*="popup_main_close"]', function (tag) {
  4006. tag[0].click();
  4007. }, true);
  4008. },
  4009.  
  4010. addButton() {
  4011. if (!pt) return;
  4012. let $toolWrap;
  4013. let svg = `<svg class="ali-btn-icon" style="margin-right: 3px;" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M853.333 938.667H170.667a85.333 85.333 0 0 1-85.334-85.334v-384A85.333 85.333 0 0 1 170.667 384H288a32 32 0 0 1 0 64H170.667a21.333 21.333 0 0 0-21.334 21.333v384a21.333 21.333 0 0 0 21.334 21.334h682.666a21.333 21.333 0 0 0 21.334-21.334v-384A21.333 21.333 0 0 0 853.333 448H736a32 32 0 0 1 0-64h117.333a85.333 85.333 0 0 1 85.334 85.333v384a85.333 85.333 0 0 1-85.334 85.334z" fill="#FFFFFF"></path><path d="M715.03 543.552a32.81 32.81 0 0 0-46.251 0L554.005 657.813v-540.48a32 32 0 0 0-64 0v539.734L375.893 543.488a32.79 32.79 0 0 0-46.229 0 32.427 32.427 0 0 0 0 46.037l169.557 168.811a32.81 32.81 0 0 0 46.251 0l169.557-168.81a32.47 32.47 0 0 0 0-45.974z" fill="#FFFFFF"></path></svg>`
  4014. let $button = $(`<div class="ali-button pl-button"><span data-role="icon" data-render-as="svg" class="icon">${svg}下载助手</span><ul class="pl-dropdown-menu" style="top: 30px; right: 0;"><li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria" >Aria下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc" >BC下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li></ul></div>`);
  4015. if (pt === 'home') {
  4016. base.listenElement(pan.btn.home, function () {
  4017. $toolWrap = $(pan.btn.home);
  4018. $('.pl-button').length === 0 && $toolWrap.append($button);
  4019. })
  4020. }
  4021. if (pt === 'share') {
  4022. $button = $(`<div class="ali-button pl-button"><span data-role="icon" data-render-as="svg" class="icon">${svg}下载助手</span><ul class="pl-dropdown-menu" style="top: 30px; right: 16px;"><li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria" >Aria下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc" >BC下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li></ul></div>`);
  4023. $button.css({ 'margin-right': '10px', "height": "36px", "width": "auto", "padding": "1px 30px" });
  4024. base.listenElement(pan.btn.share, function () {
  4025. $toolWrap = $(pan.btn.share);
  4026. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  4027. })
  4028. }
  4029. base.createDownloadIframe();
  4030. },
  4031.  
  4032. addInitButton() {
  4033. if (!pt) return;
  4034. let $toolWrap;
  4035. let $button = $(`<div class="ali-button pl-button-init"><span data-role="icon" data-render-as="svg" class="icon"><svg class="ali-btn-icon" style="margin-right: 3px;" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M853.333 938.667H170.667a85.333 85.333 0 0 1-85.334-85.334v-384A85.333 85.333 0 0 1 170.667 384H288a32 32 0 0 1 0 64H170.667a21.333 21.333 0 0 0-21.334 21.333v384a21.333 21.333 0 0 0 21.334 21.334h682.666a21.333 21.333 0 0 0 21.334-21.334v-384A21.333 21.333 0 0 0 853.333 448H736a32 32 0 0 1 0-64h117.333a85.333 85.333 0 0 1 85.334 85.333v384a85.333 85.333 0 0 1-85.334 85.334z" fill="#FFFFFF"></path><path d="M715.03 543.552a32.81 32.81 0 0 0-46.251 0L554.005 657.813v-540.48a32 32 0 0 0-64 0v539.734L375.893 543.488a32.79 32.79 0 0 0-46.229 0 32.427 32.427 0 0 0 0 46.037l169.557 168.811a32.81 32.81 0 0 0 46.251 0l169.557-168.81a32.47 32.47 0 0 0 0-45.974z" fill="#FFFFFF"></path></svg>点我点亮</span></div>`);
  4036. $button.css({ "width": "auto" });
  4037. if (pt === 'home') {
  4038. base.listenElement(pan.btn.home, function () {
  4039. $toolWrap = $(pan.btn.home);
  4040. $('.pl-button-init').length === 0 && $toolWrap.append($button);
  4041. })
  4042. }
  4043. if (pt === 'share') {
  4044. $button = $(`<div class="ali-button pl-button-init"><span data-role="icon" data-render-as="svg" class="icon"><svg class="ali-btn-icon" style="margin-right: 3px;" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M853.333 938.667H170.667a85.333 85.333 0 0 1-85.334-85.334v-384A85.333 85.333 0 0 1 170.667 384H288a32 32 0 0 1 0 64H170.667a21.333 21.333 0 0 0-21.334 21.333v384a21.333 21.333 0 0 0 21.334 21.334h682.666a21.333 21.333 0 0 0 21.334-21.334v-384A21.333 21.333 0 0 0 853.333 448H736a32 32 0 0 1 0-64h117.333a85.333 85.333 0 0 1 85.334 85.333v384a85.333 85.333 0 0 1-85.334 85.334z" fill="#FFFFFF"></path><path d="M715.03 543.552a32.81 32.81 0 0 0-46.251 0L554.005 657.813v-540.48a32 32 0 0 0-64 0v539.734L375.893 543.488a32.79 32.79 0 0 0-46.229 0 32.427 32.427 0 0 0 0 46.037l169.557 168.811a32.81 32.81 0 0 0 46.251 0l169.557-168.81a32.47 32.47 0 0 0 0-45.974z" fill="#FFFFFF"></path></svg>点我点亮</span></div>`);
  4045. $button.css({ 'margin-right': '10px', "height": "36px", "padding": "1px 30px", "width": "auto" });
  4046. base.listenElement(pan.btn.share, function () {
  4047. $toolWrap = $(pan.btn.share);
  4048. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  4049. })
  4050. }
  4051. $button.click(function () { base.initDialog() });
  4052. },
  4053.  
  4054. async getPCSLink() {
  4055. let reactDomGrid = document.querySelector(pan.dom.grid);
  4056. if (reactDomGrid) {
  4057. let dialog = await Swal.fire({
  4058. title: '提示',
  4059. html: '<div style="display: flex;align-items: center;justify-content: center;">请切换到&nbsp;&nbsp;<svg class="icon" class="icon--D3kMk " viewBox="0 0 1024 1024" width="20" height="20"><use xlink:href="#PDSDrag"></use></svg>&nbsp;<b>列表视图</b>&nbsp;&nbsp;后获取下载链接</div>',
  4060. icon: 'info',
  4061. showCloseButton: true,
  4062. showDenyButton: true,
  4063. heightAuto: false,
  4064. scrollbarPadding: false,
  4065. confirmButtonText: '切换',
  4066. denyButtonText: '不要'
  4067. });
  4068. if (dialog.isConfirmed) {
  4069. document.querySelector(pan.dom.switch).click();
  4070. return message.success('提示:<br/>切换为列表视图成功<br/>请再获取一次下载链接吧~');
  4071. }
  4072. return false;
  4073. }
  4074. selectList = this.getSelectedList();
  4075. if (selectList.length === 0) {
  4076. return message.error('提示:<br/>请勾选要下载的文件哦~');
  4077. }
  4078. if (this.isOnlyFolder()) {
  4079. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  4080. }
  4081. if (pt === 'share') {
  4082. try {
  4083. let authorization = `${base.getStorage('token').token_type} ${base.getStorage('token').access_token}`;
  4084. let xShareToken = base.getStorage('shareToken').share_token;
  4085.  
  4086. // 每次获取多少个
  4087. const batchSize = 15;
  4088.  
  4089. // 循环分批获取文件的下载链接
  4090. for (let i = 0; i < selectList.length; i += batchSize) {
  4091. // 当前批次文件
  4092. let batch = selectList.slice(i, i + batchSize);
  4093.  
  4094. // 遍历获取本批次的请求结果
  4095. for (let j = 0; j < batch.length; j++) {
  4096. let item = batch[j];
  4097. let res = await base.post(pan.pcs[0], {
  4098. expire_sec: 600,
  4099. file_id: item.fileId,
  4100. share_id: item.shareId
  4101. }, {
  4102. authorization,
  4103. "content-type": "application/json;charset=utf-8",
  4104. "x-share-token": xShareToken
  4105. });
  4106.  
  4107. // 如果成功获取到下载链接,更新当前文件的下载URL
  4108. if (res.download_url) {
  4109. item.downloadUrl = res.download_url;
  4110. }
  4111. }
  4112.  
  4113. // 每次处理完一个批次后,等待 3 秒
  4114. if (i + batchSize < selectList.length) await base.sleep(2000);
  4115. }
  4116. } catch (e) {
  4117. return message.error('提示:<br/>获取下载链接失败,接口已失效,请保存后再下载~');
  4118. }
  4119. } else {
  4120. // 每次获取多少个
  4121. const batchSize = 15;
  4122.  
  4123. // 循环分批获取文件的下载链接
  4124. for (let i = 0; i < selectList.length; i += batchSize) {
  4125. // 当前批次文件
  4126. let batch = selectList.slice(i, i + batchSize);
  4127.  
  4128. // 过滤掉已有 URL 的文件
  4129. let noUrlSelectList = batch.filter(v => !Boolean(v.url));
  4130. let queue = [];
  4131.  
  4132. // 为没有 URL 的文件生成请求队列
  4133. noUrlSelectList.forEach((item) => {
  4134. queue.push(this.getRealLink(item.driveId, item.fileId));
  4135. });
  4136.  
  4137. // 等待本批次的请求结果
  4138. const res = await Promise.all(queue);
  4139. res.forEach((val, index) => {
  4140. noUrlSelectList[index].url = val;
  4141. });
  4142.  
  4143. // 每次处理完一个批次后,等待 3 秒
  4144. if (i + batchSize < selectList.length) await base.sleep(2000);
  4145. }
  4146. }
  4147.  
  4148. let html = this.generateDom(selectList);
  4149. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  4150. },
  4151.  
  4152. generateDom(list) {
  4153. let content = '<div class="pl-main">';
  4154. let alinkAllText = '';
  4155. list.forEach((v, i) => {
  4156. if (v.type === 'folder') return;
  4157. let filename = v.name;
  4158. let fid = v.fileId;
  4159. let did = v.driveId;
  4160. let size = base.sizeFormat(v.size);
  4161. let dlink = v.downloadUrl || v.url;
  4162. if (mode === 'api') {
  4163. alinkAllText += dlink + '\r\n';
  4164. content += `<div class="pl-item">
  4165. <div class="pl-item-name listener-tip" data-size="${size}" >${filename}</div>
  4166. <button class="pl-item-link listener-tip pl-btn-primary listener-link-api blob" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接" data-did="${did}" data-fid="${fid}" data-filename="${filename}" data-link="${dlink}" data-size="${v.size}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  4167. <button class="pl-item-link listener-tip pl-btn-primary pl-btn-info listener-link-api browser" data-title="基于浏览器直接打开链接来下载文件,适用于较为古老但支持 iframe 的浏览器,点击“直接下载”后需等待下载提示弹出才能点击下个“直接下载”,否则只会下载后者,此方式下载有可能会被 IDM 捕获下载链接" data-did="${did}" data-fid="${fid}" data-filename="${filename}" data-link="${dlink}" data-index="${i}">直接下载(基于浏览器链接)</button>
  4168. <button class="pl-item-copy listener-tip pl-btn-primary pl-btn-success listener-copy-filename" data-title="本网盘于下载高峰期时可能不会显示文件名称,这时需要手动复制文件名称到下载工具中" data-filename="${filename}">复制名称</button>
  4169. <button class="pl-item-copy listener-tip pl-btn-primary pl-btn-warning listener-copy-all" href="${dlink}" data-title="不建议使用本功能,在本网盘单独复制链接并粘贴下载可能会导致服务器回报 403 错误" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  4170. <div class="pl-item-tip" style="display: none"><span><span class="pl-ext"></span></span> <span class="listener-back">返回</span></div>
  4171. <div class="pl-item-progress" style="display: none">
  4172. <div class="pl-progress">
  4173. <div class="pl-progress-outer"></div>
  4174. <div class="pl-progress-inner" style="width:5%">
  4175. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  4176. </div>
  4177. </div>
  4178. <span class="pl-btn-primary pl-btn-danger pl-progress-stop listener-stop">取消下载</span>
  4179. `;
  4180. content += `<span class="pl-btn-primary pl-btn-info pl-progress-back listener-back" style="display: none">返回</span>
  4181. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  4182. `;
  4183. content += `</div></div>`;
  4184. }
  4185. if (mode === 'aria') {
  4186. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  4187. alinkAllText += alink + '\r\n';
  4188. content += `<div class="pl-item">
  4189. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4190. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  4191. }
  4192. if (mode === 'rpc') {
  4193. content += `<div class="pl-item">
  4194. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4195. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink.replace(' ', '%20')}"><svg class="icon-rpc-devices" viewBox="-10 0 1034 1024"><g transform="matrix(1 0 0 -1 0 960)"><path fill="currentColor" d="M832 -64h-640q-53 0 -90.5 37.5t-37.5 90.5v768q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-768q0 -53 -37.5 -90.5t-90.5 -37.5zM832 768q0 27 -18.5 45.5t-45.5 18.5h-512q-27 0 -45.5 -18.5t-18.5 -45.5v-320h640v320v0zM832 320h-640v-192q0 -27 18.5 -45.5t45.5 -18.5h512q27 0 45.5 18.5t18.5 45.5v192v0zM512 128q-27 0 -45.5 18.5t-18.5 45.5t18.5 45.5t45.5 18.5t45.5 -18.5t18.5 -45.5t-18.5 -45.5t-45.5 -18.5z" /></g></svg><span style="margin-left: 5px;">将 ${filename} 推送到 RPC 下载器</span></button></div>`;
  4196. }
  4197. if (mode === 'curl') {
  4198. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  4199. alinkAllText += alink + '\r\n';
  4200. content += `<div class="pl-item">
  4201. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4202. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  4203. }
  4204. if (mode === 'bc') {
  4205. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  4206. alinkAllText += alink + '\r\n';
  4207. content += `<div class="pl-item">
  4208. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4209. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a> </div>`;
  4210. }
  4211. });
  4212. content += '</div>';
  4213. if (mode === 'api')
  4214. content += `<div class="pl-extra"><button class="pl-btn-primary listener-tip listener-download-all blob" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接">全部增强下载</button><button class="pl-btn-primary listener-tip listener-copy-all" data-link="${alinkAllText}" data-title="不建议使用本功能,在本网盘单独复制链接并粘贴下载可能会导致服务器回报 403 错误">复制全部链接</button></div>`;
  4215. if (mode === 'aria')
  4216. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  4217. if (mode === 'rpc') {
  4218. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  4219. content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">修改 RPC 参数(${rpc})</button><button class="pl-btn-primary pl-btn-success pl-btn-opacity listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  4220. }
  4221. if (mode === 'curl') {
  4222. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">修改终端类型(${terminalType[base.getValue('setting_terminal_type')]})</button></div>`;
  4223. }
  4224. if (mode === 'bc') {
  4225. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  4226. }
  4227. return content;
  4228. },
  4229.  
  4230. async sendLinkToRPC(filename, link) {
  4231. let rpc = {
  4232. domain: base.getValue('setting_rpc_domain'),
  4233. port: base.getValue('setting_rpc_port'),
  4234. path: base.getValue('setting_rpc_path'),
  4235. token: base.getValue('setting_rpc_token'),
  4236. dir: base.getValue('setting_rpc_dir'),
  4237. };
  4238.  
  4239. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  4240. let rpcData = {
  4241. id: new Date().getTime(),
  4242. jsonrpc: '2.0',
  4243. method: 'aria2.addUri',
  4244. params: [`token:${rpc.token}`, [link], {
  4245. dir: rpc.dir,
  4246. out: filename,
  4247. header: [`Referer: https://${location.host}/`]
  4248. }]
  4249. };
  4250. try {
  4251. let res = await base.post(url, rpcData, { "Referer": `https://${location.host}/` }, '');
  4252. if (res.result) return 'success';
  4253. return 'fail';
  4254. } catch (e) {
  4255. return 'fail';
  4256. }
  4257. },
  4258.  
  4259. getSelectedList() {
  4260. try {
  4261. let selectedList = [];
  4262. let reactDom = document.querySelector(pan.dom.list);
  4263. let reactObj = base.findReact(reactDom, 1);
  4264. let props = reactObj.pendingProps;
  4265. if (props) {
  4266. let fileList = props.dataSource || [];
  4267. let selectedKeys = props.selectedKeys.split(',');
  4268. fileList.forEach(function (val) {
  4269. if (selectedKeys.includes(val.fileId)) {
  4270. selectedList.push(val);
  4271. }
  4272. });
  4273. }
  4274. return selectedList;
  4275. } catch (e) {
  4276. return [];
  4277. }
  4278. },
  4279.  
  4280. detectPage() {
  4281. let path = location.pathname;
  4282. if (/^\/(drive)/.test(path)) return 'home';
  4283. if (/^\/(s|share)\//.test(path)) return 'share';
  4284. return '';
  4285. },
  4286.  
  4287. isOnlyFolder() {
  4288. for (let i = 0; i < selectList.length; i++) {
  4289. if (selectList[i].type === 'file') return false;
  4290. }
  4291. return true;
  4292. },
  4293.  
  4294. showMainDialog(title, html, footer) {
  4295. Swal.fire({
  4296. title,
  4297. html,
  4298. footer,
  4299. allowOutsideClick: false,
  4300. showCloseButton: true,
  4301. position: 'center',
  4302. width,
  4303. padding: '15px 20px 5px',
  4304. customClass,
  4305. confirmButtonText: '关闭',
  4306. willClose: function () {
  4307. base._resetData();
  4308. }
  4309. }).then(function () {
  4310. base._resetData();
  4311. });
  4312. },
  4313.  
  4314. async initPanLinker() {
  4315. pt = this.detectPage();
  4316. base.createTip();
  4317. base.registerMenuCommand();
  4318. if (base.getValue('setting_server_main') === 'v1') {
  4319. let res = await base.post(`https://api.youxiaohou.com/config/ali/?ver=${version}&a=${author}`, {}, {}, 'text');
  4320. pan = JSON.parse(base.decode(res));
  4321. } else if (base.getValue('setting_server_main') === 'v2') {
  4322. let res = await base.post(`https://api.youxiaohou.com/config/v2/ali/?ver=${version}&a=${author}`, {}, {}, 'text');
  4323. pan = JSON.parse(base.decode(res));
  4324. } else if (base.getValue('setting_server_main') === "no") {
  4325. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/ali.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  4326. pan = JSON.parse(res);
  4327. } else {
  4328. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/ali.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  4329. pan = JSON.parse(res);
  4330. base.setValue('setting_server_main', 'v2');
  4331. }
  4332. Object.freeze && Object.freeze(pan);
  4333. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('setting_init_license')) {
  4334. this.addButton();
  4335. this.addPageListener();
  4336. } else {
  4337. this.addInitButton();
  4338. }
  4339. }
  4340. };
  4341.  
  4342. //天翼云盘
  4343. let tianyi = {
  4344.  
  4345. convertLinkToAria(link, filename, ua) {
  4346. filename = base.fixFilename(filename);
  4347. return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
  4348. },
  4349.  
  4350. convertLinkToBC(link, filename, ua) {
  4351. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
  4352. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  4353. },
  4354.  
  4355. convertLinkToCurl(link, filename, ua) {
  4356. let terminal = base.getValue('setting_terminal_type');
  4357. filename = base.fixFilename(filename);
  4358. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}"`);
  4359. },
  4360.  
  4361. addPageListener() {
  4362. /*
  4363. 防止代码因其他原因被执行多次
  4364. 这段代码出自 Via轻插件,作者谷花泰
  4365. */
  4366. const key = encodeURIComponent('(改)网盘直链下载助手:天翼云盘');
  4367. if (window[key]) return;
  4368. window[key] = true;
  4369.  
  4370. function _factory(e) {
  4371. let target = $(e.target);
  4372. let item = target.parents('.pl-item');
  4373. let link = item.find('.pl-item-link.blob');
  4374. let directLink = item.find('.pl-item-link.browser');
  4375. let progress = item.find('.pl-item-progress');
  4376. let tip = item.find('.pl-item-tip');
  4377. let copy = item.find('.pl-item-copy');
  4378. let howidm = item.find('.pl-progress-how');
  4379. let back = item.find('.pl-progress-back');
  4380. let stop = item.find('.pl-progress-stop');
  4381. return {
  4382. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  4383. };
  4384. }
  4385.  
  4386. function _reset(i) {
  4387. ins[i] && clearInterval(ins[i]);
  4388. request[i] && request[i].abort();
  4389. progress[i] = 0;
  4390. idm[i] = false;
  4391. }
  4392.  
  4393. doc.on('click', '.pl-button-mode', function (e) {
  4394. mode = e.target.dataset.mode;
  4395. if (!mode) return;
  4396. Swal.fire({
  4397. heightAuto: false,
  4398. scrollbarPadding: false,
  4399. showConfirmButton: false,
  4400. html: `链接获取中`,
  4401. willOpen: function () {
  4402. Swal.showLoading();
  4403. }
  4404. });
  4405. tianyi.getPCSLink();
  4406. });
  4407. doc.on('click', '.listener-link-api.browser', async function (e) {
  4408. e.preventDefault();
  4409. let dataset = e.currentTarget.dataset;
  4410. let href = dataset.link;
  4411. $('#downloadIframe').attr('src', href);
  4412. });
  4413. doc.on('click', '.listener-link-api.blob', async function (e) {
  4414. e.preventDefault();
  4415. let o = _factory(e);
  4416. let $width = o.item.find('.pl-progress-inner');
  4417. let $text = o.item.find('.pl-progress-inner-text');
  4418. let filename = o.link[0].dataset.filename;
  4419. let index = o.link[0].dataset.index;
  4420. _reset(index);
  4421. let dataset = e.currentTarget.dataset;
  4422. let href = dataset.link;
  4423. base.get(href, { "Referer": `https://${location.host}/` }, 'blob', { filename, index });
  4424. let startTime = Date.now(); // 记录下载开始时间
  4425. let prevLoaded = 0; // 上一次的已下载数据量
  4426. let prevTime = startTime; // 上一次的时间
  4427. let size = Number(o.link[0].dataset.size);
  4428. ins[index] = setInterval(function () {
  4429. let prog = +progress[index] || 0;
  4430. // 处理普通下载的情况...
  4431. let currentTime = Date.now();
  4432. let elapsedTime = currentTime - startTime;
  4433. let totalProgress = prog / 100;
  4434. let totalElapsedSeconds = elapsedTime / 1000;
  4435. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  4436. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  4437.  
  4438. // 将剩余时间转换为天、时、分、秒
  4439. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  4440. remainingTimeSeconds %= (60 * 60 * 24);
  4441.  
  4442. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  4443. remainingTimeSeconds %= (60 * 60);
  4444.  
  4445. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  4446. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  4447.  
  4448. // 计算下载速度
  4449. let loaded = prog * size / 100; // 已下载数据量
  4450. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  4451. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  4452. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  4453.  
  4454. // 更新上一次的数据
  4455. prevLoaded = loaded;
  4456. prevTime = currentTime;
  4457.  
  4458. // 更改界面
  4459. o.link.hide();
  4460. o.directLink.hide();
  4461. o.tip.hide();
  4462. o.stop.show();
  4463. o.copy.hide();
  4464. o.progress.show();
  4465.  
  4466. // 更新进度条
  4467. $width.css('width', prog + '%');
  4468.  
  4469. // 更新进度条文本
  4470. let timeText = '';
  4471. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  4472. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  4473. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  4474. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  4475. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  4476. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  4477. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  4478. timeText = remainingSeconds + '秒';
  4479. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  4480. timeText = '即将完成';
  4481. } else {
  4482. timeText = '计算中...';
  4483. }
  4484.  
  4485. let speedText = '';
  4486. speedText = base.sizeFormat(downloadSpeed)
  4487. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  4488.  
  4489. if (prog === 100) {
  4490. setTimeout(function () {
  4491. clearInterval(ins[index]);
  4492. progress[index] = 0;
  4493. o.item.find('.pl-progress-stop').hide();
  4494. o.howidm.hide();
  4495. $text.text('下载完成~ 浏览器下载框应该弹出来了哦~');
  4496. o.back.show()
  4497. setTimeout(function () {
  4498. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  4499. }, 3000)
  4500. }, 1000)
  4501. }
  4502. }, 500);
  4503. });
  4504. doc.on('click', '.listener-retry', async function (e) {
  4505. let o = _factory(e);
  4506. o.tip.hide();
  4507. o.link.show();
  4508. o.directLink.show();
  4509. });
  4510. doc.on('click', '.listener-how', async function (e) {
  4511. let o = _factory(e);
  4512. let index = o.link[0].dataset.index;
  4513. if (request[index]) {
  4514. request[index].abort();
  4515. clearInterval(ins[index]);
  4516. o.progress.hide();
  4517. o.tip.show();
  4518. }
  4519.  
  4520. });
  4521. doc.on('click', '.listener-stop', async function (e) {
  4522. let o = _factory(e);
  4523. let index = o.link[0].dataset.index;
  4524. if (request[index]) {
  4525. request[index].abort();
  4526. clearInterval(ins[index]);
  4527. o.item.find('.pl-progress-inner-text').text('正在取消...');
  4528. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  4529. setTimeout(function () {
  4530. o.tip.hide();
  4531. o.back.hide();
  4532. o.link.show();
  4533. o.directLink.show();
  4534. o.copy.show();
  4535. o.progress.hide();
  4536. o.stop.hide();
  4537. }, 1050)
  4538. }
  4539. });
  4540. doc.on('click', '.listener-back', async function (e) {
  4541. let o = _factory(e);
  4542. o.progress.hide();
  4543. o.tip.hide();
  4544. o.link.show();
  4545. o.directLink.show();
  4546. o.copy.show();
  4547. o.stop.hide();
  4548. o.back.hide();
  4549. });
  4550. doc.on('click', '.listener-download-all', function (e) {
  4551. $('.pl-item-link.blob').each(function () {
  4552. if ($(this).css('display') !== 'none') {
  4553. $(this).click();
  4554. }
  4555. });
  4556. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  4557. setTimeout(function () {
  4558. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  4559. }, 2000)
  4560. });
  4561. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  4562. e.preventDefault();
  4563. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  4564. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  4565. setTimeout(function () {
  4566. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  4567. }, 2000)
  4568. });
  4569. doc.on('click', '.listener-link-rpc', async function (e) {
  4570. e.preventDefault();
  4571. let target = $(e.currentTarget);
  4572.  
  4573. target.find('.icon-rpc-devices').remove();
  4574. target.find('.pl-loading').remove();
  4575. target.prepend(base.createLoading());
  4576.  
  4577. let res = await tianyi.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  4578. if (res === 'success') {
  4579. $('.listener-rpc-task').show();
  4580. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  4581. } else if (res === 'assistant') {
  4582. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  4583. } else {
  4584. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  4585. }
  4586. });
  4587. doc.on('click', '.listener-send-rpc', function (e) {
  4588. $('.listener-link-rpc').click();
  4589. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  4590. });
  4591. doc.on('click', '.listener-open-setting', function () {
  4592. base.showSetting();
  4593. });
  4594. doc.on('click', '.listener-open-updatelog', function () {
  4595. base.showUpdateLog();
  4596. });
  4597. doc.on('click', '.listener-open-beautify', function () {
  4598. base.showBeautify();
  4599. });
  4600. doc.on('click', '.listener-rpc-task', function () {
  4601. let rpc = JSON.stringify({
  4602. domain: base.getValue('setting_rpc_domain'),
  4603. port: base.getValue('setting_rpc_port'),
  4604. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  4605. GM_openInTab(url, { active: true });
  4606. });
  4607. },
  4608.  
  4609. removeAD() {
  4610. base.waitForKeyElements(".advertising-mask", function (tag) {
  4611. tag.fadeOut();
  4612. }, true);
  4613. base.waitForKeyElements("a.client-download.nav-block", function (tag) {
  4614. tag.fadeOut();
  4615. }, true);
  4616. },
  4617.  
  4618. addButton() {
  4619. if (!pt) return;
  4620. let $toolWrap;
  4621. let $button = $(`<div class="tianyi-button pl-button">下载助手<ul class="pl-dropdown-menu" style="top: 26px;"><li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria" >Aria下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc" >BC下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li></ul></div>`);
  4622. if (pt === 'home') {
  4623. base.listenElement(pan.btn.home, function () {
  4624. $toolWrap = $(pan.btn.home);
  4625. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  4626. })
  4627. }
  4628. if (pt === 'share') {
  4629. base.listenElement(pan.btn.share, function () {
  4630. $toolWrap = $(pan.btn.share);
  4631. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  4632. })
  4633. }
  4634. base.createDownloadIframe();
  4635. },
  4636.  
  4637. addInitButton() {
  4638. if (!pt) return;
  4639. let $toolWrap;
  4640. let $button = $(`<div class="tianyi-button pl-button-init">点我点亮</div>`);
  4641. if (pt === 'home') {
  4642. base.listenElement(pan.btn.home, function () {
  4643. $toolWrap = $(pan.btn.home);
  4644. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  4645. })
  4646. }
  4647. if (pt === 'share') {
  4648. $button.css({ 'margin-right': '10px' });
  4649. base.listenElement(pan.btn.share, function () {
  4650. $toolWrap = $(pan.btn.share);
  4651. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  4652. })
  4653. }
  4654. $button.click(function () { base.initDialog() });
  4655. },
  4656.  
  4657. async getToken() {
  4658. let res = await base.getFinalUrl(pan.pcs[1], {});
  4659. let accessToken = res.match(/accessToken=(\w+)/)?.[1];
  4660. accessToken && base.setStorage('accessToken', accessToken);
  4661. return accessToken;
  4662. },
  4663.  
  4664. async getFileUrlByOnce(item, index, token) {
  4665. try {
  4666. if (item.downloadUrl) return {
  4667. index,
  4668. downloadUrl: item.downloadUrl
  4669. };
  4670. let time = Date.now(),
  4671. fileId = item.fileId,
  4672. o = "AccessToken=" + token + "&Timestamp=" + time + "&fileId=" + fileId,
  4673. url = pan.pcs[2] + '?fileId=' + fileId;
  4674. if (item.shareId) {
  4675. o = "AccessToken=" + token + "&Timestamp=" + time + "&dt=1&fileId=" + fileId + "&shareId=" + item.shareId;
  4676. url += '&dt=1&shareId=' + item.shareId;
  4677. }
  4678. let sign = md5(o).toString();
  4679. let res = await base.get(url, {
  4680. "accept": "application/json;charset=UTF-8",
  4681. "sign-type": 1,
  4682. "accesstoken": token,
  4683. "timestamp": time,
  4684. "signature": sign
  4685. });
  4686. if (res.res_code === 0) {
  4687. return {
  4688. index,
  4689. downloadUrl: res.fileDownloadUrl
  4690. };
  4691. } else if (res.errorCode === 'InvalidSessionKey') {
  4692. return {
  4693. index,
  4694. downloadUrl: '提示:<br/>请先登录(不可用)网盘~'
  4695. };
  4696. } else if (res.res_code === 'ShareNotFoundFlatDir') {
  4697. return {
  4698. index,
  4699. downloadUrl: '提示:<br/>请[转存]文件,之后再👉前往[我的网盘]中下载哦~'
  4700. };
  4701. } else {
  4702. return {
  4703. index,
  4704. downloadUrl: '获取下载地址失败,刷新后再试试吧~' + (res.res_code ? res.res_code : "")
  4705. };
  4706. }
  4707. } catch (e) {
  4708. return {
  4709. index,
  4710. downloadUrl: '获取下载地址失败,刷新后再试试吧~'
  4711. };
  4712. }
  4713. },
  4714.  
  4715. async getPCSLink() {
  4716. selectList = this.getSelectedList();
  4717. if (selectList.length === 0) {
  4718. return message.error('提示:<br/>请勾选要下载的文件哦~');
  4719. }
  4720. if (this.isOnlyFolder()) {
  4721. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  4722. }
  4723. let token = base.getStorage('accessToken') || await this.getToken();
  4724. if (!token) {
  4725. return message.error('提示:<br/>请先登录(不可用)网盘~');
  4726. }
  4727. let queue = [];
  4728. for (const [index, item] of selectList.entries()) {
  4729. queue.push(this.getFileUrlByOnce(item, index, token));
  4730. }
  4731.  
  4732. const res = await Promise.all(queue);
  4733. res.forEach(val => {
  4734. selectList[val.index].downloadUrl = val.downloadUrl;
  4735. });
  4736.  
  4737. let html = this.generateDom(selectList);
  4738. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  4739. },
  4740.  
  4741. generateDom(list) {
  4742. let content = '<div class="pl-main">';
  4743. let alinkAllText = '';
  4744. list.forEach((v, i) => {
  4745. if (v.isFolder) return;
  4746. let filename = v.fileName;
  4747. let ext = base.getExtension(filename);
  4748. let size = base.sizeFormat(v.size);
  4749. let dlink = v.downloadUrl;
  4750. if (mode === 'api') {
  4751. alinkAllText += dlink + '\r\n';
  4752. content += `<div class="pl-item">
  4753. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4754. <button class="pl-item-link listener-tip pl-btn-primary listener-link-api blob" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接" data-filename="${filename}" data-size="${v.size}" data-link="${dlink}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  4755. <button class="pl-item-link listener-tip pl-btn-primary pl-btn-info listener-link-api browser" data-title="基于浏览器直接打开链接来下载文件,适用于较为古老但支持 iframe 的浏览器,点击“直接下载”后需等待下载提示弹出才能点击下个“直接下载”,否则只会下载后者,此方式下载有可能会被 IDM 捕获下载链接" data-filename="${filename}" data-link="${dlink}">直接下载(基于浏览器链接)</button>
  4756. <button class="pl-item-copy pl-btn-primary pl-btn-warning listener-copy-all" href="${dlink}" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  4757. <div class="pl-item-tip" style="display: none"><span>若没有弹出IDM下载框,找到IDM <b>选项</b> -> <b>文件类型</b> -> <b>第一个框</b> 中添加后缀 <span class="pl-ext">${ext}</span>,<a href="${pan.idm}" target="_blank" class="pl-a">详见此处</a></span> <span class="listener-back">返回</span></div>
  4758. <div class="pl-item-progress" style="display: none">
  4759. <div class="pl-progress">
  4760. <div class="pl-progress-outer"></div>
  4761. <div class="pl-progress-inner" style="width:5%">
  4762. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  4763. </div>
  4764. </div>
  4765. <span class="pl-btn-primary pl-btn-danger pl-progress-stop listener-stop">取消下载</span>
  4766. `;
  4767. content += `<span class="pl-progress-tip" style="display: none" >未发现IDM,使用自带浏览器下载</span>
  4768. <span class="pl-btn-primary pl-btn-info pl-progress-back listener-back" style="display: none">返回</span>
  4769. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  4770. `;
  4771. content += `</div></div>`
  4772. }
  4773. if (mode === 'aria') {
  4774. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  4775. alinkAllText += alink + '\r\n';
  4776. content += `<div class="pl-item">
  4777. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4778. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  4779. }
  4780. if (mode === 'rpc') {
  4781. content += `<div class="pl-item">
  4782. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4783. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><svg class="icon-rpc-devices" viewBox="-10 0 1034 1024"><g transform="matrix(1 0 0 -1 0 960)"><path fill="currentColor" d="M832 -64h-640q-53 0 -90.5 37.5t-37.5 90.5v768q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-768q0 -53 -37.5 -90.5t-90.5 -37.5zM832 768q0 27 -18.5 45.5t-45.5 18.5h-512q-27 0 -45.5 -18.5t-18.5 -45.5v-320h640v320v0zM832 320h-640v-192q0 -27 18.5 -45.5t45.5 -18.5h512q27 0 45.5 18.5t18.5 45.5v192v0zM512 128q-27 0 -45.5 18.5t-18.5 45.5t18.5 45.5t45.5 18.5t45.5 -18.5t18.5 -45.5t-18.5 -45.5t-45.5 -18.5z" /></g></svg><span style="margin-left: 5px;">将 ${filename} 推送到 RPC 下载器</span></button></div>`;
  4784. }
  4785. if (mode === 'curl') {
  4786. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  4787. alinkAllText += alink + '\r\n';
  4788. content += `<div class="pl-item">
  4789. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4790. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  4791. }
  4792. if (mode === 'bc') {
  4793. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  4794. alinkAllText += alink + '\r\n';
  4795. content += `<div class="pl-item">
  4796. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4797. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a> </div>`;
  4798. }
  4799. });
  4800. content += '</div>';
  4801. if (mode === 'api')
  4802. content += `<div class="pl-extra"><button class="pl-btn-primary listener-tip listener-download-all" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接">全部增强下载</button><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  4803. if (mode === 'aria')
  4804. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  4805. if (mode === 'rpc') {
  4806. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  4807. content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">修改 RPC 参数(${rpc})</button><button class="pl-btn-primary pl-btn-success pl-btn-opacity listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  4808. }
  4809. if (mode === 'curl') {
  4810. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">修改终端类型(${terminalType[base.getValue('setting_terminal_type')]})</button></div>`;
  4811. }
  4812. if (mode === 'bc') {
  4813. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  4814. }
  4815. return content;
  4816. },
  4817.  
  4818. async sendLinkToRPC(filename, link) {
  4819. let rpc = {
  4820. domain: base.getValue('setting_rpc_domain'),
  4821. port: base.getValue('setting_rpc_port'),
  4822. path: base.getValue('setting_rpc_path'),
  4823. token: base.getValue('setting_rpc_token'),
  4824. dir: base.getValue('setting_rpc_dir'),
  4825. };
  4826.  
  4827. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  4828. let rpcData = {
  4829. id: new Date().getTime(),
  4830. jsonrpc: '2.0',
  4831. method: 'aria2.addUri',
  4832. params: [`token:${rpc.token}`, [link], {
  4833. dir: rpc.dir,
  4834. out: filename,
  4835. header: []
  4836. }]
  4837. };
  4838. try {
  4839. let res = await base.post(url, rpcData, {}, '');
  4840. if (res.result) return 'success';
  4841. return 'fail';
  4842. } catch (e) {
  4843. return 'fail';
  4844. }
  4845. },
  4846.  
  4847. getSelectedList() {
  4848. try {
  4849. return document.querySelector(".c-file-list").__vue__.selectedList;
  4850. } catch (e) {
  4851. return [document.querySelector(".info-detail").__vue__.fileDetail];
  4852. }
  4853. },
  4854.  
  4855. detectPage() {
  4856. let path = location.pathname;
  4857. if (/^\/web\/main/.test(path)) return 'home';
  4858. if (/^\/web\/share/.test(path)) return 'share';
  4859. return '';
  4860. },
  4861.  
  4862. isOnlyFolder() {
  4863. for (let i = 0; i < selectList.length; i++) {
  4864. if (!selectList[i].isFolder) return false;
  4865. }
  4866. return true;
  4867. },
  4868.  
  4869. showMainDialog(title, html, footer) {
  4870. Swal.fire({
  4871. title,
  4872. html,
  4873. footer,
  4874. allowOutsideClick: false,
  4875. showCloseButton: true,
  4876. position: 'center',
  4877. width,
  4878. padding: '15px 20px 5px',
  4879. customClass,
  4880. confirmButtonText: '关闭',
  4881. willClose: function () {
  4882. base._resetData();
  4883. }
  4884. }).then(function () {
  4885. base._resetData();
  4886. });
  4887. },
  4888.  
  4889. async initPanLinker() {
  4890. pt = this.detectPage();
  4891. base.createTip();
  4892. base.registerMenuCommand();
  4893. if (base.getValue('setting_server_main') === 'v1') {
  4894. let res = await base.post(`https://api.youxiaohou.com/config/tianyi/?ver=${version}&a=${author}`, {}, {}, 'text');
  4895. pan = JSON.parse(base.decode(res));
  4896. } else if (base.getValue('setting_server_main') === 'v2') {
  4897. let res = await base.post(`https://api.youxiaohou.com/config/v2/tianyi/?ver=${version}&a=${author}`, {}, {}, 'text');
  4898. pan = JSON.parse(base.decode(res));
  4899. } else if (base.getValue('setting_server_main') === "no") {
  4900. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/tianyi.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  4901. pan = JSON.parse(res);
  4902. } else {
  4903. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/tianyi.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  4904. pan = JSON.parse(res);
  4905. base.setValue('setting_server_main', 'v2');
  4906. }
  4907. Object.freeze && Object.freeze(pan);
  4908. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('setting_init_license')) {
  4909. this.addButton();
  4910. this.addPageListener();
  4911. } else {
  4912. this.addInitButton();
  4913. }
  4914. this.getToken();
  4915. }
  4916. };
  4917.  
  4918. //迅雷云盘
  4919. let xunlei = {
  4920.  
  4921. convertLinkToAria(link, filename, ua) {
  4922. filename = base.fixFilename(filename);
  4923. return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
  4924. },
  4925.  
  4926. convertLinkToBC(link, filename, ua) {
  4927. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
  4928. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  4929. },
  4930.  
  4931. convertLinkToCurl(link, filename, ua) {
  4932. let terminal = base.getValue('setting_terminal_type');
  4933. filename = base.fixFilename(filename);
  4934. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}"`);
  4935. },
  4936.  
  4937. addPageListener() {
  4938. /*
  4939. 防止代码因其他原因被执行多次
  4940. 这段代码出自 Via轻插件,作者谷花泰
  4941. */
  4942. const key = encodeURIComponent('(改)网盘直链下载助手:迅雷云盘');
  4943. if (window[key]) return;
  4944. window[key] = true;
  4945.  
  4946. function _factory(e) {
  4947. let target = $(e.target);
  4948. let item = target.parents('.pl-item');
  4949. let link = item.find('.pl-item-link.blob');
  4950. let directLink = item.find('.pl-item-link.browser');
  4951. let progress = item.find('.pl-item-progress');
  4952. let tip = item.find('.pl-item-tip');
  4953. let copy = item.find('.pl-item-copy');
  4954. let howidm = item.find('.pl-progress-how');
  4955. let back = item.find('.pl-progress-back');
  4956. let stop = item.find('.pl-progress-stop');
  4957. return {
  4958. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  4959. };
  4960. }
  4961.  
  4962. function _reset(i) {
  4963. ins[i] && clearInterval(ins[i]);
  4964. request[i] && request[i].abort();
  4965. progress[i] = 0;
  4966. idm[i] = false;
  4967. }
  4968.  
  4969. doc.on('click', '.pl-button-mode', function (e) {
  4970. mode = e.target.dataset.mode;
  4971. if (!mode) return;
  4972. Swal.fire({
  4973. heightAuto: false,
  4974. scrollbarPadding: false,
  4975. showConfirmButton: false,
  4976. html: `链接获取中`,
  4977. willOpen: function () {
  4978. Swal.showLoading();
  4979. }
  4980. });
  4981. xunlei.getPCSLink();
  4982. });
  4983. doc.on('click', '.pl-button-save', async function (e) {
  4984. e.preventDefault();
  4985. selectList = xunlei.getSelectedList();
  4986. if (selectList.length === 0) {
  4987. return message.error('提示:<br/>请勾选要保存到网盘的文件哦~');
  4988. }
  4989. message.info('提示:<br/>因网盘限制,请保存到自己网盘后再去下载哦~');
  4990. await base.sleep(500);
  4991. document.querySelector('.saveToCloud').click();
  4992. });
  4993. doc.on('click', '.listener-link-api.browser', async function (e) {
  4994. e.preventDefault();
  4995. let dataset = e.currentTarget.dataset;
  4996. let href = dataset.link;
  4997. $('#downloadIframe').attr('src', href);
  4998. });
  4999. doc.on('click', '.listener-link-api.blob', async function (e) {
  5000. e.preventDefault();
  5001. let o = _factory(e);
  5002. let $width = o.item.find('.pl-progress-inner');
  5003. let $text = o.item.find('.pl-progress-inner-text');
  5004. let filename = o.link[0].dataset.filename;
  5005. let index = o.link[0].dataset.index;
  5006. _reset(index);
  5007. let dataset = e.currentTarget.dataset;
  5008. let href = dataset.link;
  5009. base.get(href, { "Referer": `https://${location.host}/` }, 'blob', { filename, index });
  5010. let startTime = Date.now(); // 记录下载开始时间
  5011. let prevLoaded = 0; // 上一次的已下载数据量
  5012. let prevTime = startTime; // 上一次的时间
  5013. let size = Number(o.link[0].dataset.size);
  5014. ins[index] = setInterval(function () {
  5015. let prog = +progress[index] || 0;
  5016. let isIDM = idm[index] || false;
  5017.  
  5018. // 处理普通下载的情况...
  5019. let currentTime = Date.now();
  5020. let elapsedTime = currentTime - startTime;
  5021. let totalProgress = prog / 100;
  5022. let totalElapsedSeconds = elapsedTime / 1000;
  5023. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  5024. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  5025.  
  5026. // 将剩余时间转换为天、时、分、秒
  5027. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  5028. remainingTimeSeconds %= (60 * 60 * 24);
  5029.  
  5030. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  5031. remainingTimeSeconds %= (60 * 60);
  5032.  
  5033. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  5034. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  5035.  
  5036. // 计算下载速度
  5037. let loaded = prog * size / 100; // 已下载数据量
  5038. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  5039. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  5040. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  5041.  
  5042. // 更新上一次的数据
  5043. prevLoaded = loaded;
  5044. prevTime = currentTime;
  5045.  
  5046. // 更改界面
  5047. o.link.hide();
  5048. o.directLink.hide();
  5049. o.tip.hide();
  5050. o.stop.show();
  5051. o.copy.hide();
  5052. o.progress.show();
  5053.  
  5054. // 更新进度条
  5055. $width.css('width', prog + '%');
  5056.  
  5057. // 更新进度条文本
  5058. let timeText = '';
  5059. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  5060. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  5061. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  5062. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  5063. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  5064. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  5065. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  5066. timeText = remainingSeconds + '秒';
  5067. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  5068. timeText = '即将完成';
  5069. } else {
  5070. timeText = '计算中...';
  5071. }
  5072.  
  5073. let speedText = '';
  5074. speedText = base.sizeFormat(downloadSpeed)
  5075. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  5076.  
  5077. if (prog === 100) {
  5078. setTimeout(function () {
  5079. clearInterval(ins[index]);
  5080. progress[index] = 0;
  5081. o.item.find('.pl-progress-stop').hide();
  5082. o.howidm.hide();
  5083. $text.text('下载完成~ 浏览器下载框应该弹出来了哦~');
  5084. o.back.show()
  5085. setTimeout(function () {
  5086. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  5087. }, 3000)
  5088. }, 1000)
  5089. }
  5090. }, 500);
  5091. });
  5092. doc.on('click', '.listener-retry', async function (e) {
  5093. let o = _factory(e);
  5094. o.tip.hide();
  5095. o.link.show();
  5096. o.directLink.show();
  5097. });
  5098. doc.on('click', '.listener-how', async function (e) {
  5099. let o = _factory(e);
  5100. let index = o.link[0].dataset.index;
  5101. if (request[index]) {
  5102. request[index].abort();
  5103. clearInterval(ins[index]);
  5104. o.progress.hide();
  5105. o.tip.show();
  5106. }
  5107.  
  5108. });
  5109. doc.on('click', '.listener-stop', async function (e) {
  5110. let o = _factory(e);
  5111. let index = o.link[0].dataset.index;
  5112. if (request[index]) {
  5113. request[index].abort();
  5114. clearInterval(ins[index]);
  5115. o.item.find('.pl-progress-inner-text').text('正在取消...');
  5116. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  5117. setTimeout(function () {
  5118. o.tip.hide();
  5119. o.back.hide();
  5120. o.link.show();
  5121. o.directLink.show();
  5122. o.copy.show();
  5123. o.progress.hide();
  5124. o.stop.hide();
  5125. }, 1050)
  5126. }
  5127. });
  5128. doc.on('click', '.listener-back', async function (e) {
  5129. let o = _factory(e);
  5130. o.progress.hide();
  5131. o.tip.hide();
  5132. o.link.show();
  5133. o.directLink.show();
  5134. o.copy.show();
  5135. o.stop.hide();
  5136. o.back.hide();
  5137. });
  5138. doc.on('click', '.listener-download-all', function (e) {
  5139. $('.pl-item-link.blob').each(function () {
  5140. if ($(this).css('display') !== 'none') {
  5141. $(this).click();
  5142. }
  5143. });
  5144. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  5145. setTimeout(function () {
  5146. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  5147. }, 2000)
  5148. });
  5149.  
  5150. doc.on('click', '.listener-copy-filename', async function (e) {
  5151. base.setClipboard(e.target.dataset.filename);
  5152. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  5153. setTimeout(function () {
  5154. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  5155. }, 2000)
  5156. });
  5157. doc.on('click', '.listener-link-bc-btn', async function (e) {
  5158. let mirror = base.getMirrorList(e.target.dataset.dlink, pan.mirror);
  5159. base.setClipboard(mirror);
  5160. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  5161. setTimeout(function () {
  5162. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  5163. }, 2000)
  5164. });
  5165. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  5166. e.preventDefault();
  5167. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  5168. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  5169. setTimeout(function () {
  5170. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  5171. }, 2000)
  5172. });
  5173. doc.on('click', '.listener-link-rpc', async function (e) {
  5174. e.preventDefault();
  5175. let target = $(e.currentTarget);
  5176.  
  5177. target.find('.icon-rpc-devices').remove();
  5178. target.find('.pl-loading').remove();
  5179. target.prepend(base.createLoading());
  5180.  
  5181. let res = await xunlei.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  5182. if (res === 'success') {
  5183. $('.listener-rpc-task').show();
  5184. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  5185. } else if (res === 'assistant') {
  5186. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  5187. } else {
  5188. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  5189. }
  5190. });
  5191. doc.on('click', '.listener-send-rpc', function (e) {
  5192. $('.listener-link-rpc').click();
  5193. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  5194. });
  5195. doc.on('click', '.listener-open-setting', function () {
  5196. base.showSetting();
  5197. });
  5198. doc.on('click', '.listener-open-updatelog', function () {
  5199. base.showUpdateLog();
  5200. });
  5201. doc.on('click', '.listener-open-beautify', function () {
  5202. base.showBeautify();
  5203. });
  5204. doc.on('click', '.listener-rpc-task', function () {
  5205. let rpc = JSON.stringify({
  5206. domain: base.getValue('setting_rpc_domain'),
  5207. port: base.getValue('setting_rpc_port'),
  5208. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  5209. GM_openInTab(url, { active: true });
  5210. });
  5211. },
  5212.  
  5213. addButton() {
  5214. if (!pt) return;
  5215. let $toolWrap;
  5216. let $button = $(`
  5217. <div class="xunlei-button pl-button"><i class="xlpfont xlp-download"></i><span style="font-size: 13px;margin-left: 6px;">下载助手</span>
  5218. <ul class="pl-dropdown-menu" style="top: 34px;">
  5219. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li>
  5220. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria">Aria下载</li>
  5221. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li>
  5222. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li>
  5223. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc">BC下载</li>
  5224. <li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>
  5225. <li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li>
  5226. <li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li>
  5227. </ul>
  5228. </div>
  5229. `);
  5230. if (pt === 'home') {
  5231. base.listenElement(pan.btn.home, function () {
  5232. $toolWrap = $(pan.btn.home);
  5233. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  5234. })
  5235. }
  5236. if (pt === 'share') {
  5237. $button = $(`
  5238. <div class="xunlei-button pl-button">
  5239. <i class="xlpfont xlp-download"></i><span style="font-size: 13px;margin-left: 6px;">下载助手</span>
  5240. <ul class="pl-dropdown-menu" style="top: 34px;">
  5241. <li class="pl-dropdown-menu-item pl-button-mode pl-button-save"><i class="xlpfont xlp-file-upload"></i><span style="margin-left: 3px;">转存后下载</span></li>
  5242. <li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>
  5243. <li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li>
  5244. <li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li>
  5245. </ul>
  5246. </div>
  5247. `);
  5248. $button.css({ 'margin-right': '10px' });
  5249. base.listenElement(pan.btn.share, function () {
  5250. $toolWrap = $(pan.btn.share);
  5251. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  5252. })
  5253. }
  5254. base.createDownloadIframe();
  5255. },
  5256.  
  5257. addInitButton() {
  5258. if (!pt) return;
  5259. let $toolWrap;
  5260. let $button = $(`<div class="xunlei-button pl-button-init"><i class="xlpfont xlp-download"></i><span style="font-size: 13px;margin-left: 6px;">点我点亮</span></div>`);
  5261. if (pt === 'home') {
  5262. base.listenElement(pan.btn.home, function () {
  5263. $toolWrap = $(pan.btn.home);
  5264. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  5265. })
  5266. }
  5267. if (pt === 'share') {
  5268. $button.css({ 'margin-right': '10px' });
  5269. base.listenElement(pan.btn.share, function () {
  5270. $toolWrap = $(pan.btn.share);
  5271. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  5272. })
  5273. }
  5274. $button.click(function () { base.initDialog() });
  5275. },
  5276.  
  5277. getToken() {
  5278. let credentials = {}, captcha = {};
  5279. for (let i = 0; i < localStorage.length; i++) {
  5280. if (/^credentials_/.test(localStorage.key(i))) {
  5281. credentials = base.getStorage(localStorage.key(i));
  5282. base.setStorage('');
  5283. }
  5284. if (/^captcha_[\w]{16}/.test(localStorage.key(i))) {
  5285. captcha = base.getStorage(localStorage.key(i));
  5286. }
  5287. }
  5288. let deviceid = /(\w{32})/.exec(base.getStorage('deviceid').split(','))[0];
  5289. let token = {
  5290. credentials,
  5291. captcha,
  5292. deviceid
  5293. };
  5294. return token;
  5295. },
  5296.  
  5297. async getFileUrlByOnce(item, index, token) {
  5298. try {
  5299. if (item.downloadUrl) return {
  5300. index,
  5301. downloadUrl: item.downloadUrl
  5302. };
  5303. let res = await base.get(pan.pcs[0] + item.id, {
  5304. 'Authorization': `${token.credentials.token_type} ${token.credentials.access_token}`,
  5305. 'content-type': "application/json",
  5306. 'x-captcha-token': token.captcha.token,
  5307. 'x-device-id': token.deviceid,
  5308. });
  5309. if (res.web_content_link) {
  5310. return {
  5311. index,
  5312. downloadUrl: res.web_content_link
  5313. };
  5314. } else {
  5315. return {
  5316. index,
  5317. downloadUrl: '获取下载地址失败,刷新后再试试吧~'
  5318. };
  5319. }
  5320. } catch (e) {
  5321. return message.error('提示:<br/>请先登录(不可用)网盘后再刷新页面呢~');
  5322. }
  5323. },
  5324.  
  5325. async getPCSLink() {
  5326. selectList = this.getSelectedList();
  5327. if (selectList.length === 0) {
  5328. return message.error('提示:<br/>请勾选要下载的文件哦~');
  5329. }
  5330. if (this.isOnlyFolder()) {
  5331. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  5332. }
  5333. if (pt === 'home') {
  5334. let queue = [];
  5335. let token = this.getToken();
  5336. for (const [index, item] of selectList.entries()) {
  5337. queue.push(this.getFileUrlByOnce(item, index, token));
  5338. }
  5339.  
  5340. const res = await Promise.all(queue);
  5341. res.forEach(val => {
  5342. selectList[val.index].downloadUrl = val.downloadUrl;
  5343. });
  5344. } else {
  5345. return message.error('提示:<br/>页面错误~');
  5346. }
  5347. let html = this.generateDom(selectList);
  5348. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  5349.  
  5350. },
  5351.  
  5352. generateDom(list) {
  5353. let content = '<div class="pl-main">';
  5354. let alinkAllText = '';
  5355. list.forEach((v, i) => {
  5356. if (v.kind === 'drive#folder') return;
  5357. let filename = v.name;
  5358. let ext = base.getExtension(filename);
  5359. let size = base.sizeFormat(+v.size);
  5360. let dlink = v.downloadUrl;
  5361. if (mode === 'api') {
  5362. alinkAllText += dlink + '\r\n';
  5363. content += `<div class="pl-item">
  5364. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5365. <button class="pl-item-link listener-tip pl-btn-primary listener-link-api blob" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,下载完成可自动命名,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接" data-filename="${filename}" data-size="${v.size}" data-link="${dlink}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  5366. <a class="pl-item-link listener-tip pl-btn-primary pl-btn-info listener-link-api browser" data-title="基于浏览器直接打开链接来下载文件,适用于较为古老但支持 iframe 的浏览器,点击“直接下载”后需等待下载提示弹出才能点击下个“直接下载”,否则只会下载后者,若服务器未回报文件名,此方式下载不会被 IDM 捕获下载链接,此时建议右键此按钮,选择 “使用 IDM 下载”" data-filename="${filename}" data-link="${dlink}" href="${dlink}">直接下载(基于浏览器链接)</a>
  5367. <button class="pl-item-copy listener-tip pl-btn-primary pl-btn-success listener-copy-filename" data-title="本网盘下载时可能不会显示文件名称,这时需要手动复制文件名称到下载工具中" data-filename="${filename}">复制名称</button>
  5368. <button class="pl-item-copy pl-btn-primary pl-btn-warning listener-copy-all" href="${dlink}" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  5369. <div class="pl-item-tip" style="display: none"><span>若没有弹出IDM下载框,找到IDM <b>选项</b> -> <b>文件类型</b> -> <b>第一个框</b> 中添加后缀 <span class="pl-ext">${ext}</span>,<a href="${pan.idm}" target="_blank" class="pl-a">详见此处</a></span> <span class="listener-back">返回</span></div>
  5370. <div class="pl-item-progress" style="display: none">
  5371. <div class="pl-progress">
  5372. <div class="pl-progress-outer"></div>
  5373. <div class="pl-progress-inner" style="width:5%">
  5374. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  5375. </div>
  5376. </div>
  5377. <span class="pl-btn-primary pl-btn-danger pl-progress-stop listener-stop">取消下载</span>
  5378. `;
  5379. content += `<span class="pl-progress-tip" style="display: none" >未发现IDM,使用自带浏览器下载</span>
  5380. <span class="pl-btn-primary pl-btn-info pl-progress-back listener-back" style="display: none">返回</span>
  5381. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  5382. `;
  5383. content += `</div></div>`
  5384. }
  5385. if (mode === 'aria') {
  5386. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  5387. alinkAllText += alink + '\r\n';
  5388. content += `<div class="pl-item">
  5389. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5390. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  5391. }
  5392. if (mode === 'rpc') {
  5393. content += `<div class="pl-item">
  5394. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5395. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><svg class="icon-rpc-devices" viewBox="-10 0 1034 1024"><g transform="matrix(1 0 0 -1 0 960)"><path fill="currentColor" d="M832 -64h-640q-53 0 -90.5 37.5t-37.5 90.5v768q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-768q0 -53 -37.5 -90.5t-90.5 -37.5zM832 768q0 27 -18.5 45.5t-45.5 18.5h-512q-27 0 -45.5 -18.5t-18.5 -45.5v-320h640v320v0zM832 320h-640v-192q0 -27 18.5 -45.5t45.5 -18.5h512q27 0 45.5 18.5t18.5 45.5v192v0zM512 128q-27 0 -45.5 18.5t-18.5 45.5t18.5 45.5t45.5 18.5t45.5 -18.5t18.5 -45.5t-18.5 -45.5t-45.5 -18.5z" /></g></svg><span style="margin-left: 5px;">将 ${filename} 推送到 RPC 下载器</span></button></div>`;
  5396. }
  5397. if (mode === 'curl') {
  5398. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  5399. alinkAllText += alink + '\r\n';
  5400. content += `<div class="pl-item">
  5401. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5402. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  5403. }
  5404. if (mode === 'bc') {
  5405. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  5406. alinkAllText += alink + '\r\n';
  5407. content += `<div class="pl-item">
  5408. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5409. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a>
  5410. <button class="pl-btn-primary listener-link-bc-btn" data-dlink="${dlink}">复制镜像地址</div>
  5411. </div>`;
  5412. }
  5413. });
  5414. content += '</div>';
  5415. if (mode === 'api')
  5416. content += `<div class="pl-extra"><button class="pl-btn-primary listener-tip listener-download-all" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接">全部增强下载</button><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  5417. if (mode === 'aria')
  5418. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  5419. if (mode === 'rpc') {
  5420. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  5421. content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">修改 RPC 参数(${rpc})</button><button class="pl-btn-primary pl-btn-success pl-btn-opacity listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  5422. }
  5423. if (mode === 'curl') {
  5424. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">修改终端类型(${terminalType[base.getValue('setting_terminal_type')]})</button></div>`;
  5425. }
  5426. if (mode === 'bc') {
  5427. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  5428. }
  5429. return content;
  5430. },
  5431.  
  5432. async sendLinkToRPC(filename, link) {
  5433. let rpc = {
  5434. domain: base.getValue('setting_rpc_domain'),
  5435. port: base.getValue('setting_rpc_port'),
  5436. path: base.getValue('setting_rpc_path'),
  5437. token: base.getValue('setting_rpc_token'),
  5438. dir: base.getValue('setting_rpc_dir'),
  5439. };
  5440.  
  5441. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  5442. let rpcData = {
  5443. id: new Date().getTime(),
  5444. jsonrpc: '2.0',
  5445. method: 'aria2.addUri',
  5446. params: [`token:${rpc.token}`, [link], {
  5447. dir: rpc.dir,
  5448. out: filename,
  5449. header: []
  5450. }]
  5451. };
  5452. try {
  5453. let res = await base.post(url, rpcData, {}, '');
  5454. if (res.result) return 'success';
  5455. return 'fail';
  5456. } catch (e) {
  5457. return 'fail';
  5458. }
  5459. },
  5460.  
  5461. getSelectedList() {
  5462. try {
  5463. let doms = document.querySelectorAll('.SourceListItem__item--XxpOC');
  5464. let selectedList = [];
  5465. for (let dom of doms) {
  5466. let domVue = dom.__vue__;
  5467. if (domVue.selected.includes(domVue.info.id)) {
  5468. selectedList.push(domVue.info);
  5469. }
  5470. }
  5471. return selectedList;
  5472. } catch (e) {
  5473. return [];
  5474. }
  5475. },
  5476.  
  5477. detectPage() {
  5478. let path = location.pathname;
  5479. if (/^\/$/.test(path)) return 'home';
  5480. if (/^\/(s|share)\//.test(path)) return 'share';
  5481. return '';
  5482. },
  5483.  
  5484. isOnlyFolder() {
  5485. for (let i = 0; i < selectList.length; i++) {
  5486. if (selectList[i].kind === 'drive#file') return false;
  5487. }
  5488. return true;
  5489. },
  5490.  
  5491. showMainDialog(title, html, footer) {
  5492. Swal.fire({
  5493. title,
  5494. html,
  5495. footer,
  5496. allowOutsideClick: false,
  5497. showCloseButton: true,
  5498. position: 'center',
  5499. width,
  5500. padding: '15px 20px 5px',
  5501. customClass,
  5502. confirmButtonText: '关闭',
  5503. willClose: function () {
  5504. base._resetData();
  5505. }
  5506. }).then(function () {
  5507. base._resetData();
  5508. });
  5509. },
  5510.  
  5511. async initPanLinker() {
  5512. pt = this.detectPage();
  5513. base.createTip();
  5514. base.registerMenuCommand();
  5515. if (base.getValue('setting_server_main') === 'v1') {
  5516. let res = await base.post(`https://api.youxiaohou.com/config/xunlei/?ver=${version}&a=${author}`, {}, {}, 'text');
  5517. pan = JSON.parse(base.decode(res));
  5518. } else if (base.getValue('setting_server_main') === 'v2') {
  5519. let res = await base.post(`https://api.youxiaohou.com/config/v2/xunlei/?ver=${version}&a=${author}`, {}, {}, 'text');
  5520. pan = JSON.parse(base.decode(res));
  5521. } else if (base.getValue('setting_server_main') === "no") {
  5522. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/xunlei.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  5523. pan = JSON.parse(res);
  5524. } else {
  5525. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/xunlei.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  5526. pan = JSON.parse(res);
  5527. base.setValue('setting_server_main', 'v2');
  5528. }
  5529. Object.freeze && Object.freeze(pan);
  5530. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('setting_init_license')) {
  5531. this.addButton();
  5532. this.addPageListener();
  5533. } else {
  5534. this.addInitButton();
  5535. }
  5536. }
  5537. };
  5538.  
  5539. //夸克网盘
  5540. let quark = {
  5541.  
  5542. convertLinkToAria(link, filename, ua) {
  5543. filename = base.fixFilename(filename);
  5544. return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "Cookie: ${document.cookie}"`);
  5545. },
  5546.  
  5547. convertLinkToBC(link, filename, ua) {
  5548. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&cookie=${encodeURIComponent(document.cookie)}ZZ`;
  5549. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  5550. },
  5551.  
  5552. convertLinkToCurl(link, filename, ua) {
  5553. let terminal = base.getValue('setting_terminal_type');
  5554. filename = base.fixFilename(filename);
  5555. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}" -b "${document.cookie}"`);
  5556. },
  5557.  
  5558. addPageListener() {
  5559. /*
  5560. 防止代码因其他原因被执行多次
  5561. 这段代码出自 Via轻插件,作者谷花泰
  5562. */
  5563. const key = encodeURIComponent('(改)网盘直链下载助手:夸客网盘');
  5564. if (window[key]) return;
  5565. window[key] = true;
  5566.  
  5567. function _factory(e) {
  5568. let target = $(e.target);
  5569. let item = target.parents('.pl-item');
  5570. let link = item.find('.pl-item-link.blob');
  5571. let directLink = item.find('.pl-item-link.browser');
  5572. let progress = item.find('.pl-item-progress');
  5573. let tip = item.find('.pl-item-tip');
  5574. let copy = item.find('.pl-item-copy');
  5575. let howidm = item.find('.pl-progress-how');
  5576. let back = item.find('.pl-progress-back');
  5577. let stop = item.find('.pl-progress-stop');
  5578. return {
  5579. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  5580. };
  5581. }
  5582.  
  5583. function _reset(i) {
  5584. ins[i] && clearInterval(ins[i]);
  5585. request[i] && request[i].abort();
  5586. progress[i] = 0;
  5587. idm[i] = false;
  5588. }
  5589.  
  5590. window.addEventListener('hashchange', async function (e) {
  5591. let home = 'https://pan.quark.cn/list#/', all = 'https://pan.quark.cn/list#/list/all';
  5592. if (e.oldURL === home && e.newURL === all) return;
  5593. await base.sleep(150);
  5594. if ($('.quark-button').length > 0) return;
  5595. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('setting_init_license')) {
  5596. this.addButton();
  5597. this.addPageListener();
  5598. } else {
  5599. this.addInitButton();
  5600. }
  5601. });
  5602. doc.on('click', '.pl-button-mode', function (e) {
  5603. mode = e.target.dataset.mode;
  5604. if (!mode) return;
  5605. Swal.fire({
  5606. heightAuto: false,
  5607. scrollbarPadding: false,
  5608. showConfirmButton: false,
  5609. html: `链接获取中`,
  5610. willOpen: function () {
  5611. Swal.showLoading();
  5612. }
  5613. });
  5614. quark.getPCSLink();
  5615. });
  5616. doc.on('click', '.pl-button-save', async function (e) {
  5617. e.preventDefault();
  5618. selectList = quark.getSelectedList();
  5619. if (selectList.length === 0) {
  5620. return message.error('提示:<br/>请勾选要保存到网盘的文件哦~');
  5621. }
  5622. message.info('提示:<br/>因网盘限制,请保存到自己网盘后再去下载哦~');
  5623. await base.sleep(500);
  5624. document.querySelector('.file-info_r').click();
  5625. });
  5626. doc.on('click', '.listener-link-api.browser', async function (e) {
  5627. e.preventDefault();
  5628. let dataset = e.currentTarget.dataset;
  5629. let href = dataset.link;
  5630. $('#downloadIframe').attr('src', href);
  5631. });
  5632. doc.on('click', '.listener-link-api.blob', async function (e) {
  5633. e.preventDefault();
  5634. let o = _factory(e);
  5635. let $width = o.item.find('.pl-progress-inner');
  5636. let $text = o.item.find('.pl-progress-inner-text');
  5637. let filename = o.link[0].dataset.filename;
  5638. let index = o.link[0].dataset.index;
  5639. _reset(index);
  5640. let dataset = e.currentTarget.dataset;
  5641. let href = dataset.link;
  5642. base.get(href, { "Referer": `https://${location.host}/` }, 'blob', { filename, index });
  5643. let startTime = Date.now(); // 记录下载开始时间
  5644. let prevLoaded = 0; // 上一次的已下载数据量
  5645. let prevTime = startTime; // 上一次的时间
  5646. let size = Number(o.link[0].dataset.size);
  5647. ins[index] = setInterval(function () {
  5648. let prog = +progress[index] || 0;
  5649. // 处理普通下载的情况...
  5650. let currentTime = Date.now();
  5651. let elapsedTime = currentTime - startTime;
  5652. let totalProgress = prog / 100;
  5653. let totalElapsedSeconds = elapsedTime / 1000;
  5654. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  5655. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  5656.  
  5657. // 将剩余时间转换为天、时、分、秒
  5658. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  5659. remainingTimeSeconds %= (60 * 60 * 24);
  5660.  
  5661. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  5662. remainingTimeSeconds %= (60 * 60);
  5663.  
  5664. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  5665. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  5666.  
  5667. // 计算下载速度
  5668. let loaded = prog * size / 100; // 已下载数据量
  5669. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  5670. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  5671. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  5672.  
  5673. // 更新上一次的数据
  5674. prevLoaded = loaded;
  5675. prevTime = currentTime;
  5676.  
  5677. // 更改界面
  5678. o.link.hide();
  5679. o.directLink.hide();
  5680. o.tip.hide();
  5681. o.stop.show();
  5682. o.copy.hide();
  5683. o.progress.show();
  5684.  
  5685. // 更新进度条
  5686. $width.css('width', prog + '%');
  5687.  
  5688. // 更新进度条文本
  5689. let timeText = '';
  5690. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  5691. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  5692. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  5693. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  5694. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  5695. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  5696. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  5697. timeText = remainingSeconds + '秒';
  5698. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  5699. timeText = '即将完成';
  5700. } else {
  5701. timeText = '计算中...';
  5702. }
  5703.  
  5704. let speedText = '';
  5705. speedText = base.sizeFormat(downloadSpeed)
  5706. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  5707.  
  5708. if (prog === 100) {
  5709. setTimeout(function () {
  5710. clearInterval(ins[index]);
  5711. progress[index] = 0;
  5712. o.item.find('.pl-progress-stop').hide();
  5713. o.howidm.hide();
  5714. $text.text('下载完成~ 浏览器下载框应该弹出来了哦~');
  5715. o.back.show()
  5716. setTimeout(function () {
  5717. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  5718. }, 3000)
  5719. }, 1000)
  5720. }
  5721. }, 500);
  5722. });
  5723. doc.on('click', '.listener-retry', async function (e) {
  5724. let o = _factory(e);
  5725. o.tip.hide();
  5726. o.link.show();
  5727. o.directLink.show();
  5728. });
  5729. doc.on('click', '.listener-how', async function (e) {
  5730. let o = _factory(e);
  5731. let index = o.link[0].dataset.index;
  5732. if (request[index]) {
  5733. request[index].abort();
  5734. clearInterval(ins[index]);
  5735. o.progress.hide();
  5736. o.tip.show();
  5737. }
  5738.  
  5739. });
  5740. doc.on('click', '.listener-stop', async function (e) {
  5741. let o = _factory(e);
  5742. let index = o.link[0].dataset.index;
  5743. if (request[index]) {
  5744. request[index].abort();
  5745. clearInterval(ins[index]);
  5746. o.item.find('.pl-progress-inner-text').text('正在取消...');
  5747. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  5748. setTimeout(function () {
  5749. o.tip.hide();
  5750. o.back.hide();
  5751. o.link.show();
  5752. o.directLink.show();
  5753. o.copy.show();
  5754. o.progress.hide();
  5755. o.stop.hide();
  5756. }, 1050)
  5757. }
  5758. });
  5759. doc.on('click', '.listener-back', async function (e) {
  5760. let o = _factory(e);
  5761. o.progress.hide();
  5762. o.tip.hide();
  5763. o.link.show();
  5764. o.directLink.show();
  5765. o.copy.show();
  5766. o.stop.hide();
  5767. o.back.hide();
  5768. });
  5769. doc.on('click', '.listener-download-all', function (e) {
  5770. $('.pl-item-link.blob').each(function () {
  5771. if ($(this).css('display') !== 'none') {
  5772. $(this).click();
  5773. }
  5774. });
  5775. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  5776. setTimeout(function () {
  5777. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  5778. }, 2000)
  5779. });
  5780. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  5781. e.preventDefault();
  5782. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  5783. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  5784. setTimeout(function () {
  5785. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  5786. }, 2000)
  5787. });
  5788. doc.on('click', '.listener-link-rpc', async function (e) {
  5789. e.preventDefault();
  5790. let target = $(e.currentTarget);
  5791.  
  5792. target.find('.icon-rpc-devices').remove();
  5793. target.find('.pl-loading').remove();
  5794. target.prepend(base.createLoading());
  5795.  
  5796. let res = await quark.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  5797. if (res === 'success') {
  5798. $('.listener-rpc-task').show();
  5799. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  5800. } else if (res === 'assistant') {
  5801. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  5802. } else {
  5803. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  5804. }
  5805. });
  5806. doc.on('click', '.listener-send-rpc', function (e) {
  5807. $('.listener-link-rpc').click();
  5808. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  5809. });
  5810. doc.on('click', '.listener-open-setting', function () {
  5811. base.showSetting();
  5812. });
  5813. doc.on('click', '.listener-open-updatelog', function () {
  5814. base.showUpdateLog();
  5815. });
  5816. doc.on('click', '.listener-open-beautify', function () {
  5817. base.showBeautify();
  5818. });
  5819. doc.on('click', '.listener-rpc-task', function () {
  5820. let rpc = JSON.stringify({
  5821. domain: base.getValue('setting_rpc_domain'),
  5822. port: base.getValue('setting_rpc_port'),
  5823. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  5824. GM_openInTab(url, { active: true });
  5825. });
  5826. },
  5827.  
  5828. removeAD() {
  5829. base.waitForKeyElements('[class*="Activity--video-toolbar-activity"]', function (tag) {
  5830. tag.fadeOut();
  5831. }, true);
  5832. base.waitForKeyElements('span[class*="SectionHeaderController--icon-download"]', function (tag) {
  5833. tag.fadeOut();
  5834. }, true);
  5835. base.waitForKeyElements('div[class*="SectionHeaderController--download-popover"]', function (tag) {
  5836. tag.find(".ant-popover-arrow").css({ "left": "75%" });
  5837. });
  5838. base.waitForKeyElements('div[class*="DetailLayout--client-download"]', function (tag) {
  5839. tag.fadeOut();
  5840. }, true);
  5841. base.waitForKeyElements(".next-box.share-right-side-content", function (tag) {
  5842. tag.fadeOut();
  5843. }, true);
  5844. base.waitForKeyElements('[class*="DetailLayout--container"] .feature-screen', function (tag) {
  5845. tag.fadeOut();
  5846. });
  5847. base.waitForKeyElements('.ant-modal-content .ant-modal-body .right-wrap', function (tag) {
  5848. if (tag.find(".hint").text().includes("客户端")) tag.fadeOut();
  5849. });
  5850. base.waitForKeyElements(".pc-member-entrance span.button-text", function (tag) {
  5851. tag.text("会员中心");
  5852. let observer = new MutationObserver(function (mutations) {
  5853. mutations.forEach(function (mutation) {
  5854. if (tag.text() === "会员中心") return
  5855. tag.text("会员中心");
  5856. });
  5857. });
  5858. let config = { subtree: true, characterData: true, childList: true };
  5859. observer.observe(tag[0], config);
  5860. });
  5861. base.waitForKeyElements(".pc-member-entrance .tips", function (tag) {
  5862. tag.fadeOut();
  5863. });
  5864. base.waitForKeyElements(".modal .modal-content .halo-animated-background .halo-content .pay-modal .close", function (tag) {
  5865. tag[0].click();
  5866. });
  5867. base.waitForKeyElements(".modal .modal-content .halo-animated-background .halo-content .red-envelope .close", function (tag) {
  5868. tag[0].click();
  5869. });
  5870. },
  5871.  
  5872. addButton() {
  5873. let svg = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iMiI+PHBhdGggc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNOSAxMmwyIDIgMi0yeiIvPjxwYXRoIGQ9Ik0xNCA4aDEuNTUzYy44NSAwIDEuMTYuMDkzIDEuNDcuMjY3LjMxMS4xNzQuNTU2LjQzLjcyMi43NTYuMTY2LjMyNi4yNTUuNjUuMjU1IDEuNTR2NC44NzNjMCAuODkyLS4wODkgMS4yMTUtLjI1NSAxLjU0LS4xNjYuMzI3LS40MS41ODMtLjcyMi43NTctLjMxLjE3NC0uNjIuMjY3LTEuNDcuMjY3SDYuNDQ3Yy0uODUgMC0xLjE2LS4wOTMtMS40Ny0uMjY3YTEuNzc4IDEuNzc4IDAgMDEtLjcyMi0uNzU2Yy0uMTY2LS4zMjYtLjI1NS0uNjUtLjI1NS0xLjU0di00Ljg3M2MwLS44OTIuMDg5LTEuMjE1LjI1NS0xLjU0LjE2Ni0uMzI3LjQxLS41ODMuNzIyLS43NTcuMzEtLjE3NC42Mi0uMjY3IDEuNDctLjI2N0gxMSIvPjxwYXRoIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0iTTExIDN2MTAiLz48L2c+PC9zdmc+';
  5874. if (!pt) return;
  5875. let $toolWrap;
  5876. let $button = $(`
  5877. <div class="ant-dropdown-trigger pl-button">
  5878. <button type="button" class="quark-button ant-btn btn-file ant-btn-primary">
  5879. <img class="quark-btn-icon" src="${svg}"><span>下载助手</span>
  5880. </button>
  5881. <ul class="pl-dropdown-menu" style="top: 55px;">
  5882. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li>
  5883. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria">Aria下载</li>
  5884. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li>
  5885. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li>
  5886. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc">BC下载</li>
  5887. <li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>
  5888. <li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li>
  5889. <li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li>
  5890. </ul>
  5891. </div>`);
  5892. if (pt === 'home') {
  5893. base.listenElement(pan.btn.home, function () {
  5894. $toolWrap = $(pan.btn.home);
  5895. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  5896. });
  5897. }
  5898. if (pt === 'share') {
  5899. $button = $(`<div class="ant-dropdown-trigger pl-button"><button type="button" class="quark-button ant-btn btn-file ant-btn-primary" style="height: 40px;"><img class="quark-btn-icon" src="${svg}"><span>下载助手</span></button><ul class="pl-dropdown-menu" style="top: 100px;"><li class="pl-dropdown-menu-item pl-button-mode pl-button-save"><span class="save-btn-icon"></span>保存后下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li></ul></div>`);
  5900. base.listenElement(pan.btn.share, function () {
  5901. $toolWrap = $(pan.btn.share);
  5902. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  5903. });
  5904. }
  5905. $button.css({ "margin-right": "10px", "display": "inline-block" });
  5906. },
  5907.  
  5908. addInitButton() {
  5909. let svg = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iMiI+PHBhdGggc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNOSAxMmwyIDIgMi0yeiIvPjxwYXRoIGQ9Ik0xNCA4aDEuNTUzYy44NSAwIDEuMTYuMDkzIDEuNDcuMjY3LjMxMS4xNzQuNTU2LjQzLjcyMi43NTYuMTY2LjMyNi4yNTUuNjUuMjU1IDEuNTR2NC44NzNjMCAuODkyLS4wODkgMS4yMTUtLjI1NSAxLjU0LS4xNjYuMzI3LS40MS41ODMtLjcyMi43NTctLjMxLjE3NC0uNjIuMjY3LTEuNDcuMjY3SDYuNDQ3Yy0uODUgMC0xLjE2LS4wOTMtMS40Ny0uMjY3YTEuNzc4IDEuNzc4IDAgMDEtLjcyMi0uNzU2Yy0uMTY2LS4zMjYtLjI1NS0uNjUtLjI1NS0xLjU0di00Ljg3M2MwLS44OTIuMDg5LTEuMjE1LjI1NS0xLjU0LjE2Ni0uMzI3LjQxLS41ODMuNzIyLS43NTcuMzEtLjE3NC42Mi0uMjY3IDEuNDctLjI2N0gxMSIvPjxwYXRoIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0iTTExIDN2MTAiLz48L2c+PC9zdmc+';
  5910. if (!pt) return;
  5911. let $toolWrap;
  5912. let $button = $(`<div class="ant-dropdown-trigger pl-button-init"><button type="button" class="quark-button ant-btn btn-file ant-btn-primary" style="height: 40px;"><img class="quark-btn-icon" src="${svg}"><span>点我点亮</span></button></div>`);
  5913. $button.css({ "margin-right": "10px", "display": "inline-block" });
  5914. if (pt === 'home') {
  5915. base.listenElement(pan.btn.home, function () {
  5916. $toolWrap = $(pan.btn.home);
  5917. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  5918. })
  5919. }
  5920. if (pt === 'share') {
  5921. base.listenElement(pan.btn.share, function () {
  5922. $toolWrap = $(pan.btn.share);
  5923. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  5924. })
  5925. }
  5926. $button.click(function () { base.initDialog() });
  5927. },
  5928.  
  5929. async getPCSLink() {
  5930. selectList = this.getSelectedList();
  5931. if (selectList.length === 0) {
  5932. return message.error('提示:<br/>请勾选要下载的文件哦~');
  5933. }
  5934. if (this.isOnlyFolder()) {
  5935. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  5936. }
  5937. let fids = [];
  5938. for (const val of selectList) {
  5939. fids.push(val.fid);
  5940. }
  5941. if (pt === 'home') {
  5942. let res = await base.post(pan.pcs[0], {
  5943. "fids": fids
  5944. }, { "content-type": "application/json;charset=utf-8", "user-agent": pan.ua });
  5945. if (res.code === 31001) {
  5946. return message.error('提示:<br/>请先登录(不可用)网盘~<br/>代码:' + res.code);
  5947. }
  5948. if (res.code !== 0) {
  5949. return message.error('提示:<br/>获取链接失败了~<br/>代码:' + res.code);
  5950. }
  5951. let html = this.generateDom(res.data);
  5952. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  5953. } else {
  5954. return message.error('提示:<br/>页面错误~');
  5955. }
  5956. },
  5957.  
  5958. generateDom(list) {
  5959. let content = '<div class="pl-main">';
  5960. let alinkAllText = '';
  5961. list.forEach((v, i) => {
  5962. if (v.file === false) return;
  5963. let filename = v.file_name;
  5964. let ext = base.getExtension(filename);
  5965. let fid = v.fid;
  5966. let size = base.sizeFormat(v.size);
  5967. let dlink = v.download_url;
  5968. if (mode === 'api') {
  5969. alinkAllText += dlink + '\r\n';
  5970. content += `<div class="pl-item">
  5971. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5972. <button class="pl-item-link listener-tip pl-btn-primary pl-btn-default listener-link-api blob" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接" data-filename="${filename}" data-size="${v.size}" data-link="${dlink}" data-fid="${fid}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  5973. <button class="pl-item-link listener-tip pl-btn-primary pl-btn-info listener-link-api browser" data-title="基于浏览器直接打开链接来下载文件,适用于较为古老但支持 iframe 的浏览器,点击“直接下载”后需等待下载提示弹出才能点击下个“直接下载”,否则只会下载后者,此方式下载有可能会被 IDM 捕获下载链接" data-filename="${filename}" data-link="${dlink}" data-fid="${fid}">直接下载(基于浏览器链接)</button>
  5974. <button class="pl-item-copy pl-btn-primary pl-btn-warning listener-copy-all" href="${dlink}" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  5975. <div class="pl-item-tip" style="display: none"><span>若没有弹出IDM下载框,找到IDM <b>选项</b> -> <b>文件类型</b> -> <b>第一个框</b> 中添加后缀 <span class="pl-ext">${ext}</span>,<a href="${pan.idm}" target="_blank" class="pl-a">详见此处</a></span> <span class="listener-back">返回</span></div>
  5976. <div class="pl-item-progress" style="display: none">
  5977. <div class="pl-progress">
  5978. <div class="pl-progress-outer"></div>
  5979. <div class="pl-progress-inner" style="width:5%">
  5980. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  5981. </div>
  5982. </div>
  5983. <span class="pl-btn-primary pl-btn-danger pl-progress-stop listener-stop">取消下载</span>
  5984. `;
  5985. content += `<span class="pl-progress-tip" style="display: none" >未发现IDM,使用自带浏览器下载</span>
  5986. <span class="pl-btn-primary pl-btn-info pl-progress-back listener-back" style="display: none">返回</span>
  5987. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  5988. `;
  5989. content += `</div></div>`
  5990. }
  5991. if (mode === 'aria') {
  5992. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  5993. alinkAllText += alink + '\r\n';
  5994. content += `<div class="pl-item">
  5995. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5996. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  5997. }
  5998. if (mode === 'rpc') {
  5999. content += `<div class="pl-item">
  6000. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6001. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><svg class="icon-rpc-devices" viewBox="-10 0 1034 1024"><g transform="matrix(1 0 0 -1 0 960)"><path fill="currentColor" d="M832 -64h-640q-53 0 -90.5 37.5t-37.5 90.5v768q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-768q0 -53 -37.5 -90.5t-90.5 -37.5zM832 768q0 27 -18.5 45.5t-45.5 18.5h-512q-27 0 -45.5 -18.5t-18.5 -45.5v-320h640v320v0zM832 320h-640v-192q0 -27 18.5 -45.5t45.5 -18.5h512q27 0 45.5 18.5t18.5 45.5v192v0zM512 128q-27 0 -45.5 18.5t-18.5 45.5t18.5 45.5t45.5 18.5t45.5 -18.5t18.5 -45.5t-18.5 -45.5t-45.5 -18.5z" /></g></svg><span style="margin-left: 5px;">将 ${filename} 推送到 RPC 下载器</span></button></div>`;
  6002. }
  6003. if (mode === 'curl') {
  6004. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  6005. alinkAllText += alink + '\r\n';
  6006. content += `<div class="pl-item">
  6007. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6008. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  6009. }
  6010. if (mode === 'bc') {
  6011. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  6012. alinkAllText += alink + '\r\n';
  6013. content += `<div class="pl-item">
  6014. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6015. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a> </div>`;
  6016. }
  6017. });
  6018. content += '</div>';
  6019. if (mode === 'api')
  6020. content += `<div class="pl-extra"><button class="pl-btn-primary listener-tip listener-download-all" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接">全部增强下载</button><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  6021. if (mode === 'aria')
  6022. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  6023. if (mode === 'rpc') {
  6024. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  6025. content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">修改 RPC 参数(${rpc})</button><button class="pl-btn-primary pl-btn-success pl-btn-opacity listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  6026. }
  6027. if (mode === 'curl') {
  6028. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">修改终端类型(${terminalType[base.getValue('setting_terminal_type')]})</button></div>`;
  6029. }
  6030. if (mode === 'bc') {
  6031. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  6032. }
  6033. return content;
  6034. },
  6035.  
  6036. async sendLinkToRPC(filename, link) {
  6037. let rpc = {
  6038. domain: base.getValue('setting_rpc_domain'),
  6039. port: base.getValue('setting_rpc_port'),
  6040. path: base.getValue('setting_rpc_path'),
  6041. token: base.getValue('setting_rpc_token'),
  6042. dir: base.getValue('setting_rpc_dir'),
  6043. };
  6044.  
  6045. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  6046. let rpcData = {
  6047. id: new Date().getTime(),
  6048. jsonrpc: '2.0',
  6049. method: 'aria2.addUri',
  6050. params: [`token:${rpc.token}`, [link], {
  6051. dir: rpc.dir,
  6052. out: filename,
  6053. header: [`Cookie: ${document.cookie}`]
  6054. }]
  6055. };
  6056. try {
  6057. let res = await base.post(url, rpcData, { "Cookie": document.cookie }, '');
  6058. if (res.result) return 'success';
  6059. return 'fail';
  6060. } catch (e) {
  6061. return 'fail';
  6062. }
  6063. },
  6064.  
  6065. getSelectedList() {
  6066. try {
  6067. let selectedList = [];
  6068. let reactDom = document.getElementsByClassName('file-list')[0];
  6069. let reactObj = base.findReact(reactDom);
  6070. let props = reactObj.props;
  6071. if (props) {
  6072. let fileList = props.list || [];
  6073. let selectedKeys = props.selectedRowKeys || [];
  6074. fileList.forEach(function (val) {
  6075. if (selectedKeys.includes(val.fid)) {
  6076. selectedList.push(val);
  6077. }
  6078. });
  6079. }
  6080. return selectedList;
  6081. } catch (e) {
  6082. return [];
  6083. }
  6084. },
  6085.  
  6086. detectPage() {
  6087. let path = location.pathname;
  6088. if (/^\/(list)/.test(path)) return 'home';
  6089. if (/^\/(s|share)\//.test(path)) return 'share';
  6090. return '';
  6091. },
  6092.  
  6093. isOnlyFolder() {
  6094. for (let i = 0; i < selectList.length; i++) {
  6095. if (selectList[i].file) return false;
  6096. }
  6097. return true;
  6098. },
  6099.  
  6100. showMainDialog(title, html, footer) {
  6101. Swal.fire({
  6102. title,
  6103. html,
  6104. footer,
  6105. allowOutsideClick: false,
  6106. showCloseButton: true,
  6107. position: 'center',
  6108. width,
  6109. padding: '15px 20px 5px',
  6110. customClass,
  6111. confirmButtonText: '关闭',
  6112. willClose: function () {
  6113. base._resetData();
  6114. }
  6115. }).then(function () {
  6116. base._resetData();
  6117. });
  6118. },
  6119.  
  6120. async initPanLinker() {
  6121. pt = this.detectPage();
  6122. base.createTip();
  6123. base.registerMenuCommand();
  6124. if (base.getValue('setting_server_main') === 'v1') {
  6125. let res = await base.post(`https://api.youxiaohou.com/config/quark/?ver=${version}&a=${author}`, {}, {}, 'text');
  6126. pan = JSON.parse(base.decode(res));
  6127. } else if (base.getValue('setting_server_main') === 'v2') {
  6128. let res = await base.post(`https://api.youxiaohou.com/config/v2/quark/?ver=${version}&a=${author}`, {}, {}, 'text');
  6129. pan = JSON.parse(base.decode(res));
  6130. } else if (base.getValue('setting_server_main') === "no") {
  6131. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/quark.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  6132. pan = JSON.parse(res);
  6133. } else {
  6134. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/quark.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  6135. pan = JSON.parse(res);
  6136. base.setValue('setting_server_main', 'v2');
  6137. }
  6138. Object.freeze && Object.freeze(pan);
  6139. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('setting_init_license')) {
  6140. this.addButton();
  6141. this.addPageListener();
  6142. } else {
  6143. this.addInitButton();
  6144. }
  6145. base.createDownloadIframe();
  6146. }
  6147. };
  6148.  
  6149. //中国移动云盘/和彩云
  6150. let yidong = {
  6151.  
  6152. convertLinkToAria(link, filename, ua) {
  6153. filename = base.fixFilename(filename);
  6154. return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
  6155. },
  6156.  
  6157. convertLinkToBC(link, filename, ua) {
  6158. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
  6159. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  6160. },
  6161.  
  6162. convertLinkToCurl(link, filename, ua) {
  6163. let terminal = base.getValue('setting_terminal_type');
  6164. filename = base.fixFilename(filename);
  6165. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}"`);
  6166. },
  6167.  
  6168. addPageListener() {
  6169. /*
  6170. 防止代码因其他原因被执行多次
  6171. 这段代码出自 Via轻插件,作者谷花泰
  6172. */
  6173. const key = encodeURIComponent('(改)网盘直链下载助手:移动云盘');
  6174. if (window[key]) return;
  6175. window[key] = true;
  6176.  
  6177. function _factory(e) {
  6178. let target = $(e.target);
  6179. let item = target.parents('.pl-item');
  6180. let link = item.find('.pl-item-link.blob');
  6181. let directLink = item.find('.pl-item-link.browser');
  6182. let progress = item.find('.pl-item-progress');
  6183. let tip = item.find('.pl-item-tip');
  6184. let copy = item.find('.pl-item-copy');
  6185. let howidm = item.find('.pl-progress-how');
  6186. let back = item.find('.pl-progress-back');
  6187. let stop = item.find('.pl-progress-stop');
  6188. return {
  6189. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  6190. };
  6191. }
  6192.  
  6193. function _reset(i) {
  6194. ins[i] && clearInterval(ins[i]);
  6195. request[i] && request[i].abort();
  6196. progress[i] = 0;
  6197. idm[i] = false;
  6198. }
  6199.  
  6200. doc.on('click', '.pl-button-mode', function (e) {
  6201. mode = e.target.dataset.mode;
  6202. if (!mode) return;
  6203. Swal.fire({
  6204. heightAuto: false,
  6205. scrollbarPadding: false,
  6206. showConfirmButton: false,
  6207. html: `链接获取中`,
  6208. willOpen: function () {
  6209. Swal.showLoading();
  6210. }
  6211. });
  6212. yidong.getPCSLink();
  6213. });
  6214. doc.on('click', '.listener-link-api.browser', async function (e) {
  6215. e.preventDefault();
  6216. let dataset = e.currentTarget.dataset;
  6217. let href = dataset.link;
  6218. $('#downloadIframe').attr('src', href);
  6219. });
  6220. doc.on('click', '.listener-link-api.blob', async function (e) {
  6221. e.preventDefault();
  6222. let o = _factory(e);
  6223. let $width = o.item.find('.pl-progress-inner');
  6224. let $text = o.item.find('.pl-progress-inner-text');
  6225. let filename = o.link[0].dataset.filename;
  6226. let index = o.link[0].dataset.index;
  6227. _reset(index);
  6228. let dataset = e.currentTarget.dataset;
  6229. let href = dataset.link;
  6230. base.get(href, { "Referer": `https://${location.host}/` }, 'blob', { filename, index });
  6231. let startTime = Date.now(); // 记录下载开始时间
  6232. let prevLoaded = 0; // 上一次的已下载数据量
  6233. let prevTime = startTime; // 上一次的时间
  6234. let size = Number(o.link[0].dataset.size);
  6235. ins[index] = setInterval(function () {
  6236. let prog = +progress[index] || 0;
  6237. let isIDM = idm[index] || false;
  6238. // 处理普通下载的情况...
  6239. let currentTime = Date.now();
  6240. let elapsedTime = currentTime - startTime;
  6241. let totalProgress = prog / 100;
  6242. let totalElapsedSeconds = elapsedTime / 1000;
  6243. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  6244. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  6245.  
  6246. // 将剩余时间转换为天、时、分、秒
  6247. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  6248. remainingTimeSeconds %= (60 * 60 * 24);
  6249.  
  6250. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  6251. remainingTimeSeconds %= (60 * 60);
  6252.  
  6253. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  6254. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  6255.  
  6256. // 计算下载速度
  6257. let loaded = prog * size / 100; // 已下载数据量
  6258. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  6259. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  6260. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  6261.  
  6262. // 更新上一次的数据
  6263. prevLoaded = loaded;
  6264. prevTime = currentTime;
  6265.  
  6266. // 更改界面
  6267. o.link.hide();
  6268. o.directLink.hide();
  6269. o.tip.hide();
  6270. o.stop.show();
  6271. o.copy.hide();
  6272. o.progress.show();
  6273.  
  6274. // 更新进度条
  6275. $width.css('width', prog + '%');
  6276.  
  6277. // 更新进度条文本
  6278. let timeText = '';
  6279. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  6280. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  6281. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  6282. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  6283. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  6284. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  6285. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  6286. timeText = remainingSeconds + '秒';
  6287. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  6288. timeText = '即将完成';
  6289. } else {
  6290. timeText = '计算中...';
  6291. }
  6292.  
  6293. let speedText = '';
  6294. speedText = base.sizeFormat(downloadSpeed)
  6295. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  6296.  
  6297. if (prog === 100) {
  6298. setTimeout(function () {
  6299. clearInterval(ins[index]);
  6300. progress[index] = 0;
  6301. o.item.find('.pl-progress-stop').hide();
  6302. o.howidm.hide();
  6303. $text.text('下载完成~ 浏览器下载框应该弹出来了哦~');
  6304. o.back.show()
  6305. setTimeout(function () {
  6306. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  6307. }, 3000)
  6308. }, 1000)
  6309. }
  6310. }, 500);
  6311. });
  6312. doc.on('click', '.listener-retry', async function (e) {
  6313. let o = _factory(e);
  6314. o.tip.hide();
  6315. o.link.show();
  6316. o.directLink.show();
  6317. });
  6318. doc.on('click', '.listener-how', async function (e) {
  6319. let o = _factory(e);
  6320. let index = o.link[0].dataset.index;
  6321. if (request[index]) {
  6322. request[index].abort();
  6323. clearInterval(ins[index]);
  6324. o.progress.hide();
  6325. o.tip.show();
  6326. }
  6327.  
  6328. });
  6329. doc.on('click', '.listener-stop', async function (e) {
  6330. let o = _factory(e);
  6331. let index = o.link[0].dataset.index;
  6332. if (request[index]) {
  6333. request[index].abort();
  6334. clearInterval(ins[index]);
  6335. o.item.find('.pl-progress-inner-text').text('正在取消...');
  6336. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  6337. setTimeout(function () {
  6338. o.tip.hide();
  6339. o.back.hide();
  6340. o.link.show();
  6341. o.directLink.show();
  6342. o.copy.show();
  6343. o.progress.hide();
  6344. o.stop.hide();
  6345. }, 1050)
  6346. }
  6347. });
  6348. doc.on('click', '.listener-back', async function (e) {
  6349. let o = _factory(e);
  6350. o.progress.hide();
  6351. o.tip.hide();
  6352. o.link.show();
  6353. o.directLink.show();
  6354. o.copy.show();
  6355. o.stop.hide();
  6356. o.back.hide();
  6357. });
  6358. doc.on('click', '.listener-download-all', function (e) {
  6359. $('.pl-item-link.blob').each(function () {
  6360. if ($(this).css('display') !== 'none') {
  6361. $(this).click();
  6362. }
  6363. });
  6364. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  6365. setTimeout(function () {
  6366. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  6367. }, 2000)
  6368. });
  6369. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  6370. e.preventDefault();
  6371. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  6372. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  6373. setTimeout(function () {
  6374. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  6375. }, 2000)
  6376. });
  6377. doc.on('click', '.listener-link-rpc', async function (e) {
  6378. e.preventDefault();
  6379. let target = $(e.currentTarget);
  6380.  
  6381. target.find('.icon-rpc-devices').remove();
  6382. target.find('.pl-loading').remove();
  6383. target.prepend(base.createLoading());
  6384.  
  6385. let res = await yidong.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  6386. if (res === 'success') {
  6387. $('.listener-rpc-task').show();
  6388. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  6389. } else if (res === 'assistant') {
  6390. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  6391. } else {
  6392. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  6393. }
  6394. });
  6395. doc.on('click', '.listener-send-rpc', function (e) {
  6396. $('.listener-link-rpc').click();
  6397. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  6398. });
  6399. doc.on('click', '.listener-open-setting', function () {
  6400. base.showSetting();
  6401. });
  6402. doc.on('click', '.listener-open-updatelog', function () {
  6403. base.showUpdateLog();
  6404. });
  6405. doc.on('click', '.listener-open-beautify', function () {
  6406. base.showBeautify();
  6407. });
  6408. doc.on('click', '.listener-rpc-task', function () {
  6409. let rpc = JSON.stringify({
  6410. domain: base.getValue('setting_rpc_domain'),
  6411. port: base.getValue('setting_rpc_port'),
  6412. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  6413. GM_openInTab(url, { active: true });
  6414. });
  6415. },
  6416.  
  6417. removeAD() {
  6418. base.waitForKeyElements(".adv_swiper_menu", function (tag) {
  6419. tag.fadeOut();
  6420. });
  6421. base.waitForKeyElements(".client-bubble", function (tag) {
  6422. tag.fadeOut();
  6423. });
  6424. base.waitForKeyElements(".avs-box", function (tag) {
  6425. tag.fadeOut();
  6426. });
  6427. base.waitForKeyElements(".top-adv-swiper", function (tag) {
  6428. tag.fadeOut();
  6429. });
  6430. base.waitForKeyElements(".client_download_icon", function (tag) {
  6431. tag.fadeOut();
  6432. });
  6433. base.waitForKeyElements(".document_top_memberCenter", function (tag) {
  6434. $(tag[0]).click(function () {
  6435. Swal.fire({
  6436. html: `<iframe style="height: 700px; width: 420px; border: 0;" src="https://vip.yun.139.com/vip/"></iframe>`,
  6437. allowOutsideClick: false,
  6438. showCloseButton: true,
  6439. showConfirmButton: false,
  6440. heightAuto: false,
  6441. scrollbarPadding: false,
  6442. });
  6443. });
  6444. }, true);
  6445. },
  6446.  
  6447. addButton() {
  6448. if (!pt) return;
  6449. let $toolWrap;
  6450. let $button = $(`<div class="yidong-button pl-button btn-top"><span class="yidong-btn">下载助手</span><ul class="pl-dropdown-menu" style="top: 36px; letter-spacing: normal;"><li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria" >Aria下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc" >BC下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li></ul></div>`);
  6451. if (pt === 'home') {
  6452. base.listenElement(pan.btn.home, function () {
  6453. $toolWrap = $(pan.btn.home);
  6454. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  6455. })
  6456. }
  6457. if (pt === 'share') {
  6458. $button.removeClass('yidong-button').addClass('yidong-share-button');
  6459. base.listenElement(pan.btn.share, function () {
  6460. $toolWrap = $(pan.btn.share);
  6461. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  6462. })
  6463. }
  6464. base.createDownloadIframe();
  6465. },
  6466.  
  6467. addInitButton() {
  6468. if (!pt) return;
  6469. let $toolWrap;
  6470. let $button = $(`<div class="yidong-button pl-button-init btn-top"><span class="yidong-btn">点我点亮</span></div>`);
  6471. if (pt === 'home') {
  6472. base.listenElement(pan.btn.home, function () {
  6473. $toolWrap = $(pan.btn.home);
  6474. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  6475. })
  6476. }
  6477. if (pt === 'share') {
  6478. $button.removeClass('yidong-button').addClass('yidong-share-button');
  6479. base.listenElement(pan.btn.share, function () {
  6480. $toolWrap = $(pan.btn.share);
  6481. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  6482. })
  6483. }
  6484. $button.click(function () { base.initDialog() });
  6485. },
  6486.  
  6487. getRandomString(len) {
  6488. len = len || 16;
  6489. let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
  6490. let maxPos = $chars.length;
  6491. let pwd = '';
  6492. for (let i = 0; i < len; i++) {
  6493. pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
  6494. }
  6495. return pwd;
  6496. },
  6497.  
  6498. utob(str) {
  6499. const u = String.fromCharCode;
  6500. return str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g, function (t) {
  6501. if (t.length < 2) {
  6502. let e = t.charCodeAt(0);
  6503. return e < 128 ? t : e < 2048 ? u(192 | e >>> 6) + u(128 | 63 & e) : u(224 | e >>> 12 & 15) + u(128 | e >>> 6 & 63) + u(128 | 63 & e);
  6504. }
  6505. e = 65536 + 1024 * (t.charCodeAt(0) - 55296) + (t.charCodeAt(1) - 56320);
  6506. return u(240 | e >>> 18 & 7) + u(128 | e >>> 12 & 63) + u(128 | e >>> 6 & 63) + u(128 | 63 & e);
  6507. });
  6508. },
  6509.  
  6510. getSign(e, t, a, n) {
  6511. let r = "",
  6512. i = "";
  6513. if (t) {
  6514. let s = Object.assign({}, t);
  6515. i = JSON.stringify(s),
  6516. i = i.replace(/\s*/g, ""),
  6517. i = encodeURIComponent(i);
  6518. let c = i.split(""),
  6519. u = c.sort();
  6520. i = u.join("");
  6521. }
  6522. let A = md5(base.encode(this.utob(i)));
  6523. let l = md5(a + ":" + n);
  6524. return md5(A + l).toUpperCase();
  6525. },
  6526.  
  6527. async getFileUrlByOnce(item, index) {
  6528. try {
  6529. if (item.downloadUrl) return {
  6530. index,
  6531. downloadUrl: item.downloadUrl
  6532. };
  6533.  
  6534. if (this.detectPage() === 'home') {
  6535. let body = {
  6536. "contentID": item.contentID,
  6537. "commonAccountInfo": { "account": item.owner, "accountType": 1 },
  6538. "operation": "0",
  6539. "inline": "0",
  6540. "extInfo": { "isReturnCdnDownloadUrl": "1" }
  6541. };
  6542. let time = new Date(+new Date() + 8 * 3600 * 1000).toJSON().substr(0, 19).replace('T', ' ');
  6543. let key = this.getRandomString(16);
  6544. let sign = this.getSign(undefined, body, time, key);
  6545.  
  6546. let res = await base.post(pan.pcs[0], body, {
  6547. 'authorization': base.getCookie('authorization'),
  6548. 'x-huawei-channelSrc': '10000034',
  6549. 'x-inner-ntwk': '2',
  6550. 'mcloud-channel': '1000101',
  6551. 'mcloud-client': '10701',
  6552. 'mcloud-sign': time + "," + key + "," + sign,
  6553. 'content-type': "application/json;charset=UTF-8",
  6554. 'caller': 'web',
  6555. 'CMS-DEVICE': 'default',
  6556. 'x-DeviceInfo': '||9|7.12.0|chrome|119.0.0.0|||windows 10||zh-CN|||',
  6557. 'x-SvcType': '1',
  6558. });
  6559. if (res.success) {
  6560. return {
  6561. index,
  6562. downloadUrl: res.data.downloadURL
  6563. };
  6564. } else {
  6565. return {
  6566. index,
  6567. downloadUrl: '获取下载地址失败,刷新后再试试吧~'
  6568. };
  6569. }
  6570. }
  6571. if (this.detectPage() === 'share') {
  6572. let vueDom = document.querySelector(".main_file_list").__vue__;
  6573.  
  6574. let res = await base.post(pan.pcs[1], `linkId=${vueDom.linkID}&contentIds=${item.path}&catalogIds=`, {
  6575. 'Content-Type': 'application/x-www-form-urlencoded',
  6576. });
  6577. if (res.code === 0) {
  6578. return {
  6579. index,
  6580. downloadUrl: res.data.redrUrl
  6581. };
  6582. } else {
  6583. return {
  6584. index,
  6585. downloadUrl: '获取下载地址失败,刷新后再试试吧~'
  6586. };
  6587. }
  6588. }
  6589. } catch (e) {
  6590. return {
  6591. index,
  6592. downloadUrl: '获取下载地址失败,刷新后再试试吧~'
  6593. };
  6594. }
  6595. },
  6596.  
  6597. async getPCSLink() {
  6598. selectList = this.getSelectedList();
  6599. if (selectList.length === 0) {
  6600. return message.error('提示:<br/>请勾选要下载的文件哦~');
  6601. }
  6602. if (this.isOnlyFolder()) {
  6603. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  6604. }
  6605.  
  6606. let queue = [];
  6607. for (const [index, item] of selectList.entries()) {
  6608. queue.push(this.getFileUrlByOnce(item, index));
  6609. }
  6610.  
  6611. const res = await Promise.all(queue);
  6612. res.forEach(val => {
  6613. selectList[val.index].downloadUrl = val.downloadUrl;
  6614. });
  6615.  
  6616. let html = this.generateDom(selectList);
  6617. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  6618. },
  6619.  
  6620. generateDom(list) {
  6621. let content = '<div class="pl-main">';
  6622. let alinkAllText = '';
  6623. list.forEach((v, i) => {
  6624. if (v.dirEtag || v.caName) return;
  6625. let filename = v.contentName || v.coName;
  6626. let ext = base.getExtension(filename);
  6627. let size = base.sizeFormat(v.contentSize || v.coSize);
  6628. let dlink = v.downloadUrl;
  6629. if (mode === 'api') {
  6630. alinkAllText += dlink + '\r\n';
  6631. content += `<div class="pl-item">
  6632. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6633. <button class="pl-item-link listener-tip pl-btn-primary pl-btn-default listener-link-api blob" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接" data-filename="${filename}" data-size="${v.contentSize || v.coSize}" data-link="${dlink}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  6634. <button class="pl-item-link listener-tip pl-btn-primary pl-btn-info listener-link-api browser" data-title="基于浏览器直接打开链接来下载文件,适用于较为古老但支持 iframe 的浏览器,点击“直接下载”后需等待下载提示弹出才能点击下个“直接下载”,否则只会下载后者,此方式下载有可能会被 IDM 捕获下载链接" data-filename="${filename}" data-link="${dlink}">直接下载(基于浏览器链接)</button>
  6635. <button class="pl-item-copy pl-btn-primary pl-btn-warning listener-copy-all" href="${dlink}" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  6636. <div class="pl-item-tip" style="display: none"><span>若没有弹出IDM下载框,找到IDM <b>选项</b> -> <b>文件类型</b> -> <b>第一个框</b> 中添加后缀 <span class="pl-ext">${ext}</span>,<a href="${pan.idm}" target="_blank" class="pl-a">详见此处</a></span> <span class="listener-back">返回</span></div>
  6637. <div class="pl-item-progress" style="display: none">
  6638. <div class="pl-progress">
  6639. <div class="pl-progress-outer"></div>
  6640. <div class="pl-progress-inner" style="width:5%">
  6641. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  6642. </div>
  6643. </div>
  6644. <span class="pl-btn-primary pl-btn-danger pl-progress-stop listener-stop">取消下载</span>
  6645. `;
  6646. content += `<span class="pl-progress-tip" style="display: none" >未发现IDM,使用自带浏览器下载</span>
  6647. <span class="pl-btn-primary pl-btn-info pl-progress-back listener-back" style="display: none">返回</span>
  6648. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  6649. `;
  6650. content += `</div></div>`
  6651. }
  6652. if (mode === 'aria') {
  6653. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  6654. alinkAllText += alink + '\r\n';
  6655. content += `<div class="pl-item">
  6656. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6657. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  6658. }
  6659. if (mode === 'rpc') {
  6660. content += `<div class="pl-item">
  6661. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6662. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><svg class="icon-rpc-devices" viewBox="-10 0 1034 1024"><g transform="matrix(1 0 0 -1 0 960)"><path fill="currentColor" d="M832 -64h-640q-53 0 -90.5 37.5t-37.5 90.5v768q0 53 37.5 90.5t90.5 37.5h640q53 0 90.5 -37.5t37.5 -90.5v-768q0 -53 -37.5 -90.5t-90.5 -37.5zM832 768q0 27 -18.5 45.5t-45.5 18.5h-512q-27 0 -45.5 -18.5t-18.5 -45.5v-320h640v320v0zM832 320h-640v-192q0 -27 18.5 -45.5t45.5 -18.5h512q27 0 45.5 18.5t18.5 45.5v192v0zM512 128q-27 0 -45.5 18.5t-18.5 45.5t18.5 45.5t45.5 18.5t45.5 -18.5t18.5 -45.5t-18.5 -45.5t-45.5 -18.5z" /></g></svg><span style="margin-left: 5px;">将 ${filename} 推送到 RPC 下载器</span></button></div>`;
  6663. }
  6664. if (mode === 'curl') {
  6665. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  6666. alinkAllText += alink + '\r\n';
  6667. content += `<div class="pl-item">
  6668. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6669. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  6670. }
  6671. if (mode === 'bc') {
  6672. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  6673. alinkAllText += alink + '\r\n';
  6674. content += `<div class="pl-item">
  6675. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6676. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a> </div>`;
  6677. }
  6678. });
  6679. content += '</div>';
  6680. if (mode === 'api') {
  6681. content += `<div class="pl-extra"><button class="pl-btn-primary listener-tip listener-download-all" data-title="不建议使用本功能,若文件过大下载完成后有可能不会弹出窗口,此时请换用“RPC下载 + Mortix”的组合<br/>基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接">全部增强下载</button><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  6682. }
  6683. if (mode === 'aria')
  6684. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  6685. if (mode === 'rpc') {
  6686. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  6687. content += `<div class="pl-extra"><button class="pl-btn-primary listener-send-rpc">发送全部链接</button><button title="${rpc}" class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px">修改 RPC 参数(${rpc})</button><button class="pl-btn-primary pl-btn-success pl-btn-opacity listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  6688. }
  6689. if (mode === 'curl') {
  6690. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button><button class="pl-btn-primary pl-btn-warning listener-open-setting" style="margin-left: 10px;">修改终端类型(${terminalType[base.getValue('setting_terminal_type')]})</button></div>`;
  6691. }
  6692. if (mode === 'bc') {
  6693. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  6694. }
  6695. return content;
  6696. },
  6697.  
  6698. async sendLinkToRPC(filename, link) {
  6699. let rpc = {
  6700. domain: base.getValue('setting_rpc_domain'),
  6701. port: base.getValue('setting_rpc_port'),
  6702. path: base.getValue('setting_rpc_path'),
  6703. token: base.getValue('setting_rpc_token'),
  6704. dir: base.getValue('setting_rpc_dir'),
  6705. };
  6706.  
  6707. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  6708. let rpcData = {
  6709. id: new Date().getTime(),
  6710. jsonrpc: '2.0',
  6711. method: 'aria2.addUri',
  6712. params: [`token:${rpc.token}`, [link], {
  6713. dir: rpc.dir,
  6714. out: filename,
  6715. header: []
  6716. }]
  6717. };
  6718. try {
  6719. let res = await base.post(url, rpcData, {}, '');
  6720. if (res.result) return 'success';
  6721. return 'fail';
  6722. } catch (e) {
  6723. return 'fail';
  6724. }
  6725. },
  6726.  
  6727. getSelectedList() {
  6728. try {
  6729. return document.querySelector(".main_file_list").__vue__.selectList.map(val => val.item);
  6730. } catch (e) {
  6731. let vueDom = document.querySelector(".home-page").__vue__;
  6732. let fileList = vueDom._computedWatchers.fileList.value;
  6733. let dirList = vueDom._computedWatchers.dirList.value;
  6734. let selectedFileIndex = vueDom.selectedFile;
  6735. let selectedDirIndex = vueDom.selectedDir;
  6736. let selectFileList = fileList.filter((v, i) => {
  6737. return selectedFileIndex.includes(i);
  6738. });
  6739. let selectDirList = dirList.filter((v, i) => {
  6740. return selectedDirIndex.includes(i);
  6741. });
  6742. return [...selectFileList, ...selectDirList];
  6743. }
  6744. },
  6745.  
  6746. detectPage() {
  6747. let path = location.pathname;
  6748. if (/^\/w/.test(path)) return 'home';
  6749. if (/^\/link|shareweb/.test(path)) return 'share';
  6750. return '';
  6751. },
  6752.  
  6753. isOnlyFolder() {
  6754. for (let i = 0; i < selectList.length; i++) {
  6755. if (selectList[i].fileEtag || selectList[i].coName) return false;
  6756. }
  6757. return true;
  6758. },
  6759.  
  6760. showMainDialog(title, html, footer) {
  6761. Swal.fire({
  6762. title,
  6763. html,
  6764. footer,
  6765. allowOutsideClick: false,
  6766. showCloseButton: true,
  6767. position: 'center',
  6768. width,
  6769. padding: '15px 20px 5px',
  6770. customClass,
  6771. confirmButtonText: '关闭',
  6772. willClose: function () {
  6773. base._resetData();
  6774. }
  6775. }).then(function () {
  6776. base._resetData();
  6777. });
  6778. },
  6779.  
  6780. async initPanLinker() {
  6781. pt = this.detectPage();
  6782. base.createTip();
  6783. base.registerMenuCommand();
  6784. if (base.getValue('setting_server_main') === 'v1') {
  6785. let res = await base.post(`https://api.youxiaohou.com/config/yidong/?ver=${version}&a=${author}`, {}, {}, 'text');
  6786. pan = JSON.parse(base.decode(res));
  6787. } else if (base.getValue('setting_server_main') === 'v2') {
  6788. let res = await base.post(`https://api.youxiaohou.com/config/v2/yidong/?ver=${version}&a=${author}`, {}, {}, 'text');
  6789. pan = JSON.parse(base.decode(res));
  6790. } else if (base.getValue('setting_server_main') === "no") {
  6791. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/yidong.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  6792. pan = JSON.parse(res);
  6793. } else {
  6794. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/yidong.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  6795. pan = JSON.parse(res);
  6796. base.setValue('setting_server_main', 'v2');
  6797. }
  6798. Object.freeze && Object.freeze(pan);
  6799. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('setting_init_license')) {
  6800. this.addButton();
  6801. this.addPageListener();
  6802. } else {
  6803. this.addInitButton();
  6804. }
  6805. }
  6806. };
  6807.  
  6808. // 油小猴
  6809. let youxiaohou = {
  6810. async initPanLinker() {
  6811. base.createTip();
  6812. base.registerMenuCommand();
  6813. if (base.getValue('setting_server_main') === 'v1') {
  6814. let res = await base.post(`https://api.youxiaohou.com/config/?ver=${version}&a=${author}`, {}, {}, 'text');
  6815. pan = JSON.parse(base.decode(res));
  6816. } else if (base.getValue('setting_server_main') === 'v2') {
  6817. let res = await base.post(`https://api.youxiaohou.com/config/v2/?ver=${version}&a=${author}`, {}, {}, 'text');
  6818. pan = JSON.parse(base.decode(res));
  6819. } else if (base.getValue('setting_server_main') === "no") {
  6820. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/config.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  6821. pan = JSON.parse(res);
  6822. } else {
  6823. let res = await base.get(`https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/config.json?version=${realversion}`, { 'Cache-Control': 'no-cache' }, "text", {});
  6824. pan = JSON.parse(res);
  6825. base.setValue('setting_server_main', 'v2');
  6826. }
  6827. Object.freeze && Object.freeze(pan);
  6828. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('setting_init_license')) {
  6829. this.addButton();
  6830. } else {
  6831. this.addInitButton();
  6832. }
  6833. },
  6834. addButton() {
  6835. let $button = `
  6836. <div class="nav-item">
  6837. <div class="dropdown-wrapper">
  6838. <button type="button" aria-label="(改)下载助手" class="dropdown-title">
  6839. <span class="title">(改)下载助手⬇️</span>
  6840. <span class="arrow down"></span>
  6841. </button>
  6842. <button type="button" aria-label="(改)下载助手" class="mobile-dropdown-title">
  6843. <span class="title">(改)下载助手⬇️</span>
  6844. <span class="arrow right"></span>
  6845. </button>
  6846. <ul class="nav-dropdown" style="display:none;">
  6847. <li class="dropdown-item">
  6848. <h4>
  6849. 助手
  6850. </h4>
  6851. <ul class="dropdown-subitem-wrapper">
  6852. <li class="dropdown-subitem">
  6853. <a href="javascript:void(0)" class="listener-open-info nav-link">
  6854. 🛠️ 调试(查看暗号/协议)
  6855. </a>
  6856. </li>
  6857. </ul>
  6858. </li>
  6859. <li class="dropdown-item">
  6860. <h4>
  6861. 选项
  6862. </h4>
  6863. <ul class="dropdown-subitem-wrapper">
  6864. <li class="dropdown-subitem">
  6865. <a href="javascript:void(0)" class="listener-open-setting nav-link">
  6866. ⚙️ 助手设置
  6867. </a>
  6868. </li>
  6869. <li class="dropdown-subitem">
  6870. <a href="javascript:void(0)" class="listener-open-beautify nav-link">
  6871. 🍃️ 助手美化
  6872. </a>
  6873. </li>
  6874. <li class="dropdown-subitem">
  6875. <a href="javascript:void(0)" class="listener-open-updatelog nav-link">
  6876. 📃️ 更新日志
  6877. </a>
  6878. </li>
  6879. </ul>
  6880. </li>
  6881. </ul>
  6882. </div>
  6883. </div>
  6884. `;
  6885. doc.on('click', '.listener-open-setting', function () {
  6886. base.showSetting();
  6887. });
  6888. doc.on('click', '.listener-open-updatelog', function () {
  6889. base.showUpdateLog();
  6890. });
  6891. doc.on('click', '.listener-open-beautify', function () {
  6892. base.showBeautify();
  6893. });
  6894. doc.on('click', '.listener-open-info', function () {
  6895. base.showDebug();
  6896. });
  6897.  
  6898. document.querySelectorAll(".nav-links").forEach(function (element) {
  6899. element.innerHTML += $button
  6900. })
  6901. },
  6902. addInitButton() {
  6903. let $button = `
  6904. <div class="nav-item">
  6905. <div class="dropdown-wrapper">
  6906. <a class="nav-link listener-open-init">(改)点我点亮⬇️</a>
  6907. </div>
  6908. </div>
  6909. `;
  6910. doc.on('click', '.listener-open-init', function () {
  6911. base.initDialog();
  6912. });
  6913.  
  6914. document.querySelectorAll(".nav-links").forEach(function (element) {
  6915. element.innerHTML += $button
  6916. })
  6917. }
  6918. }
  6919.  
  6920. // 主代码
  6921. let main = {
  6922. async init() {
  6923. // 先加载默认设置
  6924. base.initDefaultConfig();
  6925. // 然后获取原脚本的 GreasyFork 信息,确保油小猴服务器信任
  6926. await base.get('https://gf.qytechs.cn/zh-CN/scripts/436446.json', { "referer": "https://gf.qytechs.cn/" }, 'json', '').then(res => {
  6927. base.setValue('setting_script_version', res.version);
  6928. base.setValue('setting_script_author', 'YouXiaoHou');
  6929. base.setValue('setting_script_name', res.name);
  6930. })
  6931. // 再加载网页样式
  6932. base.addPanLinkerStyle();
  6933. // 最后判断页面地址并加载对应的initPanLinker
  6934. if (/(pan|yun).baidu.com/.test(location.host)) {
  6935. baidu.initPanLinker();
  6936. baidu.removeAD();
  6937. }
  6938. if (/openapi.baidu.com\/oauth/.test(location.href)) {
  6939. baidu.initAuthorize()
  6940. }
  6941. if (/www.(aliyundrive|alipan).com/.test(location.host)) {
  6942. ali.initPanLinker();
  6943. ali.removeAD();
  6944. }
  6945. if (/cloud.189.cn/.test(location.host)) {
  6946. tianyi.initPanLinker();
  6947. tianyi.removeAD();
  6948. }
  6949. if (/pan.xunlei.com/.test(location.host)) {
  6950. xunlei.initPanLinker();
  6951. }
  6952. if (/pan.quark.cn/.test(location.host)) {
  6953. quark.initPanLinker();
  6954. quark.removeAD();
  6955. }
  6956. if (/(yun|caiyun).139.com/.test(location.host)) {
  6957. yidong.initPanLinker();
  6958. yidong.removeAD();
  6959. }
  6960. if (/www.youxiaohou.com/.test(location.host)) {
  6961. youxiaohou.initPanLinker();
  6962. }
  6963. },
  6964. async downloadConfig() {
  6965. // 定义要下载的链接数组及对应的文件名
  6966. let urlsAndFilenames = [
  6967. { url: `https://api.youxiaohou.com/config/v2/?ver=${version}&a=${author}`, filename: 'config.json' },
  6968. { url: `https://api.youxiaohou.com/config/v2/ali/?ver=${version}&a=${author}`, filename: 'ali.json' },
  6969. { url: `https://api.youxiaohou.com/config/v2/tianyi/?ver=${version}&a=${author}`, filename: 'tianyi.json' },
  6970. { url: `https://api.youxiaohou.com/config/v2/xunlei/?ver=${version}&a=${author}`, filename: 'xunlei.json' },
  6971. { url: `https://api.youxiaohou.com/config/v2/quark/?ver=${version}&a=${author}`, filename: 'quark.json' },
  6972. { url: `https://api.youxiaohou.com/config/v2/yidong/?ver=${version}&a=${author}`, filename: 'yidong.json' },
  6973. ];
  6974.  
  6975. // 发送多个 POST 请求并等待所有请求完成
  6976. let responses = await Promise.all(urlsAndFilenames.map(obj => base.post(obj.url, {}, {}, 'text')));
  6977.  
  6978. // 遍历所有响应并进行处理
  6979. responses.forEach((res, index) => {
  6980. let url = urlsAndFilenames[index].url;
  6981. let filename = urlsAndFilenames[index].filename;
  6982.  
  6983. // 解析响应内容(假设响应内容是 JSON 格式)
  6984. let panData = JSON.parse(base.decode(res));
  6985.  
  6986. // 创建 Blob 对象
  6987. let blob = new Blob([JSON.stringify(panData)], { type: 'application/json' });
  6988.  
  6989. // 下载 Blob 对象
  6990. base.blobDownload(blob, filename);
  6991. });
  6992. }
  6993. };
  6994. // 将函数暴露到全局作用域以便在控制台中调用
  6995. unsafeWindow.Panlinker = main;
  6996. main.init();
  6997. })();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址