Skip to content

Instantly share code, notes, and snippets.

@kradalby
Created August 3, 2020 19:05
Show Gist options
  • Save kradalby/9bf437918f63a388065fc00fb45813a3 to your computer and use it in GitHub Desktop.
Save kradalby/9bf437918f63a388065fc00fb45813a3 to your computer and use it in GitHub Desktop.
Export Photos from Photos.app
""" 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
from click import echo as print
import click
from osxphotos.photoinfo.photoinfo import PhotoInfo
from osxphotos.photoinfo import ExportResults
from osxphotos.albuminfo import AlbumInfo, FolderInfo
from pathvalidate import is_valid_filepath, sanitize_filepath
from osxphotos._export_db import ExportDB
import osxphotos
def is_jpeg(p: PhotoInfo):
jpeg = [".jpg", ".jpeg", "jpg", "jpeg"]
suffix = pathlib.Path(p.path).suffix.lower()
return suffix in jpeg
def echo_export(exportResults: ExportResults):
print()
if exportResults[0]:
print(f"Exported: {exportResults[0]}")
if exportResults[1]:
print(f"New: {exportResults[1]}")
if exportResults[2]:
print(f"Updated: {exportResults[2]}")
if exportResults[3]:
print(f"Skipped: {exportResults[3]}")
if exportResults[4]:
print(f"Exif updated: {exportResults[4]}")
def export_photo(p: PhotoInfo, destination: str, db: ExportDB):
export_settings = {
"use_persons_as_keywords": True,
"exiftool": True,
"update": True,
"export_db": db,
}
if not is_jpeg:
export_settings["use_photos_export"] = True
if p.isphoto:
if not p.ismissing:
# export the photo
if p.hasadjustments:
if not p.path_edited:
export_settings["use_photos_export"] = True
# export edited version
exported = p.export2(destination, edited=True, **export_settings)
# edited_name = pathlib.Path(p.path_edited).name
echo_export(exported)
# print(f"Exported {edited_name} to {exported}")
# export unedited version
else:
exported = p.export2(destination, **export_settings)
# print(f"Exported {p.filename} to {exported}")
echo_export(exported)
else:
print(f"Skipping missing photo: {p.filename}")
def export_album(a: AlbumInfo, destination: str, db: ExportDB):
name = sanitize_filepath(a.title, platform="auto")
destination_path = os.path.join(destination, name)
# verify path is a valid path
if not is_valid_filepath(destination_path, platform="auto"):
sys.exit(f"Invalid filepath {destination_path}")
# create destination dir if needed
if not os.path.isdir(destination_path):
os.makedirs(destination_path)
try:
for p in a.photos:
export_photo(p, destination_path, db)
except IndexError as e:
print(f"Album {a.title} has no photos, caused IndexError on .photos")
print(e)
# print(traceback.format_exc())
print(a)
print(len(a.photos))
for p in a.photos:
print(p.filename)
export_photo(p, destination_path, db)
def export_folder(f: FolderInfo, destination: str, db: ExportDB):
folder_name = sanitize_filepath(f.title, platform="auto")
destination_path = os.path.join(destination, folder_name)
# verify path is a valid path
if not is_valid_filepath(destination_path, platform="auto"):
sys.exit(f"Invalid filepath {destination_path}")
# create destination dir if needed
if not os.path.isdir(destination_path):
os.makedirs(destination_path)
for album in f.album_info:
export_album(album, destination_path, db)
for subfolder in f.subfolders:
export_folder(subfolder, destination_path, db)
@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
dbname = os.path.join(export_path, ".osxphotos_export.db")
db = ExportDB(dbname)
if library_path is not None:
photosdb = osxphotos.PhotosDB(library_path)
else:
photosdb = osxphotos.PhotosDB()
for folder in photosdb.folder_info:
export_folder(folder, export_path, db)
if __name__ == "__main__":
export() # pylint: disable=no-value-for-parameter
@VenkiiKR
Copy link

VenkiiKR commented Apr 7, 2021

Hii,
It is really helpful for export photos. exportation photos are easy we can do that but the thing is to find duplicates from the gallery is hard any solution for that?
Venkatesh K Reddy
Technical Writer | Researcher of (Duplicate Photo Finder, Driver updater)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment