Last active
May 1, 2020 02:29
-
-
Save sqbs/1a4986452387dbbd697f7cc045c5cfef to your computer and use it in GitHub Desktop.
burnsub.sh v1.2.1 bugfix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
#====================================================================== | |
# burnsub.sh by sqbs | |
#====================================================================== | |
# | |
# Special thanks to Bill, lts | |
# | |
#====================================================================== | |
# WHAT IS IT? | |
#====================================================================== | |
# | |
# A POSIX script for easy subtitle burning onto MKVs | |
# | |
# Requires: | |
# | |
# - handbrake-cli | |
# - ffmpeg | |
# - mkvtoolnix-cli | |
# | |
#====================================================================== | |
# WHAT DOES IT DO? | |
#====================================================================== | |
# | |
# Outputs an MKV with video + subs merged and a single audio track | |
# | |
#====================================================================== | |
# HOW TO USE / EXAMPLES | |
#====================================================================== | |
# | |
# When prompted to select audio/sub tracks select the number | |
# next to mkvextract: (track ID for mkvmerge & mkvextract: 1) | |
# (track ID for mkvmerge & mkvextract: 2) | |
# (track ID for mkvmerge & mkvextract: 3) | |
# | |
# burnsub.sh file1.mkv file*.mkv file_S*E*.mkv | |
# | |
# Ask for audio and sub tracks before each file | |
# | |
# burnsub.sh -f file1.mkv file*.mkv file_S*E*.mkv | |
# | |
# Same audio and sub tracks selected for all | |
# | |
# burnsub.sh -F file1.mkv file*.mkv file_S*E*.mkv | |
# | |
# Ignore corrupt/error checks and proceed with the batch | |
# | |
# burnsub.sh -fF file1.mkv file*.mkv file_S*E*.mkv | |
# | |
# Same audio + sub tracks and ignore errors. Problem files | |
# are labelled with "_ERR" in the completed filename | |
# | |
# burnsub.sh -fS file1.mkv file*.mkv file_S*E*.mkv | |
# | |
# Same audio + sub tracks but skip files with errors | |
# | |
#====================================================================== | |
# FUNCTIONS | |
#====================================================================== | |
version="1.2.1" | |
info() { | |
echo "" | |
printf "burnsub.sh v%s " "$version" | |
printf "\n\n%s\n\n" "https://gist.github.com/1a4986452387dbbd697f7cc045c5cfef" | |
} | |
help() { | |
info | |
echo "A POSIX script for easy subtitle burning onto MKVs" | |
echo "" | |
echo "Syntax: burnsub.sh [-f|F|h|t|T|S|v]" | |
echo "Options:" | |
echo "" | |
echo " f Same audio + subtitle selection for all files" | |
echo " F Continue on error" | |
echo " h Display this screen" | |
echo " t Keep all temp files" | |
echo " T Keep all temp files only on error" | |
echo " S Skip on error" | |
echo " v Display version number" | |
echo "" | |
} | |
get_user_input() { | |
file=$* | |
case "${file_ext}" in | |
"mkv") | |
printf "\nFile: \"%s\"\n\n" "$file" | |
;; | |
*) | |
printf "\nSource file is not a .mkv\n" | |
exit 1 | |
;; | |
esac | |
mkvinfo "$file" | sed -nr '/[\w\W]*(Track number|Track type|Language|Display|Name)[\w\W]*/p' | |
printf "\nSelect audio track: " | |
read -r audio_track | |
case $audio_track in | |
*[!0-9]*) | |
printf "\n\"%s\" is not a valid audio track\n" "$audio_track" | |
exit 1 | |
;; | |
*) ;; | |
esac | |
printf "Select subtitle track: " | |
read -r subtitle_track | |
case $subtitle_track in | |
*[!0-9]*) | |
printf "\n\"%s\" is not a valid subtitle track\n" "$subtitle_track" | |
exit 1 | |
;; | |
*) ;; | |
esac | |
} | |
print_execution_time() { | |
time_end=$(date +%s) | |
runtime=$((time_end - time_start)) | |
min=0 | |
hour=0 | |
day=0 | |
if [ $runtime -gt 59 ]; then | |
sec=$((runtime % 60)) | |
runtime=$((runtime / 60)) | |
if [ $runtime -gt 59 ]; then | |
min=$((runtime % 60)) | |
runtime=$((runtime / 60)) | |
if [ $runtime -gt 23 ]; then | |
hour=$((runtime % 24)) | |
day=$((runtime / 24)) | |
else | |
hour=$runtime | |
fi | |
else | |
min=$runtime | |
fi | |
else | |
sec=$runtime | |
fi | |
[ $day -gt 0 ] && output="$output ${day}d" | |
[ $hour -gt 0 ] && output="$output ${hour}h" | |
[ $min -gt 0 ] && output="$output ${min}m" | |
[ $sec -gt 0 ] && output="$output ${sec}s" | |
printf "\nExecution time: %s\n\n" "$output" | |
} | |
del_temp_files() { | |
if [ -d "${folder_path}/hc_temp/" ]; then | |
case "$1" in | |
"-"*["t"]*) ;; | |
"-"*["T"]*) | |
if [ ! "$error_subs" ] && [ ! "$error_video" ] && [ ! "$error_audio" ]; then | |
find "${folder_path}/hc_temp/" -name "*_*.tmp.*" -type f -delete | |
fi | |
;; | |
*) find "${folder_path}/hc_temp/" -name "*_*.tmp.*" -type f -delete;; | |
esac | |
fi | |
} | |
end() { | |
del_temp_files "$1" | |
print_execution_time | |
exit 0 | |
} | |
end_error() { | |
if [ "$batch" -eq 1 ]; then | |
case "$1" in | |
"-"*["F""S"]*) ;; | |
*) | |
printf "\n\nUse argument -F to ignore errors and finish batch" | |
printf "\nUse argument -S to skip on errors and finish batch\n" | |
;; | |
esac | |
fi | |
case "$1" in | |
"-"*["T"]*) ;; | |
*) del_temp_files "$1";; | |
esac | |
print_execution_time | |
exit 1 | |
} | |
#=========================================================== | |
# INIT | |
#=========================================================== | |
case "$1" in | |
"-"*["h"]*) help; exit 0;; | |
"-"*["v"]*) info; exit 0;; | |
*);; | |
esac | |
time_start=$(date +%s) | |
[ -x "$(command -v mkvmerge)" ] || pass=false | |
[ -x "$(command -v ffmpeg)" ] || pass=false | |
[ -x "$(command -v HandBrakeCLI)" ] || pass=false | |
[ "$pass" != false ] || { printf "\nPlease install mkvtoolnix-cli + ffmpeg + handbrake-cli and run me again\n\n"; exit 1; } | |
#=========================================================== | |
# MAIN | |
#=========================================================== | |
case "$1" in | |
"-"*) | |
if [ -z "$2" ]; then | |
file=0 | |
else | |
file=1 | |
fi | |
;; | |
*) | |
if [ -z "$1" ]; then | |
file=0 | |
else | |
file=1 | |
fi | |
;; | |
esac | |
if [ $file -eq 0 ]; then | |
printf "\nNo .mkv file specified\n\n" | |
exit 1 | |
fi | |
case "$1" in | |
"-"*) | |
if [ "$#" -gt 2 ]; then | |
batch=1 | |
else | |
batch=0 | |
fi | |
;; | |
*) | |
if [ "$#" -gt 1 ]; then | |
batch=1 | |
else | |
batch=0 | |
fi | |
;; | |
esac | |
printf " | |
/ / / | |
(___ ___ ___ ___ (___ ___ (___ | |
| )| )| )| )|___ | )| ) |___ | ) | |
|__/ |__/ | | / __/ |__/ |__/ __/ | / v%s | |
- | |
" "$version" | |
for var in "$@" | |
do | |
if case "$var" in "-"*["f""F""t""T""S"]*) true;; *) false;; esac; then | |
continue | |
fi | |
filename_ext=$(basename -- "$var") | |
file_ext="${filename_ext##*.}" | |
filename=${filename_ext%".$file_ext"} | |
folder_path=$(realpath "$var") | |
folder_path=${folder_path%"/$filename_ext"} | |
case "$1" in | |
"-"*"f"*) | |
if [ ! "$received_user_input" ]; then | |
get_user_input "$var" | |
received_user_input=true; | |
fi | |
;; | |
*) get_user_input "$var" ;; | |
esac | |
printf "\nPreparing \"%s\"...\n" "$filename_ext" | |
error_video="" | |
error_audio="" | |
error_subs="" | |
del_temp_files "" | |
mkdir -p "${folder_path}/hc_temp" | |
printf "\nChecking subtitle format...\n" | |
check_sub_format=$(mkvmerge -i "$var" | sed -nr "/Track ID $subtitle_track:[\w\W]*/p") | |
sub_format="" | |
if echo "$check_sub_format" | grep 'SRT'; then | |
sub_format="srt" | |
printf "\n.SRT (Text)\n" | |
elif echo "$check_sub_format" | grep 'PGS'; then | |
sub_format="sup" | |
printf "\n.SUP (Bluray/PGS)\n" | |
elif echo "$check_sub_format" | grep 'VobSub'; then | |
sub_format="sub" | |
printf "\n.IDX/.SUB (VobSub)\n" | |
fi | |
if [ ! "$sub_format" ]; then | |
printf "\nCouldn't detect a supported subtitle format (.srt/.sup/.idx/.sub)\n" | |
error_subs="_ERR_SUB" | |
case "$1" in | |
"-"*"f"*) | |
if [ $batch -eq 1 ]; then | |
printf "\nRemove -f argument to select a subtitle track for this file if available\n" | |
fi | |
end_error "$1" | |
;; | |
"-"*"F"*) | |
printf "\nContinuing...\n" | |
;; | |
"-"*"S"*) | |
printf "\nSkipping...\n" | |
continue | |
;; | |
*) | |
end_error "$1" | |
;; | |
esac | |
fi | |
printf "\nExtracting video...\n" | |
# if ffmpeg -y -v error -i "$var" -c copy -map 0:v:0 "${folder_path}/hc_temp/${filename}_video_no_sound.tmp.mp4" 2>&1 | grep "Read error"; then | |
burn_ext="mkv" | |
if mkvmerge -o "${folder_path}/hc_temp/${filename}_video_no_sound.tmp.mkv" --no-audio --no-subtitles "${folder_path}/${filename_ext}" | grep "error."; then | |
printf "\nVideo track is corrupt.\n" | |
error_video="_ERR_VIDEO" | |
case "$1" in | |
"-"*"F"*) | |
printf "\nContinuing...\n" | |
;; | |
"-"*"S"*) | |
printf "\nSkipping...\n" | |
del_temp_files "$1" | |
continue | |
;; | |
*) | |
printf "\nCan't extract video from .mkv container\n" | |
end_error "$1" | |
;; | |
esac | |
fi | |
printf "\nExtracting audio and subtitles...\n" | |
if mkvextract tracks "$var" "${audio_track}:${folder_path}/hc_temp/${filename}_audio.tmp.ac3" "${subtitle_track}:${folder_path}/hc_temp/${filename}_subtitles.tmp.${sub_format}" | tail -1 | grep -v "100%"; then | |
printf "\nAudio/subtitles track is corrupt.\n" | |
error_audio="_ERR_AUDIO_SUB" | |
case "$1" in | |
"-"*"F"*) | |
printf "\nContinuing...\n" | |
;; | |
"-"*"S"*) | |
printf "\nSkipping...\n" | |
del_temp_files "$1" | |
continue | |
;; | |
*) | |
printf "\nCan't extract audio/subs from .mkv container\n" | |
end_error "$1" | |
;; | |
esac | |
fi | |
case "$sub_format" in | |
"srt") | |
printf "\nBurning subtitles to video...\n" | |
ffmpeg -y -i "${folder_path}/hc_temp/${filename}_video_no_sound.tmp.${burn_ext}" -vf "subtitles='${folder_path}/hc_temp/${filename}_subtitles.tmp.${sub_format}'" -c:v libx265 -crf 20 -preset ultrafast "${folder_path}/hc_temp/${filename}_video_hardsubs_no_sound.tmp.${burn_ext}" | |
;; | |
"sup" | "sub") | |
printf "\nMuxing video with subtitles...\n" | |
if echo "$sub_format" | grep "sup"; then | |
mkvmerge -o "${folder_path}/hc_temp/${filename}_video_subs_no_sound.tmp.mkv" "${folder_path}/hc_temp/${filename}_video_no_sound.tmp.${burn_ext}" "${folder_path}/hc_temp/${filename}_subtitles.tmp.${sub_format}" | |
else | |
mkvmerge -o "${folder_path}/hc_temp/${filename}_video_subs_no_sound.tmp.mkv" "${folder_path}/hc_temp/${filename}_video_no_sound.tmp.${burn_ext}" "${folder_path}/hc_temp/${filename}_subtitles.tmp.idx" "${folder_path}/hc_temp/${filename}_subtitles.tmp.sub" | |
fi | |
printf "\nBurning subtitles to video...\n" | |
HandBrakeCLI -i "${folder_path}/hc_temp/${filename}_video_subs_no_sound.tmp.mkv" -o "${folder_path}/hc_temp/${filename}_video_hardsubs_no_sound.tmp.mkv" --subtitle 1 --subtitle-burned | |
;; | |
esac | |
printf "\nMuxing video with audio...\n" | |
mkvmerge -o "${folder_path}/hc_temp/${filename}_HC${error_video}${error_audio}${error_subs}.tmp.mkv" "${folder_path}/hc_temp/${filename}_video_hardsubs_no_sound.tmp.${burn_ext}" "${folder_path}/hc_temp/${filename}_audio.tmp.ac3" | |
mkdir -p "${folder_path}/hc_done" | |
mv "${folder_path}/hc_temp/${filename}_HC${error_video}${error_audio}${error_subs}.tmp.mkv" "${folder_path}/hc_done/${filename}_HC${error_video}${error_audio}${error_subs}.mkv" | |
printf "\nCleaning up...\n" | |
del_temp_files "$1" | |
done | |
end "$1" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment