// modal-new-recorder.jsx — New Recorder dialog (SRT / RTMP / SDI)
function NewRecorderModal({ open, onClose }) {
const { PROJECTS } = window.ZAMPP_DATA;
const [name, setName] = React.useState('');
const [sourceType, setSourceType] = React.useState('SRT');
const [srtUrl, setSrtUrl] = React.useState('srt://10.0.4.18:4200');
const [rtmpUrl, setRtmpUrl] = React.useState('rtmp://stream.local/live/cam_a');
const [sdiPort, setSdiPort] = React.useState(1);
const [sdiDevices, setSdiDevices] = React.useState(null);
const [recTab, setRecTab] = React.useState('video');
const [proxyTab, setProxyTab] = React.useState('video');
const [proxyOn, setProxyOn] = React.useState(true);
const [projectId, setProjectId] = React.useState(PROJECTS[0]?.id || '');
const [submitting, setSubmitting] = React.useState(false);
const [submitErr, setSubmitErr] = React.useState(null);
React.useEffect(() => {
if (sourceType !== 'SDI' || sdiDevices !== null) return;
window.ZAMPP_API.fetch('/cluster/devices/blackmagic')
.then(d => setSdiDevices(Array.isArray(d) ? d : []))
.catch(() => setSdiDevices([]));
}, [sourceType]);
const handleCreate = () => {
if (!name.trim()) { setSubmitErr('Recorder name is required.'); return; }
setSubmitting(true);
setSubmitErr(null);
const body = {
name: name.trim(),
source_type: sourceType.toLowerCase(),
source_config: sourceType === 'SRT' ? { url: srtUrl }
: sourceType === 'RTMP' ? { url: rtmpUrl }
: { port: sdiPort },
project_id: projectId || undefined,
generate_proxy: proxyOn,
};
window.ZAMPP_API.fetch('/recorders', { method: 'POST', body: JSON.stringify(body) })
.then(() => { setSubmitting(false); onClose(); })
.catch(e => { setSubmitting(false); setSubmitErr(e.message || 'Failed to create recorder'); });
};
if (!open) return null;
return (
e.stopPropagation()}>
New recorder
Configure source, codec, and destination
setName(e.target.value)} />
{[
{ id: 'SRT', label: 'SRT', desc: 'Secure Reliable Transport — pull caller', icon: 'signal' },
{ id: 'RTMP', label: 'RTMP', desc: 'Real-Time Messaging Protocol', icon: 'globe' },
{ id: 'SDI', label: 'SDI', desc: 'Blackmagic DeckLink hardware', icon: 'video' },
].map(t => (
))}
{sourceType === 'SRT' && (
)}
{sourceType === 'RTMP' && (
)}
{sourceType === 'SDI' && (
{sdiDevices === null && (
Loading DeckLink devices…
)}
{sdiDevices !== null && sdiDevices.length === 0 && (
No DeckLink devices found in cluster. Ensure the capture node is online.
)}
{sdiDevices !== null && sdiDevices.length > 0 && (
{sdiDevices.map((dev, di) => (
{(dev.model || dev.device || 'DECKLINK').toUpperCase()} · {dev.hostname}
{(dev.ports || Array.from({ length: dev.port_count || 2 }, (_, i) => ({ idx: i + 1, label: 'SDI ' + (i + 1) }))).map(p => (
))}
))}
)}
)}
Master recording
{['video', 'audio', 'container'].map(t => (
))}
{recTab === 'video' && (
)}
{recTab === 'audio' && (
)}
{recTab === 'container' && (
)}
{proxyOn && (
Proxy
{['video', 'audio', 'container'].map(t => (
))}
{proxyTab === 'video' && (
)}
{proxyTab === 'audio' && (
)}
{proxyTab === 'container' && (
)}
)}
Destination
{submitErr && (
{submitErr}
)}
);
}
window.NewRecorderModal = NewRecorderModal;