summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-05 16:00:58 +0300
committerPaul Buetow <paul@buetow.org>2026-06-05 16:00:58 +0300
commit2b8fc149015c130ce28771d1fff584b8d8b69c75 (patch)
tree01f0542368cfc7f6d216a823ba60d70d54fa0c1c
parentfe35b52c6eb141fc7a92c6407bc44b33464692e3 (diff)
Fix full last-page view redirect wrap-around
-rwxr-xr-xbin/photoalbum47
-rwxr-xr-xsrc/photoalbum.sh47
-rwxr-xr-xtests/cli.sh43
3 files changed, 96 insertions, 41 deletions
diff --git a/bin/photoalbum b/bin/photoalbum
index ef15194..15bc253 100755
--- a/bin/photoalbum
+++ b/bin/photoalbum
@@ -1213,13 +1213,31 @@ render_photo_view_and_details() {
render_view_redirects() {
local -r html_dir="$1"; shift
+ local -i max_page=0
+ local -a prefixes=()
local lastview
local nextredirect
local page
- local prefix
local prevredirect
+ local prefix
+
+ mapfile -t prefixes < <(
+ find "$DIST_DIR/$html_dir" \
+ -maxdepth 1 \
+ -regextype posix-egrep \
+ -regex '.*/[0-9]+-[0-9]+\.html' \
+ -printf '%f\n' \
+ | cut -d'-' -f1 \
+ | sort -n -u
+ )
+
+ if (( ${#prefixes[@]} == 0 )); then
+ return
+ fi
+
+ max_page=${prefixes[$(( ${#prefixes[@]} - 1 ))]}
- while IFS= read -r prefix; do
+ for prefix in "${prefixes[@]}"; do
page="$prefix"
lastview=$(last_view_number "$page" "$html_dir")
@@ -1230,27 +1248,19 @@ render_view_redirects() {
html_dir "$html_dir" \
redirect_page "$(( page - 1 ))-${MAXPREVIEWS}"
- if (( lastview == MAXPREVIEWS )); then
- template redirect "$nextredirect.html" \
- html_dir "$html_dir" \
- redirect_page "$(( page + 1 ))-1"
- else
+ if (( page == max_page )); then
template redirect "0-$MAXPREVIEWS.html" \
html_dir "$html_dir" \
redirect_page "${page}-$lastview"
template redirect "$nextredirect.html" \
html_dir "$html_dir" \
redirect_page '1-1'
+ else
+ template redirect "$nextredirect.html" \
+ html_dir "$html_dir" \
+ redirect_page "$(( page + 1 ))-1"
fi
- done < <(
- find "$DIST_DIR/$html_dir" \
- -maxdepth 1 \
- -regextype posix-egrep \
- -regex '.*/[0-9]+-[0-9]+\.html' \
- -printf '%f\n' \
- | cut -d'-' -f1 \
- | sort -u
- )
+ done
}
render_album_index_redirect() {
@@ -1609,10 +1619,7 @@ dry_run() {
if (( image_count > 0 )); then
details_count=$image_count
page_count=$(( (image_count + MAXPREVIEWS - 1) / MAXPREVIEWS ))
- redirect_count=$(( page_count * 2 ))
- if (( image_count % MAXPREVIEWS != 0 )); then
- (( ++redirect_count ))
- fi
+ redirect_count=$(( page_count * 2 + 1 ))
fi
printf 'Dry run: no files will be written.\n'
diff --git a/src/photoalbum.sh b/src/photoalbum.sh
index 7d75d1c..965dd27 100755
--- a/src/photoalbum.sh
+++ b/src/photoalbum.sh
@@ -1213,13 +1213,31 @@ render_photo_view_and_details() {
render_view_redirects() {
local -r html_dir="$1"; shift
+ local -i max_page=0
+ local -a prefixes=()
local lastview
local nextredirect
local page
- local prefix
local prevredirect
+ local prefix
+
+ mapfile -t prefixes < <(
+ find "$DIST_DIR/$html_dir" \
+ -maxdepth 1 \
+ -regextype posix-egrep \
+ -regex '.*/[0-9]+-[0-9]+\.html' \
+ -printf '%f\n' \
+ | cut -d'-' -f1 \
+ | sort -n -u
+ )
+
+ if (( ${#prefixes[@]} == 0 )); then
+ return
+ fi
+
+ max_page=${prefixes[$(( ${#prefixes[@]} - 1 ))]}
- while IFS= read -r prefix; do
+ for prefix in "${prefixes[@]}"; do
page="$prefix"
lastview=$(last_view_number "$page" "$html_dir")
@@ -1230,27 +1248,19 @@ render_view_redirects() {
html_dir "$html_dir" \
redirect_page "$(( page - 1 ))-${MAXPREVIEWS}"
- if (( lastview == MAXPREVIEWS )); then
- template redirect "$nextredirect.html" \
- html_dir "$html_dir" \
- redirect_page "$(( page + 1 ))-1"
- else
+ if (( page == max_page )); then
template redirect "0-$MAXPREVIEWS.html" \
html_dir "$html_dir" \
redirect_page "${page}-$lastview"
template redirect "$nextredirect.html" \
html_dir "$html_dir" \
redirect_page '1-1'
+ else
+ template redirect "$nextredirect.html" \
+ html_dir "$html_dir" \
+ redirect_page "$(( page + 1 ))-1"
fi
- done < <(
- find "$DIST_DIR/$html_dir" \
- -maxdepth 1 \
- -regextype posix-egrep \
- -regex '.*/[0-9]+-[0-9]+\.html' \
- -printf '%f\n' \
- | cut -d'-' -f1 \
- | sort -u
- )
+ done
}
render_album_index_redirect() {
@@ -1609,10 +1619,7 @@ dry_run() {
if (( image_count > 0 )); then
details_count=$image_count
page_count=$(( (image_count + MAXPREVIEWS - 1) / MAXPREVIEWS ))
- redirect_count=$(( page_count * 2 ))
- if (( image_count % MAXPREVIEWS != 0 )); then
- (( ++redirect_count ))
- fi
+ redirect_count=$(( page_count * 2 + 1 ))
fi
printf 'Dry run: no files will be written.\n'
diff --git a/tests/cli.sh b/tests/cli.sh
index b58610c..e4a94a6 100755
--- a/tests/cli.sh
+++ b/tests/cli.sh
@@ -1388,7 +1388,7 @@ test_dry_run_reports_cli_overrides_without_writes() {
" $dist_dir/[page]-[image]-details.html (6 details pages)" \
"$output"
test::assert_contains \
- " $dist_dir/[redirect].html (6 navigation redirects)" \
+ " $dist_dir/[redirect].html (7 navigation redirects)" \
"$output"
test::assert_not_contains "$dist_dir/html" "$output"
test::assert_contains " $dist_dir/incoming-<timestamp>.tar" "$output"
@@ -1945,6 +1945,44 @@ test_render_view_redirects_uses_numeric_last_view() {
test::teardown
}
+test_render_view_redirects_wraps_when_last_page_full() {
+ local dist_dir
+ local html_dir
+ local next_redirect_html
+ local prev_redirect_html
+ local view
+
+ test::setup
+ dist_dir="$TEST_TMPDIR/dist"
+ html_dir='.'
+ mkdir -p "$dist_dir"
+
+ # shellcheck source=/dev/null
+ source <(sed '$d' "$TEST_PHOTOALBUM")
+
+ export DIST_DIR="$dist_dir"
+ export TEMPLATE_DIR="$TEST_REPO_ROOT/share/templates/default"
+ export PHOTOALBUM_OUTPUT_MODE=quiet
+ export MAXPREVIEWS=2
+
+ for view in 1 2; do
+ : > "$dist_dir/1-$view.html"
+ : > "$dist_dir/2-$view.html"
+ : > "$dist_dir/3-$view.html"
+ done
+
+ render_view_redirects "$html_dir"
+
+ test::assert_file_exists "$dist_dir/0-2.html"
+ test::assert_file_exists "$dist_dir/3-3.html"
+ prev_redirect_html=$(<"$dist_dir/0-2.html")
+ next_redirect_html=$(<"$dist_dir/3-3.html")
+ test::assert_contains 'url=3-2.html' "$prev_redirect_html"
+ test::assert_contains 'url=1-1.html' "$next_redirect_html"
+ test::assert_path_absent "$dist_dir/4-1.html"
+ test::teardown
+}
+
test_generate_config_no_splash_keeps_index_redirect() {
local config_file
local fake_bin
@@ -2808,6 +2846,9 @@ main() {
'view redirects use numeric last view' \
test_render_view_redirects_uses_numeric_last_view
test::run_case \
+ 'view redirects wrap when last page is full' \
+ test_render_view_redirects_wraps_when_last_page_full
+ test::run_case \
'--generate SPLASH_PAGE=no keeps root index redirect' \
test_generate_config_no_splash_keeps_index_redirect
test::run_case \