Commit Graph

342 Commits

Author SHA1 Message Date
Ethanfel f0484fac86 Revert "feat: write fps.txt alongside WebP sequence audio"
This reverts commit cf62940b84.
2026-04-07 14:08:00 +02:00
Ethanfel fd25e8fa37 feat: add migration script to generate dataset.json from DB history
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 14:04:29 +02:00
Ethanfel c3c480acc7 feat: replace dataset.tsv with dataset.json annotation file
Each exported clip writes an entry to <folder>/dataset.json containing
its relative path, sound label, and fps. Re-exporting to the same path
updates the existing entry (upsert). Empty labels are skipped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 14:01:50 +02:00
Ethanfel cf62940b84 feat: write fps.txt alongside WebP sequence audio 2026-04-07 13:56:13 +02:00
Ethanfel fc9287a5a6 fix: pass source fps to ffmpeg export via fps filter 2026-04-07 13:54:38 +02:00
Ethanfel 1256819dde ui: warn mask generation is untested, recommend ComfyUI 2026-04-07 12:35:44 +02:00
Ethanfel 58043dd7e3 docs: warn mask generation is untested, recommend ComfyUI 2026-04-07 12:35:13 +02:00
Ethanfel a652872d15 docs: add GPL v3 license and GitHub source link 2026-04-07 12:34:13 +02:00
Ethanfel 9d7791557b revert: restore ff0cd00 (label history, overwrite mode, crop overlay)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 12:11:36 +02:00
Ethanfel 2352d530d0 feat: queue done marks, export UX, scrub-while-playing, counter fix
- Queue ✓: mark files green after export and on drop if already in DB
- Export folder auto-created if missing
- Scrub while playing: cursor drag seeks and continues playback
- Counter auto-advances past existing files on disk
- Instant pending marker on timeline when export starts
- WebP quality 92 + lanczos scaling
- seek() guard against unloaded state (SystemError fix)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 11:41:07 +02:00
Ethanfel 6e02a08046 Revert "feat: label history, overwrite mode, crop overlay, UX improvements"
This reverts commit ff0cd00309.
2026-04-07 11:36:40 +02:00
Ethanfel ff0cd00309 feat: label history, overwrite mode, crop overlay, UX improvements
- Editable label combo with DB history (most recent first)
- Click marker to arm overwrite mode (↺ indicator, re-exports same file)
- Portrait crop overlay: red bands on cut regions (paused only)
- Cache video dimensions to avoid mpv property reads in paintEvent
- Queue marks done files with ✓ on drop and after export
- Export folder created automatically if missing
- Play continues from new position when scrubbing during playback
- Counter auto-advances past existing files on disk
- Instant marker on timeline when export starts (optimistic)
- Marker right-click delete

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 11:34:47 +02:00
Ethanfel 6573fa6e05 feat: mpv Wayland embedding, timeline redesign, UX polish
mpv embedding:
- Replace wid/QOpenGLWidget with QOffscreenSurface + QOpenGLFramebufferObject
  + QPainter readback — works on Wayland/KDE without sub-surface compositing
- Force desktop OpenGL 3.3 core profile before QApplication (fixes black output on GLES)
- Timer-based render polling (16 ms) replaces signal-flood from mpv C thread;
  fixes playback animation and scrubbing preview
- Fix AB-loop: set ab-loop-a/b to "no" on stop (0 means infinite in mpv)

Timeline:
- Full redesign: time ruler with adaptive major/minor ticks, playhead triangle
  handle, selection region with edge lines, numbered marker badges
- Height 160 px; layout collapsed from 4 rows to 2 below timeline
- Markers appear immediately on export (optimistic update before ffmpeg finishes)
- Right-click marker → context menu to delete from DB

Hotkeys:
- Replace keyPressEvent with QShortcut(ApplicationShortcut) so keys work
  regardless of focused widget; MpvWidget gets NoFocus policy

Export:
- WebP: switch lossless→lossy quality 85, compression_level 1 (~10x faster)
- Add -threads 0 for full CPU utilisation during decode/filter
- Remember last export folder across sessions via QSettings

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 22:22:58 +02:00
Ethanfel 7931a0e3db debug: write mpv log to /tmp/8cut-mpv.log 2026-04-06 20:56:14 +02:00
Ethanfel 939199717f fix: use QOpenGLContext.getProcAddress for mpv render context proc lookup 2026-04-06 20:54:19 +02:00
Ethanfel 8863634bce debug: add mpv log output and initializeGL trace 2026-04-06 20:51:11 +02:00
Ethanfel e5f2c732d9 fix: wrap get_proc_address as CFUNCTYPE for mpv render context 2026-04-06 20:50:02 +02:00
Ethanfel 1e0c1ae892 fix: replace wid embedding with OpenGL render context — works on Wayland and X11 2026-04-06 20:48:59 +02:00
Ethanfel 2c95c2618a debug: print platform/wid/WAYLAND_DISPLAY at mpv init 2026-04-06 20:41:55 +02:00
Ethanfel c130010e36 fix: hide WAYLAND_DISPLAY during mpv init so it uses X11 wid embedding 2026-04-06 20:41:16 +02:00
Ethanfel 02c63bdfde fix: force QT_QPA_PLATFORM=xcb so mpv embeds correctly on Wayland sessions 2026-04-06 20:39:12 +02:00
Ethanfel f30955b63c debug: print drag-drop events to diagnose Wayland DnD 2026-04-06 20:37:13 +02:00
Ethanfel c80ebf9383 fix: move drag-drop to MainWindow to bypass QListWidget viewport on Wayland 2026-04-06 20:35:47 +02:00
Ethanfel 3d92a66660 fix: re-apply LC_NUMERIC=C after QApplication resets locale 2026-04-06 20:33:51 +02:00
Ethanfel bdfb9354ca fix: set LC_NUMERIC=C before mpv init to prevent segfault on non-C locales 2026-04-06 20:32:56 +02:00
Ethanfel 41c36267e9 fix: use NoDragDrop mode + viewport.setAcceptDrops for Wayland/KDE compatibility 2026-04-06 20:31:37 +02:00
Ethanfel d720fc0541 fix: accept dragMoveEvent so file drops work on all desktop environments 2026-04-06 20:30:31 +02:00
Ethanfel 31f4df4c5b fix: suppress QFrame paintEvent on mpv native window 2026-04-06 20:29:06 +02:00
Ethanfel 39bbfedb9d fix: suppress paintEngine warnings from mpv native window embedding 2026-04-06 20:28:00 +02:00
Ethanfel 025d5afe1f chore: add shebang for direct execution 2026-04-06 20:25:07 +02:00
Ethanfel 191d1cf299 fix: move SELVA_CATEGORIES to module level, harden append_to_tsv, fix tests
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 18:48:46 +02:00
Ethanfel c76eb9ec84 feat: add label/category annotation fields and TSV export for SELVA
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 18:45:29 +02:00
Ethanfel 8fb8782e65 fix: use correct venv path on Windows (Scripts/python.exe) 2026-04-06 18:30:37 +02:00
Ethanfel a74e5022b3 docs: add README 2026-04-06 18:28:59 +02:00
Ethanfel e62a712de2 perf: skip redundant repaints, cache fps, O(1) playlist dedup, fix worker leak
- TimelineWidget.set_cursor: skip update() when clamped value is
  unchanged (e.g. clicking at the boundary repeatedly).
- MainWindow: cache container_fps in self._fps on file load; keyPressEvent
  reads the cached value instead of hitting the mpv property on every key.
- PlaylistWidget: add _path_set (set[str]) alongside _paths (list[str])
  so duplicate detection in add_files is O(1) instead of O(N).
- SettingsDialog._on_install: quit+wait any previous SetupWorker before
  starting a new one, preventing leaked threads and duplicate signal
  connections on repeated installs.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 18:18:31 +02:00
Ethanfel 16e0bc231c perf: playlist O(1) updates, marker hover cache, crop pen cache, keyboard debounce, export marker fast-path
- PlaylistWidget._select: only update the two items whose label changes
  (old current → plain name, new current → add ▶) instead of rewriting
  every item in the playlist.
- TimelineWidget: pre-compute (t/duration, path) fractions in
  _hover_cache on set_markers/set_duration so mouseMoveEvent avoids
  dividing by duration on every pixel of mouse movement.
- CropBarWidget: cache QPen in __init__ instead of recreating per frame.
- _step_cursor: update label/state immediately and start the timeline's
  existing _seek_timer instead of calling _on_cursor_changed directly,
  so held arrow keys are debounced the same as mouse drag.
- _refresh_markers: call _get_markers_for(filename) directly after
  export (exact match known) and only fall back to fuzzy find_similar
  when no exact-match rows exist.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 18:07:58 +02:00
Ethanfel 4c44d78c37 perf: seek debounce, cached paint resources, async DB lookup, regex pre-compile
- TimelineWidget: debounce cursor_changed signal with 16ms timer so
  mpv.seek is called at most ~60/s during drag; flush on mouseRelease.
  Cache QPen/QFont objects in __init__ instead of recreating per frame.
- _normalize_filename: compile _QUALITY_RE and _SEP_RE once at module
  level instead of on every call.
- ProcessedDB: add check_same_thread=False; add _get_markers_for() to
  avoid a second find_similar pass; store db path.
- _DBWorker(QThread): runs find_similar + _get_markers_for off the main
  thread. _after_load starts the worker instead of blocking; stale
  results discarded if the user loads a different file first.
- MainWindow: reuse self._settings instead of creating a new QSettings
  instance in the mask row setup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 18:04:18 +02:00
Ethanfel b57131a3d9 feat: keyboard navigation for timeline
Arrow keys / J / L: step one frame; Shift = 1 second jump
Space / P: toggle play/pause
K: pause and return to cursor
E: trigger export
M: jump to next export marker (wraps)

Keys are suppressed when a text field has focus.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 17:35:46 +02:00
Ethanfel 9652b249ba feat: extract audio alongside WebP image sequence
Adds build_audio_extract_command and runs it in ExportWorker after the
frame sequence completes. Audio written to <sequence_dir>.wav (lossless
pcm_s16le). Extraction failure (no audio stream) is silently ignored.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 17:20:40 +02:00
Ethanfel fe3e642dfa fix: guard mask generation against WebP sequence export path 2026-04-06 17:19:03 +02:00
Ethanfel 855797a1b3 docs: clarify _last_export_path holds dir path for WebP sequence 2026-04-06 16:07:44 +02:00
Ethanfel f9649f7584 feat: wire WebP sequence format into export flow 2026-04-06 16:05:26 +02:00
Ethanfel 13c8a8aeab style: rename fmt_idx to idx in _cmb_format setup 2026-04-06 16:04:30 +02:00
Ethanfel c163b298c4 feat: add format combo (MP4 / WebP sequence) to export row 2026-04-06 16:02:26 +02:00
Ethanfel d3c4dea597 fix: guard makedirs in ExportWorker.run inside try/except 2026-04-06 16:01:16 +02:00
Ethanfel f86442322f feat: ExportWorker supports image_sequence mode 2026-04-06 15:59:17 +02:00
Ethanfel 1ab18e6ab5 fix: use -c:v and explicit -an in image_sequence ffmpeg command 2026-04-06 15:58:33 +02:00
Ethanfel 93028d9ac7 feat: build_sequence_dir and image_sequence flag for build_ffmpeg_command
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 15:56:16 +02:00
Ethanfel c57ab4df77 docs: image sequence export implementation plan
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 15:54:31 +02:00
Ethanfel 4f2feb1907 docs: image sequence export design
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 15:53:13 +02:00