YouTube Optimizador UI (Español)

Optimiza YouTube para un mejor rendimiento y experiencia mejorada.

// ==UserScript==
// @name         YouTube Optimizador UI (Español)
// @namespace    http://tampermonkey.net/
// @version      2.1
// @description  Optimiza YouTube para un mejor rendimiento y experiencia mejorada.
// @license      MIT
// @author       AkioBrian
// @icon         https://i.imgur.com/gDJmU8b.png
// @match        https://www.youtube.com/*
// @match        https://youtube.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';

    // ===== CONFIGURACIÓN =====
    let CONFIG = {
        removeElements: {
            sidebar: GM_getValue('sidebar', true),           // Ocultar recomendaciones laterales
            comments: GM_getValue('comments', false),        // Mantener comentarios
            shorts: GM_getValue('shorts', true),            // Ocultar Shorts
            endScreen: GM_getValue('endScreen', true),      // Ocultar pantalla final
            cards: GM_getValue('cards', true)               // Ocultar tarjetas de video
        },
        performance: {
            reducePrefetch: GM_getValue('reducePrefetch', true),    // Reducir precarga
            tabManagement: GM_getValue('tabManagement', false),     // Gestión de pestañas
            memoryCleanup: GM_getValue('memoryCleanup', true)       // Limpieza de memoria
        },
        ui: {
            compactMode: GM_getValue('compactMode', false),         // Modo compacto
            minimalTheme: GM_getValue('minimalTheme', true),        // Tema minimalista
            darkOptimized: GM_getValue('darkOptimized', true)       // Colores optimizados
        }
    };

    // ===== MENÚ DE CONFIGURACIÓN =====
    function createMenuCommands() {
        // Elementos a remover
        GM_registerMenuCommand('🔲 Sidebar: ' + (CONFIG.removeElements.sidebar ? 'OCULTO' : 'VISIBLE'), () => {
            CONFIG.removeElements.sidebar = !CONFIG.removeElements.sidebar;
            GM_setValue('sidebar', CONFIG.removeElements.sidebar);
            location.reload();
        });

        GM_registerMenuCommand('💬 Comentarios: ' + (CONFIG.removeElements.comments ? 'OCULTOS' : 'VISIBLES'), () => {
            CONFIG.removeElements.comments = !CONFIG.removeElements.comments;
            GM_setValue('comments', CONFIG.removeElements.comments);
            location.reload();
        });

        GM_registerMenuCommand('📱 Shorts: ' + (CONFIG.removeElements.shorts ? 'OCULTOS' : 'VISIBLES'), () => {
            CONFIG.removeElements.shorts = !CONFIG.removeElements.shorts;
            GM_setValue('shorts', CONFIG.removeElements.shorts);
            location.reload();
        });

        GM_registerMenuCommand('🎬 Pantalla Final: ' + (CONFIG.removeElements.endScreen ? 'OCULTA' : 'VISIBLE'), () => {
            CONFIG.removeElements.endScreen = !CONFIG.removeElements.endScreen;
            GM_setValue('endScreen', CONFIG.removeElements.endScreen);
            location.reload();
        });

        GM_registerMenuCommand('🃏 Tarjetas: ' + (CONFIG.removeElements.cards ? 'OCULTAS' : 'VISIBLES'), () => {
            CONFIG.removeElements.cards = !CONFIG.removeElements.cards;
            GM_setValue('cards', CONFIG.removeElements.cards);
            location.reload();
        });

        // Rendimiento
        GM_registerMenuCommand('⚡ Reducir Precarga: ' + (CONFIG.performance.reducePrefetch ? 'ON' : 'OFF'), () => {
            CONFIG.performance.reducePrefetch = !CONFIG.performance.reducePrefetch;
            GM_setValue('reducePrefetch', CONFIG.performance.reducePrefetch);
            location.reload();
        });

        GM_registerMenuCommand('📑 Gestión Pestañas: ' + (CONFIG.performance.tabManagement ? 'ON' : 'OFF'), () => {
            CONFIG.performance.tabManagement = !CONFIG.performance.tabManagement;
            GM_setValue('tabManagement', CONFIG.performance.tabManagement);
            location.reload();
        });

        GM_registerMenuCommand('🧹 Limpieza Memoria: ' + (CONFIG.performance.memoryCleanup ? 'ON' : 'OFF'), () => {
            CONFIG.performance.memoryCleanup = !CONFIG.performance.memoryCleanup;
            GM_setValue('memoryCleanup', CONFIG.performance.memoryCleanup);
            location.reload();
        });

        // UI
        GM_registerMenuCommand('📦 Modo Compacto: ' + (CONFIG.ui.compactMode ? 'ON' : 'OFF'), () => {
            CONFIG.ui.compactMode = !CONFIG.ui.compactMode;
            GM_setValue('compactMode', CONFIG.ui.compactMode);
            location.reload();
        });

        GM_registerMenuCommand('🎨 Tema Minimalista: ' + (CONFIG.ui.minimalTheme ? 'ON' : 'OFF'), () => {
            CONFIG.ui.minimalTheme = !CONFIG.ui.minimalTheme;
            GM_setValue('minimalTheme', CONFIG.ui.minimalTheme);
            location.reload();
        });

        GM_registerMenuCommand('🌙 Oscuro Optimizado: ' + (CONFIG.ui.darkOptimized ? 'ON' : 'OFF'), () => {
            CONFIG.ui.darkOptimized = !CONFIG.ui.darkOptimized;
            GM_setValue('darkOptimized', CONFIG.ui.darkOptimized);
            location.reload();
        });

        GM_registerMenuCommand('🔄 Restablecer Configuración', () => {
            if (confirm('¿Restablecer toda la configuración a valores por defecto?')) {
                ['sidebar', 'comments', 'shorts', 'endScreen', 'cards', 'reducePrefetch', 'tabManagement', 'memoryCleanup', 'compactMode', 'minimalTheme', 'darkOptimized'].forEach(key => {
                    GM_setValue(key, undefined);
                });
                location.reload();
            }
        });
    }

    // ===============================
    // === CSS ULTRA-RÁPIDO (ANTES DEL RENDERIZADO) ===
    // ===============================
    function injectImmediateCSS() {
        const style = document.createElement('style');
        let cssContent = '';

        // Sidebar
        if (CONFIG.removeElements.sidebar) {
            cssContent += `
                #secondary,
                ytd-watch-next-secondary-results-renderer,
                ytd-compact-video-renderer,
                #related,
                .ytd-watch-next-secondary-results-renderer {
                    display: none !important;
                }
            `;
        }

        // Comentarios
        if (CONFIG.removeElements.comments) {
            cssContent += `
                #comments,
                ytd-comments#comments,
                ytd-comment-thread-renderer,
                #comment-teaser {
                    display: none !important;
                }
            `;
        }

        // Shorts
        if (CONFIG.removeElements.shorts) {
            cssContent += `
                ytd-reel-shelf-renderer,
                ytd-rich-section-renderer[is-shorts],
                ytd-shorts,
                [is-shorts] {
                    display: none !important;
                }
            `;
        }

        // Pantalla final
        if (CONFIG.removeElements.endScreen) {
            cssContent += `
                .ytp-ce-element,
                .ytp-endscreen-element {
                    display: none !important;
                }
            `;
        }

        // Tarjetas
        if (CONFIG.removeElements.cards) {
            cssContent += `
                .ytp-cards-teaser,
                .ytp-card-add-to-playlist,
                .ytp-card,
                .ytp-cards-button {
                    display: none !important;
                }
            `;
        }

        style.textContent = cssContent;

        // Inyectar CSS tan pronto como sea posible
        if (document.head) {
            document.head.appendChild(style);
        } else {
            const headObserver = new MutationObserver(() => {
                if (document.head) {
                    document.head.appendChild(style);
                    headObserver.disconnect();
                }
            });
            headObserver.observe(document.documentElement, { childList: true });
        }
    }

    // ===============================
    // === INTERCEPTAR RESPUESTAS DE RED ===
    // ===============================
    function interceptNetworkResponses() {
        const originalFetch = window.fetch;
        window.fetch = function(...args) {
            return originalFetch.apply(this, args).then(response => {
                const url = typeof args[0] === 'string' ? args[0] : args[0].url;

                // Interceptar respuestas de YouTube que contengan datos
                if (url.includes('next') || url.includes('watch') || url.includes('browse')) {
                    return response.clone().text().then(data => {
                        try {
                            if (response.headers.get('content-type')?.includes('application/json')) {
                                let jsonData = JSON.parse(data);

                                // Remover datos de sidebar si está configurado
                                if (CONFIG.removeElements.sidebar && jsonData.contents?.twoColumnWatchNextResults?.secondaryResults) {
                                    delete jsonData.contents.twoColumnWatchNextResults.secondaryResults;
                                }

                                // Remover comentarios si está configurado
                                if (CONFIG.removeElements.comments && jsonData.contents?.twoColumnWatchNextResults?.results?.results?.contents) {
                                    jsonData.contents.twoColumnWatchNextResults.results.results.contents =
                                        jsonData.contents.twoColumnWatchNextResults.results.results.contents.filter(item =>
                                            !item.itemSectionRenderer?.targetId?.includes('comments')
                                        );
                                }

                                return new Response(JSON.stringify(jsonData), {
                                    status: response.status,
                                    statusText: response.statusText,
                                    headers: response.headers
                                });
                            }
                        } catch (e) {
                            // Si no es JSON válido, devolver respuesta original
                        }
                        return response;
                    });
                }
                return response;
            });
        };
    }

    // ===== OPTIMIZACIONES DE RENDIMIENTO =====

    // Reducir precarga de videos
    function optimizeVideoPrefetch() {
        if (!CONFIG.performance.reducePrefetch) return;

        const style = document.createElement('style');
        style.textContent = `
            ytd-thumbnail img {
                loading: lazy !important;
            }
            video {
                preload: none !important;
            }
            ytd-thumbnail:hover img {
                transition: none !important;
            }
        `;
        document.head.appendChild(style);
    }

    // Gestión de pestañas
    function setupTabManagement() {
        if (!CONFIG.performance.tabManagement) return;

        let isVisible = !document.hidden;

        function handleVisibilityChange() {
            const videos = document.querySelectorAll('video');

            if (document.hidden && isVisible) {
                videos.forEach(video => {
                    if (!video.paused) {
                        video.pause();
                        video.dataset.wasPaused = 'false';
                    }
                });
                isVisible = false;
            } else if (!document.hidden && !isVisible) {
                isVisible = true;
            }
        }

        document.addEventListener('visibilitychange', handleVisibilityChange);
    }

    // Limpieza de memoria
    function setupMemoryCleanup() {
        if (!CONFIG.performance.memoryCleanup) return;

        setInterval(() => {
            const elementsToClean = [
                'ytd-thumbnail',
                '.ytd-comment-thread-renderer',
                'ytd-video-renderer'
            ];

            elementsToClean.forEach(selector => {
                document.querySelectorAll(selector).forEach(el => {
                    if (el.hasAttribute('hidden') && el.offsetParent === null) {
                        el.remove();
                    }
                });
            });

            if (window.gc) {
                window.gc();
            }
        }, 30000);
    }

    // ===== MODO COMPACTO =====
    function applyCompactMode() {
        if (!CONFIG.ui.compactMode) return;

        const compactStyles = `
            ytd-video-renderer {
                margin-bottom: 8px !important;
                padding: 8px !important;
            }
            ytd-rich-grid-renderer {
                margin: 0 !important;
            }
            ytd-rich-grid-row {
                margin: 0 8px 16px 8px !important;
            }
            #secondary {
                width: 300px !important;
            }
            ytd-page-manager {
                margin-top: 56px !important;
            }
            #container.ytd-searchbox {
                padding: 0 8px !important;
            }
            ytd-video-renderer #thumbnail {
                width: 180px !important;
                height: 101px !important;
            }
        `;

        const style = document.createElement('style');
        style.textContent = compactStyles;
        document.head.appendChild(style);
    }

    // ===== TEMA PERSONALIZADO =====
    function applyCustomTheme() {
        if (!CONFIG.ui.minimalTheme) return;

        const themeStyles = `
            html[dark] {
                --yt-spec-brand-background-solid: #0f0f0f !important;
                --yt-spec-general-background-a: #0f0f0f !important;
                --yt-spec-general-background-b: #141414 !important;
                --yt-spec-general-background-c: #212121 !important;
                --yt-spec-text-primary: #e8e8e8 !important;
                --yt-spec-text-secondary: #aaaaaa !important;
            }
            ytd-thumbnail-overlay-resume-playback-renderer,
            ytd-thumbnail-overlay-time-status-renderer {
                opacity: 0.7 !important;
            }
            ytd-video-renderer,
            ytd-rich-item-renderer {
                border-radius: 8px !important;
                transition: none !important;
            }
            ytd-video-renderer:hover,
            ytd-rich-item-renderer:hover {
                transform: none !important;
                box-shadow: none !important;
            }
            ::-webkit-scrollbar {
                width: 6px !important;
            }
            ::-webkit-scrollbar-track {
                background: transparent !important;
            }
            ::-webkit-scrollbar-thumb {
                background: #666 !important;
                border-radius: 3px !important;
            }
            ytd-masthead[dark] {
                border-bottom: none !important;
            }
            .ytp-gradient-bottom {
                background: linear-gradient(transparent, rgba(0,0,0,0.2)) !important;
            }
        `;

        const style = document.createElement('style');
        style.textContent = themeStyles;
        document.head.appendChild(style);
    }

    // ===== LIMPIEZA ADICIONAL (FALLBACK) ===
    function setupFallbackCleanup() {
        function limpiezaCompleta() {
            // Limpieza de elementos que se escaparon del CSS
            if (CONFIG.removeElements.sidebar) {
                const sidebar = document.querySelector('#secondary, ytd-watch-next-secondary-results-renderer');
                if (sidebar) sidebar.remove();
            }

            if (CONFIG.removeElements.comments) {
                const comments = document.querySelector('#comments, ytd-comments#comments');
                if (comments) comments.remove();
            }

            if (CONFIG.removeElements.shorts) {
                document.querySelectorAll('ytd-reel-shelf-renderer, ytd-rich-section-renderer[is-shorts]').forEach(el => el.remove());
            }

            if (CONFIG.removeElements.endScreen) {
                document.querySelectorAll('.ytp-ce-element, .ytp-endscreen-element').forEach(el => el.remove());
            }

            if (CONFIG.removeElements.cards) {
                document.querySelectorAll('.ytp-cards-teaser, .ytp-card').forEach(el => el.remove());
            }
        }

        // Ejecutar limpieza inicial
        limpiezaCompleta();

        // Observer con throttle
        const cleanupObserver = new MutationObserver(() => {
            clearTimeout(cleanupObserver.timeout);
            cleanupObserver.timeout = setTimeout(limpiezaCompleta, 1000);
        });
        cleanupObserver.observe(document.body, { childList: true, subtree: false });
    }

    // ===== INICIALIZACIÓN =====
    function init() {
        console.log('🚀 YouTube Optimizador UI v2.0 activado');

        // Crear menú de comandos
        createMenuCommands();

        // Aplicar CSS inmediato
        injectImmediateCSS();

        // Interceptar respuestas de red
        interceptNetworkResponses();

        // Aplicar optimizaciones inmediatamente
        optimizeVideoPrefetch();
        applyCompactMode();
        applyCustomTheme();

        // Esperar a que el DOM esté listo para el resto
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', () => {
                setupTabManagement();
                setupMemoryCleanup();
                setupFallbackCleanup();
            });
        } else {
            setupTabManagement();
            setupMemoryCleanup();
            setupFallbackCleanup();
        }

        // Re-aplicar optimizaciones en navegación SPA
        let lastUrl = location.href;
        const observer = new MutationObserver(() => {
            if (location.href !== lastUrl) {
                lastUrl = location.href;
                setTimeout(() => {
                    setupFallbackCleanup();
                }, 1000);
            }
        });

        observer.observe(document.body, {
            childList: true,
            subtree: false
        });
    }

    // Iniciar el script
    init();

})();