您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
GeoHintr - Allows you to place written hints on your maps
当前为
// ==UserScript== // @name GeoHintr // @version 0.1 // @description GeoHintr - Allows you to place written hints on your maps // @author MrAmericanMike and Alok // @include /^(https?)?(\:)?(\/\/)?([^\/]*\.)?geoguessr\.com($|\/.*)/ // @grant none // @run-at document-start // @namespace https://greasyfork.org/users/250979 // ==/UserScript== console.log("GeoHintr"); const GH = { MYHINTS: [], round: 0, hintDiv: null, uiDiv: null, tokens: [], setHints: (hints) => { GH.MYHINTS = hints; }, init: () => { console.log("GH Init"); const targetNode = document.getElementsByTagName("body")[0]; const config = { attributes: false, childList: true, subtree: false, characterData: false }; const observer = new MutationObserver((mutationsList, observer) => { for (const mutation of mutationsList) { if (mutation.type === "childList") { GH.checkRound(); } } }); observer.observe(targetNode, config); if (!GH.hintDiv) { GH.hintDiv = document.createElement("div"); GH.hintDiv.setAttribute("class", "game-statuses"); GH.hintDiv.setAttribute("id", "GH-hint"); GH.hintDiv.setAttribute("style", "display: inline-flex; padding: 5px 0.5rem 0px; margin-top: 2px;"); GH.hintDiv.style.display = "none"; } GH.handleStorage(); GH.createUI(); GH.keyListener(); }, handleStorage: () => { GH.tokens = JSON.parse(sessionStorage.getItem("GH-TOKENS")); if (GH.tokens && GH.tokens.length > 0) { console.log("Tokens stored"); console.log(GH.tokens); } else { sessionStorage.setItem("GH-TOKENS", JSON.stringify([])); GH.tokens = JSON.parse(sessionStorage.getItem("GH-TOKENS")); console.log("Tokens set"); console.log(GH.tokens); } }, storeTokens: () => { sessionStorage.setItem("GH-TOKENS", JSON.stringify(GH.tokens)); console.log("Tokens stored"); console.log(GH.tokens); }, removeToken: (token) => { for (let i = 0; i < GH.tokens.length; i++) { if (GH.tokens[i].token === token) { GH.tokens.splice(i, 1); } } GH.storeTokens(); GH.redrawUI(); }, checkRound: () => { const roundData = document.querySelector("div[data-qa='round-number']"); if (roundData) { let roundElement = roundData.querySelector(".game-status__body"); if (roundElement) { let round = parseInt(roundElement.innerText.charAt(0)); if (!isNaN(round) && round >= 1 && round <= 5) { if (round != GH.round) { console.log("GH Round Changed"); GH.round = round; GH.doMagic(); } } } } }, doMagic: () => { let URL = null; if (window.location.pathname.includes("game")) { URL = `https://www.geoguessr.com/api/v3/games/${window.location.pathname.substring(6)}`; } else if (window.location.pathname.includes("challenge")) { URL = `https://www.geoguessr.com/api/v3/challenges/${window.location.pathname.substring(11)}/game`; } if (URL) { fetch(URL) .then((response) => response.json()) .then((data) => { const { lat, lng } = data.rounds[data.round - 1]; let coordinates = { lat, lng }; GH.checkForHints(coordinates); }) .catch((error) => { console.log("Something went wrong"); console.log(error); }); } }, checkForHints: (coordinates) => { GH.MYHINTS.forEach(hint => { if(GH.coordinatesInRange(coordinates, { lat: hint.lat, lng: hint.lng })){ GH.updateHint(hint); } }); }, updateHint: (hint) => { GH.hintDiv.innerHTML = ` <div class="game-status__body"> <style> #wrapper { width: 25vw; text-align: center; } </style> <div id="wrapper"> <p id="hint"></p> <div class="spacer" style="clear: both;"></div> </div> </div> `; if (document.getElementById("GH-hint")) { GH.hintDiv.style.display = ""; } else { document.querySelector(".game-layout__status").appendChild(GH.hintDiv); GH.hintDiv.style.display = ""; } document.getElementById("hint").innerText = hint.hint; if (hint.img) { console.log(true); let image = document.createElement("img"); image.src = hint.img; image.style.maxHeight = "25vh"; document.getElementById("wrapper").appendChild(image); } if (hint.video) { let iframe = document.createElement("iframe"); iframe.src = `https://www.youtube.com/embed/${hint.video}`; iframe.width = "100%"; iframe.style.minHeight = "25vh"; iframe.setAttribute("allowfullscreen", ""); iframe.setAttribute("frameborder", "0"); document.getElementById("wrapper").appendChild(iframe); } }, loadHints: (token, name) => { document.getElementById("GH-message").innerText = "Loading..."; fetch(`https://dongles.vercel.app/dongle/paste`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ token: token }) }) .then((results) => { return results.json(); }) .then((data) => { if (data.error) { console.log(data); throw new Error(data.error.message); } GH.setHints(data); document.getElementById("GH-message").innerText = "Hints loaded..."; GH.doMagic(); setTimeout(() => { GH.hideUI(); }, 2000); }) .catch((error) => { console.log(error); document.getElementById("GH-message").innerText = "Something went wrong..."; }); let exists = false; GH.tokens.forEach((tok) => { if(tok.token === token) { exists = true; } }); if(!exists){ GH.tokens.push({ token, name }); } GH.storeTokens(); GH.redrawUI(); }, coordinatesInRange: (original, hint) => { let ky = 40000 / 360; let kx = Math.cos(Math.PI * hint.lat / 180.0) * ky; let dx = Math.abs(hint.lng - original.lng) * kx; let dy = Math.abs(hint.lat - original.lat) * ky; return Math.sqrt(dx * dx + dy * dy) <= 0.050; }, keyListener: () => { document.addEventListener("keydown", (event) => { if (event.code === "KeyI" && event.shiftKey && event.altKey && !event.ctrlKey && !event.metaKey && !event.repeat) { if (GH.uiDiv.style.display === "block") { GH.hideUI(); } else { GH.showUI(); } } }); }, createUI: () => { if (!GH.uiDiv) { GH.uiDiv = document.createElement("div"); GH.uiDiv.setAttribute("id", "GH-ui") Object.assign(GH.uiDiv.style, { display: "none", position: "fixed", backgroundColor: "#eee9e0", zIndex: "1000", width: "fit-content", height: "fit-content", top: "48px", left: "8px", padding: "20px", borderRadius: "10px", boxShadow: "0 2px 2px 0", overflow: "hidden" }); GH.uiDiv.innerHTML = ``; GH.tokens.forEach((token) => { GH.uiDiv.innerHTML += ` <input type="text" size="10" id="${token.token}" value="${token.token}" /> <input type="text" value="${token.name}" /> <button id="GH-${token.token}">LOAD</button> <button id="GHR-${token.token}">X</button> <br /> `; }); GH.uiDiv.innerHTML += ` <input type="text" placeholder="Pastebin Token" size="10" id="pastebin_token" /> <input type="text" placeholder="Description" id="pastebin_name" /> <button id="GH-load">LOAD</button> <br /> `; GH.uiDiv.innerHTML += ` <div style="text-align: center; margin-top: 8px"> <p id="GH-message"></p> </div> `; } document.body.appendChild(GH.uiDiv); document.getElementById("GH-load").addEventListener("click", () => { GH.loadHints(document.getElementById("pastebin_token").value, document.getElementById("pastebin_name").value); }); GH.tokens.forEach((token) => { document.getElementById(`GH-${token.token}`).addEventListener("click", () => GH.loadHints(token.token, token.name)); }); GH.tokens.forEach((token) => { document.getElementById(`GHR-${token.token}`).addEventListener("click", () => GH.removeToken(token.token)); }); }, redrawUI: () => { GH.hideUI(); document.getElementById("GH-ui").remove(); GH.uiDiv = null; GH.createUI(); GH.showUI(); }, showUI: () => { GH.uiDiv.style.display = "block"; }, hideUI: () => { GH.uiDiv.style.display = "none"; } } GH.init();