- // ==UserScript==
- // @name Country Streak Counter
- // @version 1.3.2
- // @description Adds a country streak counter to the GeoGuessr website
- // @match https://www.geoguessr.com/*
- // @author victheturtle#5159
- // @license MIT
- // @icon https://www.google.com/s2/favicons?sz=64&domain=geoguessr.com
- // @namespace https://gf.qytechs.cn/users/967692-victheturtle
- // ==/UserScript==
-
- // Credits to subsymmetry for the original version of the Streak Counter
-
- let ENABLED_ON_CHALLENGES = false; //Replace with true or false
- let API_Key = 'ENTER_API_KEY_HERE'; //Replace ENTER_API_KEY_HERE with your API key (so keep the quote marks)
- let AUTOMATIC = true; //Replace with false for a manual counter. Without an API key, the counter will still be manual
-
-
- if (sessionStorage.getItem("Streak") == null) {
- sessionStorage.setItem("Streak", 0);
- };
- if (sessionStorage.getItem("StreakBackup") == null) {
- sessionStorage.setItem("StreakBackup", 0);
- };
- if (sessionStorage.getItem("Checked") == null) {
- sessionStorage.setItem("Checked", 0);
- };
-
- let streak = parseInt(sessionStorage.getItem("Streak"), 10);
- let last_guess = [0,0];
- const ERROR_RESP = -1000000;
-
- var CountryDict = {
- AF: 'AF',
- AX: 'FI', // Aland Islands
- AL: 'AL',
- DZ: 'DZ',
- AS: 'US', // American Samoa
- AD: 'AD',
- AO: 'AO',
- AI: 'GB', // Anguilla
- AQ: 'AQ', // Antarctica
- AG: 'AG',
- AR: 'AR',
- AM: 'AM',
- AW: 'NL', // Aruba
- AU: 'AU',
- AT: 'AT',
- AZ: 'AZ',
- BS: 'BS',
- BH: 'BH',
- BD: 'BD',
- BB: 'BB',
- BY: 'BY',
- BE: 'BE',
- BZ: 'BZ',
- BJ: 'BJ',
- BM: 'GB', // Bermuda
- BT: 'BT',
- BO: 'BO',
- BQ: 'NL', // Bonaire, Sint Eustatius, Saba
- BA: 'BA',
- BW: 'BW',
- BV: 'NO', // Bouvet Island
- BR: 'BR',
- IO: 'GB', // British Indian Ocean Territory
- BN: 'BN',
- BG: 'BG',
- BF: 'BF',
- BI: 'BI',
- KH: 'KH',
- CM: 'CM',
- CA: 'CA',
- CV: 'CV',
- KY: 'UK', // Cayman Islands
- CF: 'CF',
- TD: 'TD',
- CL: 'CL',
- CN: 'CN',
- CX: 'AU', // Christmas Islands
- CC: 'AU', // Cocos (Keeling) Islands
- CO: 'CO',
- KM: 'KM',
- CG: 'CG',
- CD: 'CD',
- CK: 'NZ', // Cook Islands
- CR: 'CR',
- CI: 'CI',
- HR: 'HR',
- CU: 'CU',
- CW: 'NL', // Curacao
- CY: 'CY',
- CZ: 'CZ',
- DK: 'DK',
- DJ: 'DJ',
- DM: 'DM',
- DO: 'DO',
- EC: 'EC',
- EG: 'EG',
- SV: 'SV',
- GQ: 'GQ',
- ER: 'ER',
- EE: 'EE',
- ET: 'ET',
- FK: 'GB', // Falkland Islands
- FO: 'DK', // Faroe Islands
- FJ: 'FJ',
- FI: 'FI',
- FR: 'FR',
- GF: 'FR', // French Guiana
- PF: 'FR', // French Polynesia
- TF: 'FR', // French Southern Territories
- GA: 'GA',
- GM: 'GM',
- GE: 'GE',
- DE: 'DE',
- GH: 'GH',
- GI: 'UK', // Gibraltar
- GR: 'GR',
- GL: 'DK', // Greenland
- GD: 'GD',
- GP: 'FR', // Guadeloupe
- GU: 'US', // Guam
- GT: 'GT',
- GG: 'GB', // Guernsey
- GN: 'GN',
- GW: 'GW',
- GY: 'GY',
- HT: 'HT',
- HM: 'AU', // Heard Island and McDonald Islands
- VA: 'VA',
- HN: 'HN',
- HK: 'CN', // Hong Kong
- HU: 'HU',
- IS: 'IS',
- IN: 'IN',
- ID: 'ID',
- IR: 'IR',
- IQ: 'IQ',
- IE: 'IE',
- IM: 'GB', // Isle of Man
- IL: 'IL',
- IT: 'IT',
- JM: 'JM',
- JP: 'JP',
- JE: 'GB', // Jersey
- JO: 'JO',
- KZ: 'KZ',
- KE: 'KE',
- KI: 'KI',
- KR: 'KR',
- KW: 'KW',
- KG: 'KG',
- LA: 'LA',
- LV: 'LV',
- LB: 'LB',
- LS: 'LS',
- LR: 'LR',
- LY: 'LY',
- LI: 'LI',
- LT: 'LT',
- LU: 'LU',
- MO: 'CN', // Macao
- MK: 'MK',
- MG: 'MG',
- MW: 'MW',
- MY: 'MY',
- MV: 'MV',
- ML: 'ML',
- MT: 'MT',
- MH: 'MH',
- MQ: 'FR', // Martinique
- MR: 'MR',
- MU: 'MU',
- YT: 'FR', // Mayotte
- MX: 'MX',
- FM: 'FM',
- MD: 'MD',
- MC: 'MC',
- MN: 'MN',
- ME: 'ME',
- MS: 'GB', // Montserrat
- MA: 'MA',
- MZ: 'MZ',
- MM: 'MM',
- NA: 'NA',
- NR: 'NR',
- NP: 'NP',
- NL: 'NL',
- AN: 'NL', // Netherlands Antilles
- NC: 'FR', // New Caledonia
- NZ: 'NZ',
- NI: 'NI',
- NE: 'NE',
- NG: 'NG',
- NU: 'NZ', // Niue
- NF: 'AU', // Norfolk Island
- MP: 'US', // Northern Mariana Islands
- NO: 'NO',
- OM: 'OM',
- PK: 'PK',
- PW: 'PW',
- PS: 'IL', // Palestine
- PA: 'PA',
- PG: 'PG',
- PY: 'PY',
- PE: 'PE',
- PH: 'PH',
- PN: 'GB', // Pitcairn
- PL: 'PL',
- PT: 'PT',
- PR: 'US', // Puerto Rico
- QA: 'QA',
- RE: 'FR', // Reunion
- RO: 'RO',
- RU: 'RU',
- RW: 'RW',
- BL: 'FR', // Saint Barthelemy
- SH: 'GB', // Saint Helena
- KN: 'KN',
- LC: 'LC',
- MF: 'FR', // Saint Martin
- PM: 'FR', // Saint Pierre and Miquelon
- VC: 'VC',
- WS: 'WS',
- SM: 'SM',
- ST: 'ST',
- SA: 'SA',
- SN: 'SN',
- RS: 'RS',
- SC: 'SC',
- SL: 'SL',
- SG: 'SG',
- SX: 'NL', // Sint Maarten
- SK: 'SK',
- SI: 'SI',
- SB: 'SB',
- SO: 'SO',
- ZA: 'ZA',
- GS: 'GB', // South Georgia and the South Sandwich Islands
- ES: 'ES',
- LK: 'LK',
- SD: 'SD',
- SR: 'SR',
- SJ: 'NO', // Svalbard and Jan Mayen
- SZ: 'SZ',
- SE: 'SE',
- CH: 'CH',
- SY: 'SY',
- TW: 'TW', // Taiwan
- TJ: 'TJ',
- TZ: 'TZ',
- TH: 'TH',
- TL: 'TL',
- TG: 'TG',
- TK: 'NZ', // Tokelau
- TO: 'TO',
- TT: 'TT',
- TN: 'TN',
- TR: 'TR',
- TM: 'TM',
- TC: 'GB', // Turcs and Caicos Islands
- TV: 'TV',
- UG: 'UG',
- UA: 'UA',
- AE: 'AE',
- GB: 'GB',
- US: 'US',
- UM: 'US', // US Minor Outlying Islands
- UY: 'UY',
- UZ: 'UZ',
- VU: 'VU',
- VE: 'VE',
- VN: 'VN',
- VG: 'GB', // British Virgin Islands
- VI: 'US', // US Virgin Islands
- WF: 'FR', // Wallis and Futuna
- EH: 'MA', // Western Sahara
- YE: 'YE',
- ZM: 'ZM',
- ZW: 'ZW'
- };
-
- if (AUTOMATIC && (API_Key.length <= 24 || API_Key.match("^[a-fA-F0-9]*$") == null)) {
- AUTOMATIC = false;
- };
-
- function checkGameMode() {
- return (location.pathname.startsWith("/game/") || (ENABLED_ON_CHALLENGES && location.pathname.startsWith("/challenge/")));
- };
-
- let _cndic = {};
- function cn(classNameStart) { // cn("status_section__") -> "status_section__8uP8o"
- let memorized = _cndic[classNameStart];
- if (memorized != null) return memorized;
- let selected = document.querySelector(`div[class*="${classNameStart}"]`);
- if (selected == null) return classNameStart;
- for (let className of selected.classList) {
- if (className.startsWith(classNameStart)) {
- _cndic[classNameStart] = className;
- return className;
- }
- }
- }
-
- function geoguessrStyle(number) {
- return `<div class="${cn("guess-description-distance_distanceLabel__")}">
- <div class="${cn("styles_root__")} ${cn("styles_variantWhiteTransparent__")} ${cn("styles_roundnessSmall__")}">
- <div class="${cn("styles_start__")} ${cn("styles_right__")}"></div>
- <div class="${cn("guess-description-distance_distanceValue__")}">${number}</div>
- <div class="${cn("styles_end__")} ${cn("styles_right__")}"></div>
- </div>
- </div>`;
- };
-
- function addCounter() {
- if (!checkGameMode()) {
- return;
- };
- let status_length = document.getElementsByClassName(cn("status_section__")).length;
- if (document.getElementById("country-streak") == null && status_length >= 3) {
- let position = (status_length >= 4 && document.getElementsByClassName(cn("status_label__"))[3].innerText == "TIME LEFT") ? 4 : 3;
- let newDiv0 = document.createElement("div");
- newDiv0.className = cn('status_section__');
- let statusBar = document.getElementsByClassName(cn("status_inner__"))[0];
- statusBar.insertBefore(newDiv0, statusBar.children[position]);
- newDiv0.innerHTML = `<div class="${cn("status_label__")}">Streak</div>
- <div id="country-streak" class="${cn("status_value__")}">${streak}</div>`;
- };
- };
-
- function addStreakRoundResult() {
- if (document.getElementById("country-streak2") == null && !!document.querySelector('div[data-qa="guess-description"]')
- && !document.querySelector('div[class*="standard-final-result_section__"]')) {
- let pageProps = JSON.parse(document.getElementById("__NEXT_DATA__").innerHTML).props.pageProps;
- if (pageProps.gamePlayedByCurrentUser != null && pageProps.gamePlayedByCurrentUser.mode == "streak") return;
- let newDiv = document.createElement("div");
- document.querySelector('div[data-qa="guess-description"]').appendChild(newDiv);
- newDiv.innerHTML = `<div id="country-streak2" style="text-align:center;margin-top:10px;"><h2><i>Country Streak: ${streak}</i></h2></div>`;
- };
- };
-
- function addStreakGameSummary() {
- if (document.getElementById("country-streak2") == null && !!document.querySelector('div[class*="standard-final-result_section__"]')) {
- let newDiv = document.createElement("div");
- let progressSection = document.getElementsByClassName(cn("standard-final-result_progressSection__"))[0];
- progressSection.parentNode.insertBefore(newDiv, progressSection.parentNode.children[2]);
- progressSection.style.marginTop = "10px";
- progressSection.style.marginBottom = "10px";
- newDiv.innerHTML = `<div id="country-streak2" style="text-align:center;margin-top:10px;"><h2><i>Country Streak: ${streak}</i></h2></div>`;
- };
- };
-
- function updateStreak(newStreak) {
- if (newStreak === ERROR_RESP) {
- if (document.getElementById("country-streak2") != null && (!!document.querySelector('div[data-qa="guess-description"]'))) {
- document.getElementById("country-streak2").innerHTML =
- `<div><i>Country codes could not be fetched. If your API key is new, it should activate soon.</i></div>
- <div><i>Check for typos in the API key. You might also see this message if bigdatacloud is down</i></div>
- <div><i>or in the unlikely event that you have exceeded you quota limit of 50,000 requests.</i></div>
- <div><i>In the meantime, you can press 1 to count the country as correct, or press 0 otherwise.</i></div>`;
- }
- return;
- }
- sessionStorage.setItem("Streak", newStreak);
- if (!(streak > 0 && newStreak == 0)) {
- sessionStorage.setItem("StreakBackup", newStreak);
- };
- if (document.getElementById("country-streak") != null) {
- document.getElementById("country-streak").innerHTML = newStreak;
- };
- if (document.getElementById("country-streak2") != null
- && (!!document.querySelector('div[data-qa="guess-description"]') || !!document.querySelector('div[class*="standard-final-result_section__"]'))) {
- document.getElementById("country-streak2").innerHTML = `<h2><i>Country Streak: ${newStreak}</i></h2>`;
- if (newStreak == 0) {
- if (streak >= 2) {
- document.getElementById("country-streak2").innerHTML = `<h2><i>Country Streak: 0</i></h2>
- Your streak ended after correctly guessing ${geoguessrStyle(streak)} countries in a row.`;
- } else if (streak == 1) {
- document.getElementById("country-streak2").innerHTML = `<h2><i>Country Streak: 0</i></h2>
- Your streak ended after correctly guessing ${geoguessrStyle(1)} country.`;
- };
- };
- };
- streak = newStreak;
- };
-
- async function getUserAsync(coords) {
- if (coords[0] <= -85.05) {
- return 'AQ';
- };
- let api = "https://api.bigdatacloud.net/data/reverse-geocode?latitude="+coords[0]+"&longitude="+coords[1]+"&localityLanguage=en&key="+API_Key
- let response = await fetch(api)
- .then(res => (res.status !== 200) ? ERROR_RESP : res.json())
- .then(out => (out === ERROR_RESP) ? ERROR_RESP : CountryDict[out.countryCode]);
- return response;
- };
-
- function check() {
- const game_tag = window.location.href.substring(window.location.href.lastIndexOf('/') + 1)
- let api_url = ""
- if (location.pathname.startsWith("/game/")) {
- api_url = "https://www.geoguessr.com/api/v3/games/"+game_tag;
- } else if (location.pathname.startsWith("/challenge/")) {
- api_url = "https://www.geoguessr.com/api/v3/challenges/"+game_tag+"/game";
- };
- fetch(api_url)
- .then(res => res.json())
- .then((out) => {
- let guess_counter = out.player.guesses.length;
- let guess = [out.player.guesses[guess_counter-1].lat,out.player.guesses[guess_counter-1].lng];
- if (guess[0] == last_guess[0] && guess[1] == last_guess[1]) {
- return;
- };
- last_guess = guess;
- let round = [out.rounds[guess_counter-1].lat,out.rounds[guess_counter-1].lng];
- getUserAsync(guess)
- .then(gue => {
- getUserAsync(round)
- .then(loc => {
- if (loc == ERROR_RESP || gue == ERROR_RESP) {
- updateStreak(ERROR_RESP);
- } else if (loc == gue) {
- updateStreak(streak + 1);
- } else {
- updateStreak(0);
- };
- });
- });
- }).catch(err => { throw err });
- };
-
- function doCheck() {
- if (!document.querySelector('div[class*="result-layout_root__"]')) {
- sessionStorage.setItem("Checked", 0);
- } else if (sessionStorage.getItem("Checked") == 0) {
- check();
- sessionStorage.setItem("Checked", 1);
- }
- };
-
- function tryAddCounter() {
- addCounter();
- for (let timeout of [400,1200,2000,3000,4000]) {
- if (document.getElementsByClassName(cn("status_section__")).length == 0) {
- setTimeout(addCounter, timeout);
- };
- }
- };
-
- function tryAddCounterOnRefresh() {
- setTimeout(addCounter, 50);
- setTimeout(addCounter, 300);
- };
-
- function tryAddStreak() {
- if (!checkGameMode()) {
- return;
- };
- if (AUTOMATIC) {
- doCheck();
- for (let timeout of [250,500,1200,2000]) {
- setTimeout(doCheck, timeout);
- }
- };
- for (let timeout of [250,500,1200,2000]) {
- setTimeout(addStreakRoundResult, timeout);
- setTimeout(addStreakGameSummary, timeout);
- }
- };
-
- document.addEventListener('keypress', (e) => {
- let streakBackup = parseInt(sessionStorage.getItem("StreakBackup"), 10);
- switch (e.key) {
- case '1':
- updateStreak(streak + 1);
- break;
- case '2':
- updateStreak(streak - 1);
- break;
- case '8':
- updateStreak(streakBackup + 1);
- break;
- case '0':
- updateStreak(0);
- sessionStorage.setItem("StreakBackup", 0);
- };
- });
-
- document.addEventListener('click', tryAddCounter, false);
- document.addEventListener('click', tryAddStreak, false);
- document.addEventListener('keyup', (e) => { if (e.key === " ") { tryAddStreak(); } });
- document.addEventListener('load', tryAddCounterOnRefresh(), false);