| Age | Commit message (Collapse) | Author |
|
Adds a new yes/no config setting (default no, preserving current behavior)
that orders the main album's photos by EXIF date taken (ascending) instead
of the default filename/shuffle order. Reuses the existing EXIF cache and
tag fallback chain (DateTimeOriginal -> DateTimeDigitized -> DateTime)
already used for tooltips/details/stats, so ordering never disagrees with
what those features show. Photos with no usable EXIF date fall back to
their source file's mtime, staying fully deterministic and crash-free.
CHRONOLOGICAL_ORDER takes precedence over SHUFFLE when both are enabled,
documented in album-photo-select.source.sh and docs/configuration.md.
Wired through the config registry (CONFIG_SPECS), validation, CLI flags
(--chronological/--no-chronological), --print-config, --dry-run,
--verbose logging, and shuriken.json generation metadata. Adds unit and
end-to-end tests covering default-off behavior, EXIF-date ordering with
shuffle precedence, and mtime fallback for EXIF-less photos.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
|
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>
|
|
Running `bash src/shuriken.sh --generate ...` directly from a source
checkout printed "command not found" for camera_label_from_make_model,
photo_exif_values_to and cached_photo_identify_output for every photo,
silently emptying EXIF tooltips/details and, with STATS_PAGE=yes,
omitting the whole stats/ tree. The hand-maintained source list inside
the SHURIKEN_LIB_SOURCES_BEGIN/END marker block had drifted from the
authoritative Justfile LIB_SOURCES, missing metadata-label,
metadata-cache, stats-aggregate, stats-render and stats-filter-album.
`just build` replaces the marker block with LIB_SOURCES when generating
bin/shuriken, so the installed binary and the bin-based test suite never
noticed; only direct src execution was affected.
- Add the 5 missing `source` lines to the marker block in the same order
as Justfile LIB_SOURCES, so the two lists now match exactly.
- Add tests/cli.sh case test_lib_sources_match_justfile_lib_sources that
extracts the marker-block module names and asserts they equal the
Justfile LIB_SOURCES (same set and order) to prevent future drift.
- shellcheck --check-sourced now follows the 5 newly-sourced libs;
suppress the cross-module nameref false positives (SC2178/SC2128/
SC2154) with explained directives and genuinely fix SC2004
(counts_ref[$key] -> [key]) and quote the TITLE default (${TITLE:-}).
bin/shuriken changes only by these propagated lib edits; the marker-block
source list it generates is unchanged.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
Make the template.source.sh escape/date helper family follow one
consistent shape: each escaper now has a nameref <name>_to form (hot
path, writes a named variable) plus a thin printf wrapper <name> that
delegates to it. The leading "_" now exclusively marks private
helpers; the public escape API (called from sibling modules) is
unprefixed.
- current_date_text now delegates to current_date_text_to so both
forms share the SHURIKEN_CURRENT_DATE_TEXT cache; the printf form no
longer silently re-execs `date` on every direct call. Output
unchanged.
- Drop the misleading "_" prefix on the public escape API and update
all callers: _html_escape->html_escape, _css_string_escape->
css_string_escape, _json_string->json_string, _json_bool->json_bool,
_json_string_escape->json_string_escape.
- Add the missing JSON nameref forms: json_string_escape_to,
json_string_to, json_bool_to (printf wrappers delegate to them).
- Add tests: JSON printf-vs-nameref parity and a current_date_text
caching + nameref-parity check.
No escaping/encoding or date output changes -- API-shape/perf only.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
album-metadata.source.sh aggregated six unrelated concerns. Move each
along its existing seam (pure mechanical move, no logic changes):
- EXIF presentation (photo_exif_details_html, tooltip helpers, the
_photo_exif_values_to wrapper) stays in album-metadata.source.sh,
which is now EXIF-presentation only.
- File counting (count_files, count_incoming_images, count_tree_files)
-> image.source.sh, which already owns incoming_image_files;
count_incoming_images is a direct wrapper of it.
- Tarball naming (tarball_name_plan, generated_tarball_name) ->
archive.source.sh, which already owns tarball()/resolve_tar_opts.
- Generation metadata + JSON (_collect_generation_metadata,
_generation_metadata_json, write_generation_metadata) -> new
generation-metadata.source.sh.
- Dry-run (dry_run, collect_dry_run_*, print_dry_run_plan) -> new
dry-run.source.sh.
- clear_exif_cache -> metadata-cache.source.sh, next to the cache
primitive cached_photo_identify_output.
LIB_SOURCES (Justfile + src/shuriken.sh): insert generation-metadata
and dry-run right after album-metadata, before album-render/album.
They depend on image, archive, template and metadata-cache (all earlier
or runtime-only calls), and are consumed by the album coordinator and
the dry-run CLI action, which come later. bin/shuriken regenerated via
just build. File-header comments updated to reflect the new homes.
just test, just shellcheck, just check-generated and git diff --check
all pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
The `identify -verbose` EXIF-line regex and its array-fill loop were
duplicated in three places that had already drifted: album-metadata's
photo_exif_details_html and _photo_exif_values_to (exif: only) and
stats-aggregate's _stats_parse_identify_stream (exif: plus a native
Geometry -> __geometry path).
Promote one canonical parser, photo_exif_values_to, into
metadata-cache.source.sh next to its sibling cache primitive
cached_photo_identify_output. It reads an identify stream from stdin and
fills a nameref associative array; it is a strict superset of all three
former sites (bare exif: tag keys plus the synthetic __geometry key).
- stats accumulate_photo_stats now calls photo_exif_values_to (stdin);
_stats_parse_identify_stream is removed.
- album _photo_exif_values_to is a thin wrapper that pipes
cached_photo_identify_output through the canonical parser.
- album photo_exif_details_html consumes the same parser and skips the
__geometry key it does not display.
metadata-cache is sourced before both consumers in LIB_SOURCES, so the
canonical parser is available at use time. Regenerated bin/shuriken via
`just build`. Added test_shared_identify_parser_returns_exif_and_geometry
asserting one parse yields both an exif: key and __geometry.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
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>
|
|
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>
|
|
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>
|
|
The rule that joins a camera's EXIF Make + Model into one label while
avoiding a duplicated manufacturer prefix (e.g. "Canon Canon EOS 5D" ->
"Canon EOS 5D") was implemented independently in the album tooltip builder
and the stats leaderboard tally. Extract it into a single shared helper
camera_label_from_make_model in the new src/lib/metadata-label.source.sh,
sourced before both callers.
Both prior implementations were behavior-identical (empty model -> make,
empty make -> model, exact/prefix dedup, case-sensitive), so this is a pure
DRY refactor with no observable output change. Added a focused unit test
covering dedup, plain concatenation and the empty-field edge cases.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
cached_photo_identify_output() swallowed all ImageMagick errors with
'imagemagick_identify ... || true', so a corrupt photo or identify
failure left the cache with only the signature line and no EXIF. That
signature-only file was a valid-looking cache hit, so the photo rendered
with empty tooltip/stats and the failure was never retried or warned
about again.
Now capture identify's exit status; on failure, log_warning naming the
photo and rm -f the cache file so the next run retries instead of
reusing an empty result. The function still returns 0 so one unreadable
photo does not abort generation (it runs in backgrounded render jobs
under set -euo pipefail) -- the photo just renders without EXIF, now
with a warning.
Adds tests/cli.sh test_generate_warns_and_skips_cache_on_identify_failure
and a TEST_IMAGEMAGICK_IDENTIFY_FAIL hook in the fake ImageMagick to
drive a failing identify; asserts exit 0, a warning naming the photo,
the photo still rendered, and that the failed photo's cache is absent
while a successful photo's cache is present.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
|
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>
|