YouTube NoLiveChat

Automatically closes the YouTube Live Chat (Theater Mode or Full Screen).

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         YouTube NoLiveChat
// @namespace    http://tampermonkey.net/
// @version      7.3
// @description  Automatically closes the YouTube Live Chat (Theater Mode or Full Screen).
// @author       Narc (Fixed by Gemini)
// @license      MIT
// @match        https://www.youtube.com/*
// @match        https://www.youtube.com/live_chat*
// @icon         https://i.ibb.co/yDP9ZXg/E3610-DA9-5898-49-DA-8-EBF-DB78-F039-EAAE-removebg-preview.png
// @grant        none
// @run-at       document-end
// ==/UserScript==

(function() {
    'use strict';

    const CONFIG = {
        DELAY_MS: 10000, // 10 Segundos de delay
        DEBUG: true,
        CMD_CLOSE: 'SENTINEL_CMD_CLOSE'
    };

    function log(msg, context = 'Main') {
        if (CONFIG.DEBUG) console.log(`%c[Sentinel:${context}] ${msg}`, 'color: #00ff00; font-weight: bold;');
    }

    // =================================================================
    // LADO A: O SOLDADO (Roda dentro do Iframe do Chat)
    // =================================================================
    if (window.location.pathname.startsWith('/live_chat')) {
        log('Soldado iniciado no iframe do chat.', 'Iframe');

        // Definimos a função como const antes de usar para evitar o aviso do linter
        const closeChatInsideIframe = () => {
            // Seletores específicos do ambiente do chat
            const selectors = [
                '#close-button button',
                '#chat-header #close-button button',
                'button[aria-label="Fechar"]',
                'button[aria-label="Close"]'
            ];

            let btn = null;
            for (let sel of selectors) {
                btn = document.querySelector(sel);
                if (btn) break;
            }

            if (btn) {
                // Clique Nuclear
                const opts = { bubbles: true, cancelable: true, view: window };
                btn.dispatchEvent(new MouseEvent('mousedown', opts));
                btn.dispatchEvent(new MouseEvent('mouseup', opts));
                btn.click();
                log('Botão clicado com sucesso.', 'Iframe');
            } else {
                log('ERRO: Botão de fechar não encontrado no iframe.', 'Iframe');
            }
        };

        // Escuta ordens vindas da página principal
        window.addEventListener('message', (event) => {
            if (event.data === CONFIG.CMD_CLOSE) {
                log('Ordem de fechamento recebida! Executando...', 'Iframe');
                closeChatInsideIframe();
            }
        });
        
        return; // Encerra execução aqui se for iframe
    }

    // =================================================================
    // LADO B: O COMANDANTE (Roda na Página do Vídeo)
    // =================================================================
    
    let timer = null;

    function isExpandedMode() {
        const isFullscreen = !!document.fullscreenElement;
        const watchFlexy = document.querySelector('ytd-watch-flexy');
        const isTheater = watchFlexy && watchFlexy.hasAttribute('theater');
        return isFullscreen || isTheater;
    }

    function sendCloseOrder() {
        // Verifica se ainda devemos fechar
        if (!isExpandedMode()) {
            log('Cancelando ordem: Modo expandido encerrado.', 'Commander');
            return;
        }

        const iframe = document.getElementById('chatframe');
        if (iframe && iframe.contentWindow) {
            log('Enviando ordem de fechamento para o iframe...', 'Commander');
            // Envia a mensagem para o iframe
            iframe.contentWindow.postMessage(CONFIG.CMD_CLOSE, '*');
        } else {
            log('Iframe do chat não encontrado. Tentando novamente em 2s...', 'Commander');
            setTimeout(sendCloseOrder, 2000);
        }
    }

    function scheduleOrder() {
        if (!isExpandedMode()) return;
        
        log(`Modo Expandido detectado. Timer iniciado: ${CONFIG.DELAY_MS/1000}s`, 'Commander');
        
        if (timer) clearTimeout(timer);
        timer = setTimeout(sendCloseOrder, CONFIG.DELAY_MS);
    }

    // --- Gatilhos do Comandante ---

    // 1. Tela Cheia
    document.addEventListener('fullscreenchange', () => {
        if (document.fullscreenElement) scheduleOrder();
        else if (timer) clearTimeout(timer);
    });

    // 2. Modo Teatro
    const observer = new MutationObserver((mutations) => {
        for (const m of mutations) {
            if (m.type === 'attributes' && m.attributeName === 'theater') {
                setTimeout(scheduleOrder, 500);
            }
        }
    });

    // 3. Atalho de Teste (ALT + K)
    document.addEventListener('keydown', (e) => {
        if (e.altKey && (e.key === 'k' || e.key === 'K')) {
            log('TESTE MANUAL: Enviando ordem imediata.', 'Commander');
            const iframe = document.getElementById('chatframe');
            if(iframe) iframe.contentWindow.postMessage(CONFIG.CMD_CLOSE, '*');
            else log('Iframe não achado para teste.', 'Commander');
        }
    });

    // Inicialização
    const initInt = setInterval(() => {
        const watchFlexy = document.querySelector('ytd-watch-flexy');
        if (watchFlexy) {
            observer.observe(watchFlexy, { attributes: true });
            clearInterval(initInt);
            // Verifica estado inicial
            if (isExpandedMode()) scheduleOrder();
        }
    }, 1000);

})();