Changed PhotosDB albums interface as prep for adding folders

This commit is contained in:
Rhet Turnbull
2020-04-10 17:30:37 -07:00
parent 626e460aab
commit 3e5062684a
13 changed files with 78 additions and 56 deletions

View File

@@ -368,7 +368,7 @@ def main():
photosdb = osxphotos.PhotosDB(db)
print(photosdb.keywords)
print(photosdb.persons)
print(photosdb.albums)
print(photosdb.album_names)
print(photosdb.keywords_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
#### `albums`
#### `album_names`
```python
# 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.
**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)
@@ -1113,7 +1113,7 @@ def main():
print(photosdb.keywords)
print(photosdb.persons)
print(photosdb.albums)
print(photosdb.album_names)
print(photosdb.keywords_as_dict)
print(photosdb.persons_as_dict)

View File

@@ -14,7 +14,7 @@ def main():
print(photosdb.keywords)
print(photosdb.persons)
print(photosdb.albums)
print(photosdb.album_names)
print(photosdb.keywords_as_dict)
print(photosdb.persons_as_dict)

View File

@@ -1,3 +1,3 @@
""" version info """
__version__ = "0.25.1"
__version__ = "0.26.0"

View File

@@ -120,6 +120,12 @@ class PhotosDB:
# e.g. {'1EB2B765-0765-43BA-A90C-0D0580E6172C': ['0C514A98-7B77-4E4F-801B-364B7B65EAFA']}
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
# 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']}
@@ -264,6 +270,7 @@ class PhotosDB:
k
for k in self._dbalbums_album.keys()
if self._dbalbum_details[k]["cloudownerhashedpersonid"] is None
and self._dbalbum_details[k]["intrash"] == 0
]
for k in album_keys:
title = self._dbalbum_details[k]["title"]
@@ -314,7 +321,7 @@ class PhotosDB:
return list(persons)
@property
def albums(self):
def album_names(self):
""" return list of albums found in photos database """
# Could be more than one album with same name
@@ -331,7 +338,7 @@ class PhotosDB:
return list(albums)
@property
def albums_shared(self):
def album_names_shared(self):
""" return list of shared albums found in photos database
only valid for Photos 5; on Photos <= 4, prints warning and returns empty list """
@@ -466,9 +473,9 @@ class PhotosDB:
"uuid, " # 0
"name, " # 1
"cloudLibraryState, " # 2
"cloudIdentifier " # 3
"cloudIdentifier, " # 3
"isInTrash " # 4
"FROM RKAlbum "
"WHERE isInTrash = 0"
)
for album in c:
@@ -476,6 +483,7 @@ class PhotosDB:
"title": album[1],
"cloudlibrarystate": album[2],
"cloudidentifier": album[3],
"intrash": album[4],
"cloudlocalstate": None, # Photos 5
"cloudownerfirstname": None, # Photos 5
"cloudownderlastname": None, # Photos 5
@@ -846,12 +854,10 @@ class PhotosDB:
"FROM RKPlaceForVersion "
f"WHERE versionId = '{self._dbphotos[uuid]['modelID']}'"
)
place_ids = [id[0] for id in place_ids_query.fetchall()]
self._dbphotos[uuid]["placeIDs"] = place_ids
country_code = [
countries[x] for x in place_ids if x in countries
]
self._dbphotos[uuid]["placeIDs"] = place_ids
country_code = [countries[x] for x in place_ids if x in countries]
if len(country_code) > 1:
logging.warning(f"Found more than one country code for uuid: {uuid}")
@@ -860,7 +866,7 @@ class PhotosDB:
else:
self._dbphotos[uuid]["countryCode"] = None
# get the place info that matches the RKPlace modelIDs for this photo
# get the place info that matches the RKPlace modelIDs for this photo
# (place_ids), sort by area (element 3 of the place_data tuple in places)
place_names = [
pname
@@ -986,6 +992,7 @@ class PhotosDB:
logging.debug(pformat(self._dbfaces_person))
logging.debug(self._dbfaces_uuid)
# get details about albums
c.execute(
"SELECT ZGENERICALBUM.ZUUID, ZGENERICASSET.ZUUID "
"FROM ZGENERICASSET "
@@ -995,12 +1002,15 @@ class PhotosDB:
)
for album in c:
# store by uuid in _dbalbums_uuid and by album in _dbalbums_album
if not album[1] in self._dbalbums_uuid:
self._dbalbums_uuid[album[1]] = []
if not album[0] in self._dbalbums_album:
self._dbalbums_album[album[0]] = []
self._dbalbums_uuid[album[1]].append(album[0])
self._dbalbums_album[album[0]].append(album[1])
try:
self._dbalbums_uuid[album[1]].append(album[0])
except KeyError:
self._dbalbums_uuid[album[1]] = [album[0]]
try:
self._dbalbums_album[album[0]].append(album[1])
except KeyError:
self._dbalbums_album[album[0]] = [album[1]]
# now get additional details about albums
c.execute(
@@ -1010,8 +1020,12 @@ class PhotosDB:
"ZCLOUDLOCALSTATE, " # 2
"ZCLOUDOWNERFIRSTNAME, " # 3
"ZCLOUDOWNERLASTNAME, " # 4
"ZCLOUDOWNERHASHEDPERSONID " # 5
"FROM ZGENERICALBUM"
"ZCLOUDOWNERHASHEDPERSONID, " # 5
"ZKIND, " # 6
"ZPARENTFOLDER, " # 7
"Z_PK, " # 8
"ZTRASHEDSTATE " # 9
"FROM ZGENERICALBUM "
)
for album in c:
self._dbalbum_details[album[0]] = {
@@ -1021,9 +1035,18 @@ class PhotosDB:
"cloudownderlastname": album[4],
"cloudownerhashedpersonid": album[5],
"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():
logging.debug(f"Finished walking through albums")
logging.debug(pformat(self._dbalbums_album))

View File

@@ -72,13 +72,13 @@ def test_keywords():
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
def test_albums():
def test_album_names():
import osxphotos
import collections
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert "Pumpkin Farm" in photosdb.albums
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
assert "Pumpkin Farm" in photosdb.album_names
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
def test_keywords_dict():

View File

@@ -150,13 +150,13 @@ def test_keywords():
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
def test_albums():
def test_album_names():
import osxphotos
import collections
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert "Pumpkin Farm" in photosdb.albums
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
assert "Pumpkin Farm" in photosdb.album_names
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
def test_keywords_dict():

View File

@@ -150,13 +150,13 @@ def test_keywords():
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
def test_albums():
def test_album_names():
import osxphotos
import collections
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert "Pumpkin Farm" in photosdb.albums
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
assert "Pumpkin Farm" in photosdb.album_names
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
def test_keywords_dict():
@@ -366,7 +366,7 @@ def test_count():
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = photosdb.photos()
assert len(photos) == 8
assert len(photos) == 8
def test_keyword_2():
@@ -772,7 +772,7 @@ def test_from_to_date():
assert len(photos) == 2
photos = photosdb.photos(to_date=dt.datetime(2018, 10, 28))
assert len(photos) == 6
assert len(photos) == 6
photos = photosdb.photos(
from_date=dt.datetime(2018, 9, 28), to_date=dt.datetime(2018, 9, 29)

View File

@@ -52,12 +52,12 @@ def test_keywords():
assert photosdb.keywords == []
def test_albums():
def test_album_names():
import osxphotos
import collections
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert photosdb.albums == []
assert photosdb.album_names == []
def test_keywords_dict():

View File

@@ -71,13 +71,13 @@ def test_keywords():
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
def test_albums():
def test_album_names():
import osxphotos
import collections
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert "Pumpkin Farm" in photosdb.albums
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
assert "Pumpkin Farm" in photosdb.album_names
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
def test_keywords_dict():

View File

@@ -71,13 +71,13 @@ def test_keywords():
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
def test_albums():
def test_album_names():
import osxphotos
import collections
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert "Pumpkin Farm" in photosdb.albums
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
assert "Pumpkin Farm" in photosdb.album_names
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
def test_keywords_dict():

View File

@@ -76,13 +76,13 @@ def test_keywords():
assert collections.Counter(KEYWORDS) == collections.Counter(photosdb.keywords)
def test_albums():
def test_album_names():
import osxphotos
import collections
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
assert "Pumpkin Farm" in photosdb.albums
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.albums)
assert "Pumpkin Farm" in photosdb.album_names
assert collections.Counter(ALBUMS) == collections.Counter(photosdb.album_names)
def test_keywords_dict():

View File

@@ -26,11 +26,11 @@ UUID_SHARED = [
UUID_NOT_SHARED = ["37210110-E940-4227-92D3-45C40F68EB0A"]
def test_albums():
def test_album_names():
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
albums = photosdb.albums
albums = photosdb.album_names
assert len(albums) == 1
assert albums[0] == ALBUMS[0]
@@ -40,7 +40,7 @@ def test_albums_shared():
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
albums_shared = photosdb.albums_shared
albums_shared = photosdb.album_names_shared
assert len(albums_shared) == 1
assert albums_shared[0] == ALBUMS_SHARED[0]

View File

@@ -11,22 +11,22 @@ ALBUMS = ["Pumpkin Farm", "Test Album", "Test Album (1)"]
ALBUM_DICT = {"Pumpkin Farm": 3, "Test Album": 1, "Test Album (1)": 1}
def test_albums():
def test_album_names():
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
albums = photosdb.albums
albums = photosdb.album_names
assert len(albums) == len(ALBUMS)
for album in albums:
assert album in ALBUMS
def test_albums_shared():
def test_albums_names_shared():
import osxphotos
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
albums_shared = photosdb.albums_shared
albums_shared = photosdb.album_names_shared
assert len(albums_shared) == 0
@@ -65,4 +65,3 @@ def test_not_shared():
photosdb = osxphotos.PhotosDB(dbfile=PHOTOS_DB)
photos = [p for p in photosdb.photos() if not p.shared]
assert len(photos) == 7