88 lines
2.4 KiB
Bash
Executable File
88 lines
2.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Convert Mew timeline MP4 clips into small, optimized GIFs for Neocities.
|
|
# Requires: ffmpeg, gifsicle
|
|
#
|
|
# Strategy:
|
|
# - Trim to the first few seconds
|
|
# - Sample only a few frames per second
|
|
# - Scale down to a small width
|
|
# - Use a global palette + heavy optimization
|
|
# - Aim to keep each GIF under ~5MB
|
|
#
|
|
# Usage (from this directory):
|
|
# chmod +x mp4-to-gif.sh
|
|
# ./mp4-to-gif.sh /path/to/source/mp4s
|
|
|
|
set -euo pipefail
|
|
|
|
SRC_DIR="${1:-.}"
|
|
OUT_DIR="${OUT_DIR:-.}"
|
|
|
|
# Tunables for size/quality tradeoff
|
|
FPS="${FPS:-3}" # frames per second sampled
|
|
WIDTH="${WIDTH:-360}" # output width in pixels
|
|
MAX_SECONDS="${MAX_SECONDS:-8}" # cap duration
|
|
|
|
if ! command -v ffmpeg &>/dev/null; then
|
|
echo "Error: ffmpeg not found. Install it first." >&2
|
|
exit 1
|
|
fi
|
|
|
|
if ! command -v gifsicle &>/dev/null; then
|
|
echo "Warning: gifsicle not found. Skipping extra optimization (GIFs may be larger)." >&2
|
|
fi
|
|
|
|
convert_one () {
|
|
local name="$1" # e.g. 2016-12-17_22-42-58
|
|
local in="$SRC_DIR/${name}.mp4"
|
|
|
|
# Unique temp files to avoid name clashes if run multiple times
|
|
local pal
|
|
pal="$(mktemp "${OUT_DIR}/${name}-palette-XXXX.png")"
|
|
local out_tmp
|
|
out_tmp="$(mktemp "${OUT_DIR}/${name}-tmp-XXXX.gif")"
|
|
local out_final="${OUT_DIR}/${name}.gif"
|
|
|
|
if [[ ! -f "$in" ]]; then
|
|
echo "Skip (missing): $in"
|
|
return
|
|
fi
|
|
|
|
echo "Processing $in -> $out_final"
|
|
|
|
# 1) Generate palette from trimmed, sparsely sampled, scaled frames
|
|
ffmpeg -y -t "$MAX_SECONDS" -i "$in" \
|
|
-vf "fps=${FPS},scale=${WIDTH}:-1:flags=lanczos,palettegen=stats_mode=single:max_colors=48" \
|
|
-frames:v 1 \
|
|
"$pal"
|
|
|
|
# 2) Apply palette to create GIF
|
|
ffmpeg -y -t "$MAX_SECONDS" -i "$in" -i "$pal" \
|
|
-lavfi "fps=${FPS},scale=${WIDTH}:-1:flags=lanczos [x]; [x][1:v] paletteuse=dither=bayer:bayer_scale=5:diff_mode=rectangle" \
|
|
-loop 0 \
|
|
"$out_tmp"
|
|
|
|
# 3) Extra optimization with gifsicle, if available
|
|
if command -v gifsicle &>/dev/null; then
|
|
gifsicle -O3 --lossy=40 "$out_tmp" -o "$out_final"
|
|
rm -f "$out_tmp"
|
|
else
|
|
mv "$out_tmp" "$out_final"
|
|
fi
|
|
|
|
rm -f "$pal"
|
|
|
|
# 4) Print size
|
|
if command -v du &>/dev/null; then
|
|
echo -n "Final size: "
|
|
du -h "$out_final" | cut -f1
|
|
fi
|
|
}
|
|
|
|
convert_one "2016-12-17_22-42-58"
|
|
convert_one "2017-04-01_00-14-00"
|
|
convert_one "2018-06-19_06-20-25"
|
|
|
|
echo "Done. Upload the generated *.gif files to the 'library' folder on Neocities and ensure index.html references the .gif versions."
|
|
|