Trash icon in the library was firing PATCH /assets/:id with {status:"deleted"}. The PATCH route only accepts display_name/tags/notes so it returned "No fields to update" and the asset stayed put.
* api.js: add deleteAsset(id, {hard}) helper hitting the real DELETE route.
* index.html: deleteAssetPrompt now calls deleteAsset (soft archive). Confirm dialog reworded to match.
* mam-api/routes/assets.js: list endpoint hides status=archived by default. Pass ?include_archived=true to see them in a future restore-from-trash view. Filtering by ?status=archived still works for power users.
* All HTML: bump api.js cache-buster v=4 -> v=5 so the new helper is fetched.
The api.js library-list fix from the previous commit never reached the browser because nginx served all .js with `Cache-Control: public, immutable; max-age=31536000`. The HTML referenced api.js with no version query, so the browser kept its year-cached buggy copy.
* nginx.conf: drop .js from the immutable long-cache block, add a no-cache must-revalidate block so future redeploys are picked up immediately.
* All HTML files: tag api.js refs with ?v=4 so already-running browsers fetch the new version on next page load.
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.