Skip to content

Instantly share code, notes, and snippets.

@thedava
Last active October 24, 2024 01:10
Show Gist options
  • Save thedava/a63dee2ca7df1105c8b14d3e693cb281 to your computer and use it in GitHub Desktop.
Save thedava/a63dee2ca7df1105c8b14d3e693cb281 to your computer and use it in GitHub Desktop.
Create a thumbnail grid (8x5) with ffmpeg

thedava/thumbnail.sh

Create a thumbnail grid (8 cols, 5 rows) with additional meta data in the style of ezthumb but with ffmpeg.

Requirements

  • ffmpeg
  • imagemagick (montage & convert)
  • bc
  • fonts-dejavu-core
#!/usr/bin/env bash
# Check if ffmpeg and imagemagick (montage) are installed
if ! command -v ffmpeg &> /dev/null; then
echo "FFmpeg is not installed."
exit 1
fi
if ! command -v montage &> /dev/null; then
echo "ImageMagick is not installed."
exit 1
fi
rows=5
columns=8
thumb_count=$((rows * columns))
function create_thumbnail {
filename=$(basename -- "$1")
filename_no_ext="${filename%.*}"
output_dir=$(dirname "$1")
output_thumbnail="${output_dir}/${filename_no_ext}_thumb.jpg"
#rm -f "$output_thumbnail"
if [[ -e "$output_thumbnail" ]]; then
echo "Thumbnail for $filename already exists. Skipped creation."
return 0
fi
# Extract metadata
metadata=$(ffmpeg -i "$1" 2>&1 | grep -E "Duration|Video:|Audio:")
duration=$(echo "$metadata" | grep "Duration" | awk '{print $2}' | tr -d ,)
# Calculate thumbnail interval
hours=$(echo "$duration" | cut -d: -f1 | sed 's/^0*//')
minutes=$(echo "$duration" | cut -d: -f2 | sed 's/^0*//')
seconds=$(echo "$duration" | cut -d: -f3 | cut -d. -f1 | sed 's/^0*//')
total_seconds=$((hours * 3600 + minutes * 60 + seconds))
interval=$((total_seconds / thumb_count))
# Determine filesize (for header)
file_size=$(stat -c%s "$1")
if (( file_size >= 1073741824 )); then
file_size_gb=$(echo "scale=2; $file_size / 1073741824" | bc)
file_size_display="${file_size_gb} GB"
else
file_size_mb=$(echo "scale=2; $file_size / 1048576" | bc)
file_size_display="${file_size_mb} MB"
fi
temp_dir=$(mktemp -d -t thumbnailer-XXXXXX)
echo -n "Creating $thumb_count thumbnails now"
for i in $(seq 0 $((thumb_count - 1))); do
#echo "Creating thumbnail $((i + 1)) of $thumb_count..."
timestamp=$((i * interval))
timestamp_formatted=$(printf '%02d:%02d:%02d' $((timestamp/3600)) $(((timestamp%3600)/60)) $((timestamp%60)))
(
ffmpeg -hide_banner -loglevel error -ss "$timestamp_formatted" -i "$1" -vframes 1 "$temp_dir/thumb_$i.png"
echo -n "."
) &
if (( (i + 1) % columns == 0 )); then
wait
fi
done
wait
echo
montage "$temp_dir/thumb_*.png" -tile "${columns}x${rows}" -geometry 320x+2+2 "$temp_dir/grid.png"
header_text=$(echo -e "Name: $filename\nSize: ${file_size_display}\n$metadata" | sed 's/^[[:space:]]*//gm')
convert "$temp_dir/grid.png" \
-gravity NorthWest -background White -splice 0x150 \
-fill black -font "DejaVu-Sans-Mono" -pointsize 18 -annotate +10+10 "$header_text" \
"$output_thumbnail"
rm -rf "$temp_dir"
echo "$output_thumbnail created!"
}
for input_video in "$@"; do
# Check if input_video exists
if [ ! -f "$input_video" ]; then
echo "Input file not found: $input_video"
else
create_thumbnail "$input_video"
fi
done
echo "done"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment