Greasy Fork镜像 还支持 简体中文。

Custom aliyundrive

阿里云直链导出

目前為 2022-01-09 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name Custom aliyundrive
  3. // @namespace https://github.com/invobzvr
  4. // @version 1.0
  5. // @description 阿里云直链导出
  6. // @author invobzvr
  7. // @match *://www.aliyundrive.com/drive/*
  8. // @grant GM_getValue
  9. // @grant GM_setValue
  10. // @grant GM_xmlhttpRequest
  11. // @connect 127.0.0.1
  12. // @connect localhost
  13. // @connect *
  14. // @require https://cdn.jsdelivr.net/npm/sweetalert2@11
  15. // @homepageURL https://github.com/invobzvr/invotoys.js/tree/main/aliyundrive
  16. // @supportURL https://github.com/invobzvr/invotoys.js/issues
  17. // @license GPL-3.0
  18. // ==/UserScript==
  19.  
  20. (function () {
  21. const Toast = Swal.mixin({
  22. position: 'top-end',
  23. showConfirmButton: false,
  24. timer: 3e3,
  25. timerProgressBar: true,
  26. toast: true,
  27. didOpen: tst => {
  28. tst.addEventListener('mouseenter', Swal.stopTimer);
  29. tst.addEventListener('mouseleave', Swal.resumeTimer);
  30. }
  31. });
  32.  
  33. const that = {
  34. a2config: GM_getValue('a2config', {
  35. host: '127.0.0.1',
  36. port: 6800,
  37. dir: 'Download',
  38. }),
  39. xhr: function (details) {
  40. return new Promise((res, rej) => {
  41. GM_xmlhttpRequest(Object.assign(details, {
  42. onerror: rej,
  43. onload: res,
  44. }));
  45. });
  46. },
  47. wait: function (selectors, key) {
  48. return new Promise(res => {
  49. let el = document.querySelector(selectors),
  50. iid = setInterval(() => (el ? true : el = document.querySelector(selectors)) && (key ? el[key] : true) && (clearInterval(iid), res(el)), 100);
  51. });
  52. },
  53. install: async function () {
  54. history.pushState = that.HOOK.H_PUSHSTATE;
  55. that.rk = `__reactFiber$${Object.keys(await that.wait('#root', '_reactRootContainer')).find(ii => ii.startsWith('__reactContainer$')).split('$')[1]}`;
  56. that.tbmo = new MutationObserver(that.tbmc);
  57. that.init();
  58. },
  59. init: async function () {
  60. that.listModel = (await that.wait('[class^=node-list--]'))[that.rk].return.memoizedProps.listModel;
  61. that.tbmo.observe(document.querySelector('[class^=page-content--]'), { childList: true });
  62. },
  63. tbmc: function ([mr]) {
  64. if (mr.addedNodes.length && (that.tbel = mr.addedNodes[0].querySelector('[class^=toolbar-wrapper]'))) {
  65. let btn = that.tbel.firstChild;
  66. that.tbel.insertAdjacentHTML('afterbegin', '<div style="background:#fff;height:30px;margin-left:8px;width:.1px"></div>');
  67. let dlBtn = that.tbel.insertAdjacentElement('afterbegin', btn.cloneNode(true)),
  68. a2Btn = that.tbel.insertAdjacentElement('afterbegin', btn.cloneNode(true));
  69. dlBtn.title = 'Download';
  70. dlBtn.addEventListener('click', that.download);
  71. a2Btn.title = 'Aria2';
  72. a2Btn.addEventListener('click', that.aria2);
  73. a2Btn.addEventListener('contextmenu', evt => (evt.preventDefault(), that.configa2(true)));
  74. }
  75. },
  76. onPushState: function (evt) {
  77. if (evt.detail === '/drive/' || evt.detail.startsWith('/drive/folder')) {
  78. !that.listModel && that.init();
  79. } else {
  80. that.listModel = null;
  81. that.tbmo.disconnect();
  82. }
  83. },
  84. download: async function () {
  85. let selected = that.listModel.selectedItems;
  86. selected.length !== (selected = selected.filter(ii => ii.type == 'file')).length && await Toast.fire({
  87. icon: 'warning',
  88. title: 'Folders are skipped',
  89. });
  90. if (selected.length === 1) {
  91. location.href = selected[0].downloadUrl;
  92. } else {
  93. Swal.fire({
  94. title: 'Urls',
  95. input: 'textarea',
  96. inputValue: selected.map(ii => ii.downloadUrl).join('\n'),
  97. inputAttributes: {
  98. style: `height:${window.innerHeight * .5}px;white-space:nowrap`,
  99. },
  100. width: '60%',
  101. });
  102. }
  103. },
  104. aria2: async function () {
  105. if (!that.a2config.remember) {
  106. if (!await that.configa2()) {
  107. return Toast.fire({
  108. icon: 'info',
  109. title: 'Canceled',
  110. });
  111. }
  112. }
  113. let selected = that.listModel.selectedItems;
  114. selected.length !== (selected = selected.filter(ii => ii.type == 'file')).length && Toast.fire({
  115. icon: 'warning',
  116. title: 'Folders are skipped',
  117. });
  118. let res = await that.xhr({
  119. method: 'post',
  120. responseType: 'json',
  121. url: `http://${that.a2config.host}:${that.a2config.port}/jsonrpc`,
  122. data: JSON.stringify({
  123. id: 'INVOTOYS',
  124. jsonrpc: '2.0',
  125. method: 'system.multicall',
  126. params: [selected.map(ii => ({
  127. methodName: 'aria2.addUri',
  128. params: [[ii.downloadUrl], {
  129. dir: that.a2config.dir,
  130. referer: 'https://www.aliyundrive.com/',
  131. 'user-agent': navigator.userAgent,
  132. }],
  133. }))],
  134. }),
  135. }).catch(err => err);
  136. Toast.fire(res.status == 200 ? ([...that.listModel.selectedIds].forEach(that.listModel.removeSelect), {
  137. icon: 'success',
  138. title: 'Sended successfully',
  139. }) : {
  140. icon: 'error',
  141. title: 'Failed to connect to Aria2',
  142. text: res.error || '',
  143. });
  144. },
  145. configa2: async function (save) {
  146. let ret = await Swal.fire({
  147. title: 'Aria2 Config',
  148. html: `<form>
  149. <div><span>Host</span><input class="swal2-input" name="host" value="${that.a2config.host}"></div>
  150. <div><span>Port</span><input class="swal2-input" name="port" value="${that.a2config.port}"></div>
  151. <div><span>Dir</span><input class="swal2-input" name="dir" value="${that.a2config.dir}"></div>
  152. <div><label><span>Remember</span><input name="remember" type="checkbox"${that.a2config.remember ? ' checked' : ''}></label></div>
  153. </form>`,
  154. preConfirm: () => Object.fromEntries(new FormData(Swal.getHtmlContainer().firstChild).entries()),
  155. });
  156. ret.isConfirmed && (save || ret.value.remember) && GM_setValue('a2config', that.a2config = ret.value);
  157. return ret.isConfirmed;
  158. },
  159. ORI: {
  160. H_PUSHSTATE: History.prototype.pushState,
  161. },
  162. HOOK: {
  163. H_PUSHSTATE: function () {
  164. dispatchEvent(new CustomEvent('PUSHSTATE', { detail: arguments[2] }));
  165. return that.ORI.H_PUSHSTATE.apply(this, arguments);
  166. },
  167. },
  168. };
  169.  
  170. that.install();
  171. })();

QingJ © 2025

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