|
|
@@ -0,0 +1,202 @@
|
|
|
+#!/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!
|
|
|
+
|
|
|
+You have the rights to use the material in this download for any purpose.
|
|
|
+
|
|
|
+This archive was generated: %s. Note that the gallery contents might change in the future.
|
|
|
+
|
|
|
+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, gallery:Gallery, photos:PhotosInGallery):
|
|
|
+ values = {
|
|
|
+ "title" : gallery.title,
|
|
|
+ "weight" : weight,
|
|
|
+ "menus" : {"main" : {"weight" : weight}},
|
|
|
+ }
|
|
|
+ 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, 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)
|