// ==UserScript==
// @name Retro Enhanced
// @namespace https://github.com/miagui
// @version 1.4.3
// @description Additional functionality for retro gaming related sites.
// @author Miagui
// @match *://retroachievements.org/*
// @license MIT
// @updateURL https://openuserjs.org/meta/Miagui/Retro_Enhanced.meta.js
// @downloadURL https://openuserjs.org/install/Miagui/Retro_Enhanced.user.js
// @grant GM_xmlhttpRequest
// @grant GM_log
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_listValues
// @grant GM_deleteValue
// @connect archive.org
// @connect the-eye.eu
// @connect raw.githubusercontent.com
// @connect sheets.googleapis.com
// @connect emuparadise.meg
// @connect speedrun.com
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js
// ==/UserScript==
(async function () {
var pageWithParams = (location.pathname + location.search).substr(1);
var page = location.pathname;
var loggedUser = $(".brand-top strong > a").text();
var sectionName = window.location.hash.slice(1);
// Configs
var enableSpeedrun = await GM_getValue("enableSpeedrun", false);
var enableRomSearch = await GM_getValue("enableRomSearch", true);
var enableCustomBG = await GM_getValue("enableCustomBG", true);
var enableGameplayVideo = await GM_getValue("enableGameplayVideo", true);
var enableEmuparadise = await GM_getValue("enableEmuparadise", false);
var prioritizeEmuparadise = await GM_getValue("prioritizeEmuparadise", false);
var enableGlassEffect = await await GM_getValue("enableGlassEffect", true);
var RAConsole = {
ARCADE: "Arcade",
SNES: "SNES/Super Famicom",
NES: "NES/Famicom",
GAMEBOY: "Game Boy",
GBC: "Game Boy Color",
GBA: "Game Boy Advance",
N64: "Nintendo 64",
GCN: "GameCube",
NDS: "Nintendo DS",
A2600: "Atari 2600",
A7800: "Atari 7800",
PCENGINE: "PC Engine/TurboGrafx-16",
PCENGINECD: "PC Engine CD/TurboGrafx-CD",
MASTERSYSTEM: "Master System",
GG: "Game Gear",
GENESIS: "Mega Drive",
SEGA32X: "32X",
SEGACD: "Sega CD",
SATURN: "Saturn",
DREAMCAST: "Dreamcast",
PS1: "PlayStation",
PS2: "PlayStation 2",
PSP: "PlayStation Portable",
PANASONIC3DO: "3DO Interactive Multiplayer",
NEOGEOCD: "Neo Geo CD",
NEOPOCKET: "Neo Geo Pocket",
POKEMINI: "Pokemon Mini",
VIRTUALBOY: "Virtual Boy",
SG1000: "SG-1000",
COLECO: "ColecoVision",
MSX: "MSX",
WONDERSWAN: "WonderSwan",
VECTREX: "Vectrex",
NEC8800: "PC-8000/8800",
APPLEII: "Apple II"
};
var SRConsole = {
PC: "8gej2n93",
APPLEII: "w89ryw6l",
ATARI2600: "o0644863",
ARCADE: "vm9vn63k",
NEC8800: "7g6mw8er",
COLECOVISION: "wxeo8d6r",
COMMODORE64: "gz9qox60",
MSX: "jm950z6o",
NES: "jm95z9ol",
MSX2: "83exkk6l",
MASTERSYSTEM: "83exwk6l",
ATARI7800: "gde33gek",
FAMICOMDISKSYSTEM: "mr6k409z",
PCENGINE: "5negxk6y",
GENESIS: "mr6k0ezw",
GAMEBOY: "n5683oev",
NEOGEOAES: "mx6p4w63",
GG: "w89r3w9l",
SNES: "83exk6l5",
PHILIPSCDI: "w89rjw6l",
SEGACD: "31670d9q",
PANASONIC3D0: "8gejmne3",
NEOGEOCD: "kz9w7mep",
PCFX: "p36n8568",
PS1: "wxeod9rn",
SEGA32X: "kz9wrn6p",
SEGASATURN: "lq60l642",
VIRTUALBOY: "7g6mk8er",
N64: "w89rwelk",
GAMEBOYCOLOR: "gde3g9k1",
NEOGEOPOCKETCOLOR: "7m6ydw6p",
TURBOGRAFX16CD: "p36nlxe8",
DREAMCAST: "v06d394z",
WONDERSWAN: "vm9v8n63",
PLAYSTATION2: "n5e17e27",
WONDERSWANCOLOUR: "n568kz6v",
GAMEBOYADVANCE: "3167d6q2",
GAMECUBE: "4p9z06rn",
POKÉMONMINI: "vm9vr1e3",
NDS: "7g6m8erk",
PLAYSTATIONPORTABLE: "5negk9y7",
WII: "v06dk3e4"
}
// GM_log(enableSpeedrun)
// GM_log(enableRomSearch)
// GM_log(enableCustomBG)
// GM_log(page)
// GM_log(sectionName)
if (page == "/controlpanel.php") {
$("article > .detaillist > .component:eq(1)").after("<div id='enhanced-settings' class='component'></div>")
let settingsDiv = $("#enhanced-settings");
settingsDiv.append("<h3>Retro Enhanced</h3>")
settingsDiv.append(`<table>
<tbody>
<tr>
<td>Enable ROMs search:</td>
<td><input id="enhanced-romsearch" type="checkbox" ${enableRomSearch ? "checked='checked'" : ""}></td>
</tr>
<tr>
<td>Add Emuparadise to ROMs search: <div style="font-size: 0.8em;">(For Chrome users: <a href="https://experienceleague.adobe.com/docs/target/using/experiences/vec/troubleshoot-composer/mixed-content.html?lang=en#task_FF297A08F66E47A588C14FD67C037B3A">enable this</a>; For all browsers: must click on "Add Exception and Get my File!" for the first time)</div></td>
<td><input id="enhanced-epromsearch" type="checkbox" ${enableEmuparadise ? "checked='checked'" : ""}></td>
</tr>
<tr>
<td>Prioritize Emuparadise for ROMs search (must have "Add Emuparadise to ROMs search" enabled):</td>
<td><input id="enhanced-prioritize_ep" type="checkbox" ${prioritizeEmuparadise ? "checked='checked'" : ""}></td>
</tr>
<tr>
<td>Enable Speedrun.com stats:</td>
<td><input id="enhanced-speedrun" type="checkbox" ${enableSpeedrun ? "checked='checked'" : ""}></td>
</tr>
<tr>
<td>Enable gameplay video on the game page:</td>
<td><input id="enhanced-gameplayvideo" type="checkbox" ${enableGameplayVideo ? "checked='checked'" : ""}></td>
</tr>
<tr>
<td>Enable custom game page background:</td>
<td><input id="enhanced-custombg" type="checkbox" ${enableCustomBG ? "checked='checked'" : ""}></td>
</tr>
<tr>
<td>Enable glass background effect:</td>
<td><input id="enhanced-glassEffect" type="checkbox" ${enableGlassEffect ? "checked='checked'" : ""}></td>
</tr>
</tbody>
</table>`)
$(document).on('change', '#enhanced-romsearch', function () {
GM_setValue("enableRomSearch", $("#enhanced-romsearch").is(":checked"))
})
$(document).on('change', '#enhanced-epromsearch', function () {
GM_setValue("enableEmuparadise", $("#enhanced-epromsearch").is(":checked"))
})
$(document).on('change', '#enhanced-prioritize_ep', function () {
GM_setValue("prioritizeEmuparadise", $("#enhanced-prioritize_ep").is(":checked"))
})
$(document).on('change', '#enhanced-speedrun', function () {
GM_setValue("enableSpeedrun", $("#enhanced-speedrun").is(":checked"))
})
$(document).on('change', '#enhanced-custombg', function () {
GM_setValue("enableCustomBG", $("#enhanced-custombg").is(":checked"))
})
$(document).on('change', '#enhanced-gameplayvideo', function () {
GM_setValue("enableGameplayVideo", $("#enhanced-gameplayvideo").is(":checked"))
})
$(document).on('change', '#enhanced-glassEffect', function () {
GM_setValue("enableGlassEffect", $("#enhanced-glassEffect").is(":checked"))
})
}
// =========================================
// Game Set Page
// =========================================
// Regex: game/13918
else if (page.match(/game\/[0-9]/g) != null ||
page == "/gameInfo.php") {
// General
var console = $(".navpath").children().eq(1).text(); //
var game = $(".navpath").children().eq(2).text(); //
var gameId = /([^\/]+)\/?$/g.exec($("meta[property='og:url']").attr("content"))[0]; //
var points = $("#achievement .TrueRatio").eq(0).prev().text();
var icon = $("#achievement div:eq(2) > img").attr("src")
var tag = "";
var gameImg = $("#achievement img[alt=\"In-game screenshot\"]").attr("src");
var rgxTag = /\~(.*?)\~/g;
// GM_log("Icon:" + icon)
// Check for tags
if (game.match(rgxTag) != undefined) {
tag = rgxTag.exec(game)[1];
game = game.replace(game.match(rgxTag) + " ", "");
}
// GM_log(gameId)
var isAvailable = false;
var collection = {
name: "",
url: ""
};
var results = [];
var resultsDlcs = [];
// Speedrun.com API resources
var srRoot = "https://www.speedrun.com/api/v1/";
var srLogo = "";
var srVideoUrl = "";
var srGamelink = "";
var srGameId = "";
var srRuns = [];
// GM_log(game)
// GM_log(console)
// Avoid unwanted exceptions for hubs pages.
if (console == "") return
// =========================================
// Divs Insertion
// =========================================
// Set custom background
if (gameImg != "https://media.retroachievements.org/Images/000002.png" && enableCustomBG) {
$("body").append(`<style>
body:before {
content: "";
position: fixed;
width : 110%;
height: 110%;
background: inherit;
background-size: cover;
z-index: -1;
overflow: hidden;
filter : blur(8px);
-moz-filter : blur(8px);
-webkit-filter: blur(8px);
-o-filter : blur(8px);
}
</style>`);
$("body").css({
"background-image": `url(${gameImg})`,
"background-attachment": "fixed",
"background-size": "90%",
"background-position": "center",
"background-repeat": "no-repeat"
})
}
// Change to glass background
if (enableGlassEffect) {
$(":root").attr("style", "--box-bg-color: rgba(35, 35, 35, 0.95);")
$("#leftcontainer").attr("style", "background: var(--box-bg-color);")
$("#rightcontainer").attr("style", "background: var(--box-bg-color);")
}
// Change top nav to body color
$(".brand-top").addClass("bg-body")
// Change header background to transparent
// $(".brand-top + nav").removeClass("bg-body")
// Prepare divs
$("aside > .gamealts").first().before("<div id='romsdl'></div>")
$("aside > .gamealts").first().before("<div id='speedruncom'></div>")
var divRoms = $("#romsdl");
var divSpeedruncom = $("#speedruncom");
divRoms.css("margin-top", "1em")
divSpeedruncom.css("margin", "1em 0em");
if (enableGameplayVideo || enableSpeedrun) getSpeedruns(game)
// =========================================
// Rom Search
// =========================================
if (enableRomSearch) {
// Verify if system is available
for (const prop in RAConsole) {
if (RAConsole.hasOwnProperty(prop)) {
const element = RAConsole[prop];
if (element == console) isAvailable = true;
}
}
if ((isAvailable && tag == "") || (console == RAConsole.ARCADE && tag != "")) {
var promise;
// Deprecated feature to find roms for hacks and homebrews.
// if (tag != "" && console != RAConsole.ARCADE) {
// promise = searchCustom();
// collection.name = "Custom";
// }
// Search through Emuparadise
if (enableEmuparadise && prioritizeEmuparadise) {
collection.name = "Emuparadise";
collection.url = "https://www.emuparadise.me/roms-isos-games.php"
promise = searchEmuparadise();
} else {
// resolve the promise so the function don't stop working
promise = Promise.resolve()
}
// Search through archives.org
promise.then(() => {
if (results.length == 0) {
if (console == RAConsole.NDS) {
collection.name = "No-Intro Nintendo DS Decrypted";
collection.url = "https://archive.org/download/noIntroNintendoDsDecrypted2019Jun30"
return searchArchive("https://archive.org/download/noIntroNintendoDsDecrypted2019Jun30");
} else if (console == RAConsole.PS1) {
collection.name = "[REDUMP] Disc Image Collection: Sony - Sony PlayStation";
collection.url = "https://archive.org/details/redump.psx"
return searchArchive("https://archive.org/download/redump.psx")
.then(() => {
if (results.length == 0) return searchArchive("https://archive.org/download/redump.psx.p2");
else return;
})
.then(() => {
if (results.length == 0) return searchArchive("https://archive.org/download/redump.psx.p3");
else return;
})
.then(() => {
if (results.length == 0) return searchArchive("https://archive.org/download/redump.psx.p4");
else return;
});
} else if (console == RAConsole.PS2) {
collection.name = "PS2 Redump USA CHD";
collection.url = "https://archive.org/details/ps2-redump-usa-chd-part-A"
// PS2 Redump USA CHD is separated per alphabet, so create a link from it instead of checking each page
let ps2link = "https://archive.org/download/ps2-redump-usa-chd-part-" + simplify_title(game).charAt(0).toUpperCase()
return searchArchive(ps2link)
.then(() => {
if (results.length == 0) return searchArchive("https://archive.org/download/ps2chd1");
else return;
})
.then(() => {
if (results.length == 0) return searchArchive("https://archive.org/download/ps2chd2");
else return;
})
.then(() => {
if (results.length == 0) return searchArchive("https://archive.org/download/ps2chd3");
else return;
})
.then(() => {
if (results.length == 0) return searchArchive("https://archive.org/download/ps2chd4");
else return;
})
.then(() => {
if (results.length == 0) return searchArchive("https://archive.org/download/ps2chd5");
else return;
})
}
else if (console == RAConsole.PSP) {
collection.name = "[REDUMP] Disc Image Collection: Sony PlayStation Portable"
collection.url = "https://archive.org/download/redump.psp"
return searchArchive("https://archive.org/download/redump.psp")
.then(() => {
if (results.length == 0) return searchArchive("https://archive.org/download/redump.psp.p2");
else return;
})
.then(() => {
if (results.length == 0) {
collection.name = "PSN Collection By Ghostware"
collection.url = "https://archive.org/download/PSNCollectionByGhostware"
return searchArchive("https://archive.org/download/PSNCollectionByGhostware");
}
else return;
})
} else if (console == RAConsole.SATURN) {
collection.name = "Redump Sega Saturn 2018";
collection.url = "https://archive.org/download/SegaSaturn2018July10"
return searchArchive("https://archive.org/download/SegaSaturn2018July10");
} else if (console == RAConsole.DREAMCAST) {
collection.name = "[REDUMP] Disc Image Collection: Sega - Sega Dreamcast";
collection.url = "https://archive.org/download/redump.dc.revival";
return searchArchive("https://archive.org/download/redump.dc.revival");
} else if (console == RAConsole.SEGACD) {
collection.name = "Redump Sega Mega CD & Sega CD";
collection.url = "https://archive.org/download/redump.sega_megacd-segacd"
return searchArchive("https://archive.org/download/redump.sega_megacd-segacd");
} else if (console == RAConsole.NEOGEOCD) {
collection.name = "[REDUMP] Disc Image Collection: SNK - Neo Geo CD";
collection.url = "https://archive.org/download/redump.ngcd.revival"
return searchArchive("https://archive.org/download/redump.ngcd.revival");
}
else if (console == RAConsole.ARCADE) {
collection.name = "FB Neo Nightly"
collection.url = "https://archive.org/download/2020_01_06_fbn"
return searchArcade();
} else if (console == RAConsole.A2600) {
collection.name = "No-Intro Atari 2600"
collection.url = "https://archive.org/download/nointro2600atarii"
return searchArchive("https://archive.org/download/nointro2600atarii");
} else if (console == RAConsole.NEC8800) {
collection.name = "Neo Kobe NEC PC-8801/8001"
collection.url = "https://archive.org/details/Neo_Kobe_NEC_PC-8001_2016-02-25"
return searchArchive("https://ia800202.us.archive.org/view_archive.php?archive=/18/items/Neo_Kobe_NEC_PC-8801_2016-02-25/Neo%20Kobe%20-%20NEC%20PC-8801%20%282016-02-25%29.zip")
// Search for 8001 if it finds nothing.
.then(() => {
if (results.length == 0) return searchArchive("https://ia600204.us.archive.org/view_archive.php?archive=/18/items/Neo_Kobe_NEC_PC-8001_2016-02-25/Neo%20Kobe%20-%20NEC%20PC-8001%20%282016-02-25%29.zip)");
else return;
})
} else if (console == RAConsole.APPLEII) {
collection.name = "Apple 2 TOSEC 2012"
collection.url = "https://archive.org/details/Apple_2_TOSEC_2012_04_23"
return searchArchive("https://ia802908.us.archive.org/view_archive.php?archive=/25/items/Apple_2_TOSEC_2012_04_23/Apple_2_TOSEC_2012_04_23.zip");
} else {
collection.name = "No-Intro 2016"
collection.url = "https://archive.org/download/No-Intro-Collection_2016-01-03_Fixed"
return searchNoIntro2016();
}
// exit if already has results
} else return;
})
.then(() => {
if (enableEmuparadise && results.length == 0) {
collection.name = "Emuparadise";
collection.url = "https://www.emuparadise.me/roms-isos-games.php"
return searchEmuparadise();
}
})
.then(() => {
if (console == RAConsole.PSP)
return searchArchiveDlc("https://archive.org/download/PSP-DLC/%5BNo-Intro%5D%20PSP%20DLC/")
})
.then(() => {
// GM_log(results);
if (results.length > 0) createDownloads()
if (resultsDlcs.length > 0) createDlcs()
})
} else {
// divRoms.append("<b>Searching roms for this system not supported.</b>");
GM_log("Searching roms for this system not supported.")
}
}
// =========================================
// Create Content to the Page
// =========================================
function createDownloads() {
divRoms.append("<h3>ROMs</h3>");
// divRoms.append(`<b>Found ${results.length} related result(s)`)
divRoms.append(``);
for (var i = 0; i < results.length; i++) {
let dlLink = (results[i].url).replace(/ /g, "%20");
divRoms.append("<a class='dl-links' href=" + dlLink + ">" + removeExt(results[i].name) + "</a>");
}
if (collection.url != "") divRoms.append(`<div style="margin-top:1em;">From <a href=${collection.url}>${collection.name}</a></div>`);
$(".dl-links").css("display", "block");
}
function createDlcs() {
divRoms.append(`<h3 style="margin-top: 1em;">DLCs</h3>`);
//divRoms.append(`<b>Found ${resultsDlcs.length} related result(s)`)
divRoms.append(``);
for (var i = 0; i < resultsDlcs.length; i++) {
let dlLink = (resultsDlcs[i].url).replace(/ /g, "%20");
divRoms.append("<a class='dl-links' href=" + dlLink + ">" + removeExt(resultsDlcs[i].name) + "</a>");
}
if (collection.url != "") divRoms.append(`<div style="margin-top:1em;">From <a href=https://archive.org/download/PSP-DLC/%5BNo-Intro%5D%20PSP%20DLC>PSP-DLC (No-Intro)</a></div>`);
$(".dl-links").css("display", "block");
}
function createSpeedrun() {
divSpeedruncom.append("<h3>World Records</h3>");
// divSpeedruncom.append(`<a href=${srGamelink}>
// <img style="display: block; width: 100%; object-fit: cover; margin: 1em 0em 1em 0em"
// src=${srLogo}></img>
// </a>`)
// GM_log(srRuns)
// GM_log(srRuns.length)
if (srRuns.length > 0) {
srRuns.forEach((runsData) => {
// GM_log(runsData.link)
divSpeedruncom.append(`<div><a href=${runsData.link}>${runsData.category}:</a> ${runsData.time} by ${runsData.runner}</div>`)
});
} else {
divSpeedruncom.append("<div>Couldn't find this game on Speedrun.com</div>")
}
}
function createVideo() {
if (srVideoUrl != "")
GM_log("Creating video with URL: " + srVideoUrl)
$("#achievement").children().eq(3)
.after($(`<iframe style="display: block; width: 100%; height:315px; padding-bottom: 1em"
src="${srVideoUrl}"
allowfullscreen="allowfullscreen"
autoplay="false">
</iframe>`));
}
function getSrConsoleId(consoleName) {
if (consoleName == RAConsole.A2600) {
return SRConsole.ATARI2600;
} else if (consoleName == RAConsole.A7800) {
return SRConsole.ATARI7800;
} else if (consoleName == RAConsole.APPLEII) {
return SRConsole.APPLEII;
} else if (consoleName == RAConsole.ARCADE) {
return SRConsole.ARCADE;
} else if (consoleName == RAConsole.COLECO) {
return SRConsole.COLECOVISION;
} else if (consoleName == RAConsole.DREAMCAST) {
return SRConsole.DREAMCAST;
} else if (consoleName == RAConsole.GAMEBOY) {
return SRConsole.GAMEBOY;
} else if (consoleName == RAConsole.GBA) {
return SRConsole.GAMEBOYADVANCE;
} else if (consoleName == RAConsole.GBC) {
return SRConsole.GAMEBOYCOLOR;
} else if (consoleName == RAConsole.GENESIS) {
return SRConsole.GENESIS;
} else if (consoleName == RAConsole.GG) {
return SRConsole.GG;
} else if (consoleName == RAConsole.N64) {
return SRConsole.N64;
} else if (consoleName == RAConsole.SATURN) {
return SRConsole.SEGASATURN;
} else if (consoleName == RAConsole.MASTERSYSTEM) {
return SRConsole.MASTERSYSTEM;
} else if (consoleName == RAConsole.NDS) {
return SRConsole.NDS;
} else if (consoleName == RAConsole.NEC8800) {
return SRConsole.NEC8800;
} else if (consoleName == RAConsole.NEOPOCKET) {
return SRConsole.NEOGEOPOCKETCOLOR;
} else if (consoleName == RAConsole.NES) {
return SRConsole.NES;
} else if (consoleName == RAConsole.PANASONIC3DO) {
return SRConsole.PANASONIC3D0;
} else if (consoleName == RAConsole.PCENGINE) {
return SRConsole.PCENGINE;
} else if (consoleName == RAConsole.POKEMINI) {
return SRConsole.POKÉMONMINI;
} else if (consoleName == RAConsole.PS1) {
return SRConsole.PS1;
} else if (consoleName == RAConsole.PSP) {
return SRConsole.PLAYSTATIONPORTABLE
} else if (consoleName == RAConsole.SEGA32X) {
return SRConsole.SEGA32X;
} else if (consoleName == RAConsole.SEGACD) {
return SRConsole.SEGACD;
} else if (consoleName == RAConsole.SG1000) {
return SRConsole.MASTERSYSTEM;
} else if (consoleName == RAConsole.SNES) {
return SRConsole.SNES;
} else if (consoleName == RAConsole.VIRTUALBOY) {
return SRConsole.VIRTUALBOY;
} else return "";
}
function getSpeedruns(gameName) {
var consoleId = getSrConsoleId(console);
var srSearchUrl = encodeURI(srRoot + "games?name=" + gameName + "&platform=" + consoleId)
// Games
// GM_log(srSearchUrl)
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: srSearchUrl,
onload: function (gamesResponse) {
let gamesData = JSON.parse(gamesResponse.response).data
// GM_log("Games: " + gamesData)
if (gamesData.length > 0) {
srGamelink = gamesData[0].weblink;
srGameId = gamesData[0].id;
// srLogo = gamesData[0].assets.logo.uri; don't work as of now, possibly due to API changes on Speedrun.com
resolve(gamesData[0].links[3].uri);
} else {
throw `Couldn't find this game on Speedrun.com (${srSearchUrl}).`;
}
}
})
})
.then((link) => {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: link,
onload: function (response) {
let categoriesData = JSON.parse(response.response).data
resolve(categoriesData)
}
})
})
}, err => {
throw (err)
})
.then((categories) => {
// GM_log("Categories: " + categories)
let totalRuns = 0;
return Promise.all(categories.map(category => {
// Runs
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: srRoot + `runs?game=${srGameId}&category=${category.id}&status=verified`,
onload: function (runsResponse) {
let runsData = JSON.parse(runsResponse.response).data[0];
if (runsData != undefined && runsData.status.status != "rejected") {
// Pick a eligible speedrun video and use it as the video showcase on the page
// GM_log(runsData.videos)
if (srVideoUrl == "" && runsData.videos)
srVideoUrl = toEmbedUrl(runsData.videos.links[0].uri);
// GM_log(isVideoUrl(runsData.videos.links[0].uri))
// if (isVideoUrl(runsData.videos.links[0].uri))
totalRuns++;
}
resolve(runsData)
}
})
})
.then((runsData) => {
if (runsData == undefined) return false;
// TODO: Resolve useless request if user is a guest.
let isGuest = runsData.players[0].rel == "guest" ? true : false;
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: srRoot + "users/" + runsData.players[0].id,
onload: function (userRes) {
userData = JSON.parse(userRes.response).data
srRuns.push({
category: category.name,
time: parseIso8601(runsData.times.primary),
runner: isGuest ? runsData.players[0].name : userData.names.international,
link: runsData.videos ? runsData.videos.links[0].uri : ""
})
// GM_log(srRuns.length)
// GM_log(totalRuns)
resolve(true)
}
})
})
})
}))
.then(() => {
// GM_log("Last step from promises")
// GM_log(srRuns)
if (enableSpeedrun) createSpeedrun();
if (enableGameplayVideo) createVideo();
})
})
}
// Functional
// return $.get(srSearchUrl)
// .then((gamesResponse) => {
// if (gamesResponse.data.length > 0) {
// srGamelink = gamesResponse.data[0].weblink;
// srGameId = gamesResponse.data[0].id;
// srLogo = gamesResponse.data[0].assets.logo.uri;
// return gamesResponse.data[0].links[3].uri;
// } else {
// throw `Couldn't find this game on Speedrun.com (${srSearchUrl}).`;
// }
// }, err => {
// throw (err)
// })
// // Categories
// .then((link) => {
// return $.get(link).then(response => response.data)
// }, err => {
// throw (err)
// })
// .then((categories) => {
// // GM_log(categories)
// let totalRuns = 0;
// return Promise.all(categories.map(category => {
// // Runs
// return $.get(srRoot + `runs?game=${srGameId}&category=${category.id}&status=verified`)
// .then((runsResponse) => {
// let runsData = runsResponse.data[0];
// if (runsData != undefined && runsData.status.status != "rejected") {
// // GM_log(runsData.videos)
// if (srVideoUrl == "" && runsData.videos)
// srVideoUrl = toEmbedUrl(runsData.videos.links[0].uri);
// totalRuns++;
// return runsData;
// }
// })
// .then((runsData) => {
// if (runsData == undefined) return false;
// // TODO: Resolve useless request if user is a guest.
// let isGuest = runsData.players[0].rel == "guest" ? true : false;
// return $.get(srRoot + "users/" + runsData.players[0].id)
// .then(userRes => {
// srRuns.push({
// category: category.name,
// time: parseIso8601(runsData.times.primary),
// runner: isGuest ? runsData.players[0].name : userRes.data.names.international,
// link: runsData.videos ? runsData.videos.links[0].uri : ""
// })
// // GM_log(srRuns.length)
// // GM_log(totalRuns)
// return true;
// })
// })
// }))
// .then(() => {
// if (enableSpeedrun) createSpeedrun();
// if (enableGameplayVideo) createVideo();
// })
// }, err => {
// throw (err)
// })
// }
// Broken??
// return $.get(srSearchUrl)
// .then((gamesResponse) => {
// if (gamesResponse.data.length > 0) {
// srGamelink = gamesResponse.data[0].weblink;
// srGameId = gamesResponse.data[0].id;
// srLogo = gamesResponse.data[0].assets.logo.uri;
// return gamesResponse.data[0].links[3].uri;
// } else {
// throw `Couldn't find this game on Speedrun.com (${srSearchUrl}).`;
// }
// }, err => {
// throw (err)
// })
// // Categories
// .then((link) => {
// return $.get(link).then(response => response.data)
// }, err => {
// throw (err)
// })
// .then((categories) => {
// // GM_log(categories)
// let totalRuns = 0;
// return Promise.all(categories.map(category => {
// // Runs
// return $.get(srRoot + `runs?game=${srGameId}&category=${category.id}&status=verified`)
// .then((runsResponse) => {
// let runsData = runsResponse.data[0];
// if (runsData != undefined && runsData.status.status != "rejected") {
// // GM_log(runsData.videos)
// if (srVideoUrl == "" && runsData.videos)
// srVideoUrl = toEmbedUrl(runsData.videos.links[0].uri);
// totalRuns++;
// return runsData;
// }
// })
// .then((runsData) => {
// if (runsData == undefined) return false;
// // TODO: Resolve useless request if user is a guest.
// let isGuest = runsData.players[0].rel == "guest" ? true : false;
// return $.get(srRoot + "users/" + runsData.players[0].id)
// .then(userRes => {
// srRuns.push({
// category: category.name,
// time: parseIso8601(runsData.times.primary),
// runner: isGuest ? runsData.players[0].name : userRes.data.names.international,
// link: runsData.videos ? runsData.videos.links[0].uri : ""
// })
// // GM_log(srRuns.length)
// // GM_log(totalRuns)
// return true;
// })
// })
// }))
// .then(() => {
// if (enableSpeedrun) createSpeedrun();
// if (enableGameplayVideo) createVideo();
// })
// }, err => {
// throw (err)
// })
// }
// function searchCustom() {
// var spreadsheetId = "1IhU4rxn9aZ44HHTttYxTxeGlamQ7KHmFdiAtGjFK8Sg";
// var publicKey = "AIzaSyBX7lt6Dzt4NZti7Du_xxAD_qPKb4xKZ-4";
// return new Promise((resolve, reject) => {
// GM_xmlhttpRequest({
// method: "GET",
// url: `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values/${console}!A2:C1000?key=${publicKey}`,
// onload: function (response) {
// var sheet = JSON.parse(response.responseText);
// sheet.values.forEach(row => {
// // Stop in case tag is not matching
// if (row[0] != tag) return;
// if (refinedCompare(row[1], game)) {
// // GM_log(row)
// results.push({
// name: `${row[1]} (${row[0]})`,
// url: row[2]
// });
// }
// });
// if (results.length == 0) {
// sheet.values.forEach(row => {
// if (compare(row[1], game)) {
// // GM_log(row)
// results.push({
// name: `${row[1]} (${tag})`,
// url: row[2]
// });
// }
// });
// }
// resolve(true);
// }
// })
// })
// }
// =========================================
// Archives.org (Arcade) Function
// =========================================
function searchArcade() {
var mainDir = "//archive.org/download/2020_01_06_fbn/roms/arcade.zip/arcade%2F";
var datDir = "https://raw.githubusercontent.com/libretro/FBNeo/master/dats/FinalBurn%20Neo%20(ClrMame%20Pro%20XML%2C%20Arcade%20only).dat";
return new Promise((resolve, reject) => {
// Find content in .dat file from FB Neo repo.
GM_xmlhttpRequest({
method: "GET",
url: datDir,
onload: function (response) {
// GM_log(response);
var xmlDoc = $.parseXML(response.responseText);
// Refined search
$(xmlDoc).find("game").each(function (index) {
let name = $(this).find("description").text();
if (tag == "" && name.toLowerCase().includes("hack")) return;
if (tag == "Hack" && !name.toLowerCase().includes("hack")) return;
if (refinedCompare(name, game)) {
results.push({
name: name,
url: mainDir + $(this).attr('name') + ".zip"
});
}
})
// Normal search
if (results.length == 0) {
$(xmlDoc).find("game").each(function (index) {
let name = $(this).find("description").text();
if (tag == "" && name.toLowerCase().includes("hack")) return;
if (tag == "Hack" && !name.toLowerCase().includes("hack")) return;
if (compare(name, game)) {
results.push({
name: name,
url: mainDir + $(this).attr('name') + ".zip"
});
}
})
}
resolve(true);
}
})
});
}
// =========================================
// Archives.org (No Intro 2016) Function
// =========================================
function searchNoIntro2016() {
var mainDir = "https://archive.org/download/No-Intro-Collection_2016-01-03_Fixed/";
var consoleDir = "";
var secondaryConsoleDir = "";
if (console == RAConsole.SNES) {
consoleDir = "Nintendo - Super Nintendo Entertainment System";
}
if (console == RAConsole.NES) {
consoleDir = "Nintendo - Nintendo Entertainment System";
}
if (console == RAConsole.GAMEBOY) {
consoleDir = "Nintendo - Game Boy";
}
if (console == RAConsole.GBC) {
consoleDir = "Nintendo - Game Boy Color";
}
if (console == RAConsole.GBA) {
consoleDir = "Nintendo - Game Boy Advance";
}
if (console == RAConsole.N64) {
consoleDir = "Nintendo - Nintendo 64";
}
if (console == RAConsole.A7800) {
consoleDir = "Atari - 7800";
}
if (console == RAConsole.PCENGINE) {
consoleDir = "NEC - PC Engine - TurboGrafx 16";
}
if (console == RAConsole.GENESIS) {
consoleDir = "Sega - Mega Drive - Genesis";
}
if (console == RAConsole.MASTERSYSTEM) {
consoleDir = "Sega - Master System - Mark III";
}
if (console == RAConsole.GG) {
consoleDir = "Sega - Game Gear";
}
if (console == RAConsole.NEOPOCKET) {
consoleDir = "SNK - Neo Geo Pocket";
secondaryConsoleDir = "SNK - Neo Geo Pocket Color";
}
if (console == RAConsole.POKEMINI) {
consoleDir = "Nintendo - Pokemon Mini";
}
if (console == RAConsole.VIRTUALBOY) {
consoleDir = "Nintendo - Virtual Boy.zip";
}
if (console == RAConsole.SG1000) {
consoleDir = "Sega - SG-1000";
}
if (console == RAConsole.COLECO) {
consoleDir = "Coleco - ColecoVision";
}
if (console == RAConsole.MSX) {
consoleDir = "Microsoft - MSX";
secondaryConsoleDir = "Microsoft - MSX 2";
}
if (console == RAConsole.WONDERSWAN) {
consoleDir = "Bandai - WonderSwan Color";
secondaryConsoleDir = "Bandai - WonderSwan Color"
}
if (console == RAConsole.VECTREX) {
consoleDir = "GCE - Vectrex";
}
consoleDir = consoleDir.replace(/ /g, "%20").concat(".zip/");
secondaryConsoleDir = secondaryConsoleDir.replace(/ /g, "%20").concat(".zip/");
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: mainDir + consoleDir,
onload: function (response) {
// GM_log(response);
// Refined search
$(response.responseText).find(`td`).children(":first-child").each(function (index) {
if (refinedCompare($(this).text(), game)) {
results.push({
name: $(this).text(),
url: $(this).attr('href')
});
}
});
// Normal search
if (results.length == 0) {
$(response.responseText).find(`td`).children(":first-child").each(function (index) {
if (compare($(this).text(), game)) {
results.push({
name: $(this).text(),
url: $(this).attr('href')
});
}
});
}
resolve(true);
}
})
})
.then(() => {
if (secondaryConsoleDir != "") {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: mainDir + secondaryConsoleDir,
onload: function (response) {
// GM_log(response);
// Refined search
$(response.responseText).find(`td`).children(":first-child").each(function (index) {
if (refinedCompare($(this).text(), game)) {
results.push({
name: $(this).text(),
url: $(this).attr('href')
});
}
});
// Normal search
if (results.length == 0) {
$(response.responseText).find(`td`).children(":first-child").each(function (index) {
if (compare($(this).text(), game)) {
results.push({
name: $(this).text(),
url: $(this).attr('href')
});
}
});
}
resolve(true);
}
})
})
}
})
}
// =========================================
// Archives.org (Generic) Function
// =========================================
function searchArchive(mainDir) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: mainDir,
onload: function (response) {
// GM_log(response.responseText);
// Refined search
$(response.responseText).find(`td`).children(":first-child").each(function (index) {
let title = /([^\/]+)\/?$/g.exec($(this).text())[1];
// Check in case link is already the full url
let fullUrl = $(this).attr('href').startsWith("//archive.org/download/") ?
$(this).attr('href') : `${mainDir}/${$(this).attr('href')}`
// GM_log($(this).attr('href'))
if (refinedCompare(title, game)) {
results.push({
name: title,
url: fullUrl
});
}
});
// Normal search
if (results.length == 0) {
$(response.responseText).find(`td`).children(":first-child").each(function (index) {
let title = /([^\/]+)\/?$/g.exec($(this).text())[1];
let fullUrl = $(this).attr('href').startsWith("//archive.org/download/") ?
$(this).attr('href') : `${mainDir}/${$(this).attr('href')}`
// GM_log($(this).attr('href'))
if (compare(title, game)) {
results.push({
name: title,
url: fullUrl
});
}
});
}
return resolve(true);
}
})
});
}
// =========================================
// Archives.org (DLC) Function
// =========================================
function searchArchiveDlc(mainDir) {
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: mainDir,
onload: function (response) {
// GM_log(response);
// Refined search
$(response.responseText).find(`td`).children(":first-child").each(function (index) {
let title = /([^\/]+)\/?$/g.exec($(this).text())[1];
// Check in case link is already the full url
let fullUrl = $(this).attr('href').startsWith("//archive.org/download/") ?
$(this).attr('href') : `${mainDir}/${$(this).attr('href')}`
// GM_log($(this).attr('href'))
if (refinedCompare(title, game)) {
resultsDlcs.push({
name: title,
url: fullUrl
});
}
});
// Normal search
if (resultsDlcs.length == 0) {
$(response.responseText).find(`td`).children(":first-child").each(function (index) {
let title = /([^\/]+)\/?$/g.exec($(this).text())[1];
let fullUrl = $(this).attr('href').startsWith("//archive.org/download/") ?
$(this).attr('href') : `${mainDir}/${$(this).attr('href')}`
// GM_log($(this).attr('href'))
if (compare(title, game)) {
resultsDlcs.push({
name: title,
url: fullUrl
});
}
});
}
return resolve(true);
}
})
});
}
// =========================================
// Emuparadise Function
// =========================================
function searchEmuparadise() {
var mainDir = "https://www.emuparadise.me/";
var consoleUrl;
if (console == RAConsole.SNES) {
consoleUrl = "Super_Nintendo_Entertainment_System_(SNES)_ROMs/List-All-Titles/5";
}
if (console == RAConsole.NES) {
consoleUrl = "Nintendo_Entertainment_System_ROMs/List-All-Titles/13";
}
if (console == RAConsole.GAMEBOY) {
consoleUrl = "Nintendo_Game_Boy_ROMs/List-All-Titles/12";
}
if (console == RAConsole.GBC) {
consoleUrl = "Nintendo_Game_Boy_Color_ROMs/List-All-Titles/11";
}
if (console == RAConsole.GBA) {
consoleUrl = "Nintendo_Gameboy_Advance_ROMs/List-All-Titles/31";
}
if (console == RAConsole.N64) {
consoleUrl = "Nintendo_64_ROMs/List-All-Titles/9";
}
if (console == RAConsole.GCN) {
consoleUrl = "Nintendo_Gamecube_ISOs/List-All-Titles/42"
}
if (console == RAConsole.NDS) {
consoleUrl = "Nintendo_DS_ROMs/List-All-Titles/32";
}
if (console == RAConsole.GENESIS) {
consoleUrl = "Sega_Genesis_-_Sega_Megadrive_ROMs/List-All-Titles/6";
}
if (console == RAConsole.MASTERSYSTEM) {
consoleUrl = "Sega_Master_System_ROMs/List-All-Titles/15";
}
if (console == RAConsole.SEGA32X) {
consoleUrl = "Sega_32X_ROMs/61";
}
if (console == RAConsole.SATURN) {
consoleUrl = "Sega_Saturn_ISOs/List-All-Titles/3"
}
if (console == RAConsole.SEGACD) {
consoleUrl = "Sega_CD_ISOs/List-All-Titles/10";
}
if (console == RAConsole.GG) {
consoleUrl = "Sega_Game_Gear_ROMs/List-All-Titles/14";
}
if (console == RAConsole.NEOPOCKET) {
consoleUrl = "Neo_Geo_Pocket_-_Neo_Geo_Pocket_Color_(NGPx)_ROMs/38";
}
if (console == RAConsole.A2600) {
consoleUrl = "Atari_2600_ROMs/List-All-Titles/49"
}
if (console == RAConsole.A7800) {
consoleUrl = "Atari_7800_ROMs/47"
}
if (console == RAConsole.PCENGINE) {
consoleUrl = "PC_Engine_-_TurboGrafx16_ROMs/List-All-Titles/16";
}
if (console == RAConsole.APPLEII) {
consoleUrl = "Apple_][_ROMs/List-All-Titles/24";
}
if (console == RAConsole.PS1) {
consoleUrl = "Sony_Playstation_ISOs/List-All-Titles/2";
}
if (console == RAConsole.PS2) {
consoleUrl = "Sony_Playstation_2_ISOs/List-All-Titles/41";
}
if (console == RAConsole.PSP) {
consoleUrl = "PSP_ISOs/List-All-Titles/44";
}
if (console == RAConsole.PANASONIC3DO) {
consoleUrl = "Panasonic_3DO_(3DO_Interactive_Multiplayer)_ISOs/List-All-Titles/20";
}
return new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: "GET",
url: mainDir + consoleUrl,
onload: function (response) {
// GM_log(response);
// Refined search
$(response.responseText).find(`.index.gamelist`).each(function (index) {
let epGameId = /([^\/]+)\/?$/g.exec($(this).attr('href'))[0];
// GM_log($(this).text())
if (refinedCompare($(this).text(), game)) {
results.push({
name: $(this).text(),
url: `https://www.emuparadise.me/roms/get-download.php?gid=${epGameId}&test=true`
});
}
});
// Normal search
if (results.length == 0) {
$(response.responseText).find(`.index.gamelist`).each(function (index) {
let epGameId = /([^\/]+)\/?$/g.exec($(this).attr('href'))[0];
// GM_log($(this).text())
if (compare($(this).text(), game)) {
results.push({
name: $(this).text(),
url: `https://www.emuparadise.me/roms/get-download.php?gid=${epGameId}&test=true`
});
}
});
}
return resolve(true);
}
})
});
}
// =========================================
// Utility Functions
// =========================================
function refinedCompare(a, b) {
let str1 = simplify_title(a);
let str2 = simplify_title(b);
// GM_log("*Str 1: " + str1)
// GM_log("*Str 2: " + str2)
// GM_log(str1 == str2)
if (str1 == str2)
return true;
else
return false;
}
function compare(a, b) {
// GM_log(a)
let str1 = simplify_title(a);
let str2 = simplify_title(b);
// GM_log("Str 1: " + str1)
// GM_log("Str 2: " + str2)
// GM_log(str1.includes(str2))
if (str1.includes(str2))
return true;
else
return false;
}
// Remove unnecessary characters and region headering
function simplify_title(str) {
// Dreamcast TOSEC set puts versioning into the filename
if (console == RAConsole.DREAMCAST)
str = str.replace(/v[0-9].[0-9]{3}/gs, "")
return str
.replace(/\.(zip|7z)$/,"")
.replace(/^The /g, '')
.replace(", The", '')
.replace(/'s/gs, '')
.replace('&', 'and')
.replace(/:|-| |\.|!|\?|\/|'/gs, '')
.replace(/(\r\n|\n|\r)/gs, "") // remove line breaks
.split('|')[0]
.replace(',', "")
// remove headers (old)
// .replace(/\([\w\s]+\)/gs, "")
// .replace(/\[[\w\s]+\]/gs, "")
// remove headers (everything inside parenthesis)
.replace(/\(.+\)/gs, "")
.replace(/\[.+\]/gs, "")
.toLowerCase()
}
function removeExt(str) {
return str.replace(/\.(zip|7z|chd)$/,"");
}
function parseIso8601(time) {
var parsed = "";
let regex = /(-)?P(?:([.,\d]+)Y)?(?:([.,\d]+)M)?(?:([.,\d]+)W)?(?:([.,\d]+)D)?T(?:([.,\d]+)H)?(?:([.,\d]+)M)?(?:([.,\d]+)S)?/;
let groups = regex.exec(time);
if (groups[6] != undefined) parsed = parsed.concat(`${groups[6]}h `)
if (groups[7] != undefined) parsed = parsed.concat(`${groups[7]}m `)
if (groups[8] != undefined) parsed = parsed.concat(`${groups[8]}s `)
return parsed;
}
function isVideoUrl(url) {
return (url.includes("www.youtu") || url.includes("www.twitch.tv"))
}
function toEmbedUrl(url) {
if (url.includes("twitch") || url.includes("youtu")) {
// GM_log(url);
// https://regex101.com/r/jmV6qH/1
var regexYoutube = /(?:https?:\/{2})?(?:w{3}\.)?youtu(?:be)?\.(?:com|be)(?:\/watch\?v=|\/)?([^\s&]+)/;
// https://regex101.com/r/0RofWZ/1
var regexTwitch = /(?:https?:\/{2})?www\.twitch\.tv\/(:?[\S]+\/)?([\]?)?\/([\d]+)/;
if (url.match(regexYoutube) != undefined) {
return "https://www.youtube.com/embed/" + url.match(regexYoutube)[1];
} else if (url.match(regexTwitch) != undefined) {
return "https://player.twitch.tv/?video=" + url.match(regexTwitch)[2] + "&parent=retroachievements.org&autoplay=false";
}
}
return "";
}
}
})();
Donate for the site OpenUserJS
Are you sure you want to go to an external site to donate a monetary value?
WARNING: Some countries laws may supersede the payment processors policy such as the GDPR and PayPal. While it is highly appreciated to donate, please check with your countries privacy and identity laws regarding privacy of information first. Use at your utmost discretion.