114 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			3.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| // ~/store/player.ts
 | |
| import { defineStore } from 'pinia'
 | |
| import type { Track } from '~/../types/types'
 | |
| import { useDataStore } from '~/store/data'
 | |
| 
 | |
| export const usePlayerStore = defineStore('player', {
 | |
|   state: () => ({
 | |
|     currentTrack: null as Track | null,
 | |
|     position: 0,
 | |
|     audio: null as HTMLAudioElement | null,
 | |
|   }),
 | |
| 
 | |
|   actions: {
 | |
|     async playTrack(track: Track) {
 | |
|       this.currentTrack = track
 | |
| 
 | |
|       // toggle si on reclique sur la même
 | |
|       if (this.isPlayingTrack(track)) {
 | |
|         this.togglePlay()
 | |
|         return
 | |
|       }
 | |
|       if (!this.audio) {
 | |
|         this.audio = new Audio()
 | |
|       }
 | |
| 
 | |
|       // définir la source (fichier de la compilation entière)
 | |
|       this.audio.src = this.getCompilationUrlFromTrack(track)
 | |
|       this.audio.load()
 | |
| 
 | |
|       // attendre que le player soit prêt avant de lire
 | |
|       await new Promise<void>((resolve, reject) => {
 | |
|         const onCanPlay = () => {
 | |
|           this.audio!.removeEventListener("canplay", onCanPlay)
 | |
|           resolve()
 | |
|         }
 | |
|         const onError = (e: Event) => {
 | |
|           this.audio!.removeEventListener("error", onError)
 | |
|           reject(e)
 | |
|         }
 | |
|         this.audio!.addEventListener("canplay", onCanPlay, { once: true })
 | |
|         this.audio!.addEventListener("error", onError, { once: true })
 | |
|       })
 | |
| 
 | |
|       // positionner le début
 | |
|       this.audio.currentTime = track.start ?? 0
 | |
| 
 | |
|       // lancer la lecture
 | |
|       try {
 | |
|         await this.audio.play()
 | |
|       } catch (err) {
 | |
|         console.error("Impossible de lire la piste :", err)
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     togglePlay() {
 | |
|       if (!this.audio) return
 | |
|       if (this.audio.paused) {
 | |
|         this.audio.play().catch(err => console.error(err))
 | |
|       } else {
 | |
|         this.audio.pause()
 | |
|       }
 | |
|     },
 | |
|   },
 | |
| 
 | |
|   getters: {
 | |
|     isCurrentCompilation: (state) => {
 | |
|       return (compilationId: string) =>
 | |
|         compilationId === state.currentTrack?.compilationId
 | |
|     },
 | |
| 
 | |
|     isPlayingTrack: (state) => {
 | |
|       return (track: Track) => {
 | |
|         if (!state.audio || !state.currentTrack) return false
 | |
| 
 | |
|         const currentTime = state.audio.currentTime
 | |
|         if (!currentTime || isNaN(currentTime)) return false
 | |
| 
 | |
|         const from = track.start ?? 0
 | |
|         const to = state.getTrackStop(track)
 | |
|         if (!to || isNaN(to)) return false
 | |
| 
 | |
|         return currentTime >= from && currentTime < to
 | |
|       }
 | |
|     },
 | |
| 
 | |
|     getCurrentTrack: (state) => state.currentTrack,
 | |
| 
 | |
|     getCompilationUrlFromTrack: () => {
 | |
|       return (track: Track) =>
 | |
|         `https://files.erudi.fr/evilspins/${track.compilationId}.mp3`
 | |
|     },
 | |
| 
 | |
|     getCurrentCompilation: (state) => {
 | |
|       return state.currentTrack
 | |
|         ? state.getCompilationUrlFromTrack(state.currentTrack)
 | |
|         : null
 | |
|     },
 | |
| 
 | |
|     getTrackStop: (state) => {
 | |
|       return (track: Track) => {
 | |
|         if (!state.audio) return 0
 | |
| 
 | |
|         if (track.order === 0) {
 | |
|           return Math.round(state.audio.duration)
 | |
|         } else {
 | |
|           const dataStore = useDataStore()
 | |
|           const nextTrack = dataStore.getNextTrack(track)
 | |
|           return nextTrack ? nextTrack.start : Math.round(state.audio.duration)
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   },
 | |
| })
 |