Geoguessr Blink Mode

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

目前为 2024-01-16 提交的版本。查看 最新版本

  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.8
  5. // @author macca7224
  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. // @grant none
  10. // @require https://gf.qytechs.cn/scripts/460322-geoguessr-styles-scan/code/Geoguessr%20Styles%20Scan.js?version=1151654
  11. // @namespace https://gf.qytechs.cn/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. const classicGameGuiClasses = ["section_sectionHeader__", "bars_root__", "start-standard-game_settings__", "game-options_optionLabel__"];
  31. const classicGameGuiHTML = () => `
  32. <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>
  33. <div class="${cn("start-standard-game_settings__")}">
  34. <div style="display: flex; justify-content: space-around;">
  35. <div style="display: flex; align-items: center;">
  36. <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Enabled</span>
  37. <input type="checkbox" id="enableScript" onclick="toggleBlinkMode(this)" class="${cn("toggle_toggle__")}">
  38. </div>
  39.  
  40. <div style="display: flex; align-items: center;">
  41. <span class="${cn("game-options_optionLabel__")}" 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="${cn("game-options_optionLabel__")}" 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 friendLobbyGuiClasses = ["section_sectionHeader__", "bars_root__", "game-options_optionLabel__"];
  53. const friendLobbyGuiHTML = () => `
  54. <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>
  55. <div class="${cn("start-standard-game_settings__")}" style="margin-top: 8px">
  56. <div style="display: flex; justify-content: space-around;">
  57. <div style="display: flex; align-items: center;">
  58. <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Enabled</span>
  59. <input type="checkbox" id="enableScript" onclick="toggleBlinkMode(this)" class="${cn("toggle_toggle__")}">
  60. </div>
  61.  
  62. <div style="display: flex; align-items: center;">
  63. <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Time (Seconds)</span>
  64. <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;">
  65. </div>
  66.  
  67. <div style="display: flex; align-items: center;">
  68. <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
  69. <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;">
  70. </div>
  71. </div>
  72. </div>
  73. `
  74.  
  75. const guiHeaderClasses = ["header_item__", "quick-search_wrapper__", "slanted-wrapper_root__", "label_sizeXSmall__", "toggle_toggle__"];
  76. const guiHTMLHeader = () => `
  77. <div id="blinkHeaderToggle" class="${cn("header_item__")}">
  78. <div class="${cn("quick-search_wrapper__")}">
  79. <div class="${cn("slanted-wrapper_root__")} ${cn("slanted-wrapper_variantGrayTransparent__")}">
  80. <div class="${cn("slanted-wrapper_start__")} ${cn("slanted-wrapper_right__")}"></div>
  81. <div class="${cn("quick-search_searchInputWrapper__")}">
  82. <div id="popup" style="background: rgba(26, 26, 46, 0.9); padding: 15px; width: 200px; border-radius: 10px;">
  83. <div style="display: flex; justify-content: space-between; align-items: center;">
  84. <span class="${cn("label_sizeXSmall__")}">Enabled</span>
  85. <input type="checkbox" id="enableScriptHeader" class="${cn("toggle_toggle__")}" onclick="toggleBlinkMode(this)">
  86. </div>
  87.  
  88. <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
  89. <span class="${cn("label_sizeXSmall__")}">Time (Seconds)</span>
  90. <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;">
  91. </div>
  92.  
  93. <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
  94. <span class="${cn("label_sizeXSmall__")}" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
  95. <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;">
  96. </div>
  97. </div>
  98. <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>
  99. </div>
  100. <div class="${cn("slanted-wrapper_end__")} ${cn("slanted-wrapper_right__")}"></div>
  101. </div>
  102. </div>
  103. </div>
  104. `
  105.  
  106. const guiPartyHeaderClasses = ["header_item__", "slanted-wrapper_root__", "game-options_optionLabel__"];
  107. const guiPartyHeader = () => `
  108. <div id="blinkHeaderToggle" class="${cn("header_item__")}" style="margin-right: 1rem;">
  109. <div id="popup" style="background: rgba(26, 26, 46, 0.9); padding: 15px; width: 200px; border-radius: 10px; z-index: 999;">
  110. <div style="display: flex; justify-content: space-between; align-items: center;">
  111. <span class="${cn("game-options_optionLabel__")}">Enabled</span>
  112. <input type="checkbox" id="enableScriptHeader" class="${cn("toggle_toggle__")}" onclick="toggleBlinkMode(this)">
  113. </div>
  114.  
  115. <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
  116. <span class="${cn("game-options_optionLabel__")}">Time (Seconds)</span>
  117. <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;">
  118. </div>
  119.  
  120. <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 10px;">
  121. <span class="${cn("game-options_optionLabel__")}" style="margin: 0; padding-right: 6px;">Round Delay (Seconds)</span>
  122. <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;">
  123. </div>
  124. </div>
  125. <div class="${cn("quick-search_wrapper__")}">
  126. <div class="${cn("slanted-wrapper_root__")} ${cn("slanted-wrapper_variantGrayTransparent__")}">
  127. <div class="${cn("slanted-wrapper_start__")} ${cn("slanted-wrapper_right__")}"></div>
  128. <div>
  129. <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>
  130. </div>
  131. <div class="${cn("slanted-wrapper_end__")} ${cn("slanted-wrapper_right__")}"></div>
  132. </div>
  133. </div>
  134. </div>
  135. `
  136.  
  137. if (localStorage.getItem('blinkEnabled') == null) {
  138. localStorage.setItem('blinkEnabled', 'disabled');
  139. }
  140.  
  141. if (!guiEnabled) {
  142. localStorage.setItem('blinkEnabled', 'enabled');
  143. }
  144.  
  145. if (localStorage.getItem('blinkTime') == null || isNaN(localStorage.getItem('blinkTime'))) {
  146. localStorage.setItem('blinkTime', timeLimit);
  147. }
  148. if (localStorage.getItem('delayTime') == null || isNaN(localStorage.getItem('delayTime'))) {
  149. localStorage.setItem('delayTime', roundDelay);
  150. }
  151.  
  152. if (guiEnabled) {
  153. timeLimit = parseFloat(localStorage.getItem('blinkTime'));
  154. roundDelay = parseFloat(localStorage.getItem('delayTime'));
  155. }
  156.  
  157. window.toggleBlinkMode = (e) => {
  158. localStorage.setItem('blinkEnabled', e.checked ? 'enabled' : 'disabled');
  159. if (!e.checked) {
  160. try { showPanoramaCached(); } catch {}
  161. }
  162.  
  163. if (document.querySelector('#enableScript')) {
  164. document.querySelector('#enableScript').checked = e.checked;
  165. }
  166. if (document.querySelector('#enableScriptHeader')) {
  167. document.querySelector('#enableScriptHeader').checked = e.checked;
  168. }
  169. }
  170.  
  171. window.changeBlinkTime = (e) => {
  172. if (!isNaN(e.value)) {
  173. localStorage.setItem('blinkTime', parseFloat(e.value));
  174. timeLimit = parseFloat(e.value);
  175.  
  176. if (document.querySelector('#blinkTime')) {
  177. document.querySelector('#blinkTime').value = e.value;
  178. }
  179. if (document.querySelector('#blinkTimeHeader')) {
  180. document.querySelector('#blinkTimeHeader').value = e.value;
  181. }
  182. }
  183. }
  184.  
  185. window.changeDelayTime = (e) => {
  186. if (!isNaN(e.value)) {
  187. localStorage.setItem('delayTime', parseFloat(e.value));
  188. roundDelay = parseFloat(e.value);
  189.  
  190. if (document.querySelector('#delayTime')) {
  191. document.querySelector('#delayTime').value = e.value;
  192. }
  193. if (document.querySelector('#delayTimeHeader')) {
  194. document.querySelector('#delayTimeHeader').value = e.value;
  195. }
  196. }
  197. }
  198.  
  199. const insertHeaderGui = (header, gui) => {
  200. header.insertAdjacentHTML('afterbegin', gui);
  201. const showButton = document.querySelector('#headerGuiToggle');
  202. const popup = document.querySelector('#popup');
  203. popup.style.display = 'none';
  204.  
  205. document.addEventListener('click', (e) => {
  206. const target = e.target;
  207. if (target == popup || popup.contains(target)) return;
  208. if (target.matches('#headerGuiToggle, #headerGuiToggle *')) {
  209. e.preventDefault();
  210.  
  211. popup.style.display = 'block';
  212. Popper.createPopper(showButton, popup, {
  213. placement: 'bottom',
  214. modifiers: [
  215. {
  216. name: 'offset',
  217. options: {
  218. offset: [0, 10],
  219. },
  220. },
  221. ],
  222. });
  223. } else {
  224. popup.style.display = 'none';
  225. }
  226.  
  227. if (document.querySelector('#enableScriptHeader')) {
  228. if (localStorage.getItem('blinkEnabled') === 'enabled') {
  229. document.querySelector('#enableScriptHeader').checked = true;
  230. }
  231. document.querySelector('#blinkTimeHeader').value = timeLimit;
  232. document.querySelector('#delayTimeHeader').value = roundDelay;
  233. }
  234. });
  235. }
  236.  
  237. const checkInsertGui = () => {
  238. // Play page for classic games
  239. if (document.querySelector('[class*=radio-box_root__]') && document.querySelector('#enableScript') === null && checkAllStylesFound(classicGameGuiClasses)) {
  240. document.querySelector('[class*=section_sectionMedium__]').insertAdjacentHTML('beforeend', classicGameGuiHTML());
  241. if (localStorage.getItem('blinkEnabled') === 'enabled') {
  242. document.querySelector('#enableScript').checked = true;
  243. }
  244. document.querySelector('#blinkTime').value = timeLimit;
  245. document.querySelector('#delayTime').value = roundDelay;
  246. }
  247.  
  248. // Lobby for friends party games
  249. if (document.querySelector('[class*=game-options_root__]') && document.querySelector('#enableScript') === null && checkAllStylesFound(friendLobbyGuiClasses)) {
  250. document.querySelector('[class*=game-options_optionGroup__]').insertAdjacentHTML('beforeend', friendLobbyGuiHTML());
  251. if (localStorage.getItem('blinkEnabled') === 'enabled') {
  252. document.querySelector('#enableScript').checked = true;
  253. }
  254. document.querySelector('#blinkTime').value = timeLimit;
  255. document.querySelector('#delayTime').value = roundDelay;
  256. }
  257.  
  258. // Header
  259. if (document.querySelector('[class*=header_header__]') && document.querySelector('#blinkHeaderToggle') === null && checkAllStylesFound(guiHeaderClasses)) {
  260. insertHeaderGui(document.querySelector('[class*=header_context__]'), guiHTMLHeader())
  261. } else if (document.querySelector('[class*=party-header_root__]') && document.querySelector('#blinkHeaderToggle') === null && checkAllStylesFound(guiPartyHeaderClasses)) {
  262. insertHeaderGui(document.querySelector('[class*=party-header_right__]'), guiPartyHeader())
  263. }
  264. }
  265.  
  266. let mapRoot = null;
  267. function hidePanorama() {
  268. mapRoot = document.querySelector('.mapsConsumerUiSceneInternalCoreScene__root') || mapRoot;
  269. hidePanoramaCached();
  270. }
  271.  
  272. function hidePanoramaCached() {
  273. mapRoot.style.filter = 'brightness(0%)';
  274. }
  275.  
  276. function showPanorama() {
  277. mapRoot = document.querySelector('.mapsConsumerUiSceneInternalCoreScene__root') || mapRoot;
  278. showPanoramaCached();
  279. }
  280.  
  281. function showPanoramaCached() {
  282. mapRoot.style.filter = 'brightness(100%)';
  283. }
  284.  
  285. function isLoading() {
  286. return document.querySelector('[class*=fullscreen-spinner_root__]') || !document.querySelector('.widget-scene-canvas');
  287. }
  288.  
  289. let wasBackdropThereOrLoading = false;
  290. function isBackdropThereOrLoading() {
  291. return isLoading() // loading
  292. || document.querySelector('[class*=result-layout_root__]') // classic
  293. || document.querySelector('[class*=overlay_backdrop__]') // duels / team duels
  294. || document.querySelector('[class*=game_backdrop__]') || document.querySelector('[class*=overlays_backdrop__]') // live challenges
  295. || document.querySelector('[class*=popup_backdrop__]') // BR
  296. || document.querySelector('[class*=game-starting_container__]') || document.querySelector('[class*=round-score_container__]') // bullseye
  297. || document.querySelector('[class*=overlay-modal_backlight__]'); // city streaks
  298. }
  299.  
  300. let showTimeoutID = null
  301. let hideTimeoutID = null
  302. function triggerBlink() {
  303. hidePanorama();
  304. clearTimeout(showTimeoutID);
  305. showTimeoutID = setTimeout(showPanorama, roundDelay * 1000);
  306. clearTimeout(hideTimeoutID);
  307. hideTimeoutID = setTimeout(hidePanorama, (timeLimit + roundDelay) * 1000);
  308. }
  309.  
  310. let played = false;
  311.  
  312. const checkStatus = () => {
  313. if (!(location.pathname.includes('/duels'))) {
  314. return;
  315. }
  316. let timer = document.querySelector("[class^='clock-timer_timerContainer__']");
  317. let stress = document.querySelector("[class^='stress-indicator_container__']");
  318. if ((timer !== null) && !played && (stress == null)) {
  319. showPanorama();
  320. played = true;
  321. } else if (timer == null) {
  322. played = false;
  323. }
  324. }
  325.  
  326. let observer = new MutationObserver((mutations) => {
  327. if (guiEnabled) {
  328. scanStyles().then(_ => { checkInsertGui(); });
  329. }
  330.  
  331. if (localStorage.getItem('blinkEnabled') === 'enabled') {
  332. if (isBackdropThereOrLoading()) {
  333. wasBackdropThereOrLoading = true;
  334. if (!isLoading()) hidePanorama();
  335. } else if (wasBackdropThereOrLoading) {
  336. wasBackdropThereOrLoading = false;
  337. triggerBlink();
  338. }
  339. checkStatus();
  340. }
  341.  
  342. });
  343.  
  344. observer.observe(document.body, {
  345. characterDataOldValue: false,
  346. subtree: true,
  347. childList: true,
  348. characterData: false
  349. });

QingJ © 2025

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