diff --git a/TamperMonkeyRetroachievements.js b/TamperMonkeyRetroachievements.js index f5f578f..d11887e 100644 --- a/TamperMonkeyRetroachievements.js +++ b/TamperMonkeyRetroachievements.js @@ -19,6 +19,10 @@ let cachedGameData = null; let hashListObserver = null; +let lastGameId = null; +let lastGameHashesMap = null; +let lastGameData = null; + // ========== IndexedDB helpers ========== let dbPromise = null; async function idbOpen() { @@ -71,57 +75,6 @@ async function handleRA() { const lastUpdated = parseInt(await idbGet('collectionLastUpdated')) / 1000; const lastModified = parseInt(await idbGet('collectionLastModified')); - async function injectGames(gameData, archiveDown = false, msg = '') { - const hashListParent = document.querySelector('ul.flex.flex-col.gap-3[data-testid="named-hashes"]'); - if (!hashListParent) return; - const gameId = window.location.pathname.split("/")[2]; - - const gameHashesMap = new Map(); - if (gameData?.[gameId]) { - gameData[gameId].forEach(obj => { - Object.entries(obj).forEach(([hash, url]) => { - const lowerHash = hash.toLowerCase(); - if (!gameHashesMap.has(lowerHash)) { - gameHashesMap.set(lowerHash, url); - } - }); - }); - } - - for (const li of hashListParent.querySelectorAll('li')) { - if (li.dataset.scriptInjected) continue; - li.dataset.scriptInjected = "true"; - - const hashNode = li.querySelector("div.flex.flex-col.border-l-2"); - const hashElement = hashNode?.querySelector("p.font-mono"); - if (!hashElement) continue; - - const retroHash = hashElement.innerText.trim().toLowerCase(); - hashElement.innerText = retroHash; - - const linksContainer = hashNode; - const links = []; - - const romURL = gameHashesMap.get(retroHash); - - if (romURL) { - const link = romURL.includes("myrient.erista.me") - ? `${romURL.substring(0, romURL.lastIndexOf('/') + 1)}#autoSearch=${encodeURIComponent(romURL.split("/").pop())}` - : romURL; - links.push(`Download ROM`); - } else { - const fullFileName = li.querySelector("span.font-bold")?.innerText.trim() || retroHash; - links.push(`Search on Rezi`); - } - - links.forEach(html => { - const div = document.createElement('div'); - div.innerHTML = html; - linksContainer.appendChild(div); - }); - } - } - async function fetchData() { try { const commits = await fetch(apiUrl).then(r => r.json()); @@ -165,6 +118,68 @@ async function handleRA() { } } +async function injectGames(gameData, archiveDown = false, msg = '') { + const hashListParent = document.querySelector('ul.flex.flex-col.gap-3[data-testid="named-hashes"]'); + if (!hashListParent) return; + const gameId = window.location.pathname.split("/")[2]; + + let gameHashesMap; + + // Optimization: Memoize the map creation if gameId and gameData haven't changed + if (lastGameId === gameId && lastGameData === gameData && lastGameHashesMap) { + gameHashesMap = lastGameHashesMap; + } else { + gameHashesMap = new Map(); + if (gameData?.[gameId]) { + gameData[gameId].forEach(obj => { + Object.entries(obj).forEach(([hash, url]) => { + const lowerHash = hash.toLowerCase(); + if (!gameHashesMap.has(lowerHash)) { + gameHashesMap.set(lowerHash, url); + } + }); + }); + } + // Update cache + lastGameId = gameId; + lastGameData = gameData; + lastGameHashesMap = gameHashesMap; + } + + for (const li of hashListParent.querySelectorAll('li')) { + if (li.dataset.scriptInjected) continue; + li.dataset.scriptInjected = "true"; + + const hashNode = li.querySelector("div.flex.flex-col.border-l-2"); + const hashElement = hashNode?.querySelector("p.font-mono"); + if (!hashElement) continue; + + const retroHash = hashElement.innerText.trim().toLowerCase(); + hashElement.innerText = retroHash; + + const linksContainer = hashNode; + const links = []; + + const romURL = gameHashesMap.get(retroHash); + + if (romURL) { + const link = romURL.includes("myrient.erista.me") + ? `${romURL.substring(0, romURL.lastIndexOf('/') + 1)}#autoSearch=${encodeURIComponent(romURL.split("/").pop())}` + : romURL; + links.push(`Download ROM`); + } else { + const fullFileName = li.querySelector("span.font-bold")?.innerText.trim() || retroHash; + links.push(`Search on Rezi`); + } + + links.forEach(html => { + const div = document.createElement('div'); + div.innerHTML = html; + linksContainer.appendChild(div); + }); + } +} + // ========== Myrient/Rezi auto-search ========== function handleAutoSearch(inputSelector, isMyrient = false) { const hash = window.location.hash;