diff --git a/front/src/api/player.ts b/front/src/api/player.ts index 30f9bb8dd..8b957fba9 100644 --- a/front/src/api/player.ts +++ b/front/src/api/player.ts @@ -20,6 +20,7 @@ export interface Sound { readonly currentTime: number readonly duration: number readonly buffered: number + looping: boolean play(): void | Promise pause(): void | Promise @@ -27,6 +28,7 @@ export interface Sound { seekTo(seconds: number): void | Promise seekBy(seconds: number): void | Promise + onSoundLoop: EventHookOn onSoundEnd: EventHookOn } @@ -41,11 +43,13 @@ export const registerSoundImplementation = >(implem @registerSoundImplementation export class HTMLSound implements Sound { #audio = new Audio() + #soundLoopEventHook = createEventHook() #soundEndEventHook = createEventHook() readonly isLoaded = ref(false) audioNode = createAudioSource(this.#audio) + onSoundLoop: EventHookOn onSoundEnd: EventHookOn constructor (sources: SoundSource[]) { @@ -54,11 +58,18 @@ export class HTMLSound implements Sound { this.#audio.preload = 'auto' useEventListener(this.#audio, 'ended', () => this.#soundEndEventHook.trigger(this)) + useEventListener(this.#audio, 'timeupdate', () => { + if (this.#audio.currentTime === 0) { + this.#soundLoopEventHook.trigger(this) + } + }) + useEventListener(this.#audio, 'loadeddata', () => { // https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState this.isLoaded.value = this.#audio.readyState >= 2 }) + this.onSoundLoop = this.#soundLoopEventHook.on this.onSoundEnd = this.#soundEndEventHook.on } @@ -108,6 +119,14 @@ export class HTMLSound implements Sound { get currentTime () { return this.#audio.currentTime } + + get looping () { + return this.#audio.loop + } + + set looping (value: boolean) { + this.#audio.loop = value + } } export const soundImplementation = refDefault(ref>(), HTMLSound) diff --git a/front/src/composables/audio/player.ts b/front/src/composables/audio/player.ts index 48303de5c..f11248dce 100644 --- a/front/src/composables/audio/player.ts +++ b/front/src/composables/audio/player.ts @@ -62,11 +62,25 @@ export const toggleLooping = () => { looping.value %= MODE_MAX } +watchEffect(() => { + const sound = currentSound.value + if (!sound) return + sound.looping = looping.value === LoopingMode.LoopTrack +}) + +watch(currentSound, sound => { + sound?.onSoundLoop(() => { + currentTime.value = 0 + }) +}) + // Duration export const duration = ref(0) watchEffect(() => { - if (currentSound.value?.isLoaded.value) { - duration.value = currentSound.value?.duration ?? 0 + const sound = currentSound.value + if (sound?.isLoaded.value === true) { + duration.value = sound.duration ?? 0 + currentTime.value = sound.currentTime return }