您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
自动记录国家/一级行政区连击次数
当前为
// ==UserScript== // @name 图寻连击计数器 // @namespace https://greasyfork.org/users/1179204 // @version 1.0.7 // @description 自动记录国家/一级行政区连击次数 // @author KaKa // @match *://tuxun.fun/* // @exclude *://tuxun.fun/replay-pano?* // @icon data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNDggNDgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgZmlsbD0iIzAwMDAwMCI+PGcgaWQ9IlNWR1JlcG9fYmdDYXJyaWVyIiBzdHJva2Utd2lkdGg9IjAiPjwvZz48ZyBpZD0iU1ZHUmVwb190cmFjZXJDYXJyaWVyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiPjwvZz48ZyBpZD0iU1ZHUmVwb19pY29uQ2FycmllciI+PHRpdGxlPjcwIEJhc2ljIGljb25zIGJ5IFhpY29ucy5jbzwvdGl0bGU+PHBhdGggZD0iTTI0LDEuMzJjLTkuOTIsMC0xOCw3LjgtMTgsMTcuMzhBMTYuODMsMTYuODMsMCwwLDAsOS41NywyOS4wOWwxMi44NCwxNi44YTIsMiwwLDAsMCwzLjE4LDBsMTIuODQtMTYuOEExNi44NCwxNi44NCwwLDAsMCw0MiwxOC43QzQyLDkuMTIsMzMuOTIsMS4zMiwyNCwxLjMyWiIgZmlsbD0iI2ZmOTQyNyI+PC9wYXRoPjxwYXRoIGQ9Ik0yNS4zNywxMi4xM2E3LDcsMCwxLDAsNS41LDUuNUE3LDcsMCwwLDAsMjUuMzcsMTIuMTNaIiBmaWxsPSIjZmZmZmZmIj48L3BhdGg+PC9nPjwvc3ZnPg== // @require https://cdn.jsdelivr.net/npm/sweetalert2@11 // @require https://unpkg.com/gcoord/dist/gcoord.global.prod.js // @copyright KaKa // @license BSD // ==/UserScript== (function() { const Language='zh' // ISO 639-1 语言代码 - https://baike.baidu.com/item/ISO%20639 let viewer,map,finalGuess,currentRound,gameState=false,roundPins={},gameMode,roundState,countsDiv,countsTitle,countsValue,mapsId,avgScore,avgValue_ let api_key=JSON.parse(localStorage.getItem('api_key')); let streakCounts=JSON.parse(localStorage.getItem('streakCounts')) let streakMode=JSON.parse(localStorage.getItem('streakMode')) if (!streakCounts){ streakCounts={} } if (!streakMode){ streakMode='country' } const CC_DICT = { AX: "FI", AS: "US", AI: "GB", AW: "NL", BM: "GB", BQ: "NL", BV: "NO", IO: "GB", KY: "UK", CX: "AU", CC: "AU", CK: "NZ", CW: "NL", FK: "AR", FO: "DK", GF: "FR", PF: "FR", TF: "FR", GI: "UK", GL: "DK", GP: "FR", GU: "US", GG: "GB", HM: "AU", HK: "CN", IM: "GB", JE: "GB", MO: "CN", MQ: "FR", YT: "FR", MS: "GB", AN: "NL", NC: "FR", NU: "NZ", NF: "AU", MP: "US", PS: "IL", PN: "GB", PR: "US", RE: "FR", BL: "FR", SH: "GB", MF: "FR", PM: "FR", SX: "NL", GS: "GB", SJ: "NO", TK: "NZ", TC: "GB", UM: "US", VG: "GB", VI: "US", WF: "FR", EH: "MA", TW: "CN" }; let intervalId=setInterval(function(){ const streetViewContainer= document.getElementById('viewer') if(streetViewContainer){ getSVContainer() getMap() if(map&&viewer&&viewer.location&&gameMode){ mapListener() clearInterval(intervalId)} } },500); 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 getSVContainer(){ const streetViewContainer= document.getElementById('viewer') const keys = Object.keys(streetViewContainer) const key = keys.find(key => key.startsWith("__reactFiber")) const props = streetViewContainer[key] viewer=props.return.child.memoizedProps.children[1].props.googleMapInstance const gameData=props.return.return.return.return.return.memoizedState.next.next.memoizedState.current.gameData if(gameData){ if(gameData.status&&gameData.status==='ongoing'){ gameState=roundState=true mapsId=gameData.mapsId if (['challenge','infinity'].includes(gameData.type)) gameMode=gameData.type if (!streakCounts[mapsId]){ streakCounts[mapsId]={'country':0,'state':0} } currentRound=gameData.rounds.length if(gameData.rounds[currentRound-1].endTime) currentRound+=1 } } } function mapListener(){ setMapObserver() setSVObserver() if (!roundPins[currentRound]){ getRoundPin() updatePanel(streakMode) } 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 setMapObserver() { map.on('click', (e) => { if (gameState&&roundState) finalGuess=e.lngLat }); } function setSVObserver() { viewer.addListener('position_changed', () => { if (!roundPins[currentRound]&&gameState){ getRoundPin() } }); } async function getRoundPin(){ var lat,lng,add if(viewer.pano.length===27) { [lat,lng]=await checkPano(viewer.pano) if(api_key) add=await queryGD(lat,lng) else add=await queryOSM(lat,lng) } else{ lat=viewer.location.latLng.lat() lng=viewer.location.latLng.lng() add=await queryOSM(lat,lng)} roundPins[currentRound]=add } function handleSizeChange(target) { const { width, height } = target.getBoundingClientRect(); const currentScreenWidth = window.innerWidth; const widthRatio = (width / currentScreenWidth) * 100; if (widthRatio>=90) { streakCheck() roundState=false } else { roundState=true updatePanel() } } async function queryOSM(lat, lng) { const url =`https://nominatim.openstreetmap.org/reverse?lat=${lat}&lon=${lng}&format=jsonv2&accept-language=${Language}`; const response = await fetch(url); if (response.ok) { let data = await response.json(); if(data.address) return data.address } else { return null; } } async function streakCheck(){ if(!roundState) return if(finalGuess){ var guess if(viewer.pano.length===27&&api_key) { if(api_key) guess=await queryGD(finalGuess.lat,finalGuess.lng) else guess=await queryOSM(finalGuess.lat,finalGuess.lng) } else guess=await queryOSM(finalGuess.lat,finalGuess.lng) try{ if(guess.country==='India'&&guess.state==='Arunachal Pradesh'){ guess.country='China' guess.state='Tibet'} else if(guess.country==='印度'&&guess.state==='阿鲁纳恰尔邦'){ guess.country='中国' guess.state='西藏自治区'} } catch(error) { } var isStreak if(streakMode==='country'){ if(matchCountryCode(guess)===matchCountryCode(roundPins[currentRound])){ isStreak=true } } else if(streakMode==='state'){ if(matchState(guess)===matchState(roundPins[currentRound])){ isStreak=true } } if(guess) updateBar(isStreak,guess,roundPins[currentRound],streakMode) else updateBar(false,'Undefined',roundPins[currentRound],streakMode) currentRound+=1 } } function correctAddress(item){ if(['Taiwan','HongKong','Macau','臺灣','台湾'].includes(item)) return Language=== 'zh' ? '中国' : 'China' else if(['科索沃','Kosovo'].includes(item)) return Language=== 'zh' ? '塞尔维亚' : 'Serbia' else if(!item) return 'Undefined' else return item } function updateBar(status,pin,result){ const infoBar=document.querySelector('.controls___yY74y') const streakText = infoBar.querySelector('p') streakText.style.fontSize='24px' streakText.style.color='#fff' streakText.style.fontFamily='Baloo Bhaina' infoBar.appendChild(streakText) if (infoBar){ if(status){ streakCounts[mapsId][streakMode]+=1 if(streakMode==='country') streakText.textContent = `恭喜你选对 ${correctAddress(result.country).split('/')[0]}, 连击次数: ${ streakCounts[mapsId][streakMode]}` else if(streakMode='state') streakText.textContent = `恭喜你选对 ${matchState(result).split('/')[0]}, 连击次数: ${ streakCounts[mapsId][streakMode]}` } else{ const end_count=streakCounts[mapsId][streakMode] streakCounts[mapsId][streakMode]=0 if(streakMode==='country') streakText.textContent = `答案是 ${correctAddress(result.country).split('/')[0]}, 你选了${correctAddress(pin.country).split('/')[0]}, 连击次数: ${ streakCounts[mapsId][streakMode]}, 本轮达成连击:${end_count}` else if(streakMode='state')streakText.textContent = `答案是 ${matchState(result).split('/')[0]}, 你选了${matchState(pin).split('/')[0]}, 连击次数: ${ streakCounts[mapsId][streakMode]}, 本轮达成连击:${end_count}` } localStorage.setItem('streakCounts',JSON.stringify(streakCounts)) } const scoreBar=document.querySelector('.scoreReulst___qqkPH') const avgDiv=document.createElement('div') const scoresDiv=document.querySelectorAll('.scoreReulstValue___gFyI2')[3] if(scoresDiv.textContent) var total_scores=parseInt(scoresDiv.textContent.replace(',', '')) const roundsDiv=document.querySelectorAll('.scoreReulstValue___gFyI2')[0] if(roundsDiv.textContent) var rounds=parseInt(roundsDiv.textContent.split('/')[0]) if(total_scores&&rounds) avgScore=total_scores/rounds if(avgScore) avgScore=parseInt(avgScore) const avgTitle=document.createElement('div') avgTitle.className='scoreReulstLabel___pgClU' avgTitle.textContent='平均分' const avgValue=document.createElement('div') avgValue.className='scoreReulstValue___gFyI2' avgValue.textContent=avgScore avgDiv.appendChild(avgTitle) avgDiv.appendChild(avgValue) scoreBar.appendChild(avgDiv) } async function queryGD(lat, lng) { const apiUrl = `https://restapi.amap.com/v3/geocode/regeo?output=json&location=${lng},${lat}&key=${api_key}&radius=20`; try { const response = await fetch(apiUrl); if (!response.ok) { throw new Error('Request failed with status: ' + response.status); } const data = await response.json(); if (data.status === '1' && data.regeocode) { return data.regeocode.addressComponent; } else { localStorage.removeItem('api_key'); Swal.fire('无效的API密钥', '请刷新页面并重新输入正确的高德地图API密钥', 'error'); throw new Error('Request failed: ' + data.info); } } catch (error) { console.error('Error fetching address:', error); throw error; } } function checkPano(id) { return new Promise((resolve, reject) => { const url = `https://mapsv0.bdimg.com/?qt=sdata&sid=${id}`; fetch(url) .then(response => response.json()) .then(data => { try { if (data.result.error !== 404) { const [lng,lat] = gcoord.transform([data.content[0].X/100, data.content[0].Y /100],gcoord.BD09MC, gcoord.WGS84) resolve([lat,lng]) } else { resolve(false) } } catch (error) { resolve(false) } }) .catch(error => { console.error('Request failed:', error); reject(error); }); }); } function updatePanel(){ const panel_container=document.querySelector('.roundWrapper___eTnOj ') if(!countsDiv){ countsDiv=document.createElement('div') countsDiv.className='roundInfoBox___ikizG' countsTitle=document.createElement('div') countsTitle.className='roundInfoTitle___VOdv2' if(streakMode==='country') countsTitle.textContent='国家连击' else countsTitle.textContent='一级行政区连击' countsValue=document.createElement('div') countsValue.className='roundInfoValue___zV6GS' countsDiv.appendChild(countsTitle) countsDiv.appendChild(countsValue) const divider = document.createElement('div'); divider.classList.add('ant-divider', 'css-i874aq', 'ant-divider-vertical'); divider.setAttribute('role', 'separator'); panel_container.appendChild(divider) panel_container.appendChild(countsDiv) if(gameMode){ panel_container.appendChild(divider) const avgDiv=document.createElement('div') avgDiv.className='roundInfoBox___ikizG' const avgTitle=document.createElement('div') avgTitle.className='roundInfoTitle___VOdv2' avgTitle.textContent='平均分' avgValue_=document.createElement('div') avgValue_.className='roundInfoValue___zV6GS' avgValue_.textContent=avgScore avgDiv.appendChild(avgTitle) avgDiv.appendChild(avgValue_) panel_container.appendChild(avgDiv) } } if(panel_container){ countsValue.textContent=streakCounts[mapsId][streakMode] avgValue_.textContent=avgScore } } function matchCountryCode(t) { if (t&&t.country_code){ const cc=t.country_code.toUpperCase() if(CC_DICT[cc])return CC_DICT[cc] else return cc } else return 'Undefined' } function matchState(t) { if(!t) return 'Undefined' if(t.country_code==='tw') return Language=== 'zh' ? '台湾省' : 'Taiwan Province' if (t.state) { return t.state; }else if (t.province) { return t.province; } else if (t.territory) { return t.territory; } else if (t.state_district) { return t.state_district; } else if (t.county) { return t.county; } else { return 'Undefined'; } } let onKeyDown = (e) => { if (e.key === 'p' || e.key === 'P') { e.stopImmediatePropagation(); if(streakMode!='state')streakMode='state' else streakMode='country' countsTitle.textContent = streakMode === 'country' ? '国家连击' : '一级行政区连击'; countsValue.textContent=streakCounts[mapsId][streakMode] localStorage.setItem('streakMode',JSON.stringify(streakMode)) Swal.fire({ title: '切换成功', text:`${streakMode === 'country' ? '国家连击' : '一级行政区连击'}连击计数器已就绪`, icon: 'success', timer: 1200, showConfirmButton: false, }); } } document.addEventListener("keydown", onKeyDown); })();