- Python 97%
- Shell 1.7%
- PowerShell 1.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
## Summary - **Issue #185** — Close Directory and Delete Cache (and app exit with "Always delete cache when closing workspace or exiting") no longer sync the local cache back to the network share before deleting it. Both paths now remove the share's colocated cache copy instead, so a later open of the same share doesn't hydrate the discarded tags/thumbnails back in. Directory switch and exit/close *without* delete-cache are unchanged and still sync. - **Issue #186** — Tag Filter now reliably resets to Settings → Tag Filter defaults on every Open Directory, including auto-open of the last directory on startup. `_apply_tag_filter_defaults()` now forces an immediate view refresh, and session restore takes a `directory_open_pending` flag (computed in `main.py`) so it skips restoring the persisted Tag Filter whenever an auto-open is about to run right after — removing a race against `open_directory()`'s own reset. ## Changes - `src/bulk_image_organizer/ui/main_window.py`: `_delete_share_cache_files()`, `_finalize_workspace_close(sync_to_share=...)`, `_on_close_directory_and_cache()`, `closeEvent()`, `_apply_tag_filter_defaults()`, `restore_session_if_available()` / `_restore_session_state()`. - `src/bulk_image_organizer/main.py`: compute and pass `directory_open_pending`. - Docs: `CHANGELOG.md` (0.9.4), `docs/DECISIONS.md` (DR-015, DR-021), `docs/DESIGN.md`, `resources/help/USER_GUIDE.md`. - `VERSION` bumped 0.9.3 → 0.9.4 (compiled inputs changed). ## Test plan - [x] `ruff check .` / `ruff format --check .` - [x] Full `pytest` suite (799 passed, 1 skipped) - [x] New/updated tests: `tests/test_pr13_config.py` (close-directory/app-exit network-sync coverage, session-restore-pending coverage), `tests/test_tag_filter_enhancements.py::test_open_directory_resets_tag_filter_to_defaults` - [x] `python -m pip install -e .` + `scripts/get-version.py --canonical` → `0.9.4` Fixes #185, fixes #186. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> https://claude.ai/code/session_01TrNqVfQQpmRfwhoUkKkkiJ Reviewed-on: #189 |
||
| .forgejo/ISSUE_TEMPLATE | ||
| .github/workflows | ||
| .grok/agents | ||
| docs | ||
| resources | ||
| scripts | ||
| src/bulk_image_organizer | ||
| tests | ||
| .gitignore | ||
| AGENTS.md | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| DEVELOPMENT.md | ||
| LICENSE | ||
| pyproject.toml | ||
| README.md | ||
| VERSION | ||
Bulk Image Organizer
A fast, keyboard-centric desktop application for power users who need to review, tag, deduplicate, and organize large batches of images—1,000 to 10,000 or more—in a single directory tree.
Everything stays on your machine. Tags and staging for deletion replace destructive edits until you explicitly confirm. Duplicate detection is ad-hoc—you run it when you need it. The filesystem is always the source of truth; a portable cache database beside your images keeps thumbnails and metadata fast.
Supported formats: JPEG, PNG, WEBP, TIFF, GIF, BMP (HEIC/HEIF not supported). Subsets can be enabled/disabled globally in Settings → Image Types; disabled formats are ignored by scans.
Platforms: Windows 11 and Linux (tested on Linux Mint)
Why Bulk Image Organizer?
Large photo dumps, wallpaper collections, and download folders are painful to triage in a file manager. Bulk Image Organizer is built for that workflow:
- Non-destructive by default — Tag images or stage them for deletion; nothing hits the recycle bin until you confirm.
- Responsive at scale — Background scanning and lazy thumbnails keep the UI usable while tens of thousands of files are indexed.
- Tag-driven organization — Filter, sort, bulk-assign, and sort into folders by tag.
- Ad-hoc duplicate tools — Exact and perceptual duplicate scans on demand.
- Keyboard-first — Customizable shortcuts across grid, viewer, duplicates, and trash workbenches.
Features
Grid workbench
- Recursive directory scan with progressive thumbnail loading
- Adjustable thumbnail size (display scale and cache resolution in Settings)
- Multi-select, sorting (filename, date, size, resolution, tag priority), text search, and tag filtering (any selected tag, untagged-only, hide staged deletions, horizontal/vertical orientation)
- Tag badges on thumbnails; prominent red overlay on images staged for deletion
- Session undo/redo for tag assignment, deletion staging, and crop (
Ctrl+Z/Ctrl+Y)
Image viewer
- Full-resolution zoom, pan, and fit
- Carousel and filmstrip navigation (global preferences)
- Rotation saved to the image file after a short debounce
- From Grid: horizontal mirror and interactive crop (aspect presets, undoable; originals backed up under
.originals/) - Metadata bar for filename, resolution, file size, and tags; compare coloring in duplicate Single mode
- Background preloading of adjacent images for smooth prev/next
Tagging
- Unlimited custom tags per workspace, with fourteen preset colors (including black and white) or a custom picker
- New Tag, Bulk Create, Export Tags, and Create from Sub-directories
- Single-click toggles tags on the current selection; creation requires an open directory
- Tag toolbox: middle-click excludes a tag from the Tag Filter, right-click filters to that tag only and jumps to the first match, Ctrl-click assigns a
0–9hotkey - Stage images for deletion to review them later in the Trash workbench (Delete or keypad
.) - Sort into Folders… moves singly tagged images into subfolders named after that tag; optional multi-tag folder names
Duplicates workbench
Duplicate detection is ad-hoc. When you run a scan:
- Exact duplicates — Full-file cryptographic hash (
F-DUPE_#tags) - Visual duplicates — Perceptual hash with configurable similarity (
V-DUPE_#tags)
Review groups in Dupe Grid, a comparison Multi view, or Single viewer. Keep stages lower-quality copies for deletion using a chosen criterion. Duplicate membership is ordinary tags—you can rename, recolor, or remove them like any other tag.
Trash workbench
- Review everything staged for deletion without grid overlays
- Confirm Delete sends displayed rows to the system recycle bin via
send2trash - Filter-scoped Clear Deleted Flag and Unset Applied Tags
Settings & help
- Dark and light themes
- Customizable global keyboard shortcuts
- Startup, tag-filter defaults, thumbnail cache, duplicate defaults, viewer modes, and advanced tunables
- Bundled user guide and About dialog inside the app
Data & privacy
- All processing is local; no network features beyond optional workspace-cache sync for network folders
- Local folders:
.bulk_image_organizer.dblives beside your images and travels with the folder - Network folders: Thumbnails stay on your computer; the full cache can optionally sync to the share when you close the workspace
Quick start
Run a packaged build
Linux — Extract a release tarball, then run the bulk_image_organizer binary inside.
Windows — Run bulk_image_organizer.exe. On first launch, Nuitka unpacks into %LOCALAPPDATA%\ValleyGeek\Bulk Image Organizer\. Launching a newer build removes unpack folders from older versions/builds under that path, so only the currently running build's files are kept there.
Run from source
git clone <repository-url>
cd bulk-image-organizer
python -m venv .venv
source .venv/bin/activate # Linux/macOS
# .venv\Scripts\activate # Windows
pip install -e ".[dev]"
python -m bulk_image_organizer
On Linux, ./scripts/launch-linux.sh sets up the virtual environment, installs dependencies if needed, and configures Qt platform plugins.
Command-line options
Both python -m bulk_image_organizer and the packaged executables accept command-line options — an optional directory to open immediately, --version, --theme, --no-auto-scan, --no-restore-session, --log-level, --debug, and --config-dir/--portable to relocate the global settings database. Run with --help for the full list. On Windows, run the .exe from an existing Command Prompt or PowerShell window to see this output — a normal double-click launch has no console attached by design.
Basic workflow
- Open a directory (
Ctrl+O) — The app scans in the background and fills the grid as thumbnails are ready. - Tag and filter — Create tags with New Tag, Bulk Create, or Create from Sub-directories in the right column; use Tag Filter on the sub-toolbar to narrow the grid.
- Review in the viewer — Double-click or press Enter; use arrow keys, carousel, or filmstrip to move through images.
- Find duplicates (optional) — Switch to Duplicates, run an exact or visual scan, review groups, and use Keep.
- Clean up — Stage rejects for deletion, review them in Trash, then confirm delete to send files to the recycle bin.
- Organize — Use Sort into Folders… for tagged images.
Default shortcuts and full workbench details are in the in-app Help guide (resources/help/USER_GUIDE.md).
Building releases
Linux — AppImage (BulkImageOrganizer_{version}.AppImage) or standalone folder under build/linux/:
./scripts/build-linux-appimage.sh
./scripts/build-linux.sh
Windows — single executable in an output directory (BulkImageOrganizer_{version}.exe):
scripts\manual-build-windows.ps1 -OutputPath C:\builds
CI runs lint and tests first, then parallel Linux AppImage and Windows release jobs. main publishes versioned Forgejo releases (v{version}) with both .AppImage and .exe artifacts; development branches publish dev-{branch-slug} releases with branch-named artifacts that are pruned when the branch is deleted. Versioning policy: docs/VERSIONING.md. See DEVELOPMENT.md for local validation, test layout, and contributor workflow.
Security scanning
Nuitka-compiled binaries (especially Windows .exe files) are sometimes flagged by antivirus software as false positives due to how compiled Python code is structured. Both release CI jobs scan their build artifact before publishing it, so you can verify a release independently of that risk:
- ClamAV scans the artifact after it's built; a detection fails the build, so a published release was never flagged by ClamAV's signature database at build time.
- Static analysis runs
checksec/readelf/fileon the Linux AppImage and an Authenticode signature check + PE section/entropy dump (viapefile) on the Windows executable. This is informational only and never fails the build. - VirusTotal (optional — only runs when the
VT_API_KEYsecret is configured) uploads the artifact for a multi-engine scan and links the report. Also informational only.
Each job's summary (visible on the workflow run page) includes the artifact's SHA256 hash and the scan results — compare the hash against what you downloaded, and check the summary before trusting a build if you're unsure. The scanning logic lives in scripts/security-scan-artifact.py and scripts/virustotal-scan.py.
Development
ruff check .
ruff format --check .
pytest
Architecture, design decisions, and the implementation history live in docs/DESIGN.md, docs/TECHNICAL_OUTLINE.md, and docs/DECISIONS.md.
License
MIT License. You may use, modify, and distribute this software freely. Redistributions and derivative works must include the original copyright notice and license text, attributing Bulk Image Organizer to its authors.