diff --git a/osxphotos/cli/export.py b/osxphotos/cli/export.py index 167e2264..53d37c2f 100644 --- a/osxphotos/cli/export.py +++ b/osxphotos/cli/export.py @@ -674,6 +674,17 @@ from .verbose import get_verbose_console, time_stamp, verbose_print is_flag=True, help="If specified, saves the config file but does not export any files; must be used with --save-config.", ) +@click.option( + "--print", + "print_template", + metavar="TEMPLATE", + multiple=True, + help="Render TEMPLATE string for each photo being exported and print to stdout. " + "TEMPLATE is an osxphotos template string. " + "This may be useful for creating custom reports, etc. " + "TEMPLATE will be printed after the photo is exported or skipped. " + "May be repeated to print multiple template strings. ", +) @click.option( "--beta", is_flag=True, @@ -826,6 +837,7 @@ def export( preview_if_missing, preview_suffix, preview, + print_template, profile_sort, profile, query_eval, @@ -1048,6 +1060,7 @@ def export( preview = cfg.preview preview_if_missing = cfg.preview_if_missing preview_suffix = cfg.preview_suffix + print_template = cfg.print_template query_eval = cfg.query_eval query_function = cfg.query_function ramdb = cfg.ramdb @@ -1652,6 +1665,22 @@ def export( report_writer.write(export_results) + if print_template: + options = RenderOptions(export_dir=dest) + for template in print_template: + rendered_templates, unmatched = p.render_template( + template, + options, + ) + if unmatched: + rich_click_echo( + f"[warning]Unmatched template field: {unmatched}[/]" + ) + for rendered_template in rendered_templates: + if not rendered_template: + continue + rich_click_echo(rendered_template) + progress.advance(task) # handle limit diff --git a/osxphotos/cli/query.py b/osxphotos/cli/query.py index e557ffab..62a39f33 100644 --- a/osxphotos/cli/query.py +++ b/osxphotos/cli/query.py @@ -3,10 +3,17 @@ import click import osxphotos +from osxphotos.cli.click_rich_echo import ( + rich_click_echo, + set_rich_console, + set_rich_theme, +) from osxphotos.debug import set_debug from osxphotos.photosalbum import PhotosAlbum +from osxphotos.phototemplate import RenderOptions from osxphotos.queryoptions import QueryOptions +from .color_themes import get_default_theme from .common import ( CLI_COLOR_ERROR, CLI_COLOR_WARNING, @@ -21,6 +28,7 @@ from .common import ( ) from .list import _list_libraries from .print_photo_info import print_photo_info +from .verbose import get_verbose_console @click.command() @@ -62,6 +70,23 @@ from .print_photo_info import print_photo_info "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.", ) +@click.option( + "--quiet", + is_flag=True, + help="Quiet output; doesn't actually print query results. " + "Useful with --print and --add-to-album if you don't want to see the actual query results.", +) +@click.option( + "--print", + "print_template", + metavar="TEMPLATE", + multiple=True, + help="Render TEMPLATE string for each photo queried and print to stdout. " + "TEMPLATE is an osxphotos template string. " + "This may be useful for creating custom reports, etc. " + "Most useful with --quiet. " + "May be repeated to print multiple template strings. ", +) @click.option( "--debug", required=False, is_flag=True, default=False, hidden=OSXPHOTOS_HIDDEN ) @@ -139,8 +164,10 @@ def query( person, place, portrait, + print_template, query_eval, query_function, + quiet, regex, screenshot, selected, @@ -230,6 +257,10 @@ def query( click.echo(ctx.obj.group.commands["query"].get_help(ctx), err=True) return + # set console for rich_echo to be same as for verbose_ + set_rich_console(get_verbose_console()) + set_rich_theme(get_default_theme()) + # actually have something to query # default searches for everything photos = True @@ -368,4 +399,22 @@ def query( err=True, ) - print_photo_info(photos, cli_json or json_, print_func=click.echo) + if print_template: + options = RenderOptions() + for p in photos: + for template in print_template: + rendered_templates, unmatched = p.render_template( + template, + options, + ) + if unmatched: + rich_click_echo( + f"[warning]Unmatched template field: {unmatched}[/]" + ) + for rendered_template in rendered_templates: + if not rendered_template: + continue + rich_click_echo(rendered_template) + + if not quiet: + print_photo_info(photos, cli_json or json_, print_func=click.echo) diff --git a/tests/test_cli.py b/tests/test_cli.py index 317cc9b8..7dd860da 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -8319,3 +8319,47 @@ def test_export_no_keyword(): ) assert result.exit_code == 0 assert "Exporting 11" in result.output + + +def test_export_print(): + """test export --print""" + + runner = CliRunner() + cwd = os.getcwd() + with runner.isolated_filesystem(): + result = runner.invoke( + export, + [ + ".", + "--db", + os.path.join(cwd, PHOTOS_DB_15_7), + "--print", + "uuid: {uuid}", + "--uuid", + UUID_FAVORITE, + ], + ) + assert result.exit_code == 0 + assert f"uuid: {UUID_FAVORITE}" in result.output + + +def test_query_print_quiet(): + """test query --print""" + + runner = CliRunner() + cwd = os.getcwd() + with runner.isolated_filesystem(): + result = runner.invoke( + query, + [ + "--db", + os.path.join(cwd, PHOTOS_DB_15_7), + "--print", + "uuid: {uuid}", + "--uuid", + UUID_FAVORITE, + "--quiet", + ], + ) + assert result.exit_code == 0 + assert result.output.strip() == f"uuid: {UUID_FAVORITE}"