Desktop Media Cleanup App — Requirements v1.0
1) Overview & Goals
A desktop utility that helps users quickly triage photos and videos by assigning scores and bulk‑deleting low‑scored media. The app indexes media in a chosen root folder, previews items one‑by‑one, lets users adjust a per‑file score via mouse clicks, and automates deletion of files that were marked for removal.
Primary goals
-
Fast, keyboard/mouse‑driven triage of large media libraries.
-
Clear progress feedback and a definitive “clean up completed” state.
-
Safe, reversible (optional) delete flow, per user confirmation.
Out of scope (v1): Cloud sync integrations, facial recognition, deduplication, format conversion, editing.
2) Platforms & Tech Assumptions
-
Target OS: Windows 10+, macOS 12+, (optional) Linux (Ubuntu LTS).
-
Packaging: Native installers (MSIX/EXE, DMG/PKG, AppImage/Snap optional).
-
Media preview: use OS codecs or a cross‑platform library (e.g., ffmpeg/AVFoundation/DirectShow) for thumbnails and playback.
-
Index store: single file per root (SQLite recommended; JSON allowed for MVP).
3) Core Concepts & Definitions
-
Root Folder: The folder the user chooses to clean; includes all subfolders.
-
Index: On‑disk database of discovered media and their scores/metadata.
-
Score: Integer , default 3 for each indexed file.
-
1 = reject (to delete), 5 = keep (locked), 2/3/4 = undecided.
-
-
todelete folder: Destination subfolder under each file’s current parent for files scored 1.
4) User Stories
-
As a user, I can pick a folder and immediately see its subfolders in a tree with file counts.
-
As a user, I can preview photos/videos in sequence and change their score quickly with the mouse.
-
As a user, I can skip items already at score 1 or 5 and focus only on undecided ones.
-
As a user, I can finish triage and bulk‑delete the 1‑scored files after a clear confirmation.
-
As a user, I see a "clean up completed" message when every file is either 1 or 5.
5) Functional Requirements
FR-1 Folder Navigation & Tree
-
FR-1.1 The app shows a collapsible folder tree rooted at the selected folder.
-
FR-1.2 Users can toggle among folders and subfolders; selecting a node filters the item list/preview scope.
-
FR-1.3 Each node displays the total media file count (photos + videos) within that folder including all nested subfolders.
FR-2 Indexing
-
FR-2.1 On selecting a root, the app creates/updates an index of photos and videos (configurable extensions: jpg/jpeg/png/heic/webp/mp4/mov/avi/mkv, etc.).
-
FR-2.2 Each discovered file is added with initial score = 3.
-
FR-2.3 The index stores: absolute path, file size, modified time, hash (optional), duration (video), orientation + EXIF date (photo), and current score.
-
FR-2.4 Index updates are incremental on subsequent launches (detect adds/removes/moves).
-
FR-2.5 Index file is stored at the root as
.media_index.sqlite
(or.json
for MVP).
FR-3 Preview & Scoring
-
FR-3.1 The app starts previewing media from the current selection/folder.
-
FR-3.2 Right‑click on preview adds +1 to the current file’s score (max 5).
-
FR-3.3 Left‑click on preview deducts −1 from the current file’s score (min 1).
-
FR-3.4 Keyboard shortcuts (optional but recommended):
↑
= +1,↓
= −1,Space
= next,Backspace
= previous. -
FR-3.5 The preview loop auto‑skips any item with score 1 or 5.
-
FR-3.6 When the current pass ends, the app circles back to files that are still score 2/3/4 until all files are 1 or 5.
-
FR-3.7 Video preview defaults to the first 5 seconds (toggle to full playback); photo preview fits to window with zoom/pan.
FR-4 Move & Delete
-
FR-4.1 Whenever a file’s score becomes 1, the app moves it to a sibling folder named
todelete
under its original parent (create if missing). Preserve subfolder structure relative to the root. -
FR-4.2 When all files within the selected scope are either 1 or 5, show “clean up completed”.
-
FR-4.3 Prompt: “Delete all files scored 1?” If the user confirms, permanently delete those files (see Safety below), then delete the index file.
-
FR-4.4 After deletion, recursively remove empty folders (folders with no files in them or any of their subfolders).
FR-5 Progress & Status
-
FR-5.1 Show counts: total, scored 1, scored 5, remaining (2/3/4).
-
FR-5.2 Status bar indicates current folder, preview position (e.g., 120/3,482), and pass number.
FR-6 Settings
-
FR-6.1 Configure included file extensions.
-
FR-6.2 Toggle confirm‑before‑move (default off) and confirm‑before‑delete (default on, cannot be disabled in v1).
-
FR-6.3 Option to send deletes to OS Trash/Recycle Bin instead of hard delete (recommended default).
6) Non‑Functional Requirements
-
Performance: Index 50k files in ≤ 5 minutes on SSD; preview latency ≤ 150 ms for images, ≤ 500 ms to start video.
-
Reliability: Crash‑safe index writes (transactional); resume last session state.
-
Security: No network access by default; operates only on local paths with explicit user selection.
-
Accessibility: All actions available via keyboard; high‑contrast option.
7) UX & Screens
-
Main layout: Left = folder tree with counts; center = preview; right = metadata + score display; bottom = controls & status.
-
Contextual HUD: Big overlay briefly shows new score after click (e.g., “Score: 4”).
-
Completion dialog: Summary of items to be deleted; irreversible‑action warning.
8) Data Model (SQLite Suggestion)
TABLE media (
id INTEGER PRIMARY KEY,
path TEXT UNIQUE NOT NULL,
rel_path TEXT NOT NULL,
folder_id INTEGER NOT NULL,
type TEXT CHECK(type IN ('photo','video')),
score INTEGER NOT NULL DEFAULT 3 CHECK(score BETWEEN 1 AND 5),
size_bytes INTEGER,
mtime_utc TEXT,
duration_ms INTEGER,
exif_datetime TEXT,
hash TEXT,
FOREIGN KEY(folder_id) REFERENCES folders(id)
);
TABLE folders (
id INTEGER PRIMARY KEY,
path TEXT UNIQUE NOT NULL,
rel_path TEXT NOT NULL,
total_count INTEGER NOT NULL DEFAULT 0
);
INDEX idx_media_folder ON media(folder_id);
INDEX idx_media_score ON media(score);
9) Scoring & Preview Algorithm (Reference)
function triageLoop(scope):
queue = all media in scope where score IN (2,3,4)
while queue not empty:
item = queue.popNext()
showPreview(item)
action = waitForUserClick()
if action == RIGHT_CLICK: item.score = min(5, item.score + 1)
if action == LEFT_CLICK: item.score = max(1, item.score - 1)
persistScore(item)
if item.score == 1: moveToToDelete(item)
if item.score in (2,3,4): queue.enqueue(item) // circle back later
if all items in scope have score in (1,5):
showCleanupCompleted()
if confirm("Delete all files scored 1?"):
deleteAllScoreOne(scope)
deleteIndex()
pruneEmptyFolders(scope.root)
10) File Operations & Safety
-
Moves and deletes must be atomic where possible; fall back with clear error messages.
-
During delete: if setting is “send to OS Trash,” use platform APIs; otherwise perform hard delete after confirmation.
-
Skip/record failures (e.g., permission denied, locked file) and continue; show a completion report.
11) Module Breakdown (Modularization)
-
app/
-
main
(bootstrap, window, routing) -
config
(settings load/save) -
i18n
(strings)
-
-
indexer/
-
scanner
(walk filesystem) -
metadata
(EXIF/video probes) -
store
(SQLite/JSON abstraction)
-
-
preview/
-
image_viewer
(render, zoom, pan) -
video_player
(playback, scrub)
-
-
scoring/
-
controller
(event handling, queue policy) -
state
(session state, resume)
-
-
ui/
-
folder_tree
(counts, toggles) -
status_bar
,hud
,dialogs
-
-
ops/
-
mover
(totodelete
) -
deleter
(trash/hard delete, prune empty dirs) -
reporter
(summary & logs)
-
Each module ships in a separate source file (or cohesive files) with narrow interfaces to ease updates and feature additions.
12) Acceptance Criteria
-
AC‑1: Selecting a root shows a tree with accurate counts (children included).
-
AC‑2: All files are assigned score 3 on first index.
-
AC‑3: Left/Right clicks adjust score exactly by −1/+1; scores clamp to .
-
AC‑4: Preview loop never shows items already at 1 or 5.
-
AC‑5: Files at score 1 are moved to
todelete/
under their original parents. -
AC‑6: When no items remain at 2/3/4, “clean up completed” appears.
-
AC‑7: On confirmation, all score‑1 files are deleted, the index file is removed, and empty folders are pruned.
13) Future Enhancements (Non‑blocking)
-
Duplicate detection (perceptual hash).
-
Sorting heuristics (by similarity, face detection, blurriness).
-
Multi‑root projects; exportable CSV reports.
-
Undo/redo stack and checkpoints.
14) Technology Options for a Windows App — Comparison
The app is Windows‑first with heavy filesystem work and image/video preview. Below is a pragmatic comparison of common stacks.
14.1 Quick Matrix (higher is better)
Tech | Perf. | Memory | Dev Speed | Native Win Integration | Cross‑Platform | Media Preview Maturity | Packaging |
---|---|---|---|---|---|---|---|
.NET WPF (.NET 8) | 5 | 4 | 4 | 5 | 2 | 5 | MSIX/WiX/WinGet |
.NET WinUI 3 (Windows App SDK) | 5 | 4 | 3 | 5 | 2 | 5 | MSIX/WinGet |
.NET MAUI (Windows target) | 4 | 4 | 3 | 4 | 4 | 3 | MSIX |
Avalonia UI (.NET) | 4 | 4 | 4 | 3 | 5 | 3 | MSIX/others |
Qt (C++/QML) | 5 | 5 | 3 | 4 | 5 | 5 | MSI/WiX |
Flutter (Windows) | 4 | 4 | 3 | 3 | 5 | 3 | MSIX |
Electron (JS/TS) | 3 | 2 | 5 | 3 | 5 | 4 | Squirrel/MSIX |
Tauri (Rust + WebView) | 4 | 5 | 3 | 3 | 5 | 3 | MSI/MSIX |
Python (PySide/PyQt/PyInstaller) | 3 | 3 | 4 | 3 | 5 | 3 | EXE/MSI |
Legend: 1–5 relative score. Memory = smaller footprint → higher score.
14.2 Notes & Pros/Cons
.NET WPF
-
Pros: Battle‑tested on Windows, excellent filesystem APIs, stable MVVM ecosystem, great tooling (Visual Studio, Rider). Easy thumbnails via WIC; video via Media Foundation or FFmpeg wrappers. Mature SQLite + EXIF libs.
-
Cons: Windows‑only; legacy XAML patterns but still first‑class.
-
Use when: You want the most stable Windows‑native path with top‑tier performance and full access to Windows codecs.
.NET WinUI 3 (Windows App SDK)
-
Pros: Modern WinUI controls, high‑DPI, fluent styling, future‑facing Windows stack. Deep integration with Windows features.
-
Cons: Some APIs/tooling still evolving; smaller community than WPF. Edge cases with third‑party controls vs WPF.
-
Use when: You want modern Windows look/feel and can accept newer‑stack tradeoffs.
.NET MAUI (Windows)
-
Pros: Same codebase can target Mac/iOS/Android; Windows layer sits on WinUI 3. Good for shared business logic.
-
Cons: Desktop maturity below WPF/WinUI; media preview/video plugins less polished for Windows.
-
Use when: Cross‑platform is a real requirement and you’re already in .NET.
Avalonia UI (.NET)
-
Pros: Cross‑platform WPF‑like XAML; good theming; solid desktop focus.
-
Cons: Fewer off‑the‑shelf media components; you’ll likely embed FFmpeg/LibVLC for video.
-
Use when: You want .NET + cross‑platform with a desktop‑first mindset.
Qt (C++/QML/QtQuick)
-
Pros: High performance, native feel, very mature multimedia (Qt Multimedia) and EXIF/DB tooling, excellent for large libraries.
-
Cons: C++ complexity; commercial licensing for some use cases; larger dev ramp.
-
Use when: You need top performance and true cross‑platform with robust media.
Flutter (Windows)
-
Pros: Single codebase; fast UI iteration; strong 2D GPU rendering.
-
Cons: Desktop plugins for advanced media/filesystem are still catching up vs native.
-
Use when: You have Flutter expertise and want cross‑platform UIs.
Electron (JS/TS)
-
Pros: Web skills, rapid UI dev, rich ecosystem. Chromium can preview many image/video formats; Node for filesystem.
-
Cons: Larger memory footprint; packaging/signing friction; native OS feature gaps.
-
Use when: Team is web‑heavy and footprint isn’t critical.
Tauri (Rust + WebView)
-
Pros: Tiny binaries and memory; secure; Rust for native ops; modern WebView front‑end.
-
Cons: Media playback often requires native plugins/FFmpeg; fewer production examples for heavy media.
-
Use when: You want Electron‑style dev with an order‑of‑magnitude smaller footprint and can handle native media plumbing.
Python (PySide/PyQt)
-
Pros: Quick prototyping; rich libraries; Qt underneath.
-
Cons: Packaging size, startup time, and distribution quirks; perf below C#/C++.
-
Use when: You need rapid iteration and internal tooling; less ideal for mass distribution.
14.3 Media‑Specific Considerations for This App
-
Thumbnailing & EXIF: WIC + MetadataExtractor (.NET) or Qt’s
QImageReader
+ Exiv2/QtEXIF are robust. -
Video preview: Windows Media Foundation (native/.NET wrappers) or FFmpeg/LibVLC for broad codec coverage. Browser engines (Electron/Flutter WebView) support common codecs but may choke on edge formats.
-
Large library indexing: Prefer SQLite (system.data.sqlite/.NET; QtSql/SQLite; rusqlite for Rust). Use incremental scans and file hashing on demand.
14.4 Packaging & Updates
-
Windows‑native: MSIX (WinGet), or MSI/WiX; code‑signing cert required.
-
Web stacks: Electron → Squirrel/MSIX; Tauri → MSI/MSIX. Auto‑update channel recommended but must be code‑signed.
14.5 Recommendation
For Windows‑only and fastest path to a polished tool: .NET (WPF or WinUI 3).
-
Pick WPF if you want maximum stability and ecosystem breadth.
-
Pick WinUI 3 if you want a modern Fluent look and don’t mind a newer stack.
If small footprint and you’re comfortable binding native media: Tauri (Rust backend with FFmpeg/LibVLC + WebView UI).
If cross‑platform with strong media and you’re OK with C++: Qt (C++/QML).
14.6 Suggested Starter Kits
WPF (.NET 8)
-
Imaging: WIC via
BitmapImage
; EXIF:MetadataExtractor
-
Video: Media Foundation (
MediaElement
alternatives) orFFmpeg.AutoGen
-
DB:
System.Data.SQLite
-
Packaging: MSIX + WinGet
WinUI 3
-
UI: Windows App SDK templates;
MediaPlayerElement
for video -
Same EXIF/DB approach as WPF; MSIX packaging
Tauri
-
Backend: Rust (filesystem scan, SQLite, FFmpeg/LibVLC bindings)
-
Frontend: React/Svelte/Vue in WebView; invoke via Tauri commands
-
Installer: Tauri bundler → MSI/MSIX
Qt (C++/QML)
-
Media:
QMediaPlayer
/QVideoSink
, thumbnails withQImageReader
-
EXIF: Exiv2; DB:
QtSql
+ SQLite -
Installer: WiX/MSI
沒有留言:
張貼留言