Commit graph

35 commits

Author SHA1 Message Date
4172b0d70a rip out entire auth/login flow
- remove requireAuth from all route files
- delete auth.js, tokens.js, users.js routes
- delete auth middleware
- remove session middleware and all auth deps from index.js
- delete login.html and auth-guard.js from web-ui
2026-05-27 03:39:58 +00:00
opencode
a44d8bd7c9 feat(admin): live video-presence indicators on cluster DeckLink ports
Adds per-port video signal state to the admin Cluster panel:

- New GET /cluster/devices/blackmagic/signal endpoint joins recorders by
  node_id+device_index and queries each active capture container's
  /capture/status (local: http://recorder-<id>:3001, remote: api_url/
  sidecar/<container_id>/status).  Returns receiving/connecting/lost/
  error/idle/no-recorder per port plus framesReceived and currentFps.

- bmd-card.js render() now accepts portSignals (Map or object) and
  overlays a colored dot on each BNC connector with pulse animation
  for receiving/connecting states.

- screens-admin.jsx Cluster panel polls the new endpoint every 5s,
  feeds the signal map into both the port chips (now show
  RECEIVING/CONNECTING/LOST + fps) and the BMD SVG card diagram
  rendered below them via a new BmdCardPanel component.

- styles-fixes.css adds bmd-card-* styles for the SVG diagram and
  bmd-port-signal --pulse animation.
2026-05-26 22:02:38 +00:00
78539ec8b0 Fix editor timeline interactions 2026-05-25 01:10:45 -04:00
3dad82d992 fix(editor): drag interactions, undo history, overflow clipping
Four critical fixes:
- Remove overflow:hidden on tlRef so Timeline.init's scroll survives re-renders
- Don't call _renderClips() inside mousedown (was destroying event target mid-drag)
- Use refs for undo history to eliminate stale closure in onClipsChanged callback
- Change .tl-clip-area overflow:hidden to overflow:visible so pointer events reach clip edges
2026-05-24 21:21:23 -04:00
4673efac6a fix(editor): setScale, hand pan, sort comparator, playhead sync, rename/delete, track selector 2026-05-24 21:03:12 -04:00
d94ed00312 fix: apiFetch headers spread, droppable highlight, project rename, color stability, orphaned api.js removal
- Fix apiFetch headers spread bug (custom headers overwrote Content-Type)
- Track per-bin hover state for droppable highlight
- Refresh project rail after rename from Library screen
- Use ID-hash for project colors instead of array index
- Remove orphaned js/api.js (563 lines, never loaded)
- 'All projects' rail item clears openProject filter
- Add project boundary guard to drag-and-drop bin moves
- Stabilize refreshAssets useCallback with empty deps
- 'Last 24h' filter now actually filters by created_at
2026-05-24 14:20:00 -04:00
16a1fe604f web-ui: tag IN DEV pages in sidebar from auth-guard
Adds a tiny CSS rule + DOM patch that walks .nav-item links on every
page and appends an 'IN DEV' badge to those matching a known in-dev
page (currently just editor.html). Avoids touching all 13 HTML files
for the same single-line nav change.
2026-05-21 09:59:29 -04:00
d39f86d9c5 ui: add bmd-card.js — visual DeckLink port picker
Renders an inline SVG of the detected card (Duo 2 / Quad 2 / Mini
Recorder / Mini Monitor / UltraStudio 4K Mini, with a generic fallback)
showing each connector in its real physical position. Click to select.
Used by recorders.html for SDI source selection.
2026-05-21 00:19:51 -04:00
89771a2380 feat(timeline): ripple delete on Del, extract/lift on Shift+Del 2026-05-19 23:45:41 -04:00
d21c61a8b2 fix: addClip uses s.fps instead of hardcoded TC.secondsToFrames (59.94) 2026-05-19 23:08:13 -04:00
36f165807a fix(topbar-strip): escape pageName() output before innerHTML insertion 2026-05-19 00:46:48 -04:00
130906ef42 feat(api.js): add retryAsset() helper for POST /assets/:id/retry 2026-05-19 00:17:39 -04:00
0ea8d7ce33 fix(timeline): cap right-trim at source asset boundary
When duration_ms is known, dragging the right-trim handle past the end
of the source clip could push timeline_out_frames beyond what the source
material covers.  Cap the delta so neither timeline_out_frames nor
source_out_frames can extend past the available source frames.

Also changed assetFrames fallback from origSrcOut (prevents any extension
when duration is unknown) to null, so the guard is simply skipped when
we don't have duration metadata.
2026-05-19 00:02:34 -04:00
3c689ccddf fix(timecode): correct framesToTC for all frames beyond position 3
The previous algorithm used `if (rem >= DROP)` (i.e. rem >= 4) to decide
whether to advance to the next minute group.  This fired immediately at
frame 4, still inside minute 0 of the 10-minute non-drop group, producing
00:01:00;00 for what should be 00:00:00;04.  Every timecode display in
the editor was wrong for any position past the first four frames.

Each 10-minute block has one 3600-frame non-drop minute followed by nine
3596-frame drop minutes.  The fix checks `rem < FRAMES_FIRST_MIN` (3600)
to identify the non-drop minute, then subtracts it before dividing into
drop-minute slots.  Frame labels within drop minutes are shifted by DROP
(+4) so the first usable label is :00;04 as per SMPTE 12M.
2026-05-19 00:01:18 -04:00
79d44826fe feat(api.js): add patchRecorder() helper for PATCH /recorders/:id 2026-05-18 23:32:33 -04:00
910bbf8d3f merge: bring NLE editor pages (editor.html, timeline.js, timecode.js) from main 2026-05-18 23:02:51 -04:00
1f31d1037d merge: bring sequences/auth/admin backend + auth-guard frontend into fix/library-and-signal-indicator 2026-05-18 21:25:36 -04:00
2fabc73299 fix(ui): prevent keydown listener accumulation on re-init 2026-05-18 20:05:34 -04:00
10152b5ad7 feat(ui): add DOM-based timeline engine (select, razor, playhead) 2026-05-18 20:02:41 -04:00
ad6e836345 feat(ui): add sequence API helpers to api.js 2026-05-18 19:58:35 -04:00
7d8ccc95e9 feat(ui): add 59.94 DF timecode utility module 2026-05-18 19:58:34 -04:00
4f649b41a9 feat: add shared auth-guard.js with 401 → login redirect 2026-05-18 13:21:22 -04:00
2d21d4d44d feat: auth system — CSS page transitions, API helpers, users/tokens pages 2026-05-18 12:58:24 -04:00
32bce2e263 feat(editor): splice tool (B/S key + Split button), thumbnail hydration via signed URL, enable Export (draft for now) 2026-05-18 10:25:53 -04:00
2e1bcd655f feat(editor-native): Phase A — single-track editor logic (asset library, preview, in/out markers, drafts) 2026-05-18 10:17:31 -04:00
7d76f9c549 feat(growing-files): Phase 1 - live HLS preview during recording
While a recorder is running, the capture container tees an HLS
stream into /live/<assetId>/ alongside the ProRes master upload.
The asset row is pre-created at recorder start with status='live'
so the clip appears in the library immediately. /api/v1/assets/:id/stream
returns the HLS playlist URL until recording stops, then proxy.

* docker-compose: shared wild-dragon-live mount on api/capture/web-ui
* migration 001-add-live-status: idempotent ALTER TYPE for asset_status
* mam-api: runMigrations() on boot; recorders.js pre-creates live asset
  + passes ASSET_ID; assets.js POST upserts on existing live row instead
  of inserting a duplicate, and stream route returns HLS for live assets
* capture: parallel HLS ffmpeg into /live/<assetId>/; ASSET_ID env
* web-ui: nginx serves /live/, preview.js loads hls.js, LIVE badge added
2026-05-18 07:29:50 -04:00
Zac
b68f0c6aba feat(editor): integrate openreel-video as services/editor with MAM hooks
Vendored Augani/openreel-video (MIT) into services/editor and wired it to the MAM. Editor runs as its own container on port 47435. Library assets pull in via ?asset=<uuid>; render exports route back via POST /api/v1/upload/simple. Sidebar Editor link on every page; Edit button on every preview modal. See services/editor/INTEGRATION.md for the patch map.
2026-05-17 21:44:37 -04:00
Zac
e441176961 feat(design): broadcast ops console redesign sweep
Confirmed shape brief: ops-console direction, balanced density, blue committed accent, readability emphasized.

Design system: surface scale to 5 steps tinted toward hue 266; text contrast lifted (secondary 62->72%, tertiary 44->52, added text-disabled); borders gained faint variant; status tokens renamed semantically (signal-good/warn/bad/idle); typography upgraded (Inter 400/500/600, JetBrains Mono for numerics, new 2xl/3xl/tc scale steps).

New components: tc-display timecode classes with blue glow; tally-word with good/warn/bad/rec variants; signal-strip flutter bar with modifiers; chip dense monospaced pill; manifest table styles.

Topbar status strip: new js/topbar-strip.js auto-injects a 28px strip on every page with wall clock, page name, live API latency, and system-pulse dot.

Per-page: recorders gain live signal-strip above fps line; capture timecode bumped 38->64px with blue glow; ingest drop zone slimmed 200->88px side-by-side layout so manifest gets the real estate.
2026-05-17 19:05:22 -04:00
Zac
349bc5a41d feat: multi-select + bulk move/copy/delete, brand blue, hardhat loader
* Library cards now show a checkbox on hover (and persistent when selected). Click checkbox = toggle, shift-click = range. Plain click on a card with an active selection extends/shrinks the selection instead of opening preview. Floating pill at the bottom shows count + Move / Copy / Delete / Clear. Move + Copy open a tiny bin picker (current project, default to current bin).

* mam-api/routes/assets.js: PATCH /:id now also accepts bin_id (null = move out of bin). New POST /:id/copy makes a reference-copy of the asset row (same S3 keys, new id) into the target bin/project.

* api.js: moveAsset(id, binId) and copyAsset(id, {binId, projectId}) helpers.

* All accent tokens swapped from the amber oklch(76% 0.178 52) to the Wild Dragon signature blue oklch(55% 0.20 266) = #1f3ad0 ish. Login splash + first-load splash + signal-receiving + button primary all picked it up automatically through common.css.

* Loading indicator across the app uses the AMPP Safe hardhat photo gently pulsing with a tiny blue dot underneath. .ampp-loading component lives in common.css with --sm / --xs / --inline variants. Replaces the plain "Loading assets…" empty state in index.html.
2026-05-17 14:48:34 -04:00
Zac
72545126c4 fix: delete asset actually deletes
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.
2026-05-17 12:55:55 -04:00
Zac
ea28c5189d feat: in-library asset preview + Premiere plugin installer
Click any asset card to open a modal with the H.264 proxy playing inline (or audio/image, per media_type). Esc or click outside closes. Sidebar shows status/codec/resolution/fps/duration/size/created plus tags and notes.

Plugin install side: added install-windows.ps1 that copies the CEP panel to %APPDATA%\Adobe\CEP\extensions, flips PlayerDebugMode=1 across the CSXS.8-13 hives, and prints the next steps. Plugin already wired against the current API.

* services/web-ui/public/js/preview.js: standalone IIFE that lazy-injects the modal markup + CSS on first use. Renders <video controls> (or <audio>, <img>) sourced from /api/v1/assets/:id/stream, with sidebar from /api/v1/assets/:id. Falls back to a clear empty state when proxy is still processing.
* services/web-ui/public/index.html: loads preview.js, wires asset-card click to window.openAssetPreview(asset.id), guards against delete-button clicks bubbling.
* services/premiere-plugin/install-windows.ps1: one-shot Windows installer for the CEP extension.
2026-05-17 08:55:14 -04:00
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
31ca999075 fix(api.js): correct capture paths, bin routes, device normalisation, upload camelCase, session tracking 2026-05-16 00:31:58 -04:00
3f25ea1124 Phase 2: services/web-ui/public/js/api.js 2026-04-07 22:05:44 -04:00
ee9e6865ab add services/web-ui/public/js/api.js 2026-04-07 21:58:23 -04:00