Geoguessr change Avatar to Pin/ProfilePicture

Changes the Avatar to your Pin/Profile Picture. Works in Duels, Br, Profile and many more places and not only your Avatar but also the Avatar of others

当前为 2023-05-11 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

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

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Geoguessr change Avatar to Pin/ProfilePicture
// @description  Changes the Avatar to your Pin/Profile Picture. Works in Duels, Br, Profile and many more places and not only your Avatar but also the Avatar of others
// @version      1.0.4
// @license      MIT
// @author       joniber#5011
// @match        https://www.geoguessr.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com
// @namespace https://greasyfork.org/users/1072330
// ==/UserScript==

//any questons, feedback, problems or feature request -> Discord joniber#5011

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

const PIN_IN_OWN_PROFILE = true;
//                         ^^^^  set this to <false> to NOT change your Avatar to a PIN in your own profile
const PIN_IN_OTHERS_PROFILE = true;
//                            ^^^^^  set this to <false> to NOT change the Avatar to a PIN in other profiles
const PIN_IN_DUELS_MATCHMAKING = true;
//                         ^^^^  set this to <false> to NOT change the Avatar to a PIN in that area
const PIN_IN_BR_MATCHMAKING = true;
//                         ^^^^  set this to <false> to NOT change the Avatar to a PIN in that area
const NO_AVATARS_END_OF_DUEL = true;
//                         ^^^^  set this to <false> to NOT change the Avatar to a PIN in that area
const PIN_IN_TEAM_DUEL_PRIVATE_LOBBY = true;
//                         ^^^^  set this to <false> to NOT change the Avatar to a PIN in that area
const PIN_IN_FRIEND_TAB = true;
//                         ^^^^  set this to <false> to NOT change the Avatar to a PIN in that area

//=====================================================================================\\
//  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 av = null;
let index = 0;
let player1 = null;
let player2 = null;

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');
}

async function changePinInFriendTab(link) {
    if (link != null) {
        if (!link.querySelector(`.${USER_PIN_CLASS}`)) {
            let id = link.querySelector('.anchor_variantNoUnderline__SPwsd').href;
            let wrapper = link.querySelector(
                '.transparent-avatar_background__M_sZ3.transparent-avatar_colorWhite20__fmhRd'
            );
            if (wrapper != null) {
                wrapper.lastChild.remove();
            }
            wrapper.insertAdjacentHTML('beforeend', wrapperFriend());
            let destination = link.querySelector('.styles_content__otIVG');
            destination.insertAdjacentHTML('afterbegin', profilePicture());
            const pin = destination.lastChild;

            const userId = retrieveIdFromLink(id);
            const userData = await getUserData(userId);
            const pinURL = userData.pin.url;
            pin.classList.add('styles_image__8M_kp');
            pin.setAttribute('src', '/images/auto/48/48/ce/0/plain/' + pinURL);
        }
    }
}

function changeAvatarToPin(link, avatarToRemove) {
    if (!link.querySelector(`.${USER_PIN_CLASS}`)) {
        if (link != null || link != '') {
            let destination = null;
            if (avatarToRemove == link) {
                link.querySelector('.styles_image__8M_kp').style = 'display: none';
                destination = link.firstChild;
            } else {
                link.querySelector('.player-card_lobbyCardInner__G_xzy').firstChild.remove();
                destination = link.querySelector('.player-card_lobbyCardInner__G_xzy');
            }

            destination.insertAdjacentHTML('afterbegin', wrapperDuels());
            destination = link.querySelector('.profile-header_avatarWrapper__5_jDA.up__');
            destination.insertAdjacentHTML('afterbegin', wrapper());
            destination = link.querySelector('.avatar_titleAvatarImage__A51Dx.up__');
            destination.insertAdjacentHTML('beforeend', profilePicture());
            const pin = destination.lastChild;
            let id = '/me/profile';
            if (link.querySelector('.player-card_userLink__HhoDo') != null) {
                id = link.querySelector('.player-card_userLink__HhoDo').href;
            }
            fillPin(pin, retrieveIdFromLink(id));
            destination = link.querySelector('.styles_rectangle___6gqv.up__');
            destination.insertAdjacentHTML('beforeend', levelBorder());
            const lvl = destination.lastChild;
            fillLvl(lvl, retrieveIdFromLink(id));
        }
    }
}

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

function onMutationEnd(mutations, observer) {
    if (NO_AVATARS_END_OF_DUEL) {
        const gameFinishedAvatarContainer = document.querySelector(
            '.game-finished_avatarContainer__S63IS'
        );
        if (gameFinishedAvatarContainer) {
            if (document.querySelector('.styles_rectangle___6gqv.up__') == null) {
                gameFinishedAvatarContainer.firstChild.remove();
                let destination = gameFinishedAvatarContainer;
                destination.style = 'height: fit-content';
                destination.insertAdjacentHTML('afterbegin', wrapperDuels());
                destination = document.querySelector('.profile-header_avatarWrapper__5_jDA.up__');
                destination.insertAdjacentHTML('afterbegin', wrapper());
                document.querySelector('.profile-header_avatar__y6vsp').style =
                    'display:flex; justify-content:center; align-items:center';
                document.querySelector('.avatar_titleAvatar__0pdL9').style = 'width:20rem';
                destination = document.querySelector('.avatar_titleAvatarImage__A51Dx.up__');
                destination.insertAdjacentHTML('beforeend', profilePicture());
                const pin = destination.lastChild;
                let id = '/me/profile';
                fillPin(pin, retrieveIdFromLink(id));
                destination = document.querySelector('.styles_rectangle___6gqv.up__');
                destination.insertAdjacentHTML('beforeend', levelBorder());
                const lvl = destination.lastChild;
                if (
                    document.querySelector('.shadow-text_root__o3lD9').innerHTML.startsWith('YOU')
                ) {
                    fillLvl(lvl, retrieveIdFromLink(id));
                } else {
                    lvl.lastChild.setAttribute(
                        'src',
                        '/_next/static/images/laurel-wreath-gold-53fd377e1d268ce57fcd6f0dfb9f3727.png'
                    );
                }
            }
        }
    }
}

function onMutationsDuels(mutations, observer) {
    if (player1 == null) {
        player1 = document.querySelectorAll('.lobby_avatarContainer__kN2RK')[0];
        if (player1 != null) {
            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;
            fillLvl(lvl, retrieveIdFromLink(id));
        }
        player2 = document.querySelectorAll('.lobby_avatarContainer__kN2RK')[1];
        if (player2 != null) {
            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;
            fillLvl(lvl1, retrieveIdFromLink(id1));
        }
    }
    if (player1 != null && player2 != null) {
        player1 = null;
        player2 = null;
    }

    const endOfDuelsObserver = new MutationObserver(onMutationEnd);
    endOfDuelsObserver.observe(document.querySelector('.overlay_overlay__AR02x'), OBSERVER_CONFIG);
}
function onMutationsStandard(mutations, observer) {
    if (isDuels() && !inDuels && document.querySelector('.game_hud__fhdo5')) {
        inDuels = true;
        console.log('duels mode');
        console.log(document.querySelector('.game_hud__fhdo5'));
        const duelsObserver = new MutationObserver(onMutationsDuels);
        duelsObserver.observe(document.querySelector('.game_hud__fhdo5'), OBSERVER_CONFIG);
    } else if (inDuels && !document.querySelector('.game_hud__fhdo5')) {
        inDuels = false;
        console.log('normal mode');
    }
    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_TEAM_DUEL_PRIVATE_LOBBY) {
        const link = document.querySelector(
            '.team-player-card_lobbyCard__7p_OY.team-player-card_activePlayerCard__blWk7'
        );
        if (link) {
            changeAvatarToPin(link, link);
        }
    }

    if (PIN_IN_BR_MATCHMAKING) {
        // battle royale matchmaking

        for (const link of document.querySelectorAll('.player-card_root__NvK_s')) {
            changeAvatarToPin(link, 'player-card_lobbyCardInner__G_xzy');
        }
    }
    if (PIN_IN_FRIEND_TAB) {
        for (const link of document.querySelectorAll('.chat-friend_content__zbEBt')) {
            changePinInFriendTab(link);
        }
    }
    if (isDuels() && PIN_IN_DUELS_MATCHMAKING) {
        if (!document.querySelector(`#${USER_PIN_ID}`)) {
            if (av == null) {
                av = document.querySelector('.lobby_avatarContainer__kN2RK');
            }
            if (av != null) {
                av.children[0].remove();
                let destination_dw = av;
                destination_dw.insertAdjacentHTML('afterbegin', wrapperDuels());
                destination_dw = document.querySelector(
                    '.profile-header_avatarWrapper__5_jDA.up__'
                );
                destination_dw.insertAdjacentHTML('afterbegin', wrapper());
                destination_dw = document.querySelector('.avatar_titleAvatarImage__A51Dx.up__');
                destination_dw.insertAdjacentHTML('beforeend', profilePicture1());
                const pin = destination_dw.lastChild;
                let id = 'https://www.geoguessr.com/me/profile';

                fillPin(pin, retrieveIdFromLink(id));
                destination_dw = document.querySelector('.styles_rectangle___6gqv.up__');
                destination_dw.insertAdjacentHTML('beforeend', levelBorder1());
                const lvl = destination_dw.lastChild;
                fillLvl(lvl, retrieveIdFromLink(id));
            }
            if (av != null) {
                av = null;
            }
        }
    }
    if (document.getElementById('60cf2c9800ea7b00015231a2')) {
        document.getElementById('60cf2c9800ea7b00015231a2').remove();
        if (!document.querySelector(`#${USER_PIN_ID}`)) {
            let destination = document.querySelector('.join-party_avatarWrapper__2WzCN');
            destination.insertAdjacentHTML('afterbegin', wrapper());
            destination = document.querySelector('.avatar_titleAvatarImage__A51Dx.up__');
            destination.insertAdjacentHTML('beforeend', profilePicture1());
            const pin = destination.lastChild;
            fillPin(pin, retrieveIdFromLink('/me/profile'));
            destination = document.querySelector('.styles_rectangle___6gqv.up__');
            destination.insertAdjacentHTML('beforeend', levelBorder1());
            const lvl = destination.lastChild;
            fillLvl(lvl, retrieveIdFromLink('/me/profile'));
        }
    }
}

//helpfunctions

function roundToNearest10(zahl) {
   if (zahl % 10 === 0) {
    return zahl + 10;
  } else {
    return Math.ceil(zahl / 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;
}

function wrapperFriend() {
    return `<div class="styles_circle__QFYEk styles_variantFloating__Srm_N styles_colorTransparent__2bG5I styles_borderColorTransparent__CwSAk styles_borderSizeFactorZero__MEFpf"><div class="styles_rectangle___6gqv" style="padding-top: 100%;"><div class="styles_innerCircle__Y_L_e"><div class="styles_content__otIVG up__"></div></div></div></div>`;
}
function wrapperDuels() {
    return `<div class="profile-header_avatarWrapper__5_jDA up__"></div>`;
}

function wrapperEndOfDuels() {
    return `<div class="profile-header_avatar__y6vsp 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>`;
}

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}$`));
}

const observer = new MutationObserver(onMutationsStandard);

observer.observe(document.body, OBSERVER_CONFIG);