A fully autonomous Python script that scans your ClaudeSort-organized folders
for Apple Live Photo pairs (HEIC/JPG image + MOV companion), matches them
by Apple's ContentIdentifier UUID via exiftool, renames them with rich
sortable names, and moves them together into a single destination folder—
ready to re-import as Live Photos into Apple Photos.
- Walks both source folders recursively
- Extracts
ContentIdentifierUUID from every.heic,.jpg,.jpeg,.png, and.movfile viaexiftool - A Live Photo image is identified when
LivePhotoVideoIndex(MakerNotes) ANDContentIdentifierare present - Matches images → companion MOVs by shared UUID
- Renames each pair to a rich, sortable name:
2024-06-18_183805_LivePhoto_iPhone15ProMax_CF99FFE1.heic 2024-06-18_183805_LivePhoto_iPhone15ProMax_CF99FFE1.mov - Safely moves (copy + SHA-256 verify + delete source) both files into
/Volumes/MattBook - Local/LivePhotoPairs/ - Writes a JSON manifest for audit and Apple Photos re-import
- macOS (tested on macOS 14+)
- Python 3.9+
exiftool(brew install exiftool)
cd '/Users/mattymatt/Claude Scripts and Venvs/LivePhotoSort'
python3 -m venv venv
source venv/bin/activate
# No pip packages needed — all stdlib./run.sh --dry-run./run.sh./watch_log.sh
# or manually:
tail -f logs/run_YYYYMMDD_HHMMSS.log./stop.sh
# or:
kill $(cat logs/live_photo_sort.pid)kill -9 $(cat logs/live_photo_sort.pid)LivePhotoPairs/YYYY-MM-DD_HHMMSS_LivePhoto_<Model>_<UUID8>.heicLivePhotoPairs/YYYY-MM-DD_HHMMSS_LivePhoto_<Model>_<UUID8>.movLivePhotoPairs/live_photo_manifest.json
- Open Apple Photos
- File → Import…
- Select the
LivePhotoPairsfolder - Since each pair shares the same base name AND retains
ContentIdentifiermetadata, Photos will recognise them as Live Photos automatically
LivePhotoSort/
├── live_photo_sort.py # Main: scan + pair + copy
├── triage_sort.py # Post-process: sort by device + city
├── run.sh # Background launcher
├── stop.sh # Graceful shutdown
├── watch_log.sh # Log tail helper
├── requirements.txt # geopy + tqdm (for triage_sort)
├── venv/ # Python venv
└── logs/ # Runtime logs + PID file
Reorganizes the LivePhoto Import Ready output into a hierarchy by device model and city, with pairs and orphans cleanly separated.
<dest>/sorted/
pairs/
iPhone 14 Pro/
Ventura, California/
2025-02-19_LivePhoto_XXXX.jpeg
2025-02-19_LivePhoto_XXXX.mov
orphans/
stills/
iPhone 12/
Los Angeles, California/
movs/
Unknown Device/
Unknown Location/
triage_geocache.json
source venv/bin/activate
pip install geopy tqdm# Always dry-run first
python triage_sort.py --dry-run
# Full run
python triage_sort.py
# Skip reverse geocoding (use GPS coords as folder names)
python triage_sort.py --no-geo
# Custom paths
python triage_sort.py \
--source "/Volumes/MattBook - Local/LivePhoto Import Ready" \
--dest "/Volumes/MattBook - Local/LivePhoto Sorted"| Flag | Default | Description |
|---|---|---|
--source |
LivePhoto Import Ready volume |
Root of LivePhotoSort output |
--dest |
<source>/sorted |
Output tree root |
--manifest |
Auto (newest manifest_*.json) | Explicit manifest path |
--dry-run |
off | Preview only |
--workers |
8 | Parallel exiftool workers |
--no-geo |
off | GPS coords instead of city names |
--cache |
<dest>/triage_geocache.json |
Geocode cache |