diff --git a/osxphotos/__init__.py b/osxphotos/__init__.py
index 7d156256..d54af977 100644
--- a/osxphotos/__init__.py
+++ b/osxphotos/__init__.py
@@ -28,6 +28,7 @@ from . import _applescript
# TODO: standardize _ and __ as leading char for private variables
# TODO: fix docstrings
# TODO: handle Null person for Photos 5
+# TODO: Add special albums and magic albums
# which Photos library database versions have been tested
# Photos 2.0 (10.12.6) == 2622
@@ -142,6 +143,8 @@ class PhotosDB:
self._dbalbums_uuid = {}
# Dict with information about all albums/photos by album
self._dbalbums_album = {}
+ # Dict with information about album details
+ self._dbalbum_details = {}
# Dict with information about all the volumes/photos by uuid
self._dbvolumes = {}
@@ -230,7 +233,8 @@ class PhotosDB:
""" return albums as dict of albums, count in reverse sorted order (descending) """
albums = {}
for k in self._dbalbums_album.keys():
- albums[k] = len(self._dbalbums_album[k])
+ title = self._dbalbum_details[k]["title"]
+ albums[title] = len(self._dbalbums_album[k])
albums = dict(sorted(albums.items(), key=lambda kv: kv[1], reverse=True))
return albums
@@ -246,8 +250,12 @@ class PhotosDB:
def albums(self):
""" return list of albums found in photos database """
- albums = self._dbalbums_album.keys()
- return list(albums)
+ albums = []
+ for album in self._dbalbums_album.keys():
+ albums.append(self._dbalbum_details[album]["title"])
+ return albums
+ # albums = self._dbalbums_album.keys()
+ # return list(albums)
def _setup_applescript(self):
""" setup various applescripts used internally (e.g. to close Photos) """
@@ -457,7 +465,7 @@ class PhotosDB:
)
# c.execute("select RKPerson.name, RKFace.imageID from RKFace, RKPerson where RKFace.personID = RKperson.modelID")
c.execute(
- "select RKAlbum.name, RKVersion.uuid from RKAlbum, RKVersion, RKAlbumVersion "
+ "select RKAlbum.uuid, RKVersion.uuid from RKAlbum, RKVersion, RKAlbumVersion "
+ "where RKAlbum.modelID = RKAlbumVersion.albumId and "
+ "RKAlbumVersion.versionID = RKVersion.modelId and RKVersion.type = 2 and "
+ "RKVersion.filename not like '%.pdf' and RKVersion.isInTrash = 0"
@@ -472,6 +480,33 @@ class PhotosDB:
self._dbalbums_album[album[0]].append(album[1])
i = i + 1
+ # now get additional details about albums
+ c.execute(
+ "SELECT "
+ "uuid, " # 0
+ "name, " # 1
+ "cloudLibraryState, " # 2
+ "cloudIdentifier " # 3
+ "FROM RKAlbum "
+ "WHERE isInTrash = 0"
+ )
+
+ for album in c:
+ self._dbalbum_details[album[0]] = {
+ "title": album[1],
+ "cloudlibrarystate": album[2],
+ "cloudidentifier": album[3],
+ "cloudlocalstate": None, # Photos 5
+ "cloudownerfirstname": None, # Photos 5
+ "cloudownderlastname": None, # Photos 5
+ "cloudownerhashedpersonid": None, # Photos 5
+ }
+
+ logging.debug(f"Finished walking through albums")
+ logging.debug(pformat(self._dbalbums_album))
+ logging.debug(pformat(self._dbalbums_uuid))
+ logging.debug(pformat(self._dbalbum_details))
+
c.execute(
"select count(*) from RKKeyword, RKKeywordForVersion,RKVersion, RKMaster "
+ "where RKKeyword.modelId = RKKeyWordForVersion.keywordID and "
@@ -628,18 +663,20 @@ class PhotosDB:
self._dbphotos[uuid]["edit_resource_id"] = row[2]
# get details on external edits
- c.execute( "SELECT RKVersion.uuid, "
- "RKVersion.adjustmentUuid, "
- "RKAdjustmentData.originator, "
- "RKAdjustmentData.format "
- "FROM RKVersion, RKAdjustmentData "
- "WHERE RKVersion.adjustmentUuid = RKAdjustmentData.uuid "
- "AND RKVersion.isInTrash = 0")
-
+ c.execute(
+ "SELECT RKVersion.uuid, "
+ "RKVersion.adjustmentUuid, "
+ "RKAdjustmentData.originator, "
+ "RKAdjustmentData.format "
+ "FROM RKVersion, RKAdjustmentData "
+ "WHERE RKVersion.adjustmentUuid = RKAdjustmentData.uuid "
+ "AND RKVersion.isInTrash = 0"
+ )
+
for row in c:
uuid = row[0]
if uuid in self._dbphotos:
- self._dbphotos[uuid]["adjustmentFormatID"] = row[3]
+ self._dbphotos[uuid]["adjustmentFormatID"] = row[3]
# init any uuids that had no edits
for uuid in self._dbphotos:
@@ -756,7 +793,7 @@ class PhotosDB:
"WHERE ZGENERICASSET.ZTRASHEDSTATE = 0 AND ZGENERICASSET.ZKIND = 0 "
)
c.execute(
- "SELECT ZGENERICALBUM.ZTITLE, ZGENERICASSET.ZUUID "
+ "SELECT ZGENERICALBUM.ZUUID, ZGENERICASSET.ZUUID "
"FROM ZGENERICASSET "
"JOIN Z_26ASSETS ON Z_26ASSETS.Z_34ASSETS = ZGENERICASSET.Z_PK "
"JOIN ZGENERICALBUM ON ZGENERICALBUM.Z_PK = Z_26ASSETS.Z_26ALBUMS "
@@ -771,9 +808,33 @@ class PhotosDB:
self._dbalbums_uuid[album[1]].append(album[0])
self._dbalbums_album[album[0]].append(album[1])
i = i + 1
+
+ # now get additional details about albums
+ c.execute(
+ "SELECT "
+ "ZUUID, " # 0
+ "ZTITLE, " # 1
+ "ZCLOUDLOCALSTATE, " # 2
+ "ZCLOUDOWNERFIRSTNAME, " # 3
+ "ZCLOUDOWNERLASTNAME, " # 4
+ "ZCLOUDOWNERHASHEDPERSONID " # 5
+ "FROM ZGENERICALBUM"
+ )
+ for album in c:
+ self._dbalbum_details[album[0]] = {
+ "title": album[1],
+ "cloudlocalstate": album[2],
+ "cloudownerfirstname": album[3],
+ "cloudownderlastname": album[4],
+ "cloudownerhashedpersonid": album[5],
+ "cloudlibrarystate": None, # Photos 4
+ "cloudidentifier": None, # Photos4
+ }
+
logging.debug(f"Finished walking through albums")
logging.debug(pformat(self._dbalbums_album))
logging.debug(pformat(self._dbalbums_uuid))
+ logging.debug(pformat(self._dbalbum_details))
c.execute(
"SELECT COUNT(*) "
@@ -1038,9 +1099,20 @@ class PhotosDB:
photos_sets.append(set(self._dbphotos.keys()))
else:
if albums:
+ album_titles = {}
+ for album_id in self._dbalbum_details:
+ title = self._dbalbum_details[album_id]["title"]
+ if title in album_titles:
+ album_titles[title].append(album_id)
+ else:
+ album_titles[title] = [album_id]
for album in albums:
- if album in self._dbalbums_album:
- photos_sets.append(set(self._dbalbums_album[album]))
+ # TODO: can have >1 album with same name. This globs them together.
+ # Need a way to select with album
+ # TODO: document this in docs and add test
+ if album in album_titles:
+ for album_id in album_titles[album]:
+ photos_sets.append(set(self._dbalbums_album[album_id]))
else:
logging.debug(f"Could not find album '{album}' in database")
@@ -1233,7 +1305,10 @@ class PhotoInfo:
def albums(self):
""" list of albums picture is contained in """
- return self.__info["albums"]
+ albums = []
+ for album in self.__info["albums"]:
+ albums.append(self.__db._dbalbum_details[album]["title"])
+ return albums
def keywords(self):
""" list of keywords for picture """
diff --git a/tests/Test-10.12.6.photoslibrary/database/photos.db b/tests/Test-10.12.6.photoslibrary/database/photos.db
index 3f05fbaf..c3b177f5 100644
Binary files a/tests/Test-10.12.6.photoslibrary/database/photos.db and b/tests/Test-10.12.6.photoslibrary/database/photos.db differ
diff --git a/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist b/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist
index 82f8638a..9f33ea62 100644
--- a/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist
+++ b/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist
@@ -3,8 +3,8 @@
PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate
- 2019-08-24T02:51:33Z
+ 2019-12-07T16:40:40Z
PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate
- 2019-08-24T13:19:30Z
+ 2019-12-07T16:40:41Z
diff --git a/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph-tmp.graphdb-shm b/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph-tmp.graphdb-shm
index fe9ac284..ca5a3e01 100644
Binary files a/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph-tmp.graphdb-shm and b/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph-tmp.graphdb-shm differ
diff --git a/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph.graphdb b/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph.graphdb
index 323eccdc..de2fb528 100644
Binary files a/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph.graphdb and b/tests/Test-10.12.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph.graphdb differ
diff --git a/tests/Test-10.12.6.photoslibrary/resources/moments/analysismetadata.plist b/tests/Test-10.12.6.photoslibrary/resources/moments/analysismetadata.plist
index 3a99d5f2..af372a50 100644
--- a/tests/Test-10.12.6.photoslibrary/resources/moments/analysismetadata.plist
+++ b/tests/Test-10.12.6.photoslibrary/resources/moments/analysismetadata.plist
@@ -11,6 +11,6 @@
PLLastRevGeoForcedProviderOutOfDateCheckVersionKey
1
PLLastRevGeoVerFileFetchDateKey
- 2019-08-24T02:51:30Z
+ 2019-12-07T16:40:32Z
diff --git a/tests/Test-10.12.6.photoslibrary/resources/recovery/Info.plist b/tests/Test-10.12.6.photoslibrary/resources/recovery/Info.plist
index afe288ff..040c1396 100644
--- a/tests/Test-10.12.6.photoslibrary/resources/recovery/Info.plist
+++ b/tests/Test-10.12.6.photoslibrary/resources/recovery/Info.plist
@@ -9,7 +9,7 @@
HistoricalMarker
LastHistoryRowId
- 403
+ 414
LibraryBuildTag
E3E46F2A-7168-4973-AB3E-5848F80BFC7D
LibrarySchemaVersion
diff --git a/tests/Test-10.12.6.photoslibrary/resources/recovery/RKVersion/0000000000.lij b/tests/Test-10.12.6.photoslibrary/resources/recovery/RKVersion/0000000000.lij
index e57ff789..6ec9187c 100644
Binary files a/tests/Test-10.12.6.photoslibrary/resources/recovery/RKVersion/0000000000.lij and b/tests/Test-10.12.6.photoslibrary/resources/recovery/RKVersion/0000000000.lij differ