From 47d1c82c0343eacb3491f8b6f78fed3acd1b3625 Mon Sep 17 00:00:00 2001 From: Rhet Turnbull Date: Sat, 18 Apr 2020 12:21:08 -0700 Subject: [PATCH] Added folder support for Photos <= 4, closes #93 --- osxphotos/_constants.py | 8 +- osxphotos/_version.py | 2 +- osxphotos/albuminfo.py | 119 +++++--- osxphotos/photoinfo.py | 16 +- osxphotos/photosdb.py | 274 +++++++++++++++--- .../database/RKAlbum_name.skindex | Bin 14336 -> 14336 bytes .../database/photos.db | Bin 1904640 -> 1904640 bytes .../com.apple.Photos/appPrivateData.plist | 8 +- .../PhotoAnalysisServicePreferences.plist | 4 +- .../PhotosGraph/photosgraph.graphdb | Bin 73728 -> 73728 bytes .../com.apple.photomodel/appPrivateData.plist | 2 +- .../resources/moments/analysismetadata.plist | 2 +- .../resources/moments/historicalmarker.plist | 2 +- .../resources/moments/needsanalysis | 0 .../resources/recovery/Info.plist | 4 +- .../resources/recovery/RKAlbum/0000000000.lij | Bin 88466 -> 92598 bytes .../recovery/RKAlbumVersion/0000000000.lij | Bin 747 -> 897 bytes .../recovery/RKCustomSortOrder/0000000000.lij | Bin 3188 -> 4779 bytes .../recovery/RKFolder/0000000000.lij | Bin 6679 -> 10978 bytes .../database/Photos.sqlite | Bin 2097152 -> 2097152 bytes .../database/Photos.sqlite-shm | Bin 32768 -> 32768 bytes .../database/Photos.sqlite-wal | Bin 4152 -> 0 bytes .../database/search/psi.sqlite | Bin 147456 -> 147456 bytes .../database/search/psi.sqlite-shm | Bin 32768 -> 32768 bytes .../MediaAnalysis/mediaanalysis.db | Bin 69632 -> 69632 bytes .../MediaAnalysis/mediaanalysis.db-shm | Bin 32768 -> 32768 bytes .../CLSBusinessCategoryCache.POI.sqlite-shm | Bin 32768 -> 32768 bytes .../CLSBusinessCategoryCache.POI.sqlite-wal | Bin 3213632 -> 3279552 bytes .../caches/graph/CLSContactCache.sqlite-shm | Bin 32768 -> 32768 bytes .../caches/graph/CLSContactCache.sqlite-wal | Bin 2319592 -> 2344312 bytes .../caches/graph/CLSLocationCache.sqlite-shm | Bin 32768 -> 32768 bytes .../caches/graph/CLSLocationCache.sqlite-wal | Bin 271952 -> 321392 bytes .../graph/PGCurationCache.sqlite.sqlite-shm | Bin 32768 -> 32768 bytes .../graph/PGCurationCache.sqlite.sqlite-wal | Bin 181312 -> 181312 bytes .../PhotoAnalysisServicePreferences.plist | 20 +- .../construction-photosgraph.kgdb-shm | Bin 32768 -> 32768 bytes .../PhotosGraph/photosgraph-tmp.kgdb-shm | Bin 32768 -> 32768 bytes .../caches/graph/PhotosGraph/photosgraph.kgdb | Bin 512000 -> 512000 bytes .../PhotoAnalysisServicePreferences.plist | 4 +- .../caches/vision/vnpersonsmodel.bin | Bin 7631 -> 7631 bytes tests/test_albums_folders_mojave_10_14_6.py | 100 +++---- tests/test_cli.py | 7 +- tests/test_mojave_10_14_6.py | 13 +- tests/test_shared_mojave_10_14_6.py | 9 +- tests/test_template.py | 9 +- 45 files changed, 418 insertions(+), 185 deletions(-) delete mode 100644 tests/Test-10.14.6.photoslibrary/resources/moments/needsanalysis diff --git a/osxphotos/_constants.py b/osxphotos/_constants.py index 11059831..714a32aa 100644 --- a/osxphotos/_constants.py +++ b/osxphotos/_constants.py @@ -17,8 +17,8 @@ _TESTED_DB_VERSIONS = ["6000", "4025", "4016", "3301", "2622"] _PHOTOS_3_VERSION = "3301" # versions 5.0 and later have a different database structure -_PHOTOS_4_VERSION = "4025" # latest Mojove version on 10.14.6 -_PHOTOS_5_VERSION = "6000" # seems to be current on 10.15.1 through 10.14.4 +_PHOTOS_4_VERSION = "4025" # latest Mojove version on 10.14.6 +_PHOTOS_5_VERSION = "6000" # seems to be current on 10.15.1 through 10.15.4 # which major version operating systems have been tested _TESTED_OS_VERSIONS = ["12", "13", "14", "15"] @@ -47,3 +47,7 @@ _PHOTOS_5_ALBUM_KIND = 2 # normal user album _PHOTOS_5_SHARED_ALBUM_KIND = 1505 # shared album _PHOTOS_5_FOLDER_KIND = 4000 # user folder _PHOTOS_5_ROOT_FOLDER_KIND = 3999 # root folder + +_PHOTOS_4_ALBUM_KIND = 3 # RKAlbum.albumSubclass +_PHOTOS_4_TOP_LEVEL_ALBUM = "TopLevelAlbums" +_PHOTOS_4_ROOT_FOLDER = "LibraryFolder" diff --git a/osxphotos/_version.py b/osxphotos/_version.py index f394d84c..b4fa57e0 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,3 +1,3 @@ """ version info """ -__version__ = "0.28.1" +__version__ = "0.28.2" diff --git a/osxphotos/albuminfo.py b/osxphotos/albuminfo.py index 9c545b99..4b1e4908 100644 --- a/osxphotos/albuminfo.py +++ b/osxphotos/albuminfo.py @@ -12,7 +12,13 @@ PhotosDB.folders() returns a list of FolderInfo objects import logging -from ._constants import _PHOTOS_5_ALBUM_KIND, _PHOTOS_5_FOLDER_KIND, _PHOTOS_5_VERSION +from ._constants import ( + _PHOTOS_4_ALBUM_KIND, + _PHOTOS_4_TOP_LEVEL_ALBUM, + _PHOTOS_4_VERSION, + _PHOTOS_5_ALBUM_KIND, + _PHOTOS_5_FOLDER_KIND, +) class AlbumInfo: @@ -53,14 +59,13 @@ class AlbumInfo: ["Top level folder", "sub folder 1", "sub folder 2", ...] returns empty list if album is not in any folders """ - if self._db._db_version < _PHOTOS_5_VERSION: - logging.warning("Folders not yet implemented for this DB version") - return [] - try: return self._folder_names except AttributeError: - self._folder_names = self._db._album_folder_hierarchy_list(self._uuid) + if self._db._db_version <= _PHOTOS_4_VERSION: + self._folder_names = self._db._album_folder_hierarchy_list(self._uuid) + else: + self._folder_names = self._db._album_folder_hierarchy_list(self._uuid) return self._folder_names @property @@ -70,10 +75,6 @@ class AlbumInfo: ["Top level folder", "sub folder 1", "sub folder 2", ...] returns empty list if album is not in any folders """ - if self._db._db_version < _PHOTOS_5_VERSION: - logging.warning("Folders not yet implemented for this DB version") - return [] - try: return self._folders except AttributeError: @@ -83,19 +84,23 @@ class AlbumInfo: @property def parent(self): """ returns FolderInfo object for parent folder or None if no parent (e.g. top-level album) """ - if self._db._db_version < _PHOTOS_5_VERSION: - logging.warning("Folders not yet implemented for this DB version") - return None - try: return self._parent except AttributeError: - parent_pk = self._db._dbalbum_details[self._uuid]["parentfolder"] - self._parent = ( - FolderInfo(db=self._db, uuid=self._db._dbalbums_pk[parent_pk]) - if parent_pk != self._db._folder_root_pk - else None - ) + if self._db._db_version <= _PHOTOS_4_VERSION: + parent_uuid = self._db._dbalbum_details[self._uuid]["folderUuid"] + self._parent = ( + FolderInfo(db=self._db, uuid=parent_uuid) + if parent_uuid != _PHOTOS_4_TOP_LEVEL_ALBUM + else None + ) + else: + parent_pk = self._db._dbalbum_details[self._uuid]["parentfolder"] + self._parent = ( + FolderInfo(db=self._db, uuid=self._db._dbalbums_pk[parent_pk]) + if parent_pk != self._db._folder_root_pk + else None + ) return self._parent def __len__(self): @@ -112,8 +117,12 @@ class FolderInfo: def __init__(self, db=None, uuid=None): self._uuid = uuid self._db = db - self._pk = self._db._dbalbum_details[uuid]["pk"] - self._title = self._db._dbalbum_details[uuid]["title"] + if self._db._db_version <= _PHOTOS_4_VERSION: + self._pk = None + self._title = self._db._dbfolder_details[uuid]["name"] + else: + self._pk = self._db._dbalbum_details[uuid]["pk"] + self._title = self._db._dbalbum_details[uuid]["title"] @property def title(self): @@ -131,13 +140,22 @@ class FolderInfo: try: return self._albums except AttributeError: - albums = [ - AlbumInfo(db=self._db, uuid=album) - for album, detail in self._db._dbalbum_details.items() - if not detail["intrash"] - and detail["kind"] == _PHOTOS_5_ALBUM_KIND - and detail["parentfolder"] == self._pk - ] + if self._db._db_version <= _PHOTOS_4_VERSION: + albums = [ + AlbumInfo(db=self._db, uuid=album) + for album, detail in self._db._dbalbum_details.items() + if not detail["intrash"] + and detail["albumSubclass"] == _PHOTOS_4_ALBUM_KIND + and detail["folderUuid"] == self._uuid + ] + else: + albums = [ + AlbumInfo(db=self._db, uuid=album) + for album, detail in self._db._dbalbum_details.items() + if not detail["intrash"] + and detail["kind"] == _PHOTOS_5_ALBUM_KIND + and detail["parentfolder"] == self._pk + ] self._albums = albums return self._albums @@ -147,12 +165,20 @@ class FolderInfo: try: return self._parent except AttributeError: - parent_pk = self._db._dbalbum_details[self._uuid]["parentfolder"] - self._parent = ( - FolderInfo(db=self._db, uuid=self._db._dbalbums_pk[parent_pk]) - if parent_pk != self._db._folder_root_pk - else None - ) + if self._db._db_version <= _PHOTOS_4_VERSION: + parent_uuid = self._db._dbfolder_details[self._uuid]["parentFolderUuid"] + self._parent = ( + FolderInfo(db=self._db, uuid=parent_uuid) + if parent_uuid != _PHOTOS_4_TOP_LEVEL_ALBUM + else None + ) + else: + parent_pk = self._db._dbalbum_details[self._uuid]["parentfolder"] + self._parent = ( + FolderInfo(db=self._db, uuid=self._db._dbalbums_pk[parent_pk]) + if parent_pk != self._db._folder_root_pk + else None + ) return self._parent @property @@ -161,13 +187,22 @@ class FolderInfo: try: return self._folders except AttributeError: - folders = [ - FolderInfo(db=self._db, uuid=album) - for album, detail in self._db._dbalbum_details.items() - if not detail["intrash"] - and detail["kind"] == _PHOTOS_5_FOLDER_KIND - and detail["parentfolder"] == self._pk - ] + if self._db._db_version <= _PHOTOS_4_VERSION: + folders = [ + FolderInfo(db=self._db, uuid=folder) + for folder, detail in self._db._dbfolder_details.items() + if not detail["intrash"] + and not detail["isMagic"] + and detail["parentFolderUuid"] == self._uuid + ] + else: + folders = [ + FolderInfo(db=self._db, uuid=album) + for album, detail in self._db._dbalbum_details.items() + if not detail["intrash"] + and detail["kind"] == _PHOTOS_5_FOLDER_KIND + and detail["parentfolder"] == self._pk + ] self._folders = folders return self._folders diff --git a/osxphotos/photoinfo.py b/osxphotos/photoinfo.py index b2c7438c..fc238aa5 100644 --- a/osxphotos/photoinfo.py +++ b/osxphotos/photoinfo.py @@ -21,8 +21,8 @@ from mako.template import Template from ._constants import ( _MOVIE_TYPE, _PHOTO_TYPE, + _PHOTOS_4_VERSION, _PHOTOS_5_SHARED_PHOTO_PATH, - _PHOTOS_5_VERSION, _TEMPLATE_DIR, _XMP_TEMPLATE_NAME, ) @@ -98,7 +98,7 @@ class PhotoInfo: if self._info["isMissing"] == 1: return photopath # path would be meaningless until downloaded - if self._db._db_version < _PHOTOS_5_VERSION: + if self._db._db_version <= _PHOTOS_4_VERSION: vol = self._info["volume"] if vol is not None: photopath = os.path.join("/Volumes", vol, self._info["imagePath"]) @@ -137,7 +137,7 @@ class PhotoInfo: photopath = None - if self._db._db_version < _PHOTOS_5_VERSION: + if self._db._db_version <= _PHOTOS_4_VERSION: if self._info["hasAdjustments"]: edit_id = self._info["edit_resource_id"] if edit_id is not None: @@ -269,7 +269,7 @@ class PhotoInfo: # ) # return photopath - if self._db._db_version < _PHOTOS_5_VERSION: + if self._db._db_version <= _PHOTOS_4_VERSION: vol = self._info["raw_info"]["volume"] if vol is not None: photopath = os.path.join( @@ -400,7 +400,7 @@ class PhotoInfo: def shared(self): """ returns True if photos is in a shared iCloud album otherwise false Only valid on Photos 5; returns None on older versions """ - if self._db._db_version >= _PHOTOS_5_VERSION: + if self._db._db_version > _PHOTOS_4_VERSION: return self._info["shared"] else: return None @@ -445,7 +445,7 @@ class PhotoInfo: """ Returns True if photo is a cloud asset (in an iCloud library), otherwise False """ - if self._db._db_version < _PHOTOS_5_VERSION: + if self._db._db_version <= _PHOTOS_4_VERSION: return ( True if self._info["cloudLibraryState"] is not None @@ -488,7 +488,7 @@ class PhotoInfo: If photo is missing, returns None """ photopath = None - if self._db._db_version < _PHOTOS_5_VERSION: + if self._db._db_version <= _PHOTOS_4_VERSION: if self.live_photo and not self.ismissing: live_model_id = self._info["live_model_id"] if live_model_id == None: @@ -579,7 +579,7 @@ class PhotoInfo: # implementation note: doesn't create the PlaceInfo object until requested # then memoizes the object in self._place to avoid recreating the object - if self._db._db_version < _PHOTOS_5_VERSION: + if self._db._db_version <= _PHOTOS_4_VERSION: try: return self._place # pylint: disable=access-member-before-definition except AttributeError: diff --git a/osxphotos/photosdb.py b/osxphotos/photosdb.py index 1f1f465c..86d6b812 100644 --- a/osxphotos/photosdb.py +++ b/osxphotos/photosdb.py @@ -24,6 +24,8 @@ from ._constants import ( _TESTED_DB_VERSIONS, _TESTED_OS_VERSIONS, _UNKNOWN_PERSON, + _PHOTOS_4_ALBUM_KIND, + _PHOTOS_4_TOP_LEVEL_ALBUM, _PHOTOS_5_ROOT_FOLDER_KIND, _PHOTOS_5_FOLDER_KIND, _PHOTOS_5_ALBUM_KIND, @@ -173,6 +175,9 @@ class PhotosDB: # e.g. {'AA4145F5-098C-496E-9197-B7584958FF9B': {'99D24D3E-59E7-465F-B386-A48A94B00BC1': {'F2246D82-1A12-4994-9654-3DC6FE38A7A8': None}}, } self._dbalbum_folders = {} + # Dict with information about folders + self._dbfolder_details = {} + # Will hold the primary key of root folder self._folder_root_pk = None @@ -312,7 +317,7 @@ class PhotosDB: valid only on Photos 5; on Photos <= 4, prints warning and returns empty dict """ # if _dbalbum_details[key]["cloudownerhashedpersonid"] is not None, then it's a shared album - if self._db_version < _PHOTOS_5_VERSION: + if self._db_version <= _PHOTOS_4_VERSION: logging.warning( f"albums_shared not implemented for Photos versions < {_PHOTOS_5_VERSION}" ) @@ -348,33 +353,43 @@ class PhotosDB: @property def folder_info(self): """ return list FolderInfo objects representing top-level folders in the photos database """ - if self._db_version < _PHOTOS_5_VERSION: - logging.warning("Folders not yet implemented for this DB version") - return [] - - folders = [ - FolderInfo(db=self, uuid=album) - for album, detail in self._dbalbum_details.items() - if not detail["intrash"] - and detail["kind"] == _PHOTOS_5_FOLDER_KIND - and detail["parentfolder"] == self._folder_root_pk - ] + if self._db_version <= _PHOTOS_4_VERSION: + folders = [ + FolderInfo(db=self, uuid=folder) + for folder, detail in self._dbfolder_details.items() + if not detail["intrash"] + and not detail["isMagic"] + and detail["parentFolderUuid"] == _PHOTOS_4_TOP_LEVEL_ALBUM + ] + else: + folders = [ + FolderInfo(db=self, uuid=album) + for album, detail in self._dbalbum_details.items() + if not detail["intrash"] + and detail["kind"] == _PHOTOS_5_FOLDER_KIND + and detail["parentfolder"] == self._folder_root_pk + ] return folders @property def folders(self): """ return list of top-level folder names in the photos database """ - if self._db_version < _PHOTOS_5_VERSION: - logging.warning("Folders not yet implemented for this DB version") - return [] - - folder_names = [ - detail["title"] - for detail in self._dbalbum_details.values() - if not detail["intrash"] - and detail["kind"] == _PHOTOS_5_FOLDER_KIND - and detail["parentfolder"] == self._folder_root_pk - ] + if self._db_version <= _PHOTOS_4_VERSION: + folder_names = [ + folder["name"] + for folder in self._dbfolder_details.values() + if not folder["intrash"] + and not folder["isMagic"] + and folder["parentFolderUuid"] == _PHOTOS_4_TOP_LEVEL_ALBUM + ] + else: + folder_names = [ + detail["title"] + for detail in self._dbalbum_details.values() + if not detail["intrash"] + and detail["kind"] == _PHOTOS_5_FOLDER_KIND + and detail["parentfolder"] == self._folder_root_pk + ] return folder_names @property @@ -395,7 +410,7 @@ class PhotosDB: only valid for Photos 5; on Photos <= 4, prints warning and returns empty list """ # if _dbalbum_details[key]["cloudownerhashedpersonid"] is not None, then it's a shared album - if self._db_version < _PHOTOS_5_VERSION: + if self._db_version <= _PHOTOS_4_VERSION: logging.warning( f"albums_shared not implemented for Photos versions < {_PHOTOS_5_VERSION}" ) @@ -434,7 +449,7 @@ class PhotosDB: # if _dbalbum_details[key]["cloudownerhashedpersonid"] is not None, then it's a shared album - if self._db_version < _PHOTOS_5_VERSION: + if self._db_version <= _PHOTOS_4_VERSION: logging.warning( f"album_names_shared not implemented for Photos versions < {_PHOTOS_5_VERSION}" ) @@ -538,7 +553,10 @@ class PhotosDB: # Get info on albums c.execute( - """ select RKAlbum.uuid, 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.isInTrash = 0 """ @@ -554,17 +572,31 @@ class PhotosDB: # now get additional details about albums c.execute( - "SELECT " - "uuid, " # 0 - "name, " # 1 - "cloudLibraryState, " # 2 - "cloudIdentifier, " # 3 - "isInTrash " # 4 - "FROM RKAlbum " + """ SELECT + uuid, + name, + cloudLibraryState, + cloudIdentifier, + isInTrash, + folderUuid, + albumType, + albumSubclass + FROM RKAlbum """ ) + # Order of results + # 0: uuid + # 1: name + # 2: cloudLibraryState + # 3: cloudIdentifier + # 4: isInTrash + # 5: folderUuid + # 6: albumType + # 7: albumSubclass -- if 3, normal user album + for album in c: self._dbalbum_details[album[0]] = { + "_uuid": album[0], "title": album[1], "cloudlibrarystate": album[2], "cloudidentifier": album[3], @@ -573,13 +605,71 @@ class PhotosDB: "cloudownerfirstname": None, # Photos 5 "cloudownderlastname": None, # Photos 5 "cloudownerhashedpersonid": None, # Photos 5 + "folderUuid": album[5], + "albumType": album[6], + "albumSubclass": album[7], } + # get details about folders + c.execute( + """ SELECT + uuid, + modelId, + name, + isMagic, + isInTrash, + folderType, + parentFolderUuid, + folderPath + FROM RKFolder """ + ) + + # Order of results + # 0 uuid, + # 1 modelId, + # 2 name, + # 3 isMagic, + # 4 isInTrash, + # 5 folderType, + # 6 parentFolderUuid, + # 7 folderPath + + for row in c: + uuid = row[0] + self._dbfolder_details[uuid] = { + "_uuid": row[0], + "modelId": row[1], + "name": row[2], + "isMagic": row[3], + "intrash": row[4], + "folderType": row[5], + "parentFolderUuid": row[6], + "folderPath": row[7], + } + + # build _dbalbum_folders in form uuid: [parent uuid] to be consistent with _process_database5 + for album, details in self._dbalbum_details.items(): + # album can be in a single folder + parent = details["folderUuid"] + self._dbalbum_parent_folders[album] = [parent] + + # build folder hierarchy + for album, details in self._dbalbum_details.items(): + parent_folder = details["folderUuid"] + if parent_folder != _PHOTOS_4_TOP_LEVEL_ALBUM: + # logging.warning(f"album = {details['title']}, parent = {parent_folder}") + folder_hierarchy = self._build_album_folder_hierarchy_4(parent_folder) + self._dbalbum_folders[album] = folder_hierarchy + else: + self._dbalbum_folders[album] = {} + if _debug(): 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)) + logging.debug(pformat(self._dbalbum_folders)) + logging.debug(pformat(self._dbfolder_details)) # Get info on keywords c.execute( @@ -1122,6 +1212,30 @@ class PhotosDB: logging.debug("Burst Photos (dbphotos_burst:") logging.debug(pformat(self._dbphotos_burst)) + def _build_album_folder_hierarchy_4(self, uuid, folders=None): + """ recursively build folder/album hierarchy + uuid: uuid of the album/folder being processed + folders: dict holding the folder hierarchy """ + + parent_uuid = self._dbfolder_details[uuid]["parentFolderUuid"] + + # logging.warning(f"uuid = {uuid}, parent = {parent_uuid}, folders = {folders}") + + if parent_uuid is None: + return folders + + if parent_uuid == _PHOTOS_4_TOP_LEVEL_ALBUM: + # at top of hierarchy, we're done + return folders + + # recurse to keep building + if not folders: + # first time building + folders = {uuid: None} + folders = {parent_uuid: folders} + folders = self._build_album_folder_hierarchy_4(parent_uuid, folders=folders) + return folders + def _process_database5(self): """ process the Photos database to extract info """ """ works on Photos version >= 5.0 """ @@ -1228,6 +1342,8 @@ class PhotosDB: self._folder_root_pk = self._dbalbum_details[root_uuid[0]]["pk"] # build _dbalbum_folders which is in form uuid: [list of parent uuids] + # TODO: look at this code...it works but I think I album can only be in a single folder + # which means there's a code path that will never get executed for album, details in self._dbalbum_details.items(): pk_parent = details["parentfolder"] if pk_parent is None: @@ -1246,10 +1362,10 @@ class PhotosDB: for album, details in self._dbalbum_details.items(): # if details["kind"] in [_PHOTOS_5_ALBUM_KIND, _PHOTOS_5_FOLDER_KIND]: if details["kind"] == _PHOTOS_5_ALBUM_KIND: - folder_hierarchy = self._build_album_folder_hierarchy(album) + folder_hierarchy = self._build_album_folder_hierarchy_5(album) self._dbalbum_folders[album] = folder_hierarchy elif details["kind"] == _PHOTOS_5_SHARED_ALBUM_KIND: - # shared albums can be in folders + # shared albums can't be in folders self._dbalbum_folders[album] = [] if _debug(): @@ -1257,6 +1373,7 @@ class PhotosDB: logging.debug(pformat(self._dbalbums_album)) logging.debug(pformat(self._dbalbums_uuid)) logging.debug(pformat(self._dbalbum_details)) + logging.debug(pformat(self._dbalbum_folders)) # get details on keywords c.execute( @@ -1747,14 +1864,11 @@ class PhotosDB: logging.debug("Burst Photos (dbphotos_burst:") logging.debug(pformat(self._dbphotos_burst)) - def _build_album_folder_hierarchy(self, uuid, folders=None): + def _build_album_folder_hierarchy_5(self, uuid, folders=None): """ recursively build folder/album hierarchy uuid: uuid of the album/folder being processed folders: dict holding the folder hierarchy """ - if self._db_version < _PHOTOS_5_VERSION: - raise AttributeError("Not yet implemented for this DB version") - # get parent uuid parent = self._dbalbum_details[uuid]["parentfolder"] @@ -1770,10 +1884,50 @@ class PhotosDB: # recurse to keep building folders = {parent_uuid: folders} - folders = self._build_album_folder_hierarchy(parent_uuid, folders=folders) + folders = self._build_album_folder_hierarchy_5(parent_uuid, folders=folders) return folders def _album_folder_hierarchy_list(self, album_uuid): + if self._db_version <= _PHOTOS_4_VERSION: + return self._album_folder_hierarchy_list_4(album_uuid) + else: + return self._album_folder_hierarchy_list_5(album_uuid) + + def _album_folder_hierarchy_list_4(self, album_uuid): + """ return hierarchical list of folder names album_uuid is contained in + the folder list is in form: + ["Top level folder", "sub folder 1", "sub folder 2"] + returns empty list of album is not in any folders """ + # title = photosdb._dbalbum_details[album_uuid]["title"] + folders = self._dbalbum_folders[album_uuid] + + def _recurse_folder_hierarchy(folders, hierarchy=[]): + """ recursively walk the folders dict to build list of folder hierarchy """ + if not folders: + # empty folder dict (album has no folder hierarchy) + return [] + + if len(folders) != 1: + raise ValueError("Expected only a single key in folders dict") + + folder_uuid = list(folders)[0] # first and only key of dict + + parent_title = self._dbfolder_details[folder_uuid]["name"] + hierarchy.append(parent_title) + + folders = folders[folder_uuid] + if folders: + # still have elements left to recurse + hierarchy = _recurse_folder_hierarchy(folders, hierarchy=hierarchy) + return hierarchy + + # no elements left to recurse + return hierarchy + + hierarchy = _recurse_folder_hierarchy(folders) + return hierarchy + + def _album_folder_hierarchy_list_5(self, album_uuid): """ return hierarchical list of folder names album_uuid is contained in the folder list is in form: ["Top level folder", "sub folder 1", "sub folder 2"] @@ -1808,6 +1962,46 @@ class PhotosDB: return hierarchy def _album_folder_hierarchy_folderinfo(self, album_uuid): + if self._db_version <= _PHOTOS_4_VERSION: + return self._album_folder_hierarchy_folderinfo_4(album_uuid) + else: + return self._album_folder_hierarchy_folderinfo_5(album_uuid) + + def _album_folder_hierarchy_folderinfo_4(self, album_uuid): + """ return hierarchical list of FolderInfo objects album_uuid is contained in + ["Top level folder", "sub folder 1", "sub folder 2"] + returns empty list of album is not in any folders """ + # title = photosdb._dbalbum_details[album_uuid]["title"] + folders = self._dbalbum_folders[album_uuid] + # logging.warning(f"uuid = {album_uuid}, folder = {folders}") + + def _recurse_folder_hierarchy(folders, hierarchy=[]): + """ recursively walk the folders dict to build list of folder hierarchy """ + # logging.warning(f"folders={folders},hierarchy = {hierarchy}") + if not folders: + # empty folder dict (album has no folder hierarchy) + return [] + + if len(folders) != 1: + raise ValueError("Expected only a single key in folders dict") + + folder_uuid = list(folders)[0] # first and only key of dict + hierarchy.append(FolderInfo(db=self, uuid=folder_uuid)) + + folders = folders[folder_uuid] + if folders: + # still have elements left to recurse + hierarchy = _recurse_folder_hierarchy(folders, hierarchy=hierarchy) + return hierarchy + + # no elements left to recurse + return hierarchy + + hierarchy = _recurse_folder_hierarchy(folders) + # logging.warning(f"hierarchy = {hierarchy}") + return hierarchy + + def _album_folder_hierarchy_folderinfo_5(self, album_uuid): """ return hierarchical list of FolderInfo objects album_uuid is contained in ["Top level folder", "sub folder 1", "sub folder 2"] returns empty list of album is not in any folders """ diff --git a/tests/Test-10.14.6.photoslibrary/database/RKAlbum_name.skindex b/tests/Test-10.14.6.photoslibrary/database/RKAlbum_name.skindex index 005f905f80023bde4b25d09f16a2345680cd317a..5e617eb24a2756e4b8a0c5862dd14311e7b996f0 100644 GIT binary patch delta 488 zcmZvYK}!Nb6vyA2S=VvZvJlzzkP8{;BD%^-(4|E}h`iJX2!lFwsJvLW@X|r(qH~Ha zUHSkz*Qk?+pnIR7uh21jgBe9V`0;pe{`2O|zt`z?3XSez4ZsBeLFmkz0PKx&1ORoj z4x7`DLE9dLJLt(4%b_>8&Y?4U2~b~15;`0L0a7si5z1vQ4w)$K->yH9AWlRHJvc^K zM4hM-I?S>haa;BIrAdzoQCv=XVQH_iu@y8!zt$=v9?PmYvu0&Qm%X%;6mx;EJ2&Y^ zc^+$z6A_jN@ci%7iupC>_f#bkuQ(LZtP>b;3I}ikM~wEGZx!&G^s^b2GoCrg(2-R$ zqgHH>+5hVUu6E5k9NS!MFU@}D>aUZxfBape{)9Xyzu}6wCn(ZnO^UF{rUimc6y~3} lj0Yhy*($AO5~R{TYS#^&89)J4zjVQ6+cbv0rL4mH;wNqJSD*j@ delta 234 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 At^fc4 delta 1534 zcma)5Yitx%6rMXXJG;6PTTEm`iLPaba&PkOfUgkAH+wXknl%iAViHMHGq~M z`e)lFEHNQrNp)^arES!Iplxm8ng~)zgAK8vWNj%(Ed;0wG`6H*0bB6yR)Hu!ZgP@y z&-uRZJmyYAdwoNDeX=Mxt|;WBa_?A|b}z0Z<6Rp@_86|x0_{1%8*2(!_baXM5oY={ zt%$6Bsk(0Cwzs2xRV$X4=Qr2A{>D2-_hegMgH}Z=xVw~W>JGLaGDSs%oFXz7MQl^X~crCrONd$+i>2b40-n9KnF(cf;@1B;Tr3 zwfua-2RcX@^CDEKlKh;EaBfVMt|`YO_-jr3Ud>)&7%74j#--*#Ff&7CwrUV7ka5dx zHHTP4C0^p;7f+CKqhCQkhO_7be+Ck^RhNWVgsJkjET-la%5ie}^)V9q+dTIxKWy6n zpVg@gBMNR}3Td3fi0tPW_(+Kw5k}H?2VN~R^t4Q7mVE+ZbcOmzXNlZ~-;}(w_y)~* z6EQkVzoVbf&9sJ^W=7>}Q;f{15mmpc;HtczNA7~ml#j+#zg)wgXUAP=;x2TxAt*In zW}gBF#k7k)W%fzdSEjMeC{~`V;MJ{qp}4R|FH>d5g9>Kw3ohae1|{lS@WBqfO6axT zVem7D^~IUyXQ0VC2a>*<@MKn-srnzcIoSvyrXaQCZb`y+C2S*MyA!r2Vdo@lZ^HH^ zY=6Qw6E;0yLvQee&C?1l;W!U;VxgDT(bwoIx{Q{~ruLY;GY*}P&8e1{K7^pEh0PRq z_hONkMre^aZliTRue6ZICr1RCY}M0Ph$H+ zv3LFn`w;qrArX%Twg+exomKD~e#JEybe7X|Sjuak4lGm=mL2V+Vs=%)Q|5KyLI!pN z7eru7U;xdfg&sb&3%d9@9tbD1PlMjdZUr4^#ZJ7Bx3CU1h|*igl~Ska{mt+NCBbXV zPlqId4&gYRlB5r_lr^Y^4+|w>{~v_4k)S0eBf-4$@(r{on8Xl{VlP@G<^%ASlF%lh zms&@`k3~bv<#Vvo;1erC1ws#G-PQB%IQW(Iq3{Dysn?@m7FRHWW9X53pMv+qL$xw7 ztl+lXNg89>-?a~XcvmRmap7WiUBbV`8pV#wZ6Rq3q~%J>lV(ZFmsTLHP+V>c7fCfO zt@wI9%(YcZ>u0-zg~Qs8^mJIHr;FHx_Oj6~zcc&zvtXei+Q(VHUv(mU(U)u{$Ek1^ ztt|F5t>;^(Sw7!1$iS1=Syzs;cs{XiKJh{`Gx=bO?b93UoJG9h2R5NMu5%veTZY(> z-nhnjjJJHmPU=k?oGNkfCfi6T;kY# TVvY&biHh&{u~*6G#ev@e79-?z diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.Photos/appPrivateData.plist b/tests/Test-10.14.6.photoslibrary/private/com.apple.Photos/appPrivateData.plist index a5cdd9c2..c4268fcf 100644 --- a/tests/Test-10.14.6.photoslibrary/private/com.apple.Photos/appPrivateData.plist +++ b/tests/Test-10.14.6.photoslibrary/private/com.apple.Photos/appPrivateData.plist @@ -9,12 +9,14 @@ ExpandedSidebarItemIdentifiers TopLevelAlbums + QtSnVvTkQ%i2z3hB834M1A TopLevelSlideshows + N7eQ4VhfTfeHFp9PPHaJDw IPXWorkspaceControllerZoomLevelsKey kZoomLevelIdentifierAlbums - 10 + 5 kZoomLevelIdentifierVersions 7 @@ -23,11 +25,11 @@ key 1 lastKnownDisplayName - Test Album (1) + Pumpkin Farm (1) type album uuid - Uq6qsKihRRSjMHTiD+0Azg + xJ8ya3NBRWC24gKhcwwNeQ lastKnownItemCounts diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist index 3cc13e1e..f20ca78b 100644 --- a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist +++ b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotoAnalysisServicePreferences.plist @@ -3,8 +3,8 @@ PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate - 2020-03-27T04:00:09Z + 2020-04-18T18:01:02Z PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate - 2020-03-27T04:00:10Z + 2020-04-18T17:22:55Z diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph.graphdb b/tests/Test-10.14.6.photoslibrary/private/com.apple.photoanalysisd/GraphService/PhotosGraph/photosgraph.graphdb index 8ec89205c5d1a62bec35d1ec35e2442fa3ea1649..bcc42fc2fb4d5046e16d366a8bda300e489c2364 100644 GIT binary patch literal 73728 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 literal 73728 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 diff --git a/tests/Test-10.14.6.photoslibrary/private/com.apple.photomodel/appPrivateData.plist b/tests/Test-10.14.6.photoslibrary/private/com.apple.photomodel/appPrivateData.plist index be020436..ecebb467 100644 --- a/tests/Test-10.14.6.photoslibrary/private/com.apple.photomodel/appPrivateData.plist +++ b/tests/Test-10.14.6.photoslibrary/private/com.apple.photomodel/appPrivateData.plist @@ -5,7 +5,7 @@ LithiumMessageTracer LastReportedDate - 2020-03-15T20:19:24Z + 2020-04-17T17:51:16Z diff --git a/tests/Test-10.14.6.photoslibrary/resources/moments/analysismetadata.plist b/tests/Test-10.14.6.photoslibrary/resources/moments/analysismetadata.plist index ab262e0d..3592de9e 100644 --- a/tests/Test-10.14.6.photoslibrary/resources/moments/analysismetadata.plist +++ b/tests/Test-10.14.6.photoslibrary/resources/moments/analysismetadata.plist @@ -11,6 +11,6 @@ PLLastRevGeoForcedProviderOutOfDateCheckVersionKey 1 PLLastRevGeoVerFileFetchDateKey - 2020-03-27T03:59:54Z + 2020-04-17T17:49:52Z diff --git a/tests/Test-10.14.6.photoslibrary/resources/moments/historicalmarker.plist b/tests/Test-10.14.6.photoslibrary/resources/moments/historicalmarker.plist index 89349855..51fe5a2b 100644 --- a/tests/Test-10.14.6.photoslibrary/resources/moments/historicalmarker.plist +++ b/tests/Test-10.14.6.photoslibrary/resources/moments/historicalmarker.plist @@ -3,7 +3,7 @@ LastHistoryRowId - 575 + 606 LibraryBuildTag D8C4AAA1-3AB6-4A65-BEBD-99CC3E5D433E LibrarySchemaVersion diff --git a/tests/Test-10.14.6.photoslibrary/resources/moments/needsanalysis b/tests/Test-10.14.6.photoslibrary/resources/moments/needsanalysis deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/Info.plist b/tests/Test-10.14.6.photoslibrary/resources/recovery/Info.plist index 6f690882..19fe5a2e 100644 --- a/tests/Test-10.14.6.photoslibrary/resources/recovery/Info.plist +++ b/tests/Test-10.14.6.photoslibrary/resources/recovery/Info.plist @@ -9,7 +9,7 @@ HistoricalMarker LastHistoryRowId - 575 + 606 LibraryBuildTag D8C4AAA1-3AB6-4A65-BEBD-99CC3E5D433E LibrarySchemaVersion @@ -24,7 +24,7 @@ SnapshotCompletedDate 2019-07-27T13:16:43Z SnapshotLastValidated - 2020-03-27T04:02:59Z + 2020-04-17T17:51:16Z SnapshotTables diff --git a/tests/Test-10.14.6.photoslibrary/resources/recovery/RKAlbum/0000000000.lij b/tests/Test-10.14.6.photoslibrary/resources/recovery/RKAlbum/0000000000.lij index 709d4fd4974e3bf995cd8f08638e558ce9556750..de69f777fe482bef8478958cd1d6c413e9a0f343 100644 GIT binary patch delta 775 zcmbQVnRVM`)`l&NlOh?5Co=kMZkcM#WPM0=dsUUxl6V2J(Bveuii)z(;9T$IbjMI% zlPVMQkaVDgpLuGaNmxc&NLs3gTY+UjfJdU2OSu5UGMW$Rh!^UKai^|jB-p9Jxl^i zoD0h=GcEj$earnpt_my(&I>CG$qrP_G^#SraI!Eq@ilaWxylgik~YCiEo=xKy>oCB-1JG|9Xu z9p)+{uuHl(XH5}g3WBrAa#hnrM%V4VL5x;R3c%o>y1cpuXnTd1MP;I~pHon{vyn-< zcSdq~xnFAF^mPG@Iy&(J0s*DD1=*Q-3T}x-xe6MFngYxM#$Z=WU2fbi$P@x+gIzSa zeli>9ZD8EpXL`Z(dU`=1qdeo6=?!6w1;WP4pg5npvOyZ6Wu>6ObjL_WS;p|`is6jL zjO!)`u9ljVPgO~Ljb>Ft+&rN0#yW-1m}g7g=7b+W*Su)XE<3H zoA??!3Nm?t3}bAYJd4qXmtT;{8|(m(p2-_HXIZg004)&2=Fh3ie@6n1t?;s_Of>d$ z3JP~NGD-K&NG>n;OAQoc3I+R92&W3LHB(pIE(WSFG%fW@F;}$+N-qs@P4^4%_DBl} z2ZmJ`*q`d`p8QPF0;XUcGxf@T3kXiGXE$WLHjy#QUKpp(AjrWie-vts%GkC>Svn4G<$LYzdYOAsXBe$((i`T zB)}-hl1(}>7CZ&6dPktt1$k+nZpl2BopOINyl3!FAl9!m98XR9zEWjkdD8Mer z<9T2Non9X zgoH#xQO-)_kO%~aL=?7=XubVX6JJOKmIUX8m4##ns%9Eh8D}_I7@PPSI${qAPH;%H z-cEWb$mByzNN_?!!V(e^t#>M3fkMI;XGlO&5GN=FSs3M*CVH3zmN*xdS!P=J8~c{~ z15=P6I4QIVR#kvg5Z<8U6l4kj1sx<28G&_n&#hp_5p)pCIe?ZI`efx;x(1{LTDlkd z8|5ZPMdT%>1PU?*LX6m4cZVp;gAwrtv3x@ORtX%I6Y@wbnnw=$bKgiJ$1GraibI$M RPEQ8|MXyZ7FpCwOo&auXZaDw| delta 7 OcmaD9I^AT0xD)^mP6Ffr diff --git a/tests/Test-10.15.1.photoslibrary/database/Photos.sqlite b/tests/Test-10.15.1.photoslibrary/database/Photos.sqlite index cd3245d1a175eff4ad06dce7f68ba54c5d93d9b0..8fc284302778bd773ca657a3afbd36f124453ffb 100644 GIT binary patch delta 186 zcmWm1%L&3j6hKj)KL7u}lf+CJaqB`X$OZ-pq=eavB?yCL;VxDoXdNPWT^uggIVbKf zm%NtOubLUT_^r{CRK7I&m2szYuOo%-EJ=KC7tRAH*N~>s~i5A-Epo<>* e7+{DI#+YD=8Rl4Ei51o`h!7*e25Bg*-M@aSB1AC& delta 186 zcmWm1%L&3j6hKj)KL7u}lf+CJaqB`X$OZ-pq=Z?CO$dWzA+ZlZ>kz@~;&8dnIdOlv zd$HhJNvXB1?dYX kEF@Ju$T$!Hnfo6JfCU*CCf0K@I&EzH?83;nv9Z|-0EMP4?EnA( diff --git a/tests/Test-10.15.1.photoslibrary/database/Photos.sqlite-wal b/tests/Test-10.15.1.photoslibrary/database/Photos.sqlite-wal index b7a2c385b40ca35de811599586aef3829a21b382..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 GIT binary patch literal 0 HcmV?d00001 literal 4152 zcmeHIy=xRf6rcU@?sk)0PB3V+@N^L@95cJKAG3|gd=?^Dh<1uZQwTAMQNbu8YGWZ5 zT385TrG2@KS0DcdtQn&qF_Lfd$7aKz|MQWkN37XSG$1l`*jGl zkc~~Bp0EFU7w!1`;7j`P#_>0BBoK0!&f|&c+efcmof!%P6b7L)P#?TMynf(SaAoMu z@RjD(APg^87xkAu1APYi4D=c3Gtg(C&%l4nz&~RLM5OUywfVEz) zqb+;U7`o*>Tl8Jeop`qBxlw~J-aGj1!t0OYA7~Y@-ydFTP41bRYbR`5J0UTnQs|g- zinBbHI2D{@rj@}&7{v<3h33h^DqDiBpwV!ghSLbDw<H_X10Km87ObA_2E>g^-CBDovAYKYgwP2|f zik2pubs#k;4)Lqhe%(iw_^~Rp51H#xeeCE!w$ zODvMOz%eN@Za^tQ^X3`12jTJ^vSA5fEviKxUwpVGoM=DoO4Z%lzTAE2#O&nMe5RGm zi7K!XMQnSd#DZoLD^k)pXM%~;G*fi?H*jG>RP9;8UAgW&AJ%?rP)I$xW$)VVdkV*yJyGKgmf!7*U zsy@4Sq*0aFz&nZ~lkWV~=AAdE?WuIb=k;Y3rpC-ROYJICnLYWrEf&OsgT+OPe>U^m zaTVC$m>iny#qV*WTGDTSC)B}o<(~_xHQoPbmpYK0_;+V{U4C+r@9X^uI@!B2-}h@p zfAih7!)Y;E*2k z!{xwX##|uKqkdQg#2IsdI>u_?0Dor{u%EFKXkjb>HtW0}ZUmeVNlX%~wLmLl4ba4>7T`MDfhvB&W}u9*4VbORBN0DLfIIl>TYwpiCSW^bGtkUv z1g0}K0n_xDwSE`}wazEKa1lQXZnF@RZHzi#E29=jFlvA;I`75MVvWbQU53d5K2;A) zWGn@I#uC6|EC!;C`9K-JwRu3P9`!7)Q(NqrsLK4Frm9tSX8v?lWoMWRro)^uU(Ft~ z&opLx%D==i8*0_0ozV*sN~7l@v_{WFsEwYA&>KBT3eg-r7GYJ!y2Ve-=#ddB zrEU>ArJJ&&YP?tkADN;>%85`T-4UTjx-CMH)EiXtyGMg`O@^qDIz-qV)SmlMr_QA+ z&f8P=gjr)^#xrhfV`KM}Pl;u2_p6p5UfA40eQwr(;_Y47-GRwn8dO8}zqj!l^}!^u zEQ+J}*H{#iSQ0L;OJX^=yyE6vE;}Vrpv(I%`&{0WLq+Fd&J} zT@Jf^>CV4!`P}6*mrq?jarxNgkQJa2m%T2tE^ie_n+t`zLAQtfRj8P2mMK=FJDYQP SM-rX7>~Pth`}s*t*!vHqW@!@u delta 1485 zcmbW%$!}9v6b5kL`}|(=5`1qY2rQ0M5QC5?AyTA9q6m~CQ5pzHg(ATQQXpY2V_Sx{ z_8Orqa9ayDz@kz?6oE|jj8I^~k_A$1vqDao=Y%25B;h;9_b(uu@AuC0aQ(h}lTL@} zba-}Uxw<9vH+o7n=Q_#@RJ95How%}@|N6T9!{$$WG}GGuO>Ki|G}Fvic8;mf9qR8+ zge~Ews<`5}O&QpuLKE(iOPf1B*lg6YOkuc9t;jTt98*7JdPY{L<+-t=-`6!2#>ay| zceW)Do&Wm&#aFX?+Vk_ScI%RiPqkhskN#t~ovFF;cTMT~8C}d~tZG%gQPHZ?CY9Ho z(o=OQh_FPxSr>z72e5_F0ff3Yh}HnjjMYFBV-K)_U$YzNWb6XE80&ylj0AKKA zKj1O;0rk4*M|-_c^WfJMCT*-=fQ^iwfrX6qf~J#cr92i3e$@j8-PWOE})Ik34Esu zegZ8v`uN&tJ0@T9t)GCgjBP-`*b4ZJEr7>Z3)J#c`w^(oy}rfg%&PK@r?SHn)l4-x zJ7bcXZfBZf=A`+{+%c=nIIZ=&%B8ESiqD2}Mp+*`Ip+|ZuLXq?&Y~W{) z2I-azQ6b$F;dD@c^sGr8N!K5?N9{o~*CdQ@+|kCtK36v(k^R3%b%iaJ!yPt9Q!gn# z-j&lG+UUe(b;W-6F}|j*n-sQ1m4{!AO(BUb;qta5wu8&Eo8NPJR}uxf9CG>6820PbWU=>Px# diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db b/tests/Test-10.15.1.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db index d584f58a8d1ca0d27c2b61e030ad89e3fe6f813b..5001971363d3546bb6d5189056ec4e2e8fa116ba 100644 GIT binary patch delta 22 dcmZozz|ydQWr8%L_Cy(HM(xIgtqF_^_yJOV2I2q! delta 22 dcmZozz|ydQWr8%L_(U0JM)AgktqF_^_yJJa2D$(M diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-shm b/tests/Test-10.15.1.photoslibrary/private/com.apple.mediaanalysisd/MediaAnalysis/mediaanalysis.db-shm index af8895123f6920cc32ce5fff70b6ed5e0cd4f81b..697c33515b7d2027c6310470898f6d91de297c81 100644 GIT binary patch delta 78 zcmZo@U}|V!njj(ZE8)Vr|8I06(^tPatq$-U7 delta 70 zcmZo@U}|V!njj(Zd0(%6Yp=bg$|-wa^__N0dG2nizM9u`cY=f@E-A)|iSmq$8yoBE E0W>Tgq5uE@ diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-shm index ff1b23e6ee20abc693dbf78ba24581ae26b7b7e9..182adbd53cc8239a773693b6d637a40dbf17bde0 100644 GIT binary patch delta 197 zcmZo@U}|V!s+V}A%K!q55G)|W%)lT3WOwf2Sh?}>X4`evQP)qd-M6}Ez4_aBlgciW zsvcxE2!PD}j|3p13``8t8yn4eCN6N;yn~0$Z1X=SF*XHWWhZ+?^`Ckz0!NIOXY delta 165 zcmZo@U}|V!s+V}A%K!q55G=sM%)lT3WdD>4ExtI%NpGEX)b*2V_pMgajW7DAT`5ee xdXU*505bPK5`c&@Ffnj%Y&7TD{DX(hY_b5a!{&cZVr-ikdCw_tev~683;>vQGNS+h diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSBusinessCategoryCache.POI.sqlite-wal index f1af3e7d4b2fe2069dea6066754893a67ea30d14..666a4bddc08175a0b522b790dbfd65c8566c57a6 100644 GIT binary patch delta 561 zcmXBO$ty$w0LSs3Z3e@8v(LOYGxlZ1_M9Y%iBJj$%lHdiC^@)LmVTE}$kyZ_4oVKT zM!k!}6tW#097JIXXC_h@W$JhS^zHYHES?CFm2+Vd0+Nu76r>^zI_Qy(3}nK9EM!B3 z1S3o^!vZU8u)_f-WGHaK4G(gVi#+6`0EH+*F-lMhFMKFNIVwI_3ieIW~P~G0-8h7-G^72g=W!)my;5EX;<=)^mI(K(yZ*t zOYZ!aUdd0h(QLGKf<)9kbk-`3dRcIg_;L37aFhkq*lt7;w1NpsTXXO~WQ ze*E7wnI>z|HYxGb_o;rqJZdzBrm(wN7+sIeX+1O-%|+W24b$<~nJ~>wbJMo$sYg! delta 109 zcmV~$#Sy|l006)_Jh;0Ack6)Ccx(mC&E;6qS@! rRMpfqG_|yKboKNN42_IUOwGjR7M51lHnw*54vtRFF0O8$`y=`TyV@f> diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-shm b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-shm index 77b3c69ba8bb9d3a0e6d402416c02173b2db6548..09b27bc5e4adad82948ce1e5537b292d9abe35af 100644 GIT binary patch delta 221 zcmZo@U}|V!s+V}A%K!q*K+MR%AYjSFz@P|Z^Y3@N`F2`GbIsMqZ_ZU#zexMbxY8(r z!HHD$AhSULWbS_?01;(iVldsZA)J#eC;xMjU^Zbg+sqjFm}&DLS1vY2 zb0GUY)8=n}JWPxhK=xtQ&Bwy@7#U50?DLG9k3{BhGFk%JM_D%~a6S;-e63E45ddIU BO5Okf delta 204 zcmZo@U}|V!s+V}A%K!q55G-KK#K52kWXo-sxy$pjVqVSF$8XM6R=-$b9T>LvwfAmP z)q~6i0g$=>kpM)Lfr-IzW8-Cx%_W>&mXjMe6(;|4lGtpN{ETVyA6G6mAnOCu=5KyH hOhDEV*3HMl^caDx3yhnOMCNb;SxclhU#Zh!1OU#6N*VwF diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-wal b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSContactCache.sqlite-wal index 958d2087671df6ea7020f2b39078222f9965189f..1225782415246309de8c09229d5713ab58fdf27d 100644 GIT binary patch delta 318 zcmaEHvX}8kS3hGz3u6mY3v&xg3u_Bo3wsMk3ug;g3wH}o3vUZw3xA71i(rdTi*Sob zi)f2ji+GDfi)4#bi*$=ji)@Qri+qbhi(-q?7UdTy(=(El1UP&ib7}QYe0zC%fH0FZ zs~ZCYgW~jnXm)!>x9tZODQ@5w;E}g$HJSQehnK~HL7IhuVS39Z#hB?AHYu`ff3QjM z1~UsgCnM*^Kvu@>2e&I8=i=Bu`{v!5lRo@{80d~L(0%)dLqG#L5`GuH5DowNe!IXF zrb)bvR@$}7 z{rt@p)80-$QOZ}$;=t6vv@x)gQP_5w4hI7#CkH!2y5sd_VfV#epP0_QT~Tj(<1;14 K?N;W>b-Vy;0&iac delta 81 zcmV~$#}R@+006)_F=7BoCJ;kw7UE-H&M-7%6LvxgKH2?$`Y`;u@D@x&re@|AmR4eG d8(TYx)Ltf6C{+%QPR=fBjjPtp-Q)WlUL$4)8qfd$ diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-shm index 350fc8cb04cadcb3220240ceb4edfac0344eb195..3bd83e4cefbbc218b2fcbadba729106942ed29c8 100644 GIT binary patch delta 310 zcmZo@U}|V!s+V}A%K!t63=9H(K+Z`ZW=@^P5_YBNqGNGs0!z}(gWF_u5B9iSUPG#S znAsq6|04mYI1_{4#zua|iC;t{`G7(KKr9Hv8bF*5#M6Oz#^#BP;`W=bIG8XoI!~U+ zc#>6-!HmHdD5}cD&cz_hV94MC6h1rof*Tv7A5i!^)8=!Y226~uVD{v1ete8>KxRJU z=8}L8E=G4C`#sai(DK?dDfG}(N`!Gvk@A;we8iVS9(4>GDVv2roUG8j%i z$asG81vj?MhZuh_Z9eB|zyxMZ{^rLAWE3!NE(z%10QHvq*hux)OrYhVNbWw};M diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/CLSLocationCache.sqlite-wal index 101eeb1d38972ffd719cf17f51b71e40b7c0739f..a0688cd9e12afad2f1e2725bc3e158965f5bcb6a 100644 GIT binary patch delta 8520 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 Dqkd`+ delta 17 YcmexxPWZwZfrb{w7N!>FEi3_Q07@bTz5oCK diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-shm index 42c6fc29ddf098585be49d4eef19d48ee095636a..6a3d111e9b8c219a6eb347af6a5c83c51b4c9160 100644 GIT binary patch delta 64 vcmZo@U}|V!njj%j<*?+n`TL#D;mz5*)jgsQZ~xsIqsG9z7?0G(ga!2ggGU@= delta 64 wcmZo@U}|V!njj(3wWDU*{~sGmgJ;(?a<_V~na%64>ez+aZFr820P40NF#rGn diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PGCurationCache.sqlite.sqlite-wal index 0c42aec5a6de6cac1830069f7e0d4acdc20c9964..668a6e0b0825e6427760a469dea53a3fd29ac24f 100644 GIT binary patch delta 1138 zcmYk&dn{W~90&0B3M(SLhLCN{XrftGX?xMug0>zr8LL+$%)H-WV%Z4hInr$YsA85S z!|cYIE#`6AAxtb}9(!Ry#1gMkW-?|Hk+D@w{Z4ZJ`JD4T=bK-@+_+zEEEE(Pl+ZYf zRx}z;J6vIJuRCKoNy5BISfl=STu<*F;HWcc~Eur(%re6U)ajkycn zwNNsgf$Q{p)|9v?tVL5*Y-?Vnu+@i~QrOO)9>G5<>9vG+deqSFD-n5}Rx zikl74m?>m3zaXGh9T$aGFF=-&Op-i zQNIciHwY%O=)R+Qp)U#K8w)voVS47E-Dn9#XF;~qv`u%;F`uHG63CGiE)0gFjRGl@ zkP8NkMh3ecv>;U@WYtFOka_RDP}JWJd2~d>pJfRXj=DEbfbKyz<=;rxgiq#nL$pm>#e>u z>uZgY?IAD6{O}2J<7S{D0`lV52u_{jTJBNz^kD2{?w#!Sn7eYe47CQsMBtS)8`|8# zCK`@|%)Oo$>bKX&Li4vF<1yt1*FvKE(QYYZmCL7G^#{fT!mA^yb`O)#cdCaCRvtuK&-30#ud>st>~O#A9k~|# z8D|R%%wm1XtFx4Lw@x;P$33{*Rq@wpjVSAT)Axvv=I>@wiZle~-WFkIV4DZ7^1?|@ z-0vZhz^t(?J*+DCiomnE8YO#|M$M+dO{&>b+xgrhEt8Zg$pV=pfcY7r(dD3xc}*=b zCJi=x9}~_IMw*sMEn$s0Y}V*!-3gmWHte@0l>#cpw1SCD8FJ~)NG8as6p*0Zs61A~ zD2R(%OrVqB;C^|K;-8gh>Q6F0b(D%Sd5GK{&=8} zALJK&Oe~d3MdCmqx!USY-5N?hepCB0Z2l`LX#=m8G)NkC^IV^`zlInZ?y&#X{TIIb zbg40;56P5aaNkbdIUsOJGm@%lpuIh@yn+TpGgKycQ1SXp6 zO4H@)SvO?;1@h<#21{Ano`l$okfW>VG~Y(57s4&6VC-fu^?8EGA4kMa$cl86XOyWa z7+u*5*(yjEo)@y{i*iJegXkXJxT7?7qx)4kb$jm1<3)}$q5gEFmBR!+k=UAfF0K;w z$3YG$5yd;1jmc>08e}eusL+g*^3YNq BackgroundHighlightCollection - 2020-04-16T17:31:22Z + 2020-04-17T14:33:32Z BackgroundHighlightEnrichment - 2020-04-16T17:31:21Z + 2020-04-17T14:33:32Z BackgroundJobAssetRevGeocode - 2020-04-16T17:31:22Z + 2020-04-17T14:33:33Z BackgroundJobSearch - 2020-04-16T17:31:22Z + 2020-04-17T14:33:33Z BackgroundPeopleSuggestion - 2020-04-16T17:31:21Z + 2020-04-17T14:33:31Z BackgroundUserBehaviorProcessor - 2020-04-16T06:52:39Z + 2020-04-17T07:32:04Z PhotoAnalysisGraphLastBackgroundGraphConsistencyUpdateJobDateKey - 2020-04-16T17:38:41Z + 2020-04-17T14:33:37Z PhotoAnalysisGraphLastBackgroundGraphRebuildJobDate - 2020-04-16T06:52:38Z + 2020-04-17T07:32:00Z PhotoAnalysisGraphLastBackgroundMemoryGenerationJobDate - 2020-04-16T17:31:22Z + 2020-04-17T14:33:34Z SiriPortraitDonation - 2020-04-16T06:52:39Z + 2020-04-17T07:32:04Z diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/construction-photosgraph.kgdb-shm b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/construction-photosgraph.kgdb-shm index fe9ac2845eca6fe6da8a63cd096d9cf9e24ece10..ca5a3e0161935b8d90903afe67d1ec68143a5841 100644 GIT binary patch delta 13 UcmZo@U}|V!n%JPRQR7BE03%%mZU6uP delta 13 UcmZo@U}|V!nrL9K(cnTo03odfCIA2c diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph-tmp.kgdb-shm b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph-tmp.kgdb-shm index fe9ac2845eca6fe6da8a63cd096d9cf9e24ece10..ca5a3e0161935b8d90903afe67d1ec68143a5841 100644 GIT binary patch delta 13 UcmZo@U}|V!n%JPRQR7BE03%%mZU6uP delta 13 UcmZo@U}|V!nrL9K(cnTo03odfCIA2c diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/graph/PhotosGraph/photosgraph.kgdb index 97af9cca44d954a25ee5019d0302608ced5e9c4e..2f9b30804f8949470f8b2886c400920439a9d572 100644 GIT binary patch delta 810 zcmZWnUr19?7(eIio_lxicJDd!&bh5}D{%f@zZjc1O#3Jt7 zcuue>%d?p*<^&(OkjwNsDo$dsliJS@_NOim^aKMz1Q3^k(8PxPPPt9DcUY)^foi9*)Cl4@>LMtAr+Nk=@fY*gz70!mAcM`N8ZdC! zX=1RyZ{P~zP$3&gSAn{j@aN2j>edjH*@VZTT8QpWow2s=LTOGfUBwRje%MxlpeHK{ z49d%BJaxGr!A=C&3y;H~tOEAVQ^R1Loh|siroTF16Mm;dr5IFDXQC^4w4-2(3#Q~8 zu;((?d~^K_jmF!Wnw!J1urJsU3HZYMwU{s3)EM=}v`~u{4K_sMkrtVo0jId^9)3H% zY5q(uk*wq<0dkByR=!BrS!HXohHR70N(ZEzxGtH*XX1NtNSqS=;%Vb54jCWFy+*U~ zkntLqW%pXW!V*{9vzb>0s>TH%TFYn|LcENi#>QhTAJXn4B>ZG=+IN>5`;2}6-Wtf8 zJG>~p_#dt|mfSc5>-CwTRSlOwgkY!$O5cIB2qdeiz}YC(%Tr_!eHNVsk{T&VFoJ=i z#2G4rm3pffBG{OJ-Z^Z551BtX2tB#XF7`6%)l{jZ)aMb3N}>TC0JVLKas&}9JP52* z8@51RH!b`~Xw3(@UI*~;Hva8)-Pdkw&I7xx3<+x`OmD=)viM=hYSd+uCm| CX`Imj delta 842 zcmZ8fTS!zv7@nD(*|X=IJ(u0HH`jF6GTqcY?#<0b0xx^ij9n`Vv72tSL6nLSp+)Et zp)V@i1O*}a5Y}V1kWmly&{Ks(PeIsI5tI-KS@>dS7xFeU9}M63&;NZh%;=0~bjI`8 z=nYH+r3Gn8C^t?p26i7;CJ0Q#ykh=rToPi&m*O{x7hg!j926&wAEksiNTc4HWR`J= zALcUeNSJYA0?J(S*@3>)`Tm|@Ab>EEJrV-WW4a)_)`cJf2&W+AX^&b&uc^LUl`0&f zwUzA_hWP?4VAIHrS3ZDD+U6JTykQdFWrCne=dhWK#A<`(zFBJTGL@Y6+xoMQb7;-|N43g z?ZgBDcB|Z)y3~hY2Lj?lVBM5X-_nH&HxgIrFV(GxtH8EZ1@yUE(^#Vt(qV}oW9Mht~c(f(#Z?12N`6GLyQGb0* ztMiBJL(y<+YeD#s%Iu*C) z%UA8z~T?EE1U7qSIKHD z6@%hz##yDbt+yx&BA9<_SSo42zReGST%hw!fPnJBpR+gCM#k1g;QZPM;!i?tj9)}L P3_7q5GS4p>e=q+7ckZDN diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist index 401beb19..61af2d00 100644 --- a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist +++ b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/vision/PhotoAnalysisServicePreferences.plist @@ -3,8 +3,8 @@ FaceIDModelLastGenerationKey - 2020-04-16T06:52:40Z + 2020-04-17T07:32:07Z LastContactClassificationKey - 2020-04-16T06:52:42Z + 2020-04-17T07:32:12Z diff --git a/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/vision/vnpersonsmodel.bin b/tests/Test-10.15.1.photoslibrary/private/com.apple.photoanalysisd/caches/vision/vnpersonsmodel.bin index 33d1e7bf825e600e81f65cc4f0f771d096686f7b..8cbdaf14c2c10eb51b88ebfa0e8a9879b408b352 100644 GIT binary patch delta 58 zcmV-A0LA~$JI_0ig$2obM)KgXiVgz;^5B!2104)-iuoDMe*gf`tcDn~!vp*o5TGBN Q8AIGY1L(*DFp{(FV;R;OU;qFB delta 58 zcmV-A0LA~$JI_0ig#{cO5X(!kiVgz;Qt^|T104(y=3Exde*gf$OI;ST!vp*o5OsXo QG}i@qA1BVCaX_Nb%7YIVJOBUy diff --git a/tests/test_albums_folders_mojave_10_14_6.py b/tests/test_albums_folders_mojave_10_14_6.py index 41971c2c..91bbc44f 100644 --- a/tests/test_albums_folders_mojave_10_14_6.py +++ b/tests/test_albums_folders_mojave_10_14_6.py @@ -4,32 +4,33 @@ from osxphotos._constants import _UNKNOWN_PERSON PHOTOS_DB = "./tests/Test-10.14.6.photoslibrary/database/photos.db" -# TOP_LEVEL_FOLDERS = ["Folder1"] +TOP_LEVEL_FOLDERS = ["Folder1"] -# TOP_LEVEL_CHILDREN = ["SubFolder1", "SubFolder2"] +TOP_LEVEL_CHILDREN = ["SubFolder1", "SubFolder2"] -# FOLDER_ALBUM_DICT = {"Folder1": [], "SubFolder1": [], "SubFolder2": ["AlbumInFolder"]} +FOLDER_ALBUM_DICT = {"Folder1": [], "SubFolder1": [], "SubFolder2": ["AlbumInFolder"]} -# ALBUM_NAMES = ["Pumpkin Farm", "AlbumInFolder", "Test Album", "Test Album"] -ALBUM_NAMES = ["Pumpkin Farm", "Test Album", "Test Album (1)"] +ALBUM_NAMES = ["Pumpkin Farm", "AlbumInFolder", "Test Album", "Test Album (1)"] -# ALBUM_PARENT_DICT = { -# "Pumpkin Farm": None, -# "AlbumInFolder": "SubFolder2", -# "Test Album": None, -# } +ALBUM_PARENT_DICT = { + "Pumpkin Farm": None, + "AlbumInFolder": "SubFolder2", + "Test Album": None, + "Test Album (1)": None, +} -# ALBUM_FOLDER_NAMES_DICT = { -# "Pumpkin Farm": [], -# "AlbumInFolder": ["Folder1", "SubFolder2"], -# "Test Album": [], -# } +ALBUM_FOLDER_NAMES_DICT = { + "Pumpkin Farm": [], + "AlbumInFolder": ["Folder1", "SubFolder2"], + "Test Album": [], + "Test Album (1)": [], +} ALBUM_LEN_DICT = { "Pumpkin Farm": 3, "Test Album": 1, "Test Album (1)": 1, - # "AlbumInFolder": 2, + "AlbumInFolder": 1, } ALBUM_PHOTO_UUID_DICT = { @@ -40,10 +41,7 @@ ALBUM_PHOTO_UUID_DICT = { ], "Test Album": ["8SOE9s0XQVGsuq4ONohTng"], "Test Album (1)": ["15uNd7%8RguTEgNPKHfTWw"], - # "AlbumInFolder": [ - # "3DD2C897-F19E-4CA6-8C22-B027D5A71907", - # "E9BC5C36-7CD1-40A1-A72B-8B8FAC227D51", - # ], + "AlbumInFolder": ["15uNd7%8RguTEgNPKHfTWw"], } UUID_DICT = {"two_albums": "8SOE9s0XQVGsuq4ONohTng"} @@ -51,62 +49,57 @@ UUID_DICT = {"two_albums": "8SOE9s0XQVGsuq4ONohTng"} ######### Test FolderInfo ########## -def test_folders_1(caplog): +def test_folders_1(): import osxphotos photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) folders = photosdb.folders - assert folders == [] - assert "Folders not yet implemented for this DB version" in caplog.text - # # top level folders - # folders = photosdb.folders - # assert len(folders) == 1 + # top level folders + folders = photosdb.folder_info + assert len(folders) == 1 - # # check folder names - # folder_names = [f.title for f in folders] - # assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) + # check folder names + folder_names = [f.title for f in folders] + assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) -def test_folder_names(caplog): +def test_folder_names(): import osxphotos photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) # check folder names folder_names = photosdb.folders - assert folder_names == [] - assert "Folders not yet implemented for this DB version" in caplog.text - # assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) + assert folder_names == TOP_LEVEL_FOLDERS + assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) -@pytest.mark.skip(reason="Folders not yet impleted in Photos < 5") def test_folders_len(): import osxphotos photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) # top level folders - folders = photosdb.folders + folders = photosdb.folder_info assert len(folders[0]) == len(TOP_LEVEL_CHILDREN) -@pytest.mark.skip(reason="Folders not yet impleted in Photos < 5") def test_folders_children(): import osxphotos photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) # top level folders - folders = photosdb.folders + folders = photosdb.folder_info # children of top level folder - children = folders[0].folders + children = folders[0].subfolders children_names = [f.title for f in children] assert sorted(children_names) == sorted(TOP_LEVEL_CHILDREN) - for child in folders[0].folders: + for child in folders[0].subfolders: # check valid children FolderInfo assert child.parent assert child.parent.uuid == folders[0].uuid @@ -116,38 +109,36 @@ def test_folders_children(): assert sorted(folder_names) == sorted(TOP_LEVEL_FOLDERS) -@pytest.mark.skip(reason="Folders not yet impleted in Photos < 5") def test_folders_parent(): import osxphotos photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) # top level folders - folders = photosdb.folders + folders = photosdb.folder_info # parent of top level folder should be none for folder in folders: assert folder.parent is None - for child in folder.folders: + for child in folder.subfolders: # children's parent uuid should match folder uuid assert child.parent assert child.parent.uuid == folder.uuid -@pytest.mark.skip(reason="Folders not yet impleted in Photos < 5") def test_folders_albums(): import osxphotos photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) # top level folders - folders = photosdb.folders + folders = photosdb.folder_info for folder in folders: name = folder.title albums = [a.title for a in folder.album_info] assert sorted(albums) == sorted(FOLDER_ALBUM_DICT[name]) - for child in folder.folders: + for child in folder.subfolders: name = child.title albums = [a.title for a in child.album_info] assert sorted(albums) == sorted(FOLDER_ALBUM_DICT[name]) @@ -162,14 +153,14 @@ def test_albums_1(): photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) albums = photosdb.album_info - assert len(albums) == 3 + assert len(albums) == 4 # check names album_names = [a.title for a in albums] assert sorted(album_names) == sorted(ALBUM_NAMES) -def test_albums_parent(caplog): +def test_albums_parent(): import osxphotos photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) @@ -178,11 +169,10 @@ def test_albums_parent(caplog): for album in albums: parent = album.parent.title if album.parent else None - assert "Folders not yet implemented for this DB version" in caplog.text - # assert parent == ALBUM_PARENT_DICT[album.title] + assert parent == ALBUM_PARENT_DICT[album.title] -def test_albums_folder_names(caplog): +def test_albums_folder_names(): import osxphotos photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) @@ -191,11 +181,10 @@ def test_albums_folder_names(caplog): for album in albums: folder_names = album.folder_names - assert "Folders not yet implemented for this DB version" in caplog.text - # assert folder_names == ALBUM_FOLDER_NAMES_DICT[album.title] + assert folder_names == ALBUM_FOLDER_NAMES_DICT[album.title] -def test_albums_folders(caplog): +def test_albums_folders(): import osxphotos photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB) @@ -204,9 +193,8 @@ def test_albums_folders(caplog): for album in albums: folders = album.folder_list - assert "Folders not yet implemented for this DB version" in caplog.text - # folder_names = [f.title for f in folders] - # assert folder_names == ALBUM_FOLDER_NAMES_DICT[album.title] + folder_names = [f.title for f in folders] + assert folder_names == ALBUM_FOLDER_NAMES_DICT[album.title] def test_albums_len(): diff --git a/tests/test_cli.py b/tests/test_cli.py index f0828d02..20f9eb78 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -780,7 +780,7 @@ def test_no_folder_2_15(): assert item["albums"] == ["AlbumInFolder"] -def test_no_folder_1_14(caplog): +def test_no_folder_1_14(): # test --folder on 10.14 import json import os @@ -797,6 +797,5 @@ def test_no_folder_1_14(caplog): ) assert result.exit_code == 0 json_got = json.loads(result.output) - - assert len(json_got) == 0 # single element - assert "not yet implemented" in caplog.text + assert len(json_got) == 1 # single element + assert json_got[0]["uuid"] == "15uNd7%8RguTEgNPKHfTWw" diff --git a/tests/test_mojave_10_14_6.py b/tests/test_mojave_10_14_6.py index b5ad8417..71de658f 100644 --- a/tests/test_mojave_10_14_6.py +++ b/tests/test_mojave_10_14_6.py @@ -18,7 +18,7 @@ KEYWORDS = [ "United Kingdom", ] PERSONS = ["Katie", "Suzy", "Maria"] -ALBUMS = ["Pumpkin Farm", "Test Album", "Test Album (1)"] +ALBUMS = ["Pumpkin Farm", "AlbumInFolder", "Test Album", "Test Album (1)"] KEYWORDS_DICT = { "Kids": 4, "wedding": 2, @@ -31,7 +31,12 @@ KEYWORDS_DICT = { "United Kingdom": 1, } PERSONS_DICT = {"Katie": 3, "Suzy": 2, "Maria": 1} -ALBUM_DICT = {"Pumpkin Farm": 3, "Test Album": 1, "Test Album (1)": 1} +ALBUM_DICT = { + "Pumpkin Farm": 3, + "AlbumInFolder": 1, + "Test Album": 1, + "Test Album (1)": 1, +} UUID_DICT = { "favorite": "6bxcNnzRQKGnK4uPrCJ9UQ", @@ -131,7 +136,9 @@ def test_attributes(): ) assert p.description == "Girl holding pumpkin" assert p.title == "I found one!" - assert p.albums == ["Pumpkin Farm", "Test Album (1)"] + assert sorted(p.albums) == sorted( + ["Pumpkin Farm", "AlbumInFolder", "Test Album (1)"] + ) assert p.persons == ["Katie"] assert p.path.endswith( "/tests/Test-10.14.6.photoslibrary/Masters/2019/07/27/20190727-131650/Pumkins2.jpg" diff --git a/tests/test_shared_mojave_10_14_6.py b/tests/test_shared_mojave_10_14_6.py index bb52b978..b78e592b 100644 --- a/tests/test_shared_mojave_10_14_6.py +++ b/tests/test_shared_mojave_10_14_6.py @@ -7,8 +7,13 @@ PHOTOS_DB = "./tests/Test-10.14.6.photoslibrary/database/photos.db" PHOTOS_DB_PATH = "/Test-10.14.6.photoslibrary/database/photos.db" PHOTOS_LIBRARY_PATH = "/Test-10.14.6.photoslibrary" -ALBUMS = ["Pumpkin Farm", "Test Album", "Test Album (1)"] -ALBUM_DICT = {"Pumpkin Farm": 3, "Test Album": 1, "Test Album (1)": 1} +ALBUMS = ["Pumpkin Farm", "AlbumInFolder", "Test Album", "Test Album (1)"] +ALBUM_DICT = { + "Pumpkin Farm": 3, + "AlbumInFolder": 1, + "Test Album": 1, + "Test Album (1)": 1, +} def test_album_names(): diff --git a/tests/test_template.py b/tests/test_template.py index 4d3fd666..81242795 100644 --- a/tests/test_template.py +++ b/tests/test_template.py @@ -15,7 +15,7 @@ UUID_DICT = { "0_2_0": "6191423D-8DB8-4D4C-92BE-9BBBA308AAC4", "folder_album_1": "3DD2C897-F19E-4CA6-8C22-B027D5A71907", "folder_album_no_folder": "D79B8D77-BFFC-460B-9312-034F2877D35B", - "mojave_no_folder": "15uNd7%8RguTEgNPKHfTWw", + "mojave_album_1": "15uNd7%8RguTEgNPKHfTWw", } TEMPLATE_VALUES = { @@ -341,17 +341,16 @@ def test_subst_multi_folder_albums_2(): def test_subst_multi_folder_albums_3(caplog): - """ Test substitutions for folder_album on < Photos 5 (not implemented) """ + """ Test substitutions for folder_album on < Photos 5 """ import osxphotos from osxphotos.template import render_filepath_template photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB_14_6) # photo in an album in a folder - photo = photosdb.photos(uuid=[UUID_DICT["mojave_no_folder"]])[0] + photo = photosdb.photos(uuid=[UUID_DICT["mojave_album_1"]])[0] template = "{folder_album}" - expected = ["Pumpkin Farm", "Test Album (1)"] + expected = ["Folder1/SubFolder2/AlbumInFolder", "Pumpkin Farm", "Test Album (1)"] rendered, unknown = render_filepath_template(template, photo) assert sorted(rendered) == sorted(expected) assert unknown == [] - assert "not yet implemented" in caplog.text