Skip to content

Instantly share code, notes, and snippets.

@o3bvv
Last active August 30, 2023 05:17
Show Gist options
  • Save o3bvv/cadda4888ed13cb5e5bd0119dd893005 to your computer and use it in GitHub Desktop.
Save o3bvv/cadda4888ed13cb5e5bd0119dd893005 to your computer and use it in GitHub Desktop.
Export Apple Photos with meta sidecars
import datetime
import json
import os
from pathlib import Path
from typing import Callable
from osxphotos import ExportResults
from osxphotos import PhotoInfo
def json_default(o):
if isinstance(o, (datetime.date, datetime.datetime)):
return o.isoformat()
def post_function(
photo: PhotoInfo, results: ExportResults, verbose: Callable, **kwargs
):
if not results.exported:
return
data = photo.asdict()
result = {
"uuid": data["uuid"],
"fingerprint": data["fingerprint"],
"title": data["title"],
"description": data["description"],
"labels": data["labels"],
"keywords": data["keywords"],
"comments": data["comments"],
"exif_info": data["exif_info"],
"orientation": data["orientation"],
"filesystem": {
"original_filename": data["original_filename"],
"original_filesize": data["original_filesize"],
},
"kind": {
"is_burst": data["burst"],
"is_hdr": data["hdr"],
"is_photo": data["isphoto"],
"is_video": data["ismovie"],
"is_panorama": data["panorama"],
"is_portrait": data["portrait"],
"is_screenshot": data["screenshot"],
"is_selfie": data["selfie"],
"is_slow_mo": data["slow_mo"],
"is_time_lapse": data["time_lapse"],
"is_reference": data["isreference"],
"is_live": data["live_photo"],
},
"state": {
"is_edited": data["hasadjustments"],
"is_edited_externally": data["external_edit"],
"is_visible": data["visible"],
"is_hidden": data["hidden"],
"is_shared": data["shared"],
"is_trashed": data["intrash"],
},
"dimensions": {
"height": data["height"],
"width": data["width"],
"original_height": data["original_height"],
"original_width": data["original_width"],
},
"temporal": {
"date": data["date"],
"date_added": data["date_trashed"],
"date_modified": data["date_modified"],
"date_trashed": data["date_trashed"],
"tzoffset": data["tzoffset"],
},
"location": {
"latitude": data["latitude"],
"longitude": data["longitude"],
"place": data["place"],
},
"evaluative": {
"is_favorite": data["favorite"],
"scores": data["score"],
"likes": data["likes"],
},
"raw": {
"is_raw": data["israw"],
"has_raw": data["has_raw"],
},
"faces": [
{
k: v
for k, v in x.asdict().items()
if not k.startswith("_")
}
for x in photo.face_info
],
"people": [
{
"uuid": x.uuid,
"name": x.name,
"display_name": x.display_name,
}
for x in photo.person_info
],
"albums": photo.album_info and [
{
"name_path": x.folder_names + [x.title, ],
"uuid_path": x.folder_list + [x.uuid, ],
}
for x in photo.album_info
],
"burst": {
"burst_uuid": photo._info["burstUUID"],
"is_burst_default_pick": photo.burst_default_pick,
"is_burst_key": photo.burst_key,
"is_burst_selected": photo.burst_selected,
},
}
ts = int(photo.date.timestamp())
times = (ts, ts)
for exported in results.exported:
exported = Path(exported)
result["filesystem"]["filename"] = exported.name
result["filesystem"]["filesize"] = exported.stat().st_size
p = exported.with_name(exported.name + ".json")
with p.open("wt") as f:
json.dump(result, f, indent=2, default=json_default)
os.utime(p, times=times)
until osxphotos export /path/to/destination/media/ \
--db '/path/to/Photos Library.photoslibrary' \
--exportdb /path/to/destination/osxphotos.db \
--report /path/to/destination/osxphotos.csv \
--post-function "post.py::post_function" \
--export-by-date \
--skip-original-if-edited \
--jpeg-ext jpg \
--download-missing \
--use-photokit \
--retry 10 \
--touch-file \
--update \
--ignore-signature \
--overwrite \
--filename "{original_name[/,-|:,-]}" \
--verbose \
; do sleep 5; done
until osxphotos export /path/to/destination/media/ \
--db '/path/to/Photos Library.photoslibrary' \
--exportdb /path/to/destination/osxphotos.db \
--report /path/to/destination/osxphotos.csv \
--post-function "post.py::post_function" \
--export-by-date \
--skip-original-if-edited \
--jpeg-ext jpg \
--download-missing \
--use-photokit \
--retry 10 \
--touch-file \
--update \
--force-update \
--filename "{original_name[/,-|:,-]}" \
--verbose
; do sleep 5; done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment