Add frontend/src/components/VideoPreview.tsx

This commit is contained in:
Zac Gaetano 2026-04-14 09:21:17 -04:00
parent 0c1f78637b
commit df84c6cbbc

View file

@ -0,0 +1,67 @@
import React, { useEffect, useRef } from 'react';
import Hls from 'hls.js';
interface VideoPreviewProps {
portIndex: number;
}
export function VideoPreview({ portIndex }: VideoPreviewProps) {
const videoRef = useRef<HTMLVideoElement>(null);
const hlsRef = useRef<Hls | null>(null);
useEffect(() => {
const src = `/hls/port_${portIndex}.m3u8`;
if (!videoRef.current) {
return;
}
if (Hls.isSupported()) {
const hls = new Hls({
enableWorker: true,
lowLatencyMode: true,
});
hlsRef.current = hls;
hls.loadSource(src);
hls.attachMedia(videoRef.current);
hls.on(Hls.Events.MANIFEST_PARSED, () => {
videoRef.current?.play().catch((err) => {
console.error('Failed to autoplay video:', err);
});
});
hls.on(Hls.Events.ERROR, (event, data) => {
console.error('HLS.js error:', data);
});
} else if (videoRef.current.canPlayType('application/vnd.apple.mpegurl')) {
// Safari native HLS support
videoRef.current.src = src;
videoRef.current.play().catch((err) => {
console.error('Failed to autoplay video:', err);
});
} else {
console.error('HLS streaming is not supported in this browser');
}
return () => {
if (hlsRef.current) {
hlsRef.current.destroy();
hlsRef.current = null;
}
};
}, [portIndex]);
return (
<div className="bg-black rounded-lg overflow-hidden aspect-video">
<video
ref={videoRef}
className="w-full h-full"
controls
muted
playsInline
/>
</div>
);
}