diff options
| author | Paul Buetow <paul@buetow.org> | 2026-05-30 22:13:12 +0300 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2026-05-30 22:13:12 +0300 |
| commit | dbfab00f3bbb7c21a04ec5036cb35ff463837a5a (patch) | |
| tree | 60d2dcac2dc9f8c601a097532b3ac9a816a84241 | |
| parent | f3f8244849fbe94ce482b4b660aae4a007d07b8d (diff) | |
Refactor photoalbum bash script
| -rw-r--r-- | README.md | 3 | ||||
| -rwxr-xr-x | src/photoalbum.sh | 423 |
2 files changed, 282 insertions, 144 deletions
@@ -12,7 +12,8 @@ make sudo make install ``` -Also, as a requirement, `convert` from ImageMagick needs to be installed. +Also, as a requirement, ImageMagick needs to be installed. The script prefers the +modern `magick` command and falls back to `convert` when needed. ## Usage diff --git a/src/photoalbum.sh b/src/photoalbum.sh index 7eb3e3b..bc721ee 100755 --- a/src/photoalbum.sh +++ b/src/photoalbum.sh @@ -1,21 +1,20 @@ -#!/bin/env bash +#!/usr/bin/env bash +set -euo pipefail # photoalbum (c) 2011 - 2014, 2022 by Paul Buetow # https://codeberg.org/snonux/photoalbum -readonly VERSION='PHOTOALBUMVERSION' -readonly DEFAULTRC='/etc/default/photoalbum' -declare ARG1="$1" ; shift -declare RC_FILE="$1" ; shift +declare -r VERSION='PHOTOALBUMVERSION' +declare -r DEFAULTRC='/etc/default/photoalbum' -usage () { +usage() { cat - <<USAGE >&2 - Usage: + Usage: $0 clean|generate|version|makemake [rcfile] USAGE } -makemake () { +makemake() { [ ! -f ./photoalbumrc ] && cp "$DEFAULTRC" ./photoalbumrc cat <<MAKEFILE > ./Makefile all: @@ -26,50 +25,76 @@ MAKEFILE echo 'You may now customize ./photoalbumrc and run make' } -tarball () { +imagemagick() { + if command -v magick >/dev/null 2>&1; then + magick "$@" + elif command -v convert >/dev/null 2>&1; then + convert "$@" + else + echo 'ERROR: ImageMagick is required; install magick or convert' >&2 + return 127 + fi +} + +tarball() { + local -r tarball_name="$1"; shift + local -r tar_opts="${TAR_OPTS:--c}" + local base + # Cleanup tarball from prev run if any - find "$DIST_DIR" -maxdepth 1 -type f -name \*.tar -delete - declare base="$(basename "$INCOMING_DIR")" + find "$DIST_DIR" -maxdepth 1 -type f -name '*.tar' -delete + base=$(basename "$INCOMING_DIR") echo "Creating tarball $DIST_DIR/$tarball_name from $INCOMING_DIR" - cd "$(dirname "$INCOMING_DIR")" - tar "$TAR_OPTS" -f "$DIST_DIR/$tarball_name" "$base" - cd - &>/dev/null + ( + cd "$(dirname "$INCOMING_DIR")" + tar "$tar_opts" -f "$DIST_DIR/$tarball_name" "$base" + ) } -template () { - declare template="$1" ; shift - declare html="$1" ; shift - declare dist_html="$DIST_DIR/$html_dir" +template() { + local -r template_name="$1"; shift + local -r html="$1"; shift + local -r dist_html="$DIST_DIR/$html_dir" + echo "Generating $dist_html/$html" - [ ! -d "$dist_html" ] && mkdir -p "$dist_html" - source "$TEMPLATE_DIR/$template.tmpl" >> "$dist_html/$html" + mkdir -p "$dist_html" + source "$TEMPLATE_DIR/$template_name.tmpl" >> "$dist_html/$html" } -cleanphotos () { - find "$DIST_DIR/photos" -maxdepth 1 -type f | while read photo; do - local basename=$(basename $photo) +cleanphotos() { + local basename + local photo + local sub + + while IFS= read -r photo; do + basename=$(basename "$photo") + if [ -f "$INCOMING_DIR/$basename" ]; then continue fi + echo "Cleaning up $photo" for sub in thumbs blurs photos; do if [ -f "$DIST_DIR/$sub/$basename" ]; then rm -v "$DIST_DIR/$sub/$basename" fi done - done + done < <(find "$DIST_DIR/photos" -maxdepth 1 -type f) } -scalephotos () { - cd "$INCOMING_DIR" && find ./ -maxdepth 1 -type f | sort | - while read -r photo; do - declare photo="$(sed 's#^\./##' <<< "$photo")" - declare destphoto="$DIST_DIR/photos/$photo" - declare destphoto_nospace="${destphoto// /_}" - declare dirname="$(dirname "$destphoto")" - [ ! -d "$dirname" ] && mkdir -p "$dirname" +scalephotos() { + local destphoto + local destphoto_nospace + local dirname + local photo + + while IFS= read -r photo; do + destphoto="$DIST_DIR/photos/$photo" + destphoto_nospace="${destphoto// /_}" + dirname=$(dirname "$destphoto") + mkdir -p "$dirname" if [ -f "$destphoto_nospace" ]; then echo "Already exists: $destphoto_nospace" @@ -77,198 +102,310 @@ scalephotos () { fi echo "Processing $photo to $destphoto_nospace" - if [ -n "$HEIGHT" ]; then + if [ -n "${HEIGHT:-}" ]; then # Scale down size. - convert -auto-orient -geometry "$HEIGHT" "$photo" "$destphoto_nospace" + imagemagick \ + -auto-orient \ + -geometry "$HEIGHT" \ + "$INCOMING_DIR/$photo" \ + "$destphoto_nospace" else - # Keep original size - convert -auto-orient "$photo" "$destphoto_nospace" + # Keep original size. + imagemagick \ + -auto-orient \ + "$INCOMING_DIR/$photo" \ + "$destphoto_nospace" fi - done -} - -randomphoto () { - declare photos_dir="$1" ; shift - basename $(find "$photos_dir" -type f -maxpdeth 1 -mindepth 1 | sort -R | head -n 1) + done < <( + find "$INCOMING_DIR" -maxdepth 1 -type f -printf '%f\n' \ + | sort + ) } -random_animation_css_class () { +random_animation_css_class() { local -r speed="$1"; shift - cat <<END | grep -v fading | sort -R | head -n 1 -animate-fading-$speed -animate-opacity-$speed -animate-top-$speed -animate-left-$speed -animate-right-$speed -animate-bottom-$speed -animate-zoom-$speed -END + local -a classes=( + "animate-opacity-$speed" + "animate-top-$speed" + "animate-left-$speed" + "animate-right-$speed" + "animate-bottom-$speed" + "animate-zoom-$speed" + ) + + printf '%s\n' "${classes[@]}" | sort -R | sed -n '1p' } -maybe_shuffle () { - if [ "$SHUFFLE" = yes ]; then +maybe_shuffle() { + if [ "${SHUFFLE:-no}" = yes ]; then sort -R else sort fi } -albumhtml () { - declare photos_dir="$1" ; shift - declare html_dir="$1" ; shift - declare thumbs_dir="$1" ; shift - declare blurs_dir="$1" ; shift - export backhref="$1" ; shift +newest_html() { + local -r pattern="$1"; shift - declare -i num=1 - declare -i i=0 - declare name="page-$num" + find "$DIST_DIR/$html_dir" \ + -maxdepth 1 \ + -name "$pattern" \ + -printf '%T@ %f\n' \ + | sort -nr \ + | sed -n '1{s/^[^ ]* //;p}' +} + +albumhtml() { + local -r photos_dir="$1"; shift + local -r html_dir="$1"; shift + local -r thumbs_dir="$1"; shift + local -r blurs_dir="$1"; shift + local -r backhref="$1"; shift + + local animation_class + local background_image + local dirname + local height + local lastview + local name + local next + local nextredirect + local page + local photo + local prev + local prefix + local prevredirect + local redirect_page + local show_header_bar + local -i i=0 + local -i num=1 + + export backhref + name="page-$num" # Random background image for preview page. - export background_image="$(randomphoto $photos_dir)" - export show_header_bar='yes' + background_image=$(randomphoto "$photos_dir") + show_header_bar='yes' + export background_image show_header_bar template 'header' "$name.html" - cd "$DIST_DIR/$photos_dir" && find ./ -type f | maybe_shuffle | sed 's;^\./;;' | - while read -r photo; do - let i++ + while IFS= read -r photo; do + (( ++i )) - if [ "$i" -gt "$MAXPREVIEWS" ]; then + if (( i > MAXPREVIEWS )); then i=1 - let num++ - declare next="page-$num" + (( ++num )) + next="page-$num" + prev="${prev:-}" + export next prev template next "$name.html" template footer "$name.html" - export prev="$name" - declare name="$next" + prev="$name" + name="$next" - export background_image="$(randomphoto $photos_dir)" - export show_header_bar='no' + background_image=$(randomphoto "$photos_dir") + show_header_bar='no' + export background_image prev show_header_bar template header "$name.html" template prev "$name.html" fi - # Preview page - export animation_class=$(random_animation_css_class slow) + # Preview page. + animation_class=$(random_animation_css_class slow) + export animation_class template preview "$name.html" - # View page - export background_image="$photo" - export show_header_bar='no' + # View page. + background_image="$photo" + show_header_bar='no' + export background_image show_header_bar template header "$num-$i.html" - export animation_class=$(random_animation_css_class fast) + animation_class=$(random_animation_css_class fast) + export animation_class template view "$num-$i.html" template footer "$num-$i.html" - if [[ -f "$DIST_DIR/$thumbs_dir/$photo" && -f "$DIST_DIR/$blurs_dir/$photo" ]]; then - echo "Already exists: $DIST_DIR/$thumbs_dir/$photo and $DIST_DIR/$blurs_dir/$photo" + if [[ -f "$DIST_DIR/$thumbs_dir/$photo" \ + && -f "$DIST_DIR/$blurs_dir/$photo" ]]; then + echo "Already exists: $DIST_DIR/$thumbs_dir/$photo and" \ + "$DIST_DIR/$blurs_dir/$photo" else - declare dirname="$DIST_DIR/$thumbs_dir" - test ! -d "$dirname" && mkdir -p "$dirname" + dirname="$DIST_DIR/$thumbs_dir" + mkdir -p "$dirname" echo "Creating thumb $DIST_DIR/$thumbs_dir/$photo" - # Double the height, as CSS will scale up/down images based on boxing too. - declare height=$((THUMBHEIGHT * 2)) - convert -geometry "x$height" "$photo" "$DIST_DIR/$thumbs_dir/$photo" + # Double the height, as CSS scales images based on boxing too. + height=$(( THUMBHEIGHT * 2 )) + imagemagick \ + -geometry "x$height" \ + "$DIST_DIR/$photos_dir/$photo" \ + "$DIST_DIR/$thumbs_dir/$photo" dirname="$DIST_DIR/$blurs_dir" - test ! -d "$dirname" && mkdir -p "$dirname" + mkdir -p "$dirname" echo "Creating blur $DIST_DIR/$blurs_dir/$photo" - convert -flip -blur 0x8 "$DIST_DIR/$thumbs_dir/$photo" "$DIST_DIR/$blurs_dir/$photo" + imagemagick \ + -flip \ + -blur 0x8 \ + "$DIST_DIR/$thumbs_dir/$photo" \ + "$DIST_DIR/$blurs_dir/$photo" fi - done - - template footer "$(cd "$DIST_DIR/$html_dir";ls -t page-*.html | head -n 1)" + done < <( + find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ + | maybe_shuffle + ) - cd "$DIST_DIR/$html_dir" && ls | grep '.*\.html$' | - grep -v page- | cut -d'-' -f1 | uniq | + template footer "$(newest_html 'page-*.html')" - while read -r prefix; do - declare page="$(ls -t "$prefix"-*.html | head -n 1 | sed 's#\(.*\)-.*.html#\1#')" - declare lastview="$(ls -t "$prefix"-*.html | head -n 1 | sed 's/.*-\(.*\).html/\1/')" + while IFS= read -r prefix; do + page=$(newest_html "$prefix-*.html" | sed 's#\(.*\)-.*.html#\1#') + lastview=$(newest_html "$prefix-*.html" | sed 's/.*-\(.*\).html/\1/') - declare prevredirect="${page}-0" - declare nextredirect="${page}-$((lastview+1))" + prevredirect="${page}-0" + nextredirect="${page}-$(( lastview + 1 ))" - declare redirect_page="$(( page-1 ))-${MAXPREVIEWS}" + redirect_page="$(( page - 1 ))-${MAXPREVIEWS}" + export redirect_page template redirect "$prevredirect.html" - if [ "$lastview" -eq "$MAXPREVIEWS" ]; then - declare redirect_page="$(( page+1 ))-1" + if (( lastview == MAXPREVIEWS )); then + redirect_page="$(( page + 1 ))-1" else - declare redirect_page="${page}-$lastview" + redirect_page="${page}-$lastview" + export redirect_page template redirect "0-$MAXPREVIEWS.html" redirect_page='1-1' fi export redirect_page template redirect "$nextredirect.html" - done - - # Create per album index/redirect page - declare redirect_page='page-1' + done < <( + find "$DIST_DIR/$html_dir" \ + -maxdepth 1 \ + -name '*.html' \ + ! -name 'page-*' \ + -printf '%f\n' \ + | cut -d'-' -f1 \ + | sort -u + ) + + # Create per album index/redirect page. + redirect_page='page-1' + export redirect_page template 'redirect' 'index.html' } -randomphoto () { - ls -f "$DIST_DIR/photos/" | sort -R | head -n 1 +randomphoto() { + local -r photos_dir="$1"; shift + local photo + local -a photos=() + + while IFS= read -r photo; do + photos+=("$photo") + done < <( + find "$DIST_DIR/$photos_dir" -maxdepth 1 -type f -printf '%f\n' \ + | sort + ) + + if (( ${#photos[@]} == 0 )); then + echo "ERROR: No photos found in $DIST_DIR/$photos_dir" >&2 + return 1 + fi + + printf '%s\n' "${photos[RANDOM % ${#photos[@]}]}" } -generate () { +generate() { + local base + local html_dir + local now + local redirect_page + local tarball_name='' + if [ ! -d "$INCOMING_DIR" ]; then echo "ERROR: You have to create $INCOMING_DIR first" >&2 exit 1 fi - if [ "$TARBALL_INCLUDE" = yes ]; then - declare base="$(basename "$INCOMING_DIR")" - declare now="$(date +'%Y-%m-%d-%H%M%S')" - declare tarball_name="${base}-${now}$TARBALL_SUFFIX" + if [ "${TARBALL_INCLUDE:-no}" = yes ]; then + base=$(basename "$INCOMING_DIR") + now=$(date +'%Y-%m-%d-%H%M%S') + tarball_name="${base}-${now}${TARBALL_SUFFIX:-.tar}" fi - test ! -d "$DIST_DIR/photos" && mkdir -p "$DIST_DIR/photos" + mkdir -p "$DIST_DIR/photos" cleanphotos scalephotos - find "$DIST_DIR" -type f -name \*.html -delete - declare -a dirs=( $(find "$DIST_DIR/photos" -mindepth 1 -maxdepth 1 -type d | sort) ) - + find "$DIST_DIR" -type f -name '*.html' -delete albumhtml 'photos' 'html' 'thumbs' 'blurs' '..' - # Create top level index/redirect page - declare html_dir='./' - declare redirect_page='./html/index' + # Create top level index/redirect page. + html_dir='./' + redirect_page='./html/index' + export redirect_page template 'redirect' 'index.html' - if [ "$TARBALL_INCLUDE" = 'yes' ]; then - tarball + if [ "${TARBALL_INCLUDE:-no}" = yes ]; then + tarball "$tarball_name" fi } -if [ -z "$RC_FILE" ]; then - if [ -f photoalbumrc ]; then - RC_FILE=photoalbumrc +resolve_rc_file() { + local rc_file="${1:-}" + + if [ -n "$rc_file" ]; then + printf '%s\n' "$rc_file" + elif [ -f photoalbumrc ]; then + printf '%s\n' photoalbumrc elif [ -f ~/.photoalbumrc ]; then - RC_FILE=~/.photoalbumrc + printf '%s\n' ~/.photoalbumrc else - RC_FILE="$DEFAULTRC" + printf '%s\n' "$DEFAULTRC" fi -fi +} -if [ ! -f "$RC_FILE" ]; then - echo "Error: Can not find config file $RC_FILE" >&2 - exit 1 -fi +apply_config_defaults() { + HEIGHT="${HEIGHT:-}" + ORIGINAL_BASEPATH="${ORIGINAL_BASEPATH:-}" + SHUFFLE="${SHUFFLE:-no}" + TARBALL_INCLUDE="${TARBALL_INCLUDE:-no}" + TARBALL_SUFFIX="${TARBALL_SUFFIX:-.tar}" + TAR_OPTS="${TAR_OPTS:--c}" +} + +main() { + local -r arg1="${1:-}" + local -r rc_file="$(resolve_rc_file "${2:-}")" -source "$RC_FILE" + if [ ! -f "$rc_file" ]; then + echo "Error: Can not find config file $rc_file" >&2 + exit 1 + fi -case "$ARG1" in - clean) [ -d "$DIST_DIR" ] && rm -Rf "$DIST_DIR";; - generate) generate;; - version) echo "This is Photoalbum Version $VERSION";; - makemake) makemake;; - *) usage;; -esac + source "$rc_file" + apply_config_defaults + + case "$arg1" in + clean) + if [ -d "$DIST_DIR" ]; then + rm -rf "$DIST_DIR" + fi + ;; + generate) + generate + ;; + version) + echo "This is Photoalbum Version $VERSION" + ;; + makemake) + makemake + ;; + *) + usage + ;; + esac +} -exit 0 +main "$@" |
