osxphotos/examples/export_previews.py
2023-06-15 22:11:35 -07:00

127 lines
4.4 KiB
Python

""" Export previews for photos in the Photos library
To run this with osxphotos on currently selected photos:
osxphotos run export_previews.py --selected export_path
"""
from __future__ import annotations
import pathlib
import shutil
import click
import osxphotos
from osxphotos.cli import echo, echo_error, query_command, verbose
from osxphotos.cli.export import get_dirnames_from_template, get_filenames_from_template
from osxphotos.cli.param_types import TemplateString
from osxphotos.utils import pluralize
@query_command
@click.option("--dry-run", is_flag=True, help="Dry run, don't actually export")
@click.option(
"--directory",
type=TemplateString(),
help="Directory to export to under export_path. This is an osxphotos template string. "
"For example, to export previews to directories based on creation date: "
"--directory '{created.year}/{created.mm}/{created.dd}' ",
)
@click.option(
"--filename",
"filename_template",
type=TemplateString(),
help="Filename for exported preview. "
"This is an osxphotos template string; "
"for example, to export previews to filename based on creation date: "
"--filename '{original_name}-{created.year}-{created.mm}-{created.dd}' ",
)
@click.argument(
"export_dir", type=click.Path(exists=True, file_okay=False, dir_okay=True)
)
def export_previews(
photos: list[osxphotos.PhotoInfo],
dry_run: bool,
directory: str,
filename_template: str,
export_dir: str,
**kwargs,
):
"""Export previews for photos in the Photos library.
Pass one or more query options to select photos to export or use without query options
to export all images.
If --directory is passed, the previews will be exported to subdirectories under export_path
based on the template string passed to --directory. For example, to export previews to
directories based on creation date: --directory '{created.year}/{created.mm}/{created.dd}'
If --filename is passed, the previews will be exported with the filename specified by the
template string passed to --filename. For example, to export previews to filename based on
creation date: --filename '{original_name}-{created.year}-{created.mm}-{created.dd}'
If --dry-run is passed, the previews will not actually be exported but the export will be
simulated and the export paths printed to stdout.
"""
verbose(f"Found {len(photos)} photo(s)")
count = 0
for photo in photos:
try:
# first derivative is the largest preview, so use that one
preview = pathlib.Path(photo.path_derivatives[0])
except IndexError:
echo(f"No preview for {photo.original_filename} ({photo.uuid})")
continue
verbose(f"Found preview for {photo.original_filename}: {preview}")
count += export_preview_to_directory_with_filename(
photo, preview, export_dir, directory, filename_template, dry_run
)
echo(f"Exported {count} preview {pluralize(count, 'image', 'images')}")
def export_preview_to_directory_with_filename(
photo: osxphotos.PhotoInfo,
preview_path: pathlib.Path,
export_dir: str,
directory: str,
filename_template: str,
dry_run: bool,
) -> int:
"""Export preview for photo to directory with filename; returns count of images exported"""
count = 0
for dirname in get_dirnames_from_template(
photo=photo,
directory=directory,
export_by_date=False,
dest=export_dir,
dry_run=dry_run,
):
for filename in get_filenames_from_template(
photo=photo,
filename_template=filename_template,
export_dir=export_dir,
dest_path=dirname,
original_name=True,
):
# need to change filename extension to match preview
filename = pathlib.Path(filename).with_suffix(preview_path.suffix)
dest_path = pathlib.Path(dirname) / filename
echo(
f"Exporting preview for {photo.original_filename} ({photo.uuid}) to {dest_path}"
)
if not dry_run:
try:
shutil.copy(preview_path, dest_path)
except Exception as e:
echo_error(f"Error exporting preview: {e}")
continue
count += 1
return count
if __name__ == "__main__":
export_previews()