This workspace contains a local photo-organization script for macOS. It uses exiftool metadata, filename clues, and optional image inspection to rename and group exported photos and videos.
- Reads EXIF and media timestamps such as
DateTimeOriginal,CreateDate, and QuickTime creation dates. - Uses location tags when they exist. If the file only has GPS coordinates, it uses a coordinate-based location label instead.
- Preserves meaningful words from the current filename when the name is not just a camera default like
IMG_1234. - Optionally inspects image contents with Apple Vision on-device and blends that label with filename or metadata clues.
- Copies or moves files into folders shaped like
YEAR/DATE/LOCATION/. - Can also keep everything in one flat destination folder if you disable subfolders in the job config.
- Renames files using a pattern like
YYYY-MM-DD_HHMMSS_location_descriptor.ext. - Defaults to a dry run so you can preview changes before touching any files.
Edit [photo_organizer_config.json](/Users/anthonylarosa/File Organizer/photo_organizer_config.json) and change the folder paths to the ones you want to organize.
Example defaults:
- Source:
/Users/anthonylarosa/Pictures/Exported Photos - Destination:
/Users/anthonylarosa/Pictures/Organized Photos - Mode:
copy
Use move instead of copy if you want the originals relocated rather than duplicated.
Set "group_in_subfolders": false if you want renamed files to stay in one destination folder instead of being split into date/location folders.
The inspection block controls image-content labels. In the current config it is enabled with "provider": "apple_vision", so it runs locally on your Mac and does not need an API key. Set "enabled" to false if you want to turn that off.
You can launch the native macOS app bundle instead of running terminal commands:
- Open Photo Organizer.app
- Double-click [Photo Organizer.command](/Users/anthonylarosa/File Organizer/Photo Organizer.command)
To rebuild the bundle after code changes:
python3 scripts/build_app_bundle.pyThe .app stores its live config in ~/Library/Application Support/Photo Organizer/photo_organizer_config.json. On first launch it seeds that file from the template bundled from your current workspace config.
The app lets you:
- Pick the source and destination folders
- Switch between copy and move
- Turn local image inspection on or off
- Toggle which filename parts are used: date, time, location, filename words, and image labels
- Keep a flat output folder or group into subfolders
- Preview every rename in a table before anything changes
- Select only the rows you want to organize
- Inspect the full source path, target path, timestamp, location, and labels for the selected row
- Run the organizer and watch the log in one window
The app flow is:
- Pick the source and destination folders.
- Click
Preview Changes. - Review the list and select the files you want to edit.
- Click
Organize Selected.
The app uses one overall confirmation before it changes the selected rows. If you want per-file confirmation, keep using the CLI with --apply --confirm.
The config also supports a naming block if you want to control those filename parts outside the app:
"naming": {
"include_date": true,
"include_time": true,
"include_location": true,
"include_text_descriptor": true,
"include_visual_descriptor": true
}- Make a small test source folder with a few copied photos.
- Point the config
sourceat that test folder. - Point
destinationat an empty test output folder. - If you want a flat output folder, set
"group_in_subfolders": false. - Run a dry run first:
python3 scripts/photo_organizer.py --config photo_organizer_config.json --verbose- If the plan looks right, run with per-file confirmation:
python3 scripts/photo_organizer.py --config photo_organizer_config.json --apply --confirm --verboseThat mode asks before each copy or move. Use y for yes, n to skip, a to approve all remaining files, or q to stop the run.
Run:
python3 scripts/photo_organizer.py --config photo_organizer_config.json --verboseOr combine it with confirmation and apply:
python3 scripts/photo_organizer.py --config photo_organizer_config.json --apply --confirm --verboseThe script uses sips plus a small Swift helper backed by Apple Vision. Results are cached in .photo_organizer_inspection_cache.json so repeated runs do not keep re-inspecting unchanged files in the same source folder.
If you later want cloud-based labels instead, change "provider" to "openai" and set OPENAI_API_KEY.
- Videos still rely on metadata and filename clues. Visual inspection is only used for image files.
- Repeated
copyruns are idempotent for unchanged files. If a matching organized file already exists, the script skips it instead of creating_2,_3, and so on. - If two different files would land on the same name, the script appends
_2,_3, and so on. - Files with no usable timestamp are still organized, but they go under
unknown-year/unknown-date.