diff --git a/front/src/composables/audio/player.ts b/front/src/composables/audio/player.ts index c9961c5fd..844ef8cb4 100644 --- a/front/src/composables/audio/player.ts +++ b/front/src/composables/audio/player.ts @@ -1,5 +1,5 @@ import { createGlobalState, tryOnMounted, useIntervalFn, useRafFn, useStorage, useTimeoutFn, whenever } from '@vueuse/core' -import { computed, nextTick, ref, watch, watchEffect, type Ref } from 'vue' +import { computed, ref, watch, watchEffect, type Ref } from 'vue' import { useTracks } from '~/composables/audio/tracks' import { setGain } from './audio-api' @@ -28,7 +28,7 @@ export const isPlaying = ref(false) // Use Player export const usePlayer = createGlobalState(() => { - const { currentSound, createTrack } = useTracks() + const { currentSound } = useTracks() const { playNext } = useQueue() watchEffect(() => { @@ -43,12 +43,6 @@ export const usePlayer = createGlobalState(() => { sound.pause() }) - const stop = async () => { - isPlaying.value = false - seekTo(0) - return nextTick() - } - // Create first track when we initalize the page // NOTE: We want to have it called only once, hence we're using createGlobalState const initializeFirstTrack = createGlobalState(() => tryOnMounted(() => { @@ -59,8 +53,6 @@ export const usePlayer = createGlobalState(() => { trackRadioPopulating() trackListenSubmissions() - - createTrack(currentIndex.value) })) // Volume @@ -208,7 +200,6 @@ export const usePlayer = createGlobalState(() => { return { initializeFirstTrack, isPlaying, - stop, volume, mute, looping, diff --git a/front/src/composables/audio/queue.ts b/front/src/composables/audio/queue.ts index 5f38fdcfd..c269c8274 100644 --- a/front/src/composables/audio/queue.ts +++ b/front/src/composables/audio/queue.ts @@ -6,7 +6,7 @@ import { computed, ref, shallowReactive, watchEffect } from 'vue' import { getMany, setMany } from 'idb-keyval' import { useClamp } from '@vueuse/math' -import { looping, LoopingMode, isPlaying, usePlayer } from '~/composables/audio/player' +import { looping, LoopingMode, isPlaying } from '~/composables/audio/player' import { useStore } from '~/store' import { useTracks } from '~/composables/audio/tracks' @@ -166,13 +166,17 @@ export const useQueue = createGlobalState(() => { } // Play track - const playTrack = async (trackIndex: number, force = false) => { + const playTrack = async (trackIndex: number, forceRestartIfCurrent = false) => { if (isPlaying.value) currentSound.value?.pause() + if (currentIndex.value !== trackIndex) currentSound.value?.seekTo(0) - if (force && currentIndex.value === trackIndex) { + const shouldRestart = forceRestartIfCurrent && currentIndex.value === trackIndex + const nextTrackIsTheSame = queue.value[trackIndex].id === currentTrack.value.id + + if (shouldRestart || nextTrackIsTheSame) { currentSound.value?.seekTo(0) if (isPlaying.value) currentSound.value?.play() - return + if (shouldRestart) return } currentIndex.value = trackIndex @@ -270,8 +274,9 @@ export const useQueue = createGlobalState(() => { // Clear const clearRadio = ref(false) const clear = async () => { - const { stop } = usePlayer() - await stop() + currentSound.value?.pause() + currentSound.value?.seekTo(0) + currentSound.value?.dispose() clearRadio.value = true tracks.value.length = 0 } diff --git a/front/src/composables/audio/tracks.ts b/front/src/composables/audio/tracks.ts index e631302b1..a02f39e09 100644 --- a/front/src/composables/audio/tracks.ts +++ b/front/src/composables/audio/tracks.ts @@ -1,7 +1,7 @@ import type { QueueTrack, QueueTrackSource } from '~/composables/audio/queue' import type { Sound } from '~/api/player' -import { createGlobalState, syncRef, whenever } from '@vueuse/core' +import { createGlobalState, syncRef, useTimeoutFn, whenever } from '@vueuse/core' import { computed, ref } from 'vue' import { connectAudioSource } from '~/composables/audio/audio-api' @@ -55,30 +55,40 @@ export const useTracks = createGlobalState(() => { const createSoundPromise = async () => { const sources = getTrackSources(track) - const { playNext, currentIndex } = useQueue() + const { playTrack, currentIndex } = useQueue() const SoundImplementation = soundImplementation.value const sound = new SoundImplementation(sources) sound.onSoundEnd(() => { console.log('TRACK ENDED, PLAYING NEXT') - createTrack(currentIndex.value + 1) // NOTE: We push it to the end of the job queue - setTimeout(playNext, 0) + setTimeout(() => { + playTrack(currentIndex.value + 1) + }, 0) }) soundCache.set(track.id, sound) soundPromises.delete(track.id) return sound } - console.log('NO TRACK IN CACHE, CREATING') + console.log('NO TRACK IN CACHE, CREATING', track) const soundPromise = createSoundPromise() soundPromises.set(track.id, soundPromise) return soundPromise } + // Preload next track + const { start: startPreloadTimeout, stop: stopPreloadTimeout } = useTimeoutFn(async (index) => { + const { queue } = useQueue() + const sound = await createSound(queue.value[index as number]) + await sound.preload() + }, 100, { immediate: false }) + // Create track from queue const createTrack = async (index: number) => { + stopPreloadTimeout() + const { queue, currentIndex } = useQueue() if (queue.value.length <= index || index === -1) return console.log('LOADING TRACK', index) @@ -97,10 +107,8 @@ export const useTracks = createGlobalState(() => { // NOTE: Preload next track if (index === currentIndex.value && index + 1 < queue.value.length) { - setTimeout(async () => { - const sound = await createSound(queue.value[index + 1]) - await sound.preload() - }, 100) + // @ts-expect-error vueuse is wrongly typed? + startPreloadTimeout(index + 1) } } @@ -110,7 +118,9 @@ export const useTracks = createGlobalState(() => { const initialize = createGlobalState(() => { const { currentIndex, currentTrack: track } = useQueue() - whenever(track, () => createTrack(currentIndex.value)) + whenever(track, () => { + createTrack(currentIndex.value) + }, { immediate: true }) syncRef(track, currentTrack, { direction: 'ltr' })