From 194354a3b42de0b59aa74ff8b5a35a1b7f8f51d6 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Sun, 14 Jun 2026 16:55:08 +0300 Subject: om0 add stats aggregation module Add src/lib/stats.source.sh implementing the aggregation layer for the stats site feature. collect_photo_exif_stats() iterates the album's incoming photos, reads each one's cached identify -verbose output via album.source.sh's cache helper, and fills global STATS_* associative arrays for the camera leaderboard, per-camera photo lists, temporal, exposure, dimension, format and enum stats. Builds exactly the v1 stat set recommended by docs/stats-exif-audit.md (rendering is left to the sibling tasks pm0/rm0/um0). Wire stats.source.sh into the Justfile LIB_SOURCES list (after album, before config) and regenerate bin/shuriken. Add unit tests exercising synthetic identify fixtures, rational/bucket boundaries, DateTimeOriginal substring parsing, missing-field tolerance, and the cached-output path. Co-Authored-By: Claude Opus 4.8 --- src/lib/stats.source.sh | 512 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 512 insertions(+) create mode 100644 src/lib/stats.source.sh (limited to 'src') diff --git a/src/lib/stats.source.sh b/src/lib/stats.source.sh new file mode 100644 index 0000000..2ac2928 --- /dev/null +++ b/src/lib/stats.source.sh @@ -0,0 +1,512 @@ +# Stats aggregation for the album stats page (feature plan: +# /home/paul/.pi/plans/shuriken-stats-site.md, field audit: +# docs/stats-exif-audit.md). This module turns the per-photo +# `identify -verbose` output that album.source.sh already caches into +# aggregated, photographer-friendly counters. +# +# Scope: aggregation only. Rendering (stats.tmpl / camera.tmpl) lives in the +# sibling tasks pm0/rm0/um0; this module just fills the data structures they +# read. +# +# ---------------------------------------------------------------------------- +# Public API / handoff contract +# ---------------------------------------------------------------------------- +# collect_photo_exif_stats iterates the album's photos and fills these globals +# (all declared with `declare -gA` so the render tasks can read them after the +# call without namerefs): +# +# STATS_CAMERAS[] = count (camera leaderboard) +# STATS_CAMERA_SLUGS[] = slug (camera-.html) +# STATS_CAMERA_PHOTOS[] = newline-separated photo filenames +# STATS_LENSES[] = count (sparse; may be empty) +# STATS_YEARS[] = count +# STATS_MONTHS[<01..12>] = count +# STATS_APERTURE[] = count (e.g. "f/2.8") +# STATS_SHUTTER[] = count (e.g. "1/250s") +# STATS_ISO[] = count (e.g. "400") +# STATS_FOCAL[] = count (e.g. "35-70mm") +# STATS_MEGAPIXELS[] = count (e.g. "10-20MP") +# STATS_ASPECT[] = count (e.g. "3:2") +# STATS_ORIENTATION[] = count (Landscape/Portrait/Square) +# STATS_FORMAT[] = count (JPEG/PNG/WEBP/GIF) +# STATS_EXPOSURE_PROGRAM[