summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/album-metadata.source.sh64
-rw-r--r--src/lib/metadata-cache.source.sh38
-rw-r--r--src/lib/stats-aggregate.source.sh28
3 files changed, 81 insertions, 49 deletions
diff --git a/src/lib/album-metadata.source.sh b/src/lib/album-metadata.source.sh
index b74bf8f..767ec4c 100644
--- a/src/lib/album-metadata.source.sh
+++ b/src/lib/album-metadata.source.sh
@@ -8,31 +8,40 @@
photo_exif_details_html() {
local -r photo="$1"; shift
local -r photo_path="$1"; shift
+ # exif_values is filled via the shared parser and iterated below.
+ # shellcheck disable=SC2034
+ local -A exif_values=()
local key
local key_html
- local line
local value
local value_html
local -i exif_count=0
- while IFS= read -r line; do
- if [[ "$line" =~ ^[[:space:]]*exif:([^:]+):[[:space:]]*(.*)$ ]]; then
- key="exif:${BASH_REMATCH[1]}"
- value="${BASH_REMATCH[2]}"
- key_html=$(_html_escape "$key")
- value_html=$(_html_escape "$value")
-
- if (( exif_count == 0 )); then
- printf '<table class="details">\n'
- printf '<tbody>\n'
- fi
-
- printf '<tr><th>%s</th><td>%s</td></tr>\n' \
- "$key_html" \
- "$value_html"
- (( ++exif_count ))
+ # Parse via the single canonical reader/parser (task 8r0) instead of a
+ # private exif: regex loop. The parser also yields a synthetic __geometry key
+ # from the native Geometry line; the details table only shows real exif: tags
+ # (rendered with their historical "exif:" label prefix), so __geometry is
+ # skipped explicitly below.
+ _photo_exif_values_to exif_values "$photo" "$photo_path"
+
+ for key in "${!exif_values[@]}"; do
+ if [ "$key" = '__geometry' ]; then
+ continue
+ fi
+ value="${exif_values[$key]}"
+ key_html=$(_html_escape "exif:$key")
+ value_html=$(_html_escape "$value")
+
+ if (( exif_count == 0 )); then
+ printf '<table class="details">\n'
+ printf '<tbody>\n'
fi
- done < <(cached_photo_identify_output "$photo" "$photo_path")
+
+ printf '<tr><th>%s</th><td>%s</td></tr>\n' \
+ "$key_html" \
+ "$value_html"
+ (( ++exif_count ))
+ done
if (( exif_count == 0 )); then
printf '<p class="details-empty">No EXIF details available.</p>\n'
@@ -58,20 +67,19 @@ _first_exif_value_to() {
done
}
+# Fill the caller's associative array with a photo's parsed EXIF values. Thin
+# wrapper that pairs the shared cache reader with the shared stream parser
+# (photo_exif_values_to, promoted to metadata-cache.source.sh in task 8r0): it
+# reads the cached identify output for this photo and pipes it through the one
+# canonical parser. The parser also captures a __geometry key, which album code
+# simply ignores.
_photo_exif_values_to() {
- local -n output_ref="$1"; shift
+ local -r target_array="$1"; shift
local -r photo="$1"; shift
local -r photo_path="$1"; shift
- local line
- output_ref=()
- while IFS= read -r line; do
- if [[ "$line" =~ ^[[:space:]]*exif:([^:]+):[[:space:]]*(.*)$ ]]; then
- # output_ref writes to the caller-provided associative array.
- # shellcheck disable=SC2034
- output_ref["${BASH_REMATCH[1]}"]="${BASH_REMATCH[2]}"
- fi
- done < <(cached_photo_identify_output "$photo" "$photo_path")
+ photo_exif_values_to "$target_array" \
+ < <(cached_photo_identify_output "$photo" "$photo_path")
}
_photo_exif_tooltip_text_from_values() {
diff --git a/src/lib/metadata-cache.source.sh b/src/lib/metadata-cache.source.sh
index 45edd3c..ba40ca9 100644
--- a/src/lib/metadata-cache.source.sh
+++ b/src/lib/metadata-cache.source.sh
@@ -102,3 +102,41 @@ cached_photo_identify_output() {
print_cached_photo_identify_output "$cache_file"
}
+
+# Canonical `identify -verbose` stream parser. Reads an identify stream from
+# stdin and fills the caller-provided associative array (by nameref) with one
+# entry per recognised field. Promoted here (task 8r0) from three near-identical
+# copies that had already drifted -- album-metadata had two exif:-only loops and
+# stats-aggregate added a native Geometry path. This single definition is a
+# strict superset of all three: it lives next to cached_photo_identify_output so
+# both the album (tooltips, details tables) and the stats aggregator share one
+# regex and one set of key conventions, isolating any future identify-format
+# drift to one place.
+#
+# Keys produced:
+# - exif:* lines -> stored under the bare tag name (e.g. "Make", "FNumber"),
+# i.e. WITHOUT the leading "exif:" -- callers that want the prefixed label
+# (the details table) re-add it. This matches the historical album and stats
+# array keys exactly.
+# - the native Geometry line ("WxH+x+y") -> stored under the synthetic key
+# "__geometry"; stats reads this for dimension tallies, album ignores it.
+#
+# Reads from stdin (not from a photo path) so it composes with the cache layer:
+# stats pipes a fixture or cache stream straight in, while album wraps it with
+# `photo_exif_values_to ref < <(cached_photo_identify_output ...)`.
+photo_exif_values_to() {
+ local -n output_ref="$1"; shift
+ local line
+
+ output_ref=()
+ while IFS= read -r line; do
+ if [[ "$line" =~ ^[[:space:]]*exif:([^:]+):[[:space:]]*(.*)$ ]]; then
+ # output_ref writes to the caller-provided associative array.
+ # shellcheck disable=SC2034
+ output_ref["${BASH_REMATCH[1]}"]="${BASH_REMATCH[2]}"
+ elif [[ "$line" =~ ^[[:space:]]*Geometry:[[:space:]]*(.*)$ ]]; then
+ # shellcheck disable=SC2034
+ output_ref[__geometry]="${BASH_REMATCH[1]}"
+ fi
+ done
+}
diff --git a/src/lib/stats-aggregate.source.sh b/src/lib/stats-aggregate.source.sh
index 6b30f62..77603c5 100644
--- a/src/lib/stats-aggregate.source.sh
+++ b/src/lib/stats-aggregate.source.sh
@@ -499,8 +499,8 @@ _stats_record_enums() {
# Record dimension stats (megapixels, aspect ratio, orientation) from the native
# Geometry field. Geometry is "WxH+x+y"; the leading WxH is what we need. These
-# are native fields, not exif: lines, so they come from the separate native
-# parser path in _stats_parse_identify_stream.
+# are native fields, not exif: lines, so they come from the native Geometry
+# (__geometry) path in the shared photo_exif_values_to parser.
_stats_record_dimensions() {
local -n values_ref="$1"; shift
local -r photo="$1"; shift
@@ -618,24 +618,6 @@ _stats_tally() {
fi
}
-# Parse one photo's `identify -verbose` stream into an associative array. The
-# current album.source.sh regex only captures exif: lines, but the audit needs
-# the native Geometry field for dimensions, so this adds a second match path
-# storing it under the synthetic key __geometry.
-_stats_parse_identify_stream() {
- local -n values_ref="$1"; shift
- local line
-
- values_ref=()
- while IFS= read -r line; do
- if [[ "$line" =~ ^[[:space:]]*exif:([^:]+):[[:space:]]*(.*)$ ]]; then
- values_ref["${BASH_REMATCH[1]}"]="${BASH_REMATCH[2]}"
- elif [[ "$line" =~ ^[[:space:]]*Geometry:[[:space:]]*(.*)$ ]]; then
- values_ref[__geometry]="${BASH_REMATCH[1]}"
- fi
- done
-}
-
# Aggregate a single photo: parse its identify stream (from stdin) and update
# every counter. Split out from collect_photo_exif_stats so tests can feed a
# synthetic fixture without stubbing the cache layer.
@@ -646,7 +628,11 @@ accumulate_photo_stats() {
local -A exif_values=()
local record_fn
- _stats_parse_identify_stream exif_values
+ # Parse the identify stream from stdin via the single canonical parser
+ # (photo_exif_values_to, promoted to metadata-cache.source.sh in task 8r0).
+ # It captures both exif: tags and the native Geometry line under __geometry,
+ # which _stats_record_dimensions consumes.
+ photo_exif_values_to exif_values
STATS_TOTALS[photos]=$(( STATS_TOTALS[photos] + 1 ))
# Dispatch the EXIF-driven recorders from the registry list so categories are
# not hardcoded here. Each takes the parsed values array plus the photo path.