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