This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.39.14"
|
||||
__version__ = "0.39.15"
|
||||
|
||||
@@ -60,6 +60,11 @@ class FileUtilABC(ABC):
|
||||
def convert_to_jpeg(cls, src_file, dest_file, compression_quality=1.0):
|
||||
pass
|
||||
|
||||
@classmethod
|
||||
@abstractmethod
|
||||
def rename(cls, src, dest):
|
||||
pass
|
||||
|
||||
|
||||
class FileUtilMacOS(FileUtilABC):
|
||||
""" Various file utilities """
|
||||
@@ -201,6 +206,21 @@ class FileUtilMacOS(FileUtilABC):
|
||||
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
|
||||
def _sig(st):
|
||||
""" return tuple of (mode, size, mtime) of file based on os.stat
|
||||
@@ -266,3 +286,7 @@ class FileUtilNoOp(FileUtil):
|
||||
@classmethod
|
||||
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}")
|
||||
|
||||
@classmethod
|
||||
def rename(cls, src, dest):
|
||||
cls.verbose(f"rename: {src}, {dest}")
|
||||
|
||||
@@ -49,7 +49,7 @@ from ..photokit import (
|
||||
PhotoKitFetchFailed,
|
||||
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):
|
||||
@@ -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(
|
||||
self,
|
||||
dest,
|
||||
@@ -749,6 +777,8 @@ def export2(
|
||||
)
|
||||
all_results += results
|
||||
else:
|
||||
# TODO: move this big if/else block to separate functions
|
||||
# e.g. _export_with_photos_export or such
|
||||
# use_photo_export
|
||||
# export live_photo .mov file?
|
||||
live_photo = True if live_photo and self.live_photo else False
|
||||
@@ -763,7 +793,10 @@ def export2(
|
||||
else:
|
||||
# didn't get passed a filename, add _edited
|
||||
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:
|
||||
photolib = PhotoLibrary()
|
||||
photo = None
|
||||
@@ -786,13 +819,17 @@ def export2(
|
||||
)
|
||||
)
|
||||
if photo:
|
||||
try:
|
||||
exported = photo.export(
|
||||
dest.parent, dest.name, version=PHOTOS_VERSION_CURRENT
|
||||
)
|
||||
all_results.exported.extend(exported)
|
||||
except Exception as e:
|
||||
all_results.error.append((str(dest), e))
|
||||
if not dry_run:
|
||||
try:
|
||||
exported = photo.export(
|
||||
dest.parent, dest.name, version=PHOTOS_VERSION_CURRENT
|
||||
)
|
||||
all_results.exported.extend(exported)
|
||||
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:
|
||||
try:
|
||||
exported = _export_photo_uuid_applescript(
|
||||
@@ -827,13 +864,17 @@ def export2(
|
||||
photo = [p for p in bursts if p.uuid.startswith(self.uuid)]
|
||||
photo = photo[0] if photo else None
|
||||
if photo:
|
||||
try:
|
||||
exported = photo.export(
|
||||
dest.parent, dest.name, version=PHOTOS_VERSION_ORIGINAL
|
||||
)
|
||||
all_results.exported.extend(exported)
|
||||
except Exception as e:
|
||||
all_results.error.append((str(dest), e))
|
||||
if not dry_run:
|
||||
try:
|
||||
exported = photo.export(
|
||||
dest.parent, dest.name, version=PHOTOS_VERSION_ORIGINAL
|
||||
)
|
||||
all_results.exported.extend(exported)
|
||||
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:
|
||||
try:
|
||||
exported = _export_photo_uuid_applescript(
|
||||
@@ -851,6 +892,13 @@ def export2(
|
||||
except ExportError as e:
|
||||
all_results.error.append((str(dest), e))
|
||||
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:
|
||||
for exported_file in all_results.exported:
|
||||
all_results.touched.append(exported_file)
|
||||
@@ -859,9 +907,6 @@ def export2(
|
||||
if update:
|
||||
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
|
||||
sidecars = []
|
||||
sidecar_json_files_skipped = []
|
||||
@@ -1769,3 +1814,4 @@ def _write_sidecar(self, filename, sidecar_str):
|
||||
f = open(filename, "w")
|
||||
f.write(sidecar_str)
|
||||
f.close()
|
||||
|
||||
|
||||
@@ -107,3 +107,21 @@ def test_convert_to_jpeg_quality():
|
||||
assert FileUtil.convert_to_jpeg(imgfile, outfile, compression_quality=0.1)
|
||||
assert outfile.is_file()
|
||||
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()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user