import { useEffect, useRef, useState } from "react"; import type { Particle } from "@/api/types"; import { useDownloadUrl } from "@/hooks/use-download-url"; import { Skeleton } from "@/components/ui/skeleton"; import { AudioLevelBars } from "@/components/audio/audio-level-bars"; import { useAudioSource } from "@/components/audio/use-audio-source"; type MediaParticle = Extract; interface MediaParticleViewProps { particle: MediaParticle; paused: boolean; onEnded: () => void; onProgress?: (ratio: number) => void; } export function MediaParticleView({ particle, paused, onEnded, onProgress, }: MediaParticleViewProps) { const { data: url, error } = useDownloadUrl(particle.properties.object_id); const videoRef = useRef(null); const audioRef = useRef(null); const isAudio = particle.properties.mime_type?.startsWith("audio/"); // WORKAROUND: useAudioSource needs an audio element, but audioRef is only set after mount const [audioEl, setAudioEl] = useState(null); const audioSource = useAudioSource(audioEl); useEffect(() => { const el = isAudio ? audioRef.current : videoRef.current; if (!el) return; if (paused) { el.pause(); } else { el.play().catch(() => { console.warn("Playback failed", { particleId: particle.id }); }); } }, [paused, isAudio, particle.id]); if (error) { return (
Failed to load media
); } if (!url) { return ; } if (isAudio) { return (
); } return (
); }