Custom aliyundrive

阿里云直链导出

当前为 2022-01-11 提交的版本,查看 最新版本

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

QingJ © 2025

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