Skip to content

Commit

Permalink
support download portrait
Browse files Browse the repository at this point in the history
  • Loading branch information
yuuxie committed Jan 9, 2024
1 parent 966715d commit fcc7499
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 8 deletions.
63 changes: 61 additions & 2 deletions src/icloudpd/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from icloudpd.email_notifications import send_2sa_notification
from icloudpd.string_helpers import truncate_middle
from icloudpd.autodelete import autodelete_photos
from icloudpd.paths import clean_filename, local_download_path
from icloudpd.paths import clean_filename, local_download_path, filename_with_size
from icloudpd import exif_datetime
# Must import the constants object so that we can mock values in tests.
from icloudpd import constants
Expand Down Expand Up @@ -242,6 +242,17 @@
is_flag=True,
default=False,
)
@click.option(
"--enable-edited-photos",
help="Download the edited photos, such as portrait (default: Not download)",
is_flag=False,
)
@click.option(
"--edited-photo-size",
help="Edited(like portrait) Photo size to download (default: full)",
type=click.Choice(["full", "medium", "thumb"]),
default="full",
)
# a hacky way to get proper version because automatic detection does not
# work for some reason
@click.version_option(version="1.17.3")
Expand Down Expand Up @@ -282,7 +293,9 @@ def main(
delete_after_download: bool,
domain: str,
watch_with_interval: Optional[int],
dry_run: bool
dry_run: bool,
enable_edited_photos: bool,
edited_photo_size
):
"""Download all iCloud photos to a local directory"""

Expand Down Expand Up @@ -337,6 +350,8 @@ def main(
set_exif_datetime,
skip_live_photos,
live_photo_size,
enable_edited_photos,
edited_photo_size,
dry_run) if directory is not None else (
lambda _s: lambda _c,
_p: False),
Expand Down Expand Up @@ -387,6 +402,8 @@ def download_builder(
set_exif_datetime: bool,
skip_live_photos: bool,
live_photo_size: str,
enable_edited_photos: bool,
edited_photo_size: str,
dry_run: bool) -> Callable[[PyiCloudService], Callable[[Counter, PhotoAsset], bool]]:
"""factory for downloader"""
def state_(
Expand Down Expand Up @@ -599,6 +616,48 @@ def download_photo_(counter: Counter, photo: PhotoAsset) -> bool:
"Downloaded %s",
truncated_path
)

# Also download the edited photo (such as portrait) if present
if enable_edited_photos:
edited_size = edited_photo_size + "Edited"
if edited_size in photo.versions:
version = photo.versions[edited_size]
filename = version["filename"]
if edited_photo_size != "full":
filename = f"-{edited_photo_size}.".join(filename.rsplit(".", 1))

edited_download_path = os.path.join(download_dir, filename)
edited_file_exist = os.path.isfile(edited_download_path)
if only_print_filenames and not edited_file_exist:
print(edited_download_path)
else:
if edited_file_exist:
edited_file_size = os.stat(edited_download_path).st_size
edited_photo_size_num = version["size"]
if edited_file_size != edited_photo_size_num:
# The case exists when you edited on a portrait photo
edited_download_path = f"-{edited_photo_size_num}.".join(
edited_download_path.rsplit(".", 1)
)
logger.debug(
"%s deduplicated",
truncate_middle(edited_download_path, 96)
)
edited_file_exist = os.path.isfile(edited_download_path)
if edited_file_exist:
logger.debug(
"%s already exists",
truncate_middle(edited_download_path, 96)
)
if not edited_file_exist:
truncated_path = truncate_middle(edited_download_path, 96)
logger.debug("Downloading %s...", truncated_path)
download_result = download.download_media(
logger, dry_run, icloud, photo, edited_download_path, edited_size)
success = download_result and success
if download_result:
logger.info("Downloaded %s", truncated_path)

return success
return download_photo_
return state_
Expand Down
57 changes: 57 additions & 0 deletions src/pyicloud_ipd/services/photos.py
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,12 @@ def __init__(self, service, master_record, asset_record):
u"thumb": u"resVidSmall"
}

EDITED_VERSION_LOOKUP = {
u"fullEdited": u"resJPEGFull",
u"mediumEdited": u"resJPEGMed",
u"thumbEdited": u"resJPEGThumb",
}

@property
def id(self):
return self._master_record['recordName']
Expand Down Expand Up @@ -667,6 +673,57 @@ def versions(self):

self._versions[key] = version

# Resource for the edited photos (portrait)
# The portrait photo resources are in the
if self.item_type != "movie":
for key, prefix in self.EDITED_VERSION_LOOKUP.items():
if '%sRes' % prefix in self._asset_record['fields']:
f = self._asset_record['fields']

type_entry = f.get('%sFileType' % prefix)

# Follow the convention of "Image Capture" that add E to the beginning.
edited_filename = re.sub(r'_(\d{4})\.', r'_E\1.', self.filename)
if edited_filename == self.filename:
# In case the file name not match the above pattern
edited_filename = f"-EDITED.".join(self.filename.rsplit(".", 1))

# In case the file type extension is not the same as original file.
if type_entry and type_entry['value'] in self.ITEM_TYPE_EXTENSIONS:
file_extension = self.ITEM_TYPE_EXTENSIONS[type_entry['value']]
edited_filename_splits = edited_filename.rsplit(".", 1)
if edited_filename_splits[1] != file_extension:
edited_filename = edited_filename_splits[0] + "." + file_extension

version = {'filename': edited_filename}

if type_entry:
version['type'] = type_entry['value']
else:
version['type'] = None

width_entry = f.get('%sWidth' % prefix)
if width_entry:
version['width'] = width_entry['value']
else:
version['width'] = None

height_entry = f.get('%sHeight' % prefix)
if height_entry:
version['height'] = height_entry['value']
else:
version['height'] = None

size_entry = f.get('%sRes' % prefix)
if size_entry:
version['size'] = size_entry['value']['size']
version['url'] = size_entry['value']['downloadURL']
else:
version['size'] = None
version['url'] = None

self._versions[key] = version

return self._versions

def download(self, version='original', **kwargs):
Expand Down
6 changes: 0 additions & 6 deletions src/starters/icloudpd.py

This file was deleted.

0 comments on commit fcc7499

Please sign in to comment.