Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for external adjustments, #1518 #1525

Merged
merged 1 commit into from
Apr 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions osxphotos/adjustmentsinfo.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
""" AdjustmentsInfo class to read adjustments data for photos edited in Apple's Photos.app
In Catalina and Big Sur, the adjustments data (data about edits done to the photo)
is stored in a plist file in
is stored in a plist file in
~/Pictures/Photos Library.photoslibrary/resources/renders/X/UUID.plist
where X is first character of the photo's UUID string and UUID is the full UUID,
where X is first character of the photo's UUID string and UUID is the full UUID,
e.g.: ~/Pictures/Photos Library.photoslibrary/resources/renders/3/30362C1D-192F-4CCD-9A2A-968F436DC0DE.plist

Thanks to @neilpa who figured out how to decode this information:
Expand All @@ -11,13 +11,16 @@

import datetime
import json
import logging
import plistlib
import zlib

from .datetime_utils import datetime_naive_to_utc

__all__ = ["AdjustmentsDecodeError", "AdjustmentsInfo"]

logger = logging.getLogger("osxphotos")


class AdjustmentsDecodeError(Exception):
"""Could not decode adjustments plist file"""
Expand All @@ -44,6 +47,7 @@ def __init__(self, plist_file):
try:
self._adjustments = self._decode_adjustments_from_plist(self._plist)
except Exception as e:
logger.debug(f"Could not decode adjustments data: {plist_file}")
self._adjustments = None

def _decode_adjustments_from_plist(self, plist):
Expand All @@ -70,7 +74,11 @@ def _load_plist_file(self, plist_file):
plist as dict
"""
with open(str(plist_file), "rb") as fd:
plist_dict = plistlib.load(fd)
try:
plist_dict = plistlib.load(fd)
except Exception as e:
logger.debug(f"Could not load plist file: {plist_file}")
plist_dict = {}
return plist_dict

@property
Expand Down Expand Up @@ -113,43 +121,40 @@ def adjustments(self):
"""List of adjustment dictionaries (or empty list if none or could not be decoded)"""
try:
return self._adjustments["adjustments"] if self._adjustments else []
except KeyError:
except (KeyError, TypeError):
return []

@property
def adj_metadata(self):
"""Metadata dictionary or None if adjustment data could not be decoded"""
try:
return self._adjustments["metadata"] if self._adjustments else None
except KeyError:
except (KeyError, TypeError):
return None

@property
def adj_orientation(self):
"""EXIF orientation of image or 0 if none specified or None if adjustments could not be decoded"""
try:
return self._adjustments["metadata"]["orientation"]
except KeyError:
# no orientation field
return 0
except TypeError:
# adjustments is None
except (KeyError, TypeError):
# no orientation field or adjustments is None
return 0

@property
def adj_format_version(self):
"""Format version for adjustments data (formatVersion field from adjustmentData) or None if adjustments could not be decoded"""
try:
return self._adjustments["formatVersion"] if self._adjustments else None
except KeyError:
except (KeyError, TypeError):
return None

@property
def adj_version_info(self):
"""version info for adjustments data or None if adjustments data could not be decoded"""
try:
return self._adjustments["versionInfo"] if self._adjustments else None
except KeyError:
except (KeyError, TypeError):
return None

def asdict(self):
Expand Down
267 changes: 267 additions & 0 deletions tests/ExternalAdjustments-14.4.1.photoslibrary/com.apple.Photos.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>ExportDirectory</key>
<string>/Users/mika/Desktop</string>
<key>ExportMastersDirectory</key>
<string>/Users/mika/Desktop</string>
<key>IPXAdjustmentSliderOptionCollapse_SmartColor</key>
<true/>
<key>IPXAdjustmentSliderOptionCollapse_SmartTone</key>
<true/>
<key>IPXAdjustmentsExpandedIdentifiers</key>
<dict>
<key>CinematicDepthEffect</key>
<true/>
<key>DGDefinition2Operation</key>
<true/>
<key>DGVignetteEffectOperation</key>
<true/>
<key>DepthEffect</key>
<true/>
<key>RKCurvesOperation</key>
<false/>
<key>RKLevelsOperation</key>
<true/>
<key>RKNoiseReductionOperation</key>
<true/>
<key>RKProSharpenOperation</key>
<true/>
<key>RKRetouchOperation</key>
<true/>
<key>RKSelectiveColorOperation</key>
<true/>
<key>SmartBlackAndWhite</key>
<true/>
<key>SmartColor</key>
<true/>
<key>SmartTone</key>
<true/>
<key>WhiteBalance</key>
<true/>
</dict>
<key>IPXAspectRatioCustomHeight</key>
<integer>4500</integer>
<key>IPXAspectRatioCustomWidth</key>
<integer>3000</integer>
<key>IPXCurvesRangeDefault</key>
<integer>0</integer>
<key>IPXCurvesShowOverlay</key>
<true/>
<key>IPXDefaultAutoplayVideos</key>
<false/>
<key>IPXDefaultDidPromoteiCloudPhotosInGettingStarted</key>
<true/>
<key>IPXDefaultHasBeenLaunched</key>
<true/>
<key>IPXDefaultHasChosenToEnableiCloudPhotosInGettingStarted</key>
<false/>
<key>IPXDefaultIsRestoringViewControllers</key>
<false/>
<key>IPXDefaultLibraryURLBookmark</key>
<data>
Ym9va6ADAAAAAAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnAIA
AAUAAAABAQAAVXNlcnMAAAAEAAAAAQEAAG1pa2EHAAAAAQEAAERlc2t0b3AAHAAAAAEB
AABQaG90b21hdG9yVGVzdC5waG90b3NsaWJyYXJ5EAAAAAEGAAAEAAAAFAAAACAAAAAw
AAAACAAAAAQDAAAWPgAAAAAAAAgAAAAEAwAAYWMAAAAAAAAIAAAABAMAAGZjAAAAAAAA
CAAAAAQDAAAKttUEAAAAABAAAAABBgAAbAAAAHwAAACMAAAAnAAAAAgAAAAABAAAQcXo
VNRVmd4YAAAAAQIAAAIAAAAAAAAADwAAAAAAAAAAAAAAAAAAAAgAAAAEAwAAAgAAAAAA
AAAEAAAAAwMAAPUBAAAIAAAAAQkAAGZpbGU6Ly8vBgAAAAEBAABTeXN0ZW0AAAgAAAAE
AwAAAJCClucAAAAIAAAAAAQAAEHF1gPBgAAAJAAAAAEBAAA4QzE1QUQ5Ny05OUMwLTQy
NzYtQjgwMS1FODRGQzQ3MzY4NDMYAAAAAQIAAIEAAAABAAAA7xMAAAEAAAAAAAAAAAAA
AAEAAAABAQAALwAAAAAAAAABBQAA4gAAAAECAABlM2IzMjBkMGM2MTllZTkzYjFhY2I3
ZWMwM2UyMjViOGIwYTNmZDFiNmRmNjgxMmY2OGY3MGRlYWIwZWI5NThiOzAwOzAwMDAw
MDAwOzAwMDAwMDAwOzAwMDAwMDAwOzAwMDAwMDAwMDAwMDAwMjA7Y29tLmFwcGxlLmFw
cC1zYW5kYm94LnJlYWQtd3JpdGU7MDE7MDEwMDAwMTE7MDAwMDAwMDAwNGQ1YjYwYTs0
MTsvdXNlcnMvbWlrYS9kZXNrdG9wL3Bob3RvbWF0b3J0ZXN0LnBob3Rvc2xpYnJhcnkA
AADMAAAA/v///wEAAAAAAAAAEAAAAAQQAABUAAAAAAAAAAUQAACsAAAAAAAAABAQAADU
AAAAAAAAAEAQAADEAAAAAAAAAAIgAACcAQAAAAAAAAUgAAAQAQAAAAAAABAgAAAgAQAA
AAAAABEgAABQAQAAAAAAABIgAAAwAQAAAAAAABMgAABAAQAAAAAAACAgAAB8AQAAAAAA
ADAgAACoAQAAAAAAAAHAAAD0AAAAAAAAABHAAAAUAAAAAAAAABLAAAAEAQAAAAAAAIDw
AACwAQAAAAAAAA==
</data>
<key>IPXDefaultShowEditedBadge</key>
<integer>1</integer>
<key>IPXDefaultShowFaces</key>
<true/>
<key>IPXDefaultShowKeywordsBadge</key>
<integer>1</integer>
<key>IPXDefaultShowLibraryChooserOnLaunch</key>
<false/>
<key>IPXDefaultShowLocationBadge</key>
<integer>1</integer>
<key>IPXDefaultShowPhotoCellCaptions</key>
<integer>1</integer>
<key>IPXDefaultShowReferencedFileBadge</key>
<integer>1</integer>
<key>IPXDefaultWorkspace</key>
<data>
YnBsaXN0MDDUAQIDBAUGBwpYJHZlcnNpb25ZJGFyY2hpdmVyVCR0b3BYJG9iamVjdHMS
AAGGoF8QD05TS2V5ZWRBcmNoaXZlctEICVRyb290gAGvEBULDBEdHiQqMT0+P0BBQkNE
RUlNUFRVJG51bGzSDQ4PEF8QFnJlc3RvcmF0aW9uRGVzdGluYXRpb25WJGNsYXNzgAKA
FNYSExQVFg4XGBkYGxxfEDBJUFhOYXZpZ2F0aW9uRGVzdGluYXRpb25BdXhpbGlhcnlT
dG9yZUFyY2hpdmVLZXlfEDNJUFhOYXZpZ2F0aW9uRGVzdGluYXRpb25QYXJlbnREZXN0
aW5hdGlvbkFyY2hpdmVLZXlfEEJJUFhOYXZpZ2F0aW9uRGVzdGluYXRpb25SZXF1aXJl
ZERlc3RpbmF0aW9uQXV4aWxpYXJ5S2V5c0FyY2hpdmVLZXlfECdJUFhOYXZpZ2F0aW9u
RGVzdGluYXRpb25UaXRsZUFyY2hpdmVLZXlfECxJUFhOYXZpZ2F0aW9uRGVzdGluYXRp
b25JZGVudGlmaWVyQXJjaGl2ZUtleYAEgACAEYAAgAOAE18QFmNvbS5hcHBsZS5waG90
b3MuYWxidW3THyAOISIjXxAxVVhBdXhpbGlhcnlOYXZpZ2F0aW9uU3RvcmVOYW1lc3Bh
Y2VEaWN0QXJjaGl2ZUtleV8QLlVYQXV4aWxpYXJ5TmF2aWdhdGlvblN0b3JlR2xvYmFs
RGljdEFyY2hpdmVLZXmABYAHgBDTJSYOJygpV05TLmtleXNaTlMub2JqZWN0c6CggAbS
KywtLlokY2xhc3NuYW1lWCRjbGFzc2VzXxATTlNNdXRhYmxlRGljdGlvbmFyeaMtLzBc
TlNEaWN0aW9uYXJ5WE5TT2JqZWN00yUmDjI3KaQzNDU2gAiACYAKgAukODk6O4AMgA2A
DoAPgAZfECBJUFhDdXJhdGVkTGlicmFyeURlc3RpbmF0aW9uVGltZV8QIklQWFBob3Rv
c09iamVjdFRyYW5zaWVudElkZW50aWZpZXJfEBpJUFhDdXJhdGVkTGlicmFyeVpvb21M
ZXZlbF8QIlVYU291cmNlQ29udHJvbGxlclNlbmRlcklkZW50aWZpZXIjQcXoVxVig1Zf
EBlQWFBob3Rvc1ZpcnR1YWxDb2xsZWN0aW9uEARfEBZJUFhXb3Jrc3BhY2VDb250cm9s
bGVy0issRkdfEBtVWERlc3RpbmF0aW9uQXV4aWxpYXJ5U3RvcmWiSDBfEBtVWERlc3Rp
bmF0aW9uQXV4aWxpYXJ5U3RvcmXSJg5KTKE0gAmAEtIrLE5PVU5TU2V0ok4w0issUVJf
EBhJUFhOYXZpZ2F0aW9uRGVzdGluYXRpb26iUzBfEBhJUFhOYXZpZ2F0aW9uRGVzdGlu
YXRpb27SKyxVVlxJUFhXb3Jrc3BhY2WiVzBcSVBYV29ya3NwYWNlAAgAEQAaACQAKQAy
ADcASQBMAFEAUwBrAHEAdgCPAJYAmACaAKcA2gEQAVUBfwGuAbABsgG0AbYBuAG6AdMB
2gIOAj8CQQJDAkUCTAJUAl8CYAJhAmMCaAJzAnwCkgKWAqMCrAKzArgCugK8Ar4CwALF
AscCyQLLAs0CzwLyAxcDNANZA2IDfgOAA5kDngO8A78D3QPiA+QD5gPoA+0D8wP2A/sE
FgQZBDQEOQRGBEkAAAAAAAACAQAAAAAAAABYAAAAAAAAAAAAAAAAAAAEVg==
</data>
<key>IPXExportFileNaingPreset_Masters</key>
<dict>
<key>AlbumName</key>
<string>Product Selects</string>
<key>CustomString</key>
<string></string>
<key>FormatString</key>
<string>%f</string>
<key>Name</key>
<string>Untitled</string>
<key>StartingCounterNumber</key>
<integer>1</integer>
</dict>
<key>IPXExportFileNaingPreset_Versions</key>
<dict>
<key>AlbumName</key>
<string>Export Panel Placeholder</string>
<key>CustomString</key>
<string></string>
<key>FormatString</key>
<string>%n</string>
<key>Name</key>
<string>Untitled</string>
<key>StartingCounterNumber</key>
<integer>1</integer>
</dict>
<key>IPXExportIntoMomentsSubfolders</key>
<false/>
<key>IPXExportMastersMetadataMode</key>
<integer>0</integer>
<key>IPXExportPhotosViewExpanded</key>
<true/>
<key>IPXExportPreset_Versions</key>
<dict>
<key>BlackPointCompensation</key>
<false/>
<key>DestinationPixelHeight</key>
<integer>1024</integer>
<key>DestinationPixelWidth</key>
<integer>1024</integer>
<key>ExportColorSpace</key>
<integer>1</integer>
<key>ExportSizeStyle</key>
<integer>2</integer>
<key>ImageFormat</key>
<integer>0</integer>
<key>ImageQuality</key>
<real>0.75</real>
<key>IncludeGPS</key>
<true/>
<key>IncludeIPTC</key>
<true/>
<key>MovieExportQuality</key>
<string>AVAssetExportPreset1280x720</string>
<key>RenderingIntent</key>
<integer>0</integer>
</dict>
<key>IPXExternalEditLastUsedApplicationURLBookmark</key>
<data>
Ym9va0wDAAAAAAQQMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAbAIA
AAwAAAABAQAAQXBwbGljYXRpb25zFAAAAAEBAABBZG9iZSBQaG90b3Nob3AgMjAyNBgA
AAABAQAAQWRvYmUgUGhvdG9zaG9wIDIwMjQuYXBwDAAAAAEGAAAEAAAAGAAAADQAAAAI
AAAABAMAAEbfLQQAAAAACAAAAAQDAAB4ItAEAAAAAAgAAAAEAwAALFLQBAAAAAAMAAAA
AQYAAGgAAAB4AAAAiAAAAAgAAAAABAAAQcXm5E+NPuEYAAAAAQIAAAIAAAAAAAAADwAA
AAAAAAAAAAAAAAAAAAgAAAABCQAAZmlsZTovLy8GAAAAAQEAAFN5c3RlbQAACAAAAAQD
AAAAkIKW5wAAAAgAAAAABAAAQcXWA8GAAAAkAAAAAQEAADhDMTVBRDk3LTk5QzAtNDI3
Ni1CODAxLUU4NEZDNDczNjg0MxgAAAABAgAAgQAAAAEAAADvEwAAAQAAAAAAAAAAAAAA
AQAAAAEBAAAvAAAAAAAAAAEFAADnAAAAAQIAADM3M2VjMmYxNThhZGNlNmRjOThiYzY3
YjAzY2I0YzZmYWJlMGRmNmZlNzlmNmNlNmRiZWIxZDgxYmY1ZmVhMGI7MDA7MDAwMDAw
MDA7MDAwMDAwMDA7MDAwMDAwMDA7MDAwMDAwMDAwMDAwMDAxYTtjb20uYXBwbGUuYXBw
LXNhbmRib3gucmVhZDswMTswMTAwMDAwZjswMDAwMDAwMDA0ZDA1MjJjOzAwOy9hcHBs
aWNhdGlvbnMvYWRvYmUgcGhvdG9zaG9wIDIwMjQvYWRvYmUgcGhvdG9zaG9wIDIwMjQu
YXBwAACoAAAA/v///wEAAAAAAAAADQAAAAQQAABUAAAAAAAAAAUQAACYAAAAAAAAABAQ
AAC8AAAAAAAAAEAQAACsAAAAAAAAAAIgAABoAQAAAAAAAAUgAADcAAAAAAAAABAgAADs
AAAAAAAAABEgAAAcAQAAAAAAABIgAAD8AAAAAAAAABMgAAAMAQAAAAAAACAgAABIAQAA
AAAAADAgAAB0AQAAAAAAAIHwAAB8AQAAAAAAAA==
</data>
<key>IPXInfoPanelFrame</key>
<string>{{968, 393}, {287, 94}}</string>
<key>IPXPhotoEditCropAspectRatioLocked</key>
<true/>
<key>IPXPluginHostClearVisualizeConstraints</key>
<true/>
<key>IPXWhatsNewCurrentVersion</key>
<integer>6</integer>
<key>IPXWorkspace.UXSourceListWidth</key>
<real>400</real>
<key>LastCuratedLibraryFirstTimeExperienceReadinessLogged</key>
<integer>1</integer>
<key>LastKnownHasSharedLibrary</key>
<integer>0</integer>
<key>LastKnownHasSharedLibraryPreview</key>
<integer>0</integer>
<key>NSNavLastRootDirectory</key>
<string>~/Desktop</string>
<key>NSNavPanelExpandedSizeForOpenMode</key>
<string>{800, 448}</string>
<key>NSPreferencesContentSize</key>
<string>{600, 518}</string>
<key>NSPreferencesSelectedIndex</key>
<integer>0</integer>
<key>NSScrollViewShouldScrollUnderTitlebar</key>
<false/>
<key>NSWindow Frame KeywordInspector</key>
<string>1471 474 762 319 0 0 2560 1415 </string>
<key>NSWindow Frame MainWindow</key>
<string>637 98 1512 950 0 0 2560 1415 </string>
<key>NSWindow Frame NSNavPanelAutosaveName</key>
<string>884 483 800 448 0 0 2560 1415 </string>
<key>NSWindow Frame NSSpellCheckerSubstitutionsPanel2</key>
<string>691 407 425 137 0 0 2560 1415 </string>
<key>NSWindow Frame Preferences</key>
<string>980 483 600 546 0 0 2560 1415 </string>
<key>PXRootSettingsHideWIPAlerts</key>
<false/>
<key>RecentlyDeletedItemsConfirmed</key>
<true/>
<key>RetouchAutoSourceDefaultsKey</key>
<true/>
<key>RetouchBrushRadiusDefaultsKey</key>
<real>27.486760853293411</real>
<key>StoryExportAspectRatio</key>
<string>16x9</string>
<key>allPhotosPreferredIndividualItemsColumns</key>
<integer>9</integer>
<key>curatedLibraryInitialNavigationVersion</key>
<integer>1</integer>
<key>curatedLibraryZoomLevel</key>
<integer>4</integer>
<key>didShowCompletedCurationFooterAnimation</key>
<true/>
<key>didShowCurationFooter</key>
<true/>
<key>photosGridPreferredIndividualItemsColumns</key>
<integer>7</integer>
<key>storyTitleStyleNextIndex</key>
<integer>80</integer>
<key>userDefaultsPhotosGridVersion</key>
<integer>3</integer>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>LibrarySchemaVersion</key>
<integer>5001</integer>
<key>MetaSchemaVersion</key>
<integer>3</integer>
</dict>
</plist>
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>hostname</key>
<string>Machine-Max.local</string>
<key>hostuuid</key>
<string>2AD2CC76-2AE5-5DFB-BC60-18107842D061</string>
<key>pid</key>
<integer>770</integer>
<key>processname</key>
<string>photolibraryd</string>
<key>uid</key>
<integer>501</integer>
</dict>
</plist>
Binary file not shown.
Binary file not shown.
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Loading