Commit graph

910 commits

Author SHA1 Message Date
463cc3694d feat(web-ui): nested bins tree, DragonFlame logo, recorder modal 2x2 grid, cleanup .bak
- Library: nested bins with expand/collapse tree in sidebar
  - buildBinTree() + collectDescendantIds() helpers
  - BinTreeNodes recursive component with hover sub-bin create (+) button
  - Selecting a parent bin shows assets from all descendant bins too
- Home: canvas DragonFlame particle animation behind logo (90 flame + 30 spark), logo 140px
- Recorder modal: source-type-grid 3-col → 2x2 so Deltacast card no longer overflows
- CSS: launcher background radial gradient taller; launcher-logo-wrap 160x200px
- Cleanup: remove capture.js.bak: screens-home.jsx
2026-06-02 23:33:58 -04:00
bd662f6917 fix(migration): wrap ALTER TYPE ADD VALUE in DO block with IF NOT EXISTS check 2026-06-03 00:41:04 +00:00
a04ef2de3a feat(promotion): implement manual growing files promotion via BullMQ queue + pending_migration status + right click Move to S3 2026-06-03 00:38:50 +00:00
62b9a90291 fix(recorders): stop capture containers in the background to prevent API TimeoutError on large file uploads 2026-06-03 00:22:36 +00:00
600af4564e fix: restore screens-library.jsx and visuals.jsx to clean state + add deriveGrowingRaster scanHint fix 2026-06-03 00:19:55 +00:00
d8df8755e2 fix: main.c migrate-to-library + deltacast audit cleanup 2026-06-02 19:01:31 -04:00
5525041901 feat/fix: visuals.jsx — growing migrate flow + deltacast cleanup 2026-06-02 18:40:16 -04:00
29238a339e feat/fix: screens-library.jsx — growing migrate flow + deltacast cleanup 2026-06-02 18:39:10 -04:00
9ae619357b feat/fix: proxy.js — growing migrate flow + deltacast cleanup 2026-06-02 18:39:08 -04:00
1f342826bd feat/fix: promotion.js — growing migrate flow + deltacast cleanup 2026-06-02 18:38:56 -04:00
167d9ad009 feat/fix: filmstrip.js — growing migrate flow + deltacast cleanup 2026-06-02 18:38:24 -04:00
b0f504ca69 feat/fix: thumbnail.js — growing migrate flow + deltacast cleanup 2026-06-02 18:38:21 -04:00
a8b59f087d fix(recorders): pre-create live asset with .mxf key when growing_enabled (was .mov, broke proxy lookup -> error) 2026-06-02 22:10:30 +00:00
228f68ab6d fix(audio): use_wallclock_as_timestamps on both raw FIFOs to align A/V by arrival time (no deadlock, replaces barrier) 2026-06-02 22:02:32 +00:00
d0d881c735 Revert "fix(audio): per-port A/V start barrier so video+audio FIFOs begin at the same instant (fixes fixed A/V offset)"
This reverts commit bebfe7a43d.
2026-06-02 22:01:51 +00:00
bebfe7a43d fix(audio): per-port A/V start barrier so video+audio FIFOs begin at the same instant (fixes fixed A/V offset) 2026-06-02 21:59:34 +00:00
20d913fbad fix(audio): hardware-paced audio (no wall-clock silence mixing) + aresample=async to lock A/V sync 2026-06-02 21:50:11 +00:00
3eacb35c1e fix(capture): replace continuous idle preview with 1fps JPEG snapshot to stop FIFO contention halving capture fps 2026-06-02 21:40:52 +00:00
de3e09f39e fix: restore correct capture files after merge 2026-06-02 21:31:46 +00:00
52f039554c merge: keep correct local capture files, reject placeholder uploads 2026-06-02 21:31:29 +00:00
ec1699907d fix(deltacast): non-blocking write + 64MB FIFO + GPU runtime for capture container 2026-06-02 21:31:06 +00:00
1cef8c3bb3 fix(deltacast-bridge): non-blocking write_all + larger FIFO (64MB) to prevent frame drops 2026-06-02 17:06:40 -04:00
82697d92de fix(deltacast-bridge): restore BUFFER_PACKING YUV422_8 fix that was lost during git checkout 2026-06-02 16:59:23 -04:00
87fd3164c6 Fix: restore all deltacast-bridge fixes (buffer packing YUV422_8, SDI interface, F_SETPIPE_SZ, deinterlacing bypass) 2026-06-02 16:43:45 -04:00
0aa010dacc fix(deltacast-bridge): restore BUFFER_PACKING YUV422_8 + SDI interface + F_SETPIPE_SZ fixes 2026-06-02 16:42:45 -04:00
9ac27ff194 fix(capture): deinterlacing bypass for progressive signals + fps calculation fix 2026-06-02 16:24:45 -04:00
13feb0a6a2 fix(uxp): promisify fs calls for UXP compatibility (v2.2.3)
fs.writeFile/fs.readFile/fs.stat are callback-based and don't return
Promises in the UXP sandbox. await on them resolves immediately, causing
race conditions where files aren't written before import.

Added _writeFile/_readFile/_stat wrappers that use fs.promises when
available and fall back to manual Promise wrapping otherwise.

Also bumped version to 2.2.3 to match web-ui data.jsx.
2026-06-02 20:17:00 +00:00
702187c1dc revert: restore orange accent + original home layout
- Revert accent from Flame Blue #1025A1 to electric amber #E8821C
- Restore all rgba accent values to orange spectrum
- Revert avatar to bg-3 background + accent text (was blue bg + white)
- Revert primary button text to dark #0a0c10 (was white on blue)
- Restore centered hero with logo pulse + 'Let's Create' kicker
- Restore single-grid tile layout (all tiles in one launcher-grid)
- Restore settings as separate centered row below main grid
- Restore centered footer + large wordmark with amber glow

Co-Authored-By: OWL <noreply@anthropic.com>
2026-06-02 19:31:30 +00:00
1ff0f2d865 fix(capture-manager): apply deinterlacing bypass + fps calculated from frames/elapsed 2026-06-02 15:14:40 -04:00
bdebc3adac fix(capture-manager): calculate currentFps from frames/elapsed instead of ffmpeg running average 2026-06-02 14:46:09 -04:00
a200cabad4 fix(deltacast-bridge): pin buffer packing + sdi interface + f_setpipe_sz 2026-06-02 14:21:44 -04:00
3ac685ed3b fix(deltacast-bridge): pin BUFFER_PACKING to YUV422_8; guard frame size
Relying on the SDK default for VHD_CORE_SP_BUFFER_PACKING caused the board
to deliver raw slot buffers whose byte size did not match the width*height*2
contract declared to ffmpeg (pix_fmt=uyvy422). ffmpeg consumed frames at the
wrong stride, causing every frame to shift progressively, rolling and
shearing the picture ("bounces and bends").

Fix: explicitly set VHD_BUFPACK_VIDEO_YUV422_8 on the video stream before
StartStream so the board always delivers tightly-packed 8-bit UYVY.

Safety net: video thread now asserts sz==width*height*2 and skips+warns on
any mismatch so a future packing divergence is immediately visible in logs
rather than silently corrupting video.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 17:00:07 +00:00
Claude
22853da023 fix(capture): authenticate sidecar->mam-api calls with bearer token
The live-thumbnail and manual /start,/stop sidecar->mam-api calls hit the CSRF
guard (403 missing X-Requested-With). Match the working pattern in index.js:
send Authorization: Bearer $MAM_API_TOKEN (= CAPTURE_TOKEN, injected by
recorders.js), which is CSRF-exempt. Falls back to the UI header only when no
token is set (dev). Fixes [livethumb] failed ... 403 — posters now persist.

🤖 Generated with Claude Code
2026-06-02 16:00:13 +00:00
Claude
b40f640fa1 build(capture): add .dockerignore to keep stale bridge build/ out of image context
A native deltacast-bridge build leaves services/capture/deltacast-bridge/build/
with a CMakeCache.txt pinned to the host path. When copied into the Docker
build context it conflicts with the in-image cmake step and fails the capture
image build. Exclude build artifacts from the context.

🤖 Generated with Claude Code
2026-06-02 15:23:03 +00:00
Claude
a2790601c9 feat(library): first-frame poster thumbnail for live recordings
Replace the HLS 'connecting…' player in the library with a real frame grabbed
from the start of the recording, while the recording is still live.

Flow:
- recorders.js already pre-creates the asset as status='live' + ASSET_ID env
- capture-manager.start() fires _publishLiveThumbnail() (non-blocking): polls
  /live/<id> for the first seg-*.ts, extracts frame 0 via ffmpeg (scaled JPEG,
  yuvj420p), uploads to S3 thumbnails/<id>.jpg, then POSTs the key to mam-api
- new mam-api POST /assets/:id/live-thumbnail sets thumbnail_s3_key on the still
  -live row (status untouched); idempotent no-op once finalized
- visuals.jsx AssetThumb: for live assets, show the static poster once the key /
  signed URL is available, else fall back to the live HLS preview. Pulsing LIVE
  border kept either way
- POST /assets gains an optional status param (default 'processing'); 'live'
  skips the proxy/thumbnail queue
- capture /stop route now finalizes the pre-created asset by id (guarded) instead
  of POSTing a duplicate

🤖 Generated with Claude Code
2026-06-02 15:21:05 +00:00
Claude
f8eda7fc37 Merge design/overhaul-tasteskill: Flame Blue accent, home recomposition, motion layer
UI overhaul:
- Flame Blue (#1025A1) accent — official Wild Dragon brand standard
- Home: compact left-aligned header, primary ops + secondary 4-col rows
- Typography: hyphen fixes, sidebar version removed, topbar 48px
- Motion: staggered tile entry, button scale press, nav transitions
- Jobs stats: semantic card variants (active/failed/total)

🤖 Generated with Claude Code
2026-06-02 13:28:54 +00:00
4062be101d design: swap accent to Flame Blue #1025A1 (Wild Dragon brand standard)
Replace the electric amber placeholder with the official brand accent from
the Wild Dragon Forge Noir Edition identity guide (Pantone 286 C).

- --accent: #1025A1 (Flame Blue)
- --accent-hover: #1830B8 (Ember-adjacent)
- --accent-text: #C7CFEA (Halo — readable on dark surfaces, 13:1 contrast)
- Primary button text reverts to white (11.7:1 contrast on Flame Blue)
- Avatar uses Flame Blue background + white initials
- All rgba hardcodes updated to match new hue across CSS and JSX

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-02 08:56:29 -04:00
e54b8403e7 design: overhaul pass — amber accent, home recomposition, motion layer
Lever 1 (color): Replace #5B7CFA AI-blue with electric amber #E8821C across
all accent tokens, tile tones, logo glows, and hardcoded rgba values. Dark
text on amber primary buttons for WCAG AA contrast.

Lever 2 (home): Collapse centered logo hero into compact left-aligned header.
Split tile grid into primary ops row (Library, Recorders, Playout) + secondary
4-col row (Downloads, Jobs, Dashboard, Settings) with reduced visual weight.

Lever 3 (typography): Remove v1.2.0 from sidebar. Fix em-dashes to hyphens or
periods across all visible UI strings (option labels, body copy, error messages).
Topbar height 56px -> 48px.

Lever 4 (motion): Staggered entry animation for launcher tiles
(prefers-reduced-motion gated). Tactile scale(0.97) on primary/record buttons.
Smooth 150ms nav active-item transitions.

Lever 5 (blocks): Jobs stats row semantic card variants (amber glow when
active, red border when failed, quiet muted style for Total).

Lever 6 (spacing): Topbar 48px, launcher inner gap tightened, status left-aligned.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-06-02 08:20:15 -04:00
Claude
f218650b85 fix(scheduler): mark orphaned live assets error immediately when recorder stops
When a capture sidecar crashes before finalize() runs (e.g. wrong node,
filter error, hardware fault), the asset stays 'live' indefinitely — library
shows 'Recording' badge for up to 120 minutes until the stale-timeout fires.

Add an orphan check that runs every scheduler tick: if an asset is 'live'
and its recorder is 'stopped', mark it 'error' immediately. This runs before
the 120-minute staleness guard so the library clears within 15 seconds.

🤖 Generated with Claude Code
2026-06-02 11:43:22 +00:00
Claude
08be8fea77 fix(deltacast-bridge): video EPIPE reopens FIFO instead of stopping port permanently
When a capture sidecar stopped/restarted, the bridge video thread got EPIPE
on the FIFO write, set g_port_stop[port]=1, and the port went dead — requiring
a full bridge restart to recover. Subsequent record attempts on that port would
hang in 'connecting' forever.

Fix: mirror the audio thread pattern — on EPIPE, close the FIFO and loop back
to open() blocking for the next reader. Hardware lock errors (SDK failures)
still stop the port via g_port_stop as before. Only reader-disconnect (EPIPE)
now recovers gracefully.

This was the cause of port 6 (Ghost) failure in the burn test.

🤖 Generated with Claude Code
2026-06-02 11:33:17 +00:00
Claude
858c9f7b97 fix(deltacast-bridge): call VHD_SetBiDirCfg before board open + set channel SDI mode
ROOT CAUSE of 'connecting' hangs and intermittent port failures:
The DELTA-12G-e-h 8c is a bidirectional card. Without calling
VHD_SetBiDirCfg(board_index, VHD_BIDIR_80) before streaming, the
board remains in its default bi-dir config (likely 4RX/4TX) — so
RX stream opens fail with VHDERR_RESOURCEUNAVAILABLE on channels
configured as TX, causing random 'connecting' hangs per the SDK docs.

Per SDK Tools.cpp SetNbChannels() pattern:
1. Open temporary board handle
2. Check IS_BIDIR + channel counts
3. Call VHD_SetBiDirCfg(board_index, VHD_BIDIR_80) for 8ch bidir
4. Close temp handle, then open real board handle for streaming

Also add VHD_SetChannelProperty(VHD_CHANNEL_MODE_SDI) for ASI-type
channels per Sample_RX.cpp — required for 12G-ASI/3G-ASI channel
types to correctly detect incoming video standard.

🤖 Generated with Claude Code
2026-06-02 11:23:39 +00:00
Claude
59294856a2 feat(library): remove Audio tab (revisit later)
🤖 Generated with Claude Code
2026-06-02 11:18:30 +00:00
Claude
d509876444 feat(monitors): always-on tiles with last-frame freeze, elapsed timer, port badge
- MonitorTile now persists lastAssetId in local state so tiles continue
  showing content after a recording stops (frozen HLS, then thumbnail)
- When recording stops: HlsPreview stays alive briefly while segments are
  hot, then fetches /api/v1/assets/{id}/thumbnail for a frozen still
- Idle tiles that never recorded show FauxFrame with IDLE badge as before
- Per-tile elapsed timer ticks every second using feed.started_at
- capturePort badge (Port N / SDI N) visible on each tile
- Monitors poll interval tightened from 5s -> 3s for faster live_asset_id pickup

🤖 Generated with Claude Code
2026-06-02 11:15:21 +00:00
Claude
e97a289722 fix(node-agent): handle bridge spawn ENOENT + add pid:host for process detection
Two bugs causing deltacast recorder 500s:

1. startDeltacastBridge() had no proc.on('error') handler — ENOENT when
   deltacast-bridge binary not in container PATH crashed the entire node-agent
   process (unhandled error event). Added error handler that logs and clears
   _dcBridge so the sidecar start continues.

2. node-agent container lacked pid:host — _dcBridgeProcessAlive() scans /proc
   but without host PID namespace it only sees container PIDs, so it always
   returned false and tried to re-spawn the bridge (hitting bug 1).
   pid:host lets the /proc scan see the host's deltacast-bridge systemd process.

🤖 Generated with Claude Code
2026-06-02 10:48:09 +00:00
Claude
6895fbc5af feat(ingest): show capture port on recorder cards + growing indicator on schedule blocks
- Recorder cards now display a Port chip showing the bridge port (deltacast)
  or SDI device index (blackmagic) so operators can see at a glance which
  physical input each recorder is bound to.

- Schedule blocks render with a green accent + flame glyph when the backing
  recorder has growing_enabled=true, so the EPG view distinguishes
  edit-while-record slots from regular close-then-publish recordings.

🤖 Generated with Claude Code
2026-06-02 04:09:17 +00:00
Zac
8a675992c2 fix(deltacast-bridge): configure both stereo channels + INTERFACE for audio extraction (SDK Sample_RXAudio) 2026-06-02 02:01:33 +00:00
Zac Gaetano
4d1b23959c Merge: library recording thumbnails live preview 2026-06-02 01:36:00 +00:00
Zac Gaetano
d1d3033ed5 Merge: recorder card live framerate + elapsed timer 2026-06-02 01:36:00 +00:00
Zac
46dc17ffb1 fix(web-ui): show live HLS preview for recording assets in library
Live/in-progress assets had no thumbnail_s3_key, so AssetThumb fell
through to FauxFrame (black box) and then an absolute red border div
was drawn on top, producing the 'black box with red outline' symptom.

Fix: when asset.status === 'live', render a new LiveThumb component
instead of FauxFrame + border overlay. LiveThumb attaches hls.js (or
native HLS on Safari) to /live/<assetId>/index.m3u8, shows a muted
live video feed, and displays a 'Connecting…' placeholder with a
record icon + live-colour border while the manifest loads. Falls back
to a 'Recording…' placeholder if hls.js is unavailable or playback
fails after retries.

The red border overlay is removed from the non-live path; the LIVE
badge rendered by AssetCard's thumb-status div still appears on top
of the live video.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 01:35:27 +00:00
Claude
c083d1006a fix: deltacast audio missing after ffmpeg restart (EPIPE cascade + stale FIFO guard)
Root cause A (main.c): audio_thread set the global g_stop flag on EPIPE
(ffmpeg reader died). This killed ALL port threads across the entire bridge
process. Bridge process then exited with all 8 ports gone.

Root cause B (node-agent/index.js): startDeltacastBridge() skipped respawn
when FIFOs existed in /dev/shm/deltacast, even if the bridge process was dead.
Next ffmpeg opened the audio FIFO read-end and blocked forever (no writer) →
no audio (or video) for any new recording.

Fix A (main.c):
- Add per-port atomic g_port_stop[MAX_PORTS] flags.
- Audio thread: on EPIPE, close the FIFO fd and loop back to reopen it.
  The VHD ANC stream stays open across reconnects. Other ports unaffected.
- Video thread: on EPIPE or stream error, set only g_port_stop[port], not
  the global g_stop. Other ports keep running.
- MAX_PORTS #define moved before globals so g_port_stop[MAX_PORTS] compiles.

Fix B (node-agent/index.js):
- Add _dcBridgeProcessAlive() — scans /proc/<pid>/cmdline for deltacast-bridge.
- startDeltacastBridge(): if FIFOs exist but no live bridge process is found,
  spawn a fresh bridge instead of silently returning. Detects bridges started
  externally (e.g. sudo on the host before node-agent started).

Requires: bridge rebuild + restart on zampp3. No capture image rebuild needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 01:35:07 +00:00