Geoguessr Blink Mode

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

当前为 2023-06-21 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Geoguessr Blink Mode
  3. // @description Shows the round briefly, then screen goes black and you have unlimited time to make your guess.
  4. // @version 1.2.4
  5. // @author macca#8949
  6. // @license MIT
  7. // @match https://www.geoguessr.com/*
  8. // @require https://unpkg.com/@popperjs/core@2.11.5/dist/umd/popper.min.js
  9. // @run-at document-start
  10. // @grant none
  11. // @namespace https://greasyfork.org/en/scripts/438579-geoguessr-blink-mode
  12. // @icon https://www.svgrepo.com/show/40039/eye.svg
  13. // ==/UserScript==
  14.  
  15.  
  16. const guiEnabled = true
  17. // ^^^^ Set to false (all lowercase) if you want to hide the GUI and manually enable the script/set the time, otherwise true
  18.  
  19. let timeLimit = 1.5
  20. // ^^^ Modify this number above to change the time
  21.  
  22. let roundDelay = 0
  23. // ^ Modify this number above to change the length of time the round is delayed for
  24.  
  25.  
  26.  
  27. // --------- DON'T MODIFY ANYTHING BELOW THIS LINE -------- //
  28.  
  29.  
  30.  
  31. const classicGameGuiHTML = `
  32. <div class="section_sectionHeader__WQ7Xz section_sizeMedium__yPqLK"><div class="bars_root___G89E bars_center__vAqnw"><div class="bars_before__xAA7R bars_lengthLong__XyWLx"></div><span class="bars_content__UVGlL"><h3>Blink Mode settings</h3></span><div class="bars_after__Z1Rxt bars_lengthLong__XyWLx"></div></div></div>
  33. <div class="start-standard-game_settings__x94PU">
  34. <div style="display: flex; justify-content: space-around;">
  35. <div style="display: flex; align-items: center;">
  36. <span class="game-options_optionLabel__dJ_Cy" style="margin: 0; padding-right: 6px;">Enabled</span>
  37. <input type="checkbox" id="enableScript" onclick="toggleBlinkMode(this)" class="toggle_toggle__hwnyw">
  38. </div>
  39.  
  40. <div style="display: flex; align-items: center;">
  41. <span class="game-options_optionLabel__dJ_Cy" style="margin: 0; padding-right: 6px;">Time (Seconds)</span>
  42. <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;">
  43. </div>
  44. </div>
  45. <div style="margin-top: 10px">
  46. <span class="game-options_optionLabel__dJ_Cy" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
  47. <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;">
  48. </div>
  49. </div>
  50. `
  51.  
  52. const friendLobbyGuiHTML = `
  53. <div class="section_sectionHeader__WQ7Xz section_sizeMedium__yPqLK" style="margin-top: 10px"><div class="bars_root___G89E"><span class="bars_content__UVGlL"><h2>Blink Mode Settings</h2></span><div class="bars_after__Z1Rxt bars_lengthLong__XyWLx"></div></div></div>
  54. <div class="start-standard-game_settings__x94PU" style="margin-top: 8px">
  55. <div style="display: flex; justify-content: space-around;">
  56. <div style="display: flex; align-items: center;">
  57. <span class="game-options_optionLabel__dJ_Cy" style="margin: 0; padding-right: 6px;">Enabled</span>
  58. <input type="checkbox" id="enableScript" onclick="toggleBlinkMode(this)" class="toggle_toggle__hwnyw">
  59. </div>
  60.  
  61. <div style="display: flex; align-items: center;">
  62. <span class="game-options_optionLabel__dJ_Cy" style="margin: 0; padding-right: 6px;">Time (Seconds)</span>
  63. <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;">
  64. </div>
  65.  
  66. <div style="display: flex; align-items: center;">
  67. <span class="game-options_optionLabel__dJ_Cy" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
  68. <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;">
  69. </div>
  70. </div>
  71. </div>
  72. `
  73.  
  74. const guiHTMLHeader = `
  75. <div id="blinkHeaderToggle" class="header_item__8_Ol1">
  76. <div class="quick-search_wrapper__SP8ZI">
  77. <div class="slanted-wrapper_root__2eaEs slanted-wrapper_variantGrayTransparent__aufaF">
  78. <div class="slanted-wrapper_start__Kl7rv slanted-wrapper_right__G0JWR"></div>
  79. <div class="quick-search_searchInputWrapper__WWuRE">
  80. <div id="popup" style="background: rgba(26, 26, 46, 0.9); padding: 15px; width: 200px; border-radius: 10px;">
  81. <div style="display: flex; justify-content: space-between; align-items: center;">
  82. <span class="game-options_optionLabel__dJ_Cy">Enabled</span>
  83. <input type="checkbox" id="enableScriptHeader" class="toggle_toggle__hwnyw" onclick="toggleBlinkMode(this)">
  84. </div>
  85.  
  86. <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
  87. <span class="game-options_optionLabel__dJ_Cy">Time (Seconds)</span>
  88. <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;">
  89. </div>
  90.  
  91. <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
  92. <span class="game-options_optionLabel__dJ_Cy" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
  93. <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;">
  94. </div>
  95. </div>
  96. <button style="width: 59.19px" id="headerGuiToggle" class="quick-search_searchInputButton__kK9Hz"><picture style="justify-content: center" class="quick-search_iconSection__3Wdfr"><img src="https://www.svgrepo.com/show/40039/eye.svg" style="width: 15px; filter: brightness(0) invert(1); opacity: 60%;"></picture></button>
  97. </div>
  98. <div class="slanted-wrapper_end__cD1Qu slanted-wrapper_right__G0JWR"></div>
  99. </div>
  100. </div>
  101. </div>
  102. `
  103.  
  104. const guiPartyHeader = `
  105. <div id="blinkHeaderToggle" class="header_item__8_Ol1" style="margin-right: 1rem;">
  106. <div id="popup" style="background: rgba(26, 26, 46, 0.9); padding: 15px; width: 200px; border-radius: 10px; z-index: 999;">
  107. <div style="display: flex; justify-content: space-between; align-items: center;">
  108. <span class="game-options_optionLabel__dJ_Cy">Enabled</span>
  109. <input type="checkbox" id="enableScriptHeader" class="toggle_toggle__hwnyw" onclick="toggleBlinkMode(this)">
  110. </div>
  111.  
  112. <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
  113. <span class="game-options_optionLabel__dJ_Cy">Time (Seconds)</span>
  114. <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;">
  115. </div>
  116.  
  117. <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
  118. <span class="game-options_optionLabel__dJ_Cy" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
  119. <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;">
  120. </div>
  121. </div>
  122. <div class="quick-search_wrapper__SP8ZI">
  123. <div class="slanted-wrapper_root__2eaEs slanted-wrapper_variantGrayTransparent__aufaF">
  124. <div class="slanted-wrapper_start__Kl7rv slanted-wrapper_right__G0JWR"></div>
  125. <div>
  126. <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="quick-search_iconSection__3Wdfr"><img src="https://www.svgrepo.com/show/40039/eye.svg" style="width: 15px; filter: brightness(0) invert(1); opacity: 60%;"></picture></button>
  127. </div>
  128. <div class="slanted-wrapper_end__cD1Qu slanted-wrapper_right__G0JWR"></div>
  129. </div>
  130. </div>
  131. </div>
  132. `
  133.  
  134. if (localStorage.getItem('blinkEnabled') == null) {
  135. localStorage.setItem('blinkEnabled', 'disabled');
  136. }
  137.  
  138. if (!guiEnabled) {
  139. localStorage.setItem('blinkEnabled', 'enabled');
  140. }
  141.  
  142. if (localStorage.getItem('blinkTime') == null || isNaN(localStorage.getItem('blinkTime'))) {
  143. localStorage.setItem('blinkTime', timeLimit);
  144. }
  145. if (localStorage.getItem('delayTime') == null || isNaN(localStorage.getItem('delayTime'))) {
  146. localStorage.setItem('delayTime', roundDelay);
  147. }
  148.  
  149. if (guiEnabled) {
  150. timeLimit = parseFloat(localStorage.getItem('blinkTime'));
  151. roundDelay = parseFloat(localStorage.getItem('delayTime'));
  152. }
  153.  
  154. window.toggleBlinkMode = (e) => {
  155. localStorage.setItem('blinkEnabled', e.checked ? 'enabled' : 'disabled');
  156. if (!e.checked) {
  157. try { showPanoramaCached(); } catch {}
  158. }
  159.  
  160. if (document.querySelector('#enableScript')) {
  161. document.querySelector('#enableScript').checked = e.checked;
  162. }
  163. if (document.querySelector('#enableScriptHeader')) {
  164. document.querySelector('#enableScriptHeader').checked = e.checked;
  165. }
  166. }
  167.  
  168. window.changeBlinkTime = (e) => {
  169. if (!isNaN(e.value)) {
  170. localStorage.setItem('blinkTime', parseFloat(e.value));
  171. timeLimit = parseFloat(e.value);
  172.  
  173. if (document.querySelector('#blinkTime')) {
  174. document.querySelector('#blinkTime').value = e.value;
  175. }
  176. if (document.querySelector('#blinkTimeHeader')) {
  177. document.querySelector('#blinkTimeHeader').value = e.value;
  178. }
  179. }
  180. }
  181.  
  182. window.changeDelayTime = (e) => {
  183. if (!isNaN(e.value)) {
  184. localStorage.setItem('delayTime', parseFloat(e.value));
  185. roundDelay = parseFloat(e.value);
  186.  
  187. if (document.querySelector('#delayTime')) {
  188. document.querySelector('#delayTime').value = e.value;
  189. }
  190. if (document.querySelector('#delayTimeHeader')) {
  191. document.querySelector('#delayTimeHeader').value = e.value;
  192. }
  193. }
  194. }
  195.  
  196. const insertHeaderGui = (header, gui) => {
  197. header.insertAdjacentHTML('afterbegin', gui);
  198. const showButton = document.querySelector('#headerGuiToggle');
  199. const popup = document.querySelector('#popup');
  200. popup.style.display = 'none';
  201.  
  202. document.addEventListener('click', (e) => {
  203. const target = e.target;
  204. if (target == popup || popup.contains(target)) return;
  205. if (target.matches('#headerGuiToggle, #headerGuiToggle *')) {
  206. e.preventDefault();
  207.  
  208. popup.style.display = 'block';
  209. Popper.createPopper(showButton, popup, {
  210. placement: 'bottom',
  211. modifiers: [
  212. {
  213. name: 'offset',
  214. options: {
  215. offset: [0, 10],
  216. },
  217. },
  218. ],
  219. });
  220. } else {
  221. popup.style.display = 'none';
  222. }
  223.  
  224. if (document.querySelector('#enableScriptHeader')) {
  225. if (localStorage.getItem('blinkEnabled') === 'enabled') {
  226. document.querySelector('#enableScriptHeader').checked = true;
  227. }
  228. document.querySelector('#blinkTimeHeader').value = timeLimit;
  229. document.querySelector('#delayTimeHeader').value = roundDelay;
  230. }
  231. });
  232. }
  233.  
  234. const checkInsertGui = () => {
  235. // Play page for classic games
  236. if (document.querySelector('.radio-box_root__ka_9S') && document.querySelector('#enableScript') === null) {
  237. document.querySelector('.section_sectionMedium__yXgE6').insertAdjacentHTML('beforeend', classicGameGuiHTML);
  238. if (localStorage.getItem('blinkEnabled') === 'enabled') {
  239. document.querySelector('#enableScript').checked = true;
  240. }
  241. document.querySelector('#blinkTime').value = timeLimit;
  242. document.querySelector('#delayTime').value = roundDelay;
  243. }
  244.  
  245. // Lobby for friends party games
  246. if (document.querySelector('.game-options_root__ppDoQ') && document.querySelector('#enableScript') === null) {
  247. document.querySelector('.game-options_optionGroup__qNKx1').insertAdjacentHTML('beforeend', friendLobbyGuiHTML);
  248. if (localStorage.getItem('blinkEnabled') === 'enabled') {
  249. document.querySelector('#enableScript').checked = true;
  250. }
  251. document.querySelector('#blinkTime').value = timeLimit;
  252. document.querySelector('#delayTime').value = roundDelay;
  253. }
  254.  
  255. // Header
  256. if (document.querySelector('.header_header___qZAn') && document.querySelector('#blinkHeaderToggle') === null) {
  257. insertHeaderGui(document.querySelector('.header_context__UqsBa'), guiHTMLHeader)
  258. } else if (document.querySelector('.party-header_root__EQbn1') && document.querySelector('#blinkHeaderToggle') === null) {
  259. insertHeaderGui(document.querySelector('.party-header_right__qHcU4'), guiPartyHeader)
  260. }
  261. }
  262.  
  263. let mapRoot = null;
  264. function hidePanorama() {
  265. mapRoot = document.querySelector('.mapsConsumerUiSceneInternalCoreScene__root') || mapRoot;
  266. hidePanoramaCached();
  267. }
  268.  
  269. function hidePanoramaCached() {
  270. mapRoot.style.filter = 'brightness(0%)';
  271. }
  272.  
  273. function showPanorama() {
  274. mapRoot = document.querySelector('.mapsConsumerUiSceneInternalCoreScene__root') || mapRoot;
  275. showPanoramaCached();
  276. }
  277.  
  278. function showPanoramaCached() {
  279. mapRoot.style.filter = 'brightness(100%)';
  280. }
  281.  
  282. function isLoading() {
  283. return document.querySelector('.fullscreen-spinner_root__IwRRr') || !document.querySelector('.widget-scene-canvas');
  284. }
  285.  
  286. let wasBackdropThereOrLoading = false;
  287. function isBackdropThereOrLoading() {
  288. return isLoading() // loading
  289. || document.querySelector('.result-layout_root__NfX12') // classic
  290. || document.querySelector('.overlay_backdrop__Rh_QC') // duels / team duels
  291. || document.querySelector('.game_backdrop__A_Ze9') || document.querySelector('.overlays_backdrop__sIb35') // live challenges
  292. || document.querySelector('.popup_backdrop__R52hP') // BR
  293. || document.querySelector('.game-starting_container__TMoWC') || document.querySelector('.round-score_container__avps2') // bullseye
  294. || document.querySelector('.overlay-modal_backlight__Ekx7t'); // city streaks
  295. }
  296.  
  297. let showTimeoutID = null
  298. let hideTimeoutID = null
  299. function triggerBlink() {
  300. hidePanorama();
  301. clearTimeout(showTimeoutID);
  302. showTimeoutID = setTimeout(showPanorama, roundDelay * 1000);
  303. clearTimeout(hideTimeoutID);
  304. hideTimeoutID = setTimeout(hidePanorama, (timeLimit + roundDelay) * 1000);
  305. }
  306.  
  307. let observer = new MutationObserver((mutations) => {
  308. if (guiEnabled) {
  309. checkInsertGui();
  310. }
  311.  
  312. if (localStorage.getItem('blinkEnabled') === 'enabled') {
  313. if (isBackdropThereOrLoading()) {
  314. wasBackdropThereOrLoading = true;
  315. if (!isLoading()) hidePanorama();
  316. } else if (wasBackdropThereOrLoading) {
  317. wasBackdropThereOrLoading = false;
  318. triggerBlink();
  319. }
  320. }
  321.  
  322. });
  323.  
  324. observer.observe(document.body, {
  325. characterDataOldValue: false,
  326. subtree: true,
  327. childList: true,
  328. characterData: false
  329. });