Greasy Fork

Greasy Fork is available in English.

Extended Duels Summary in Activies Page

Adds opponent name and final score to Activies Page for duels

当前为 2024-04-17 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Extended Duels Summary in Activies Page
// @namespace    http://tampermonkey.net/
// @version      1.1.1
// @description  Adds opponent name and final score to Activies Page for duels
// @author       tyow
// @namespace    http://greasyfork.icu/users/1011193
// @match        *://*.geoguessr.com/*
// @license      MIT
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @require      http://greasyfork.icu/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 extractOpponentId = (duelData, userId) => {
    for (const team of duelData.teams) {
        for (const player of team.players) {
            if (player.playerId !== userId) {
                return player.playerId;
            }
        }
    }
    return null;
};


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


const appendGameSummary = (div, opponentName, opponentId, 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 opponentLink = document.createElement('a');
    opponentLink.href = `/user/${opponentId}`;

    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 = opponentName;

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

    const summaryTextNode = document.createTextNode(` against `);
    div.appendChild(summaryTextNode);

    div.appendChild(opponentLink);

    const roundTotal = document.createTextNode(` after ${rounds} rounds`);
    div.appendChild(roundTotal);

    const secondLine = document.createElement('div');
    secondLine.innerHTML = `The final score was ${playerScore} - ${opponentScore}`;
    div.appendChild(secondLine);
};


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(_ => {
        // TODO: Mark divs that have been or are being actively worked on
        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/"]');
            return a !== null;
        });

        for (const div of filteredDivs) {
            const duelLink = div.querySelector('a[href^="/duels/"]');
            div.className += " extraSummary"

            if (duelLink) {
                const duelHref = duelLink.getAttribute('href');
                let duelId = 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}`;
                //doingRequest = true;
                fetch(api_url, {method: "GET", "credentials": "include"})
                    .then(res => res.json())
                    .then(async json => {
                    // console.log('Duel data:', json);
                    const userLink = div.querySelector('a[href^="/user/"]');
                    let userId;

                    if (userLink) {
                        const userHref = userLink.getAttribute('href');
                        userId = userHref.split('/user/')[1];
                    } else {
                        userId = await fetchUserId(); // Function to make API call and get userId
                    }

                    //                console.log('User ID:', userId);
                    const { userTeam, userTeamHealth, opposingTeamHealth, userWon, rounds } = extractUserInfo(json, userId);
                    const opponentId = extractOpponentId(json, userId);

                    if (opponentId) {
                        const opponentName = await fetchPlayerName(opponentId);
                        //                  console.log('Opponent Name:', opponentName);
                        appendGameSummary(div, opponentName, opponentId, userTeamHealth, opposingTeamHealth, rounds);
                    }
                }).catch(err => { throw(err); });
            }
        }
    })
}

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