Recorder model was creating capture containers but ffmpeg never spawned
inside them, so SRT/RTMP listeners bound the host port without ingesting
anything. Thumbnail extraction was also crashing on yuv444p sources,
leaving uploaded assets stuck at status=processing forever.
* capture/src/index.js: read RECORDER_ID/SOURCE_TYPE/LISTEN/LISTEN_PORT/
STREAM_KEY/SOURCE_URL from env on startup and call captureManager.start()
immediately. SIGTERM handler now flushes ffmpeg + S3 upload and POSTs the
asset to mam-api before exiting.
* worker/ffmpeg/executor.js: force -pix_fmt yuv420p on proxy transcode and
-pix_fmt yuvj420p on thumbnail extraction so mjpeg encoder accepts the
input regardless of source pixel format.
* mam-api/routes/assets.js: when capture posts proxyKey=null but hiresKey
is set (SRT/RTMP case), enqueue a proxy job from the hires so the asset
ends up with a browser-playable proxy + thumbnail instead of stuck-ready.
* mam-api/routes/recorders.js: accept UI field aliases (codec/resolution/
proxy_config), clean up unstarted containers on port collision, bump the
docker stop timeout to 5min so long uploads can flush.
* web-ui/recorders.html: change default ports from 1935/9000 to 41936/49001
to avoid common collisions with other RTMP/SRT services.
api.js sends parts as { partNumber, ETag } (uppercase) but upload.js
was reading p.etag (lowercase), resulting in undefined ETag passed to
S3 CompleteMultipartUpload → InvalidPart error on all large file uploads.
Also handle both casings defensively.
GET /api/v1/jobs now queries the proxy, thumbnail, and conform BullMQ
queues directly and returns normalized job objects with id, type,
status, progress, asset_id, timestamps, and error fields.
Also adds DELETE /:id to remove completed/failed jobs from the queue,
supporting the clearCompleted action in jobs.html.
The PostgreSQL jobs table is still used only for conform job creation
(POST /conform) to preserve that workflow.
nginx resolves upstream hostnames at config load time, which fails when
sibling containers haven't registered with the Docker DNS yet. Using
resolver 127.0.0.11 with set $upstream defers resolution to request
time, preventing the "host not found in upstream" startup crash.
pool.js was using DB_HOST/DB_USER/etc which were never set.
The docker-compose.yml passes DATABASE_URL. Parse that if present,
fall back to individual vars for local dev.
All host ports are now configurable via .env variables with sensible
defaults. This prevents collisions when deploying alongside existing
services on TrueNAS or any other host.
- Accept source_type, source_url, listen, listen_port, stream_key
- Validate: SDI requires device; SRT/RTMP caller requires source_url
- Pass all params through to captureManager.start()
- On stop: if proxyKey is null (network source), include needsProxy flag
in MAM API registration so worker can generate proxy asynchronously