- A command-line tool to download synchronize your iCloud Drive.
- Works on Linux, Windows, and MacOS.
- Run as a scheduled cron task to keep a local backup of your iCloud Drive folders and contents
iCloud Drive Sync's basic operation is as follows:
- Download changes from iCloud Drive to your local filesystem
- Upload files from your local file system to iCloud Drive
- Monitor local file system for changes and apply to iCloud Drive, then repeat from step 1 every --resync-period minutes
iCloud Drive Sync first connects to the iCloud service and begins walking the folder structure in iCloud Drive. It creates local folders under the --directory you provide, if needed and downloads files that have a modification date newer than those that exist. If the file does not exist locally, it is downloaded and its modification time is set to that of the iCloud Drive item. When complete, iCloud Drive Sync then walks the directory structure under --directory and uploads files that are newer or don't exist in iCloud, including directories. When the upload phase is complete, iCloud Drive Sync watches the local filesystem for changes and makes the corresponding add/delete/upload to iCloud Drive. If you delete a local directory and all its children, every filesystem event translates to a webservice call to delete the object, followed by a webservice call to update the parent folder's child objects, so deleting can be slow.
iCloud Drive Sync does not monitor your iCloud Drive to download changes, but does loop every --resync-period minutes effectively brute-forcing a sync to and from iCloud Drive.
Do not use the pyicloud
Python package that can be installed using pip
.
icloudds
depends on my forked version of python pyicloud library implementation https://github.com/gordonaspin/pyicloud. My forked implementation resolves
a retrieval limit of 200 albums (in Photos) and has added features to properly set timestamps of objects uploaded to iCloud Drive.
git clone https://github.com/gordonaspin/pyicloud
cd pyicloud
pip install .
If you need to install Python, see the Requirements section for instructions.
$ python icloudds.py -h
Usage: icloudds.py <options>
Synchronize local folder with iCloud Drive and watch for file system changes
Options:
-d, --directory <directory> Local directory that should be used for
download
-u, --username <username> Your iCloud username or email address
-p, --password <password> Your iCloud password (default: use PyiCloud
keyring or prompt for password)
--cookie-directory </cookie/directory>
Directory to store cookies for
authentication (default: ~/.pyicloud)
--sleep-period <sleep_period> Sleep period before checking if file system
is dirty (default: 60 minutes) [1<=x<=1440]
--resync-period <resync_period>
Resync to/from iCloud Drive every resync-
period minutes (default: 240 minutes)
[1<=x<=1440]
--smtp-username <smtp_username>
Your SMTP username, for sending email
notifications when two-step authentication
expires.
--smtp-password <smtp_password>
Your SMTP password, for sending email
notifications when two-step authentication
expires.
--smtp-host <smtp_host> Your SMTP server host. Defaults to:
smtp.gmail.com
--smtp-port <smtp_port> Your SMTP server port. Default: 587 (Gmail)
[x>=0]
--smtp-no-tls Pass this flag to disable TLS for SMTP (TLS
is required for Gmail)
--notification-email <notification_email>
Email address where you would like to
receive email notifications. Default: SMTP
username
--notification-script PATH Runs an external script when two factor
authentication expires. (path required:
/path/to/my/script.sh)
--log-level [debug|info|error] Log level (default: debug)
--unverified-https Overrides default https context with
unverified https context
--version Show the version and exit.
-h, --help Show this message and exit.
Example:
``` sh
icloudds --directory ./Drive \
--username [email protected] \
--password pass1234 \
--directory Drive/ \
--sync
- Python 3.10+
- pip
- sqlite3
- Install Homebrew (if not already installed):
which brew > /dev/null 2>&1 || /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
- Install Python (includes
pip
):
brew install python
Alternatively, you can download the latest Python 3.x installer for Mac.
sudo apt-get update
sudo apt-get install -y python
If your Apple account has two-factor authentication enabled, you will be prompted for a code when you run the script.
Two-factor authentication will expire after an interval set by Apple, at which point you will have to re-authenticate. This interval is currently two months.
Authentication cookies will be stored in a temp directory (/tmp/pyicloud
on Linux, or /var/tmp/...
on MacOS.) This directory can be configured with the --cookie-directory
option.
You can receive an email notification when two-factor authentication expires by passing the
--smtp-username
and --smtp-password
options. Emails will be sent to --smtp-username
by default,
or you can send to a different email address with --notification-email
.
If you want to send notification emails using your Gmail account, and you have enabled two-factor authentication, you will need to generate an App Password at https://myaccount.google.com/apppasswords
You can store your password in the system keyring using the icloud
command-line tool
(installed with the pyicloud
dependency):
$ icloud --username [email protected]
ICloud Password for [email protected]:
Save password in keyring? (y/N)
If you have stored a password in the keyring, you will not be required to provide a password when running the script.
If you would like to delete a password stored in your system keyring,
you can clear a stored password using the --delete-from-keyring
command-line option:
icloud --username [email protected] --delete-from-keyring
When you run the script for the first time, you might see an error message like this:
Bad Request (400)
This error often happens because your account hasn't used the iCloud API before, so Apple's servers need to prepare some information about your iCloud Drive. This process can take around 5-10 minutes, so please wait a few minutes and try again.
If you are still seeing this message after 30 minutes, then please open an issue on GitHub and post the script output.
This script is available in a Docker image:
docker pull gordonaspin/icloudds:latest
The iamge defines an entrypoint:
ENTRYPOINT [ "icloudds", "-d", "/drive", "--cookie-directory", "/cookies" ]
Usage:
# Downloads all iCloud Drive items to ./Drive
docker pull gordonaspin/icloudds:latest
docker run -it --name icloudds \
-v $(pwd)/Drive:/drive \
-v $(pwd)/cookies:/cookies \
gordonaspin/icloudds:latest \
--username [email protected] \
--sync
On Windows:
- use
%cd%
instead of$(pwd)
- or full path, e.g.
-v c:/icloud/Drive:/drive
Building docker image from this repo and gordonaspin/pyicloud repo image locally:
docker build --tag your-repo/icloudds:latest --progress=plain -f ./Dockerfile.from_repo
docker build --tag your-repo/icloudds:latest --progress=plain -f ./Dockerfile.local
# the pyicloud icloud command line utility
# this will optionally create a python keyring in the container for future use, cookies will go to a tmp folder in the container
docker exec -it icloudds icloud --username [email protected]
# run icloudds -h
docker exec -it icloudds icloudds -h
# start the container with mounts for the Drive folder and cookie storage:
docker run -it --name icloudds -v ~/iCloud\ Drive:/drive -v ~/.pyicloud:/cookies your-repo/icloudds -u [email protected] --sync
Want to contribute to iCloud Drive sync ? Awesome! Check out the contributing guidelines to get involved.