// ==UserScript== // @name Elo tracker // @version 0.3 // @description Adds an elo tracker to the GeoGuessr website // @match https://www.geoguessr.com/* // @run-at document-start // @author eru // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com // @grant none // @namespace https://greasyfork.org/users/1348455 // @downloadURL none // ==/UserScript== /* jshint esversion: 8 */ const API_URL = 'https://ggstats.eu'; function getMode(mode_string) { let low = mode_string.toLowerCase(); if (low.includes('no')) return 'nm'; if (low.includes('mov')) return 'move'; if (low.includes('nm')) return 'nmpz'; } async function getUserInfo() { try { const response = await fetch('https://www.geoguessr.com/api/v3/profiles'); if (!response.ok) { throw new Error(`HTTP error! Status: ${response.status}`); } const data = await response.json(); return {nick: data.user.nick, hexId: data.user.id, pinUrl: data.user.pin.url, level: data.user.br.level}; } catch (error) { console.error('Error fetching data:', error); return null; } } function updateElo(data) { fetch(API_URL+'/add-elo', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }).then(response => response.json()).then(data => console.log('Success:', data)).catch((error) => console.error('Error:', error)); } function run() { const elo_string = document.querySelector('div[class*="reward-item_rating__"]').firstChild.textContent; const mode_string = document.querySelector('div[class*="game-mode-brand_possibleTitle__"]').textContent; const mode_elo_container = document.querySelector('div[class*="reward-item_gameModeRating__"]'); getUserInfo() .then(infos => { const { nick, hexId, pinUrl, level } = infos; const data = { name: nick, playerHexId: hexId, elo: parseInt(elo_string), pinUrl: pinUrl, level: parseInt(level), mode: getMode(mode_string), modeElo: mode_elo_container ? parseInt(mode_elo_container.firstChild.textContent) : null }; console.log(data); updateElo(data); }) } let lastDoCheckCall = 0; // Any changes in the DOM triggers the MutationObserver callback new MutationObserver(async (mutations) => { // First make sure we are in a game if (!location.pathname.includes("/duels/") || lastDoCheckCall >= (Date.now() - 50)) return; lastDoCheckCall = Date.now(); // Then make sure we are in the finished game screen if (!document.querySelector('div[class*="game-finished-ranked_container__"]')) { sessionStorage.setItem("Checked", 0); return; } else if ((sessionStorage.getItem("Checked") || 0) == 0) { setTimeout(run, 4000); sessionStorage.setItem("Checked", 1); } }).observe(document.body, { subtree: true, childList: true });