// ==UserScript== // @name GeoTracker // @namespace http://tampermonkey.net/ // @version 1.0 // @description Get the exact location, even the exact coordinates of a location in GeoGuessr through Discord // @author ottersek & 19costa & kruzzi steam weedcocainespeed // @match https://www.geoguessr.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com // @grant GM_webRequest // @license MIT // @downloadURL none // ==/UserScript== let discordWebhookUrl = localStorage.getItem('discordWebhookUrl'); if (!discordWebhookUrl) { discordWebhookUrl = prompt('Discord Webhook:', 'https://discord.com/api/webhooks/xxxxxx/xxxxxx'); if (discordWebhookUrl) { localStorage.setItem('discordWebhookUrl', discordWebhookUrl); } else { alert('You must provide a Discord Webhook URL to continue.'); } } window.alert = function (message) { nativeAlert(message); }; const originalFetch = window.fetch; window.fetch = function (url, options) { if (url === "https://www.geoguessr.com/api/v4/cd0d1298-a3aa-4bd0-be09-ccf513ad14b1") { return } return originalFetch.call(this, url, options); }; async function getAddress(lat, lon) { const response = await fetch(`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lon}&format=json`) return await response.json(); } function displayLocationInfo() { const coordinates = coordinateClimber(); getAddress(coordinates[0], coordinates[1]).then(data => { const embed = createEmbed(data); sendToDiscord(embed); }); } function createEmbed(data) { const coordinates = coordinateClimber(); const lat = coordinates[0]; const lon = coordinates[1]; const googleMapsUrl = `https://www.google.com/maps/place/${lat},${lon}`; return { title: "<:genesis_tick:1153936410651414579> Location Tracked", description: `Postal Address: \`${data.address.road}\`\nPost Code: \`${data.address.postcode}\`\nMaps: [Click to open the exact location in Google Maps](${googleMapsUrl})`, color: 6225664, fields: [ { name: "Country 🌍", value: `\`${data.address.country}\``, inline: true }, { name: "County 🏑", value: `\`${data.address.county}\``, inline: true }, { name: "City πŸ™οΈ", value: `\`${data.address.city}\``, inline: true }, { name: "Road πŸ›£οΈ", value: `\`${data.address.road}\``, inline: true }, { name: "State 🏞️", value: `\`${data.address.state}\``, inline: true }, { name: "Village/Suburb 🏘️", value: `\`${data.address.village || data.address.suburb}\``, inline: true } ], author: { name: "github.com/ottersek/geotracker", url: "https://github.com/ottersek/geotracker", icon_url: "https://github.githubassets.com/assets/GitHub-Mark-ea2971cee799.png" }, footer: { text: "github.com/ottersek", icon_url: "https://avatars.githubusercontent.com/u/121310374?v=4" } }; } function sendToDiscord(embed) { const payload = JSON.stringify({ embeds: [embed], username: "GeoTracker", avatar_url: "https://play-lh.googleusercontent.com/DboQuoFNkqgfcl5NiLeXsSgUOLo1F_BMe0g9ZBQBFzq5GpX5M1o7LbJeMgocXmbfy8Y" }); fetch(discordWebhookUrl, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: payload }) .then(response => { if (response.status === 204) { console.log("Mensaje enviado a Discord con Γ©xito."); } else { console.error("Error al enviar el mensaje a Discord."); } }) .catch(error => { console.error("Error en la solicitud fetch: " + error); }); } function placeMarker(safeMode, skipGet, coords) { const isPanic = document.getElementsByClassName("coordinate-map_canvasContainer__7d8Yw")[0] if(isPanic){panicPlaceMarker(isPanic); return;} const isStreaks = document.getElementsByClassName("guess-map__canvas-container")[0] === undefined let location = skipGet ? coords : coordinateClimber(isStreaks) if (isStreaks) { placeMarkerStreaksMode(location) return; } let [lat, lng] = location if (safeMode) { const sway = [Math.random() > 0.5,Math.random() > 0.5] const multiplier = Math.random() * 4 const horizontalAmount = Math.random() * multiplier const verticalAmount = Math.random() * multiplier sway[0] ? lat += verticalAmount : lat -= verticalAmount sway[1] ? lng += horizontalAmount : lat -= horizontalAmount } const element = document.getElementsByClassName("guess-map__canvas-container")[0] const keys = Object.keys(element) // all keys const key = keys.find(key => key.startsWith("__reactFiber$")) const place = element[key].return.memoizedProps.onMarkerLocationChanged flag = false; place({lat: lat, lng: lng}) toggleClick(({lat: lat, lng: lng})) displayDistanceFromCorrect({lat: lat, lng: lng}) injectOverride() } function placeMarkerStreaksMode(code) { let element = document.getElementsByClassName("region-map_map__5e4h8")[0] if(!element){ element = document.getElementsByClassName("region-map_map__7jxcD")[0] } const keys = Object.keys(element) const reactKey = keys.find(key => key.startsWith("__reactFiber$")) const placeMarkerFunction = element[reactKey].return.memoizedProps.onRegionSelected if(typeof code !== "string"){ let [lat,lng] = code getAddress(lat, lng).then(data => { const countryCode = data.address.country_code placeMarkerFunction(countryCode) }) return } placeMarkerFunction(code) } function panicPlaceMarker(element){ const keys = Object.keys(element) const key = keys.find(key => key.startsWith("__reactFiber$")) const props = element[key] const clickProperty = props.return.memoizedProps.map.__e3_.click const clickFunction = clickProperty[getDynamicIndex(Object.keys(clickProperty),clickProperty)].xe console.log(clickFunction) let [lat,lng] = coordinateClimber() lat += 0.1 lng += 0.1 let y = { "latLng": { "lat": () => lat, "lng": () => lng, } } clickFunction(y) } function getDynamicIndex(indexArray,clickProperty){ for(let i = 0; i < indexArray.length;i++){ if(clickProperty[indexArray[i]]?.xe.toString().slice(0,20) === "l=>{let e={lat:l.lat"){ return indexArray[i] } } alert("Maprunner Placer failed. \n Please report this on GitHub or Greasyfork.") } function coordinateClimber(isStreaks){ let timeout = 10 let path = document.querySelector('div[data-qa="panorama"]'); while (timeout > 0){ const props = path[Object.keys(path).find(key => key.startsWith("__reactFiber$"))] const checkReturns = iterateReturns(props,isStreaks) if(checkReturns){ return checkReturns } path = path.parentNode timeout-- } alert("Failed to find co-ordinates. Please make an issue on GitHub or GreasyFork. " + "Please make sure you mention the game mode in your report.") } function iterateReturns(element,isStreaks){ let timeout = 10 let path = element while(timeout > 0){ if(path){ const coords = checkProps(path.memoizedProps,isStreaks) if(coords){ return coords } } if(!path["return"]){ return } path = path["return"] timeout-- } } function checkProps(props,isStreaks){ if(props?.panoramaRef){ const found = props.panoramaRef.current.location.latLng return [found.lat(),found.lng()] } if(props.streakLocationCode && isStreaks){ return props.streakLocationCode } if(props.gameState){ const x = props.gameState[props.gameState.rounds.length-1] return [x.lat,x.lng] } if(props.lat){ return [props.lat,props.lng] } } function mapsFromCoords() { const [lat, lon] = coordinateClimber() if (!lat || !lon) { return; } window.open(`https://www.google.com/maps/place/${lat},${lon}`); } function getGuessDistance(manual) { const coords = coordinateClimber() const clat = coords[0] * (Math.PI / 180) const clng = coords[1] * (Math.PI / 180) const y = document.getElementsByClassName("guess-map__canvas-container")[0] const keys = Object.keys(y) const key = keys.find(key => key.startsWith("__reactFiber$")) const props = y[key] const user = manual ?? props.return.memoizedProps.markers[0] if (!coords || !user) { return null } const ulat = user.lat * (Math.PI / 180) const ulng = user.lng * (Math.PI / 180) const distance = Math.acos(Math.sin(clat) * Math.sin(ulat) + Math.cos(clat) * Math.cos(ulat) * Math.cos(ulng - clng)) * 6371 return distance } function displayDistanceFromCorrect(manual) { let unRoundedDistance = getGuessDistance(manual) let distance = Math.round(unRoundedDistance) if (distance === null) { return } let text = `${distance} km (${Math.round(distance * 0.621371)} miles)` setGuessButtonText(text) } function setGuessButtonText(text) { let x = document.querySelector('button[data-qa="perform-guess"]'); if(!x){ return null} x.innerText = text } function toggleClick(coords) { const disableSpaceBar = (e) => { if (e.keyCode === 32) { const distance = getGuessDistance() if ((distance < 1 || isNaN(distance)) && !flag) { e.stopImmediatePropagation(); preventedActionPopup() document.removeEventListener("keyup", disableSpaceBar); flag = true } } }; document.addEventListener("keyup", disableSpaceBar); setTimeout(() => { const distance = getGuessDistance() if ((distance < 1 || isNaN(distance)) && !flag) { let old = document.getElementsByClassName("button_button__CnARx button_variantPrimary__xc8Hp")[0][Object.keys(document.getElementsByClassName("button_button__CnARx button_variantPrimary__xc8Hp")[0])[1]].onClick document.getElementsByClassName("button_button__CnARx button_variantPrimary__xc8Hp")[0][Object.keys(document.getElementsByClassName("button_button__CnARx button_variantPrimary__xc8Hp")[0])[1]].onClick = (() => { flag = true preventedActionPopup() document.getElementsByClassName("button_button__CnARx button_variantPrimary__xc8Hp")[0][Object.keys(document.getElementsByClassName("button_button__CnARx button_variantPrimary__xc8Hp")[0])[1]].onClick = (() => old()) }) } }, 500) } function preventedActionPopup() { alert(`Geoguessr Resolver has prevented you from making a perfect guess. Making perfect guesses will very likely result in a ban from competitive. Press "guess" again to proceed anyway.`) } function injectOverride() { document.getElementsByClassName("guess-map__canvas-container")[0].onpointermove = (() => { displayDistanceFromCorrect() }) } function getBRCoordinateGuesses() { const gameRoot = document.getElementsByClassName("game_root__2vV1H")[0] const props = gameRoot[Object.keys(document.getElementsByClassName("game_root__2vV1H")[0])[0]] const gameProps = props.return.return.memoizedProps.value.gameState const roundNumber = gameProps.currentRoundNumber const playerArray = gameProps.players let bestGuessDistance = Number.MAX_SAFE_INTEGER playerArray.forEach((player) => { const guesses = player.coordinateGuesses if(guesses){ const guess = guesses[guesses.length - 1] if(guess && guess.roundNumber === roundNumber){ if(guess.distance < bestGuessDistance){ bestGuessDistance = guess.distance } } } }) if (bestGuessDistance === Number.MAX_SAFE_INTEGER) { return null; } return Math.round(bestGuessDistance / 1000) } function displayBRGuesses(){ const distance = getBRCoordinateGuesses() if (distance === null) { alert("There have been no guesses this round") return; } alert(`The best guess this round is ${distance} km from the correct location. (This may include your guess)`) } function setInnerText(){ const text = ` GeoTracker loaded succesfully, if you got any errors, report the issue in github/greasyfork, thanks! ` if(document.getElementsByClassName("header_logo__vV0HK")[0]){ document.getElementsByClassName("header_logo__vV0HK")[0].innerText = text } } GM_webRequest([ { selector: 'https://www.geoguessr.com/api/v4/trails', action: 'cancel' }, ]); let onKeyDown = (e) => { if (e.keyCode === 49) { e.stopImmediatePropagation(); placeMarker(true, false, undefined) } if (e.keyCode === 50) { e.stopImmediatePropagation(); placeMarker(false, false, undefined) } if (e.keyCode === 51) { e.stopImmediatePropagation(); displayLocationInfo() } if (e.keyCode === 52) { e.stopImmediatePropagation(); mapsFromCoords() } if (e.keyCode === 53) { e.stopImmediatePropagation(); displayBRGuesses() } } setInnerText() document.addEventListener("keydown", onKeyDown); let flag = false