您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
A GGn user script to help with No-Intro uploads/trumps
当前为
// ==UserScript== // @name GGn No-Intro Helper // @description A GGn user script to help with No-Intro uploads/trumps // @namespace http://tampermonkey.net/ // @version 2.3.1 // @author BestGrapeLeaves // @license MIT // @match *://gazellegames.net/upload.php?groupid=* // @match *://gazellegames.net/torrents.php?id=* // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_listValues // @grant GM_deleteValue // @grant GM_setValue // @grant GM_getValue // @connect datomatic.no-intro.org // @icon https://i.imgur.com/UFOk0Iu.png // ==/UserScript== /******/ (() => { // webpackBootstrap /******/ "use strict"; var __webpack_exports__ = {}; ;// CONCATENATED MODULE: ./src/inserts/checkForTrumpsButton.ts function checkForTrumpsButton() { const existing = $("#check-for-no-intro-trumps-button"); const button = existing.length > 0 ? existing : $(`<input id="check-for-no-intro-trumps-button" type="button" value="Check for No-Intro Trumps" style="background: hotpink; color: black; font-weight: bold; margin-left: 10px;"/>`); const progress = (text)=>{ button.val(text); }; const disable = ()=>{ button.prop("disabled", true); button.css("background-color", "pink"); button.css("color", "darkslategray"); button.css("box-shadow", "none"); }; const insert = ()=>{ button.detach(); $(".torrent_table > tbody > tr:first-child > td:first-child").first().append(button); }; return { disable, progress, insert, button }; } ;// CONCATENATED MODULE: ./src/utils/dom/extractNoIntroLinkFromDescription.ts function extractNoIntroLinkFromDescription(torrentId) { const links = $(`#torrent_${torrentId} #description a`); return links.map(function() { return $(this).attr("href"); }).get().map((link)=>{ const url = new URL(link); url.protocol = "https:"; // Rarely descriptions have the http protocol return url.toString(); }).find((link)=>link.startsWith("https://datomatic.no-intro.org/")); } ;// CONCATENATED MODULE: ./src/utils/dom/getNoIntroTorrentsOnPage.ts function notFalse(x) { return x !== false; } function getNoIntroTorrentsOnPage() { return $('a[title="Permalink"]').map(function() { const torrentId = new URLSearchParams($(this).attr("href").replace("torrents.php", "")).get("torrentid"); const noIntroLink = extractNoIntroLinkFromDescription(torrentId); if (!noIntroLink) { return false; } const reported = $(this).parent().parent().find(".reported_label").text() === "Reported"; return { torrentId, a: $(this), noIntroLink, reported, permalink: window.location.origin + "/" + $(this).attr("href") }; }).get().filter(notFalse); } ;// CONCATENATED MODULE: ./src/inserts/insertAddCopyHelpers.ts function insertAddCopyHelpers() { getNoIntroTorrentsOnPage().forEach((param)=>{ let { torrentId , a , noIntroLink } = param; // Extract edition information const editionInfo = a.parents(".group_torrent").parent().prev().find(".group_torrent > td > strong").text(); const [editionYear, ...rest] = editionInfo.split(" - "); const editionName = rest.join(" - "); const formatedEditionInfo = `${editionName} (${editionYear})`; // GroupId const groupId = new URLSearchParams(window.location.search).get("id"); // Create params const params = new URLSearchParams(); params.set("groupid", groupId); params.set("edition", formatedEditionInfo); params.set("no-intro", noIntroLink); // Insert button const addCopyButton = $(`<a href="upload.php?${params.toString()}" title="Add Copy" id="ac_${torrentId}">AC</a>`); $([ " | ", addCopyButton ]).insertAfter(a); }); } ;// CONCATENATED MODULE: ./src/constants.ts // REGEXES const PARENS_TAGS_REGEX = /\(.*?\)/g; const NO_INTRO_TAGS_REGEX = /\((Unl|Proto|Sample|Aftermarket|Homebrew)\)|\(Rev \d+\)|\(v[\d\.]+\)|\(Beta(?: \d+)?\)/; // LISTS const GGN_REGIONS = [ "USA", "Europe", "Japan", "Asia", "Australia", "France", "Germany", "Spain", "Italy", "UK", "Netherlands", "Sweden", "Russia", "China", "Korea", "Hong Kong", "Taiwan", "Brazil", "Canada", "Japan, USA", "Japan, Europe", "USA, Europe", "Europe, Australia", "Japan, Asia", "UK, Australia", "World", "Region-Free", "Other", ]; // TABLES const REGION_TO_LANGUAGE = { USA: "English", Europe: "English", Japan: "Japanese", World: "English", "USA, Europe": "English", Other: "English", Korea: "Korean", Taiwan: "Chinese" }; const TWO_LETTER_REGION_CODE_TO_NAME = { en: "English", de: "German", fr: "French", cz: "Czech", zh: "Chinese", it: "Italian", ja: "Japanese", ko: "Korean", pl: "Polish", pt: "Portuguese", ru: "Russian", es: "Spanish" }; ;// CONCATENATED MODULE: ./src/utils/GMCache.ts class GMCache { getKeyName(key) { return `cache${this.name}.${key}`; } get(key) { const res = GM_getValue(this.getKeyName(key)); if (res === undefined) { return undefined; } const { value , expires } = res; if (expires && expires < Date.now()) { this.delete(key); return undefined; } return value; } set(key, value, ttl) { const expires = Date.now() + ttl; GM_setValue(this.getKeyName(key), { value, expires }); } delete(key) { GM_deleteValue(this.getKeyName(key)); } cleanUp() { const keys = GM_listValues(); keys.forEach((key)=>{ if (key.startsWith(this.getKeyName(""))) { const { expires } = GM_getValue(key); if (expires < Date.now()) { GM_deleteValue(key); } } }); } clear() { const keys = GM_listValues(); keys.forEach((key)=>{ if (key.startsWith(this.getKeyName(""))) { GM_deleteValue(key); } }); } constructor(name){ this.name = name; } } ;// CONCATENATED MODULE: ./src/utils/noIntroToGGnLanguage.ts function noIntroToGGnLanguage(region, possiblyLanguages) { if (possiblyLanguages === undefined) { // @ts-expect-error return REGION_TO_LANGUAGE[region] || "Other"; } const twoLetterCodes = possiblyLanguages.split(",").map((l)=>l.trim().toLowerCase()); const isLanguages = twoLetterCodes.every((l)=>l.length === 2); if (!isLanguages || twoLetterCodes.length === 0) { // @ts-expect-error return REGION_TO_LANGUAGE[region] || "Other"; } if (twoLetterCodes.length > 1) { return "Multi-Language"; } return TWO_LETTER_REGION_CODE_TO_NAME[twoLetterCodes[0]] || "Other"; } ;// CONCATENATED MODULE: ./src/utils/fetchNoIntro.ts const cache = new GMCache("no-intro"); // @ts-expect-error unsafeWindow.GGN_NO_INTRO_HELPER_CACHE = cache; function fetchNoIntro(url) { return new Promise((resolve, reject)=>{ if (url.endsWith("n=")) { return reject(new Error("Blacklist no-intro url. Fetch was aborted to prevent IP ban.")); } const cached = cache.get(url); if (cached) { resolve({ ...cached, cached: true }); return; } GM_xmlhttpRequest({ method: "GET", url, timeout: 5000, onload: (param)=>{ let { responseText } = param; 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)"); if (!dumpsTitle) { // @ts-expect-error unsafeWindow.GMPARSER = scraped; console.error("GGn No-Intro Helper: dumps title not found, set parser as global: GMPARSER", responseText); throw new Error("No dump's title found"); } 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(); // Region/Lang const [region, possiblyLanguages] = title.match(/\(.+?\)/g).map((p)=>p.slice(1, -1)); const matchedGGnRegion = GGN_REGIONS.find((r)=>r === region) || "Other"; const matchedGGnLanguage = noIntroToGGnLanguage(matchedGGnRegion, possiblyLanguages); // One hour seems appropriate const extension = filename.split(".").pop() || ""; const info = { // We stopped shipping entire filenames // when zibzab reported that it varies from dump to dump // like some can have a "bad" filename // title is 100% accurate, and filename shouldn't vary extension, title, filename: title + "." + extension, language: matchedGGnLanguage, region: matchedGGnRegion, cached: false }; cache.set(url, info, 1000 * 60 * 60); resolve(info); } catch (err) { console.error("zibzab helper failed to parse no-intro:", err); reject(new Error("Failed to parse no-intro :/\nPlease report to BestGrapeLeaves,\nincluding the error that was logged to the browser console")); } }, ontimeout: ()=>{ reject(new Error("Request to No-Intro timed out after 5 seconds")); } }); }); } ;// CONCATENATED MODULE: ./src/utils/dom/fetchTorrentFilelist.ts // We are fetching files for checking, // might as well reduce load on servers and save to dom (like the button does) function fetchTorrentFilelist(torrentId) { const parseFromDom = ()=>$(`#files_${torrentId} > table > tbody > tr:not(.colhead_dark) > td:first-child`).map(function() { return $(this).text(); }).get(); return new Promise((resolve)=>{ // @ts-expect-error if ($("#files_" + torrentId).raw().innerHTML === "") { // $('#files_' + torrentId).gshow().raw().innerHTML = '<h4>Loading...</h4>'; ajax.get("torrents.php?action=torrentfilelist&torrentid=" + torrentId, function(response) { // @ts-expect-error $("#files_" + torrentId).ghide(); // @ts-expect-error $("#files_" + torrentId).raw().innerHTML = response; resolve(parseFromDom()); }); } else { resolve(parseFromDom()); } }); } ;// CONCATENATED MODULE: ./src/utils/dom/checkIfTrumpable.ts async function checkIfTrumpable(torrent) { try { const { title , cached } = await fetchNoIntro(torrent.noIntroLink); const desiredFilename = title + ".zip"; const files = await fetchTorrentFilelist(torrent.torrentId); if (files.length !== 1) { return { trumpable: true, desiredFilename, cached, inditermint: "Couldn't determine if the torrent is trumpable -\nMultiple/No zip files found in torrent" }; } const actualFilename = files[0]; return { trumpable: desiredFilename !== actualFilename, desiredFilename, actualFilename, cached }; } catch (err) { console.error("GGn No-Intro Helper: Error checking trumpability", err); return { trumpable: true, cached: false, inditermint: "Couldn't determine if the torrent is trumpable -\nFailed fetching No-Intro:\n" + err.message }; } } ;// CONCATENATED MODULE: ./src/inserts/smallPre.ts function smallPre(text, bgColor) { return `<pre style=" padding: 0px; margin: 0; background-color: ${bgColor}; color: black; font-weight: bold; font-size: 12px; padding-left: 3px; padding-right: 3px; width: fit-content; ">${text}</pre>`; } ;// CONCATENATED MODULE: ./src/inserts/insertTrumpNotice.ts function inditermintNoticeInfo(param) { let { inditermint } = param; return { title: "Couldn't determine if the torrent is trumpable:", details: inditermint, color: "pink" }; } function reportedNoticeInfo(param) { let { inditermint } = param; return { title: "Torrent was trumped and reported!", details: "", color: "var(--darkRed)" }; } function trumpableNoticeInfo(param) { let { actualFilename , desiredFilename } = param; return { title: "This torrent is trumpable!", details: `The filename in the torrent is: ${smallPre(actualFilename, "lightcoral")} but the desired filename, based on <i>No-Intro</i> is: ${smallPre(desiredFilename, "lightgreen")}`, color: "hotpink" }; } function reportableNoticeInfo(param) { let { fixedVersion , torrentId , actualFilename , desiredFilename , noIntroLink } = param; const form = $("<div/></div>"); const trumpingTorrentInput = $(`<input type="text" value="${fixedVersion.permalink}" placeholder="https://gazellegames.net/torrents.php?id=xxxxx&torrentid=yyyyyy" style="width: 75%; background: #ffb952; color: black;"/>`); const commentTextarea = $(`<textarea placeholder="Previous upload didn't like hummus" style="height: 100px; width: 90%; background: #ffb952; color: black; margin: 0;"/>`); commentTextarea.text(`ROM name changed on No-Intro. Reported filename : ${actualFilename} Trumping filename : ${desiredFilename} No-Intro for reference : ${noIntroLink}`); const submitInputButton = $(`<input id="no-intro-helper-submit-trump-report-${torrentId}" type="button" value="REPORT" style="width: 70px; margin: 0; background: #ffb952; color: black; font-weight: bolder;"/>`); const errorMessage = $("<div style='color: red; font-weight: bold; font-size: 13px; white-space: pre-line;'></div>").hide(); form.append(`<p style="font-size: 12px;">Trumping Torrent Permalink:</p>`, trumpingTorrentInput, `<p style="font-size: 12px;">Report Comment:</p>`, commentTextarea, `<p style="font-size: 12px;">Submit Report:</p>`, submitInputButton, errorMessage); submitInputButton.click(async ()=>{ // If it's disabled this should in theory not trigger, // but just in case jquery does some shenaningans // when you manually trigger a click event if (submitInputButton.prop("disabled") === true) { return; } errorMessage.hide(); submitInputButton.prop("disabled", true); const data = new FormData(); data.append("submit", "true"); data.append("torrentid", torrentId); data.append("categoryid", "1"); data.append("type", "trump"); data.append("sitelink", fixedVersion.permalink); data.append("extra", commentTextarea.val()); data.append("id_token", new Date().getTime().toString()); try { await fetch("/reportsv2.php?action=takereport", { method: "POST", body: data }); location.reload(); } catch (err) { console.error("Error submitting trump report", err); console.error("Form data sent:", Object.fromEntries([ ...data.entries() ])); errorMessage.text(`An error occurred while submitting the trump report. If you believe this is a problem with the script, please report to BestGrapeLeaves (including console logs if you can). Error Message: ${err.message}`); errorMessage.show(); submitInputButton.prop("disabled", false); } }); return { title: "Torrent needs to be reported for trump!", details: form, color: "#ff7600" }; } function insertTrumpNotice(torrent) { const { inditermint , fixedVersion , torrentId , reported } = torrent; // Settings let info; let type; if (inditermint) { type = "inditermint"; info = inditermintNoticeInfo(torrent); } else if (fixedVersion) { if (reported) { type = "reported"; info = reportedNoticeInfo(torrent); } else { type = "reportable"; info = reportableNoticeInfo(torrent); } } else { type = "trumpable"; info = trumpableNoticeInfo(torrent); } const { color , details , title } = info; // Elements const detailsDiv = $(`<div style="font-weight: normal; color: white;"></div>`).hide(); detailsDiv.append(details); const titleSpan = $(` <span style="color: ${color}; font-size: 14px; font-weight: bold;">${title}</span>`); const actionsDiv = $(`<div id="trump-notice-links-${torrentId}" style="font-weight: normal; font-size: 11px; display: inline; margin: 5px; user-select: none;"></div>`); // Toggle Details if (type !== "reported") { const toggleDetailsActionSpan = $(`<span style="cursor: pointer; margin-right: 5px;">[Expand]</span>`); toggleDetailsActionSpan.click(()=>{ const collapsed = toggleDetailsActionSpan.text() === "[Expand]"; if (collapsed) { toggleDetailsActionSpan.text("[Collapse]"); detailsDiv.show(); } else { toggleDetailsActionSpan.text("[Expand]"); detailsDiv.hide(); } }); actionsDiv.append(toggleDetailsActionSpan); } // Send Report if (type === "reportable") { const sendReportActionSpan = $(`<span style="cursor: pointer; margin-right: 5px;">[Send Report]</span>`); sendReportActionSpan.click(()=>{ $(`#no-intro-helper-submit-trump-report-${torrentId}`).click(); }); actionsDiv.append(sendReportActionSpan); } // Cheer if (type === "reported") { const cheerActionSpan = $(`<span style="cursor: pointer; margin-right: 5px; position: absolute;">[Cheer]</span>`); cheerActionSpan.click(()=>{ cheerActionSpan.text("HOORAY!"); cheerActionSpan.animate({ opacity: 0 }, // @ts-expect-error { duration: 2000, step: function(now) { cheerActionSpan.css({ transform: "rotate(" + now * 360 * 5 + "deg)" }); } }, "swing"); }); actionsDiv.append(cheerActionSpan); } // Tree const wrapper = $(`<div></div>`); titleSpan.append(actionsDiv); wrapper.append(titleSpan); wrapper.append(detailsDiv); // Place let currentlyAdaptedToSmallScreen; function placeTrumpNotice() { console.log("adapting", window.innerWidth); if (window.innerWidth <= 800) { if (currentlyAdaptedToSmallScreen) { return; } currentlyAdaptedToSmallScreen = true; $(`#torrent${torrentId}`).css("border-bottom", "none"); wrapper.css("margin-left", "25px"); wrapper.detach(); wrapper.insertAfter(`#torrent${torrentId}`); } else { if (currentlyAdaptedToSmallScreen === false) { return; } currentlyAdaptedToSmallScreen = false; $(`#torrent${torrentId}`).css("border-bottom", ""); wrapper.css("margin-left", "0px"); wrapper.detach(); wrapper.appendTo(`#torrent${torrentId} > td:first-child`); } } placeTrumpNotice(); $(window).resize(placeTrumpNotice); // Call global hook (for other scripts) // @ts-expect-error if (typeof unsafeWindow.GM_GGN_NOINTRO_HELPER_ADDED_LINKS === "function") { // @ts-expect-error unsafeWindow.GM_GGN_NOINTRO_HELPER_ADDED_LINKS({ ...torrent, links: actionsDiv }); } } ;// CONCATENATED MODULE: ./src/inserts/insertTrumpSuggestions.ts async function checkForImproperlyNamedTorrents(torrents) { const { disable , progress } = checkForTrumpsButton(); disable(); let prevCached = false; const results = []; for(let i = 0; i < torrents.length; i++){ const torrent = torrents[i]; progress(`Checking For Trumps ${i + 1}/${torrents.length}...`); // timeout to avoid rate limiting if (!prevCached) { await new Promise((resolve)=>setTimeout(resolve, 500)); } // Check trump const TrumpCheckResult = await checkIfTrumpable(torrent); const { cached } = TrumpCheckResult; prevCached = cached; results.push({ ...TrumpCheckResult, ...torrent }); } return results; } // Filter the torrents that have a trump uploaded function attachFixedVersionsToTorrents(torrents) { const trumpCanidates = []; const validTorrents = []; for (const torrent of torrents){ if (torrent.trumpable) { trumpCanidates.push(torrent); continue; } validTorrents.push(torrent); } // Efficiency is not my greatest of concerns, // if you want implement a graph theory solution in O(1) or something const processed = trumpCanidates.map((c)=>({ ...c, fixedVersion: validTorrents.find((v)=>!v.inditermint && v.noIntroLink === c.noIntroLink) })); return [ ...validTorrents, ...processed ]; } async function insertTrumpSuggestions(results) { const { progress } = checkForTrumpsButton(); let trumps = 0; results.forEach((torrent)=>{ if (!torrent.trumpable) { return; } if (!torrent.inditermint && !torrent.fixedVersion) { trumps++; } insertTrumpNotice(torrent); }); if (trumps === 0) { progress("No Trumps Found"); } else if (trumps === 1) { progress("1 Trump Found"); } else { progress(`${trumps} Trumps Found`); } } async function findAndDisplayTrumps() { const torrents = getNoIntroTorrentsOnPage(); const results = await checkForImproperlyNamedTorrents(torrents); const processed = attachFixedVersionsToTorrents(results); console.log("GGn No-Intro Helper: Trumps", processed); insertTrumpSuggestions(processed); } ;// CONCATENATED MODULE: ./src/pages/torrents.ts function trumpSuggestions() { const torrents = getNoIntroTorrentsOnPage(); if (torrents.length === 0) { return; } const { button , insert } = checkForTrumpsButton(); insert(); if (torrents.length <= 4) { findAndDisplayTrumps(); } button.click((e)=>{ e.stopImmediatePropagation(); findAndDisplayTrumps(); }); } function torrentsPageMain() { insertAddCopyHelpers(); trumpSuggestions(); } ;// CONCATENATED MODULE: ./src/inserts/uploadLinkParserUI.ts function uploadNoIntroLinkParserUI() { // elements const container = $(`<tr id="no-intro-url" name="no-intro-url"> <td class="label">No-Intro Link</td> </tr>`); const input = $('<input type="text" id="no-intro-url-input" name="no-intro-url-input" size="70%" class="input_tog" value="">'); const error = $('<p id="no-intro-url-error" name="no-intro-url-error" style="color: red; white-space:pre-line;"></p>').hide(); const loading = $('<p id="no-intro-url-loading" name="no-intro-url-loading" style="color: green;">Loading...</p>').hide(); // structure const td = $("<td></td>"); td.append(input); td.append(error); td.append(loading); container.append(td); // utils const setError = (msg)=>{ error.text(msg); error.show(); }; const setLoading = (isLoading)=>{ if (isLoading) { loading.show(); } else { loading.hide(); } }; return { loading, error, container, input, setError, setLoading }; } ;// CONCATENATED MODULE: ./src/utils/dom/setUploadEdition.ts function setUploadEdition(edition) { try { $("#groupremasters").val(edition).change(); GroupRemaster(); } catch { // group remaster always throws (regardless of the userscript) } } ;// CONCATENATED MODULE: ./src/utils/generateTorrentDescription.ts const generateTorrentDescription = function() { let url = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : "xxx", filename = arguments.length > 1 && arguments[1] !== void 0 ? arguments[1] : "xxx"; return `[align=center]${filename} matches [url=${url}]No-Intro checksum[/url] Compressed with [url=https://sourceforge.net/projects/trrntzip/]torrentzip.[/url][/align] `; }; ;// CONCATENATED MODULE: ./src/pages/upload.ts function linkParser() { // UI const { error , container , input , setError , setLoading } = uploadNoIntroLinkParserUI(); // watch link input let justChecked = ""; input.on("paste", (e)=>{ e.preventDefault(); const text = e.originalEvent.clipboardData.getData("text/plain"); input.val(text); submit(); }); input.change(submit); // React to release type change, and insert input $("select#miscellaneous").change(function() { const selected = $("select#miscellaneous option:selected").text(); if (selected === "ROM") { container.insertBefore("#regionrow"); $("textarea#release_desc").val(generateTorrentDescription()); /// xxx temporary } else { container.detach(); } }); // handle submit async function submit() { // Prechecks error.hide(); const url = input.val(); if (justChecked === url) { return; } if (!url.startsWith("https://datomatic.no-intro.org/")) { setError("Invalid URL"); return; } // Go justChecked = url; setLoading(true); try { const { filename , language , region } = await fetchNoIntro(url); $("textarea#release_desc").val(generateTorrentDescription(url, filename)); $("select#region").val(region); $("select#language").val(language); } catch (err) { setError(err.message || err || "An unexpected error has occurred"); } finally{ setLoading(false); } } } function magicNoIntroPress() { const filename = $("#file").val(); 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); // @ts-expect-error Update title updateReleaseTitle($("#title").raw().value + " " + tags); // Get url params const params = new URLSearchParams(window.location.search); // Set correct edition (fallback to guessing) const editionInfo = params.get("edition"); $("#groupremasters > option").each(function() { const title = $(this).text().toLowerCase(); console.log("checking", title); if (editionInfo && title === editionInfo.toLowerCase()) { setUploadEdition($(this).val()); return false; // This breaks out of the jquery loop } else { if (title.includes("no-intro") || title.includes("nointro")) { setUploadEdition($(this).val()); } } }); // Trigger no-intro link scraper const noIntroLink = params.get("no-intro"); if (noIntroLink) { $("#no-intro-url-input").val(noIntroLink).change(); } } function uploadPageMain() { // Insert No Intro magic button const noIntroMagicButton = $('<input type="button" value="No-Intro"></input>'); noIntroMagicButton.click(()=>magicNoIntroPress()); noIntroMagicButton.insertAfter("#file"); linkParser(); } ;// CONCATENATED MODULE: ./src/index.ts async function main() { console.log("GGn No-Intro Helper: Starting..."); if (window.location.pathname === "/torrents.php") { torrentsPageMain(); } else if (window.location.pathname === "/upload.php") { uploadPageMain(); } // Blacklist no-intro URLs that lead to ban $("a").click(function() { if (/https?:\/\/datomatic\.no-intro\.org\/index\.php\?page=show_record&s=(.*?)&n=$/i.test($(this).attr("href"))) { $(this).text("BLACKLISTED"); return false; } }); } main().catch((e)=>{ console.log(e); }); /******/ })() ;