Commit graph

634 commits

Author SHA1 Message Date
6eb98d866b fix(youtube-import): export proxyQueue singleton for clean SIGTERM shutdown (issue #94 bug 7) 2026-05-26 07:38:07 -04:00
cb0efdfdae fix(proxy): export thumbnailQueue singleton for clean SIGTERM shutdown (issue #94 bug 7) 2026-05-26 07:36:54 -04:00
a6c9529c50 fix(promotion): singleton proxyQueue; await promote(); return shutdown fn (issue #94 bugs 3, 4) 2026-05-26 07:36:08 -04:00
e289554e44 fix(trim): update jobs table status on complete/fail (issue #94 bug 2) 2026-05-26 07:35:28 -04:00
bec64e668d fix(conform): mark asset error on failure; scope asset lookup by project_id (issue #94 bugs 1, 9) 2026-05-26 07:35:13 -04:00
a0b7b42524 feat(db): add growing_retention_days setting (migration 015) 2026-05-26 07:27:23 -04:00
09e2987c14 feat(db): add growing_enabled column to recorders (migration 014) 2026-05-26 07:27:17 -04:00
ee0c2a12de Use HTML img tag for screenshot 2026-05-26 01:47:28 +00:00
782ff5b7b6 Try relative path for screenshot 2026-05-26 01:38:14 +00:00
a20b0d3fe3 Use absolute URL for screenshot in README 2026-05-26 01:36:24 +00:00
f420584e1a Move feature overview to README with screenshot 2026-05-26 01:34:18 +00:00
0d85899627 Add home dashboard screenshot 2026-05-26 01:28:44 +00:00
be9ae32a3b Add feature overview documentation 2026-05-25 21:24:48 -04:00
7fc502513e fix(#78): GET /assets — include_archived filter now independent of status filter 2026-05-25 19:29:23 -04:00
2e1ac72585 fix(#79): proxy worker respects live/ingesting status on error 2026-05-25 18:36:39 -04:00
fba671ad40 fix(#53): show error banner with retry when loadData() rejects 2026-05-25 17:42:39 -04:00
33c82cab1a fix(#38,#54): fix apiFetch Content-Type header order; fix normalizeAsset seed hash 2026-05-25 17:42:06 -04:00
75c23448b4 fix(#65): GET /schedules returns 400 for unknown status query param 2026-05-25 17:40:58 -04:00
548c2ab8a4 fix(#72,#59): remove nginx /health stub — API endpoint proxies through correctly 2026-05-25 17:38:40 -04:00
15b4d45375 fix(#48): add type:module to mam-api package.json 2026-05-25 17:37:56 -04:00
4c8c3b72bb fix filmstrip: append probe to DOM, fix race condition, add 15s timeout 2026-05-25 11:26:02 -04:00
7ea3a235da fix: filmstrip — fetch video chunk as Blob URL, append probe to DOM, add timeout 2026-05-25 11:21:38 -04:00
0481fb3ecf fix: filmstrip probe video — append to DOM, fix src/handler race, add timeout 2026-05-25 11:14:55 -04:00
37c406bf4d fix filmstrip: use hls.js for HLS stream frame capture, not only direct streams 2026-05-25 09:30:40 -04:00
b345f5f6a4 fix editor: use assetsRef to avoid stale closure in handleExternalDrop 2026-05-25 09:29:05 -04:00
OpenCode
87f14b7c71 Fix asset filmstrip and editor UX 2026-05-25 05:14:36 +00:00
c501d88c63 Auto refresh library after ingest 2026-05-25 01:13:19 -04:00
78539ec8b0 Fix editor timeline interactions 2026-05-25 01:10:45 -04:00
de895dd7f8 Fix library refresh behavior 2026-05-25 01:08:38 -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
721f847b28 fix: remove openreel editor; fire df:assets-changed on upload/ingest complete 2026-05-24 20:36:04 -04:00
c36c732f47 fix: comment out editor service in docker-compose to unblock deployment 2026-05-24 18:58:22 -04:00
60e306d1db fix(hls): retry on playback failure with exponential backoff 2026-05-24 16:52:04 -04:00
ce31a45124 feat(editor): Phase 1 core NLE editor React SPA rewrite 2026-05-24 16:20:38 -04:00
7189df7957 docs: add NLE editor React polish plan (phases 1-3) 2026-05-24 14:53:56 -04:00
f21157f3c7 fix: refresh bin counts after asset move
Dispatch df:bins-changed custom event from onBinDrop and
AssetContextMenu.moveToBin so the bin rail counts update
immediately after moving an asset into a bin.
2026-05-24 14:50:22 -04:00
a5ab57d144 fix: add missing > to close bin rail div opening tag
Missing > after title attribute caused Babel parse error,
preventing Library component from being registered globally.
2026-05-24 14:46:36 -04:00
0ebc7ef777 fix: use window.RenameProjectModal via React.createElement
RenameProjectModal is exported to window from screens-projects.jsx,
so Library screen must reference it via window object and use
React.createElement instead of JSX syntax.
2026-05-24 14:30:22 -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
af905cf936 fix: bin creation 500 error + add drag-and-drop + project rename
- Fix 500 error when creating bins: missing updated_at column on bins table
  (migration 013 adds the column, schema.sql updated)
- Add drag-and-drop support for moving asset cards/list rows onto bin rail items
  with visual droppable highlight
- Add right-click context menu on project rail items (Rename/Delete)
- Expose RenameProjectModal via window so Library screen can reuse it
- Bins context menu already existed — was hidden by the 500 error
2026-05-24 13:27:24 -04:00
c312991bac feat: implement advanced features (conform, auto-relink, GUI redesign, docs, tests)
- #30 FCP XML Export & Conform: slide panel UI, preset system, FCP XML generation,
  conform job submission with progress polling via BullMQ
- #31 Hi-Res Auto-Relink: clip list with checkboxes, batch-trim server endpoint,
  trimWorker with frame-accurate FFmpeg trimming, auto-relink in Premiere via
  ExtendScript, temp segment signed URL endpoint
- #32 GUI Redesign: complete rewrite with Wild Dragon OKLCH design tokens
  (accent oklch(45% 0.20 266)), slide panels, preset cards, chip components
- #34 Cleanup Task: existing task validated and properly registered
- #35 Testing: comprehensive 33-scenario E2E test plan
- #36 Documentation: advanced features guide with workflows, troubleshooting,
  presets table, and architecture overview
- #24 PR merge: verified mergeable

All server endpoints, worker queues, and ExtendScript functions wired together
2026-05-24 13:19:24 -04:00
77130ac769 feat(server): temp segments cleanup task
Hourly cron that deletes expired temp_segments from S3 and DB.
Implements issue #34. Registered alongside scheduler in index.js.
2026-05-24 12:43:08 -04:00
a016175fc8 feat(db): migration 012 — advanced features schema
Add 'trim' to job_type enum, create temp_segments table with
expiry/job/asset indexes, and add conform_source_sequence_id
to assets for lineage tracking.

Closes #33
2026-05-24 12:42:22 -04:00
543248b8c2 Merge remote-tracking branch 'origin/feat/premiere-installer' 2026-05-24 12:03:46 -04:00
eadafffb18 fix(premiere-plugin): v1.0.1 — actually load + connect under CEP 12
End-to-end debugging against a live Premiere Pro 2025 + auth-enabled mam-api
surfaced four real bugs that made v1.0.0 install cleanly but never load,
plus the missing auth flow. All four are fixed and the panel is verified
connected (status dot green, Reconnect button shown, project list populated).

  - manifest.xml: a comment in the <Resources> block contained "--" (inside
    "--enable-nodejs"/"--mixed-context"), which is illegal per the XML spec.
    CEP 12's strict parser logged
        ERROR XPATH Double hyphen within comment
    and skipped the panel entirely. Comment rewritten without double hyphens.

  - manifest.xml: lacked the Version="X.Y" attribute on <ExtensionManifest>
    and used a non-standard AbstractionLayers/empty <ExtensionList/>
    structure. CEP rejected it with
        Unsupported Manifest version ''
    Manifest rewritten to the standard CSXS 7.0 schema (ExtensionList +
    DispatchInfoList + RequiredRuntimeList), matching the working AMPP
    panel template.

  - main.js: re-declared `const csInterface = new CSInterface()` at top
    level even though CSInterface.js already declared the same binding.
    CEP 12 shares script-realm lexical scope across <script> tags, so the
    second const threw
        Identifier 'csInterface' has already been declared
    The throw fired before setupEventListeners(), so the Connect button's
    click handler was never attached. This is the root cause of the
    original "clicking Connect does nothing" symptom; everything else was
    secondary. Removed the duplicate declaration; main.js now uses the
    binding from CSInterface.js.

  - No auth support against AUTH_ENABLED=true servers. mam-api supports
    Bearer tokens (POST /api/v1/tokens), so added:
      • API token input field (password-masked) next to Server URL
      • localStorage persistence on every keystroke
      • window.fetch monkey-patch that injects
          Authorization: Bearer <token>
        on every request whose URL starts with the configured server.
        Signed S3 download URLs are NOT touched.

Drive-by fixes that came out of the same debugging pass:
  - Server URL input listener was 'change' (fires on blur); switched to
    'input' so typing-then-clicking-Connect immediately commits.
  - restoreSettings() now strips trailing slashes from the stored URL so
    older saved values like 'http://host/' stop producing //api/v1 404s.
  - CSS selector `input[type="text"].server-url` didn't match the new
    password input → the token field was unstyled and effectively invisible.
    Generalized to `input.server-url`; restructured the connection bar into
    `.connection-controls--stacked` (flex column) of two `.server-input-row`
    rows so two input fields fit cleanly.
  - Build scripts now parse ExtensionBundleVersion from both element form
    (<ExtensionBundleVersion>X</...>) and attribute form
    (ExtensionBundleVersion="X"), since the manifest rewrite switched
    schemas.

Version bumped 1.0.0 → 1.0.1. New artifacts committed at
services/premiere-plugin/build/releases/v1.0.1/ (.exe 2 MB, .zxp 35 KB).
v1.0.0 left in place so editors who downloaded it can verify they're on
the broken version.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 19:24:10 -04:00
a6d789279c Merge pull request 'fix(jobs): real cancel for active jobs + multi-threaded thumbnail worker' (#29) from fix/jobs-cancel-and-concurrency into main 2026-05-23 17:23:52 -04:00
91325a4267 fix(jobs): real cancel for active jobs + multi-threaded thumbnail worker
DELETE /jobs/:id was throwing "404 not found" when the operator tried to
cancel a running job. BullMQ refuses job.remove() while a job is in the
active state; the route caught that error and fell through to the
404 branch, which was misleading because the job actually exists — the
queue was just refusing to drop it from under the worker.

Fix:
- Detect 'active' state explicitly and call moveToFailed(err, '0', false)
  first. Token '0' bypasses the per-worker lock check (the operator-side
  cancel doesn't hold the worker lock). That transitions active -> failed
  and frees the queue's concurrency slot.
- If moveToFailed itself fails (lock owned by a live worker), fall back
  to job.discard() so at least the result is thrown away.
- If remove() then fails (stalled, broken state), drop the job's Redis
  key directly via queue.client. Last-resort obliteration.
- Stop swallowing getJob() errors — if Redis is sad, surface it via
  next(err) instead of returning a misleading 404.
- Return { cancelled: true } when the job was active, so the client
  can show "Cancelled" rather than "Removed" in any future toast.

While here: thumbnail jobs now run with concurrency 4 by default
(proxy 2, conform 1, import 1 unchanged). Every queue defaulted to
concurrency 1 before, so a single stalled job blocked the entire queue.
All three are overridable via PROXY_CONCURRENCY / THUMBNAIL_CONCURRENCY
/ CONFORM_CONCURRENCY env vars for nodes with more headroom.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 17:23:07 -04:00
2b85fb49df Merge pull request 'fix(jobs): cancel running + delete failed jobs so the queue can be unstuck' (#28) from fix/jobs-cancel-stuck into main 2026-05-23 16:54:50 -04:00
eb6c723713 fix(jobs): cancel running + delete failed jobs to unstick the queue
The Jobs page only exposed a delete button for queued + done jobs, so a
stalled-active job (worker died holding a BullMQ concurrency slot) had
no way out from the UI. Operators were watching the queue back up
behind a single stuck thumbnail job with no kill switch.

- Running jobs now show a "Cancel" button (red text). Confirm copy
  spells out that the worker may run a few seconds longer in the
  background but the queue slot frees up immediately.
- Failed jobs now show the X icon for delete in addition to the
  existing Retry button.
- Both routes hit the same DELETE /jobs/:id endpoint; BullMQ's
  job.remove() works on any state including stalled-active.
- handleDelete takes an optional mode ('cancel' | 'delete') only to
  customise the confirm prompt and error toast wording.

Right-aligned the action cell so the Retry/Cancel/Delete buttons sit
flush right like the rest of the table's actions.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-23 16:54:05 -04:00