(改)网盘直链下载助手

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

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

  1. // ==UserScript==
  2. // @name (改)网盘直链下载助手
  3. // @namespace https://github.com/syhyz1990/baiduyun
  4. // @version 1.0.9.3
  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. // @supportURL https://github.com/hmjz100/Online-disk-direct-link-download-assistant/issues
  11. // @compatible Chrome
  12. // @compatible Edge
  13. // @compatible Firefox
  14. // @compatible Safari
  15. // @compatible Opera
  16. // @require https://unpkg.com/jquery@3.6.0/dist/jquery.min.js
  17. // @require https://unpkg.com/sweetalert2@11/dist/sweetalert2.min.js
  18. // @require https://unpkg.com/js-md5@0.7.3/build/md5.min.js
  19. // @resource Swal https://unpkg.com/sweetalert2@11/dist/sweetalert2.min.css
  20. // @resource SwalDark https://unpkg.com/@sweetalert2/theme-dark@5/dark.min.css
  21. // @match *://pan.baidu.com/disk/home*
  22. // @match *://yun.baidu.com/disk/home*
  23. // @match *://pan.baidu.com/disk/timeline*
  24. // @match *://yun.baidu.com/disk/timeline*
  25. // @match *://pan.baidu.com/disk/main*
  26. // @match *://yun.baidu.com/disk/main*
  27. // @match *://pan.baidu.com/youth/pan/main*
  28. // @match *://yun.baidu.com/youth/pan/main*
  29. // @match *://pan.baidu.com/disk/base*
  30. // @match *://yun.baidu.com/disk/base*
  31. // @match *://pan.baidu.com/s/*
  32. // @match *://pan.baidu.com/aipan/*
  33. // @match *://yun.baidu.com/s/*
  34. // @match *://yun.baidu.com/aipan/*
  35. // @match *://pan.baidu.com/share/*
  36. // @match *://yun.baidu.com/share/*
  37. // @match *://openapi.baidu.com/*
  38. // @match *://www.aliyundrive.com/s/*
  39. // @match *://www.aliyundrive.com/drive*
  40. // @match *://www.alipan.com/s/*
  41. // @match *://www.alipan.com/drive*
  42. // @match *://cloud.189.cn/web/*
  43. // @match *://pan.xunlei.com/*
  44. // @match *://pan.quark.cn/*
  45. // @match *://yun.139.com/*
  46. // @match *://caiyun.139.com/*
  47. // @match *://*.youxiaohou.com/*
  48. // @connect baidu.com
  49. // @connect baidupcs.com
  50. // @connect aliyundrive.com
  51. // @connect aliyundrive.net
  52. // @connect alipan.com
  53. // @connect alicloudccp.com
  54. // @connect 189.cn
  55. // @connect xunlei.com
  56. // @connect quark.cn
  57. // @connect youxiaohou.com
  58. // @connect greasyfork.org
  59. // @connect gcore.jsdelivr.net
  60. // @connect localhost
  61. // @connect *
  62. // @run-at document-idle
  63. // @grant unsafeWindow
  64. // @grant window.close
  65. // @grant GM_xmlhttpRequest
  66. // @grant GM_setClipboard
  67. // @grant GM_setValue
  68. // @grant GM_getValue
  69. // @grant GM_deleteValue
  70. // @grant GM_openInTab
  71. // @grant GM_info
  72. // @grant GM_registerMenuCommand
  73. // @grant GM_cookie
  74. // @grant GM_getResourceText
  75. // ==/UserScript==
  76.  
  77. (function Panlinker() {
  78. 'use strict';
  79.  
  80. /*
  81. 防止代码因其他原因被执行多次
  82. 这段代码出自 Via轻插件,作者谷花泰
  83. */
  84. const key = encodeURIComponent('(改)网盘直链下载助手:主代码');
  85. if (window[key]) return;
  86. window[key] = true;
  87.  
  88. /*
  89. 网盘直链下载助手
  90. 以下代码均改自 网盘直链下载助手,作者油小猴
  91. */
  92. /* 全局参数 */
  93. let pt = '', selectList = [], params = {}, mode = '', width = '', pan = {}, color = '',
  94. doc = $(document), progress = {}, request = {}, ins = {}, idm = {}, colored = false,
  95. scriptInfo = GM_info.script,
  96. realauthor = scriptInfo.author,
  97. realname = scriptInfo.name,
  98. realversion = scriptInfo.version,
  99. manageHandler = GM_info.scriptHandler,
  100. manageVersion = GM_info.version;
  101.  
  102.  
  103. /* 设置选项 */
  104. // Shell类型(用于curl下载)
  105. let terminalType = {
  106. wc: "Microsoft Windows 命令提示符",
  107. wp: "Microsoft Windows PowerShell",
  108. lt: "Linux 终端",
  109. ls: "Linux Shell",
  110. mt: "Apple MacOS 终端",
  111. };
  112.  
  113. // 使用油小猴服务器
  114. let monkeyServer = {
  115. v1: "使用 [用油小猴服务器 V1 接口]",
  116. v2: "使用 [用油小猴服务器 V2 接口]",
  117. no: "不使用 [用 jsdelivr 连接本项目 Github 仓库]"
  118. };
  119.  
  120. // 更换 百度网盘新界面/阿里云盘/迅雷云盘/移动云盘 主题颜色
  121. let assistantTheme = {
  122. yes: "更换主题颜色",
  123. no: "不更换主题颜色"
  124. };
  125.  
  126. /* Sweet Alert 2 */
  127. // 自定义元素 Class 名(于 showMainDialog() 中)
  128. let customClass = {
  129. popup: 'pl-popup',
  130. header: 'pl-header',
  131. title: 'pl-title',
  132. closeButton: 'pl-close',
  133. content: 'pl-content',
  134. input: 'pl-input',
  135. footer: 'pl-footer'
  136. };
  137.  
  138. // Toast 提示配置
  139. let toast = Swal.mixin({
  140. toast: true,
  141. position: 'top-end',
  142. showConfirmButton: false,
  143. timer: 3500,
  144. timerProgressBar: true,
  145. showCloseButton: true,
  146. didOpen: function (toast) {
  147. toast.addEventListener('mouseenter', Swal.stopTimer);
  148. toast.addEventListener('mouseleave', Swal.resumeTimer);
  149. }
  150. });
  151.  
  152. // Toast 简易调用
  153. let message = {
  154. success: function (text) {
  155. toast.fire({ title: text, icon: 'success' });
  156. },
  157. error: function (text) {
  158. toast.fire({ title: text, icon: 'error' });
  159. },
  160. warning: function (text) {
  161. toast.fire({ title: text, icon: 'warning' });
  162. },
  163. info: function (text) {
  164. toast.fire({ title: text, icon: 'info' });
  165. },
  166. question: function (text) {
  167. toast.fire({ title: text, icon: 'question' });
  168. }
  169. };
  170.  
  171. /* 基础函数 */
  172. let base = {
  173. // 创建 GreaseMonkey 菜单
  174. registerMenuCommand() {
  175. GM_registerMenuCommand('⚙️ 设置', function () {
  176. base.showSetting();
  177. });
  178. GM_registerMenuCommand('🍃️ 美化', function () {
  179. base.showBeautify();
  180. });
  181. GM_registerMenuCommand('📃 更新', function () {
  182. base.showUpdateLog();
  183. });
  184. GM_registerMenuCommand('🛠️ 调试', function () {
  185. base.showDebug();
  186. });
  187. },
  188.  
  189. // 取消注册
  190. unRegisterInit(value) {
  191. message.warning("正在注入设置项目...");
  192. base.setValue('setting_init_code', value);
  193. base.setValue('license', value);
  194. history.go(0)
  195. },
  196.  
  197. /*-- 对象类型判断
  198. 示例:
  199. isType([]) // 输出"array"
  200. isType(123) // 输出"number"
  201. isType(null) // 输出"null"
  202. isType(new Date()) // 输出"date"
  203. */
  204. isType(obj) {
  205. return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
  206. },
  207.  
  208.  
  209. // 获取本地保存的数值(仅用于 Greasemonkey)
  210. getValue(name) {
  211. return GM_getValue(name);
  212. },
  213.  
  214. // 增改本地保存的数值(仅用于 Greasemonkey)
  215. setValue(name, value) {
  216. GM_setValue(name, value);
  217. },
  218.  
  219. // 删除本地保存的数值(仅用于 Greasemonkey)
  220. deleteValue(name) {
  221. GM_deleteValue(name);
  222. },
  223.  
  224. // 获取本地保存的数值
  225. getStorage(key) {
  226. try {
  227. return JSON.parse(localStorage.getItem(key));
  228. } catch (e) {
  229. return localStorage.getItem(key);
  230. }
  231. },
  232.  
  233. // 修改本地保存的数值
  234. setStorage(key, value) {
  235. if (this.isType(value) === 'object' || this.isType(value) === 'array') {
  236. return localStorage.setItem(key, JSON.stringify(value));
  237. }
  238. return localStorage.setItem(key, value);
  239. },
  240.  
  241. // 设置剪贴板
  242. setClipboard(text) {
  243. GM_setClipboard(text, 'text');
  244. },
  245.  
  246. // 加密成base64(先转换成URL编码)
  247. encode(str) {
  248. return btoa(unescape(encodeURIComponent(str)));
  249. },
  250.  
  251. // 从base64解密
  252. decode(str) {
  253. return decodeURIComponent(escape(atob(str)));
  254. },
  255.  
  256. // 数字补零
  257. repairTimer(i) {
  258. if (i >= 0 && i <= 9) {
  259. return "0" + i;
  260. } else {
  261. return i;
  262. }
  263. },
  264.  
  265. // 接受文件名并返回大写扩展名
  266. getExtension(name) {
  267. const reg = /(?!\.)\w+$/;
  268. if (reg.test(name)) {
  269. let match = name.match(reg);
  270. return match[0].toUpperCase();
  271. }
  272. return '';
  273. },
  274.  
  275. // 文件大小转换(以字节为单位)
  276. sizeFormat(value) {
  277. if (value === +value) {
  278. let unit = ["字节(B)", "千字节(KB)", "兆字节(MB)", "吉字节(GB)", "太字节(TB)", "拍字节(PB)", "艾字节(EB)", "泽字节(ZB)", "尧字节(YB)"];
  279. if (value === 0) {
  280. return "0字节(B)";
  281. } else {
  282. let index = Math.floor(Math.log(value) / Math.log(1024));
  283. let size = value / Math.pow(1024, index);
  284. size = size.toFixed(1);
  285. return size + unit[index];
  286. }
  287. }
  288. return '';
  289. },
  290.  
  291. // 根据数组中的每个文件名进行排序,使用 localeCompare 方法来比较中文字符串的顺序。
  292. sortByName(arr) {
  293. const handle = function () {
  294. return (a, b) => {
  295. const p1 = a.filename ? a.filename : a.server_filename;
  296. const p2 = b.filename ? b.filename : b.server_filename;
  297. return p1.localeCompare(p2, "zh-CN");
  298. };
  299. };
  300. arr.sort(handle());
  301. },
  302.  
  303. // 替换特殊字符为下划线
  304. fixFilename(name) {
  305. let replace = /[!?&|`"'*\/:<>\\]/g
  306. return name.replace(replace, '_');
  307. },
  308.  
  309. // 传递 Document Cookie
  310. getCookie(name) {
  311. let cname = name + "=";
  312. let ca = document.cookie.split(';');
  313. for (let i = 0; i < ca.length; i++) {
  314. let c = ca[i].trim();
  315. if (c.indexOf(cname) == 0) return c.substring(cname.length, c.length);
  316. }
  317. return "";
  318. },
  319.  
  320. // 接受Blob对象和文件名,然后创建临时链接指向blob对象,之后创建a标签指向临时链接和设置文件名,最后模拟点击a标签实现下载和释放临时链接
  321. blobDownload(blob, filename) {
  322. if (blob instanceof Blob) {
  323. const url = URL.createObjectURL(blob);
  324. const a = document.createElement('a');
  325. a.href = url;
  326. a.download = filename;
  327. a.click();
  328. URL.revokeObjectURL(url);
  329. }
  330. },
  331.  
  332. /* 请求 */
  333. // 使用 Post 发送请求
  334. post(url, data, headers, type, maxRetries = 3, currentRetry = 0) {
  335. if (this.isType(data) === 'object') {
  336. data = JSON.stringify(data);
  337. }
  338. return new Promise((resolve, reject) => {
  339. const sendRequest = function () {
  340. GM_xmlhttpRequest({
  341. method: "POST", url, headers, data,
  342. responseType: type || 'json',
  343. onloadstart() {
  344. console.log('【(改)网盘直链下载助手】Post(start)\n请求地址:' + url + '\n请求头部:', headers);
  345. },
  346. onload: function (res) {
  347. // 尝试格式化请求结果以方便调试
  348. if (res.response) {
  349. try {
  350. res.decodedResponse = JSON.parse(res.response);
  351. } catch (e) { }
  352. try {
  353. res.decodedResponse = JSON.parse(base.decode(res.response));
  354. } catch (e) { }
  355. }
  356. if (res.responseText) {
  357. try {
  358. res.decodedResponseText = JSON.parse(res.responseText);
  359. } catch (e) { }
  360. try {
  361. res.decodedResponseText = JSON.parse(base.decode(res.responseText));
  362. } catch (e) { }
  363. }
  364. console.log('【(改)网盘直链下载助手】Post(load)\n请求地址:' + url + '\n请求头部:', headers, '\n请求数据:' + JSON.stringify(data) + '\n请求结果:', res);
  365. type === 'blob' ? resolve(res) : resolve(res.response || res.responseText);
  366. },
  367. onerror: function (err) {
  368. if (currentRetry < maxRetries) {
  369. currentRetry++;
  370. console.error(`【(改)网盘直链下载助手】Post(error)\n请求出现错误,可能是网络问题\n5秒后将重试 (错误次数:${currentRetry}/${maxRetries})...`, err);
  371. setTimeout(function () {
  372. console.log(`【(改)网盘直链下载助手】Post(error)\n重新尝试请求...`);
  373. sendRequest(); // 重新发送请求
  374. }, 5000)
  375. } else {
  376. reject('【(改)网盘直链下载助手】Post(error)\n请求出现错误,可能是网络问题\n无法继续请求,达到最大错误次数。', err); // 达到最大重试次数,拒绝 Promise
  377. }
  378. },
  379. });
  380. };
  381. sendRequest(); // 初始请求
  382. });
  383. },
  384.  
  385. // 使用 Get 发送请求
  386. get(url, headers, type, extra, maxRetries = 3, currentRetry = 0) {
  387. return new Promise((resolve, reject) => {
  388. const sendRequest = function () {
  389. let requestObj = GM_xmlhttpRequest({
  390. method: "GET", url, headers,
  391. responseType: type || 'json',
  392. onload: function (res) {
  393. if (res.status === 204) {
  394. console.log('【(改)网盘直链下载助手】Get(load)\n\x1B[31m该请求已被某个下载工具捕获。' + (res.statusText ? ("\n\x1B[0m工具提示:\x1B[31m" + res.statusText) : "") + '\x1B[0m\n请求地址:' + url + '\n请求头部:', headers, '\n请求结果:', res);
  395. requestObj.abort();
  396. idm[extra.index] = true;
  397. return;
  398. }
  399. if (type === 'blob') {
  400. console.log('【(改)网盘直链下载助手】Get(load) Blob\n请求地址:' + url + '\n请求头部:', headers, '\n请求结果:', res);
  401. res.status === 200 && base.blobDownload(res.response, extra.filename);
  402. resolve(res);
  403. } else {
  404. // 尝试格式化请求结果以方便调试
  405. if (res.response) {
  406. try {
  407. res.decodedResponse = JSON.parse(res.response);
  408. } catch (e) { }
  409. try {
  410. res.decodedResponse = JSON.parse(base.decode(res.response));
  411. } catch (e) { }
  412. }
  413. if (res.responseText) {
  414. try {
  415. res.decodedResponseText = JSON.parse(res.responseText);
  416. } catch (e) { }
  417. try {
  418. res.decodedResponseText = JSON.parse(base.decode(res.responseText));
  419. } catch (e) { }
  420. }
  421. console.log('【(改)网盘直链下载助手】Get(load)\n请求地址:' + url + '\n请求头部:', headers, '\n请求结果:', res);
  422. resolve(res.response || res.responseText);
  423. }
  424. },
  425. onprogress: function (res) {
  426. if (extra && extra.filename && extra.index) {
  427. res.total > 0 ? progress[extra.index] = (res.loaded * 100 / res.total).toFixed(2) : progress[extra.index] = 0.00;
  428. console.log('【(改)网盘直链下载助手】Get(progress)\n\x1B[31m该请求正在进行中。' + (progress[extra.index] ? ("\n\x1B[0m下载进度:\x1B[31m" + progress[extra.index]) : "") + '\x1B[0m');
  429. }
  430. },
  431. onloadstart() {
  432. console.log('【(改)网盘直链下载助手】Get(start)\n请求地址:' + url + '\n请求头部:', headers);
  433. extra && extra.filename && extra.index && (request[extra.index] = requestObj);
  434. },
  435. onerror: function (err) {
  436. if (currentRetry < maxRetries) {
  437. currentRetry++;
  438. console.error(`【(改)网盘直链下载助手】Get(error)\n请求出现错误,可能是网络问题\n5秒后将重试 (错误次数:${currentRetry}/${maxRetries})...`, err);
  439. setTimeout(function () {
  440. console.log(`【(改)网盘直链下载助手】Get(error)\n重新尝试请求...`);
  441. sendRequest(); // 重新发送请求
  442. }, 5000)
  443. } else {
  444. reject('【(改)网盘直链下载助手】Get(error)\n请求出现错误,可能是网络问题\n无法继续请求,达到最大错误次数。', err); // 达到最大重试次数,拒绝 Promise
  445. }
  446. },
  447. });
  448. };
  449.  
  450. sendRequest(); // 初始请求
  451. });
  452. },
  453.  
  454. // 使用 Get 发送请求获取跳转后的链接
  455. getFinalUrl(url, headers, maxRetries = 3, currentRetry = 0) {
  456. return new Promise((resolve, reject) => {
  457. const sendRequest = function () {
  458. let requestObj = GM_xmlhttpRequest({
  459. method: "GET", url, headers,
  460. onloadstart() {
  461. console.log('【(改)网盘直链下载助手】Get(start) FinalUrl\n请求地址:' + url + '\n请求头部:', headers);
  462. },
  463. onload: function (res) {
  464. console.log('【(改)网盘直链下载助手】Get(load) FinalUrl\n请求地址:' + url + '\n请求头部:', headers, '\n返回结果:', res);
  465. resolve(res.finalUrl)
  466. },
  467. onerror: function (err) {
  468. if (currentRetry < maxRetries) {
  469. currentRetry++;
  470. console.error(`【(改)网盘直链下载助手】Get(error) FinalUrl\n请求出现错误,可能是网络问题\n5秒后将重试 (错误次数:${currentRetry}/${maxRetries})...`);
  471. setTimeout(function () {
  472. console.log(`【(改)网盘直链下载助手】Get(error) FinalUrl\n重新尝试请求...`);
  473. sendRequest(); // 重新发送请求
  474. }, 5000)
  475. } else {
  476. reject('【(改)网盘直链下载助手】Get(error) FinalUrl\n请求出现错误,可能是网络问题\n无法继续请求,达到最大错误次数。', err); // 达到最大重试次数,拒绝 Promise
  477. }
  478. },
  479. });
  480. };
  481. sendRequest(); // 初始请求
  482. });
  483. },
  484.  
  485. // RPC测试
  486. async rpcTest(domain, port, path, token) {
  487. return new Promise((resolve, reject) => {
  488. let rpc = { domain, port, path, token };
  489. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  490. let rpcData = {
  491. id: new Date().getTime(),
  492. jsonrpc: '2.0',
  493. method: 'system.listMethods',
  494. params: [`token:${rpc.token}`],
  495. };
  496. GM_xmlhttpRequest({
  497. method: "POST", url, headers: {}, data: JSON.stringify(rpcData),
  498. responseType: 'json',
  499. onloadstart() {
  500. console.log('【(改)网盘直链下载助手】Post(start) RPCTest\n请求地址:' + url + '\n请求内容:', rpcData);
  501. },
  502. onload: function (res) {
  503. console.log('【(改)网盘直链下载助手】Post(load) RPCTest\n请求地址:' + url + '\n请求结果:', res);
  504. if (res.response) {
  505. resolve("success");
  506. } else {
  507. resolve("fail");
  508. }
  509. },
  510. onerror: function (err) {
  511. console.error('【(改)网盘直链下载助手】Post(error) RPCTest\n请求失败', err);
  512. resolve("fail");
  513. },
  514. });
  515. });
  516. },
  517.  
  518. // 将对象转换为 URL 加密
  519. stringify(obj) {
  520. let str = '';
  521. for (var key in obj) {
  522. if (obj.hasOwnProperty(key)) {
  523. var value = obj[key];
  524. if (Array.isArray(value)) {
  525. for (var i = 0; i < value.length; i++) {
  526. str += encodeURIComponent(key) + '=' + encodeURIComponent(value[i]) + '&';
  527. }
  528. } else {
  529. str += encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&';
  530. }
  531. }
  532. }
  533. return str.slice(0, -1); // 去掉末尾的 "&"
  534. },
  535.  
  536. // 动态添加样式
  537. addStyle(id, tag, css, element, position) {
  538. tag = tag || 'style';
  539. element = element || 'body';
  540. let styleDom = document.getElementById(id);
  541. if (styleDom) styleDom.remove();
  542. let style = document.createElement(tag);
  543. style.rel = 'stylesheet';
  544. style.id = id;
  545. tag === 'style' ? style.innerHTML = css : style.href = css;
  546. if (position === "before") {
  547. $(element).prepend($(style));
  548. } else {
  549. $(element).append($(style));
  550. }
  551. },
  552.  
  553. hexToRgba(hex) {
  554. // 去掉 # 号
  555. hex = hex.replace(/^#/, '');
  556. // 如果是四位十六进制颜色值,转换为八位
  557. if (hex.length === 4) {
  558. hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2] + hex[3] + hex[3];
  559. }
  560. // 解析 RGB 分量
  561. var r = parseInt(hex.substring(0, 2), 16);
  562. var g = parseInt(hex.substring(2, 4), 16);
  563. var b = parseInt(hex.substring(4, 6), 16);
  564. var a = '';
  565. // 如果是八位十六进制颜色值,解析 alpha 通道
  566. if (hex.length === 8) {
  567. var a = 1;
  568. a = parseInt(hex.substring(6, 8), 16) / 255; // 将 alpha 值转换为 0 到 1 之间的小数
  569. a = ',' + a
  570. }
  571. // 返回 rgba 格式字符串
  572. return r + ', ' + g + ', ' + b + a;
  573. },
  574.  
  575. replaceColors(cssText, baseURI, type, colorMap) {
  576. if (!cssText) return '';
  577. var 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']
  578. colorList.forEach(function (oldColor) {
  579. cssText = cssText.replace(new RegExp(base.hexToRgba(oldColor), 'ig'), base.hexToRgba(color));
  580. cssText = cssText.replace(new RegExp(oldColor, 'ig'), color);
  581. });
  582. if (type === 'other') {
  583. // 遍历颜色映射数组,将旧颜色替换为新颜色,并添加过渡效果
  584. colorMap.forEach(function (colorPair) {
  585. var oldColor = colorPair[0];
  586. var newColor = colorPair[1];
  587. // 判断新颜色是否为 color
  588. cssText = cssText.replace(new RegExp(oldColor, 'ig'), newColor);
  589. });
  590. return cssText;
  591. }
  592. if (colorMap) {
  593. // 遍历颜色映射数组,将旧颜色替换为新颜色,并添加过渡效果
  594. colorMap.forEach(function (colorPair) {
  595. var oldColor = colorPair[0];
  596. var newColor = colorPair[1];
  597. // 判断新颜色是否为 color
  598. if (oldColor.includes("#")) {
  599. cssText = cssText.replace(new RegExp(oldColor + '(.*?)}', 'ig'), newColor + '$1; ' + 'transition: all 0.1s ease;}');
  600. } else {
  601. cssText = cssText.replace(new RegExp(oldColor, 'ig'), newColor);
  602. }
  603. });
  604. };
  605. if (baseURI) {
  606. // 替换相对路径资源为绝对路径
  607. cssText = cssText.replace(/url\((?!['"]?(?:data|https?):)['"]?([^'"\)]*)['"]?\)/ig, function (match, p1) {
  608. // 如果URL是相对路径,则将其转换为绝对路径
  609. var absoluteURL = new URL(p1, baseURI).href;
  610. return 'url(' + absoluteURL + ')';
  611. });
  612. };
  613. return cssText;
  614. },
  615.  
  616. setColors(colorMap, type) {
  617. let cssText
  618. document.querySelectorAll('link[rel="stylesheet"]').forEach(function (tag) {
  619. if (!tag.parentElement) return;
  620. // 对于link标签,异步获取其CSS内容
  621. fetch(tag.href)
  622. .then(response => response.text())
  623. .then(responseText => {
  624. let id = 'Panlinker-ColorUI-' + tag.href
  625. // 替换颜色并添加样式
  626. cssText = base.replaceColors(responseText, tag.href, type, colorMap);
  627. if (responseText === base.replaceColors(responseText, '', type, colorMap)) return;
  628. let newStyle = document.createElement('style');
  629. newStyle.id = id;
  630. newStyle.textContent = responseText;
  631. if (location.pathname.includes("youth/pan")) {
  632. base.addStyle(id, 'style', cssText, 'body', "before");
  633. tag.remove()
  634. } else {
  635. base.addStyle(id, 'style', cssText, tag.parentElement.tagName || 'body');
  636. }
  637. console.log(`【(改)网盘直链下载助手】UI\n修改 <link> 元素 <style> 元素 样式\n元素:`, tag, `\n样式:`, newStyle);
  638. });
  639. })
  640. document.querySelectorAll('[id^="Panlinker-ColorUI-"]').forEach(function (tag) {
  641. if (!tag.parentElement) return;
  642. // 替换颜色并添加样式
  643. if (
  644. tag.innerText === base.replaceColors(tag.innerText, '', type, colorMap)
  645. ) return;
  646. cssText = base.replaceColors(tag.innerText, '', type, colorMap);
  647. tag.innerText = cssText;
  648. console.log(`【(改)网盘直链下载助手】UI\n修改 Panlinker-ColorUI <style> 元素 样式\n元素:`, tag);
  649. });
  650. let count = 0;
  651. if (!colored) {
  652. base.waitForKeyElements('style:not([id^="Panlinker-"],[id^="swal-pub"],[class^="darkreader"])', function (tag) {
  653. if (!tag.parent()) return;
  654. let id = tag[0].id;
  655. // 替换颜色并添加样式
  656. if (
  657. tag.innerText === base.replaceColors(tag.innerText, '', type, colorMap)
  658. ) return;
  659. id = id ? id : `Panlinker-ColorUI-${count++}`
  660. cssText = base.replaceColors(tag.text(), '', type, colorMap);
  661. tag.attr("id", id)
  662. tag.text(cssText)
  663. console.log(`【(改)网盘直链下载助手】UI\n修改 <style> 元素 样式\n元素:`, tag[0]);
  664. })
  665. colored = true;
  666. }
  667. },
  668.  
  669. // 延迟
  670. sleep(time) {
  671. return new Promise(resolve => setTimeout(resolve, time));
  672. },
  673.  
  674. // 获取大版本
  675. getMajorVersion(version) {
  676. const [major] = (version || '').split('.');
  677. return /^\d+$/.test(major) ? major : null;
  678. },
  679.  
  680. // 查找 React 组件实例
  681. findReact(dom, traverseUp = 0) {
  682. const key = Object.keys(dom).find(key => {
  683. return key.startsWith("__reactFiber$")
  684. || key.startsWith("__reactInternalInstance$");
  685. });
  686. const domFiber = dom[key];
  687. if (domFiber == null) return null;
  688.  
  689. if (domFiber._currentElement) {
  690. let compFiber = domFiber._currentElement._owner;
  691. for (let i = 0; i < traverseUp; i++) {
  692. compFiber = compFiber._currentElement._owner;
  693. }
  694. return compFiber._instance;
  695. }
  696.  
  697. const GetCompFiber = fiber => {
  698. let parentFiber = fiber.return;
  699. while (typeof parentFiber.type == "string") {
  700. parentFiber = parentFiber.return;
  701. }
  702. return parentFiber;
  703. };
  704. let compFiber = GetCompFiber(domFiber);
  705. for (let i = 0; i < traverseUp; i++) {
  706. compFiber = GetCompFiber(compFiber);
  707. }
  708. return compFiber.stateNode || compFiber;
  709. },
  710.  
  711. // 初始化设置项目
  712. initDefaultConfig() {
  713. let value = [
  714. // RPC 设置
  715. {
  716. name: 'setting_rpc_domain',
  717. value: 'http://localhost'
  718. }, {
  719. name: 'setting_rpc_port',
  720. value: '16800'
  721. }, {
  722. name: 'setting_rpc_path',
  723. value: '/jsonrpc'
  724. }, {
  725. name: 'setting_rpc_token',
  726. value: ''
  727. }, {
  728. name: 'setting_rpc_dir',
  729. value: 'D:\\Downloads\\'
  730. },
  731. // 杂项
  732. {
  733. name: 'setting_terminal_type',
  734. value: 'wc'
  735. }, {
  736. name: 'setting_theme_color',
  737. value: '#574AB8'
  738. }, {
  739. name: 'setting_init_code',
  740. value: ''
  741. }, {
  742. name: 'license',
  743. value: ''
  744. },
  745. // 额外
  746. {
  747. name: 'setting_youxiaohou_server',
  748. value: 'v2'
  749. }, {
  750. name: 'setting_baidu_theme',
  751. value: 'no'
  752. }, {
  753. name: 'setting_ali_theme',
  754. value: 'no'
  755. }, {
  756. name: 'setting_tianyi_theme',
  757. value: 'no'
  758. }, {
  759. name: 'setting_xunlei_theme',
  760. value: 'no'
  761. }, {
  762. name: 'setting_quark_theme',
  763. value: 'no'
  764. }, {
  765. name: 'setting_yidong_theme',
  766. value: 'no'
  767. }];
  768.  
  769. value.forEach(function (v) {
  770. // 没有对应的项目就添加上项目
  771. if (!base.getValue(v.name)) base.setValue(v.name, v.value);
  772. });
  773. },
  774.  
  775. // 设置界面
  776. showSetting() {
  777. let dom = ''
  778. dom += `<div style="text-align: center;">带星号的设置项目将在网页刷新后生效</div>`
  779. 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>`;
  780. 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>`;
  781. 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>`;
  782. 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>`;
  783. 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>`;
  784. 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>`;
  785. 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>`;
  786.  
  787. dom += `<label class="pl-setting-label"><div class="pl-label">终端类型</div><select class="swal2-select pl-input listener-terminal">`;
  788. Object.keys(terminalType).forEach(k => {
  789. dom += `<option value="${k}" ${base.getValue('setting_terminal_type') === k ? 'selected' : ''}>${terminalType[k]}</option>`;
  790. });
  791. dom += `</select></label>`;
  792. 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>`;
  793.  
  794. dom += `<label class="pl-setting-label"><div class="pl-label">使用油小猴服务器*</div><select class="swal2-select pl-input listener-youxiaohou-server">`;
  795. Object.keys(monkeyServer).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_youxiaohou_server') === value ? 'selected' : ''}>${monkeyServer[value]}</option>`; });
  796. dom += `</select></label>`;
  797.  
  798. dom += `<button type="button" style="margin-top: 30px;" class="pl-button-mini swal2-deny swal2-styled listener-register">熄灭已经点亮的按钮*</button>`
  799.  
  800. dom = '<div>' + dom + '</div>';
  801.  
  802. Swal.fire({
  803. title: '助手设置',
  804. html: dom,
  805. icon: 'info',
  806. iconHtml: '⚙︎',
  807. allowOutsideClick: false,
  808. showCloseButton: true,
  809. showConfirmButton: false,
  810. heightAuto: false,
  811. scrollbarPadding: false,
  812. footer: pan.footer,
  813. });
  814. doc.on('click', '.listener-register', async function (e) {
  815. base.unRegisterInit(111111);
  816. });
  817. doc.on('click', '.listener-rpc-test', async function (e) {
  818. e.preventDefault();
  819. let domain = base.getValue('setting_rpc_domain'),
  820. port = base.getValue('setting_rpc_port'),
  821. path = base.getValue('setting_rpc_path'),
  822. token = base.getValue('setting_rpc_token');
  823. if (e.target.innerHTML !== "测试") return;
  824. e.target.innerHTML = "等待";
  825. e.target.style.opacity = 0.9;
  826. let result = await base.rpcTest(domain, port, path, token);
  827. if (result === "success") {
  828. e.target.innerHTML = "成功";
  829. e.target.style.backgroundColor = "#52c41a";
  830. } else {
  831. e.target.innerHTML = "失败";
  832. e.target.style.backgroundColor = "#cb1616";
  833. }
  834. e.target.style.opacity = "";
  835. setTimeout(function () {
  836. e.target.innerHTML = "测试";
  837. e.target.style.backgroundColor = "";
  838. }, 3000)
  839. });
  840. doc.on('input', '.listener-rpc-domain', async function (e) {
  841. base.setValue('setting_rpc_domain', e.target.value);
  842. document.getElementById("pl-rpcDomain").innerHTML = e.target.value;
  843. });
  844. doc.on('input', '.listener-rpc-port', async function (e) {
  845. base.setValue('setting_rpc_port', e.target.value);
  846. document.getElementById("pl-rpcPort").innerHTML = e.target.value;
  847. });
  848. doc.on('input', '.listener-rpc-path', async function (e) {
  849. base.setValue('setting_rpc_path', e.target.value);
  850. document.getElementById("pl-rpcPath").innerHTML = e.target.value;
  851. });
  852. doc.on('input', '.listener-rpc-token', async function (e) {
  853. base.setValue('setting_rpc_token', e.target.value);
  854. });
  855. doc.on('input', '.listener-rpc-dir', async function (e) {
  856. base.setValue('setting_rpc_dir', e.target.value);
  857. });
  858. doc.on('change', '.listener-terminal', async function (e) {
  859. base.setValue('setting_terminal_type', e.target.value);
  860. });
  861. doc.on('change', '.listener-youxiaohou-server', async function (e) {
  862. base.setValue('setting_youxiaohou_server', e.target.value);
  863. });
  864. },
  865.  
  866. // 美化界面
  867. showBeautify() {
  868. let dom = '',
  869. btn = '',
  870. 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'],
  871. 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/>罗兰紫'];
  872. dom += `<div style="text-align: center;">带星号的美化项目将在网页刷新后生效</div>`
  873.  
  874. colorList.forEach((v, i) => {
  875. btn += `<div style="background: ${v};border: 1px solid ${v}" class="pl-color-box ${v === base.getValue('setting_theme_color') ? 'listener-color' : 'listener-color'}">
  876. <div data-color="${v}" class="pl-mask">${colorNameList[i]} ${v === base.getValue('setting_theme_color') ? '<span id="pl-thisColor">(当前)</span>' : ''}</div>
  877. </div>`;
  878. });
  879.  
  880. dom += `<label class="pl-setting-label"><div class="pl-label">主题颜色</div> <div class="pl-color">${btn}</div></label>`;
  881.  
  882. dom += `<label class="pl-setting-label"><div class="pl-label">[百度网盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-baidu-theme">`;
  883. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_baidu_theme') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  884. dom += `</select></label>`;
  885. dom += `<label class="pl-setting-label" style="padding-top:0;flex-direction:row-reverse;text-align:right;"><span>旧版页面会美化,新版页面则是更换主题色👆</span></label>`;
  886.  
  887. dom += `<label class="pl-setting-label"><div class="pl-label">[阿里云盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-ali-theme">`;
  888. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_ali_theme') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  889. dom += `</select></label>`;
  890.  
  891. dom += `<label class="pl-setting-label"><div class="pl-label">[天翼云盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-tianyi-theme">`;
  892. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_tianyi_theme') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  893. dom += `</select></label>`;
  894.  
  895. dom += `<label class="pl-setting-label"><div class="pl-label">[迅雷云盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-xunlei-theme">`;
  896. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_xunlei_theme') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  897. dom += `</select></label>`;
  898.  
  899. dom += `<label class="pl-setting-label"><div class="pl-label">[夸克网盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-quark-theme">`;
  900. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_quark_theme') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  901. dom += `</select></label>`;
  902.  
  903. dom += `<label class="pl-setting-label"><div class="pl-label">[移动云盘]<br/>更换界面为主题颜色*</div><select class="swal2-select pl-input listener-yidong-theme">`;
  904. Object.keys(assistantTheme).forEach(value => { dom += `<option value="${value}" ${base.getValue('setting_yidong_theme') === value ? 'selected' : ''}>${assistantTheme[value]}</option>`; });
  905. dom += `</select></label>`;
  906.  
  907. dom = '<div>' + dom + '</div>';
  908.  
  909. Swal.fire({
  910. title: '助手美化',
  911. html: dom,
  912. icon: 'success',
  913. iconHtml: '🍃︎',
  914. allowOutsideClick: false,
  915. showCloseButton: true,
  916. showConfirmButton: false,
  917. heightAuto: false,
  918. scrollbarPadding: false,
  919. 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>',
  920. });
  921. doc.on('click', '.listener-color', async function (e) {
  922. if (e.target.dataset.color) {
  923. if (document.getElementById("pl-thisColor")) {
  924. document.getElementById("pl-thisColor").remove();
  925. }
  926. e.target.innerHTML += '<span id="pl-thisColor">(当前)</span>';
  927. base.setValue('setting_theme_color', e.target.dataset.color);
  928. base.addPanLinkerStyle();
  929. }
  930. });
  931. doc.on('change', '.listener-baidu-theme', async function (e) {
  932. base.setValue('setting_baidu_theme', e.target.value);
  933. });
  934. doc.on('change', '.listener-ali-theme', async function (e) {
  935. base.setValue('setting_ali_theme', e.target.value);
  936. });
  937. doc.on('change', '.listener-tianyi-theme', async function (e) {
  938. base.setValue('setting_tianyi_theme', e.target.value);
  939. });
  940. doc.on('change', '.listener-xunlei-theme', async function (e) {
  941. base.setValue('setting_xunlei_theme', e.target.value);
  942. });
  943. doc.on('change', '.listener-quark-theme', async function (e) {
  944. base.setValue('setting_quark_theme', e.target.value);
  945. });
  946. doc.on('change', '.listener-yidong-theme', async function (e) {
  947. base.setValue('setting_yidong_theme', e.target.value);
  948. });
  949. },
  950.  
  951. // 调试信息界面
  952. showDebug() {
  953. let debugInfo = '';
  954. let server = '';
  955. if (base.getValue('setting_youxiaohou_server') === 'v1') {
  956. server = `https://api.youxiaohou.com/config/?ver=${version}&a=${author}`;
  957. } else if (base.getValue('setting_youxiaohou_server') === 'v2') {
  958. server = `https://api.youxiaohou.com/config/v2/?ver=${version}&a=${author}`;
  959. } else if (base.getValue('setting_youxiaohou_server') === "no") {
  960. server = `https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/config.json?version=${realversion}`;
  961. } else {
  962. server = `https://gcore.jsdelivr.net/gh/hmjz100/Online-disk-direct-link-download-assistant@main/config/config.json?version=${realversion}`;
  963. base.setValue('setting_youxiaohou_server', 'v2');
  964. }
  965. debugInfo += `<span>以下内容均为脚本自检信息<br/>本页面仅作为调试使用<span>`;
  966. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[外置]<br/>管理器名称</div>${manageHandler ? manageHandler : "无法获取"}</label>`;
  967. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[外置]<br/>管理器版本</div>${manageVersion ? manageVersion : "无法获取"}</label>`;
  968. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[内置]<br/>信息服务器</div>[${base.getValue('setting_youxiaohou_server')}]${server ? server : "无法获取"}</label>`;
  969. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[内置]<br/>脚本名称</div>${realname ? realname : "无法获取"}</label>`;
  970. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[内置]<br/>脚本版本</div>${realversion ? realversion : "无法获取"}</label>`;
  971. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[内置]<br/>脚本作者</div>${realauthor ? realauthor : "无法获取"}</label>`;
  972. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[上报]<br/>脚本版本</div>${version ? version : "无法获取"}</label>`;
  973. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[上报]<br/>脚本作者</div>${author ? author : "无法获取"}</label>`;
  974.  
  975. if (pan.num) {
  976. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>初始化暗号</div>${pan.num ? pan.num : "无法获取"}</label>`;
  977. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>初始化协议</div>${pan.license ? pan.license : "无法获取"}</label>`;
  978. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>UA代理</div><code>${pan.ua ? pan.ua : "此网站暂无"}</code></label>`;
  979. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>公众号码</div>${pan.img ? `${pan.img}<img src="${pan.img}"></img>` : "无法获取"}</label>`;
  980. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>万能助手</div>${pan.assistant ? pan.assistant : "此网站暂无"}</label>`;
  981. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>网盘CDN</div>${pan.mirror ? pan.mirror : "此网站暂无"}</label>`;
  982. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>RPC管理</div>${pan.d ? pan.d : "无法获取"}</label>`;
  983. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>IDM介绍</div>${pan.idm ? pan.idm : "此网盘暂无"}</label>`;
  984. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>提示文本</div><code>${JSON.stringify(pan.init) ? JSON.stringify(pan.init) : "无法获取"}</code></label>`;
  985. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>网盘接口</div><code>${JSON.stringify(pan.pcs) ? JSON.stringify(pan.pcs) : "无法获取"}</code></label>`;
  986. debugInfo += `<label class="pl-setting-label"><div class="pl-label">[下发]<br/>Toast页脚</div>${pan.footer ? pan.footer : "此网站暂无"}</label>`;
  987. } else {
  988. debugInfo += `<label>上报的服务器请求未完成,部分信息未能显示</label>`;
  989. }
  990.  
  991.  
  992. debugInfo = '<div>' + debugInfo + '</div>';
  993.  
  994. Swal.fire({
  995. icon: 'info',
  996. title: '调试信息',
  997. html: debugInfo,
  998. allowOutsideClick: false,
  999. showCloseButton: true,
  1000. heightAuto: false,
  1001. scrollbarPadding: false,
  1002. confirmButtonText: '关闭'
  1003. });
  1004. },
  1005.  
  1006. // 更新日志界面
  1007. showUpdateLog() {
  1008. Swal.fire({
  1009. icon: 'info',
  1010. title: '更新日志',
  1011. html: `<div style="text-align: left;">
  1012. V1.0.9.3<br/>1、若网盘不支持在分享中下载,将仅显示保存网盘按钮;<br/>2、优化下载界面,支持选择 Iframe Blob 的方式来下载文件,增加按钮的提示文本;<br/>3、优化 CSS 样式,统一了 SweetAlert2 按钮样式,同时适配了 Dark Reader 插件,界面更协调;<br/>4、支持修改油小猴网站主题色;<br/>5、原有主题相关设置现已移动至助手美化页面中。<br/><br/>
  1013. V1.0.9.2<br/>1、修复使用API下载时有可能会导致IDM无限弹窗的Bug。<br/><br/>
  1014. V1.0.9.1<br/>1、修复在百度网盘旧版下脚本无法删除元素的Bug。<br/><br/>
  1015. V1.0.9<br/>1、跟进官方V6.2.7,修复因无法进行百度授权而导致获取直链报错 9019 Bug。<br/><br/>
  1016. V1.0.8.9<br/>1、跟进官方V6.2.3,优化保存到网盘提示,修复阿里云盘、移动云盘失效的问题;<br/>2、优化修改网盘主题的代码,减少对页面的破坏。<br/><br/>
  1017. V1.0.8.8<br/>1、修复下载菜单字体过小的Bug。<br/><br/>
  1018. V1.0.8.7<br/>1、修复在阿里云盘分享页面下点击“未点亮”按钮时没有任何反应的Bug;<br/>2、更新并优化网盘界面精简规则;<br/>3、支持更换 百度网盘、阿里云盘、迅雷云盘、夸克网盘、移动云盘 界面的主题颜色。<br/><br/>
  1019. V1.0.8.6<br/>1、新增移动云盘会员中心页面,可在网盘中点击“会员中心”按钮查看(但无法使用第三方支付)。<br/><br/>
  1020. V1.0.8.5<br/>1、跟进官方V6.1.6,修复迅雷网盘分享页面无法选中文件,修复移动云盘无法判断页面。<br/><br/>
  1021. V1.0.8.4<br/>1、修复因重复绑定按钮而导致命令重复执行的Bug;<br/>2、优化调试信息界面排版;<br/>3、移除对百度网盘手机网页版的支持。<br/><br/>
  1022. V1.0.8.3<br/>1、适配阿里云盘新域名alipan.com。<br/><br/>
  1023. V1.0.8.2<br/>1、更换新图标。<br/><br/>
  1024. V1.0.8.1<br/>1、修复因重复绑定按钮而导致RPC下载会发送多条下载请求的Bug;<br/>2、选择不使用油小猴服务器时,“用ghproxy连接Github仓库”更换为“用jsdelivr连接Github仓库”;<br/>3、跟进官方V6.1.4版本,修复移动网盘无法获取链接,支持阿里云盘新域名alipan.com。<br/><br/>
  1025. V1.0.8<br/>1、修复迅雷网盘无法勾选文件。<br/><br/>
  1026. V1.0.7.9<br/>1、更新精简网盘元素匹配规则,防止因通知横条而导致不能点到“API下载”以下的按钮。<br/><br/>
  1027. V1.0.7.8<br/>1、跟进官方V6.1.2,加入V2接口。<br/>2、修复百度网盘下载时因为获取不到accessToken而一直转圈。<br/><br/>
  1028. V1.0.7.7<br/>1、修复百度网盘的按钮会因为主题不同而被改变颜色的Bug;<br/>2、更新夸克网盘按钮与界面。<br/><br/>
  1029. V1.0.7.6<br/>1、修复“注入”功能;<br/>2、黑暗模式支持随设置热切换。<br/><br/>
  1030. V1.0.7.5<br/>1、修复阿里云盘下载逻辑;<br/>2、精简代码;<br/>3、支持深色模式;<br/>4、修改部分提示文本;<br/>5、修改部分CSS;<br/>6、设置可测试RPC连接。<br/><br/>
  1031. V1.0.7.4<br/>1、优化下载逻辑;<br/>2、修复阿里云盘无法使用API下载。<br/><br/>
  1032. V1.0.7.3<br/>1、如果出现网络请求错误时支持自动重新请求;<br/>2、可选择是否使用油小猴服务器。<br/><br/>
  1033. V1.0.7.2<br/>1、修复使用RPC下载时会重复发送链接的Bug。<br/><br/>
  1034. V1.0.7.1<br/>1、[实验功能,不影响正常使用]支持百度网盘手机网页版,勾选文件后可在顶栏找到“下载助手”按钮。<br/><br/>
  1035. V1.0.7<br/>1、重构夸克网盘、阿里云盘按钮。<br/><br/>
  1036. V1.0.6.9<br/>1、下载窗口加入关闭按钮。<br/><br/>
  1037. V1.0.6.8<br/>1、修复夸克网盘按钮错位。<br/><br/>
  1038. V1.0.6.7<br/>1、将百度网盘界面修改为主题色,可在设置选择是否修改;<br/>2、增加主题色名称,更改部分内容颜色;<br/>3、移动云盘API下载支持批量复制;<br/>4、优化控制台输出结果;<br/>5、百度网盘API下载不使用IDM时可以显示剩余时间;<br/>6、“取消点亮按钮”按钮的位置现已移动到设置页面。<br/>7homo特有的彩蛋又回来力(喜)。<br/><br/>
  1039. V1.0.6.6<br/>1、修复暗号错误。<br/><br/>
  1040. V1.0.6.5<br/>1、修复即使输入正确暗号也不能成功点亮按钮的服务器错误。<br/><br/>
  1041. V1.0.6.4<br/>1、跟进官方V6.1.1版本,修复阿里云盘获取下载链接时的问题。<br/><br/>
  1042. V1.0.6.3<br/>1、照顾小屏幕用户,将始终显示复制全部链接的按钮;<br/>2、增加取消下载时的动画。<br/><br/>
  1043. V1.0.6.2<br/>1、修复部分界面错位,实现CSS内置;<br/>2、百度网盘界面将变得更加简洁。<br/><br/>
  1044. V1.0.6.1<br/>1、新增百度云盘API下载支持复制链接;<br/>2、为了照顾手机浏览器用户,增大项目之间间隙,新增隐藏IDM提示选项,可在助手设置中启用;<br/>3、修改CSS,界面会出现更多的主题色;<br/>4、支持在游小猴官网查看暗号;<br/>5、修复部分语法错误。<br/><br/>
  1045. V1.0.6<br/>1、修复了打开阿里云盘分享连接时因下载移动端广告导致只能点击API下载;<br/>2、跟进官方6.0.4版本,修复夸克网盘获取下载链接失效、支持移动云盘。<br/><br/>
  1046. V1.0.5.5<br/>1、感谢<a href="https://github.com/Night-stars-1">Night-stars-1</a>的帮助,修复因为原作者服务器导致的初始化暗号识别错误;<br/>2、修改一些文本以及提供给服务器的信息。<br/><br/>
  1047. V1.0.5.4<br/>1、小修小改css,让主题色出现在更多地方;<br/>2、修改下载链接获取失败的提示;<br/>3、增加更多的主题色,可在助手设置查看;<br/>4homo彩蛋被删去力(悲)。<br/><br/>
  1048. V1.0.5.3<br/>1、修啦修啦,阿里云盘可以摸到下载菜单了。<br/><br/>
  1049. V1.0.5.2<br/>1、增加脚本信息菜单(没有用);<br/>2、优化阿里云盘显示svg图片;<br/>3、修改弹窗按钮颜色。<br/><br/>
  1050. V1.0.5.1<br/>1、修复在切换按钮主题后夸克网盘不能正常显示按钮。<br/><br/>
  1051. V1.0.5<br/>1、跟进官方V5.0.4版本;<br/>2、小改动,照着官方版本更正文件名称检测;<br/>3、保留彩蛋,但必须舍弃官方暗号。<br/><br/>
  1052. V1.0.4<br/>大改!<br/>1、修复了原作者留下的夸克网盘切换文件夹就多一个“下载助手”按钮的大BUG;<br/>2、终于来了,在下载菜单增加“助手设置”“更新日志”按钮;<br/>【再也不用点进油猴管理再进设置了(保留油猴管理内设置)】<br/>3、修改阿里云盘和夸克网盘下载助手按钮样式;<br/>4、增加“取消点亮按钮”油猴菜单;<br/>5、修改部分css,使其与选择的主题更贴切。<br/><br/>
  1053. V1.0.3<br/>1、增加一个小彩蛋; 提示:<br/>homo(需在未点亮按钮状态触发)<br/>【需要重新恢复按钮为未点亮状态请进入 已安装脚本->编辑->开发者->重置到出厂->确定】<br/>2、修改/增加默认主题色。<br/><br/>
  1054. V1.0.2<br/>1、修改并加宽界面,调整部分css,使Sweetalert2界面更美观,更与原版相近;<br/>2、修改部分提示文字,使文字更容易复制。 <br/><br/>
  1055. V1.0.1<br/>1、去除更新提示;<br/>2、更新Sweetalert211版本;<br/>3、部分CDN节点更换为jsdelivr。<br/><br/>
  1056. V1.0.0<br/>1、增加“注入”功能(bushi);<br/>2、去除广告。
  1057. </div>`,
  1058. allowOutsideClick: false,
  1059. showCloseButton: false,
  1060. heightAuto: false,
  1061. scrollbarPadding: false,
  1062. confirmButtonText: '我已阅',
  1063. });
  1064. },
  1065.  
  1066. // 创建浮动标签
  1067. createTip() {
  1068. // 添加提示框到 body
  1069. $('body').append('<div class="pl-tooltip"></div>');
  1070.  
  1071. // 监听所有带有 .listener-tip 类的元素的鼠标移动事件
  1072. $(document).on('mousemove', '.listener-tip', function (e) {
  1073. // 获取提示文字
  1074. let tip = e.currentTarget.dataset.title || `${e.currentTarget.innerText} <span style="margin-left: 10px;color: ${color}">${e.currentTarget.dataset.size}</span>`;
  1075.  
  1076. // 设置提示框的位置并使用 fadeIn() 渐变显示
  1077. $('.pl-tooltip').html(tip).css({
  1078. 'left': e.pageX + 10 + 'px',
  1079. 'top': e.pageY + 20 + 'px' // 增加一些间距
  1080. }).show();
  1081. });
  1082.  
  1083. $(document).on('mouseleave', '.listener-tip, pl-tooltip', function (e) {
  1084. $('.pl-tooltip').hide();
  1085. });
  1086. },
  1087.  
  1088.  
  1089. // 创建加载弹窗
  1090. createLoading() {
  1091. return $('<div class="pl-loading"><div class="pl-loading-box"><div><div></div><div></div></div></div></div>');
  1092. },
  1093.  
  1094. // 创建下载用的隐藏 iframe
  1095. createDownloadIframe() {
  1096. let $div = $('<div style="padding:0;margin:0;display:block"></div>');
  1097. let $iframe = $('<iframe src="javascript:;" id="downloadIframe" style="display:none"></iframe>');
  1098. $div.append($iframe);
  1099. $('body').append($div);
  1100. },
  1101.  
  1102. // 获取镜像列表
  1103. getMirrorList(link, mirror, thread = 2) {
  1104. let host = new URL(link).host;
  1105. let mirrors = [];
  1106. for (let i = 0; i < mirror.length; i++) {
  1107. for (let j = 0; j < thread; j++) {
  1108. let item = link.replace(host, mirror[i]) + '&'.repeat(j);
  1109. mirrors.push(item);
  1110. }
  1111. }
  1112. return mirrors.join('\n');
  1113. },
  1114.  
  1115. // 监听元素出现并执行回调
  1116. listenElement(element, callback) {
  1117. let checkInterval = 1000; // 检查元素的间隔时间(毫秒)
  1118. let wasElementFound = false; // 用于跟踪元素是否之前已经找到
  1119.  
  1120. function checkElement() {
  1121. if (document.querySelector(element)) {
  1122. wasElementFound = true;
  1123. callback();
  1124. } else if (wasElementFound) {
  1125. wasElementFound = false; // 元素消失后重置标志
  1126. }
  1127.  
  1128. setTimeout(checkElement, checkInterval);
  1129. }
  1130. checkElement();
  1131. },
  1132.  
  1133. // 创建基础样式
  1134. addPanLinkerStyle() {
  1135. color = base.getValue('setting_theme_color');
  1136.  
  1137. let swalcss = `
  1138. .swal2-styled{transition: all 0.2s ease;}
  1139. .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 }
  1140. .swal2-styled.swal2-confirm{border:0;border-radius:.25em;background:initial;background-color:${color};color:#fff;font-size:1em}
  1141. .swal2-styled.swal2-confirm:hover,.swal2-styled.swal2-deny:hover{opacity:0.8;background-image:none!important}
  1142. .swal2-styled.swal2-confirm:focus{box-shadow:0 0 0 3px ${color}80}
  1143. .swal2-styled.swal2-deny:focus{box-shadow:0 0 0 3px #dc374180}
  1144. .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}
  1145. .swal2-timer-progress-bar{width:100%;height:.25em;background:${color}33 }
  1146. .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}
  1147. .swal2-progress-steps .swal2-progress-step.swal2-active-progress-step{background:${color} }
  1148. .swal2-progress-steps .swal2-progress-step-line{z-index:10;flex-shrink:0;width:2.5em;height:.4em;margin:0 -1px;background:${color}}
  1149. .swal2-popup {padding:1.25em 0 1.25em;flex-direction:column}
  1150. .swal2-close {position:absolute;top:1px;right:1px;transition: all 0.2s ease;}
  1151. div:where(.swal2-container) .swal2-html-container{padding: 1.3em 1.3em 0.3em;}
  1152. div:where(.swal2-container) button:where(.swal2-close):hover {color:${color}!important;font-size:60px!important}
  1153. `;
  1154.  
  1155. // 先监听颜色方案变化 Panlinker-SweetAlert2-Default
  1156. window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
  1157. if (e.matches) {
  1158. // 切换到暗色主题
  1159. base.addStyle('swal-pub-style', 'style', GM_getResourceText('SwalDark'));
  1160. } else {
  1161. // 切换到浅色主题
  1162. base.addStyle('swal-pub-style', 'style', GM_getResourceText('Swal'));
  1163. }
  1164. base.addStyle('Panlinker-SweetAlert2-User', 'style', swalcss);
  1165. });
  1166. // 再修改主题 Panlinker-SweetAlert2-Default
  1167. if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  1168. // 切换到暗色主题
  1169. base.addStyle('swal-pub-style', 'style', GM_getResourceText('SwalDark'));
  1170. } else {
  1171. // 切换到浅色主题
  1172. base.addStyle('swal-pub-style', 'style', GM_getResourceText('Swal'));
  1173. }
  1174. base.addStyle('Panlinker-SweetAlert2-User', 'style', swalcss);
  1175.  
  1176. let uicss = `
  1177. ::-webkit-scrollbar {
  1178. width: 8px;
  1179. height: 8px;
  1180. transition: all 0.2s ease;
  1181. }
  1182.  
  1183. ::-webkit-scrollbar-track {
  1184. border-radius: 10px;
  1185. background: #fff;
  1186. }
  1187.  
  1188. ::-webkit-scrollbar-thumb,
  1189. ::-webkit-scrollbar-thumb:hover {
  1190. border-radius: 10px;
  1191. }
  1192.  
  1193. ::-webkit-scrollbar-thumb {
  1194. background-color: ${color}90 !important
  1195. }
  1196.  
  1197. ::-webkit-scrollbar-thumb:hover {
  1198. background-color: ${color}D0 !important
  1199. }
  1200.  
  1201. .swal2-popup {
  1202. font-size: 16px
  1203. }
  1204.  
  1205. .pl-a {
  1206. color: ${color};
  1207. }
  1208.  
  1209. .pl-a:hover {
  1210. color: ${color}90;
  1211. }
  1212.  
  1213. .pl-popup {
  1214. font-size: 12px;
  1215. width: 90%;
  1216. }
  1217.  
  1218. .pl-popup a:not(.pl-btn-primary) {
  1219. color: ${color};
  1220. }
  1221.  
  1222. .pl-popup a:hover:not(.pl-btn-primary) {
  1223. color: ${color}90;
  1224. }
  1225.  
  1226. .pl-header {
  1227. padding: 0;
  1228. align-items: flex-start;
  1229. border-bottom: 1px solid #eee;
  1230. margin: 0 0 10px;
  1231. padding: 0 0 5px;
  1232. }
  1233.  
  1234. .pl-title {
  1235. font-size: 16px;
  1236. line-height: 1;
  1237. white-space: nowrap;
  1238. text-overflow: ellipsis;
  1239. }
  1240.  
  1241. .pl-content {
  1242. padding: 0;
  1243. font-size: 12px;
  1244. }
  1245.  
  1246. .pl-main {
  1247. background-color:${color}15;
  1248. overflow: auto;
  1249. border-radius: 10px;
  1250. max-height:calc(${document.documentElement.clientHeight}px - 250px);
  1251. }
  1252.  
  1253. .pl-footer {
  1254. font-size: 15px;
  1255. margin-top: 10px;
  1256. padding-top: 5px;
  1257. color: #f56c6c;
  1258. text-align: center;
  1259. display: flex !important;
  1260. align-items: center;
  1261. justify-content: center;
  1262. }
  1263.  
  1264. .pl-item {
  1265. display: flex;
  1266. align-items: center;
  1267. line-height: 22px;
  1268. height: 50px;
  1269. background-color: ${color}30;
  1270. border-radius: 5px;
  1271. margin: 8px 6px;
  1272. }
  1273.  
  1274. .pl-item-name {
  1275. flex: 0 0 170px;
  1276. text-align: left;
  1277. margin: 6px;
  1278. overflow: hidden;
  1279. white-space: nowrap;
  1280. text-overflow: ellipsis;
  1281. cursor: default;
  1282. height: 30px;
  1283. }
  1284.  
  1285. .pl-item-link {
  1286. flex: 1;
  1287. text-align: left;
  1288. white-space: nowrap;
  1289. text-overflow: ellipsis;
  1290. cursor: pointer;
  1291. overflow: hidden;
  1292. }
  1293.  
  1294. .pl-item-tip {
  1295. display: flex;
  1296. justify-content: space-between;
  1297. flex: 1;
  1298. }
  1299.  
  1300. .pl-ext {
  1301. display: inline-block;
  1302. width: 44px;
  1303. background: #999;
  1304. color: #fff;
  1305. height: 16px;
  1306. line-height: 16px;
  1307. font-size: 12px;
  1308. border-radius: 3px;
  1309. }
  1310.  
  1311. .pl-retry {
  1312. padding: 3px 10px;
  1313. background: #cc3235;
  1314. color: #fff;
  1315. border-radius: 3px;
  1316. cursor: pointer;
  1317. }
  1318.  
  1319. .pl-browserdownload {
  1320. padding: 3px 10px;
  1321. background: ${color};
  1322. color: #fff;
  1323. border-radius: 3px;
  1324. cursor: pointer;
  1325. }
  1326.  
  1327. .pl-item-progress {
  1328. display: flex;
  1329. flex: 1;
  1330. align-items: center
  1331. }
  1332.  
  1333. .pl-progress {
  1334. display: inline-block;
  1335. vertical-align: middle;
  1336. width: 100%;
  1337. box-sizing: border-box;
  1338. line-height: 1;
  1339. position: relative;
  1340. height: 20px;
  1341. flex: 1
  1342. }
  1343.  
  1344. .pl-progress-outer {
  1345. height: 20px;
  1346. border-radius: 100px;
  1347. background-color: #c1c1c1a1;
  1348. overflow: hidden;
  1349. position: relative;
  1350. vertical-align: middle;
  1351. }
  1352.  
  1353. .pl-progress-inner {
  1354. position: absolute;
  1355. left: 0;
  1356. top: 0;
  1357. background-color: ${color};
  1358. border-radius: 100px;
  1359. line-height: 1;
  1360. white-space: nowrap;
  1361. transition: width .6s ease;
  1362. height: 20px;
  1363. display: inline-flex;
  1364. text-align: center;
  1365. align-items: center
  1366. }
  1367.  
  1368. .pl-progress-inner-text {
  1369. display: inline-block;
  1370. vertical-align: middle;
  1371. cursor: default;
  1372. color: #ffffff;
  1373. font-size: 12px;
  1374. margin: 0 5px;
  1375. height: 20px;
  1376. width: 100%;
  1377. }
  1378.  
  1379. .pl-progress-tip {
  1380. flex: 1;
  1381. text-align: right
  1382. }
  1383.  
  1384. .pl-progress-how {
  1385. flex: 0 0 100px;
  1386. background: #ddd;
  1387. border-radius: 3px;
  1388. margin-left: 10px;
  1389. cursor: pointer;
  1390. text-align: center;
  1391. color: #000;
  1392. }
  1393.  
  1394. .pl-progress-back {
  1395. background: #717171;
  1396. cursor: pointer;
  1397. margin: 6px 6px;
  1398. font-size: 12px;
  1399. border: 0;
  1400. border-radius: 4px;
  1401. color: #ffffff;
  1402. outline: none;
  1403. display: flex;
  1404. align-items: center;
  1405. justify-content: center;
  1406. padding: 0.625em 1.1em;
  1407. }
  1408.  
  1409. .pl-progress-stop {
  1410. background: #cc3235;
  1411. cursor: pointer;
  1412. margin: 6px 6px;
  1413. font-size: 12px;
  1414. border: 0;
  1415. border-radius: 4px;
  1416. color: #ffffff;
  1417. outline: none;
  1418. display: flex;
  1419. align-items: center;
  1420. justify-content: center;
  1421. padding: 0.625em 1.1em;
  1422. }
  1423.  
  1424. .pl-progress-inner-text:after {
  1425. display: inline-block;
  1426. content: "";
  1427. height: 100%;
  1428. vertical-align: middle;
  1429. }
  1430.  
  1431. .pl-btn-primary {
  1432. background: ${color};
  1433. border: 0;
  1434. border-radius: 4px;
  1435. color: #ffffff;
  1436. cursor: pointer;
  1437. font-size: 12px;
  1438. outline: none;
  1439. display: flex;
  1440. align-items: center;
  1441. justify-content: center;
  1442. margin: 6px 6px;
  1443. padding: 0.625em 1.1em;
  1444. transition: 0.3s opacity;
  1445. }
  1446.  
  1447. .pl-btn-primary:hover {
  1448. opacity: 0.8;
  1449. transition: 0.3s opacity;
  1450. }
  1451.  
  1452. .pl-btn-primary:focus{
  1453. box-shadow:0 0 0 3px ${color}80;
  1454. }
  1455.  
  1456. .pl-btn-success {
  1457. background: #55af28;
  1458. }
  1459.  
  1460. .pl-btn-success:focus{
  1461. box-shadow:0 0 0 3px #55af2880;
  1462. }
  1463.  
  1464. .pl-btn-info {
  1465. background: #606266;
  1466. }
  1467.  
  1468. .pl-btn-info:focus{
  1469. box-shadow:0 0 0 3px #60626680;
  1470. }
  1471.  
  1472. .pl-btn-warning {
  1473. background: #da9328;
  1474. }
  1475.  
  1476. .pl-btn-warning:focus{
  1477. box-shadow:0 0 0 3px #da932880;
  1478. }
  1479.  
  1480. .pl-btn-danger {
  1481. background: #cc3235;
  1482. }
  1483.  
  1484. .pl-btn-danger:focus{
  1485. box-shadow:0 0 0 3px #cc323580;
  1486. }
  1487.  
  1488. .pl-btn-opacity {
  1489. animation: easeOpacity 1.2s 2;
  1490. animation-fill-mode: forwards
  1491. }
  1492.  
  1493. .pl-button-mini {
  1494. padding: 5px 10px;
  1495. }
  1496.  
  1497. .pl-dropdown-menu-item {
  1498. height: 30px;
  1499. display: flex;
  1500. align-items: center;
  1501. justify-content: center;
  1502. cursor: pointer;
  1503. color: ${color};
  1504. transition: all 0.2s ease;
  1505. }
  1506.  
  1507. .pl-dropdown-menu-item:hover {
  1508. background-color: ${color}15;
  1509. }
  1510.  
  1511. .pl-button-mode {
  1512. padding: 0px;
  1513. padding-left: 0px !important;
  1514. color: ${color} !important;
  1515. transition: all 0.2s ease;
  1516. }
  1517.  
  1518. .pl-button-mode:hover {
  1519. background-color: ${color}33 !important;
  1520. }
  1521.  
  1522. .g-button-menu.pl-button-mode {
  1523. padding: 0px !important;
  1524. }
  1525.  
  1526. .pl-button,
  1527. .pl-dropdown-menu {
  1528. transition: all 0.2s ease;
  1529. }
  1530.  
  1531. .pl-button .pl-dropdown-menu {
  1532. display: none;
  1533. }
  1534.  
  1535. .pl-button:hover .pl-dropdown-menu {
  1536. display: block;
  1537. }
  1538.  
  1539. .pl-button-init {
  1540. opacity: 0.5;
  1541. animation: easeInitOpacity 1.2s 3;
  1542. animation-fill-mode: forwards
  1543. }
  1544.  
  1545. @keyframes easeInitOpacity {
  1546. from {
  1547. opacity: 0.5;
  1548. }
  1549.  
  1550. 50% {
  1551. opacity: 1
  1552. }
  1553.  
  1554. to {
  1555. opacity: 0.5;
  1556. }
  1557. }
  1558.  
  1559. @keyframes easeOpacity {
  1560. from {
  1561. opacity: 1;
  1562. }
  1563.  
  1564. 50% {
  1565. opacity: 0.35
  1566. }
  1567.  
  1568. to {
  1569. opacity: 1;
  1570. }
  1571. }
  1572.  
  1573. .baidu-button {
  1574. background: ${color} !important;
  1575. border-color: ${color} !important;
  1576. border: 1px solid ${color} !important;
  1577. display: inline-flex;
  1578. }
  1579.  
  1580. .baidu-button:hover {
  1581. background: ${color}b0 !important;
  1582. border-color: ${color} !important;
  1583. }
  1584.  
  1585. header[style="display: none;"]~.pl-button {
  1586. display: inline-block;
  1587. position: fixed;
  1588. top: 0.6em;
  1589. left: 65%;
  1590. z-index: 99999;
  1591. }
  1592.  
  1593. .ali-button {
  1594. background: ${color};
  1595. border: 0 solid transparent;
  1596. font-size: 14px;
  1597. margin-left: 20px;
  1598. padding: 8px 16px;
  1599. position: relative;
  1600. height: 32px;
  1601. border-radius: 100px;
  1602. display: flex;
  1603. align-items: center;
  1604. justify-content: center;
  1605. color: var(--basic_white);
  1606. cursor: pointer;
  1607. transition: all .3s ease;
  1608. }
  1609.  
  1610. .ali-button:hover {
  1611. background: ${color}D0
  1612. }
  1613.  
  1614. .ali-btn-icon {
  1615. vertical-align: -0.2em;
  1616. }
  1617.  
  1618. .tianyi-button {
  1619. margin-right: 20px;
  1620. padding: 4px 12px;
  1621. border-radius: 4px;
  1622. color: #fff;
  1623. font-size: 12px;
  1624. border: 1px solid ${color};
  1625. background: ${color};
  1626. cursor: pointer;
  1627. position: relative;
  1628. }
  1629.  
  1630. .tianyi-button:hover {
  1631. border-color: ${color}b0;
  1632. background: ${color}b0;
  1633. }
  1634.  
  1635. .yidong-button {
  1636. float: left;
  1637. position: relative;
  1638. margin: 20px 24px 20px 0;
  1639. width: 110px;
  1640. height: 36px;
  1641. background: ${color};
  1642. border-radius: 2px;
  1643. font-size: 14px;
  1644. color: #fff;
  1645. line-height: 39px;
  1646. text-align: center;
  1647. cursor: pointer;
  1648. }
  1649.  
  1650. .yidong-share-button {
  1651. display: inline-block;
  1652. position: relative;
  1653. font-size: 14px;
  1654. line-height: 36px;
  1655. height: 36px;
  1656. text-align: center;
  1657. color: #fff;
  1658. border: 1px solid ${color};
  1659. border-radius: 2px;
  1660. padding: 0 24px;
  1661. background: ${color};
  1662. }
  1663.  
  1664. .yidong-share-button:hover {
  1665. background: ${color}b0;
  1666. }
  1667.  
  1668. .yidong-button:hover {
  1669. background: ${color}b0;
  1670. }
  1671.  
  1672. .yidong-btn {
  1673. background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAMAAAC7IEhfAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAGNQTFRFAAAA////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////mkUNoAAAACF0Uk5TAAbHPP9AMRtr9PwrV8zqXfmNgDODHTLD4iJxhGJJ8Z269m0aDgAAAMZJREFUeJzd0ssOgyAQBVDUK74rWq0PFP3/ryxqTMdGqJtuvGHD5CTDTGDs3nFc17kEPcC7BH3At/Tjvk5AYbBU+NcrwghL4uQDk3gtRSF1KWCCQEpghkd+3jp/ICNQoDANU0AQCJQmWAJ3h8+q3mFdvSywQdttsGvRWGAPLReoHXrbG6WWAzBoJ+3DaCnWI39NLbcvszvLeuTB2fYoqbNBNo7sGjzk31BhMsEJitxmiKk8zSQwE8gFjBGcNuCzOmdqPrib5A2JRQ7qK9g+hQAAAABJRU5ErkJggg==);
  1674. height: 20px;
  1675. line-height: 20px;
  1676. display: inline-block;
  1677. background-repeat: no-repeat;
  1678. background-size: 20px 20px;
  1679. text-indent: 25px;
  1680. }
  1681.  
  1682. .xunlei-button {
  1683. display: inline-flex;
  1684. align-items: center;
  1685. justify-content: center;
  1686. border: 0 solid transparent;
  1687. border-radius: 5px;
  1688. box-shadow: 0 0 0 0 transparent;
  1689. width: fit-content;
  1690. white-space: nowrap;
  1691. flex-shrink: 0;
  1692. font-size: 14px;
  1693. line-height: 1.5;
  1694. outline: 0;
  1695. touch-action: manipulation;
  1696. transition: background .3s ease, color .3s ease, border .3s ease, box-shadow .3s ease;
  1697. color: #fff;
  1698. background: ${color};
  1699. margin-left: 12px;
  1700. padding: 0px 12px;
  1701. position: relative;
  1702. cursor: pointer;
  1703. height: 36px;
  1704. }
  1705.  
  1706. .xunlei-button:hover {
  1707. background: ${color}b0;
  1708. }
  1709.  
  1710. .quark-button {
  1711. background: ${color} !important;
  1712. background-color:${color} !important;
  1713. }
  1714.  
  1715. .quark-button:hover {
  1716. background: ${color}b0 !important;
  1717. background-color:${color}b0 !important;
  1718. }
  1719.  
  1720. .quark-btn-icon {
  1721. width: 20px;
  1722. height: 20px;
  1723. vertical-align: -0.3em;
  1724. }
  1725.  
  1726. .element-clicked {
  1727. opacity: 0.5;
  1728. }
  1729.  
  1730. .pl-extra {
  1731. margin-top: 10px;
  1732. background-color:${color}15;
  1733. border-radius: 10px;
  1734. display: flex
  1735. }
  1736.  
  1737. .pl-extra button {
  1738. flex: 1
  1739. }
  1740.  
  1741. .pointer {
  1742. cursor: pointer
  1743. }
  1744.  
  1745. .pl-setting-label {
  1746. display: flex;
  1747. align-items: center;
  1748. justify-content: space-between;
  1749. padding-top: 10px;
  1750. }
  1751.  
  1752. .pl-label {
  1753. flex: 0 0 100px;
  1754. text-align: left;
  1755. }
  1756.  
  1757. .pl-input {
  1758. flex: 1;
  1759. padding: 8px 10px !important;
  1760. border: 1px solid #c2c2c2;
  1761. border-radius: 5px;
  1762. font-size: 14px !important;
  1763. min-width: 300px;
  1764. margin: 0;
  1765. darktheme
  1766. }
  1767.  
  1768. .init-input {
  1769. width: 400px;
  1770. margin: 1em 1em 3px;
  1771. font-size: 20px;
  1772. text-align: center;
  1773. font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Ubuntu, "Helvetica Neue", sans-serif;
  1774. font-weight: 300;
  1775. }
  1776.  
  1777. .pl-color {
  1778. flex: 1;
  1779. display: flex;
  1780. flex-wrap: wrap
  1781. }
  1782.  
  1783. .pl-color-box {
  1784. width: 55px;
  1785. height: 55px;
  1786. margin: 10px 10px 0 0;
  1787. box-sizing: border-box;
  1788. border: 1px solid #fff;
  1789. cursor: pointer
  1790. }
  1791.  
  1792. .pl-mask {
  1793. width: 53px;
  1794. height: 53px;
  1795. opacity: 0;
  1796. transition: opacity 0.3s;
  1797. color: #fff;
  1798. font-size: 13px;
  1799. display: flex;
  1800. align-items: center;
  1801. justify-content: center;
  1802. flex-direction: column;
  1803. }
  1804.  
  1805. .pl-color-box:hover .pl-mask {
  1806. opacity: 1;
  1807. }
  1808.  
  1809. .pl-close:focus {
  1810. outline: 0;
  1811. box-shadow: none;
  1812. }
  1813.  
  1814. .tag-danger {
  1815. color: #cc3235;
  1816. margin: 0 5px;
  1817. }
  1818.  
  1819. .pl-tooltip {
  1820. position: absolute;
  1821. color: #ffffff;
  1822. max-width: 600px;
  1823. font-size: 12px;
  1824. padding: 5px 10px;
  1825. background: #333;
  1826. border-radius: 5px;
  1827. z-index: 110000;
  1828. line-height: 1.3;
  1829. display: none;
  1830. word-break: break-all;
  1831. }
  1832.  
  1833. @keyframes load {
  1834. 0% {
  1835. transform: rotate(0deg)
  1836. }
  1837.  
  1838. 100% {
  1839. transform: rotate(360deg)
  1840. }
  1841. }
  1842.  
  1843. .pl-loading-box>div>div {
  1844. position: absolute;
  1845. border-radius: 50%;
  1846. }
  1847.  
  1848. .pl-loading-box>div>div:nth-child(1) {
  1849. top: 9px;
  1850. left: 9px;
  1851. width: 82px;
  1852. height: 82px;
  1853. background: #ffffff;
  1854. }
  1855.  
  1856. .pl-loading-box>div>div:nth-child(2) {
  1857. top: 14px;
  1858. left: 38px;
  1859. width: 25px;
  1860. height: 25px;
  1861. background: #666666;
  1862. animation: load 1s linear infinite;
  1863. transform-origin: 12px 36px;
  1864. }
  1865.  
  1866. .pl-loading {
  1867. width: 16px;
  1868. height: 16px;
  1869. display: inline-block;
  1870. overflow: hidden;
  1871. background: none;
  1872. }
  1873.  
  1874. .pl-loading-box {
  1875. width: 100%;
  1876. height: 100%;
  1877. position: relative;
  1878. transform: translateZ(0) scale(0.16);
  1879. backface-visibility: hidden;
  1880. transform-origin: 0 0;
  1881. }
  1882.  
  1883. .pl-loading-box div {
  1884. box-sizing: content-box;
  1885. }
  1886.  
  1887. .pl-dropdown-menu {
  1888. position: absolute;
  1889. padding: 5px 0;
  1890. color: ${color};
  1891. background: themecolor;
  1892. z-index: 999;
  1893. width: 110px;
  1894. border-radius: 5px;
  1895. box-shadow: 0 1px 6px ${color}33;
  1896. -webkit-box-shadow: 0 1px 6px ${color}33;
  1897. text-align: center;
  1898. border: none;
  1899. transition: all 0.2s ease;
  1900. }
  1901.  
  1902. .pl-button-save {
  1903. background-color: ${color} !important;
  1904. color:#fff !important;
  1905. }
  1906.  
  1907. .pl-button-save:hover {
  1908. background-color: ${color}D0 !important;
  1909. color:#fff !important;
  1910. }
  1911.  
  1912. .swal2-container {
  1913. z-index: 100000;
  1914. }
  1915.  
  1916. body.swal2-height-auto {
  1917. height: inherit;
  1918. }
  1919.  
  1920. svg.icon-rpc-devices {
  1921. width: 13px;
  1922. height: 13px;
  1923. }
  1924.  
  1925. [class^="swal2-"], [class*="pl-btn"] {
  1926. transition:all 0.3s ease;
  1927. }
  1928.  
  1929. @media (prefers-color-scheme: dark) [data-theme=system] * {
  1930. color-scheme: dark;
  1931. }
  1932.  
  1933. /* RGB! */
  1934. @keyframes hue-rotate {
  1935. 0% {
  1936. filter: hue-rotate()
  1937. }
  1938.  
  1939. to {
  1940. filter: hue-rotate(-360deg)
  1941. }
  1942. }
  1943.  
  1944. /* Webkit, Opera, IE9, Chrome*/
  1945. ::selection {
  1946. background-color: ${color} !important;
  1947. background: ${color} !important;
  1948. color: white !important;
  1949. }
  1950.  
  1951. /* Mozilla Firefox */
  1952. ::-moz-selection {
  1953. background-color: ${color} !important;
  1954. background: ${color} !important;
  1955. color: white !important;
  1956. }
  1957.  
  1958. /* 百度网盘 */
  1959. :not([class*="rwl-exempt"]) ::selection {
  1960. background-color: ${color} !important;
  1961. background: ${color} !important;
  1962. color: white !important;
  1963. }
  1964. `;
  1965. // 先监听颜色方案变化
  1966. window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
  1967. if (e.matches) {
  1968. // 切换到暗色主题
  1969. let dark = uicss.replace("themecolor", "#19191a").replace("darktheme", "color-scheme: dark;");
  1970. base.addStyle('Panlinker-UI', 'style', dark);
  1971. } else {
  1972. // 切换到浅色主题
  1973. let light = uicss.replace("themecolor", "#fff").replace("darktheme", "");
  1974. base.addStyle('Panlinker-UI', 'style', light);
  1975. }
  1976. });
  1977. // 再修改主题
  1978. if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  1979. let dark = uicss.replace("themecolor", "#19191a").replace("darktheme", "color-scheme: dark;");
  1980. base.addStyle('Panlinker-UI', 'style', dark);
  1981. } else {
  1982. // 切换到浅色主题
  1983. let light = uicss.replace("themecolor", "#fff").replace("darktheme", "");
  1984. base.addStyle('Panlinker-UI', 'style', light);
  1985. }
  1986.  
  1987.  
  1988.  
  1989. if (/(pan|yun).baidu.com/.test(location.host) && base.getValue('setting_baidu_theme') === 'yes') {
  1990. base.addStyle('Panlinker-UI-Baidu', 'style', `
  1991. #layoutMain,
  1992. .DxdbeCb {
  1993. border-radius: 10px;
  1994. border-bottom-left-radius: 0;
  1995. border-bottom-right-radius: 0;
  1996. background: #ffffffA0 !important
  1997. }
  1998. .KPDwCE,
  1999. .DxdbeCb .OFaPaO .tanwePYr,
  2000. .xGLMIab .fufHyA:hover,
  2001. .module-search-timeline .form-box {
  2002. background: #ffffffA0 !important;
  2003. }
  2004. .KPDwCE .JDeHdxb,
  2005. .NHcGw .AuPKyz,
  2006. .xGLMIab .tvPMvPb,
  2007. .xGLMIab .FcQMwt,
  2008. .cazEfA .yfHIsP,
  2009. .hscjZ4QL .bbxnZ0Bq .ehnyLxWZ span,
  2010. .module-topToolBar,
  2011. .module-timeline-view .timeline-title-curday {
  2012. background: transparent !important;
  2013. border-bottom: 0;
  2014. }
  2015. .MdLxwM {
  2016. background :#fff !important;
  2017. }
  2018. .aside-absolute-container .QGOvsxb .remainingSpaceUi_span {
  2019. /*background: ${color} !important;*/
  2020. background: #8af248 !important;
  2021. border-radius: 10px 0 0 10px;
  2022. border-right: #fff 1px solid;
  2023. border-bottom: #fff 1px solid;
  2024. }
  2025. .xtJbHcb .CDaavKb .KQcHyA {
  2026. background: rgb(244,207,0) !important;
  2027. padding: 8px 15px;
  2028. }
  2029. .xtJbHcb .web-header-nav-new-version-inner {
  2030. background: ${color} !important;
  2031. padding: 8px 15px;
  2032. line-height: 15px;
  2033. width: auto;
  2034. height: auto;
  2035. }
  2036. a {
  2037. transition: all 0.2s ease !important;
  2038. }
  2039. .module-share-header .slide-show-header .slide-show-center {
  2040. float: inline-end;
  2041. margin: 10px 8px;
  2042. text-align: right;
  2043. }
  2044. .module-share-header .slide-show-header .slide-show-center .subscribe-btn {
  2045. background:${color}
  2046. }
  2047. #bd-main .bd-left {
  2048. margin: auto !important;
  2049. }
  2050. .verify-input input {
  2051. padding-left: 0 !important;
  2052. text-align: center !important;
  2053. }
  2054. .verify-input input:focus {
  2055. border: 2px solid ${color} !important;
  2056. }
  2057. `, 'body');
  2058. }
  2059. if (/(pan|yun).baidu.com/.test(location.host) && location.pathname !== '/disk/home' && base.getValue('setting_baidu_theme') === 'yes') {
  2060. base.setColors([
  2061. ['#717fff', `${color}`],
  2062. ['#717FFF', `${color}`],
  2063. ['#06a8ff', `${color}`],
  2064. ['#06A8FF', `${color}`],
  2065. ['#06a7ff', `${color}`],
  2066. ['#06A7FF', `${color}`],
  2067. ['#dcdfe6', `${color}`],
  2068. ['#DCDFE6', `${color}`],
  2069. ['#0095ff', `${color}`],
  2070. ['#0095FF', `${color}`],
  2071. ['#09aaff', `${color}`],
  2072. ['#09AAFF', `${color}`],
  2073. ['#0ca6ff', `${color}`],
  2074. ['#0CA6FF', `${color}`],
  2075. ['#5040ff', `${color}`],
  2076. ['#5040FF', `${color}`],
  2077. ['#454d5a', `${color}`],
  2078. ['#454D5A', `${color}`],
  2079. ['#a2abbd', `${color}`],
  2080. ['#A2ABBD', `${color}`],
  2081. ['#030b1a', `${color}`],
  2082. ['#030B1A', `${color}`],
  2083. ['#afb3bf', `${color}`],
  2084. ['#AFB3BF', `${color}`],
  2085. ['#ff436a', `${color}`],
  2086. ['#FF436A', `${color}`],
  2087. ['#03081a', `${color}`],
  2088. ['#03081A', `${color}`],
  2089. ['#2974b6', `${color}`],
  2090. ['#2974B6', `${color}`],
  2091. ['#0596e6', `${color}`],
  2092. ['#0596E6', `${color}`],
  2093.  
  2094. ['#C3EAFF', `${color}`],
  2095. ['#c0d9fe', `${color}50`],
  2096. ['#0098EA', `${color}D0`],
  2097.  
  2098. ['#38b9ff', `${color}D0`],
  2099. ['#38B9FF', `${color}D0`],
  2100. ['#42d8ff', `${color}D0`],
  2101. ['#42D8FF', `${color}D0`],
  2102. ['#a48dff', `${color}D0`],
  2103. ['#A48DFF', `${color}D0`],
  2104. ['#6b79f2', `${color}D0`],
  2105. ['#6B79F2', `${color}D0`],
  2106.  
  2107. ['#9c86f2', `${color}90`],
  2108. ['#9C86F2', `${color}90`],
  2109. ['#83d3ff', `${color}90`],
  2110. ['#83D3FF', `${color}90`],
  2111. ['#C4D8F4', `${color}90`],
  2112.  
  2113. ['#fafafc', `${color}20`],
  2114. ['#FAFAFC', `${color}20`],
  2115. ['#f5fbff', `${color}20`],
  2116. ['#F5FBFF', `${color}20`],
  2117. ['#b4e5ff', `${color}20`],
  2118. ['#B4E5FF', `${color}20`],
  2119. ['#f0faff', `${color}20`],
  2120. ['#F0FAFF', `${color}20`],
  2121. ['#c4d8f4', `${color}20`],
  2122.  
  2123. ['#f1f3f8', `${color}15`],
  2124. ['#F1F3F8', `${color}15`],
  2125.  
  2126. ['#f2faff', `${color}10`],
  2127. ['#F2FAFF', `${color}10`],
  2128. ['#eef9fe', `${color}10`],
  2129. ['#EEF9FE', `${color}10`],
  2130. ['#f7f9fc', `${color}10`],
  2131. ['#F7F9FC', `${color}10`],
  2132. ['#f5f6fa', `${color}10`],
  2133. ['#F5F6FA', `${color}10`],
  2134. ['#b4e5ff', `${color}10`],
  2135. ['#B4E5FF', `${color}10`],
  2136. ['#e6f6ff', `${color}10`],
  2137. ['#E6F6FF', `${color}10`],
  2138.  
  2139. ['6,167,255,.1', base.hexToRgba(`${color}15`)],
  2140. ['6,167,255,.23', base.hexToRgba(`${color}3b`)],
  2141. ['164,141,255,.2', base.hexToRgba(`${color}30`)],
  2142. ['196,182,255,.2', base.hexToRgba(`${color}20`)],
  2143. ['113,127,255,.2', base.hexToRgba(`${color}40`)],
  2144. ['3,8,26,.6', base.hexToRgba(`${color}D0`)],
  2145. ['255,32,102,.4', base.hexToRgba(`${color}66`)],
  2146. ]);
  2147. };
  2148. if (/www.(aliyundrive|alipan).com/.test(location.host) && base.getValue('setting_ali_theme') === 'yes') {
  2149. base.setColors([
  2150. ['#3763ff', `${color}`],
  2151. ['#8664ff', `${color}D0`],
  2152. ['99, 125, 255', base.hexToRgba(`${color}`)],
  2153. ['132, 133, 141', base.hexToRgba(`${color}`)],
  2154. ['112, 136, 255', base.hexToRgba(`${color}`)],
  2155. ['97, 122, 250', base.hexToRgba(`${color}`)],
  2156. ['68, 109, 255', base.hexToRgba(`${color}`)],
  2157. ['82, 110, 250', base.hexToRgba(`${color}20`)],
  2158. ['122, 144, 255', base.hexToRgba(`${color}D0`)],
  2159. ['138, 157, 255', base.hexToRgba(`${color}D0`)],
  2160. ['49, 49, 54', base.hexToRgba(`${color}`)],
  2161. ]);
  2162. };
  2163. if (/cloud.189.cn/.test(location.host) && base.getValue('setting_tianyi_theme') === 'yes') {
  2164. base.setColors([
  2165. ['#2b89ea', `${color}`],
  2166. ['#1874d3', `${color}F0`],
  2167. ['#1890ff', `${color}`],
  2168. ['#388fc9', `${color}`],
  2169. ['#0087ff', `${color}`],
  2170. ['#255697', `${color}`],
  2171. ['#3ea6ff', `${color}80`],
  2172. ['#1d52f2', `${color}`],
  2173. ['#3699ff', `${color}D0`],
  2174. ['#f4f9fe', `${color}10`],
  2175. ['#eaf5ff', `${color}20`],
  2176. ], "other");
  2177. }
  2178. if (/pan.xunlei.com/.test(location.host) && base.getValue('setting_xunlei_theme') === 'yes') {
  2179. base.setColors([
  2180. ['#3f85ff', `${color}`],
  2181. ['63,133,255,.1', base.hexToRgba(`${color}20`)],
  2182. ['#2670ea', `${color}D0`],
  2183. ['#619bff', `${color}D0`],
  2184. ['#ecf3ff', `${color}10`],
  2185. ['#f6faff', `${color}10`],
  2186. ['#1a2845', `${color}20`],
  2187. ['#eee', `${color}20`],
  2188. ], "other");
  2189. base.addStyle('Panlinker-UI-Xunlei', 'style', `
  2190. .web-header {
  2191. background: linear-gradient(0deg,${color}D0,${color})
  2192. }
  2193. `);
  2194. };
  2195. if (/pan.quark.cn/.test(location.host) && base.getValue('setting_quark_theme') === 'yes') {
  2196. base.setColors([
  2197. ['#0d53ff', `${color}`],
  2198. ['#e6f1ff', `${color}20`],
  2199. ['#f0faff', `${color}20`],
  2200. ['#7da3ff', `${color}D0`],
  2201. ['#ddd', `${color}D0`],
  2202. ['17,17,17,.9', base.hexToRgba(`${color}D0`)],
  2203. ['40,40,255,.04', base.hexToRgba(`${color}20`)],
  2204. ['#f7f7ff', 'transparent'],
  2205. ['238,247,255,0', base.hexToRgba(`${color}00`)],
  2206. ]);
  2207. base.addStyle('Panlinker-UI-Quark', 'style', `
  2208. .file-list .hover-oper .hover-transparent-bg {
  2209. background: transparent !important;
  2210. }
  2211. /* .viewer-toolbar-cus,
  2212. .viewer-cus .close {
  2213. background-color: ${color} !important;
  2214. } */
  2215. `);
  2216. };
  2217. if (/(yun|caiyun).139.com/.test(location.host) && base.getValue('setting_yidong_theme') === 'yes') {
  2218. base.setColors([
  2219. ['#3181f9', `${color}`],
  2220. ['#5a9afa', `${color}`],
  2221. ['#98c0fc', `${color}D0`],
  2222. ['#2d76e5', `${color}D0`],
  2223. ['49,129,249,.08', base.hexToRgba(`${color}20`)],
  2224. ]);
  2225. };
  2226. if (/.*.youxiaohou.com/.test(location.host)) {
  2227. base.setColors([
  2228. ['#00aefe', `${color}`],
  2229. ['#4e6e8e', `${color}`],
  2230. ['#009fe8', `${color}`],
  2231. ['#008fd1', `${color}`],
  2232. ['#05b0ff', `${color}D0`],
  2233. ], "other");
  2234. };
  2235. },
  2236.  
  2237. // 暗号界面
  2238. async initDialog() {
  2239. let secret = ""
  2240. if (base.getValue('setting_youxiaohou_server') === 'v1') {
  2241. secret = "当前暗号是‘" + pan.num + "’";
  2242. } else if (base.getValue('setting_youxiaohou_server') === 'v2') {
  2243. secret = "当前开源协议是‘" + pan.license + "’,暗号是‘" + pan.num + "’";
  2244. } else if (base.getValue('setting_youxiaohou_server') === "no") {
  2245. secret = "当前暗号是‘" + pan.num + "’";
  2246. } else {
  2247. base.setValue('setting_youxiaohou_server', 'v2');
  2248. secret = '<span style="color:red">检测到当前配置不正确,已自动修复<br/>请在刷新页面后再继续输入</span>';
  2249. }
  2250. let dialog = await Swal.fire({
  2251. title: `请阅读完以下全文再继续`,
  2252. allowOutsideClick: false,
  2253. showCloseButton: true,
  2254. showDenyButton: true,
  2255. confirmButtonText: '确定',
  2256. heightAuto: false,
  2257. scrollbarPadding: false,
  2258. html: `<div><img style="width: 250px;margin-bottom: 10px;" src="${pan.img}" alt="${pan.img}">
  2259. <input class="swal2-input init-input" id="init" type="text" placeholder="${pan.init[1]}"></div>
  2260. <div><span>服务器说道: ${pan.init[0]}”;</span></div>
  2261. <div><span>脚本说道: ${secret}”。</span></div>
  2262. <div>↓</div>
  2263. <div><span>但史丹利不知道的是,他可以按下<span style="color:red;font-style:italic;vertical-align:unset;">红色按钮</span>来点亮按钮</span></div>
  2264. <div><span>或者有仪式感地 输入以上暗号/开源协议 点亮</span></div>
  2265. <div><span>输入一些<span style="font-style:italic;vertical-align:unset;">恶臭的数字</span>甚至有彩蛋</span></div>
  2266. <div>↓</div>
  2267. <div><span><a target="_blank" href="https://www.youxiaohou.com" style="vertical-align:unset;">原作者</a>开发很辛苦,所以请有能力的你请支持下他的公众号</span></div>
  2268. <div><span>实在不行的话,那就来给这个改版点个<a href="https://github.com/hmjz100/Online-disk-direct-link-download-assistant/" style="vertical-align:unset;">Star</a>吧...</span></div>
  2269. <div><span>点亮后不仅能精简网盘界面 还能改变众多网盘主题色哦!</span></div>
  2270. `,
  2271. denyButtonText: '我就不输入,点我“注入”直接点亮'
  2272. });
  2273. if (dialog.isDenied) {
  2274. console.log("【(改)网盘直链下载助手】\n正在注入点亮按钮设置项目...");
  2275. message.warning("正在注入设置项目...");
  2276. setTimeout(function () {
  2277. base.setValue('setting_init_code', pan.num);
  2278. base.setValue('license', pan.license);
  2279. message.success("注入成功了!");
  2280. setTimeout(function () {
  2281. message.success(pan.init[2]);
  2282. setTimeout(function () {
  2283. location.reload();
  2284. }, 1500);
  2285. }, 1500);
  2286. }, 2500);
  2287. };
  2288. if (dialog.isConfirmed) {
  2289. if (pan.num === $('#init').val() || pan.license === $('#init').val()) {
  2290. console.log("【(改)网盘直链下载助手】\n暗号或协议正确")
  2291. message.success(pan.init[2]);
  2292. setTimeout(function () {
  2293. base.setValue('setting_init_code', pan.num);
  2294. base.setValue('license', pan.license);
  2295. location.reload();
  2296. }, 3000)
  2297. } else if ($('#init').val() === '114514' || $('#init').val() === '1919810' || $('#init').val() === '1145141919810') {
  2298. /*---
  2299. homo彩蛋又回来力(喜)
  2300. imageUrl: 'https://pic4.zhimg.com/80/v2-1b97a088e156c015108dec663bba8b04.jpg',
  2301. imageUrl: 'https://lh1.hetaousercontent.com/img/7d4c1c0b4adb0e95.jpg',
  2302. */
  2303. await Swal.fire({
  2304. icon: 'error',
  2305. title: '1145141919810',
  2306. html: '<span>homo特有的数字当然不行啦<br/>哼哼哼啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊</span>',
  2307. timer: 4000,
  2308. imageUrl: 'https://pic4.zhimg.com/80/v2-1b97a088e156c015108dec663bba8b04.jpg',
  2309. allowOutsideClick: false,
  2310. timerProgressBar: true,
  2311. showConfirmButton: false,
  2312. showDenyButton: true,
  2313. heightAuto: false,
  2314. scrollbarPadding: false,
  2315. denyButtonText: '哼哼哼啊啊啊啊啊啊啊啊啊啊',
  2316. });
  2317. message.info("成就:你触发了一个homo特有的彩蛋!");
  2318. setTimeout(function () {
  2319. Swal.fire({
  2320. title: '1145141919810',
  2321. text: 'homo特有的数字当然不行啦...吗?',
  2322. icon: 'question',
  2323. imageUrl: 'https://lh1.hetaousercontent.com/img/7d4c1c0b4adb0e95.jpg',
  2324. showConfirmButton: false,
  2325. allowOutsideClick: false,
  2326. });
  2327. setTimeout(function () {
  2328. base.setValue('setting_init_code', pan.num);
  2329. message.success("成就:哼哼哼啊啊啊啊啊啊啊啊地注入成功(喜)");
  2330. location.reload();
  2331. }, 3000)
  2332. }, 4000)
  2333. } else {
  2334. console.log("【(改)网盘直链下载助手】\n暗号错误")
  2335. await Swal.fire({
  2336. imageUrl: pan.img,
  2337. title: pan.init[3],
  2338. heightAuto: false,
  2339. scrollbarPadding: false,
  2340. html: `<div><span>${pan.init[4]}<br/>你可以在返回后选择“注入”立即点亮按钮,<br/>或者在输入框键入以下暗号:“${pan.num}”。</span></div>`,
  2341. confirmButtonText: '重新输入',
  2342. });
  2343. await this.initDialog();
  2344. return;
  2345. };
  2346. }
  2347. },
  2348. /*--- waitForKeyElements(): 一个实用函数,用于 Greasemonkey 脚本,
  2349. 它可以检测和处理AJAX加载的内容。
  2350. 使用示例:
  2351. base.waitForKeyElements (
  2352. "div.comments"
  2353. , commentCallbackFunction
  2354. );
  2355. // 页面特定的函数,用于在找到节点时执行我们想要的操作。
  2356. function commentCallbackFunction (jNode) {
  2357. jNode.text ("waitForKeyElements() 更改了这段注释。");
  2358. }
  2359. 重要提示:<br/>这个函数需要你的脚本加载了jQuery。
  2360. */
  2361. waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector) {
  2362. var targetNodes, btargetsFound;
  2363.  
  2364. if (typeof iframeSelector == "undefined")
  2365. targetNodes = $(selectorTxt);
  2366. else
  2367. targetNodes = $(iframeSelector).contents()
  2368. .find(selectorTxt);
  2369.  
  2370. if (targetNodes && targetNodes.length > 0) {
  2371. btargetsFound = true;
  2372. targetNodes.each(function () {
  2373. var jThis = $(this);
  2374. var alreadyFound = jThis.data('alreadyFound') || false;
  2375.  
  2376. if (!alreadyFound) {
  2377. //--- 调用载荷函数。
  2378. var cancelFound = actionFunction(jThis);
  2379. if (cancelFound) {
  2380. btargetsFound = false;
  2381. } else {
  2382. jThis.data('alreadyFound', true);
  2383. }
  2384. }
  2385. });
  2386. } else {
  2387. btargetsFound = false;
  2388. }
  2389.  
  2390. //--- 获取这个选择器的定时器控制变量。
  2391. var controlObj = base.waitForKeyElements.controlObj || {};
  2392. var controlKey = selectorTxt.replace(/[^\w]/g, "_");
  2393. var timeControl = controlObj[controlKey];
  2394.  
  2395. //--- 现在根据情况设置或清除定时器。
  2396. if (btargetsFound && bWaitOnce && timeControl) {
  2397. //--- 唯一需要清除定时器的情况。
  2398. clearInterval(timeControl);
  2399. delete controlObj[controlKey]
  2400. } else {
  2401. //--- 如果需要的话,设置一个定时器。
  2402. if (!timeControl) {
  2403. timeControl = setInterval(function () {
  2404. base.waitForKeyElements(selectorTxt, actionFunction, bWaitOnce, iframeSelector);
  2405. }, 1000);
  2406. controlObj[controlKey] = timeControl;
  2407. }
  2408. }
  2409. base.waitForKeyElements.controlObj = controlObj;
  2410. },
  2411. };
  2412. // 用于油小猴服务器检测的脚本信息,防止服务器返回更新信息
  2413. let author = base.getValue('setting_script_author'),
  2414. version = base.getValue('setting_script_version')
  2415.  
  2416. //百度网盘
  2417. let baidu = {
  2418.  
  2419. _getExtra() {
  2420. let seKey = decodeURIComponent(base.getCookie('BDCLND'));
  2421. return '{' + '"sekey":"' + seKey + '"' + "}";
  2422. },
  2423.  
  2424. _getSurl() {
  2425. let reg = /(?<=s\/|surl=)([a-zA-Z0-9_-]+)/g;
  2426. if (reg.test(location.href)) {
  2427. return location.href.match(reg)[0];
  2428. }
  2429. return '';
  2430. },
  2431.  
  2432. _getFidList() {
  2433. let fidlist = [];
  2434. for (const v of selectList) {
  2435. if (+v.isdir !== 1) {
  2436. fidlist.push(v.fs_id);
  2437. }
  2438. }
  2439. return '[' + fidlist + ']';
  2440. },
  2441.  
  2442. _resetData() {
  2443. progress = {};
  2444. $.each(request, function (key) {
  2445. (request[key]).abort();
  2446. });
  2447. $.each(ins, function (key) {
  2448. clearInterval(ins[key]);
  2449. });
  2450. idm = {};
  2451. ins = {};
  2452. request = {};
  2453. },
  2454.  
  2455. setBDUSS() {
  2456. try {
  2457. GM_cookie && GM_cookie('list', { name: 'BDUSS' }, (cookies, error) => {
  2458. if (!error) {
  2459. let BDUSS = cookies?.[0]?.value;
  2460. if (BDUSS) {
  2461. base.setStorage("baiduyunPlugin_BDUSS", { BDUSS });
  2462. }
  2463. }
  2464. });
  2465. } catch (e) {
  2466. console.error("【(改)网盘直链下载助手】\nsetBDUSS\n错误信息:", e)
  2467. try {
  2468. let BDUSS = document.cookie.match(/BDUSS=(.*?)(;|$)/);
  2469. base.setStorage("baiduyunPlugin_BDUSS", { BDUSS: BDUSS });
  2470. } catch (e) {
  2471. console.error("【(改)网盘直链下载助手】\nsetBDUSS\n错误信息:", e)
  2472. }
  2473. }
  2474. },
  2475.  
  2476. getBDUSS() {
  2477. let baiduyunPlugin_BDUSS = base.getStorage('baiduyunPlugin_BDUSS') ? base.getStorage('baiduyunPlugin_BDUSS') : '{"baiduyunPlugin_BDUSS":""}';
  2478. return baiduyunPlugin_BDUSS.BDUSS || '';
  2479. },
  2480.  
  2481. convertLinkToAria(link, filename, ua) {
  2482. let BDUSS = this.getBDUSS();
  2483. if (!!BDUSS) {
  2484. filename = base.fixFilename(filename);
  2485. return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "User-Agent: ${ua}" --header "Cookie: BDUSS=${BDUSS}"`);
  2486. }
  2487. return {
  2488. link: pan.assistant,
  2489. text: pan.init[5]
  2490. };
  2491. },
  2492.  
  2493. convertLinkToBC(link, filename, ua) {
  2494. let BDUSS = this.getBDUSS();
  2495. if (!!BDUSS) {
  2496. let cookie = `BDUSS=${BDUSS}`;
  2497. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&cookie=${encodeURIComponent(cookie)}&user_agent=${encodeURIComponent(ua)}ZZ`;
  2498. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  2499. }
  2500. return {
  2501. link: pan.assistant,
  2502. text: pan.init[5]
  2503. };
  2504. },
  2505.  
  2506. convertLinkToCurl(link, filename, ua) {
  2507. let BDUSS = this.getBDUSS();
  2508. if (!!BDUSS) {
  2509. let terminal = base.getValue('setting_terminal_type');
  2510. filename = base.fixFilename(filename);
  2511. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}" -A "${ua}" -b "BDUSS=${BDUSS}"`);
  2512. }
  2513. return {
  2514. link: pan.assistant,
  2515. text: pan.init[5]
  2516. };
  2517. },
  2518.  
  2519. addPageListener() {
  2520. /*
  2521. 防止代码因其他原因被执行多次
  2522. 这段代码出自 Via轻插件,作者谷花泰
  2523. */
  2524. const key = encodeURIComponent('(改)网盘直链下载助手:百度网盘');
  2525. if (window[key]) return;
  2526. window[key] = true;
  2527.  
  2528. function _factory(e) {
  2529. let target = $(e.target);
  2530. let item = target.parents('.pl-item');
  2531. let link = item.find('.pl-item-link.blob');
  2532. let directLink = item.find('.pl-item-link.browser');
  2533. let progress = item.find('.pl-item-progress');
  2534. let tip = item.find('.pl-item-tip');
  2535. let copy = item.find('.pl-item-copy');
  2536. let howidm = item.find('.pl-progress-how');
  2537. let back = item.find('.pl-progress-back');
  2538. let stop = item.find('.pl-progress-stop');
  2539. return {
  2540. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  2541. };
  2542. }
  2543.  
  2544. function _reset(i) {
  2545. ins[i] && clearInterval(ins[i]);
  2546. request[i] && request[i].abort();
  2547. progress[i] = 0;
  2548. idm[i] = false;
  2549. }
  2550.  
  2551. doc.on('mouseenter mouseleave click', '.pl-button.g-dropdown-button', function (e) {
  2552. if (e.type === 'mouseleave') {
  2553. $(e.currentTarget).removeClass('button-open');
  2554. } else {
  2555. $(e.currentTarget).addClass('button-open');
  2556. $(e.currentTarget).find('.pl-dropdown-menu').show();
  2557. }
  2558. });
  2559. doc.on('mouseleave', '.pl-button.g-dropdown-button .pl-dropdown-menu', function (e) {
  2560. $(e.currentTarget).hide();
  2561. });
  2562.  
  2563. doc.on('click', '.pl-button-mode', function (e) {
  2564. mode = e.target.dataset.mode;
  2565. if (!mode) return;
  2566. Swal.fire({
  2567. heightAuto: false,
  2568. scrollbarPadding: false,
  2569. showConfirmButton: false,
  2570. html: `链接获取中`,
  2571. willOpen: function () {
  2572. Swal.showLoading();
  2573. }
  2574. });
  2575. baidu.getPCSLink();
  2576. });
  2577. doc.on('click', '.pl-button-save', async function (e) {
  2578. e.preventDefault();
  2579. selectList = baidu.getSelectedList();
  2580. if (selectList.length === 0) {
  2581. return message.error('提示:<br/>请勾选要保存到网盘的文件哦~');
  2582. }
  2583. message.info('提示:<br/>因网盘限制,请保存到自己网盘后再去下载哦~');
  2584. await base.sleep(500);
  2585. document.querySelector('.tools-share-save-hb').click();
  2586. });
  2587. doc.on('click', '.listener-link-api.browser', async function (e) {
  2588. e.preventDefault();
  2589. let dataset = e.currentTarget.dataset;
  2590. let href = dataset.link;
  2591. $('#downloadIframe').attr('src', href);
  2592. });
  2593. doc.on('click', '.listener-link-api.blob', async function (e) {
  2594. e.preventDefault();
  2595. let o = _factory(e);
  2596. let $width = o.item.find('.pl-progress-inner');
  2597. let $text = o.item.find('.pl-progress-inner-text');
  2598. let filename = o.link[0].dataset.filename;
  2599. let index = o.link[0].dataset.index;
  2600. _reset(index);
  2601. base.get(o.link[0].dataset.link, { "User-Agent": pan.ua }, 'blob', { filename, index });
  2602. let startTime = Date.now(); // 记录下载开始时间
  2603. let prevLoaded = 0; // 上一次的已下载数据量
  2604. let prevTime = startTime; // 上一次的时间
  2605. let size = Number(o.link[0].dataset.size);
  2606. ins[index] = setInterval(function () {
  2607. let prog = +progress[index] || 0;
  2608. let isIDM = idm[index] || false;
  2609.  
  2610. if (isIDM) {
  2611. // 处理IDM的代码
  2612. o.tip.hide();
  2613. o.progress.hide();
  2614. o.copy.show();
  2615. o.directLink.show()
  2616. o.link.text('链接已被IDM捕获~请查看IDM下载窗口哦!').animate({ opacity: '0.5' }, "slow").show();
  2617. clearInterval(ins[index]);
  2618. setTimeout(function () {
  2619. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  2620. }, 2000)
  2621. idm[index] = false;
  2622. } else {
  2623. // 处理普通下载的情况...
  2624. let currentTime = Date.now();
  2625. let elapsedTime = currentTime - startTime;
  2626. let totalProgress = prog / 100;
  2627. let totalElapsedSeconds = elapsedTime / 1000;
  2628. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  2629. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  2630.  
  2631. // 将剩余时间转换为天、时、分、秒
  2632. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  2633. remainingTimeSeconds %= (60 * 60 * 24);
  2634.  
  2635. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  2636. remainingTimeSeconds %= (60 * 60);
  2637.  
  2638. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  2639. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  2640.  
  2641. // 计算下载速度
  2642. let loaded = prog * size / 100; // 已下载数据量
  2643. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  2644. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  2645. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  2646.  
  2647. // 更新上一次的数据
  2648. prevLoaded = loaded;
  2649. prevTime = currentTime;
  2650.  
  2651. // 更改界面
  2652. o.link.hide();
  2653. o.directLink.hide();
  2654. o.tip.hide();
  2655. o.stop.show();
  2656. o.copy.hide();
  2657. o.progress.show();
  2658.  
  2659. // 更新进度条
  2660. $width.css('width', prog + '%');
  2661.  
  2662. // 更新进度条文本
  2663. let timeText = '';
  2664. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  2665. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  2666. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  2667. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  2668. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  2669. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  2670. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  2671. timeText = remainingSeconds + '秒';
  2672. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  2673. timeText = '即将完成';
  2674. } else {
  2675. timeText = '计算中...';
  2676. }
  2677.  
  2678. let speedText = '';
  2679. speedText = base.sizeFormat(downloadSpeed)
  2680. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  2681.  
  2682. if (prog === 100) {
  2683. setTimeout(function () {
  2684. clearInterval(ins[index]);
  2685. progress[index] = 0;
  2686. o.item.find('.pl-progress-stop').hide();
  2687. o.howidm.hide();
  2688. $text.text('下载完成了!浏览器下载框应该弹出来了哦~');
  2689. o.back.show()
  2690. setTimeout(function () {
  2691. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  2692. }, 3000)
  2693. }, 3000)
  2694. }
  2695. }
  2696. }, 500);
  2697. });
  2698. doc.on('click', '.listener-retry', async function (e) {
  2699. let o = _factory(e);
  2700. o.tip.hide();
  2701. o.link.show();
  2702. o.directLink.show();
  2703. });
  2704. doc.on('click', '.listener-how', async function (e) {
  2705. let o = _factory(e);
  2706. let index = o.link[0].dataset.index;
  2707. if (request[index]) {
  2708. request[index].abort();
  2709. clearInterval(ins[index]);
  2710. o.progress.hide();
  2711. o.tip.show();
  2712. }
  2713.  
  2714. });
  2715. doc.on('click', '.listener-stop', async function (e) {
  2716. let o = _factory(e);
  2717. let index = o.link[0].dataset.index;
  2718. if (request[index]) {
  2719. request[index].abort();
  2720. clearInterval(ins[index]);
  2721. o.item.find('.pl-progress-inner-text').text('正在取消...');
  2722. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  2723. setTimeout(function () {
  2724. o.tip.hide();
  2725. o.back.hide();
  2726. o.link.show();
  2727. o.directLink.show();
  2728. o.copy.show();
  2729. o.progress.hide();
  2730. o.stop.hide();
  2731. }, 1050)
  2732. }
  2733. });
  2734. doc.on('click', '.listener-back', async function (e) {
  2735. let o = _factory(e);
  2736. o.progress.hide();
  2737. o.tip.hide();
  2738. o.link.show();
  2739. o.directLink.show();
  2740. o.copy.show();
  2741. o.stop.hide();
  2742. o.back.hide();
  2743. });
  2744. doc.on('click', '.listener-download-all', function (e) {
  2745. $('.pl-item-link.blob').each(function () {
  2746. if ($(this).css('display') !== 'none') {
  2747. $(this).click();
  2748. }
  2749. });
  2750. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  2751. setTimeout(function () {
  2752. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  2753. }, 2000)
  2754. });
  2755. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  2756. e.preventDefault();
  2757. if (!e.target.dataset.link) {
  2758. $(e.target).removeClass('listener-copy-all').addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  2759. } else {
  2760. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  2761. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  2762. setTimeout(
  2763. function () {
  2764. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  2765. }, 2000
  2766. )
  2767. }
  2768. });
  2769. doc.on('click', '.listener-link-rpc', async function (e) {
  2770. e.preventDefault();
  2771. let target = $(e.currentTarget);
  2772.  
  2773. target.find('.icon-rpc-devices').remove();
  2774. target.find('.pl-loading').remove();
  2775. target.prepend(base.createLoading());
  2776.  
  2777. let res = await baidu.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  2778. if (res === 'success') {
  2779. $('.listener-rpc-task').show();
  2780. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  2781. } else if (res === 'assistant') {
  2782. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  2783. } else {
  2784. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  2785. }
  2786. });
  2787. doc.on('click', '.listener-send-rpc', function (e) {
  2788. $('.listener-link-rpc').click();
  2789. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  2790. });
  2791. doc.on('click', '.listener-open-setting', function () {
  2792. base.showSetting();
  2793. });
  2794. doc.on('click', '.listener-open-updatelog', function () {
  2795. base.showUpdateLog();
  2796. });
  2797. doc.on('click', '.listener-open-beautify', function () {
  2798. base.showBeautify();
  2799. });
  2800. doc.on('click', '.listener-rpc-task', function (e) {
  2801. e.preventDefault();
  2802. let rpc = JSON.stringify({
  2803. domain: base.getValue('setting_rpc_domain'),
  2804. port: base.getValue('setting_rpc_port'),
  2805. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  2806. GM_openInTab(url, { active: true });
  2807. });
  2808. document.documentElement.addEventListener('mouseup', function (e) {
  2809. if (e.target.nodeName === 'A' && ~e.target.className.indexOf('pl-a')) {
  2810. e.stopPropagation();
  2811. }
  2812. }, true);
  2813. },
  2814.  
  2815. removeAD() {
  2816. base.waitForKeyElements(".wp-s-header-user__vip-center", function (tag) {
  2817. tag.remove();
  2818. });
  2819. base.waitForKeyElements(".wp-s-header-user__create-team-content", function (tag) {
  2820. tag.remove();
  2821. });
  2822. base.waitForKeyElements(".app-user-vip-center-box.vip-center-type-2", function (tag) {
  2823. tag.remove();
  2824. }, true);
  2825. base.waitForKeyElements(".wp-s-header__vip-btn-tip", function (tag) {
  2826. tag.fadeToggle();
  2827. }, true);
  2828. base.waitForKeyElements(".app-user-vip-center-tip", function (tag) {
  2829. tag.fadeToggle();
  2830. }, true);
  2831. base.waitForKeyElements("#web-header-text-s-45", function (tag) {
  2832. tag.fadeToggle();
  2833. }, true);
  2834. base.waitForKeyElements(".wp-s-header__vip-btn", function (tag) {
  2835. tag[0].innerText = "会员中心";
  2836. }, true);
  2837. base.waitForKeyElements(".KQcHyA", function (tag) {
  2838. tag[0].innerText = "会员中心";
  2839. }, true);
  2840. base.waitForKeyElements(".gOIbzPb", function (tag) {
  2841. tag.fadeToggle();
  2842. }, true);
  2843. base.waitForKeyElements(".wp-s-header-user__create-team-title", function (tag) {
  2844. tag.fadeToggle();
  2845. }, true);
  2846. base.waitForKeyElements(".web-header-ad-item", function (tag) {
  2847. tag.fadeToggle();
  2848. });
  2849. base.waitForKeyElements(".wp-s-header__game-entry", function (tag) {
  2850. tag.fadeToggle();
  2851. }, true)
  2852. base.waitForKeyElements(".bd-aside-ad", function (tag) {
  2853. tag.fadeToggle();
  2854. }, true)
  2855. base.waitForKeyElements(".btn-img-tips", function (tag) {
  2856. tag.fadeToggle();
  2857. }, true)
  2858. base.waitForKeyElements(".nd-operate-guidance", function (tag) {
  2859. tag.fadeToggle();
  2860. }, true)
  2861. base.waitForKeyElements(".module-operation-content", function (tag) {
  2862. tag[0].remove()
  2863. document.querySelector(".module-canvas").click();
  2864. }, true)
  2865. base.waitForKeyElements(".newIcon", function (tag) {
  2866. tag.fadeToggle();
  2867. }, true);
  2868. base.waitForKeyElements(".u-badge__content.is-dot", function (tag) {
  2869. tag.fadeToggle();
  2870. }, true);
  2871. base.waitForKeyElements(".wp-side-options.g-clearfix", function (tag) {
  2872. tag.fadeToggle();
  2873. }, true);
  2874. base.waitForKeyElements(".wp-s-header-user__drop-channel", function (tag) {
  2875. tag.fadeToggle();
  2876. }, true);
  2877. base.waitForKeyElements(".app-download", function (tag) {
  2878. tag.fadeToggle();
  2879. }, true);
  2880. base.waitForKeyElements('.g-button[title="保存到手机"]', function (tag) {
  2881. tag.fadeToggle();
  2882. }, true)
  2883. base.waitForKeyElements('.yike-entrance', function (tag) {
  2884. tag.remove();
  2885. })
  2886. base.waitForKeyElements("p.wp-s-aside-nav__main-item-text", function (tag) {
  2887. if (tag[0].innerHTML.match(/(插件|相册|笔记)/) && tag[0].closest('a') && tag[0].closest('a').getAttribute('target') !== "_blank") {
  2888. $(tag[0].closest('a')).fadeToggle();
  2889. } else {
  2890. tag[0].innerHTML = tag[0].innerHTML.replace("百度", "");
  2891. }
  2892. }, true);
  2893. base.waitForKeyElements('dd[node-type="header-link"]', function (tag) {
  2894. tag.children().each(function () {
  2895. let tag = $(this);
  2896. if (!tag.attr("node-type")) return;
  2897. let type = tag.attr("node-type");
  2898. if (
  2899. type !== "disk-home" &&
  2900. type !== "mbox-homepage" &&
  2901. type !== "find-apps"
  2902. ) {
  2903. tag.fadeToggle();
  2904. }
  2905. });
  2906. }, true);
  2907. base.waitForKeyElements(".__yunguanjia", function (tag) {
  2908. tag[0].innerHTML = `
  2909. <div class="yunguanjia-list __yunguanjia row g-clearfix _item sel">
  2910. <span type="radio" class="radio-box _radioInput __yunguanjiaRadio">
  2911. <span class="device-name">添加我的电脑</span>
  2912. </span>
  2913. <div class="__yunguanjiaTips radio-tips" style="display: block;">
  2914. 用电脑下载并登录最新百度网盘客户端,即自动完成添加。
  2915. <a href="//pan.baidu.com/download" target="_blank">下载百度网盘客户端</a>
  2916. <br/>
  2917. <a>(改)网盘直链下载助手</a> 修复该选项
  2918. </div>
  2919. </div>`;
  2920. }, true)
  2921. // 美化分享页面
  2922. if (pt === 'share') {
  2923. base.waitForKeyElements(`iframe[src^="/buy/ad"]`, function (tag) {
  2924. tag.fadeToggle();
  2925. }, true)
  2926. base.waitForKeyElements(`.theme-white.init-new`, function (tag) {
  2927. 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'
  2928. }, true)
  2929. base.waitForKeyElements(`#layoutApp`, function (tag) {
  2930. 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'
  2931. 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'
  2932. }, true)
  2933. base.waitForKeyElements(`#bd-main .bd-left`, function (tag) {
  2934. tag[0].style.background = '#ffffffC0';
  2935. tag[0].style.borderRadius = '10px';
  2936.  
  2937. }, true)
  2938. base.waitForKeyElements(`.KPDwCE`, function (tag) {
  2939. tag[0].style.setProperty('background', 'transparent');
  2940. }, true)
  2941. base.waitForKeyElements('.share-list .KPDwCE .AuPKyz', function (tag) {
  2942. tag[0].style.setProperty('background', 'transparent');
  2943. }, true)
  2944. }
  2945. },
  2946.  
  2947. addButton() {
  2948. if (!pt) return;
  2949. let $toolWrap;
  2950. let $button = $(`
  2951. <div class="g-dropdown-button pointer pl-button">
  2952. <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>
  2953. <div class="menu" style="color: ${color};border-color: ${color};width:auto;z-index:41;">
  2954. <div class="g-button-menu pl-button-mode" data-mode="api">API下载</div>
  2955. <div class="g-button-menu pl-button-mode" data-mode="aria">Aria下载</div>
  2956. <div class="g-button-menu pl-button-mode" data-mode="rpc">RPC下载</div>
  2957. <div class="g-button-menu pl-button-mode" data-mode="curl">cURL下载</div>
  2958. <div class="g-button-menu pl-button-mode" data-mode="bc">BC下载</div>
  2959. <div class="g-button-menu pl-button-mode listener-open-setting">助手设置</div>
  2960. <div class="g-button-menu pl-button-mode listener-open-beautify">助手美化</div>
  2961. <div class="g-button-menu pl-button-mode listener-open-updatelog">更新日志</div>
  2962. </div>
  2963. </div>
  2964. `);
  2965. if (pt === 'home') $toolWrap = pan.btn.home;
  2966. if (pt === 'main') {
  2967. $toolWrap = pan.btn.main;
  2968. $button = $(`
  2969. <div class="wp-s-agile-tool-bar__h-group pl-button">
  2970. <div class="wp-s-agile-tool-bar__h-action is-need-left-sep is-main">
  2971. <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">
  2972. <i class="u-icon u-icon-download"></i>
  2973. <span>下载助手</span>
  2974. </button>
  2975. <ul class="dropdown-list nd-common-float-menu pl-dropdown-menu">
  2976. <li class="sub cursor-p pl-button-mode" data-mode="api">API下载</li>
  2977. <li class="sub cursor-p pl-button-mode" data-mode="aria">Aria下载</li>
  2978. <li class="sub cursor-p pl-button-mode" data-mode="rpc">RPC下载</li>
  2979. <li class="sub cursor-p pl-button-mode" data-mode="curl">cURL下载</li>
  2980. <li class="sub cursor-p pl-button-mode" data-mode="bc">BC下载</li>
  2981. <li class="sub cursor-p pl-button-mode listener-open-setting">助手设置</li>
  2982. <li class="sub cursor-p pl-button-mode listener-open-beautify">助手美化</li>
  2983. <li class="sub cursor-p pl-button-mode listener-open-updatelog">更新日志</li>
  2984. </ul>
  2985. </div>
  2986. </div>`);
  2987. }
  2988. if (pt === 'youth') {
  2989. $toolWrap = pan.btn.main;
  2990. $button = $(`
  2991. <div class="wp-s-agile-tool-bar__h-group pl-button">
  2992. <div class="wp-s-agile-tool-bar__h-action is-need-left-sep is-main">
  2993. <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">
  2994. <i class="u-icon u-icon-more"></i>
  2995. <span>网盘助手</span>
  2996. </button>
  2997. <ul class="dropdown-list nd-common-float-menu pl-dropdown-menu">
  2998. <li class="sub cursor-p pl-button-mode listener-open-setting">助手设置</li>
  2999. <li class="sub cursor-p pl-button-mode listener-open-beautify">助手美化</li>
  3000. <li class="sub cursor-p pl-button-mode listener-open-updatelog">更新日志</li>
  3001. </ul>
  3002. </div>
  3003. </div>`);
  3004. }
  3005. if (pt === 'share') {
  3006. $toolWrap = pan.btn.share;
  3007. $button = $(`
  3008. <div class="g-dropdown-button pointer pl-button">
  3009. <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>
  3010. <div class="menu" style="color: ${color};border-color: ${color};width:auto;z-index:41;">
  3011. <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>
  3012. <div class="g-button-menu pl-button-mode listener-open-setting">助手设置</div>
  3013. <div class="g-button-menu pl-button-mode listener-open-beautify">助手美化</div>
  3014. <div class="g-button-menu pl-button-mode listener-open-updatelog">更新日志</div>
  3015. </div>
  3016. </div>
  3017. `);
  3018. }
  3019. base.listenElement($toolWrap, function () {
  3020. $toolWrap = $($toolWrap);
  3021. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  3022. })
  3023. this.setBDUSS();
  3024. base.createDownloadIframe();
  3025. },
  3026.  
  3027. addInitButton() {
  3028. if (!pt) return;
  3029. let $toolWrap;
  3030. 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>`);
  3031. if (pt === 'home') {
  3032. $toolWrap = pan.btn.home;
  3033. }
  3034. if (pt === 'main' || pt === 'youth') {
  3035. $toolWrap = pan.btn.main;
  3036. $button = $(`
  3037. <div class="wp-s-agile-tool-bar__h-group pl-button-init">
  3038. <div class="wp-s-agile-tool-bar__h-action is-need-left-sep is-main">
  3039. <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">
  3040. <i class="u-icon u-icon-download"></i>
  3041. <span>点我点亮</span>
  3042. </button>
  3043. </div>
  3044. </div>`);
  3045. }
  3046. if (pt === 'share') $toolWrap = pan.btn.share;
  3047. $button.click(function () { base.initDialog() });
  3048. base.listenElement($toolWrap, function () {
  3049. $toolWrap = $($toolWrap);
  3050. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  3051. })
  3052. },
  3053.  
  3054. async getToken() {
  3055. function openTab() {
  3056. GM_openInTab(pan.pcs[3], { active: true, insert: true, setParent: true });
  3057. base.deleteValue('baidu_access_token');
  3058. };
  3059.  
  3060. const waitForToken = function () {
  3061. new Promise((resolve) => {
  3062. let attempts = 0;
  3063. const interval = setInterval(function () {
  3064. const token = base.getValue('baidu_access_token');
  3065. if (token) {
  3066. clearInterval(interval);
  3067. resolve(token);
  3068. }
  3069. attempts++;
  3070. if (attempts > 60) {
  3071. clearInterval(interval);
  3072. resolve('');
  3073. }
  3074. }, 1000);
  3075. })
  3076. };
  3077.  
  3078. if (manageHandler === 'Tampermonkey' && base.getMajorVersion(manageVersion) >= 5) {
  3079. openTab();
  3080. return waitForToken();
  3081. }
  3082.  
  3083. let res = await base.getFinalUrl(pan.pcs[3]);
  3084.  
  3085. if (!res.includes('authorize') && !res.includes('access_token=')) {
  3086. openTab();
  3087. return waitForToken();
  3088. }
  3089.  
  3090. if (res.includes('authorize')) {
  3091. // 使用await关键字等待base.get函数的返回结果,获取网页内容
  3092. let html = await base.get(pan.pcs[3], {}, 'text');
  3093.  
  3094. // 使用正则表达式匹配html中的'bdstoken'和'client_id'
  3095. let bdstoken = html.match(/name="bdstoken"\s+value="([^"]+)"/)?.[1];
  3096. let client_id = html.match(/name="client_id"\s+value="([^"]+)"/)?.[1];
  3097.  
  3098. // 构建一个包含所需参数的数据对象,包含百度授权所需参数
  3099. let data = {
  3100. grant_permissions_arr: 'netdisk',
  3101. bdstoken: bdstoken,
  3102. client_id: client_id,
  3103. response_type: "token",
  3104. display: "page",
  3105. grant_permissions: "basic,netdisk"
  3106. };
  3107.  
  3108. // 向服务器发送POST请求,实现自动授权
  3109. await base.post(pan.pcs[3], base.stringify(data), {
  3110. 'Content-Type': 'application/x-www-form-urlencoded',
  3111. });
  3112.  
  3113. // 授权完后再次获取'access_token'
  3114. let res2 = await base.getFinalUrl(pan.pcs[3]);
  3115. let accessToken = res2.match(/access_token=([^&]+)/)?.[1];
  3116. accessToken && base.setValue('baidu_access_token', accessToken);
  3117. return accessToken;
  3118. };
  3119. // 如果已有'access_token',则获取新的'access_token'
  3120. let accessToken = res.match(/access_token=([^&]+)/)?.[1];
  3121. accessToken && base.setValue('baidu_access_token', accessToken);
  3122. return accessToken;
  3123. },
  3124.  
  3125. async getPCSLink() {
  3126. selectList = this.getSelectedList();
  3127. let fidList = this._getFidList(), url, res;
  3128.  
  3129. if (pt === 'home' || pt === 'main') {
  3130. if (selectList.length === 0) {
  3131. return message.error('提示:<br/>先勾选要下载的文件哦~');
  3132. }
  3133. if (fidList.length === 2) {
  3134. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  3135. }
  3136. fidList = encodeURIComponent(fidList);
  3137. let accessToken = base.getValue('baidu_access_token')
  3138. if (!accessToken || accessToken === undefined) {
  3139. message.error('提示:<br/>稍后请在新标签页中授权助手获取信息~');
  3140. return setTimeout(async function () {
  3141. await baidu.getToken();
  3142. }, 1500)
  3143. }
  3144. url = `${pan.pcs[0]}&fsids=${fidList}&access_token=${accessToken}`;
  3145. res = await base.get(url, { "User-Agent": pan.ua });
  3146. } else {
  3147. return message.error('提示:<br/>页面错误~');
  3148. this.getShareData();
  3149. if (!params.bdstoken) {
  3150. return message.error('提示:<br/>请先登录网盘~');
  3151. }
  3152. if (selectList.length === 0) {
  3153. return message.error('提示:<br/>请勾选要下载的文件哦~');
  3154. }
  3155. if (fidList.length === 2) {
  3156. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  3157. }
  3158. }
  3159. if (res.list[0] && (res.errno === 0 || res.errmsg === "succ")) {
  3160. let html = this.generateDom(res.list);
  3161. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  3162. } else if (res.errno === 112) {
  3163. return message.error('提示:<br/>页面过期了,刷新重试下吧~<br/>代码:' + res.errno);
  3164. } else if (res.errno === 9019) {
  3165. return message.error('提示:<br/>获取下载链接失败,刷新网页后再试试吧~<br/>代码:' + res.errno);
  3166. } else {
  3167. base.deleteValue('baidu_access_token');
  3168. if (res.errno) {
  3169. return message.error('提示:<br/>获取下载链接失败,刷新网页后再试试吧~<br/>代码:' + res.errno);
  3170. } else {
  3171. return message.error('提示:<br/>获取下载链接失败,刷新网页后再试试吧~');
  3172. }
  3173. }
  3174. },
  3175.  
  3176. generateDom(list) {
  3177. let content = '<div class="pl-main">';
  3178. let alinkAllText = '';
  3179. base.sortByName(list);
  3180. list.forEach((v, i) => {
  3181. if (v.isdir === 1) return;
  3182. let filename = v.server_filename || v.filename;
  3183. let ext = base.getExtension(filename);
  3184. let size = base.sizeFormat(v.size);
  3185. let dlink = v.dlink + '&access_token=' + base.getValue('baidu_access_token');
  3186. if (mode === 'api') {
  3187. alinkAllText += dlink + '\r\n';
  3188. content += `<div class="pl-item">
  3189. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3190. <button class="pl-item-link listener-tip pl-btn-primary listener-link-api blob" data-title="推荐使用本功能,基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载有可能会被 IDM 捕获下载链接" data-filename="${filename}" data-size="${v.size}" data-link="${dlink}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  3191. <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>
  3192. <button class="pl-item-copy listener-tip pl-btn-primary listener-copy-all" href="${dlink}" data-title="不建议使用本功能,在本网盘单独复制链接并粘贴下载可能会导致服务器回报 403 错误" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  3193. <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>
  3194. <div class="pl-item-progress" style="display: none">
  3195. <div class="pl-progress">
  3196. <div class="pl-progress-outer"></div>
  3197. <div class="pl-progress-inner" style="width:5%">
  3198. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  3199. </div>
  3200. </div>
  3201. <span class="pl-progress-stop listener-stop">取消下载</span>
  3202. `;
  3203. content += `<span class="pl-progress-tip" style="display: none" >未发现IDM,使用自带浏览器下载</span>
  3204. <span class="pl-progress-back listener-back" style="display: none">返回</span>
  3205. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  3206. `;
  3207. content += `</div></div>`
  3208. }
  3209. if (mode === 'aria') {
  3210. let alink = this.convertLinkToAria(dlink, filename, pan.ua);
  3211. if (typeof (alink) === 'object') {
  3212. content += `<div class="pl-item">
  3213. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3214. <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>`;
  3215. } else {
  3216. alinkAllText += alink + '\r\n';
  3217. content += `<div class="pl-item">
  3218. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3219. <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>`;
  3220. }
  3221. }
  3222. if (mode === 'rpc') {
  3223. content += `<div class="pl-item">
  3224. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3225. <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>`;
  3226. }
  3227. if (mode === 'curl') {
  3228. let alink = this.convertLinkToCurl(dlink, filename, pan.ua);
  3229. if (typeof (alink) === 'object') {
  3230. content += `<div class="pl-item">
  3231. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3232. <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>`;
  3233. } else {
  3234. alinkAllText += alink + '\r\n';
  3235. content += `<div class="pl-item">
  3236. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3237. <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>`;
  3238. }
  3239. }
  3240. if (mode === 'bc') {
  3241. let alink = this.convertLinkToBC(dlink, filename, pan.ua);
  3242. if (typeof (alink) === 'object') {
  3243. alinkAllText += decodeURIComponent(alink.text) + '\r\n';
  3244. content += `<div class="pl-item">
  3245. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3246. <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>`;
  3247. } else {
  3248. alinkAllText += alink + '\r\n';
  3249. content += `<div class="pl-item">
  3250. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  3251. <a class="pl-item-link pl-a" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a> </div>`;
  3252. }
  3253. }
  3254. });
  3255.  
  3256. content += '</div>';
  3257.  
  3258. if (mode === 'api')
  3259. content += `<div class="pl-extra"><button class="pl-btn-primary listener-download-all">全部增强下载</button><button class="pl-btn-primary listener-tip listener-copy-all" data-link="${alinkAllText}" data-title="不建议使用本功能,在本网盘单独复制链接并粘贴下载可能会导致服务器回报 403 错误">复制全部链接</button></div>`;
  3260. if (mode === 'aria')
  3261. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  3262. if (mode === 'rpc') {
  3263. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  3264. 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>`;
  3265. }
  3266. if (mode === 'curl') {
  3267. 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>`;
  3268. }
  3269. if (mode === 'bc') {
  3270. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  3271. }
  3272. return content;
  3273. },
  3274.  
  3275. async sendLinkToRPC(filename, link) {
  3276. let rpc = {
  3277. domain: base.getValue('setting_rpc_domain'),
  3278. port: base.getValue('setting_rpc_port'),
  3279. path: base.getValue('setting_rpc_path'),
  3280. token: base.getValue('setting_rpc_token'),
  3281. dir: base.getValue('setting_rpc_dir'),
  3282. };
  3283. let BDUSS = this.getBDUSS();
  3284. if (!BDUSS) return 'assistant';
  3285.  
  3286. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  3287. let rpcData = {
  3288. id: new Date().getTime(),
  3289. jsonrpc: '2.0',
  3290. method: 'aria2.addUri',
  3291. params: [`token:${rpc.token}`, [link], {
  3292. dir: rpc.dir,
  3293. out: filename,
  3294. header: [`User-Agent: ${pan.ua}`, `Cookie: BDUSS=${BDUSS}`]
  3295. }]
  3296. };
  3297. try {
  3298. let res = await base.post(url, rpcData, { "User-Agent": pan.ua }, '');
  3299. if (res.result) return 'success';
  3300. return 'fail';
  3301. } catch (e) {
  3302. return 'fail';
  3303. }
  3304. },
  3305.  
  3306. getSelectedList() {
  3307. var List, selectList
  3308. try {
  3309. List = require("system-core:context/context.js").instanceForSystem.list;
  3310. selectList = List.getSelected();
  3311. /*if (!selectList.length) {
  3312. selectList = List.getCurrentList();
  3313. }*/
  3314. return selectList;
  3315. } catch (e) { }
  3316. try {
  3317. List = unsafeWindow.document.querySelector('.wp-s-core-pan');
  3318. if (List && List.__vue__.selectedList) {
  3319. selectList = List.__vue__.selectedList;
  3320. return selectList;
  3321. }
  3322. } catch (e) { }
  3323. try {
  3324. List = unsafeWindow.document.querySelector('.file-list');
  3325. if (List && List.__vue__.allFileList) {
  3326. selectList = List.__vue__.allFileList.filter(function (item) { return !!item.selected; });
  3327. return selectList;
  3328. }
  3329. } catch (e) { }
  3330. },
  3331.  
  3332. getLogid() {
  3333. let ut = require("system-core:context/context.js").instanceForSystem.tools.baseService;
  3334. return ut.base64Encode(base.getCookie("BAIDUID"));
  3335. },
  3336.  
  3337. getShareData() {
  3338. let res = locals.dump();
  3339. params.shareType = 'secret';
  3340. params.sign = '';
  3341. params.timestamp = '';
  3342. params.bdstoken = res.bdstoken.value;
  3343. params.channel = 'chunlei';
  3344. params.clienttype = 0;
  3345. params.web = 1;
  3346. params.app_id = 250528;
  3347. params.encrypt = 0;
  3348. params.product = 'share';
  3349. params.logid = this.getLogid();
  3350. params.primaryid = res.shareid.value;
  3351. params.uk = res.share_uk.value;
  3352. params.shareType === 'secret' && (params.extra = this._getExtra());
  3353. params.surl = this._getSurl();
  3354. },
  3355.  
  3356. detectPage() {
  3357. let path = location.pathname;
  3358. if (/^\/disk\/home/.test(path)) return 'home';
  3359. if (/^\/disk\/main/.test(path)) return 'main';
  3360. if (/^\/youth\/pan\/main/.test(path)) return 'youth';
  3361. if (/^\/(s|share)\//.test(path)) return 'share';
  3362. return '';
  3363. },
  3364.  
  3365. showMainDialog(title, html, footer) {
  3366. Swal.fire({
  3367. title,
  3368. html,
  3369. footer,
  3370. allowOutsideClick: false,
  3371. showCloseButton: true,
  3372. heightAuto: false,
  3373. scrollbarPadding: false,
  3374. position: 'center',
  3375. width,
  3376. padding: '15px 20px 5px',
  3377. customClass,
  3378. confirmButtonText: '关闭',
  3379. }).then(function () {
  3380. this._resetData();
  3381. });
  3382. },
  3383.  
  3384. async initAuthorize() {
  3385. base.registerMenuCommand();
  3386. Swal.fire({
  3387. heightAuto: false,
  3388. scrollbarPadding: false,
  3389. showConfirmButton: false,
  3390. allowOutsideClick: false,
  3391. allowEscapeKey: false,
  3392. allowEnterKey: false,
  3393. html: `请稍后`,
  3394. willOpen: function () {
  3395. Swal.showLoading();
  3396. },
  3397. });
  3398. if (base.getValue('setting_youxiaohou_server') === 'v1') {
  3399. let res = await base.post(`https://api.youxiaohou.com/config/?ver=${version}&a=${author}`, {}, {}, 'text');
  3400. pan = JSON.parse(base.decode(res));
  3401. } else if (base.getValue('setting_youxiaohou_server') === 'v2') {
  3402. let res = await base.post(`https://api.youxiaohou.com/config/v2/?ver=${version}&a=${author}`, {}, {}, 'text');
  3403. pan = JSON.parse(base.decode(res));
  3404. } else if (base.getValue('setting_youxiaohou_server') === "no") {
  3405. 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", {});
  3406. pan = JSON.parse(res);
  3407. } else {
  3408. 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", {});
  3409. pan = JSON.parse(res);
  3410. base.setValue('setting_youxiaohou_server', 'v2');
  3411. }
  3412. Object.freeze && Object.freeze(pan);
  3413. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('license')) {
  3414. let url = new URL(location.href)
  3415. let auth = new URL(pan.pcs[3])
  3416. if (
  3417. /openapi.baidu.com\/oauth\/2.0\/authorize/.test(location.href) &&
  3418. (location.href.includes('basic+netdisk') || location.href.includes('basic,netdisk')) &&
  3419. (
  3420. url.searchParams.get("client_id") === auth.searchParams.get("client_id")/* ||
  3421. url.searchParams.get("client_id") === 'L6g70tBRRIXLsY0Z3HwKqlRE' || // pcstest_oauth
  3422. url.searchParams.get("client_id") === 'fSds3K4w43rw37tOqlQmTa2kDwaczK4U' || // 小度智能词典笔专业版
  3423. url.searchParams.get("client_id") === 'TFwtw8uwHxpdkvVqVKdIlx1XqXUnr1zG' || // 印象笔记
  3424. url.searchParams.get("client_id") === '9dgBV9yesuBVOXaxls7aVHbLBLqU8yyg' || // WPS文档
  3425. url.searchParams.get("client_id") === 'IlLqBbU3GjQ0t46TRwFateTprHWl39zF' // 百度手机助手 */
  3426. )
  3427. ) {
  3428. let dialog = await Swal.fire({
  3429. icon: 'info',
  3430. title: `提示`,
  3431. html: '你好呀,为了获取百度网盘文件的下载直链<br/>我们需要您的授权来使 “下载助手” 读取您的网盘数据<br/><br/>由于使用了别的应用ID,所以授权的应用名称会有不同<br/>获取到的数据仅用于生成直链,请放心授权ヾ(≧▽≦*)o',
  3432. showConfirmButton: true,
  3433. showDenyButton: true,
  3434. allowOutsideClick: false,
  3435. allowEscapeKey: false,
  3436. allowEnterKey: false,
  3437. confirmButtonText: '授权',
  3438. denyButtonText: '再想想',
  3439. position: 'center'
  3440. });
  3441. if (dialog.isConfirmed) {
  3442. base.waitForKeyElements("button#auth-allow", function (element) {
  3443. element[0].click();
  3444. })
  3445. return;
  3446. }
  3447. if (dialog.isDenied) {
  3448. let dialog = await Swal.fire({
  3449. icon: 'question',
  3450. title: `好吧(* ̄3 ̄)╭`,
  3451. html: '那就再想一想<br/>想好了就按下 “授权” 按钮吧~',
  3452. timer: 180000,
  3453. toast: true,
  3454. timerProgressBar: true,
  3455. showConfirmButton: false,
  3456. showDenyButton: false,
  3457. position: 'bottom-end',
  3458. })
  3459. return;
  3460. }
  3461. } else if (/openapi.baidu.com\/oauth\/2.0\/login_success/.test(location.href)) {
  3462. let int = setInterval(async function () {
  3463. if (location.href.includes('access_token') && (location.href.includes('basic+netdisk') || location.href.includes('basic,netdisk'))) {
  3464. clearInterval(int)
  3465. let token = location.href.match(/access_token=(.*?)&/)[1];
  3466. base.setValue('baidu_access_token', token);
  3467. let dialog = await Swal.fire({
  3468. icon: 'success',
  3469. title: `成功啦`,
  3470. html: '你已 成功授权/授权过 脚本读取您的网盘数据<br/>等待 <span id="second">3</span> 秒之后将关闭此页面',
  3471. timer: 3000,
  3472. timerProgressBar: true,
  3473. showConfirmButton: true,
  3474. showDenyButton: false,
  3475. allowOutsideClick: false,
  3476. allowEscapeKey: false,
  3477. allowEnterKey: false,
  3478. confirmButtonText: '关闭页面',
  3479. position: 'center',
  3480. willOpen: function () {
  3481. let sec = 3.1;
  3482. setInterval(() => {
  3483. sec -= 0.1;
  3484. document.getElementById("second").innerText = sec.toFixed(1);
  3485. }, 100);
  3486. setTimeout(() => {
  3487. window.close()
  3488. }, 3100);
  3489. },
  3490. });
  3491. if (dialog.isConfirmed) {
  3492. window.close()
  3493. return;
  3494. }
  3495. } else {
  3496. clearInterval(int)
  3497. Swal.close()
  3498. }
  3499. }, 1)
  3500. } else {
  3501. Swal.close()
  3502. }
  3503. } else {
  3504. Swal.close()
  3505. }
  3506. },
  3507.  
  3508. async initPanLinker() {
  3509. pt = this.detectPage();
  3510. base.createTip();
  3511. base.registerMenuCommand();
  3512. if (base.getValue('setting_youxiaohou_server') === 'v1') {
  3513. let res = await base.post(`https://api.youxiaohou.com/config/?ver=${version}&a=${author}`, {}, {}, 'text');
  3514. pan = JSON.parse(base.decode(res));
  3515. } else if (base.getValue('setting_youxiaohou_server') === 'v2') {
  3516. let res = await base.post(`https://api.youxiaohou.com/config/v2/?ver=${version}&a=${author}`, {}, {}, 'text');
  3517. pan = JSON.parse(base.decode(res));
  3518. } else if (base.getValue('setting_youxiaohou_server') === "no") {
  3519. 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", {});
  3520. pan = JSON.parse(res);
  3521. } else {
  3522. 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", {});
  3523. pan = JSON.parse(res);
  3524. base.setValue('setting_youxiaohou_server', 'v2');
  3525. }
  3526. Object.freeze && Object.freeze(pan);
  3527. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('license')) {
  3528. this.addButton();
  3529. this.addPageListener();
  3530. } else {
  3531. this.addInitButton();
  3532. }
  3533. },
  3534. };
  3535.  
  3536. //阿里云盘
  3537. let ali = {
  3538.  
  3539. convertLinkToAria(link, filename, ua) {
  3540. filename = base.fixFilename(filename);
  3541. return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "Referer: https://${location.host}/"`);
  3542. },
  3543.  
  3544. convertLinkToBC(link, filename, ua) {
  3545. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&refer=${encodeURIComponent(`https://${location.host}/`)}ZZ`;
  3546. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  3547. },
  3548.  
  3549. convertLinkToCurl(link, filename, ua) {
  3550. let terminal = base.getValue('setting_terminal_type');
  3551. filename = base.fixFilename(filename);
  3552. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}" -e "https://${location.host}/"`);
  3553. },
  3554.  
  3555. addPageListener() {
  3556. /*
  3557. 防止代码因其他原因被执行多次
  3558. 这段代码出自 Via轻插件,作者谷花泰
  3559. */
  3560. const key = encodeURIComponent('(改)网盘直链下载助手:阿里云盘');
  3561. if (window[key]) return;
  3562. window[key] = true;
  3563.  
  3564. function _factory(e) {
  3565. let target = $(e.target);
  3566. let item = target.parents('.pl-item');
  3567. let link = item.find('.pl-item-link.blob');
  3568. let directLink = item.find('.pl-item-link.browser');
  3569. let progress = item.find('.pl-item-progress');
  3570. let tip = item.find('.pl-item-tip');
  3571. let copy = item.find('.pl-item-copy');
  3572. let howidm = item.find('.pl-progress-how');
  3573. let back = item.find('.pl-progress-back');
  3574. let stop = item.find('.pl-progress-stop');
  3575. return {
  3576. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  3577. };
  3578. }
  3579.  
  3580. function _reset(i) {
  3581. ins[i] && clearInterval(ins[i]);
  3582. request[i] && request[i].abort();
  3583. progress[i] = 0;
  3584. idm[i] = false;
  3585. }
  3586. doc.on('click', '.pl-button-mode', function (e) {
  3587. mode = e.target.dataset.mode;
  3588. if (!mode) return;
  3589. Swal.fire({
  3590. heightAuto: false,
  3591. scrollbarPadding: false,
  3592. showConfirmButton: false,
  3593. html: `链接获取中`,
  3594. willOpen: function () {
  3595. Swal.showLoading();
  3596. }
  3597. });
  3598. ali.getPCSLink();
  3599. });
  3600. doc.on('click', '.listener-link-api.browser', async function (e) {
  3601. e.preventDefault();
  3602. let dataset = e.currentTarget.dataset;
  3603. let href = dataset.link;
  3604. $('#downloadIframe').attr('src', href);
  3605. });
  3606. doc.on('click', '.listener-link-api.blob', async function (e) {
  3607. e.preventDefault();
  3608. let o = _factory(e);
  3609. let $width = o.item.find('.pl-progress-inner');
  3610. let $text = o.item.find('.pl-progress-inner-text');
  3611. let filename = o.link[0].dataset.filename;
  3612. let index = o.link[0].dataset.index;
  3613. _reset(index);
  3614. let dataset = e.currentTarget.dataset;
  3615. let href = dataset.link;
  3616. //let url = await this.getRealLink(dataset.did, dataset.fid);
  3617. //if (url) href = url;
  3618. base.get(href, { "Referer": `https://${location.host}/` }, 'blob', { filename, index });
  3619. let startTime = Date.now(); // 记录下载开始时间
  3620. let prevLoaded = 0; // 上一次的已下载数据量
  3621. let prevTime = startTime; // 上一次的时间
  3622. let size = Number(o.link[0].dataset.size);
  3623. ins[index] = setInterval(function () {
  3624. let prog = +progress[index] || 0;
  3625. // 处理普通下载的情况...
  3626. let currentTime = Date.now();
  3627. let elapsedTime = currentTime - startTime;
  3628. let totalProgress = prog / 100;
  3629. let totalElapsedSeconds = elapsedTime / 1000;
  3630. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  3631. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  3632.  
  3633. // 将剩余时间转换为天、时、分、秒
  3634. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  3635. remainingTimeSeconds %= (60 * 60 * 24);
  3636.  
  3637. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  3638. remainingTimeSeconds %= (60 * 60);
  3639.  
  3640. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  3641. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  3642.  
  3643. // 计算下载速度
  3644. let loaded = prog * size / 100; // 已下载数据量
  3645. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  3646. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  3647. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  3648.  
  3649. // 更新上一次的数据
  3650. prevLoaded = loaded;
  3651. prevTime = currentTime;
  3652.  
  3653. // 更改界面
  3654. o.link.hide();
  3655. o.directLink.hide();
  3656. o.tip.hide();
  3657. o.stop.show();
  3658. o.copy.hide();
  3659. o.progress.show();
  3660.  
  3661. // 更新进度条
  3662. $width.css('width', prog + '%');
  3663.  
  3664. // 更新进度条文本
  3665. let timeText = '';
  3666. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  3667. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  3668. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  3669. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  3670. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  3671. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  3672. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  3673. timeText = remainingSeconds + '秒';
  3674. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  3675. timeText = '即将完成';
  3676. } else {
  3677. timeText = '计算中...';
  3678. }
  3679.  
  3680. let speedText = '';
  3681. speedText = base.sizeFormat(downloadSpeed)
  3682.  
  3683. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  3684.  
  3685. if (prog === 100) {
  3686. setTimeout(function () {
  3687. clearInterval(ins[index]);
  3688. progress[index] = 0;
  3689. o.item.find('.pl-progress-stop').hide();
  3690. o.howidm.hide();
  3691. $text.text('下载完成了!浏览器下载框应该弹出来了哦~');
  3692. o.back.show()
  3693. setTimeout(function () {
  3694. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  3695. }, 3000)
  3696. }, 3000)
  3697. }
  3698. }, 500);
  3699. });
  3700. doc.on('click', '.listener-retry', async function (e) {
  3701. let o = _factory(e);
  3702. o.tip.hide();
  3703. o.link.show();
  3704. o.directLink.show();
  3705. });
  3706. doc.on('click', '.listener-how', async function (e) {
  3707. let o = _factory(e);
  3708. let index = o.link[0].dataset.index;
  3709. if (request[index]) {
  3710. request[index].abort();
  3711. clearInterval(ins[index]);
  3712. o.progress.hide();
  3713. o.tip.show();
  3714. }
  3715.  
  3716. });
  3717. doc.on('click', '.listener-stop', async function (e) {
  3718. let o = _factory(e);
  3719. let index = o.link[0].dataset.index;
  3720. if (request[index]) {
  3721. request[index].abort();
  3722. clearInterval(ins[index]);
  3723. o.item.find('.pl-progress-inner-text').text('正在取消...');
  3724. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  3725. setTimeout(function () {
  3726. o.tip.hide();
  3727. o.back.hide();
  3728. o.link.show();
  3729. o.directLink.show();
  3730. o.copy.show();
  3731. o.progress.hide();
  3732. o.stop.hide();
  3733. }, 1050)
  3734. }
  3735. });
  3736. doc.on('click', '.listener-back', async function (e) {
  3737. let o = _factory(e);
  3738. o.progress.hide();
  3739. o.tip.hide();
  3740. o.link.show();
  3741. o.directLink.show();
  3742. o.copy.show();
  3743. o.stop.hide();
  3744. o.back.hide();
  3745. });
  3746. doc.on('click', '.listener-copy-filename', async function (e) {
  3747. base.setClipboard(e.target.dataset.filename);
  3748. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  3749. setTimeout(function () {
  3750. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  3751. }, 2000)
  3752. });
  3753. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  3754. e.preventDefault();
  3755. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  3756. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  3757. setTimeout(function () {
  3758. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  3759. }, 2000)
  3760. });
  3761. doc.on('click', '.listener-link-rpc', async function (e) {
  3762. e.preventDefault();
  3763. let target = $(e.currentTarget);
  3764.  
  3765. target.find('.icon-rpc-devices').remove();
  3766. target.find('.pl-loading').remove();
  3767. target.prepend(base.createLoading());
  3768.  
  3769. let res = await ali.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  3770. if (res === 'success') {
  3771. $('.listener-rpc-task').show();
  3772. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  3773. } else if (res === 'assistant') {
  3774. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  3775. } else {
  3776. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  3777. }
  3778. });
  3779. doc.on('click', '.listener-send-rpc', function (e) {
  3780. $('.listener-link-rpc').click();
  3781. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  3782. });
  3783. doc.on('click', '.listener-download-all.blob', function (e) {
  3784. $('.pl-item-link.blob').each(function () {
  3785. if ($(this).css('display') !== 'none') {
  3786. $(this).click();
  3787. }
  3788. });
  3789. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  3790. setTimeout(function () {
  3791. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  3792. }, 2000)
  3793. });
  3794. doc.on('click', '.listener-open-setting', function () {
  3795. base.showSetting();
  3796. });
  3797. doc.on('click', '.listener-open-updatelog', function () {
  3798. base.showUpdateLog();
  3799. });
  3800. doc.on('click', '.listener-open-beautify', function () {
  3801. base.showBeautify();
  3802. });
  3803. doc.on('click', '.listener-rpc-task', function () {
  3804. let rpc = JSON.stringify({
  3805. domain: base.getValue('setting_rpc_domain'),
  3806. port: base.getValue('setting_rpc_port'),
  3807. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  3808. GM_openInTab(url, { active: true });
  3809. });
  3810. document.documentElement.addEventListener('mouseup', function (e) {
  3811. if (e.target.nodeName === 'A' && ~e.target.className.indexOf('pl-a')) {
  3812. e.stopPropagation();
  3813. }
  3814. }, true);
  3815. },
  3816.  
  3817. async getRealLink(d, f) {
  3818. let authorization = `${base.getStorage('token').token_type} ${base.getStorage('token').access_token}`;
  3819. let res = await base.post(pan.pcs[1], {
  3820. drive_id: d,
  3821. file_id: f
  3822. }, {
  3823. authorization,
  3824. "content-type": "application/json;charset=utf-8",
  3825. "referer": "https://www.aliyundrive.com/",
  3826. "x-canary": "client=windows,app=adrive,version=v6.0.0"
  3827. });
  3828. if (res.code === 'AccessTokenInvalid') {
  3829. return message.error('提示:<br/>Token过期了,请刷新网页后再试');
  3830. }
  3831. if (res.url) {
  3832. return res.url;
  3833. }
  3834. return '';
  3835. },
  3836.  
  3837. removeAD() {
  3838. base.waitForKeyElements('[class*="share-list-banner"]', function (tag) {
  3839. tag.fadeToggle();
  3840. }, true);
  3841. base.waitForKeyElements('[class*="to-app"]', function (tag) {
  3842. tag.fadeToggle();
  3843. }, true);
  3844. base.waitForKeyElements('[class*="btn-mobile-save"]', function (tag) {
  3845. tag.fadeToggle();
  3846. });
  3847. base.waitForKeyElements('div[class*="text"]', function (tag) {
  3848. if (tag[0].innerHTML.match("SVIP"))
  3849. tag.fadeToggle();
  3850. }, true);
  3851. base.waitForKeyElements('[class*="SplashScreenImg--close"]', function (tag) {
  3852. tag[0].click();
  3853. }, true);
  3854. base.waitForKeyElements('[class*="container"]', function (tag) {
  3855. tag.find('[class^="icon-close"]').click();
  3856. }, true);
  3857. base.waitForKeyElements('[class*="popup_main_close"]', function (tag) {
  3858. tag[0].click();
  3859. }, true);
  3860. },
  3861.  
  3862. addButton() {
  3863. if (!pt) return;
  3864. let $toolWrap;
  3865. 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>`
  3866. 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>`);
  3867. if (pt === 'home') {
  3868. base.listenElement(pan.btn.home, function () {
  3869. $toolWrap = $(pan.btn.home);
  3870. $('.pl-button').length === 0 && $toolWrap.append($button);
  3871. })
  3872. }
  3873. if (pt === 'share') {
  3874. $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>`);
  3875. $button.css({ 'margin-right': '10px', "height": "36px", "width": "auto", "padding": "1px 30px" });
  3876. base.listenElement(pan.btn.share, function () {
  3877. $toolWrap = $(pan.btn.share);
  3878. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  3879. })
  3880. }
  3881. base.createDownloadIframe();
  3882. },
  3883.  
  3884. addInitButton() {
  3885. if (!pt) return;
  3886. let $toolWrap;
  3887. 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>`);
  3888. $button.css({ "width": "auto" });
  3889. if (pt === 'home') {
  3890. base.listenElement(pan.btn.home, function () {
  3891. $toolWrap = $(pan.btn.home);
  3892. $('.pl-button-init').length === 0 && $toolWrap.append($button);
  3893. })
  3894. }
  3895. if (pt === 'share') {
  3896. $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>`);
  3897. $button.css({ 'margin-right': '10px', "height": "36px", "padding": "1px 30px", "width": "auto" });
  3898. base.listenElement(pan.btn.share, function () {
  3899. $toolWrap = $(pan.btn.share);
  3900. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  3901. })
  3902. }
  3903. $button.click(function () { base.initDialog() });
  3904. },
  3905.  
  3906. async getPCSLink() {
  3907. let reactDomGrid = document.querySelector(pan.dom.grid);
  3908. if (reactDomGrid) {
  3909. let dialog = await Swal.fire({
  3910. title: '提示',
  3911. 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>',
  3912. icon: 'info',
  3913. showCloseButton: true,
  3914. showDenyButton: true,
  3915. heightAuto: false,
  3916. scrollbarPadding: false,
  3917. confirmButtonText: '切换',
  3918. denyButtonText: '不要'
  3919. });
  3920. if (dialog.isConfirmed) {
  3921. document.querySelector(pan.dom.switch).click();
  3922. return message.success('提示:<br/>切换为列表视图成功<br/>请再获取一次下载链接吧~');
  3923. }
  3924. return false;
  3925. }
  3926. selectList = this.getSelectedList();
  3927. if (selectList.length === 0) {
  3928. return message.error('提示:<br/>请勾选要下载的文件哦~');
  3929. }
  3930. if (this.isOnlyFolder()) {
  3931. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  3932. }
  3933. if (pt === 'share') {
  3934. if (selectList.length > 20) {
  3935. return message.error('提示:<br/>一次最多只能勾选 20 个文件哦!');
  3936. }
  3937. try {
  3938. let authorization = `${base.getStorage('token').token_type} ${base.getStorage('token').access_token}`;
  3939. let xShareToken = base.getStorage('shareToken').share_token;
  3940.  
  3941. for (let i = 0; i < selectList.length; i++) {
  3942. let res = await base.post(pan.pcs[0], {
  3943. expire_sec: 600,
  3944. file_id: selectList[i].fileId,
  3945. share_id: selectList[i].shareId
  3946. }, {
  3947. authorization,
  3948. "content-type": "application/json;charset=utf-8",
  3949. "x-share-token": xShareToken
  3950. });
  3951. if (res.download_url) {
  3952. selectList[i].downloadUrl = res.download_url;
  3953. }
  3954. }
  3955. } catch (e) {
  3956. return message.error('提示:<br/>请先登录网盘~');
  3957. }
  3958. } else {
  3959. if (selectList.length > 20) {
  3960. return message.error('提示:<br/>每次最多只能选 20 个文件哦~');
  3961. }
  3962. let noUrlSelectList = selectList.filter(v => !Boolean(v.url))
  3963. let queue = [];
  3964. noUrlSelectList.forEach((item, index) => {
  3965. queue.push(this.getRealLink(item.driveId, item.fileId));
  3966. });
  3967.  
  3968. const res = await Promise.all(queue);
  3969. res.forEach((val, index) => {
  3970. noUrlSelectList[index].url = val;
  3971. });
  3972.  
  3973. }
  3974. let html = this.generateDom(selectList);
  3975. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  3976. },
  3977.  
  3978. generateDom(list) {
  3979. let content = '<div class="pl-main">';
  3980. let alinkAllText = '';
  3981. list.forEach((v, i) => {
  3982. if (v.type === 'folder') return;
  3983. let filename = v.name;
  3984. let fid = v.fileId;
  3985. let did = v.driveId;
  3986. let size = base.sizeFormat(v.size);
  3987. let dlink = v.downloadUrl || v.url;
  3988. if (mode === 'api') {
  3989. alinkAllText += dlink + '\r\n';
  3990. content += `<div class="pl-item">
  3991. <div class="pl-item-name listener-tip" data-size="${size}" >${filename}</div>
  3992. <button class="pl-item-link listener-tip pl-btn-primary listener-link-api blob" data-title="推荐使用本功能,基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接" data-did="${did}" data-fid="${fid}" data-filename="${filename}" data-link="${dlink}" data-size="${v.size}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  3993. <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>
  3994. <button class="pl-item-copy listener-tip pl-btn-primary pl-btn-success listener-copy-filename" data-title="本网盘于下载高峰期时可能不会显示文件名称,这时需要手动复制文件名称到下载工具中" data-filename="${filename}">复制名称</button>
  3995. <button class="pl-item-copy listener-tip pl-btn-primary listener-copy-all" href="${dlink}" data-title="不建议使用本功能,在本网盘单独复制链接并粘贴下载可能会导致服务器回报 403 错误" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  3996. <div class="pl-item-tip" style="display: none"><span><span class="pl-ext"></span></span> <span class="listener-back">返回</span></div>
  3997. <div class="pl-item-progress" style="display: none">
  3998. <div class="pl-progress">
  3999. <div class="pl-progress-outer"></div>
  4000. <div class="pl-progress-inner" style="width:5%">
  4001. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  4002. </div>
  4003. </div>
  4004. <span class="pl-progress-stop listener-stop">取消下载</span>
  4005. `;
  4006. content += `<span class="pl-progress-back listener-back" style="display: none">返回</span>
  4007. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  4008. `;
  4009. content += `</div></div>`;
  4010. }
  4011. if (mode === 'aria') {
  4012. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  4013. alinkAllText += alink + '\r\n';
  4014. content += `<div class="pl-item">
  4015. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4016. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  4017. }
  4018. if (mode === 'rpc') {
  4019. content += `<div class="pl-item">
  4020. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4021. <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>`;
  4022. }
  4023. if (mode === 'curl') {
  4024. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  4025. alinkAllText += alink + '\r\n';
  4026. content += `<div class="pl-item">
  4027. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4028. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  4029. }
  4030. if (mode === 'bc') {
  4031. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  4032. alinkAllText += alink + '\r\n';
  4033. content += `<div class="pl-item">
  4034. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4035. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a> </div>`;
  4036. }
  4037. });
  4038. content += '</div>';
  4039. if (mode === 'api')
  4040. content += `<div class="pl-extra"><button class="pl-btn-primary listener-download-all blob">全部增强下载</button><button class="pl-btn-primary listener-tip listener-copy-all" data-link="${alinkAllText}" data-title="不建议使用本功能,在本网盘单独复制链接并粘贴下载可能会导致服务器回报 403 错误">复制全部链接</button></div>`;
  4041. if (mode === 'aria')
  4042. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  4043. if (mode === 'rpc') {
  4044. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  4045. 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>`;
  4046. }
  4047. if (mode === 'curl') {
  4048. 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>`;
  4049. }
  4050. if (mode === 'bc') {
  4051. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  4052. }
  4053. return content;
  4054. },
  4055.  
  4056. async sendLinkToRPC(filename, link) {
  4057. let rpc = {
  4058. domain: base.getValue('setting_rpc_domain'),
  4059. port: base.getValue('setting_rpc_port'),
  4060. path: base.getValue('setting_rpc_path'),
  4061. token: base.getValue('setting_rpc_token'),
  4062. dir: base.getValue('setting_rpc_dir'),
  4063. };
  4064.  
  4065. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  4066. let rpcData = {
  4067. id: new Date().getTime(),
  4068. jsonrpc: '2.0',
  4069. method: 'aria2.addUri',
  4070. params: [`token:${rpc.token}`, [link], {
  4071. dir: rpc.dir,
  4072. out: filename,
  4073. header: [`Referer: https://${location.host}/`]
  4074. }]
  4075. };
  4076. try {
  4077. let res = await base.post(url, rpcData, { "Referer": `https://${location.host}/` }, '');
  4078. if (res.result) return 'success';
  4079. return 'fail';
  4080. } catch (e) {
  4081. return 'fail';
  4082. }
  4083. },
  4084.  
  4085. getSelectedList() {
  4086. try {
  4087. let selectedList = [];
  4088. let reactDom = document.querySelector(pan.dom.list);
  4089. let reactObj = base.findReact(reactDom, 1);
  4090. let props = reactObj.pendingProps;
  4091. if (props) {
  4092. let fileList = props.dataSource || [];
  4093. let selectedKeys = props.selectedKeys.split(',');
  4094. fileList.forEach(function (val) {
  4095. if (selectedKeys.includes(val.fileId)) {
  4096. selectedList.push(val);
  4097. }
  4098. });
  4099. }
  4100. return selectedList;
  4101. } catch (e) {
  4102. return [];
  4103. }
  4104. },
  4105.  
  4106. detectPage() {
  4107. let path = location.pathname;
  4108. if (/^\/(drive)/.test(path)) return 'home';
  4109. if (/^\/(s|share)\//.test(path)) return 'share';
  4110. return '';
  4111. },
  4112.  
  4113. isOnlyFolder() {
  4114. for (let i = 0; i < selectList.length; i++) {
  4115. if (selectList[i].type === 'file') return false;
  4116. }
  4117. return true;
  4118. },
  4119.  
  4120. showMainDialog(title, html, footer) {
  4121. Swal.fire({
  4122. title,
  4123. html,
  4124. footer,
  4125. allowOutsideClick: false,
  4126. showCloseButton: true,
  4127. position: 'center',
  4128. width,
  4129. padding: '15px 20px 5px',
  4130. customClass,
  4131. confirmButtonText: '关闭',
  4132. });
  4133. },
  4134.  
  4135. async initPanLinker() {
  4136. pt = this.detectPage();
  4137. base.createTip();
  4138. base.registerMenuCommand();
  4139. if (base.getValue('setting_youxiaohou_server') === 'v1') {
  4140. let res = await base.post(`https://api.youxiaohou.com/config/ali/?ver=${version}&a=${author}`, {}, {}, 'text');
  4141. pan = JSON.parse(base.decode(res));
  4142. } else if (base.getValue('setting_youxiaohou_server') === 'v2') {
  4143. let res = await base.post(`https://api.youxiaohou.com/config/v2/ali/?ver=${version}&a=${author}`, {}, {}, 'text');
  4144. pan = JSON.parse(base.decode(res));
  4145. } else if (base.getValue('setting_youxiaohou_server') === "no") {
  4146. 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", {});
  4147. pan = JSON.parse(res);
  4148. } else {
  4149. 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", {});
  4150. pan = JSON.parse(res);
  4151. base.setValue('setting_youxiaohou_server', 'v2');
  4152. }
  4153. Object.freeze && Object.freeze(pan);
  4154. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('license')) {
  4155. this.addButton();
  4156. this.addPageListener();
  4157. } else {
  4158. this.addInitButton();
  4159. }
  4160. }
  4161. };
  4162.  
  4163. //天翼云盘
  4164. let tianyi = {
  4165.  
  4166. convertLinkToAria(link, filename, ua) {
  4167. filename = base.fixFilename(filename);
  4168. return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
  4169. },
  4170.  
  4171. convertLinkToBC(link, filename, ua) {
  4172. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
  4173. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  4174. },
  4175.  
  4176. convertLinkToCurl(link, filename, ua) {
  4177. let terminal = base.getValue('setting_terminal_type');
  4178. filename = base.fixFilename(filename);
  4179. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}"`);
  4180. },
  4181.  
  4182. addPageListener() {
  4183. /*
  4184. 防止代码因其他原因被执行多次
  4185. 这段代码出自 Via轻插件,作者谷花泰
  4186. */
  4187. const key = encodeURIComponent('(改)网盘直链下载助手:天翼云盘');
  4188. if (window[key]) return;
  4189. window[key] = true;
  4190.  
  4191. function _factory(e) {
  4192. let target = $(e.target);
  4193. let item = target.parents('.pl-item');
  4194. let link = item.find('.pl-item-link.blob');
  4195. let directLink = item.find('.pl-item-link.browser');
  4196. let progress = item.find('.pl-item-progress');
  4197. let tip = item.find('.pl-item-tip');
  4198. let copy = item.find('.pl-item-copy');
  4199. let howidm = item.find('.pl-progress-how');
  4200. let back = item.find('.pl-progress-back');
  4201. let stop = item.find('.pl-progress-stop');
  4202. return {
  4203. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  4204. };
  4205. }
  4206.  
  4207. function _reset(i) {
  4208. ins[i] && clearInterval(ins[i]);
  4209. request[i] && request[i].abort();
  4210. progress[i] = 0;
  4211. idm[i] = false;
  4212. }
  4213.  
  4214. doc.on('click', '.pl-button-mode', function (e) {
  4215. mode = e.target.dataset.mode;
  4216. if (!mode) return;
  4217. Swal.fire({
  4218. heightAuto: false,
  4219. scrollbarPadding: false,
  4220. showConfirmButton: false,
  4221. html: `链接获取中`,
  4222. willOpen: function () {
  4223. Swal.showLoading();
  4224. }
  4225. });
  4226. tianyi.getPCSLink();
  4227. });
  4228. doc.on('click', '.listener-link-api.browser', async function (e) {
  4229. e.preventDefault();
  4230. let dataset = e.currentTarget.dataset;
  4231. let href = dataset.link;
  4232. $('#downloadIframe').attr('src', href);
  4233. });
  4234. doc.on('click', '.listener-link-api.blob', async function (e) {
  4235. e.preventDefault();
  4236. let o = _factory(e);
  4237. let $width = o.item.find('.pl-progress-inner');
  4238. let $text = o.item.find('.pl-progress-inner-text');
  4239. let filename = o.link[0].dataset.filename;
  4240. let index = o.link[0].dataset.index;
  4241. _reset(index);
  4242. let dataset = e.currentTarget.dataset;
  4243. let href = dataset.link;
  4244. base.get(href, { "Referer": `https://${location.host}/` }, 'blob', { filename, index });
  4245. let startTime = Date.now(); // 记录下载开始时间
  4246. let prevLoaded = 0; // 上一次的已下载数据量
  4247. let prevTime = startTime; // 上一次的时间
  4248. let size = Number(o.link[0].dataset.size);
  4249. ins[index] = setInterval(function () {
  4250. let prog = +progress[index] || 0;
  4251. // 处理普通下载的情况...
  4252. let currentTime = Date.now();
  4253. let elapsedTime = currentTime - startTime;
  4254. let totalProgress = prog / 100;
  4255. let totalElapsedSeconds = elapsedTime / 1000;
  4256. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  4257. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  4258.  
  4259. // 将剩余时间转换为天、时、分、秒
  4260. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  4261. remainingTimeSeconds %= (60 * 60 * 24);
  4262.  
  4263. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  4264. remainingTimeSeconds %= (60 * 60);
  4265.  
  4266. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  4267. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  4268.  
  4269. // 计算下载速度
  4270. let loaded = prog * size / 100; // 已下载数据量
  4271. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  4272. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  4273. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  4274.  
  4275. // 更新上一次的数据
  4276. prevLoaded = loaded;
  4277. prevTime = currentTime;
  4278.  
  4279. // 更改界面
  4280. o.link.hide();
  4281. o.directLink.hide();
  4282. o.tip.hide();
  4283. o.stop.show();
  4284. o.copy.hide();
  4285. o.progress.show();
  4286.  
  4287. // 更新进度条
  4288. $width.css('width', prog + '%');
  4289.  
  4290. // 更新进度条文本
  4291. let timeText = '';
  4292. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  4293. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  4294. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  4295. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  4296. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  4297. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  4298. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  4299. timeText = remainingSeconds + '秒';
  4300. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  4301. timeText = '即将完成';
  4302. } else {
  4303. timeText = '计算中...';
  4304. }
  4305.  
  4306. let speedText = '';
  4307. speedText = base.sizeFormat(downloadSpeed)
  4308. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  4309.  
  4310. if (prog === 100) {
  4311. setTimeout(function () {
  4312. clearInterval(ins[index]);
  4313. progress[index] = 0;
  4314. o.item.find('.pl-progress-stop').hide();
  4315. o.howidm.hide();
  4316. $text.text('下载完成了!浏览器下载框应该弹出来了哦~');
  4317. o.back.show()
  4318. setTimeout(function () {
  4319. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  4320. }, 3000)
  4321. }, 3000)
  4322. }
  4323. }, 500);
  4324. });
  4325. doc.on('click', '.listener-retry', async function (e) {
  4326. let o = _factory(e);
  4327. o.tip.hide();
  4328. o.link.show();
  4329. o.directLink.show();
  4330. });
  4331. doc.on('click', '.listener-how', async function (e) {
  4332. let o = _factory(e);
  4333. let index = o.link[0].dataset.index;
  4334. if (request[index]) {
  4335. request[index].abort();
  4336. clearInterval(ins[index]);
  4337. o.progress.hide();
  4338. o.tip.show();
  4339. }
  4340.  
  4341. });
  4342. doc.on('click', '.listener-stop', async function (e) {
  4343. let o = _factory(e);
  4344. let index = o.link[0].dataset.index;
  4345. if (request[index]) {
  4346. request[index].abort();
  4347. clearInterval(ins[index]);
  4348. o.item.find('.pl-progress-inner-text').text('正在取消...');
  4349. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  4350. setTimeout(function () {
  4351. o.tip.hide();
  4352. o.back.hide();
  4353. o.link.show();
  4354. o.directLink.show();
  4355. o.copy.show();
  4356. o.progress.hide();
  4357. o.stop.hide();
  4358. }, 1050)
  4359. }
  4360. });
  4361. doc.on('click', '.listener-back', async function (e) {
  4362. let o = _factory(e);
  4363. o.progress.hide();
  4364. o.tip.hide();
  4365. o.link.show();
  4366. o.directLink.show();
  4367. o.copy.show();
  4368. o.stop.hide();
  4369. o.back.hide();
  4370. });
  4371. doc.on('click', '.listener-download-all', function (e) {
  4372. $('.pl-item-link.blob').each(function () {
  4373. if ($(this).css('display') !== 'none') {
  4374. $(this).click();
  4375. }
  4376. });
  4377. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  4378. setTimeout(function () {
  4379. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  4380. }, 2000)
  4381. });
  4382. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  4383. e.preventDefault();
  4384. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  4385. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  4386. setTimeout(function () {
  4387. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  4388. }, 2000)
  4389. });
  4390. doc.on('click', '.listener-link-rpc', async function (e) {
  4391. e.preventDefault();
  4392. let target = $(e.currentTarget);
  4393.  
  4394. target.find('.icon-rpc-devices').remove();
  4395. target.find('.pl-loading').remove();
  4396. target.prepend(base.createLoading());
  4397.  
  4398. let res = await tianyi.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  4399. if (res === 'success') {
  4400. $('.listener-rpc-task').show();
  4401. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  4402. } else if (res === 'assistant') {
  4403. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  4404. } else {
  4405. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  4406. }
  4407. });
  4408. doc.on('click', '.listener-send-rpc', function (e) {
  4409. $('.listener-link-rpc').click();
  4410. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  4411. });
  4412. doc.on('click', '.listener-open-setting', function () {
  4413. base.showSetting();
  4414. });
  4415. doc.on('click', '.listener-open-updatelog', function () {
  4416. base.showUpdateLog();
  4417. });
  4418. doc.on('click', '.listener-open-beautify', function () {
  4419. base.showBeautify();
  4420. });
  4421. doc.on('click', '.listener-rpc-task', function () {
  4422. let rpc = JSON.stringify({
  4423. domain: base.getValue('setting_rpc_domain'),
  4424. port: base.getValue('setting_rpc_port'),
  4425. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  4426. GM_openInTab(url, { active: true });
  4427. });
  4428. },
  4429.  
  4430. removeAD() {
  4431. base.waitForKeyElements(".advertising-mask", function (tag) {
  4432. tag.fadeToggle();
  4433. }, true);
  4434. base.waitForKeyElements("a.client-download.nav-block", function (tag) {
  4435. tag.fadeToggle();
  4436. }, true);
  4437. },
  4438.  
  4439. addButton() {
  4440. if (!pt) return;
  4441. let $toolWrap;
  4442. 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>`);
  4443. if (pt === 'home') {
  4444. base.listenElement(pan.btn.home, function () {
  4445. $toolWrap = $(pan.btn.home);
  4446. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  4447. })
  4448. }
  4449. if (pt === 'share') {
  4450. base.listenElement(pan.btn.share, function () {
  4451. $toolWrap = $(pan.btn.share);
  4452. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  4453. })
  4454. }
  4455. base.createDownloadIframe();
  4456. },
  4457.  
  4458. addInitButton() {
  4459. if (!pt) return;
  4460. let $toolWrap;
  4461. let $button = $(`<div class="tianyi-button pl-button-init">点我点亮</div>`);
  4462. if (pt === 'home') {
  4463. base.listenElement(pan.btn.home, function () {
  4464. $toolWrap = $(pan.btn.home);
  4465. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  4466. })
  4467. }
  4468. if (pt === 'share') {
  4469. $button.css({ 'margin-right': '10px' });
  4470. base.listenElement(pan.btn.share, function () {
  4471. $toolWrap = $(pan.btn.share);
  4472. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  4473. })
  4474. }
  4475. $button.click(function () { base.initDialog() });
  4476. },
  4477.  
  4478. async getToken() {
  4479. let res = await base.getFinalUrl(pan.pcs[1], {});
  4480. let accessToken = res.match(/accessToken=(\w+)/)?.[1];
  4481. accessToken && base.setStorage('accessToken', accessToken);
  4482. return accessToken;
  4483. },
  4484.  
  4485. async getFileUrlByOnce(item, index, token) {
  4486. try {
  4487. if (item.downloadUrl) return {
  4488. index,
  4489. downloadUrl: item.downloadUrl
  4490. };
  4491. let time = Date.now(),
  4492. fileId = item.fileId,
  4493. o = "AccessToken=" + token + "&Timestamp=" + time + "&fileId=" + fileId,
  4494. url = pan.pcs[2] + '?fileId=' + fileId;
  4495. if (item.shareId) {
  4496. o = "AccessToken=" + token + "&Timestamp=" + time + "&dt=1&fileId=" + fileId + "&shareId=" + item.shareId;
  4497. url += '&dt=1&shareId=' + item.shareId;
  4498. }
  4499. let sign = md5(o).toString();
  4500. let res = await base.get(url, {
  4501. "accept": "application/json;charset=UTF-8",
  4502. "sign-type": 1,
  4503. "accesstoken": token,
  4504. "timestamp": time,
  4505. "signature": sign
  4506. });
  4507. if (res.res_code === 0) {
  4508. return {
  4509. index,
  4510. downloadUrl: res.fileDownloadUrl
  4511. };
  4512. } else if (res.errorCode === 'InvalidSessionKey') {
  4513. return {
  4514. index,
  4515. downloadUrl: '提示:<br/>请先登录网盘~'
  4516. };
  4517. } else if (res.res_code === 'ShareNotFoundFlatDir') {
  4518. return {
  4519. index,
  4520. downloadUrl: '提示:<br/>请[转存]文件,之后再👉前往[我的网盘]中下载哦~'
  4521. };
  4522. } else {
  4523. return {
  4524. index,
  4525. downloadUrl: '获取下载地址失败,刷新后再试试吧~' + (res.res_code ? res.res_code : "")
  4526. };
  4527. }
  4528. } catch (e) {
  4529. return {
  4530. index,
  4531. downloadUrl: '获取下载地址失败,刷新后再试试吧~'
  4532. };
  4533. }
  4534. },
  4535.  
  4536. async getPCSLink() {
  4537. selectList = this.getSelectedList();
  4538. if (selectList.length === 0) {
  4539. return message.error('提示:<br/>请勾选要下载的文件哦~');
  4540. }
  4541. if (this.isOnlyFolder()) {
  4542. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  4543. }
  4544. let token = base.getStorage('accessToken') || await this.getToken();
  4545. if (!token) {
  4546. return message.error('提示:<br/>请先登录网盘~');
  4547. }
  4548. let queue = [];
  4549. for (const [index, item] of selectList.entries()) {
  4550. queue.push(this.getFileUrlByOnce(item, index, token));
  4551. }
  4552.  
  4553. const res = await Promise.all(queue);
  4554. res.forEach(val => {
  4555. selectList[val.index].downloadUrl = val.downloadUrl;
  4556. });
  4557.  
  4558. let html = this.generateDom(selectList);
  4559. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  4560. },
  4561.  
  4562. generateDom(list) {
  4563. let content = '<div class="pl-main">';
  4564. let alinkAllText = '';
  4565. list.forEach((v, i) => {
  4566. if (v.isFolder) return;
  4567. let filename = v.fileName;
  4568. let ext = base.getExtension(filename);
  4569. let size = base.sizeFormat(v.size);
  4570. let dlink = v.downloadUrl;
  4571. if (mode === 'api') {
  4572. alinkAllText += dlink + '\r\n';
  4573. content += `<div class="pl-item">
  4574. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4575. <button class="pl-item-link listener-tip pl-btn-primary listener-link-api blob" data-title="推荐使用本功能,基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接" data-filename="${filename}" data-size="${v.size}" data-link="${dlink}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  4576. <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>
  4577. <button class="pl-item-copy pl-btn-primary listener-copy-all" href="${dlink}" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  4578. <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>
  4579. <div class="pl-item-progress" style="display: none">
  4580. <div class="pl-progress">
  4581. <div class="pl-progress-outer"></div>
  4582. <div class="pl-progress-inner" style="width:5%">
  4583. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  4584. </div>
  4585. </div>
  4586. <span class="pl-progress-stop listener-stop">取消下载</span>
  4587. `;
  4588. content += `<span class="pl-progress-tip" style="display: none" >未发现IDM,使用自带浏览器下载</span>
  4589. <span class="pl-progress-back listener-back" style="display: none">返回</span>
  4590. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  4591. `;
  4592. content += `</div></div>`
  4593. }
  4594. if (mode === 'aria') {
  4595. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  4596. alinkAllText += alink + '\r\n';
  4597. content += `<div class="pl-item">
  4598. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4599. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  4600. }
  4601. if (mode === 'rpc') {
  4602. content += `<div class="pl-item">
  4603. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4604. <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>`;
  4605. }
  4606. if (mode === 'curl') {
  4607. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  4608. alinkAllText += alink + '\r\n';
  4609. content += `<div class="pl-item">
  4610. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4611. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  4612. }
  4613. if (mode === 'bc') {
  4614. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  4615. alinkAllText += alink + '\r\n';
  4616. content += `<div class="pl-item">
  4617. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  4618. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a> </div>`;
  4619. }
  4620. });
  4621. content += '</div>';
  4622. if (mode === 'api')
  4623. content += `<div class="pl-extra"><button class="pl-btn-primary listener-download-all">全部增强下载</button><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  4624. if (mode === 'aria')
  4625. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  4626. if (mode === 'rpc') {
  4627. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  4628. 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>`;
  4629. }
  4630. if (mode === 'curl') {
  4631. 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>`;
  4632. }
  4633. if (mode === 'bc') {
  4634. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  4635. }
  4636. return content;
  4637. },
  4638.  
  4639. async sendLinkToRPC(filename, link) {
  4640. let rpc = {
  4641. domain: base.getValue('setting_rpc_domain'),
  4642. port: base.getValue('setting_rpc_port'),
  4643. path: base.getValue('setting_rpc_path'),
  4644. token: base.getValue('setting_rpc_token'),
  4645. dir: base.getValue('setting_rpc_dir'),
  4646. };
  4647.  
  4648. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  4649. let rpcData = {
  4650. id: new Date().getTime(),
  4651. jsonrpc: '2.0',
  4652. method: 'aria2.addUri',
  4653. params: [`token:${rpc.token}`, [link], {
  4654. dir: rpc.dir,
  4655. out: filename,
  4656. header: []
  4657. }]
  4658. };
  4659. try {
  4660. let res = await base.post(url, rpcData, {}, '');
  4661. if (res.result) return 'success';
  4662. return 'fail';
  4663. } catch (e) {
  4664. return 'fail';
  4665. }
  4666. },
  4667.  
  4668. getSelectedList() {
  4669. try {
  4670. return document.querySelector(".c-file-list").__vue__.selectedList;
  4671. } catch (e) {
  4672. return [document.querySelector(".info-detail").__vue__.fileDetail];
  4673. }
  4674. },
  4675.  
  4676. detectPage() {
  4677. let path = location.pathname;
  4678. if (/^\/web\/main/.test(path)) return 'home';
  4679. if (/^\/web\/share/.test(path)) return 'share';
  4680. return '';
  4681. },
  4682.  
  4683. isOnlyFolder() {
  4684. for (let i = 0; i < selectList.length; i++) {
  4685. if (!selectList[i].isFolder) return false;
  4686. }
  4687. return true;
  4688. },
  4689.  
  4690. showMainDialog(title, html, footer) {
  4691. Swal.fire({
  4692. title,
  4693. html,
  4694. footer,
  4695. allowOutsideClick: false,
  4696. showCloseButton: true,
  4697. position: 'center',
  4698. width,
  4699. padding: '15px 20px 5px',
  4700. customClass,
  4701. confirmButtonText: '关闭',
  4702. });
  4703. },
  4704.  
  4705. async initPanLinker() {
  4706. pt = this.detectPage();
  4707. base.createTip();
  4708. base.registerMenuCommand();
  4709. if (base.getValue('setting_youxiaohou_server') === 'v1') {
  4710. let res = await base.post(`https://api.youxiaohou.com/config/tianyi/?ver=${version}&a=${author}`, {}, {}, 'text');
  4711. pan = JSON.parse(base.decode(res));
  4712. } else if (base.getValue('setting_youxiaohou_server') === 'v2') {
  4713. let res = await base.post(`https://api.youxiaohou.com/config/v2/tianyi/?ver=${version}&a=${author}`, {}, {}, 'text');
  4714. pan = JSON.parse(base.decode(res));
  4715. } else if (base.getValue('setting_youxiaohou_server') === "no") {
  4716. 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", {});
  4717. pan = JSON.parse(res);
  4718. } else {
  4719. 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", {});
  4720. pan = JSON.parse(res);
  4721. base.setValue('setting_youxiaohou_server', 'v2');
  4722. }
  4723. Object.freeze && Object.freeze(pan);
  4724. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('license')) {
  4725. this.addButton();
  4726. this.addPageListener();
  4727. } else {
  4728. this.addInitButton();
  4729. }
  4730. this.getToken();
  4731. }
  4732. };
  4733.  
  4734. //迅雷云盘
  4735. let xunlei = {
  4736.  
  4737. convertLinkToAria(link, filename, ua) {
  4738. filename = base.fixFilename(filename);
  4739. return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
  4740. },
  4741.  
  4742. convertLinkToBC(link, filename, ua) {
  4743. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
  4744. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  4745. },
  4746.  
  4747. convertLinkToCurl(link, filename, ua) {
  4748. let terminal = base.getValue('setting_terminal_type');
  4749. filename = base.fixFilename(filename);
  4750. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}"`);
  4751. },
  4752.  
  4753. addPageListener() {
  4754. /*
  4755. 防止代码因其他原因被执行多次
  4756. 这段代码出自 Via轻插件,作者谷花泰
  4757. */
  4758. const key = encodeURIComponent('(改)网盘直链下载助手:迅雷云盘');
  4759. if (window[key]) return;
  4760. window[key] = true;
  4761.  
  4762. function _factory(e) {
  4763. let target = $(e.target);
  4764. let item = target.parents('.pl-item');
  4765. let link = item.find('.pl-item-link.blob');
  4766. let directLink = item.find('.pl-item-link.browser');
  4767. let progress = item.find('.pl-item-progress');
  4768. let tip = item.find('.pl-item-tip');
  4769. let copy = item.find('.pl-item-copy');
  4770. let howidm = item.find('.pl-progress-how');
  4771. let back = item.find('.pl-progress-back');
  4772. let stop = item.find('.pl-progress-stop');
  4773. return {
  4774. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  4775. };
  4776. }
  4777.  
  4778. function _reset(i) {
  4779. ins[i] && clearInterval(ins[i]);
  4780. request[i] && request[i].abort();
  4781. progress[i] = 0;
  4782. idm[i] = false;
  4783. }
  4784.  
  4785. doc.on('click', '.pl-button-mode', function (e) {
  4786. mode = e.target.dataset.mode;
  4787. if (!mode) return;
  4788. Swal.fire({
  4789. heightAuto: false,
  4790. scrollbarPadding: false,
  4791. showConfirmButton: false,
  4792. html: `链接获取中`,
  4793. willOpen: function () {
  4794. Swal.showLoading();
  4795. }
  4796. });
  4797. xunlei.getPCSLink();
  4798. });
  4799. doc.on('click', '.pl-button-save', async function (e) {
  4800. e.preventDefault();
  4801. selectList = xunlei.getSelectedList();
  4802. if (selectList.length === 0) {
  4803. return message.error('提示:<br/>请勾选要保存到网盘的文件哦~');
  4804. }
  4805. message.info('提示:<br/>因网盘限制,请保存到自己网盘后再去下载哦~');
  4806. await base.sleep(500);
  4807. document.querySelector('.saveToCloud').click();
  4808. });
  4809. doc.on('click', '.listener-link-api.browser', async function (e) {
  4810. e.preventDefault();
  4811. let dataset = e.currentTarget.dataset;
  4812. let href = dataset.link;
  4813. $('#downloadIframe').attr('src', href);
  4814. });
  4815. doc.on('click', '.listener-link-api.blob', async function (e) {
  4816. e.preventDefault();
  4817. let o = _factory(e);
  4818. let $width = o.item.find('.pl-progress-inner');
  4819. let $text = o.item.find('.pl-progress-inner-text');
  4820. let filename = o.link[0].dataset.filename;
  4821. let index = o.link[0].dataset.index;
  4822. _reset(index);
  4823. let dataset = e.currentTarget.dataset;
  4824. let href = dataset.link;
  4825. base.get(href, { "Referer": `https://${location.host}/` }, 'blob', { filename, index });
  4826. let startTime = Date.now(); // 记录下载开始时间
  4827. let prevLoaded = 0; // 上一次的已下载数据量
  4828. let prevTime = startTime; // 上一次的时间
  4829. let size = Number(o.link[0].dataset.size);
  4830. ins[index] = setInterval(function () {
  4831. let prog = +progress[index] || 0;
  4832. let isIDM = idm[index] || false;
  4833.  
  4834. // 处理普通下载的情况...
  4835. let currentTime = Date.now();
  4836. let elapsedTime = currentTime - startTime;
  4837. let totalProgress = prog / 100;
  4838. let totalElapsedSeconds = elapsedTime / 1000;
  4839. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  4840. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  4841.  
  4842. // 将剩余时间转换为天、时、分、秒
  4843. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  4844. remainingTimeSeconds %= (60 * 60 * 24);
  4845.  
  4846. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  4847. remainingTimeSeconds %= (60 * 60);
  4848.  
  4849. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  4850. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  4851.  
  4852. // 计算下载速度
  4853. let loaded = prog * size / 100; // 已下载数据量
  4854. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  4855. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  4856. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  4857.  
  4858. // 更新上一次的数据
  4859. prevLoaded = loaded;
  4860. prevTime = currentTime;
  4861.  
  4862. // 更改界面
  4863. o.link.hide();
  4864. o.directLink.hide();
  4865. o.tip.hide();
  4866. o.stop.show();
  4867. o.copy.hide();
  4868. o.progress.show();
  4869.  
  4870. // 更新进度条
  4871. $width.css('width', prog + '%');
  4872.  
  4873. // 更新进度条文本
  4874. let timeText = '';
  4875. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  4876. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  4877. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  4878. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  4879. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  4880. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  4881. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  4882. timeText = remainingSeconds + '秒';
  4883. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  4884. timeText = '即将完成';
  4885. } else {
  4886. timeText = '计算中...';
  4887. }
  4888.  
  4889. let speedText = '';
  4890. speedText = base.sizeFormat(downloadSpeed)
  4891. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  4892.  
  4893. if (prog === 100) {
  4894. setTimeout(function () {
  4895. clearInterval(ins[index]);
  4896. progress[index] = 0;
  4897. o.item.find('.pl-progress-stop').hide();
  4898. o.howidm.hide();
  4899. $text.text('下载完成了!浏览器下载框应该弹出来了哦~');
  4900. o.back.show()
  4901. setTimeout(function () {
  4902. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  4903. }, 3000)
  4904. }, 3000)
  4905. }
  4906. }, 500);
  4907. });
  4908. doc.on('click', '.listener-retry', async function (e) {
  4909. let o = _factory(e);
  4910. o.tip.hide();
  4911. o.link.show();
  4912. o.directLink.show();
  4913. });
  4914. doc.on('click', '.listener-how', async function (e) {
  4915. let o = _factory(e);
  4916. let index = o.link[0].dataset.index;
  4917. if (request[index]) {
  4918. request[index].abort();
  4919. clearInterval(ins[index]);
  4920. o.progress.hide();
  4921. o.tip.show();
  4922. }
  4923.  
  4924. });
  4925. doc.on('click', '.listener-stop', async function (e) {
  4926. let o = _factory(e);
  4927. let index = o.link[0].dataset.index;
  4928. if (request[index]) {
  4929. request[index].abort();
  4930. clearInterval(ins[index]);
  4931. o.item.find('.pl-progress-inner-text').text('正在取消...');
  4932. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  4933. setTimeout(function () {
  4934. o.tip.hide();
  4935. o.back.hide();
  4936. o.link.show();
  4937. o.directLink.show();
  4938. o.copy.show();
  4939. o.progress.hide();
  4940. o.stop.hide();
  4941. }, 1050)
  4942. }
  4943. });
  4944. doc.on('click', '.listener-back', async function (e) {
  4945. let o = _factory(e);
  4946. o.progress.hide();
  4947. o.tip.hide();
  4948. o.link.show();
  4949. o.directLink.show();
  4950. o.copy.show();
  4951. o.stop.hide();
  4952. o.back.hide();
  4953. });
  4954. doc.on('click', '.listener-download-all', function (e) {
  4955. $('.pl-item-link.blob').each(function () {
  4956. if ($(this).css('display') !== 'none') {
  4957. $(this).click();
  4958. }
  4959. });
  4960. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  4961. setTimeout(function () {
  4962. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  4963. }, 2000)
  4964. });
  4965.  
  4966. doc.on('click', '.listener-copy-filename', async function (e) {
  4967. base.setClipboard(e.target.dataset.filename);
  4968. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  4969. setTimeout(function () {
  4970. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  4971. }, 2000)
  4972. });
  4973. doc.on('click', '.listener-link-bc-btn', async function (e) {
  4974. let mirror = base.getMirrorList(e.target.dataset.dlink, pan.mirror);
  4975. base.setClipboard(mirror);
  4976. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  4977. setTimeout(function () {
  4978. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  4979. }, 2000)
  4980. });
  4981. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  4982. e.preventDefault();
  4983. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  4984. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  4985. setTimeout(function () {
  4986. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  4987. }, 2000)
  4988. });
  4989. doc.on('click', '.listener-link-rpc', async function (e) {
  4990. e.preventDefault();
  4991. let target = $(e.currentTarget);
  4992.  
  4993. target.find('.icon-rpc-devices').remove();
  4994. target.find('.pl-loading').remove();
  4995. target.prepend(base.createLoading());
  4996.  
  4997. let res = await xunlei.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  4998. if (res === 'success') {
  4999. $('.listener-rpc-task').show();
  5000. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  5001. } else if (res === 'assistant') {
  5002. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  5003. } else {
  5004. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  5005. }
  5006. });
  5007. doc.on('click', '.listener-send-rpc', function (e) {
  5008. $('.listener-link-rpc').click();
  5009. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  5010. });
  5011. doc.on('click', '.listener-open-setting', function () {
  5012. base.showSetting();
  5013. });
  5014. doc.on('click', '.listener-open-updatelog', function () {
  5015. base.showUpdateLog();
  5016. });
  5017. doc.on('click', '.listener-open-beautify', function () {
  5018. base.showBeautify();
  5019. });
  5020. doc.on('click', '.listener-rpc-task', function () {
  5021. let rpc = JSON.stringify({
  5022. domain: base.getValue('setting_rpc_domain'),
  5023. port: base.getValue('setting_rpc_port'),
  5024. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  5025. GM_openInTab(url, { active: true });
  5026. });
  5027. },
  5028.  
  5029. addButton() {
  5030. if (!pt) return;
  5031. let $toolWrap;
  5032. let $button = $(`
  5033. <div class="xunlei-button pl-button"><i class="xlpfont xlp-download"></i><span style="font-size: 13px;margin-left: 6px;">下载助手</span>
  5034. <ul class="pl-dropdown-menu" style="top: 34px;">
  5035. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li>
  5036. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria">Aria下载</li>
  5037. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li>
  5038. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li>
  5039. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc">BC下载</li>
  5040. <li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>
  5041. <li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li>
  5042. <li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li>
  5043. </ul>
  5044. </div>
  5045. `);
  5046. if (pt === 'home') {
  5047. base.listenElement(pan.btn.home, function () {
  5048. $toolWrap = $(pan.btn.home);
  5049. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  5050. })
  5051. }
  5052. if (pt === 'share') {
  5053. $button = $(`
  5054. <div class="xunlei-button pl-button">
  5055. <i class="xlpfont xlp-download"></i><span style="font-size: 13px;margin-left: 6px;">下载助手</span>
  5056. <ul class="pl-dropdown-menu" style="top: 34px;">
  5057. <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>
  5058. <li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>
  5059. <li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li>
  5060. <li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li>
  5061. </ul>
  5062. </div>
  5063. `);
  5064. $button.css({ 'margin-right': '10px' });
  5065. base.listenElement(pan.btn.share, function () {
  5066. $toolWrap = $(pan.btn.share);
  5067. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  5068. })
  5069. }
  5070. base.createDownloadIframe();
  5071. },
  5072.  
  5073. addInitButton() {
  5074. if (!pt) return;
  5075. let $toolWrap;
  5076. 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>`);
  5077. if (pt === 'home') {
  5078. base.listenElement(pan.btn.home, function () {
  5079. $toolWrap = $(pan.btn.home);
  5080. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  5081. })
  5082. }
  5083. if (pt === 'share') {
  5084. $button.css({ 'margin-right': '10px' });
  5085. base.listenElement(pan.btn.share, function () {
  5086. $toolWrap = $(pan.btn.share);
  5087. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  5088. })
  5089. }
  5090. $button.click(function () { base.initDialog() });
  5091. },
  5092.  
  5093. getToken() {
  5094. let credentials = {}, captcha = {};
  5095. for (let i = 0; i < localStorage.length; i++) {
  5096. if (/^credentials_/.test(localStorage.key(i))) {
  5097. credentials = base.getStorage(localStorage.key(i));
  5098. base.setStorage('');
  5099. }
  5100. if (/^captcha_[\w]{16}/.test(localStorage.key(i))) {
  5101. captcha = base.getStorage(localStorage.key(i));
  5102. }
  5103. }
  5104. let deviceid = /(\w{32})/.exec(base.getStorage('deviceid').split(','))[0];
  5105. let token = {
  5106. credentials,
  5107. captcha,
  5108. deviceid
  5109. };
  5110. return token;
  5111. },
  5112.  
  5113. async getFileUrlByOnce(item, index, token) {
  5114. try {
  5115. if (item.downloadUrl) return {
  5116. index,
  5117. downloadUrl: item.downloadUrl
  5118. };
  5119. let res = await base.get(pan.pcs[0] + item.id, {
  5120. 'Authorization': `${token.credentials.token_type} ${token.credentials.access_token}`,
  5121. 'content-type': "application/json",
  5122. 'x-captcha-token': token.captcha.token,
  5123. 'x-device-id': token.deviceid,
  5124. });
  5125. if (res.web_content_link) {
  5126. return {
  5127. index,
  5128. downloadUrl: res.web_content_link
  5129. };
  5130. } else {
  5131. return {
  5132. index,
  5133. downloadUrl: '获取下载地址失败,刷新后再试试吧~'
  5134. };
  5135. }
  5136. } catch (e) {
  5137. return message.error('提示:<br/>请先登录网盘后再刷新页面呢~');
  5138. }
  5139. },
  5140.  
  5141. async getPCSLink() {
  5142. selectList = this.getSelectedList();
  5143. if (selectList.length === 0) {
  5144. return message.error('提示:<br/>请勾选要下载的文件哦~');
  5145. }
  5146. if (this.isOnlyFolder()) {
  5147. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  5148. }
  5149. if (pt === 'home') {
  5150. let queue = [];
  5151. let token = this.getToken();
  5152. for (const [index, item] of selectList.entries()) {
  5153. queue.push(this.getFileUrlByOnce(item, index, token));
  5154. }
  5155.  
  5156. const res = await Promise.all(queue);
  5157. res.forEach(val => {
  5158. selectList[val.index].downloadUrl = val.downloadUrl;
  5159. });
  5160. } else {
  5161. return message.error('提示:<br/>页面错误~');
  5162. }
  5163. let html = this.generateDom(selectList);
  5164. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  5165.  
  5166. },
  5167.  
  5168. generateDom(list) {
  5169. let content = '<div class="pl-main">';
  5170. let alinkAllText = '';
  5171. list.forEach((v, i) => {
  5172. if (v.kind === 'drive#folder') return;
  5173. let filename = v.name;
  5174. let ext = base.getExtension(filename);
  5175. let size = base.sizeFormat(+v.size);
  5176. let dlink = v.downloadUrl;
  5177. if (mode === 'api') {
  5178. alinkAllText += dlink + '\r\n';
  5179. content += `<div class="pl-item">
  5180. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5181. <button class="pl-item-link listener-tip pl-btn-primary listener-link-api blob" data-title="推荐使用本功能,下载完成可自动命名,基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接" data-filename="${filename}" data-size="${v.size}" data-link="${dlink}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  5182. <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>
  5183. <button class="pl-item-copy listener-tip pl-btn-primary pl-btn-success listener-copy-filename" data-title="本网盘下载时可能不会显示文件名称,这时需要手动复制文件名称到下载工具中" data-filename="${filename}">复制名称</button>
  5184. <button class="pl-item-copy pl-btn-primary listener-copy-all" href="${dlink}" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  5185. <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>
  5186. <div class="pl-item-progress" style="display: none">
  5187. <div class="pl-progress">
  5188. <div class="pl-progress-outer"></div>
  5189. <div class="pl-progress-inner" style="width:5%">
  5190. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  5191. </div>
  5192. </div>
  5193. <span class="pl-progress-stop listener-stop">取消下载</span>
  5194. `;
  5195. content += `<span class="pl-progress-tip" style="display: none" >未发现IDM,使用自带浏览器下载</span>
  5196. <span class="pl-progress-back listener-back" style="display: none">返回</span>
  5197. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  5198. `;
  5199. content += `</div></div>`
  5200. }
  5201. if (mode === 'aria') {
  5202. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  5203. alinkAllText += alink + '\r\n';
  5204. content += `<div class="pl-item">
  5205. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5206. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  5207. }
  5208. if (mode === 'rpc') {
  5209. content += `<div class="pl-item">
  5210. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5211. <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>`;
  5212. }
  5213. if (mode === 'curl') {
  5214. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  5215. alinkAllText += alink + '\r\n';
  5216. content += `<div class="pl-item">
  5217. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5218. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  5219. }
  5220. if (mode === 'bc') {
  5221. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  5222. alinkAllText += alink + '\r\n';
  5223. content += `<div class="pl-item">
  5224. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5225. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a>
  5226. <button class="pl-btn-primary listener-link-bc-btn" data-dlink="${dlink}">复制镜像地址</div>
  5227. </div>`;
  5228. }
  5229. });
  5230. content += '</div>';
  5231. if (mode === 'api')
  5232. content += `<div class="pl-extra"><button class="pl-btn-primary listener-download-all">全部增强下载</button><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  5233. if (mode === 'aria')
  5234. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  5235. if (mode === 'rpc') {
  5236. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  5237. 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>`;
  5238. }
  5239. if (mode === 'curl') {
  5240. 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>`;
  5241. }
  5242. if (mode === 'bc') {
  5243. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  5244. }
  5245. return content;
  5246. },
  5247.  
  5248. async sendLinkToRPC(filename, link) {
  5249. let rpc = {
  5250. domain: base.getValue('setting_rpc_domain'),
  5251. port: base.getValue('setting_rpc_port'),
  5252. path: base.getValue('setting_rpc_path'),
  5253. token: base.getValue('setting_rpc_token'),
  5254. dir: base.getValue('setting_rpc_dir'),
  5255. };
  5256.  
  5257. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  5258. let rpcData = {
  5259. id: new Date().getTime(),
  5260. jsonrpc: '2.0',
  5261. method: 'aria2.addUri',
  5262. params: [`token:${rpc.token}`, [link], {
  5263. dir: rpc.dir,
  5264. out: filename,
  5265. header: []
  5266. }]
  5267. };
  5268. try {
  5269. let res = await base.post(url, rpcData, {}, '');
  5270. if (res.result) return 'success';
  5271. return 'fail';
  5272. } catch (e) {
  5273. return 'fail';
  5274. }
  5275. },
  5276.  
  5277. getSelectedList() {
  5278. try {
  5279. let doms = document.querySelectorAll('.SourceListItem__item--XxpOC');
  5280. let selectedList = [];
  5281. for (let dom of doms) {
  5282. let domVue = dom.__vue__;
  5283. if (domVue.selected.includes(domVue.info.id)) {
  5284. selectedList.push(domVue.info);
  5285. }
  5286. }
  5287. return selectedList;
  5288. } catch (e) {
  5289. return [];
  5290. }
  5291. },
  5292.  
  5293. detectPage() {
  5294. let path = location.pathname;
  5295. if (/^\/$/.test(path)) return 'home';
  5296. if (/^\/(s|share)\//.test(path)) return 'share';
  5297. return '';
  5298. },
  5299.  
  5300. isOnlyFolder() {
  5301. for (let i = 0; i < selectList.length; i++) {
  5302. if (selectList[i].kind === 'drive#file') return false;
  5303. }
  5304. return true;
  5305. },
  5306.  
  5307. showMainDialog(title, html, footer) {
  5308. Swal.fire({
  5309. title,
  5310. html,
  5311. footer,
  5312. allowOutsideClick: false,
  5313. showCloseButton: true,
  5314. position: 'center',
  5315. width,
  5316. padding: '15px 20px 5px',
  5317. customClass,
  5318. confirmButtonText: '关闭',
  5319. });
  5320. },
  5321.  
  5322. async initPanLinker() {
  5323. pt = this.detectPage();
  5324. base.createTip();
  5325. base.registerMenuCommand();
  5326. if (base.getValue('setting_youxiaohou_server') === 'v1') {
  5327. let res = await base.post(`https://api.youxiaohou.com/config/xunlei/?ver=${version}&a=${author}`, {}, {}, 'text');
  5328. pan = JSON.parse(base.decode(res));
  5329. } else if (base.getValue('setting_youxiaohou_server') === 'v2') {
  5330. let res = await base.post(`https://api.youxiaohou.com/config/v2/xunlei/?ver=${version}&a=${author}`, {}, {}, 'text');
  5331. pan = JSON.parse(base.decode(res));
  5332. } else if (base.getValue('setting_youxiaohou_server') === "no") {
  5333. 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", {});
  5334. pan = JSON.parse(res);
  5335. } else {
  5336. 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", {});
  5337. pan = JSON.parse(res);
  5338. base.setValue('setting_youxiaohou_server', 'v2');
  5339. }
  5340. Object.freeze && Object.freeze(pan);
  5341. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('license')) {
  5342. this.addButton();
  5343. this.addPageListener();
  5344. } else {
  5345. this.addInitButton();
  5346. }
  5347. }
  5348. };
  5349.  
  5350. //夸克网盘
  5351. let quark = {
  5352.  
  5353. convertLinkToAria(link, filename, ua) {
  5354. filename = base.fixFilename(filename);
  5355. return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "Cookie: ${document.cookie}"`);
  5356. },
  5357.  
  5358. convertLinkToBC(link, filename, ua) {
  5359. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&cookie=${encodeURIComponent(document.cookie)}ZZ`;
  5360. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  5361. },
  5362.  
  5363. convertLinkToCurl(link, filename, ua) {
  5364. let terminal = base.getValue('setting_terminal_type');
  5365. filename = base.fixFilename(filename);
  5366. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}" -b "${document.cookie}"`);
  5367. },
  5368.  
  5369. addPageListener() {
  5370. /*
  5371. 防止代码因其他原因被执行多次
  5372. 这段代码出自 Via轻插件,作者谷花泰
  5373. */
  5374. const key = encodeURIComponent('(改)网盘直链下载助手:夸客网盘');
  5375. if (window[key]) return;
  5376. window[key] = true;
  5377.  
  5378. function _factory(e) {
  5379. let target = $(e.target);
  5380. let item = target.parents('.pl-item');
  5381. let link = item.find('.pl-item-link.blob');
  5382. let directLink = item.find('.pl-item-link.browser');
  5383. let progress = item.find('.pl-item-progress');
  5384. let tip = item.find('.pl-item-tip');
  5385. let copy = item.find('.pl-item-copy');
  5386. let howidm = item.find('.pl-progress-how');
  5387. let back = item.find('.pl-progress-back');
  5388. let stop = item.find('.pl-progress-stop');
  5389. return {
  5390. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  5391. };
  5392. }
  5393.  
  5394. function _reset(i) {
  5395. ins[i] && clearInterval(ins[i]);
  5396. request[i] && request[i].abort();
  5397. progress[i] = 0;
  5398. idm[i] = false;
  5399. }
  5400.  
  5401. window.addEventListener('hashchange', async function (e) {
  5402. let home = 'https://pan.quark.cn/list#/', all = 'https://pan.quark.cn/list#/list/all';
  5403. if (e.oldURL === home && e.newURL === all) return;
  5404. await base.sleep(150);
  5405. if ($('.quark-button').length > 0) return;
  5406. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('license')) {
  5407. this.addButton();
  5408. this.addPageListener();
  5409. } else {
  5410. this.addInitButton();
  5411. }
  5412. });
  5413. doc.on('click', '.pl-button-mode', function (e) {
  5414. mode = e.target.dataset.mode;
  5415. if (!mode) return;
  5416. Swal.fire({
  5417. heightAuto: false,
  5418. scrollbarPadding: false,
  5419. showConfirmButton: false,
  5420. html: `链接获取中`,
  5421. willOpen: function () {
  5422. Swal.showLoading();
  5423. }
  5424. });
  5425. quark.getPCSLink();
  5426. });
  5427. doc.on('click', '.pl-button-save', async function (e) {
  5428. e.preventDefault();
  5429. selectList = quark.getSelectedList();
  5430. if (selectList.length === 0) {
  5431. return message.error('提示:<br/>请勾选要保存到网盘的文件哦~');
  5432. }
  5433. message.info('提示:<br/>因网盘限制,请保存到自己网盘后再去下载哦~');
  5434. await base.sleep(500);
  5435. document.querySelector('.file-info_r').click();
  5436. });
  5437. doc.on('click', '.listener-link-api.browser', async function (e) {
  5438. e.preventDefault();
  5439. let dataset = e.currentTarget.dataset;
  5440. let href = dataset.link;
  5441. $('#downloadIframe').attr('src', href);
  5442. });
  5443. doc.on('click', '.listener-link-api.blob', async function (e) {
  5444. e.preventDefault();
  5445. let o = _factory(e);
  5446. let $width = o.item.find('.pl-progress-inner');
  5447. let $text = o.item.find('.pl-progress-inner-text');
  5448. let filename = o.link[0].dataset.filename;
  5449. let index = o.link[0].dataset.index;
  5450. _reset(index);
  5451. let dataset = e.currentTarget.dataset;
  5452. let href = dataset.link;
  5453. base.get(href, { "Referer": `https://${location.host}/` }, 'blob', { filename, index });
  5454. let startTime = Date.now(); // 记录下载开始时间
  5455. let prevLoaded = 0; // 上一次的已下载数据量
  5456. let prevTime = startTime; // 上一次的时间
  5457. let size = Number(o.link[0].dataset.size);
  5458. ins[index] = setInterval(function () {
  5459. let prog = +progress[index] || 0;
  5460. // 处理普通下载的情况...
  5461. let currentTime = Date.now();
  5462. let elapsedTime = currentTime - startTime;
  5463. let totalProgress = prog / 100;
  5464. let totalElapsedSeconds = elapsedTime / 1000;
  5465. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  5466. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  5467.  
  5468. // 将剩余时间转换为天、时、分、秒
  5469. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  5470. remainingTimeSeconds %= (60 * 60 * 24);
  5471.  
  5472. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  5473. remainingTimeSeconds %= (60 * 60);
  5474.  
  5475. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  5476. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  5477.  
  5478. // 计算下载速度
  5479. let loaded = prog * size / 100; // 已下载数据量
  5480. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  5481. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  5482. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  5483.  
  5484. // 更新上一次的数据
  5485. prevLoaded = loaded;
  5486. prevTime = currentTime;
  5487.  
  5488. // 更改界面
  5489. o.link.hide();
  5490. o.directLink.hide();
  5491. o.tip.hide();
  5492. o.stop.show();
  5493. o.copy.hide();
  5494. o.progress.show();
  5495.  
  5496. // 更新进度条
  5497. $width.css('width', prog + '%');
  5498.  
  5499. // 更新进度条文本
  5500. let timeText = '';
  5501. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  5502. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  5503. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  5504. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  5505. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  5506. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  5507. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  5508. timeText = remainingSeconds + '秒';
  5509. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  5510. timeText = '即将完成';
  5511. } else {
  5512. timeText = '计算中...';
  5513. }
  5514.  
  5515. let speedText = '';
  5516. speedText = base.sizeFormat(downloadSpeed)
  5517. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  5518.  
  5519. if (prog === 100) {
  5520. setTimeout(function () {
  5521. clearInterval(ins[index]);
  5522. progress[index] = 0;
  5523. o.item.find('.pl-progress-stop').hide();
  5524. o.howidm.hide();
  5525. $text.text('下载完成了!浏览器下载框应该弹出来了哦~');
  5526. o.back.show()
  5527. setTimeout(function () {
  5528. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  5529. }, 3000)
  5530. }, 3000)
  5531. }
  5532. }, 500);
  5533. });
  5534. doc.on('click', '.listener-retry', async function (e) {
  5535. let o = _factory(e);
  5536. o.tip.hide();
  5537. o.link.show();
  5538. o.directLink.show();
  5539. });
  5540. doc.on('click', '.listener-how', async function (e) {
  5541. let o = _factory(e);
  5542. let index = o.link[0].dataset.index;
  5543. if (request[index]) {
  5544. request[index].abort();
  5545. clearInterval(ins[index]);
  5546. o.progress.hide();
  5547. o.tip.show();
  5548. }
  5549.  
  5550. });
  5551. doc.on('click', '.listener-stop', async function (e) {
  5552. let o = _factory(e);
  5553. let index = o.link[0].dataset.index;
  5554. if (request[index]) {
  5555. request[index].abort();
  5556. clearInterval(ins[index]);
  5557. o.item.find('.pl-progress-inner-text').text('正在取消...');
  5558. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  5559. setTimeout(function () {
  5560. o.tip.hide();
  5561. o.back.hide();
  5562. o.link.show();
  5563. o.directLink.show();
  5564. o.copy.show();
  5565. o.progress.hide();
  5566. o.stop.hide();
  5567. }, 1050)
  5568. }
  5569. });
  5570. doc.on('click', '.listener-back', async function (e) {
  5571. let o = _factory(e);
  5572. o.progress.hide();
  5573. o.tip.hide();
  5574. o.link.show();
  5575. o.directLink.show();
  5576. o.copy.show();
  5577. o.stop.hide();
  5578. o.back.hide();
  5579. });
  5580. doc.on('click', '.listener-download-all', function (e) {
  5581. $('.pl-item-link.blob').each(function () {
  5582. if ($(this).css('display') !== 'none') {
  5583. $(this).click();
  5584. }
  5585. });
  5586. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  5587. setTimeout(function () {
  5588. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  5589. }, 2000)
  5590. });
  5591. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  5592. e.preventDefault();
  5593. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  5594. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  5595. setTimeout(function () {
  5596. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  5597. }, 2000)
  5598. });
  5599. doc.on('click', '.listener-link-rpc', async function (e) {
  5600. e.preventDefault();
  5601. let target = $(e.currentTarget);
  5602.  
  5603. target.find('.icon-rpc-devices').remove();
  5604. target.find('.pl-loading').remove();
  5605. target.prepend(base.createLoading());
  5606.  
  5607. let res = await quark.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  5608. if (res === 'success') {
  5609. $('.listener-rpc-task').show();
  5610. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  5611. } else if (res === 'assistant') {
  5612. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  5613. } else {
  5614. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  5615. }
  5616. });
  5617. doc.on('click', '.listener-send-rpc', function (e) {
  5618. $('.listener-link-rpc').click();
  5619. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  5620. });
  5621. doc.on('click', '.listener-open-setting', function () {
  5622. base.showSetting();
  5623. });
  5624. doc.on('click', '.listener-open-updatelog', function () {
  5625. base.showUpdateLog();
  5626. });
  5627. doc.on('click', '.listener-open-beautify', function () {
  5628. base.showBeautify();
  5629. });
  5630. doc.on('click', '.listener-rpc-task', function () {
  5631. let rpc = JSON.stringify({
  5632. domain: base.getValue('setting_rpc_domain'),
  5633. port: base.getValue('setting_rpc_port'),
  5634. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  5635. GM_openInTab(url, { active: true });
  5636. });
  5637. },
  5638.  
  5639. removeAD() {
  5640. base.waitForKeyElements('[class*="Activity--video-toolbar-activity"]', function (tag) {
  5641. tag.fadeToggle();
  5642. }, true);
  5643. base.waitForKeyElements('span[class*="SectionHeaderController--icon-download"]', function (tag) {
  5644. tag.fadeToggle();
  5645. }, true);
  5646. base.waitForKeyElements('div[class*="SectionHeaderController--download-popover"]', function (tag) {
  5647. tag.find(".ant-popover-arrow").css({ "left": "75%" });
  5648. });
  5649. base.waitForKeyElements('div[class*="DetailLayout--client-download"]', function (tag) {
  5650. tag.fadeToggle();
  5651. }, true);
  5652. base.waitForKeyElements(".next-box.share-right-side-content", function (tag) {
  5653. tag.fadeToggle();
  5654. }, true);
  5655. base.waitForKeyElements('[class*="DetailLayout--container"] .feature-screen', function (tag) {
  5656. tag.fadeToggle();
  5657. });
  5658. base.waitForKeyElements('.ant-modal-content .ant-modal-body .right-wrap', function (tag) {
  5659. if (tag.find(".hint").text().includes("客户端")) tag.fadeToggle();
  5660. });
  5661. base.waitForKeyElements(".pc-member-entrance span.button-text", function (tag) {
  5662. tag.text("会员中心");
  5663. var observer = new MutationObserver(function (mutations) {
  5664. mutations.forEach(function (mutation) {
  5665. if (tag.text() === "会员中心") return
  5666. tag.text("会员中心");
  5667. });
  5668. });
  5669. var config = { subtree: true, characterData: true, childList: true };
  5670. observer.observe(tag[0], config);
  5671. });
  5672. base.waitForKeyElements(".pc-member-entrance .tips", function (tag) {
  5673. tag.fadeToggle();
  5674. });
  5675. base.waitForKeyElements(".modal .modal-content .halo-animated-background .halo-content .pay-modal .close", function (tag) {
  5676. tag[0].click();
  5677. });
  5678. base.waitForKeyElements(".modal .modal-content .halo-animated-background .halo-content .red-envelope .close", function (tag) {
  5679. tag[0].click();
  5680. });
  5681. },
  5682.  
  5683. addButton() {
  5684. let svg = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iMiI+PHBhdGggc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNOSAxMmwyIDIgMi0yeiIvPjxwYXRoIGQ9Ik0xNCA4aDEuNTUzYy44NSAwIDEuMTYuMDkzIDEuNDcuMjY3LjMxMS4xNzQuNTU2LjQzLjcyMi43NTYuMTY2LjMyNi4yNTUuNjUuMjU1IDEuNTR2NC44NzNjMCAuODkyLS4wODkgMS4yMTUtLjI1NSAxLjU0LS4xNjYuMzI3LS40MS41ODMtLjcyMi43NTctLjMxLjE3NC0uNjIuMjY3LTEuNDcuMjY3SDYuNDQ3Yy0uODUgMC0xLjE2LS4wOTMtMS40Ny0uMjY3YTEuNzc4IDEuNzc4IDAgMDEtLjcyMi0uNzU2Yy0uMTY2LS4zMjYtLjI1NS0uNjUtLjI1NS0xLjU0di00Ljg3M2MwLS44OTIuMDg5LTEuMjE1LjI1NS0xLjU0LjE2Ni0uMzI3LjQxLS41ODMuNzIyLS43NTcuMzEtLjE3NC42Mi0uMjY3IDEuNDctLjI2N0gxMSIvPjxwYXRoIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0iTTExIDN2MTAiLz48L2c+PC9zdmc+';
  5685. if (!pt) return;
  5686. let $toolWrap;
  5687. let $button = $(`
  5688. <div class="ant-dropdown-trigger pl-button">
  5689. <button type="button" class="quark-button ant-btn btn-file ant-btn-primary">
  5690. <img class="quark-btn-icon" src="${svg}"><span>下载助手</span>
  5691. </button>
  5692. <ul class="pl-dropdown-menu" style="top: 55px;">
  5693. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li>
  5694. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria">Aria下载</li>
  5695. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li>
  5696. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li>
  5697. <li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc">BC下载</li>
  5698. <li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>
  5699. <li class="pl-dropdown-menu-item pl-button-mode listener-open-beautify">助手美化</li>
  5700. <li class="pl-dropdown-menu-item pl-button-mode listener-open-updatelog">更新日志</li>
  5701. </ul>
  5702. </div>`);
  5703. if (pt === 'home') {
  5704. base.listenElement(pan.btn.home, function () {
  5705. $toolWrap = $(pan.btn.home);
  5706. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  5707. });
  5708. }
  5709. if (pt === 'share') {
  5710. $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>`);
  5711. base.listenElement(pan.btn.share, function () {
  5712. $toolWrap = $(pan.btn.share);
  5713. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  5714. });
  5715. }
  5716. $button.css({ "margin-right": "10px", "display": "inline-block" });
  5717. },
  5718.  
  5719. addInitButton() {
  5720. let svg = 'data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjIiIGhlaWdodD0iMjIiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBzdHJva2U9IiNGRkZGRkYiIHN0cm9rZS13aWR0aD0iMiI+PHBhdGggc3Ryb2tlLWxpbmVjYXA9InJvdW5kIiBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNOSAxMmwyIDIgMi0yeiIvPjxwYXRoIGQ9Ik0xNCA4aDEuNTUzYy44NSAwIDEuMTYuMDkzIDEuNDcuMjY3LjMxMS4xNzQuNTU2LjQzLjcyMi43NTYuMTY2LjMyNi4yNTUuNjUuMjU1IDEuNTR2NC44NzNjMCAuODkyLS4wODkgMS4yMTUtLjI1NSAxLjU0LS4xNjYuMzI3LS40MS41ODMtLjcyMi43NTctLjMxLjE3NC0uNjIuMjY3LTEuNDcuMjY3SDYuNDQ3Yy0uODUgMC0xLjE2LS4wOTMtMS40Ny0uMjY3YTEuNzc4IDEuNzc4IDAgMDEtLjcyMi0uNzU2Yy0uMTY2LS4zMjYtLjI1NS0uNjUtLjI1NS0xLjU0di00Ljg3M2MwLS44OTIuMDg5LTEuMjE1LjI1NS0xLjU0LjE2Ni0uMzI3LjQxLS41ODMuNzIyLS43NTcuMzEtLjE3NC42Mi0uMjY3IDEuNDctLjI2N0gxMSIvPjxwYXRoIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIgZD0iTTExIDN2MTAiLz48L2c+PC9zdmc+';
  5721. if (!pt) return;
  5722. let $toolWrap;
  5723. 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>`);
  5724. $button.css({ "margin-right": "10px", "display": "inline-block" });
  5725. if (pt === 'home') {
  5726. base.listenElement(pan.btn.home, function () {
  5727. $toolWrap = $(pan.btn.home);
  5728. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  5729. })
  5730. }
  5731. if (pt === 'share') {
  5732. base.listenElement(pan.btn.share, function () {
  5733. $toolWrap = $(pan.btn.share);
  5734. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  5735. })
  5736. }
  5737. $button.click(function () { base.initDialog() });
  5738. },
  5739.  
  5740. async getPCSLink() {
  5741. selectList = this.getSelectedList();
  5742. if (selectList.length === 0) {
  5743. return message.error('提示:<br/>请勾选要下载的文件哦~');
  5744. }
  5745. if (this.isOnlyFolder()) {
  5746. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  5747. }
  5748. let fids = [];
  5749. for (const val of selectList) {
  5750. fids.push(val.fid);
  5751. }
  5752. if (pt === 'home') {
  5753. let res = await base.post(pan.pcs[0], {
  5754. "fids": fids
  5755. }, { "content-type": "application/json;charset=utf-8", "user-agent": pan.ua });
  5756. if (res.code === 31001) {
  5757. return message.error('提示:<br/>请先登录网盘~<br/>代码:' + res.code);
  5758. }
  5759. if (res.code !== 0) {
  5760. return message.error('提示:<br/>获取链接失败了~<br/>代码:' + res.code);
  5761. }
  5762. let html = this.generateDom(res.data);
  5763. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  5764. } else {
  5765. return message.error('提示:<br/>页面错误~');
  5766. }
  5767. },
  5768.  
  5769. generateDom(list) {
  5770. let content = '<div class="pl-main">';
  5771. let alinkAllText = '';
  5772. list.forEach((v, i) => {
  5773. if (v.file === false) return;
  5774. let filename = v.file_name;
  5775. let ext = base.getExtension(filename);
  5776. let fid = v.fid;
  5777. let size = base.sizeFormat(v.size);
  5778. let dlink = v.download_url;
  5779. if (mode === 'api') {
  5780. alinkAllText += dlink + '\r\n';
  5781. content += `<div class="pl-item">
  5782. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5783. <button class="pl-item-link listener-tip pl-btn-primary pl-btn-default listener-link-api blob" data-title="推荐使用本功能,基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接" data-filename="${filename}" data-size="${v.size}" data-link="${dlink}" data-fid="${fid}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  5784. <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>
  5785. <button class="pl-item-copy pl-btn-primary listener-copy-all" href="${dlink}" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  5786. <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>
  5787. <div class="pl-item-progress" style="display: none">
  5788. <div class="pl-progress">
  5789. <div class="pl-progress-outer"></div>
  5790. <div class="pl-progress-inner" style="width:5%">
  5791. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  5792. </div>
  5793. </div>
  5794. <span class="pl-progress-stop listener-stop">取消下载</span>
  5795. `;
  5796. content += `<span class="pl-progress-tip" style="display: none" >未发现IDM,使用自带浏览器下载</span>
  5797. <span class="pl-progress-back listener-back" style="display: none">返回</span>
  5798. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  5799. `;
  5800. content += `</div></div>`
  5801. }
  5802. if (mode === 'aria') {
  5803. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  5804. alinkAllText += alink + '\r\n';
  5805. content += `<div class="pl-item">
  5806. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5807. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  5808. }
  5809. if (mode === 'rpc') {
  5810. content += `<div class="pl-item">
  5811. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5812. <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>`;
  5813. }
  5814. if (mode === 'curl') {
  5815. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  5816. alinkAllText += alink + '\r\n';
  5817. content += `<div class="pl-item">
  5818. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5819. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  5820. }
  5821. if (mode === 'bc') {
  5822. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  5823. alinkAllText += alink + '\r\n';
  5824. content += `<div class="pl-item">
  5825. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  5826. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a> </div>`;
  5827. }
  5828. });
  5829. content += '</div>';
  5830. if (mode === 'api')
  5831. content += `<div class="pl-extra"><button class="pl-btn-primary listener-download-all">全部增强下载</button><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  5832. if (mode === 'aria')
  5833. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  5834. if (mode === 'rpc') {
  5835. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  5836. 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>`;
  5837. }
  5838. if (mode === 'curl') {
  5839. 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>`;
  5840. }
  5841. if (mode === 'bc') {
  5842. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  5843. }
  5844. return content;
  5845. },
  5846.  
  5847. async sendLinkToRPC(filename, link) {
  5848. let rpc = {
  5849. domain: base.getValue('setting_rpc_domain'),
  5850. port: base.getValue('setting_rpc_port'),
  5851. path: base.getValue('setting_rpc_path'),
  5852. token: base.getValue('setting_rpc_token'),
  5853. dir: base.getValue('setting_rpc_dir'),
  5854. };
  5855.  
  5856. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  5857. let rpcData = {
  5858. id: new Date().getTime(),
  5859. jsonrpc: '2.0',
  5860. method: 'aria2.addUri',
  5861. params: [`token:${rpc.token}`, [link], {
  5862. dir: rpc.dir,
  5863. out: filename,
  5864. header: [`Cookie: ${document.cookie}`]
  5865. }]
  5866. };
  5867. try {
  5868. let res = await base.post(url, rpcData, { "Cookie": document.cookie }, '');
  5869. if (res.result) return 'success';
  5870. return 'fail';
  5871. } catch (e) {
  5872. return 'fail';
  5873. }
  5874. },
  5875.  
  5876. getSelectedList() {
  5877. try {
  5878. let selectedList = [];
  5879. let reactDom = document.getElementsByClassName('file-list')[0];
  5880. let reactObj = base.findReact(reactDom);
  5881. let props = reactObj.props;
  5882. if (props) {
  5883. let fileList = props.list || [];
  5884. let selectedKeys = props.selectedRowKeys || [];
  5885. fileList.forEach(function (val) {
  5886. if (selectedKeys.includes(val.fid)) {
  5887. selectedList.push(val);
  5888. }
  5889. });
  5890. }
  5891. return selectedList;
  5892. } catch (e) {
  5893. return [];
  5894. }
  5895. },
  5896.  
  5897. detectPage() {
  5898. let path = location.pathname;
  5899. if (/^\/(list)/.test(path)) return 'home';
  5900. if (/^\/(s|share)\//.test(path)) return 'share';
  5901. return '';
  5902. },
  5903.  
  5904. isOnlyFolder() {
  5905. for (let i = 0; i < selectList.length; i++) {
  5906. if (selectList[i].file) return false;
  5907. }
  5908. return true;
  5909. },
  5910.  
  5911. showMainDialog(title, html, footer) {
  5912. Swal.fire({
  5913. title,
  5914. html,
  5915. footer,
  5916. allowOutsideClick: false,
  5917. showCloseButton: true,
  5918. position: 'center',
  5919. width,
  5920. padding: '15px 20px 5px',
  5921. customClass,
  5922. confirmButtonText: '关闭',
  5923. });
  5924. },
  5925.  
  5926. async initPanLinker() {
  5927. pt = this.detectPage();
  5928. base.createTip();
  5929. base.registerMenuCommand();
  5930. if (base.getValue('setting_youxiaohou_server') === 'v1') {
  5931. let res = await base.post(`https://api.youxiaohou.com/config/quark/?ver=${version}&a=${author}`, {}, {}, 'text');
  5932. pan = JSON.parse(base.decode(res));
  5933. } else if (base.getValue('setting_youxiaohou_server') === 'v2') {
  5934. let res = await base.post(`https://api.youxiaohou.com/config/v2/quark/?ver=${version}&a=${author}`, {}, {}, 'text');
  5935. pan = JSON.parse(base.decode(res));
  5936. } else if (base.getValue('setting_youxiaohou_server') === "no") {
  5937. 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", {});
  5938. pan = JSON.parse(res);
  5939. } else {
  5940. 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", {});
  5941. pan = JSON.parse(res);
  5942. base.setValue('setting_youxiaohou_server', 'v2');
  5943. }
  5944. Object.freeze && Object.freeze(pan);
  5945. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('license')) {
  5946. this.addButton();
  5947. this.addPageListener();
  5948. } else {
  5949. this.addInitButton();
  5950. }
  5951. base.createDownloadIframe();
  5952. }
  5953. };
  5954.  
  5955. //中国移动云盘/和彩云
  5956. let yidong = {
  5957.  
  5958. convertLinkToAria(link, filename, ua) {
  5959. filename = base.fixFilename(filename);
  5960. return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
  5961. },
  5962.  
  5963. convertLinkToBC(link, filename, ua) {
  5964. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
  5965. return encodeURIComponent(`bc://http/${base.encode(bc)}`);
  5966. },
  5967.  
  5968. convertLinkToCurl(link, filename, ua) {
  5969. let terminal = base.getValue('setting_terminal_type');
  5970. filename = base.fixFilename(filename);
  5971. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}"`);
  5972. },
  5973.  
  5974. addPageListener() {
  5975. /*
  5976. 防止代码因其他原因被执行多次
  5977. 这段代码出自 Via轻插件,作者谷花泰
  5978. */
  5979. const key = encodeURIComponent('(改)网盘直链下载助手:移动云盘');
  5980. if (window[key]) return;
  5981. window[key] = true;
  5982.  
  5983. function _factory(e) {
  5984. let target = $(e.target);
  5985. let item = target.parents('.pl-item');
  5986. let link = item.find('.pl-item-link.blob');
  5987. let directLink = item.find('.pl-item-link.browser');
  5988. let progress = item.find('.pl-item-progress');
  5989. let tip = item.find('.pl-item-tip');
  5990. let copy = item.find('.pl-item-copy');
  5991. let howidm = item.find('.pl-progress-how');
  5992. let back = item.find('.pl-progress-back');
  5993. let stop = item.find('.pl-progress-stop');
  5994. return {
  5995. item, link, directLink, progress, tip, copy, howidm, back, stop, target,
  5996. };
  5997. }
  5998.  
  5999. function _reset(i) {
  6000. ins[i] && clearInterval(ins[i]);
  6001. request[i] && request[i].abort();
  6002. progress[i] = 0;
  6003. idm[i] = false;
  6004. }
  6005.  
  6006. doc.on('click', '.pl-button-mode', function (e) {
  6007. mode = e.target.dataset.mode;
  6008. if (!mode) return;
  6009. Swal.fire({
  6010. heightAuto: false,
  6011. scrollbarPadding: false,
  6012. showConfirmButton: false,
  6013. html: `链接获取中`,
  6014. willOpen: function () {
  6015. Swal.showLoading();
  6016. }
  6017. });
  6018. yidong.getPCSLink();
  6019. });
  6020. doc.on('click', '.listener-link-api.browser', async function (e) {
  6021. e.preventDefault();
  6022. let dataset = e.currentTarget.dataset;
  6023. let href = dataset.link;
  6024. $('#downloadIframe').attr('src', href);
  6025. });
  6026. doc.on('click', '.listener-link-api.blob', async function (e) {
  6027. e.preventDefault();
  6028. let o = _factory(e);
  6029. let $width = o.item.find('.pl-progress-inner');
  6030. let $text = o.item.find('.pl-progress-inner-text');
  6031. let filename = o.link[0].dataset.filename;
  6032. let index = o.link[0].dataset.index;
  6033. _reset(index);
  6034. let dataset = e.currentTarget.dataset;
  6035. let href = dataset.link;
  6036. base.get(href, { "Referer": `https://${location.host}/` }, 'blob', { filename, index });
  6037. let startTime = Date.now(); // 记录下载开始时间
  6038. let prevLoaded = 0; // 上一次的已下载数据量
  6039. let prevTime = startTime; // 上一次的时间
  6040. let size = Number(o.link[0].dataset.size);
  6041. ins[index] = setInterval(function () {
  6042. let prog = +progress[index] || 0;
  6043. let isIDM = idm[index] || false;
  6044. // 处理普通下载的情况...
  6045. let currentTime = Date.now();
  6046. let elapsedTime = currentTime - startTime;
  6047. let totalProgress = prog / 100;
  6048. let totalElapsedSeconds = elapsedTime / 1000;
  6049. let estimatedTotalTimeSeconds = totalElapsedSeconds / totalProgress;
  6050. let remainingTimeSeconds = estimatedTotalTimeSeconds - totalElapsedSeconds;
  6051.  
  6052. // 将剩余时间转换为天、时、分、秒
  6053. let remainingDays = Math.floor(remainingTimeSeconds / (60 * 60 * 24));
  6054. remainingTimeSeconds %= (60 * 60 * 24);
  6055.  
  6056. let remainingHours = Math.floor(remainingTimeSeconds / (60 * 60));
  6057. remainingTimeSeconds %= (60 * 60);
  6058.  
  6059. let remainingMinutes = Math.floor(remainingTimeSeconds / 60);
  6060. let remainingSeconds = Math.floor(remainingTimeSeconds % 60);
  6061.  
  6062. // 计算下载速度
  6063. let loaded = prog * size / 100; // 已下载数据量
  6064. let currentTimeDiff = currentTime - prevTime; // 当前时间与上一次时间的差值
  6065. let loadedDiff = loaded - prevLoaded; // 当前已下载数据量与上一次的差值
  6066. let downloadSpeed = (currentTimeDiff !== 0) ? loadedDiff / (currentTimeDiff / 1000) : 0; // 下载速度(单位:字节/秒)
  6067.  
  6068. // 更新上一次的数据
  6069. prevLoaded = loaded;
  6070. prevTime = currentTime;
  6071.  
  6072. // 更改界面
  6073. o.link.hide();
  6074. o.directLink.hide();
  6075. o.tip.hide();
  6076. o.stop.show();
  6077. o.copy.hide();
  6078. o.progress.show();
  6079.  
  6080. // 更新进度条
  6081. $width.css('width', prog + '%');
  6082.  
  6083. // 更新进度条文本
  6084. let timeText = '';
  6085. if (Number.isFinite(remainingDays) && remainingDays > 0) {
  6086. timeText = remainingDays + '天 ' + base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  6087. } else if (Number.isFinite(remainingHours) && remainingHours > 0) {
  6088. timeText = base.repairTimer(remainingHours) + '时:' + base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  6089. } else if (Number.isFinite(remainingMinutes) && remainingMinutes > 0) {
  6090. timeText = base.repairTimer(remainingMinutes) + '分:' + base.repairTimer(remainingSeconds) + '秒';
  6091. } else if (Number.isFinite(remainingSeconds) && remainingSeconds > 0) {
  6092. timeText = remainingSeconds + '秒';
  6093. } else if (Number.isFinite(remainingSeconds) && remainingSeconds === 0) {
  6094. timeText = '即将完成';
  6095. } else {
  6096. timeText = '计算中...';
  6097. }
  6098.  
  6099. let speedText = '';
  6100. console.log(downloadSpeed)
  6101. speedText = base.sizeFormat(downloadSpeed)
  6102. $text.text(prog + '% | 剩余时间:' + timeText + ' | 速度:' + speedText + '/秒');
  6103.  
  6104. if (prog === 100) {
  6105. setTimeout(function () {
  6106. clearInterval(ins[index]);
  6107. progress[index] = 0;
  6108. o.item.find('.pl-progress-stop').hide();
  6109. o.howidm.hide();
  6110. $text.text('下载完成了!浏览器下载框应该弹出来了哦~');
  6111. o.back.show()
  6112. setTimeout(function () {
  6113. o.link.text('增强下载(基于浏览器文件流)').animate({ opacity: '1' }, "slow");
  6114. }, 3000)
  6115. }, 3000)
  6116. }
  6117. }, 500);
  6118. });
  6119. doc.on('click', '.listener-retry', async function (e) {
  6120. let o = _factory(e);
  6121. o.tip.hide();
  6122. o.link.show();
  6123. o.directLink.show();
  6124. });
  6125. doc.on('click', '.listener-how', async function (e) {
  6126. let o = _factory(e);
  6127. let index = o.link[0].dataset.index;
  6128. if (request[index]) {
  6129. request[index].abort();
  6130. clearInterval(ins[index]);
  6131. o.progress.hide();
  6132. o.tip.show();
  6133. }
  6134.  
  6135. });
  6136. doc.on('click', '.listener-stop', async function (e) {
  6137. let o = _factory(e);
  6138. let index = o.link[0].dataset.index;
  6139. if (request[index]) {
  6140. request[index].abort();
  6141. clearInterval(ins[index]);
  6142. o.item.find('.pl-progress-inner-text').text('正在取消...');
  6143. o.item.find('.pl-progress-inner').css('width', 100 + '%');
  6144. setTimeout(function () {
  6145. o.tip.hide();
  6146. o.back.hide();
  6147. o.link.show();
  6148. o.directLink.show();
  6149. o.copy.show();
  6150. o.progress.hide();
  6151. o.stop.hide();
  6152. }, 1050)
  6153. }
  6154. });
  6155. doc.on('click', '.listener-back', async function (e) {
  6156. let o = _factory(e);
  6157. o.progress.hide();
  6158. o.tip.hide();
  6159. o.link.show();
  6160. o.directLink.show();
  6161. o.copy.show();
  6162. o.stop.hide();
  6163. o.back.hide();
  6164. });
  6165. doc.on('click', '.listener-download-all', function (e) {
  6166. $('.pl-item-link.blob').each(function () {
  6167. if ($(this).css('display') !== 'none') {
  6168. $(this).click();
  6169. }
  6170. });
  6171. $(e.target).text('下载开始,下载进度见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  6172. setTimeout(function () {
  6173. $(e.target).text('全部增强下载').animate({ opacity: '1' }, "slow");
  6174. }, 2000)
  6175. });
  6176. doc.on('click', '.listener-link-aria, .listener-copy-all', function (e) {
  6177. e.preventDefault();
  6178. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  6179. $(e.target).text('复制成功').animate({ opacity: '0.5' }, "slow");
  6180. setTimeout(function () {
  6181. $(e.target).text('重新复制').animate({ opacity: '1' }, "slow");
  6182. }, 2000)
  6183. });
  6184. doc.on('click', '.listener-link-rpc', async function (e) {
  6185. e.preventDefault();
  6186. let target = $(e.currentTarget);
  6187.  
  6188. target.find('.icon-rpc-devices').remove();
  6189. target.find('.pl-loading').remove();
  6190. target.prepend(base.createLoading());
  6191.  
  6192. let res = await yidong.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  6193. if (res === 'success') {
  6194. $('.listener-rpc-task').show();
  6195. target.removeClass('pl-btn-danger').html('发送成功了!快去看看吧~').animate({ opacity: '0.5' }, "slow");
  6196. } else if (res === 'assistant') {
  6197. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  6198. } else {
  6199. target.addClass('pl-btn-danger').text('发送失败,检查一下您的RPC配置信息哦!').animate({ opacity: '0.5' }, "slow");
  6200. }
  6201. });
  6202. doc.on('click', '.listener-send-rpc', function (e) {
  6203. $('.listener-link-rpc').click();
  6204. $(e.target).text('发送完成,发送结果见上方按钮哦~').animate({ opacity: '0.5' }, "slow");
  6205. });
  6206. doc.on('click', '.listener-open-setting', function () {
  6207. base.showSetting();
  6208. });
  6209. doc.on('click', '.listener-open-updatelog', function () {
  6210. base.showUpdateLog();
  6211. });
  6212. doc.on('click', '.listener-open-beautify', function () {
  6213. base.showBeautify();
  6214. });
  6215. doc.on('click', '.listener-rpc-task', function () {
  6216. let rpc = JSON.stringify({
  6217. domain: base.getValue('setting_rpc_domain'),
  6218. port: base.getValue('setting_rpc_port'),
  6219. }), url = `${pan.d}/?rpc=${base.encode(rpc)}#${base.getValue('setting_rpc_token')}`;
  6220. GM_openInTab(url, { active: true });
  6221. });
  6222. },
  6223.  
  6224. removeAD() {
  6225. base.waitForKeyElements(".adv_swiper_menu", function (tag) {
  6226. tag.fadeToggle();
  6227. });
  6228. base.waitForKeyElements(".client-bubble", function (tag) {
  6229. tag.fadeToggle();
  6230. });
  6231. base.waitForKeyElements(".avs-box", function (tag) {
  6232. tag.fadeToggle();
  6233. });
  6234. base.waitForKeyElements(".top-adv-swiper", function (tag) {
  6235. tag.fadeToggle();
  6236. });
  6237. base.waitForKeyElements(".client_download_icon", function (tag) {
  6238. tag.fadeToggle();
  6239. });
  6240. base.waitForKeyElements(".document_top_memberCenter", function (tag) {
  6241. $(tag[0]).click(function () {
  6242. Swal.fire({
  6243. html: `<iframe style="height: 700px; width: 420px; border: 0;" src="https://vip.yun.139.com/vip/"></iframe>`,
  6244. allowOutsideClick: false,
  6245. showCloseButton: true,
  6246. showConfirmButton: false,
  6247. heightAuto: false,
  6248. scrollbarPadding: false,
  6249. });
  6250. });
  6251. }, true);
  6252. },
  6253.  
  6254. addButton() {
  6255. if (!pt) return;
  6256. let $toolWrap;
  6257. 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>`);
  6258. if (pt === 'home') {
  6259. base.listenElement(pan.btn.home, function () {
  6260. $toolWrap = $(pan.btn.home);
  6261. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  6262. })
  6263. }
  6264. if (pt === 'share') {
  6265. $button.removeClass('yidong-button').addClass('yidong-share-button');
  6266. base.listenElement(pan.btn.share, function () {
  6267. $toolWrap = $(pan.btn.share);
  6268. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  6269. })
  6270. }
  6271. base.createDownloadIframe();
  6272. },
  6273.  
  6274. addInitButton() {
  6275. if (!pt) return;
  6276. let $toolWrap;
  6277. let $button = $(`<div class="yidong-button pl-button-init btn-top"><span class="yidong-btn">点我点亮</span></div>`);
  6278. if (pt === 'home') {
  6279. base.listenElement(pan.btn.home, function () {
  6280. $toolWrap = $(pan.btn.home);
  6281. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  6282. })
  6283. }
  6284. if (pt === 'share') {
  6285. $button.removeClass('yidong-button').addClass('yidong-share-button');
  6286. base.listenElement(pan.btn.share, function () {
  6287. $toolWrap = $(pan.btn.share);
  6288. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  6289. })
  6290. }
  6291. $button.click(function () { base.initDialog() });
  6292. },
  6293.  
  6294. getRandomString(len) {
  6295. len = len || 16;
  6296. let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
  6297. let maxPos = $chars.length;
  6298. let pwd = '';
  6299. for (let i = 0; i < len; i++) {
  6300. pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
  6301. }
  6302. return pwd;
  6303. },
  6304.  
  6305. utob(str) {
  6306. const u = String.fromCharCode;
  6307. return str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g, function (t) {
  6308. if (t.length < 2) {
  6309. let e = t.charCodeAt(0);
  6310. 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);
  6311. }
  6312. e = 65536 + 1024 * (t.charCodeAt(0) - 55296) + (t.charCodeAt(1) - 56320);
  6313. return u(240 | e >>> 18 & 7) + u(128 | e >>> 12 & 63) + u(128 | e >>> 6 & 63) + u(128 | 63 & e);
  6314. });
  6315. },
  6316.  
  6317. getSign(e, t, a, n) {
  6318. let r = "",
  6319. i = "";
  6320. if (t) {
  6321. let s = Object.assign({}, t);
  6322. i = JSON.stringify(s),
  6323. i = i.replace(/\s*/g, ""),
  6324. i = encodeURIComponent(i);
  6325. let c = i.split(""),
  6326. u = c.sort();
  6327. i = u.join("");
  6328. }
  6329. let A = md5(base.encode(this.utob(i)));
  6330. let l = md5(a + ":" + n);
  6331. return md5(A + l).toUpperCase();
  6332. },
  6333.  
  6334. async getFileUrlByOnce(item, index) {
  6335. try {
  6336. if (item.downloadUrl) return {
  6337. index,
  6338. downloadUrl: item.downloadUrl
  6339. };
  6340.  
  6341. if (this.detectPage() === 'home') {
  6342. let body = {
  6343. "contentID": item.contentID,
  6344. "commonAccountInfo": { "account": item.owner, "accountType": 1 },
  6345. "operation": "0",
  6346. "inline": "0",
  6347. "extInfo": { "isReturnCdnDownloadUrl": "1" }
  6348. };
  6349. let time = new Date(+new Date() + 8 * 3600 * 1000).toJSON().substr(0, 19).replace('T', ' ');
  6350. let key = this.getRandomString(16);
  6351. let sign = this.getSign(undefined, body, time, key);
  6352.  
  6353. let res = await base.post(pan.pcs[0], body, {
  6354. 'authorization': base.getCookie('authorization'),
  6355. 'x-huawei-channelSrc': '10000034',
  6356. 'x-inner-ntwk': '2',
  6357. 'mcloud-channel': '1000101',
  6358. 'mcloud-client': '10701',
  6359. 'mcloud-sign': time + "," + key + "," + sign,
  6360. 'content-type': "application/json;charset=UTF-8",
  6361. 'caller': 'web',
  6362. 'CMS-DEVICE': 'default',
  6363. 'x-DeviceInfo': '||9|7.12.0|chrome|119.0.0.0|||windows 10||zh-CN|||',
  6364. 'x-SvcType': '1',
  6365. });
  6366. if (res.success) {
  6367. return {
  6368. index,
  6369. downloadUrl: res.data.downloadURL
  6370. };
  6371. } else {
  6372. return {
  6373. index,
  6374. downloadUrl: '获取下载地址失败,刷新后再试试吧~'
  6375. };
  6376. }
  6377. }
  6378. if (this.detectPage() === 'share') {
  6379. let vueDom = document.querySelector(".main_file_list").__vue__;
  6380.  
  6381. let res = await base.post(pan.pcs[1], `linkId=${vueDom.linkID}&contentIds=${item.path}&catalogIds=`, {
  6382. 'Content-Type': 'application/x-www-form-urlencoded',
  6383. });
  6384. if (res.code === 0) {
  6385. return {
  6386. index,
  6387. downloadUrl: res.data.redrUrl
  6388. };
  6389. } else {
  6390. return {
  6391. index,
  6392. downloadUrl: '获取下载地址失败,刷新后再试试吧~'
  6393. };
  6394. }
  6395. }
  6396. } catch (e) {
  6397. return {
  6398. index,
  6399. downloadUrl: '获取下载地址失败,刷新后再试试吧~'
  6400. };
  6401. }
  6402. },
  6403.  
  6404. async getPCSLink() {
  6405. selectList = this.getSelectedList();
  6406. if (selectList.length === 0) {
  6407. return message.error('提示:<br/>请勾选要下载的文件哦~');
  6408. }
  6409. if (this.isOnlyFolder()) {
  6410. return message.error('提示:<br/>请打开文件夹后再勾选文件~');
  6411. }
  6412.  
  6413. let queue = [];
  6414. for (const [index, item] of selectList.entries()) {
  6415. queue.push(this.getFileUrlByOnce(item, index));
  6416. }
  6417.  
  6418. const res = await Promise.all(queue);
  6419. res.forEach(val => {
  6420. selectList[val.index].downloadUrl = val.downloadUrl;
  6421. });
  6422.  
  6423. let html = this.generateDom(selectList);
  6424. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  6425. },
  6426.  
  6427. generateDom(list) {
  6428. let content = '<div class="pl-main">';
  6429. let alinkAllText = '';
  6430. list.forEach((v, i) => {
  6431. if (v.dirEtag || v.caName) return;
  6432. let filename = v.contentName || v.coName;
  6433. let ext = base.getExtension(filename);
  6434. let size = base.sizeFormat(v.contentSize || v.coSize);
  6435. let dlink = v.downloadUrl;
  6436. if (mode === 'api') {
  6437. alinkAllText += dlink + '\r\n';
  6438. content += `<div class="pl-item">
  6439. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6440. <button class="pl-item-link listener-tip pl-btn-primary pl-btn-default listener-link-api blob" data-title="推荐使用本功能,基于浏览器的 Blob 文件流下载文件,适用于较新的浏览器,可以在此窗口中显示下载剩余时间和下载速度,此方式下载不会被 IDM 捕获下载链接" data-filename="${filename}" data-size="${v.contentSize || v.coSize}" data-link="${dlink}" data-index="${i}">增强下载(基于浏览器文件流)</button>
  6441. <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>
  6442. <button class="pl-item-copy pl-btn-primary listener-copy-all" href="${dlink}" data-filename="${filename}" data-link="${dlink}">复制链接</button>
  6443. <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>
  6444. <div class="pl-item-progress" style="display: none">
  6445. <div class="pl-progress">
  6446. <div class="pl-progress-outer"></div>
  6447. <div class="pl-progress-inner" style="width:5%">
  6448. <div class="pl-progress-inner-text">正在加载进度...0%</div>
  6449. </div>
  6450. </div>
  6451. <span class="pl-progress-stop listener-stop">取消下载</span>
  6452. `;
  6453. content += `<span class="pl-progress-tip" style="display: none" >未发现IDM,使用自带浏览器下载</span>
  6454. <span class="pl-progress-back listener-back" style="display: none">返回</span>
  6455. <span class="pl-progress-how listener-how" style="display: none">如何唤起IDM?</span>
  6456. `;
  6457. content += `</div></div>`
  6458. }
  6459. if (mode === 'aria') {
  6460. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  6461. alinkAllText += alink + '\r\n';
  6462. content += `<div class="pl-item">
  6463. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6464. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 aria2c 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  6465. }
  6466. if (mode === 'rpc') {
  6467. content += `<div class="pl-item">
  6468. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6469. <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>`;
  6470. }
  6471. if (mode === 'curl') {
  6472. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  6473. alinkAllText += alink + '\r\n';
  6474. content += `<div class="pl-item">
  6475. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6476. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制 curl 命令行" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>复制 ${filename} 下载命令行</a> </div>`;
  6477. }
  6478. if (mode === 'bc') {
  6479. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  6480. alinkAllText += alink + '\r\n';
  6481. content += `<div class="pl-item">
  6482. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  6483. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}<br/>下载 ${filename}</a> </div>`;
  6484. }
  6485. });
  6486. content += '</div>';
  6487. if (mode === 'api') {
  6488. content += `<div class="pl-extra"><button class="pl-btn-primary listener-download-all">全部增强下载</button><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  6489. }
  6490. if (mode === 'aria')
  6491. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部命令行</button></div>`;
  6492. if (mode === 'rpc') {
  6493. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  6494. 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>`;
  6495. }
  6496. if (mode === 'curl') {
  6497. 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>`;
  6498. }
  6499. if (mode === 'bc') {
  6500. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  6501. }
  6502. return content;
  6503. },
  6504.  
  6505. async sendLinkToRPC(filename, link) {
  6506. let rpc = {
  6507. domain: base.getValue('setting_rpc_domain'),
  6508. port: base.getValue('setting_rpc_port'),
  6509. path: base.getValue('setting_rpc_path'),
  6510. token: base.getValue('setting_rpc_token'),
  6511. dir: base.getValue('setting_rpc_dir'),
  6512. };
  6513.  
  6514. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  6515. let rpcData = {
  6516. id: new Date().getTime(),
  6517. jsonrpc: '2.0',
  6518. method: 'aria2.addUri',
  6519. params: [`token:${rpc.token}`, [link], {
  6520. dir: rpc.dir,
  6521. out: filename,
  6522. header: []
  6523. }]
  6524. };
  6525. try {
  6526. let res = await base.post(url, rpcData, {}, '');
  6527. if (res.result) return 'success';
  6528. return 'fail';
  6529. } catch (e) {
  6530. return 'fail';
  6531. }
  6532. },
  6533.  
  6534. getSelectedList() {
  6535. try {
  6536. return document.querySelector(".main_file_list").__vue__.selectList.map(val => val.item);
  6537. } catch (e) {
  6538. let vueDom = document.querySelector(".home-page").__vue__;
  6539. let fileList = vueDom._computedWatchers.fileList.value;
  6540. let dirList = vueDom._computedWatchers.dirList.value;
  6541. let selectedFileIndex = vueDom.selectedFile;
  6542. let selectedDirIndex = vueDom.selectedDir;
  6543. let selectFileList = fileList.filter((v, i) => {
  6544. return selectedFileIndex.includes(i);
  6545. });
  6546. let selectDirList = dirList.filter((v, i) => {
  6547. return selectedDirIndex.includes(i);
  6548. });
  6549. return [...selectFileList, ...selectDirList];
  6550. }
  6551. },
  6552.  
  6553. detectPage() {
  6554. let path = location.pathname;
  6555. if (/^\/w/.test(path)) return 'home';
  6556. if (/^\/link|shareweb/.test(path)) return 'share';
  6557. return '';
  6558. },
  6559.  
  6560. isOnlyFolder() {
  6561. for (let i = 0; i < selectList.length; i++) {
  6562. if (selectList[i].fileEtag || selectList[i].coName) return false;
  6563. }
  6564. return true;
  6565. },
  6566.  
  6567. showMainDialog(title, html, footer) {
  6568. Swal.fire({
  6569. title,
  6570. html,
  6571. footer,
  6572. allowOutsideClick: false,
  6573. showCloseButton: true,
  6574. position: 'center',
  6575. width,
  6576. padding: '15px 20px 5px',
  6577. customClass,
  6578. confirmButtonText: '关闭',
  6579. });
  6580. },
  6581.  
  6582. async initPanLinker() {
  6583. pt = this.detectPage();
  6584. base.createTip();
  6585. base.registerMenuCommand();
  6586. if (base.getValue('setting_youxiaohou_server') === 'v1') {
  6587. let res = await base.post(`https://api.youxiaohou.com/config/yidong/?ver=${version}&a=${author}`, {}, {}, 'text');
  6588. pan = JSON.parse(base.decode(res));
  6589. } else if (base.getValue('setting_youxiaohou_server') === 'v2') {
  6590. let res = await base.post(`https://api.youxiaohou.com/config/v2/yidong/?ver=${version}&a=${author}`, {}, {}, 'text');
  6591. pan = JSON.parse(base.decode(res));
  6592. } else if (base.getValue('setting_youxiaohou_server') === "no") {
  6593. 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", {});
  6594. pan = JSON.parse(res);
  6595. } else {
  6596. 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", {});
  6597. pan = JSON.parse(res);
  6598. base.setValue('setting_youxiaohou_server', 'v2');
  6599. }
  6600. Object.freeze && Object.freeze(pan);
  6601. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('license')) {
  6602. this.addButton();
  6603. this.addPageListener();
  6604. } else {
  6605. this.addInitButton();
  6606. }
  6607. }
  6608. };
  6609.  
  6610. // 油小猴
  6611. let youxiaohou = {
  6612. async initPanLinker() {
  6613. base.createTip();
  6614. base.registerMenuCommand();
  6615. if (base.getValue('setting_youxiaohou_server') === 'v1') {
  6616. let res = await base.post(`https://api.youxiaohou.com/config/?ver=${version}&a=${author}`, {}, {}, 'text');
  6617. pan = JSON.parse(base.decode(res));
  6618. } else if (base.getValue('setting_youxiaohou_server') === 'v2') {
  6619. let res = await base.post(`https://api.youxiaohou.com/config/v2/?ver=${version}&a=${author}`, {}, {}, 'text');
  6620. pan = JSON.parse(base.decode(res));
  6621. } else if (base.getValue('setting_youxiaohou_server') === "no") {
  6622. 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", {});
  6623. pan = JSON.parse(res);
  6624. } else {
  6625. 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", {});
  6626. pan = JSON.parse(res);
  6627. base.setValue('setting_youxiaohou_server', 'v2');
  6628. }
  6629. Object.freeze && Object.freeze(pan);
  6630. if (pan.num === base.getValue('setting_init_code') || pan.license === base.getValue('license')) {
  6631. this.addButton();
  6632. } else {
  6633. this.addInitButton();
  6634. }
  6635. },
  6636. addButton() {
  6637. let $button = `
  6638. <div class="nav-item">
  6639. <div class="dropdown-wrapper">
  6640. <button type="button" aria-label="(改)下载助手" class="dropdown-title">
  6641. <span class="title">(改)下载助手⬇️</span>
  6642. <span class="arrow down"></span>
  6643. </button>
  6644. <button type="button" aria-label="(改)下载助手" class="mobile-dropdown-title">
  6645. <span class="title">(改)下载助手⬇️</span>
  6646. <span class="arrow right"></span>
  6647. </button>
  6648. <ul class="nav-dropdown" style="display:none;">
  6649. <li class="dropdown-item">
  6650. <h4>
  6651. 助手
  6652. </h4>
  6653. <ul class="dropdown-subitem-wrapper">
  6654. <li class="dropdown-subitem">
  6655. <a href="javascript:void(0)" class="listener-open-info nav-link">
  6656. 🛠️ 调试(查看暗号/协议)
  6657. </a>
  6658. </li>
  6659. </ul>
  6660. </li>
  6661. <li class="dropdown-item">
  6662. <h4>
  6663. 选项
  6664. </h4>
  6665. <ul class="dropdown-subitem-wrapper">
  6666. <li class="dropdown-subitem">
  6667. <a href="javascript:void(0)" class="listener-open-setting nav-link">
  6668. ⚙️ 助手设置
  6669. </a>
  6670. </li>
  6671. <li class="dropdown-subitem">
  6672. <a href="javascript:void(0)" class="listener-open-beautify nav-link">
  6673. 🍃️ 助手美化
  6674. </a>
  6675. </li>
  6676. <li class="dropdown-subitem">
  6677. <a href="javascript:void(0)" class="listener-open-updatelog nav-link">
  6678. 📃️ 更新日志
  6679. </a>
  6680. </li>
  6681. </ul>
  6682. </li>
  6683. </ul>
  6684. </div>
  6685. </div>
  6686. `;
  6687. doc.on('click', '.listener-open-setting', function () {
  6688. base.showSetting();
  6689. });
  6690. doc.on('click', '.listener-open-updatelog', function () {
  6691. base.showUpdateLog();
  6692. });
  6693. doc.on('click', '.listener-open-beautify', function () {
  6694. base.showBeautify();
  6695. });
  6696. doc.on('click', '.listener-open-info', function () {
  6697. base.showDebug();
  6698. });
  6699.  
  6700. document.querySelectorAll(".nav-links").forEach(function (element) {
  6701. element.innerHTML += $button
  6702. })
  6703. },
  6704. addInitButton() {
  6705. let $button = `
  6706. <div class="nav-item">
  6707. <div class="dropdown-wrapper">
  6708. <a class="nav-link listener-open-init">(改)点我点亮⬇️</a>
  6709. </div>
  6710. </div>
  6711. `;
  6712. doc.on('click', '.listener-open-init', function () {
  6713. base.initDialog();
  6714. });
  6715.  
  6716. document.querySelectorAll(".nav-links").forEach(function (element) {
  6717. element.innerHTML += $button
  6718. })
  6719. }
  6720. }
  6721.  
  6722. // 主代码
  6723. let main = {
  6724. async init() {
  6725. // 先加载默认设置
  6726. base.initDefaultConfig();
  6727. // 然后获取原脚本的 GreasyFork 信息,确保油小猴服务器信任
  6728. await base.get('https://greasyfork.org/zh-CN/scripts/436446.json', { "referer": "https://greasyfork.org/" }, 'json', '').then(res => {
  6729. base.setValue('setting_script_version', res.version);
  6730. base.setValue('setting_script_author', 'YouXiaoHou');
  6731. base.setValue('setting_script_name', res.name);
  6732. })
  6733. // 再加载网页样式
  6734. base.addPanLinkerStyle();
  6735. // 最后判断页面地址并加载对应的initPanLinker
  6736. if (/(pan|yun).baidu.com/.test(location.host)) {
  6737. baidu.initPanLinker();
  6738. baidu.removeAD();
  6739. }
  6740. if (/openapi.baidu.com\/oauth/.test(location.href)) {
  6741. baidu.initAuthorize()
  6742. }
  6743. if (/www.(aliyundrive|alipan).com/.test(location.host)) {
  6744. ali.initPanLinker();
  6745. ali.removeAD();
  6746. }
  6747. if (/cloud.189.cn/.test(location.host)) {
  6748. tianyi.initPanLinker();
  6749. tianyi.removeAD();
  6750. }
  6751. if (/pan.xunlei.com/.test(location.host)) {
  6752. xunlei.initPanLinker();
  6753. }
  6754. if (/pan.quark.cn/.test(location.host)) {
  6755. quark.initPanLinker();
  6756. quark.removeAD();
  6757. }
  6758. if (/(yun|caiyun).139.com/.test(location.host)) {
  6759. yidong.initPanLinker();
  6760. yidong.removeAD();
  6761. }
  6762. if (/www.youxiaohou.com/.test(location.host)) {
  6763. youxiaohou.initPanLinker();
  6764. }
  6765. },
  6766. async downloadConfig() {
  6767. // 定义要下载的链接数组及对应的文件名
  6768. let urlsAndFilenames = [
  6769. { url: `https://api.youxiaohou.com/config/v2/?ver=${version}&a=${author}`, filename: 'config.json' },
  6770. { url: `https://api.youxiaohou.com/config/v2/ali/?ver=${version}&a=${author}`, filename: 'ali.json' },
  6771. { url: `https://api.youxiaohou.com/config/v2/tianyi/?ver=${version}&a=${author}`, filename: 'tianyi.json' },
  6772. { url: `https://api.youxiaohou.com/config/v2/xunlei/?ver=${version}&a=${author}`, filename: 'xunlei.json' },
  6773. { url: `https://api.youxiaohou.com/config/v2/quark/?ver=${version}&a=${author}`, filename: 'quark.json' },
  6774. { url: `https://api.youxiaohou.com/config/v2/yidong/?ver=${version}&a=${author}`, filename: 'yidong.json' },
  6775. ];
  6776.  
  6777. // 发送多个 POST 请求并等待所有请求完成
  6778. let responses = await Promise.all(urlsAndFilenames.map(obj => base.post(obj.url, {}, {}, 'text')));
  6779.  
  6780. // 遍历所有响应并进行处理
  6781. responses.forEach((res, index) => {
  6782. let url = urlsAndFilenames[index].url;
  6783. let filename = urlsAndFilenames[index].filename;
  6784.  
  6785. // 解析响应内容(假设响应内容是 JSON 格式)
  6786. let panData = JSON.parse(base.decode(res));
  6787.  
  6788. // 创建 Blob 对象
  6789. let blob = new Blob([JSON.stringify(panData)], { type: 'application/json' });
  6790.  
  6791. // 下载 Blob 对象
  6792. base.blobDownload(blob, filename);
  6793. });
  6794. }
  6795. };
  6796. // 将函数暴露到全局作用域以便在控制台中调用
  6797. unsafeWindow.Panlinker = main;
  6798. main.init();
  6799. })();