Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

iPhone Photo Lister

Direct AFC access to /DCIM and PhotoData/Photos.sqlite. No backup, no MTP/WPD layer. Includes hidden, trashed, and hidden-from-Explorer files -- confirmed against a real device: 327 files in DCIM, 40 hidden, 16 trashed, 3 non-empty albums resolved correctly.

Install

pip install -r requirements.txt

Linux

usbmuxd is usually already running if GVFS can see the iPhone. Check with:

systemctl status usbmuxd

If missing: pacman -S usbmuxd (or libimobiledevice, which pulls it in as a dependency).

Windows

  1. Install Apple Mobile Device Support -- via iTunes (Microsoft Store or apple.com) or a standalone extract of the MSI.
  2. Confirm the Apple Mobile Device Service is running (services.msc).
  3. On first connect, tap "Trust This Computer" on the phone -- this step can't be skipped, it's enforced by the lockdown protocol itself.

No code changes needed after that. create_using_usbmux() finds the right transport on any OS.

Usage

python main.py list
python main.py list --with-labels
python main.py list --with-labels --json result.json
python main.py export ./out                    # everything
python main.py export ./out --hidden            # only hidden photos
python main.py export ./out --trashed           # only Recently Deleted
python main.py export ./out --favorite          # only favorites
python main.py export ./out --album Twitter     # only photos in this album
python main.py download /DCIM/100APPLE/IMG_0001.HEIC ./IMG_0001.HEIC

export downloads matching files into a local directory in one batch, printing progress as it goes. Filters can't be combined (e.g. --hidden --album X isn't AND/OR-composable in this version -- only one filter is applied at a time, whichever is set). If a filter flag needs Photos.sqlite data, export pulls it automatically first. Files with the same name from different 10xAPPLE folders get prefixed with the folder name to avoid overwriting each other.

--with-labels pulls Photos.sqlite over AFC and joins hidden/trashed/favorite/album data onto each file. Without it, list only does the DCIM walk.

export-all

python main.py export-all ./out

Downloads every photo once, then sorts into:

./out/                 -- plain photos: not hidden, not trashed, not in any album
./out/HIDDEN/          -- hidden photos
./out/TRASHED/         -- Recently Deleted
./out/<album name>/    -- one folder per non-empty album
./out/.cache/          -- actual downloaded files (hidden folder, don't touch)

A photo can appear in more than one folder -- iOS doesn't remove a photo from an album when it's hidden or moved to Recently Deleted, so e.g. a hidden photo that's also in "Twitter" shows up in both HIDDEN/ and Twitter/. Each file is downloaded from the device exactly once into .cache/; every other location is a hardlink to that same file (same inode, zero extra disk space, works without admin rights on Windows -- unlike symlinks). Falls back to a real copy if hardlinking fails (e.g. output dir on a different filesystem than expected).

Notes on Photos.sqlite

  • Path is /PhotoData/Photos.sqlite, same AFC root as /DCIM. Mobilebackup2Service was tried first but throws BackupFilterPasswordRequiredError as soon as a domain filter is applied, even on an unencrypted backup -- that's a protocol-level restriction, not something fixable with different parameters.
  • -wal/-shm side files are pulled too when present, since they can hold the latest writes not yet checkpointed into the main file.
  • The asset-album join table (e.g. Z_30ASSETS) has a device-specific number in its name that does not necessarily match the number in its own column names -- observed Z_30ASSETS with columns Z_3ASSETS / Z_30ALBUMS. Resolved by column suffix, not by parsing the number.
  • ZGENERICALBUM.ZKIND = 2 is the only kind that maps to a real user-created album. Other kinds are Apple smart albums (ZTITLE usually NULL) or sync bookkeeping rows with a non-null title (e.g. progress-fs-import at ZKIND ~3570-3573) -- both excluded.
  • ZASSET schema varies across iOS versions (ZADDITIONALASSETATTRIBUTES and similar tables appeared in later releases). Columns are resolved by name with fallback candidates rather than assumed fixed.

Known gaps

  • .MISC under DCIM is skipped by default (afc_lister.py, folder names starting with .). Remove that check if it turns out to hold media too.

About

Python utility to quickly export your photo library

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages