Skip to content

Instantly share code, notes, and snippets.

@Mirochiu
Created June 2, 2026 07:37
Show Gist options
  • Select an option

  • Save Mirochiu/927b3b99e1d71959d4084bbcbc78ee9a to your computer and use it in GitHub Desktop.

Select an option

Save Mirochiu/927b3b99e1d71959d4084bbcbc78ee9a to your computer and use it in GitHub Desktop.
#!/usr/bin/env bash
set -euo pipefail
# =========================================================
# FFmpeg Static Build Auto Updater
# Test on Ubuntu 22.04
# Source: https://johnvansickle.com/ffmpeg/
# =========================================================
BASE_URL="https://johnvansickle.com/ffmpeg/releases"
FILE_NAME="ffmpeg-release-amd64-static.tar.xz"
INSTALL_DIR="/usr/local/bin"
TMP_DIR="$(mktemp -d)"
BACKUP_DIR="/usr/local/bin/ffmpeg-backup-$(date +%Y%m%d-%H%M%S)"
cleanup() {
# Safety guard against accidental rm -rf misuse
# ${TMP_DIR:-} prevents unbound variable errors
# -n ensures the variable is not empty
# -d ensures the target is a directory
# Restrict deletion scope to /tmp/ only
# Prevent root directory deletion (/)
# Use -- to prevent path being interpreted as options
if [[ -n "${TMP_DIR:-}" ]] \
&& [[ -d "$TMP_DIR" ]] \
&& [[ "$TMP_DIR" == /tmp/* ]] \
&& [[ "$TMP_DIR" != "/" ]]; then
rm -rf -- "$TMP_DIR"
else
echo "WARNING: Skip unsafe cleanup path: '$TMP_DIR'"
fi
}
trap cleanup EXIT
# ---------------------------------------------------------
# Download helper
# ---------------------------------------------------------
download() {
local url="$1"
local output="$2"
if command -v curl >/dev/null 2>&1; then
curl -L --progress-bar -o "$output" "$url"
elif command -v wget >/dev/null 2>&1; then
wget -q --show-progress -O "$output" "$url"
else
echo "ERROR: curl or wget required"
exit 1
fi
}
# ---------------------------------------------------------
# normalize version string
# e.g.
# 7.0.2-static -> 7.0.2
# 7.1-amd64-static -> 7.1
# ffmpeg-7.1.1-xxx -> 7.1.1
# ---------------------------------------------------------
normalize_version() {
echo "$1" \
| grep -oE '[0-9]+(\.[0-9]+){1,2}' \
| head -n1
}
get_version() {
local ffmpeg_bin="${1:-ffmpeg}"
# resolve from PATH if not absolute/relative path
if [[ "$ffmpeg_bin" != */* ]]; then
ffmpeg_bin=$(command -v "$ffmpeg_bin" || true)
fi
if [[ ! -x "$ffmpeg_bin" ]]; then
echo "ERROR: ffmpeg not executable: $ffmpeg_bin" >&2
return 1
fi
local raw
raw=$("$ffmpeg_bin" -version 2>/dev/null | head -n1 | awk '{print $3}')
if [[ -z "$raw" ]]; then
echo "ERROR: cannot detect version from $ffmpeg_bin" >&2
return 1
fi
normalize_version "$raw"
# RAW_CURRENT=$(ffmpeg -version | head -n1 | awk '{print $3}')
# normalize_version "$RAW_CURRENT"
}
# ---------------------------------------------------------
# Root check
# ---------------------------------------------------------
if [[ $EUID -ne 0 ]]; then
echo "Please run with sudo:"
echo "sudo $0"
exit 1
fi
# ---------------------------------------------------------
# Current installed version
# ---------------------------------------------------------
CURRENT_VERSION=$(get_version)
echo "Current version: ${CURRENT_VERSION}"
# only allow release version format:
# 7.1
# 7.1.1
# 6.0
if [[ "$CURRENT_VERSION" != "none" ]]; then
if ! [[ "$CURRENT_VERSION" =~ ^[0-9]+(\.[0-9]+){1,2}$ ]]; then
echo
echo "ERROR: Unknown FFmpeg version format"
echo "Detected version: ${CURRENT_VERSION}"
echo
echo "Refusing automatic update for safety."
exit 1
fi
fi
# ---------------------------------------------------------
# Download latest release checksum
# ---------------------------------------------------------
cd "$TMP_DIR"
echo "Fetching latest release & info..."
download "${BASE_URL}/${FILE_NAME}.md5" "${FILE_NAME}.md5"
download "${BASE_URL}/${FILE_NAME}" "${FILE_NAME}"
# ---------------------------------------------------------
# Verify MD5
# ---------------------------------------------------------
EXPECTED_MD5=$(cut -d ' ' -f1 "${FILE_NAME}.md5")
ACTUAL_MD5=$(md5sum "${FILE_NAME}" | cut -d ' ' -f1)
if [[ "$EXPECTED_MD5" != "$ACTUAL_MD5" ]]; then
echo "ERROR: MD5 verification failed"
echo "Expected: $EXPECTED_MD5"
echo "Actual : $ACTUAL_MD5"
exit 1
fi
echo "MD5 verification passed"
# ---------------------------------------------------------
# Extract
# ---------------------------------------------------------
echo "Extracting..."
tar -xf "${FILE_NAME}"
EXTRACT_DIR=$(find . -maxdepth 1 -type d -name "ffmpeg-*-amd64-static" | head -n1)
if [[ -z "$EXTRACT_DIR" ]]; then
echo "ERROR: Cannot find extracted directory"
exit 1
fi
REMOTE_RAW=$("${EXTRACT_DIR}/ffmpeg" -version | head -n1 | awk '{print $3}')
LATEST_VERSION=$(echo "$REMOTE_RAW" | grep -oE '[0-9]+(\.[0-9]+){1,2}' | head -n1)
echo "Latest version : ${LATEST_VERSION}"
if ! [[ "$LATEST_VERSION" =~ ^[0-9]+(\.[0-9]+){1,2}$ ]]; then
echo
echo "ERROR: Invalid remote version format"
echo "Remote version: ${LATEST_VERSION}"
exit 1
fi
# ---------------------------------------------------------
# Compare versions
# ---------------------------------------------------------
if [[ "$CURRENT_VERSION" == "$LATEST_VERSION" ]]; then
echo
echo "FFmpeg already up to date."
exit 0
fi
echo
echo "Updating FFmpeg..."
echo
# ---------------------------------------------------------
# Backup
# ---------------------------------------------------------
echo "Backing up existing binaries..."
mkdir -p "$BACKUP_DIR"
for bin in ffmpeg ffprobe ffplay qt-faststart; do
if [[ -f "${INSTALL_DIR}/${bin}" ]]; then
cp "${INSTALL_DIR}/${bin}" "${BACKUP_DIR}/"
fi
done
# ---------------------------------------------------------
# Install
# ---------------------------------------------------------
echo "Installing new binaries..."
install -m 755 "${EXTRACT_DIR}/ffmpeg" "${INSTALL_DIR}/ffmpeg"
install -m 755 "${EXTRACT_DIR}/ffprobe" "${INSTALL_DIR}/ffprobe"
if [[ -f "${EXTRACT_DIR}/ffplay" ]]; then
install -m 755 "${EXTRACT_DIR}/ffplay" "${INSTALL_DIR}/ffplay"
fi
if [[ -f "${EXTRACT_DIR}/qt-faststart" ]]; then
install -m 755 "${EXTRACT_DIR}/qt-faststart" "${INSTALL_DIR}/qt-faststart"
fi
# ---------------------------------------------------------
# Done
# ---------------------------------------------------------
NEW_VERSION=$(get_version)
echo
echo "======================================="
echo "FFmpeg update completed"
echo "Old version : ${CURRENT_VERSION}"
echo "New version : ${NEW_VERSION}"
echo "Backup path : ${BACKUP_DIR}"
echo "======================================="
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment