Manual clips now follow the same pattern as scan exports:
clip_003_m1_0.mp4 (manual) vs clip_003_a1_0.mp4 (auto-scan).
The clip number matches the vid folder number.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
clip_001_a1_0 now matches vid_001 instead of using an independent
counter that created confusing double numbering.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
load_for_file and add_scan_results triggered N redundant timeline repaints
via tab_changed → _on_scan_regions_edited for each tab add/remove.
blockSignals(True) during programmatic tab operations eliminates the cascade.
Also adds EAT_LARGE embedding model (1024-dim) and updates design docs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Export layout changed from clip_NNN group dirs to vid_NNN per-video folders
- Automatic DB migration rewrites old paths and moves files on startup
- Per-video counter with DB cross-check to prevent overwrites
- Changelog popup on version bump with "don't show again" checkbox
- Scan region resize now requires Shift+drag to prevent accidental edits
- Recalculate vid folder and counter on file load
- Add EAT_LARGE embedding model variant
- Update tests for new flat export path structure
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
tab_changed was only updating export count, not the timeline overlay.
Now calls _on_scan_regions_edited which refreshes both.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Use microsecond-precision timestamps to prevent version merging on
sub-second scans
- Clear undo stack when switching scan versions (stale row references)
- Parse timestamp labels robustly instead of hard-coded string slicing
- "Clear All" in hard negatives dialog respects active model filter
- Remove time.sleep from tests (no longer needed with microsecond timestamps)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
New HardNegativesDialog shows all hard negatives in a table with model
filter dropdown, multi-select delete, and clear all. Accessible from
TrainDialog via "Manage..." button next to the hard negatives checkbox.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add source_model column to hard_negatives table with migration. New
get_hard_negatives() returns full rows, delete_hard_negatives_by_ids()
for bulk deletion. get_training_data() gains use_hard_negatives param.
TrainDialog has "Use hard negatives" checkbox. Scan panel passes current
model name when marking negatives.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Each model tab now has a version combo showing scan history. When multiple
versions exist for a (file, model), users can switch between them to
compare results across training iterations. Added _current_table() and
_tab_table() helpers to unwrap the new container→table widget hierarchy.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Training cancel: connect finished signal to re-enable button (was stuck disabled)
- Waveform worker: disconnect stale signal and wait on file switch, clean up on close
- DatasetStatsDialog: numeric sort via DisplayRole, remove dead widget allocation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Details button in Train dialog opens a stats view showing:
- Class totals (positive/soft/negative) with colored balance bar
- Per-video table sortable by column
- Warnings for low clip counts, class imbalance, negative-only videos
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- WaveformWorker extracts low-res audio envelope via ffmpeg, drawn as
green polygon on timeline track
- _safe_disconnect() replaces bare TypeError catches for signal cleanup
- Train button toggles to Cancel during training, calls worker.cancel()
- Dynamic GPU batch sizing: 64 for ≥16GB VRAM, 32 for ≥8GB, 16 default
- Overlap warning before exporting clips that intersect existing markers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fresh databases were missing scan_export column — broke first export
- Threshold slider now filters existing scan results without rescanning
- N key toggles hard negative on selected scan regions
- All 59 tests passing
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- setup-windows.ps1 and setup_env.sh detect nvidia-smi for CUDA vs CPU PyTorch
- Startup logs Python version, venv path, PyTorch/CUDA/GPU, scikit-learn, librosa
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Prefetch next video's audio while GPU processes current embeddings
- Don't cancel Scan All when switching files in playlist
- Windows setup script now creates venv, installs PyTorch + requirements
- 8cut.bat auto-detects venv
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Show bright green playback position line in review mode
- Model history button next to scan model dropdown
- Skip backup on restore if identical timestamped copy already exists
- Auto-rescan when restoring a model version
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Scan regions can be disabled (Del/Backspace) instead of deleted, shown greyed out
- Resize scan regions by dragging timeline edges or editing table cells
- Grey ghost overlay shows trimmed portions of resized regions
- Ctrl+Z undo for disable, resize, drag, and negative toggle actions
- Fix training stats including scan-exported clips when checkbox unchecked
- Switch classifier to HistGradientBoostingClassifier (multi-threaded)
- Timestamped model saves with latest copy at base path
- Fix next-folder counter not detecting scan export folders
- Each scan area exports to its own numbered clip folder
- Platform-aware HW encoder detection (Linux/Windows/macOS)
- Auto-detect VAAPI render device instead of hardcoding
- Use shutil.move for cross-drive safety on Windows
- Comprehensive README rewrite with scan workflow documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fuse overlapping scan regions before display (merge adjacent 1s-hop windows)
- Hard negatives: mark false positives from scan panel for training feedback
- Toggle with "Add to Negatives" button, red text + red timeline regions
- Stored in dedicated hard_negatives table, always included in training
- Model versioning: auto-backup on retrain, right-click model combo to rollback
- Scan review mode: "Review" toggle hides spread/markers for free navigation
- Scan exports: saved to DB with scan_export flag, no timeline markers
- Training dialog checkbox to optionally include scan exports
- Single group folder per batch with area numbering (clip_042_a1_0.mp4)
- Export scan results: skip negatives, skip regions < 8s, respect spread
- Button shows estimated clip count, updates on spread/fuse/negative changes
- Timeline: reload scan regions on file load, "Clear all markers" context menu
- Default training model changed to HUBERT_XLARGE
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Stash profile and crop_center at export start for async safety
- Scope get_group/delete_group by profile to prevent cross-profile leaks
- Guard auto-negative sampling when no markers exist (prevents flood)
- Wrap ffmpeg subprocess with clean timeout error message
- Fix scan-all panel reload to use stashed profile, not live value
- Remove dead warnings import
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace librosa with direct ffmpeg subprocess for 10x faster audio loading
- Add ScanResultsPanel with per-model tabs, seek-on-click, delete, and export
- Persist scan results in DB per (filename, profile, model)
- Add model selector dropdown to switch between trained embedding models
- Add "Scan All" button for batch scanning playlist videos
- Support manual negative examples via negative class folder
- Configurable auto-negative margin (default 30s, 0 = disabled)
- Deduplicate nearby training markers (8s min gap)
- Parallel audio loading with ThreadPoolExecutor during training
- Progress callbacks from training for UI status updates
- Cache bypass in scan_video (skip audio loading when embeddings cached)
- Move all caches (models, embeddings, downloads) into project directory
- Add 8cut.sh launcher script with auto venv/conda detection
- Fix 11 bugs across thread safety, signal handling, and state management
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Fix test_utils.py importing build_annotation_json_path from main
instead of core.annotations (all 59 tests pass now)
- Fix get_training_data double-counting clips at same start_time
in both positive and soft sets — subtract positive from soft
- Add cancel_flag to train_classifier so training can be interrupted
between videos (TrainWorker passes self as cancel_flag)
- Remove orphaned core/export.py (was for deleted server API)
- Remove stale Dockerfile and docker-compose.yml (referenced server)
- Clean up leftover server/__pycache__ and client/ build artifacts
- Add torch to requirements.txt (was only mentioned in comments)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove legacy distance-mode scanning (build_profile, _similarity, etc.)
and hand-crafted intensity features — pipeline is now embedding-only
- Integrate Microsoft BEATs as embedding option alongside wav2vec2/HuBERT
- Add TrainDialog with positive class selector, model picker, video dir
fallback, and live training stats
- Add TrainWorker QThread with cancel support and proper lifecycle cleanup
- Add source_path column to DB for robust source video tracking
- Add get_export_folders/get_training_data/get_training_stats to DB
- Wire source_path in all export DB writes (_on_clip_done, _on_auto_clip_done)
- Cancel scan/train workers in closeEvent to prevent use-after-free crashes
- Add setup_env.sh supporting both conda and python venv (CUDA 12.8)
- Update requirements.txt with all actual dependencies
- Update 8cut_train.py with --positive flag for new DB-driven training
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause of poor discrimination: MFCC[0] (energy) dominated the
feature vector, making cosine similarity see all audio as similar.
Changes:
- Skip MFCC[0], use 12 coefficients instead of 20
- Add delta MFCCs for temporal dynamics
- Add 7-band spectral contrast for tonal vs noise quality
- Switch from cosine similarity to euclidean-distance-based score
- Pre-compute STFT once for whole file (10-20x faster)
- Vectorized sliding window via cumulative sums (no Python loop)
- Lower sample rate 22050→16000 Hz (faster, no quality loss)
- 62-dim feature vector (was 40-dim mean+std of raw MFCCs)
- Default threshold 0.05 (new similarity scale)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1. Rename ScanWorker.finished → scan_done to stop shadowing
QThread.finished. Previously, cancelled scans leaked the QThread
because the custom signal was never emitted.
2. Block signals on combobox reset in _on_scan_ref_changed to
prevent re-entrant call when user cancels folder dialog.
3. Merge overlapping scan regions into clusters before S-key
navigation so it jumps to the next distinct match, not 1s forward
through overlapping windows.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When cancelling a scan during file change, connect finished signal
to deleteLater instead of calling it immediately on a running thread.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add Scan button, threshold spinner, mode combobox, and reference source
combobox to the settings row. Implement handler methods for starting scans,
handling results/errors, cleanup of workers, and reference folder selection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add scan region storage and rendering to TimelineWidget:
- _scan_regions list in __init__ for (start, end, score) tuples
- set_scan_regions() and clear_scan_regions() methods
- paintEvent draws semi-transparent blue rectangles with score-based opacity
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Switch DELETE /export to query param (path param strips leading /)
- Add CropKeyframe Pydantic model for typed keyframe validation
- Convert keyframes to tuples before passing to apply_keyframes_to_jobs
- Remove dead QFrame import from main.py
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Autoclip (A): adjusts clip count to fit current pause position
- Pause no longer resets playback position — stays where paused
- Play resumes from pause point instead of restarting
- Spread/clips changes update loop end without restarting playback
- Number keys 1-9 export to subprofiles
- Click-away clears focus from spinboxes so hotkeys work again
- Lock mode: double-click marker jumps cursor to end of clip span
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Subprofiles: lightweight export variants that append a suffix to the
export folder (e.g. _soft, _intense). Each gets its own export button
in the transport row. Managed via "+" menu, persisted in QSettings.
- Play loop now updates immediately when spread/clips spinboxes change.
- Lock mode: ignore stale mpv position updates while user is dragging
to prevent the play position from jumping back.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- setup-windows.ps1: downloads libmpv DLL and ffmpeg, installs pip deps
- 8cut.bat: double-click launcher
- main.py: add_dll_directory for libmpv next to script (not just frozen)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Enables cross-platform builds for Windows and macOS. Adds _bin() helper
to resolve bundled ffmpeg in frozen builds, and configures ctypes library
path for bundled libmpv.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace the bottom status bar with a right-aligned label on the
settings row, saving vertical space. Add "Export complete" message
when a batch finishes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>