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.
Find a file
Zac ac1878452f fix: library + caller-only recorders + live signal indicator
Three problems blocked the end-to-end flow:

1) Library always rendered empty because /assets returns {assets,total} but
   index.html (and capture.html) assumed r.data was an array. Fixed in
   api.js by unwrapping r.data.assets centrally; total is kept on r.total.

2) SRT/RTMP caller mode pulled audio only. ffmpeg opened the network input
   before the H264 SPS arrived, marked the video stream as pix_fmt=none,
   and silently dropped it from the stream map. Added -probesize 32M
   -analyzeduration 10M -fflags +genpts and explicit -map 0✌️0?/0🅰️0? so
   each track survives independently of when it appears.

3) Hitting Record gave no feedback about whether a stream was actually
   arriving. capture-manager now parses ffmpeg progress lines (frame=...
   fps=...) and tracks framesReceived, currentFps, lastFrameAt, lastError.
   getStatus() returns a derived signal enum (connecting | receiving |
   lost | error | stopped). The recorder controller gives each spawned
   container a stable network alias `recorder-<id>` and the GET
   /recorders/:id/status endpoint proxies the live capture status through.
   recorders.html polls that every 2s and renders the badge under each
   active card with the running frame/fps counter or the ffmpeg error.

Also:
* recorders.html: dropped the listener-mode UI entirely. All new recorders
  are caller-mode (pull). The MAM is no longer offered as an RTMP/SRT
  server. Legacy listener records still render but read-only.
2026-05-17 07:39:58 -04:00
services fix: library + caller-only recorders + live signal indicator 2026-05-17 07:39:58 -04:00
.env.example fix(infra+workers): S3 creds, ffprobe, BullMQ awaits, thumbnail seek, bin optional, docker-compose vars, jobs Redis, recorders stop codes: .env.example 2026-05-16 00:29:45 -04:00
.gitignore add .gitignore 2026-04-07 21:58:17 -04:00
docker-compose.yml chore: use env-var port bindings — no hardcoded host ports 2026-05-16 08:27:25 -04:00
README.md add README.md 2026-04-07 21:58:16 -04:00
setup-repo.sh add setup-repo.sh 2026-04-07 21:58:16 -04:00

Wild Dragon

Self-hosted Media Asset Management platform built to replace Grass Valley AMPP FramelightX.

Services

Service Port Description
web-ui 8080 Browser-based MAM interface + capture controls
mam-api 3000 REST API — assets, projects, bins, jobs
capture 3001 SDI capture daemon (Blackmagic DeckLink + FFmpeg)
worker Async job processor (proxy gen, thumbnails, conform)
db 5432 PostgreSQL 16 metadata store
queue 6379 Redis 7 job queue (BullMQ)

Quick Start

# Clone
git clone https://forge.wilddragon.net/zgaetano/wild-dragon.git
cd wild-dragon

# Configure
cp .env.example .env
# Edit .env with your S3 credentials and secrets

# Launch
docker compose up -d

# Open
open http://localhost:8080

Architecture

SDI Input (DeckLink) → capture service → dual FFmpeg streams
                                          ├─ HiRes (ProRes) → S3
                                          └─ Proxy (H.264)  → S3
                                                                ↓
                        web-ui ← mam-api ← PostgreSQL ← worker (BullMQ)
                                                          ├─ proxy_gen
                                                          ├─ thumbnail
                                                          └─ conform (EDL → FFmpeg → export)

Tech Stack

  • Backend: Node.js / Express
  • Frontend: Vanilla HTML/CSS/JS
  • Database: PostgreSQL 16
  • Queue: Redis 7 + BullMQ
  • Storage: S3-compatible (RustFS)
  • Media Processing: FFmpeg
  • Capture: Blackmagic DeckLink SDK
  • Deployment: Docker Compose

License

MIT