LinkSwift

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

Εγκατάσταση αυτού του κώδικαΒοήθεια
Κώδικας προτεινόμενος από τον δημιιουργό

Μπορεί, επίσης, να σας αρέσει ο κώδικας (改)百度网盘会员青春版.

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