Dragonflight - self-hosted broadcast media asset management. SRT/RTMP/SDI ingest via Blackmagic DeckLink, FFmpeg proxy generation, growing-file editing via SMB + Premiere Pro CEP panel, BullMQ job queue, S3-compatible storage (RustFS). Replaces Grass Valley AMPP FramelightX.
Right-click any event block to open a context menu (Edit, Cancel,
Copy schedule ID, Delete) — actions per status mirror the List view so
the two surfaces stay in lockstep. Menu is viewport-clamped and
dismisses on outside click / scroll, same pattern as the asset menu in
the Library.
Drag-to-resize works for pending schedules only (the schedules PUT
rejects edits to running rows, and terminal statuses are read-only):
- Drag the left edge to move the start time
- Drag the right edge to move the end time
- Drag the body to shift the whole block in time
All gestures snap to 15-minute increments to match the new-schedule
click snap. Minimum duration is clamped to 5 minutes; the block clamps
to the visible day on both edges. While dragging the title shows the
preview range ("Start time → end time") and the block lifts with a
project-tinted shadow.
A short pointer click (< 4px travel) still opens the edit modal — the
click and drag share the same pointerdown so the operator never has
to know which gesture they made first.
Implementation: replaces the <button> block with a <div> hosting three
zones (left handle / body / right handle). Pointer events with
setPointerCapture so drags survive losing the cursor over the block,
and pointerup demotes back to click if travel was below threshold.
Optimistic local update on resize, PUT /schedules/:id with just the
two changed time fields, refetch to reconcile.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| deploy | ||
| docs | ||
| services | ||
| .env.example | ||
| .gitignore | ||
| DESIGN.md | ||
| docker-compose.gpu.yml | ||
| docker-compose.worker.yml | ||
| docker-compose.yml | ||
| PRODUCT.md | ||
| README.md | ||
| setup-repo.sh | ||
Dragonflight
Self-hosted broadcast media-asset management. Replaces Grass Valley AMPP FramelightX. SDI / SRT / RTMP ingest, growing-file editing via Premiere Pro, S3-compatible storage, scheduling, and a queue-driven proxy pipeline.
Repo renamed from
wild-dragon→dragonflight(2026-05-23). The old URL still redirects.
Features
- Ingest — SRT (caller + listener), RTMP, and SDI capture via Blackmagic DeckLink cards (FFmpeg patched against SDK 16.x); per-recorder codec settings (ProRes / H.264 / DNxHR / HEVC) and audio routing
- Growing-file editing — capture writes the hi-res master to a local SMB landing zone; editors can mount the share in Premiere Pro and edit the live file via the included CEP panel, then relink to the final S3 master after promotion
- Recorder scheduler — one-shot, daily, or weekly windows; a 15s tick loop fires the existing /recorders/:id/start + /stop endpoints
- Library — projects, bins, asset detail with frame-anchored persistent comments, right-click context menu (move-to-bin, rename, delete), and a global cmd/ctrl-K search across assets / projects / recorders / jobs / users
- Jobs — BullMQ-backed proxy + thumbnail queue with per-job retry, bulk "retry all failed", and inline error messages
- Settings — S3 (with env-var fallback), global proxy encoder (CPU/libx264 or GPU/NVENC/VAAPI), growing-files config, capture SDK uploader (Blackmagic / AJA / Deltacast)
- Cluster — primary + worker topology with heartbeat health, remote node-agent for off-host DeckLink capture
- API —
deploy/api-smoke.shexercises every endpoint (27 routes, pass/fail summary)
Services
| Service | Port | Description |
|---|---|---|
| web-ui | 47434 | Browser SPA + capture controls |
| mam-api | 47432 | REST API + recorder orchestration + scheduler tick |
| capture | 47433 / 9000 / 1935 | DeckLink/SRT/RTMP capture sidecar |
| worker | — | BullMQ proxy + thumbnail workers |
| db | 5432 | PostgreSQL 16 |
| queue | 6379 | Redis 7 |
Quick start
# Clone (repo renamed; old URL still redirects)
git clone https://forge.wilddragon.net/zgaetano/dragonflight.git
cd dragonflight
# Configure
cp .env.example .env
# Edit .env — S3 credentials + SESSION_SECRET at minimum
# Launch
docker compose up -d
# Open
open http://localhost:47434
Architecture
SDI / SRT / RTMP ──► capture (FFmpeg)
├─ HLS preview tee ──► /live/<assetId>/index.m3u8
└─ master output
├─ growing_enabled=true:
│ /growing/<projectId>/<clip>.mov
│ (Premiere mounts SMB, edits live)
│ └─► promotion worker uploads to S3
│
└─ growing_enabled=false:
multipart stream → S3
assets POST ──► proxy job ──► worker
├─ libx264 (CPU) or NVENC/VAAPI (GPU)
├─ thumbnail job
└─ status: ingesting → processing → ready
Tech stack
- Runtime: Node.js 22, Docker Compose
- Backend: Express, PostgreSQL 16, Redis 7 + BullMQ
- Frontend: Vanilla React via in-browser Babel (no bundler), hls.js
- Media: FFmpeg 7.1 with SDK 16 DeckLink patches; ProRes, H.264, HEVC, DNxHR, MOV/MP4/MXF containers
- Storage: S3-compatible (RustFS) for masters + proxies + thumbnails
Operations
deploy/api-smoke.sh— verify every API endpoint after a deploydeploy/onboard-node.sh— provision a remote worker host (DeckLink cards on a separate machine)deploy/test-cluster.sh— primary↔worker connectivity smokedocs/GROWING_FILES_QUICKSTART.md— Premiere CEP panel install + growing-file capture flow
License
Proprietary — Wild Dragon LLC, all rights reserved.