Skip to content

Commit

Permalink
Fix for external adjustments, #1518 (#1525)
Browse files Browse the repository at this point in the history
  • Loading branch information
RhetTbull committed Apr 20, 2024
1 parent a080b97 commit 53bbb45
Show file tree
Hide file tree
Showing 70 changed files with 2,011 additions and 12 deletions.
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.
Empty file.

0 comments on commit 53bbb45

Please sign in to comment.