summaryrefslogtreecommitdiff
path: root/src/lib/stats.source.sh
AgeCommit message (Collapse)Author
2026-06-16cn0 split stats.source.sh into aggregate/render/filter-album modulesPaul Buetow
Pure code move: split the ~1248-line stats.source.sh (SRP+SoC) into three cohesive modules, all functions and STATS_* constants/globals moved verbatim: - stats-aggregate.source.sh: EXIF parsing, bucketing, _stats_tally, reset/collect_photo_exif_stats and the STATS_* maps. - stats-render.source.sh: stats overview page (sections, bars, leaderboard, render_stats_page, _stats_build_body, _stats_filter_link, background pickers). - stats-filter-album.source.sh: per-filter mini-albums (render_filter_pages, gallery/view/thumbnail builders, _stats_enqueue_filter_album). Updated LIB_SOURCES accordingly. No logic change (verified: all 55 functions and top-level globals preserved; full suite, shellcheck, check-generated, diff all pass). The SoC point (HTML built in bash rather than templates) is left for a follow-up (nn0/qn0). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15Stats backgrounds: fit the category instead of album-wide randomPaul Buetow
The filter mini-album pages all drew their blurred background from the whole album, so a filter page's background did not relate to its category. Mirror the main album instead: - A filter gallery's background is now a random photo from THAT filter's own set (like the album preview pages pick a random album photo). - A filter view page's background is the photo it shows (like the album view pages). - The stats overview still uses a random album-wide photo. Adds _stats_pick_background (random pick from a filter's photo list) and drops the now-unused album-wide background preload from render_filter_pages. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15Move the stats site into a stats/ subdir to keep the album root smallPaul Buetow
The filter mini-albums put thousands of HTML files directly in the album root. Reorganise so only the main album lives in DIST_DIR and all stats content goes under stats/: stats/index.html - the stats overview (was stats.html) stats/<pagebase>/index.html - each filter gallery (was <pagebase>.html) stats/<pagebase>/<index>.html - each filter view page (was <pagebase>--N.html) Each mini-album is its own directory, so no single directory holds more than one filter's pages. Links updated accordingly: the overview links to <pagebase>/, the gallery thumbnails link to sibling <index>.html, view prev/next/gallery are same-dir, and assets/album-details/back-to-stats resolve via the ../.. backhref. The header Stats link and camera.tmpl back link point at stats/index.html. Mini-albums still reuse the shared photos/thumbs/blurs assets and render in parallel. Tests and the dry-run plan updated for the new layout; README documents the stats/ subdirectory structure. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15Cache the background photo list for filter pagesPaul Buetow
_stats_random_background scanned the photos directory once per page; with a filter mini-album per stat bucket that is thousands of scans. Load the sorted photo list once into a global (STATS_BG_PHOTOS) that render_filter_pages populates before forking the render jobs, so each background subshell inherits the cached array and just indexes into it. The seeded pick is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15Make every stat bucket a clickable filter mini-album, rendered in parallelPaul Buetow
Generalises the per-camera mini-albums to every stats category: clicking any row on the stats page (camera, lens, year, month, aperture, shutter, ISO, focal length, megapixels, aspect, orientation, format, exposure program, metering, white balance, flash) now opens a filter mini-album of just the matching photos, with view pages whose prev/next cycle within the filter. Aggregation: a single _stats_tally now records, for every tallied bucket, the bucket's photo list and a unique filename-safe "pagebase" (camera-canon-eos-r5, iso-400, year-2023, ...) with collision resolution, exposed via STATS_FILTER_* maps. The old camera-only STATS_CAMERA_SLUGS/PHOTOS/SLUG_OWNERS are gone. Render: every bar/leaderboard row is wrapped in a link to its bucket's pagebase via _stats_filter_link. render_filter_pages replaces render_camera_pages and renders ALL filter mini-albums (gallery + per-photo view pages) reusing camera.tmpl/cameraview.tmpl. The galleries/view pages reuse the album's shared photos/thumbs/blurs assets -- only the HTML differs. Parallelism: filter pages render through the shared job pool, throttled to IMAGE_JOBS (the same pool the album view pages use). The album render warms every photo's EXIF cache (via details pages) before the parallel filter render, so the filter jobs only read the cache. Tests updated for the new STATS_FILTER_* structures and extended to assert non-camera filter mini-albums (orientation, ISO) and their stats-page links. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15Per-camera mini-albums: full-width grid + camera-scoped view navigationPaul Buetow
Two fixes to the per-camera pages: - The camera thumbnail grid is now full-width and reflows with the window like the main album. Previously it sat inside the 900px-wide stats column, so wide thumbnails only fit ~2 per row. camera.tmpl now puts the grid in a full-width sibling block (centered by the body, like the album's direct thumbnail children); the heading/back-link stay in the narrow stats column. - Each camera is now a self-contained mini album. Thumbnails link to per-camera view pages (camera-<slug>--<index>.html) whose prev/next cycle only through that camera's photos, instead of linking into the shared album view pages (where next/prev walked the whole album and left the camera). The view pages reuse the album's look (blurred background, EXIF tooltip, animation) and offer Gallery / Details (to the album details page) / Direct-link nav. The "--" index separator can never collide with a gallery name since slugs never contain "--". Adds cameraview.tmpl + its render field, _stats_render_camera_{gallery,views} and the cameraview body builders. Tests updated for the new thumbnail links and extended to assert the per-camera view pages and their camera-scoped navigation; required-context-vars test now also covers the camera and cameraview templates. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15Stats/camera pages: blurred background, album-like camera thumbs, spacingPaul Buetow
Three refinements to the stats site: - Stats and per-camera pages now get a random blurred background image (same seeded pick the album preview pages use) instead of a plain black page. Adds _stats_random_background + STATS_BLURS_DIR; falls back to black when no photos exist (e.g. isolated unit tests). - Per-camera thumbnails now behave like the main album: they link to each photo's album view page (navigation, details, EXIF tooltip) and carry the same seeded animation class, instead of linking to the raw image. render_album_pages records a photo -> "<page>-<preview>" map (ALBUM_VIEW_PAGE_BY_PHOTO) that the camera pages read; photos with no recorded view page fall back to the image. - Spacing: the camera leaderboard rows get padding + a separator line so the long wrapping camera names are distinguishable, and the stats sections, headings, bar rows, back-link, and camera grid get moderate extra spacing so nothing looks cramped. Tests updated for the new camera-thumbnail markup and extended to assert the stats background and the album view-page links; camera.tmpl comment corrected. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14um0 add per-camera filter pagesPaul Buetow
Implement render_camera_pages <html_dir> <backhref> in stats.source.sh: one camera-<slug>.html per camera in STATS_CAMERA_SLUGS, reusing the aggregation's collision-resolved slugs and per-camera photo lists so filenames match pm0's leaderboard links. Each page reuses the shared header/footer chrome plus a new camera.tmpl that renders an HTML-escaped camera heading, a pre-built thumbnail grid, and a back-to-stats link. Thumbnails reuse preview.tmpl's markup style (thumb image from thumbs/) but link to the full-size image under photos/ rather than a per-photo view page, since the view-page name is not derivable outside the album pagination loop. The photos and thumbs dir names are fixed to match generate()'s render_album_pages call. Cameras are walked in LC_ALL=C label order for reproducible output, and cameras with no recorded photos are skipped. Adds the camera_name/camera_thumbs render field specs and a tests/cli.sh case covering per-camera files, slug collisions, HTML escaping, thumbnail link targets, and determinism. This provides the function + template + tests only; wiring into generate() and the STATS_PAGE toggle remain for rm0. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14pm0 pin leaderboard sort collation for reproducible outputPaul Buetow
Review follow-up: _stats_keys_by_count_desc sorted the count tie-break under the caller's locale, so the generated stats page could differ byte-for-byte across locales/machines. Pin the sort with LC_ALL=C to keep the static output reproducible, consistent with the project's seeded / deterministic generation behavior. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14pm0 add stats page template and render functionPaul Buetow
Render the aggregated STATS_* counters from the om0 module into a static stats.html. render_stats_page builds the variable-length body (camera leaderboard, temporal/exposure/dimension histograms, format and enum breakdowns) as HTML and hands it to the new stats.tmpl through a raw context field, wrapping it with the shared header/footer the way view/details pages do. Bars are pure CSS so the page stays JavaScript-free. - new template share/templates/default/stats.tmpl (page chrome + body) - render_stats_page <html_dir> <backhref> [page_name] plus small section builders in src/lib/stats.source.sh; EXIF-derived labels are HTML-escaped - new TEMPLATE_RENDER_FIELD_SPECS field render_stats_body_html (context_raw) and 'stats' added to render_backhref_html's required list - camera leaderboard entries link to camera-<slug>.html (um0 owns those) - Stats nav link wired into the shared header bar - tests cover leaderboard links, counts/percentages, a histogram section, &/< escaping, and omission of empty categories Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14om0 fix camera slug collisions and align ISO fallback orderPaul Buetow
Review follow-up on the stats aggregation module: - Distinct camera labels that sanitized to the same slug (e.g. two models differing only in punctuation) shared one STATS_CAMERA_PHOTOS list and one camera-<slug>.html link, so um0 would render a merged/ambiguous per-camera page. Add _stats_resolve_camera_slug, which uniquifies colliding slugs with a numeric suffix and tracks ownership in a new STATS_SLUG_OWNERS reverse map. It returns via a nameref (not command substitution) so the global mutation persists in the caller's shell. - Align the stats ISO fallback order with album.source.sh's tooltip builder (ISOSpeedRatings -> PhotographicSensitivity -> ISO) so a photo with multiple ISO tags buckets the same value it displays. - Document that the format breakdown trusts the file extension. - Add test_stats_distinct_cameras_get_unique_slugs covering the collision fix and slug reuse on re-encounter. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-14om0 add stats aggregation modulePaul Buetow
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 <noreply@anthropic.com>