Extended Duels Summary in Activies Page

Adds opponent name and final score to Activies Page for duels

目前为 2025-02-11 提交的版本。查看 最新版本

// ==UserScript==
// @name         Extended Duels Summary in Activies Page
// @namespace    http://tampermonkey.net/
// @version      1.2
// @description  Adds opponent name and final score to Activies Page for duels
// @author       tyow
// @namespace    https://gf.qytechs.cn/users/1011193
// @match        *://*.geoguessr.com/*
// @license      MIT
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @require      https://gf.qytechs.cn/scripts/460322-geoguessr-styles-scan/code/Geoguessr%20Styles%20Scan.js?version=1151668
// ==/UserScript==

const extractUserInfo = (duelData, userId) => {
    let userTeam = null;
    let userTeamHealth = 0;
    let opposingTeamHealth = 0;
    let userWon = false;

    for (const team of duelData.teams) {
        const isUserInTeam = team.players.some(player => player.playerId === userId);
        if (isUserInTeam) {
            userTeam = team.name;
            userTeamHealth = team.health;
            userWon = duelData.result.winningTeamId === team.id;
        } else {
            opposingTeamHealth = team.health;
        }
    }

    return { userTeam, userTeamHealth, opposingTeamHealth, userWon, rounds: duelData.rounds.length };
};

const fetchPlayerName = async (playerId) => {
    const playerApiUrl = `https://www.geoguessr.com/api/v3/users/${playerId}`;
    try {
        const response = await fetch(playerApiUrl, { method: "GET", "credentials": "include" });
        const data = await response.json();
        return data.nick;
    } catch (error) {
        console.error('Failed to fetch player data:', error);
        return null;
    }
};

const extractPlayerIds = (duelData, userId) => {
    let ourTeam = null;
    let theirTeam = null;
    for (const team of duelData.teams) {
        if (team.players.some(player => player.playerId === userId)) {
            ourTeam = team;
        } else {
            theirTeam = team;
        }
    }
    let partnerId = null;
    for (const player of ourTeam.players) {
        if (player.playerId !== userId) {
            partnerId = player.playerId;
        }
    }
    let opposingPlayerIds = theirTeam.players.map(player => player.playerId);

    return { user: userId, partner: partnerId, opponents: opposingPlayerIds };
};


GM_addStyle(`
    .lostColor {
        color: #e94560;
    }
    .wonColor {
        color: #6cb928;
    }
`);


const createNickLink = (id, name) => {
    const link = document.createElement('a');
    link.href = `/user/${id}`;

    const rootDiv = document.createElement('div');
    rootDiv.className = cn("user-nick_root__");

    const nickWrapperDiv = document.createElement('div');
    nickWrapperDiv.className = cn("user-nick_nickWrapper__");

    const nickDiv = document.createElement('div');
    nickDiv.className = cn("user-nick_nick__");
    nickDiv.textContent = name;

    nickWrapperDiv.appendChild(nickDiv);
    rootDiv.appendChild(nickWrapperDiv);
    link.appendChild(rootDiv);

    return link;
}


const appendGameSummary = (div, partnerName, partnerId,
                                opponent1Name, opponent1Id,
                                opponent2Name, opponent2Id,
                           playerScore, opponentScore, rounds) =>
{
    div.innerHTML = div.innerHTML.substring(0, div.innerHTML.length - 1);
    const res = playerScore > opponentScore ? "won" : "lost";
    div.innerHTML = div.innerHTML.replace("played", `<span class='${res}Color'>${res}</span>`)

    const partnerLink = partnerName ? createNickLink(partnerId, partnerName) : null;
    const opponent1Link = createNickLink(opponent1Id, opponent1Name);
    const opponent2Link = opponent2Name ? createNickLink(opponent2Id, opponent2Name) : null;

    if (partnerLink) {
        div.appendChild(document.createTextNode(` with `));
        div.appendChild(partnerLink);
    }

    div.appendChild(document.createTextNode(` against `));
    div.appendChild(opponent1Link);

    if (opponent2Link) {
        div.appendChild(document.createTextNode(` and `));
        div.appendChild(opponent2Link);
    }

    const roundsAndScore = document.createTextNode(` after ${rounds} rounds. The final score was ${playerScore} - ${opponentScore}.`);
    div.appendChild(roundsAndScore);
};


const checkURL = () => location.pathname.endsWith("/me/activities")

const fetchUserId = async () => {
    // Check if the user ID is already stored in the browser's storage
    const storedUserId = GM_getValue('userId');

    if (storedUserId) {
        return storedUserId;
    } else {
        // Make the API call if the user ID is not stored
        const response = await fetch('https://www.geoguessr.com/api/v3/profiles', {
            method: "GET",
            credentials: "include" // or other appropriate options
        });
        const data = await response.json();
        const userId = data.user.id; // Assuming the response JSON has an 'id' field
        // Store the user ID in the browser's storage
        GM_setValue('userId', userId);

        return userId;
    }
};


const run = async () => {
    scanStyles().then(_ => {
        const allDivs = document.querySelectorAll("[class^='activities_description__']");

        const filteredDivs = Array.from(allDivs).filter(div => {
            if (div.classList.length == 2 && div.classList[1] == "extraSummary") return false;
            const a = div.querySelector('a[href^="/duels/"]');
            const team_a = div.querySelector('a[href^="/team-duels/"]');
            return a !== null || team_a !== null;
        });

        for (const div of filteredDivs) {
            let isTeamDuel = false;
            let duelLink = div.querySelector('a[href^="/duels/"]');
            if (duelLink === null) {
                duelLink = div.querySelector('a[href^="/team-duels/"]');
                isTeamDuel = true;
            }
            div.className += " extraSummary";

            if (duelLink) {
                const duelHref = duelLink.getAttribute('href');
                let duelId = isTeamDuel ? duelHref.split('/team-duels/')[1] : duelHref.split('/duels/')[1];
                if (duelId.endsWith('/summary')) {
                    duelId = duelId.slice(0, -'/summary'.length);
                }

                let api_url = `https://game-server.geoguessr.com/api/duels/${duelId}`;
                fetch(api_url, {method: "GET", "credentials": "include"})
                    .then(res => res.json())
                    .then(async json =>
                {
                    const userLink = div.querySelector('a[href^="/user/"]');
                    const userId = userLink ? userLink.getAttribute('href').split('/user/')[1] : await fetchUserId();

                    const { userTeam, userTeamHealth, opposingTeamHealth, userWon, rounds } = extractUserInfo(json, userId);
                    const playerIds = extractPlayerIds(json, userId);
                    const partnerId = playerIds.partner;
                    if (partnerId) {
                        const partnerName = await fetchPlayerName(partnerId);
                        const opponent1Name = await fetchPlayerName(playerIds.opponents[0]);
                        const opponent2Name = await fetchPlayerName(playerIds.opponents[1]);
                        appendGameSummary(div, partnerName, partnerId,
                               opponent1Name, playerIds.opponents[0],
                               opponent2Name, playerIds.opponents[1],
                               userTeamHealth, opposingTeamHealth, rounds);
                    } else {
                        const opponentName = await fetchPlayerName(playerIds.opponents[0]);
                        appendGameSummary(div, null, null,
                                          opponentName, playerIds.opponents[0],
                                          null, null,
                                          userTeamHealth, opposingTeamHealth, rounds);
                    }
                }).catch(err => { throw(err); });
            }
        }
    })
}

new MutationObserver((mutations) => {
    if (!checkURL()) return;
    run();
}).observe(document.body, { subtree: true, childList: true });

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址