Skip to content

Instantly share code, notes, and snippets.

@AlexTMjugador
Last active April 23, 2023 17:29
Show Gist options
  • Save AlexTMjugador/0b7619b4526de25d4047501fd446212a to your computer and use it in GitHub Desktop.
Save AlexTMjugador/0b7619b4526de25d4047501fd446212a to your computer and use it in GitHub Desktop.
Shell script to create nice-looking animated Discord stickers. Supports processing several files in parallel.
#!/bin/sh -e
# Shell script to convert videos to APNG images suitable for use as Discord
# stickers. Tools used:
# - ffmpeg
# - pngquant
# - apngasm
while getopts r:f:p:m:h option; do
case $option in
r) # Resolution
RESOLUTION="$OPTARG";;
f) # FPS
FPS="$OPTARG";;
p) # Palette size
PALETTE_SIZE="$OPTARG";;
m) # Duration multiplier (useful for squeezing a bit more content in the 5 second limit)
DURATION_MULTIPLIER="$OPTARG";;
h|*) # Help
echo "Usage: $0 [-r WxH] [-f FPS] [-p PALETTE_SIZE] [-m DURATION_MULTIPLIER]"
exit 1;;
esac
done
readonly RESOLUTION="${RESOLUTION:-132x132}"
readonly FPS="${FPS:-16}"
readonly PALETTE_SIZE="${PALETTE_SIZE:-32}"
readonly DURATION_MULTIPLIER="${DURATION_MULTIPLIER:-1}"
WORK_DIRECTORY=$(mktemp -d -t discticker.XXX)
readonly WORK_DIRECTORY
trap 'rm -rf "$WORK_DIRECTORY"' EXIT INT TERM
shift $((OPTIND - 1))
for video in "$@"; do
{
video_basename="${video##*/}"
result_file="${video_basename%.*}.png"
mkdir "$WORK_DIRECTORY/$video_basename"
ffmpeg -hide_banner -i "$video" \
-filter:v "setpts=$DURATION_MULTIPLIER*PTS,fps=$FPS,trim=duration=4.95" \
-s "$RESOLUTION" \
"$WORK_DIRECTORY/$video_basename/frame%03d.png"
pngquant --speed 1 --ext .png --force "$PALETTE_SIZE" -- "$WORK_DIRECTORY/$video_basename"/frame*.png
apngasm "$result_file" "$WORK_DIRECTORY/$video_basename"/frame*.png 1 "$FPS" -z2
result_size=$(stat -c%s "$result_file")
if [ "$result_size" -ge $((512 * 1024)) ]; then
echo "! $result_file exceeds the 512 KiB Discord size limit. Aborting conversion"
rm "$result_file"
else
echo "> Sticker stored at $result_file ($((result_size / 1024)) KiB)"
fi
} &
done
wait
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment