basic page rendering

This commit is contained in:
Nick Pegg 2024-08-03 18:02:02 -07:00
parent 4f5bd76f8a
commit 321cbee134
7 changed files with 117 additions and 29 deletions

View file

@ -63,7 +63,6 @@ def cmd_init(args: Namespace) -> None:
skel_files.append(album_file_path) skel_files.append(album_file_path)
if not album_file_path.exists():
album_file_path.parent.mkdir(exist_ok=True) album_file_path.parent.mkdir(exist_ok=True)
album_file_path.write_bytes(skel_file_path.read_bytes()) album_file_path.write_bytes(skel_file_path.read_bytes())
logger.debug(f"Created skeleton file {album_file_path}") logger.debug(f"Created skeleton file {album_file_path}")

View file

@ -11,7 +11,7 @@ logger = logging.getLogger(__name__)
@dataclass @dataclass
class Config: class Config:
# Size of thumbnails when looking at a folder page # Size of thumbnails when looking at a folder page
thumbnail_size: tuple[int, int] = (128, 128) thumbnail_size: tuple[int, int] = (256, 256)
# Size of the image when looking at the standalone image page # Size of the image when looking at the standalone image page
view_size: tuple[int, int] = (1920, 1080) view_size: tuple[int, int] = (1920, 1080)

View file

@ -6,8 +6,7 @@ from typing import Iterator
from jinja2 import Environment, FileSystemLoader, select_autoescape from jinja2 import Environment, FileSystemLoader, select_autoescape
from PIL import Image, UnidentifiedImageError from PIL import Image, UnidentifiedImageError
from rich.console import Console from rich.progress import Progress, track
from rich.progress import track
from photoalbum.config import Config from photoalbum.config import Config
@ -18,7 +17,7 @@ logger = logging.getLogger(__name__)
class ImageDirectory: class ImageDirectory:
path: Path path: Path
children: list["ImageDirectory"] children: list["ImageDirectory"]
images: list[Path] images: list["ImagePath"]
is_root: bool = False is_root: bool = False
def walk(self) -> Iterator["ImageDirectory"]: def walk(self) -> Iterator["ImageDirectory"]:
@ -26,7 +25,7 @@ class ImageDirectory:
for child in self.children: for child in self.children:
yield from child.walk() yield from child.walk()
def image_paths(self) -> list[Path]: def image_paths(self) -> list["ImagePath"]:
""" """
Iterate through all images in this dir and children Iterate through all images in this dir and children
""" """
@ -36,6 +35,29 @@ class ImageDirectory:
return images return images
@dataclass
class ImagePath:
path: Path
def thumbnail_filename(self) -> str:
return self.path.stem + ".thumb" + self.path.suffix
def thumbnail_path(self) -> Path:
return self.path.parent / "slides" / self.thumbnail_filename()
def display_filename(self) -> str:
return self.path.stem + ".screen" + self.path.suffix
def display_path(self) -> Path:
return self.path.parent / "slides" / self.display_filename()
def html_filename(self) -> str:
return self.path.with_suffix(".html").name
def html_path(self) -> Path:
return self.path.parent / "slides" / self.html_filename()
def generate(config: Config, album_path: Path) -> None: def generate(config: Config, album_path: Path) -> None:
""" """
Main generation function Main generation function
@ -75,7 +97,7 @@ 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(file_path) image_dir.images.append(ImagePath(file_path))
image_dirs[image_dir.path] = image_dir image_dirs[image_dir.path] = image_dir
@ -99,22 +121,22 @@ def generate_thumbnails(config: Config, root_dir: ImageDirectory) -> None:
""" """
for image_path in track(root_dir.image_paths(), description="Making thumbnails..."): for image_path in track(root_dir.image_paths(), description="Making thumbnails..."):
logger.debug(image_path) logger.debug(image_path)
orig_img = Image.open(image_path) orig_img = Image.open(image_path.path)
slides_path = image_path.parent / "slides" slides_path = image_path.path.parent / "slides"
slides_path.mkdir(exist_ok=True) slides_path.mkdir(exist_ok=True)
thumb_img = orig_img.copy() thumb_img = orig_img.copy()
thumb_img.thumbnail(config.thumbnail_size) thumb_img.thumbnail(config.thumbnail_size)
thumb_filename = image_path.stem + ".thumb" + image_path.suffix thumb_path = image_path.thumbnail_path()
thumb_img.save(slides_path / thumb_filename) thumb_img.save(thumb_path)
logger.info(f'Generated thumbnail size "{image_path}" -> "{thumb_filename}"') logger.info(f'Generated thumbnail size "{image_path.path}" -> "{thumb_path}"')
screen_img = orig_img.copy() screen_img = orig_img.copy()
screen_img.thumbnail(config.view_size) screen_img.thumbnail(config.view_size)
screen_filename = image_path.stem + ".screen" + image_path.suffix screen_path = image_path.display_path()
screen_img.save(slides_path / screen_filename) screen_img.save(screen_path)
logger.info(f'Generated screen size "{image_path}" -> "{screen_filename}"') logger.info(f'Generated screen size "{image_path.path}" -> "{screen_path}"')
def generate_html(config: Config, root_dir: ImageDirectory) -> None: def generate_html(config: Config, root_dir: ImageDirectory) -> None:
@ -129,20 +151,30 @@ def generate_html(config: Config, root_dir: ImageDirectory) -> None:
album_tmpl = jinja_env.get_template("album.html") album_tmpl = jinja_env.get_template("album.html")
photo_tmpl = jinja_env.get_template("photo.html") photo_tmpl = jinja_env.get_template("photo.html")
with Console().status("Rendering HTML..."): with Progress() as progress:
task = progress.add_task("Rendering HTML...", total=len(root_dir.image_paths()))
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"
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:
f.write(album_tmpl.render()) f.write(
album_tmpl.render(
album_dir=album_dir,
)
)
for image_path in album_dir.images: for image_path in 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
html_path = ( html_path = image_path.html_path()
image_path.parent / "slides" / image_path.with_suffix(".html").name
)
html_path.parent.mkdir(exist_ok=True) html_path.parent.mkdir(exist_ok=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:
f.write(photo_tmpl.render()) f.write(
photo_tmpl.render(
image_path=image_path,
)
)
progress.update(task, advance=1)

View file

@ -1 +1,29 @@
This is the album template {% extends "base.html" %}
{% block content %}
{% if album_dir.children %}
<h1>Albums</h1>
<div id="albums">
{% for child in album_dir.children %}
<div class="album">
<a href="{{child.path.name}}/">
{{child.path.name}}
</a>
</div>
{% endfor %}
</div>
{% endif %}
{% if album_dir.images %}
<h1>Photos</h1>
<div id="photos">
{% for image in album_dir.images %}
<div class="thumbnail">
<a href="slides/{{image.html_filename()}}">
<img src="slides/{{image.thumbnail_filename()}}" />
</a>
</div>
{% endfor %}
</div>
{% endif %}
{% endblock %}

View file

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{ static_dir }}/index.css" type="text/css">
<title>My Photos</title>
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>

View file

@ -1 +1,17 @@
This is the photo template {% extends "base.html" %}
{% block content %}
<div id="nav">
prev
<a href="..">up</a>
next
</div>
<div id="photo">
<img src="{{image_path.display_filename()}}" />
</div>
<div id="download">
<a href="../{{image_path.path.name}}">view full size</a>
</div>
{% endblock %}

View file

@ -1,5 +1,5 @@
# Size of thumbnails when viewing an album # Max size of thumbnails when viewing an album
thumbnail_size: [128, 128] thumbnail_size: [256, 256]
# Size of images when viewing a single one on screen # Max size of images when viewing a single one on screen
view_size: [1920, 1080] view_size: [1920, 1080]