// ==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();
})();