Skip to content

Instantly share code, notes, and snippets.

@theMackabu
Created December 5, 2024 05:48
Show Gist options
  • Save theMackabu/dcc617c526463e84956ef781c2b26fda to your computer and use it in GitHub Desktop.
Save theMackabu/dcc617c526463e84956ef781c2b26fda to your computer and use it in GitHub Desktop.
Title card creator
#!/bin/bash
# usage: ./create_card.sh <background_image> "<song_name>" "<artist>" "<year>" "<duration>"
# create base image with background
magick "$1" -gravity center -extent 1186x640 base.png
# add dark overlay
magick base.png \( +clone -fill black -colorize 89% \) -composite overlay.png
# add text with shadows
magick overlay.png \
\( -size 1186x640 xc:transparent \
-fill black -font "Inter-Bold" \
-pointsize 109 \
-annotate +47+490 "$2" \
-pointsize 72 \
-annotate +47+593 "$3 - $4" \
-pointsize 44 \
-annotate +1017+598 "$5" \
-channel A -gaussian-blur 5x5 \
-channel A -evaluate multiply 0.5 +channel \
\) -composite \
\( -size 1186x640 xc:transparent \
-fill white -font "Inter-Bold" \
-pointsize 109 \
-annotate +45+488 "$2" \
-pointsize 72 \
-annotate +45+591 "$3 - $4" \
-pointsize 44 \
-annotate +1015+596 "$5" \
\) -composite \
output_title_card.png
# clean up temporary files
rm base.png overlay.png
#!/bin/bash
# usage: ./generate_video.sh "url"
# function to convert to snake_case
to_snake_case() {
echo "$1" | tr '[:upper:]' '[:lower:]' | \
sed -e 's/[^a-zA-Z0-9]/_/g' -e 's/__*/_/g' -e 's/^_//' -e 's/_$//'
}
# function to sanitize text for ImageMagick
sanitize() {
echo "$1" | sed 's/"/\\"/g'
}
# function to truncate text
truncate_text() {
local text="$1"
if [ ${#text} -gt 50 ]; then
echo "${text:0:47}..."
else
echo "$text"
fi
}
# function to process title - remove everything before the - if it exists
process_title() {
local title="$1"
if [[ "$title" == *-* ]]; then
title=$(echo "$title" | sed 's/^.*- *//')
fi
echo "$title"
}
# get the title to check if file exists
echo "Checking metadata..."
TITLE=$(yt-dlp --get-title "$1")
TITLE=$(process_title "$TITLE")
TITLE_TRUNCATED=$(truncate_text "$TITLE")
FILENAME=$(to_snake_case "$TITLE_TRUNCATED")
# check if file exists
if [ -f "${FILENAME}.mp4" ]; then
echo "Error: ${FILENAME}.mp4 already exists"
exit 1
fi
# download audio
echo "Downloading audio..."
yt-dlp -f bestaudio --extract-audio --audio-format mp3 --output "temp_audio.%(ext)s" --print-json "$1" > metadata.json 2>/dev/null
ARTIST=$(cat metadata.json | jq -r '.uploader')
YEAR=$(cat metadata.json | jq -r '.upload_date[0:4]')
DURATION=$(cat metadata.json | jq -r '.duration')
rm metadata.json
# format duration to MM:SS
DURATION_FORMATTED=$(printf "%02d:%02d" $((DURATION/60)) $((DURATION%60)))
# download thumbnail
echo "Downloading thumbnail..."
yt-dlp --write-thumbnail --skip-download --convert-thumbnails jpg "$1" -o "temp_thumb" 2>/dev/null
# create title card using the external script
echo "Generating title card..."
./create_title_card.sh temp_thumb.jpg "$(sanitize "$TITLE_TRUNCATED")" "$(sanitize "$ARTIST")" "$YEAR" "$DURATION_FORMATTED"
# create MP4 with title card and audio
echo "Creating final video..."
ffmpeg -loop 1 -i output_title_card.png -i temp_audio.mp3 \
-c:v libx264 -preset ultrafast -tune stillimage \
-c:a aac -b:a 192k -pix_fmt yuv420p \
-shortest \
-movflags +faststart \
"${FILENAME}.mp4" 2>/dev/null
# clean up temporary files
rm temp_thumb.jpg output_title_card.png temp_audio.mp3
echo "Done! Created ${FILENAME}.mp4"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment