Completed implementation of --jpeg-ext, fixed --dry-run, closes #330, #346

This commit is contained in:
Rhet Turnbull
2021-01-11 06:45:35 -08:00
parent 55c088eea2
commit 4d924d0826
4 changed files with 108 additions and 20 deletions

View File

@@ -1,3 +1,3 @@
""" version info """ """ version info """
__version__ = "0.39.14" __version__ = "0.39.15"

View File

@@ -60,6 +60,11 @@ class FileUtilABC(ABC):
def convert_to_jpeg(cls, src_file, dest_file, compression_quality=1.0): def convert_to_jpeg(cls, src_file, dest_file, compression_quality=1.0):
pass pass
@classmethod
@abstractmethod
def rename(cls, src, dest):
pass
class FileUtilMacOS(FileUtilABC): class FileUtilMacOS(FileUtilABC):
""" Various file utilities """ """ Various file utilities """
@@ -201,6 +206,21 @@ class FileUtilMacOS(FileUtilABC):
src_file, dest_file, compression_quality=compression_quality src_file, dest_file, compression_quality=compression_quality
) )
@classmethod
def rename(cls, src, dest):
""" Copy src to dest
Args:
src: path to source file
dest: path to destination file
Returns:
Name of renamed file (dest)
"""
os.rename(str(src), str(dest))
return dest
@staticmethod @staticmethod
def _sig(st): def _sig(st):
""" return tuple of (mode, size, mtime) of file based on os.stat """ return tuple of (mode, size, mtime) of file based on os.stat
@@ -266,3 +286,7 @@ class FileUtilNoOp(FileUtil):
@classmethod @classmethod
def convert_to_jpeg(cls, src_file, dest_file, compression_quality=1.0): def convert_to_jpeg(cls, src_file, dest_file, compression_quality=1.0):
cls.verbose(f"convert_to_jpeg: {src_file}, {dest_file}, {compression_quality}") cls.verbose(f"convert_to_jpeg: {src_file}, {dest_file}, {compression_quality}")
@classmethod
def rename(cls, src, dest):
cls.verbose(f"rename: {src}, {dest}")

View File

@@ -49,7 +49,7 @@ from ..photokit import (
PhotoKitFetchFailed, PhotoKitFetchFailed,
PhotoLibrary, PhotoLibrary,
) )
from ..utils import dd_to_dms_str, findfiles, noop from ..utils import dd_to_dms_str, findfiles, noop, get_preferred_uti_extension
class ExportError(Exception): class ExportError(Exception):
@@ -311,6 +311,34 @@ def _check_export_suffix(src, dest, edited):
) )
# not a class method, don't import into PhotoInfo
def rename_jpeg_files(files, jpeg_ext, fileutil):
""" rename any jpeg files in files so that extension matches jpeg_ext
Args:
files: list of file paths
jpeg_ext: extension to use for jpeg files found in files, e.g. "jpg"
fileutil: a FileUtil object
Returns:
list of files with updated names
Note: If non-jpeg files found, they will be ignore and returned in the return list
"""
jpeg_ext = "." + jpeg_ext
jpegs = [".jpeg", ".jpg"]
new_files = []
for file in files:
path = pathlib.Path(file)
if path.suffix.lower() in jpegs and path.suffix != jpeg_ext:
new_file = path.parent / (path.stem + jpeg_ext)
fileutil.rename(file, new_file)
new_files.append(new_file)
else:
new_files.append(file)
return new_files
def export( def export(
self, self,
dest, dest,
@@ -749,6 +777,8 @@ def export2(
) )
all_results += results all_results += results
else: else:
# TODO: move this big if/else block to separate functions
# e.g. _export_with_photos_export or such
# use_photo_export # use_photo_export
# export live_photo .mov file? # export live_photo .mov file?
live_photo = True if live_photo and self.live_photo else False live_photo = True if live_photo and self.live_photo else False
@@ -763,7 +793,10 @@ def export2(
else: else:
# didn't get passed a filename, add _edited # didn't get passed a filename, add _edited
filestem = f"{dest.stem}{edited_identifier}" filestem = f"{dest.stem}{edited_identifier}"
dest = dest.parent / f"{filestem}.jpeg" uti = self.uti_edited if edited and self.uti_edited else self.uti
ext = get_preferred_uti_extension(uti)
dest = dest.parent / f"{filestem}{ext}"
if use_photokit: if use_photokit:
photolib = PhotoLibrary() photolib = PhotoLibrary()
photo = None photo = None
@@ -786,13 +819,17 @@ def export2(
) )
) )
if photo: if photo:
try: if not dry_run:
exported = photo.export( try:
dest.parent, dest.name, version=PHOTOS_VERSION_CURRENT exported = photo.export(
) dest.parent, dest.name, version=PHOTOS_VERSION_CURRENT
all_results.exported.extend(exported) )
except Exception as e: all_results.exported.extend(exported)
all_results.error.append((str(dest), e)) except Exception as e:
all_results.error.append((str(dest), e))
else:
# dry_run, don't actually export
all_results.exported.append(str(dest))
else: else:
try: try:
exported = _export_photo_uuid_applescript( exported = _export_photo_uuid_applescript(
@@ -827,13 +864,17 @@ def export2(
photo = [p for p in bursts if p.uuid.startswith(self.uuid)] photo = [p for p in bursts if p.uuid.startswith(self.uuid)]
photo = photo[0] if photo else None photo = photo[0] if photo else None
if photo: if photo:
try: if not dry_run:
exported = photo.export( try:
dest.parent, dest.name, version=PHOTOS_VERSION_ORIGINAL exported = photo.export(
) dest.parent, dest.name, version=PHOTOS_VERSION_ORIGINAL
all_results.exported.extend(exported) )
except Exception as e: all_results.exported.extend(exported)
all_results.error.append((str(dest), e)) except Exception as e:
all_results.error.append((str(dest), e))
else:
# dry_run, don't actually export
all_results.exported.append(str(dest))
else: else:
try: try:
exported = _export_photo_uuid_applescript( exported = _export_photo_uuid_applescript(
@@ -851,6 +892,13 @@ def export2(
except ExportError as e: except ExportError as e:
all_results.error.append((str(dest), e)) all_results.error.append((str(dest), e))
if all_results.exported: if all_results.exported:
if jpeg_ext:
# use_photos_export (both PhotoKit and AppleScript) don't use the
# file extension provided (instead they use extension for UTI)
# so if jpeg_ext is set, rename any non-conforming jpegs
all_results.exported = rename_jpeg_files(
all_results.exported, jpeg_ext, fileutil
)
if touch_file: if touch_file:
for exported_file in all_results.exported: for exported_file in all_results.exported:
all_results.touched.append(exported_file) all_results.touched.append(exported_file)
@@ -859,9 +907,6 @@ def export2(
if update: if update:
all_results.new.extend(all_results.exported) all_results.new.extend(all_results.exported)
# else:
# all_results.error.append((str(dest), f"Error exporting photo {self.uuid} to {dest} with use_photos_export"))
# export metadata # export metadata
sidecars = [] sidecars = []
sidecar_json_files_skipped = [] sidecar_json_files_skipped = []
@@ -1769,3 +1814,4 @@ def _write_sidecar(self, filename, sidecar_str):
f = open(filename, "w") f = open(filename, "w")
f.write(sidecar_str) f.write(sidecar_str)
f.close() f.close()

View File

@@ -107,3 +107,21 @@ def test_convert_to_jpeg_quality():
assert FileUtil.convert_to_jpeg(imgfile, outfile, compression_quality=0.1) assert FileUtil.convert_to_jpeg(imgfile, outfile, compression_quality=0.1)
assert outfile.is_file() assert outfile.is_file()
assert outfile.stat().st_size < 1000000 assert outfile.stat().st_size < 1000000
def test_rename_file():
# rename file with valid src, dest
import pathlib
import tempfile
from osxphotos.fileutil import FileUtil
temp_dir = tempfile.TemporaryDirectory(prefix="osxphotos_")
src = "tests/test-images/wedding.jpg"
dest = f"{temp_dir.name}/foo.jpg"
dest2 = f"{temp_dir.name}/bar.jpg"
FileUtil.copy(src, dest)
result = FileUtil.rename(dest, dest2)
assert result
assert pathlib.Path(dest2).exists()
assert not pathlib.Path(dest).exists()