erynwells.me/scripts/new-photo-post

156 lines
4.8 KiB
Python
Executable file

#!/usr/bin/env python3
# Eryn Wells <eryn@erynwells.me>
'''
New script.
'''
import argparse
import datetime
import os
import os.path
import shutil
import subprocess
from PIL import Image
from PIL.ExifTags import TAGS
from typing import Optional
from website.metadata import slugify
PHOTOS_CONTENT_DIR = 'content/photos'
def parse_args(argv, *a, **kw):
parser = argparse.ArgumentParser(*a, **kw)
parser.add_argument('-e', '--edit', action='store_true')
parser.add_argument('-n', '--dry-run', action='store_true')
parser.add_argument('-t', '--title')
parser.add_argument('-s', '--slug')
parser.add_argument('--dump-exif', action='store_true')
parser.add_argument('photos', nargs='+')
args = parser.parse_args(argv)
return args
def main(argv):
args = parse_args(argv[1:], prog=argv[0])
earliest_exif_date: Optional[datetime.datetime] = None
for index, photo in enumerate(args.photos):
print(f'image\t\t{photo}')
try:
image = Image.open(photo)
except IOError:
continue
raw_exif = image._getexif()
friendly_exif = {TAGS[k]: v for k, v in raw_exif.items() if k in TAGS}
try:
date_string = f'{friendly_exif["DateTime"]} {friendly_exif["OffsetTime"]}'
exif_date = datetime.datetime.strptime(date_string, '%Y:%m:%d %H:%M:%S %z')
except KeyError:
exif_date = datetime.datetime.strptime(friendly_exif["DateTime"], '%Y:%m:%d %H:%M:%S')
print(f'capture-time\t{exif_date.isoformat()}')
iso_rating = friendly_exif.get('ISOSpeedRatings')
if iso_rating:
print(f'iso\t\t{iso_rating}')
focal_length_35mm = friendly_exif.get('FocalLengthIn35mmFilm')
focal_length = friendly_exif.get('FocalLength')
if focal_length or focal_length_35mm:
print(f'focal-length\t{focal_length} {focal_length_35mm}')
fstop = friendly_exif.get('FNumber')
if fstop:
print(f'f-stop\t\t{fstop}')
exposure_time = friendly_exif.get('ExposureTime')
if exposure_time:
print(f'exposure-time\t{exposure_time}')
if not earliest_exif_date or exif_date < earliest_exif_date:
earliest_exif_date = exif_date
if index < len(args.photos) - 1:
print()
if not earliest_exif_date:
earliest_exif_date = datetime.datetime.now()
year = earliest_exif_date.year
month = earliest_exif_date.month
if args.slug:
name = args.slug
elif args.title:
name = slugify(args.title)
else:
name = os.path.splitext(os.path.basename(photo))[0]
post_path_year = os.path.join(PHOTOS_CONTENT_DIR, f'{year:04}', name)
post_path_year_month = os.path.join(PHOTOS_CONTENT_DIR, f'{year:04}', f'{month:02}', name)
if os.path.exists(post_path_year):
if os.path.exists(post_path_year_month):
print("Couldn't find path for photo post. Both of the following paths exist.", file=sys.stderr)
print(f' {post_path_year}', file=sys.stderr)
print(f' {post_path_year_month}', file=sys.stderr)
return -1
else:
post_path = post_path_year_month
else:
post_path = post_path_year
try:
hugo_command = ['hugo', 'new', '--clock', earliest_exif_date.isoformat(), post_path]
if not args.dry_run:
result = subprocess.run(hugo_command)
result.check_returncode()
else:
print(' '.join(hugo_command), file=sys.stderr)
except subprocess.CalledProcessError:
print(f'Failed to create new Hugo post', file=sys.stderr)
return -1
index_file_path = os.path.join(post_path, 'index.md')
if args.title and not args.dry_run:
# The hugo command can't set a title for a post so I need to do it myself.
with open(index_file_path) as index_file:
index_file_contents = index_file.readlines()
for i in range(len(index_file_contents)):
line = index_file_contents[i]
if not line.startswith('title:'):
continue
updated_line = f'title: "{args.title}"\n'
index_file_contents[i] = updated_line
with open(index_file_path, 'w') as index_file:
index_file.writelines(index_file_contents)
if not args.dry_run and args.edit:
editor = os.environ.get('EDITOR', 'vi')
subprocess.run([editor, index_file_path], shell=True)
for photo in args.photos:
print(f'Copy {photo} -> {post_path}')
try:
if not args.dry_run:
shutil.copy(photo, post_path)
except IOError:
print(f'Failed to copy {photo}', file=sys.stderr)
return -2
if __name__ == '__main__':
import sys
result = main(sys.argv)
sys.exit(0 if not result else result)