Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 94 additions & 8 deletions gallery.sh
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ MY_CSS="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.6.2/css/boots
# true=enable, false=disable
MY_DEBUG=true

# Sorting option: 'filename' (default) or 'exiftime'
MY_SORT_MODE="filename"

#########################################################################################
#### End Configuration Section
#########################################################################################
Expand All @@ -39,9 +42,10 @@ MY_DATETIME+=" UTC"

function usage {
MY_RETURN_CODE="$1"
echo -e "Usage: $MY_SCRIPT_NAME [-t <title>] [-d <thumbdir>] [-h]:
echo -e "Usage: $MY_SCRIPT_NAME [-t <title>] [-d <thumbdir>] [-s <sort_mode>] [-h]:
[-t <title>]\\t sets the title (default: $MY_TITLE)
[-d <thumbdir>]\\t sets the thumbdir (default: $MY_THUMBDIR)
[-s <sort_mode>]\\t sets sorting mode: 'filename' (default) or 'exiftime'
[-h]\\t\\t displays help (this message)"
exit "$MY_RETURN_CODE"
}
Expand All @@ -64,14 +68,48 @@ function getFileSize(){
echo "$MY_FILE_SIZE"
}

while getopts ":t:d:h" opt; do
# Function to get EXIF date as a sortable string YYYYMMDD_HHMMSS
function getExifDate() {
local file="$1"
local exif_data

# Extract the DateTimeOriginal line from jhead output, falling back to File date
exif_data=$($MY_EXIF_COMMAND "$file" 2>/dev/null | grep "Date/Time")
if [[ -z "$exif_data" ]]; then
exif_data=$($MY_EXIF_COMMAND "$file" 2>/dev/null | grep "File date")
fi

if [[ -n "$exif_data" ]]; then
# Extract the date/time after the last colon and space: "YYYY:MM:DD HH:MM:SS"
local dt="${exif_data##*: }"
# Remove colons: "YYYYMMDD HHMMSS"
dt="${dt//:/}"
# Replace space with underscore: "YYYYMMDD_HHMMSS"
local sortable_date="${dt// /_}"
echo "$sortable_date"
else
# If no EXIF date, return current timestamp or a very early date to push it to end/beginning
# Using 0 ensures files without EXIF go to the beginning when sorting ascending
echo "00000000_000000"
fi
}

while getopts ":t:d:s:h" opt; do
case $opt in
t)
MY_TITLE="$OPTARG"
;;
d)
MY_THUMBDIR="$OPTARG"
;;
s)
if [[ "$OPTARG" == "exiftime" || "$OPTARG" == "filename" ]]; then
MY_SORT_MODE="$OPTARG"
else
echo "Invalid sort mode: $OPTARG. Use 'filename' or 'exiftime'."
usage 1
fi
;;
h)
usage 0
;;
Expand All @@ -82,7 +120,7 @@ while getopts ":t:d:h" opt; do
esac
done

debugOutput "- $MY_SCRIPT_NAME : $MY_DATETIME"
debugOutput "- $MY_SCRIPT_NAME : $MY_DATETIME (Sort Mode: $MY_SORT_MODE)"

### Check Commands
command -v $MY_CONVERT_COMMAND >/dev/null 2>&1 || { echo >&2 "!!! $MY_CONVERT_COMMAND it's not installed. Aborting."; exit 1; }
Expand Down Expand Up @@ -122,29 +160,77 @@ cat > "$MY_INDEX_HTML_FILE" << EOF
<main class="container">
EOF

### Photos (JPG)
### Photos (JPG) - Check if any exist first
if [[ $(find . -maxdepth 1 -type f -iname \*.jpg | wc -l) -gt 0 ]]; then

# Collect all JPG files into an array initially
MY_RAW_FILES=()
for MY_FILENAME in *.[jJ][pP][gG]; do
# Check if the glob actually matched something (bash doesn't expand to literal pattern if no match)
[[ -e "$MY_FILENAME" ]] || continue
MY_RAW_FILES+=("$MY_FILENAME")
done

MY_NUM_FILES=${#MY_RAW_FILES[@]}

# If sorting by EXIF, we need to create a sort key for each file
if [[ "$MY_SORT_MODE" == "exiftime" ]]; then
debugOutput "Sorting by EXIF time..."
SORT_TEMP_FILE=$(mktemp)

for MY_FILENAME in "${MY_RAW_FILES[@]}"; do
SORT_KEY=$(getExifDate "$MY_FILENAME")
echo "${SORT_KEY} ${MY_FILENAME}" >> "$SORT_TEMP_FILE"
done

# Sort the file and extract just the filenames back into an array
MY_SORTED_FILES=()
while IFS=' ' read -r _ filename; do
MY_SORTED_FILES+=("$filename")
done < <(sort "$SORT_TEMP_FILE")

rm -f "$SORT_TEMP_FILE"

# Update the working list and count
MY_RAW_FILES=("${MY_SORTED_FILES[@]}")
MY_NUM_FILES=${#MY_RAW_FILES[@]}
else
# If sorting by filename, we just use the glob order (which is alphabetical)
# But we need to ensure MY_RAW_FILES matches the glob expansion order.
# Since bash globs are alphabetical, and our initial loop was alphabetical,
# we can just re-glob or keep the array if it was built correctly.
# To be safe and consistent with previous behavior, rebuild from glob:
MY_RAW_FILES=()
for MY_FILENAME in *.[jJ][pP][gG]; do
[[ -e "$MY_FILENAME" ]] || continue
MY_RAW_FILES+=("$MY_FILENAME")
done
MY_NUM_FILES=${#MY_RAW_FILES[@]}
fi

MY_ROWS='3'
echo '<div class="row row-cols-sm-1 row-cols-md-'"$((MY_ROWS-2))"' row-cols-lg-'"$((MY_ROWS-1))"' row-cols-xl-'"$MY_ROWS"' py-5">' >> "$MY_INDEX_HTML_FILE"
## Generate Images

## Generate Images and Index Links
MY_NUM_FILES=0
for MY_FILENAME in *.[jJ][pP][gG]; do
for MY_FILENAME in "${MY_RAW_FILES[@]}"; do
MY_FILELIST[MY_NUM_FILES]=$MY_FILENAME
(( MY_NUM_FILES++ ))

for MY_RES in "${MY_HEIGHTS[@]}"; do
if [[ ! -s $MY_THUMBDIR/$MY_RES/$MY_FILENAME ]]; then
debugOutput "$MY_THUMBDIR/$MY_RES/$MY_FILENAME"
$MY_CONVERT_COMMAND -auto-orient -strip -quality $MY_QUALITY -resize x"$MY_RES" "$MY_FILENAME" "$MY_THUMBDIR/$MY_RES/$MY_FILENAME"
fi
done

cat >> "$MY_INDEX_HTML_FILE" << EOF
<div class="col">
<p>
<a href="$MY_THUMBDIR/$MY_FILENAME.html"><img src="$MY_THUMBDIR/$MY_HEIGHT_SMALL/$MY_FILENAME" alt="Thumbnail: $MY_FILENAME" class="rounded mx-auto d-block" height="$((MY_HEIGHT_SMALL/2))"></a>
</p>
</div>
EOF
(( MY_NUM_FILES++ ))
done
echo '</div>' >> "$MY_INDEX_HTML_FILE"

Expand Down Expand Up @@ -308,4 +394,4 @@ cat >> "$MY_INDEX_HTML_FILE" << EOF
</html>
EOF

debugOutput "= done"
debugOutput "= done"