Working on issue #206
This commit is contained in:
@@ -1543,6 +1543,7 @@ def export(
|
||||
results_updated = []
|
||||
results_skipped = []
|
||||
results_exif_updated = []
|
||||
results_touched = []
|
||||
if verbose_:
|
||||
for p in photos:
|
||||
results = export_photo(
|
||||
@@ -1578,6 +1579,7 @@ def export(
|
||||
results_updated.extend(results.updated)
|
||||
results_skipped.extend(results.skipped)
|
||||
results_exif_updated.extend(results.exif_updated)
|
||||
results_touched.extend(results.touched)
|
||||
|
||||
else:
|
||||
# show progress bar
|
||||
@@ -1616,24 +1618,31 @@ def export(
|
||||
results_updated.extend(results.updated)
|
||||
results_skipped.extend(results.skipped)
|
||||
results_exif_updated.extend(results.exif_updated)
|
||||
results_touched.extend(results.touched)
|
||||
stop_time = time.perf_counter()
|
||||
# print summary results
|
||||
if update:
|
||||
photo_str_new = "photos" if len(results_new) != 1 else "photo"
|
||||
photo_str_updated = "photos" if len(results_new) != 1 else "photo"
|
||||
photo_str_skipped = "photos" if len(results_skipped) != 1 else "photo"
|
||||
photo_str_touched = "photos" if len(results_touched) != 1 else "photo"
|
||||
photo_str_exif_updated = (
|
||||
"photos" if len(results_exif_updated) != 1 else "photo"
|
||||
)
|
||||
click.echo(
|
||||
f"Exported: {len(results_new)} {photo_str_new}, "
|
||||
+ f"updated: {len(results_updated)} {photo_str_updated}, "
|
||||
+ f"skipped: {len(results_skipped)} {photo_str_skipped}, "
|
||||
+ f"updated EXIF data: {len(results_exif_updated)} {photo_str_exif_updated}"
|
||||
)
|
||||
summary = f"Exported: {len(results_new)} {photo_str_new}, " \
|
||||
f"updated: {len(results_updated)} {photo_str_updated}, " \
|
||||
f"skipped: {len(results_skipped)} {photo_str_skipped}, " \
|
||||
f"updated EXIF data: {len(results_exif_updated)} {photo_str_exif_updated}"
|
||||
if touch_file:
|
||||
summary += f", touched date: {len(results_touched)} {photo_str_touched}"
|
||||
click.echo(summary)
|
||||
else:
|
||||
photo_str = "photos" if len(results_exported) != 1 else "photo"
|
||||
click.echo(f"Exported: {len(results_exported)} {photo_str}")
|
||||
photo_str_touched = "photos" if len(results_touched) != 1 else "photo"
|
||||
summary = f"Exported: {len(results_exported)} {photo_str}"
|
||||
if touch_file:
|
||||
summary += f", touched date: {len(results_touched)} {photo_str_touched}"
|
||||
click.echo(summary)
|
||||
click.echo(f"Elapsed time: {(stop_time-start_time):.3f} seconds")
|
||||
else:
|
||||
click.echo("Did not find any photos to export")
|
||||
@@ -2125,25 +2134,26 @@ def export_photo(
|
||||
if photo.ismissing:
|
||||
space = " " if not verbose_ else ""
|
||||
verbose(f"{space}Skipping missing photo {photo.filename}")
|
||||
return ExportResults([], [], [], [], [])
|
||||
return ExportResults([], [], [], [], [], [])
|
||||
elif not os.path.exists(photo.path):
|
||||
space = " " if not verbose_ else ""
|
||||
verbose(
|
||||
f"{space}WARNING: file {photo.path} is missing but ismissing=False, "
|
||||
f"skipping {photo.filename}"
|
||||
)
|
||||
return ExportResults([], [], [], [], [])
|
||||
return ExportResults([], [], [], [], [], [])
|
||||
elif photo.ismissing and not photo.iscloudasset or not photo.incloud:
|
||||
verbose(
|
||||
f"Skipping missing {photo.filename}: not iCloud asset or missing from cloud"
|
||||
)
|
||||
return ExportResults([], [], [], [], [])
|
||||
return ExportResults([], [], [], [], [], [])
|
||||
|
||||
results_exported = []
|
||||
results_new = []
|
||||
results_updated = []
|
||||
results_skipped = []
|
||||
results_exif_updated = []
|
||||
results_touched = []
|
||||
|
||||
filenames = get_filenames_from_template(photo, filename_template, original_name)
|
||||
for filename in filenames:
|
||||
@@ -2196,6 +2206,7 @@ def export_photo(
|
||||
results_updated.extend(export_results.updated)
|
||||
results_skipped.extend(export_results.skipped)
|
||||
results_exif_updated.extend(export_results.exif_updated)
|
||||
results_touched.extend(export_results.touched)
|
||||
|
||||
if verbose_:
|
||||
for exported in export_results.exported:
|
||||
@@ -2253,6 +2264,7 @@ def export_photo(
|
||||
results_updated.extend(export_results_edited.updated)
|
||||
results_skipped.extend(export_results_edited.skipped)
|
||||
results_exif_updated.extend(export_results_edited.exif_updated)
|
||||
results_touched.extend(export_results.touched)
|
||||
|
||||
if verbose_:
|
||||
for exported in export_results_edited.exported:
|
||||
@@ -2270,6 +2282,7 @@ def export_photo(
|
||||
results_updated,
|
||||
results_skipped,
|
||||
results_exif_updated,
|
||||
results_touched
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -36,7 +36,8 @@ from ..fileutil import FileUtil
|
||||
from ..utils import dd_to_dms_str, findfiles
|
||||
|
||||
ExportResults = namedtuple(
|
||||
"ExportResults", ["exported", "new", "updated", "skipped", "exif_updated"]
|
||||
"ExportResults",
|
||||
["exported", "new", "updated", "skipped", "exif_updated", "touched"],
|
||||
)
|
||||
|
||||
|
||||
@@ -376,6 +377,9 @@ def export2(
|
||||
# list of all files skipped because they do not need to be updated (for use with update=True)
|
||||
update_skipped_files = []
|
||||
|
||||
# list of all files with utime touched (touch_file = True)
|
||||
touched_files = []
|
||||
|
||||
# check edited and raise exception trying to export edited version of
|
||||
# photo that hasn't been edited
|
||||
if edited and not self.hasadjustments:
|
||||
@@ -566,6 +570,7 @@ def export2(
|
||||
update_new_files = results.new
|
||||
update_updated_files = results.updated
|
||||
update_skipped_files = results.skipped
|
||||
touched_files = results.touched
|
||||
|
||||
# copy live photo associated .mov if requested
|
||||
if live_photo and self.live_photo:
|
||||
@@ -592,6 +597,7 @@ def export2(
|
||||
update_new_files.extend(results.new)
|
||||
update_updated_files.extend(results.updated)
|
||||
update_skipped_files.extend(results.skipped)
|
||||
touched_files.extend(results.touched)
|
||||
else:
|
||||
logging.debug(f"Skipping missing live movie for {filename}")
|
||||
|
||||
@@ -618,6 +624,7 @@ def export2(
|
||||
update_new_files.extend(results.new)
|
||||
update_updated_files.extend(results.updated)
|
||||
update_skipped_files.extend(results.skipped)
|
||||
touched_files.extend(results.touched)
|
||||
else:
|
||||
logging.debug(f"Skipping missing RAW photo for {filename}")
|
||||
else:
|
||||
@@ -662,6 +669,7 @@ def export2(
|
||||
)
|
||||
|
||||
if exported is not None:
|
||||
# TODO: add touch_file code
|
||||
exported_files.extend(exported)
|
||||
else:
|
||||
logging.warning(
|
||||
@@ -704,6 +712,7 @@ def export2(
|
||||
raise e
|
||||
|
||||
# if exiftool, write the metadata
|
||||
# TODO: add touch_file code to update touch time
|
||||
if update:
|
||||
exif_files = update_new_files + update_updated_files + update_skipped_files
|
||||
else:
|
||||
@@ -784,6 +793,7 @@ def export2(
|
||||
update_updated_files,
|
||||
update_skipped_files,
|
||||
exif_files_updated,
|
||||
touched_files,
|
||||
)
|
||||
|
||||
|
||||
@@ -826,6 +836,7 @@ def _export_photo(
|
||||
update_updated_files = []
|
||||
update_new_files = []
|
||||
update_skipped_files = []
|
||||
touched_files = []
|
||||
|
||||
dest_str = str(dest)
|
||||
dest_exists = dest.exists()
|
||||
@@ -838,11 +849,15 @@ def _export_photo(
|
||||
# not update, export the file
|
||||
logging.debug(f"Exporting file with {op_desc} {src} {dest}")
|
||||
exported_files.append(dest_str)
|
||||
if touch_file:
|
||||
touched_files.append(dest_str)
|
||||
else: # updating
|
||||
if not dest_exists:
|
||||
# update, destination doesn't exist (new file)
|
||||
logging.debug(f"Update: exporting new file with {op_desc} {src} {dest}")
|
||||
update_new_files.append(dest_str)
|
||||
if touch_file:
|
||||
touched_files.append(dest_str)
|
||||
else:
|
||||
# update, destination exists, but we might not need to replace it...
|
||||
if touch_file:
|
||||
@@ -863,33 +878,38 @@ def _export_photo(
|
||||
)
|
||||
):
|
||||
# destination exists but its signature is "identical"
|
||||
logging.debug(f"Update: skipping identical original files {src} {dest}")
|
||||
# call set_stat because code can reach this spot if no export DB but exporting a RAW or live photo
|
||||
# potentially re-writes the data in the database but ensures database is complete
|
||||
export_db.set_stat_orig_for_file(dest_str, fileutil.file_sig(dest_str))
|
||||
update_skipped_files.append(dest_str)
|
||||
else:
|
||||
# destination exists but is different
|
||||
logging.debug(
|
||||
f"Update: removing existing file prior to {op_desc} {src} {dest}"
|
||||
)
|
||||
update_updated_files.append(dest_str)
|
||||
# destination exists but signature is different
|
||||
if touch_file and fileutil.cmp(src, dest) and not sig_cmp:
|
||||
# destination exists, signature matches original but does not match expected touch time
|
||||
# skip exporting but update touch time
|
||||
update_skipped_files.append(dest_str)
|
||||
touched_files.append(dest_str)
|
||||
else:
|
||||
# destination exists but is different
|
||||
update_updated_files.append(dest_str)
|
||||
if touch_file:
|
||||
touched_files.append(dest_str)
|
||||
|
||||
if not update_skipped_files:
|
||||
if dest_exists and (update or overwrite):
|
||||
# need to remove the destination first
|
||||
logging.debug(
|
||||
f"Update: removing existing file prior to export_as_hardlink {src} {dest}"
|
||||
f"Update: removing existing file prior to {op_desc} {src} {dest}"
|
||||
)
|
||||
# dest.unlink()
|
||||
fileutil.unlink(dest)
|
||||
if export_as_hardlink:
|
||||
fileutil.hardlink(src, dest)
|
||||
else:
|
||||
fileutil.copy(src, dest_str, norsrc=no_xattr)
|
||||
if touch_file:
|
||||
ts = self.date.timestamp()
|
||||
fileutil.utime(dest, (ts, ts))
|
||||
|
||||
if touched_files:
|
||||
ts = self.date.timestamp()
|
||||
fileutil.utime(dest, (ts, ts))
|
||||
|
||||
export_db.set_data(
|
||||
dest_str,
|
||||
@@ -906,6 +926,7 @@ def _export_photo(
|
||||
update_updated_files,
|
||||
update_skipped_files,
|
||||
[],
|
||||
touched_files,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user