152 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			152 lines
		
	
	
	
		
			4.8 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
#!/usr/bin/env python3
 | 
						|
# Eryn Wells <eryn@erynwells.me>
 | 
						|
 | 
						|
import argparse
 | 
						|
import datetime
 | 
						|
import os
 | 
						|
import os.path as osp
 | 
						|
import shutil
 | 
						|
import subprocess
 | 
						|
from PIL import Image
 | 
						|
from PIL.ExifTags import TAGS
 | 
						|
from typing import Optional
 | 
						|
from erynwells_me.metadata import slugify
 | 
						|
from erynwells_me.paths import content_path
 | 
						|
 | 
						|
 | 
						|
PHOTOS_CONTENT_DIR = osp.join(content_path(), '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 = osp.splitext(osp.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)
 |