/** * Home Dashboard Page * Features "Continue Watching" and "Recently Added" content */ class HomePage { constructor(app) { this.app = app; this.container = null; // Will be set in renderLayout this.isLoading = false; } async init() { // Initialization if needed } async show() { this.renderLayout(); await this.loadDashboardData(); } hide() { // Cleanup if needed if (this.container) { this.container.innerHTML = ''; } } renderLayout() { const pageHome = document.getElementById('page-home'); if (!pageHome) return; pageHome.innerHTML = `

Continue Watching

Loading history...

Recently Added Movies

Coming soon

Recently Added Series

Coming soon
`; this.container = document.getElementById('home-content'); } async loadDashboardData() { if (this.isLoading) return; this.isLoading = true; try { // 1. Load Watch History const history = await window.API.request('GET', '/history?limit=12'); if (history && Array.isArray(history)) { this.renderHistory(history); } // 2. Load Recent Items this.renderRecentMovies(); this.renderRecentSeries(); } catch (err) { console.error('[Dashboard] Error loading data:', err); } finally { this.isLoading = false; } } renderHistory(items) { const list = document.getElementById('continue-watching-list'); const section = document.getElementById('continue-watching-section'); if (!list || !section) return; if (items.length === 0) { section.classList.add('hidden'); return; } section.classList.remove('hidden'); list.innerHTML = items.map(item => this.createCard(item)).join(''); // Attach click listeners list.querySelectorAll('.dashboard-card').forEach(card => { card.addEventListener('click', () => { const id = card.dataset.id; const item = items.find(i => i.item_id === id); if (item) { const type = item.item_type || item.type; if (type === 'series' && !isResume) { this.navigateToSeries(item); } else { this.playItem(item, true); // true for resume } } }); }); } navigateToSeries(item) { if (!this.app.pages.series) return; // Prepare the series object as expected by SeriesPage.showSeriesDetails const series = { series_id: item.item_id, sourceId: item.source_id, name: item.name || (item.data ? item.data.title : 'Series'), cover: item.stream_icon || (item.data ? item.data.poster : null), plot: item.data ? item.data.description : '', year: item.data ? item.data.year : '' }; // Switch page this.app.navigateTo('series'); // Show details (delay slightly to ensure page is visible) setTimeout(() => { this.app.pages.series.showSeriesDetails(series); }, 100); } async renderRecentMovies() { const list = document.getElementById('recent-movies-list'); if (!list) return; try { const movies = await window.API.request('GET', '/channels/recent?type=movie&limit=12'); if (!movies || movies.length === 0) { list.innerHTML = '
No recent movies found
'; return; } list.innerHTML = movies.map(item => this.createRecentCard(item)).join(''); // Attach listeners list.querySelectorAll('.dashboard-card').forEach(card => { card.addEventListener('click', () => { const id = card.dataset.id; const item = movies.find(m => m.item_id === id); if (item) this.playItem(item); }); }); } catch (err) { console.error('[Dashboard] Error loading recent movies:', err); } } async renderRecentSeries() { const list = document.getElementById('recent-series-list'); if (!list) return; try { const series = await window.API.request('GET', '/channels/recent?type=series&limit=12'); if (!series || series.length === 0) { list.innerHTML = '
No recent series found
'; return; } list.innerHTML = series.map(item => this.createRecentCard(item)).join(''); // Attach listeners list.querySelectorAll('.dashboard-card').forEach(card => { card.addEventListener('click', () => { const id = card.dataset.id; const item = series.find(s => s.item_id === id); if (item) this.navigateToSeries(item); }); }); } catch (err) { console.error('[Dashboard] Error loading recent series:', err); } } createCard(item) { const { data, progress, duration, item_id } = item; const type = item.item_type || item.type; const percent = Math.min(100, Math.round((progress / duration) * 100)); // Proxy the poster if it's an external URL const poster = data.poster || '/img/poster-placeholder.jpg'; const posterUrl = poster.startsWith('http') ? `/api/proxy/image?url=${encodeURIComponent(poster)}` : poster; return `
${data.title || item.name}
${item.name || data.title || 'Unknown Title'}
${data.subtitle || (type === 'movie' ? 'Movie' : 'Series')}
`; } createRecentCard(item) { const { data, item_id } = item; const type = item.type || item.item_type; const poster = item.stream_icon || data.poster || '/img/poster-placeholder.jpg'; const posterUrl = poster.startsWith('http') ? `/api/proxy/image?url=${encodeURIComponent(poster)}` : poster; return `
${item.name}
${item.name || (data && data.title) || 'Unknown Title'}
${(data && data.subtitle) || (type === 'movie' ? 'Movie' : 'Series')}
`; } async playItem(item, isResume = false) { if (!this.app.pages.watch) return; try { const type = item.item_type || item.type; const streamType = type === 'movie' ? 'movie' : 'series'; const sourceId = item.source_id; const streamId = item.item_id; const container = item.container_extension || 'mp4'; const result = await window.API.request('GET', `/proxy/xtream/${sourceId}/stream/${streamId}/${streamType}?container=${container}`); if (result && result.url) { const content = { id: item.item_id, type: type, title: item.name || item.data.title, subtitle: item.data.subtitle || (type === 'movie' ? 'Movie' : 'Series'), poster: item.stream_icon || item.data.poster, sourceId: sourceId, resumeTime: isResume ? item.progress : 0, containerExtension: container }; // Switch to watch page this.app.navigateTo('watch'); this.app.pages.watch.play(content, result.url); } } catch (err) { console.error('[Dashboard] Playback failed:', err); } } } window.HomePage = HomePage;