网盘直链下载助手

👆👆👆👆👆👆👆 - 支持批量获取 ✅百度网盘 ✅阿里云盘 ✅天翼云盘 ✅迅雷云盘 ✅夸克网盘 ✅移动云盘 六大网盘的直链下载地址,配合 IDM,Xdown,Aria2,Curl,比特彗星等工具高效🚀🚀🚀下载,完美适配 Chrome,Edge,FireFox,360,QQ,搜狗,百分,遨游,星愿,Opera,猎豹,Vivaldi,Yandex,Kiwi 等 18 种浏览器。可在无法安装客户端的环境下使用,助手免费开源。😎

Installera detta skript?
Författaren's rekommenderade skript

Du kanske också gillar 网盘智能识别助手.

Installera detta skript
  1. // ==UserScript==
  2. // @name 网盘直链下载助手
  3. // @namespace https://github.com/syhyz1990/baiduyun
  4. // @version 6.2.7
  5. // @author GreasyFork
  6. // @description 👆👆👆👆👆👆👆 - 支持批量获取 ✅百度网盘 ✅阿里云盘 ✅天翼云盘 ✅迅雷云盘 ✅夸克网盘 ✅移动云盘 六大网盘的直链下载地址,配合 IDM,Xdown,Aria2,Curl,比特彗星等工具高效🚀🚀🚀下载,完美适配 Chrome,Edge,FireFox,360,QQ,搜狗,百分,遨游,星愿,Opera,猎豹,Vivaldi,Yandex,Kiwi 等 18 种浏览器。可在无法安装客户端的环境下使用,助手免费开源。😎
  7. // @license AGPL-3.0-or-later
  8. // @homepage https://www.youxiaohou.com/install.html
  9. // @supportURL https://github.com/syhyz1990/baiduyun
  10. // @antifeature membership
  11. // @match *://pan.baidu.com/disk/home*
  12. // @match *://yun.baidu.com/disk/home*
  13. // @match *://pan.baidu.com/disk/main*
  14. // @match *://yun.baidu.com/disk/main*
  15. // @match *://pan.baidu.com/s/*
  16. // @match *://yun.baidu.com/s/*
  17. // @match *://pan.baidu.com/share/*
  18. // @match *://yun.baidu.com/share/*
  19. // @match *://openapi.baidu.com/*
  20. // @match *://www.aliyundrive.com/s/*
  21. // @match *://www.aliyundrive.com/drive*
  22. // @match *://www.alipan.com/s/*
  23. // @match *://www.alipan.com/drive*
  24. // @match *://cloud.189.cn/web/*
  25. // @match *://pan.xunlei.com/*
  26. // @match *://pan.quark.cn/*
  27. // @match *://yun.139.com/*
  28. // @match *://caiyun.139.com/*
  29. // @require https://unpkg.com/jquery@3.7.0/dist/jquery.min.js
  30. // @require https://unpkg.com/sweetalert2@10.16.6/dist/sweetalert2.all.min.js
  31. // @require https://unpkg.com/js-md5@0.7.3/build/md5.min.js
  32. // @connect baidu.com
  33. // @connect baidupcs.com
  34. // @connect aliyundrive.com
  35. // @connect alipan.com
  36. // @connect 189.cn
  37. // @connect xunlei.com
  38. // @connect quark.cn
  39. // @connect youxiaohou.com
  40. // @connect yun.139.com
  41. // @connect caiyun.139.com
  42. // @connect localhost
  43. // @connect *
  44. // @run-at document-idle
  45. // @grant unsafeWindow
  46. // @grant GM_xmlhttpRequest
  47. // @grant GM_setClipboard
  48. // @grant GM_setValue
  49. // @grant GM_getValue
  50. // @grant GM_deleteValue
  51. // @grant GM_openInTab
  52. // @grant GM_info
  53. // @grant GM_registerMenuCommand
  54. // @grant GM_cookie
  55. // @grant window.close
  56. // @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxMjggMTI4Ij48cGF0aCBkPSJNMTAzLjYgMTA3LjRjMy41LTIuMiA4LjktNi4xIDEzLjgtMTIuNXM3LjMtMTIuNSA4LjUtMTYuNWMuNS0xLjcgMi4yLTcuNSAyLjItMTQuNyAwLTEwLjEtMy4zLTI1LjEtMTUuNC0zNi44LTE0LjUtMTQtMzIuMS0xNC4zLTM1LjctMTQuMy04IDAtMTUuNyAxLjktMjIuNiA1LjJDNDQgMjMgMzUuNyAzMS40IDMwLjggNDEuN2MtMS4zIDIuOC00IDQuNy03LjEgNS00IC4zLTcuNSA0LjQtOC45IDkuNi0uNSAxLjktMS42IDMuNS0zLjEgNC43QzQuNCA2Ni44IDAgNzUuNyAwIDg1YzAgNi44IDIuMyAxMy4xIDYuMSAxOC4yIDUuNSA3LjQgMTQuMiAxMi4yIDI0IDEyLjJoNDcuMWM0LjQgMCAxMS0uNSAxOC4zLTMuNSAzLjItMS40IDUuOS0zIDguMS00LjV6IiBmaWxsPSIjNDQ0Ii8+PHBhdGggZD0iTTExOS44IDY0LjNjLjEtMTcuMS0xMC40LTI4LTEyLjUtMzAuMUM5NSAyMi4xIDc5LjkgMjEuOCA3Ni45IDIxLjhjLTE3LjYgMC0zMy4zIDEwLjUtMzkuOSAyNi43LS42IDEuMy0xLjggMi4zLTMuNCAyLjNoLS40Yy01LjggMC0xMC42IDQuOC0xMC42IDEwLjd2LjVjMCAxLjQtLjggMi42LTEuOSAzLjNDMTMuNCA2OSA4LjggNzYuOCA4LjggODVjMCAxMi4yIDkuOSAyMi4zIDIyLjIgMjIuM2g0NS4yYzMuNi0uMSAxNy42LS45IDI5LjYtMTIgMi45LTIuOCAxMy45LTEzLjcgMTQtMzF6IiBmaWxsPSIjMTM5N2Q4Ii8+PHBhdGggZD0iTTExMC44IDU3LjRsLjIgMy4zYzAgMS4zLTEuMSAyLjQtMi4zIDIuNC0xLjMgMC0yLjMtMS4xLTIuMy0yLjRsLS4xLTIuOHYtLjNjMC0xLjIuOS0yLjIgMi4xLTIuM2guM2MuNyAwIDEuMy4zIDEuNy43LS4yLjEuMy41LjQgMS40em0tMy4zLTEwLjNjMCAxLjItMSAyLjMtMi4yIDIuM2gtLjFjLS44IDAtMS42LS41LTItMS4yLTQuNi04LjMtMTMuMy0xMy41LTIyLjgtMTMuNS0xLjIgMC0yLjMtMS0yLjMtMi4ydi0uMWMwLTEuMiAxLTIuMyAyLjItMi4zaC4xYTMwLjM3IDMwLjM3IDAgMCAxIDE1LjggNC40YzQuNiAyLjggOC40IDYuOCAxMS4xIDExLjUuMS4zLjIuNy4yIDEuMXpNODguMyA3My44TDczLjUgOTMuMmMtMS41IDEuOS0zLjUgMy4xLTUuNyAzLjVoLS4yYy0uNC4xLS44LjEtMS4yLjEtLjYgMC0xLjEtLjEtMS42LS4yLTIuMi0uNC00LjItMS43LTUuNi0zLjVMNDQuMyA3My45Yy0yLTIuNi0yLjUtNS40LTEuNC03LjcuMS0uMS4xLS4yLjItLjIgMS4yLTIgMy41LTMuMiA2LjQtMy4yaDYuNnYtNS43YzAtNi44IDQuNy0xMiAxMC45LTEyIDQuOCAwIDguNSAyLjYgMTAuMyA3LjIuNSAxLjMtLjIgMi43LTEuNSAzLjJzLTIuOC0uMS0zLjMtMS40Yy0xLjEtMi43LTIuOS00LTUuNS00LTMuNSAwLTYgMy02IDd2OC4xYzAgLjUtLjIgMS0uNiAxLjQtLjYuNy0xLjcgMS4xLTIuNiAxLjFoLTguNGMtMS4zIDAtMiAuNC0yLjEuNy0uMi40IDAgMS4zLjkgMi40TDYzLjEgOTBjLjkgMS4yIDIuMSAxLjggMy4zIDEuOHMyLjMtLjYgMy4xLTEuN2wxNC44LTE5LjNjLjktMS4xIDEuMS0yIC45LTIuNC0uMi0uMy0uOS0uNy0yLjEtLjdoLTcuNmMtLjkgMC0xLjctLjUtMi4xLTEuMi0uMy0uNC0uNC0uOC0uNC0xLjMgMC0xLjQgMS4xLTIuNSAyLjUtMi41aDcuNmMzLjEgMCA1LjUgMS4zIDYuNiAzLjVsLjMuN2MuNyAyLjEuMSA0LjYtMS43IDYuOXoiIGZpbGw9IiM0NDQiLz48L3N2Zz4=
  57. // ==/UserScript==
  58.  
  59. (function () {
  60. 'use strict';
  61.  
  62. let pt = '', selectList = [], params = {}, mode = '', width = 800, pan = {}, color = '',
  63. doc = $(document), progress = {}, request = {}, ins = {}, idm = {};
  64. const scriptInfo = GM_info.script;
  65. const version = scriptInfo.version;
  66. const author = scriptInfo.author;
  67. const name = scriptInfo.name;
  68. const manageHandler = GM_info.scriptHandler;
  69. const manageVersion = GM_info.version;
  70. const customClass = {
  71. popup: 'pl-popup',
  72. header: 'pl-header',
  73. title: 'pl-title',
  74. closeButton: 'pl-close',
  75. content: 'pl-content',
  76. input: 'pl-input',
  77. footer: 'pl-footer'
  78. };
  79.  
  80. const terminalType = {
  81. wc: "Windows CMD",
  82. wp: "Windows PowerShell",
  83. lt: "Linux 终端",
  84. ls: "Linux Shell",
  85. mt: "MacOS 终端",
  86. };
  87.  
  88. let toast = Swal.mixin({
  89. toast: true,
  90. position: 'top',
  91. showConfirmButton: false,
  92. timer: 3500,
  93. timerProgressBar: false,
  94. didOpen: (toast) => {
  95. toast.addEventListener('mouseenter', Swal.stopTimer);
  96. toast.addEventListener('mouseleave', Swal.resumeTimer);
  97. }
  98. });
  99.  
  100. const message = {
  101. success: (text) => {
  102. toast.fire({title: text, icon: 'success'});
  103. },
  104. error: (text) => {
  105. toast.fire({title: text, icon: 'error'});
  106. },
  107. warning: (text) => {
  108. toast.fire({title: text, icon: 'warning'});
  109. },
  110. info: (text) => {
  111. toast.fire({title: text, icon: 'info'});
  112. },
  113. question: (text) => {
  114. toast.fire({title: text, icon: 'question'});
  115. }
  116. };
  117.  
  118. let base = {
  119.  
  120. getCookie(name) {
  121. let cname = name + "=";
  122. let ca = document.cookie.split(';');
  123. for (let i = 0; i < ca.length; i++) {
  124. let c = ca[i].trim();
  125. if (c.indexOf(cname) == 0) return c.substring(cname.length, c.length);
  126. }
  127. return "";
  128. },
  129.  
  130. isType(obj) {
  131. return Object.prototype.toString.call(obj).replace(/^\[object (.+)\]$/, '$1').toLowerCase();
  132. },
  133.  
  134. getValue(name) {
  135. return GM_getValue(name);
  136. },
  137.  
  138. setValue(name, value) {
  139. GM_setValue(name, value);
  140. },
  141.  
  142. deleteValue(name) {
  143. GM_deleteValue(name);
  144. },
  145.  
  146. getStorage(key) {
  147. try {
  148. return JSON.parse(localStorage.getItem(key));
  149. } catch (e) {
  150. return localStorage.getItem(key);
  151. }
  152. },
  153.  
  154. setStorage(key, value) {
  155. if (this.isType(value) === 'object' || this.isType(value) === 'array') {
  156. return localStorage.setItem(key, JSON.stringify(value));
  157. }
  158. return localStorage.setItem(key, value);
  159. },
  160.  
  161. setClipboard(text) {
  162. GM_setClipboard(text, 'text');
  163. },
  164.  
  165. e(str) {
  166. return btoa(unescape(encodeURIComponent(str)));
  167. },
  168.  
  169. d(str) {
  170. return decodeURIComponent(escape(atob(str)));
  171. },
  172.  
  173. getExtension(name) {
  174. const reg = /(?!\.)\w+$/;
  175. if (reg.test(name)) {
  176. let match = name.match(reg);
  177. return match[0].toUpperCase();
  178. }
  179. return '';
  180. },
  181.  
  182. sizeFormat(value) {
  183. if (value === +value) {
  184. let unit = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
  185. let index = Math.floor(Math.log(value) / Math.log(1024));
  186. let size = value / Math.pow(1024, index);
  187. size = size.toFixed(1);
  188. return size + unit[index];
  189. }
  190. return '';
  191. },
  192.  
  193. sortByName(arr) {
  194. const handle = () => {
  195. return (a, b) => {
  196. const p1 = a.filename ? a.filename : a.server_filename;
  197. const p2 = b.filename ? b.filename : b.server_filename;
  198. return p1.localeCompare(p2, "zh-CN");
  199. };
  200. };
  201. arr.sort(handle());
  202. },
  203.  
  204. fixFilename(name) {
  205. return name.replace(/[!?&|`"'*\/:<>\\]/g, '_');
  206. },
  207.  
  208. blobDownload(blob, filename) {
  209. if (blob instanceof Blob) {
  210. const url = URL.createObjectURL(blob);
  211. const a = document.createElement('a');
  212. a.href = url;
  213. a.download = filename;
  214. a.click();
  215. URL.revokeObjectURL(url);
  216. }
  217. },
  218.  
  219. post(url, data, headers, type) {
  220. if (this.isType(data) === 'object') {
  221. data = JSON.stringify(data);
  222. }
  223. return new Promise((resolve, reject) => {
  224. GM_xmlhttpRequest({
  225. method: "POST", url, headers, data,
  226. responseType: type || 'json',
  227. onload: (res) => {
  228. type === 'blob' ? resolve(res) : resolve(res.response || res.responseText);
  229. },
  230. onerror: (err) => {
  231. reject(err);
  232. },
  233. });
  234. });
  235. },
  236.  
  237. get(url, headers, type, extra) {
  238. return new Promise((resolve, reject) => {
  239. let requestObj = GM_xmlhttpRequest({
  240. method: "GET", url, headers,
  241. responseType: type || 'json',
  242. onload: (res) => {
  243. if (res.status === 204) {
  244. requestObj.abort();
  245. idm[extra.index] = true;
  246. }
  247. if (type === 'blob') {
  248. res.status === 200 && base.blobDownload(res.response, extra.filename);
  249. resolve(res);
  250. } else {
  251. resolve(res.response || res.responseText);
  252. }
  253. },
  254. onprogress: (res) => {
  255. if (extra && extra.filename && extra.index) {
  256. res.total > 0 ? progress[extra.index] = (res.loaded * 100 / res.total).toFixed(2) : progress[extra.index] = 0.00;
  257. }
  258. },
  259. onloadstart() {
  260. extra && extra.filename && extra.index && (request[extra.index] = requestObj);
  261. },
  262. onerror: (err) => {
  263. reject(err);
  264. },
  265. });
  266. });
  267. },
  268.  
  269. getFinalUrl(url, headers) {
  270. return new Promise((resolve, reject) => {
  271. let requestObj = GM_xmlhttpRequest({
  272. method: "GET", url, headers,
  273. onload: (res) => {
  274. resolve(res.finalUrl)
  275. },
  276. onerror: (err) => {
  277. reject(err);
  278. }
  279. });
  280. });
  281. },
  282.  
  283. stringify(obj) {
  284. let str = '';
  285. for (var key in obj) {
  286. if (obj.hasOwnProperty(key)) {
  287. var value = obj[key];
  288. if (Array.isArray(value)) {
  289. for (var i = 0; i < value.length; i++) {
  290. str += encodeURIComponent(key) + '=' + encodeURIComponent(value[i]) + '&';
  291. }
  292. } else {
  293. str += encodeURIComponent(key) + '=' + encodeURIComponent(value) + '&';
  294. }
  295. }
  296. }
  297. return str.slice(0, -1); // 去掉末尾的 "&"
  298. },
  299.  
  300. addStyle(id, tag, css) {
  301. tag = tag || 'style';
  302. let doc = document, styleDom = doc.getElementById(id);
  303. if (styleDom) return;
  304. let style = doc.createElement(tag);
  305. style.rel = 'stylesheet';
  306. style.id = id;
  307. tag === 'style' ? style.innerHTML = css : style.href = css;
  308. doc.getElementsByTagName('head')[0].appendChild(style);
  309. },
  310.  
  311. sleep(time) {
  312. return new Promise(resolve => setTimeout(resolve, time));
  313. },
  314.  
  315. getMajorVersion(version) {
  316. const [major] = (version || '').split('.');
  317. return /^\d+$/.test(major) ? major : null;
  318. },
  319.  
  320. findReact(dom, traverseUp = 0) {
  321. const key = Object.keys(dom).find(key => {
  322. return key.startsWith("__reactFiber$")
  323. || key.startsWith("__reactInternalInstance$");
  324. });
  325. const domFiber = dom[key];
  326. if (domFiber == null) return null;
  327.  
  328. if (domFiber._currentElement) {
  329. let compFiber = domFiber._currentElement._owner;
  330. for (let i = 0; i < traverseUp; i++) {
  331. compFiber = compFiber._currentElement._owner;
  332. }
  333. return compFiber._instance;
  334. }
  335.  
  336. const GetCompFiber = fiber => {
  337. let parentFiber = fiber.return;
  338. while (typeof parentFiber.type == "string") {
  339. parentFiber = parentFiber.return;
  340. }
  341. return parentFiber;
  342. };
  343. let compFiber = GetCompFiber(domFiber);
  344. for (let i = 0; i < traverseUp; i++) {
  345. compFiber = GetCompFiber(compFiber);
  346. }
  347. return compFiber.stateNode || compFiber;
  348. },
  349.  
  350. initDefaultConfig() {
  351. let value = [{
  352. name: 'setting_rpc_domain',
  353. value: 'http://localhost'
  354. }, {
  355. name: 'setting_rpc_port',
  356. value: '16800'
  357. }, {
  358. name: 'setting_rpc_path',
  359. value: '/jsonrpc'
  360. }, {
  361. name: 'setting_rpc_token',
  362. value: ''
  363. }, {
  364. name: 'setting_rpc_dir',
  365. value: 'D:'
  366. }, {
  367. name: 'setting_terminal_type',
  368. value: 'wc'
  369. }, {
  370. name: 'setting_theme_color',
  371. value: '#09AAFF'
  372. }, {
  373. name: 'setting_init_code',
  374. value: ''
  375. }, {
  376. name: 'license',
  377. value: ''
  378. }];
  379.  
  380. value.forEach((v) => {
  381. base.getValue(v.name) === undefined && base.setValue(v.name, v.value);
  382. });
  383. },
  384.  
  385. showSetting() {
  386. let dom = '', btn = '',
  387. colorList = ['#09AAFF', '#cc3235', '#526efa', '#518c17', '#ed944b', '#f969a5', '#bca280'];
  388. dom += `<label class="pl-setting-label"><div class="pl-label">RPC主机</div><input type="text" placeholder="主机地址,需带上http(s)://" class="pl-input listener-domain" value="${base.getValue('setting_rpc_domain')}"></label>`;
  389. dom += `<label class="pl-setting-label"><div class="pl-label">RPC端口</div><input type="text" placeholder="端口号,例如:Motrix为16800" class="pl-input listener-port" value="${base.getValue('setting_rpc_port')}"></label>`;
  390. dom += `<label class="pl-setting-label"><div class="pl-label">RPC路径</div><input type="text" placeholder="路径,默认为/jsonrpc" class="pl-input listener-path" value="${base.getValue('setting_rpc_path')}"></label>`;
  391. dom += `<label class="pl-setting-label"><div class="pl-label">RPC密钥</div><input type="text" placeholder="无密钥无需填写" class="pl-input listener-token" value="${base.getValue('setting_rpc_token')}"></label>`;
  392. dom += `<label class="pl-setting-label"><div class="pl-label">保存路径</div><input type="text" placeholder="文件下载后保存路径,例如:D:" class="pl-input listener-dir" value="${base.getValue('setting_rpc_dir')}"></label>`;
  393.  
  394. colorList.forEach((v) => {
  395. btn += `<div data-color="${v}" style="background: ${v};border: 1px solid ${v}" class="pl-color-box listener-color ${v === base.getValue('setting_theme_color') ? 'checked' : ''}"></div>`;
  396. });
  397. dom += `<label class="pl-setting-label"><div class="pl-label">终端类型</div><select class="pl-input listener-terminal">`;
  398. Object.keys(terminalType).forEach(k => {
  399. dom += `<option value="${k}" ${base.getValue('setting_terminal_type') === k ? 'selected' : ''}>${terminalType[k]}</option>`;
  400. });
  401. dom += `</select></label>`;
  402. dom += `<label class="pl-setting-label"><div class="pl-label">主题颜色</div> <div class="pl-color">${btn}<div></label>`;
  403. dom = '<div>' + dom + '</div>';
  404.  
  405. Swal.fire({
  406. title: '助手配置',
  407. html: dom,
  408. icon: 'info',
  409. showCloseButton: true,
  410. showConfirmButton: false,
  411. footer: pan.footer,
  412. }).then(() => {
  413. message.success('设置成功!');
  414. history.go(0);
  415. });
  416.  
  417. doc.on('click', '.listener-color', async (e) => {
  418. base.setValue('setting_theme_color', e.target.dataset.color);
  419. message.success('设置成功!');
  420. history.go(0);
  421. });
  422. doc.on('input', '.listener-domain', async (e) => {
  423. base.setValue('setting_rpc_domain', e.target.value);
  424. });
  425. doc.on('input', '.listener-port', async (e) => {
  426. base.setValue('setting_rpc_port', e.target.value);
  427. });
  428. doc.on('input', '.listener-path', async (e) => {
  429. base.setValue('setting_rpc_path', e.target.value);
  430. });
  431. doc.on('input', '.listener-token', async (e) => {
  432. base.setValue('setting_rpc_token', e.target.value);
  433. });
  434. doc.on('input', '.listener-dir', async (e) => {
  435. base.setValue('setting_rpc_dir', e.target.value);
  436. });
  437. doc.on('change', '.listener-terminal', async (e) => {
  438. base.setValue('setting_terminal_type', e.target.value);
  439. });
  440. },
  441.  
  442. registerMenuCommand() {
  443. GM_registerMenuCommand('⚙️ 设置', () => {
  444. this.showSetting();
  445. });
  446. },
  447.  
  448. createTip() {
  449. $('body').append('<div class="pl-tooltip"></div>');
  450.  
  451. doc.on('mouseenter mouseleave', '.listener-tip', (e) => {
  452. if (e.type === 'mouseenter') {
  453. let filename = e.currentTarget.innerText;
  454. let size = e.currentTarget.dataset.size;
  455. let tip = `${filename}<span style="margin-left: 10px;color: #f56c6c;">${size}</span>`;
  456. $(e.currentTarget).css({opacity: '0.5'});
  457. $('.pl-tooltip').html(tip).css({
  458. 'left': e.pageX + 10 + 'px',
  459. 'top': e.pageY - e.currentTarget.offsetTop > 14 ? e.pageY + 'px' : e.pageY + 20 + 'px'
  460. }).show();
  461. } else {
  462. $(e.currentTarget).css({opacity: '1'});
  463. $('.pl-tooltip').hide(0);
  464. }
  465. });
  466. },
  467.  
  468. createLoading() {
  469. return $('<div class="pl-loading"><div class="pl-loading-box"><div><div></div><div></div></div></div></div>');
  470. },
  471.  
  472. createDownloadIframe() {
  473. let $div = $('<div style="padding:0;margin:0;display:block"></div>');
  474. let $iframe = $('<iframe src="javascript:;" id="downloadIframe" style="display:none"></iframe>');
  475. $div.append($iframe);
  476. $('body').append($div);
  477. },
  478.  
  479. getMirrorList(link, mirror, thread = 2) {
  480. let host = new URL(link).host;
  481. let mirrors = [];
  482. for (let i = 0; i < mirror.length; i++) {
  483. for (let j = 0; j < thread; j++) {
  484. let item = link.replace(host, mirror[i]) + '&'.repeat(j);
  485. mirrors.push(item);
  486. }
  487. }
  488. return mirrors.join('\n');
  489. },
  490.  
  491. listenElement(element, callback) {
  492. const checkInterval = 500; // 检查元素的间隔时间(毫秒)
  493. let wasElementFound = false; // 用于跟踪元素是否之前已经找到
  494.  
  495. function checkElement() {
  496. if (document.querySelector(element)) {
  497. wasElementFound = true;
  498. callback();
  499. } else if (wasElementFound) {
  500. wasElementFound = false; // 元素消失后重置标志
  501. }
  502.  
  503. setTimeout(checkElement, checkInterval);
  504. }
  505.  
  506. checkElement();
  507. },
  508.  
  509. addPanLinkerStyle() {
  510. color = base.getValue('setting_theme_color');
  511. let css = `
  512. body::-webkit-scrollbar { display: none }
  513. ::-webkit-scrollbar { width: 6px; height: 10px }
  514. ::-webkit-scrollbar-track { border-radius: 0; background: none }
  515. ::-webkit-scrollbar-thumb { background-color: rgba(85,85,85,.4) }
  516. ::-webkit-scrollbar-thumb,::-webkit-scrollbar-thumb:hover { border-radius: 5px; -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,.2) }
  517. ::-webkit-scrollbar-thumb:hover { background-color: rgba(85,85,85,.3) }
  518. .swal2-popup { font-size: 16px !important; }
  519. .pl-popup { font-size: 12px !important; }
  520. .pl-popup a { color: ${color} !important; }
  521. .pl-header { padding: 0!important;align-items: flex-start!important; border-bottom: 1px solid #eee!important; margin: 0 0 10px!important; padding: 0 0 5px!important; }
  522. .pl-title { font-size: 16px!important; line-height: 1!important;white-space: nowrap!important; text-overflow: ellipsis!important;}
  523. .pl-content { padding: 0 !important; font-size: 12px!important; }
  524. .pl-main { max-height: 400px;overflow-y:scroll; }
  525. .pl-footer {font-size: 12px!important;justify-content: flex-start!important; margin: 10px 0 0!important; padding: 5px 0 0!important; color: #f56c6c!important; }
  526. .pl-item { display: flex; align-items: center; line-height: 22px; }
  527. .pl-item-name { flex: 0 0 150px; text-align: left;margin-right: 10px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; cursor:default; }
  528. .pl-item-link { flex: 1; overflow: hidden; text-align: left; white-space: nowrap; text-overflow: ellipsis;cursor:pointer }
  529. .pl-item-btn { background: ${color}; padding: 4px 5px; border-radius: 3px; line-height: 1; cursor: pointer; color: #fff; }
  530. .pl-item-tip { display: flex; justify-content: space-between;flex: 1; }
  531. .pl-back { width: 70px; background: #ddd; border-radius: 3px; cursor:pointer; margin:1px 0; }
  532. .pl-ext { display: inline-block; width: 44px; background: #999; color: #fff; height: 16px; line-height: 16px; font-size: 12px; border-radius: 3px;}
  533. .pl-retry {padding: 3px 10px; background: #cc3235; color: #fff; border-radius: 3px; cursor: pointer;}
  534. .pl-browserdownload { padding: 3px 10px; background: ${color}; color: #fff; border-radius: 3px; cursor: pointer;}
  535. .pl-item-progress { display:flex;flex: 1;align-items:center}
  536. .pl-progress { display: inline-block;vertical-align: middle;width: 100%; box-sizing: border-box;line-height: 1;position: relative;height:15px; flex: 1}
  537. .pl-progress-outer { height: 15px;border-radius: 100px;background-color: #ebeef5;overflow: hidden;position: relative;vertical-align: middle;}
  538. .pl-progress-inner{ position: absolute;left: 0;top: 0;background-color: #409eff;text-align: right;border-radius: 100px;line-height: 1;white-space: nowrap;transition: width .6s ease;}
  539. .pl-progress-inner-text { display: inline-block;vertical-align: middle;color: #d1d1d1;font-size: 12px;margin: 0 5px;height: 15px}
  540. .pl-progress-tip{ flex:1;text-align:right}
  541. .pl-progress-how{ flex: 0 0 90px; background: #ddd; border-radius: 3px; margin-left: 10px; cursor: pointer; text-align: center;}
  542. .pl-progress-stop{ flex: 0 0 50px; padding: 0 10px; background: #cc3235; color: #fff; border-radius: 3px; cursor: pointer;margin-left:10px;height:20px}
  543. .pl-progress-inner-text:after { display: inline-block;content: "";height: 100%;vertical-align: middle;}
  544. .pl-btn-primary { background: ${color}; border: 0; border-radius: 4px; color: #ffffff; cursor: pointer; font-size: 12px; outline: none; display:flex; align-items: center; justify-content: center; margin: 2px 0; padding: 6px 0;transition: 0.3s opacity; }
  545. .pl-btn-primary:hover { opacity: 0.9;transition: 0.3s opacity; }
  546. .pl-btn-success { background: #55af28; animation: easeOpacity 1.2s 2; animation-fill-mode:forwards }
  547. .pl-btn-info { background: #606266; }
  548. .pl-btn-warning { background: #da9328; }
  549. .pl-btn-warning { background: #da9328; }
  550. .pl-btn-danger { background: #cc3235; }
  551. .ali-button {display: inline-flex;align-items: center;justify-content: center;border: 0 solid transparent;border-radius: 5px;box-shadow: 0 0 0 0 transparent;width: fit-content;white-space: nowrap;flex-shrink: 0;font-size: 14px;line-height: 1.5;outline: 0;touch-action: manipulation;transition: background .3s ease,color .3s ease,border .3s ease,box-shadow .3s ease;color: #fff;background: rgb(99 125 255);margin-left: 20px;padding: 1px 12px;position: relative; cursor:pointer; height: 32px;}
  552. .ali-button:hover {background: rgb(122, 144, 255)}
  553. .tianyi-button {margin-right: 20px; padding: 4px 12px; border-radius: 4px; color: #fff; font-size: 12px; border: 1px solid #0073e3; background: #2b89ea; cursor: pointer; position: relative;}
  554. .tianyi-button:hover {border-color: #1874d3; background: #3699ff;}
  555. .yidong-button {float: left; position: relative; margin: 20px 24px 20px 0; width: 98px; height: 36px; background: #3181f9; border-radius: 2px; font-size: 14px; color: #fff; line-height: 39px; text-align: center; cursor: pointer;}
  556. .yidong-share-button {display: inline-block; position: relative; font-size: 14px; line-height: 36px; height: 36px; text-align: center; color: #fff; border: 1px solid #5a9afa; border-radius: 2px; padding: 0 24px; margin-left: 24px; background: #3181f9; cursor: pointer;}
  557. .yidong-button:hover {background: #2d76e5;}
  558. .xunlei-button {display: inline-flex;align-items: center;justify-content: center;border: 0 solid transparent;border-radius: 5px;box-shadow: 0 0 0 0 transparent;width: fit-content;white-space: nowrap;flex-shrink: 0;font-size: 14px;line-height: 1.5;outline: 0;touch-action: manipulation;transition: background .3s ease,color .3s ease,border .3s ease,box-shadow .3s ease;color: #fff;background: #3f85ff;margin-left: 12px;padding: 0px 12px;position: relative; cursor:pointer; height: 36px;}
  559. .xunlei-button:hover {background: #619bff}
  560. .quark-button {display: inline-flex; align-items: center; justify-content: center; border: 1px solid #ddd; border-radius: 8px; white-space: nowrap; flex-shrink: 0; font-size: 14px; line-height: 1.5; outline: 0; color: #333; background: #fff; margin-right: 10px; padding: 0px 14px; position: relative; cursor: pointer; height: 36px;}
  561. .quark-button:hover { background:#f6f6f6 }
  562. .pl-dropdown-menu {position: absolute;right: 0;top: 30px;padding: 5px 0;color: rgb(37, 38, 43);background: #fff;z-index: 999;width: 102px;border: 1px solid #ddd;border-radius: 10px; box-shadow: 0 0 1px 1px rgb(28 28 32 / 5%), 0 8px 24px rgb(28 28 32 / 12%);}
  563. .pl-dropdown-menu-item { height: 30px;display: flex;align-items: center;justify-content: center;cursor:pointer }
  564. .pl-dropdown-menu-item:hover { background-color: rgba(132,133,141,0.08);}
  565. .pl-button .pl-dropdown-menu { display: none; }
  566. .pl-button:hover .pl-dropdown-menu { display: block!important; }
  567. .pl-button-init { opacity: 0.5; animation: easeInitOpacity 1.2s 3; animation-fill-mode:forwards }
  568. @keyframes easeInitOpacity { from { opacity: 0.5; } 50% { opacity: 1 } to { opacity: 0.5; } }
  569. @keyframes easeOpacity { from { opacity: 1; } 50% { opacity: 0.35 } to { opacity: 1; } }
  570. .element-clicked { opacity: 0.5; }
  571. .pl-extra { margin-top: 10px;display:flex}
  572. .pl-extra button { flex: 1}
  573. .pointer { cursor:pointer }
  574. .pl-setting-label { display: flex;align-items: center;justify-content: space-between;padding-top: 10px; }
  575. .pl-label { flex: 0 0 100px;text-align:left; }
  576. .pl-input { flex: 1; padding: 8px 10px; border: 1px solid #c2c2c2; border-radius: 5px; font-size: 14px }
  577. .pl-color { flex: 1;display: flex;flex-wrap: wrap; margin-right: -10px;}
  578. .pl-color-box { width: 35px;height: 35px;margin:10px 10px 0 0;; box-sizing: border-box;border:1px solid #fff;cursor:pointer }
  579. .pl-color-box.checked { border:3px dashed #111!important }
  580. .pl-close:focus { outline: 0; box-shadow: none; }
  581. .tag-danger {color:#cc3235;margin: 0 5px;}
  582. .pl-tooltip { position: absolute; color: #ffffff; max-width: 600px; font-size: 12px; padding: 5px 10px; background: #333; border-radius: 5px; z-index: 110000; line-height: 1.3; display:none; word-break: break-all;}
  583. @keyframes load { 0% { transform: rotate(0deg) } 100% { transform: rotate(360deg) } }
  584. .pl-loading-box > div > div { position: absolute;border-radius: 50%;}
  585. .pl-loading-box > div > div:nth-child(1) { top: 9px;left: 9px;width: 82px;height: 82px;background: #ffffff;}
  586. .pl-loading-box > div > div:nth-child(2) { top: 14px;left: 38px;width: 25px;height: 25px;background: #666666;animation: load 1s linear infinite;transform-origin: 12px 36px;}
  587. .pl-loading { width: 16px;height: 16px;display: inline-block;overflow: hidden;background: none;}
  588. .pl-loading-box { width: 100%;height: 100%;position: relative;transform: translateZ(0) scale(0.16);backface-visibility: hidden;transform-origin: 0 0;}
  589. .pl-loading-box div { box-sizing: content-box; }
  590. .swal2-container { z-index:100000!important; }
  591. body.swal2-height-auto { height: inherit!important; }
  592. .btn-operate .btn-main { display:flex; align-items:center; }
  593. `;
  594. this.addStyle('panlinker-style', 'style', css);
  595. },
  596.  
  597. async initDialog() {
  598. let result = await Swal.fire({
  599. title: pan.init[0],
  600. html: `<div><img style="width: 250px;margin-bottom: 10px;" src="${pan.img}" alt="${pan.img}"><input class="swal2-input" id="init" type="text" placeholder="${pan.init[1]}"></div>`,
  601. allowOutsideClick: false,
  602. showCloseButton: true,
  603. confirmButtonText: '确定'
  604. });
  605. if (result.isDismissed && result.dismiss === 'close') return;
  606. if (pan.num === $('#init').val() || pan.license === $('#init').val()) {
  607. base.setValue('setting_init_code', pan.num);
  608. base.setValue('license', pan.license);
  609. message.success(pan.init[2]);
  610. setTimeout(() => {
  611. history.go(0);
  612. }, 1500);
  613. } else {
  614. await Swal.fire({
  615. title: pan.init[3],
  616. text: pan.init[4],
  617. confirmButtonText: '重新输入',
  618. imageUrl: pan.img,
  619. });
  620. await this.initDialog();
  621. }
  622. },
  623. };
  624.  
  625. let baidu = {
  626.  
  627. _getExtra() {
  628. let seKey = decodeURIComponent(base.getCookie('BDCLND'));
  629. return '{' + '"sekey":"' + seKey + '"' + "}";
  630. },
  631.  
  632. _getSurl() {
  633. let reg = /(?<=s\/|surl=)([a-zA-Z0-9_-]+)/g;
  634. if (reg.test(location.href)) {
  635. return location.href.match(reg)[0];
  636. }
  637. return '';
  638. },
  639.  
  640. _getFidList() {
  641. let fidlist = [];
  642. selectList.forEach(v => {
  643. if (+v.isdir === 1) return;
  644. fidlist.push(v.fs_id);
  645. });
  646. return '[' + fidlist + ']';
  647. },
  648.  
  649. _resetData() {
  650. progress = {};
  651. $.each(request, (key) => {
  652. (request[key]).abort();
  653. });
  654. $.each(ins, (key) => {
  655. clearInterval(ins[key]);
  656. });
  657. idm = {};
  658. ins = {};
  659. request = {};
  660. },
  661.  
  662. setBDUSS() {
  663. try {
  664. GM_cookie && GM_cookie('list', {name: 'BDUSS'}, (cookies, error) => {
  665. if (!error) {
  666. let BDUSS = cookies?.[0]?.value;
  667. if (BDUSS) {
  668. base.setStorage("baiduyunPlugin_BDUSS", {BDUSS});
  669. }
  670. }
  671. });
  672. } catch (e) {
  673. }
  674. },
  675.  
  676. getBDUSS() {
  677. let baiduyunPlugin_BDUSS = base.getStorage('baiduyunPlugin_BDUSS') ? base.getStorage('baiduyunPlugin_BDUSS') : '{"baiduyunPlugin_BDUSS":""}';
  678. return baiduyunPlugin_BDUSS.BDUSS || '';
  679. },
  680.  
  681. convertLinkToAria(link, filename, ua) {
  682. let BDUSS = this.getBDUSS();
  683. if (!!BDUSS) {
  684. filename = base.fixFilename(filename);
  685. return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "User-Agent: ${ua}" --header "Cookie: BDUSS=${BDUSS}"`);
  686. }
  687. return {
  688. link: pan.assistant,
  689. text: pan.init[5]
  690. };
  691. },
  692.  
  693. convertLinkToBC(link, filename, ua) {
  694. let BDUSS = this.getBDUSS();
  695. if (!!BDUSS) {
  696. let cookie = `BDUSS=${BDUSS}`;
  697. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&cookie=${encodeURIComponent(cookie)}&user_agent=${encodeURIComponent(ua)}ZZ`;
  698. return encodeURIComponent(`bc://http/${base.e(bc)}`);
  699. }
  700. return {
  701. link: pan.assistant,
  702. text: pan.init[5]
  703. };
  704. },
  705.  
  706. convertLinkToCurl(link, filename, ua) {
  707. let BDUSS = this.getBDUSS();
  708. if (!!BDUSS) {
  709. let terminal = base.getValue('setting_terminal_type');
  710. filename = base.fixFilename(filename);
  711. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}" -A "${ua}" -b "BDUSS=${BDUSS}"`);
  712. }
  713. return {
  714. link: pan.assistant,
  715. text: pan.init[5]
  716. };
  717. },
  718.  
  719. addPageListener() {
  720. function _factory(e) {
  721. let target = $(e.target);
  722. let item = target.parents('.pl-item');
  723. let link = item.find('.pl-item-link');
  724. let progress = item.find('.pl-item-progress');
  725. let tip = item.find('.pl-item-tip');
  726. return {
  727. item, link, progress, tip, target,
  728. };
  729. }
  730.  
  731. function _reset(i) {
  732. ins[i] && clearInterval(ins[i]);
  733. request[i] && request[i].abort();
  734. progress[i] = 0;
  735. idm[i] = false;
  736. }
  737.  
  738. doc.on('mouseenter mouseleave click', '.pl-button.g-dropdown-button', (e) => {
  739. if (e.type === 'mouseleave') {
  740. $(e.currentTarget).removeClass('button-open');
  741. } else {
  742. $(e.currentTarget).addClass('button-open');
  743. $(e.currentTarget).find('.pl-dropdown-menu').show();
  744. }
  745. });
  746. doc.on('mouseleave', '.pl-button.g-dropdown-button .pl-dropdown-menu', (e) => {
  747. $(e.currentTarget).hide();
  748. });
  749.  
  750. doc.on('click', '.pl-button-mode', (e) => {
  751. mode = e.target.dataset.mode;
  752. Swal.showLoading();
  753. this.getPCSLink();
  754. });
  755. doc.on('click', '.listener-link-api', async (e) => {
  756. e.preventDefault();
  757. let o = _factory(e);
  758. let $width = o.item.find('.pl-progress-inner');
  759. let $text = o.item.find('.pl-progress-inner-text');
  760. let filename = o.link[0].dataset.filename;
  761. let index = o.link[0].dataset.index;
  762. _reset(index);
  763. base.get(o.link[0].dataset.link, {"User-Agent": pan.ua}, 'blob', {filename, index});
  764. ins[index] = setInterval(() => {
  765. let prog = +progress[index] || 0;
  766. let isIDM = idm[index] || false;
  767. if (isIDM) {
  768. o.tip.hide();
  769. o.progress.hide();
  770. o.link.text('已成功唤起IDM,请查看IDM下载框!').animate({opacity: '0.5'}, "slow").show();
  771. clearInterval(ins[index]);
  772. idm[index] = false;
  773. } else {
  774. o.link.hide();
  775. o.tip.hide();
  776. o.progress.show();
  777. $width.css('width', prog + '%');
  778. $text.text(prog + '%');
  779. if (prog === 100) {
  780. clearInterval(ins[index]);
  781. progress[index] = 0;
  782. o.item.find('.pl-progress-stop').hide();
  783. o.item.find('.pl-progress-tip').html('下载完成,正在弹出浏览器下载框!');
  784. }
  785. }
  786. }, 500);
  787. });
  788. doc.on('click', '.listener-retry', async (e) => {
  789. let o = _factory(e);
  790. o.tip.hide();
  791. o.link.show();
  792. });
  793. doc.on('click', '.listener-how', async (e) => {
  794. let o = _factory(e);
  795. let index = o.link[0].dataset.index;
  796. if (request[index]) {
  797. request[index].abort();
  798. clearInterval(ins[index]);
  799. o.progress.hide();
  800. o.tip.show();
  801. }
  802.  
  803. });
  804. doc.on('click', '.listener-stop', async (e) => {
  805. let o = _factory(e);
  806. let index = o.link[0].dataset.index;
  807. if (request[index]) {
  808. request[index].abort();
  809. clearInterval(ins[index]);
  810. o.tip.hide();
  811. o.progress.hide();
  812. o.link.show(0);
  813. }
  814. });
  815. doc.on('click', '.listener-back', async (e) => {
  816. let o = _factory(e);
  817. o.tip.hide();
  818. o.link.show();
  819. });
  820. doc.on('click', '.listener-link-aria, .listener-copy-all', (e) => {
  821. e.preventDefault();
  822. if (!e.target.dataset.link) {
  823. $(e.target).removeClass('listener-copy-all').addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  824. } else {
  825. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  826. $(e.target).text('复制成功,快去粘贴吧!').animate({opacity: '0.5'}, "slow");
  827. }
  828. });
  829. doc.on('click', '.listener-link-rpc', async (e) => {
  830. let target = $(e.currentTarget);
  831. target.find('.icon').remove();
  832. target.find('.pl-loading').remove();
  833. target.prepend(base.createLoading());
  834. let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  835. if (res === 'success') {
  836. $('.listener-rpc-task').show();
  837. target.removeClass('pl-btn-danger').html('发送成功,快去看看吧!').animate({opacity: '0.5'}, "slow");
  838. } else if (res === 'assistant') {
  839. target.addClass('pl-btn-danger').html(`${pan.init[5]}👉<a href="${pan.assistant}" target="_blank" class="pl-a">点击此处安装</a>👈`);
  840. } else {
  841. target.addClass('pl-btn-danger').text('发送失败,请检查您的RPC配置信息!').animate({opacity: '0.5'}, "slow");
  842. }
  843. });
  844. doc.on('click', '.listener-send-rpc', (e) => {
  845. $('.listener-link-rpc').click();
  846. $(e.target).text('发送完成,发送结果见上方按钮!').animate({opacity: '0.5'}, "slow");
  847. });
  848. doc.on('click', '.listener-open-setting', () => {
  849. base.showSetting();
  850. });
  851. doc.on('click', '.listener-rpc-task', () => {
  852. let rpc = JSON.stringify({
  853. domain: base.getValue('setting_rpc_domain'),
  854. port: base.getValue('setting_rpc_port'),
  855. }), url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue('setting_rpc_token')}`;
  856. GM_openInTab(url, {active: true});
  857. });
  858. document.documentElement.addEventListener('mouseup', (e) => {
  859. if (e.target.nodeName === 'A' && ~e.target.className.indexOf('pl-a')) {
  860. e.stopPropagation();
  861. }
  862. }, true);
  863. },
  864.  
  865. addButton() {
  866. if (!pt) return;
  867. let $toolWrap;
  868. let $button = $(`<div class="g-dropdown-button pointer pl-button"><div style="color:#fff;background: ${color};border-color:${color}" class="g-button g-button-blue"><span class="g-button-right"><em class="icon icon-download"></em><span class="text" style="width: 60px;">下载助手</span></span></div><div class="menu" style="width:auto;z-index:41;border-color:${color}"><div style="color:${color}" class="g-button-menu pl-button-mode" data-mode="api">API下载</div><div style="color:${color}" class="g-button-menu pl-button-mode" data-mode="aria">Aria下载</div><div style="color:${color}" class="g-button-menu pl-button-mode" data-mode="rpc">RPC下载</div><div style="color:${color}" class="g-button-menu pl-button-mode" data-mode="curl">cURL下载</div><div style="color:${color}" class="g-button-menu pl-button-mode" data-mode="bc">BC下载</div><li class="g-button-menu pl-button-mode listener-open-setting">助手设置</li>${pan.code == 200 && version < pan.version ? pan.new : ''}</div></div>`);
  869. if (pt === 'home') $toolWrap = $(pan.btn.home);
  870. if (pt === 'main') {
  871. $toolWrap = $(pan.btn.main);
  872. $button = $(`<div class="pl-button" style="position: relative; display: inline-block; margin-right: 8px;"><button class="u-button u-button--primary u-button--small is-round is-has-icon" style="background: ${color};border-color: ${color};font-size: 14px; padding: 8px 16px; border: none;"><i class="u-icon u-icon-download"></i><span>下载助手</span></button><ul class="dropdown-list nd-common-float-menu pl-dropdown-menu"><li class="sub cursor-p pl-button-mode" data-mode="api">API下载</li><li class="sub cursor-p pl-button-mode" data-mode="aria">Aria下载</li><li class="sub cursor-p pl-button-mode" data-mode="rpc">RPC下载</li><li class="sub cursor-p pl-button-mode" data-mode="curl">cURL下载</li><li class="sub cursor-p pl-button-mode" data-mode="bc" >BC下载</li><li class="sub cursor-p pl-button-mode listener-open-setting">助手设置</li>${pan.code == 200 && version < pan.version ? pan.newX : ''}</ul></div>`);
  873. }
  874. if (pt === 'share') $toolWrap = $(pan.btn.share);
  875. $toolWrap.prepend($button);
  876. this.setBDUSS();
  877. this.addPageListener();
  878. },
  879.  
  880. addInitButton() {
  881. if (!pt) return;
  882. let $toolWrap;
  883. let $button = $(`<div class="g-dropdown-button pointer pl-button-init" style="opacity:.5"><div style="color:#fff;background: ${color};border-color:${color}" class="g-button g-button-blue"><span class="g-button-right"><em class="icon icon-download"></em><span class="text" style="width: 60px;">下载助手</span></span></div></div>`);
  884. if (pt === 'home') $toolWrap = $(pan.btn.home);
  885. if (pt === 'main') {
  886. $toolWrap = $(pan.btn.main);
  887. $button = $(`<div class="pl-button-init" style="opacity:.5; display: inline-block; margin-right: 8px;"><button class="u-button u-button--primary u-button--small is-round is-has-icon" style="background: ${color};border-color: ${color};font-size: 14px; padding: 8px 16px; border: none;"><i class="u-icon u-icon-download"></i><span>下载助手</span></button></div>`);
  888. }
  889. if (pt === 'share') $toolWrap = $(pan.btn.share);
  890. $toolWrap.prepend($button);
  891. $button.click(() => base.initDialog());
  892. },
  893.  
  894. async getToken() {
  895. const openTab = () => {
  896. GM_openInTab(pan.pcs[3], {active: false, insert: true, setParent: true});
  897. base.deleteValue('baidu_access_token');
  898. };
  899.  
  900. const waitForToken = () => new Promise((resolve) => {
  901. let attempts = 0;
  902. const interval = setInterval(() => {
  903. const token = base.getValue('baidu_access_token');
  904. if (token) {
  905. clearInterval(interval);
  906. resolve(token);
  907. }
  908. attempts++;
  909. if (attempts > 60) {
  910. clearInterval(interval);
  911. resolve('');
  912. }
  913. }, 1000);
  914. });
  915.  
  916. if (manageHandler === 'Tampermonkey' && base.getMajorVersion(manageVersion) >= 5) {
  917. openTab();
  918. return waitForToken();
  919. }
  920. let res = await base.getFinalUrl(pan.pcs[3]);
  921.  
  922. if (!res.includes('authorize') && !res.includes('access_token=')) {
  923. openTab();
  924. return waitForToken();
  925. }
  926. if (res.includes('authorize')) {
  927. let html = await base.get(pan.pcs[3], {}, 'text');
  928. let bdstoken = html.match(/name="bdstoken"\s+value="([^"]+)"/)?.[1];
  929. let client_id = html.match(/name="client_id"\s+value="([^"]+)"/)?.[1];
  930. let data = {
  931. grant_permissions_arr: 'netdisk',
  932. bdstoken: bdstoken,
  933. client_id: client_id,
  934. response_type: "token",
  935. display: "page",
  936. grant_permissions: "basic,netdisk"
  937. };
  938. await base.post(pan.pcs[3], base.stringify(data), {
  939. 'Content-Type': 'application/x-www-form-urlencoded',
  940. });
  941. let res2 = await base.getFinalUrl(pan.pcs[3]);
  942. let accessToken = res2.match(/access_token=([^&]+)/)?.[1];
  943. accessToken && base.setValue('baidu_access_token', accessToken);
  944. return accessToken;
  945. }
  946. let accessToken = res.match(/access_token=([^&]+)/)?.[1];
  947. accessToken && base.setValue('baidu_access_token', accessToken);
  948. return accessToken;
  949. },
  950.  
  951. async getPCSLink(maxRequestTime = 1) {
  952. selectList = this.getSelectedList();
  953. let fidList = this._getFidList(), url, res;
  954.  
  955. if (pt === 'home' || pt === 'main') {
  956. if (selectList.length === 0) {
  957. return message.error('提示:请先勾选要下载的文件!');
  958. }
  959. if (fidList.length === 2) {
  960. return message.error('提示:请打开文件夹后勾选文件!');
  961. }
  962. fidList = encodeURIComponent(fidList);
  963. let accessToken = base.getValue('baidu_access_token') || await this.getToken();
  964. url = `${pan.pcs[0]}&fsids=${fidList}&access_token=${accessToken}`;
  965. res = await base.get(url, {"User-Agent": pan.ua});
  966. }
  967. if (pt === 'share') {
  968. this.getShareData();
  969. if (!params.bdstoken) {
  970. return message.error('提示:请先登录网盘!');
  971. }
  972. if (selectList.length === 0) {
  973. return message.error('提示:请先勾选要下载的文件!');
  974. }
  975. if (fidList.length === 2) {
  976. return message.error('提示:请打开文件夹后勾选文件!');
  977. }
  978. let dialog = await Swal.fire({
  979. toast: true,
  980. icon: 'info',
  981. title: `提示:请将文件<span class="tag-danger">[保存到网盘]</span>👉前往<span class="tag-danger">[我的网盘]</span>中下载!`,
  982. showConfirmButton: true,
  983. confirmButtonText: '点击保存',
  984. position: 'top',
  985. });
  986. if (dialog.isConfirmed) {
  987. $('.tools-share-save-hb')[0].click();
  988. }
  989. return;
  990. }
  991. if (res.errno === 0) {
  992. let html = this.generateDom(res.list);
  993. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  994. } else if (res.errno === 112) {
  995. return message.error('提示:页面过期,请刷新重试!');
  996. } else if (res.errno === 9019) {
  997. maxRequestTime--;
  998. await this.getToken();
  999. if (maxRequestTime > 0) {
  1000. await this.getPCSLink(maxRequestTime);
  1001. } else {
  1002. message.error('提示:获取下载链接失败!请刷新网页后重试!');
  1003. }
  1004. } else {
  1005. base.deleteValue('baidu_access_token');
  1006. message.error('提示:获取下载链接失败!请刷新网页后重试!');
  1007. }
  1008. },
  1009.  
  1010. generateDom(list) {
  1011. let content = '<div class="pl-main">';
  1012. let alinkAllText = '';
  1013. base.sortByName(list);
  1014. list.forEach((v, i) => {
  1015. if (v.isdir === 1) return;
  1016. let filename = v.server_filename || v.filename;
  1017. let ext = base.getExtension(filename);
  1018. let size = base.sizeFormat(v.size);
  1019. let dlink = v.dlink + '&access_token=' + base.getValue('baidu_access_token');
  1020. if (mode === 'api') {
  1021. content += `<div class="pl-item">
  1022. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1023. <a class="pl-item-link pl-a listener-link-api" href="${dlink}" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
  1024. <div class="pl-item-tip" style="display: none"><span>若没有弹出IDM下载框,找到IDM <b>选项</b> -> <b>文件类型</b> -> <b>第一个框</b> 中添加后缀 <span class="pl-ext">${ext}</span>,<a href="${pan.idm}" target="_blank" class="pl-a">详见此处</a></span> <span class="pl-back listener-back">返回</span></div>
  1025. <div class="pl-item-progress" style="display: none">
  1026. <div class="pl-progress">
  1027. <div class="pl-progress-outer"></div>
  1028. <div class="pl-progress-inner" style="width:5%">
  1029. <div class="pl-progress-inner-text">0%</div>
  1030. </div>
  1031. </div>
  1032. <span class="pl-progress-stop listener-stop">取消下载</span>
  1033. <span class="pl-progress-tip">未发现IDM,使用自带浏览器下载</span>
  1034. <span class="pl-progress-how listener-how">如何唤起IDM?</span>
  1035. </div></div>`;
  1036. }
  1037. if (mode === 'aria') {
  1038. let alink = this.convertLinkToAria(dlink, filename, pan.ua);
  1039. if (typeof (alink) === 'object') {
  1040. content += `<div class="pl-item">
  1041. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1042. <a class="pl-item-link pl-a" target="_blank" href="${alink.link}" data-filename="${filename}" data-link="${alink.link}">${decodeURIComponent(alink.text)}</a> </div>`;
  1043. } else {
  1044. alinkAllText += alink + '\r\n';
  1045. content += `<div class="pl-item">
  1046. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1047. <a class="pl-item-link pl-a listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  1048. }
  1049. }
  1050. if (mode === 'rpc') {
  1051. content += `<div class="pl-item">
  1052. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1053. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
  1054. }
  1055. if (mode === 'curl') {
  1056. let alink = this.convertLinkToCurl(dlink, filename, pan.ua);
  1057. if (typeof (alink) === 'object') {
  1058. content += `<div class="pl-item">
  1059. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1060. <a class="pl-item-link pl-a" target="_blank" href="${alink.link}" data-filename="${filename}" data-link="${alink.link}">${decodeURIComponent(alink.text)}</a> </div>`;
  1061. } else {
  1062. alinkAllText += alink + '\r\n';
  1063. content += `<div class="pl-item">
  1064. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1065. <a class="pl-item-link pl-a listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  1066. }
  1067. }
  1068. if (mode === 'bc') {
  1069. let alink = this.convertLinkToBC(dlink, filename, pan.ua);
  1070. if (typeof (alink) === 'object') {
  1071. content += `<div class="pl-item">
  1072. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1073. <a class="pl-item-link pl-a" target="_blank" href="${alink.link}" data-filename="${filename}" data-link="${alink.link}">${decodeURIComponent(alink.text)}</a> </div>`;
  1074. } else {
  1075. content += `<div class="pl-item">
  1076. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1077. <a class="pl-item-link pl-a" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  1078. }
  1079.  
  1080. }
  1081. });
  1082. content += '</div>';
  1083. if (mode === 'aria')
  1084. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  1085. if (mode === 'rpc') {
  1086. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  1087. 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 listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  1088. }
  1089. if (mode === 'curl')
  1090. 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>`;
  1091. return content;
  1092. },
  1093.  
  1094. async sendLinkToRPC(filename, link) {
  1095. let rpc = {
  1096. domain: base.getValue('setting_rpc_domain'),
  1097. port: base.getValue('setting_rpc_port'),
  1098. path: base.getValue('setting_rpc_path'),
  1099. token: base.getValue('setting_rpc_token'),
  1100. dir: base.getValue('setting_rpc_dir'),
  1101. };
  1102. let BDUSS = this.getBDUSS();
  1103. if (!BDUSS) return 'assistant';
  1104.  
  1105. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  1106. let rpcData = {
  1107. id: new Date().getTime(),
  1108. jsonrpc: '2.0',
  1109. method: 'aria2.addUri',
  1110. params: [`token:${rpc.token}`, [link], {
  1111. dir: rpc.dir,
  1112. out: filename,
  1113. header: [`User-Agent: ${pan.ua}`, `Cookie: BDUSS=${BDUSS}`]
  1114. }]
  1115. };
  1116. try {
  1117. let res = await base.post(url, rpcData, {"User-Agent": pan.ua}, '');
  1118. if (res.result) return 'success';
  1119. return 'fail';
  1120. } catch (e) {
  1121. return 'fail';
  1122. }
  1123. },
  1124.  
  1125. getSelectedList() {
  1126. try {
  1127. return require('system-core:context/context.js').instanceForSystem.list.getSelected();
  1128. } catch (e) {
  1129. return document.querySelector('.wp-s-core-pan').__vue__.selectedList;
  1130. }
  1131. },
  1132.  
  1133. getLogid() {
  1134. let ut = require("system-core:context/context.js").instanceForSystem.tools.baseService;
  1135. return ut.base64Encode(base.getCookie("BAIDUID"));
  1136. },
  1137.  
  1138. getShareData() {
  1139. let res = locals.dump();
  1140. params.shareType = 'secret';
  1141. params.sign = '';
  1142. params.timestamp = '';
  1143. params.bdstoken = res.bdstoken.value;
  1144. params.channel = 'chunlei';
  1145. params.clienttype = 0;
  1146. params.web = 1;
  1147. params.app_id = 250528;
  1148. params.encrypt = 0;
  1149. params.product = 'share';
  1150. params.logid = this.getLogid();
  1151. params.primaryid = res.shareid.value;
  1152. params.uk = res.share_uk.value;
  1153. params.shareType === 'secret' && (params.extra = this._getExtra());
  1154. params.surl = this._getSurl();
  1155. },
  1156.  
  1157. detectPage() {
  1158. let path = location.pathname;
  1159. if (/^\/disk\/home/.test(path)) return 'home';
  1160. if (/^\/disk\/main/.test(path)) return 'main';
  1161. if (/^\/(s|share)\//.test(path)) return 'share';
  1162. return '';
  1163. return '';
  1164. },
  1165.  
  1166. showMainDialog(title, html, footer) {
  1167. Swal.fire({
  1168. title,
  1169. html,
  1170. footer,
  1171. allowOutsideClick: false,
  1172. showCloseButton: true,
  1173. showConfirmButton: false,
  1174. position: 'top',
  1175. width,
  1176. padding: '15px 20px 5px',
  1177. customClass,
  1178. }).then(() => {
  1179. this._resetData();
  1180. });
  1181. },
  1182.  
  1183. async initPanLinker() {
  1184. base.initDefaultConfig();
  1185. base.addPanLinkerStyle();
  1186. pt = this.detectPage();
  1187. let res = await base.post
  1188. (`https://api.youxiaohou.com/config/v2?ver=${version}&a=${author}`, {}, {}, 'text');
  1189. pan = JSON.parse(base.d(res));
  1190. Object.freeze && Object.freeze(pan);
  1191. pan.num === base.getValue('setting_init_code') ||
  1192. pan.license === base.getValue('license') ? this.addButton() : this.addInitButton();
  1193. base.createTip();
  1194. base.registerMenuCommand();
  1195. },
  1196.  
  1197. async initAuthorize() {
  1198. let ins = setInterval(() => {
  1199. if (/openapi.baidu.com\/oauth\/2.0\/authorize/.test(location.href)) {
  1200. let confirmButton = document.querySelector('#auth-allow');
  1201. if (confirmButton) {
  1202. confirmButton.click();
  1203. return;
  1204. }
  1205. }
  1206. if (/openapi.baidu.com\/oauth\/2.0\/login_success/.test(location.href)) {
  1207. if (location.href.includes('access_token')) {
  1208. let token = location.href.match(/access_token=(.*?)&/)[1];
  1209. base.setValue('baidu_access_token', token);
  1210. window.close()
  1211. }
  1212. }
  1213. }, 200)
  1214. }
  1215. };
  1216.  
  1217. let ali = {
  1218.  
  1219. convertLinkToAria(link, filename, ua) {
  1220. filename = base.fixFilename(filename);
  1221. return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "Referer: https://www.aliyundrive.com/"`);
  1222. },
  1223.  
  1224. convertLinkToBC(link, filename, ua) {
  1225. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&refer=${encodeURIComponent('https://www.aliyundrive.com/')}ZZ`;
  1226. return encodeURIComponent(`bc://http/${base.e(bc)}`);
  1227. },
  1228.  
  1229. convertLinkToCurl(link, filename, ua) {
  1230. let terminal = base.getValue('setting_terminal_type');
  1231. filename = base.fixFilename(filename);
  1232. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}" -e "https://www.aliyundrive.com/"`);
  1233. },
  1234.  
  1235. addPageListener() {
  1236. doc.on('click', '.pl-button-mode', (e) => {
  1237. mode = e.target.dataset.mode;
  1238. Swal.showLoading();
  1239. this.getPCSLink();
  1240. });
  1241. doc.on('click', '.listener-link-api', async (e) => {
  1242. e.preventDefault();
  1243. let dataset = e.currentTarget.dataset;
  1244. let href = dataset.link;
  1245. // let url = await this.getRealLink(dataset.did, dataset.fid);
  1246. // if (url) href = url;
  1247. $('#downloadIframe').attr('src', href);
  1248. // let d = document.createElement("a");
  1249. // d.download = e.currentTarget.dataset.filename;
  1250. // d.rel = "noopener";
  1251. // d.href = href;
  1252. // d.dispatchEvent(new MouseEvent("click"));
  1253. });
  1254. doc.on('click', '.listener-link-api-btn', async (e) => {
  1255. base.setClipboard(e.target.dataset.filename);
  1256. $(e.target).text('复制成功').animate({opacity: '0.5'}, "slow");
  1257. });
  1258. doc.on('click', '.listener-link-aria, .listener-copy-all', (e) => {
  1259. e.preventDefault();
  1260. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  1261. $(e.target).text('复制成功,快去粘贴吧!').animate({opacity: '0.5'}, "slow");
  1262. });
  1263. doc.on('click', '.listener-link-rpc', async (e) => {
  1264. let target = $(e.currentTarget);
  1265. target.find('.icon').remove();
  1266. target.find('.pl-loading').remove();
  1267. target.prepend(base.createLoading());
  1268. let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  1269. if (res === 'success') {
  1270. $('.listener-rpc-task').show();
  1271. target.removeClass('pl-btn-danger').html('发送成功,快去看看吧!').animate({opacity: '0.5'}, "slow");
  1272. } else {
  1273. target.addClass('pl-btn-danger').text('发送失败,请检查您的RPC配置信息!').animate({opacity: '0.5'}, "slow");
  1274. }
  1275. });
  1276. doc.on('click', '.listener-send-rpc', (e) => {
  1277. $('.listener-link-rpc').click();
  1278. $(e.target).text('发送完成,发送结果见上方按钮!').animate({opacity: '0.5'}, "slow");
  1279. });
  1280. doc.on('click', '.listener-open-setting', () => {
  1281. base.showSetting();
  1282. });
  1283. doc.on('click', '.listener-rpc-task', () => {
  1284. let rpc = JSON.stringify({
  1285. domain: base.getValue('setting_rpc_domain'),
  1286. port: base.getValue('setting_rpc_port'),
  1287. }), url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue('setting_rpc_token')}`;
  1288. GM_openInTab(url, {active: true});
  1289. });
  1290. },
  1291.  
  1292. async getRealLink(d, f) {
  1293. let authorization = `${base.getStorage('token').token_type} ${base.getStorage('token').access_token}`;
  1294. let res = await base.post(pan.pcs[1], {
  1295. drive_id: d,
  1296. file_id: f
  1297. }, {
  1298. authorization,
  1299. "content-type": "application/json;charset=utf-8",
  1300. "referer": "https://www.aliyundrive.com/",
  1301. "x-canary": "client=windows,app=adrive,version=v6.0.0"
  1302. });
  1303. if (res.code === 'AccessTokenInvalid') {
  1304. return message.error('提示:Token过期,请刷新网页后重试!');
  1305. }
  1306. if (res.url) {
  1307. return res.url;
  1308. }
  1309. return '';
  1310. },
  1311.  
  1312. addButton() {
  1313. if (!pt) return;
  1314. let $toolWrap;
  1315. let $button = $(`<div class="ali-button pl-button"><svg 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="#fff"/><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="#FF9C00"/></svg><span>下载助手</span><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>${pan.code == 200 && version < pan.version ? pan.new : ''}</ul></div>`);
  1316. if (pt === 'home') {
  1317. base.listenElement(pan.btn.home, () => {
  1318. $toolWrap = $(pan.btn.home);
  1319. $('.pl-button').length === 0 && $toolWrap.append($button);
  1320. })
  1321. }
  1322. if (pt === 'share') {
  1323. $button.css({'margin-right': '10px'});
  1324. base.listenElement(pan.btn.share, () => {
  1325. $toolWrap = $(pan.btn.share);
  1326. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  1327. })
  1328. }
  1329. base.createDownloadIframe();
  1330. this.addPageListener();
  1331. },
  1332.  
  1333. addInitButton() {
  1334. if (!pt) return;
  1335. let $toolWrap;
  1336. let $button = $(`<div class="ali-button pl-button-init"><svg 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="#fff"/><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="#FF9C00"/></svg><span>下载助手</span></div>`);
  1337. if (pt === 'home') {
  1338. base.listenElement(pan.btn.home, () => {
  1339. $toolWrap = $(pan.btn.home);
  1340. $('.pl-button-init').length === 0 && $toolWrap.append($button);
  1341. })
  1342. }
  1343. if (pt === 'share') {
  1344. $button.css({'margin-right': '10px'});
  1345. base.listenElement(pan.btn.share, () => {
  1346. $toolWrap = $(pan.btn.share);
  1347. $('.pl-butto-init').length === 0 && $toolWrap.prepend($button);
  1348. })
  1349. }
  1350. $button.click(() => base.initDialog());
  1351. },
  1352.  
  1353. async getPCSLink() {
  1354. let reactDomGrid = document.querySelector(pan.dom.grid);
  1355. if (reactDomGrid) {
  1356. let res = await Swal.fire({
  1357. title: '提示',
  1358. html: '<div style="display: flex;align-items: center;justify-content: center;">请先切换到 <b>列表视图</b>(<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M132 928c-32.8 0-59.2-26.4-59.2-59.2s26.4-59.2 59.2-59.2h760c32.8 0 59.2 26.4 59.2 59.2S924.8 928 892 928H132zm0-356.8c-32.8 0-59.2-26.4-59.2-59.2s26.4-59.2 59.2-59.2h760c32.8 0 59.2 26.4 59.2 59.2s-26.4 59.2-59.2 59.2H132zm0-356c-32.8 0-59.2-26.4-59.2-59.2S99.2 96.8 132 96.8h760c32.8 0 59.2 26.4 59.2 59.2s-26.4 59.2-59.2 59.2H132z"/></svg>)后获取!</div>',
  1359. confirmButtonText: '点击切换'
  1360. });
  1361. if (res) {
  1362. document.querySelector(pan.dom.switch).click();
  1363. return message.success('切换成功,请重新获取下载链接!');
  1364. }
  1365. return false;
  1366. }
  1367. selectList = this.getSelectedList();
  1368. if (selectList.length === 0) {
  1369. return message.error('提示:请先勾选要下载的文件!');
  1370. }
  1371. if (this.isOnlyFolder()) {
  1372. return message.error('提示:请打开文件夹后勾选文件!');
  1373. }
  1374. if (pt === 'share') {
  1375. if (selectList.length > 20) {
  1376. return message.error('提示:单次最多可勾选 20 个文件!');
  1377. }
  1378. try {
  1379. let authorization = `${base.getStorage('token').token_type} ${base.getStorage('token').access_token}`;
  1380. let xShareToken = base.getStorage('shareToken').share_token;
  1381.  
  1382. for (let i = 0; i < selectList.length; i++) {
  1383. let res = await base.post(pan.pcs[0], {
  1384. expire_sec: 600,
  1385. file_id: selectList[i].fileId,
  1386. share_id: selectList[i].shareId
  1387. }, {
  1388. authorization,
  1389. "content-type": "application/json;charset=utf-8",
  1390. "x-share-token": xShareToken
  1391. });
  1392. if (res.download_url) {
  1393. selectList[i].downloadUrl = res.download_url;
  1394. }
  1395. }
  1396. } catch (e) {
  1397. return message.error('提示:请先登录网盘!');
  1398. }
  1399. } else {
  1400. if (selectList.length > 20) {
  1401. return message.error('提示:单次最多可勾选 20 个文件!');
  1402. }
  1403. let noUrlSelectList = selectList.filter(v => !Boolean(v.url))
  1404. let queue = [];
  1405. noUrlSelectList.forEach((item, index) => {
  1406. queue.push(this.getRealLink(item.driveId, item.fileId));
  1407. });
  1408.  
  1409. const res = await Promise.all(queue);
  1410. res.forEach((val, index) => {
  1411. noUrlSelectList[index].url = val;
  1412. });
  1413.  
  1414. }
  1415. let html = this.generateDom(selectList);
  1416. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  1417. },
  1418.  
  1419. generateDom(list) {
  1420. let content = '<div class="pl-main">';
  1421. let alinkAllText = '';
  1422. list.forEach((v, i) => {
  1423. if (v.type === 'folder') return;
  1424. let filename = v.name;
  1425. let fid = v.fileId;
  1426. let did = v.driveId;
  1427. let size = base.sizeFormat(v.size);
  1428. let dlink = v.downloadUrl || v.url;
  1429. if (mode === 'api') {
  1430. content += `<div class="pl-item">
  1431. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1432. <a class="pl-item-link listener-link-api" data-did="${did}" data-fid="${fid}" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
  1433. <div class="pl-item-btn listener-link-api-btn" data-filename="${filename}">复制文件名</div>
  1434. </div>`;
  1435. }
  1436. if (mode === 'aria') {
  1437. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  1438. alinkAllText += alink + '\r\n';
  1439. content += `<div class="pl-item">
  1440. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1441. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  1442. }
  1443. if (mode === 'rpc') {
  1444. content += `<div class="pl-item">
  1445. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1446. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
  1447. }
  1448. if (mode === 'curl') {
  1449. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  1450. alinkAllText += alink + '\r\n';
  1451. content += `<div class="pl-item">
  1452. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1453. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  1454. }
  1455. if (mode === 'bc') {
  1456. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  1457. content += `<div class="pl-item">
  1458. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1459. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  1460. }
  1461. });
  1462. content += '</div>';
  1463. if (mode === 'aria')
  1464. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  1465. if (mode === 'rpc') {
  1466. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  1467. 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 listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  1468. }
  1469. if (mode === 'curl')
  1470. 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>`;
  1471. return content;
  1472. },
  1473.  
  1474. async sendLinkToRPC(filename, link) {
  1475. let rpc = {
  1476. domain: base.getValue('setting_rpc_domain'),
  1477. port: base.getValue('setting_rpc_port'),
  1478. path: base.getValue('setting_rpc_path'),
  1479. token: base.getValue('setting_rpc_token'),
  1480. dir: base.getValue('setting_rpc_dir'),
  1481. };
  1482.  
  1483. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  1484. let rpcData = {
  1485. id: new Date().getTime(),
  1486. jsonrpc: '2.0',
  1487. method: 'aria2.addUri',
  1488. params: [`token:${rpc.token}`, [link], {
  1489. dir: rpc.dir,
  1490. out: filename,
  1491. header: [`Referer: https://www.aliyundrive.com/`]
  1492. }]
  1493. };
  1494. try {
  1495. let res = await base.post(url, rpcData, {"Referer": "https://www.aliyundrive.com/"}, '');
  1496. if (res.result) return 'success';
  1497. return 'fail';
  1498. } catch (e) {
  1499. return 'fail';
  1500. }
  1501. },
  1502.  
  1503. getSelectedList() {
  1504. try {
  1505. let selectedList = [];
  1506. let reactDom = document.querySelector(pan.dom.list);
  1507. let reactObj = base.findReact(reactDom, 1);
  1508. let props = reactObj.pendingProps;
  1509. if (props) {
  1510. let fileList = props.dataSource || [];
  1511. let selectedKeys = props.selectedKeys.split(',');
  1512. fileList.forEach((val) => {
  1513. if (selectedKeys.includes(val.fileId)) {
  1514. selectedList.push(val);
  1515. }
  1516. });
  1517. }
  1518. return selectedList;
  1519. } catch (e) {
  1520. return [];
  1521. }
  1522. },
  1523.  
  1524. detectPage() {
  1525. let path = location.pathname;
  1526. if (/^\/(drive)/.test(path)) return 'home';
  1527. if (/^\/(s|share)\//.test(path)) return 'share';
  1528. return '';
  1529. },
  1530.  
  1531. isOnlyFolder() {
  1532. for (let i = 0; i < selectList.length; i++) {
  1533. if (selectList[i].type === 'file') return false;
  1534. }
  1535. return true;
  1536. },
  1537.  
  1538. showMainDialog(title, html, footer) {
  1539. Swal.fire({
  1540. title,
  1541. html,
  1542. footer,
  1543. allowOutsideClick: false,
  1544. showCloseButton: true,
  1545. showConfirmButton: false,
  1546. position: 'top',
  1547. width,
  1548. padding: '15px 20px 5px',
  1549. customClass,
  1550. });
  1551. },
  1552.  
  1553. async initPanLinker() {
  1554. base.initDefaultConfig();
  1555. base.addPanLinkerStyle();
  1556. pt = this.detectPage();
  1557. let res = await base.post
  1558. (`https://api.youxiaohou.com/config/v2/ali?ver=${version}&a=${author}`, {}, {}, 'text');
  1559. pan = JSON.parse(base.d(res));
  1560. Object.freeze && Object.freeze(pan);
  1561. pan.num === base.getValue('setting_init_code') ||
  1562. pan.license === base.getValue('license') ? this.addButton() : this.addInitButton();
  1563. base.createTip();
  1564. base.registerMenuCommand();
  1565. }
  1566. };
  1567.  
  1568. let tianyi = {
  1569.  
  1570. convertLinkToAria(link, filename, ua) {
  1571. filename = base.fixFilename(filename);
  1572. return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
  1573. },
  1574.  
  1575. convertLinkToBC(link, filename, ua) {
  1576. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
  1577. return encodeURIComponent(`bc://http/${base.e(bc)}`);
  1578. },
  1579.  
  1580. convertLinkToCurl(link, filename, ua) {
  1581. let terminal = base.getValue('setting_terminal_type');
  1582. filename = base.fixFilename(filename);
  1583. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}"`);
  1584. },
  1585.  
  1586. addPageListener() {
  1587. doc.on('click', '.pl-button-mode', (e) => {
  1588. mode = e.target.dataset.mode;
  1589. Swal.showLoading();
  1590. this.getPCSLink();
  1591. });
  1592. doc.on('click', '.listener-link-api', async (e) => {
  1593. e.preventDefault();
  1594. $('#downloadIframe').attr('src', e.currentTarget.dataset.link);
  1595. });
  1596. doc.on('click', '.listener-link-aria, .listener-copy-all', (e) => {
  1597. e.preventDefault();
  1598. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  1599. $(e.target).text('复制成功,快去粘贴吧!').animate({opacity: '0.5'}, "slow");
  1600. });
  1601. doc.on('click', '.listener-link-rpc', async (e) => {
  1602. let target = $(e.currentTarget);
  1603. target.find('.icon').remove();
  1604. target.find('.pl-loading').remove();
  1605. target.prepend(base.createLoading());
  1606. let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  1607. if (res === 'success') {
  1608. $('.listener-rpc-task').show();
  1609. target.removeClass('pl-btn-danger').html('发送成功,快去看看吧!').animate({opacity: '0.5'}, "slow");
  1610. } else {
  1611. target.addClass('pl-btn-danger').text('发送失败,请检查您的RPC配置信息!').animate({opacity: '0.5'}, "slow");
  1612. }
  1613. });
  1614. doc.on('click', '.listener-send-rpc', (e) => {
  1615. $('.listener-link-rpc').click();
  1616. $(e.target).text('发送完成,发送结果见上方按钮!').animate({opacity: '0.5'}, "slow");
  1617. });
  1618. doc.on('click', '.listener-open-setting', () => {
  1619. base.showSetting();
  1620. });
  1621. doc.on('click', '.listener-rpc-task', () => {
  1622. let rpc = JSON.stringify({
  1623. domain: base.getValue('setting_rpc_domain'),
  1624. port: base.getValue('setting_rpc_port'),
  1625. }), url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue('setting_rpc_token')}`;
  1626. GM_openInTab(url, {active: true});
  1627. });
  1628. },
  1629.  
  1630. addButton() {
  1631. if (!pt) return;
  1632. let $toolWrap;
  1633. let $button = $(`<div class="tianyi-button pl-button">下载助手<ul class="pl-dropdown-menu" style="top: 26px;"><li class="pl-dropdown-menu-item pl-button-mode" data-mode="api">API下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="aria" >Aria下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="rpc">RPC下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="curl">cURL下载</li><li class="pl-dropdown-menu-item pl-button-mode" data-mode="bc" >BC下载</li><li class="pl-dropdown-menu-item pl-button-mode listener-open-setting">助手设置</li>${pan.code == 200 && version < pan.version ? pan.new : ''}</ul></div>`);
  1634. if (pt === 'home') {
  1635. base.listenElement(pan.btn.home, () => {
  1636. $toolWrap = $(pan.btn.home);
  1637. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  1638. })
  1639. }
  1640. if (pt === 'share') {
  1641. base.listenElement(pan.btn.share, () => {
  1642. $toolWrap = $(pan.btn.share);
  1643. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  1644. })
  1645. }
  1646. base.createDownloadIframe();
  1647. this.addPageListener();
  1648. },
  1649.  
  1650. addInitButton() {
  1651. if (!pt) return;
  1652. let $toolWrap;
  1653. let $button = $(`<div class="tianyi-button pl-button-init">下载助手</div>`);
  1654. if (pt === 'home') {
  1655. base.listenElement(pan.btn.home, () => {
  1656. $toolWrap = $(pan.btn.home);
  1657. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  1658. })
  1659. }
  1660. if (pt === 'share') {
  1661. $button.css({'margin-right': '10px'});
  1662. base.listenElement(pan.btn.share, () => {
  1663. $toolWrap = $(pan.btn.share);
  1664. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  1665. })
  1666. }
  1667. $button.click(() => base.initDialog());
  1668. },
  1669.  
  1670. async getToken() {
  1671. let res = await base.getFinalUrl(pan.pcs[1], {});
  1672. let accessToken = res.match(/accessToken=(\w+)/)?.[1];
  1673. accessToken && base.setStorage('accessToken', accessToken);
  1674. return accessToken;
  1675. },
  1676.  
  1677. async getFileUrlByOnce(item, index, token) {
  1678. try {
  1679. if (item.downloadUrl) return {
  1680. index,
  1681. downloadUrl: item.downloadUrl
  1682. };
  1683. let time = Date.now(),
  1684. fileId = item.fileId,
  1685. o = "AccessToken=" + token + "&Timestamp=" + time + "&fileId=" + fileId,
  1686. url = pan.pcs[2] + '?fileId=' + fileId;
  1687. if (item.shareId) {
  1688. o = "AccessToken=" + token + "&Timestamp=" + time + "&dt=1&fileId=" + fileId + "&shareId=" + item.shareId;
  1689. url += '&dt=1&shareId=' + item.shareId;
  1690. }
  1691. let sign = md5(o).toString();
  1692. let res = await base.get(url, {
  1693. "accept": "application/json;charset=UTF-8",
  1694. "sign-type": 1,
  1695. "accesstoken": token,
  1696. "timestamp": time,
  1697. "signature": sign
  1698. });
  1699. if (res.res_code === 0) {
  1700. return {
  1701. index,
  1702. downloadUrl: res.fileDownloadUrl
  1703. };
  1704. } else if (res.errorCode === 'InvalidSessionKey') {
  1705. return {
  1706. index,
  1707. downloadUrl: '提示:请先登录网盘!'
  1708. };
  1709. } else if (res.res_code === 'ShareNotFoundFlatDir') {
  1710. return {
  1711. index,
  1712. downloadUrl: '提示:请先[转存]文件,👉前往[我的网盘]中下载!'
  1713. };
  1714. } else {
  1715. return {
  1716. index,
  1717. downloadUrl: '获取下载地址失败,请刷新重试!'
  1718. };
  1719. }
  1720. } catch (e) {
  1721. return {
  1722. index,
  1723. downloadUrl: '获取下载地址失败,请刷新重试!'
  1724. };
  1725. }
  1726. },
  1727.  
  1728. async getPCSLink() {
  1729. selectList = this.getSelectedList();
  1730. if (selectList.length === 0) {
  1731. return message.error('提示:请先勾选要下载的文件!');
  1732. }
  1733. if (this.isOnlyFolder()) {
  1734. return message.error('提示:请打开文件夹后勾选文件!');
  1735. }
  1736. let token = base.getStorage('accessToken') || await this.getToken();
  1737. if (!token) {
  1738. return message.error('提示:请先登录网盘!');
  1739. }
  1740. let queue = [];
  1741. selectList.forEach((item, index) => {
  1742. queue.push(this.getFileUrlByOnce(item, index, token));
  1743. });
  1744.  
  1745. const res = await Promise.all(queue);
  1746. res.forEach(val => {
  1747. selectList[val.index].downloadUrl = val.downloadUrl;
  1748. });
  1749.  
  1750. let html = this.generateDom(selectList);
  1751. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  1752. },
  1753.  
  1754. generateDom(list) {
  1755. let content = '<div class="pl-main">';
  1756. let alinkAllText = '';
  1757. list.forEach((v, i) => {
  1758. if (v.isFolder) return;
  1759. let filename = v.fileName;
  1760. let size = base.sizeFormat(v.size);
  1761. let dlink = v.downloadUrl;
  1762. if (mode === 'api') {
  1763. content += `<div class="pl-item">
  1764. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1765. <a class="pl-item-link listener-link-api" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
  1766. </div>`;
  1767. }
  1768. if (mode === 'aria') {
  1769. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  1770. alinkAllText += alink + '\r\n';
  1771. content += `<div class="pl-item">
  1772. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1773. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  1774. }
  1775. if (mode === 'rpc') {
  1776. content += `<div class="pl-item">
  1777. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1778. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
  1779. }
  1780. if (mode === 'curl') {
  1781. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  1782. alinkAllText += alink + '\r\n';
  1783. content += `<div class="pl-item">
  1784. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1785. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  1786. }
  1787. if (mode === 'bc') {
  1788. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  1789. content += `<div class="pl-item">
  1790. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  1791. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  1792. }
  1793. });
  1794. content += '</div>';
  1795. if (mode === 'aria')
  1796. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  1797. if (mode === 'rpc') {
  1798. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  1799. 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 listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  1800. }
  1801. if (mode === 'curl')
  1802. 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>`;
  1803. return content;
  1804. },
  1805.  
  1806. async sendLinkToRPC(filename, link) {
  1807. let rpc = {
  1808. domain: base.getValue('setting_rpc_domain'),
  1809. port: base.getValue('setting_rpc_port'),
  1810. path: base.getValue('setting_rpc_path'),
  1811. token: base.getValue('setting_rpc_token'),
  1812. dir: base.getValue('setting_rpc_dir'),
  1813. };
  1814.  
  1815. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  1816. let rpcData = {
  1817. id: new Date().getTime(),
  1818. jsonrpc: '2.0',
  1819. method: 'aria2.addUri',
  1820. params: [`token:${rpc.token}`, [link], {
  1821. dir: rpc.dir,
  1822. out: filename,
  1823. header: []
  1824. }]
  1825. };
  1826. try {
  1827. let res = await base.post(url, rpcData, {}, '');
  1828. if (res.result) return 'success';
  1829. return 'fail';
  1830. } catch (e) {
  1831. return 'fail';
  1832. }
  1833. },
  1834.  
  1835. getSelectedList() {
  1836. try {
  1837. return document.querySelector(".c-file-list").__vue__.selectedList;
  1838. } catch (e) {
  1839. return [document.querySelector(".info-detail").__vue__.fileDetail];
  1840. }
  1841. },
  1842.  
  1843. detectPage() {
  1844. let path = location.pathname;
  1845. if (/^\/web\/main/.test(path)) return 'home';
  1846. if (/^\/web\/share/.test(path)) return 'share';
  1847. return '';
  1848. },
  1849.  
  1850. isOnlyFolder() {
  1851. for (let i = 0; i < selectList.length; i++) {
  1852. if (!selectList[i].isFolder) return false;
  1853. }
  1854. return true;
  1855. },
  1856.  
  1857. showMainDialog(title, html, footer) {
  1858. Swal.fire({
  1859. title,
  1860. html,
  1861. footer,
  1862. allowOutsideClick: false,
  1863. showCloseButton: true,
  1864. showConfirmButton: false,
  1865. position: 'top',
  1866. width,
  1867. padding: '15px 20px 5px',
  1868. customClass,
  1869. });
  1870. },
  1871.  
  1872. async initPanLinker() {
  1873. base.initDefaultConfig();
  1874. base.addPanLinkerStyle();
  1875. pt = this.detectPage();
  1876. let res = await base.post
  1877. (`https://api.youxiaohou.com/config/v2/tianyi?ver=${version}&a=${author}`, {}, {}, 'text');
  1878. pan = JSON.parse(base.d(res));
  1879. Object.freeze && Object.freeze(pan);
  1880. pan.num === base.getValue('setting_init_code') ||
  1881. pan.license === base.getValue('license') ? this.addButton() : this.addInitButton();
  1882. this.getToken();
  1883. base.createTip();
  1884. base.registerMenuCommand();
  1885. }
  1886. };
  1887.  
  1888. let xunlei = {
  1889.  
  1890. convertLinkToAria(link, filename, ua) {
  1891. filename = base.fixFilename(filename);
  1892. return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
  1893. },
  1894.  
  1895. convertLinkToBC(link, filename, ua) {
  1896. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
  1897. return encodeURIComponent(`bc://http/${base.e(bc)}`);
  1898. },
  1899.  
  1900. convertLinkToCurl(link, filename, ua) {
  1901. let terminal = base.getValue('setting_terminal_type');
  1902. filename = base.fixFilename(filename);
  1903. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}"`);
  1904. },
  1905.  
  1906. addPageListener() {
  1907. doc.on('click', '.pl-button-mode', (e) => {
  1908. mode = e.target.dataset.mode;
  1909. Swal.showLoading();
  1910. this.getPCSLink();
  1911. });
  1912. doc.on('click', '.listener-link-api', async (e) => {
  1913. e.preventDefault();
  1914. $('#downloadIframe').attr('src', e.currentTarget.dataset.link);
  1915. });
  1916. doc.on('click', '.listener-link-api-btn', async (e) => {
  1917. base.setClipboard(e.target.dataset.filename);
  1918. $(e.target).text('复制成功').animate({opacity: '0.5'}, "slow");
  1919. });
  1920. doc.on('click', '.listener-link-bc-btn', async (e) => {
  1921. let mirror = base.getMirrorList(e.target.dataset.dlink, pan.mirror);
  1922. base.setClipboard(mirror);
  1923. $(e.target).text('复制成功').animate({opacity: '0.5'}, "slow");
  1924. });
  1925. doc.on('click', '.listener-link-aria, .listener-copy-all', (e) => {
  1926. e.preventDefault();
  1927. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  1928. $(e.target).text('复制成功,快去粘贴吧!').animate({opacity: '0.5'}, "slow");
  1929. });
  1930. doc.on('click', '.listener-link-rpc', async (e) => {
  1931. let target = $(e.currentTarget);
  1932. target.find('.icon').remove();
  1933. target.find('.pl-loading').remove();
  1934. target.prepend(base.createLoading());
  1935. let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  1936. if (res === 'success') {
  1937. $('.listener-rpc-task').show();
  1938. target.removeClass('pl-btn-danger').html('发送成功,快去看看吧!').animate({opacity: '0.5'}, "slow");
  1939. } else {
  1940. target.addClass('pl-btn-danger').text('发送失败,请检查您的RPC配置信息!').animate({opacity: '0.5'}, "slow");
  1941. }
  1942. });
  1943. doc.on('click', '.listener-send-rpc', (e) => {
  1944. $('.listener-link-rpc').click();
  1945. $(e.target).text('发送完成,发送结果见上方按钮!').animate({opacity: '0.5'}, "slow");
  1946. });
  1947. doc.on('click', '.listener-open-setting', () => {
  1948. base.showSetting();
  1949. });
  1950. doc.on('click', '.listener-rpc-task', () => {
  1951. let rpc = JSON.stringify({
  1952. domain: base.getValue('setting_rpc_domain'),
  1953. port: base.getValue('setting_rpc_port'),
  1954. }), url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue('setting_rpc_token')}`;
  1955. GM_openInTab(url, {active: true});
  1956. });
  1957. },
  1958.  
  1959. addButton() {
  1960. if (!pt) return;
  1961. let $toolWrap;
  1962. let $button = $(`<div class="xunlei-button pl-button"><i class="xlpfont xlp-download"></i><span style="font-size: 13px;margin-left: 6px;">下载助手</span><ul class="pl-dropdown-menu" style="top: 34px;"><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>${pan.code == 200 && version < pan.version ? pan.new : ''}</ul></div>`);
  1963. if (pt === 'home') {
  1964. base.listenElement(pan.btn.home, () => {
  1965. $toolWrap = $(pan.btn.home);
  1966. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  1967. })
  1968. }
  1969. if (pt === 'share') {
  1970. $button.css({'margin-right': '10px'});
  1971. base.listenElement(pan.btn.share, () => {
  1972. $toolWrap = $(pan.btn.share);
  1973. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  1974. })
  1975. }
  1976. base.createDownloadIframe();
  1977. this.addPageListener();
  1978. },
  1979.  
  1980. addInitButton() {
  1981. if (!pt) return;
  1982. let $toolWrap;
  1983. 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>`);
  1984. if (pt === 'home') {
  1985. base.listenElement(pan.btn.home, () => {
  1986. $toolWrap = $(pan.btn.home);
  1987. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  1988. })
  1989. }
  1990. if (pt === 'share') {
  1991. $button.css({'margin-right': '10px'});
  1992. base.listenElement(pan.btn.share, () => {
  1993. $toolWrap = $(pan.btn.share);
  1994. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  1995. })
  1996. }
  1997. $button.click(() => base.initDialog());
  1998. },
  1999.  
  2000. getToken() {
  2001. let credentials = {}, captcha = {};
  2002. for (let i = 0; i < localStorage.length; i++) {
  2003. if (/^credentials_/.test(localStorage.key(i))) {
  2004. credentials = base.getStorage(localStorage.key(i));
  2005. base.setStorage('');
  2006. }
  2007. if (/^captcha_[\w]{16}/.test(localStorage.key(i))) {
  2008. captcha = base.getStorage(localStorage.key(i));
  2009. }
  2010. }
  2011. let deviceid = /(\w{32})/.exec(base.getStorage('deviceid').split(','))[0];
  2012. let token = {
  2013. credentials,
  2014. captcha,
  2015. deviceid
  2016. };
  2017. return token;
  2018. },
  2019.  
  2020. async getFileUrlByOnce(item, index, token) {
  2021. try {
  2022. if (item.downloadUrl) return {
  2023. index,
  2024. downloadUrl: item.downloadUrl
  2025. };
  2026. let res = await base.get(pan.pcs[0] + item.id, {
  2027. 'Authorization': `${token.credentials.token_type} ${token.credentials.access_token}`,
  2028. 'content-type': "application/json",
  2029. 'x-captcha-token': token.captcha.token,
  2030. 'x-device-id': token.deviceid,
  2031. });
  2032. if (res.web_content_link) {
  2033. return {
  2034. index,
  2035. downloadUrl: res.web_content_link
  2036. };
  2037. } else {
  2038. return {
  2039. index,
  2040. downloadUrl: '获取下载地址失败,请刷新重试!'
  2041. };
  2042. }
  2043. } catch (e) {
  2044. return message.error('提示:请先登录网盘后刷新页面!');
  2045. }
  2046. },
  2047.  
  2048. async getPCSLink() {
  2049. selectList = this.getSelectedList();
  2050. if (selectList.length === 0) {
  2051. return message.error('提示:请先勾选要下载的文件!');
  2052. }
  2053. if (this.isOnlyFolder()) {
  2054. return message.error('提示:请打开文件夹后勾选文件!');
  2055. }
  2056. if (pt === 'home') {
  2057. let queue = [];
  2058. let token = this.getToken();
  2059. selectList.forEach((item, index) => {
  2060. queue.push(this.getFileUrlByOnce(item, index, token));
  2061. });
  2062. const res = await Promise.all(queue);
  2063. res.forEach(val => {
  2064. selectList[val.index].downloadUrl = val.downloadUrl;
  2065. });
  2066. } else {
  2067. let dialog = await Swal.fire({
  2068. toast: true,
  2069. icon: 'info',
  2070. title: `提示:请将文件<span class="tag-danger">[保存到网盘]</span>👉前往<span class="tag-danger">[我的网盘]</span>中下载!`,
  2071. showConfirmButton: true,
  2072. confirmButtonText: '点击保存',
  2073. position: 'top',
  2074. });
  2075. if (dialog.isConfirmed) {
  2076. document.querySelector('.saveToCloud').click();
  2077. return;
  2078. }
  2079. }
  2080. let html = this.generateDom(selectList);
  2081. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  2082.  
  2083. },
  2084.  
  2085. generateDom(list) {
  2086. let content = '<div class="pl-main">';
  2087. let alinkAllText = '';
  2088. list.forEach((v, i) => {
  2089. if (v.kind === 'drive#folder') return;
  2090. let filename = v.name;
  2091. let size = base.sizeFormat(+v.size);
  2092. let dlink = v.downloadUrl;
  2093. if (mode === 'api') {
  2094. content += `<div class="pl-item">
  2095. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2096. <a class="pl-item-link listener-link-api" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
  2097. <div class="pl-item-btn listener-link-api-btn" data-filename="${filename}">复制文件名</div>
  2098. </div>`;
  2099. }
  2100. if (mode === 'aria') {
  2101. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  2102. alinkAllText += alink + '\r\n';
  2103. content += `<div class="pl-item">
  2104. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2105. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  2106. }
  2107. if (mode === 'rpc') {
  2108. content += `<div class="pl-item">
  2109. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2110. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
  2111. }
  2112. if (mode === 'curl') {
  2113. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  2114. alinkAllText += alink + '\r\n';
  2115. content += `<div class="pl-item">
  2116. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2117. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  2118. }
  2119. if (mode === 'bc') {
  2120. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  2121. content += `<div class="pl-item">
  2122. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2123. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a>
  2124. <div class="pl-item-btn listener-link-bc-btn" data-dlink="${dlink}">复制镜像地址</div>
  2125. </div>`;
  2126. }
  2127. });
  2128. content += '</div>';
  2129. if (mode === 'aria')
  2130. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  2131. if (mode === 'rpc') {
  2132. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  2133. 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 listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  2134. }
  2135. if (mode === 'curl')
  2136. 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>`;
  2137. return content;
  2138. },
  2139.  
  2140. async sendLinkToRPC(filename, link) {
  2141. let rpc = {
  2142. domain: base.getValue('setting_rpc_domain'),
  2143. port: base.getValue('setting_rpc_port'),
  2144. path: base.getValue('setting_rpc_path'),
  2145. token: base.getValue('setting_rpc_token'),
  2146. dir: base.getValue('setting_rpc_dir'),
  2147. };
  2148.  
  2149. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  2150. let rpcData = {
  2151. id: new Date().getTime(),
  2152. jsonrpc: '2.0',
  2153. method: 'aria2.addUri',
  2154. params: [`token:${rpc.token}`, [link], {
  2155. dir: rpc.dir,
  2156. out: filename,
  2157. header: []
  2158. }]
  2159. };
  2160. try {
  2161. let res = await base.post(url, rpcData, {}, '');
  2162. if (res.result) return 'success';
  2163. return 'fail';
  2164. } catch (e) {
  2165. return 'fail';
  2166. }
  2167. },
  2168.  
  2169. getSelectedList() {
  2170. try {
  2171. let doms = document.querySelectorAll('.SourceListItem__item--XxpOC');
  2172. let selectedList = [];
  2173. for (let dom of doms) {
  2174. let domVue = dom.__vue__;
  2175. if (domVue.selected.includes(domVue.info.id)) {
  2176. selectedList.push(domVue.info);
  2177. }
  2178. }
  2179. return selectedList;
  2180. } catch (e) {
  2181. return [];
  2182. }
  2183. },
  2184.  
  2185. detectPage() {
  2186. let path = location.pathname;
  2187. if (/^\/$/.test(path)) return 'home';
  2188. if (/^\/(s|share)\//.test(path)) return 'share';
  2189. return '';
  2190. },
  2191.  
  2192. isOnlyFolder() {
  2193. for (let i = 0; i < selectList.length; i++) {
  2194. if (selectList[i].kind === 'drive#file') return false;
  2195. }
  2196. return true;
  2197. },
  2198.  
  2199. showMainDialog(title, html, footer) {
  2200. Swal.fire({
  2201. title,
  2202. html,
  2203. footer,
  2204. allowOutsideClick: false,
  2205. showCloseButton: true,
  2206. showConfirmButton: false,
  2207. position: 'top',
  2208. width,
  2209. padding: '15px 20px 5px',
  2210. customClass,
  2211. });
  2212. },
  2213.  
  2214. async initPanLinker() {
  2215. base.initDefaultConfig();
  2216. base.addPanLinkerStyle();
  2217. pt = this.detectPage();
  2218. let res = await base.post
  2219. (`https://api.youxiaohou.com/config/v2/xunlei?ver=${version}&a=${author}`, {}, {}, 'text');
  2220. pan = JSON.parse(base.d(res));
  2221. Object.freeze && Object.freeze(pan);
  2222. pan.num === base.getValue('setting_init_code') ||
  2223. pan.license === base.getValue('license') ? this.addButton() : this.addInitButton();
  2224. base.createTip();
  2225. base.registerMenuCommand();
  2226. }
  2227. };
  2228.  
  2229. let quark = {
  2230.  
  2231. convertLinkToAria(link, filename, ua) {
  2232. filename = base.fixFilename(filename);
  2233. return encodeURIComponent(`aria2c "${link}" --out "${filename}" --header "Cookie: ${document.cookie}"`);
  2234. },
  2235.  
  2236. convertLinkToBC(link, filename, ua) {
  2237. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}&cookie=${encodeURIComponent(document.cookie)}ZZ`;
  2238. return encodeURIComponent(`bc://http/${base.e(bc)}`);
  2239. },
  2240.  
  2241. convertLinkToCurl(link, filename, ua) {
  2242. let terminal = base.getValue('setting_terminal_type');
  2243. filename = base.fixFilename(filename);
  2244. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}" -b "${document.cookie}"`);
  2245. },
  2246.  
  2247. addPageListener() {
  2248. window.addEventListener('hashchange', async (e) => {
  2249. let home = 'https://pan.quark.cn/list#/', all = 'https://pan.quark.cn/list#/list/all';
  2250. if (e.oldURL === home && e.newURL === all) return;
  2251. await base.sleep(150);
  2252. if ($('.quark-button').length > 0) return;
  2253. pan.num === base.getValue('setting_init_code') ||
  2254. pan.license === base.getValue('license') ? this.addButton() : this.addInitButton();
  2255. });
  2256. doc.on('click', '.pl-button-mode', (e) => {
  2257. mode = e.target.dataset.mode;
  2258. Swal.showLoading();
  2259. this.getPCSLink();
  2260. });
  2261. doc.on('click', '.listener-link-api', async (e) => {
  2262. e.preventDefault();
  2263. $('#downloadIframe').attr('src', e.currentTarget.dataset.link);
  2264. });
  2265. doc.on('click', '.listener-link-aria, .listener-copy-all', (e) => {
  2266. e.preventDefault();
  2267. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  2268. $(e.target).text('复制成功,快去粘贴吧!').animate({opacity: '0.5'}, "slow");
  2269. });
  2270. doc.on('click', '.listener-link-rpc', async (e) => {
  2271. let target = $(e.currentTarget);
  2272. target.find('.icon').remove();
  2273. target.find('.pl-loading').remove();
  2274. target.prepend(base.createLoading());
  2275. let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  2276. if (res === 'success') {
  2277. $('.listener-rpc-task').show();
  2278. target.removeClass('pl-btn-danger').html('发送成功,快去看看吧!').animate({opacity: '0.5'}, "slow");
  2279. } else {
  2280. target.addClass('pl-btn-danger').text('发送失败,请检查您的RPC配置信息!').animate({opacity: '0.5'}, "slow");
  2281. }
  2282. });
  2283. doc.on('click', '.listener-send-rpc', (e) => {
  2284. $('.listener-link-rpc').click();
  2285. $(e.target).text('发送完成,发送结果见上方按钮!').animate({opacity: '0.5'}, "slow");
  2286. });
  2287. doc.on('click', '.listener-open-setting', () => {
  2288. base.showSetting();
  2289. });
  2290. doc.on('click', '.listener-rpc-task', () => {
  2291. let rpc = JSON.stringify({
  2292. domain: base.getValue('setting_rpc_domain'),
  2293. port: base.getValue('setting_rpc_port'),
  2294. }), url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue('setting_rpc_token')}`;
  2295. GM_openInTab(url, {active: true});
  2296. });
  2297. },
  2298.  
  2299. addButton() {
  2300. if (!pt) return;
  2301. let $toolWrap;
  2302. let $button = $(`<div class="quark-button pl-button"><svg width="22" height="22" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke="#555" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 2-2z"/><path d="M14 8h1.553c.85 0 1.16.093 1.47.267.311.174.556.43.722.756.166.326.255.65.255 1.54v4.873c0 .892-.089 1.215-.255 1.54-.166.327-.41.583-.722.757-.31.174-.62.267-1.47.267H6.447c-.85 0-1.16-.093-1.47-.267a1.778 1.778 0 01-.722-.756c-.166-.326-.255-.65-.255-1.54v-4.873c0-.892.089-1.215.255-1.54.166-.327.41-.583.722-.757.31-.174.62-.267 1.47-.267H11"/><path stroke-linecap="round" stroke-linejoin="round" d="M11 3v10"/></g></svg><b>下载助手</b><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>${pan.code == 200 && version < pan.version ? pan.new : ''}</ul></div>`);
  2303. if (pt === 'home') {
  2304. base.listenElement(pan.btn.home, () => {
  2305. $toolWrap = $(pan.btn.home);
  2306. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  2307. });
  2308. }
  2309. if (pt === 'share') {
  2310. $button.css({'margin-right': '10px'});
  2311. base.listenElement(pan.btn.share, () => {
  2312. $toolWrap = $(pan.btn.share);
  2313. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  2314. });
  2315. }
  2316. },
  2317.  
  2318. addInitButton() {
  2319. if (!pt) return;
  2320. let $toolWrap;
  2321. let $button = $(`<div class="quark-button pl-button-init"><svg width="22" height="22" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd" stroke="#555" stroke-width="2"><path stroke-linecap="round" stroke-linejoin="round" d="M9 12l2 2 2-2z"/><path d="M14 8h1.553c.85 0 1.16.093 1.47.267.311.174.556.43.722.756.166.326.255.65.255 1.54v4.873c0 .892-.089 1.215-.255 1.54-.166.327-.41.583-.722.757-.31.174-.62.267-1.47.267H6.447c-.85 0-1.16-.093-1.47-.267a1.778 1.778 0 01-.722-.756c-.166-.326-.255-.65-.255-1.54v-4.873c0-.892.089-1.215.255-1.54.166-.327.41-.583.722-.757.31-.174.62-.267 1.47-.267H11"/><path stroke-linecap="round" stroke-linejoin="round" d="M11 3v10"/></g></svg><b>下载助手</b></div>`);
  2322. if (pt === 'home') {
  2323. base.listenElement(pan.btn.home, () => {
  2324. $toolWrap = $(pan.btn.home);
  2325. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  2326. })
  2327. }
  2328. if (pt === 'share') {
  2329. $button.css({'margin-right': '10px'});
  2330. base.listenElement(pan.btn.share, () => {
  2331. $toolWrap = $(pan.btn.share);
  2332. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  2333. })
  2334. }
  2335. $button.click(() => base.initDialog());
  2336. },
  2337.  
  2338. async getPCSLink() {
  2339. selectList = this.getSelectedList();
  2340. if (selectList.length === 0) {
  2341. return message.error('提示:请先勾选要下载的文件!');
  2342. }
  2343. if (this.isOnlyFolder()) {
  2344. return message.error('提示:请打开文件夹后勾选文件!');
  2345. }
  2346. let fids = [];
  2347. selectList.forEach(val => {
  2348. fids.push(val.fid);
  2349. });
  2350. if (pt === 'home') {
  2351. let res = await base.post(pan.pcs[0], {
  2352. "fids": fids
  2353. }, {"content-type": "application/json;charset=utf-8", "user-agent": pan.ua});
  2354. if (res.code === 31001) {
  2355. return message.error('提示:请先登录网盘!');
  2356. }
  2357. if (res.code !== 0) {
  2358. return message.error('提示:获取链接失败!');
  2359. }
  2360. let html = this.generateDom(res.data);
  2361. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  2362. } else {
  2363. let dialog = await Swal.fire({
  2364. toast: true,
  2365. icon: 'info',
  2366. title: `提示:请将文件<span class="tag-danger">[保存到网盘]</span>👉前往<span class="tag-danger">[我的网盘]</span>中下载!`,
  2367. showConfirmButton: true,
  2368. confirmButtonText: '点击保存',
  2369. position: 'top',
  2370. });
  2371. if (dialog.isConfirmed) {
  2372. document.querySelector('.file-info_r').click();
  2373. return;
  2374. }
  2375. }
  2376. },
  2377.  
  2378. generateDom(list) {
  2379. let content = '<div class="pl-main">';
  2380. let alinkAllText = '';
  2381. list.forEach((v, i) => {
  2382. if (v.file === false) return;
  2383. let filename = v.file_name;
  2384. let fid = v.fid;
  2385. let size = base.sizeFormat(v.size);
  2386. let dlink = v.download_url;
  2387. if (mode === 'api') {
  2388. content += `<div class="pl-item">
  2389. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2390. <a class="pl-item-link listener-link-api" data-fid="${fid}" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
  2391. </div>`;
  2392. }
  2393. if (mode === 'aria') {
  2394. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  2395. alinkAllText += alink + '\r\n';
  2396. content += `<div class="pl-item">
  2397. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2398. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  2399. }
  2400. if (mode === 'rpc') {
  2401. content += `<div class="pl-item">
  2402. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2403. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
  2404. }
  2405. if (mode === 'curl') {
  2406. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  2407. alinkAllText += alink + '\r\n';
  2408. content += `<div class="pl-item">
  2409. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2410. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  2411. }
  2412. if (mode === 'bc') {
  2413. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  2414. content += `<div class="pl-item">
  2415. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2416. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  2417. }
  2418. });
  2419. content += '</div>';
  2420. if (mode === 'aria')
  2421. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  2422. if (mode === 'rpc') {
  2423. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  2424. 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 listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  2425. }
  2426. if (mode === 'curl')
  2427. 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>`;
  2428. return content;
  2429. },
  2430.  
  2431. async sendLinkToRPC(filename, link) {
  2432. let rpc = {
  2433. domain: base.getValue('setting_rpc_domain'),
  2434. port: base.getValue('setting_rpc_port'),
  2435. path: base.getValue('setting_rpc_path'),
  2436. token: base.getValue('setting_rpc_token'),
  2437. dir: base.getValue('setting_rpc_dir'),
  2438. };
  2439.  
  2440. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  2441. let rpcData = {
  2442. id: new Date().getTime(),
  2443. jsonrpc: '2.0',
  2444. method: 'aria2.addUri',
  2445. params: [`token:${rpc.token}`, [link], {
  2446. dir: rpc.dir,
  2447. out: filename,
  2448. header: [`Cookie: ${document.cookie}`]
  2449. }]
  2450. };
  2451. try {
  2452. let res = await base.post(url, rpcData, {"Cookie": document.cookie}, '');
  2453. if (res.result) return 'success';
  2454. return 'fail';
  2455. } catch (e) {
  2456. return 'fail';
  2457. }
  2458. },
  2459.  
  2460. getSelectedList() {
  2461. try {
  2462. let selectedList = [];
  2463. let reactDom = document.getElementsByClassName('file-list')[0];
  2464. let reactObj = base.findReact(reactDom);
  2465. let props = reactObj.props;
  2466. if (props) {
  2467. let fileList = props.list || [];
  2468. let selectedKeys = props.selectedRowKeys || [];
  2469. fileList.forEach((val) => {
  2470. if (selectedKeys.includes(val.fid)) {
  2471. selectedList.push(val);
  2472. }
  2473. });
  2474. }
  2475. return selectedList;
  2476. } catch (e) {
  2477. return [];
  2478. }
  2479. },
  2480.  
  2481. detectPage() {
  2482. let path = location.pathname;
  2483. if (/^\/(list)/.test(path)) return 'home';
  2484. if (/^\/(s|share)\//.test(path)) return 'share';
  2485. return '';
  2486. },
  2487.  
  2488. isOnlyFolder() {
  2489. for (let i = 0; i < selectList.length; i++) {
  2490. if (selectList[i].file) return false;
  2491. }
  2492. return true;
  2493. },
  2494.  
  2495. showMainDialog(title, html, footer) {
  2496. Swal.fire({
  2497. title,
  2498. html,
  2499. footer,
  2500. allowOutsideClick: false,
  2501. showCloseButton: true,
  2502. showConfirmButton: false,
  2503. position: 'top',
  2504. width,
  2505. padding: '15px 20px 5px',
  2506. customClass,
  2507. });
  2508. },
  2509.  
  2510. async initPanLinker() {
  2511. base.initDefaultConfig();
  2512. base.addPanLinkerStyle();
  2513. pt = this.detectPage();
  2514. let res = await base.post
  2515. (`https://api.youxiaohou.com/config/v2/quark?ver=${version}&a=${author}`, {}, {}, 'text');
  2516. pan = JSON.parse(base.d(res));
  2517. Object.freeze && Object.freeze(pan);
  2518. pan.num === base.getValue('setting_init_code') ||
  2519. pan.license === base.getValue('license') ? this.addButton() : this.addInitButton();
  2520. this.addPageListener();
  2521. base.createTip();
  2522. base.createDownloadIframe();
  2523. base.registerMenuCommand();
  2524. }
  2525. };
  2526.  
  2527. let yidong = {
  2528.  
  2529. convertLinkToAria(link, filename, ua) {
  2530. filename = base.fixFilename(filename);
  2531. return encodeURIComponent(`aria2c "${link}" --out "${filename}"`);
  2532. },
  2533.  
  2534. convertLinkToBC(link, filename, ua) {
  2535. let bc = `AA/${encodeURIComponent(filename)}/?url=${encodeURIComponent(link)}ZZ`;
  2536. return encodeURIComponent(`bc://http/${base.e(bc)}`);
  2537. },
  2538.  
  2539. convertLinkToCurl(link, filename, ua) {
  2540. let terminal = base.getValue('setting_terminal_type');
  2541. filename = base.fixFilename(filename);
  2542. return encodeURIComponent(`${terminal !== 'wp' ? 'curl' : 'curl.exe'} -L -C - "${link}" -o "${filename}"`);
  2543. },
  2544.  
  2545. addPageListener() {
  2546. doc.on('click', '.pl-button-mode', (e) => {
  2547. mode = e.target.dataset.mode;
  2548. Swal.showLoading();
  2549. this.getPCSLink();
  2550. });
  2551. doc.on('click', '.listener-link-api', async (e) => {
  2552. e.preventDefault();
  2553. $('#downloadIframe').attr('src', e.currentTarget.dataset.link);
  2554. });
  2555. doc.on('click', '.listener-link-aria, .listener-copy-all', (e) => {
  2556. e.preventDefault();
  2557. base.setClipboard(decodeURIComponent(e.target.dataset.link));
  2558. $(e.target).text('复制成功,快去粘贴吧!').animate({opacity: '0.5'}, "slow");
  2559. });
  2560. doc.on('click', '.listener-link-rpc', async (e) => {
  2561. let target = $(e.currentTarget);
  2562. target.find('.icon').remove();
  2563. target.find('.pl-loading').remove();
  2564. target.prepend(base.createLoading());
  2565. let res = await this.sendLinkToRPC(e.currentTarget.dataset.filename, e.currentTarget.dataset.link);
  2566. if (res === 'success') {
  2567. $('.listener-rpc-task').show();
  2568. target.removeClass('pl-btn-danger').html('发送成功,快去看看吧!').animate({opacity: '0.5'}, "slow");
  2569. } else {
  2570. target.addClass('pl-btn-danger').text('发送失败,请检查您的RPC配置信息!').animate({opacity: '0.5'}, "slow");
  2571. }
  2572. });
  2573. doc.on('click', '.listener-send-rpc', (e) => {
  2574. $('.listener-link-rpc').click();
  2575. $(e.target).text('发送完成,发送结果见上方按钮!').animate({opacity: '0.5'}, "slow");
  2576. });
  2577. doc.on('click', '.listener-open-setting', () => {
  2578. base.showSetting();
  2579. });
  2580. doc.on('click', '.listener-rpc-task', () => {
  2581. let rpc = JSON.stringify({
  2582. domain: base.getValue('setting_rpc_domain'),
  2583. port: base.getValue('setting_rpc_port'),
  2584. }), url = `${pan.d}/?rpc=${base.e(rpc)}#${base.getValue('setting_rpc_token')}`;
  2585. GM_openInTab(url, {active: true});
  2586. });
  2587. },
  2588.  
  2589. addButton() {
  2590. if (!pt) return;
  2591. let $toolWrap;
  2592. let $button = $(`<div class="yidong-button pl-button">下载助手<ul class="pl-dropdown-menu" style="top: 36px;"><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>${pan.code == 200 && version < pan.version ? pan.new : ''}</ul></div>`);
  2593. if (pt === 'home') {
  2594. base.listenElement(pan.btn.home, () => {
  2595. $toolWrap = $(pan.btn.home);
  2596. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  2597. })
  2598. }
  2599. if (pt === 'share') {
  2600. $button.removeClass('yidong-button').addClass('yidong-share-button');
  2601. base.listenElement(pan.btn.share, () => {
  2602. $toolWrap = $(pan.btn.share);
  2603. $('.pl-button').length === 0 && $toolWrap.prepend($button);
  2604. })
  2605. }
  2606. base.createDownloadIframe();
  2607. this.addPageListener();
  2608. },
  2609.  
  2610. addInitButton() {
  2611. if (!pt) return;
  2612. let $toolWrap;
  2613. let $button = $(`<div class="yidong-button pl-button-init">下载助手</div>`);
  2614. if (pt === 'home') {
  2615. base.listenElement(pan.btn.home, () => {
  2616. $toolWrap = $(pan.btn.home);
  2617. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  2618. })
  2619. }
  2620. if (pt === 'share') {
  2621. $button.removeClass('yidong-button').addClass('yidong-share-button');
  2622. base.listenElement(pan.btn.share, () => {
  2623. $toolWrap = $(pan.btn.share);
  2624. $('.pl-button-init').length === 0 && $toolWrap.prepend($button);
  2625. })
  2626. }
  2627. $button.click(() => base.initDialog());
  2628. },
  2629.  
  2630. getRandomString(len) {
  2631. len = len || 16;
  2632. let $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
  2633. let maxPos = $chars.length;
  2634. let pwd = '';
  2635. for (let i = 0; i < len; i++) {
  2636. pwd += $chars.charAt(Math.floor(Math.random() * maxPos));
  2637. }
  2638. return pwd;
  2639. },
  2640.  
  2641. utob(str) {
  2642. const u = String.fromCharCode;
  2643. return str.replace(/[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g, (t) => {
  2644. if (t.length < 2) {
  2645. let e = t.charCodeAt(0);
  2646. 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);
  2647. }
  2648. e = 65536 + 1024 * (t.charCodeAt(0) - 55296) + (t.charCodeAt(1) - 56320);
  2649. return u(240 | e >>> 18 & 7) + u(128 | e >>> 12 & 63) + u(128 | e >>> 6 & 63) + u(128 | 63 & e);
  2650. });
  2651. },
  2652.  
  2653. getSign(e, t, a, n) {
  2654. let r = "",
  2655. i = "";
  2656. if (t) {
  2657. let s = Object.assign({}, t);
  2658. i = JSON.stringify(s),
  2659. i = i.replace(/\s*/g, ""),
  2660. i = encodeURIComponent(i);
  2661. let c = i.split(""),
  2662. u = c.sort();
  2663. i = u.join("");
  2664. }
  2665. let A = md5(base.e(this.utob(i)));
  2666. let l = md5(a + ":" + n);
  2667. return md5(A + l).toUpperCase();
  2668. },
  2669.  
  2670. async getFileUrlByOnce(item, index) {
  2671. try {
  2672. if (item.downloadUrl) return {
  2673. index,
  2674. downloadUrl: item.downloadUrl
  2675. };
  2676. if (this.detectPage() === 'home') {
  2677. let body = {
  2678. "contentID": item.contentID,
  2679. "commonAccountInfo": {"account": item.owner, "accountType": 1},
  2680. "operation": "0",
  2681. "inline": "0",
  2682. "extInfo": {"isReturnCdnDownloadUrl": "1"}
  2683. };
  2684. let time = new Date(+new Date() + 8 * 3600 * 1000).toJSON().substr(0, 19).replace('T', ' ');
  2685. let key = this.getRandomString(16);
  2686. let sign = this.getSign(undefined, body, time, key);
  2687.  
  2688. let res = await base.post(pan.pcs[0], body, {
  2689. 'authorization': base.getCookie('authorization'),
  2690. 'x-huawei-channelSrc': '10000034',
  2691. 'x-inner-ntwk': '2',
  2692. 'mcloud-channel': '1000101',
  2693. 'mcloud-client': '10701',
  2694. 'mcloud-sign': time + "," + key + "," + sign,
  2695. 'content-type': "application/json;charset=UTF-8",
  2696. 'caller': 'web',
  2697. 'CMS-DEVICE': 'default',
  2698. 'x-DeviceInfo': '||9|7.12.0|chrome|118.0.0.0||windows 10||zh-CN|||',
  2699. 'x-SvcType': '1',
  2700. });
  2701. if (res.success) {
  2702. return {
  2703. index,
  2704. downloadUrl: res.data.downloadURL
  2705. };
  2706. } else {
  2707. return {
  2708. index,
  2709. downloadUrl: '获取下载地址失败,请刷新重试!'
  2710. };
  2711. }
  2712. }
  2713. if (this.detectPage() === 'share') {
  2714. let vueDom = document.querySelector(".main_file_list").__vue__;
  2715.  
  2716. let res = await base.post(pan.pcs[1], `linkId=${vueDom.linkID}&contentIds=${item.path}&catalogIds=`, {
  2717. 'Content-Type': 'application/x-www-form-urlencoded',
  2718. });
  2719. if (res.code === 0) {
  2720. return {
  2721. index,
  2722. downloadUrl: res.data.redrUrl
  2723. };
  2724. } else {
  2725. return {
  2726. index,
  2727. downloadUrl: '获取下载地址失败,请刷新重试!'
  2728. };
  2729. }
  2730. }
  2731. } catch (e) {
  2732. return {
  2733. index,
  2734. downloadUrl: '获取下载地址失败,请刷新重试!'
  2735. };
  2736. }
  2737. },
  2738.  
  2739. async getPCSLink() {
  2740. selectList = this.getSelectedList();
  2741. if (selectList.length === 0) {
  2742. return message.error('提示:请先勾选要下载的文件!');
  2743. }
  2744. if (this.isOnlyFolder()) {
  2745. return message.error('提示:请打开文件夹后勾选文件!');
  2746. }
  2747.  
  2748. let queue = [];
  2749. selectList.forEach((item, index) => {
  2750. queue.push(this.getFileUrlByOnce(item, index));
  2751. });
  2752.  
  2753. const res = await Promise.all(queue);
  2754. res.forEach(val => {
  2755. selectList[val.index].downloadUrl = val.downloadUrl;
  2756. });
  2757.  
  2758. let html = this.generateDom(selectList);
  2759. this.showMainDialog(pan[mode][0], html, pan[mode][1]);
  2760. },
  2761.  
  2762. generateDom(list) {
  2763. let content = '<div class="pl-main">';
  2764. let alinkAllText = '';
  2765. list.forEach((v, i) => {
  2766. if (v.dirEtag || v.caName) return;
  2767. let filename = v.contentName || v.coName;
  2768. let size = base.sizeFormat(v.contentSize || v.coSize);
  2769. let dlink = v.downloadUrl;
  2770. if (mode === 'api') {
  2771. content += `<div class="pl-item">
  2772. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2773. <a class="pl-item-link listener-link-api" data-filename="${filename}" data-link="${dlink}" data-index="${i}">${dlink}</a>
  2774. </div>`;
  2775. }
  2776. if (mode === 'aria') {
  2777. let alink = this.convertLinkToAria(dlink, filename, navigator.userAgent);
  2778. alinkAllText += alink + '\r\n';
  2779. content += `<div class="pl-item">
  2780. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2781. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制aria2c链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  2782. }
  2783. if (mode === 'rpc') {
  2784. content += `<div class="pl-item">
  2785. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2786. <button class="pl-item-link listener-link-rpc pl-btn-primary pl-btn-info" data-filename="${filename}" data-link="${dlink}"><em class="icon icon-device"></em><span style="margin-left: 5px;">推送到 RPC 下载器</span></button></div>`;
  2787. }
  2788. if (mode === 'curl') {
  2789. let alink = this.convertLinkToCurl(dlink, filename, navigator.userAgent);
  2790. alinkAllText += alink + '\r\n';
  2791. content += `<div class="pl-item">
  2792. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2793. <a class="pl-item-link listener-link-aria" href="${alink}" title="点击复制curl链接" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  2794. }
  2795. if (mode === 'bc') {
  2796. let alink = this.convertLinkToBC(dlink, filename, navigator.userAgent);
  2797. content += `<div class="pl-item">
  2798. <div class="pl-item-name listener-tip" data-size="${size}">${filename}</div>
  2799. <a class="pl-item-link" href="${decodeURIComponent(alink)}" title="点击用比特彗星下载" data-filename="${filename}" data-link="${alink}">${decodeURIComponent(alink)}</a> </div>`;
  2800. }
  2801. });
  2802. content += '</div>';
  2803. if (mode === 'aria')
  2804. content += `<div class="pl-extra"><button class="pl-btn-primary listener-copy-all" data-link="${alinkAllText}">复制全部链接</button></div>`;
  2805. if (mode === 'rpc') {
  2806. let rpc = base.getValue('setting_rpc_domain') + ':' + base.getValue('setting_rpc_port') + base.getValue('setting_rpc_path');
  2807. 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 listener-rpc-task" style="margin-left: 10px;display: none">查看下载任务</button></div>`;
  2808. }
  2809. if (mode === 'curl')
  2810. 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>`;
  2811. return content;
  2812. },
  2813.  
  2814. async sendLinkToRPC(filename, link) {
  2815. let rpc = {
  2816. domain: base.getValue('setting_rpc_domain'),
  2817. port: base.getValue('setting_rpc_port'),
  2818. path: base.getValue('setting_rpc_path'),
  2819. token: base.getValue('setting_rpc_token'),
  2820. dir: base.getValue('setting_rpc_dir'),
  2821. };
  2822.  
  2823. let url = `${rpc.domain}:${rpc.port}${rpc.path}`;
  2824. let rpcData = {
  2825. id: new Date().getTime(),
  2826. jsonrpc: '2.0',
  2827. method: 'aria2.addUri',
  2828. params: [`token:${rpc.token}`, [link], {
  2829. dir: rpc.dir,
  2830. out: filename,
  2831. header: []
  2832. }]
  2833. };
  2834. try {
  2835. let res = await base.post(url, rpcData, {}, '');
  2836. if (res.result) return 'success';
  2837. return 'fail';
  2838. } catch (e) {
  2839. return 'fail';
  2840. }
  2841. },
  2842.  
  2843. getSelectedList() {
  2844. try {
  2845. return document.querySelector(".main_file_list").__vue__.selectList.map(val => val.item);
  2846. } catch (e) {
  2847. let vueDom = document.querySelector(".home-page").__vue__;
  2848. let fileList = vueDom._computedWatchers.fileList.value;
  2849. let dirList = vueDom._computedWatchers.dirList.value;
  2850. let selectedFileIndex = vueDom.selectedFile;
  2851. let selectedDirIndex = vueDom.selectedDir;
  2852. let selectFileList = fileList.filter((v, i) => {
  2853. return selectedFileIndex.includes(i);
  2854. });
  2855. let selectDirList = dirList.filter((v, i) => {
  2856. return selectedDirIndex.includes(i);
  2857. });
  2858. return [...selectFileList, ...selectDirList];
  2859. }
  2860. },
  2861.  
  2862. detectPage() {
  2863. let path = location.pathname;
  2864. if (/^\/w/.test(path)) return 'home';
  2865. if (/^\/link|shareweb/.test(path)) return 'share';
  2866. return '';
  2867. },
  2868.  
  2869. isOnlyFolder() {
  2870. for (let i = 0; i < selectList.length; i++) {
  2871. if (selectList[i].fileEtag || selectList[i].coName) return false;
  2872. }
  2873. return true;
  2874. },
  2875.  
  2876. showMainDialog(title, html, footer) {
  2877. Swal.fire({
  2878. title,
  2879. html,
  2880. footer,
  2881. allowOutsideClick: false,
  2882. showCloseButton: true,
  2883. showConfirmButton: false,
  2884. position: 'top',
  2885. width,
  2886. padding: '15px 20px 5px',
  2887. customClass,
  2888. });
  2889. },
  2890.  
  2891. async initPanLinker() {
  2892. base.initDefaultConfig();
  2893. base.addPanLinkerStyle();
  2894. pt = this.detectPage();
  2895. let res = await base.post
  2896. (`https://api.youxiaohou.com/config/v2/yidong?ver=${version}&a=${author}`, {}, {}, 'text');
  2897. pan = JSON.parse(base.d(res));
  2898. Object.freeze && Object.freeze(pan);
  2899. pan.num === base.getValue('setting_init_code') ||
  2900. pan.license === base.getValue('license') ? this.addButton() : this.addInitButton();
  2901. base.createTip();
  2902. base.registerMenuCommand();
  2903. }
  2904. };
  2905.  
  2906. let main = {
  2907. init() {
  2908. if (/(pan|yun).baidu.com/.test(location.host)) {
  2909. baidu.initPanLinker();
  2910. }
  2911. if (/openapi.baidu.com\/oauth/.test(location.href)) {
  2912. baidu.initAuthorize()
  2913. }
  2914. if (/www.(aliyundrive|alipan).com/.test(location.host)) {
  2915. ali.initPanLinker();
  2916. }
  2917. if (/cloud.189.cn/.test(location.host)) {
  2918. tianyi.initPanLinker();
  2919. }
  2920. if (/pan.xunlei.com/.test(location.host)) {
  2921. xunlei.initPanLinker();
  2922. }
  2923. if (/pan.quark.cn/.test(location.host)) {
  2924. quark.initPanLinker();
  2925. }
  2926. if (/(yun|caiyun).139.com/.test(location.host)) {
  2927. yidong.initPanLinker();
  2928. }
  2929. }
  2930. };
  2931.  
  2932. main.init();
  2933. })();