- Each source folder now has its own recursive flag (checkbox on add,
toggle badge on its chip). scan_folder/sync_metadata_from_folder both
honor it, so "top-level only" actually excludes subfolders end-to-end
instead of just the tagging queue while sync still scanned recursively.
- New /api/set_folder_recursive to flip an existing folder's mode without
removing/re-adding it.
- SAFETY FIX: found while testing — when the configured folder list is
empty, the app fell back to the parent directory of wherever server.py
lives, which for a typical install (PHOTON dropped directly in the
user's home folder) means defaulting to the entire home directory.
Caught this before any scan/start actually ran against it. Fixed so an
explicitly-configured empty list (config file exists, list is empty)
is respected as "zero folders" instead of silently substituted with a
guessed default — the guessed default now only applies on a genuinely
fresh install where no config file exists yet at all.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Server: S.folder (singular) -> S.folders (list). New /api/add_folder
and /api/remove_folder endpoints; /api/scan and /api/choose_folder
updated to work with the list (choose_folder now appends instead of
replacing). Legacy single-folder config migrates transparently.
- All folders feed one combined pending queue/journal/search, per the
simpler of the two designs discussed.
- organize_alias now resolves each photo's own source folder via
find_owning_folder(), so category aliases land next to the original
instead of in one designated folder -- verified live with two
configured folders that the alias for each photo lands in its own
folder and nothing leaks into the other.
- Delete path-safety, thumbnail/photo serving, resolve_portable_path,
undo_all, and sync-on-scan all extended to check/act across every
configured folder instead of just one.
- Frontend: folder list renders as removable chips; Add (typed path) and
Browse (native picker, now appends) both wired to the new endpoints;
Rescan All re-scans the current set without changing it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Stop/pause could block the downscale thread for up to 60s and throw an
unhandled exception on shutdown; queue puts are now stop-aware
- /api/delete_photo(s) now refuse to delete anything outside the
configured photo folder
- organize_alias used a stale startup-time default folder instead of the
folder actually being scanned/tagged
- journal_write is append-only, so retagging a photo left stale duplicate
lines that inflated category counts and search results; reads now dedupe
by path and the journal is compacted once on startup
- batch delete now does one journal rewrite for the whole set instead of
one per file
- add PHOTON.app: a signed, dependency-free Swift menu-bar app that starts
server.py in the background (or attaches to an already-running instance),
opens the console, and exposes Open/Restart/Stop/Show Log/Quit
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Search & Edit becomes a multi-view library: Tagged/Untagged/Failed/Videos/Duplicates
- Bulk select (click, shift-click range, select-all-matching) with bulk recategorize,
CSV/JSON export, and original-quality ZIP download (verified byte-identical)
- Video browsing/tagging via ffmpeg frame extraction, native playback with range support
- Duplicate detection via a lightweight perceptual-hash index (no new dependencies)
- Full-resolution photo/video viewer with editable metadata, prev/next navigation
- Date range, file-type, and category quick-filters; saved searches (localStorage)
- Appearance settings: accent color picker, grid density, results-per-page; full dark mode
- Auto-detects its photo folder (CLI arg > env var > last used > parent directory),
so the app can be dropped into any photo collection and just work