""" Export all photos to specified directory using album names as folders If file has been edited, also export the edited version, otherwise, export the original version This will result in duplicate photos if photo is in more than album """ import os.path import pathlib import sys import click from pathvalidate import is_valid_filepath, sanitize_filepath import osxphotos @click.command() @click.argument("export_path", type=click.Path(exists=True)) @click.option( "--default-album", help="Default folder for photos with no album. Defaults to 'unfiled'", default="unfiled", ) @click.option( "--library-path", help="Path to Photos library, default to last used library", default=None, ) def export(export_path, default_album, library_path): export_path = os.path.expanduser(export_path) library_path = os.path.expanduser(library_path) if library_path else None if library_path is not None: photosdb = osxphotos.PhotosDB(library_path) else: photosdb = osxphotos.PhotosDB() photos = photosdb.photos() for p in photos: if not p.ismissing: albums = p.albums if not albums: albums = [default_album] for album in albums: click.echo(f"exporting {p.filename} in album {album}") # make sure no invalid characters in destination path (could be in album name) album_name = sanitize_filepath(album, platform="auto") # create destination folder, if necessary, based on album name dest_dir = os.path.join(export_path, album_name) # verify path is a valid path if not is_valid_filepath(dest_dir, platform="auto"): sys.exit(f"Invalid filepath {dest_dir}") # create destination dir if needed if not os.path.isdir(dest_dir): os.makedirs(dest_dir) # export the photo if p.hasadjustments: # export edited version exported = p.export(dest_dir, edited=True) edited_name = pathlib.Path(p.path_edited).name click.echo(f"Exported {edited_name} to {exported}") # export unedited version exported = p.export(dest_dir) click.echo(f"Exported {p.filename} to {exported}") else: click.echo(f"Skipping missing photo: {p.filename}") if __name__ == "__main__": export() # pylint: disable=no-value-for-parameter