improve autoplay

This commit is contained in:
2026-09-03 12:36:51 +01:00
parent e39d068ebe
commit 257765983f
+24 -21
View File
@@ -9,7 +9,7 @@ import PauseIcon from '@/icons/PauseIcon.vue';
import PlayIcon from '@/icons/PlayIcon.vue';
import StopIcon from '@/icons/StopIcon.vue';
import { useAudioPlayerStore, useConfigStore, useFlagStore } from '@/stores';
import { computed, ref, useTemplateRef, watchEffect } from 'vue';
import { computed, ref, useTemplateRef, watch } from 'vue';
const config = useConfigStore()
const flags = useFlagStore()
@@ -18,12 +18,13 @@ const player = useAudioPlayerStore()
const audio = useTemplateRef('audio')
const file = ref<dto.File>()
const next = ref<dto.File>()
const playing = ref(false)
const duration = ref(0)
const progress = ref(0)
const src = computed(() => `${config.value!.serverUrl}/file/${player.file?.id}`)
const src = computed(() =>
file.value ? `${config.value!.serverUrl}/file/${file.value.id}` : undefined,
)
function play() {
if (audio.value) {
@@ -65,33 +66,35 @@ function timeupdate() {
progress.value = audio.value?.currentTime || 0
}
watchEffect(() => {
// When a new file is pushed to the player store, queue it up
if (player.file && player.file !== file.value) {
next.value = player.file
}
// Mirror the app-wide selection into the local ref. Pre-flush so the <audio>
// element and its :src are in the DOM before the playback watch runs.
watch(() => player.file, (selected) => {
file.value = selected
})
watchEffect(() => {
// When a new file is queued, substitute it for the current file
// This two-stage approach enables unmounting the audio element to prevent playback issues
if (next.value) {
if (!flags.has('autoplay')) {
stop()
}
}
// Load and (optionally) start the new track. `flush: 'post'` runs this right
// after the DOM updates but still in the microtask chain of the click that
// selected the file, so play() counts as user-initiated on iOS/Safari. The
// single <audio> element is never unmounted, so once iOS has seen one
// gesture-driven play() it stays unlocked for every later track.
watch(file, (selected) => {
const el = audio.value
if (!el) return
file.value = next.value
next.value = undefined
})
el.load()
if (selected && flags.has('autoplay')) {
el.play().catch(() => {})
} else {
stop()
}
}, { flush: 'post' })
</script>
<template>
<section class="audio-player">
<audio v-if="file && !next"
<audio v-if="file"
ref="audio"
preload="metadata"
:autoplay="flags.value.includes('autoplay')"
:loop="flags.value.includes('loop')"
:src="src"
v-on:loadedmetadata="onloadedmetadata"