Skip to content

Releases: SysAdminDoc/OpenCut

v1.9.33 — Preflight checklist

13 Apr 02:19

Choose a tag to compare

Every long pipeline now runs a ~100ms preflight probe before kicking off. Missing Whisper, bad filepath, <500MB free — the modal spells it out before the user commits to a 10-minute wait. Currently wired into /interview-polish; /full and /shorts-pipeline definitions are present in PIPELINES, ready to enable.

v1.9.32 — Batch Interview Polish

13 Apr 02:16

Choose a tag to compare

Polish an entire shoot in one click. A 'Polish batch (N)' button appears on the Interview Polish card when there are 2+ files in the Batch picker; runs v1.9.29 sequentially across every file (serial, to keep Whisper from OOMing). Per-file progress toasts, final summary alert. Each run lands in job history as a normal job so Session Context / Journal / Apply-to-selection all work on batch results.

v1.9.31 — CLI `opencut polish`

13 Apr 02:12

Choose a tag to compare

New opencut polish <file> subcommand runs the full v1.9.29 Interview Polish pipeline against a locally running backend. Auto-detects the port (or use --port), submits the job, polls to completion, prints a Rich step table + output paths. Non-zero exit on any failure so it composes with shell scripts and task schedulers.

Flags: --no-repeats, --no-fillers, --no-chapters, --timeout, -o/--output.

No backend changes. See commit 83293b8.

v1.9.30 — Replay on selected clip

13 Apr 02:08

Choose a tag to compare

Job-history and Welcome-back rows gain Apply to selection alongside Re-run when the current clip differs from the original. Clones the stored payload, swaps filepath, fires the same job on the new clip. Turns the job store into a de-facto preset history.

Frontend-only feature; no new backend routes.

v1.9.29 — Interview Polish pipeline

12 Apr 22:14

Choose a tag to compare

OpenCut v1.9.29 — Interview Polish

Third of five feature releases. This is the marquee item — a real
one-click pipeline for interview / podcast content that composes six
existing OpenCut capabilities into a single button.

What's new

A new Interview Polish card sits at the top of the Cut tab. Hit
the big button on a selected clip and OpenCut runs the whole
interview-grade flow:

  1. Detect speech segments — silence removal
  2. Transcribe audio — Whisper (any installed backend)
  3. Find and cut repeated takes — Jaccard similarity on transcript
  4. Remove filler words — "um", "uh", "like", context-aware
  5. Speaker diarization — advisory; flags the step with a how-to-enable hint if WhisperX is available
  6. Generate captions + chapters — SRT, YouTube chapter markdown,
    and a final Premiere XML with every cut applied

Three opt-out checkboxes let you skip repeat-detection, filler cut,
or chapter generation if you don't want them on a given run.

UX

  • A real step checklist — not just a progress bar. Each of the 6
    steps renders with:
    • A status icon (pending / ok / failed / skipped)
    • Per-step stat detail: "3 fillers removed", "2 repeats cut",
      "8 chapters generated", "kept 247 segments"
    • A clear "why skipped" reason when a step is opted out or the
      backend dep is missing
  • Result strip shows the compression ratio ("Compressed to 62% of
    original (18:34)") plus three one-click actions:
    • Import to Premiere — pulls the XML into the active project,
      journaled so you can revert from the v1.9.28 Journal tab
    • Open SRT — launches the captions file in its default app
    • Open Chapters — opens the YouTube chapter markdown

Under the hood

  • New POST /interview-polish endpoint in routes/captions.py
    (~230 lines). Composes existing core modules directly —
    captions.transcribe, fillers.detect_fillers,
    repeat_detect.detect_repeated_takes +
    merge_repeat_ranges, chapter_gen.generate_chapters — and
    carries intermediate results from one step to the next so the
    transcript isn't re-run between stages.
  • Per-step status is captured in a steps array in the job result.
    The frontend renders each entry as a checklist row.
  • Range subtraction for repeat removal is inlined in the route
    because it's the only caller; no speculative shared helper.
  • Diarization is advisory in this release — shipping speaker labels
    requires an HF token in settings, so we report the step as skipped
    with a clear "Run Captions → WhisperX with an HF token to label
    speakers" hint instead of silently failing.

Tests

  • 4 new cases in TestInterviewPolish: route registered, CSRF
    enforced, missing filepath → 400 INVALID_INPUT, bad filepath
    → 400.
  • Full focused suite: 155 passed, 3 skipped.

Artifact

Windows x64 PyInstaller build attached as
OpenCut-Server-v1.9.29-win-x64.zip (~226 MB).

What's next

The planned v1.9.30 (live audio preview) and v1.10.0 (sequence
assistant) are in progress as part of the same feature-release
cycle. See the roadmap comment in v1.9.27 release notes.

v1.9.28 — Operation Journal + Rollback

12 Apr 22:05

Choose a tag to compare

OpenCut v1.9.28 — Operation Journal + Rollback

Second of five feature releases this cycle. This is the trust feature —
the thing that lets you commit to automated edits knowing you can take
them back without relying on Premiere's native undo stack.

What's new

Operation Journal. Every OpenCut action that writes to your
Premiere project is now recorded in a persistent SQLite journal at
~/.opencut/journal.db. A new Operation Journal card at the top
of the Settings tab lists recent operations in reverse-chronological
order with a one-click Revert button for actions that support it.

Instrumented forward operations

Action Revert behavior
Add sequence markers (e.g. beat markers) Deletes exactly the markers OpenCut added by fingerprinting {time, comment}
Batch rename project items Restores each item's previous name (by node id with a name-lookup fallback)
Import sequence from XML (silence remove, full pipeline, etc.) Removes the sequence by name
Import overlay video Deletes the imported project item by node id

Recorded but not auto-revertible

Some actions are kept in the history for context, but the ExtendScript
API doesn't offer a reliable inverse. These show a "No auto-revert"
pill instead of a Revert button:

  • Import captions (caption tracks don't have a clean deletion API)
  • Create smart bins (item bin membership isn't always recoverable)

This is intentional: we'd rather be honest about what we can and can't
reverse than pretend to revert and silently fail.

UX

  • Card lives at the top of Settings so it's always one click away.
  • Empty state tells you plainly: "No operations recorded yet. Run an
    action that writes to your Premiere project and it will appear
    here."
  • Loading skeleton on first open; visible error with the server
    message if the journal can't be read.
  • Refresh button re-queries; Clear button wipes the journal (with a
    confirm prompt — it does not undo anything in Premiere).
  • Reverted entries are dimmed and swap their Revert button for a
    "Reverted" pill.
  • Relative timestamps ("3 min ago", "yesterday").

Under the hood

Backend:

  • opencut/journal.py — SQLite store with WAL mode, thread-local
    connections, and close_all_connections() wired into the atexit
    chain alongside job_store and footage_index_db.
  • opencut/routes/journal.py — five endpoints:
    GET /journal/list, POST /journal/record,
    POST /journal/mark-reverted/<id>, DELETE /journal/<id>,
    POST /journal/clear. All mutation endpoints CSRF-protected.
    Unknown action types are rejected at record time so typos can't
    corrupt the revert flow.
  • VALID_ACTIONS / REVERTIBLE_ACTIONS frozensets keep the contract
    explicit and easy to extend when new revertible operations are added.

ExtendScript:

  • Four new inverse helpers in host/index.jsx:
    ocRemoveSequenceMarkers, ocUnrenameItems,
    ocRemoveImportedSequence, ocRemoveImportedItem. ES3-compliant,
    with a _ocParse helper for older runtimes that lack JSON.parse.

Frontend:

  • main.js records after every instrumented forward op completes
    successfully. Records never fail loudly — if the journal endpoint
    is unreachable the user sees no warning because the forward op
    already succeeded.
  • PremiereBridge extended with four new dispatch helpers.
  • New CSS (~100 lines) matching the existing Studio Graphite palette.

Tests

  • tests/test_journal.py — 14 new cases covering the store
    (record round-trip, mark_reverted idempotency, clear_all,
    revertible flag mapping, unknown-action rejection, reverted filter)
    and the routes (CSRF requirement, 404/409/400 error paths,
    delete, clear-empty).
  • Full suite: 151 passed, 3 skipped.

Artifact

Windows x64 PyInstaller build attached as
OpenCut-Server-v1.9.28-win-x64.zip (~226 MB). Unzip and run
OpenCut-Server\OpenCut-Server.exe or the standard launchers.

What's next

v1.9.29 (in progress): Interview Polish pipeline — a real 6-step
one-click chain that runs silence removal → repeated-take detection →
filler cut → speaker diarization → captions → chapters in one flow
with step-by-step progress and revertable final timeline apply.

v1.9.27 — Session Context: Where you left off

12 Apr 21:54

Choose a tag to compare

OpenCut v1.9.27 — Session Context

First of five feature releases landing this cycle. Small, zero-risk,
surfaces existing data the panel was already collecting.

What's new

"Where you left off" card. On the first successful connection
after launching the panel — or reconnecting after a server restart —
a dismissible card now appears above the workspace listing the last
5 completed OpenCut jobs, plus any jobs that were mid-flight when
the server died.

Each history row has three quick actions:

  • Open — launches the output file in its default app (Premiere,
    VLC, Photos, whatever) via os.startfile on Windows, open on
    macOS, xdg-open on Linux.
  • Reveal — shows the file in Explorer / Finder / the system file
    manager (explorer /select, / open -R / xdg-open on parent
    dir).
  • Re-run — replays the same job with the same params, using the
    stored endpoint and payload already persisted in
    ~/.opencut/jobs.db.

Interrupted jobs get their own inline banner with a View history
jump that expands the existing job-history tray — no more generic
showAlert() popup that users couldn't act on.

Behavior

  • Card appears once per panel session (the _updateCheckDone gate).
    Dismiss is sticky for the rest of the session.
  • If there's nothing to show (fresh machine, empty history), the
    card silently stays hidden — no empty state noise.
  • Loading skeleton while fetching; clear error text if the history
    endpoint is unreachable.
  • Responsive: rows collapse to a stacked layout below 720 px panel
    width. Focus-visible rings on every action button.

Under the hood

  • New route: POST /system/open-path — CSRF-protected, validates
    the path through validate_filepath (no traversal, null bytes, or
    UNC), dispatches to the OS file manager. Only mode=open and
    mode=reveal are accepted.
  • No new data infrastructure. Uses the existing
    /jobs/history?limit=5&status=complete and /jobs/interrupted
    endpoints plus the SQLite job store that's been persisting
    endpoint + payload since v1.5.
  • Frontend: one new card component in main.js with empty /
    loading / error states, slide-in animation matching the alert
    banner shell, and styles that respect the existing Studio
    Graphite palette.

Tests

  • tests/test_new_features.TestOpenPath — 6 cases covering CSRF,
    empty path, bad mode, missing file, traversal rejection, and a
    platform-aware OS-dispatch mock.
  • Broader suite: 158 passed, 3 skipped.

Artifact

Windows x64 PyInstaller build attached as
OpenCut-Server-v1.9.27-win-x64.zip (~226 MB). Unzip and run
OpenCut-Server\OpenCut-Server.exe or the standard launchers.

What's next

v1.9.28 (in progress): Operation Journal + one-click Rollback —
every OpenCut action that modifies the Premiere project becomes
revertable from a Journal tab.

OpenCut v1.9.26 — Install rate limit 429 + structured filepath errors

11 Apr 23:11

Choose a tag to compare

v1.9.26 — Two bugs caught by deep behavioral smoke test

Rolling QA caught two more real bugs by exercising the actual running binary — neither were visible to static code review.

1. Install routes returned 200 + job_id on rate-limited retries, then failed async

make_install_route() was checking rate_limit("model_install") inside the @async_job body, so the rate limit violation surfaced only after a job record + worker thread were already created. The client got 200 OK + {"job_id": "..."} and had to poll /status/<id> to discover the failure.

Fix: moved the rate-limit check to the synchronous Flask handler layer — now returns 429 RATE_LIMITED immediately with no job spawned.

first call:  200 {"job_id": "..."}           (install begins in worker)
second call: 429 {"code": "RATE_LIMITED",    ← synchronous
                  "error": "A model_install operation is already running...",
                  "suggestion": "Wait for the current install to finish, then retry."}

2. @async_job filepath errors lacked code + suggestion

When a route rejected a filepath through @async_job, the response was {"error": "No file path provided"} with no structured code field. The CEP/UXP panels' ERROR_CODE_ACTIONS table relies on code to pick the right recovery hint — without it, users saw only the raw message.

Fix: @async_job now classifies filepath failures into INVALID_INPUT (empty, traversal, null byte, UNC prefix) vs FILE_NOT_FOUND (missing, not-a-file) and attaches a suggestion:

{"error": "No file path provided",
 "code": "INVALID_INPUT",
 "suggestion": "Select a clip in Premiere or pass `filepath` in the request body."}

Applies to all 97 async routes that go through the @async_job decorator.

How this was found

A 9-step behavioral smoke test on the v1.9.25 exe that submitted real payloads and inspected the response shapes:

  1. CSRF enforcement (no-token / bad-token → 403) ✓
  2. Empty body → 400 (but code was None — bug!)
  3. Path traversal → 400 (same bug)
  4. Non-existent file → 400 (same bug)
  5. Real silence-detect job submission
  6. Bad JSON body → 400 ✓
  7. 100 MB oversize payload → 413 ✓
  8. Double install call — expected 429 but got 200 twice (bug!)
  9. Shutdown → 200 ✓

Downloads

Windows

  • OpenCut-Server-v1.9.26-Windows.zip — 🆕 ready-to-run bundle, extract + double-click OpenCut-Server.exe
  • OpenCut-Server-Windows.tar.gz — same contents, tarball format

Linux

  • OpenCut-Server-Linux.tar.gz

macOS

  • OpenCut-Server-macOS.tar.gz

Built by GitHub Actions CI and uploaded automatically.

OpenCut v1.9.25 — /system/dependencies 6000x speedup

11 Apr 22:47

Choose a tag to compare

v1.9.25 — Settings tab load time: 6.5 s → 0 ms

Caught during the v1.9.24 binary smoke test: GET /system/dependencies took ~6.5 s on the first cold call because it runs 20+ importlib.import_module() probes (torch, mediapipe, audiocraft, pyannote, onnxruntime, rembg, realesrgan, gfpgan, insightface, ...) plus an ffmpeg -version subprocess plus an ollama HTTP probe — all synchronously in one request. This blocked the Settings tab render on first open.

Fix

  • New module-level _deps_cache in opencut/routes/system.py with a threading.Lock and a 60-second TTL.
  • Cold call still pays the ~5 s import tax once; every subsequent call within the window returns from memory in <1 ms.
  • New ?fresh=1 query param bypasses the cache so the frontend can force a re-check after an install/uninstall.

Measured (via compiled PyInstaller exe)

cold call:   5513 ms   (20+ importlib + ffmpeg + ollama)
warm call:     87 ms   (HTTP roundtrip overhead only — cached in memory)
fresh=1:      173 ms   (bypasses cache; sys.modules warm)

~63x speedup on steady-state.

How this was found

Part of a rolling QA cycle: every tagged release gets an end-to-end binary smoke test against the PyInstaller exe (not just the Flask test client). That exercise caught v1.9.23's OPENCUT_PORT regression in v1.9.24, and now v1.9.25's dependency-check slowness.

Downloads

Windows

  • OpenCut-Server-v1.9.25-Windows.zip (225 MB) — 🆕 ready-to-run Windows bundle. Extract anywhere, double-click OpenCut-Server.exe. Self-contained PyInstaller onedir build with Python 3.12 + all dependencies. This is the easiest download for Windows users.
  • OpenCut-Server-Windows.tar.gz — same contents as the zip, tarball format for CI/WSL/Linux extraction

Linux

  • OpenCut-Server-Linux.tar.gz — PyInstaller onedir, Python 3.12, Ubuntu-built

macOS

  • OpenCut-Server-macOS.tar.gz — PyInstaller onedir, Python 3.12, macOS-built

Running it (Windows)

# Extract the zip
# Double-click OpenCut-Server.exe
# OR from a terminal:
cd OpenCut-Server
./OpenCut-Server.exe

# Env-var config (new in v1.9.24):
OPENCUT_PORT=5799 ./OpenCut-Server.exe
OPENCUT_HOST=0.0.0.0 OPENCUT_PORT=5679 ./OpenCut-Server.exe

Server listens on http://127.0.0.1:5679 by default. Point the CEP/UXP Adobe Premiere Pro panel at it or use the REST API directly.

OpenCut v1.9.24 — Env-var config fix

11 Apr 22:44

Choose a tag to compare

v1.9.24 — Binary smoke-test regression fix

Found during an end-to-end smoke test of the v1.9.23 Windows binary: running OPENCUT_PORT=5789 ./OpenCut-Server.exe silently ignored the env var and bound to 5679 anyway. CLAUDE.md had long advertised env-based config, but opencut/server.py::main() only read argparse flags with hardcoded defaults — nothing was actually reading OPENCUT_PORT / OPENCUT_HOST / OPENCUT_DEBUG.

Fix

main() now reads these env vars before parsing args and uses them as the argparse defaults, so:

  • Docker-compose / the VBS launcher can configure the backend entirely via env
  • CLI flags (--host, --port, --debug) still override env when both are set
  • Values are sanity-checked: port must be 1–65535, non-integer values fall back to 5679, bad OPENCUT_DEBUG strings fall back to off
  • OPENCUT_DEBUG accepts 1, true, yes, on (case-insensitive)

Verified with a two-process smoke test:

  1. OPENCUT_PORT=5799 python -m opencut.server → binds to 5799 ✓
  2. GET /health → 200 with version 1.9.24 ✓
  3. GET /system/status → 200 with CPU/RAM/GPU/jobs keys ✓
  4. POST /shutdown → 200, clean exit ✓

Downloads

  • Windows: OpenCut-Server-Windows.tar.gz
  • Linux: OpenCut-Server-Linux.tar.gz
  • macOS: OpenCut-Server-macOS.tar.gz

Binaries built by GitHub Actions CI and uploaded automatically after the tag push. Refresh in a few minutes if the download links show "(no assets yet)".