Geoguessr Blink Mode

Shows the round briefly, then screen goes black and you have unlimited time to make your guess.

目前为 2023-09-06 提交的版本。查看 最新版本

// ==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.2.5
// @author       macca#8949
// @license      MIT
// @match        https://www.geoguessr.com/*
// @require      https://unpkg.com/@popperjs/[email protected]/dist/umd/popper.min.js
// @run-at       document-start
// @grant        none
// @require      https://gf.qytechs.cn/scripts/460322-geoguessr-styles-scan/code/Geoguessr%20Styles%20Scan.js?version=1151654
// @namespace    https://gf.qytechs.cn/en/scripts/438579-geoguessr-blink-mode
// @icon         https://www.svgrepo.com/show/40039/eye.svg
// ==/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 classicGameGuiClasses = ["section_sectionHeader__", "bars_root__", "start-standard-game_settings__", "game-options_optionLabel__"];
const classicGameGuiHTML = () => `
<div class="${cn("section_sectionHeader__")} ${cn("section_sizeMedium__")}"><div class="${cn("bars_root__")} ${cn("bars_center__")}"><div class="${cn("bars_before__")} ${cn("bars_lengthLong__")}"></div><span class="${cn("bars_content__")}"><h3>Blink Mode settings</h3></span><div class="${cn("bars_after__")} ${cn("bars_lengthLong__")}"></div></div></div>
<div class="${cn("start-standard-game_settings__")}">
  <div style="display: flex; justify-content: space-around;">
    <div style="display: flex; align-items: center;">
      <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Enabled</span>
      <input type="checkbox" id="enableScript" onclick="toggleBlinkMode(this)" class="${cn("toggle_toggle__")}">
    </div>

    <div style="display: flex; align-items: center;">
      <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Time (Seconds)</span>
      <input type="text" id="blinkTime" onchange="changeBlinkTime(this)" style="background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px; width: 60px;">
    </div>
  </div>
  <div style="margin-top: 10px">
    <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
    <input type="text" id="delayTime" onchange="changeDelayTime(this)" style="background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px; width: 60px;">
  </div>
</div>
`

const friendLobbyGuiClasses = ["section_sectionHeader__", "bars_root__", "game-options_optionLabel__"];
const friendLobbyGuiHTML = () => `
<div class="${cn("section_sectionHeader__")} ${cn("section_sizeMedium__")}" style="margin-top: 10px"><div class="${cn("bars_root__")}"><span class="${cn("bars_content__")}"><h2>Blink Mode Settings</h2></span><div class="${cn("bars_after__")} ${cn("bars_lengthLong__")}"></div></div></div>
<div class="${cn("start-standard-game_settings__")}" style="margin-top: 8px">
  <div style="display: flex; justify-content: space-around;">
    <div style="display: flex; align-items: center;">
      <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Enabled</span>
      <input type="checkbox" id="enableScript" onclick="toggleBlinkMode(this)" class="${cn("toggle_toggle__")}">
    </div>

    <div style="display: flex; align-items: center;">
      <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Time (Seconds)</span>
      <input type="text" id="blinkTime" onchange="changeBlinkTime(this)" style="background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px; width: 60px;">
    </div>

    <div style="display: flex; align-items: center;">
      <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
      <input type="text" id="delayTime" onchange="changeDelayTime(this)" style="background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px; width: 60px;">
    </div>
  </div>
</div>
`

const guiHeaderClasses = ["header_item__", "quick-search_wrapper__", "slanted-wrapper_root__", "label_sizeXSmall__", "toggle_toggle__"];
const guiHTMLHeader = () => `
<div id="blinkHeaderToggle" class="${cn("header_item__")}">
  <div class="${cn("quick-search_wrapper__")}">
    <div class="${cn("slanted-wrapper_root__")} ${cn("slanted-wrapper_variantGrayTransparent__")}">
      <div class="${cn("slanted-wrapper_start__")} ${cn("slanted-wrapper_right__")}"></div>
      <div class="${cn("quick-search_searchInputWrapper__")}">
        <div id="popup" style="background: rgba(26, 26, 46, 0.9); padding: 15px; width: 200px; border-radius: 10px;">
          <div style="display: flex; justify-content: space-between; align-items: center;">
            <span class="${cn("label_sizeXSmall__")}">Enabled</span>
            <input type="checkbox" id="enableScriptHeader" class="${cn("toggle_toggle__")}" onclick="toggleBlinkMode(this)">
          </div>

          <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
            <span class="${cn("label_sizeXSmall__")}">Time (Seconds)</span>
            <input type="text" id="blinkTimeHeader" onchange="changeBlinkTime(this)" style="background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px; width: 60px;">
          </div>

          <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
            <span class="${cn("label_sizeXSmall__")}" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
            <input type="text" id="delayTimeHeader" onchange="changeDelayTime(this)" style="background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px; width: 60px;">
          </div>
        </div>
        <button style="width: 59.19px" id="headerGuiToggle" class="${cn("quick-search_searchInputButton__")}"><picture style="justify-content: center" class="${cn("quick-search_iconSection__")}"><img src="https://www.svgrepo.com/show/40039/eye.svg" style="width: 15px; filter: brightness(0) invert(1); opacity: 60%;"></picture></button>
      </div>
      <div class="${cn("slanted-wrapper_end__")} ${cn("slanted-wrapper_right__")}"></div>
    </div>
  </div>
</div>
`

const guiPartyHeaderClasses = ["header_item__", "slanted-wrapper_root__", "game-options_optionLabel__"];
const guiPartyHeader = () => `
<div id="blinkHeaderToggle" class="${cn("header_item__")}" style="margin-right: 1rem;">
  <div id="popup" style="background: rgba(26, 26, 46, 0.9); padding: 15px; width: 200px; border-radius: 10px; z-index: 999;">
    <div style="display: flex; justify-content: space-between; align-items: center;">
      <span class="${cn("game-options_optionLabel__")}">Enabled</span>
      <input type="checkbox" id="enableScriptHeader" class="${cn("toggle_toggle__")}" onclick="toggleBlinkMode(this)">
    </div>

    <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
      <span class="${cn("game-options_optionLabel__")}">Time (Seconds)</span>
      <input type="text" id="blinkTimeHeader" onchange="changeBlinkTime(this)" style="background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px; width: 60px;">
    </div>

    <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
      <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
      <input type="text" id="delayTimeHeader" onchange="changeDelayTime(this)" style="background: rgba(255,255,255,0.1); color: white; border: none; border-radius: 5px; width: 60px;">
    </div>
  </div>
  <div class="${cn("quick-search_wrapper__")}">
    <div class="${cn("slanted-wrapper_root__")} ${cn("slanted-wrapper_variantGrayTransparent__")}">
      <div class="${cn("slanted-wrapper_start__")} ${cn("slanted-wrapper_right__")}"></div>
      <div>
        <button id="headerGuiToggle" style="width: 59.19px; background-color: inherit;border: initial;cursor: pointer;min-height: 2rem;min-width: 2rem;padding: var(--padding-y) var(--padding-x);"><picture style="justify-content: center" class="${cn("quick-search_iconSection__")}"><img src="https://www.svgrepo.com/show/40039/eye.svg" style="width: 15px; filter: brightness(0) invert(1); opacity: 60%;"></picture></button>
      </div>
      <div class="${cn("slanted-wrapper_end__")} ${cn("slanted-wrapper_right__")}"></div>
    </div>
  </div>
</div>
`

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*=radio-box_root__]') && document.querySelector('#enableScript') === null && checkAllStylesFound(classicGameGuiClasses)) {
        document.querySelector('[class*=section_sectionMedium__]').insertAdjacentHTML('beforeend', 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*=game-options_root__]') && document.querySelector('#enableScript') === null && checkAllStylesFound(friendLobbyGuiClasses)) {
        document.querySelector('[class*=game-options_optionGroup__]').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_header__]') && document.querySelector('#blinkHeaderToggle') === null && checkAllStylesFound(guiHeaderClasses)) {
        insertHeaderGui(document.querySelector('[class*=header_context__]'), guiHTMLHeader())
    } else if (document.querySelector('[class*=party-header_root__]') && document.querySelector('#blinkHeaderToggle') === null && checkAllStylesFound(guiPartyHeaderClasses)) {
        insertHeaderGui(document.querySelector('[class*=party-header_right__]'), guiPartyHeader())
    }
}

let mapRoot = null;
function hidePanorama() {
    mapRoot = document.querySelector('.mapsConsumerUiSceneInternalCoreScene__root') || mapRoot;
    hidePanoramaCached();
}

function hidePanoramaCached() {
    mapRoot.style.filter = 'brightness(0%)';
}

function showPanorama() {
    mapRoot = document.querySelector('.mapsConsumerUiSceneInternalCoreScene__root') || 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*=game_backdrop__]') || document.querySelector('[class*=overlays_backdrop__]') // 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 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();
        }
    }

});

observer.observe(document.body, {
  characterDataOldValue: false,
  subtree: true,
  childList: true,
  characterData: false
});

QingJ © 2025

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