docs: playlist and processed-files DB design
This commit is contained in:
@@ -0,0 +1,80 @@
|
|||||||
|
# Playlist & Processed-Files Database Design
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Two new features added to the existing 8-cut tool:
|
||||||
|
|
||||||
|
1. **Playlist** — a queue of source video files; auto-advances to the next file after each export.
|
||||||
|
2. **Processed-files database** — SQLite store of exported source filenames; warns when a newly loaded file is fuzzy-similar to one already processed.
|
||||||
|
|
||||||
|
## Stack additions
|
||||||
|
|
||||||
|
- `sqlite3` (Python built-in) — persistent DB at `~/.8cut.db`
|
||||||
|
- `difflib.SequenceMatcher` (Python built-in) — fuzzy filename similarity, threshold 0.75
|
||||||
|
|
||||||
|
## Layout
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────────────────────────────┐
|
||||||
|
│ [Drop video files here] │
|
||||||
|
├─────────────────┬────────────────────────────────────┤
|
||||||
|
│ QUEUE │ │
|
||||||
|
│ ▶ clip_a.mp4 │ mpv video preview │
|
||||||
|
│ clip_b.mp4 │ │
|
||||||
|
│ clip_c.mp4 ├────────────────────────────────────┤
|
||||||
|
│ │ Timeline ──────|cursor────── │
|
||||||
|
│ ├────────────────────────────────────┤
|
||||||
|
│ │ [▶ Play 8s] [⏸] cursor / dur │
|
||||||
|
├─────────────────┴────────────────────────────────────┤
|
||||||
|
│ Name: [clip] Folder: [~] → clip_001.mp4 [Export] │
|
||||||
|
└──────────────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
- Drop one or multiple files → all added to the queue
|
||||||
|
- Clicking a queue item loads it immediately
|
||||||
|
- `▶` marks the current file
|
||||||
|
- Auto-advances to next item after a successful export
|
||||||
|
|
||||||
|
## Components
|
||||||
|
|
||||||
|
### `ProcessedDB`
|
||||||
|
|
||||||
|
Wraps `sqlite3`. DB file: `~/.8cut.db`, created on first run.
|
||||||
|
|
||||||
|
Table:
|
||||||
|
```sql
|
||||||
|
CREATE TABLE IF NOT EXISTS processed (
|
||||||
|
filename TEXT NOT NULL,
|
||||||
|
processed_at TEXT NOT NULL
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Methods:
|
||||||
|
- `add(filename: str)` — inserts row with `filename` and current UTC ISO timestamp
|
||||||
|
- `find_similar(filename: str) -> str | None` — loads all filenames, iterates with `SequenceMatcher(None, a, b).ratio() >= 0.75`, returns the best-matching stored filename or `None`
|
||||||
|
|
||||||
|
### `PlaylistWidget(QListWidget)`
|
||||||
|
|
||||||
|
- Accepts file drops (via `dragEnterEvent` / `dropEvent`)
|
||||||
|
- Emits `file_selected = pyqtSignal(str)` when an item is activated (click or auto-advance)
|
||||||
|
- `add_files(paths: list[str])` — appends paths, skips duplicates already in the list
|
||||||
|
- `advance()` — selects the next item; if at end, does nothing (queue exhausted)
|
||||||
|
- Current item shown with a `▶ ` prefix in the display text; others show bare filename
|
||||||
|
|
||||||
|
### `MainWindow` changes
|
||||||
|
|
||||||
|
- Drop zone (`dragEnterEvent`/`dropEvent`) now calls `playlist.add_files(paths)` instead of loading directly
|
||||||
|
- `playlist.file_selected` connected to `_load_file`
|
||||||
|
- `_after_load`: calls `db.find_similar(os.path.basename(path))` — if match found, shows `"⚠ Similar to already processed: {match}"` in status bar
|
||||||
|
- `_on_export_done`: calls `db.add(os.path.basename(self._file_path))`, then `self._playlist.advance()`
|
||||||
|
|
||||||
|
## Warning behavior
|
||||||
|
|
||||||
|
- Warning is informational only — does not block export
|
||||||
|
- Shown in the existing status bar with a `⚠` prefix
|
||||||
|
- Shown each time a file is loaded (queue advance or manual click)
|
||||||
|
|
||||||
|
## Error handling
|
||||||
|
|
||||||
|
- DB connection errors on startup: logged to stderr, app continues without DB (warning feature silently disabled)
|
||||||
|
- Queue exhaustion (advance past last item): silently does nothing; user can add more files
|
||||||
Reference in New Issue
Block a user