kopia lustrzana https://dev.funkwhale.audio/funkwhale/funkwhale
Add track looping logic
rodzic
e47dbc5ab5
commit
7c68fee276
|
@ -20,6 +20,7 @@ export interface Sound {
|
||||||
readonly currentTime: number
|
readonly currentTime: number
|
||||||
readonly duration: number
|
readonly duration: number
|
||||||
readonly buffered: number
|
readonly buffered: number
|
||||||
|
looping: boolean
|
||||||
|
|
||||||
play(): void | Promise<void>
|
play(): void | Promise<void>
|
||||||
pause(): void | Promise<void>
|
pause(): void | Promise<void>
|
||||||
|
@ -27,6 +28,7 @@ export interface Sound {
|
||||||
seekTo(seconds: number): void | Promise<void>
|
seekTo(seconds: number): void | Promise<void>
|
||||||
seekBy(seconds: number): void | Promise<void>
|
seekBy(seconds: number): void | Promise<void>
|
||||||
|
|
||||||
|
onSoundLoop: EventHookOn<Sound>
|
||||||
onSoundEnd: EventHookOn<Sound>
|
onSoundEnd: EventHookOn<Sound>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,11 +43,13 @@ export const registerSoundImplementation = <T extends Constructor<Sound>>(implem
|
||||||
@registerSoundImplementation
|
@registerSoundImplementation
|
||||||
export class HTMLSound implements Sound {
|
export class HTMLSound implements Sound {
|
||||||
#audio = new Audio()
|
#audio = new Audio()
|
||||||
|
#soundLoopEventHook = createEventHook<HTMLSound>()
|
||||||
#soundEndEventHook = createEventHook<HTMLSound>()
|
#soundEndEventHook = createEventHook<HTMLSound>()
|
||||||
|
|
||||||
readonly isLoaded = ref(false)
|
readonly isLoaded = ref(false)
|
||||||
|
|
||||||
audioNode = createAudioSource(this.#audio)
|
audioNode = createAudioSource(this.#audio)
|
||||||
|
onSoundLoop: EventHookOn<HTMLSound>
|
||||||
onSoundEnd: EventHookOn<HTMLSound>
|
onSoundEnd: EventHookOn<HTMLSound>
|
||||||
|
|
||||||
constructor (sources: SoundSource[]) {
|
constructor (sources: SoundSource[]) {
|
||||||
|
@ -54,11 +58,18 @@ export class HTMLSound implements Sound {
|
||||||
this.#audio.preload = 'auto'
|
this.#audio.preload = 'auto'
|
||||||
|
|
||||||
useEventListener(this.#audio, 'ended', () => this.#soundEndEventHook.trigger(this))
|
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', () => {
|
useEventListener(this.#audio, 'loadeddata', () => {
|
||||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState
|
// https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement/readyState
|
||||||
this.isLoaded.value = this.#audio.readyState >= 2
|
this.isLoaded.value = this.#audio.readyState >= 2
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.onSoundLoop = this.#soundLoopEventHook.on
|
||||||
this.onSoundEnd = this.#soundEndEventHook.on
|
this.onSoundEnd = this.#soundEndEventHook.on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +119,14 @@ export class HTMLSound implements Sound {
|
||||||
get currentTime () {
|
get currentTime () {
|
||||||
return this.#audio.currentTime
|
return this.#audio.currentTime
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get looping () {
|
||||||
|
return this.#audio.loop
|
||||||
|
}
|
||||||
|
|
||||||
|
set looping (value: boolean) {
|
||||||
|
this.#audio.loop = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const soundImplementation = refDefault(ref<Constructor<Sound>>(), HTMLSound)
|
export const soundImplementation = refDefault(ref<Constructor<Sound>>(), HTMLSound)
|
||||||
|
|
|
@ -62,11 +62,25 @@ export const toggleLooping = () => {
|
||||||
looping.value %= MODE_MAX
|
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
|
// Duration
|
||||||
export const duration = ref(0)
|
export const duration = ref(0)
|
||||||
watchEffect(() => {
|
watchEffect(() => {
|
||||||
if (currentSound.value?.isLoaded.value) {
|
const sound = currentSound.value
|
||||||
duration.value = currentSound.value?.duration ?? 0
|
if (sound?.isLoaded.value === true) {
|
||||||
|
duration.value = sound.duration ?? 0
|
||||||
|
currentTime.value = sound.currentTime
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Ładowanie…
Reference in New Issue