From 2b8fc149015c130ce28771d1fff584b8d8b69c75 Mon Sep 17 00:00:00 2001 From: Paul Buetow Date: Fri, 5 Jun 2026 16:00:58 +0300 Subject: Fix full last-page view redirect wrap-around --- bin/photoalbum | 47 +++++++++++++++++++++++++++-------------------- src/photoalbum.sh | 47 +++++++++++++++++++++++++++-------------------- tests/cli.sh | 43 ++++++++++++++++++++++++++++++++++++++++++- 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-.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 @@ -2807,6 +2845,9 @@ main() { test::run_case \ '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 -- cgit v1.2.3