Greasy Fork 还支持 简体中文。

VGMLoaderX

Automatically downloads albums from KHInsider without an account.

目前為 2024-03-30 提交的版本,檢視 最新版本

  1. // ==UserScript==
  2. // @name VGMLoaderX
  3. // @name:de VGMLoaderX
  4. // @name:en VGMLoaderX
  5. // @namespace sun/userscripts
  6. // @version 1.0.23
  7. // @description Automatically downloads albums from KHInsider without an account.
  8. // @description:de Lädt Alben von KHInsider automatisch und ohne Account herunter.
  9. // @description:en Automatically downloads albums from KHInsider without an account.
  10. // @compatible chrome
  11. // @compatible edge
  12. // @compatible firefox
  13. // @compatible opera
  14. // @compatible safari
  15. // @homepageURL https://forgejo.sny.sh/sun/userscripts
  16. // @supportURL https://forgejo.sny.sh/sun/userscripts/issues
  17. // @contributionURL https://liberapay.com/sun
  18. // @contributionAmount €1.00
  19. // @author Sunny <sunny@sny.sh>
  20. // @include https://downloads.khinsider.com/game-soundtracks/album/*
  21. // @match https://downloads.khinsider.com/game-soundtracks/album/*
  22. // @connect vgmdownloads.com
  23. // @connect vgmsite.com
  24. // @connect vgmtreasurechest.com
  25. // @run-at document-end
  26. // @inject-into page
  27. // @grant GM.xmlHttpRequest
  28. // @grant GM_xmlhttpRequest
  29. // @noframes
  30. // @require https://unpkg.com/@zip.js/zip.js/dist/zip.js
  31. // @require https://unpkg.com/file-saver
  32. // @require https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
  33. // @icon https://forgejo.sny.sh/sun/userscripts/raw/branch/main/icons/VGMLoaderX.ico
  34. // @copyright 2021-present, Sunny (https://sny.sh/)
  35. // @license For Good Eyes Only; https://forgejo.sny.sh/sun/userscripts/src/branch/main/LICENSE.md
  36. // ==/UserScript==
  37.  
  38. (function () {
  39. "use strict";
  40.  
  41. document.querySelectorAll('a[href^="/cp/add_album/"]').forEach((x) => {
  42. x.addEventListener("click", (e) => {
  43. e.preventDefault();
  44.  
  45. let format = Array(
  46. ...document.querySelectorAll("#songlist_header th[align=right]"),
  47. ).map((x) => x.textContent);
  48. if (format.length === 1) {
  49. format = format[0];
  50. } else {
  51. const input = prompt(
  52. "Please enter your desired format (one of " +
  53. format.join(", ") +
  54. "):",
  55. format[0],
  56. );
  57.  
  58. if (!input) return;
  59. if (!format.includes(input.toUpperCase())) {
  60. format = format[0];
  61. alert("Invalid format supplied. Using " + format + " instead.");
  62. } else {
  63. format = input;
  64. }
  65. }
  66.  
  67. const element = document.getElementsByClassName("albumMassDownload")[0];
  68. element.style.height = "auto";
  69. element.style.marginBottom = "2em";
  70.  
  71. const input = eval(
  72. document
  73. .querySelector("#pageContent script")
  74. .textContent.slice(5, -3)
  75. .replace("function", "function x")
  76. .replace("return p}", "return p}x"),
  77. );
  78.  
  79. const mediaPath = input.match(/mediaPath='(.+?)'/)[1];
  80. const tracks = JSON.parse(
  81. input.match(/tracks=(\[.+?,\])/)[1].replace(",]", "]"),
  82. );
  83. const output = tracks.map(
  84. (x) =>
  85. mediaPath +
  86. x.file.split(".").slice(0, -1).join(".") +
  87. "." +
  88. format.toLowerCase(),
  89. );
  90. const names = tracks.map((x) => x.name);
  91.  
  92. const blobWriter = new zip.BlobWriter("application/zip");
  93. const writer = new zip.ZipWriter(blobWriter);
  94.  
  95. function forSync(i) {
  96. element.innerHTML =
  97. "Downloading track " +
  98. (i + 1) +
  99. " of " +
  100. output.length +
  101. " (" +
  102. (names[i] || "Track " + (i + 1)) +
  103. ")…";
  104. GM.xmlHttpRequest({
  105. method: "GET",
  106. url: output[i],
  107. responseType: "blob",
  108. onload: async (response) => {
  109. await writer.add(
  110. decodeURIComponent(output[i].split("/").pop()),
  111. new zip.BlobReader(response.response),
  112. );
  113.  
  114. if (output[i + 1]) {
  115. forSync(i + 1);
  116. } else {
  117. await writer.close();
  118. const blob = await blobWriter.getData();
  119. saveAs(
  120. blob,
  121. document.getElementsByTagName("h2")[0].textContent + ".zip",
  122. );
  123. element.innerHTML =
  124. "Album successfully downloaded. ZIP file has been passed to the browser.";
  125. }
  126. },
  127. });
  128. }
  129. forSync(0);
  130. });
  131. });
  132. })();