UNPKG

@zyrecx/tflix

Version:

TFlix transforms Cineby.app into a TV-friendly experience for Samsung TVs running TizenBrew with enhanced remote navigation.

195 lines (165 loc) 5.56 kB
/** * TFlix Performance Optimizer * This module implements performance optimizations for smoother operation on Tizen TVs */ /** * Initialize performance optimizations */ function initializePerformanceOptimizations() { // Apply optimizations once DOM is loaded if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', applyOptimizations); } else { applyOptimizations(); } } /** * Apply various performance optimizations */ function applyOptimizations() { // Optimize images and lazy loading optimizeImages(); // Reduce animation complexity reduceAnimations(); // Optimize scrolling performance optimizeScrolling(); // Debounce event handlers setupEventDebouncing(); // Memory management setupMemoryManagement(); } /** * Optimize images with lazy loading and size optimizations */ function optimizeImages() { // Find all images that don't have loading attribute const images = document.querySelectorAll('img:not([loading])'); images.forEach(img => { // Add lazy loading img.setAttribute('loading', 'lazy'); // Add decoding async for better performance img.setAttribute('decoding', 'async'); // Set explicit width/height if missing to avoid layout shifts if (!img.hasAttribute('width') && !img.hasAttribute('height')) { const computedStyle = window.getComputedStyle(img); const width = computedStyle.width; const height = computedStyle.height; if (width && width !== 'auto' && height && height !== 'auto') { img.setAttribute('width', parseInt(width)); img.setAttribute('height', parseInt(height)); } } }); // Set up intersection observer for better lazy loading if ('IntersectionObserver' in window) { const imageObserver = new IntersectionObserver((entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; if (img.dataset.src) { img.src = img.dataset.src; delete img.dataset.src; } observer.unobserve(img); } }); }); document.querySelectorAll('img[data-src]').forEach(img => { imageObserver.observe(img); }); } } /** * Reduce animation complexity for better performance */ function reduceAnimations() { // Create a style element to inject optimized animation rules const style = document.createElement('style'); style.textContent = ` /* Reduce CSS animation complexity */ * { animation-duration: 0.001s !important; transition-duration: 0.001s !important; } /* Only keep essential animations */ .tflix-focused { animation-duration: 0.2s !important; transition-duration: 0.2s !important; } /* Reduce motion for users who prefer it */ @media (prefers-reduced-motion: reduce) { * { animation: none !important; transition: none !important; } } `; document.head.appendChild(style); } /** * Optimize scrolling performance */ function optimizeScrolling() { // Disable smooth scrolling which can be performance heavy const scrollableElements = document.querySelectorAll('div, main, section'); scrollableElements.forEach(el => { const style = window.getComputedStyle(el); const overflow = style.getPropertyValue('overflow'); const overflowY = style.getPropertyValue('overflow-y'); if (overflow === 'auto' || overflow === 'scroll' || overflowY === 'auto' || overflowY === 'scroll') { // Add will-change for better rendering performance el.style.willChange = 'transform'; // Use translate3d for hardware acceleration el.style.transform = 'translate3d(0,0,0)'; } }); } /** * Set up event debouncing for better performance */ function setupEventDebouncing() { // Debounce scroll and resize events let scrollTimeout; let resizeTimeout; const originalAddEventListener = EventTarget.prototype.addEventListener; EventTarget.prototype.addEventListener = function(type, listener, options) { if (type === 'scroll') { const debouncedListener = function(e) { clearTimeout(scrollTimeout); scrollTimeout = setTimeout(() => { listener.call(this, e); }, 100); }; return originalAddEventListener.call(this, type, debouncedListener, options); } else if (type === 'resize') { const debouncedListener = function(e) { clearTimeout(resizeTimeout); resizeTimeout = setTimeout(() => { listener.call(this, e); }, 100); }; return originalAddEventListener.call(this, type, debouncedListener, options); } return originalAddEventListener.call(this, type, listener, options); }; } /** * Set up memory management to prevent memory leaks */ function setupMemoryManagement() { // Clear unused objects periodically setInterval(() => { // Force garbage collection (though we can't directly call it) // This trick helps in some browsers const arr = []; for (let i = 0; i < 1000; i++) { arr.push(new Array(10000).join('x')); } arr.length = 0; }, 60000); // Every minute } // Export the initialization function export { initializePerformanceOptimizations };