// ==UserScript==
// @name Geoguessr Blink Mode
// @description Shows the round briefly, then screen goes black and you have unlimited time to make your guess.
// @version 1.3.5
// @author macca7224
// @license MIT
// @match https://www.geoguessr.com/*
// @require https://unpkg.com/@popperjs/core@2.11.5/dist/umd/popper.min.js
// @grant none
// @require https://greasyfork.org/scripts/460322-geoguessr-styles-scan/code/Geoguessr%20Styles%20Scan.js?version=1151654
// @namespace https://greasyfork.org/en/scripts/438579-geoguessr-blink-mode
// @icon https://www.svgrepo.com/show/40039/eye.svg
// @downloadURL none
// ==/UserScript==
const guiEnabled = true
// ^^^^ Set to false (all lowercase) if you want to hide the GUI and manually enable the script/set the time, otherwise true
let timeLimit = 1.5
// ^^^ Modify this number above to change the time
let roundDelay = 0
// ^ Modify this number above to change the length of time the round is delayed for
// --------- DON'T MODIFY ANYTHING BELOW THIS LINE -------- //
const styleElement = document.createElement("style");
document.head.appendChild(styleElement);
styleElement.innerHTML = `
.toggle_toggle__ {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: var(--ds-color-white-10);
border: 0;
border-radius: 2rem;
cursor: pointer;
display: inline-block;
height: 1.25rem;
position: relative;
transition: background-color .2s ease;
width: 2.5rem;
}
.toggle_toggle__:checked {
background: var(--ds-color-brand-50);
}
.toggle_toggle__:after {
background: var(--ds-color-white);
border-radius: 100%;
content: "";
height: 1rem;
left: 0;
margin: .125rem;
opacity: .1;
position: absolute;
top: 0;
transition: transform .1s ease,opacity .1s ease;
width: 1rem;
}
.toggle_toggle__:checked:after {
opacity: 1;
transform: translateX(125%);
}
.toggle_toggle__:before {
background: var(--ds-color-purple-50);
content: "";
height: 100%;
left: 0;
opacity: 0;
position: absolute;
top: 0;
transition: opacity .3s ease;
width: 100%;
}`;
const classicGameGuiClasses = ["map-stats_mapStat__", "map-selector_selector__"];
const classicGameGuiHTML = () => `
`
const friendLobbyGuiClasses = ["section_sectionHeader__", "bars_root__", "toggle-option_wrapper__"];
const friendLobbyGuiHTML = () => `
`
const guiHeaderClasses = ["menu-item_container__", "quick-search_wrapper__"];
const guiHTMLHeader = () => `
`
const guiPartyHeaderClasses = ["header_item__", "slanted-wrapper_root__", "game-options_optionLabel__"];
const guiPartyHeader = () => `
`
if (localStorage.getItem('blinkEnabled') == null) {
localStorage.setItem('blinkEnabled', 'disabled');
}
if (!guiEnabled) {
localStorage.setItem('blinkEnabled', 'enabled');
}
if (localStorage.getItem('blinkTime') == null || isNaN(localStorage.getItem('blinkTime'))) {
localStorage.setItem('blinkTime', timeLimit);
}
if (localStorage.getItem('delayTime') == null || isNaN(localStorage.getItem('delayTime'))) {
localStorage.setItem('delayTime', roundDelay);
}
if (guiEnabled) {
timeLimit = parseFloat(localStorage.getItem('blinkTime'));
roundDelay = parseFloat(localStorage.getItem('delayTime'));
}
window.toggleBlinkMode = (e) => {
localStorage.setItem('blinkEnabled', e.checked ? 'enabled' : 'disabled');
if (!e.checked) {
try { showPanoramaCached(); } catch {}
}
if (document.querySelector('#enableScript')) {
document.querySelector('#enableScript').checked = e.checked;
}
if (document.querySelector('#enableScriptHeader')) {
document.querySelector('#enableScriptHeader').checked = e.checked;
}
}
window.changeBlinkTime = (e) => {
if (!isNaN(e.value)) {
localStorage.setItem('blinkTime', parseFloat(e.value));
timeLimit = parseFloat(e.value);
if (document.querySelector('#blinkTime')) {
document.querySelector('#blinkTime').value = e.value;
}
if (document.querySelector('#blinkTimeHeader')) {
document.querySelector('#blinkTimeHeader').value = e.value;
}
}
}
window.changeDelayTime = (e) => {
if (!isNaN(e.value)) {
localStorage.setItem('delayTime', parseFloat(e.value));
roundDelay = parseFloat(e.value);
if (document.querySelector('#delayTime')) {
document.querySelector('#delayTime').value = e.value;
}
if (document.querySelector('#delayTimeHeader')) {
document.querySelector('#delayTimeHeader').value = e.value;
}
}
}
const insertHeaderGui = (header, gui) => {
header.insertAdjacentHTML('afterbegin', gui);
const showButton = document.querySelector('#headerGuiToggle');
const popup = document.querySelector('#popup');
popup.style.display = 'none';
document.addEventListener('click', (e) => {
const target = e.target;
if (target == popup || popup.contains(target)) return;
if (target.matches('#headerGuiToggle, #headerGuiToggle *')) {
e.preventDefault();
popup.style.display = 'block';
Popper.createPopper(showButton, popup, {
placement: 'bottom',
modifiers: [
{
name: 'offset',
options: {
offset: [0, 10],
},
},
],
});
} else {
popup.style.display = 'none';
}
if (document.querySelector('#enableScriptHeader')) {
if (localStorage.getItem('blinkEnabled') === 'enabled') {
document.querySelector('#enableScriptHeader').checked = true;
}
document.querySelector('#blinkTimeHeader').value = timeLimit;
document.querySelector('#delayTimeHeader').value = roundDelay;
}
});
}
const checkInsertGui = () => {
// Play page for classic games
if (document.querySelector('[class*=map-block_mapStatsContainer__]') && document.querySelector('#enableScript') === null && checkAllStylesFound(classicGameGuiClasses)) {
document.querySelector('[class*=map-block_mapStatsContainer__]').insertAdjacentHTML('afterend', classicGameGuiHTML());
if (localStorage.getItem('blinkEnabled') === 'enabled') {
document.querySelector('#enableScript').checked = true;
}
document.querySelector('#blinkTime').value = timeLimit;
document.querySelector('#delayTime').value = roundDelay;
}
// Lobby for friends party games
if (document.querySelector('[class*=party-modal_heading__]') && document.querySelector('#enableScript') === null && checkAllStylesFound(friendLobbyGuiClasses)) {
const columns = document.querySelectorAll('[class*=settings-modal_column__]');
columns[columns.length - 1].insertAdjacentHTML('beforeend', friendLobbyGuiHTML());
if (localStorage.getItem('blinkEnabled') === 'enabled') {
document.querySelector('#enableScript').checked = true;
}
document.querySelector('#blinkTime').value = timeLimit;
document.querySelector('#delayTime').value = roundDelay;
}
// Header
if (document.querySelector('[class*=header-tablet-desktop_desktopSectionRight__]') && document.querySelector('#blinkHeaderToggle') === null && checkAllStylesFound(guiHeaderClasses)) {
insertHeaderGui(document.querySelector('[class*=header-tablet-desktop_desktopSectionRight__]'), guiHTMLHeader())
} else if (document.querySelector('[class*=party-header_root__]') && document.querySelector('#blinkHeaderToggle') === null && checkAllStylesFound(guiPartyHeaderClasses)) {
insertHeaderGui(document.querySelector('[class*=party-header_right__]'), guiPartyHeader())
} else if (document.querySelector('[class*=header-desktop_desktopSectionRight__]') && document.querySelector('#blinkHeaderToggle') === null && checkAllStylesFound(guiHeaderClasses)) {
insertHeaderGui(document.querySelector('[class*=header-desktop_desktopSectionRight__]'), guiHTMLHeader())
}
}
let mapRoot = null;
function getMapRoot() {
return document.querySelector("[data-qa=panorama]");
}
function hidePanorama() {
mapRoot = getMapRoot() || mapRoot;
hidePanoramaCached();
}
function hidePanoramaCached() {
mapRoot.style.filter = 'brightness(0%)';
}
function showPanorama() {
mapRoot = getMapRoot() || mapRoot;
showPanoramaCached();
}
function showPanoramaCached() {
mapRoot.style.filter = 'brightness(100%)';
}
function isLoading() {
return document.querySelector('[class*=fullscreen-spinner_root__]') || !document.querySelector('.widget-scene-canvas');
}
let wasBackdropThereOrLoading = false;
function isBackdropThereOrLoading() {
return isLoading() // loading
|| document.querySelector('[class*=result-layout_root__]') // classic
|| document.querySelector('[class*=overlay_backdrop__]') // duels / team duels
|| document.querySelector('[class*=round-starting_wrapper____]') // live challenges
|| document.querySelector('[class*=popup_backdrop__]') // BR
|| document.querySelector('[class*=game-starting_container__]') || document.querySelector('[class*=round-score_container__]') // bullseye
|| document.querySelector('[class*=overlay-modal_backlight__]'); // city streaks
}
let showTimeoutID = null
let hideTimeoutID = null
function triggerBlink() {
hidePanorama();
clearTimeout(showTimeoutID);
showTimeoutID = setTimeout(showPanorama, roundDelay * 1000);
clearTimeout(hideTimeoutID);
hideTimeoutID = setTimeout(hidePanorama, (timeLimit + roundDelay) * 1000);
}
let played = false;
const checkStatus = () => {
if (!(location.pathname.includes('/duels'))) {
return;
}
let timer = document.querySelector("[class^='clock-timer_timerContainer__']");
let stress = document.querySelector("[class^='stress-indicator_container__']");
if ((timer !== null) && !played && (stress == null)) {
showPanorama();
played = true;
} else if (timer == null) {
played = false;
}
}
let observer = new MutationObserver((mutations) => {
if (guiEnabled) {
scanStyles().then(_ => { checkInsertGui(); });
}
if (localStorage.getItem('blinkEnabled') === 'enabled') {
if (isBackdropThereOrLoading()) {
wasBackdropThereOrLoading = true;
if (!isLoading()) hidePanorama();
} else if (wasBackdropThereOrLoading) {
wasBackdropThereOrLoading = false;
triggerBlink();
}
checkStatus();
}
});
observer.observe(document.body, {
characterDataOldValue: false,
subtree: true,
childList: true,
characterData: false
});