#!/bin/bash

# v0.27.12

# 2015-05-07

# Save this as handofmyth.sh and make the file executable

# HandOfMyth adapted from Mythbrake by Erik Winblad, soulctcher@gmail.com

# Original Mythbrake written by Ares Drake, ares.drake@gmail.com

# Licensed under GPL v3

#

# This Script shall be called as MythTV user job.

# It will transcode the DVB recordings (MPEG files) using Handbrake.

# It will re-encode with H.264 to save space.

#

#RELEASE NOTES:##############

# v0.27.12

# 1- Added in safeguard to sanitize forward slash regardless of the option. Thanks to The Goldbergs for using that character in a subtitle.

# 2- A few tiny cleanup items.

#

# v0.27.11

# 1- Adjusted output file permission to 664 from 660.

# 2- Added a umask 0002 command in front of the directory creation to fix parent directory to be 775.

# 3- Adjusted log directory creation command.

# 4- Added hyphens into the file name to match the format of filebot's output.

# 5- Added an option to turn off sanitizing the title, subtitle, category, season, and episode parameters with sed.

# 6- Corrected a few spots where logic syntax was incorrect.

# 7- Added the switch to bring up to 6 subtitle tracks over to the converted file.

#

# v0.27.10

# 1- Re-added logic in for Title/Season directory structure.

#

# v0.27.9

# 1- Added a fix for the case where there are audio tracks, but none have languages.

#

# v0.27.8

# 1- Fixed the 10th parameter issue created in 0.27.7 by setting off the 10 with curly braces.

#

# v0.27.7

# 1- If the subtitle is empty, add the original air date to give filebot more to go on.

#

# v0.27.6

# 1- Added some more descriptive debugging output.

# 2- Added filebot function to rename the episode using TheTVDB if the episode data

# does not contain any Season/Episode information.

#

# v0.27.5

# 1- Added logic to clear the .tmp file if the script runs successfully.

# 2- Added a successful email notification to the end of the script.

# 3- Added a chmod 660 to the outfile.

#

# v0.27.4

# 1- Re-adjusted HandbrakeCLI settings to 29.97 fps. (The previous setting was jittery.)

#

# v0.27.3

# 1- Adjusted HandbrakeCLI settings to 23.976 frames-per-second.

# 2- Decided to handle commercial cutting transcode internal to the script;

# be sure to flag the commercials prior to running the user script.

#

# v0.27.2

# 1- Moved the directory check further up.

# 2- Added Season/Episode (SxE) and subtitle to filename.

#

# v0.27.1

# 1- Fork of script started after Mythbrake version 1.3b.

# 2- The new numbering schema follows the MythTV numbering.

# 3- Everything will now be converted to H.264.

# 4- The script will default to English.

# 5- It is recommended that you do commercial removal prior to HandOfMyth to relieve complication.

# 6- Checks for log directory existence and tries to create it if missing.

# 7- Adjusted various spelling mistakes through portions of script.

# 8- Adjusted general formatting in a few areas; I will continue to clean this up in further releases.

#

#USAGE:######################

# This Script shall be called as a MythTV user job like as follows:

# /path/to/handofmyth.sh "%DIR%" "%FILE%" "%CHANID%" "%STARTTIMEUTC%" "%TITLE%" "%SUBTITLE%" "%CATEGORY%" "%SEASON%" "%EPISODE%" "%ORIGINALAIRDATE%"

#############################

#

#REQUIREMENTS################

# You need to have the following programs installed:

# mediainfo: http://mediainfo.sourceforge.net/

# handbrake with dependencies: http://www.handbrake.fr/

# filebot with dependencies: http://www.filebot.net/

# Installation of these is covered on their sites

#############################

######SOME CONSTANSTS FOR USER EDITING######

############################################

logdir = "/path/to/log/directory" #change to your needs for logs

errormail = "email@addr.ess" # this email address will be informed in case of errors

outdir = "/output/directory" # specify directory where you want the transcoded file to be placed

sanitize = "true" # if set to true, sed will sanitize some of the parameters

#Audio track (language) selection, your values must match the output syntax of mediainfo

#check "mediainfo --Inform="Audio;%Language/String% yoursourcefile.mpg" in the terminal for syntax

lang_1 = "English" #Primary language you want to keep

lang_2 = "none" #Secondary language you want to keep, use "none" to skip, "qaa" is canonical language, (typically English)

lang_3 = "none" #Third language you want to keep, use "none" to skip

lang1_name = "English" #This is the label of the 1st audio stream inside the final video file

lang2_name = "none" #This is the label of the 2nd audio stream inside the final video file

lang3_name = "none" #This is the label of the 3rd audio stream inside the final video file

######END constants for user editing######

######CHECK FOR LOG########

######DIRECTORY FIRST!#####

if [ ! -d " $logdir " ] ; then

mkdir -p -- " $logdir "

fi

######DEFINE SOME BASIC VARIABLES######

#######################################

scriptstarttime =$ ( date + % F- % H % M % S )

mythrecordingsdir = "$1" # specify directory where MythTV stores its recordings

file = "$2"

# using sed to sanitize the variables to avoid problematic file names, only alphanumerical, space, hyphen and underscore allowed, other characters are transformed to underscore

titlepre = "$5"

if [ sanitize == "true" ]

then

subtitle = " $(echo "$6" | sed 's/[^A-Za-z0-9_ -]/_/g') "

title = " $(echo "$5" | sed 's/[^A-Za-z0-9_ -]/_/g') "

category = " $(echo "$7" | sed 's/[^A-Za-z0-9_ -]/_/g') "

season = " $(echo "$8" | sed 's/[^A-Za-z0-9_ -]/_/g') "

episode = " $(echo "$9" | sed 's/[^A-Za-z0-9_ -]/_/g') "

else

subtitle = " $(echo "$6" | sed 's:/:_:g') "

title = " $(echo "$5" | sed 's:/:_:g') "

category = " $(echo "$7" | sed 's:/:_:g') "

season = " $(echo "$8" | sed 's:/:_:g') "

episode = " $(echo "$9" | sed 's:/:_:g') "

fi

sxe = " $8x$9"

originalairdate = " ${10} "

if [ " $sxe " == " 0x0" ]

then

sxe = ""

fi

chanid = "$3"

starttime = "$4"

if [ -z " $category " ]

then

category = "Unknown" #name for unknown category

fi

logfile = " $logdir / $scriptstarttime - $title .log"

touch " $logfile "

chown mythtv:mythtv " $logfile "

chmod a+rw " $logfile "

#If no subtitle, put the original air date in the subtitle field.

if [ " $subtitle " == "" ]

then

subtitle = " $originalairdate "

fi

filename = " $title - $sxe - $subtitle .mp4" # can be customized

if [ -f " $outdir / $filename " ]

# do not overwrite outfile, if already exists, change name

then

filename = " $title - $sxe - $subtitle - $scriptstarttime .mp4"

fi

let lang_1_count = 0

let lang_2_count = 0

let lang_3_count = 0

lang_1_track = ""

lang_2_track = ""

lang_3_track = ""

######Variables finished

######DO SOME LOGGING######

###########################

echo "Transcode job $title starting at $scriptstarttime " >> " $logfile "

echo "Original file: $mythrecordingsdir / $file " >> " $logfile "

echo "Target file: $outfile " >> " $logfile "

echo "ChanId: $chanid Time: $starttime " >> " $logfile "

echo "The title parameter was: $titlepre " >> " $logfile "

######SOURCEFILE CHECK######

############################

if [ ! -f " $mythrecordingsdir / $file " ]

then

#source file does not exist

scriptstoptime =$ ( date + % F- % H % M % S )

echo "Error at $scriptstoptime : Source file not found " >> " $logfile "

echo "Maybe wrong path or missing permissions?" >> " $logfile "

mail -s "MythTV source file error on $HOSTNAME " " $errormail " < " $logfile "

mv " $logfile " " $logfile -FAILED"

exit 1

fi

######DIRETORY FUN######

########################

echo "Checking if $outdir / $title /Season $season exists" >> " $logfile "

if [ ! -d " $outdir / $title /Season $season " ]

then

echo "Creating $outdir / $title /Season $season " >> " $logfile "

umask 0002

mkdir -m 775 -p -- " $outdir / $title /Season $season "

fi

echo "Setting outdir to $outdir / $title /Season $season " >> " $logfile "

outdir = " $outdir / $title /Season $season "

echo "Setting outfile to $outdir / $filename " >> " $logfile "

outfile = " $outdir / $filename "

######MEDIAINFO CHECK######

###########################

fullmediainfo = ( mediainfo $mythrecordingsdir / " $file " )

if [ $? ! = 0 ]

# There were errors with Mediainfo.

then

scriptstoptime =$ ( date + % F- % H % M % S )

echo "Error prior to encoding at $scriptstoptime " >> " $logfile "

echo "Mediainfo encountered an error. Maybe mediainfo is not installed, or not in your path" >> " $logfile "

echo "Mediainfo encountered an error. Maybe mediainfo is not installed, or not in your path"

mail -s "MythTV Mediainfo Error on $HOSTNAME " " $errormail " < " $logfile "

mv " $logfile " " $logfile -FAILED"

exit 1

else

echo "Mediainfo Run successful." >> " $logfile "

fi

#######ANALAYZE AUDIO TRACKS AND DO LANGUAGE SELECTION######

############################################################

acount =$ ( mediainfo --Inform = "General;%AudioCount%" " $mythrecordingsdir / $file " )

#acount=number of audio tracks present in source file

#Read all values into arrays

bitrate = " $(mediainfo --Inform="Audio;:%BitRate%" "$mythrecordingsdir/$file") "

IFS = ':' read -ra ARBITR <<< " $bitrate "

language = " $(mediainfo --Inform="Audio;:%Language/String%" "$mythrecordingsdir/$file") "

IFS = ':' read -ra ARLANG <<< " $language "

channels = " $(mediainfo --Inform="Audio;:%Channel(s) %" " $mythrecordingsdir / $file " ) "

IFS=':' read -ra ARCHAN <<< " $channels "

acodec=" $ ( mediainfo --Inform = "Audio;:%Format%" " $mythrecordingsdir / $file " ) "

IFS=':' read -ra ARCODEC <<< " $acodec "

#Finished building arrays

echo " Array built successful, starting looping over audio tracks. There are $acount tracks, so we loop $acount times. " >> " $logfile "

for (( I=1; I <= " $acount "; I++ ))

do

#loop through all tracks, currently active track is $I

# ${ARBITR[$I]} , ${ARLANG[$I]} , ${ARCHAN[$I]} , ${ARCODEC[$I]} gives values for track $I

echo " loop number $I . " >> " $logfile "

#select track for first language

currentlang= ${ARLANG[$I]}

if [ -z " $currentlang " ]

then

currentlang=" English "

fi

if [ " $currentlang " == " $lang_1 " ]

then

echo -n " track $I matching $lang1_name " >> " $logfile "

let " lang_1_count += 1 " #let $lang_1_count = $lang_1_count +1

if [ $lang_1_count -eq 1 ]

then

#if this is the first track with desired language, we use it.

echo " and is the first track matching " >> " $logfile "

lang_1_track= $I

let lang_1_chan=" ${ARCHAN[$I]} "

lang_1_codec=" ${ARCODEC[$I]} "

elif [ " ${ARCHAN[$I]} " -gt " ${ARCHAN[$lang_1_track]} " ]

then

echo " and is better than previous match " >> " $logfile "

#there is already a track with the same desired language but this current track

#has more channels, so we use this one instead of the previous track.

lang_1_track= $I

let lang_1_chan= ${ARCHAN[$I]}

lang_1_codec=" ${ARCODEC[$I]} "

fi

fi

echo " Audio track1 iteration successful " >> " $logfile "

#select track for second language

if [ " $lang_2 " != " none " ]

then

if [ " $currentlang " == " $lang_2 " ]

then

echo -n " track $I matching $lang2_name " >> " $logfile "

let " lang_2_count += 1 "

if [ $lang_2_count -eq 1 ]

then

#if this is the first track with desired language, we use it.

echo " and is the first track matching " >> " $logfile "

let lang_2_track= $I

let lang_2_chan=" ${ARCHAN[$I]} "

lang_2_codec=" ${ARCODEC[$I]} "

elif [ " ${ARCHAN[$I]} " -gt " ${ARCHAN[$lang_2_track]} " ]

then

echo " and is better than previous match " >> " $logfile "

#there is already a track with the same desired language but this current track

#has more channels, so we use this one instead of the previous track.

let lang_2_track= $I

let lang_2_chan= ${ARCHAN[$I]}

lang_2_codec=" ${ARCODEC[$I]} "

fi

fi

fi

echo " Audio track2 iteration successful " >> " $logfile "

if [ " $lang_3 " != " none " ]

then

#select track for third language

if [ " $currentlang " == " $lang_3 " ]

then

echo -n " track $I matching $lang3_name " >> " $logfile "

let " lang_3_count += 1 "

if [ $lang_3_count -eq 1 ]

then

#if this is the first track with desired language, we use it.

echo " and is the first track matching " >> " $logfile "

let lang_3_track= $I

let lang_3_chan=" ${ARCHAN[$I]} "

lang_3_codec=" ${ARCODEC[$I]} "

elif [ " ${ARCHAN[$I]} " -gt " ${ARCHAN[$lang_3_track]} " ]

then

echo " and is better than previous match " >> " $logfile "

#there is already a track with the same desired language but this current track

#has more channels, so we use this one instead of the previous track.

let lang_3_track= $I

let lang_3_chan=" ${ARCHAN[$I]} "

lang_3_codec=" ${ARCODEC[$I]} "

fi

fi

fi

echo " Audio track3 iteration successful " >> " $logfile "

done

echo " Audio track iteration successful " >> " $logfile "

#okay, how may tracks to include in the outfile now?

let totallangcount=( $lang_1_count + $lang_2_count + $lang_3_count )

if [ $totallangcount -eq 0 ]

# No suitable audio track found.

then

scriptstoptime= $(date +%F-%H%M%S)

echo " Audio track error at $scriptstoptime " >> " $logfile "

echo " The script was unable to find a matching audio track, aborting. " >> " $logfile "

mail -s " MythTV Audio Track Error on $HOSTNAME " " $errormail " < " $logfile "

mv " $logfile " " $logfile -FAILED "

exit 1

else

echo " Audio selection successful. " >> " $logfile "

fi

echo " Total number of tracks selected: $totallangcount " >> " $logfile "

###Now generate Handbrake commands from the above####

if [ $lang_1_count -ge 1 ]

then

echo " Selected track $lang_1_track for $lang_1 " >> " $logfile "

audiotacks=" $lang_1_track " #Handbrake_CLI -a

if [ $lang_1_chan -gt 2 ]

# more than 2 channels present, pass through track without transcoding,perfect quality

then

audioname=" $lang1_name -Surround " #Handbrake_CLI -A

audiocodec=" copy " #Handbrake_CLI -E

audiobitrate=" auto " #Handbrake_CLI -B

audiodownmix=" auto " #Handbrake_CLI -6

else

audioname=" $lang1_name -Stereo "

audiocodec=" faac "

audiobitrate=" 128 "

audiodownmix=" stereo "

fi

else

echo " No track found for $lang_1 = $lang1_name " >> " $logfile "

fi

if [ $lang_2_count -ge 1 ]

then

echo " Selected track $lang_2_track for $lang_2 " >> " $logfile "

if [ -z " $audiotacks " ]

#no track for first language present

then

audiotacks=" $lang_2_track " #Handbrake_CLI -a

if [ $lang_2_chan -gt 2 ]

# more than 2 channels present

#pass through track without transcoding,perfect quality

then

audioname=" $lang2_name -Surround " #Handbrake_CLI -A

audiocodec=" copy " #Handbrake_CLI -E

audiobitrate=" auto " #Handbrake_CLI -B

audiodownmix=" auto " #Handbrake_CLI -6

else

audioname=" $lang2_name -Stereo "

audiocodec=" faac "

audiobitrate=" 128 "

audiodownmix=" stereo "

fi

else

#first track present, append

audiotacks=" $audiotracks , $lang_2_track " #Handbrake_CLI -a

if [ $lang_2_chan -gt 2 ]

# more than 2 channels present

#pass through track without transcoding,perfect quality

then

audioname=" $audioname , $lang2_name -Surround " #Handbrake_CLI -A

audiocodec=" $audiocodec ,copy " #Handbrake_CLI -E

audiobitrate=" $audiobitrate ,auto " #Handbrake_CLI -B

audiodownmix=" $audiodownmix ,auto " #Handbrake_CLI -6

else

audioname=" $audioname , $lang2_name -Stereo "

audiocodec=" $audiocodec ,faac "

audiobitrate=" $audiobitrate , 128 "

audiodownmix=" $audiodownmix ,stereo "

fi

fi

else

echo " No track found for $lang_2 = $lang2_name " >> " $logfile "

fi

if [ $lang_3_count -ge 1 ]

then

echo " Selected track $lang_3_track for $lang_3 " >> " $logfile "

if [ -z " $audiotacks " ]

#no track for first or second language present

then

audiotacks=" $lang_3_track " #Handbrake_CLI -a

if [ $lang_3_chan -gt 2 ]

# more than 2 channels present

#pass through track without transcoding,perfect quality

then

audioname=" $lang3_name -Surround " #Handbrake_CLI -A

audiocodec=" copy " #Handbrake_CLI -E

audiobitrate=" auto " #Handbrake_CLI -B

audiodownmix=" auto " #Handbrake_CLI -6

else

audioname=" $lang3_name -Stereo "

audiocodec=" faac "

audiobitrate=" 128 "

audiodownmix=" stereo "

fi

else

#previous track present, append

audiotacks=" $audiotracks , $lang_3_track " #Handbrake_CLI -a

if [ $lang_3_chan -gt 2 ]

# more than 2 channels present

#pass through track without transcoding,perfect quality

then

audioname=" $audioname , $lang3_name -Surround " #Handbrake_CLI -A

audiocodec=" $audiocodec ,copy " #Handbrake_CLI -E

audiobitrate=" $audiobitrate ,auto " #Handbrake_CLI -B

audiodownmix=" $audiodownmix ,auto " #Handbrake_CLI -6

else

audioname=" $audioname , $lang3_name -Stereo "

audiocodec=" $audiocodec ,faac "

audiobitrate=" $audiobitrate , 128 "

audiodownmix=" $audiodownmix ,stereo "

fi

fi

else

echo " No track found for $lang_3 = $lang3_name " >> " $logfile "

fi

echo " Finished Audio Selection " >> " $logfile "

#################FINISHED AUDIO TRACK SELECTION############

echo " $audiotacks , $audioname , $audiocodec , $audiobitrate , $audiodownmix "

echo " $audiotacks , $audioname , $audiocodec , $audiobitrate , $audiodownmix " >> " $logfile "

#HandBrakeCLI -q 19.0 -e x264 -r 25 -a $audiotacks -A $audioname -E $audiocodec -B $audiobitrate -6 $audiodownmix -f mp4 --crop 0:0:0:0 -d -m -x b-adapt=2:rc-lookahead=50:ref=3:bframes=3:me=umh:subme=8:trellis=1:merange=20:direct=auto -i " $mythrecordingsdir / $file " -o " $outfile " -4 --optimize 2>> " $logfile "

##############################################################

### Hard cut the commercials here using the generated cut list.

echo " Generate cutlist " >> " $logfile "

mythutil --gencutlist --chanid " $chanid " --starttime " $starttime "

echo " Transcode and honor cutlist " >> " $logfile "

mythtranscode --chanid " $chanid " --starttime " $starttime " --mpeg2 --honorcutlist

mythcommflag --file " $file .tmp " --rebuild

##############################################################

### Transcoding starts here.

# User job: Re-encode in AVC H.264: saves space, but keeps H.264, x264 via HandbrakeCLI

echo " User job Re-encode starts " >> " $logfile "

echo " audiotacks = $audiotacks audioname = $audioname audiocodec = $audiocodec audiobitrate = $audiobitrate audiodownmix = $audiodownmix mythrecordingsdir = $mythrecordingsdir file = $file outfile = $outfile " >> " $logfile "

HandBrakeCLI -q 21.0 -e x264 -r 29.97 -a " $audiotacks " -A " $audioname " -E " $audiocodec " -B " $audiobitrate " -6 " $audiodownmix " -f mp4 -d -m -s 1,2,3,4,5,6 -x b-adapt=2:rc-lookahead=40:ref=3:bframes=3:me=umh:subme=8:trellis=1:merange=16:direct=auto -i " $mythrecordingsdir / $file .tmp " --output " $outfile " -4 --optimize --two-pass >> " $logfile "

if [ $? != 0 ]

# There were errors in the Handbrake Run.

then

scriptstoptime= $(date +%F-%H%M%S)

echo " Transcoding-Error at $scriptstoptime " >> " $logfile "

echo " Interrupted file $outfile " >> " $logfile "

echo " ###################################" >> "$logfile"

echo $fullmediainfo >> " $logfile "

echo "###################################" >> " $logfile "

outmediainfo = ( mediainfo " $outfile " )

echo $outmediainfo >> " $logfile "

echo "###################################" >> " $logfile "

mail -s "MythTV Transcoding Error on $HOSTNAME " " $errormail " < " $logfile "

mv " $logfile " " $logfile -FAILED"

exit 1

else

echo "Transcode Run successful." >> " $logfile "

file " $outfile " >> " $logfile "

fi

#check if outfile exists

if [ ! -f " $outfile " ] ;

then

scriptstoptime =$ ( date + % F- % H % M % S )

echo "Output-Error at $scriptstoptime " >> " $logfile "

echo "Output file $outfile does not exist" >> " $logfile "

echo "###################################" >> " $logfile "

echo $fullmediainfo >> " $logfile "

echo "###################################" >> " $logfile "

outmediainfo = ( mediainfo " $outfile " )

echo $outmediainfo >> " $logfile "

echo "###################################" >> " $logfile "

mail -s "MythTV output file error on $HOSTNAME " " $errormail " < " $logfile "

mv " $logfile " " $logfile -FAILED"

exit 1

fi

scriptstoptime =$ ( date + % F- % H % M % S )

echo "successfully finished at $scriptstoptime " >> " $logfile "

echo "Transcoded file: $outfile " >> " $logfile "

#Transcoding now done, following is some maintenance work

chown mythtv:mythtv " $outfile "

chmod 664 " $outfile "

#If no SxE, run filebot to grab information on the show

echo "sxe=[ $sxe ]"

if [ " $sxe " = "" ]

then

echo "SxE is blank, running episode through filebot" >> " $logfile "

filebot -rename " $outfile " --db TheTVDB -non-strict >> " $logfile "

fi

#Further maintenance work

echo "Removing $mythrecordingsdir / $file .tmp." >> " $logfile "

rm -fv " $mythrecordingsdir / $file .tmp" >> " $logfile "

mail -s "MythTV has successfully recorded $title $sxe $subtitle " " $errormail " < " $logfile "