Greasy Fork

Greasy Fork is available in English.

Zibzab's GameDox/Rom Upload Helper

try to take over the world :)

当前为 2022-09-03 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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();
  }
})();