您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds random zooms and screen blackouts in Geoguessr for challenge play. Special thanks to Chhote for the idea!!
// ==UserScript== // @name Geoguessr Random Zoom Mode GeoDK // @namespace https://geodk.dev/ // @version 1.0.1 // @description Adds random zooms and screen blackouts in Geoguessr for challenge play. Special thanks to Chhote for the idea!! // @author Dorukhan Bozkurt (geoDK) // @match https://www.geoguessr.com/* // @icon https://www.svgrepo.com/show/40039/eye.svg // @license MIT // @grant none // ==/UserScript== (function () { 'use strict'; let zoomTime = parseFloat(localStorage.getItem('zoomTime')) || 1.0; let zoomNumber = parseInt(localStorage.getItem('zoomNumber')) || 3; let zoomDelay = parseFloat(localStorage.getItem('zoomDelay')) || 0; let zoomEnabled = localStorage.getItem('zoomEnabled') === 'enabled'; const blinkTime = 500; // ms const scaleMin = 3.0; const scaleMax = 5.0; let wasBackdropThereOrLoading = false; function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function simulatePanDrag() { const canvas = document.querySelector('.widget-scene-canvas'); if (!canvas) return; const rect = canvas.getBoundingClientRect(); const startX = rect.left + rect.width / 2; const startY = rect.top + rect.height / 2; const dragDistance = 300; const angle = Math.random() * 2 * Math.PI; const endX = startX + Math.cos(angle) * dragDistance; const endY = startY + Math.sin(angle) * dragDistance; canvas.dispatchEvent(new MouseEvent('mousedown', { bubbles: true, clientX: startX, clientY: startY })); canvas.dispatchEvent(new MouseEvent('mousemove', { bubbles: true, clientX: endX, clientY: endY })); canvas.dispatchEvent(new MouseEvent('mouseup', { bubbles: true, clientX: endX, clientY: endY })); } function getPanoramaEl() { return document.querySelector("[data-qa=panorama]"); } function applyRandomZoom(pano) { if (!pano) return; pano.style.transition = 'none'; const randPercent = () => `${Math.random() * 100}%`; const zoomLevel = scaleMin + Math.random() * (scaleMax - scaleMin); pano.style.transformOrigin = `${randPercent()} ${randPercent()}`; pano.style.transform = `scale(${zoomLevel})`; } function resetZoom(pano) { if (!pano) return; pano.style.transform = 'scale(1)'; pano.style.transformOrigin = 'center center'; } function hidePanorama() { const pano = getPanoramaEl(); if (pano) pano.style.filter = 'brightness(0%)'; } function showPanorama() { const pano = getPanoramaEl(); if (pano) pano.style.filter = 'brightness(100%)'; } function isBackdropThereOrLoading() { return document.querySelector('[class*=overlay_backdrop__]') || document.querySelector('[class*=round-starting_wrapper__]') || document.querySelector('[class*=fullscreen-spinner_root__]') || document.querySelector('[class*=game-starting_container__]'); } async function handleRoundStart() { if (!zoomEnabled) return; const pano = getPanoramaEl(); if (!pano) return; resetZoom(pano); showPanorama(); if (zoomDelay > 0) { hidePanorama(); await sleep(zoomDelay * 1000); showPanorama(); } for (let i = 0; i < zoomNumber; i++) { simulatePanDrag(); applyRandomZoom(pano); await sleep(zoomTime * 1000); if (i < zoomNumber - 1) { hidePanorama(); await sleep(blinkTime); showPanorama(); resetZoom(pano); } } hidePanorama(); resetZoom(pano); } const observer = new MutationObserver(() => { addSettingsUI(); if (isBackdropThereOrLoading()) { wasBackdropThereOrLoading = true; } else if (wasBackdropThereOrLoading) { wasBackdropThereOrLoading = false; handleRoundStart(); } }); observer.observe(document.body, { childList: true, subtree: true }); function addSettingsUI() { // For party mode settings const partyPanel = document.querySelector('[class*=party-modal_heading__]'); const partyColumns = document.querySelectorAll('[class*=settings-modal_column__]'); if (partyPanel && partyColumns.length && !document.getElementById('zoomModeSettings')) { partyColumns[partyColumns.length - 1].insertAdjacentHTML('beforeend', getSettingsHTML(true)); bindSettingHandlers(); return; } // For regular game interface const gameContainer = document.querySelector('[class*=map-block_mapStatsContainer__]') || document.querySelector('[class*=status_container__]') || document.querySelector('[class*=game-map_gameMap__]'); if (!gameContainer || document.getElementById('zoomModeSettings')) return; gameContainer.insertAdjacentHTML('afterend', getSettingsHTML(false)); bindSettingHandlers(); } function getSettingsHTML(isPartyMode) { if (isPartyMode) { return ` <div id="zoomModeSettings" class="toggle-option_wrapper__"> <div class="toggle-option_label__">Random Zoom Mode</div> <input type="checkbox" id="zoomEnabled" class="toggle_toggle__"> <div class="numeric-option_wrapper__"> <div class="numeric-option_label__">Zoom Time (s)</div> <input type="number" id="zoomTime" value="${zoomTime}" min="0.1" step="0.1"> </div> <div class="numeric-option_wrapper__"> <div class="numeric-option_label__">Zoom Number</div> <input type="number" id="zoomNumber" value="${zoomNumber}" min="1" step="1"> </div> <div class="numeric-option_wrapper__"> <div class="numeric-option_label__">Start Delay (s)</div> <input type="number" id="zoomDelay" value="${zoomDelay}" min="0" step="0.1"> </div> </div>`; } else { return ` <div id="zoomModeSettings" style="position: absolute; bottom: 20px; left: 20px; background: rgba(255, 255, 255, 0.05); padding: 12px; border-radius: 12px; z-index: 999; backdrop-filter: blur(4px); color: white; width: 220px; font-family: inherit; box-shadow: 0 0 8px rgba(0,0,0,0.2);"> <h3 style="margin-bottom: 10px; font-size: 16px; text-align: center;">🎥 geoDK's Random Zoom Mode</h3> <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;"> <label style="margin-right: 10px;">Enabled</label> <input type="checkbox" id="zoomEnabled"> </div> <div style="margin-bottom: 10px;"> <label style="display: block; margin-bottom: 4px;">Zoom Time (s)</label> <input type="number" id="zoomTime" value="${zoomTime}" min="0.1" step="0.1" style="width: 100%;"> </div> <div style="margin-bottom: 10px;"> <label style="display: block; margin-bottom: 4px;">Zoom Number</label> <input type="number" id="zoomNumber" value="${zoomNumber}" min="1" step="1" style="width: 100%;"> </div> <div> <label style="display: block; margin-bottom: 4px;">Start Delay (s)</label> <input type="number" id="zoomDelay" value="${zoomDelay}" min="0" step="0.1" style="width: 100%;"> </div> </div>`; } } function bindSettingHandlers() { const enabledEl = document.getElementById('zoomEnabled'); if (!enabledEl) return; enabledEl.checked = zoomEnabled; enabledEl.addEventListener('change', e => { zoomEnabled = e.target.checked; localStorage.setItem('zoomEnabled', zoomEnabled ? 'enabled' : 'disabled'); }); document.getElementById('zoomTime').addEventListener('change', e => { zoomTime = parseFloat(e.target.value); localStorage.setItem('zoomTime', zoomTime); }); document.getElementById('zoomNumber').addEventListener('change', e => { zoomNumber = parseInt(e.target.value); localStorage.setItem('zoomNumber', zoomNumber); }); document.getElementById('zoomDelay').addEventListener('change', e => { zoomDelay = parseFloat(e.target.value); localStorage.setItem('zoomDelay', zoomDelay); }); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址