window.App = window.App || {}; App.favorites = App.favorites || {}; (function() { const { FAVORITES_KEY, FAVORITES_VISIBILITY_KEY } = App.constants; // Favorites storage helpers. App.favorites.getAll = function() { try { const raw = localStorage.getItem(FAVORITES_KEY); const parsed = raw ? JSON.parse(raw) : []; return Array.isArray(parsed) ? parsed : []; } catch (err) { return []; } }; App.favorites.setAll = function(items) { localStorage.setItem(FAVORITES_KEY, JSON.stringify(items)); }; App.favorites.getKey = function(video) { if (!video) return null; return video.key || video.id || video.url || null; }; App.favorites.normalize = function(video) { const key = App.favorites.getKey(video); if (!key) return null; return { key, id: video.id || null, url: video.url || '', title: video.title || '', thumb: video.thumb || '', channel: video.channel || '', duration: video.duration || 0 }; }; App.favorites.getSet = function() { return new Set(App.favorites.getAll().map((item) => item.key)); }; App.favorites.isVisible = function() { return localStorage.getItem(FAVORITES_VISIBILITY_KEY) !== 'false'; }; App.favorites.setVisible = function(isVisible) { localStorage.setItem(FAVORITES_VISIBILITY_KEY, isVisible ? 'true' : 'false'); }; // UI helpers for rendering and syncing heart states. App.favorites.setButtonState = function(button, isFavorite) { button.classList.toggle('is-favorite', isFavorite); button.textContent = isFavorite ? '♥' : '♡'; button.setAttribute('aria-pressed', isFavorite ? 'true' : 'false'); button.setAttribute('aria-label', isFavorite ? 'Remove from favorites' : 'Add to favorites'); }; App.favorites.syncButtons = function() { const favoritesSet = App.favorites.getSet(); document.querySelectorAll('.favorite-btn[data-fav-key]').forEach((button) => { const key = button.dataset.favKey; if (!key) return; App.favorites.setButtonState(button, favoritesSet.has(key)); }); }; App.favorites.toggle = function(video) { const key = App.favorites.getKey(video); if (!key) return; const favorites = App.favorites.getAll(); const existingIndex = favorites.findIndex((item) => item.key === key); if (existingIndex >= 0) { favorites.splice(existingIndex, 1); } else { const entry = App.favorites.normalize(video); if (entry) favorites.unshift(entry); } App.favorites.setAll(favorites); App.favorites.renderBar(); App.favorites.syncButtons(); }; App.favorites.renderBar = function() { const bar = document.getElementById('favorites-bar'); const list = document.getElementById('favorites-list'); const empty = document.getElementById('favorites-empty'); if (!bar || !list) return; const favorites = App.favorites.getAll(); const visible = App.favorites.isVisible(); bar.style.display = visible ? 'block' : 'none'; list.innerHTML = ""; favorites.forEach((item) => { const card = document.createElement('div'); card.className = 'favorite-card'; card.dataset.favKey = item.key; card.innerHTML = ` ${item.title}

${item.title}

${item.channel}

`; card.onclick = () => App.player.open(item.url); const favoriteBtn = card.querySelector('.favorite-btn'); if (favoriteBtn) { favoriteBtn.onclick = (event) => { event.stopPropagation(); App.favorites.toggle(item); }; } list.appendChild(card); }); if (empty) { empty.style.display = favorites.length > 0 ? 'none' : 'block'; } }; })();