图寻连击计数器

自动记录国家/一级行政区连击次数

Fra 31.08.2024. Se den seneste versjonen.

// ==UserScript==
// @name         图寻连击计数器
// @namespace    https://greasyfork.org/users/1179204
// @version      1.0.1
// @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
// @copyright    KaKa
// @license      BSD
// ==/UserScript==

(function() {
    let viewer,map,finalGuess,currentRound,gameState=false,roundPins={},roundState,countsDiv,countsTitle,countsValue,streakMode='country'

    let streakCounts=JSON.parse(localStorage.getItem('streakCounts'))
    if (!streakCounts){
        streakCounts={'country':0,'state':0}
    }

    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: "GB", 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){
                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
                currentRound=gameData.rounds.length
            }
        }
    }

    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(){
        const lat=viewer.location.latLng.lat()
        const lng=viewer.location.latLng.lng()
        const add=await queryOSM(lat,lng,'en')
        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, language) {
        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){
            const guess=await queryOSM(finalGuess.lat,finalGuess.lng,'en')
            try{
                if(guess.country==='India'&&guess.state==='Arunachal Pradesh'){
                    guess.country='China'
                    guess.state='Tibet'}
            }
            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 'China'
        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[streakMode]+=1
                console.log(result.country)
                if(streakMode==='country') streakText.textContent = `恭喜你选中 ${correctAddress(result.country)}, 连击次数: ${ streakCounts[streakMode]}`
                else if(streakMode='state') streakText.textContent = `恭喜你选中 ${matchState(result)}, 连击次数: ${ streakCounts[streakMode]}`

            }

            else{
                const end_count=streakCounts[streakMode]
                streakCounts[streakMode]=0
                if(streakMode==='country') streakText.textContent = `答案是 ${correctAddress(result.country)}, 你选了${correctAddress(pin.country)}, 连击次数: ${ streakCounts[streakMode]}, 本轮达成连击:${end_count}`
                else if(streakMode='state')streakText.textContent = `答案是 ${matchState(result)}, 你选了${matchState(pin)}, 连击次数: ${ streakCounts[streakMode]}, 本轮达成连击:${end_count}`
            }
            localStorage.setItem('streakCounts',JSON.stringify(streakCounts))
        }

    }
    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(panel_container){
            countsValue.textContent=streakCounts[streakMode]}

    }

    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.state) {
            return t.state;
        }else if (t.province) {
            return t.province;
        } 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[streakMode]
            Swal.fire({
                title: '切换成功',
                text:`${streakMode} 连击计数器已就绪`,
                icon: 'success',
                timer: 1000,
                showConfirmButton: false,
            });
        }
    }

    document.addEventListener("keydown", onKeyDown);
})();