1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
# Shared photo listing and random-pick primitives (task br0). Several modules
# need the same two low-level operations: "list the files in a dist photos
# directory, sorted" and "pick one seeded-random entry from a list". Before this
# module they were re-implemented in album-photo-select, image-pipeline and
# stats-render, each with the same find|sort idiom and the same collect /
# empty-check / random_index / print dance. Centralising them here removes that
# duplication while keeping behaviour identical at every call site.
#
# Home rationale: the consumers live in three otherwise-unrelated subsystems
# (album rendering, the image pipeline, the stats pages), so the helpers do not
# belong to any one of them -- putting them in, say, album-photo-select would
# make image-pipeline depend on album code. This small low-level module depends
# only on random_index (random.source.sh), _display_path (template.source.sh)
# and the $DIST_DIR global, so it is sourced early -- after random/template but
# before image-pipeline / album-* / stats-* -- so every definition precedes its
# uses. All libs are sourced before any code runs.
# List the regular files directly inside "$DIST_DIR/<dir>", one basename per
# line, sorted. This is the canonical replacement for the recurring
# find "$DIST_DIR/<dir>" -maxdepth 1 -type f -printf '%f\n' | sort
# idiom. Stderr is left untouched so callers keep full control: a caller that
# wants the find error on a missing directory gets it, and one that wants it
# suppressed (the stats background loader) adds its own 2>/dev/null. This is the
# SORTED listing; album_photo_files deliberately keeps its own maybe_shuffle
# variant because the album's display order is the configurable shuffle, not a
# plain sort. Uses $FIND (compat.source.sh): -printf is GNU-only, so this must
# run against the resolved GNU find, not whatever "find" plain resolves to on
# macOS/FreeBSD. The trailing plain "sort" is POSIX-portable and left as-is.
list_photos() {
local -r photos_dir="$1"; shift
"$FIND" "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' | sort
}
# Pick one seeded-random entry from an already-collected list, addressed by
# nameref, and print it WITHOUT a trailing newline. The namespace seeds the
# choice so a given RANDOM_SEED yields a stable pick. Returns 1 (printing
# nothing) when the list is empty, leaving the empty/error policy to the caller.
# This is the shared core of pick_random_photo / random_splash_photo /
# _stats_random_background / _stats_pick_background, so the random_index call
# (and thus selection determinism) lives in exactly one place. Each caller keeps
# its own namespace string, so seeding is unchanged from the former inline code.
_pick_random_from_list() {
local -r namespace="$1"; shift
local -n _list_ref="$1"; shift
local -i index
if (( ${#_list_ref[@]} == 0 )); then
return 1
fi
index=$(random_index "$namespace" "${#_list_ref[@]}")
printf '%s' "${_list_ref[index]}"
}
# Pick one seeded-random photo from the sorted listing of "$DIST_DIR/<dir>".
# This is the canonical "random photo" picker (formerly album-render's
# randomphoto): it prints the chosen basename followed by a newline, and on an
# empty directory emits an error and returns 1. The selection namespace is
# "photo:<dir>:<ctx>" (ctx defaults to the directory name), matching the
# historical context exactly so determinism is unchanged.
pick_random_photo() {
local -r photos_dir="$1"; shift
local -r context="${1:-$photos_dir}"
local photo
local -a photos=()
while IFS= read -r photo; do
photos+=("$photo")
done < <(list_photos "$photos_dir")
if (( ${#photos[@]} == 0 )); then
printf 'ERROR: No photos found in %s\n' \
"$(_display_path "$DIST_DIR/$photos_dir")" >&2
return 1
fi
_pick_random_from_list "photo:$photos_dir:$context" photos
printf '\n'
}
|