// ==UserScript== // @name Ranked History // @namespace http://tampermonkey.net/ // @version 0.1 // @description This script will generate a log of all locations. where you played ranked matches. To access the map, wait for the game page to load completely and press the "H" key on your keyboard. // @author HenriqueM // @match https://www.geoguessr.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com // @grant none // @license MIT // @downloadURL none // ==/UserScript== function loadjscssfile(filename, filetype){ var fileref= undefined if (filetype=="js"){ //if filename is a external JavaScript file fileref=document.createElement('script') fileref.setAttribute("type","text/javascript") fileref.setAttribute("src", filename) } else if (filetype=="css"){ //if filename is an external CSS file fileref=document.createElement("link") fileref.setAttribute("rel", "stylesheet") fileref.setAttribute("type", "text/css") fileref.setAttribute("href", filename) } if (typeof fileref!="undefined") { document.getElementsByTagName("head")[0].appendChild(fileref) } } function loadMap() { // Criação da div do modal var modalDiv = document.createElement("div"); modalDiv.id = "map-modal"; modalDiv.style.position = "fixed"; modalDiv.style.top = "0"; modalDiv.style.right = "0"; modalDiv.style.display = "flex"; modalDiv.style.zIndex = "100"; modalDiv.style.background = "white"; modalDiv.style.justifyContent = "center"; modalDiv.style.padding = "1rem"; modalDiv.style.margin = "1rem"; modalDiv.style.left = "50%"; modalDiv.style.transform = "translate(-50%, 0)"; // Criação da div do mapa dentro do modal var mapDiv = document.createElement("div"); mapDiv.id = "world-map"; mapDiv.style.width = "1000px"; mapDiv.style.height = "600px"; // Adicionando a div do mapa dentro da div do modal modalDiv.appendChild(mapDiv); // Adicionando a div do modal ao final do body do documento document.body.appendChild(modalDiv); $(function(){ $('#world-map').vectorMap({ map: 'world_mill', scaleColors: ['#C8EEFF', '#0071A4'], normalizeFunction: 'polynomial', hoverOpacity: 0.7, hoverColor: false, markerStyle: { initial: { r: 4, fill: '#F8E23B', stroke: '#383f47' } }, backgroundColor: '#383f47', markers: getAllCompetitiveLocations() }); }) } function getAllGameLocations() { let storageData = localStorage.getItem('gameLocations'); if (storageData) { // A LocalStorage está definida, então analisar o conteúdo como JSON storageData = JSON.parse(storageData); // Verificar se o conteúdo é um array if (!Array.isArray(storageData)) { return [] } else { const arrayDeArrays = storageData.map(game => game.rounds) const arrayAchatado = arrayDeArrays.reduce(function(acumulador, valorAtual) { // Concatenar cada array no acumulador return acumulador.concat(valorAtual); }, []); const formatado = arrayAchatado.map(l => { return { latLng: [l.lat, l.lng], name: '' } }) return formatado; } } else { return [] } } function getAllCompetitiveLocations() { let storageData = localStorage.getItem('competitiveLocations'); if (storageData) { // A LocalStorage está definida, então analisar o conteúdo como JSON storageData = JSON.parse(storageData); // Verificar se o conteúdo é um array if (!Array.isArray(storageData)) { return [] } else { const arrayDeArrays = storageData.map(game => game.rounds) // Todo corrgiir o index abaixo const arrayDeArrays2 = storageData.map(game => game.teams[0].roundResults) const arrayAchatado = arrayDeArrays.reduce(function(acumulador, valorAtual) { // Concatenar cada array no acumulador return acumulador.concat(valorAtual); }, []); const arrayAchatado2 = arrayDeArrays2.reduce(function(acumulador, valorAtual) { // Concatenar cada array no acumulador return acumulador.concat(valorAtual); }, []); const formatado = arrayAchatado.map((l, i) => { return { latLng: [l.panorama.lat, l.panorama.lng], name: '', color: '#5000ff', style: { fill: calcularCor(arrayAchatado2[i].score), stroke: calcularCor(arrayAchatado2[i].score), } } }) return formatado; } } else { return [] } } function getGameMode() { if(location.pathname.includes("/battle-royale/") ) { return 'battle-royale' } if(location.pathname.includes("/duels/") ) { return 'duels' } return null } function calcularCor(valor) { // Normalizar o valor para um intervalo entre 0 e 1 const normalizedValue = valor / 5000; // Calcular os componentes RGB da cor const red = Math.round(255 * (1 - normalizedValue)); const green = Math.round(255 * normalizedValue); const blue = 0; // Sem azul para esta transição // Formatar a cor no formato RGB const cor = `rgb(${red}, ${green}, ${blue})`; return cor; } (function() { 'use strict'; async function getLocationObjectGame() { const tag = window.location.href.substring(window.location.href.lastIndexOf('/') + 1) const gameMode = getGameMode() console.log(getGameMode(), 'a'); let game_endpoint = "https://www.geoguessr.com/api/v3/games/" + tag; if(gameMode) { game_endpoint = `https://game-server.geoguessr.com/api/${gameMode}/${tag}` } const api_url = game_endpoint const res = await fetch(api_url, { method: 'GET', credentials: 'include' }); return await res.json(); } async function saveGameLocations() { const chave = getGameMode() ? 'competitiveLocations' : 'gameLocations' const chavePrimaria = getGameMode() ? 'gameId' : 'token' // Obter o objeto de localização do jogo const gameinfo = await getLocationObjectGame(); // Verificar se a LocalStorage está definida e se é um array let storageData = localStorage.getItem(chave); if (storageData) { // A LocalStorage está definida, então analisar o conteúdo como JSON storageData = JSON.parse(storageData); // Verificar se o conteúdo é um array if (!Array.isArray(storageData)) { // Se não for um array, definir como um array vazio storageData = []; } else { // Verificar se já existe um objeto com o mesmo token na LocalStorage const existingIndex = storageData.findIndex(item => item[chavePrimaria] === gameinfo[chavePrimaria]); if (existingIndex !== -1) { // Se um objeto com o mesmo token foi encontrado, substituí-lo pelo novo objeto storageData[existingIndex] = gameinfo; } else { // Se não houver um objeto com o mesmo token, adicionar o novo objeto ao array storageData.push(gameinfo); } } } else { // Se a LocalStorage não estiver definida, definir como um array contendo apenas o novo objeto storageData = [gameinfo]; } // Salvar o array atualizado de volta na LocalStorage localStorage.setItem(chave, JSON.stringify(storageData)); } function checkGameMode() { return location.pathname.includes("/game/") || location.pathname.includes("/challenge/") || location.pathname.includes("/battle-royale/") || location.pathname.includes("/duels/"); }; function doCheck() { if (!document.querySelector('div[class*="result-layout_root__"]') && !document.querySelector('div[class*="game-finished-ranked_"]')) { sessionStorage.setItem("Checked", 0); } else if ((sessionStorage.getItem("Checked") || 0) == 0) { saveGameLocations(); sessionStorage.setItem("Checked", 1); } }; let lastDoCheckCall = 0; new MutationObserver(async (mutations) => { if (!checkGameMode() || lastDoCheckCall >= (Date.now() - 50)) return; lastDoCheckCall = Date.now(); doCheck() }).observe(document.body, { subtree: true, childList: true }); // --------------- document.addEventListener("keypress", function handleKeyPress(event) { // Verificar se a tecla pressionada é "h" if (event.key === "h") { loadMap() } if (event.key === "ç") { alert('salvo'); saveGameLocations(); } }); loadjscssfile("https://code.jquery.com/jquery-3.7.1.min.js", "js") loadjscssfile("https://cdnjs.cloudflare.com/ajax/libs/jvectormap/2.0.5/jquery-jvectormap.css", "css") loadjscssfile("https://jvectormap.com/js/jquery-jvectormap-2.0.5.min.js", "js") loadjscssfile("https://jvectormap.com/js/jquery-jvectormap-world-mill.js", "js") })();