summaryrefslogtreecommitdiff
path: root/src/lib/album-render.source.sh
AgeCommit message (Collapse)Author
2026-07-18Add DETAILS_PAGE setting to make per-photo details pages optionalPaul Buetow
Album owners can now set DETAILS_PAGE=no (or pass --no-details) to skip generating each photo's *-details.html EXIF summary page and its "Details" navigation redirects, without touching the normal thumbnail overview, per-photo view pages, EXIF tooltips, or STATS_PAGE, which all stay independently controlled. Every "Details" link (on view pages and stats filter mini-album view pages) and every "-details" redirect stub is gated on the setting so no generated page ever links to a file that was not rendered. Wired the new field through CONFIG_SPECS (registry-driven defaults/validation/print-config/CLI override), the --details/--no-details CLI flags, usage() help, the verbose effective-config log, shuriken.json generation metadata, and the dry-run plan. DETAILS_PAGE=yes (the default) keeps prior output byte-for-byte identical. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-06-28Refactor over-length functions into ~30-line helpers (vr0)Paul Buetow
Pure, behavior-preserving refactor: extract _-prefixed helpers from six functions that exceeded the project's 50-line threshold, leaving each original as a thin orchestrator. Generated HTML, dry-run output, shuriken.json, EXIF cache behavior and the flush-grid layout are all byte-identical (full test suite green). Refactored: - _generation_metadata_json -> _generation_metadata_json_head + _generation_metadata_json_settings - print_dry_run_plan -> _print_dry_run_settings + _print_dry_run_files - _photo_exif_tooltip_text_from_values -> _collect_exif_tooltip_parts + _emit_exif_tooltip_parts - cached_photo_identify_output -> _rebuild_photo_identify_cache - render_album_pages -> _render_album_page (one page record) - append_preview_grid -> _roll_and_align_page_tiles + _emit_page_tiles (uniquely-named namerefs to avoid circular-nameref) Left intact (delicate errexit/trap management that must stay in one function scope, where a split would change semantics): source_template_file, refresh_splash, generate_staged, replace_dist_with_staging. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-28nr0: dry-run reuses real paging/redirect logic via shared helpersPaul Buetow
collect_dry_run_page_plan re-derived page_count via the ceil formula and redirect_count via a magic "*4+2", duplicating logic owned by album_page_records (pagination) and render_page_view_redirects (redirect files). The preview could silently drift from a real --generate. Single source of truth: - album_page_count_for_image_count (album-photo-select.source.sh) owns the MAXPREVIEWS-per-page grouping count that album_page_records realises. - ALBUM_REDIRECTS_PER_PAGE=4 / ALBUM_REDIRECTS_LAST_PAGE_EXTRA=2 + album_redirect_count_for_page_count (album-render.source.sh) own the per-page (4) plus last-page-extra (2) redirect tally that render_page_view_redirects actually emits. dry-run now predicts both counts through these helpers (no dist files touched, side-effect free). Confirmed the real redirect count is page_count*4+2, so output is byte-identical: partial-final-page (3 preview pages / 14 navigation redirects) and empty album (0 / 0) unchanged. Regenerated bin/shuriken; just test/shellcheck/check-generated all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-25Fill the album's short final page with a full-row tilePaul Buetow
A short final preview page (e.g. one leftover photo when the photo count isn't a multiple of the page size) can't be aligned to a multiple of 12 cells, so it left an orphaned bottom-right corner. The album's LAST page now widens its leftover final single tile into a "fill" tile spanning the whole row (grid-column: 1 / -1) at any breakpoint, so the bottom edge is flush; object-fit: cover keeps the wider crop undistorted. append_preview_grid takes a fill_last flag: render_full_preview_page sets it only for the page with no "next" link; stats mini-albums pass 'no' so their small galleries are unaffected. build_tile_block gains a 'fill' layout and header.tmpl an a.fill-row rule. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24Extract shared list_photos/pick_random_photo helper (br0)Paul Buetow
Collapse the duplicated "find photos, error on empty, random_index by ctx, return one" pattern into a single photo-list.source.sh exposing list_photos <dir> and pick_random_photo <dir> <ctx>. Consumers in album-photo-select, album-render, image-pipeline and stats-render now call the shared helpers; _stats_load_background_photos keeps its caching via a cached list_photos call rather than re-listing per filter page. Per-call-site random_index ctx strings are preserved, so selection semantics are unchanged. Sourced before its consumers in LIB_SOURCES (Justfile + src/shuriken.sh); bin/shuriken regenerated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24Split album-render.source.sh along its four seams (ar0)Paul Buetow
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>
2026-06-24Encapsulate job pool behind a single handle (job_pool_*)Paul Buetow
Replace the four-parallel-nameref job-pool API (pids/statuses/labels/failed, each needing its own `shellcheck disable=SC2034` at every call site) with a single pool handle: a name prefix whose four backing variables (${pool}_pids/_statuses/_labels/_failed) are derived on demand by the helpers. Bash can't nest indexed arrays in an associative array, so a prefixed-handle with declare -g backing vars is the simplest pure-nameref encoding (no eval). New public API: job_pool_init <pool> job_pool_submit <pool> <label> <cmd...> job_pool_wait <pool> # returns 1 if any job failed Migrate all callers (scalephotos, create_all_photo_derivatives, render_album_pages, render_view_redirects, render_filter_pages) to the handle. queue_preview_page_render_job / queue_album_view_render_job / _album_record_view_photo / _stats_enqueue_filter_album now take one pool arg instead of four names. Drop the dead wrappers and unused parameterization: wait_for_image_job_slot, wait_for_template_render_job_slot and their _jobs variants only ever passed IMAGE_JOBS, so the max_jobs parameter is gone and throttling is fixed at IMAGE_JOBS inside the pool. Also removes wait_for_album_view_render_jobs (now just job_pool_wait). Throttling (max IMAGE_JOBS concurrent), failure detection and failed-job propagation are unchanged; the parallel-throttling and failure-logging tests pass unmodified. SC2034 disable-comments across the touched files drop 29->7. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22Cap the 2x2 feature tiles at two per pagePaul Buetow
Each tile rolled for a feature independently, so a page (or stats gallery) could fill up with large 2x2 hero tiles. append_preview_grid now counts the features it has placed and stops offering the "feature" layout to tile_layout_for once two have been used, so any single grid gets at most two feature tiles; later tiles fall back to subdivided or single. The cap is per append_preview_grid call, so it applies to both the main preview pages and the stats mini-album galleries. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22Reuse the album tile grid for stats mini-album galleries (DRY)Paul Buetow
The per-camera and per-filter stats mini-album galleries rendered their own plain img.thumb grid, so they did not get the dynamic tiles. Make them reuse the album's shared grid builder instead. Generalize append_preview_grid (and build_tile_block / build_subdivided_tile / build_preview_thumbnail) to take an href_prefix rather than a page number: the main album passes "<page_num>-" (view pages "<page>-<n>.html") and the stats mini-albums pass "" (view pages bare "<n>.html") -- the only difference between the two grids. The duplicate _stats_filter_thumbnail is removed; _stats_build_filter_thumbs now calls append_preview_grid, and camera.tmpl wraps the result in the same thumbs-grid container. Stats galleries now get the identical 2x2 feature tiles, subdivided sub-thumbnails, entry animations and hover effects as the main overview. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22Add large 2x2 feature tiles and a CSS-grid overviewPaul Buetow
Allow a single photo to be blown up into a large "feature" tile that spans a 2x2 block of the album overview, controlled by a new THUMB_FEATURE_PERCENT (0-100, default 10; 0 disables). Each tile rolls for a feature first, then for a subdivision, otherwise stays a normal square. To pack mixed-size tiles (normal 1x1, subdivided 1x1, feature 2x2) without gaps, the overview is now a real CSS grid with grid-auto-flow: dense, so smaller tiles backfill the holes a 2x2 feature would leave. Tile spacing moved from per-image padding to the grid gap. Feature tiles reuse the img.thumb class and its dramatic hover. THUMB_FEATURE_PERCENT is wired through the same layers as THUMB_SUBDIVIDE_PERCENT: config defaults, 0..100 validation, --print-config, the --feature CLI flag, the usage text, and the shuriken.json / --dry-run metadata, with docs and tests updated. Generated HTML and CSS pass the W3C Nu HTML checker and CSS validator. Setting both percentages to 0 reproduces the previous all-1x1 grid. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22Add dynamic subdivided thumbnail tilesPaul Buetow
Make the album preview grid livelier: with a configurable probability (THUMB_SUBDIVIDE_PERCENT, default 30%) a square thumbnail tile is subdivided into several smaller thumbnails packed into the same square footprint, chosen at random from: - quad: 2x2 squares (4 photos) - two-wide: two stacked full-width strips (2 photos) - squares+wide: two squares plus one full-width strip, strip on the top or the bottom (3 photos) Each sub-thumbnail stays its own clickable photo with its own view page; subdivision only groups consecutive photos visually, so preview numbering and the view/details/redirect pages are unchanged. No new images are generated (CSS object-fit crops the existing aspect-correct thumbs into squares or wide strips). Sub-thumbnails get the same random entry animation and the same dramatic hover (flip/scale/rotate/filter) as full thumbs. The layout choice reuses the seeded random_index, so builds stay reproducible under RANDOM_SEED. THUMB_SUBDIVIDE_PERCENT=0 reproduces the previous output byte-for-byte. The new option is wired through the config defaults, validation (0..100), --print-config, the --subdivide CLI flag, the usage text, and the shuriken.json / --dry-run metadata, with docs and tests updated. Generated HTML and CSS pass the W3C Nu HTML checker and CSS validator. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21Fix W3C HTML validation errors in generated pages; release 0.10.10.10.1Paul Buetow
Every shuriken-generated page failed W3C validation. Fixed across the templates and the bash thumbnail builders so all page categories (splash, gallery, photo view, details, stats overview, stats filter mini-albums and redirect stubs) validate cleanly: - Add <!DOCTYPE html>, <html lang="en"> and <meta charset="utf-8"> to the header, splash and redirect templates. - Drop the obsolete type="text/css" on <style> and border='0' on <img>. - Fix invalid CSS "margin: 2 auto" -> "margin: 2px auto". - Add required alt attributes to every <img> (splash, thumbnails, views). - Replace the obsolete name attribute on <a> thumbnail anchors with id (in album-render.source.sh and stats-filter-album.source.sh, where the markup is actually built, plus preview.tmpl for consistency). - Give redirect stubs a <title>; drop trailing slashes on void elements. Updated the affected cli.sh assertions and rebuilt bin/shuriken. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-17pn0 decouple stats from album internalsPaul Buetow
Stats reached directly into album-module internals: the private global ALBUM_VIEW_PAGE_BY_PHOTO and the EXIF cache reader cached_photo_identify_output. Introduce a clean boundary, behaviour and generated HTML byte-identical. - Promote the EXIF identify cache primitive (cached_photo_identify_output plus its private helpers photo_cache_signature and print_cached_photo_identify_output) out of album-metadata.source.sh into a new shared src/lib/metadata-cache.source.sh, sourced before both album and stats (right after metadata-label in LIB_SOURCES). It is a low-level metadata primitive used by both consumers, so it no longer belongs to album internals. Signature/behaviour unchanged. - Add album_view_page_for_photo accessor in album-render.source.sh as the documented public API; keep ALBUM_VIEW_PAGE_BY_PHOTO as the album's private backing store. stats-filter-album.source.sh now calls the accessor instead of indexing the global, so a change to album page naming/caching stays contained in the album module. - Add test_album_stats_decoupling_boundary asserting the accessor returns the backing-store value and that the assembled bin/shuriken keeps the cache primitive in the shared module and no longer indexes the global from the stats filter section. Existing stats/album tests unchanged. Verified: 3-image fixture (STATS_PAGE=yes, fixed seed) diff -r of stashed original vs new build is byte-identical across all 47 dist files (only the inherent generated_at timestamp normalized). just test, just shellcheck, just check-generated and git diff --check all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16wn0 batch preview-thumbnail rendering per pagePaul Buetow
Each thumbnail on a preview page (page-N.html) used to be rendered by its own "template preview" call, paying the full source_template_file cost -- an "env -i bash" invocation -- per thumbnail. With MAXPREVIEWS thumbnails per page that was N template renders per page just for the grid. render_full_preview_page now builds the markup for ALL of a page's thumbnails in bash (build_preview_thumbnail / append_preview_thumbnail) and emits the whole grid in ONE render via a new previewpage.tmpl that takes the pre-built HTML through a context_raw "preview_thumbs" field -- the same pattern the stats filter galleries (camera.tmpl) already use. Per-thumbnail markup is byte-identical to the old preview.tmpl output: same <a name=... href=...><img class='thumb <anim>' .../></a> structure, order, HTML escaping and seeded "slow" animation class. Header and footer stay as their own template calls, so a page now costs ~1 previewpage render + header/footer instead of N + chrome. The parallel job-pool integration and failure contract are unchanged: each preview page is still one background render job. Added the render_preview_thumbs_html field spec (hn0 dispatch pattern, context_raw kind), registered previewpage in the validate_template_dir required templates and in the required-context-vars test expectations, and pointed the four generation template-failure tests at previewpage.tmpl (generation no longer renders preview.tmpl). The standalone "template preview" engine unit tests keep exercising preview.tmpl, which still ships. Verified byte-identical output: generated the fixture album (including a spaces/special-char filename) twice with RANDOM_SEED=42 using the parent commit's bin/shuriken vs the new bin; every .html file is identical. just test, just shellcheck, just check-generated and git diff --check all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16in0 split album.source.sh into cohesive modulesPaul Buetow
Refactor the ~1442-line album.source.sh ([SRP] violation) into three cohesive modules, leaving album.source.sh a thin coordinator. Pure code move, no behavior change -- whole functions and their doc comments moved verbatim; the assembled bin/shuriken contains the same function set. - image-pipeline.source.sh: ImageMagick derivative generation (create_photo_derivatives, create_all_photo_derivatives) and photo asset prep (prepare_generation_photo_assets). - album-metadata.source.sh: EXIF identify caching, exif tooltip/details helpers, file counts, shuriken.json metadata, EXIF cache clearing and the dry-run plan. - album-render.source.sh: preview/view/details/splash/redirect page rendering, the parallel render-job orchestration and the ALBUM_VIEW_PAGE_BY_PHOTO global. - album.source.sh: thin coordinator (generate, refresh_splash, generate_stats_pages, site-asset/archive/html-clean helpers). Add the three modules to LIB_SOURCES (Justfile) and to the SHURIKEN_LIB_SOURCES markers in src/shuriken.sh, ordered after random and before album.source.sh / stats.source.sh. just build, just test, just shellcheck, just check-generated and git diff --check all pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>