import { useEffect, useRef, useState } from "react"; import type { VideoScene } from "../../api/types"; import type { PanelProps } from "./EditorPanels"; const GROUP = 5; const clock = (s: number) => { const t = Math.max(0, Math.round(s)); return `${Math.floor(t / 60)}:${String(t % 60).padStart(2, "0")}`; }; /** Each scene's voiceover, grouped by five (one group open at a time), to play with a progress bar. */ export function Voiceovers(p: PanelProps & { scenes: VideoScene[] }) { const { scenes } = p; const [openGroup, setOpenGroup] = useState(0); const [playing, setPlaying] = useState<{ id: number; at: number; length: number } | null>(null); const audio = useRef(null); const ready = scenes.filter((s) => s.audio_url).length; const total = Math.round(scenes.reduce((n, s) => n + Number(s.duration_seconds ?? 0), 0)); // Stop playback when leaving the tab. useEffect(() => () => audio.current?.pause(), []); function toggle(s: VideoScene) { const el = audio.current; if (!el || !s.audio_url) return; if (playing?.id === s.id) { el.pause(); setPlaying(null); return; } el.src = s.audio_url; el.currentTime = 0; setPlaying({ id: s.id, at: 0, length: Number(s.duration_seconds ?? 0) }); el.play().catch(() => setPlaying(null)); } const groups: VideoScene[][] = []; for (let i = 0; i < scenes.length; i += GROUP) groups.push(scenes.slice(i, i + GROUP)); return (

Voiceovers

{ready} / {scenes.length} scenes · {total}s total Ready Pending
); }