Complete file organizer, deduplicator & secure shredder. One engine β CLI, YAML config, GUI all call the exact same
run_job()function.
filevault.py β THE ENGINE (all logic lives here)
βββ run_job(cfg) β single function: CLI, GUI and YAML all call this
filevault_gui.py β GUI frontend: builds same cfg dict, calls run_job()
filevault.yaml β YAML config: loaded to same cfg dict, runs same engine
plugins/ β custom rename rule plugins
There is no gap between GUI and CLI. If a feature works in the GUI, it works from CLI and YAML too.
pip install customtkinter blake3 pymupdf pypdf pikepdf
pip install python-docx openpyxl python-pptx Pillow imagehash
pip install watchdog pyyaml piexif
# CLI β basic
python filevault.py /source /target
# CLI β dry-run, move unique only, no sub-folders
python filevault.py /source /target --dry-run --move-mode unique --no-subfolders
# YAML config
python filevault.py --config filevault.yaml
# GUI (requires display β see VNC setup for Docker)
python filevault_gui.py
# Or launch GUI from CLI
python filevault.py --gui
# Watch mode (real-time daemon)
python filevault.py /source /target --watch
# Scheduler β daily at 2 AM
python filevault.py /source /target --schedule daily --at 02:00
# Undo last job
python filevault.py --undo
# Windows right-click menu (run as Administrator)
python filevault.py --register-context-menu| Flag | Default | Description |
|---|---|---|
source target |
required | Source and target folders |
--config FILE |
β | Load YAML/JSON config (CLI flags override it) |
--dry-run |
off | Preview all actions, zero files touched |
--move-mode |
all |
all / unique / dupes |
--no-subfolders |
off | Dump all files flat in target root |
--subfolder-mode |
unique_dupes |
unique_dupes / by_type / flat |
--passes N |
7 | Shred overwrite passes |
--workers N |
8 | Parallel hash threads |
--no-shred-dupes |
off | Move dupes without shredding source |
--shred-all |
off | Shred even unique files after copy |
--date-prefix |
off | Prefix images with EXIF date |
--no-metadata-rename |
off | Skip smart rename |
--quick-scan |
off | Hash first 4MB only (faster) |
--plugin-dir DIR |
β | Load rename plugins from folder |
--watch |
off | Real-time file watcher daemon |
--schedule |
β | once / daily / interval |
--at TIME |
β | Time for once/daily e.g. 02:00 |
--every N |
60 | Minutes for interval |
--undo |
off | Reverse last job from report |
--no-json/csv/html |
off | Suppress specific report formats |
--register-context-menu |
β | Add Windows right-click menu entry |
--gui |
off | Launch GUI |
| Mode | What happens | Use case |
|---|---|---|
all |
Move unique + dupes, source fully emptied | Full migration |
unique |
Move only unique files, shred dupes in-place, nothing goes to target/duplicates | Clean archive |
dupes |
Move only extra copies to target, unique files stay | Audit duplicates |
| Subfolder Mode | Result |
|---|---|
unique_dupes |
target/unique/ + target/duplicates/ |
by_type |
target/pdf/, target/images/, target/office/, target/other/ |
flat |
All files directly in target/, no sub-folders created |
Set use_subfolders: false in YAML or --no-subfolders in CLI to skip sub-folder creation entirely.
Applies to image files before copy. Configure in YAML:
exif_edits:
remove_gps: true # strip GPS coordinates (privacy)
remove_device: true # strip Make/Model/Software
set_datetime: null # null = remove all date fields
set_author: "Your Name" # set Artist + Copyright
set_description: null # null = remove descriptionOr in GUI: βοΈ Configure β π¬ EXIF Metadata Editor section.
Drop .py files in a folder and point plugin_dir at it:
# plugins/my_rule.py
EXTENSIONS = [".pdf", ".epub"] # or ["*"] for all
def rename(fp, meta) -> str | None:
if meta.get("title"):
return f"[DONE] {meta['title']}{fp.suffix}"
return None # None = skip this plugin# One-time
schedule:
type: once
at: "2026-03-10 02:00"
# Daily
schedule:
type: daily
at: "02:00"
# Every N minutes
schedule:
type: interval
every_minutes: 60Every job writes filevault_report.json. Undo reads it and reverse-moves everything:
python filevault.py --undo # real undo
python filevault.py --undo --dry-run # preview undo
python filevault.py --undo --config filevault.yaml # custom report pathGUI: β©οΈ Undo tab.
| Feature | FileVault | CCleaner | dupeGuru | AllDup |
|---|---|---|---|---|
| Copy integrity gate (verify before shred) | β | β | β | β |
| PDF/eBook smart rename from metadata | β | β | β | β |
| EXIF metadata editor (strip GPS, date, device) | β | β | β | β |
| Plugin system for rename rules | β | β | β | β |
| Watch mode daemon | β | β | β | β |
| Undo last job | β | β | β | β |
| Scheduler (once/daily/interval) | β | β | β | β |
| Windows context-menu integration | β | β | β | β |
| CLI + YAML + GUI same engine | β | β | β | β |
| HTML audit dashboard (offline, shareable) | β | β | β | β |
| Photo perceptual hash (survives recompress) | β | β | β | β |
| DoD secure shred (up to 35 passes) | β | β | β | β |
| Fully open source | β | β | β | β |
pip install customtkinter blake3 pymupdf pypdf pikepdf python-docx openpyxl python-pptx
pip install Pillow imagehash watchdog pyyaml piexifMinimum (no GUI, no smart rename, no perceptual hash):
# Zero extra deps β uses stdlib sha256, basic file ops
python filevault.py /source /targetMIT