PlonkViewer for GeoGuessr

Click on your marker to view google street view imagery at the location that you guessed!

// ==UserScript==
// @name         PlonkViewer for GeoGuessr
// @version      1.1
// @author       Han75
// @license      MIT
// @description  Click on your marker to view google street view imagery at the location that you guessed!
// @match        https://www.geoguessr.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com
// @namespace    https://greasyfork.org/en/users/973646
// ==/UserScript==

/**
 * IMPORTANT PLEASE READ THIS COMMENT. EXTENTION WILL NOT WORK IF YOU DONT.
 * This is a google street view API key. It is paid, but you can borrow geoguessr's API key for free. Follow these steps to do this:
 * 1. Start a game on geoguessr, then press F12 to open the developer tools menu. You may want to resize this menu to make it bigger
 * 2. Go to the "network" tab. If it's hidden, you may have to click the double arrows ">>" icon to find it.
 * 3. In the "filter" box, copy this phrase(Without the quotes): "ViewportInfoService"
 * 4. Click on the viewportinfoservice pop-up under the "Name" section.
 * 5. In the "general">"Request URL" section you should see something that looks like this:
 *  https://maps.googleapis.com/maps/api/js/ViewportInfoService.GetViewportInfo?...
 *      {Lots of random text and numbers}...&key=TheAPIKey_12345&token=119870
 *    in this case, the API key that we are interested in is "TheAPIKey_12345".
 *    copy the Key and paste it below where it says "KEY_HERE".
 */


const API_KEY = `KEY_HERE`;
//GeoGuessr games API
const GEO_GAME_API = `https://www.geoguessr.com/api/v3/games/`;
//Google API endpoint that finds the nearest street view location.
//Returns closest latlong in under the key ["location"]["lat"], ["location"]["lng"]
const ENDPOINT_10KM_SV_API = `https://maps.googleapis.com/maps/api/streetview/metadata?key=${API_KEY}&radius=10000&location=`;
//Returns closest latlong in under the key ["location"]["lat"], ["location"]["lng"]
const ENDPOINT_100KM_SV_API = `https://maps.googleapis.com/maps/api/streetview/metadata?key=${API_KEY}&radius=100000&location=`;
//The street view location. Add `{lattitude},{longitude}` to this.
const ENDPOINT_SV_URL = `https://google.com/maps?q&layer=c&cbll=`;

async function latlngToGSV(lat, lng) {
    //Search for streetview coverage within a 10 KM radius(Smaller radius helps to find official coverage)
    let dataURL = `${ENDPOINT_10KM_SV_API}${lat},${lng}`;
    let res = await fetch(dataURL);
    let data = await res.json();
    let retURL = "";
    //If no street view in a 10 KM radius, search a 100KM radius. With this setting its more likely to find 
    //photo spheres and trekker. 
    if(data["status"] === "ZERO_RESULTS"){
        let dataaURL = `${ENDPOINT_100KM_SV_API}${lat},${lng}`;
        let ress = await fetch(dataaURL);
        let dataa = await ress.json();
        //If coverage cannot be found, return street view of the eifel tower. 
        if(dataa["status"]==="ZERO_RESULTS"){
            retURL = "https://google.com/maps?q&layer=c&cbll=48.8568513,2.2967612";
        }else{
        //If coverage is found return street view link to the coverage. 
            retURL = `${ENDPOINT_SV_URL}${dataa["location"]["lat"]},${dataa["location"]["lng"]}`;
        }
    }else{
        retURL = `${ENDPOINT_SV_URL}${data["location"]["lat"]},${data["location"]["lng"]}`;
    }
    return retURL;
}
//Get player guesses for a game.
async function getPlayerGuesses() {
    let gameID = document.querySelector('meta[property="og:url"]').getAttribute("content").split("/")[4];
    let dataURL = `${GEO_GAME_API}${gameID}`;
    let res = await fetch(dataURL);
    let data = await res.json();
    return data["player"]["guesses"];
}

window.onload = (e) => {
    // Select the target node (the element to be monitored for changes)
    let targetNode = document.body;
    let stopRepeat=false;
    // Options for the observer (which mutations to observe)
    let config = { attributes: true, childList: true, subtree: true };

    // Callback function to execute when mutations are observed
    let oldContext="";
    let callback = function (mutationsList, observer) {
        // Get all divs with the desired attribute
        if(API_KEY==="KEY_HERE") return;
        
        let link = document.querySelector('meta[property="og:url"]').getAttribute("content");
        let context = link.split("/")[3];
        if (oldContext!=context){
            oldContext=context;
            stopRepeat=false;
        }
        let divs;
        switch(context){
            case "game":
                if(stopRepeat) return;
                divs = document.querySelectorAll('div[data-qa="guess-marker"]');
                // If there are more than one divs, execute the desired function
                if (divs.length > 1) {
                    stopRepeat=true;
                    executeFunction(divs);
                }
                break;
            case "results":
                if(stopRepeat||!document.querySelector("title").innerText.includes("Game breakdown")) return;
                divs = document.querySelectorAll('div.map-pin_mapPin__fiygK:not(.map-pin_clickable__2reGS)');
                if (divs.length > 1) {
                    stopRepeat=true;
                    executeFunction(divs);
                }
                break;
            default:
                stopRepeat=false;
        }

            
        
    };

    // Create an observer instance linked to the callback function
    let observer = new MutationObserver(callback);

    // Start observing the target node for configured mutations
    observer.observe(targetNode, config);

    async function executeFunction(playerMarkers) {

        
        let playerGuesses = await getPlayerGuesses();
        if(playerGuesses===undefined||playerGuesses.length===undefined){
            return;
        }
        for (let i = 0; i < playerGuesses.length; i++) {

            let lat = playerGuesses[i]["lat"];
            let lng = playerGuesses[i]["lng"];
            let streetViewURL = await latlngToGSV(lat, lng);
            playerMarkers[i].style.cursor="pointer";
            playerMarkers[i].addEventListener("click", function () {
                window.open(streetViewURL, "_blank");
            });
        }
    }
    
}