initiation librodrome
This commit is contained in:
187
app/stores/player.ts
Normal file
187
app/stores/player.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import type { Song } from '~/types/song'
|
||||
import type { PlayerMode, RepeatMode } from '~/types/player'
|
||||
|
||||
export const usePlayerStore = defineStore('player', () => {
|
||||
// State
|
||||
const isPlaying = ref(false)
|
||||
const currentSong = ref<Song | null>(null)
|
||||
const currentTime = ref(0)
|
||||
const duration = ref(0)
|
||||
const volume = ref(0.8)
|
||||
const mode = ref<PlayerMode>('guided')
|
||||
const repeatMode = ref<RepeatMode>('none')
|
||||
const isShuffled = ref(false)
|
||||
const playlist = ref<Song[]>([])
|
||||
const queue = ref<Song[]>([])
|
||||
const isExpanded = ref(false)
|
||||
|
||||
// Computed
|
||||
const progress = computed(() => {
|
||||
if (duration.value === 0) return 0
|
||||
return (currentTime.value / duration.value) * 100
|
||||
})
|
||||
|
||||
const formattedCurrentTime = computed(() => formatTime(currentTime.value))
|
||||
const formattedDuration = computed(() => formatTime(duration.value))
|
||||
const isGuidedMode = computed(() => mode.value === 'guided')
|
||||
|
||||
const currentIndex = computed(() => {
|
||||
if (!currentSong.value) return -1
|
||||
return playlist.value.findIndex(s => s.id === currentSong.value!.id)
|
||||
})
|
||||
|
||||
const hasNext = computed(() => {
|
||||
if (repeatMode.value === 'all') return playlist.value.length > 0
|
||||
return currentIndex.value < playlist.value.length - 1
|
||||
})
|
||||
|
||||
const hasPrev = computed(() => {
|
||||
return currentIndex.value > 0
|
||||
})
|
||||
|
||||
// Actions
|
||||
function setSong(song: Song) {
|
||||
currentSong.value = song
|
||||
currentTime.value = 0
|
||||
duration.value = song.duration
|
||||
}
|
||||
|
||||
function setPlaylist(songs: Song[]) {
|
||||
playlist.value = songs
|
||||
}
|
||||
|
||||
function setMode(newMode: PlayerMode) {
|
||||
mode.value = newMode
|
||||
}
|
||||
|
||||
function togglePlay() {
|
||||
isPlaying.value = !isPlaying.value
|
||||
}
|
||||
|
||||
function play() {
|
||||
isPlaying.value = true
|
||||
}
|
||||
|
||||
function pause() {
|
||||
isPlaying.value = false
|
||||
}
|
||||
|
||||
function setCurrentTime(time: number) {
|
||||
currentTime.value = time
|
||||
}
|
||||
|
||||
function setDuration(dur: number) {
|
||||
duration.value = dur
|
||||
}
|
||||
|
||||
function setVolume(vol: number) {
|
||||
volume.value = Math.max(0, Math.min(1, vol))
|
||||
}
|
||||
|
||||
function toggleRepeat() {
|
||||
const modes: RepeatMode[] = ['none', 'all', 'one']
|
||||
const idx = modes.indexOf(repeatMode.value)
|
||||
repeatMode.value = modes[(idx + 1) % modes.length]
|
||||
}
|
||||
|
||||
function toggleShuffle() {
|
||||
isShuffled.value = !isShuffled.value
|
||||
}
|
||||
|
||||
function toggleExpanded() {
|
||||
isExpanded.value = !isExpanded.value
|
||||
}
|
||||
|
||||
function nextSong(): Song | null {
|
||||
if (playlist.value.length === 0) return null
|
||||
|
||||
if (repeatMode.value === 'one') {
|
||||
currentTime.value = 0
|
||||
return currentSong.value
|
||||
}
|
||||
|
||||
let nextIdx = currentIndex.value + 1
|
||||
if (nextIdx >= playlist.value.length) {
|
||||
if (repeatMode.value === 'all') {
|
||||
nextIdx = 0
|
||||
}
|
||||
else {
|
||||
pause()
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
const song = playlist.value[nextIdx]
|
||||
setSong(song)
|
||||
return song
|
||||
}
|
||||
|
||||
function prevSong(): Song | null {
|
||||
if (playlist.value.length === 0) return null
|
||||
|
||||
// If more than 3 seconds in, restart current song
|
||||
if (currentTime.value > 3) {
|
||||
currentTime.value = 0
|
||||
return currentSong.value
|
||||
}
|
||||
|
||||
let prevIdx = currentIndex.value - 1
|
||||
if (prevIdx < 0) {
|
||||
if (repeatMode.value === 'all') {
|
||||
prevIdx = playlist.value.length - 1
|
||||
}
|
||||
else {
|
||||
currentTime.value = 0
|
||||
return currentSong.value
|
||||
}
|
||||
}
|
||||
|
||||
const song = playlist.value[prevIdx]
|
||||
setSong(song)
|
||||
return song
|
||||
}
|
||||
|
||||
return {
|
||||
// State
|
||||
isPlaying,
|
||||
currentSong,
|
||||
currentTime,
|
||||
duration,
|
||||
volume,
|
||||
mode,
|
||||
repeatMode,
|
||||
isShuffled,
|
||||
playlist,
|
||||
queue,
|
||||
isExpanded,
|
||||
// Computed
|
||||
progress,
|
||||
formattedCurrentTime,
|
||||
formattedDuration,
|
||||
isGuidedMode,
|
||||
currentIndex,
|
||||
hasNext,
|
||||
hasPrev,
|
||||
// Actions
|
||||
setSong,
|
||||
setPlaylist,
|
||||
setMode,
|
||||
togglePlay,
|
||||
play,
|
||||
pause,
|
||||
setCurrentTime,
|
||||
setDuration,
|
||||
setVolume,
|
||||
toggleRepeat,
|
||||
toggleShuffle,
|
||||
toggleExpanded,
|
||||
nextSong,
|
||||
prevSong,
|
||||
}
|
||||
})
|
||||
|
||||
function formatTime(seconds: number): string {
|
||||
const mins = Math.floor(seconds / 60)
|
||||
const secs = Math.floor(seconds % 60)
|
||||
return `${mins}:${secs.toString().padStart(2, '0')}`
|
||||
}
|
||||
Reference in New Issue
Block a user