Skip to content

Instantly share code, notes, and snippets.

@adisbladis
Last active March 5, 2022 15:38
Show Gist options
  • Save adisbladis/dac5943d29f12ab08cd9002dcc263968 to your computer and use it in GitHub Desktop.
Save adisbladis/dac5943d29f12ab08cd9002dcc263968 to your computer and use it in GitHub Desktop.
Download all photos from an iCloud account
#!/usr/bin/env python
'''Download all iCloud albums in parallel
Should work on python 2.7/3.x with the following installed:
https://pypi.python.org/pypi/pyicloud/
https://pypi.python.org/pypi/pycurl/
https://pypi.python.org/pypi/futures/ (included in Python 3)
'''
from concurrent.futures import ThreadPoolExecutor
from getpass import getpass
import pyicloud
import os.path
import pycurl
import sys
import os
if sys.version_info[0] == 2:
input = raw_input # noqa
# pyicloud requires some monkey-patching to work with python3
if sys.version_info[0] == 3:
import urllib
from urllib.parse import unquote
urllib.unquote = unquote
class PhotoAlbum(pyicloud.services.photos.PhotoAlbum):
def _parse_binary_feed(self, *args):
return list(super()._parse_binary_feed(*args))
pyicloud.services.photos.PhotoAlbum = PhotoAlbum
def download_photo(url, outfile, dl_size):
try:
stat = os.stat(outfile)
except OSError:
pass
else:
if stat.st_size != dl_size:
print('Size mismatch for "{}": {} != {}'.format(
outfile, stat.st_size, dl_size))
else:
print("Already have {}, skipping".format(outfile))
return
with open(outfile, 'wb') as f:
c = pycurl.Curl()
c.setopt(c.URL, url)
c.setopt(c.WRITEDATA, f)
c.perform()
c.close()
print("Saved {}".format(outfile))
if __name__ == '__main__':
username = input('Username: ')
password = getpass()
api = pyicloud.PyiCloudService(username, password)
with ThreadPoolExecutor(max_workers=8) as e:
try:
os.mkdir('icloud-data')
except OSError:
pass
for photo in api.photos.all:
outfile = os.path.join('icloud-data', photo.filename)
url = photo.versions['original']['url']
dl_size = int(photo.versions['original']['size'])
e.submit(download_photo, url, outfile, dl_size)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment