您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Show more information about a geoguessr player on their profile page
// ==UserScript== // @name GeoGuessr More Player Stats // @namespace http://tampermonkey.net/ // @version 0.0.5 // @description Show more information about a geoguessr player on their profile page // @author btastic // @match https://www.geoguessr.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com // @grant none // @license MIT // ==/UserScript== function checkURL() { return location.pathname.includes("/user") || location.pathname.includes("/me/profile"); } function insertAfter(newNode, existingNode) { existingNode.parentNode.insertBefore(newNode, existingNode.nextSibling); } async function getUserProgress(profileId) { return fetch(location.origin + "/api/v4/ranked-system/progress/" + profileId) .then(out => out.json()) .catch(err => { console.log(err); return null; }); } async function getUserStats(profileId) { return fetch(location.origin + "/api/v3/users/" + profileId + "/stats") .then(out => out.json()) .catch(err => { console.log(err); return null; }); } function appendDivWithText(divToAppendTo, divId, text) { let div = document.createElement("div"); insertAfter(div, divToAppendTo); div.innerHTML = '<div id="' + divId + '"></div>'; document.getElementById(divId).innerText = text; } function displayAverageGameScore(moreInfoDiv, stats) { let averageGameScoreText = "Average game score: " + stats.averageGameScore.amount + " " + stats.averageGameScore.unit + " (" + Math.round(stats.averageGameScore.percentage, 2) + "%)"; appendDivWithText(moreInfoDiv, "average-gs", averageGameScoreText) } function displayAverageTimeToPlonk(moreInfoDiv, stats) { let averageTimeToPlonkText = "Average time to plonk: " + stats.averageTime; appendDivWithText(moreInfoDiv, "average-ttp", averageTimeToPlonkText) } function displayAverageDistance(moreInfoDiv, stats) { let averageDistanceText = "Average guess distance: " + stats.averageDistance.meters.amount + " " + stats.averageDistance.meters.unit; appendDivWithText(moreInfoDiv, "average-distance", averageDistanceText) } function displayGuessesFirstPercentage(moreInfoDiv, user) { let percentageText = null; if(user) { percentageText = Math.round(user.guessedFirstRate * 100) + "%"; } let guessFirstPercentage = percentageText ?? "N/A"; appendDivWithText(moreInfoDiv, "guesses-first", "Guesses first: " + guessFirstPercentage) } function createMoreInfoDiv(baseDiv, proDiv) { let moreInfoDiv = document.createElement("div"); moreInfoDiv.innerHTML = `<div id="more-info"></div>`; if (proDiv) { baseDiv.style = "display: inline-block; margin-right: 10px"; moreInfoDiv.style.display = "inline-block"; } insertAfter(moreInfoDiv, baseDiv); return moreInfoDiv; } let observer = new MutationObserver(async (mutations) => { if (!checkURL()) { return; } const profileLink = (location.pathname.includes("/me/profile")) ? document.querySelector('[name="copy-link"]').value : location.href; const profileId = profileLink.substr(profileLink.lastIndexOf("/") + 1); let user = await getUserProgress(profileId); let stats = await getUserStats(profileId); if(document.getElementById("more-info") != null) { return; } let proDiv = document.querySelector("[class*='profile-header_proBadgeWrapper__']"); let baseDiv = (proDiv) ? proDiv.firstChild : document.querySelector("[data-qa='user-card-title']"); let moreInfoDiv = createMoreInfoDiv(baseDiv, proDiv); displayAverageGameScore(moreInfoDiv, stats); displayAverageTimeToPlonk(moreInfoDiv, stats); displayAverageDistance(moreInfoDiv, stats); displayGuessesFirstPercentage(moreInfoDiv, user); }) observer.observe(document.body, { subtree: true, childList: true });