Added --preview-if-missing, #446

This commit is contained in:
Rhet Turnbull
2021-07-04 10:03:36 -07:00
parent 675371f0d7
commit 632169f277
11 changed files with 169 additions and 133 deletions

View File

@@ -1,3 +1,3 @@
""" version info """
__version__ = "0.42.57"
__version__ = "0.42.58"

View File

@@ -709,7 +709,15 @@ def cli(ctx, db, json_, debug):
"--preview",
is_flag=True,
help="Export preview image generated by Photos. "
"This is a lower-resolution image used by Photos to quickly preview the image.",
"This is a lower-resolution image used by Photos to quickly preview the image. "
"See also --preview-suffix and --preview-if-missing.",
)
@click.option(
"--preview-if-missing",
is_flag=True,
help="Export preview image generated by Photos if the actual photo file is missing from the library. "
"This may be helpful if photos were not copied to the Photos library and the original photo is missing. "
"See also --preview-suffix and --preview.",
)
@click.option(
"--preview-suffix",
@@ -717,7 +725,8 @@ def cli(ctx, db, json_, debug):
help="Optional suffix template for naming preview photos. Default name for preview photos is in form "
f"'photoname{DEFAULT_PREVIEW_SUFFIX}.ext'. For example, with '--preview-suffix _low_res', the preview photo "
f"would be named 'photoname_low_res.ext'. The default suffix is '{DEFAULT_PREVIEW_SUFFIX}'. "
"Multi-value templates (see Templating System) are not permitted with --preview-suffix.",
"Multi-value templates (see Templating System) are not permitted with --preview-suffix. "
"See also --preview and --preview-if-missing.",
)
@click.option(
"--download-missing",
@@ -1180,6 +1189,7 @@ def export(
post_function,
preview,
preview_suffix,
preview_if_missing,
):
"""Export photos from the Photos database.
Export path DEST is required.
@@ -1342,6 +1352,7 @@ def export(
post_function = cfg.post_function
preview = cfg.preview
preview_suffix = cfg.preview_suffix
preview_if_missing = cfg.preview_if_missing
# config file might have changed verbose
VERBOSE = bool(verbose)
@@ -1753,6 +1764,7 @@ def export(
export_dir=dest,
export_preview=preview,
preview_suffix=preview_suffix,
preview_if_missing=preview_if_missing,
)
if post_function:
@@ -2409,6 +2421,7 @@ def export_photo(
export_dir=None,
export_preview=False,
preview_suffix=None,
preview_if_missing=False,
):
"""Helper function for export that does the actual export
@@ -2452,6 +2465,7 @@ def export_photo(
export_dir: top-level export directory for {export_dir} template
export_preview: export the preview image generated by Photos
preview_suffix: str, template to use as suffix for preview images
preview_if_missing: bool, export preview if original is missing
Returns:
list of path(s) of exported photo or None if photo was missing
@@ -2598,6 +2612,7 @@ def export_photo(
export_dir=export_dir,
export_preview=export_preview,
preview_suffix=rendered_preview_suffix,
preview_if_missing=preview_if_missing,
)
if export_edited and photo.hasadjustments:
@@ -2682,6 +2697,7 @@ def export_photo(
export_dir=export_dir,
export_preview=not export_original and export_preview,
preview_suffix=rendered_preview_suffix,
preview_if_missing=preview_if_missing,
)
return results
@@ -2759,9 +2775,9 @@ def export_photo_with_template(
export_dir,
export_preview,
preview_suffix,
preview_if_missing,
):
"""Evaluate directory template then export photo to each directory"""
results = ExportResults()
dest_paths = get_dirnames_from_template(
@@ -2770,17 +2786,18 @@ def export_photo_with_template(
# export the photo to each path in dest_paths
for dest_path in dest_paths:
# TODO: if --skip-original-if-edited, it's possible edited version is on disk but
# original is missing, in which case we should download the edited version
if export_original:
if missing:
if missing and not preview_if_missing:
space = " " if not verbose else ""
verbose_(
f"{space}Skipping missing photo {photo.original_filename} ({photo.uuid})"
)
results.missing.append(str(pathlib.Path(dest_path) / filename))
continue
elif photo.intrash and (not photo.path or use_photos_export):
elif (
photo.intrash
and (not photo.path or use_photos_export)
and not preview_if_missing
):
# skip deleted files if they're missing or using use_photos_export
# as AppleScript/PhotoKit cannot export deleted photos
space = " " if not verbose else ""
@@ -2794,12 +2811,16 @@ def export_photo_with_template(
continue
else:
# exporting the edited version
if missing:
if missing and not preview_if_missing:
space = " " if not verbose else ""
verbose_(f"{space}Skipping missing edited photo for {filename}")
results.missing.append(str(pathlib.Path(dest_path) / filename))
continue
elif photo.intrash and (not photo.path_edited or use_photos_export):
elif (
photo.intrash
and (not photo.path_edited or use_photos_export)
and not preview_if_missing
):
# skip deleted files if they're missing or using use_photos_export
# as AppleScript/PhotoKit cannot export deleted photos
space = " " if not verbose else ""
@@ -2815,86 +2836,86 @@ def export_photo_with_template(
while tries <= retry:
tries += 1
error = 0
try:
export_results = photo.export2(
dest_path,
original_filename=filename,
edited=edited,
original=export_original,
edited_filename=filename,
sidecar=sidecar_flags,
sidecar_drop_ext=sidecar_drop_ext,
live_photo=export_live,
raw_photo=export_raw,
export_as_hardlink=export_as_hardlink,
overwrite=overwrite,
use_photos_export=use_photos_export,
exiftool=exiftool,
merge_exif_keywords=exiftool_merge_keywords,
merge_exif_persons=exiftool_merge_persons,
use_albums_as_keywords=album_keyword,
use_persons_as_keywords=person_keyword,
keyword_template=keyword_template,
description_template=description_template,
update=update,
ignore_signature=ignore_signature,
export_db=export_db,
fileutil=fileutil,
dry_run=dry_run,
touch_file=touch_file,
convert_to_jpeg=convert_to_jpeg,
jpeg_quality=jpeg_quality,
ignore_date_modified=ignore_date_modified,
use_photokit=use_photokit,
verbose=verbose_,
exiftool_flags=exiftool_option,
jpeg_ext=jpeg_ext,
replace_keywords=replace_keywords,
render_options=render_options,
preview=export_preview,
preview_suffix=preview_suffix,
)
for warning_ in export_results.exiftool_warning:
verbose_(f"exiftool warning for file {warning_[0]}: {warning_[1]}")
for error_ in export_results.exiftool_error:
click.echo(
click.style(
f"exiftool error for file {error_[0]}: {error_[1]}",
fg=CLI_COLOR_ERROR,
),
err=True,
)
for error_ in export_results.error:
click.echo(
click.style(
f"Error exporting photo ({photo.uuid}: {photo.original_filename}) as {error_[0]}: {error_[1]}",
fg=CLI_COLOR_ERROR,
),
err=True,
)
error += 1
if not error or tries > retry:
results += export_results
break
else:
click.echo(
"Retrying export for photo ({photo.uuid}: {photo.original_filename})"
)
except Exception as e:
# try:
export_results = photo.export2(
dest_path,
original_filename=filename,
edited=edited,
original=export_original,
edited_filename=filename,
sidecar=sidecar_flags,
sidecar_drop_ext=sidecar_drop_ext,
live_photo=export_live,
raw_photo=export_raw,
export_as_hardlink=export_as_hardlink,
overwrite=overwrite,
use_photos_export=use_photos_export,
exiftool=exiftool,
merge_exif_keywords=exiftool_merge_keywords,
merge_exif_persons=exiftool_merge_persons,
use_albums_as_keywords=album_keyword,
use_persons_as_keywords=person_keyword,
keyword_template=keyword_template,
description_template=description_template,
update=update,
ignore_signature=ignore_signature,
export_db=export_db,
fileutil=fileutil,
dry_run=dry_run,
touch_file=touch_file,
convert_to_jpeg=convert_to_jpeg,
jpeg_quality=jpeg_quality,
ignore_date_modified=ignore_date_modified,
use_photokit=use_photokit,
verbose=verbose_,
exiftool_flags=exiftool_option,
jpeg_ext=jpeg_ext,
replace_keywords=replace_keywords,
render_options=render_options,
preview=export_preview or (missing and preview_if_missing),
preview_suffix=preview_suffix,
)
for warning_ in export_results.exiftool_warning:
verbose_(f"exiftool warning for file {warning_[0]}: {warning_[1]}")
for error_ in export_results.exiftool_error:
click.echo(
click.style(
f"Error exporting photo ({photo.uuid}: {photo.original_filename}) as {filename}: {e}",
f"exiftool error for file {error_[0]}: {error_[1]}",
fg=CLI_COLOR_ERROR,
),
err=True,
)
if tries > retry:
results.error.append((str(pathlib.Path(dest) / filename), e))
break
else:
click.echo(
f"Retrying export for photo ({photo.uuid}: {photo.original_filename})"
)
for error_ in export_results.error:
click.echo(
click.style(
f"Error exporting photo ({photo.uuid}: {photo.original_filename}) as {error_[0]}: {error_[1]}",
fg=CLI_COLOR_ERROR,
),
err=True,
)
error += 1
if not error or tries > retry:
results += export_results
break
else:
click.echo(
"Retrying export for photo ({photo.uuid}: {photo.original_filename})"
)
# except Exception as e:
# click.echo(
# click.style(
# f"Error exporting photo ({photo.uuid}: {photo.original_filename}) as {filename}: {e}",
# fg=CLI_COLOR_ERROR,
# ),
# err=True,
# )
# if tries > retry:
# results.error.append((str(pathlib.Path(dest) / filename), e))
# break
# else:
# click.echo(
# f"Retrying export for photo ({photo.uuid}: {photo.original_filename})"
# )
if verbose:
if update:

View File

@@ -770,18 +770,10 @@ def export2(
# get path to source file and verify it's not None and is valid file
# TODO: how to handle ismissing or not hasadjustments and edited=True cases?
export_src_dest = []
if edited:
if self.path_edited is not None:
export_src_dest.append((self.path_edited, dest_edited))
else:
raise FileNotFoundError(
f"Cannot export edited photo if path_edited is None"
)
else:
if self.path is not None:
export_src_dest.append((self.path, dest_original))
else:
raise FileNotFoundError("Cannot export photo if path is None")
if edited and self.path_edited is not None:
export_src_dest.append((self.path_edited, dest_edited))
elif not edited and self.path is not None:
export_src_dest.append((self.path, dest_original))
for src, dest in export_src_dest:
if not pathlib.Path(src).is_file():
@@ -907,7 +899,7 @@ def export2(
all_results += results
# copy associated RAW image if requested
if raw_photo and self.has_raw:
if raw_photo and self.has_raw and self.path_raw:
raw_path = pathlib.Path(self.path_raw)
raw_ext = raw_path.suffix
raw_name = dest.parent / f"{dest.stem}{raw_ext}"