# photoscli `photoscli` is a macOS-only command-line exporter for Apple Photos. It uses a small Objective-C PhotoKit bridge from Go to list albums, inspect assets, export optimized previews or originals, keep resumable manifests, and produce machine-readable logs for backup automation. The tool is designed for repeatable, resumable Photos backups rather than one-off drag-and-drop exports. For a practical step-by-step manual with recommended backup workflows, recovery steps, automation examples, and troubleshooting, see `USERGUIDE.md`. ## Highlights - List albums, photos, and the Photos folder/album tree. - Export one album or back up the whole Photos tree. - Export JPEG previews with configurable size and quality, or original files. - Skip already-exported assets through a JSONL or SQLite manifest. - Resume interrupted runs safely. - Parallel export with live worker progress and ETA. - Optional structured logging to `export.log` or SQLite `logs` table. - Dry-run mode for planning large backups. - Filters for favorites, media type, date, estimated size, and excluded albums. - Failure tracking with `failures.jsonl` and `retry-failed`. - Deduplicated failure management with `failures list`, `failures clear`, and `retry-failed --clear-on-success`. - Verification, reporting, and diff commands for backup integrity. - Optional XMP sidecar verification with `verify --sidecar`. - Metadata-only XMP refresh for manifest-backed exports with `--metadata-only`. - Status command for quick backup summaries. - Opt-in rich XMP sidecar metadata with `--sidecar xmp`. - Optional Apple MapKit reverse geocoding for GPS assets on macOS 26+ with `--reverse-geocode`. - Script-friendly exit codes and optional JSON summaries. - 100% test coverage for the Go CLI and parsing layers. ## Requirements - Apple Silicon Mac, M1/M2/M3/M4 or newer (`darwin/arm64`). - macOS with Apple Photos. - Go 1.25 or newer. - Xcode command-line tools. - Photos privacy permission for the built binary or terminal app. The provided release binary is Apple Silicon only. Intel Macs are not currently a supported release target. The production build uses cgo and links against Apple frameworks through the Objective-C bridge in `bridge/`. ## Release Assets Release zip files are named with the supported architecture: ```text photoscli--macos-arm64.zip ``` The zip contains the Apple Silicon binary plus README, USERGUIDE, and CHANGELOG. ## Build ```bash make build ``` The binary is written to: ```bash ./bin/photoscli ``` Run the full local release pipeline: ```bash make pipeline ``` The pipeline cleans artifacts, builds the test bridge, runs vet, runs race-enabled tests with coverage, builds the real PhotoKit bridge, builds the CLI, and verifies the embedded version. ## Quick Start List albums: ```bash ./bin/photoscli albums ``` Inspect an album by title or PhotoKit local identifier: ```bash ./bin/photoscli photos --album-id "Vacation" ``` Export preview JPEGs from one album: ```bash ./bin/photoscli export --album-id "Vacation" --out ./export ``` Export higher-quality previews: ```bash ./bin/photoscli export --album-id "Vacation" --out ./export --size 2048 --quality 92 ``` Export originals: ```bash ./bin/photoscli export --album-id "Vacation" --out ./originals --originals ``` Back up the entire Photos album tree: ```bash ./bin/photoscli backup-all --out ./photos-backup --manifest sqlite --log ``` Preview what would happen before writing anything: ```bash ./bin/photoscli backup-all --out ./photos-backup --dry-run --json ``` Verify a backup later: ```bash ./bin/photoscli verify --out ./photos-backup --manifest sqlite ``` ## Commands ### `albums` Lists user-created albums as tab-separated ID and title. ```bash photoscli albums ``` Example output: ```text 5E9F.../L0/001 Vacation 8A1B.../L0/001 Work ``` ### `photos` Lists assets in an album. `--album-id` accepts a PhotoKit local identifier or an exact album title. ```bash photoscli photos --album-id "Vacation" ``` Output includes ID, filename, cloud state, media type, dimensions, optional creation date, optional duration, and a `*` marker for favorites. ### `tree` Prints the Photos folder and album hierarchy. ```bash photoscli tree ``` ### `export` Exports assets from one album. ```bash photoscli export --album-id --out [flags] ``` Useful examples: ```bash photoscli export --album-id "Family" --out ./family --size 2560 --quality 90 photoscli export --album-id "Favorites" --out ./favorites --only-favorites photoscli export --album-id "Videos" --out ./videos --media videos --include-videos photoscli export --album-id "Archive" --out ./archive --originals --retry 3 photoscli export --album-id "Vacation" --out ./vacation --date-template YYYY/MM/DD photoscli export --album-id "Vacation" --out ./vacation --sidecar xmp --reverse-geocode ``` ### `backup-all` Walks the Photos folder/album tree and exports every album to a matching folder structure. ```bash photoscli backup-all --out [flags] ``` Duplicate sibling album names are disambiguated by adding the album ID to the generated folder name. Useful examples: ```bash photoscli backup-all --out ./backup --manifest sqlite --log photoscli backup-all --out ./backup --exclude-album "Recently Deleted" --exclude-album "Temp*" photoscli backup-all --out ./backup --since 2024-01-01 --sort newest photoscli backup-all --out ./backup --concurrency 8 --retry 3 photoscli backup-all --out ./backup --dry-run --json photoscli backup-all --out ./backup --sidecar xmp --reverse-geocode ``` ### `report` Shows manifest and failure counts for an output directory. ```bash photoscli report --out ./backup --manifest sqlite ``` Example output: ```text entries 12345 failures 2 ``` ### `diff` Compares an album against the manifest and prints assets missing from the manifest. ```bash photoscli diff --album-id "Vacation" --out ./backup --manifest jsonl ``` Exit code is `2` when missing assets are found. ### `verify` Checks that manifest entries have corresponding files on disk. ```bash photoscli verify --out ./backup --manifest sqlite ``` Exit code is `2` when files are missing. ### `retry-failed` Retries assets recorded in `failures.jsonl`. ```bash photoscli retry-failed --out ./backup ``` This is useful after transient iCloud or network failures. Use `--clear-on-success` to remove successfully retried assets from `failures.jsonl`. ### `failures` Lists or clears deduplicated failure records. ```bash photoscli failures list --out ./backup photoscli failures clear --out ./backup ``` ### `status` Shows a quick backup summary. ```bash photoscli status --out ./backup --manifest sqlite photoscli status --out ./backup --manifest sqlite --json ``` ## Export Flags Common flags for `export` and `backup-all`: - `--out `: destination directory. - `--size `: longest-side target for preview export, default `1024`. - `--quality <1-100>`: JPEG preview quality, default `85`. - `--originals`: export original files instead of previews. - `--concurrency `: parallel workers, default `3`, capped by bridge slot count. - `--retry `: retry failed exports with a small backoff. - `--dry-run`: print planned exports without writing files, manifests, or logs. - `--json`: print a machine-readable summary to stdout. - `--verify`: run manifest/file verification after export. - `--sidecar` with `verify`: also verify expected `.xmp` sidecars. - `--log`: enable structured export logging. - `--manifest jsonl|sqlite`: choose manifest backend, default `jsonl`. - `--no-manifest`: disable manifest reads/writes. - `--sort oldest|newest`: asset sort order where supported, default `oldest`. - `--since `: only include assets on or after `YYYY-MM-DD` or RFC3339 date. - `--only-favorites`: only export favorite assets. - `--media photos|videos|all`: media filter, default `photos`. - `--include-videos`: compatibility flag that includes videos/audio. - `--min-size `: filter by estimated pixel count. - `--max-size `: filter by estimated pixel count. - `--format jpeg|heic|png`: preview format hint. Current bridge output is still the existing preview path; non-JPEG bridge output is future work. - `--sidecar none|xmp`: write opt-in XMP metadata sidecars next to exported files. - `--metadata-only`: with `--sidecar xmp`, refresh XMP sidecars for manifest-backed files without exporting media. - `--reverse-geocode`: with `--sidecar xmp`, add cached Apple MapKit address metadata for GPS assets on macOS 26+. - `--date-template