diff options
| author | Paul Buetow <paul@buetow.org> | 2026-06-24 11:16:07 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-06-24 11:16:07 +0300 |
| commit | 3b0ac59ded124ad8c8038ef6b1b6094a495a04c2 (patch) | |
| tree | 0432c50200c2323a48b35645b8ae271109780697 | |
| parent | 928f28d0c51ca47f9958fda4c4bb7c8b0c571e34 (diff) | |
Split album-render.source.sh along its four seams (ar0)
album-render.source.sh bundled four concerns that change for unrelated
reasons. Extract three focused siblings, leaving album-render as the page
orchestrator:
- album-tile-layout.source.sh tile_layout_for, build_tile_block,
build_subdivided_tile
- album-thumbnail-html.source.sh build_preview_thumbnail,
append_preview_grid
- album-photo-select.source.sh album_photo_files, album_page_records,
splash_photo_files, random_splash_photo,
randomphoto
album-render.source.sh keeps page assembly, the per-photo view/details
pages, navigation redirects, index/splash, and the job_pool_* plumbing.
Every function moved whole with no body/signature change. The
album_view_page_for_photo accessor and its private ALBUM_VIEW_PAGE_BY_PHOTO
map stay in album-render so the stats mini-album boundary is unchanged.
LIB_SOURCES (Justfile + src/shuriken.sh) sources the three new modules
before album-render. Regenerated bin/shuriken.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| -rw-r--r-- | Justfile | 2 | ||||
| -rwxr-xr-x | bin/shuriken | 682 | ||||
| -rw-r--r-- | src/lib/album-photo-select.source.sh | 111 | ||||
| -rw-r--r-- | src/lib/album-render.source.sh | 333 | ||||
| -rw-r--r-- | src/lib/album-thumbnail-html.source.sh | 106 | ||||
| -rw-r--r-- | src/lib/album-tile-layout.source.sh | 140 | ||||
| -rwxr-xr-x | src/shuriken.sh | 6 |
7 files changed, 742 insertions, 638 deletions
@@ -7,7 +7,7 @@ PREFIX := env_var_or_default("PREFIX", "/usr") BINDIR := env_var_or_default("BINDIR", PREFIX + "/bin") DATADIR := env_var_or_default("DATADIR", PREFIX + "/share") SYSCONFDIR := env_var_or_default("SYSCONFDIR", "/etc/default") -LIB_SOURCES := "src/lib/logging.source.sh src/lib/bootstrap.source.sh src/lib/paths.source.sh src/lib/imagemagick.source.sh src/lib/process.source.sh src/lib/archive.source.sh src/lib/template.source.sh src/lib/job-pool.source.sh src/lib/image.source.sh src/lib/random.source.sh src/lib/metadata-label.source.sh src/lib/metadata-cache.source.sh src/lib/image-pipeline.source.sh src/lib/album-metadata.source.sh src/lib/generation-metadata.source.sh src/lib/dry-run.source.sh src/lib/album-render.source.sh src/lib/album.source.sh src/lib/stats-aggregate.source.sh src/lib/stats-render.source.sh src/lib/stats-filter-album.source.sh src/lib/config.source.sh src/lib/config.print.source.sh src/lib/config.sync.source.sh src/lib/config.staging.source.sh src/lib/config.validate.source.sh src/lib/config.cli.source.sh src/lib/action.source.sh" +LIB_SOURCES := "src/lib/logging.source.sh src/lib/bootstrap.source.sh src/lib/paths.source.sh src/lib/imagemagick.source.sh src/lib/process.source.sh src/lib/archive.source.sh src/lib/template.source.sh src/lib/job-pool.source.sh src/lib/image.source.sh src/lib/random.source.sh src/lib/metadata-label.source.sh src/lib/metadata-cache.source.sh src/lib/image-pipeline.source.sh src/lib/album-metadata.source.sh src/lib/generation-metadata.source.sh src/lib/dry-run.source.sh src/lib/album-tile-layout.source.sh src/lib/album-thumbnail-html.source.sh src/lib/album-photo-select.source.sh src/lib/album-render.source.sh src/lib/album.source.sh src/lib/stats-aggregate.source.sh src/lib/stats-render.source.sh src/lib/stats-filter-album.source.sh src/lib/config.source.sh src/lib/config.print.source.sh src/lib/config.sync.source.sh src/lib/config.staging.source.sh src/lib/config.validate.source.sh src/lib/config.cli.source.sh src/lib/action.source.sh" default: build diff --git a/bin/shuriken b/bin/shuriken index c668b2e..512806b 100755 --- a/bin/shuriken +++ b/bin/shuriken @@ -2491,228 +2491,20 @@ print_dry_run_plan() { fi } -# Inlined from src/lib/album-render.source.sh -# Maps each album photo filename to its view-page basename ("<page>-<preview>") -# as assigned during render_album_pages. Declared globally so it always exists -# for the accessor even when no album was rendered. +# Inlined from src/lib/album-tile-layout.source.sh +# Album thumbnail-grid tile layout / subdivision. Split out of +# album-render.source.sh (task ar0) so the "how do consecutive thumbnails get +# grouped into tiles" concern (feature 2x2 hero tiles, subdivided multi-thumb +# tiles, plain squares) lives apart from the page orchestration and the raw +# thumbnail HTML. These deciders change for visual/CSS reasons, independent of +# the job plumbing or the photo-selection policy. # -# This is the album module's PRIVATE backing store (task pn0). Outside callers -# must NOT index it directly: use the album_view_page_for_photo accessor below. -# Keeping the map private behind a documented function decouples consumers (the -# stats filter mini-albums) from how the album internally names or caches view -# pages, so a change to the page-naming scheme stays contained in this module. -declare -gA ALBUM_VIEW_PAGE_BY_PHOTO=() - -# Public album API (task pn0): return the view-page basename for a photo, or the -# empty string when the photo was not rendered into the album. The stats filter -# mini-albums call this to link each photo's "Details" to the album's own -# details page, instead of reaching into ALBUM_VIEW_PAGE_BY_PHOTO directly. -album_view_page_for_photo() { - local -r photo="$1"; shift - - printf '%s' "${ALBUM_VIEW_PAGE_BY_PHOTO[$photo]:-}" -} - -album_photo_files() { - local -r photos_dir="$1"; shift - - find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ - | maybe_shuffle -} - -start_preview_page() { - local -r photos_dir="$1"; shift - local -r html_dir="$1"; shift - local -r blurs_dir="$1"; shift - local -r backhref="$1"; shift - local -r page_name="$1"; shift - local -r header_bar="$1"; shift - local background_image - - background_image=$(randomphoto "$photos_dir" "$page_name") - template header "$page_name.html" \ - html_dir "$html_dir" \ - backhref "$backhref" \ - blurs_dir "$blurs_dir" \ - background_image "$background_image" \ - show_header_bar "$header_bar" -} - -finish_preview_page() { - local -r page_name="$1"; shift - local -r html_dir="$1"; shift - local -r backhref="$1"; shift - local -r tarball_name="$1"; shift - - template footer "$page_name.html" \ - html_dir "$html_dir" \ - backhref "$backhref" \ - tarball_name "$tarball_name" -} - -finish_preview_page_with_next() { - local -r page_name="$1"; shift - local -r html_dir="$1"; shift - local -r backhref="$1"; shift - local -r tarball_name="$1"; shift - local -r next_page="$1"; shift - local -r prev_page="$1"; shift - - template next "$page_name.html" \ - html_dir "$html_dir" \ - next "$next_page" \ - prev "$prev_page" - finish_preview_page "$page_name" "$html_dir" "$backhref" "$tarball_name" -} - -render_previous_page_link() { - local -r page_name="$1"; shift - local -r html_dir="$1"; shift - local -r prev_page="$1"; shift - - template prev "$page_name.html" \ - html_dir "$html_dir" \ - prev "$prev_page" -} - -# Assemble one complete preview page (page-N.html) in a single call: header, -# optional previous-page link, every thumbnail in order, then the footer (with -# a next-page link unless this is the last page). The appends to the one page -# file happen here, in sequence, so the per-page ordering is preserved even when -# this whole function runs as one backgrounded render job (parallelism is only -# ACROSS pages, never within a page). The page's photos are the trailing -# positional arguments; each photo's preview index is its 1-based position. -render_full_preview_page() { - local -r photos_dir="$1"; shift - local -r html_dir="$1"; shift - local -r thumbs_dir="$1"; shift - local -r blurs_dir="$1"; shift - local -r backhref="$1"; shift - local -r tarball_name="$1"; shift - local -r page_name="$1"; shift - local -r page_num="$1"; shift - local -r header_bar="$1"; shift - local -r prev_page="$1"; shift - local -r next_page="$1"; shift - - start_preview_page \ - "$photos_dir" "$html_dir" "$blurs_dir" "$backhref" "$page_name" \ - "$header_bar" - if [ -n "$prev_page" ]; then - render_previous_page_link "$page_name" "$html_dir" "$prev_page" - fi - - # Batch all of this page's thumbnails into ONE template call. Building the - # markup in bash and emitting it via the raw "preview_thumbs" field collapses - # what used to be N "template preview" renders (one env -i bash per - # thumbnail) into a single previewpage render per page. append_preview_grid - # also groups the page's photos into tiles (some subdivided into smaller - # thumbnails), so the per-page ordering and preview numbering stay here. - local preview_thumbs='' - # The main album's view pages are "<page_num>-<preview_num>.html", so the - # shared grid builder gets "<page_num>-" as the href prefix. - append_preview_grid preview_thumbs \ - "$thumbs_dir" "$backhref" "$page_num-" "$@" - template previewpage "$page_name.html" \ - html_dir "$html_dir" \ - preview_thumbs "$preview_thumbs" - - if [ -n "$next_page" ]; then - finish_preview_page_with_next \ - "$page_name" "$html_dir" "$backhref" "$tarball_name" \ - "$next_page" "$prev_page" - else - finish_preview_page "$page_name" "$html_dir" "$backhref" "$tarball_name" - fi -} - -# Enqueue one complete preview page as a background render job in the given job -# pool (throttled to IMAGE_JOBS). Mirrors queue_album_view_render_job: job_pool_submit -# waits for a free slot, backgrounds the whole-page assembly, and tracks its -# pid/label so a failed job is reported by job_pool_wait and makes generation -# fail loudly. The page's photos are passed as trailing positional args; the -# background subshell forks a private copy of them, so the caller is free to -# reuse its per-page accumulator for the next page. -queue_preview_page_render_job() { - local -r photos_dir="$1"; shift - local -r html_dir="$1"; shift - local -r thumbs_dir="$1"; shift - local -r blurs_dir="$1"; shift - local -r backhref="$1"; shift - local -r tarball_name="$1"; shift - local -r page_name="$1"; shift - local -r page_num="$1"; shift - local -r header_bar="$1"; shift - local -r prev_page="$1"; shift - local -r next_page="$1"; shift - local -r pool="$1"; shift - # Remaining positional args ("$@") are this page's photos in order. - - job_pool_submit "$pool" "template render job for preview $page_name" \ - render_full_preview_page \ - "$photos_dir" \ - "$html_dir" \ - "$thumbs_dir" \ - "$blurs_dir" \ - "$backhref" \ - "$tarball_name" \ - "$page_name" \ - "$page_num" \ - "$header_bar" \ - "$prev_page" \ - "$next_page" \ - "$@" -} - -# Build a whole thumbnail-grid buffer by walking a list of photos and grouping -# them into tiles. Most tiles are a single square thumbnail, but (controlled by -# THUMB_FEATURE_PERCENT / THUMB_SUBDIVIDE_PERCENT) some become a 2x2 feature tile -# or are subdivided into several smaller thumbnails. Each photo keeps its 1-based -# position as its preview number (tiling only groups CONSECUTIVE photos visually, -# never reorders them), so the view-page links stay correct. The view-page link -# is "${href_prefix}${preview_num}.html": the main album passes "<page_num>-"; the -# stats mini-albums pass "" (their view pages are bare "<index>.html"). This is -# the single shared grid builder for both the main preview pages and the stats -# mini-album galleries. Tile blocks are separated by a single newline; the -# template adds the trailing newline. -append_preview_grid() { - local -n buffer_ref="$1"; shift - local -r thumbs_dir="$1"; shift - local -r backhref="$1"; shift - local -r href_prefix="$1"; shift - local -a photos=("$@") - local -i i=0 - local -i count - local layout - local block - # Cap the big 2x2 feature tiles at this many per page; once reached, later - # tiles are no longer offered the "feature" layout (they fall back to - # subdivided/single), so a page never gets crowded with hero tiles. - local -ri max_features=2 - local -i features_used=0 - - while (( i < ${#photos[@]} )); do - # Decide this tile's layout from the photos still available; the first - # photo's name is the seeded-random context so the choice is stable. - # Features are only offered until the per-page cap is reached. - read -r layout count < <( - tile_layout_for "$(( ${#photos[@]} - i ))" "${photos[i]}" \ - "$(( features_used < max_features ? 1 : 0 ))" - ) - if [ "$layout" = feature ]; then - (( ++features_used )) - fi - block=$(build_tile_block \ - "$thumbs_dir" "$backhref" "$href_prefix" "$layout" "$(( i + 1 ))" \ - "${photos[@]:i:count}") - if [ -z "$buffer_ref" ]; then - buffer_ref="$block" - else - buffer_ref+=$'\n'"$block" - fi - (( i += count )) - done -} +# tile_layout_for rolls the seeded random layout for the next tile; +# build_tile_block / build_subdivided_tile emit the chosen tile's markup. They +# call build_preview_thumbnail (album-thumbnail-html.source.sh) at runtime, and +# are themselves driven by append_preview_grid there; all libs are sourced +# before any code runs, so the cross-module calls resolve regardless of source +# order. # Decide the layout for the next tile, printing "<layout> <photo-count>". When # feature_allowed is non-zero each tile rolls first for a "feature" (one photo @@ -2841,6 +2633,70 @@ build_subdivided_tile() { printf '</div>' } +# Inlined from src/lib/album-thumbnail-html.source.sh +# Album thumbnail HTML. Split out of album-render.source.sh (task ar0) so the +# "what markup does one thumbnail / a whole grid emit" concern lives apart from +# the tile-layout deciders (album-tile-layout.source.sh), the page orchestration +# and the photo-selection policy. This markup changes for HTML/CSS reasons +# (escaping, classes, link shape), independent of how tiles are grouped or how +# jobs are wired. +# +# append_preview_grid walks a photo list into tiles by calling tile_layout_for / +# build_tile_block (album-tile-layout.source.sh); build_preview_thumbnail emits +# one thumbnail's <a>/<img>. All libs are sourced before any code runs, so the +# calls between this module and album-tile-layout resolve regardless of source +# order. + +# Build a whole thumbnail-grid buffer by walking a list of photos and grouping +# them into tiles. Most tiles are a single square thumbnail, but (controlled by +# THUMB_FEATURE_PERCENT / THUMB_SUBDIVIDE_PERCENT) some become a 2x2 feature tile +# or are subdivided into several smaller thumbnails. Each photo keeps its 1-based +# position as its preview number (tiling only groups CONSECUTIVE photos visually, +# never reorders them), so the view-page links stay correct. The view-page link +# is "${href_prefix}${preview_num}.html": the main album passes "<page_num>-"; the +# stats mini-albums pass "" (their view pages are bare "<index>.html"). This is +# the single shared grid builder for both the main preview pages and the stats +# mini-album galleries. Tile blocks are separated by a single newline; the +# template adds the trailing newline. +append_preview_grid() { + local -n buffer_ref="$1"; shift + local -r thumbs_dir="$1"; shift + local -r backhref="$1"; shift + local -r href_prefix="$1"; shift + local -a photos=("$@") + local -i i=0 + local -i count + local layout + local block + # Cap the big 2x2 feature tiles at this many per page; once reached, later + # tiles are no longer offered the "feature" layout (they fall back to + # subdivided/single), so a page never gets crowded with hero tiles. + local -ri max_features=2 + local -i features_used=0 + + while (( i < ${#photos[@]} )); do + # Decide this tile's layout from the photos still available; the first + # photo's name is the seeded-random context so the choice is stable. + # Features are only offered until the per-page cap is reached. + read -r layout count < <( + tile_layout_for "$(( ${#photos[@]} - i ))" "${photos[i]}" \ + "$(( features_used < max_features ? 1 : 0 ))" + ) + if [ "$layout" = feature ]; then + (( ++features_used )) + fi + block=$(build_tile_block \ + "$thumbs_dir" "$backhref" "$href_prefix" "$layout" "$(( i + 1 ))" \ + "${photos[@]:i:count}") + if [ -z "$buffer_ref" ]; then + buffer_ref="$block" + else + buffer_ref+=$'\n'"$block" + fi + (( i += count )) + done +} + # Render the HTML for a single preview thumbnail (HTML-escaping every value the # way preview.tmpl's context_html fields did). Returned without a trailing # newline so callers control separators. The view-page link is @@ -2885,6 +2741,296 @@ build_preview_thumbnail() { "$thumbs_dir_html" "$photo_html" } +# Inlined from src/lib/album-photo-select.source.sh +# Album photo listing and random selection. Split out of +# album-render.source.sh (task ar0) so the "which photos are in this album, in +# what order, and which one do we pick for a background/splash" concern lives +# apart from the page orchestration, the tile-layout deciders and the thumbnail +# HTML. This is selection POLICY (shuffle/sort, splash-requires-a-blur, seeded +# random pick) and changes for different reasons than the rendering plumbing. +# +# These helpers are called by the orchestrator (album-render.source.sh) and by +# the per-page render jobs at runtime; all libs are sourced before any code runs, +# so availability does not depend on source order. + +album_photo_files() { + local -r photos_dir="$1"; shift + + find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ + | maybe_shuffle +} + +# Group the album's photos into pages of at most MAXPREVIEWS, in their final +# (shuffled/sorted) order. The result is emitted one line per page as a +# tab-separated record "<page_num>\t<photo>\t<photo>..." so the caller can walk +# pages without keeping every page in memory at once. Order is fully +# deterministic (album_photo_files already applies the seeded shuffle), so the +# downstream parallelism only changes timing, never which photo lands where. +album_page_records() { + local -r photos_dir="$1"; shift + local photo + local -i num=1 + local -i count=0 + local line='' + + while IFS= read -r photo; do + if (( count == MAXPREVIEWS )); then + printf '%d\t%s\n' "$num" "$line" + (( ++num )) + count=0 + line='' + fi + if (( count == 0 )); then + line="$photo" + else + line="$line"$'\t'"$photo" + fi + (( ++count )) + done < <(album_photo_files "$photos_dir") + + if (( count > 0 )); then + printf '%d\t%s\n' "$num" "$line" + fi +} + +splash_photo_files() { + local -r photos_dir="$1"; shift + local -r blurs_dir="$1"; shift + local photo + + while IFS= read -r photo; do + if [ -f "$DIST_DIR/$blurs_dir/$photo" ]; then + printf '%s\n' "$photo" + fi + done < <( + find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ + | sort + ) +} + +random_splash_photo() { + local -r photos_dir="$1"; shift + local -r blurs_dir="$1"; shift + local -i index + local photo + local -a photos=() + + while IFS= read -r photo; do + photos+=("$photo") + done < <(splash_photo_files "$photos_dir" "$blurs_dir") + + if (( ${#photos[@]} == 0 )); then + printf 'ERROR: No splash photos found in %s with matching blurs in %s\n' \ + "$(_display_path "$DIST_DIR/$photos_dir")" \ + "$(_display_path "$DIST_DIR/$blurs_dir")" >&2 + return 1 + fi + + index=$(random_index "photo:$photos_dir:splash" "${#photos[@]}") + printf '%s\n' "${photos[index]}" +} + +randomphoto() { + local -r photos_dir="$1"; shift + local -r context="${1:-$photos_dir}" + local -i index + local photo + local -a photos=() + + while IFS= read -r photo; do + photos+=("$photo") + done < <( + find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ + | sort + ) + + if (( ${#photos[@]} == 0 )); then + printf 'ERROR: No photos found in %s\n' \ + "$(_display_path "$DIST_DIR/$photos_dir")" >&2 + return 1 + fi + + index=$(random_index "photo:$photos_dir:$context" "${#photos[@]}") + printf '%s\n' "${photos[index]}" +} + +# Inlined from src/lib/album-render.source.sh +# Album page orchestration. After the ar0 split this module owns only the page +# assembly and the job plumbing: it builds the preview pages, the per-photo +# view/details pages, the navigation redirects and the index/splash, driving the +# job_pool_* pool so pages render in parallel. The three concerns it used to +# bundle now live in siblings, all sourced before this file: +# - album-tile-layout.source.sh (tile_layout_for/build_tile_block/...) +# - album-thumbnail-html.source.sh (build_preview_thumbnail/append_preview_grid) +# - album-photo-select.source.sh (album_photo_files/randomphoto/splash/...) +# This module calls into all three at runtime; all libs are sourced before any +# code runs, so the cross-module calls resolve regardless of source order. +# +# Maps each album photo filename to its view-page basename ("<page>-<preview>") +# as assigned during render_album_pages. Declared globally so it always exists +# for the accessor even when no album was rendered. +# +# This is the album module's PRIVATE backing store (task pn0). Outside callers +# must NOT index it directly: use the album_view_page_for_photo accessor below. +# Keeping the map private behind a documented function decouples consumers (the +# stats filter mini-albums) from how the album internally names or caches view +# pages, so a change to the page-naming scheme stays contained in this module. +declare -gA ALBUM_VIEW_PAGE_BY_PHOTO=() + +# Public album API (task pn0): return the view-page basename for a photo, or the +# empty string when the photo was not rendered into the album. The stats filter +# mini-albums call this to link each photo's "Details" to the album's own +# details page, instead of reaching into ALBUM_VIEW_PAGE_BY_PHOTO directly. +album_view_page_for_photo() { + local -r photo="$1"; shift + + printf '%s' "${ALBUM_VIEW_PAGE_BY_PHOTO[$photo]:-}" +} + +start_preview_page() { + local -r photos_dir="$1"; shift + local -r html_dir="$1"; shift + local -r blurs_dir="$1"; shift + local -r backhref="$1"; shift + local -r page_name="$1"; shift + local -r header_bar="$1"; shift + local background_image + + background_image=$(randomphoto "$photos_dir" "$page_name") + template header "$page_name.html" \ + html_dir "$html_dir" \ + backhref "$backhref" \ + blurs_dir "$blurs_dir" \ + background_image "$background_image" \ + show_header_bar "$header_bar" +} + +finish_preview_page() { + local -r page_name="$1"; shift + local -r html_dir="$1"; shift + local -r backhref="$1"; shift + local -r tarball_name="$1"; shift + + template footer "$page_name.html" \ + html_dir "$html_dir" \ + backhref "$backhref" \ + tarball_name "$tarball_name" +} + +finish_preview_page_with_next() { + local -r page_name="$1"; shift + local -r html_dir="$1"; shift + local -r backhref="$1"; shift + local -r tarball_name="$1"; shift + local -r next_page="$1"; shift + local -r prev_page="$1"; shift + + template next "$page_name.html" \ + html_dir "$html_dir" \ + next "$next_page" \ + prev "$prev_page" + finish_preview_page "$page_name" "$html_dir" "$backhref" "$tarball_name" +} + +render_previous_page_link() { + local -r page_name="$1"; shift + local -r html_dir="$1"; shift + local -r prev_page="$1"; shift + + template prev "$page_name.html" \ + html_dir "$html_dir" \ + prev "$prev_page" +} + +# Assemble one complete preview page (page-N.html) in a single call: header, +# optional previous-page link, every thumbnail in order, then the footer (with +# a next-page link unless this is the last page). The appends to the one page +# file happen here, in sequence, so the per-page ordering is preserved even when +# this whole function runs as one backgrounded render job (parallelism is only +# ACROSS pages, never within a page). The page's photos are the trailing +# positional arguments; each photo's preview index is its 1-based position. +render_full_preview_page() { + local -r photos_dir="$1"; shift + local -r html_dir="$1"; shift + local -r thumbs_dir="$1"; shift + local -r blurs_dir="$1"; shift + local -r backhref="$1"; shift + local -r tarball_name="$1"; shift + local -r page_name="$1"; shift + local -r page_num="$1"; shift + local -r header_bar="$1"; shift + local -r prev_page="$1"; shift + local -r next_page="$1"; shift + + start_preview_page \ + "$photos_dir" "$html_dir" "$blurs_dir" "$backhref" "$page_name" \ + "$header_bar" + if [ -n "$prev_page" ]; then + render_previous_page_link "$page_name" "$html_dir" "$prev_page" + fi + + # Batch all of this page's thumbnails into ONE template call. Building the + # markup in bash and emitting it via the raw "preview_thumbs" field collapses + # what used to be N "template preview" renders (one env -i bash per + # thumbnail) into a single previewpage render per page. append_preview_grid + # also groups the page's photos into tiles (some subdivided into smaller + # thumbnails), so the per-page ordering and preview numbering stay here. + local preview_thumbs='' + # The main album's view pages are "<page_num>-<preview_num>.html", so the + # shared grid builder gets "<page_num>-" as the href prefix. + append_preview_grid preview_thumbs \ + "$thumbs_dir" "$backhref" "$page_num-" "$@" + template previewpage "$page_name.html" \ + html_dir "$html_dir" \ + preview_thumbs "$preview_thumbs" + + if [ -n "$next_page" ]; then + finish_preview_page_with_next \ + "$page_name" "$html_dir" "$backhref" "$tarball_name" \ + "$next_page" "$prev_page" + else + finish_preview_page "$page_name" "$html_dir" "$backhref" "$tarball_name" + fi +} + +# Enqueue one complete preview page as a background render job in the given job +# pool (throttled to IMAGE_JOBS). Mirrors queue_album_view_render_job: job_pool_submit +# waits for a free slot, backgrounds the whole-page assembly, and tracks its +# pid/label so a failed job is reported by job_pool_wait and makes generation +# fail loudly. The page's photos are passed as trailing positional args; the +# background subshell forks a private copy of them, so the caller is free to +# reuse its per-page accumulator for the next page. +queue_preview_page_render_job() { + local -r photos_dir="$1"; shift + local -r html_dir="$1"; shift + local -r thumbs_dir="$1"; shift + local -r blurs_dir="$1"; shift + local -r backhref="$1"; shift + local -r tarball_name="$1"; shift + local -r page_name="$1"; shift + local -r page_num="$1"; shift + local -r header_bar="$1"; shift + local -r prev_page="$1"; shift + local -r next_page="$1"; shift + local -r pool="$1"; shift + # Remaining positional args ("$@") are this page's photos in order. + + job_pool_submit "$pool" "template render job for preview $page_name" \ + render_full_preview_page \ + "$photos_dir" \ + "$html_dir" \ + "$thumbs_dir" \ + "$blurs_dir" \ + "$backhref" \ + "$tarball_name" \ + "$page_name" \ + "$page_num" \ + "$header_bar" \ + "$prev_page" \ + "$next_page" \ + "$@" +} + render_view_page() { local -r html_dir="$1"; shift local -r photos_dir="$1"; shift @@ -3168,39 +3314,6 @@ queue_album_view_render_job() { "$photo" } -# Group the album's photos into pages of at most MAXPREVIEWS, in their final -# (shuffled/sorted) order. The result is emitted one line per page as a -# tab-separated record "<page_num>\t<photo>\t<photo>..." so the caller can walk -# pages without keeping every page in memory at once. Order is fully -# deterministic (album_photo_files already applies the seeded shuffle), so the -# downstream parallelism only changes timing, never which photo lands where. -album_page_records() { - local -r photos_dir="$1"; shift - local photo - local -i num=1 - local -i count=0 - local line='' - - while IFS= read -r photo; do - if (( count == MAXPREVIEWS )); then - printf '%d\t%s\n' "$num" "$line" - (( ++num )) - count=0 - line='' - fi - if (( count == 0 )); then - line="$photo" - else - line="$line"$'\t'"$photo" - fi - (( ++count )) - done < <(album_photo_files "$photos_dir") - - if (( count > 0 )); then - printf '%d\t%s\n' "$num" "$line" - fi -} - # Per-photo bookkeeping shared by the album loop: queue the view+details render # job, record the page/preview as a rendered view page (for redirect generation) # and remember the photo -> view-page mapping for the stats mini-albums. Kept @@ -3315,67 +3428,6 @@ render_album_pages() { render_album_index "$photos_dir" "$html_dir" "$blurs_dir" "$backhref" } -splash_photo_files() { - local -r photos_dir="$1"; shift - local -r blurs_dir="$1"; shift - local photo - - while IFS= read -r photo; do - if [ -f "$DIST_DIR/$blurs_dir/$photo" ]; then - printf '%s\n' "$photo" - fi - done < <( - find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ - | sort - ) -} - -random_splash_photo() { - local -r photos_dir="$1"; shift - local -r blurs_dir="$1"; shift - local -i index - local photo - local -a photos=() - - while IFS= read -r photo; do - photos+=("$photo") - done < <(splash_photo_files "$photos_dir" "$blurs_dir") - - if (( ${#photos[@]} == 0 )); then - printf 'ERROR: No splash photos found in %s with matching blurs in %s\n' \ - "$(_display_path "$DIST_DIR/$photos_dir")" \ - "$(_display_path "$DIST_DIR/$blurs_dir")" >&2 - return 1 - fi - - index=$(random_index "photo:$photos_dir:splash" "${#photos[@]}") - printf '%s\n' "${photos[index]}" -} - -randomphoto() { - local -r photos_dir="$1"; shift - local -r context="${1:-$photos_dir}" - local -i index - local photo - local -a photos=() - - while IFS= read -r photo; do - photos+=("$photo") - done < <( - find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ - | sort - ) - - if (( ${#photos[@]} == 0 )); then - printf 'ERROR: No photos found in %s\n' \ - "$(_display_path "$DIST_DIR/$photos_dir")" >&2 - return 1 - fi - - index=$(random_index "photo:$photos_dir:$context" "${#photos[@]}") - printf '%s\n' "${photos[index]}" -} - # Inlined from src/lib/album.source.sh # Album coordinator: ties together the image pipeline (image-pipeline.source.sh), # page rendering and parallel orchestration (album-render.source.sh) and the EXIF diff --git a/src/lib/album-photo-select.source.sh b/src/lib/album-photo-select.source.sh new file mode 100644 index 0000000..0a889bc --- /dev/null +++ b/src/lib/album-photo-select.source.sh @@ -0,0 +1,111 @@ +# Album photo listing and random selection. Split out of +# album-render.source.sh (task ar0) so the "which photos are in this album, in +# what order, and which one do we pick for a background/splash" concern lives +# apart from the page orchestration, the tile-layout deciders and the thumbnail +# HTML. This is selection POLICY (shuffle/sort, splash-requires-a-blur, seeded +# random pick) and changes for different reasons than the rendering plumbing. +# +# These helpers are called by the orchestrator (album-render.source.sh) and by +# the per-page render jobs at runtime; all libs are sourced before any code runs, +# so availability does not depend on source order. + +album_photo_files() { + local -r photos_dir="$1"; shift + + find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ + | maybe_shuffle +} + +# Group the album's photos into pages of at most MAXPREVIEWS, in their final +# (shuffled/sorted) order. The result is emitted one line per page as a +# tab-separated record "<page_num>\t<photo>\t<photo>..." so the caller can walk +# pages without keeping every page in memory at once. Order is fully +# deterministic (album_photo_files already applies the seeded shuffle), so the +# downstream parallelism only changes timing, never which photo lands where. +album_page_records() { + local -r photos_dir="$1"; shift + local photo + local -i num=1 + local -i count=0 + local line='' + + while IFS= read -r photo; do + if (( count == MAXPREVIEWS )); then + printf '%d\t%s\n' "$num" "$line" + (( ++num )) + count=0 + line='' + fi + if (( count == 0 )); then + line="$photo" + else + line="$line"$'\t'"$photo" + fi + (( ++count )) + done < <(album_photo_files "$photos_dir") + + if (( count > 0 )); then + printf '%d\t%s\n' "$num" "$line" + fi +} + +splash_photo_files() { + local -r photos_dir="$1"; shift + local -r blurs_dir="$1"; shift + local photo + + while IFS= read -r photo; do + if [ -f "$DIST_DIR/$blurs_dir/$photo" ]; then + printf '%s\n' "$photo" + fi + done < <( + find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ + | sort + ) +} + +random_splash_photo() { + local -r photos_dir="$1"; shift + local -r blurs_dir="$1"; shift + local -i index + local photo + local -a photos=() + + while IFS= read -r photo; do + photos+=("$photo") + done < <(splash_photo_files "$photos_dir" "$blurs_dir") + + if (( ${#photos[@]} == 0 )); then + printf 'ERROR: No splash photos found in %s with matching blurs in %s\n' \ + "$(_display_path "$DIST_DIR/$photos_dir")" \ + "$(_display_path "$DIST_DIR/$blurs_dir")" >&2 + return 1 + fi + + index=$(random_index "photo:$photos_dir:splash" "${#photos[@]}") + printf '%s\n' "${photos[index]}" +} + +randomphoto() { + local -r photos_dir="$1"; shift + local -r context="${1:-$photos_dir}" + local -i index + local photo + local -a photos=() + + while IFS= read -r photo; do + photos+=("$photo") + done < <( + find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ + | sort + ) + + if (( ${#photos[@]} == 0 )); then + printf 'ERROR: No photos found in %s\n' \ + "$(_display_path "$DIST_DIR/$photos_dir")" >&2 + return 1 + fi + + index=$(random_index "photo:$photos_dir:$context" "${#photos[@]}") + printf '%s\n' "${photos[index]}" +} diff --git a/src/lib/album-render.source.sh b/src/lib/album-render.source.sh index d438cef..e039b07 100644 --- a/src/lib/album-render.source.sh +++ b/src/lib/album-render.source.sh @@ -1,3 +1,14 @@ +# Album page orchestration. After the ar0 split this module owns only the page +# assembly and the job plumbing: it builds the preview pages, the per-photo +# view/details pages, the navigation redirects and the index/splash, driving the +# job_pool_* pool so pages render in parallel. The three concerns it used to +# bundle now live in siblings, all sourced before this file: +# - album-tile-layout.source.sh (tile_layout_for/build_tile_block/...) +# - album-thumbnail-html.source.sh (build_preview_thumbnail/append_preview_grid) +# - album-photo-select.source.sh (album_photo_files/randomphoto/splash/...) +# This module calls into all three at runtime; all libs are sourced before any +# code runs, so the cross-module calls resolve regardless of source order. +# # Maps each album photo filename to its view-page basename ("<page>-<preview>") # as assigned during render_album_pages. Declared globally so it always exists # for the accessor even when no album was rendered. @@ -19,13 +30,6 @@ album_view_page_for_photo() { printf '%s' "${ALBUM_VIEW_PAGE_BY_PHOTO[$photo]:-}" } -album_photo_files() { - local -r photos_dir="$1"; shift - - find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ - | maybe_shuffle -} - start_preview_page() { local -r photos_dir="$1"; shift local -r html_dir="$1"; shift @@ -170,227 +174,6 @@ queue_preview_page_render_job() { "$@" } -# Build a whole thumbnail-grid buffer by walking a list of photos and grouping -# t |
