Geoguessr change Avatar to Pin

Adds the competitive rating to usernames

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

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==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);