// ==UserScript== // @name 图寻音效 // @namespace https://greasyfork.org/users/1179204 // @version 1.0.1 // @description 增加地图点击音效以及倒计时提醒音效 // @author KaKa // @icon https://www.svgrepo.com/show/521999/bell.svg // @match *://tuxun.fun/* // @exclude *://tuxun.fun/replay-pano?* // @grant GM_addStyle // @license BSD // @downloadURL none // ==/UserScript== (function() { let map,streetViewPanorama,currentIndex=0,isPointCount=false,isPlay=true let bellIcon=` ` let silenceIcon=` ` let iconUrl=svgToUrl(bellIcon) const button = document.createElement('button'); button.id = 'replay'; GM_addStyle(` #replay { position:absolute; left:24px; bottom:20%; width: 40px; height: 40px; border: none; border-radius:20px; background-image: url('${iconUrl}'); background-size: auto; background-position: center; background-color:#000000; background-repeat: no-repeat; cursor: pointer; color: white; font-size: 16px; display: inline-flex; align-items: center; justify-content: center; z-Index:9999 } `); button.onclick = () => { if(!isPlay){ isPlay=true button.style.backgroundImage=`url('${iconUrl}')` } else{ isPlay=false button.style.backgroundImage=`url(${svgToUrl(silenceIcon)})` } } const water_effect='https://www.geoguessr.com/_next/static/audio/place-guess-water-81b402df882cdb731e83a5463582d9c6.mp3' const land_effects=[ 'https://www.geoguessr.com/_next/static/audio/place-guess-land-1ac6606a711c3f128d917f3287d06b5f.mp3', 'https://www.geoguessr.com/_next/static/audio/place-guess-land-2-9a5a0a2fa6b2595f8a8e59312b5f41a9.mp3', 'https://www.geoguessr.com/_next/static/audio/place-guess-land-3-16f00d5f32e748cc49b45c8197b1986a.mp3', 'https://www.geoguessr.com/_next/static/audio/place-guess-land-4-9e3d39d2743652364f518acfc8ec9163.mp3', 'https://www.geoguessr.com/_next/static/audio/place-guess-land-5-dac7ac12a1b2ab0c6e97063e8e017095.mp3', 'https://www.geoguessr.com/_next/static/audio/place-guess-land-6-c4f4f4a8fcf8a6b2fbf1771d6538cadd.mp3'] const countdown='https://www.geoguessr.com/_next/static/audio/new-effect-timer-countdown-0ebc3024e8d1ef071d03f958f2813c0f.mp3' const pointCount='https://www.geoguessr.com/_next/static/audio/effect-point-count-4401d2046fe66715ea454bc6d2dddc2d.mp3' let intervalId=setInterval(function(){ const streetViewContainer= document.getElementById('viewer') const wrapper=document.querySelector('.wrapper___NMMQn') if(streetViewContainer){ getSvContainer() getMap() if(map&&streetViewPanorama){ wrapper.appendChild(button) mapListener() map.on('click', async (e) => { const lat=e.lngLat.lat const lng=e.lngLat.lng if(!isPointCount){ const isWater=await isTileCenterBlue(lat,lng) if(!isWater)playAudio(land_effects[currentIndex]) else playAudio(water_effect) currentIndex+=1 if(currentIndex===6)currentIndex=0} }); clearInterval(intervalId)} } },500); function svgToUrl(svgText) { const svgBlob = new Blob([svgText], {type: 'image/svg+xml'}); const svgUrl = URL.createObjectURL(svgBlob); return svgUrl; } function getSvContainer(){ const streetViewContainer= document.getElementById('viewer') const keys = Object.keys(streetViewContainer) const key = keys.find(key => key.startsWith("__reactFiber")) const props = streetViewContainer[key] streetViewPanorama=props.return.child.memoizedProps.children[1].props.googleMapInstance } function getMap(){ var mapContainer = document.getElementById('map') const keys = Object.keys(mapContainer) const key = keys.find(key => key.startsWith("__reactFiber$")) const props = mapContainer[key] const x = props.child.memoizedProps.value.map map=x.getMap() } function getTileUrl(lat,lng){ function lon2tile(lng,zoom) { return (Math.floor((lng+180)/360*Math.pow(2,zoom))); } function lat2tile(lat,zoom){ return (Math.floor((1-Math.log(Math.tan(lat*Math.PI/180) + 1/Math.cos(lat*Math.PI/180))/Math.PI)/2 *Math.pow(2,zoom))); } const zoom=20 const tileX=lon2tile(lng,zoom) const tileY=lat2tile(lat,zoom) return `https://maprastertile-drcn.dbankcdn.cn/display-service/v1/online-render/getTile/23.12.09.11/${zoom}/${tileX}/${tileY}/?language=zh&p=46&scale=2&mapType=ROADMAP&presetStyleId=standard&pattern=JPG&key=DAEDANitav6P7Q0lWzCzKkLErbrJG4kS1u%2FCpEe5ZyxW5u0nSkb40bJ%2BYAugRN03fhf0BszLS1rCrzAogRHDZkxaMrloaHPQGO6LNg==` } async function isTileCenterBlue(lat, lng) { const tileSize = 256; const url = getTileUrl(lat, lng); try { const response = await fetch(url); const blob = await response.blob(); const imageBitmap = await createImageBitmap(blob); const canvas = document.createElement('canvas'); canvas.width = tileSize; canvas.height = tileSize; const context = canvas.getContext('2d'); context.drawImage(imageBitmap, 0, 0, tileSize, tileSize); const imageData = context.getImageData(0, 0, tileSize, tileSize); const data = imageData.data; const centerX = Math.floor(tileSize / 2); const centerY = Math.floor(tileSize / 2); const centerIndex = (centerY * tileSize + centerX) * 4; const r = data[centerIndex]; const g = data[centerIndex + 1]; const b = data[centerIndex + 2]; function isCloseToBlue(r, g, b) { return r===129 && g===212 &&b===255; } return isCloseToBlue(r, g, b); } catch (error) { console.error('Error fetching or processing the tile:', error); return false; } } function playAudio(source) { if(!isPlay)return const audio = new Audio(); audio.loop = false; audio.volume = 1; if (source===pointCount) audio.volume = 0.5 if (source===countdown) audio.volume = 0.6 if (source===water_effect) audio.volume = 0.8 audio.src = source; audio.play().catch(error => { console.error('播放音频失败:', error); }); if(source===countdown){ setTimeout(() => { audio.pause(); audio.remove(); }, 16000);} else{ audio.addEventListener('ended', () => { audio.remove(); if (source===pointCount)isPointCount=false }); } } function mapListener(){ var mapContainer = document.querySelector('.maplibregl-canvas') const observer = new MutationObserver((mutationsList, observer) => { for(let mutation of mutationsList) { if (mutation.type === 'attributes' && mutation.attributeName === 'style') { handleSizeChange(mapContainer); } } }); observer.observe(mapContainer, { attributes: true, attributeFilter: ['style'] }); } function handleSizeChange(target) { const currentUrl = window.location.href; const { width, height } = target.getBoundingClientRect(); const currentScreenWidth = window.innerWidth; const widthRatio = (width / currentScreenWidth) * 100; if (widthRatio>=90){ if(currentUrl.includes('challenge')){ isPointCount=true setTimeout(function(){playAudio(pointCount)},200) } } } const observer = new MutationObserver((mutationsList) => { for (const mutation of mutationsList) { if (mutation.type === 'childList') { mutation.addedNodes.forEach(node => { node.querySelectorAll && node.querySelectorAll('.countdownTimer___pqf8b').forEach(childNode => { let intervalId = setInterval(function() { const timeLeft = childNode.innerHTML.toString(); if (timeLeft.includes(':15')) { playAudio(countdown) clearInterval(intervalId); } }, 100); }); }); } } }); const config = { childList: true, subtree: true }; observer.observe(document.body, config); })();