#!/usr/bin/python3 from typing import List, Optional from pydantic import BaseModel import yaml import shutil import zipfile import os import sys from datetime import datetime as dt # ---- yaml_filename = 'galleries.yaml' content_dir = "./content" zip_dir = "./downloads" # ---- def makeThankYou(gallery:str, date_generated:str): return """Thank you for purchasing the "%s" gallery from larsee.com/photography! By purchasing this product you are granted a license to use the images for any purpose. This archive was generated: %s. In the future the gallery contents might change. Don't hesitate to contact me if you have questions or other inquiries. This is my private email: lars@f-w.dk Sincerely, Lars Ole Pontoppidan """ % (gallery, date_generated) # ---- class Gallery(BaseModel): folder_name: str title: str description: Optional[str] = None cover_photo: Optional[str] = None photos: List[str] class Galleries(BaseModel): picture_root: str galleries: List[Gallery] def loadGalleries(yaml_file_path: str) -> Galleries: with open(yaml_file_path, 'r') as file: data = yaml.safe_load(file) return Galleries(**data) def fileTitle(s:str) -> str: sp = s.split("/") return sp[-1] class Photo(): def __init__(self, photo_root:str, source_file:str, prefix:str, index:int): sp = source_file.split("/") self.photoPath = sp[0] self.photoName = sp[1] self.destName = prefix + "_%02d.jpg" % index self.photoRoot = photo_root def getDestJpgName(self): return self.destName def getHqFileSource(self): return os.path.join(self.photoRoot, self.photoPath, "hq", self.photoName + "_hq.jpg") def getRawFilePath(self): opt1 = os.path.join(self.photoRoot, self.photoPath, self.photoName + ".NEF") opt2 = os.path.join(self.photoRoot, self.photoPath, self.photoName + ".JPG") if os.path.isfile(opt1): return opt1 elif os.path.isfile(opt2): return opt2 else: raise Exception("Can't find source file for: " + self.photoName) def getPp3FilePath(self): return self.getRawFilePath() + ".pp3" def getTifFilePath(self): return os.path.join(self.photoRoot, self.photoPath, "converted", self.photoName + ".tif") class PhotosInGallery(): def __init__(self, photo_root:str, gallery:Gallery): self.photos:List[Photo] = [] self.cover_photo:Optional[Photo] = None for idx, photo in enumerate(gallery.photos, start=1): p = Photo(photo_root, photo, gallery.folder_name, idx) self.photos.append(p) if photo == gallery.cover_photo: self.cover_photo = p def makeIndexFile(weight:int, weight_rev:int, gallery:Gallery, photos:PhotosInGallery): values = { "title" : gallery.title, "weight" : weight, "menus" : {"main" : {"weight" : weight_rev}}, } if gallery.description is not None: values["description"] = gallery.description if photos.cover_photo is not None: values["featured_image"] = photos.cover_photo.getDestJpgName() return "---\n" + yaml.dump(values, default_flow_style=False) + "---\n" def makeGalleries(yaml_root:Galleries): print("Purging old galleries") for item in os.listdir(content_dir): item_path = os.path.join(content_dir, item) if os.path.isdir(item_path): print(f" deleting folder: {item_path}") shutil.rmtree(item_path) print("Setting up galleries") for idx, gallery in enumerate(yaml_root.galleries): path = os.path.join(content_dir, gallery.folder_name) weight = len(yaml_root.galleries) - idx print(" making dir: " + path) os.makedirs(path, exist_ok=True) photos = PhotosInGallery(yaml_root.picture_root, gallery) index = makeIndexFile(weight, idx + 1, gallery, photos) with open(os.path.join(path, "index.md"), "w") as f: f.write(index) # Link in the pictures for photo in photos.photos: #os.symlink(photo.getHqFileSource(), os.path.join(path, photo.getSimpleJpgName())) shutil.copyfile(photo.getHqFileSource(), os.path.join(path, photo.getDestJpgName())) def makeZipDownloads(yaml_root:Galleries): if os.path.isdir(zip_dir): print("Purging old downloads") shutil.rmtree(zip_dir) os.makedirs(zip_dir, exist_ok=True) # Get the current date and time dt_now = dt.now() print("Making download zips, archive date: " + dt_now.strftime("%B %d, %Y")) for gallery in yaml_root.galleries: photos = PhotosInGallery(yaml_root.picture_root, gallery) # Create a ZIP file for the gallery zip_path = os.path.join(zip_dir, "Gallery %s.zip" % gallery.folder_name) print(" making zip: " + zip_path) #gallery_folder = "%s_%s" % (gallery.folder_name, dt_now.strftime("%b_%d_%Y")) gallery_folder = gallery.folder_name with zipfile.ZipFile(zip_path, 'w') as myzip: def addToZip(path:str, sub_folder:Optional[str] = None): if sub_folder is None: myzip.write(path, os.path.join(gallery_folder, os.path.basename(path))) else: myzip.write(path, os.path.join(gallery_folder, sub_folder, os.path.basename(path))) for photo in photos.photos: addToZip(photo.getRawFilePath()) addToZip(photo.getPp3FilePath()) addToZip(photo.getTifFilePath(), "converted") myzip.writestr('Thank you.txt', makeThankYou(gallery.title, dt_now.strftime("%B %d, %Y"))) def main(galleries:bool, zips:bool): print("Loading " + yaml_filename) yaml_root = loadGalleries(yaml_filename) if galleries: makeGalleries(yaml_root) if zips: makeZipDownloads(yaml_root) def usage(): print(""" Usage: make_galleries OPTIONS Options: -g Make galleries -z Make download zips """) if __name__ == "__main__": zips = "-z" in sys.argv galleries = "-g" in sys.argv if zips == False and galleries == False: usage() else: main(galleries, zips)