Simple plug-in system #476
RhetTbull
started this conversation in
Show and tell
Replies: 1 comment
-
I'll share the templates I referenced in #469. There's also a few other leftover templates I was experimenting with. """Template functions for use with osxphotos, generally:
$ osxphotos export \
--filename {function:templates.py::export_filename} \
--directory {function:templates.py::export_directory} \
...
"""
from typing import List, Union
import datetime as dt
import pathlib
import osxphotos
from osxphotos.datetime_formatter import DateTimeFormatter
### Template functions
def export_directory(photo: osxphotos.PhotoInfo, **kwargs) -> Union[List, str]:
"""Generates an export directory path for the given photo based on the content
creation date that includes a month name. Equivalent to setting `--directory` to:
'{created.year}/{created.mm}.{created.mon|lower}/{created.dd}'
"""
dtf = DateTimeFormatter(photo.date)
return f'{dtf.year}/{dtf.mm}.{dtf.mon.lower()}/{dtf.dd}'
def export_filename(photo: osxphotos.PhotoInfo, **kwargs) -> Union[List, str]:
"""Generates a unique filename, sans extension, for the given photo from the
content creation date, original filename, and internal UUID from Photos. Equivalent
to setting `--filename` to:
'{function:templates.py::export_prefix}.{original_name}.{uuid}'
"""
prefix = export_prefix(photo, **kwargs)
original_name = pathlib.Path(photo.original_filename).stem
return f'{prefix}.{original_name}.{photo.uuid}'
def export_prefix(photo: osxphotos.PhotoInfo, **kwargs) -> Union[List, str]:
"""Generates a 9-character, base36 string that encodes the millisecond difference
of the creation date and midnight (UTC) Sept 4, 1888 (Kodak 1 patent date). Useful
as a short, "usually" unique photo identifier where the lexicographic sort is
equivalent to the chronological sort. Standard timestamps don't maintain this
property when mixing files that cross timezone boundaries.
"""
millis = millis_between(photo.date, kodak_epoch)
# 9 digits in base36 can encode ~3211 years of millis
# 36**9 / (366 * 24 * 60 * 60 * 1000)
return base36_encode(millis).rjust(9, '0')
def created_millis_from_utc_prior_day(photo: osxphotos.PhotoInfo, **kwargs) -> Union[List, str]:
return str(millis_from_utc_prior_day(photo.date))
def created_millis_from_kodak_epoch(photo: osxphotos.PhotoInfo, **kwargs) -> Union[List, str]:
return str(millis_between(photo.date, kodak_epoch))
def created_millis_from_daguerreotype_epoch(photo: osxphotos.PhotoInfo, **kwargs) -> Union[List, str]:
return str(millis_between(photo.date, daguerreotype_epoch))
def created_millis_from_min_datetime(photo: osxphotos.PhotoInfo, **kwargs) -> Union[List, str]:
return str(millis_between(photo.date, utc_midnight(year=1, month=1, day=1)))
### Helpers
def millis_from_utc_prior_day(date: dt.datetime) -> int:
yesterday = (date - dt.timedelta(days=1)).date()
midnight = utc_midnight(yesterday.year, yesterday.month, yesterday.day)
return millis_between(date, yesterday)
def millis_between(date: dt.datetime, epoch: dt.datetime) -> int:
return int((date - epoch).total_seconds() * 1000)
def utc_midnight(year: int, month: int, day: int) -> dt.datetime:
return dt.datetime(year, month, day, tzinfo=dt.timezone.utc)
# https://www.smh.com.au/world/worlds-oldest-camera-sold-20070527-gdq8pi.html
# The camera on auction in Vienna was first advertised for sale
# on September 5, 1839, weeks before another Daguerreotype,
# produced by Daguerre's brother-in-law, Alphonse Giroux was
# commercially available.
daguerreotype_epoch = utc_midnight(year=1839, month=9, day=5)
# https://www.eastman.org/camera-obscura-revolutionary-kodak
# The first successful roll-film hand camera, the Kodak, was launched publicly
# in the summer of 1888. Inventor George Eastman received a patent (number 388,850)
# for the camera’s shutter and the trademark (number 15,825) for the Kodak name
# on September 4, 1888.
kodak_epoch = utc_midnight(year=1888, month=9, day=4)
def base36_encode(num: int):
alphabet = '0123456789abcdefghijklmnopqrstuvwxyz'
base36 = ''
while num:
num, i = divmod(num, 36)
base36 = alphabet[i] + base36
return base36 or '0' |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
In the last few releases, I've added the ability to supply your own python functions for custom queries, templates, and post-processing. Together these effectively provide a simple plug-in system for customizing osxphotos.
--query-function
allows you to use supply a custom function for filtering results--post-function
allows you to supply a custom function for post-processing exported files{function}
allows you to supply a custom function for use in the template system (also able to do custom template filters)Together these should allow you to implement highly customizable workflows with just a small amount of custom code while utilizing all the other features of osxphotos. If you find these useful and build any interesting workflows, I'd love to hear about it!
To give you an idea of how you could use these, if you saved the following code in
best_selfies.py
, and run it with:osxphotos export /path/to/export --query-function best_selfies.py::best_selfies --filename {function:best_selfies.py::name_my_selfie} --post-function best_selfies.py::post_function
it will find your best selfie for each year and export it with a custom name then run custom post-processing, all with just a few lines of code.
best_selfies.py
:Beta Was this translation helpful? Give feedback.
All reactions