Skip to content

Instantly share code, notes, and snippets.

@HBIDamian
Last active March 5, 2026 02:18
Show Gist options
  • Select an option

  • Save HBIDamian/65d081303d75cd3aefaeff4792f9018e to your computer and use it in GitHub Desktop.

Select an option

Save HBIDamian/65d081303d75cd3aefaeff4792f9018e to your computer and use it in GitHub Desktop.
Jellyfin - Set English Audio to Default (set -v to see the verbose of ffmpeg)
#!/bin/bash
FFMPEG="/usr/lib/jellyfin-ffmpeg/ffmpeg"
FFPROBE="/usr/lib/jellyfin-ffmpeg/ffprobe"
VERBOSE=false
SUMMARY=""
COUNT=0
# --- COLOR PALETTE ---
# Standard
BLACK='\033[0;30m'
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
GRAY='\033[0;37m'
WHITE='\033[0;38m'
# Bold
B_RED='\033[1;31m'
B_GREEN='\033[1;32m'
B_YELLOW='\033[1;33m'
B_CYAN='\033[1;36m'
# UI Elements
DIM='\033[2m'
UNDERLINE='\033[4m'
BOLD='\033[1m'
XBOLD='\033[21m'
NC='\033[0m' # No Color (Reset)
while getopts "v" opt; do
case $opt in
v) VERBOSE=true ;;
*) echo "Usage: $0 [-v]"; exit 1 ;;
esac
done
# High-Visibility Block Spinner
spinner() {
local pid=$1
local current=$2
local total=$3
local filename=$4
local delay=0.1
# This sequence uses fading blocks which are very visible
local spinstr='█▓▒░▒▓'
while kill -0 "$pid" 2>/dev/null; do
for (( i=0; i<${#spinstr}; i++ )); do
if ! kill -0 "$pid" 2>/dev/null; then break; fi
# [█] [1/8] Filename...
printf "\r${B_CYAN}[%s]${NC} ${B_WHITE}%s/%s${NC} %s" "${spinstr:$i:1}" "$current" "$total" "$filename"
sleep $delay
done
done
}
echo -e "${GRAY}---------------------------------------${NC}"
echo -e "${CYAN}[ℹ]${NC} Jellyfin English Default Track Setter"
echo -e "${GRAY}---------------------------------------${NC}"
if ! ls *.mkv >/dev/null 2>&1; then
echo ""
echo -e "${CYAN}[${RED}✖${CYAN}]${NC} No .mkv files found in $(pwd)"
exit 1
fi
echo ""
echo -e "${GRAY}---------------------------------------${NC}"
echo -e "${CYAN}[ℹ]${NC} Starting batch process in: $(pwd)"
[ "$VERBOSE" = true ] && echo -e "${YELLOW}[⚠]${NC} Verbose mode enabled${NC}"
for f in *.mkv; do
if [ "$VERBOSE" = true ]; then
echo "Processing: $f"
# Silent Probe to find track
LINE_NUM=$($FFPROBE -v error -select_streams a -show_entries stream=index:stream_tags=language -of csv=p=0 "$f" | grep -ni ",eng" | cut -d':' -f1 | head -n 1)
if [ -z "$LINE_NUM" ]; then
SUMMARY+="\n${YELLOW}[⚠] SKIP:${NC} '$f' (No English track)"
continue
fi
TRACK_INDEX=$((LINE_NUM - 1))
if $FFMPEG -i "$f" -map 0 -c copy -disposition:a 0 -disposition:a:$TRACK_INDEX default "temp_$f" -y; then
mv "temp_$f" "$f"
SUMMARY+="\n${GREEN}[✔] OK:${NC} '$f'"
((COUNT++))
else
rm -f "temp_$f"
SUMMARY+="\n${RED}[✖] FAIL:${NC} '$f'"
fi
else
# Run background logic
(
LINE_NUM=$($FFPROBE -v error -select_streams a -show_entries stream=index:stream_tags=language -of csv=p=0 "$f" | grep -ni ",eng" | cut -d':' -f1 | head -n 1)
[ -z "$LINE_NUM" ] && exit 2
TRACK_INDEX=$((LINE_NUM - 1))
if $FFMPEG -i "$f" -map 0 -c copy -disposition:a 0 -disposition:a:$TRACK_INDEX default "temp_$f" -y -loglevel error; then
mv "temp_$f" "$f"
exit 0
else
rm -f "temp_$f"
exit 1
fi
) &
FF_PID=$!
spinner $FF_PID "$f"
wait $FF_PID
EXIT_CODE=$?
# Clean line and print status
printf "\r\033[K"
if [ $EXIT_CODE -eq 0 ]; then
echo -e "${CYAN}[${GREEN}✔${CYAN}]${NC} $f"
SUMMARY+="\n${GREEN}[✔] OK:${NC} '$f'"
((COUNT++))
elif [ $EXIT_CODE -eq 2 ]; then
echo -e "${CYAN}[${YELLOW}⚠${CYAN}]${NC} $f (No English track)"
SUMMARY+="\n${YELLOW}[⚠] SKIP:${NC} '$f'"
else
echo -e "${CYAN}[${RED}✖${CYAN}]${NC} $f (Error)"
SUMMARY+="\n${RED}[✖] FAIL:${NC} '$f'"
fi
fi
done
echo ""
echo -e "${GRAY}---------------------------------------${NC}"
echo -e "\n${CYAN}Final Report:${NC}"
echo -e "${GRAY}---------------------------------------${NC}"
echo -e "${SUMMARY:-No files processed.}"
echo -e "${GRAY}---------------------------------------${NC}"
echo -e "Done! Updated ${GREEN}$COUNT${NC} files."
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment