import React, { useState, useEffect } from 'react'; import { useWebSocket } from './hooks/useWebSocket'; import { useRecorder } from './hooks/useRecorder'; import { PortCard } from './components/PortCard'; import { VideoPreview } from './components/VideoPreview'; import { ConfigPanel } from './components/ConfigPanel'; import { SCTE35Trigger } from './components/SCTE35Trigger'; import { PortStatus, RecorderConfig } from './types'; export default function App() { const [ports, setPorts] = useState([]); const [selectedPort, setSelectedPort] = useState(null); const [configPort, setConfigPort] = useState(null); const [configs, setConfigs] = useState>({}); const wsUrl = `ws://${window.location.host}/ws`; const { isConnected, lastMessage } = useWebSocket(wsUrl); const { startRecording, stopRecording, injectSCTE35 } = useRecorder(); // Update ports from WebSocket messages useEffect(() => { if (lastMessage?.type === 'port_status' && lastMessage.ports) { setPorts(lastMessage.ports); } }, [lastMessage]); // Initial fetch of port statuses useEffect(() => { fetch('/api/ports') .then(r => r.json()) .then(setPorts) .catch(console.error); }, []); const handleStartRecording = async (portIndex: number) => { const config = configs[portIndex] || defaultConfig(portIndex); await startRecording(portIndex, config); }; const handleSaveConfig = (config: RecorderConfig) => { setConfigs(prev => ({ ...prev, [config.port_index]: config })); // If not recording, optionally auto-start? No — just save }; const handleInjectSCTE35 = async (eventId: number, durationSeconds: number) => { await injectSCTE35(eventId, durationSeconds); }; return (
{/* Header */}

Deltacast SDI Recorder

{isConnected ? 'Connected' : 'Disconnected'}
{/* Port Cards Grid - responsive: 1 col mobile, 2 tablet, 4 desktop */}
{ports.map(port => ( ))} {ports.length === 0 && (
No ports available. Check backend connection.
)}
{/* Selected Port Detail View */} {selectedPort !== null && (

Port {selectedPort} Preview

Ad Break Control

)}
{/* Config Panel Modal */} {configPort !== null && ( setConfigPort(null)} /> )}
); } function defaultConfig(portIndex: number): RecorderConfig { return { port_index: portIndex, codec: 'PRORES', bitrate: '185M', quality_profile: 'hq', recording_path: `/recordings/port_${portIndex}_{timestamp}.mxf`, srt_enabled: false, srt_destination: '', preview_enabled: true, }; }