Changed PhotosDB albums interface as prep for adding folders
This commit is contained in:
10
README.md
10
README.md
@@ -368,7 +368,7 @@ def main():
|
|||||||
photosdb = osxphotos.PhotosDB(db)
|
photosdb = osxphotos.PhotosDB(db)
|
||||||
print(photosdb.keywords)
|
print(photosdb.keywords)
|
||||||
print(photosdb.persons)
|
print(photosdb.persons)
|
||||||
print(photosdb.albums)
|
print(photosdb.album_names)
|
||||||
|
|
||||||
print(photosdb.keywords_as_dict)
|
print(photosdb.keywords_as_dict)
|
||||||
print(photosdb.persons_as_dict)
|
print(photosdb.persons_as_dict)
|
||||||
@@ -554,17 +554,17 @@ keywords = photosdb.keywords
|
|||||||
|
|
||||||
Returns a list of the keywords found in the Photos library
|
Returns a list of the keywords found in the Photos library
|
||||||
|
|
||||||
#### `albums`
|
#### `album_names`
|
||||||
```python
|
```python
|
||||||
# assumes photosdb is a PhotosDB object (see above)
|
# assumes photosdb is a PhotosDB object (see above)
|
||||||
albums = photosdb.albums
|
albums = photosdb.album_names
|
||||||
```
|
```
|
||||||
|
|
||||||
Returns a list of the albums found in the Photos library.
|
Returns a list of the albums found in the Photos library.
|
||||||
|
|
||||||
**Note**: In Photos 5.0 (MacOS 10.15/Catalina), It is possible to have more than one album with the same name in Photos. Albums with duplicate names are treated as a single album and the photos in each are combined. For example, if you have two albums named "Wedding" and each has 2 photos, osxphotos will treat this as a single album named "Wedding" with 4 photos in it.
|
**Note**: In Photos 5.0 (MacOS 10.15/Catalina), It is possible to have more than one album with the same name in Photos. Albums with duplicate names are treated as a single album and the photos in each are combined. For example, if you have two albums named "Wedding" and each has 2 photos, osxphotos will treat this as a single album named "Wedding" with 4 photos in it.
|
||||||
|
|
||||||
#### `albums_shared`
|
#### `album_names_shared`
|
||||||
|
|
||||||
Returns list of shared albums found in photos database (e.g. albums shared via iCloud photo sharing)
|
Returns list of shared albums found in photos database (e.g. albums shared via iCloud photo sharing)
|
||||||
|
|
||||||
@@ -1113,7 +1113,7 @@ def main():
|
|||||||
|
|
||||||
print(photosdb.keywords)
|
print(photosdb.keywords)
|
||||||
print(photosdb.persons)
|
print(photosdb.persons)
|
||||||
print(photosdb.albums)
|
print(photosdb.album_names)
|
||||||
|
|
||||||
print(photosdb.keywords_as_dict)
|
print(photosdb.keywords_as_dict)
|
||||||
print(photosdb.persons_as_dict)
|
print(photosdb.persons_as_dict)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ def main():
|
|||||||
|
|
||||||
print(photosdb.keywords)
|
print(photosdb.keywords)
|
||||||
print(photosdb.persons)
|
print(photosdb.persons)
|
||||||
print(photosdb.albums)
|
print(photosdb.album_names)
|
||||||
|
|
||||||
print(photosdb.keywords_as_dict)
|
print(photosdb.keywords_as_dict)
|
||||||
print(photosdb.persons_as_dict)
|
print(photosdb.persons_as_dict)
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
""" version info """
|
""" version info """
|
||||||
|
|
||||||
__version__ = "0.25.1"
|
__version__ = "0.26.0"
|
||||||
|
|||||||
@@ -120,6 +120,12 @@ class PhotosDB:
|
|||||||
# e.g. {'1EB2B765-0765-43BA-A90C-0D0580E6172C': ['0C514A98-7B77-4E4F-801B-364B7B65EAFA']}
|
# e.g. {'1EB2B765-0765-43BA-A90C-0D0580E6172C': ['0C514A98-7B77-4E4F-801B-364B7B65EAFA']}
|
||||||
self._dbalbums_uuid = {}
|
self._dbalbums_uuid = {}
|
||||||
|
|
||||||
|
# Dict with information about all albums/photos by primary key in the album database
|
||||||
|
# key is album pk, value is album uuid
|
||||||
|
# e.g. {'43': '0C514A98-7B77-4E4F-801B-364B7B65EAFA'}
|
||||||
|
# specific to Photos versions >= 5
|
||||||
|
self._dbalbums_pk = {}
|
||||||
|
|
||||||
# Dict with information about all albums/photos by album
|
# Dict with information about all albums/photos by album
|
||||||
# key is album UUID, value is list of photo UUIDs contained in that album
|
# key is album UUID, value is list of photo UUIDs contained in that album
|
||||||
# e.g. {'0C514A98-7B77-4E4F-801B-364B7B65EAFA': ['1EB2B765-0765-43BA-A90C-0D0580E6172C']}
|
# e.g. {'0C514A98-7B77-4E4F-801B-364B7B65EAFA': ['1EB2B765-0765-43BA-A90C-0D0580E6172C']}
|
||||||
@@ -264,6 +270,7 @@ class PhotosDB:
|
|||||||
k
|
k
|
||||||
for k in self._dbalbums_album.keys()
|
for k in self._dbalbums_album.keys()
|
||||||
if self._dbalbum_details[k]["cloudownerhashedpersonid"] is None
|
if self._dbalbum_details[k]["cloudownerhashedpersonid"] is None
|
||||||
|
and self._dbalbum_details[k]["intrash"] == 0
|
||||||
]
|
]
|
||||||
for k in album_keys:
|
for k in album_keys:
|
||||||
title = self._dbalbum_details[k]["title"]
|
title = self._dbalbum_details[k]["title"]
|
||||||
@@ -314,7 +321,7 @@ class PhotosDB:
|
|||||||
return list(persons)
|
return list(persons)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def albums(self):
|
def album_names(self):
|
||||||
""" return list of albums found in photos database """
|
""" return list of albums found in photos database """
|
||||||
|
|
||||||
# Could be more than one album with same name
|
# Could be more than one album with same name
|
||||||
@@ -331,7 +338,7 @@ class PhotosDB:
|
|||||||
return list(albums)
|
return list(albums)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def albums_shared(self):
|
def album_names_shared(self):
|
||||||
""" return list of shared albums found in photos database
|
""" return list of shared albums found in photos database
|
||||||
only valid for Photos 5; on Photos <= 4, prints warning and returns empty list """
|
only valid for Photos 5; on Photos <= 4, prints warning and returns empty list """
|
||||||
|
|
||||||
@@ -466,9 +473,9 @@ class PhotosDB:
|
|||||||
"uuid, " # 0
|
"uuid, " # 0
|
||||||
"name, " # 1
|
"name, " # 1
|
||||||
"cloudLibraryState, " # 2
|
"cloudLibraryState, " # 2
|
||||||
"cloudIdentifier " # 3
|
"cloudIdentifier, " # 3
|
||||||
|
"isInTrash " # 4
|
||||||
"FROM RKAlbum "
|
"FROM RKAlbum "
|
||||||
"WHERE isInTrash = 0"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
for album in c:
|
for album in c:
|
||||||
@@ -476,6 +483,7 @@ class PhotosDB:
|
|||||||
"title": album[1],
|
"title": album[1],
|
||||||
"cloudlibrarystate": album[2],
|
"cloudlibrarystate": album[2],
|
||||||
"cloudidentifier": album[3],
|
"cloudidentifier": album[3],
|
||||||
|
"intrash": album[4],
|
||||||
"cloudlocalstate": None, # Photos 5
|
"cloudlocalstate": None, # Photos 5
|
||||||
"cloudownerfirstname": None, # Photos 5
|
"cloudownerfirstname": None, # Photos 5
|
||||||
"cloudownderlastname": None, # Photos 5
|
"cloudownderlastname": None, # Photos 5
|
||||||
@@ -848,10 +856,8 @@ class PhotosDB:
|
|||||||
)
|
)
|
||||||
|
|
||||||
place_ids = [id[0] for id in place_ids_query.fetchall()]
|
place_ids = [id[0] for id in place_ids_query.fetchall()]
|
||||||
self._dbphotos[uuid]["placeIDs"] = place_ids
|
self._dbphotos[uuid]["placeIDs"] = place_ids
|
||||||
country_code = [
|
country_code = [countries[x] for x in place_ids if x in countries]
|
||||||
countries[x] for x in place_ids if x in countries
|
|
||||||
]
|
|
||||||
if len(country_code) > 1:
|
if len(country_code) > 1:
|
||||||
logging.warning(f"Found more than one country code for uuid: {uuid}")
|
logging.warning(f"Found more than one country code for uuid: {uuid}")
|
||||||
|
|
||||||
@@ -986,6 +992,7 @@ class PhotosDB:
|
|||||||
logging.debug(pformat(self._dbfaces_person))
|
logging.debug(pformat(self._dbfaces_person))
|
||||||
logging.debug(self._dbfaces_uuid)
|
logging.debug(self._dbfaces_uuid)
|
||||||
|
|
||||||
|
# get details about albums
|
||||||
c.execute(
|
c.execute(
|
||||||
"SELECT ZGENERICALBUM.ZUUID, ZGENERICASSET.ZUUID "
|
"SELECT ZGENERICALBUM.ZUUID, ZGENERICASSET.ZUUID "
|
||||||
"FROM ZGENERICASSET "
|
"FROM ZGENERICASSET "
|
||||||
@@ -995,12 +1002,15 @@ class PhotosDB:
|
|||||||
)
|
)
|
||||||
for album in c:
|
for album in c:
|
||||||
# store by uuid in _dbalbums_uuid and by album in _dbalbums_album
|
# store by uuid in _dbalbums_uuid and by album in _dbalbums_album
|
||||||
if not album[1] in self._dbalbums_uuid:
|
try:
|
||||||
self._dbalbums_uuid[album[1]] = []
|
self._dbalbums_uuid[album[1]].append(album[0])
|
||||||
if not album[0] in self._dbalbums_album:
|
except KeyError:
|
||||||
self._dbalbums_album[album[0]] = []
|
self._dbalbums_uuid[album[1]] = [album[0]]
|
||||||
self._dbalbums_uuid[album[1]].append(album[0])
|
|
||||||
self._dbalbums_album[album[0]].append(album[1])
|
try:
|
||||||
|
self._dbalbums_album[album[0]].append(album[1])
|
||||||
|
except KeyError:
|
||||||
|
self._dbalbums_album[album[0]] = [album[1]]
|
||||||
|
|
||||||
# now get additional details about albums
|
# now get additional details about albums
|
||||||
c.execute(
|
c.execute(
|
||||||
@@ -1010,8 +1020,12 @@ class PhotosDB:
|
|||||||
"ZCLOUDLOCALSTATE, " # 2
|
"ZCLOUDLOCALSTATE, " # 2
|
||||||
"ZCLOUDOWNERFIRSTNAME, " # 3
|
"ZCLOUDOWNERFIRSTNAME, " # 3
|
||||||
"ZCLOUDOWNERLASTNAME, " # 4
|
"ZCLOUDOWNERLASTNAME, " # 4
|
||||||
"ZCLOUDOWNERHASHEDPERSONID " # 5
|
"ZCLOUDOWNERHASHEDPERSONID, " # 5
|
||||||
"FROM ZGENERICALBUM"
|
"ZKIND, " # 6
|
||||||
|
"ZPARENTFOLDER, " # 7
|
||||||
|
"Z_PK, " # 8
|
||||||
|
"ZTRASHEDSTATE " # 9
|
||||||
|
"FROM ZGENERICALBUM "
|
||||||
)
|
)
|
||||||
for album in c:
|
for album in c:
|
||||||
self._dbalbum_details[album[0]] = {
|
self._dbalbum_details[album[0]] = {
|
||||||
@@ -1021,9 +1035,18 @@ class PhotosDB:
|
|||||||
"cloudownderlastname": album[4],
|
"cloudownderlastname": album[4],
|
||||||
"cloudownerhashedpersonid": album[5],
|
"cloudownerhashedpersonid": album[5],
|
||||||
"cloudlibrarystate": None, # Photos 4
|
"cloudlibrarystate": None, # Photos 4
|
||||||
"cloudidentifier": None, # Photos4
|
"cloudidentifier": None, # Photos 4
|
||||||
|
"kind": album[6],
|
||||||
|
"parentfolder": album[7],
|
||||||
|
"pk": album[8],
|
||||||
|
"intrash": album[9],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# add cross-reference by pk to uuid
|
||||||
|
# needed to extract folder hierarchy
|
||||||
|
# in Photos >= 5, folders are special albums
|
||||||
|
self._dbalbums_pk[album[8]] = album[0]
|
||||||
|
|
||||||
if _debug():
|
if _debug():
|
||||||
logging.debug(f"Finished walking through albums")
|
logging.debug(f"Finished walking through albums")
|
||||||
logging.debug(pformat(self._dbalbums_album))
|
logging.debug(pformat(self._dbalbums_album))
|
||||||
|
|||||||
@@ -72,13 +72,13 @@ def test_keywords():
|
|||||||
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
||||||
|
|
||||||
|
|
||||||
def test_albums():
|
def test_album_names():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
assert "Pumpkin Farm" in photosdb.albums
|
assert "Pumpkin Farm" in photosdb.album_names
|
||||||
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
|
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
|
||||||
|
|
||||||
|
|
||||||
def test_keywords_dict():
|
def test_keywords_dict():
|
||||||
|
|||||||
@@ -150,13 +150,13 @@ def test_keywords():
|
|||||||
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
||||||
|
|
||||||
|
|
||||||
def test_albums():
|
def test_album_names():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
assert "Pumpkin Farm" in photosdb.albums
|
assert "Pumpkin Farm" in photosdb.album_names
|
||||||
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
|
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
|
||||||
|
|
||||||
|
|
||||||
def test_keywords_dict():
|
def test_keywords_dict():
|
||||||
|
|||||||
@@ -150,13 +150,13 @@ def test_keywords():
|
|||||||
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
||||||
|
|
||||||
|
|
||||||
def test_albums():
|
def test_album_names():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
assert "Pumpkin Farm" in photosdb.albums
|
assert "Pumpkin Farm" in photosdb.album_names
|
||||||
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
|
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
|
||||||
|
|
||||||
|
|
||||||
def test_keywords_dict():
|
def test_keywords_dict():
|
||||||
|
|||||||
@@ -52,12 +52,12 @@ def test_keywords():
|
|||||||
assert photosdb.keywords == []
|
assert photosdb.keywords == []
|
||||||
|
|
||||||
|
|
||||||
def test_albums():
|
def test_album_names():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
assert photosdb.albums == []
|
assert photosdb.album_names == []
|
||||||
|
|
||||||
|
|
||||||
def test_keywords_dict():
|
def test_keywords_dict():
|
||||||
|
|||||||
@@ -71,13 +71,13 @@ def test_keywords():
|
|||||||
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
||||||
|
|
||||||
|
|
||||||
def test_albums():
|
def test_album_names():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
assert "Pumpkin Farm" in photosdb.albums
|
assert "Pumpkin Farm" in photosdb.album_names
|
||||||
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
|
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
|
||||||
|
|
||||||
|
|
||||||
def test_keywords_dict():
|
def test_keywords_dict():
|
||||||
|
|||||||
@@ -71,13 +71,13 @@ def test_keywords():
|
|||||||
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
||||||
|
|
||||||
|
|
||||||
def test_albums():
|
def test_album_names():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
assert "Pumpkin Farm" in photosdb.albums
|
assert "Pumpkin Farm" in photosdb.album_names
|
||||||
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
|
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
|
||||||
|
|
||||||
|
|
||||||
def test_keywords_dict():
|
def test_keywords_dict():
|
||||||
|
|||||||
@@ -76,13 +76,13 @@ def test_keywords():
|
|||||||
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
|
||||||
|
|
||||||
|
|
||||||
def test_albums():
|
def test_album_names():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
import collections
|
import collections
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
assert "Pumpkin Farm" in photosdb.albums
|
assert "Pumpkin Farm" in photosdb.album_names
|
||||||
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
|
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
|
||||||
|
|
||||||
|
|
||||||
def test_keywords_dict():
|
def test_keywords_dict():
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ UUID_SHARED = [
|
|||||||
UUID_NOT_SHARED = ["37210110-E940-4227-92D3-45C40F68EB0A"]
|
UUID_NOT_SHARED = ["37210110-E940-4227-92D3-45C40F68EB0A"]
|
||||||
|
|
||||||
|
|
||||||
def test_albums():
|
def test_album_names():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
albums = photosdb.albums
|
albums = photosdb.album_names
|
||||||
|
|
||||||
assert len(albums) == 1
|
assert len(albums) == 1
|
||||||
assert albums[0] == ALBUMS[0]
|
assert albums[0] == ALBUMS[0]
|
||||||
@@ -40,7 +40,7 @@ def test_albums_shared():
|
|||||||
import osxphotos
|
import osxphotos
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
albums_shared = photosdb.albums_shared
|
albums_shared = photosdb.album_names_shared
|
||||||
|
|
||||||
assert len(albums_shared) == 1
|
assert len(albums_shared) == 1
|
||||||
assert albums_shared[0] == ALBUMS_SHARED[0]
|
assert albums_shared[0] == ALBUMS_SHARED[0]
|
||||||
|
|||||||
@@ -11,22 +11,22 @@ ALBUMS = ["Pumpkin Farm", "Test Album", "Test Album (1)"]
|
|||||||
ALBUM_DICT = {"Pumpkin Farm": 3, "Test Album": 1, "Test Album (1)": 1}
|
ALBUM_DICT = {"Pumpkin Farm": 3, "Test Album": 1, "Test Album (1)": 1}
|
||||||
|
|
||||||
|
|
||||||
def test_albums():
|
def test_album_names():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
albums = photosdb.albums
|
albums = photosdb.album_names
|
||||||
|
|
||||||
assert len(albums) == len(ALBUMS)
|
assert len(albums) == len(ALBUMS)
|
||||||
for album in albums:
|
for album in albums:
|
||||||
assert album in ALBUMS
|
assert album in ALBUMS
|
||||||
|
|
||||||
|
|
||||||
def test_albums_shared():
|
def test_albums_names_shared():
|
||||||
import osxphotos
|
import osxphotos
|
||||||
|
|
||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
albums_shared = photosdb.albums_shared
|
albums_shared = photosdb.album_names_shared
|
||||||
|
|
||||||
assert len(albums_shared) == 0
|
assert len(albums_shared) == 0
|
||||||
|
|
||||||
@@ -65,4 +65,3 @@ def test_not_shared():
|
|||||||
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
|
||||||
photos = [p for p in photosdb.photos() if not p.shared]
|
photos = [p for p in photosdb.photos() if not p.shared]
|
||||||
assert len(photos) == 7
|
assert len(photos) == 7
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user