diff --git a/web/src/components/Player.vue b/web/src/components/Player.vue index 0696918..7b19ee8 100644 --- a/web/src/components/Player.vue +++ b/web/src/components/Player.vue @@ -1,69 +1,73 @@ @@ -80,13 +84,13 @@ const store = usePlayerStore(); const activeBot = computed(() => store.activeBot); const currentSong = computed(() => store.currentSong); -// Progress bar state -const progressBarRef = ref(null); +// Progress — use manual timer instead of relying on reactive getters const currentElapsed = ref(0); const progressPercent = ref(0); const progressTooltipVisible = ref(false); const progressTooltipX = ref(0); const progressTooltipTime = ref('0:00'); +const progressBarRef = ref(null); let rafId: number | null = null; function formatTime(seconds: number): string { @@ -97,22 +101,33 @@ function formatTime(seconds: number): string { } function updateProgress() { - const elapsed = store.elapsed; + // Directly compute elapsed from raw values (bypass Vue reactivity) + const bot = store.activeBot; + if (bot?.playing && !bot.paused && store.playStartedAt > 0) { + currentElapsed.value = (Date.now() - store.playStartedAt) / 1000; + } else if (bot?.paused) { + currentElapsed.value = store.pausedElapsed; + } + const duration = currentSong.value?.duration ?? 0; - currentElapsed.value = elapsed; - progressPercent.value = duration > 0 ? Math.min((elapsed / duration) * 100, 100) : 0; + progressPercent.value = duration > 0 + ? Math.min((currentElapsed.value / duration) * 100, 100) + : 0; + rafId = requestAnimationFrame(updateProgress); } -function onProgressMouseDown(e: MouseEvent) { +function onProgressClick(e: MouseEvent) { const bar = progressBarRef.value; if (!bar) return; const rect = bar.getBoundingClientRect(); const ratio = Math.max(0, Math.min(1, (e.clientX - rect.left) / rect.width)); const duration = currentSong.value?.duration ?? 0; - // Visual-only seek (server-side seeking not supported) - progressPercent.value = ratio * 100; - progressTooltipTime.value = formatTime(ratio * duration); + const seekTime = ratio * duration; + // Can't seek server-side FFmpeg stream — show tooltip with target time + progressTooltipTime.value = `跳转不可用 (${formatTime(seekTime)})`; + progressTooltipVisible.value = true; + setTimeout(() => { progressTooltipVisible.value = false; }, 1500); } function onProgressHover(e: MouseEvent) { @@ -134,11 +149,6 @@ onUnmounted(() => { if (rafId !== null) cancelAnimationFrame(rafId); }); -function toggleQueue() { - showQueue.value = !showQueue.value; - console.log('Queue panel toggled:', showQueue.value); -} - function togglePlay() { if (store.isPlaying) { store.pause(); @@ -178,33 +188,38 @@ function cycleMode() {