FEAT: side A/B
This commit is contained in:
@@ -1,9 +1,5 @@
|
||||
import type { Box, Artist, Track } from '~/../types/types'
|
||||
import { FAVORITES_BOX_ID, useFavoritesStore } from '~/store/favorites'
|
||||
|
||||
// stores/data.ts
|
||||
import { defineStore } from 'pinia'
|
||||
import { useUiStore } from '~/store/ui'
|
||||
|
||||
export const useDataStore = defineStore('data', {
|
||||
state: () => ({
|
||||
@@ -37,7 +33,7 @@ export const useDataStore = defineStore('data', {
|
||||
artistObj = { id: 0, name: a, url: '', coverId: '' }
|
||||
} else if (a && typeof a === 'object' && 'id' in (a as any)) {
|
||||
const idVal = (a as any).id as number | undefined
|
||||
artistObj = idVal != null ? (artistMap.get(idVal) ?? (a as Artist)) : (a as Artist)
|
||||
artistObj = idVal != null ? artistMap.get(idVal) ?? (a as Artist) : (a as Artist)
|
||||
} else {
|
||||
artistObj = { id: 0, name: '', url: '', coverId: '' }
|
||||
}
|
||||
@@ -47,25 +43,17 @@ export const useDataStore = defineStore('data', {
|
||||
artist: artistObj
|
||||
}
|
||||
})
|
||||
const favBox: Box = {
|
||||
id: FAVORITES_BOX_ID,
|
||||
type: 'playlist',
|
||||
name: 'Favoris',
|
||||
duration: 0,
|
||||
tracks: [],
|
||||
description: '',
|
||||
color1: '#0f172a',
|
||||
color2: '#1e293b',
|
||||
color3: '#334155',
|
||||
state: 'box-list'
|
||||
}
|
||||
if (!this.boxes.find((b) => b.id === FAVORITES_BOX_ID)) {
|
||||
this.boxes = [...this.boxes, favBox]
|
||||
}
|
||||
this.isLoaded = true
|
||||
} finally {
|
||||
this.isLoading = false
|
||||
}
|
||||
},
|
||||
|
||||
setActiveSideByBoxId(boxId: string, side: 'A' | 'B') {
|
||||
const box = this.boxes.find((box) => box.id === boxId.replace(/[AB]$/, ''))
|
||||
if (box) {
|
||||
box.activeSide = side
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -76,15 +64,16 @@ export const useDataStore = defineStore('data', {
|
||||
return state.boxes.find((box) => box.id === id)
|
||||
}
|
||||
},
|
||||
// Obtenir toutes les pistes d'une box donnée
|
||||
getTracksByboxId: (state) => (id: string) => {
|
||||
if (id === FAVORITES_BOX_ID) {
|
||||
const fav = useFavoritesStore()
|
||||
return fav.trackIds
|
||||
.map((tid) => state.tracks.find((t) => t.id === tid))
|
||||
.filter((t): t is Track => !!t)
|
||||
getTracksByboxId: (state) => (id: string, side?: 'A' | 'B') => {
|
||||
const box = state.boxes.find((box) => box.id === id)
|
||||
if (box?.type !== 'compilation' || !side) {
|
||||
return state.tracks.filter((track) => track.boxId === id)
|
||||
}
|
||||
return state.tracks.filter((track) => track.boxId === id)
|
||||
return state.tracks.filter((track) => track.boxId === id && track.side === side)
|
||||
},
|
||||
getActiveSideByBoxId: (state) => (id: string) => {
|
||||
const box = state.boxes.find((box) => box.id === id)
|
||||
return box?.activeSide
|
||||
},
|
||||
// Filtrer les artistes selon certains critères
|
||||
getArtistById: (state) => (id: number) => state.artists.find((artist) => artist.id === id),
|
||||
@@ -101,7 +90,7 @@ export const useDataStore = defineStore('data', {
|
||||
},
|
||||
getFirstTrackOfBox() {
|
||||
return (box: Box) => {
|
||||
const tracks = this.getTracksByboxId(box.id)
|
||||
const tracks = this.getTracksByboxId(box.id, box.activeSide)
|
||||
.slice()
|
||||
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
||||
return tracks.length > 0 ? tracks[0] : null
|
||||
@@ -123,7 +112,7 @@ export const useDataStore = defineStore('data', {
|
||||
return (track: Track) => {
|
||||
// Récupérer toutes les tracks de la même box et les trier par ordre
|
||||
const tracksInBox = state.tracks
|
||||
.filter((t) => t.boxId === track.boxId)
|
||||
.filter((t) => t.boxId === track.boxId && t.side === track.side)
|
||||
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
||||
|
||||
// Trouver l’index de la track courante
|
||||
@@ -135,7 +124,7 @@ export const useDataStore = defineStore('data', {
|
||||
getPrevTrack: (state) => {
|
||||
return (track: Track) => {
|
||||
const tracksInBox = state.tracks
|
||||
.filter((t) => t.boxId === track.boxId)
|
||||
.filter((t) => t.boxId === track.boxId && t.side === track.side)
|
||||
.sort((a, b) => (a.order ?? 0) - (b.order ?? 0))
|
||||
|
||||
const index = tracksInBox.findIndex((t) => t.id === track.id)
|
||||
|
||||
@@ -1,144 +0,0 @@
|
||||
import { defineStore } from 'pinia'
|
||||
import type { Track, Box, BoxType, Artist } from '~/../types/types'
|
||||
|
||||
export const FAVORITES_BOX_ID = 'FAV'
|
||||
const STORAGE_KEY = 'evilspins:favorites:v2' // Version changée pour forcer la mise à jour
|
||||
|
||||
export const useFavoritesStore = defineStore('favorites', {
|
||||
state: () => ({
|
||||
favoritesPlaylist: {
|
||||
id: FAVORITES_BOX_ID,
|
||||
type: 'userPlaylist' as BoxType,
|
||||
name: 'Favoris',
|
||||
description: 'Vos titres favoris',
|
||||
color1: '#FFD700',
|
||||
color2: '#FFA500',
|
||||
color3: '#FF8C00',
|
||||
duration: 0,
|
||||
state: 'box-hidden',
|
||||
tracks: [] as Track[],
|
||||
isPublic: false
|
||||
} as Box,
|
||||
version: 1
|
||||
}),
|
||||
getters: {
|
||||
trackIds: (state) => state.favoritesPlaylist.tracks?.map((t) => t.id) || [],
|
||||
tracks: (state) => state.favoritesPlaylist.tracks || [],
|
||||
isFavorite: (state) => (trackId: number) =>
|
||||
state.favoritesPlaylist.tracks?.some((t) => t.id === trackId) || false
|
||||
},
|
||||
|
||||
actions: {
|
||||
load() {
|
||||
if (!process.client) return
|
||||
try {
|
||||
const raw = localStorage.getItem(STORAGE_KEY)
|
||||
if (raw) {
|
||||
const data = JSON.parse(raw)
|
||||
if (data.version === this.version && data.playlist) {
|
||||
this.favoritesPlaylist = { ...this.favoritesPlaylist, ...data.playlist }
|
||||
} else if (Array.isArray(data)) {
|
||||
// Migration depuis l'ancienne version
|
||||
this.favoritesPlaylist.tracks = data
|
||||
.filter((x) => typeof x === 'number')
|
||||
.map((id) => ({ id }) as unknown as Track) // On ne stocke que l'ID, les infos seront complétées par le dataStore
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading favorites:', error)
|
||||
}
|
||||
},
|
||||
|
||||
save() {
|
||||
if (!process.client) return
|
||||
try {
|
||||
localStorage.setItem(
|
||||
STORAGE_KEY,
|
||||
JSON.stringify({
|
||||
version: this.version,
|
||||
playlist: this.favoritesPlaylist
|
||||
})
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Error saving favorites:', error)
|
||||
}
|
||||
},
|
||||
|
||||
// Crée une copie virtuelle d'une piste pour les favoris
|
||||
createVirtualTrack(originalTrack: Track): Track {
|
||||
// Crée une copie profonde de la piste
|
||||
const virtualTrack = JSON.parse(JSON.stringify(originalTrack)) as Track
|
||||
|
||||
// Marque la piste comme provenant d'une playlist utilisateur
|
||||
virtualTrack.source = 'userPlaylist'
|
||||
virtualTrack.originalTrackId = originalTrack.id
|
||||
virtualTrack.boxId = FAVORITES_BOX_ID
|
||||
|
||||
// Si la piste a un artiste sous forme d'objet, on le convertit en chaîne pour éviter les problèmes de référence
|
||||
if (virtualTrack.artist && typeof virtualTrack.artist === 'object') {
|
||||
virtualTrack.artist = (virtualTrack.artist as Artist).name
|
||||
}
|
||||
|
||||
return virtualTrack
|
||||
},
|
||||
|
||||
// Ajoute une piste aux favoris si elle n'y est pas déjà
|
||||
add(track: Track) {
|
||||
if (!this.isFavorite(track.id)) {
|
||||
// Crée une copie virtuelle de la piste
|
||||
const virtualTrack = this.createVirtualTrack(track)
|
||||
|
||||
if (!this.favoritesPlaylist.tracks) {
|
||||
this.favoritesPlaylist.tracks = []
|
||||
}
|
||||
|
||||
// Ajoute la piste virtuelle au début de la liste
|
||||
this.favoritesPlaylist.tracks.unshift(virtualTrack)
|
||||
this.updateDuration()
|
||||
this.save()
|
||||
}
|
||||
},
|
||||
|
||||
// Supprime une piste des favoris
|
||||
remove(trackId: number) {
|
||||
if (this.favoritesPlaylist.tracks) {
|
||||
const index = this.favoritesPlaylist.tracks.findIndex((t) => t.id === trackId)
|
||||
if (index >= 0) {
|
||||
this.favoritesPlaylist.tracks.splice(index, 1)
|
||||
this.updateDuration()
|
||||
this.save()
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Bascule l'état favori d'une piste
|
||||
toggle(track: Track) {
|
||||
if (this.isFavorite(track.id)) {
|
||||
this.remove(track.id)
|
||||
} else {
|
||||
this.add(track)
|
||||
}
|
||||
},
|
||||
|
||||
// Met à jour la durée totale de la playlist
|
||||
updateDuration() {
|
||||
if (this.favoritesPlaylist.tracks) {
|
||||
this.favoritesPlaylist.duration = this.favoritesPlaylist.tracks.reduce(
|
||||
(total, track) => total + (track.duration || 0),
|
||||
0
|
||||
)
|
||||
}
|
||||
},
|
||||
|
||||
// Récupère la piste suivante dans les favoris
|
||||
getNextTrack(currentTrackId: number): Track | null {
|
||||
if (!this.favoritesPlaylist.tracks) return null
|
||||
const currentIndex = this.favoritesPlaylist.tracks.findIndex((t) => t.id === currentTrackId)
|
||||
if (currentIndex >= 0 && currentIndex < this.favoritesPlaylist.tracks.length - 1) {
|
||||
const nextTrack = this.favoritesPlaylist.tracks[currentIndex + 1]
|
||||
return nextTrack ? { ...nextTrack } : null
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -3,7 +3,6 @@ import { defineStore } from 'pinia'
|
||||
import type { Track, Box } from '~/../types/types'
|
||||
import { useDataStore } from '~/store/data'
|
||||
import { useCardStore } from '~/store/card'
|
||||
import { useFavoritesStore, FAVORITES_BOX_ID } from '~/store/favorites'
|
||||
|
||||
export const usePlayerStore = defineStore('player', {
|
||||
state: () => ({
|
||||
@@ -40,18 +39,8 @@ export const usePlayerStore = defineStore('player', {
|
||||
if (!track) return
|
||||
|
||||
const dataStore = useDataStore()
|
||||
const favoritesStore = useFavoritesStore()
|
||||
|
||||
// Vérifier si on est dans la playlist des favoris
|
||||
if (track.boxId === FAVORITES_BOX_ID) {
|
||||
const nextTrack = favoritesStore.getNextTrack(track.id)
|
||||
if (nextTrack) {
|
||||
await this.playTrack(nextTrack)
|
||||
return
|
||||
}
|
||||
}
|
||||
// Comportement par défaut pour les playlists standards
|
||||
else if (track.type === 'playlist') {
|
||||
if (track.type === 'playlist') {
|
||||
const next = dataStore.getNextPlaylistTrack(track)
|
||||
if (next && next.boxId === track.boxId) {
|
||||
await this.playTrack(next)
|
||||
@@ -85,16 +74,10 @@ export const usePlayerStore = defineStore('player', {
|
||||
},
|
||||
|
||||
async playTrack(track: Track) {
|
||||
// Si c'est une piste de la playlist utilisateur, on utilise directement cette piste
|
||||
if (track.boxId === FAVORITES_BOX_ID) {
|
||||
this.currentTrack = track
|
||||
await this.loadAndPlayTrack(track)
|
||||
} else {
|
||||
// Pour les autres types de pistes, on utilise la logique existante
|
||||
this.isCompilationTrack(track)
|
||||
? await this.playCompilationTrack(track)
|
||||
: await this.playPlaylistTrack(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) {
|
||||
@@ -214,7 +197,6 @@ export const usePlayerStore = defineStore('player', {
|
||||
|
||||
async togglePlay() {
|
||||
if (!this.audio) return
|
||||
|
||||
try {
|
||||
if (this.audio.paused) {
|
||||
await this.audio.play()
|
||||
@@ -240,11 +222,11 @@ export const usePlayerStore = defineStore('player', {
|
||||
this.progressionLast = progression
|
||||
}
|
||||
// update current track when changing time in compilation
|
||||
const cur = this.currentTrack
|
||||
if (cur && cur.type === 'compilation') {
|
||||
const currentTrack = this.currentTrack
|
||||
if (currentTrack && currentTrack.type === 'compilation') {
|
||||
const dataStore = useDataStore()
|
||||
const tracks = dataStore
|
||||
.getTracksByboxId(cur.boxId)
|
||||
.getTracksByboxId(currentTrack.boxId, currentTrack.side)
|
||||
.slice()
|
||||
.filter((t) => t.type === 'compilation')
|
||||
.sort((a, b) => (a.start ?? 0) - (b.start ?? 0))
|
||||
@@ -261,7 +243,7 @@ export const usePlayerStore = defineStore('player', {
|
||||
break
|
||||
}
|
||||
}
|
||||
if (nextTrack && nextTrack.id !== cur.id) {
|
||||
if (nextTrack && nextTrack.id !== currentTrack.id) {
|
||||
// only update metadata reference; do not reload audio
|
||||
this.currentTrack = nextTrack
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ export const useUiStore = defineStore('ui', {
|
||||
selectBox(id: string) {
|
||||
const dataStore = useDataStore()
|
||||
dataStore.boxes.forEach((box) => {
|
||||
id = id.replace(/[AB]$/, '')
|
||||
box.state = box.id === id ? 'box-selected' : 'box-hidden'
|
||||
})
|
||||
},
|
||||
@@ -57,7 +58,7 @@ export const useUiStore = defineStore('ui', {
|
||||
// Récupérer la position de l'élément
|
||||
const elementRect = boxElement.getBoundingClientRect()
|
||||
// Calculer la position de défilement (une boîte plus haut)
|
||||
const offsetPosition = elementRect.top + window.pageYOffset - (elementRect.height * 1.5)
|
||||
const offsetPosition = elementRect.top + window.pageYOffset - elementRect.height * 1.5
|
||||
// Faire défiler à la nouvelle position
|
||||
window.scrollTo({
|
||||
top: offsetPosition,
|
||||
|
||||
Reference in New Issue
Block a user