Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b4897ff1b5 | ||
|
|
661a573bf5 | ||
|
|
0c9bd87602 | ||
|
|
896d888710 |
@@ -4,6 +4,14 @@ All notable changes to this project will be documented in this file. Dates are d
|
||||
|
||||
Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
|
||||
|
||||
#### [v0.44.4](https://github.com/RhetTbull/osxphotos/compare/v0.44.3...v0.44.4)
|
||||
|
||||
> 4 January 2022
|
||||
|
||||
- Refactored photoinfo, photoexporter; #462 [`a73dc72`](https://github.com/RhetTbull/osxphotos/commit/a73dc72558b77152f4c90f143b6a60924b8905c8)
|
||||
- More refactoring of export code, #462 [`147b30f`](https://github.com/RhetTbull/osxphotos/commit/147b30f97308db65868dc7a8d177d77ad0d0ad40)
|
||||
- Export DB can now reside outside export directory, #568 [`76aee7f`](https://github.com/RhetTbull/osxphotos/commit/76aee7f189b4b32e2e263a4e798711713ed17a14)
|
||||
|
||||
#### [v0.44.3](https://github.com/RhetTbull/osxphotos/compare/v0.44.2...v0.44.3)
|
||||
|
||||
> 31 December 2021
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
""" version info """
|
||||
|
||||
__version__ = "0.44.4"
|
||||
__version__ = "0.44.5"
|
||||
|
||||
@@ -2954,11 +2954,9 @@ def export_photo_to_directory(
|
||||
try:
|
||||
exporter = PhotoExporter(photo)
|
||||
export_results = exporter.export2(
|
||||
dest_path,
|
||||
original_filename=filename,
|
||||
dest=dest_path,
|
||||
edited=edited,
|
||||
original=export_original,
|
||||
edited_filename=filename,
|
||||
filename=filename,
|
||||
sidecar=sidecar_flags,
|
||||
sidecar_drop_ext=sidecar_drop_ext,
|
||||
live_photo=export_live,
|
||||
|
||||
@@ -292,10 +292,8 @@ class PhotoExporter:
|
||||
|
||||
results = self.export2(
|
||||
dest,
|
||||
original=not edited,
|
||||
original_filename=filename,
|
||||
filename=filename,
|
||||
edited=edited,
|
||||
edited_filename=filename,
|
||||
live_photo=live_photo,
|
||||
raw_photo=raw_photo,
|
||||
export_as_hardlink=export_as_hardlink,
|
||||
@@ -317,10 +315,8 @@ class PhotoExporter:
|
||||
def export2(
|
||||
self,
|
||||
dest,
|
||||
original=True,
|
||||
original_filename=None,
|
||||
filename=None,
|
||||
edited=False,
|
||||
edited_filename=None,
|
||||
live_photo=False,
|
||||
raw_photo=False,
|
||||
export_as_hardlink=False,
|
||||
@@ -368,8 +364,7 @@ class PhotoExporter:
|
||||
in which case export will use the extension provided by Photos upon export.
|
||||
e.g. to get the extension of the edited photo,
|
||||
reference PhotoInfo.path_edited
|
||||
original: (boolean, default=True); if True, will export the original version of the photo
|
||||
edited: (boolean, default=False); if True will export the edited version of the photo (only one of original or edited can be used)
|
||||
edited: (boolean, default=False); if True will export the edited version of the photo otherwise exports the original version
|
||||
live_photo: (boolean, default=False); if True, will also export the associated .mov for live photos
|
||||
raw_photo: (boolean, default=False); if True, will also export the associated RAW photo
|
||||
export_as_hardlink: (boolean, default=False); if True, will hardlink files instead of copying them
|
||||
@@ -452,16 +447,13 @@ class PhotoExporter:
|
||||
|
||||
if verbose and not callable(verbose):
|
||||
raise TypeError("verbose must be callable")
|
||||
|
||||
if verbose is None:
|
||||
verbose = self._verbose
|
||||
|
||||
self._render_options = render_options or RenderOptions()
|
||||
|
||||
export_original = original
|
||||
export_original = not edited
|
||||
export_edited = edited
|
||||
if export_original and export_edited:
|
||||
raise ValueError("Cannot export both original and edited photos")
|
||||
if export_edited and not self.photo.hasadjustments:
|
||||
raise ValueError(
|
||||
"Photo does not have adjustments, cannot export edited version"
|
||||
@@ -473,13 +465,13 @@ class PhotoExporter:
|
||||
elif not dry_run and not os.path.isdir(dest):
|
||||
raise FileNotFoundError("Invalid path passed to export")
|
||||
|
||||
original_filename = original_filename or self.photo.original_filename
|
||||
dest_original = pathlib.Path(dest) / original_filename
|
||||
|
||||
edited_filename = edited_filename or self._get_edited_filename(
|
||||
original_filename
|
||||
)
|
||||
dest_edited = pathlib.Path(dest) / edited_filename
|
||||
if export_edited:
|
||||
filename = filename or self._get_edited_filename(
|
||||
self.photo.original_filename
|
||||
)
|
||||
else:
|
||||
filename = filename or self.photo.original_filename
|
||||
dest = pathlib.Path(dest) / filename
|
||||
|
||||
# Is there something to convert?
|
||||
if convert_to_jpeg and self.photo.isphoto:
|
||||
@@ -488,39 +480,25 @@ class PhotoExporter:
|
||||
if export_original and self.photo.uti_original != "public.jpeg":
|
||||
# not a jpeg but will convert to jpeg upon export so fix file extension
|
||||
something_to_convert = True
|
||||
dest_original = dest_original.parent / f"{dest_original.stem}{ext}"
|
||||
dest = dest.parent / f"{dest.stem}{ext}"
|
||||
if export_edited and self.photo.uti != "public.jpeg":
|
||||
# in Big Sur+, edited HEICs are HEIC
|
||||
something_to_convert = True
|
||||
dest_edited = dest_edited.parent / f"{dest_edited.stem}{ext}"
|
||||
dest_edited = dest.parent / f"{dest.stem}{ext}"
|
||||
convert_to_jpeg = something_to_convert
|
||||
else:
|
||||
convert_to_jpeg = False
|
||||
|
||||
# TODO: need to look at this to see what happens if original not being exported but edited exists and already has an increment
|
||||
dest_original, increment_file_count = self._validate_dest_path(
|
||||
dest_original, increment=increment, update=update, overwrite=overwrite
|
||||
)
|
||||
dest_original = pathlib.Path(dest_original)
|
||||
|
||||
if export_edited:
|
||||
dest_edited, increment_file_count = self._validate_dest_path(
|
||||
dest_edited,
|
||||
increment=increment,
|
||||
update=update,
|
||||
overwrite=overwrite,
|
||||
count=increment_file_count,
|
||||
)
|
||||
dest_edited = pathlib.Path(dest_edited)
|
||||
|
||||
self._render_options.filepath = (
|
||||
str(dest_original) if export_original else str(dest_edited)
|
||||
dest, _ = self._validate_dest_path(
|
||||
dest, increment=increment, update=update, overwrite=overwrite
|
||||
)
|
||||
dest = pathlib.Path(dest)
|
||||
self._render_options.filepath = str(dest)
|
||||
all_results = ExportResults()
|
||||
|
||||
if use_photos_export:
|
||||
self._export_photo_with_photos_export(
|
||||
dest=dest_original if export_original else dest_edited,
|
||||
dest=dest,
|
||||
all_results=all_results,
|
||||
fileutil=fileutil,
|
||||
export_db=export_db,
|
||||
@@ -540,17 +518,11 @@ class PhotoExporter:
|
||||
# find the source file on disk and export
|
||||
# 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 and self.photo.path_edited is not None:
|
||||
export_src_dest.append((self.photo.path_edited, dest_edited))
|
||||
elif not edited and self.photo.path is not None:
|
||||
export_src_dest.append((self.photo.path, dest_original))
|
||||
|
||||
# TODO: this for loop not necessary
|
||||
for src, dest in export_src_dest:
|
||||
if not pathlib.Path(src).is_file():
|
||||
raise FileNotFoundError(f"{src} does not appear to exist")
|
||||
src = self.photo.path_edited if edited else self.photo.path
|
||||
if src and not pathlib.Path(src).is_file():
|
||||
raise FileNotFoundError(f"{src} does not appear to exist")
|
||||
|
||||
if src:
|
||||
# found source now try to find right destination
|
||||
if update and dest.exists():
|
||||
# destination exists, check to see if destination is the right UUID
|
||||
@@ -595,11 +567,6 @@ class PhotoExporter:
|
||||
# increment the destination file
|
||||
dest = pathlib.Path(increment_filename(dest))
|
||||
|
||||
if export_original:
|
||||
dest_original = dest
|
||||
else:
|
||||
dest_edited = dest
|
||||
|
||||
# export the dest file
|
||||
results = self._export_photo(
|
||||
src,
|
||||
@@ -618,8 +585,6 @@ class PhotoExporter:
|
||||
)
|
||||
all_results += results
|
||||
|
||||
dest = dest_original if export_original else dest_edited
|
||||
|
||||
# copy live photo associated .mov if requested
|
||||
if (
|
||||
export_original
|
||||
@@ -730,7 +695,6 @@ class PhotoExporter:
|
||||
sidecar_xmp_files_skipped = []
|
||||
sidecar_xmp_files_written = []
|
||||
|
||||
dest = dest_original if export_original else dest_edited
|
||||
dest_suffix = "" if sidecar_drop_ext else dest.suffix
|
||||
if sidecar & SIDECAR_JSON:
|
||||
sidecar_filename = dest.parent / pathlib.Path(
|
||||
|
||||
@@ -725,8 +725,10 @@ class PhotoInfo:
|
||||
self._uti_original = self.uti
|
||||
elif self._db._photos_ver >= 7:
|
||||
# Monterey+
|
||||
self._uti_original = get_uti_for_extension(
|
||||
pathlib.Path(self.original_filename).suffix
|
||||
# there are some cases with UTI_original is None (photo imported with no extension) so fallback to UTI and hope it's right
|
||||
self._uti_original = (
|
||||
get_uti_for_extension(pathlib.Path(self.original_filename).suffix)
|
||||
or self.uti
|
||||
)
|
||||
else:
|
||||
self._uti_original = self._info["UTI_original"]
|
||||
@@ -1025,7 +1027,7 @@ class PhotoInfo:
|
||||
@property
|
||||
def israw(self):
|
||||
"""returns True if photo is a raw image. For images with an associated RAW+JPEG pair, see has_raw"""
|
||||
return "raw-image" in self.uti_original
|
||||
return "raw-image" in self.uti_original if self.uti_original else False
|
||||
|
||||
@property
|
||||
def raw_original(self):
|
||||
|
||||
@@ -520,7 +520,8 @@ class PhotoAsset:
|
||||
== Photos.PHAssetResourceTypeAlternatePhoto
|
||||
):
|
||||
data = self._request_resource_data(resource)
|
||||
ext = pathlib.Path(self.raw_filename).suffix[1:]
|
||||
suffix = pathlib.Path(self.raw_filename).suffix
|
||||
ext = suffix[1:] if suffix else ""
|
||||
break
|
||||
else:
|
||||
raise PhotoKitExportError(
|
||||
|
||||
@@ -591,6 +591,9 @@ def get_preferred_uti_extension(uti):
|
||||
def get_uti_for_extension(extension):
|
||||
"""get UTI for a given file extension"""
|
||||
|
||||
if not extension:
|
||||
return None
|
||||
|
||||
# accepts extension with or without leading 0
|
||||
if extension[0] == ".":
|
||||
extension = extension[1:]
|
||||
|
||||
Reference in New Issue
Block a user