Geoguessr change Avatar to Pin

Adds the competitive rating to usernames

目前為 2023-05-07 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Geoguessr change Avatar to Pin
// @description  Adds the competitive rating to usernames
// @version      1.0.0
// @license      MIT
// @author       joniber#5011
// @namespace
// @match        https://www.geoguessr.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com
// @namespace https://greasyfork.org/users/1072330
// ==/UserScript==

//=====================================================================================\\
//    change these values however you like (make sure to hit ctrl+s afterwards)        \\
//=====================================================================================\\



const PIN_IN_OWN_PROFILE = true;
//                            ^^^^^ set this to 'false' if you don't want to display rating in the friends tab
const PIN_IN_OTHERS_PROFILE = true;
//                            ^^^^  set this to 'false' if you don't want to display rating in leaderboards
const PIN_IN_DUELS_MATCHMAKING = true;
//                            ^^^^  set this to 'false' if you don't want to display rating in matchmaking lobbies
const PIN_IN_BR_MATCHMAKING = true;
//                            ^^^^  set this to 'false' if you don't want to display rating ingame
const NO_AVATARS_END_OF_DUEL = true;
//=====================================================================================\\
//  don't edit anything after this point unless you know what you're doing             \\
//=====================================================================================\\

const GEOGUESSR_USER_ENDPOINT = 'https://geoguessr.com/api/v3/users';

const SCRIPT_PREFIX = 'up__';
const USER_PIN_CLASS = SCRIPT_PREFIX + 'userPin';
const USER_PIN_ID = SCRIPT_PREFIX + 'profilePin';


let player1 = null
let player2 = null

const OBSERVER_CONFIG = {
    characterDataOldValue: false,
    subtree: true,
    childList: true,
    characterData: false,
};

const ERROR_MESSAGE = (wrong) => '${wrong}';


function pathMatches(path) {
    return location.pathname.match(new RegExp(`^/(?:[^/]+/)?${path}$`));
}

function wrapperDuels(){
 return `<div class="profile-header_avatarWrapper__5_jDA up__"></div>`
}

function wrapper(){
 return `<div class="profile-header_avatar__y6vsp"><div class="avatar_titleAvatar__0pdL9"><div class="styles_rectangle___6gqv up__" style="padding-top: 100%;"><div class="avatar_titleAvatarImage__A51Dx up__"></div></div></div></div>`
}

function profilePicture(){
    return `<img class="styles_image__8M_kp ${USER_PIN_CLASS}" loading="auto" style="object-fit:cover;">`

}
function profilePicture1(){
    return `<img class="styles_image__8M_kp" id="${USER_PIN_ID}" loading="auto" style="object-fit:cover;">`

}

function levelBorder(){
   return `<picture class="avatar_titleAvatarFrame__AT57_ ${USER_PIN_CLASS}"><source type="image/avif"><source type="image/webp"><img class="avatar_titleAvatarFrame__AT57_"></picture>`
}

function levelBorder1(){
   return `<picture class="avatar_titleAvatarFrame__AT57_" id="${USER_PIN_ID}"><source type="image/avif"><source type="image/webp"><img class="avatar_titleAvatarFrame__AT57_"></picture>`
}


async function fillPin(pin, userId) {
    const userData = await getUserData(userId);
        const pinURL = userData.pin.url;
        pin.setAttribute('src', "/images/auto/144/144/ce/0/plain/" + pinURL)
}

async function fillLvl(lvl, userId){
    const userData = await getUserData(userId);
       const level = roundToNearest10(userData.progress.level)
       lvl.firstChild.setAttribute('srcset', "/static/avatars/tiers/low-quality/tier-" + level + ".avif")
       lvl.children[1].setAttribute('srcset', "/static/avatars/tiers/low-quality/tier-" + level + ".webp")
       lvl.lastChild.setAttribute('src', "/static/avatars/tiers/low-quality/tier-" + level + ".png")
    }


function changeAvatarToPin(link) {
     if(!document.querySelector(`.${USER_PIN_CLASS}`)){
            document.querySelector('.profile-header_fullBodyAvatar___LRnw').remove();
            let destination = document.querySelector(".profile-header_avatarWrapper__5_jDA")
            destination.insertAdjacentHTML("beforeend", wrapper());

            destination = document.querySelector('.avatar_titleAvatarImage__A51Dx.up__')
            destination.insertAdjacentHTML("beforeend", profilePicture())
            const pin = destination.lastChild
            fillPin(pin, retrieveIdFromLink(location.href))

            destination = document.querySelector(".styles_rectangle___6gqv.up__")
            destination.insertAdjacentHTML("beforeend", levelBorder())
            const lvl = destination.lastChild
            fillLvl(lvl, retrieveIdFromLink(location.href))


        }
}

function changeAvatarInGame(link) {
    if(!document.querySelector(`.${USER_PIN_CLASS}`)){
            document.querySelector('.profile-header_fullBodyAvatar___LRnw').remove();
            let destination = document.querySelector(".profile-header_avatarWrapper__5_jDA")
            destination.insertAdjacentHTML("beforeend", wrapper());

            destination = document.querySelector('.avatar_titleAvatarImage__A51Dx.up__')
            destination.insertAdjacentHTML("beforeend", profilePicture())
            const pin = destination.lastChild
            fillPin(pin, retrieveIdFromLink(location.href))

            destination = document.querySelector(".styles_rectangle___6gqv.up__")
            destination.insertAdjacentHTML("beforeend", levelBorder())
            const lvl = destination.lastChild
            fillLvl(lvl, retrieveIdFromLink(location.href))

        }
}

let inBattleRoyale = false;
let inDuels = false;
let lastOpenedMapHighscoreTab = 0;

function onMutationsBr(mutations, observer) {
    for(let q in document.getElementsByTagName('canvas')){
        q.remove();
    }
    if (PIN_IN_BR_MATCHMAKING) {
        // battle royale distance
        for (const link of document.querySelectorAll('.distance-player-list_name__fPSwC a')) {
            changeAvatarInGame(link);
        }

        // battle royale countries
        for (const link of document.querySelectorAll(
            '.countries-player-list_playerName__g4tnM a'
        )) {
            changeAvatarInGame(link);
        }
    }
}

function onMutationsDuels(mutations, observer) {
    // for(let i = 0; i<2; i++){
    //     let q = document.getElementsByTagName('canvas')[i];
    //     if(q!=null){
    //     q.remove();
    //     }
    // }
    if(NO_AVATARS_END_OF_DUEL){
        let avatar_end_of_duel_wrapper = document.querySelector('.game-finished_avatarContainer__S63IS')
        if (avatar_end_of_duel_wrapper != null){
            avatar_end_of_duel_wrapper.style.display="none";
        }
    }
    if (PIN_IN_DUELS_MATCHMAKING) {
        if(player1 == null){
         player1 = document.querySelectorAll('.lobby_avatarContainer__kN2RK')[0];
            if(player1 != null){
                console.log("--------------Player1------------")

                                 player1.children[0].firstChild.remove()
                                 player1.children[0].remove()
                    let destination1 = player1
                    destination1.insertAdjacentHTML('afterBegin', wrapperDuels())
                    destination1 = document.querySelector('.profile-header_avatarWrapper__5_jDA.up__')
                    destination1.insertAdjacentHTML('afterBegin', wrapper())
                   destination1 = document.querySelector('.avatar_titleAvatarImage__A51Dx.up__')
            destination1.insertAdjacentHTML("beforeEnd", profilePicture())
            const pin = destination1.lastChild
            let id = player1.lastChild.firstChild.href

            fillPin(pin, retrieveIdFromLink(id))
            destination1 = document.querySelector(".styles_rectangle___6gqv.up__")
            destination1.insertAdjacentHTML("beforeEnd", levelBorder())
            const lvl = destination1.lastChild
            console.log(player1)
            console.log(id)
            fillLvl(lvl, retrieveIdFromLink(id))

            }
        }
        if(player2 == null){
            player2 = document.querySelectorAll('.lobby_avatarContainer__kN2RK')[1];
            if(player2 != null){
                                console.log("--------------Player2------------")


                player2.children[0].firstChild.remove()
                player2.children[0].remove()
                let destination2 = player2
                    destination2.insertAdjacentHTML('afterBegin', wrapperDuels())
                    destination2 = document.querySelectorAll('.profile-header_avatarWrapper__5_jDA.up__')[1];
                    destination2.insertAdjacentHTML('afterBegin', wrapper())
                   destination2 = document.querySelectorAll('.avatar_titleAvatarImage__A51Dx.up__')[1];
            destination2.insertAdjacentHTML("beforeEnd", profilePicture())
            const pin1 = destination2.lastChild
            let id1 = player2.lastChild.firstChild.href

            fillPin(pin1, retrieveIdFromLink(id1))
            destination2 = document.querySelectorAll(".styles_rectangle___6gqv.up__")[1]
            destination2.insertAdjacentHTML("beforeEnd", levelBorder())
            const lvl1 = destination2.lastChild
            console.log(player2)
            console.log(id1)
            fillLvl(lvl1, retrieveIdFromLink(id1))
            }
        }

        if(player1 != null && player2 != null){
            player1 = null;
            player2 = null;
        }

    }}
function onMutationsStandard(mutations, observer) {
    if (isBattleRoyale() && document.querySelector('.game_hud__h3YxY ul') && !inBattleRoyale) {
        inBattleRoyale = true;
        const brObserver = new MutationObserver(onMutationsBr);
        brObserver.observe(document.querySelector('.game_hud__h3YxY ul'), OBSERVER_CONFIG);
    } else if (isDuels() && document.querySelector('.game_hud__fhdo5') && !inDuels) {
        inDuels = true;
        const duelsObserver = new MutationObserver(onMutationsDuels);
        duelsObserver.observe(document.querySelector('.game_hud__fhdo5'), OBSERVER_CONFIG);
    } else if (inBattleRoyale && !document.querySelector('.game_hud__h3YxY ul')) {
        inBattleRoyale = false;
    } else if (inDuels && !document.querySelector('.game_hud__fhdo5')) {
        inDuels = false;
    }
    if (inBattleRoyale || inDuels) {
        return;
    }
    if (isProfile() ) {
        if(!PIN_IN_OWN_PROFILE && isOwnProfile()){
         return
        }

        if(!PIN_IN_OTHERS_PROFILE && isOtherProfile()){
         return
        }


        if(!document.querySelector(`#${USER_PIN_ID}`)){
            document.querySelector('.profile-header_fullBodyAvatar___LRnw').remove();
            let destination = document.querySelector(".profile-header_avatarWrapper__5_jDA")
            destination.insertAdjacentHTML("beforeend", wrapper());

            destination = document.querySelector('.avatar_titleAvatarImage__A51Dx.up__')
            destination.insertAdjacentHTML("beforeend", profilePicture1())
            const pin = destination.lastChild
            fillPin(pin, retrieveIdFromLink(location.href))
            destination = document.querySelector(".styles_rectangle___6gqv.up__")
            destination.insertAdjacentHTML("beforeend", levelBorder1())
            const lvl = destination.lastChild
            fillLvl(lvl, retrieveIdFromLink(location.href))
        }
        }




    if (PIN_IN_BR_MATCHMAKING) {
        // battle royale matchmaking
        for (const link of document.querySelectorAll('.player-card_root__NvK_s')) {
            changeAvatarToPin(link);
        }




    }


   
}


//helpfunctions

function roundToNearest10(number) {
   return Math.ceil(number / 10) * 10;
}

function retrieveIdFromLink(link) {
    if (link.endsWith('/me/profile')) {
        const data = document.querySelector('#__NEXT_DATA__').text;
        const json = JSON.parse(data);
        return json.props.middlewareResults[1].account.user.userId;
    }
    return link.split('/').at(-1);
}

function isOtherProfile() {
    return pathMatches('user/.+');
}

function isOwnProfile() {
    return pathMatches('me/profile');
}

function isProfile() {
    return isOwnProfile() || isOtherProfile();
}

function isBattleRoyale() {
    return pathMatches('battle-royale/.+');
}

function isDuels() {
    return pathMatches('duels/.+');
}

async function getUserData(id) {
    const response = await fetch(`${GEOGUESSR_USER_ENDPOINT}/${id}`);
    const json = await response.json();

    return json;
}

const observer = new MutationObserver(onMutationsStandard);

observer.observe(document.body, OBSERVER_CONFIG);