Skip to content

Commit

Permalink
Feat 1524 list methods photosalbum (#1562)
Browse files Browse the repository at this point in the history
* Add list and set methods to PhotosAlbum, #1524

* Added example

* Fixed example
  • Loading branch information
RhetTbull authored Jun 8, 2024
1 parent cb4097e commit 2f1f9d1
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 44 deletions.
62 changes: 42 additions & 20 deletions API_README.md

Large diffs are not rendered by default.

14 changes: 14 additions & 0 deletions examples/add_to_album.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""Example that shows how to add PhotoInfo objects to an album in Photos"""

from osxphotos import PhotosDB
from osxphotos.photosalbum import PhotosAlbum

# If album exists it will be used, otherwise it will be created
album = PhotosAlbum("Best Photos")
best_photos = [p for p in PhotosDB(verbose=print).photos() if p.score.overall > 0.9]

# use album.add() or album.append() to add a single photo
# use album.update() or album.extend() to add an iterable of photos
album.extend(best_photos)
print(f"Added {len(best_photos)} photos to album {album.name}")
print(f"Album contains {len(album.photos())} photos")
4 changes: 2 additions & 2 deletions examples/import_shared.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def get_shared_album_info(shared_albums: list[AlbumInfo]) -> dict[str, int]:
"""Return dict with info about shared albums"""
albums = {}
for album in shared_albums:
photo_owners = {photo.owner for photo in album.photos}
photo_owners = {photo.owner or "None" for photo in album.photos}
album_key = f"{album.title} ({pluralize_photos(album.photos)} by {', '.join(photo_owners)}"
albums[album_key] = album
return albums
Expand Down Expand Up @@ -264,7 +264,7 @@ def import_photos(
album_names.append(album_name)
for album_name in album_names:
album = PhotosAlbumPhotoScript(album_name)
album.add_list(imported_photos)
album.update(imported_photos)

# metadata
for imported_photo in imported_photos:
Expand Down
4 changes: 3 additions & 1 deletion examples/top_10_unnamed_faces.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,12 @@ def main():

for p in top_10_unnamed:
photos = get_person_photos(p)
if not photos:
continue
album_name = f"Unnamed person: {p.uuid} ({len(photos)})"
print(f"Creating album '{album_name}'")
album = PhotosAlbum(album_name)
album.add_list(photos)
album.update(photos)

if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion osxphotos/cli/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ def query(
err=True,
)
try:
album_query.add_list(photos)
album_query.update(photos)
except Exception as e:
click.secho(
f"Error adding photos to album {add_to_album}: {e}",
Expand Down
3 changes: 2 additions & 1 deletion osxphotos/cli/repl.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ def repl(ctx, cli_obj, db, emacs, beta, **kwargs):
from osxphotos.momentinfo import MomentInfo
from osxphotos.photoexporter import PhotoExporter
from osxphotos.photoquery import QueryOptions
from osxphotos.photosalbum import PhotosAlbum
from osxphotos.placeinfo import PlaceInfo
from osxphotos.scoreinfo import ScoreInfo
from osxphotos.searchinfo import SearchInfo
Expand Down Expand Up @@ -123,7 +124,7 @@ def inspect(obj):
print(
"- AlbumInfo, ExifTool, PhotoInfo, PhotoExporter, ExportOptions, ExportResults, "
"PhotosDB, PlaceInfo, QueryOptions, MomentInfo, ScoreInfo, SearchInfo, "
"SidecarWriter, ExifWriter\n"
"SidecarWriter, ExifWriter, PhotosAlbum\n"
)
print("The following variables are defined:")
print(f"- photosdb: PhotosDB() instance for '{photosdb.library_path}'")
Expand Down
44 changes: 31 additions & 13 deletions osxphotos/photosalbum.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
from __future__ import annotations

import unicodedata
from typing import List, Optional
from collections.abc import Iterable
from typing import Any, Callable, Optional

from more_itertools import chunked

Expand All @@ -28,7 +29,9 @@ def get_unicode_variants(s: str) -> list[str]:
return variants


def folder_by_path(folders: List[str], verbose: Optional[callable] = None) -> Folder:
def folder_by_path(
folders: list[str], verbose: Optional[Callable[..., Any]] = None
) -> Folder:
"""Get (and create if necessary) a Photos Folder by path (passed as list of folder names)"""
library = PhotosLibrary()
verbose = verbose or noop
Expand Down Expand Up @@ -56,7 +59,7 @@ def folder_by_path(folders: List[str], verbose: Optional[callable] = None) -> Fo


def album_by_path(
folders_album: List[str], verbose: Optional[callable] = None
folders_album: list[str], verbose: Optional[Callable[..., Any]] = None
) -> Album:
"""Get (and create if necessary) a Photos Album by path (pass as list of folders, album name)"""
library = PhotosLibrary()
Expand Down Expand Up @@ -96,7 +99,7 @@ class PhotosAlbum:
def __init__(
self,
name: str,
verbose: Optional[callable] = None,
verbose: Optional[Callable[..., Any]] = None,
split_folder: Optional[str] = None,
rich: bool = False,
):
Expand Down Expand Up @@ -126,22 +129,30 @@ def add(self, photo: PhotoInfo):
f"Added {self._format_name(photo.original_filename)} ({self._format_uuid(photo.uuid)}) to album {self._format_album(self.name)}"
)

def add_list(self, photo_list: List[PhotoInfo]):
photos = []
for p in photo_list:
def update(self, photos: Iterable[PhotoInfo]):
photoscript_photos = []
for p in photos:
try:
photos.append(photoscript.Photo(p.uuid))
photoscript_photos.append(photoscript.Photo(p.uuid))
except Exception as e:
self.verbose(
f"Error creating Photo object for photo {self._format_uuid(p.uuid)}: {e}"
)
for photolist in chunked(photos, 10):
for photolist in chunked(photoscript_photos, 10):
self.album.add(photolist)
photo_len = len(photo_list)
photo_len = len(photos)
self.verbose(
f"Added {self._format_num(photo_len)} {pluralize(photo_len, 'photo', 'photos')} to album {self._format_album(self.name)}"
)

def append(self, photo: PhotoInfo):
"""Add photo to album"""
self.add(photo)

def extend(self, photos: Iterable[PhotoInfo]):
"""Add list of photos to album"""
self.update(photos)

def photos(self):
return self.album.photos()

Expand Down Expand Up @@ -171,14 +182,21 @@ def add(self, photo: Photo):
f"Added {self._format_name(photo.filename)} ({self._format_uuid(photo.uuid)}) to album {self._format_album(self.name)}"
)

def add_list(self, photo_list: List[Photo]):
for photolist in chunked(photo_list, 10):
def update(self, photos: Iterable[Photo]):
for photolist in chunked(photos, 10):
self.album.add(photolist)
photo_len = len(photo_list)
photo_len = len(photos)
self.verbose(
f"Added {self._format_num(photo_len)} {pluralize(photo_len, 'photo', 'photos')} to album {self._format_album(self.name)}"
)

def append(self, photo: Photo):
"""Add photo to album"""
self.add(photo)

def extend(self, photos: Iterable[Photo]):
"""Add list of photos to album"""
self.update(photos)

class PhotosAlbumPhotoScriptByPath(PhotosAlbumPhotoScript):
"""Add photoscript.Photo objects to album"""
Expand Down
12 changes: 6 additions & 6 deletions tests/test_photosalbum_unicode.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ def test_unicode_album(addalbum_library):
# get the album
album_name_nfc = UNICODE_ALBUM_NFC
album_nfc = PhotosAlbum(album_name_nfc, split_folder=None)
album_nfc.add_list(photos)
album_nfc.update(photos)

# again with NFD
album_name_nfd = UNICODE_ALBUM_NFD
album_nfd = PhotosAlbum(album_name_nfd, split_folder=None)
album_nfd.add_list(photos)
album_nfd.update(photos)

assert album_nfc.album.uuid == album_nfd.album.uuid

Expand All @@ -55,12 +55,12 @@ def test_unicode_folder_album_1(addalbum_library):
# get the album
album_name_nfc = f"{UNICODE_FOLDER_NFC}/{UNICODE_ALBUM_NFC}"
album_nfc = PhotosAlbum(album_name_nfc, split_folder="/")
album_nfc.add_list(photos)
album_nfc.update(photos)

# again with NFD
album_name_nfd = f"{UNICODE_FOLDER_NFD}/{UNICODE_ALBUM_NFD}"
album_nfd = PhotosAlbum(album_name_nfd, split_folder="/")
album_nfd.add_list(photos)
album_nfd.update(photos)

assert album_nfc.album.uuid == album_nfd.album.uuid

Expand All @@ -80,11 +80,11 @@ def test_unicode_folder_album_2(addalbum_library):
# get the album
album_name_nfc = f"{UNICODE_FOLDER_NFC}/{UNICODE_ALBUM_NFC}"
album_nfc = PhotosAlbum(album_name_nfc, split_folder="/")
album_nfc.add_list(photos)
album_nfc.update(photos)

# again with NFD
album_name_nfd = f"{UNICODE_FOLDER_NFC}/{UNICODE_ALBUM_NFD}"
album_nfd = PhotosAlbum(album_name_nfd, split_folder="/")
album_nfd.add_list(photos)
album_nfd.update(photos)

assert album_nfc.album.uuid == album_nfd.album.uuid

0 comments on commit 2f1f9d1

Please sign in to comment.