您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Optimiza YouTube para un mejor rendimiento y experiencia mejorada.
// ==UserScript== // @name YouTube Optimizador UI (Español) // @namespace AkioBrian // @version 2.2 // @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 CON VALORES POR DEFECTO CONSISTENTES ===== const DEFAULT_CONFIG = { removeElements: { sidebar: true, comments: false, shorts: true, endScreen: true, cards: true }, performance: { reducePrefetch: true, tabManagement: false, memoryCleanup: true }, ui: { minimalTheme: true, } }; let CONFIG = { removeElements: { sidebar: GM_getValue('sidebar', DEFAULT_CONFIG.removeElements.sidebar), comments: GM_getValue('comments', DEFAULT_CONFIG.removeElements.comments), shorts: GM_getValue('shorts', DEFAULT_CONFIG.removeElements.shorts), endScreen: GM_getValue('endScreen', DEFAULT_CONFIG.removeElements.endScreen), cards: GM_getValue('cards', DEFAULT_CONFIG.removeElements.cards) }, performance: { reducePrefetch: GM_getValue('reducePrefetch', DEFAULT_CONFIG.performance.reducePrefetch), tabManagement: GM_getValue('tabManagement', DEFAULT_CONFIG.performance.tabManagement), memoryCleanup: GM_getValue('memoryCleanup', DEFAULT_CONFIG.performance.memoryCleanup) }, ui: { minimalTheme: GM_getValue('minimalTheme', DEFAULT_CONFIG.ui.minimalTheme), } }; // ===== VARIABLES GLOBALES PARA CLEANUP ===== let observers = []; let intervals = []; let originalFetch = null; let isVisible = !document.hidden; // ===== UTILIDADES ===== function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } function addObserver(observer) { observers.push(observer); return observer; } function addInterval(interval) { intervals.push(interval); return interval; } function cleanup() { observers.forEach(observer => observer.disconnect()); intervals.forEach(interval => clearInterval(interval)); observers = []; intervals = []; if (originalFetch && window.fetch !== originalFetch) { window.fetch = originalFetch; } } // ===== MENÚ DE CONFIGURACIÓN ===== function createMenuCommands() { const menuItems = [ ['sidebar', '🔲 Sidebar', 'removeElements'], ['comments', '💬 Comentarios', 'removeElements'], ['shorts', '📱 Shorts', 'removeElements'], ['endScreen', '🎬 Pantalla Final', 'removeElements'], ['cards', '🃏 Tarjetas', 'removeElements'], ['reducePrefetch', '⚡ Reducir Precarga', 'performance'], ['tabManagement', '📑 Gestión Pestañas', 'performance'], ['memoryCleanup', '🧹 Limpieza Memoria', 'performance'], ['minimalTheme', '🌙 Oscuro Optimizado', 'ui'], ]; menuItems.forEach(([key, label, category]) => { const currentValue = CONFIG[category][key]; const statusText = category === 'removeElements' ? (currentValue ? 'OCULTO' : 'VISIBLE') : (currentValue ? 'ON' : 'OFF'); GM_registerMenuCommand(`${label}: ${statusText}`, () => { CONFIG[category][key] = !CONFIG[category][key]; GM_setValue(key, CONFIG[category][key]); location.reload(); }); }); GM_registerMenuCommand('🔄 Restablecer Configuración', () => { if (confirm('¿Restablecer toda la configuración a valores por defecto?')) { Object.keys(DEFAULT_CONFIG).forEach(category => { Object.keys(DEFAULT_CONFIG[category]).forEach(key => { GM_setValue(key, DEFAULT_CONFIG[category][key]); }); }); location.reload(); } }); } // ===== CSS INMEDIATO CON SELECTORES ROBUSTOS ===== function injectImmediateCSS() { const style = document.createElement('style'); let cssContent = ''; if (CONFIG.removeElements.sidebar) { cssContent += ` #secondary:not([hidden]), ytd-watch-next-secondary-results-renderer:not([hidden]), #related:not([hidden]), [class*="secondary-results"]:not([hidden]) { display: none !important; } `; } if (CONFIG.removeElements.comments) { cssContent += ` #comments:not([hidden]), ytd-comments:not([hidden]), [id*="comment"]:not([hidden]), [class*="comment"]:not(.comment-button):not([hidden]) { display: none !important; } `; } if (CONFIG.removeElements.shorts) { cssContent += ` ytd-reel-shelf-renderer:not([hidden]), [is-shorts]:not([hidden]), [class*="shorts"]:not([hidden]), ytd-rich-section-renderer[is-shorts]:not([hidden]) { display: none !important; } `; } if (CONFIG.removeElements.endScreen) { cssContent += ` .ytp-ce-element:not([hidden]), .ytp-endscreen-element:not([hidden]) { display: none !important; } `; } if (CONFIG.removeElements.cards) { cssContent += ` .ytp-cards-teaser:not([hidden]), .ytp-card:not([hidden]), .ytp-cards-button:not([hidden]), [class*="card"]:not(.yt-card):not([hidden]) { display: none !important; } `; } style.textContent = cssContent; style.id = 'youtube-optimizer-css'; const injectCSS = () => { if (document.head) { const existing = document.getElementById('youtube-optimizer-css'); if (existing) existing.remove(); document.head.appendChild(style); } }; if (document.head) { injectCSS(); } else { const headObserver = addObserver(new MutationObserver(() => { if (document.head) { injectCSS(); headObserver.disconnect(); } })); headObserver.observe(document.documentElement, { childList: true }); } } // ===== INTERCEPTACIÓN DE RED MEJORADA ===== function interceptNetworkResponses() { if (originalFetch) return; // Evitar múltiples interceptaciones 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; if (!url || !url.includes('youtube.com')) { return response; } // Solo interceptar URLs relevantes de YouTube const relevantEndpoints = ['next', 'watch', 'browse']; const isRelevant = relevantEndpoints.some(endpoint => url.includes(endpoint)); if (!isRelevant) { return response; } const contentType = response.headers.get('content-type'); if (!contentType || !contentType.includes('application/json')) { return response; } return response.clone().text().then(data => { try { let jsonData = JSON.parse(data); let modified = false; // Validar estructura antes de modificar if (jsonData && typeof jsonData === 'object') { // Remover sidebar if (CONFIG.removeElements.sidebar && jsonData.contents?.twoColumnWatchNextResults?.secondaryResults) { delete jsonData.contents.twoColumnWatchNextResults.secondaryResults; modified = true; } // Remover comentarios if (CONFIG.removeElements.comments && jsonData.contents?.twoColumnWatchNextResults?.results?.results?.contents) { const originalLength = jsonData.contents.twoColumnWatchNextResults.results.results.contents.length; jsonData.contents.twoColumnWatchNextResults.results.results.contents = jsonData.contents.twoColumnWatchNextResults.results.results.contents.filter(item => !item.itemSectionRenderer?.targetId?.includes('comments') ); modified = originalLength !== jsonData.contents.twoColumnWatchNextResults.results.results.contents.length; } } if (modified) { return new Response(JSON.stringify(jsonData), { status: response.status, statusText: response.statusText, headers: response.headers }); } } catch (error) { console.warn('YouTube Optimizer: Error parsing JSON response:', error); } return response; }).catch(() => response); }).catch(error => { console.warn('YouTube Optimizer: Fetch interceptor error:', error); throw error; }); }; } // ===== OPTIMIZACIONES DE RENDIMIENTO ===== function optimizeVideoPrefetch() { if (!CONFIG.performance.reducePrefetch) return; const style = document.createElement('style'); style.textContent = ` ytd-thumbnail img { loading: lazy !important; } video:not(.video-stream) { preload: none !important; } ytd-thumbnail:hover img { transition: none !important; } [class*="thumbnail"] img { loading: lazy !important; } `; style.id = 'youtube-optimizer-prefetch'; document.head?.appendChild(style); } // ===== GESTIÓN DE PESTAÑAS MEJORADA ===== function setupTabManagement() { if (!CONFIG.performance.tabManagement) return; function handleVisibilityChange() { const videos = document.querySelectorAll('video'); if (document.hidden && isVisible) { videos.forEach(video => { if (!video.paused) { video.pause(); video.dataset.wasPausedByOptimizer = 'true'; } }); isVisible = false; } else if (!document.hidden && !isVisible) { isVisible = true; // No resumir automáticamente - usuario debe decidir } } document.addEventListener('visibilitychange', handleVisibilityChange); } // ===== LIMPIEZA DE MEMORIA CON INTERSECTION OBSERVER ===== function setupMemoryCleanup() { if (!CONFIG.performance.memoryCleanup) return; // Intersection Observer para elementos fuera del viewport const intersectionObserver = addObserver(new IntersectionObserver((entries) => { entries.forEach(entry => { if (!entry.isIntersecting) { const element = entry.target; // Limpiar solo elementos no visibles hace más de 30 segundos if (!element.dataset.lastVisible) { element.dataset.lastVisible = Date.now(); } else if (Date.now() - element.dataset.lastVisible > 30000) { element.remove(); intersectionObserver.unobserve(element); } } else { entry.target.dataset.lastVisible = Date.now(); } }); }, { threshold: 0 })); // Observer para nuevos elementos const elementObserver = addObserver(new MutationObserver(debounce((mutations) => { mutations.forEach(mutation => { mutation.addedNodes.forEach(node => { if (node.nodeType === 1) { // Element node const cleanableElements = node.querySelectorAll?.('ytd-thumbnail, ytd-video-renderer, ytd-comment-thread-renderer') || []; cleanableElements.forEach(el => intersectionObserver.observe(el)); } }); }); }, 1000))); elementObserver.observe(document.body, { childList: true, subtree: true }); // Limpieza periódica más eficiente const cleanupInterval = addInterval(setInterval(() => { // Forzar garbage collection si está disponible if (typeof window.gc === 'function') { window.gc(); } // Limpiar elementos marcados para eliminación document.querySelectorAll('[data-last-visible]').forEach(el => { if (Date.now() - parseInt(el.dataset.lastVisible) > 60000 && el.offsetParent === null) { el.remove(); } }); }, 60000)); } // ===== TEMA OSCURO OPTIMIZADO ===== function applyCustomTheme() { if (!CONFIG.ui.minimalTheme) return; const themeStyles = ` html[dark] { --yt-spec-brand-background-solid: #000000 !important; --yt-spec-general-background-a: #000000 !important; --yt-spec-general-background-b: #101010 !important; --yt-spec-general-background-c: #151515 !important; --yt-spec-text-primary: #d9d9d9 !important; --yt-spec-text-secondary: #bbbbbb !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; style.id = 'youtube-optimizer-theme'; document.head?.appendChild(style); } // ===== LIMPIEZA FALLBACK MEJORADA ===== function setupFallbackCleanup() { const cleanupActions = { sidebar: () => CONFIG.removeElements.sidebar && document.querySelectorAll('#secondary, ytd-watch-next-secondary-results-renderer').forEach(el => el?.remove()), comments: () => CONFIG.removeElements.comments && document.querySelectorAll('#comments, ytd-comments#comments').forEach(el => el?.remove()), shorts: () => CONFIG.removeElements.shorts && document.querySelectorAll('ytd-reel-shelf-renderer, ytd-rich-section-renderer[is-shorts]').forEach(el => el?.remove()), endScreen: () => CONFIG.removeElements.endScreen && document.querySelectorAll('.ytp-ce-element, .ytp-endscreen-element').forEach(el => el?.remove()), cards: () => CONFIG.removeElements.cards && document.querySelectorAll('.ytp-cards-teaser, .ytp-card').forEach(el => el?.remove()) }; const executeCleanup = debounce(() => { try { Object.values(cleanupActions).forEach(action => action()); } catch (error) { console.warn('YouTube Optimizer: Cleanup error:', error); } }, 500); // Ejecutar limpieza inicial executeCleanup(); // Observer con debounce para cambios en el DOM const cleanupObserver = addObserver(new MutationObserver(executeCleanup)); cleanupObserver.observe(document.body, { childList: true, subtree: false, attributes: false }); } // ===== INICIALIZACIÓN ===== function init() { console.log('🚀 YouTube Optimizador UI v2.2 activado'); // Limpiar estado previo en navegación SPA cleanup(); createMenuCommands(); injectImmediateCSS(); interceptNetworkResponses(); optimizeVideoPrefetch(); applyCustomTheme(); const initializeWhenReady = () => { setupTabManagement(); setupMemoryCleanup(); setupFallbackCleanup(); }; if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initializeWhenReady, { once: true }); } else { initializeWhenReady(); } // Manejo de navegación SPA mejorado let lastUrl = location.href; const navigationObserver = addObserver(new MutationObserver(debounce(() => { if (location.href !== lastUrl) { lastUrl = location.href; // Re-aplicar solo lo necesario después de navegación setTimeout(() => { injectImmediateCSS(); setupFallbackCleanup(); }, 500); } }, 100))); navigationObserver.observe(document.body, { childList: true, subtree: false }); // Cleanup al salir de la página window.addEventListener('beforeunload', cleanup, { once: true }); } // Iniciar el script init(); })();