Merge: library recording thumbnails live preview
This commit is contained in:
commit
4d1b23959c
1 changed files with 41 additions and 21 deletions
|
|
@ -491,13 +491,6 @@ function HlsPreview({ assetId, recorderId, muted = true, controls = false, class
|
|||
|
||||
/* ===== Recorders ===== */
|
||||
function _normRecorder(r) {
|
||||
let elapsed = '·';
|
||||
if (r.status === 'recording' && r.started_at) {
|
||||
const s = Math.floor((Date.now() - new Date(r.started_at)) / 1000);
|
||||
elapsed = String(Math.floor(s / 3600)).padStart(2, '0') + ':' +
|
||||
String(Math.floor((s % 3600) / 60)).padStart(2, '00') + ':' +
|
||||
String(s % 60).padStart(2, '0');
|
||||
}
|
||||
const cfg = r.source_config || {};
|
||||
return {
|
||||
...r,
|
||||
|
|
@ -505,8 +498,9 @@ function _normRecorder(r) {
|
|||
url: cfg.url || cfg.address || cfg.srt_url || cfg.rtmp_url || r.source_type || '·',
|
||||
codec: r.recording_codec || '·',
|
||||
res: r.recording_resolution || '·',
|
||||
framerate: r.recording_framerate || 'native',
|
||||
node: r.node_id ? r.node_id.slice(0, 8) : 'primary',
|
||||
elapsed,
|
||||
elapsed: '·',
|
||||
bitrate: '·',
|
||||
health: 100,
|
||||
audio: false,
|
||||
|
|
@ -610,15 +604,43 @@ function RecorderRow({ recorder: initialRecorder, onRefresh }) {
|
|||
return () => clearInterval(id);
|
||||
}, [isRec, recorder.id]);
|
||||
|
||||
// Tick elapsed every second while recording. Seed from liveStatus.duration
|
||||
// (authoritative from the capture container) when available; fall back to
|
||||
// wall-clock diff from recorder.started_at so the counter never freezes.
|
||||
const [elapsedSecs, setElapsedSecs] = React.useState(0);
|
||||
React.useEffect(() => {
|
||||
if (!isRec) { setElapsedSecs(0); return; }
|
||||
const base = () => {
|
||||
if (liveStatus && liveStatus.duration != null) return liveStatus.duration;
|
||||
if (recorder.started_at) return Math.floor((Date.now() - new Date(recorder.started_at).getTime()) / 1000);
|
||||
return 0;
|
||||
};
|
||||
// Snap to latest authoritative value immediately, then tick from there.
|
||||
const anchor = { at: Date.now(), secs: base() };
|
||||
setElapsedSecs(anchor.secs);
|
||||
const id = setInterval(() => {
|
||||
setElapsedSecs(anchor.secs + Math.floor((Date.now() - anchor.at) / 1000));
|
||||
}, 1000);
|
||||
return () => clearInterval(id);
|
||||
// Re-anchor whenever liveStatus.duration arrives from the poll.
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [isRec, liveStatus && liveStatus.duration, recorder.started_at]);
|
||||
|
||||
const displayElapsed = React.useMemo(() => {
|
||||
if (liveStatus && liveStatus.duration != null) {
|
||||
const d = Math.max(0, liveStatus.duration);
|
||||
return String(Math.floor(d / 3600)).padStart(2, '0') + ':' +
|
||||
String(Math.floor((d % 3600) / 60)).padStart(2, '0') + ':' +
|
||||
String(d % 60).padStart(2, '0');
|
||||
if (!isRec) return '·';
|
||||
const d = Math.max(0, elapsedSecs);
|
||||
return String(Math.floor(d / 3600)).padStart(2, '0') + ':' +
|
||||
String(Math.floor((d % 3600) / 60)).padStart(2, '0') + ':' +
|
||||
String(d % 60).padStart(2, '0');
|
||||
}, [isRec, elapsedSecs]);
|
||||
|
||||
// Show live fps when recording and signal is healthy; fall back to configured value.
|
||||
const displayFramerate = React.useMemo(() => {
|
||||
if (isRec && liveStatus && liveStatus.currentFps != null && liveStatus.currentFps > 0) {
|
||||
return Number(liveStatus.currentFps).toFixed(2) + ' fps';
|
||||
}
|
||||
return recorder.elapsed;
|
||||
}, [liveStatus, recorder.elapsed]);
|
||||
return recorder.framerate || 'native';
|
||||
}, [isRec, liveStatus, recorder.framerate]);
|
||||
|
||||
const displaySignal = liveStatus
|
||||
? (liveStatus.signal || '·')
|
||||
|
|
@ -709,12 +731,10 @@ function RecorderRow({ recorder: initialRecorder, onRefresh }) {
|
|||
{displaySignal}
|
||||
</div>
|
||||
</div>
|
||||
{liveStatus?.currentFps != null && (
|
||||
<div className="recorder-stat">
|
||||
<div className="stat-label">FPS</div>
|
||||
<div className="stat-val mono">{Number(liveStatus.currentFps).toFixed(1)}</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="recorder-stat">
|
||||
<div className="stat-label">Framerate</div>
|
||||
<div className="stat-val mono">{displayFramerate}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="recorder-actions">
|
||||
{!isRec && (
|
||||
|
|
|
|||
Loading…
Reference in a new issue