Minehut folder download

Download folders from Minehut's file manager without having to pay

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

  1. // ==UserScript==
  2. // @name Minehut folder download
  3. // @namespace Violentmonkey Scripts
  4. // @match *://app.minehut.com/*
  5. // @grant none
  6. // @version 1.0
  7. // @author -
  8. // @require https://greasyfork.org/scripts/441873-zip-js/code/zipjs.js?version=1030820
  9. // @description Download folders from Minehut's file manager without having to pay
  10. // @license MIT
  11. // ==/UserScript==
  12.  
  13.  
  14. (() => {
  15. let downloadFolder = (async (progressFn) => {
  16. function getCookieValue(cookieName) {
  17. let name = cookieName + "=";
  18. let decodedCookie = decodeURIComponent(document.cookie);
  19. let cookieArray = decodedCookie.split(';');
  20. for (let i = 0; i < cookieArray.length; i++) {
  21. let cookie = cookieArray[i];
  22. while (cookie.charAt(0) === ' ') {
  23. cookie = cookie.substring(1);
  24. }
  25. if (cookie.indexOf(name) === 0) {
  26. return cookie.substring(name.length, cookie.length);
  27. }
  28. }
  29. return "";
  30. }
  31.  
  32. let accessToken = getCookieValue('access_token_prd');
  33. let slgToken = localStorage.getItem('slg_user_token');
  34. let minehutSession = localStorage.getItem('minehut_session_id');
  35. let activeServerData = localStorage.getItem('activeServer');
  36.  
  37. if (!accessToken || !slgToken || !minehutSession || !activeServerData) {
  38. alert('You must select a server to use this script°');
  39. return;
  40. }
  41.  
  42. let activeServer = JSON.parse(activeServerData);
  43. let sideCarBase = `https://${activeServer._id}.manager.minehut.com`;
  44.  
  45. let headers = {
  46. 'Content-Type': 'application/json',
  47. Authorization: `Bearer ${accessToken}`,
  48. 'x-profile-id': slgToken,
  49. 'x-session-id': minehutSession
  50. };
  51.  
  52. async function apiRequest(url, method = 'GET', body = undefined) {
  53. return await fetch('https://api.minehut.com' + url, {
  54. method: method,
  55. headers: headers,
  56. body: body
  57. });
  58. }
  59.  
  60. async function sideCarRequest(url, method = 'GET', body = undefined) {
  61. return await fetch(sideCarBase + url, {
  62. method: method,
  63. headers: headers,
  64. body: body
  65. });
  66. }
  67.  
  68. async function list(path) {
  69. let response = await apiRequest(`/file/${activeServer._id}/list/${path}`);
  70. return await response.json();
  71. }
  72.  
  73. async function download(path) {
  74. let response = await sideCarRequest(`/file/download?files=${JSON.stringify([path])}`);
  75. return await response.blob();
  76. }
  77.  
  78. async function listRecursive(path) {
  79. let files = await list(path);
  80. let fileList = [];
  81. for (let file of files.files) {
  82. if (file.directory) {
  83. fileList = fileList.concat(await listRecursive(`${path}/${file.name}`));
  84. } else if (!file.blocked) {
  85. fileList.push(`${path}/${file.name}`);
  86. }
  87. }
  88. return fileList;
  89. }
  90.  
  91. function downloadBlob(blob, fileName) {
  92. let a = document.createElement('a');
  93. a.href = URL.createObjectURL(blob);
  94. a.download = fileName;
  95. a.click();
  96. URL.revokeObjectURL(a.href);
  97. }
  98.  
  99. async function createZip(files, progressFn) {
  100. const zipFileWriter = new zip.BlobWriter();
  101. const zipWriter = new zip.ZipWriter(zipFileWriter);
  102.  
  103. let i = 1;
  104. for (let path of files) {
  105. progressFn(`Downloading (${i}/${files.length}) ...`);
  106. let data = await download(path);
  107. await zipWriter.add(path.replace(/^\/+/, ''), new zip.BlobReader(data));
  108. i++;
  109. }
  110. await zipWriter.close();
  111. return await zipFileWriter.getData();
  112. }
  113.  
  114. let folderName = prompt('Enter the full path of the folder to download (e.g. world or plugins/WorldEdit)');
  115. if (!folderName) {
  116. alert('You must enter a folder name');
  117. return;
  118. }
  119.  
  120. if (!folderName.startsWith('/')) {
  121. folderName = '/' + folderName;
  122. }
  123. if (folderName.endsWith('/')) {
  124. folderName = folderName.slice(0, -1);
  125. }
  126.  
  127. progressFn('Scanning folder...');
  128. let contents = await listRecursive(folderName);
  129. let result = await createZip(contents, progressFn);
  130. let name = folderName.split('/').pop();
  131. if (name === '') {
  132. name = 'root';
  133. }
  134. downloadBlob(result, name + '.zip');
  135. });
  136.  
  137. let activeDownload = false;
  138. let button = document.createElement('button');
  139. button.className = 'themed___PBHap primary-theme___q1d2u no-border___6w-uL themed-control___KmjCR no-underline___h2l-L page-control___rxMPx';
  140. button.textContent = 'Download Folder';
  141. button.style.position = 'fixed';
  142. button.style.zIndex = '10000';
  143. button.style.top = '5px';
  144. button.style.right = '5px';
  145. button.style.display = 'none';
  146. button.onclick = async () => {
  147. if (activeDownload) {
  148. return;
  149. }
  150. activeDownload = true;
  151. button.textContent = 'Starting...';
  152. try {
  153. await downloadFolder(progress => {
  154. button.textContent = progress;
  155. });
  156. } catch (e) {
  157. alert('An error occurred while downloading the folder');
  158. }
  159. activeDownload = false;
  160. button.textContent = 'Download Folder';
  161. };
  162.  
  163. document.body.appendChild(button);
  164.  
  165. setInterval(() => {
  166. if (window.location.pathname.startsWith('/dashboard/files')) {
  167. button.style.display = 'block';
  168. } else {
  169. button.style.display = 'none';
  170. }
  171. }, 250);
  172. })();