Skip to content

Commit 63feda7

Browse files
committed
v1.2.0: Add 16 improvements — reframe tool, clip preview, command palette, trim, merge, auto-crop, health monitor, progress parsing, output dedup, recent clips, per-op presets, audio waveforms, sub-tab filter, cancel kills subprocess, temp cleanup, reconnect UI
1 parent 717bd52 commit 63feda7

6 files changed

Lines changed: 1584 additions & 31 deletions

File tree

CHANGELOG.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,26 @@
1818
- **Collapsible Cards**: Click card headers to collapse/expand dense form sections
1919
- **Job Time Estimates**: Estimated processing time in the progress banner based on historical job data
2020
- **Localization Framework**: Language selector in Settings (placeholder for future i18n support)
21+
- **Video Reframe**: Resize/crop video for TikTok, Shorts, Reels, Instagram, Square, or custom dimensions with crop/pad/stretch modes
22+
- **Clip Preview Thumbnail**: Visual thumbnail + duration/resolution metadata when selecting a clip
23+
- **Command Palette**: Ctrl+K fuzzy search across all 28+ operations with keyboard navigation
24+
- **Recent Clips**: Dropdown of last 10 used clips, persisted across sessions
25+
- **Trim Tool**: Set in/out points to extract a clip portion (stream copy or re-encode)
26+
- **Merge/Concatenate**: Join multiple clips into one (fast stream copy or re-encoded for mixed formats)
27+
- **Auto-Crop Detect**: Smart reframe anchor using FFmpeg cropdetect for talking-head content
28+
- **Audio Waveform Everywhere**: Waveform preview buttons on Denoise and Normalize tabs (reuses Silence tab infrastructure)
29+
- **Per-Operation Presets**: Save/load settings per operation (persisted to localStorage)
30+
- **Server Health Monitor**: 10-second heartbeat with reconnect banner and toast notification
31+
- **Output Deduplication**: Auto-increment suffix prevents overwriting previous outputs
32+
33+
### Backend Improvements
34+
- **FFmpeg Progress Parsing**: `_run_ffmpeg_with_progress()` helper parses `-progress pipe:1` for real percentage updates
35+
- **Subprocess Kill on Cancel**: Job cancellation now terminates the running FFmpeg process via `_kill_job_process()`
36+
- **Temp File Cleanup**: Stale `opencut_preview_*.jpg` files cleaned up on server startup
37+
- **File Serving Endpoint**: `GET /file` serves local audio/video for preview player (path-restricted)
38+
39+
### Backend (14 new endpoints)
2140

22-
### Backend (8 new endpoints)
2341
- `POST /audio/waveform` - Extract waveform peak data via FFmpeg PCM extraction
2442
- `POST /video/preview-frame` - Extract single frame as base64 JPEG at timestamp
2543
- `GET /system/dependencies` - Check 24 optional deps + FFmpeg install status
@@ -28,6 +46,11 @@
2846
- `GET/POST/DELETE /workflows` - Custom workflow CRUD to `~/.opencut/workflows.json`
2947
- `GET/POST /settings/export|import` - Bundle presets + favorites + workflows
3048
- `POST /system/estimate-time` - Historical ratio-based time estimation
49+
- `POST /video/reframe` - Resize/crop video for target aspect ratio
50+
- `GET /video/reframe/presets` - Available reframe platform presets
51+
- `GET /file` - Serve local files for audio/video preview
52+
- `POST /video/merge` - Concatenate multiple clips (demux or filter modes)
53+
- `POST /video/trim` - Extract clip portion by in/out timecodes
3154

3255
## v1.1.0 (2026-03-15)
3356

CLAUDE.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
- **AI**: faster-whisper, demucs, pedalboard, MusicGen, Real-ESRGAN, rembg, etc.
99

1010
## Key Files
11-
- `opencut/server.py` (~6500 lines) - Flask backend, all API routes, job system
12-
- `extension/com.opencut.panel/client/main.js` (~3900 lines) - Frontend controller
13-
- `extension/com.opencut.panel/client/index.html` (~2100 lines) - UI layout (6 tabs)
14-
- `extension/com.opencut.panel/client/style.css` (~2850 lines) - Themes & styles
11+
- `opencut/server.py` (~7550 lines) - Flask backend, all API routes, job system
12+
- `extension/com.opencut.panel/client/main.js` (~5340 lines) - Frontend controller
13+
- `extension/com.opencut.panel/client/index.html` (~2490 lines) - UI layout (6 tabs)
14+
- `extension/com.opencut.panel/client/style.css` (~3690 lines) - Themes & styles
1515
- `extension/com.opencut.panel/host/index.jsx` (~1150 lines) - ExtendScript host
1616
- `opencut_server.spec` - PyInstaller spec
1717
- `OpenCut.iss` - Inno Setup installer script
@@ -74,3 +74,18 @@
7474
- Collapsible card headers
7575
- Job time estimates (historical ratio-based, stored in `~/.opencut/job_times.json`)
7676
- i18n language selector placeholder
77+
- Video reframe tool (resize/crop for TikTok, Shorts, Reels, square, custom dims; crop/pad/stretch modes)
78+
- Clip preview thumbnail + metadata on selection
79+
- Command palette (Ctrl+K) with fuzzy search across all 28+ operations
80+
- Recent clips dropdown (last 10, persisted to localStorage)
81+
- Trim tool with in/out points (stream copy or re-encode)
82+
- Merge/concatenate clips (fast demux or re-encoded filter modes)
83+
- Auto-crop detect for reframe (FFmpeg cropdetect → smart anchor)
84+
- Waveform preview buttons on denoise/normalize tabs
85+
- Per-operation preset save/load (localStorage)
86+
- FFmpeg real progress parsing via `-progress pipe:1`
87+
- Job cancel kills FFmpeg subprocess (Popen terminate/kill)
88+
- Temp file cleanup on server startup
89+
- Server health ping with reconnect banner (10s interval)
90+
- Output file deduplication (auto-increment suffix)
91+
- Sub-tab visibility persistence infrastructure

extension/com.opencut.panel/client/index.html

Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@
132132

133133
<!-- ===== MAIN CONTENT ===== -->
134134
<main class="main">
135+
<div class="server-status-banner hidden" id="serverStatusBanner">
136+
<span id="serverStatusMsg">Server disconnected. Reconnecting...</span>
137+
</div>
135138

136139
<!-- MEDIA SELECTION (persistent across all tabs) -->
137140
<section class="card" id="clipSection">
@@ -148,6 +151,18 @@
148151
<select class="clip-select" id="clipSelect">
149152
<option value="" disabled selected>Loading project media...</option>
150153
</select>
154+
<div class="clip-preview-row" id="clipPreviewRow">
155+
<div class="clip-thumb" id="clipThumb"></div>
156+
<div class="clip-meta" id="clipMeta">
157+
<span id="clipMetaRes"></span>
158+
<span id="clipMetaDur"></span>
159+
<span id="clipMetaSize"></span>
160+
</div>
161+
</div>
162+
<div class="recent-clips-row">
163+
<button class="btn-sm btn-ghost" id="recentClipsBtn" title="Recent clips">Recent</button>
164+
<div class="recent-clips-dropdown hidden" id="recentClipsDropdown"></div>
165+
</div>
151166
<div class="file-info hidden" id="fileInfoBox">
152167
<div class="file-name" id="fileNameDisplay"></div>
153168
<div class="file-meta" id="fileMetaDisplay"></div>
@@ -169,6 +184,7 @@
169184
<button class="sub-tab active" data-sub="silence">Silence</button>
170185
<button class="sub-tab" data-sub="fillers">Fillers</button>
171186
<button class="sub-tab" data-sub="full">Full Edit</button>
187+
<button class="sub-tab" data-sub="trim">Trim</button>
172188
</div>
173189

174190
<div class="sub-panel active" id="sub-silence">
@@ -275,6 +291,50 @@
275291
<button class="btn-primary" id="runFullBtn" disabled>Run Full Pipeline</button>
276292
</section>
277293
</div>
294+
295+
<!-- TRIM -->
296+
<div class="sub-panel" id="sub-trim">
297+
<section class="card">
298+
<div class="card-header">
299+
<div class="card-title">
300+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 9l6 6 6-6"/></svg>
301+
Trim Clip
302+
</div>
303+
</div>
304+
<p class="card-desc">Set in/out points to extract a portion of your clip. Use timecodes or seconds.</p>
305+
306+
<div class="form-group">
307+
<label>Start Time</label>
308+
<input type="text" id="trimStart" placeholder="00:00:00" value="00:00:00">
309+
<span class="hint-inline">HH:MM:SS or seconds (e.g. 5.5)</span>
310+
</div>
311+
312+
<div class="form-group">
313+
<label>End Time</label>
314+
<input type="text" id="trimEnd" placeholder="00:00:30" value="00:00:30">
315+
<span class="hint-inline">HH:MM:SS or seconds</span>
316+
</div>
317+
318+
<div class="form-group">
319+
<label>Mode</label>
320+
<select id="trimMode">
321+
<option value="copy">Stream Copy (instant, frame-approximate)</option>
322+
<option value="reencode">Re-encode (precise, slower)</option>
323+
</select>
324+
</div>
325+
326+
<div class="form-group" id="trimQualityGroup">
327+
<label>Quality</label>
328+
<select id="trimQuality">
329+
<option value="high" selected>High (CRF 18)</option>
330+
<option value="medium">Medium (CRF 23)</option>
331+
<option value="low">Low (CRF 28)</option>
332+
</select>
333+
</div>
334+
335+
<button class="btn-primary" id="runTrimBtn" disabled>Trim Clip</button>
336+
</section>
337+
</div>
278338
</div>
279339

280340
<!-- ======== TAB: CAPTIONS ======== -->
@@ -1086,6 +1146,8 @@
10861146
<button class="sub-tab" data-sub="vid-transition">Transitions</button>
10871147
<button class="sub-tab" data-sub="vid-particles">Particles</button>
10881148
<button class="sub-tab" data-sub="vid-titles">Titles</button>
1149+
<button class="sub-tab" data-sub="vid-reframe">Reframe</button>
1150+
<button class="sub-tab" data-sub="vid-merge">Merge</button>
10891151
<button class="sub-tab" data-sub="vid-upscale">Upscale</button>
10901152
<button class="sub-tab" data-sub="vid-color">Color</button>
10911153
<button class="sub-tab" data-sub="vid-remove">Remove</button>
@@ -1703,6 +1765,130 @@
17031765
</section>
17041766
</div>
17051767

1768+
<!-- REFRAME / RESIZE FOR PHONE -->
1769+
<div class="sub-panel" id="sub-vid-reframe">
1770+
<section class="card">
1771+
<div class="card-header">
1772+
<div class="card-title">
1773+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="5" y="2" width="14" height="20" rx="2"/><line x1="12" y1="18" x2="12" y2="18.01"/></svg>
1774+
Reframe for Phone / Social
1775+
</div>
1776+
</div>
1777+
<p class="card-desc">Resize and crop video to fit vertical (TikTok, Shorts, Reels), square, or custom dimensions. Smart crop keeps the important center content.</p>
1778+
1779+
<div class="form-group">
1780+
<label>Target Format</label>
1781+
<select id="reframePreset">
1782+
<option value="tiktok">TikTok / Shorts (1080×1920, 9:16)</option>
1783+
<option value="instagram_reel">Instagram Reel / Story (1080×1920, 9:16)</option>
1784+
<option value="instagram_post">Instagram Post (1080×1080, 1:1)</option>
1785+
<option value="instagram_land">Instagram Landscape (1080×566)</option>
1786+
<option value="youtube">YouTube 1080p (1920×1080, 16:9)</option>
1787+
<option value="youtube_4k">YouTube 4K (3840×2160, 16:9)</option>
1788+
<option value="square">Square (1080×1080, 1:1)</option>
1789+
<option value="custom">Custom Dimensions</option>
1790+
</select>
1791+
</div>
1792+
1793+
<div class="form-group hidden" id="reframeCustomDims">
1794+
<label>Width × Height</label>
1795+
<div style="display:flex;gap:8px;align-items:center;">
1796+
<input type="number" id="reframeCustomW" min="16" max="7680" value="1080" style="width:80px;">
1797+
<span>×</span>
1798+
<input type="number" id="reframeCustomH" min="16" max="7680" value="1920" style="width:80px;">
1799+
</div>
1800+
</div>
1801+
1802+
<div class="form-group">
1803+
<label>Resize Mode</label>
1804+
<select id="reframeMode">
1805+
<option value="crop">Crop (fill frame, cut edges)</option>
1806+
<option value="pad">Pad (fit inside, add bars)</option>
1807+
<option value="stretch">Stretch (distort to fit)</option>
1808+
</select>
1809+
</div>
1810+
1811+
<div class="form-group" id="reframeCropPosGroup">
1812+
<label>Crop Position</label>
1813+
<select id="reframeCropPos">
1814+
<option value="center" selected>Center</option>
1815+
<option value="top">Top</option>
1816+
<option value="bottom">Bottom</option>
1817+
<option value="left">Left</option>
1818+
<option value="right">Right</option>
1819+
</select>
1820+
<span class="hint-inline">Where to anchor the crop</span>
1821+
</div>
1822+
1823+
<div class="form-group hidden" id="reframePadColorGroup">
1824+
<label>Bar Color</label>
1825+
<select id="reframePadColor">
1826+
<option value="black" selected>Black</option>
1827+
<option value="white">White</option>
1828+
<option value="0x111111">Dark Gray</option>
1829+
<option value="0x1a1a2e">Dark Navy</option>
1830+
</select>
1831+
</div>
1832+
1833+
<div class="form-group">
1834+
<label>Quality</label>
1835+
<select id="reframeQuality">
1836+
<option value="high" selected>High (CRF 18)</option>
1837+
<option value="medium">Medium (CRF 23)</option>
1838+
<option value="low">Low (CRF 28)</option>
1839+
</select>
1840+
</div>
1841+
1842+
<div class="hint-inline" id="reframeInfo"></div>
1843+
1844+
<button class="btn-primary" id="runReframeBtn" disabled>Reframe Video</button>
1845+
</section>
1846+
</div>
1847+
1848+
<!-- MERGE / CONCATENATE -->
1849+
<div class="sub-panel" id="sub-vid-merge">
1850+
<section class="card">
1851+
<div class="card-header">
1852+
<div class="card-title">
1853+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/></svg>
1854+
Merge / Concatenate Clips
1855+
</div>
1856+
</div>
1857+
<p class="card-desc">Join multiple clips into a single video file. Add clips using the batch picker or drag and drop.</p>
1858+
1859+
<div class="form-group">
1860+
<label>Merge Files</label>
1861+
<div class="merge-file-list" id="mergeFileList">
1862+
<div class="hint" style="padding:8px 12px;">No files added. Use batch picker or drop files.</div>
1863+
</div>
1864+
<div style="display:flex;gap:6px;margin-top:6px;">
1865+
<button class="btn-sm btn-secondary" id="mergeAddCurrentBtn">Add Current Clip</button>
1866+
<button class="btn-sm btn-secondary" id="mergeAddAllBtn">Add All Project Media</button>
1867+
<button class="btn-sm btn-ghost" id="mergeClearBtn">Clear</button>
1868+
</div>
1869+
</div>
1870+
1871+
<div class="form-group">
1872+
<label>Mode</label>
1873+
<select id="mergeMode">
1874+
<option value="concat_demux">Fast (stream copy, same codec only)</option>
1875+
<option value="concat_filter">Re-encode (different codecs/resolutions OK)</option>
1876+
</select>
1877+
</div>
1878+
1879+
<div class="form-group">
1880+
<label>Quality</label>
1881+
<select id="mergeQuality">
1882+
<option value="high" selected>High (CRF 18)</option>
1883+
<option value="medium">Medium (CRF 23)</option>
1884+
<option value="low">Low (CRF 28)</option>
1885+
</select>
1886+
</div>
1887+
1888+
<button class="btn-primary" id="runMergeBtn" disabled>Merge Clips</button>
1889+
</section>
1890+
</div>
1891+
17061892
<!-- PRO UPSCALE -->
17071893
<div class="sub-panel" id="sub-vid-upscale">
17081894
<section class="card">
@@ -2213,6 +2399,15 @@
22132399

22142400
</main>
22152401

2402+
<!-- Command Palette -->
2403+
<div class="command-palette-overlay hidden" id="commandPaletteOverlay">
2404+
<div class="command-palette">
2405+
<input type="text" id="commandPaletteInput" placeholder="Search operations... (e.g. denoise, reframe, captions)" autocomplete="off" spellcheck="false">
2406+
<div class="command-palette-results" id="commandPaletteResults"></div>
2407+
<div class="command-palette-hint">Navigate with arrow keys, Enter to select, Esc to close</div>
2408+
</div>
2409+
</div>
2410+
22162411
<!-- Side-by-Side Preview Modal -->
22172412
<div class="preview-modal hidden" id="previewModal">
22182413
<div class="preview-modal-header">

0 commit comments

Comments
 (0)