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