Add cover images to albums. If a cover.jpg doesn't exist, use the first image

This commit is contained in:
Nick Pegg 2024-08-04 11:57:08 -07:00
parent 2875805444
commit 217950eeaf
3 changed files with 62 additions and 16 deletions

View file

@ -2,7 +2,7 @@ import logging
from dataclasses import dataclass from dataclasses import dataclass
from pathlib import Path from pathlib import Path
from pprint import pformat from pprint import pformat
from typing import Iterator from typing import Iterator, Optional
from jinja2 import Environment, FileSystemLoader, select_autoescape from jinja2 import Environment, FileSystemLoader, select_autoescape
from PIL import Image, UnidentifiedImageError from PIL import Image, UnidentifiedImageError
@ -20,6 +20,8 @@ class ImageDirectory:
images: list["ImagePath"] images: list["ImagePath"]
is_root: bool = False is_root: bool = False
cover_path: Optional["ImagePath"] = None
def walk(self) -> Iterator["ImageDirectory"]: def walk(self) -> Iterator["ImageDirectory"]:
yield self yield self
for child in self.children: for child in self.children:
@ -34,6 +36,13 @@ class ImageDirectory:
images += image_dir.images images += image_dir.images
return images return images
def cover_image_paths(self) -> list["ImagePath"]:
images = []
for image_dir in self.walk():
if image_dir.cover_path is not None:
images.append(image_dir.cover_path)
return images
@dataclass @dataclass
class ImagePath: class ImagePath:
@ -97,8 +106,20 @@ def find_images(root_path: Path) -> ImageDirectory:
for filename in sorted(filenames): for filename in sorted(filenames):
file_path = dirpath / filename file_path = dirpath / filename
if is_image(file_path): if is_image(file_path):
image_dir.images.append(ImagePath(file_path)) ip = ImagePath(file_path)
# Set a cover image for the album. Use "cover.jpg" if one exists,
# otherwise use the first image we find.
if file_path.stem == "cover":
image_dir.cover_path = ip
# Don't add the cover image to the list of images, we want to handle
# that separately
continue
image_dir.images.append(ip)
if image_dir.cover_path is None and len(image_dir.images) > 0:
image_dir.cover_path = image_dir.images[0]
image_dirs[image_dir.path] = image_dir image_dirs[image_dir.path] = image_dir
return image_dirs[root_path] return image_dirs[root_path]
@ -119,8 +140,10 @@ def generate_thumbnails(config: Config, root_dir: ImageDirectory) -> None:
""" """
Find all of the images and generate thumbnails and on-screen versions Find all of the images and generate thumbnails and on-screen versions
""" """
for image_path in track(root_dir.image_paths(), description="Making thumbnails..."): # Include cover images here because we want thumbnails for all of them
logger.debug(image_path)
all_images = root_dir.image_paths() + root_dir.cover_image_paths()
for image_path in track(all_images, description="Making thumbnails..."):
orig_img = Image.open(image_path.path) orig_img = Image.open(image_path.path)
slides_path = image_path.path.parent / "slides" slides_path = image_path.path.parent / "slides"
@ -156,9 +179,7 @@ def generate_html(config: Config, root_dir: ImageDirectory) -> None:
for album_dir in root_dir.walk(): for album_dir in root_dir.walk():
html_path = album_dir.path / "index.html" html_path = album_dir.path / "index.html"
root_path = root_dir.path.relative_to( root_path = root_dir.path.relative_to(html_path.parent, walk_up=True)
html_path.parent, walk_up=True
)
logger.debug(f"Rendering {html_path}") logger.debug(f"Rendering {html_path}")
with html_path.open("w") as f: with html_path.open("w") as f:
@ -172,18 +193,19 @@ def generate_html(config: Config, root_dir: ImageDirectory) -> None:
for pos, image_path in enumerate(album_dir.images): for pos, image_path in enumerate(album_dir.images):
# TODO: If a file with a matching name but .txt or .md, add that as the # TODO: If a file with a matching name but .txt or .md, add that as the
# description for the image # description for the image
if image_path.path.stem == "cover":
continue
html_path = image_path.html_path() html_path = image_path.html_path()
root_path = root_dir.path.relative_to( root_path = root_dir.path.relative_to(html_path.parent, walk_up=True)
html_path.parent, walk_up=True
)
html_path.parent.mkdir(exist_ok=True) html_path.parent.mkdir(exist_ok=True)
prev_image = None prev_image = None
next_image = None next_image = None
if pos != 0: if pos != 0:
prev_image = album_dir.images[pos-1] prev_image = album_dir.images[pos - 1]
if pos < len(album_dir.images) - 1: if pos < len(album_dir.images) - 1:
next_image = album_dir.images[pos+1] next_image = album_dir.images[pos + 1]
logger.debug(f"Rendering {html_path}") logger.debug(f"Rendering {html_path}")
with html_path.open("w") as f: with html_path.open("w") as f:

View file

@ -9,19 +9,30 @@
</p> </p>
{% endif %} {% endif %}
{% if not album_dir.is_root %}
<h1>{{album_dir.path.name}}</h1>
{% endif %}
{% if album_dir.children %} {% if album_dir.children %}
<ul id="album-children"> <div id="album-children">
{% for child in album_dir.children %} {% for child in album_dir.children %}
<li class="album"> <div class="album">
<a href="{{child.path.name}}/"> <a href="{{child.path.name}}/">
<div>
{% if child.cover_path %}
<img src="{{child.path.name}}/slides/{{child.cover_path.thumbnail_filename()}}" />
{% endif %}
</div>
<div>
{{child.path.name}} {{child.path.name}}
</div>
</a> </a>
</li> </div>
{% endfor %} {% endfor %}
</ul> </div>
{% endif %} {% endif %}
{% if album_dir.images %} {% if album_dir.images %}
<h2>Photos</h2>
<div id="album-photos"> <div id="album-photos">
{% for image in album_dir.images %} {% for image in album_dir.images %}
<div class="thumbnail"> <div class="thumbnail">

View file

@ -25,6 +25,7 @@ body {
#content > * { #content > * {
width: fit-content; width: fit-content;
margin-top: 1em;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
} }
@ -33,6 +34,18 @@ ul {
padding-left: 1.5em; padding-left: 1.5em;
} }
#album-children {
display: flex;
flex-wrap: wrap;
justify-content: center;
}
#album-children > * {
margin: 1em;
padding: 0.75em;
background-color: lightgrey;
}
#album-photos { #album-photos {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;