From 9a0cc3e8fa024b485010dbe47791435acf0f7163 Mon Sep 17 00:00:00 2001 From: Rhet Turnbull Date: Sun, 2 May 2021 08:35:37 -0700 Subject: [PATCH] Added --add-to-album to query --- osxphotos/_version.py | 2 +- osxphotos/cli.py | 36 +++++++++++++++++++++-- osxphotos/photosalbum.py | 54 +++++----------------------------- tests/test_cli_add_to_album.py | 23 +++++++++++++++ 4 files changed, 65 insertions(+), 50 deletions(-) diff --git a/osxphotos/_version.py b/osxphotos/_version.py index 8ad822ca..6fffd7f8 100644 --- a/osxphotos/_version.py +++ b/osxphotos/_version.py @@ -1,3 +1,3 @@ """ version info """ -__version__ = "0.42.14" +__version__ = "0.42.15" diff --git a/osxphotos/cli.py b/osxphotos/cli.py index 641abe8a..81f19867 100644 --- a/osxphotos/cli.py +++ b/osxphotos/cli.py @@ -1630,8 +1630,9 @@ def export( for filename in export_results.exported ] except Exception as e: - click.echo( + click.secho( f"Error adding photo {p.original_filename} ({p.uuid}) to album {album_export.name}: {e}", + fg=CLI_COLOR_ERROR, err=True, ) @@ -1643,8 +1644,9 @@ def export( for filename in export_results.skipped ] except Exception as e: - click.echo( + click.secho( f"Error adding photo {p.original_filename} ({p.uuid}) to album {album_skipped.name}: {e}", + fg=CLI_COLOR_ERROR, err=True, ) @@ -1656,8 +1658,9 @@ def export( for filename in export_results.missing ] except Exception as e: - click.echo( + click.secho( f"Error adding photo {p.original_filename} ({p.uuid}) to album {album_missing.name}: {e}", + fg=CLI_COLOR_ERROR, err=True, ) @@ -1807,6 +1810,14 @@ def help(ctx, topic, **kw): is_flag=True, help="Search for photos that are not in iCloud (have not been synched)", ) +@click.option( + "--add-to-album", + metavar="ALBUM", + help="Add all photos from query to album ALBUM in Photos. Album ALBUM will be created " + "if it doesn't exist. All photos in the query results will be added to this album. " + "This only works if the Photos library being queried is the last-opened (default) library in Photos. " + "This feature is currently experimental. I don't know how well it will work on large query sets.", +) @DB_ARGUMENT @click.pass_obj @click.pass_context @@ -1884,6 +1895,7 @@ def query( max_size, regex, query_eval, + add_to_album, ): """Query the Photos database using 1 or more search options; if more than one option is provided, they are treated as "AND" @@ -2054,6 +2066,24 @@ def query( # below needed for to make CliRunner work for testing cli_json = cli_obj.json if cli_obj is not None else None + + if add_to_album and photos: + album_query = PhotosAlbum(add_to_album, verbose=None) + photo_len = len(photos) + photo_word = "photos" if photo_len > 1 else "photo" + click.echo( + f"Adding {photo_len} {photo_word} to album '{album_query.name}'. Note: Photos may prompt you to confirm this action.", + err=True, + ) + try: + album_query.add_list(photos) + except Exception as e: + click.secho( + f"Error adding photos to album {add_to_album}", + fg=CLI_COLOR_ERROR, + err=True, + ) + print_photo_info(photos, cli_json or json_) diff --git a/osxphotos/photosalbum.py b/osxphotos/photosalbum.py index 9eafb41a..aa4b435a 100644 --- a/osxphotos/photosalbum.py +++ b/osxphotos/photosalbum.py @@ -1,6 +1,6 @@ """ PhotosAlbum class to create an album in default Photos library and add photos to it """ -from typing import Optional +from typing import Optional, List import photoscript from .photoinfo import PhotoInfo from .utils import noop @@ -25,50 +25,12 @@ class PhotosAlbum: f"Added {photo.original_filename} ({photo.uuid}) to album {self.name}" ) + def add_list(self, photo_list: List[PhotoInfo]): + photos = [photoscript.Photo(p.uuid) for p in photo_list] + self.album.add(photos) + photo_len = len(photos) + photo_word = "photos" if photo_len > 1 else "photo" + self.verbose(f"Added {photo_len} {photo_word} to album {self.name}") + def photos(self): return self.album.photos() - - -# def add_photo_to_album(photo, album_pairs, results): -# # todo: class PhotoAlbum -# # keeps a name, maintains state -# """ add photo to album(s) as defined in album_pairs - -# Args: -# photo: PhotoInfo object -# album_pairs: list of tuples with [(album name, results_list)] -# results: ExportResults object - -# Returns: -# updated ExportResults object -# """ -# for album, result_list in album_pairs: -# try: -# if album_export is None: -# # first time fetching the album, see if it exists already -# album_export = photos_library.album( -# add_exported_to_album -# ) -# if album_export is None: -# # album doesn't exist, so create it -# verbose_( -# f"Creating Photos album '{add_exported_to_album}'" -# ) -# album_export = photos_library.create_album( -# add_exported_to_album -# ) -# exported_photo = photoscript.Photo(p.uuid) -# album_export.add([exported_photo]) -# verbose_( -# f"Added {p.original_filename} ({p.uuid}) to album {add_exported_to_album}" -# ) -# exported_album = [ -# (filename, add_exported_to_album) -# for filename in export_results.exported -# ] -# export_results.exported_album = exported_album -# if -# except Exception as e: -# click.echo( -# f"Error adding photo {p.original_filename} ({p.uuid}) to album {add_exported_to_album}" -# ) diff --git a/tests/test_cli_add_to_album.py b/tests/test_cli_add_to_album.py index a2ef5380..56c47397 100644 --- a/tests/test_cli_add_to_album.py +++ b/tests/test_cli_add_to_album.py @@ -90,3 +90,26 @@ def test_export_add_to_album(addalbum_library): got_uuids = [p.uuid for p in missing_album.photos()] assert sorted(got_uuids) == sorted(list(UUID_MISSING.keys())) + +@pytest.mark.addalbum +def test_query_add_to_album(addalbum_library): + from osxphotos.cli import query + + runner = CliRunner() + cwd = os.getcwd() + with runner.isolated_filesystem(): + QUERY_ALBUM = "OSXPhotos Query" + + uuid_opt = [f"--uuid={uuid}" for uuid in UUID_EXPORT] + + result = runner.invoke(query, ["--add-to-album", QUERY_ALBUM, *uuid_opt]) + assert result.exit_code == 0 + + photoslib = photoscript.PhotosLibrary() + album = photoslib.album(QUERY_ALBUM) + assert album is not None + + assert len(album) == len(UUID_EXPORT) + got_uuids = [p.uuid for p in album.photos()] + assert sorted(got_uuids) == sorted(list(UUID_EXPORT.keys())) +