diff --git a/js/musicPlayer.js b/js/musicPlayer.js index 75752cc..b9c2222 100644 --- a/js/musicPlayer.js +++ b/js/musicPlayer.js @@ -9,7 +9,10 @@ export class MusicPlayer { this.displayedSongs = []; this.indiceActual = -1; this.isPlaying = false; + this.audioPlayer = document.getElementById("audioPlayer"); + this.preloaderAudio = document.createElement('audio'); + this.currentArtist = ""; this.currentAlbumId = null; this.currentSongId = null; @@ -26,6 +29,7 @@ export class MusicPlayer { this.isReady = false; this.isInitializing = false; this.miniplayerManuallyClosed = false; + this.isPreloading = false; } setDB(databaseInstance) { @@ -117,9 +121,19 @@ export class MusicPlayer { } }); this.audioPlayer.addEventListener("ended", () => this.handleAudioEnded()); - this.audioPlayer.addEventListener("timeupdate", () => this.updateProgressBar()); + this.audioPlayer.addEventListener("timeupdate", () => this.handleTimeUpdate()); this.audioPlayer.addEventListener("error", () => this.handleAudioErrorEvent()); - + this.audioPlayer.addEventListener("volumechange", () => { + this.preloaderAudio.volume = this.audioPlayer.volume; + }); + + this.preloaderAudio.addEventListener("error", (e) => { + this.isPreloading = false; + }); + this.preloaderAudio.addEventListener("canplaythrough", () => { + this.isPreloading = true; + }); + const progressBarContainer = document.getElementById('progressBarContainer'); progressBarContainer.addEventListener('click', (event) => this.seek(event)); progressBarContainer.addEventListener('mousemove', (event) => this.updateSeekHover(event)); @@ -138,9 +152,9 @@ export class MusicPlayer { if (this.shuffleMode) { this.shuffleArray(this.cancionesActuales); const newIndex = this.cancionesActuales.findIndex(s => s.id === this.displayedSongs[index].id); - this.playSong(this.cancionesActuales[newIndex], newIndex); + this.playSong(newIndex); } else { - this.playSong(this.cancionesActuales[index], index); + this.playSong(index); } } } @@ -187,7 +201,7 @@ export class MusicPlayer { return document.querySelector("#tokenSelectorContainer .select-selected span").dataset.value; } - handleAudioEnded() { this.playNext(); } + handleAudioEnded() { this.playNext(true); } handleAudioErrorEvent() { this.handleAudioError(_('playbackError')); } togglePlayerVisibility() { @@ -583,10 +597,59 @@ export class MusicPlayer { gsap.from(".album-group", { duration: 0.5, opacity: 0, y: 20, stagger: 0.1, ease: "power3.out" }); } - playSong(cancion, index) { - if (!this.isReady || !this.audioPlayer || !cancion || !cancion.url) return; - - const songItemElement = document.querySelector(`.song-item[data-index='${index}']`); + _getNextSongIndex() { + if (this.cancionesActuales.length === 0) return -1; + if (this.shuffleMode) { + if (this.cancionesActuales.length <= 1) return 0; + let nextIndex; + do { + nextIndex = Math.floor(Math.random() * this.cancionesActuales.length); + } while (nextIndex === this.indiceActual); + return nextIndex; + } + return (this.indiceActual + 1) % this.cancionesActuales.length; + } + + _getPreviousSongIndex() { + if (this.cancionesActuales.length === 0) return -1; + if (this.shuffleMode) { + return this._getNextSongIndex(); + } + return (this.indiceActual - 1 + this.cancionesActuales.length) % this.cancionesActuales.length; + } + + preloadNextSong() { + this.isPreloading = false; + const nextIndex = this._getNextSongIndex(); + if (nextIndex === -1 || nextIndex === this.indiceActual) return; + + const nextSong = this.cancionesActuales[nextIndex]; + if (nextSong && nextSong.url) { + this.preloaderAudio.innerHTML = ''; + const source = document.createElement('source'); + source.src = nextSong.url; + source.type = this.getMimeType(nextSong.extension); + this.preloaderAudio.appendChild(source); + this.preloaderAudio.load(); + } + } + + handleTimeUpdate() { + this.updateProgressBar(); + if (this.audioPlayer.duration && this.audioPlayer.currentTime > this.audioPlayer.duration - 15) { + if (!this.isPreloading && this.preloaderAudio.currentSrc === '') { + this.preloadNextSong(); + } + } + } + + playSong(index, fromNext = false) { + if (!this.isReady || !this.audioPlayer || index < 0 || !this.cancionesActuales[index]) return; + + const cancion = this.cancionesActuales[index]; + this.indiceActual = index; + + const songItemElement = document.querySelector(`.song-item[data-id='${cancion.id}']`); const playIconElement = songItemElement ? songItemElement.querySelector('.play-icon') : null; if (playIconElement) { @@ -599,12 +662,6 @@ export class MusicPlayer { } document.body.classList.add('miniplayer-active'); - this.audioPlayer.innerHTML = ''; - const source = document.createElement('source'); - source.src = cancion.url; - source.type = this.getMimeType(cancion.extension); - this.audioPlayer.appendChild(source); - const tl = gsap.timeline(); tl.to(['#albumCover', '#trackTitle', '#trackArtist'], { opacity: 0, y: -10, duration: 0.2, ease: "power2.in", stagger: 0.05 }) .add(() => { @@ -614,11 +671,22 @@ export class MusicPlayer { }) .to(['#albumCover', '#trackTitle', '#trackArtist'], { opacity: 1, y: 0, duration: 0.4, ease: "power2.out", stagger: 0.07 }); + if (fromNext && this.isPreloading) { + this.audioPlayer.innerHTML = this.preloaderAudio.innerHTML; + this.preloaderAudio.innerHTML = ''; + this.isPreloading = false; + } else { + this.audioPlayer.innerHTML = ''; + const source = document.createElement('source'); + source.src = cancion.url; + source.type = this.getMimeType(cancion.extension); + this.audioPlayer.appendChild(source); + } + this.audioPlayer.load(); this.audioPlayer.play().then(() => { this.isPlaying = true; document.getElementById('playPauseBtn').innerHTML = ''; - this.indiceActual = index; this.currentSongId = cancion.id; this.currentSongArtistId = cancion.artistId; this.markCurrentSong(); @@ -629,6 +697,7 @@ export class MusicPlayer { if (!this.miniplayerManuallyClosed) { document.getElementById('fab-music-player').style.display = 'none'; } + this.preloadNextSong(); }).catch((error) => { this.handleAudioError(_('playbackError')); if (playIconElement) { @@ -658,38 +727,20 @@ export class MusicPlayer { } } - playNext() { + playNext(fromEnded = false) { if (!this.isReady || this.cancionesActuales.length === 0) return; - let nextIndex; - if (this.shuffleMode) { - if (this.cancionesActuales.length <= 1) { - nextIndex = 0; - } else { - do { - nextIndex = Math.floor(Math.random() * this.cancionesActuales.length); - } while (nextIndex === this.indiceActual); - } - } else { - nextIndex = (this.indiceActual + 1) % this.cancionesActuales.length; + const nextIndex = this._getNextSongIndex(); + if (nextIndex !== -1) { + this.playSong(nextIndex, fromEnded); } - if (this.cancionesActuales[nextIndex]) this.playSong(this.cancionesActuales[nextIndex], nextIndex); } playPrevious() { if (!this.isReady || this.cancionesActuales.length === 0) return; - let prevIndex; - if (this.shuffleMode) { - if (this.cancionesActuales.length <= 1) { - prevIndex = 0; - } else { - do { - prevIndex = Math.floor(Math.random() * this.cancionesActuales.length); - } while (prevIndex === this.indiceActual); - } - } else { - prevIndex = (this.indiceActual - 1 + this.cancionesActuales.length) % this.cancionesActuales.length; + const prevIndex = this._getPreviousSongIndex(); + if (prevIndex !== -1) { + this.playSong(prevIndex); } - if (this.cancionesActuales[prevIndex]) this.playSong(this.cancionesActuales[prevIndex], prevIndex); } toggleShuffle() { @@ -697,6 +748,7 @@ export class MusicPlayer { this.shuffleMode = !this.shuffleMode; document.getElementById('shuffleBtn').classList.toggle("active", this.shuffleMode); showNotification(this.shuffleMode ? _('shuffleOn') : _('shuffleOff'), 'info', 1500); + this.preloadNextSong(); } markCurrentSong() {