bucket + card sharer
This commit is contained in:
@@ -3,62 +3,65 @@ import { defineStore } from 'pinia'
|
||||
import type { Track, Box } from '~/../types/types'
|
||||
import { useDataStore } from '~/store/data'
|
||||
import { useCardStore } from '~/store/card'
|
||||
import { usePlatineStore } from '~/store/platine'
|
||||
|
||||
export const usePlayerStore = defineStore('player', {
|
||||
state: () => ({
|
||||
currentTrack: null as Track | null,
|
||||
position: 0,
|
||||
audio: null as HTMLAudioElement | null,
|
||||
progressionLast: 0,
|
||||
isPlaying: false,
|
||||
isLoading: false,
|
||||
history: [] as string[]
|
||||
}),
|
||||
|
||||
actions: {
|
||||
attachAudio(el: HTMLAudioElement) {
|
||||
this.audio = el
|
||||
// attach listeners if not already attached (idempotent enough for our use)
|
||||
this.audio.addEventListener('play', () => {
|
||||
this.isPlaying = true
|
||||
// Révéler la carte quand la lecture commence
|
||||
if (this.currentTrack) {
|
||||
const cardStore = useCardStore()
|
||||
if (!cardStore.isCardRevealed(this.currentTrack.id)) {
|
||||
requestAnimationFrame(() => {
|
||||
cardStore.revealCard(this.currentTrack!.id)
|
||||
})
|
||||
attachAudio() {
|
||||
const platineStore = usePlatineStore()
|
||||
|
||||
// Écouter les changements de piste dans le platineStore
|
||||
watch(
|
||||
() => platineStore.currentTrack,
|
||||
(newTrack) => {
|
||||
if (newTrack) {
|
||||
this.currentTrack = newTrack
|
||||
// Révéler la carte quand la lecture commence
|
||||
const cardStore = useCardStore()
|
||||
if (!cardStore.isCardRevealed(newTrack.id)) {
|
||||
requestAnimationFrame(() => {
|
||||
cardStore.revealCard(newTrack.id)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
this.currentTrack = null
|
||||
}
|
||||
}
|
||||
})
|
||||
this.audio.addEventListener('playing', () => {})
|
||||
this.audio.addEventListener('pause', () => {
|
||||
this.isPlaying = false
|
||||
})
|
||||
this.audio.addEventListener('ended', async () => {
|
||||
const track = this.currentTrack
|
||||
if (!track) return
|
||||
)
|
||||
|
||||
const dataStore = useDataStore()
|
||||
// Comportement par défaut pour les playlists standards
|
||||
if (track.type === 'playlist') {
|
||||
const next = dataStore.getNextPlaylistTrack(track)
|
||||
if (next && next.boxId === track.boxId) {
|
||||
await this.playTrack(next)
|
||||
return
|
||||
// Écouter les changements d'état de lecture
|
||||
watch(
|
||||
() => platineStore.isPlaying,
|
||||
(isPlaying) => {
|
||||
if (isPlaying) {
|
||||
// Gérer la logique de lecture suivante quand la lecture se termine
|
||||
if (platineStore.currentTrack?.type === 'playlist') {
|
||||
const dataStore = useDataStore()
|
||||
const nextTrack = dataStore.getNextPlaylistTrack(platineStore.currentTrack)
|
||||
if (nextTrack) {
|
||||
platineStore.loadTrack(nextTrack)
|
||||
platineStore.play()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Si on arrive ici, c'est qu'il n'y a pas de piste suivante
|
||||
this.currentTrack = null
|
||||
this.isPlaying = false
|
||||
})
|
||||
)
|
||||
},
|
||||
|
||||
async playBox(box: Box) {
|
||||
const platineStore = usePlatineStore()
|
||||
|
||||
// Si c'est la même box, on toggle simplement la lecture
|
||||
if (this.currentTrack?.boxId === box.id && this.currentTrack?.side === box.activeSide) {
|
||||
this.togglePlay()
|
||||
platineStore.togglePlay()
|
||||
return
|
||||
}
|
||||
|
||||
@@ -67,7 +70,9 @@ export const usePlayerStore = defineStore('player', {
|
||||
const dataStore = useDataStore()
|
||||
const firstTrack = dataStore.getFirstTrackOfBox(box)
|
||||
if (firstTrack) {
|
||||
await this.playTrack(firstTrack)
|
||||
this.currentTrack = firstTrack
|
||||
await platineStore.loadTrack(firstTrack)
|
||||
await platineStore.play()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error playing box:', error)
|
||||
@@ -75,121 +80,77 @@ export const usePlayerStore = defineStore('player', {
|
||||
},
|
||||
|
||||
async playTrack(track: Track) {
|
||||
// Pour les autres types de pistes, on utilise la logique existante
|
||||
this.isCompilationTrack(track)
|
||||
? await this.playCompilationTrack(track)
|
||||
: await this.playPlaylistTrack(track)
|
||||
},
|
||||
|
||||
async playCompilationTrack(track: Track) {
|
||||
const platineStore = usePlatineStore()
|
||||
// Si c'est la même piste, on toggle simplement la lecture
|
||||
if (this.currentTrack?.id === track.id) {
|
||||
// Si la lecture est en cours, on met en pause
|
||||
if (this.isPlaying) {
|
||||
this.togglePlay()
|
||||
return
|
||||
}
|
||||
|
||||
// Si c'est une compilation, on vérifie si on est dans la plage de la piste
|
||||
if (track.type === 'compilation' && track.start !== undefined) {
|
||||
const dataStore = useDataStore()
|
||||
const nextTrack = dataStore.getNextTrack(track)
|
||||
|
||||
// Si on a une piste suivante et qu'on est dans la plage de la piste courante
|
||||
if (nextTrack?.start && this.position >= track.start && this.position < nextTrack.start) {
|
||||
this.togglePlay()
|
||||
return
|
||||
}
|
||||
// Si c'est la dernière piste de la compilation
|
||||
else if (!nextTrack && this.position >= track.start) {
|
||||
this.togglePlay()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sinon, on charge et on lit la piste
|
||||
this.currentTrack = track
|
||||
await this.loadAndPlayTrack(track)
|
||||
},
|
||||
|
||||
async playPlaylistTrack(track: Track) {
|
||||
// Toggle simple si c'est la même piste
|
||||
if (this.currentTrack?.id === track.id) {
|
||||
this.togglePlay()
|
||||
platineStore.togglePlay()
|
||||
return
|
||||
}
|
||||
|
||||
// Sinon, on charge et on lit la piste
|
||||
this.currentTrack = track
|
||||
await this.loadAndPlayTrack(track)
|
||||
await platineStore.loadTrack(track)
|
||||
platineStore.play()
|
||||
},
|
||||
|
||||
async playCompilationTrack(track: Track) {
|
||||
const platineStore = usePlatineStore()
|
||||
|
||||
// Si c'est la même piste, on toggle simplement la lecture
|
||||
if (this.currentTrack?.id === track.id) {
|
||||
platineStore.togglePlay()
|
||||
return
|
||||
}
|
||||
|
||||
// Pour les compilations, on charge la piste avec le point de départ
|
||||
this.currentTrack = track
|
||||
await platineStore.loadTrack(track)
|
||||
|
||||
// Si c'est une compilation, on définit la position de départ
|
||||
if (track.type === 'compilation' && track.start !== undefined) {
|
||||
platineStore.seek(track.start)
|
||||
}
|
||||
|
||||
platineStore.play()
|
||||
},
|
||||
|
||||
async playPlaylistTrack(track: Track) {
|
||||
const platineStore = usePlatineStore()
|
||||
|
||||
// Toggle simple si c'est la même piste
|
||||
if (this.currentTrack?.id === track.id) {
|
||||
platineStore.togglePlay()
|
||||
return
|
||||
}
|
||||
|
||||
// Sinon, on charge et on lit la piste
|
||||
this.currentTrack = track
|
||||
await platineStore.loadTrack(track)
|
||||
platineStore.play()
|
||||
},
|
||||
|
||||
async loadTrack(track: Track) {
|
||||
if (!this.audio) return
|
||||
|
||||
return new Promise<void>((resolve) => {
|
||||
this.currentTrack = track
|
||||
const audio = this.audio as HTMLAudioElement
|
||||
|
||||
// Si c'est la même source, on ne fait rien
|
||||
if (audio.src === track.url) {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
|
||||
// Nouvelle source
|
||||
audio.src = track.url
|
||||
|
||||
// Une fois que suffisamment de données sont chargées
|
||||
const onCanPlay = () => {
|
||||
audio.removeEventListener('canplay', onCanPlay)
|
||||
resolve()
|
||||
}
|
||||
audio.addEventListener('canplay', onCanPlay)
|
||||
|
||||
// Timeout de sécurité
|
||||
setTimeout(resolve, 1000)
|
||||
})
|
||||
const platineStore = usePlatineStore()
|
||||
await platineStore.loadTrack(track)
|
||||
},
|
||||
|
||||
async loadAndPlayTrack(track: Track) {
|
||||
if (!this.audio) {
|
||||
const newAudio = new Audio()
|
||||
this.attachAudio(newAudio)
|
||||
}
|
||||
|
||||
const audio = this.audio as HTMLAudioElement
|
||||
const platineStore = usePlatineStore()
|
||||
|
||||
try {
|
||||
this.isLoading = true
|
||||
// Mettre en pause
|
||||
audio.pause()
|
||||
|
||||
// Pour les compilations, on utilise l'URL de la piste avec le point de départ
|
||||
// Charger la piste
|
||||
await platineStore.loadTrack(track)
|
||||
|
||||
// Pour les compilations, on définit la position de départ
|
||||
if (track.type === 'compilation' && track.start !== undefined) {
|
||||
audio.src = track.url
|
||||
audio.currentTime = track.start
|
||||
} else {
|
||||
// Pour les playlists, on charge la piste individuelle
|
||||
audio.currentTime = 0
|
||||
await this.loadTrack(track)
|
||||
platineStore.seek(track.start)
|
||||
}
|
||||
|
||||
// Attendre que les métadonnées soient chargées
|
||||
await new Promise<void>((resolve) => {
|
||||
const onCanPlay = () => {
|
||||
audio.removeEventListener('canplay', onCanPlay)
|
||||
resolve()
|
||||
}
|
||||
audio.addEventListener('canplay', onCanPlay)
|
||||
// Timeout de sécurité
|
||||
setTimeout(resolve, 1000)
|
||||
})
|
||||
|
||||
// Lancer la lecture
|
||||
await audio.play()
|
||||
this.history.push(this.currentTrack?.id)
|
||||
await platineStore.play()
|
||||
this.history.push(track.id.toString()) // S'assurer que l'ID est une chaîne
|
||||
this.isLoading = false
|
||||
} catch (error) {
|
||||
console.error('Error loading/playing track:', error)
|
||||
@@ -197,33 +158,30 @@ export const usePlayerStore = defineStore('player', {
|
||||
}
|
||||
},
|
||||
|
||||
async togglePlay() {
|
||||
if (!this.audio) return
|
||||
try {
|
||||
if (this.audio.paused) {
|
||||
await this.audio.play()
|
||||
} else {
|
||||
this.audio.pause()
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error toggling play state:', error)
|
||||
}
|
||||
togglePlay() {
|
||||
const platineStore = usePlatineStore()
|
||||
platineStore.togglePlay()
|
||||
},
|
||||
|
||||
updateTime() {
|
||||
const audio = this.audio
|
||||
if (!audio) return
|
||||
const platineStore = usePlatineStore()
|
||||
|
||||
// update current position
|
||||
this.position = audio.currentTime
|
||||
// Mettre à jour la position actuelle
|
||||
if (platineStore.currentTrack) {
|
||||
this.position = platineStore.currentTurns / 0.75 // Convertir les tours en secondes
|
||||
|
||||
// compute and cache a stable progression value
|
||||
const duration = audio.duration
|
||||
const progression = (this.position / duration) * 100
|
||||
if (!isNaN(progression)) {
|
||||
this.progressionLast = progression
|
||||
// Calculer et mettre en cache la progression
|
||||
const duration = platineStore.totalTurns / 0.75 // Durée totale en secondes
|
||||
const progression = (this.position / duration) * 100
|
||||
if (!isNaN(progression) && isFinite(progression)) {
|
||||
this.progressionLast = progression
|
||||
}
|
||||
}
|
||||
// update current track when changing time in compilation
|
||||
},
|
||||
|
||||
// update current track when changing time in compilation
|
||||
async updateCurrentTrack() {
|
||||
const platineStore = usePlatineStore()
|
||||
const currentTrack = this.currentTrack
|
||||
if (currentTrack && currentTrack.type === 'compilation') {
|
||||
const dataStore = useDataStore()
|
||||
@@ -234,7 +192,7 @@ export const usePlayerStore = defineStore('player', {
|
||||
.sort((a, b) => (a.start ?? 0) - (b.start ?? 0))
|
||||
|
||||
if (tracks.length > 0) {
|
||||
const now = audio.currentTime
|
||||
const now = platineStore.currentTurns / 0.75
|
||||
// find the last track whose start <= now (fallback to first track)
|
||||
let nextTrack = tracks[0]
|
||||
for (const t of tracks) {
|
||||
@@ -254,7 +212,7 @@ export const usePlayerStore = defineStore('player', {
|
||||
if (nextTrack.id && !cardStore.isCardRevealed(nextTrack.id)) {
|
||||
// Utiliser requestAnimationFrame pour une meilleure synchronisation avec le rendu
|
||||
requestAnimationFrame(() => {
|
||||
cardStore.revealCard(nextTrack.id!)
|
||||
cardStore.revealCard(nextTrack.id)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -290,21 +248,26 @@ export const usePlayerStore = defineStore('player', {
|
||||
}
|
||||
},
|
||||
|
||||
isPaused: (state) => {
|
||||
return state.audio?.paused ?? true
|
||||
isPaused() {
|
||||
const platineStore = usePlatineStore()
|
||||
return !platineStore.isPlaying
|
||||
},
|
||||
|
||||
getCurrentTrack: (state) => state.currentTrack,
|
||||
|
||||
getCurrentBox: (state) => {
|
||||
return state.currentTrack ? state.currentTrack.url : null
|
||||
return state.currentTrack ? state.currentTrack.boxId : null
|
||||
},
|
||||
|
||||
getCurrentProgression(state) {
|
||||
if (!state.audio) return 0
|
||||
const duration = state.audio.duration
|
||||
const progression = (state.position / duration) * 100
|
||||
return isNaN(progression) ? state.progressionLast : progression
|
||||
getCurrentProgression() {
|
||||
const platineStore = usePlatineStore()
|
||||
if (!platineStore.currentTrack) return 0
|
||||
|
||||
// Calculer la progression en fonction des tours actuels et totaux
|
||||
if (platineStore.totalTurns > 0) {
|
||||
return (platineStore.currentTurns / platineStore.totalTurns) * 100
|
||||
}
|
||||
return 0
|
||||
},
|
||||
|
||||
getCurrentCoverUrl(state) {
|
||||
|
||||
Reference in New Issue
Block a user