VGMLoaderX

Automatically downloads albums from KHInsider without an account.

Fra 24.02.2024. Se den seneste versjonen.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name               VGMLoaderX
// @name:de            VGMLoaderX
// @name:en            VGMLoaderX
// @namespace          sun/userscripts
// @version            1.0.22
// @description        Automatically downloads albums from KHInsider without an account.
// @description:de     Lädt Alben von KHInsider automatisch und ohne Account herunter.
// @description:en     Automatically downloads albums from KHInsider without an account.
// @compatible         chrome
// @compatible         edge
// @compatible         firefox
// @compatible         opera
// @compatible         safari
// @homepageURL        https://forgejo.sny.sh/sun/userscripts
// @supportURL         https://forgejo.sny.sh/sun/userscripts/issues
// @contributionURL    https://liberapay.com/sun
// @contributionAmount €1.00
// @author             Sunny <[email protected]>
// @include            https://downloads.khinsider.com/game-soundtracks/album/*
// @match              https://downloads.khinsider.com/game-soundtracks/album/*
// @connect            vgmdownloads.com
// @connect            vgmsite.com
// @run-at             document-end
// @inject-into        page
// @grant              GM.xmlHttpRequest
// @grant              GM_xmlhttpRequest
// @noframes
// @require            https://unpkg.com/@zip.js/zip.js/dist/zip.js
// @require            https://unpkg.com/file-saver
// @require            https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js
// @icon               https://forgejo.sny.sh/sun/userscripts/raw/branch/main/icons/VGMLoaderX.ico
// @copyright          2021-present, Sunny (https://sny.sh/)
// @license            For Good Eyes Only; https://forgejo.sny.sh/sun/userscripts/src/branch/main/LICENSE.md
// ==/UserScript==

(function () {
  "use strict";

  document.querySelectorAll('a[href^="/cp/add_album/"]').forEach((x) => {
    x.addEventListener("click", (e) => {
      e.preventDefault();

      let format = Array(
        ...document.querySelectorAll("#songlist_header th[align=right]"),
      ).map((x) => x.textContent);
      if (format.length === 1) {
        format = format[0];
      } else {
        const input = prompt(
          "Please enter your desired format (one of " +
            format.join(", ") +
            "):",
          format[0],
        );

        if (!input) return;
        if (!format.includes(input.toUpperCase())) {
          format = format[0];
          alert("Invalid format supplied. Using " + format + " instead.");
        } else {
          format = input;
        }
      }

      const element = document.getElementsByClassName("albumMassDownload")[0];
      element.style.height = "auto";
      element.style.marginBottom = "2em";

      const input = eval(
        document
          .querySelector("#pageContent script")
          .textContent.slice(5, -3)
          .replace("function", "function x")
          .replace("return p}", "return p}x"),
      );

      const mediaPath = input.match(/mediaPath='(.+?)'/)[1];
      const tracks = JSON.parse(
        input.match(/tracks=(\[.+?,\])/)[1].replace(",]", "]"),
      );
      const output = tracks.map(
        (x) =>
          mediaPath +
          x.file.split(".").slice(0, -1).join(".") +
          "." +
          format.toLowerCase(),
      );
      const names = tracks.map((x) => x.name);

      const blobWriter = new zip.BlobWriter("application/zip");
      const writer = new zip.ZipWriter(blobWriter);

      function forSync(i) {
        element.innerHTML =
          "Downloading track " +
          (i + 1) +
          " of " +
          output.length +
          " (" +
          (names[i] || "Track " + (i + 1)) +
          ")…";
        GM.xmlHttpRequest({
          method: "GET",
          url: output[i],
          responseType: "blob",
          onload: async (response) => {
            await writer.add(
              decodeURIComponent(output[i].split("/").pop()),
              new zip.BlobReader(response.response),
            );

            if (output[i + 1]) {
              forSync(i + 1);
            } else {
              await writer.close();
              const blob = await blobWriter.getData();
              saveAs(
                blob,
                document.getElementsByTagName("h2")[0].textContent + ".zip",
              );
              element.innerHTML =
                "Album successfully downloaded. ZIP file has been passed to the browser.";
            }
          },
        });
      }
      forSync(0);
    });
  });
})();