diff --git a/js/constants.js b/js/constants.js new file mode 100644 index 0000000..3d1aeaa --- /dev/null +++ b/js/constants.js @@ -0,0 +1,20 @@ +export const API_URLS = { + TMDB_BASE: 'https://api.themoviedb.org/3', + TMDB_IMAGE_BASE: 'https://image.tmdb.org/t/p', + PLEX_TV: 'https://plex.tv/api/resources', + YOUTUBE_EMBED: 'https://www.youtube.com/embed/', + IMDB_TITLE: 'https://www.imdb.com/title/' +}; + +export const CONFIG = { + DEFAULT_API_KEY: '4e44d9029b1270a757cddc766a1bcb63', + DB_NAME: 'PlexDB', + DB_VERSION: 6 +}; + +export const STORAGE_KEYS = { + USER_HISTORY: 'cineplex_userHistory', + USER_PREFERENCES: 'cineplex_userPreferences', + FAVORITES: 'cineplex_favorites', + RECOMMENDATIONS_CACHE: 'cineplex_recommendations' +}; \ No newline at end of file diff --git a/js/eventListeners.js b/js/eventListeners.js index 842b37d..191d454 100644 --- a/js/eventListeners.js +++ b/js/eventListeners.js @@ -1,5 +1,5 @@ import { state } from './state.js'; -import { switchView, resetView, showMainView, showItemDetails, applyFilters, searchByActor, loadContent, toggleFavorite, addStreamToList, downloadM3U, showTrailer, closeTrailer, openSettingsModal, saveSettings, updateSectionTitle, generateStatistics, loadFavorites, loadLocalContent, phpScriptGenerator, initPhotosView, handlePhotoGridClick, handlePhotoTokenChange, showNextPhoto, showPrevPhoto, closePhotoLightbox, activateSettingsTab, deleteHistoryItem, clearAllHistory, getTrailerKey } from './ui.js'; +import { switchView, resetView, showMainView, showItemDetails, applyFilters, searchByActor, loadContent, toggleFavorite, addStreamToList, downloadM3U, showTrailer, closeTrailer, openSettingsModal, saveSettings, updateSectionTitle, generateStatistics, loadFavorites, loadLocalContent, phpScriptGenerator, initPhotosView, handlePhotoGridClick, handlePhotoTokenChange, showNextPhoto, showPrevPhoto, closePhotoLightbox, activateSettingsTab, deleteHistoryItem, clearAllHistory, getTrailerKey, initializeHeroSection } from './ui.js'; import { debounce, showNotification, _ } from './utils.js'; import { clearContentData, loadTokensToEditor, saveTokensFromEditor, exportDatabase, importDatabase } from './db.js'; import { startPlexScan } from './plex.js'; @@ -159,9 +159,26 @@ export function setupEventListeners() { } }); + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') { + // Check if hero section is active but background is gone + const heroSection = document.getElementById('hero-section'); + const bg1 = document.querySelector('.hero-background-1'); + if (heroSection && heroSection.style.display !== 'none' && state.currentView === 'home' && state.heroIntervalId) { + const isBgVisible = (bg1.style.backgroundImage && bg1.style.backgroundImage !== 'none') || + (document.querySelector('.hero-background-2').style.backgroundImage && document.querySelector('.hero-background-2').style.backgroundImage !== 'none'); + + if (!isBgVisible || bg1.style.opacity === '0' && document.querySelector('.hero-background-2').style.opacity === '0') { + console.log('Hero background missing on visibility change, re-initializing.'); + initializeHeroSection(); + } + } + } + }); + window.addEventListener('indexedDBUpdated', handleDatabaseUpdate); - const eqBtn = document.getElementById('eqBtn'); + const eqBtn = document.getElementById('eqBtn');"" const closeEqBtn = document.getElementById('closeEqBtn'); const equalizerPanel = document.getElementById('equalizer-panel'); diff --git a/js/musicPlayer.js b/js/musicPlayer.js index 568a228..20698d1 100644 --- a/js/musicPlayer.js +++ b/js/musicPlayer.js @@ -573,7 +573,7 @@ export class MusicPlayer { this.currentSongId = cancion.id; this.currentSongArtistId = cancion.artistId; this.markCurrentSong(); - this.markCurrentArtist(cancion.artistId); + this.ensureArtistVisible(cancion.artistId); if (playIconElement) { playIconElement.className = 'fas fa-play play-icon'; } @@ -663,14 +663,16 @@ export class MusicPlayer { } } - markCurrentArtist(artistIdToMark = null) { + markCurrentArtist() { if (!this.isReady) return; - const targetArtistId = artistIdToMark !== null ? artistIdToMark : this.currentArtistId; - document.querySelectorAll(".artist-card").forEach(card => card.classList.remove("current-artist")); - if (targetArtistId !== null) { - const artistCard = document.querySelector(`.artist-card[data-id='${targetArtistId}']`); - if (artistCard) artistCard.classList.add("current-artist"); - } + const targetArtistId = this.currentSongArtistId; + document.querySelectorAll(".artist-card").forEach(card => { + if (targetArtistId != null && card.dataset.id == targetArtistId) { + card.classList.add("current-artist"); + } else { + card.classList.remove("current-artist"); + } + }); } updateProgressBar() { @@ -845,4 +847,25 @@ export class MusicPlayer { const infoModal = bootstrap.Modal.getOrCreateInstance(document.getElementById('infoModal')); infoModal.show(); } + + ensureArtistVisible(artistId) { + if (!this.isReady || artistId === null) return; + const artistCard = document.querySelector(`.artist-card[data-id='${artistId}']`); + if (artistCard) { + this.markCurrentArtist(artistId); + return; + } + + const fullList = this._generateFullArtistListForToken(this._getCurrentTokenFilter()); + const artistIndex = fullList.findIndex(a => a.id == artistId); + + if (artistIndex !== -1) { + const targetPage = Math.floor(artistIndex / this.artistsPageSize); + if (this.currentPage !== targetPage) { + this.currentPage = targetPage; + this.loadArtists(fullList, this.currentPage); + } + } + this.markCurrentArtist(artistId); + } } \ No newline at end of file diff --git a/js/ui.js b/js/ui.js index feae219..300fd8e 100644 --- a/js/ui.js +++ b/js/ui.js @@ -56,6 +56,9 @@ export function resetView() { const heroSection = document.getElementById('hero-section'); const mainContent = document.getElementById('main-content'); const contentSection = document.getElementById('content-section'); + const heroContent = document.querySelector('.hero-content'); + const heroBg1 = document.querySelector('.hero-background-1'); + const heroBg2 = document.querySelector('.hero-background-2'); // Hide all main content sections if (mainContent) { @@ -73,8 +76,28 @@ export function resetView() { if (heroSection) { if (state.settings.showHero) { heroSection.style.display = 'flex'; - heroSection.classList.add('loading'); // Add loading class to hero + + // Clear dynamic hero content and reset to default + if (state.heroIntervalId) { + clearInterval(state.heroIntervalId); + state.heroIntervalId = null; + } + + if (heroContent) { + heroContent.querySelector('.hero-title').textContent = _('welcomeToCinePlex'); + heroContent.querySelector('.hero-subtitle').textContent = _('welcomeSubtitle'); + heroContent.querySelector('#hero-rating').innerHTML = ''; + heroContent.querySelector('#hero-year').innerHTML = ''; + heroContent.querySelector('#hero-extra').innerHTML = ''; + heroContent.querySelector('.hero-buttons').style.display = 'none'; + } + + gsap.set(heroBg1, { backgroundImage: 'url(img/hero-def.png)', autoAlpha: 1, scale: 1 }); + gsap.set(heroBg2, { autoAlpha: 0 }); + heroSection.classList.add('no-overlay'); + initializeHeroSection(); + } else { heroSection.style.display = 'none'; } @@ -1198,21 +1221,43 @@ export async function searchByActor(actorId, actorName) { export async function initializeHeroSection() { const heroSection = document.getElementById('hero-section'); - if (heroSection.style.display === 'none') return; + if (heroSection.style.display === 'none' || !state.settings.showHero) return; + + // Clear existing timers for slide changes and initial load + if (state.heroIntervalId) { + clearInterval(state.heroIntervalId); + state.heroIntervalId = null; + } + if (state.heroLoadTimeoutId) { + clearTimeout(state.heroLoadTimeoutId); + state.heroLoadTimeoutId = null; + } const bg1 = document.querySelector('.hero-background-1'); const bg2 = document.querySelector('.hero-background-2'); const content = document.querySelector('.hero-content'); + const heroButtons = content.querySelector('.hero-buttons'); // Set static background and show default content + content.querySelector('.hero-title').textContent = _('heroWelcome'); + content.querySelector('.hero-subtitle').textContent = _('heroSubtitle'); + content.querySelector('#hero-rating').innerHTML = ''; + content.querySelector('#hero-year').innerHTML = ''; + content.querySelector('#hero-extra').innerHTML = ''; + heroButtons.style.display = 'none'; + heroSection.classList.add('no-overlay'); gsap.set(bg1, { backgroundImage: `url(img/hero-def.png)`, autoAlpha: 1, scale: 1 }); gsap.set(bg2, { autoAlpha: 0 }); - gsap.set(content, { autoAlpha: 1 }); // Show welcome message + gsap.set(content, { autoAlpha: 1 }); heroSection.classList.remove('loading'); - // After 5 seconds, load the dynamic content - setTimeout(loadTmdbHeroContent, 5000); + // After 5 seconds, load the dynamic content if we are still on the home view + state.heroLoadTimeoutId = setTimeout(() => { + if (state.currentView === 'home') { + loadTmdbHeroContent(); + } + }, 5000); async function loadTmdbHeroContent() { heroSection.classList.remove('no-overlay'); @@ -1276,13 +1321,15 @@ export async function initializeHeroSection() { } function updateHeroContent(item) { - const heroTitle = document.querySelector('.hero-title'); - const heroSubtitle = document.querySelector('.hero-subtitle'); - const heroRating = document.querySelector('#hero-rating'); - const heroYear = document.querySelector('#hero-year'); - const heroExtra = document.querySelector('#hero-extra'); - const heroPlayBtn = document.getElementById('hero-play-btn'); - const heroInfoBtn = document.getElementById('hero-info-btn'); + const heroContent = document.querySelector('.hero-content'); + const heroTitle = heroContent.querySelector('.hero-title'); + const heroSubtitle = heroContent.querySelector('.hero-subtitle'); + const heroRating = heroContent.querySelector('#hero-rating'); + const heroYear = heroContent.querySelector('#hero-year'); + const heroExtra = heroContent.querySelector('#hero-extra'); + const heroButtons = heroContent.querySelector('.hero-buttons'); + const heroPlayBtn = heroButtons.querySelector('#hero-play-btn'); + const heroInfoBtn = heroButtons.querySelector('#hero-info-btn'); const type = item.title ? 'movie' : 'tv'; const title = item.title || item.name; @@ -1294,6 +1341,8 @@ function updateHeroContent(item) { if (heroYear) heroYear.innerHTML = ` ${(item.release_date || item.first_air_date).slice(0, 4)}`; if (heroExtra) heroExtra.innerHTML = ` ${type === 'movie' ? _('moviesSectionTitle') : _('seriesSectionTitle')}`; + heroButtons.style.display = 'block'; + if (heroPlayBtn) { heroPlayBtn.onclick = () => addStreamToList(title, type, heroPlayBtn); heroPlayBtn.disabled = !isAvailable;