Greasy Fork

Zibzab's GameDox/Rom Upload Helper

try to take over the world :)

目前为 2022-09-03 提交的版本。查看 最新版本

// ==UserScript==
// @name         Zibzab's GameDox/Rom Upload Helper
// @namespace    http://tampermonkey.net/
// @version      1.6
// @description  try to take over the world :)
// @author       BestGrapeLeaves
// @match        https://gazellegames.net/upload.php?groupid=*
// @match        https://gazellegames.net/torrents.php?id=*
// @icon         https://i.imgur.com/UFOk0Iu.png
// @grant        GM_xmlhttpRequest
// @connect      datomatic.no-intro.org
// @license      MIT
// ==/UserScript==

// Code is a spaghetti mess, don't read it. Do something else with your time.
(function () {
  "use strict";

  const PARENS_TAGS_REGEX = /\(.*?\)/g;
  const NO_INTRO_TAGS_REGEX =
    /\((Unl|Proto|Sample|Aftermarket|Homebrew)\)|\(Rev \d+\)|\(v[\d\.]+\)|\(Beta(?: \d+)?\)/;
  const GAME_DOX_INSERT = `[align=center] pdf pages
[/align]
`;
  const genRomInsert = (
    url = "xxx",
    filename = "xxx"
  ) => `[align=center]${filename} matches [url=${url}]No-Intro checksum[/url]
Compressed with [url=https://sourceforge.net/projects/trrntzip/]torrentzip.[/url][/align]
`;

  const regionToLanguage = {
    USA: "English",
    Europe: "English",
    Japan: "Japanese",
    World: "English",
    "USA, Europe": "English",
    Other: "English",
    Korea: "Korean",
    Taiwan: "Chinese",
  };

  const twoLetterLanguageCodeToGGn = {
    en: "English",
    de: "German",
    fr: "French",
    cz: "Czech",
    zh: "Chinese",
    it: "Italian",
    ja: "Japanese",
    ko: "Korean",
    pl: "Polish",
    pt: "Portuguese",
    ru: "Russian",
    es: "Spanish",
  };

  const parseLanguage = (region, possiblyLanguages) => {
    if (possiblyLanguages === undefined) {
      return regionToLanguage[region] || "Other";
    }

    const twoLetterCodes = possiblyLanguages
      .split(",")
      .map((l) => l.trim().toLowerCase());
    const isLanguages = twoLetterCodes.every((l) => l.length === 2);
    if (!isLanguages || twoLetterCodes.length === 0) {
      return regionToLanguage[region] || "Other";
    }

    if (twoLetterCodes.length > 1) {
      return "Multi-Language";
    }

    return twoLetterLanguageCodeToGGn[twoLetterCodes[0]] || "Other";
  };

  // Add Copy button, stolen boilerplate shamelessly from trump helper script
  function insertAddCopyHelpers() {
    $('a[title="Permalink"]').each(function () {
      const torrentId = $(this)
        .attr("href")
        .replace(/.*?\?torrentid=/, "");
      console.log("ac", torrentId);

      const links = $(`#torrent_${torrentId} #description a`);
      const noIntroLink = links
        .filter(function () {
          return $(this)
            .attr("href")
            .startsWith("https://datomatic.no-intro.org/");
        })
        .first()
        .attr("href");

      if (!noIntroLink) {
        return;
      }

      const editionInfo = $(this)
        .parents(".group_torrent")
        .parent()
        .prev()
        .find(".group_torrent > td > strong")
        .text();
      // Convert to upload format of edition info
      const [editionYear, ...rest] = editionInfo.split(" - ");
      const editionName = rest.join(" - ");
      const formatedEditionInfo = `${editionName} (${editionYear})`;

      const groupId = window.location.href.replace(/.*?\?id=/, "");
      const params = new URLSearchParams(url.search);
      params.set("groupid", groupId);
      params.set("edition", formatedEditionInfo);
      params.set("no-intro", noIntroLink);

      const addCopyButton = $(
        `<a href="upload.php?${params.toString()}" title="Add Copy" id="ac_${torrentId}">AC</a>`
      );
      $([" | ", addCopyButton]).insertAfter(this);
    });
  }

  // No Intro Button
  function makeNoIntro(filename) {
    const tags = filename
      ? filename
          .match(PARENS_TAGS_REGEX)
          .filter((p) => NO_INTRO_TAGS_REGEX.test(p))
          .join(" ")
      : "";

    // Release type = ROM
    $("select#miscellaneous").val("ROM").change();
    // It is a special edition
    if (!$("input#remaster").prop("checked")) {
      $("input#remaster").prop("checked", true);
      Remaster();
    }
    // Not a scene release
    $("#ripsrc_home").prop("checked", true);
    // Update title
    updateReleaseTitle($("#title").raw().value + " " + tags);

    // Get url params
    const params = new URLSearchParams(window.location.search);

    // Set correct edition (fallback to guessing)
    const setEdition = (edition) => {
      try {
        $("#groupremasters").val(edition).change();
        GroupRemaster();
      } catch {
        // group remaster always throws (regardless of the userscript)
      }
    };
    const editionInfo = params.get("edition");
    $("#groupremasters > option").each(function () {
      const title = $(this).text().toLowerCase();
      console.log("checking", title);
      if (title === editionInfo.toLowerCase()) {
        setEdition($(this).val());
        return false; // This breaks out of the jquery loop
      } else {
        if (title.includes("no-intro") || title.includes("nointro")) {
          setEdition($(this).val());
        }
      }
    });

    // Trigger no-intro link scraper
    const noIntroLink = params.get("no-intro");
    if (noIntroLink) {
      $("#no-intro-url-input").val(noIntroLink).change();
    }
  }

  function noIntroUI() {
    // elements
    const noIntroContainer = $(
      `<tr id="no-intro-url" name="no-intro-url">
      <td class="label">No-Intro Link</td>
    </tr>`
    );
    const noIntroInput = $(
      '<input type="text" id="no-intro-url-input" name="no-intro-url-input" size="70%" class="input_tog" value="">'
    );
    const noIntroError = $(
      '<p id="no-intro-url-error" name="no-intro-url-error" style="color: red; white-space:pre-line;"></p>'
    ).hide();
    const noIntroLoading = $(
      '<p id="no-intro-url-loading" name="no-intro-url-loading" style="color: green;">Loading...</p>'
    ).hide();
    // structure
    const td = $("<td></td>");
    td.append(noIntroInput);
    td.append(noIntroError);
    td.append(noIntroLoading);
    noIntroContainer.append(td);
    // utils
    const error = (msg) => {
      noIntroError.text(msg);
      noIntroError.show();
    };
    const loading = (isLoading) => {
      if (isLoading) {
        noIntroLoading.show();
      } else {
        noIntroLoading.hide();
      }
    };
    return { loading, error, noIntroContainer, noIntroInput, noIntroError };
  }

  function torrentViewPage() {
    insertAddCopyHelpers();
  }

  function uploadPage() {
    // Insert No Intro button
    const nointro = $('<input type="button" value="No-Intro"></input>');
    nointro.click(() => makeNoIntro($("#file").val()));
    nointro.insertAfter("#file");

    // Link parser UI
    const { noIntroContainer, noIntroInput, noIntroError, error, loading } =
      noIntroUI();

    function submitNoInput() {
      noIntroError.hide();
      const url = noIntroInput.val();

      if (justChecked === url) {
        return;
      }

      if (!url.startsWith("https://datomatic.no-intro.org/")) {
        error("Invalid URL");
        return;
      }

      justChecked = url;
      loading(true);
      GM_xmlhttpRequest({
        method: "GET",
        url,
        timeout: 5000,
        onload: ({ responseText }) => {
          try {
            const parser = new DOMParser();
            const scraped = parser.parseFromString(responseText, "text/html");

            // HTML is great
            const dumpsTitle = [
              ...scraped.querySelectorAll("td.TableTitle"),
            ].find((td) => td.innerText.trim() === "Dump(s)");
            const filename =
              dumpsTitle.parentElement.parentElement.parentElement.nextElementSibling
                .querySelector(
                  "table > tbody > tr:nth-child(2) > td:last-child"
                )
                .innerText.trim();
            const title = scraped
              .querySelector("tr.romname_section > td")
              .innerText.trim();
            const parenMatches = title
              .match(/\(.+?\)/g)
              .map((p) => p.slice(1, -1));
            const [region, possiblyLanguages] = parenMatches;
            const matchedGGnRegion =
              php_torrent_form_regions.find((r) => r === region) || "Other";
            const matchedGGnLanguage = parseLanguage(
              matchedGGnRegion,
              possiblyLanguages
            );
            $("textarea#release_desc").val(genRomInsert(url, filename));
            $("select#region").val(matchedGGnRegion);
            $("select#language").val(matchedGGnLanguage);
            loading(false);
          } catch (err) {
            loading(false);
            error(
              "Failed to parse no-intro :/\nPlease report to BestGrapeLeaves,\nthe error was logged to the browser console"
            );
            console.error("zibzab helper failed to parse no-intro:", err);
          }
        },
        ontimeout: () => {
          loading(false);
          error("Request to no-intro timed out after 5 seconds");
        },
      });
    }
    // watch link input
    let justChecked = "";
    noIntroInput.on("paste", (e) => {
      e.preventDefault();
      const text = e.originalEvent.clipboardData.getData("text/plain");
      noIntroInput.val(text);
      submitNoInput();
    });
    noIntroInput.change(submitNoInput);
    // React to release type change
    $("select#miscellaneous").change(function () {
      const selected = $("select#miscellaneous option:selected").text();
      if (selected === "GameDOX") {
        noIntroContainer.detach();
        $("input#release_title").val(
          $("input#release_title").val() + " - Manual"
        );
        $("select#gamedox").val("Guide").change();
        $("select#format").val("PDF").change();
        $("input#scan").click();
        Scan();
        $("textarea#release_desc").val(
          $("textarea#release_desc").val() + GAME_DOX_INSERT
        );
      } else if (selected === "ROM") {
        noIntroContainer.insertBefore("#regionrow");
        $("textarea#release_desc").val(genRomInsert());
      } else {
        noIntroContainer.detach();
      }
    });
  }

  if (window.location.pathname === "/torrents.php") {
    torrentViewPage();
  } else if (window.location.pathname === "/upload.php") {
    uploadPage();
  }
})();