Skip to content

Instantly share code, notes, and snippets.

@sixem
Created June 25, 2021 15:22
Show Gist options
  • Save sixem/4447157b8ecbf5fecd9e7a78a06b6ad2 to your computer and use it in GitHub Desktop.
Save sixem/4447157b8ecbf5fecd9e7a78a06b6ad2 to your computer and use it in GitHub Desktop.
Downloads a YouTube video with all the subtitles packed into a .mkv file
#!/bin/bash
# ======================================================================== #
# Downloads a YouTube video with all the subtitles packed into a .mkv file #
# ======================================================================== #
# Usage: ./ytdl-subs.sh "YOUTUBE_URL" "OUTPUT_NAME_WITHOUT_EXTENSION"
UUID=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)
youtube-dl --all-subs --write-sub --sub-format srt "$1" --format bestvideo+bestaudio -o "$UUID"
declare -a SUBS=()
declare -a LANGS=()
TARGET=""
METADATA=""
MAPPED=""
function join_by
{
local d=${1-}
local f=${2-}
if shift 2; then
printf %s "$f" "${@/#/$d}"
fi
}
for NAME in $(find . -name "$UUID*\.mp4" -o -name "$UUID*\.webm" -o -name "$UUID*\.mkv"); do
BASENAME=$(basename "$NAME")
if [ ! -f "${BASENAME%.*}.mkv" ]; then
ffmpeg -i "$BASENAME" -c:v copy -c:a copy "${BASENAME%.*}.mkv"
TARGET="${BASENAME%.*}.mkv"
else
TARGET="$BASENAME"
fi
if [[ ! "$BASENAME" == *"\.mkv" ]]; then
rm "$BASENAME"
fi
done
for NAME in $(find . -name "$UUID*\.vtt" -o -name "$UUID*\.srt"); do
BASENAME=$(basename "$NAME")
if [[ ! "$BASENAME" == *"\.srt" ]]; then
if [ ! -f "${BASENAME%.*}.srt" ]; then
ffmpeg -i "$BASENAME" "${BASENAME%.*}.srt"
fi
rm "$BASENAME"
fi
done
for NAME in $(find . -name "$UUID*\.srt"); do
BASENAME=$(basename "$NAME")
[[ "$BASENAME" =~ \.([A-Za-z]+)\.srt ]]
LANGS=("${LANGS[@]}" "${BASH_REMATCH[1]}")
SUBS=("${SUBS[@]}" "$BASENAME")
done
for INDEX in "${!LANGS[@]}"; do
LANG=$(printf '%s\n' "${LANGS[$INDEX]}" | awk '{ print toupper($0) }')
METADATA="${METADATA}-metadata:s:s:$INDEX language=$LANG "
MAPPED="${MAPPED}-map $((INDEX + 1)) "
done
ffmpeg -i "$TARGET" -f srt \
-i $(join_by ' -i ' "${SUBS[@]}") \
-map 0:v -map 0:a $MAPPED \
-c:v copy -c:a copy \
$METADATA \
-c:s copy "$2.mkv"
rm "$TARGET"
for NAME in $(find . -name "$UUID*\.vtt" -o -name "$UUID*\.srt"); do
rm $(basename "$NAME")
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment