#!env/bin/python3 # Eryn Wells ''' New script. ''' import argparse import datetime import os.path import re import shutil import subprocess from PIL import Image from PIL.ExifTags import TAGS PHOTOS_CONTENT_DIR = 'content/photos' def slugify(s): return re.sub(r'[‘’“”]', '', re.sub(r'\s+', '-', s.strip().lower())) def parse_args(argv, *a, **kw): parser = argparse.ArgumentParser(*a, **kw) parser.add_argument('-n', '--dry-run', action='store_true') parser.add_argument('-t', '--title') parser.add_argument('-s', '--slug') 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 = None for photo in args.photos: 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'{photo} -> {exif_date.isoformat()}') if not earliest_exif_date or exif_date < earliest_exif_date: earliest_exif_date = exif_date 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)) except subprocess.CalledProcessError: print(f'Failed to create new Hugo post', file=sys.stderr) return -1 if args.title: # The hugo command can't set a title for a post so I need to do it myself. index_file_path = os.path.join(post_path, 'index.md') 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) 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)