make_galleries.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #!/usr/bin/python3
  2. from typing import List, Optional
  3. from pydantic import BaseModel
  4. import yaml
  5. import shutil
  6. import zipfile
  7. import os
  8. import sys
  9. from datetime import datetime as dt
  10. # ----
  11. yaml_filename = 'galleries.yaml'
  12. content_dir = "./content"
  13. zip_dir = "./downloads"
  14. # ----
  15. def makeThankYou(gallery:str, date_generated:str):
  16. return """Thank you for purchasing the "%s" gallery from larsee.com/photography!
  17. By purchasing this product you are granted a license to use the images for any purpose.
  18. This archive was generated: %s. In the future the gallery contents might change.
  19. Don't hesitate to contact me if you have questions or other inquiries. This is my private email: lars@f-w.dk
  20. Sincerely,
  21. Lars Ole Pontoppidan
  22. """ % (gallery, date_generated)
  23. # ----
  24. class Gallery(BaseModel):
  25. folder_name: str
  26. title: str
  27. description: Optional[str] = None
  28. cover_photo: Optional[str] = None
  29. photos: List[str]
  30. class Galleries(BaseModel):
  31. picture_root: str
  32. galleries: List[Gallery]
  33. def loadGalleries(yaml_file_path: str) -> Galleries:
  34. with open(yaml_file_path, 'r') as file:
  35. data = yaml.safe_load(file)
  36. return Galleries(**data)
  37. def fileTitle(s:str) -> str:
  38. sp = s.split("/")
  39. return sp[-1]
  40. class Photo():
  41. def __init__(self, photo_root:str, source_file:str, prefix:str, index:int):
  42. sp = source_file.split("/")
  43. self.photoPath = sp[0]
  44. self.photoName = sp[1]
  45. self.destName = prefix + "_%02d.jpg" % index
  46. self.photoRoot = photo_root
  47. def getDestJpgName(self):
  48. return self.destName
  49. def getHqFileSource(self):
  50. return os.path.join(self.photoRoot, self.photoPath, "hq", self.photoName + "_hq.jpg")
  51. def getRawFilePath(self):
  52. opt1 = os.path.join(self.photoRoot, self.photoPath, self.photoName + ".NEF")
  53. opt2 = os.path.join(self.photoRoot, self.photoPath, self.photoName + ".JPG")
  54. if os.path.isfile(opt1):
  55. return opt1
  56. elif os.path.isfile(opt2):
  57. return opt2
  58. else:
  59. raise Exception("Can't find source file for: " + self.photoName)
  60. def getPp3FilePath(self):
  61. return self.getRawFilePath() + ".pp3"
  62. def getTifFilePath(self):
  63. return os.path.join(self.photoRoot, self.photoPath, "converted", self.photoName + ".tif")
  64. class PhotosInGallery():
  65. def __init__(self, photo_root:str, gallery:Gallery):
  66. self.photos:List[Photo] = []
  67. self.cover_photo:Optional[Photo] = None
  68. for idx, photo in enumerate(gallery.photos, start=1):
  69. p = Photo(photo_root, photo, gallery.folder_name, idx)
  70. self.photos.append(p)
  71. if photo == gallery.cover_photo:
  72. self.cover_photo = p
  73. def makeIndexFile(weight:int, weight_rev:int, gallery:Gallery, photos:PhotosInGallery):
  74. values = {
  75. "title" : gallery.title,
  76. "weight" : weight,
  77. "menus" : {"main" : {"weight" : weight_rev}},
  78. }
  79. if gallery.description is not None:
  80. values["description"] = gallery.description
  81. if photos.cover_photo is not None:
  82. values["featured_image"] = photos.cover_photo.getDestJpgName()
  83. return "---\n" + yaml.dump(values, default_flow_style=False) + "---\n"
  84. def makeGalleries(yaml_root:Galleries):
  85. print("Purging old galleries")
  86. for item in os.listdir(content_dir):
  87. item_path = os.path.join(content_dir, item)
  88. if os.path.isdir(item_path):
  89. print(f" deleting folder: {item_path}")
  90. shutil.rmtree(item_path)
  91. print("Setting up galleries")
  92. for idx, gallery in enumerate(yaml_root.galleries):
  93. path = os.path.join(content_dir, gallery.folder_name)
  94. weight = len(yaml_root.galleries) - idx
  95. print(" making dir: " + path)
  96. os.makedirs(path, exist_ok=True)
  97. photos = PhotosInGallery(yaml_root.picture_root, gallery)
  98. index = makeIndexFile(weight, idx + 1, gallery, photos)
  99. with open(os.path.join(path, "index.md"), "w") as f:
  100. f.write(index)
  101. # Link in the pictures
  102. for photo in photos.photos:
  103. #os.symlink(photo.getHqFileSource(), os.path.join(path, photo.getSimpleJpgName()))
  104. shutil.copyfile(photo.getHqFileSource(), os.path.join(path, photo.getDestJpgName()))
  105. def makeZipDownloads(yaml_root:Galleries):
  106. if os.path.isdir(zip_dir):
  107. print("Purging old downloads")
  108. shutil.rmtree(zip_dir)
  109. os.makedirs(zip_dir, exist_ok=True)
  110. # Get the current date and time
  111. dt_now = dt.now()
  112. print("Making download zips, archive date: " + dt_now.strftime("%B %d, %Y"))
  113. for gallery in yaml_root.galleries:
  114. photos = PhotosInGallery(yaml_root.picture_root, gallery)
  115. # Create a ZIP file for the gallery
  116. zip_path = os.path.join(zip_dir, "Gallery %s.zip" % gallery.folder_name)
  117. print(" making zip: " + zip_path)
  118. #gallery_folder = "%s_%s" % (gallery.folder_name, dt_now.strftime("%b_%d_%Y"))
  119. gallery_folder = gallery.folder_name
  120. with zipfile.ZipFile(zip_path, 'w') as myzip:
  121. def addToZip(path:str, sub_folder:Optional[str] = None):
  122. if sub_folder is None:
  123. myzip.write(path, os.path.join(gallery_folder, os.path.basename(path)))
  124. else:
  125. myzip.write(path, os.path.join(gallery_folder, sub_folder, os.path.basename(path)))
  126. for photo in photos.photos:
  127. addToZip(photo.getRawFilePath())
  128. addToZip(photo.getPp3FilePath())
  129. addToZip(photo.getTifFilePath(), "converted")
  130. myzip.writestr('Thank you.txt', makeThankYou(gallery.title, dt_now.strftime("%B %d, %Y")))
  131. def main(galleries:bool, zips:bool):
  132. print("Loading " + yaml_filename)
  133. yaml_root = loadGalleries(yaml_filename)
  134. if galleries:
  135. makeGalleries(yaml_root)
  136. if zips:
  137. makeZipDownloads(yaml_root)
  138. def usage():
  139. print("""
  140. Usage:
  141. make_galleries OPTIONS
  142. Options:
  143. -g Make galleries
  144. -z Make download zips
  145. """)
  146. if __name__ == "__main__":
  147. zips = "-z" in sys.argv
  148. galleries = "-g" in sys.argv
  149. if zips == False and galleries == False:
  150. usage()
  151. else:
  152. main(galleries, zips)