summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-05 00:25:18 +0300
committerPaul Buetow <paul@buetow.org>2026-06-05 00:25:18 +0300
commit3cf33952612d27f48258d4084f5d651d01931613 (patch)
treee5fa62339e34db2a8084834eec9bbdac77c82699
parentbba997dffebb35792165c5aebb4b1a1893f21422 (diff)
Add splash page support for task 8j0
-rw-r--r--README.md29
-rwxr-xr-xbin/photoalbum83
-rw-r--r--share/templates/default/splash.tmpl78
-rw-r--r--src/photoalbum.default.conf2
-rwxr-xr-xsrc/photoalbum.sh83
-rwxr-xr-xtests/cli.sh118
-rwxr-xr-xtests/helpers.sh1
7 files changed, 374 insertions, 20 deletions
diff --git a/README.md b/README.md
index b828b48..13d25df 100644
--- a/README.md
+++ b/README.md
@@ -68,7 +68,7 @@ missing, run `photoalbum --init` first.
The config file is a Bash file with assignments such as `INCOMING_DIR`,
`DIST_DIR`, `TEMPLATE_DIR`, `TITLE`, `HEIGHT`, `THUMBHEIGHT`, `MAXPREVIEWS`,
-`RANDOM_SEED`, `SHUFFLE`, and `TARBALL_INCLUDE`.
+`RANDOM_SEED`, `SHUFFLE`, `SPLASH_PAGE`, and `TARBALL_INCLUDE`.
Before generating, `photoalbum` validates the loaded config and command-line
overrides. It checks required values, positive integer settings, `yes`/`no`
@@ -87,11 +87,12 @@ tarball filename uses `<timestamp>` as a placeholder so the output is stable.
`--print-config` writes stable shell-style assignments to stdout in this order:
`CONFIG_SOURCE`, `INCOMING_DIR`, `DIST_DIR`, `TEMPLATE_DIR`, `TITLE`, `HEIGHT`,
-`THUMBHEIGHT`, `MAXPREVIEWS`, `RANDOM_SEED`, `SHUFFLE`, `TARBALL_INCLUDE`,
-`TARBALL_SUFFIX`, `TAR_OPTS`, and `ORIGINAL_BASEPATH`. Scalar values use Bash
-`%q` quoting and `TAR_OPTS` is normalized to a Bash array assignment, so the
-output can be parsed by shell tooling. `--quiet` does not suppress this output,
-and `--verbose` does not add human-readable diagnostics to it.
+`THUMBHEIGHT`, `MAXPREVIEWS`, `RANDOM_SEED`, `SHUFFLE`, `SPLASH_PAGE`,
+`TARBALL_INCLUDE`, `TARBALL_SUFFIX`, `TAR_OPTS`, and `ORIGINAL_BASEPATH`.
+Scalar values use Bash `%q` quoting and `TAR_OPTS` is normalized to a Bash array
+assignment, so the output can be parsed by shell tooling. `--quiet` does not
+suppress this output, and `--verbose` does not add human-readable diagnostics to
+it.
Successful generation writes `photoalbum.json` into the output directory. This
metadata records the generator version and timestamp, config source, template
@@ -112,14 +113,20 @@ The following long options override config values:
| `--random-seed VALUE` | `RANDOM_SEED` |
| `--shuffle` | `SHUFFLE=yes` |
| `--no-shuffle` | `SHUFFLE=no` |
+| `--splash` | `SPLASH_PAGE=yes` |
+| `--no-splash` | `SPLASH_PAGE=no` |
| `--tarball` | `TARBALL_INCLUDE=yes` |
| `--no-tarball` | `TARBALL_INCLUDE=no` |
-By default, background photos, animation classes, generated timestamps, and
-`--shuffle` preview order remain non-deterministic. Set `RANDOM_SEED` in the
-config, or pass `--random-seed VALUE`, to make those choices repeatable for
-stable tests or reproducible album builds. Use the same seed and inputs to
-produce the same HTML.
+By default, the generated root `index.html` is a no-JavaScript splash page using
+a randomly selected album photo. Set `SPLASH_PAGE=no` or pass `--no-splash` to
+restore the top-level redirect to `page-1.html`.
+
+By default, splash and background photos, animation classes, generated
+timestamps, and `--shuffle` preview order remain non-deterministic. Set
+`RANDOM_SEED` in the config, or pass `--random-seed VALUE`, to make those
+choices repeatable for stable tests or reproducible album builds. Use the same
+seed and inputs to produce the same HTML.
`--dry-run` and `--print-config` accept the same override options as
`--generate`. `--clean` accepts the same override options, but only `--dist`
diff --git a/bin/photoalbum b/bin/photoalbum
index 3036718..e64f433 100755
--- a/bin/photoalbum
+++ b/bin/photoalbum
@@ -31,6 +31,8 @@ usage() {
--thumbheight VALUE
--maxpreviews N
--random-seed VALUE
+ --splash
+ --no-splash
--shuffle
--no-shuffle
--tarball
@@ -425,6 +427,16 @@ validate_template_context() {
redirect)
required_vars+=(redirect_page)
;;
+ splash)
+ required_vars+=(
+ backhref
+ background_image
+ blurs_dir
+ enter_page
+ photo
+ photos_dir
+ )
+ ;;
details)
required_vars+=(
animation_class
@@ -464,6 +476,7 @@ source_template_file() {
render_background_image_css="$render_background_image_css" \
render_blurs_dir_css="$render_blurs_dir_css" \
render_current_date_text="$render_current_date_text" \
+ render_enter_page_html="$render_enter_page_html" \
render_exif_details_html="$render_exif_details_html" \
render_height_html="$render_height_html" \
render_html_dir_html="$render_html_dir_html" \
@@ -535,6 +548,9 @@ prepare_template_render_vars() {
_css_string_escape "$(template_context_value "$context_name" blurs_dir)"
)
render_current_date_text=$(_html_escape "$(current_date_text)")
+ render_enter_page_html=$(
+ _html_escape "$(template_context_value "$context_name" enter_page)"
+ )
render_exif_details_html=$(
template_context_value "$context_name" exif_details
)
@@ -602,6 +618,7 @@ template() {
local render_background_image_css
local render_blurs_dir_css
local render_current_date_text
+ local render_enter_page_html
local render_exif_details_html
local render_height_html
local render_html_dir
@@ -1153,6 +1170,38 @@ render_album_index_redirect() {
redirect_page 'page-1'
}
+render_album_splash_page() {
+ local -r photos_dir="$1"; shift
+ local -r html_dir="$1"; shift
+ local -r blurs_dir="$1"; shift
+ local -r backhref="$1"; shift
+ local photo
+
+ photo=$(randomphoto "$photos_dir" splash)
+ template 'splash' 'index.html' \
+ html_dir "$html_dir" \
+ backhref "$backhref" \
+ blurs_dir "$blurs_dir" \
+ background_image "$photo" \
+ photos_dir "$photos_dir" \
+ photo "$photo" \
+ enter_page 'page-1'
+}
+
+render_album_index() {
+ local -r photos_dir="$1"; shift
+ local -r html_dir="$1"; shift
+ local -r blurs_dir="$1"; shift
+ local -r backhref="$1"; shift
+
+ if [ "${SPLASH_PAGE:-yes}" = yes ]; then
+ render_album_splash_page "$photos_dir" "$html_dir" "$blurs_dir" \
+ "$backhref"
+ else
+ render_album_index_redirect "$html_dir"
+ fi
+}
+
render_album_pages() {
local -r photos_dir="$1"; shift
local -r html_dir="$1"; shift
@@ -1214,7 +1263,7 @@ render_album_pages() {
finish_preview_page "$name" "$html_dir" "$backhref" "$tarball_name"
render_view_redirects "$html_dir"
- render_album_index_redirect "$html_dir"
+ render_album_index "$photos_dir" "$html_dir" "$blurs_dir" "$backhref"
}
randomphoto() {
@@ -1331,6 +1380,7 @@ write_generation_metadata() {
printf ' "maxpreviews": %s,\n' "$(_json_string "${MAXPREVIEWS:-}")"
printf ' "random_seed": %s,\n' "$(_json_string "${RANDOM_SEED:-}")"
printf ' "shuffle": %s,\n' "$(_json_bool "${SHUFFLE:-no}")"
+ printf ' "splash_page": %s,\n' "$(_json_bool "${SPLASH_PAGE:-yes}")"
printf ' "original_basepath": %s\n' \
"$(_json_string "${ORIGINAL_BASEPATH:-}")"
printf ' }\n'
@@ -1405,6 +1455,7 @@ dry_run() {
printf 'Max previews per page: %s\n' "$MAXPREVIEWS"
printf 'Random seed: %s\n' "${RANDOM_SEED:-}"
printf 'Shuffle: %s\n' "${SHUFFLE:-no}"
+ printf 'Splash page: %s\n' "${SPLASH_PAGE:-yes}"
printf 'Image count: %s\n' "$image_count"
printf 'Tarball setting: %s\n' "${TARBALL_INCLUDE:-no}"
if [ "${TARBALL_INCLUDE:-no}" = yes ]; then
@@ -1420,8 +1471,13 @@ dry_run() {
printf ' %s/blurs\n' "$DIST_DIR"
printf 'Planned generated files:\n'
- printf ' %s/index.html (%s album index redirect)\n' \
- "$DIST_DIR" "$html_index_count"
+ if [ "${SPLASH_PAGE:-yes}" = yes ]; then
+ printf ' %s/index.html (%s splash page)\n' \
+ "$DIST_DIR" "$html_index_count"
+ else
+ printf ' %s/index.html (%s album index redirect)\n' \
+ "$DIST_DIR" "$html_index_count"
+ fi
printf ' %s/photoalbum.json\n' "$DIST_DIR"
printf ' %s/photos/* (%s image files)\n' "$DIST_DIR" "$image_count"
printf ' %s/thumbs/* (%s image files)\n' "$DIST_DIR" "$image_count"
@@ -1471,6 +1527,7 @@ print_config() {
print_shell_assignment MAXPREVIEWS "$MAXPREVIEWS"
print_shell_assignment RANDOM_SEED "${RANDOM_SEED:-}"
print_shell_assignment SHUFFLE "${SHUFFLE:-no}"
+ print_shell_assignment SPLASH_PAGE "${SPLASH_PAGE:-yes}"
print_shell_assignment TARBALL_INCLUDE "${TARBALL_INCLUDE:-no}"
print_shell_assignment TARBALL_SUFFIX "${TARBALL_SUFFIX:-.tar}"
print_shell_array_assignment TAR_OPTS "${tar_opts[@]}"
@@ -1666,6 +1723,7 @@ apply_config_defaults() {
ORIGINAL_BASEPATH="${ORIGINAL_BASEPATH:-}"
RANDOM_SEED="${RANDOM_SEED:-}"
SHUFFLE="${SHUFFLE:-no}"
+ SPLASH_PAGE="${SPLASH_PAGE:-yes}"
TARBALL_INCLUDE="${TARBALL_INCLUDE:-no}"
TARBALL_SUFFIX="${TARBALL_SUFFIX:-.tar}"
if ! declare -p TAR_OPTS >/dev/null 2>&1; then
@@ -1713,6 +1771,9 @@ apply_cli_overrides() {
if [ -n "$cli_shuffle" ]; then
SHUFFLE="$cli_shuffle"
fi
+ if [ -n "$cli_splash_page" ]; then
+ SPLASH_PAGE="$cli_splash_page"
+ fi
if [ -n "$cli_tarball_include" ]; then
TARBALL_INCLUDE="$cli_tarball_include"
fi
@@ -1805,6 +1866,10 @@ validate_template_dir() {
config_error "TEMPLATE_DIR $TEMPLATE_DIR must be a readable directory"
fi
+ if [ "${SPLASH_PAGE:-yes}" = yes ]; then
+ required_templates+=(splash)
+ fi
+
for template_name in "${required_templates[@]}"; do
if [ ! -r "$TEMPLATE_DIR/$template_name.tmpl" ]; then
config_error \
@@ -1844,6 +1909,7 @@ validate_generation_config() {
validate_positive_integer_config_var THUMBHEIGHT
validate_positive_integer_config_var MAXPREVIEWS
validate_yes_no_config_var SHUFFLE
+ validate_yes_no_config_var SPLASH_PAGE
validate_yes_no_config_var TARBALL_INCLUDE
if [ ! -d "$INCOMING_DIR" ]; then
@@ -1880,6 +1946,7 @@ validate_print_config() {
validate_positive_integer_config_var THUMBHEIGHT
validate_positive_integer_config_var MAXPREVIEWS
validate_yes_no_config_var SHUFFLE
+ validate_yes_no_config_var SPLASH_PAGE
validate_yes_no_config_var TARBALL_INCLUDE
resolve_tar_opts tar_opts
}
@@ -1962,6 +2029,14 @@ parse_cli_arguments() {
cli_shuffle='no'
has_config_overrides='yes'
;;
+ --splash)
+ cli_splash_page='yes'
+ has_config_overrides='yes'
+ ;;
+ --no-splash)
+ cli_splash_page='no'
+ has_config_overrides='yes'
+ ;;
--tarball)
cli_tarball_include='yes'
has_config_overrides='yes'
@@ -2035,6 +2110,7 @@ log_configured_action() {
log_verbose "Effective incoming directory: ${INCOMING_DIR:-}"
log_verbose "Effective output directory: ${DIST_DIR:-}"
log_verbose "Effective template directory: ${TEMPLATE_DIR:-}"
+ log_verbose "Effective splash page setting: ${SPLASH_PAGE:-yes}"
log_verbose "Effective tarball setting: ${TARBALL_INCLUDE:-no}"
}
@@ -2094,6 +2170,7 @@ main() {
local cli_maxpreviews=''
local cli_random_seed=''
local cli_shuffle=''
+ local cli_splash_page=''
local cli_tarball_include=''
local cli_template_dir=''
local cli_thumbheight=''
diff --git a/share/templates/default/splash.tmpl b/share/templates/default/splash.tmpl
new file mode 100644
index 0000000..ce3483d
--- /dev/null
+++ b/share/templates/default/splash.tmpl
@@ -0,0 +1,78 @@
+cat <<END
+<html>
+<head>
+ <title>${render_title_html}</title>
+ <style type="text/css">
+ body {
+ background-color: #000000;
+ color: #ffffff;
+ background-image:
+ linear-gradient(rgba(0, 0, 0, 0.35), rgba(0, 0, 0, 0.85)),
+ url("${render_backhref_css}/${render_blurs_dir_css}/${render_background_image_css}");
+ background-size: cover;
+ background-repeat: no-repeat;
+ background-position: center center;
+ font-family: verdana, sans-serif;
+ margin: 0;
+ min-height: 100vh;
+ text-align: center;
+ }
+
+ a {
+ color: #ffffff;
+ }
+
+ main.splash {
+ align-items: center;
+ box-sizing: border-box;
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ min-height: 100vh;
+ padding: 24px;
+ }
+
+ h1 {
+ background-color: #000000;
+ border: 3px solid #ffffff;
+ box-sizing: border-box;
+ font-size: 2em;
+ margin: 0 0 18px;
+ max-width: 900px;
+ padding: 8px 12px;
+ width: 100%;
+ }
+
+ img.splash-photo {
+ background-color: #000000;
+ border: 3px solid #ffffff;
+ box-sizing: border-box;
+ max-height: 72vh;
+ max-width: 95vw;
+ object-fit: contain;
+ padding: 5px;
+ }
+
+ p.enter {
+ background-color: #000000;
+ border: 3px solid #ffffff;
+ font-size: 1.2em;
+ margin: 18px 0 0;
+ padding: 8px 14px;
+ }
+ </style>
+</head>
+
+<body>
+ <main class="splash">
+ <h1>${render_title_html}</h1>
+ <a href="${render_enter_page_html}.html">
+ <img class="splash-photo" src="${render_backhref_html}/${render_photos_dir_html}/${render_photo_html}" />
+ </a>
+ <p class="enter">
+ <a href="${render_enter_page_html}.html">Enter album</a>
+ </p>
+ </main>
+</body>
+</html>
+END
diff --git a/src/photoalbum.default.conf b/src/photoalbum.default.conf
index a4ffb1b..1af7bf2 100644
--- a/src/photoalbum.default.conf
+++ b/src/photoalbum.default.conf
@@ -9,6 +9,8 @@ HEIGHT=1200
MAXPREVIEWS=40
# Randomly shuffle all previews.
# SHUFFLE=yes
+# Generate a splash landing page at index.html.
+SPLASH_PAGE=yes
# Set to any non-empty value for repeatable background, animation, timestamp,
# and shuffled preview choices.
# RANDOM_SEED=album-build-1
diff --git a/src/photoalbum.sh b/src/photoalbum.sh
index facc320..c36e025 100755
--- a/src/photoalbum.sh
+++ b/src/photoalbum.sh
@@ -31,6 +31,8 @@ usage() {
--thumbheight VALUE
--maxpreviews N
--random-seed VALUE
+ --splash
+ --no-splash
--shuffle
--no-shuffle
--tarball
@@ -425,6 +427,16 @@ validate_template_context() {
redirect)
required_vars+=(redirect_page)
;;
+ splash)
+ required_vars+=(
+ backhref
+ background_image
+ blurs_dir
+ enter_page
+ photo
+ photos_dir
+ )
+ ;;
details)
required_vars+=(
animation_class
@@ -464,6 +476,7 @@ source_template_file() {
render_background_image_css="$render_background_image_css" \
render_blurs_dir_css="$render_blurs_dir_css" \
render_current_date_text="$render_current_date_text" \
+ render_enter_page_html="$render_enter_page_html" \
render_exif_details_html="$render_exif_details_html" \
render_height_html="$render_height_html" \
render_html_dir_html="$render_html_dir_html" \
@@ -535,6 +548,9 @@ prepare_template_render_vars() {
_css_string_escape "$(template_context_value "$context_name" blurs_dir)"
)
render_current_date_text=$(_html_escape "$(current_date_text)")
+ render_enter_page_html=$(
+ _html_escape "$(template_context_value "$context_name" enter_page)"
+ )
render_exif_details_html=$(
template_context_value "$context_name" exif_details
)
@@ -602,6 +618,7 @@ template() {
local render_background_image_css
local render_blurs_dir_css
local render_current_date_text
+ local render_enter_page_html
local render_exif_details_html
local render_height_html
local render_html_dir
@@ -1153,6 +1170,38 @@ render_album_index_redirect() {
redirect_page 'page-1'
}
+render_album_splash_page() {
+ local -r photos_dir="$1"; shift
+ local -r html_dir="$1"; shift
+ local -r blurs_dir="$1"; shift
+ local -r backhref="$1"; shift
+ local photo
+
+ photo=$(randomphoto "$photos_dir" splash)
+ template 'splash' 'index.html' \
+ html_dir "$html_dir" \
+ backhref "$backhref" \
+ blurs_dir "$blurs_dir" \
+ background_image "$photo" \
+ photos_dir "$photos_dir" \
+ photo "$photo" \
+ enter_page 'page-1'
+}
+
+render_album_index() {
+ local -r photos_dir="$1"; shift
+ local -r html_dir="$1"; shift
+ local -r blurs_dir="$1"; shift
+ local -r backhref="$1"; shift
+
+ if [ "${SPLASH_PAGE:-yes}" = yes ]; then
+ render_album_splash_page "$photos_dir" "$html_dir" "$blurs_dir" \
+ "$backhref"
+ else
+ render_album_index_redirect "$html_dir"
+ fi
+}
+
render_album_pages() {
local -r photos_dir="$1"; shift
local -r html_dir="$1"; shift
@@ -1214,7 +1263,7 @@ render_album_pages() {
finish_preview_page "$name" "$html_dir" "$backhref" "$tarball_name"
render_view_redirects "$html_dir"
- render_album_index_redirect "$html_dir"
+ render_album_index "$photos_dir" "$html_dir" "$blurs_dir" "$backhref"
}
randomphoto() {
@@ -1331,6 +1380,7 @@ write_generation_metadata() {
printf ' "maxpreviews": %s,\n' "$(_json_string "${MAXPREVIEWS:-}")"
printf ' "random_seed": %s,\n' "$(_json_string "${RANDOM_SEED:-}")"
printf ' "shuffle": %s,\n' "$(_json_bool "${SHUFFLE:-no}")"
+ printf ' "splash_page": %s,\n' "$(_json_bool "${SPLASH_PAGE:-yes}")"
printf ' "original_basepath": %s\n' \
"$(_json_string "${ORIGINAL_BASEPATH:-}")"
printf ' }\n'
@@ -1405,6 +1455,7 @@ dry_run() {
printf 'Max previews per page: %s\n' "$MAXPREVIEWS"
printf 'Random seed: %s\n' "${RANDOM_SEED:-}"
printf 'Shuffle: %s\n' "${SHUFFLE:-no}"
+ printf 'Splash page: %s\n' "${SPLASH_PAGE:-yes}"
printf 'Image count: %s\n' "$image_count"
printf 'Tarball setting: %s\n' "${TARBALL_INCLUDE:-no}"
if [ "${TARBALL_INCLUDE:-no}" = yes ]; then
@@ -1420,8 +1471,13 @@ dry_run() {
printf ' %s/blurs\n' "$DIST_DIR"
printf 'Planned generated files:\n'
- printf ' %s/index.html (%s album index redirect)\n' \
- "$DIST_DIR" "$html_index_count"
+ if [ "${SPLASH_PAGE:-yes}" = yes ]; then
+ printf ' %s/index.html (%s splash page)\n' \
+ "$DIST_DIR" "$html_index_count"
+ else
+ printf ' %s/index.html (%s album index redirect)\n' \
+ "$DIST_DIR" "$html_index_count"
+ fi
printf ' %s/photoalbum.json\n' "$DIST_DIR"
printf ' %s/photos/* (%s image files)\n' "$DIST_DIR" "$image_count"
printf ' %s/thumbs/* (%s image files)\n' "$DIST_DIR" "$image_count"
@@ -1471,6 +1527,7 @@ print_config() {
print_shell_assignment MAXPREVIEWS "$MAXPREVIEWS"
print_shell_assignment RANDOM_SEED "${RANDOM_SEED:-}"
print_shell_assignment SHUFFLE "${SHUFFLE:-no}"
+ print_shell_assignment SPLASH_PAGE "${SPLASH_PAGE:-yes}"
print_shell_assignment TARBALL_INCLUDE "${TARBALL_INCLUDE:-no}"
print_shell_assignment TARBALL_SUFFIX "${TARBALL_SUFFIX:-.tar}"
print_shell_array_assignment TAR_OPTS "${tar_opts[@]}"
@@ -1666,6 +1723,7 @@ apply_config_defaults() {
ORIGINAL_BASEPATH="${ORIGINAL_BASEPATH:-}"
RANDOM_SEED="${RANDOM_SEED:-}"
SHUFFLE="${SHUFFLE:-no}"
+ SPLASH_PAGE="${SPLASH_PAGE:-yes}"
TARBALL_INCLUDE="${TARBALL_INCLUDE:-no}"
TARBALL_SUFFIX="${TARBALL_SUFFIX:-.tar}"
if ! declare -p TAR_OPTS >/dev/null 2>&1; then
@@ -1713,6 +1771,9 @@ apply_cli_overrides() {
if [ -n "$cli_shuffle" ]; then
SHUFFLE="$cli_shuffle"
fi
+ if [ -n "$cli_splash_page" ]; then
+ SPLASH_PAGE="$cli_splash_page"
+ fi
if [ -n "$cli_tarball_include" ]; then
TARBALL_INCLUDE="$cli_tarball_include"
fi
@@ -1805,6 +1866,10 @@ validate_template_dir() {
config_error "TEMPLATE_DIR $TEMPLATE_DIR must be a readable directory"
fi
+ if [ "${SPLASH_PAGE:-yes}" = yes ]; then
+ required_templates+=(splash)
+ fi
+
for template_name in "${required_templates[@]}"; do
if [ ! -r "$TEMPLATE_DIR/$template_name.tmpl" ]; then
config_error \
@@ -1844,6 +1909,7 @@ validate_generation_config() {
validate_positive_integer_config_var THUMBHEIGHT
validate_positive_integer_config_var MAXPREVIEWS
validate_yes_no_config_var SHUFFLE
+ validate_yes_no_config_var SPLASH_PAGE
validate_yes_no_config_var TARBALL_INCLUDE
if [ ! -d "$INCOMING_DIR" ]; then
@@ -1880,6 +1946,7 @@ validate_print_config() {
validate_positive_integer_config_var THUMBHEIGHT
validate_positive_integer_config_var MAXPREVIEWS
validate_yes_no_config_var SHUFFLE
+ validate_yes_no_config_var SPLASH_PAGE
validate_yes_no_config_var TARBALL_INCLUDE
resolve_tar_opts tar_opts
}
@@ -1962,6 +2029,14 @@ parse_cli_arguments() {
cli_shuffle='no'
has_config_overrides='yes'
;;
+ --splash)
+ cli_splash_page='yes'
+ has_config_overrides='yes'
+ ;;
+ --no-splash)
+ cli_splash_page='no'
+ has_config_overrides='yes'
+ ;;
--tarball)
cli_tarball_include='yes'
has_config_overrides='yes'
@@ -2035,6 +2110,7 @@ log_configured_action() {
log_verbose "Effective incoming directory: ${INCOMING_DIR:-}"
log_verbose "Effective output directory: ${DIST_DIR:-}"
log_verbose "Effective template directory: ${TEMPLATE_DIR:-}"
+ log_verbose "Effective splash page setting: ${SPLASH_PAGE:-yes}"
log_verbose "Effective tarball setting: ${TARBALL_INCLUDE:-no}"
}
@@ -2094,6 +2170,7 @@ main() {
local cli_maxpreviews=''
local cli_random_seed=''
local cli_shuffle=''
+ local cli_splash_page=''
local cli_tarball_include=''
local cli_template_dir=''
local cli_thumbheight=''
diff --git a/tests/cli.sh b/tests/cli.sh
index a554d58..44786f6 100755
--- a/tests/cli.sh
+++ b/tests/cli.sh
@@ -40,6 +40,9 @@ test::write_preflight_config() {
if [ "$omitted_var" != SHUFFLE ]; then
printf 'SHUFFLE=no\n'
fi
+ if [ "$omitted_var" != SPLASH_PAGE ]; then
+ printf 'SPLASH_PAGE=yes\n'
+ fi
if [ "$omitted_var" != TARBALL_INCLUDE ]; then
printf 'TARBALL_INCLUDE=no\n'
fi
@@ -134,6 +137,7 @@ assert metadata["settings"]["height"] == "120"
assert metadata["settings"]["thumbheight"] == "30"
assert metadata["settings"]["maxpreviews"] == maxpreviews
assert metadata["settings"]["shuffle"] is False
+assert isinstance(metadata["settings"]["splash_page"], bool)
assert "original_basepath" in metadata["settings"]
PY
}
@@ -869,6 +873,7 @@ THUMBHEIGHT=300
MAXPREVIEWS=40
RANDOM_SEED=''
SHUFFLE=no
+SPLASH_PAGE=yes
TARBALL_INCLUDE=yes
TARBALL_SUFFIX=.tar
TAR_OPTS=( -c )
@@ -1002,6 +1007,7 @@ THUMBHEIGHT=30
MAXPREVIEWS=7
RANDOM_SEED=''
SHUFFLE=yes
+SPLASH_PAGE=yes
TARBALL_INCLUDE=no
TARBALL_SUFFIX=.tar
TAR_OPTS=( -c )
@@ -1037,6 +1043,7 @@ THUMBHEIGHT=30
MAXPREVIEWS=8
RANDOM_SEED=''
SHUFFLE=no
+SPLASH_PAGE=yes
TARBALL_INCLUDE=no
TARBALL_SUFFIX=.tar
TAR_OPTS=( -c )
@@ -1082,6 +1089,7 @@ test_print_config_applies_cli_overrides_without_writes() {
--maxpreviews 9 \
--random-seed cli-seed \
--shuffle \
+ --no-splash \
--tarball
)
expected=$(cat <<EOF
@@ -1095,6 +1103,7 @@ THUMBHEIGHT=45
MAXPREVIEWS=9
RANDOM_SEED=cli-seed
SHUFFLE=yes
+SPLASH_PAGE=no
TARBALL_INCLUDE=yes
TARBALL_SUFFIX=.tar
TAR_OPTS=( -c )
@@ -1126,10 +1135,12 @@ test_print_config_applies_negative_cli_overrides() {
output=$(
cd "$TEST_TMPDIR"
- "$TEST_PHOTOALBUM" --print-config --no-shuffle --no-tarball
+ "$TEST_PHOTOALBUM" \
+ --print-config --no-shuffle --no-splash --no-tarball
)
test::assert_contains 'SHUFFLE=no' "$output"
+ test::assert_contains 'SPLASH_PAGE=no' "$output"
test::assert_contains 'TARBALL_INCLUDE=no' "$output"
test::teardown
}
@@ -1274,6 +1285,7 @@ test_dry_run_reports_cli_overrides_without_writes() {
--maxpreviews 2 \
--random-seed dry-seed \
--shuffle \
+ --no-splash \
--tarball
)
@@ -1290,6 +1302,7 @@ test_dry_run_reports_cli_overrides_without_writes() {
test::assert_contains 'Max previews per page: 2' "$output"
test::assert_contains 'Random seed: dry-seed' "$output"
test::assert_contains 'Shuffle: yes' "$output"
+ test::assert_contains 'Splash page: no' "$output"
test::assert_contains 'Image count: 6' "$output"
test::assert_contains 'Tarball setting: yes' "$output"
test::assert_contains 'Tarball name plan: incoming-<timestamp>.tar' \
@@ -1297,7 +1310,9 @@ test_dry_run_reports_cli_overrides_without_writes() {
test::assert_contains 'Planned directories:' "$output"
test::assert_contains " $dist_dir/photos" "$output"
test::assert_contains 'Planned generated files:' "$output"
- test::assert_contains " $dist_dir/index.html" "$output"
+ test::assert_contains \
+ " $dist_dir/index.html (1 album index redirect)" \
+ "$output"
test::assert_contains " $dist_dir/photoalbum.json" "$output"
test::assert_contains " $dist_dir/photos/* (6 image files)" "$output"
test::assert_contains " $dist_dir/thumbs/* (6 image files)" "$output"
@@ -1573,6 +1588,7 @@ test_generate_preflight_rejects_invalid_yes_no_values() {
local output
local -a bool_vars=(
SHUFFLE
+ SPLASH_PAGE
TARBALL_INCLUDE
)
@@ -1781,7 +1797,15 @@ test_integration_generates_album_outputs_and_cleans() {
test::assert_contains 'Next 2 pictures' "$page_html"
test::assert_contains 'No EXIF details available.' "$details_html"
test::assert_contains 'href="1-1.html">Image view</a>' "$details_html"
- test::assert_contains 'url=page-1.html' "$top_index_html"
+ test::assert_contains '<title>Integration album</title>' "$top_index_html"
+ test::assert_contains 'Enter album' "$top_index_html"
+ test::assert_contains 'href="page-1.html"' "$top_index_html"
+ test::assert_contains \
+ '<img class="splash-photo" src="./photos/' \
+ "$top_index_html"
+ test::assert_not_contains '<script' "$top_index_html"
+ test::assert_not_contains 'javascript:' "$top_index_html"
+ test::assert_not_contains "http-equiv='refresh'" "$top_index_html"
test::assert_find_count 0 "$TEST_TMPDIR/dist" '*.tar'
test::assert_generation_metadata \
"$TEST_TMPDIR/dist/photoalbum.json" \
@@ -1822,6 +1846,82 @@ test_integration_generates_album_outputs_and_cleans() {
test::teardown
}
+test_generate_config_no_splash_keeps_index_redirect() {
+ local config_file
+ local fake_bin
+ local top_index_html
+
+ test::setup
+ fake_bin="$TEST_TMPDIR/bin"
+ config_file="$TEST_TMPDIR/photoalbum.conf"
+
+ test::install_fake_imagemagick "$fake_bin"
+ PATH="$fake_bin:$PATH" \
+ test::generate_fixture_images "$TEST_TMPDIR/incoming"
+ test::write_album_config \
+ "$config_file" "$TEST_TMPDIR/incoming" "$TEST_TMPDIR/dist" \
+ 'No splash config album' 40
+ printf 'SPLASH_PAGE=no\n' >> "$config_file"
+
+ (
+ cd "$TEST_TMPDIR"
+ PATH="$fake_bin:$PATH" "$TEST_PHOTOALBUM" --generate
+ )
+
+ top_index_html=$(<"$TEST_TMPDIR/dist/index.html")
+ test::assert_contains 'url=page-1.html' "$top_index_html"
+ test::assert_not_contains 'Enter album' "$top_index_html"
+ test::assert_not_contains '<script' "$top_index_html"
+ test::assert_not_contains 'javascript:' "$top_index_html"
+
+ python3 - "$TEST_TMPDIR/dist/photoalbum.json" <<'PY'
+import json
+import pathlib
+import sys
+
+metadata = json.loads(pathlib.Path(sys.argv[1]).read_text())
+assert metadata["settings"]["splash_page"] is False
+PY
+
+ test::teardown
+}
+
+test_generate_cli_no_splash_overrides_config() {
+ local config_file
+ local fake_bin
+ local template_dir
+ local top_index_html
+
+ test::setup
+ fake_bin="$TEST_TMPDIR/bin"
+ config_file="$TEST_TMPDIR/photoalbum.conf"
+ template_dir="$TEST_TMPDIR/templates"
+
+ test::install_fake_imagemagick "$fake_bin"
+ PATH="$fake_bin:$PATH" \
+ test::generate_fixture_images "$TEST_TMPDIR/incoming"
+ cp -R "$TEST_REPO_ROOT/share/templates/default" "$template_dir"
+ rm -f "$template_dir/splash.tmpl"
+ test::write_album_config \
+ "$config_file" "$TEST_TMPDIR/incoming" "$TEST_TMPDIR/dist" \
+ 'No splash CLI album' 40
+ printf 'TEMPLATE_DIR=%q\n' "$template_dir" >> "$config_file"
+ printf 'SPLASH_PAGE=yes\n' >> "$config_file"
+
+ (
+ cd "$TEST_TMPDIR"
+ PATH="$fake_bin:$PATH" "$TEST_PHOTOALBUM" \
+ --generate --no-splash
+ )
+
+ top_index_html=$(<"$TEST_TMPDIR/dist/index.html")
+ test::assert_contains 'url=page-1.html' "$top_index_html"
+ test::assert_not_contains 'Enter album' "$top_index_html"
+ test::assert_not_contains '<script' "$top_index_html"
+ test::assert_not_contains 'javascript:' "$top_index_html"
+ test::teardown
+}
+
test_generate_replaces_dist_after_success() {
local config_file
local fake_bin
@@ -2084,6 +2184,7 @@ test_generate_escapes_html_values() {
local photo_name
local title
local title_html
+ local top_index_html
local view_html
test::setup
@@ -2123,14 +2224,18 @@ test_generate_escapes_html_values() {
)
page_html=$(<"$TEST_TMPDIR/dist/page-1.html")
+ top_index_html=$(<"$TEST_TMPDIR/dist/index.html")
view_html=$(<"$TEST_TMPDIR/dist/1-1.html")
details_html=$(<"$TEST_TMPDIR/dist/1-1-details.html")
test::assert_no_html_subdir_output "$TEST_TMPDIR/dist"
test::assert_contains "<title>$title_html</title>" "$page_html"
+ test::assert_contains "<title>$title_html</title>" "$top_index_html"
test::assert_contains \
"background-image: url(\"./blurs/$css_photo\");" \
"$page_html"
+ test::assert_contains "url(\"./blurs/$css_photo\")" "$top_index_html"
+ test::assert_contains "src=\"./photos/$photo_html\"" "$top_index_html"
test::assert_contains "name='$photo_html'" "$page_html"
test::assert_contains "src='./thumbs/$photo_html'" "$page_html"
test::assert_contains '&amp;&quot;&#39;.tar' "$page_html"
@@ -2145,6 +2250,7 @@ test_generate_escapes_html_values() {
test::assert_contains "<td>$exif_value_html</td>" "$details_html"
test::assert_contains "href=\"1-1.html\">Image view</a>" "$details_html"
test::assert_not_contains '<title>A & "quoted" <title>' "$page_html"
+ test::assert_not_contains "$photo_name" "$top_index_html"
test::assert_not_contains "$photo_name" "$view_html"
test::assert_not_contains "O'Neil & \"<camera>\"" "$details_html"
@@ -2516,6 +2622,12 @@ main() {
'--generate creates output structure and --clean removes it' \
test_integration_generates_album_outputs_and_cleans
test::run_case \
+ '--generate SPLASH_PAGE=no keeps root index redirect' \
+ test_generate_config_no_splash_keeps_index_redirect
+ test::run_case \
+ '--generate --no-splash keeps root index redirect' \
+ test_generate_cli_no_splash_overrides_config
+ test::run_case \
'--generate replaces final dist after success' \
test_generate_replaces_dist_after_success
test::run_case \
diff --git a/tests/helpers.sh b/tests/helpers.sh
index 19f8b21..22bf986 100755
--- a/tests/helpers.sh
+++ b/tests/helpers.sh
@@ -393,6 +393,7 @@ test::write_album_config() {
printf 'INCOMING_DIR=%q\n' "$incoming_dir"
printf 'DIST_DIR=%q\n' "$dist_dir"
printf 'TEMPLATE_DIR=%q/share/templates/default\n' "$TEST_REPO_ROOT"
+ printf 'SPLASH_PAGE=yes\n'
printf 'TARBALL_INCLUDE=no\n'
} > "$config_file"
}