끄투 방 참가 알림

실시간으로 참여자 수 변화를 감지해 사인파 소리 재생 및 자동 시작/관전 버튼 클릭

// ==UserScript==
// @name          끄투 방 참가 알림
// @namespace     끄투 방 참가 알림
// @match         https://kkutu.co.kr/*
// @version       1.3
// @description   실시간으로 참여자 수 변화를 감지해 사인파 소리 재생 및 자동 시작/관전 버튼 클릭
// @icon          https://www.google.com/s2/favicons?domain=kkutu.co.kr
// @grant         none
// @license       MIT
// ==/UserScript==

(function () {
    'use strict';

    let previousCount = 0;
    const autoStartCheckboxId = 'autoStartCheckbox';
    const autoSpectateCheckboxId = 'autoSpectateCheckbox';

    function setCookie(name, value, days) {
        const date = new Date();
        date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
        document.cookie = `${name}=${value}; expires=${date.toUTCString()}; path=/`;
    }

    function getCookie(name) {
        const cookies = document.cookie.split('; ').reduce((acc, cookie) => {
            const [key, value] = cookie.split('=');
            acc[key] = value;
            return acc;
        }, {});
        return cookies[name] || null;
    }

    function createCheckbox(id, labelText, topOffset) {
        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.id = id;
        checkbox.style.position = 'fixed';
        checkbox.style.top = `${topOffset}px`;
        checkbox.style.right = '10px';
        document.body.appendChild(checkbox);

        const label = document.createElement('label');
        label.htmlFor = id;
        label.innerText = labelText;
        label.style.position = 'fixed';
        label.style.top = `${topOffset}px`;
        label.style.right = '30px';
        document.body.appendChild(label);

        return checkbox;
    }

    const autoStartCheckbox = createCheckbox(autoStartCheckboxId, '자동 시작', 10);
    const autoSpectateCheckbox = createCheckbox(autoSpectateCheckboxId, '자동 관전', 40);

    autoStartCheckbox.checked = getCookie(autoStartCheckboxId) === 'true';
    autoSpectateCheckbox.checked = getCookie(autoSpectateCheckboxId) === 'true';

    autoStartCheckbox.addEventListener('change', () => {
        setCookie(autoStartCheckboxId, autoStartCheckbox.checked, 7);
        console.log('자동 시작 설정:', autoStartCheckbox.checked);
    });

    autoSpectateCheckbox.addEventListener('change', () => {
        setCookie(autoSpectateCheckboxId, autoSpectateCheckbox.checked, 7);
        console.log('자동 관전 설정:', autoSpectateCheckbox.checked);
    });

    // 사인파 소리 재생 함수
    function playSineWave(frequency, duration) {
        const audioContext = new (window.AudioContext || window.webkitAudioContext)();
        const oscillator = audioContext.createOscillator();
        oscillator.type = 'sine';
        oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime);
        oscillator.connect(audioContext.destination);
        oscillator.start();
        oscillator.stop(audioContext.currentTime + duration);
    }

    function playTripleBeep() {
        const audioContext = new (window.AudioContext || window.webkitAudioContext)();
        const frequencies = [1220, 1220, 1220];
        const times = [0, 0.3, 0.6];

        frequencies.forEach((freq, index) => {
            const oscillator = audioContext.createOscillator();
            oscillator.type = 'sine';
            oscillator.frequency.setValueAtTime(freq, audioContext.currentTime + times[index]);
            oscillator.connect(audioContext.destination);
            oscillator.start(audioContext.currentTime + times[index]);
            oscillator.stop(audioContext.currentTime + times[index] + 0.2);
        });
    }


    function getUserCounts() {
        const spectators = document.querySelectorAll('.room-user-spectate');
        let readyCount = 0;
        let waitingCount = 0;
        let spectatorsCount = spectators.length; // 관전 인원 초기화

        document.querySelectorAll('.room-user-ready').forEach((user) => {
            if (user.textContent.includes('준비') && !user.classList.contains('room-user-master')) {
                readyCount++;
            } else if (user.textContent.includes('대기')) {
                waitingCount++;
            } else if (user.classList.contains('room-user-master')) {
                // 방장이 '준비'인 경우
                if (user.textContent.includes('관전')) {
                    // 방장이 관전 중이라면, 관전 인원에 추가
                    spectatorsCount++;
                } else {
                    // 방장이 '준비' 상태라면 준비 인원에 추가
                    readyCount++;
                }
            }
        });

        console.log('준비 인원:', readyCount);
        console.log('대기 인원:', waitingCount);
        console.log('관전 인원:', spectatorsCount);

        return { readyCount, waitingCount, spectatorsCount };
    }

    function getTeamCounts() {
        const teamCounts = { A: 0, B: 0, C: 0, D: 0, 개인: 0 };
        document.querySelectorAll('.room-user-team').forEach((user) => {
            if (user.classList.contains('team-1')) teamCounts.A++;
            else if (user.classList.contains('team-2')) teamCounts.B++;
            else if (user.classList.contains('team-3')) teamCounts.C++;
            else if (user.classList.contains('team-4')) teamCounts.D++;
            else if (user.classList.contains('room-user-ready') && user.classList.contains('room-user-spectate')) {
                return;
            } else {
                teamCounts.개인++;
            }
        });

        console.log('팀 인원:', teamCounts);
        return teamCounts;
    }

    function canStartGame() {
        const { readyCount, waitingCount } = getUserCounts();
        const { A, B, C, D, 개인 } = getTeamCounts();
        const teams = { A, B, C, D };

        if (waitingCount > 0) {
            console.log('대기 인원이 존재하여 게임 시작 불가');
            return false; // 대기 인원이 존재할 경우 게임 시작 불가
        }

        if (readyCount < 2) {
            console.log('준비 인원이 2인 미만으로 게임 시작 불가');
            return false; // 준비 인원이 2인 미만일 경우 시작 불가
        }

        // 팀 인원 수 체크
        const teamSizes = Object.values(teams).filter(count => count > 0);
        const allEqual = teamSizes.length > 0 && teamSizes.every(size => size === teamSizes[0]);

        // 팀 수가 0인 경우는 개인 인원이 2명 이상이면 게임 시작 가능
        if (teamSizes.length === 0 && 개인 >= 2) {
            console.log('팀이 없지만 개인 인원이 2명 이상이므로 게임 시작 가능');
            return true; // 개인 인원이 2명 이상인 경우 게임 시작 가능
        }

        // 팀 수가 불균형한 경우
        if (!allEqual) {
            console.log('팀 수 불균형 (실행 금지)');
            return false; // 팀 수 불균형
        }

        // 개인이 있을 경우
        if (개인 > 0) {
            const sameTeamCount = Object.values(teams).some(count => count >= 2);
            if (sameTeamCount) {
                console.log('팀이 2명 이상이며 개인이 존재하므로 게임 시작 불가');
                return false; // 팀이 2명 이상인 경우 게임 시작 불가
            }
        }

        // 두 팀 이상의 인원이 있어야 게임 시작 가능
        const totalTeams = Object.values(teams).filter(count => count > 0).length;
        if (totalTeams < 2) {
            console.log('상대팀이 없으므로 게임 시작 불가');
            return false; // 상대팀이 없는 경우 게임 시작 불가
        }

        console.log('게임 시작 가능');
        return true; // 조건을 모두 만족한 경우
    }

    function autoStartGame() {
        const startBtn = document.getElementById('StartBtn');
        if (!startBtn || startBtn.style.display === 'none') {
            return;
        }

        if (canStartGame()) {
            console.log('게임 시작 버튼 클릭');
            startBtn.click(); // 게임 시작 클릭
        }
    }

    function autoSpectate() {
        const spectateBtn = document.getElementById('SpectateBtn');
        if (spectateBtn && spectateBtn.style.display === 'block' && !spectateBtn.classList.contains('toggled')) {
            spectateBtn.click(); // 관전 클릭
            console.log('관전 버튼 클릭');
        }
    }

    const observer = new MutationObserver(() => {
        const element = document.querySelector('.room-head-limit');
        if (!element) return;

        const match = element.textContent.match(/참여자 (\d+) \/ (\d+)/);
        if (!match) return;

        const currentCount = parseInt(match[1], 10);
        const maxCount = parseInt(match[2], 10);

        if (currentCount !== previousCount) {
            if (currentCount > previousCount) {
                if (currentCount === maxCount) {
                    playTripleBeep();
                } else {
                    playSineWave(880, 0.2); // 참가자 수가 늘어났을 때
                }
            } else {
                playSineWave(440, 0.2); // 참가자 수가 줄어들었을 때
            }

            previousCount = currentCount;
        }

        if (autoStartCheckbox.checked) {
            autoStartGame();
        }

        if (autoSpectateCheckbox.checked) {
            autoSpectate();
        }
    });

    const config = { childList: true, subtree: true };
    observer.observe(document.body, config);
})();

QingJ © 2025

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