mythtv-handbrake.sh

A working script to convert Mythtv recordings to x265 below, it cuts the commercials out too.

#!/bin/bash
#By:
#http://reubencrane.com/blog/?p=80
#Modified by Marty Gilbert, 04/15/2013
#My attempt to cut commercials from myth recording and save as mkv
#Run as MythTV User Job with %FILE% as argument 1
#Argument 1: filename
######## USER SETTINGS ###############
logdir="/var/log/mythtv"
mythrecordingsdir="/media/xxx/TV/Recorded"
tmpdir="/media/xxx/TV/tmp"
outdir="/media/xxx/TV/Transcoded"
#outdir="/tmp"
scriptstarttime=$(date +%F-%H%M%S)
logfile="$logdir/$scriptstarttime-COMCUT.log"
#Database Info
USER="mythtv";
PASS="mythtv";
DB="mythconverg";
HANDBRAKE="/bin/HandBrakeCLI";
FFMPEG="/bin/ffmpeg";
MKVMERGE="/bin/mkvmerge";
######## NICE THE PROCESS ##################3
MYPID=$$
renice 19 $MYPID
ionice -c 3 -p $MYPID
######## CLEAN-UP FROM PREVIOUS JOB ###############
rm -f $tmpdir/tmp*.mpg*
######## GET INFO FROM DB ###############
CHANID=$(echo $1 | cut -c 1-4);
STARTTIME=$(echo $1 | cut -c 6-19);
#Retrieve recording info from mysql
W=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT data FROM recordedmarkup WHERE chanid=$CHANID AND starttime=$STARTTIME AND type=30;");
L=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT data FROM recordedmarkup WHERE chanid=$CHANID AND starttime=$STARTTIME AND type=31;");
FPS=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT data FROM recordedmarkup WHERE chanid=$CHANID AND starttime=$STARTTIME AND type=32;");
#type values/meanings in recordedmarkup:
#   0 MARK_CUT_END
#   1 MARK_CUT_START
#   4 MARK_COMM_START
#   5 MARK_COMM_END
QRY=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT type,mark FROM recordedmarkup WHERE chanid=$CHANID AND starttime=$STARTTIME AND type in (0,1,4,5) ORDER BY mark;");
NAME=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT title FROM recordedprogram WHERE chanid=$CHANID AND starttime=$STARTTIME;");
USTART=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT unix_timestamp(starttime) FROM recordedprogram WHERE chanid=$CHANID AND starttime=$STARTTIME;");
MYSTART=`date "+%Y_%m_%d_%I%M" -d "@$USTART"`
NAME=`echo "$NAME" | sed 's/ /_/g' | sed 's/://g' | sed 's/?//g' | sed s/"'"/""/g`
NAME="$MYSTART"_"$NAME";
#debug
echo "Query: $QRY" >> "$logfile";
echo "FPS: $FPS" >> "$logfile";
echo "NAME: $NAME" >> "$logfile";
echo "L: $L" >> "$logfile";
echo "W: $W" >> "$logfile";
##############
# FUNCTIONS
##############
#### ffmpeg Cut Src Files into clips ###
function ffmpeg_cut_src {
    #convert QRY to array
    array=( $( for i in $QRY ; do echo $i ; done ) )
    SS=0.0 #SLOW SEEK
    SKIP=0 #FAST SEEK
    cnt=${#array[@]} #NUMBER OF ARRAY ELEMENTS
    if [ "$cnt" -eq 0 ]; then
        #encode file to the $tmpdir so it can be processed
        #does this do anything? or can I just copy it?
        "$FFMPEG" -i "$mythrecordingsdir/$1" -vcodec copy -acodec copy "$tmpdir/tmp_orig.mpg"
        #cp "mythrecordingsdir/$1" "$tmpdir/tmp_orig.mpg"
        echo "No slices. One big file" >> "$logfile"
        return 1;
    fi
    for (( i=0 ; i> "$logfile"
        if [ "$1" -eq 1 ]; then
            echo "only one file found" >> "$logfile";
            output="$outdir/$NAME.mkv"
        else
            output="$file.mkv"
        fi
        "$HANDBRAKE" -i "$file" -o "$output" -f mkv -e x265 -Z "H.265 MKV 720p30" -q 30 -E copy:ac3
        echo "HandBrakeCLI exit code:$?" >> "$logfile"
    done
}
#### MKVMERGE FILES ######
function merge_files {
    MERGE=" "
    PLUS=""
    #for file in $(find $tmpdir -name tmp\*.mpg.mkv | sort); do
    #echo "for file in $(ls -rt $tmpdir/tmp*.mpg.mkv); do"
    for file in $(ls -1 $tmpdir/tmp*.mpg.mkv); do
        echo "File Found for Merging - $file"
        MERGE=$(echo "$MERGE $PLUS$file")
        PLUS="+"
    done
    echo "$MKVMERGE" -o $outdir/$NAME.mkv "$MERGE" >> "$logfile"
    "$MKVMERGE" -o $outdir/$NAME.mkv $MERGE
    echo "mkvmerge exit code:$? " >> "$logfile"
}
###### END OF FUNCTIONS #########
######## BEGIN MAIN EXECUTION ###############
echo "ComCut & Transcode job $1 starting at $scriptstarttime" >> "$logfile"
#cut the file, if commercials were flagged
ffmpeg_cut_src $1;
numslices=$?
#Encode the slice(s)
handbrake_encode $numslices;
#If more than one slice, combine them
if [ "$numslices" -gt 1 ]; then
    merge_files;
fi
echo "Job Finished! $(date +%F-%H%M%S)"  >> "$logfile"
######## END MAIN EXECUTION ###############

You can make a userjob to run it. Just use %FILE% as the first argument.
The converted Simpsons with no commercials is 137.5 MB.
I added the Transcoded folder to Plex, the MythRecordings plugin for Plex, doesn’t say which recordings you’ve watched. So I’ll just use Plex, and save on space. Assuming I delete the original files.
Doesn’t take very long to transcode it either.
The audio will be copied, assuming it’s ac3, that’s what my recordings are in. You might need to change “-E copy:ac3”.
And thanks to the Filename, Plex doesn’t find it, if you add the folder as TV Shows. Going to have to change the output filename in the script, no date, and just The Simpsons followed by episode.
Update
Script with filenames that Plex likes below. The filename will look like “Family.Guy.S16E9”. Oh and you need a Python script, unless you know bash, then you can read the xml from bash. Easier in Python.
mythtv-handbrake.sh:

#!/bin/bash
#By:
#http://reubencrane.com/blog/?p=80
#Modified by Marty Gilbert, 04/15/2013
#My attempt to cut commercials from myth recording and save as mkv
#Run as MythTV User Job with %FILE% as argument 1
#Argument 1: filename
######## USER SETTINGS ###############
logdir="/var/log/mythtv"
mythrecordingsdir="/media/xxx/TV/Recorded"
tmpdir="/media/xxx/TV/tmp"
outdir="/media/xxx/TV/Transcoded"
#outdir="/tmp"
scriptstarttime=$(date +%F-%H%M%S)
logfile="$logdir/$scriptstarttime-COMCUT.log"
#Database Info
USER="mythtv";
PASS="mythtv";
DB="mythconverg";
HANDBRAKE="/bin/HandBrakeCLI";
FFMPEG="/bin/ffmpeg";
MKVMERGE="/bin/mkvmerge";
######## NICE THE PROCESS ##################3
MYPID=$$
renice 19 $MYPID
ionice -c 3 -p $MYPID
######## CLEAN-UP FROM PREVIOUS JOB ###############
rm -f $tmpdir/tmp*.mpg*
######## GET INFO FROM DB ###############
CHANID=$(echo $1 | cut -c 1-4);
STARTTIME=$(echo $1 | cut -c 6-19);
#Retrieve recording info from mysql
W=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT data FROM recordedmarkup WHERE chanid=$CHANID AND starttime=$STARTTIME AND type=30;");
L=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT data FROM recordedmarkup WHERE chanid=$CHANID AND starttime=$STARTTIME AND type=31;");
FPS=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT data FROM recordedmarkup WHERE chanid=$CHANID AND starttime=$STARTTIME AND type=32;");
#type values/meanings in recordedmarkup:
#   0 MARK_CUT_END
#   1 MARK_CUT_START
#   4 MARK_COMM_START
#   5 MARK_COMM_END
QRY=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT type,mark FROM recordedmarkup WHERE chanid=$CHANID AND starttime=$STARTTIME AND type in (0,1,4,5) ORDER BY mark;");
NAME=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT title FROM recordedprogram WHERE chanid=$CHANID AND starttime=$STARTTIME;");
EP=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT subtitle FROM recordedprogram WHERE chanid=$CHANID AND starttime=$STARTTIME;");
USTART=$(mysql -u$USER -p$PASS $DB --disable-column-names -e "SELECT unix_timestamp(starttime) FROM recordedprogram WHERE chanid=$CHANID AND starttime=$STARTTIME;");
MYSTART=`date "+%Y_%m_%d_%I%M" -d "@$USTART"`
#NAME="$MYSTART"_"$NAME";
SE=`/usr/local/bin/xmlcat.py "$NAME" "$EP"`
NAME=`echo "$NAME" | sed 's/ /./g' | sed 's/://g' | sed 's/?//g' | sed s/"'"/""/g`;
NAME="$NAME"."$SE"
#debug
echo "Query: $QRY" >> "$logfile";
echo "FPS: $FPS" >> "$logfile";
echo "NAME: $NAME" >> "$logfile";
echo "L: $L" >> "$logfile";
echo "W: $W" >> "$logfile";
##############
# FUNCTIONS
##############
#### ffmpeg Cut Src Files into clips ###
function ffmpeg_cut_src {
    #convert QRY to array
    array=( $( for i in $QRY ; do echo $i ; done ) )
    SS=0.0 #SLOW SEEK
    SKIP=0 #FAST SEEK
    cnt=${#array[@]} #NUMBER OF ARRAY ELEMENTS
    if [ "$cnt" -eq 0 ]; then
        #encode file to the $tmpdir so it can be processed
        #does this do anything? or can I just copy it?
        "$FFMPEG" -i "$mythrecordingsdir/$1" -vcodec copy -acodec copy "$tmpdir/tmp_orig.mpg"
        #cp "mythrecordingsdir/$1" "$tmpdir/tmp_orig.mpg"
        echo "No slices. One big file" >> "$logfile"
        return 1;
    fi
    for (( i=0 ; i> "$logfile"
        if [ "$1" -eq 1 ]; then
            echo "only one file found" >> "$logfile";
            output="$outdir/$NAME.mkv"
        else
            output="$file.mkv"
        fi
        "$HANDBRAKE" -i "$file" -o "$output" -f mkv -e x265 -Z "H.265 MKV 720p30" -q 30 -E copy:ac3
        echo "HandBrakeCLI exit code:$?" >> "$logfile"
    done
}
#### MKVMERGE FILES ######
function merge_files {
    MERGE=" "
    PLUS=""
    #for file in $(find $tmpdir -name tmp\*.mpg.mkv | sort); do
    #echo "for file in $(ls -rt $tmpdir/tmp*.mpg.mkv); do"
    for file in $(ls -1 $tmpdir/tmp*.mpg.mkv); do
        echo "File Found for Merging - $file"
        MERGE=$(echo "$MERGE $PLUS$file")
        PLUS="+"
    done
    echo "$MKVMERGE" -o $outdir/$NAME.mkv "$MERGE" >> "$logfile"
    "$MKVMERGE" -o $outdir/$NAME.mkv $MERGE
    echo "mkvmerge exit code:$? " >> "$logfile"
}
###### END OF FUNCTIONS #########
######## BEGIN MAIN EXECUTION ###############
echo "ComCut & Transcode job $1 starting at $scriptstarttime" >> "$logfile"
#cut the file, if commercials were flagged
ffmpeg_cut_src $1;
numslices=$?
#Encode the slice(s)
handbrake_encode $numslices;
#If more than one slice, combine them
if [ "$numslices" -gt 1 ]; then
    merge_files;
fi
echo "Job Finished! $(date +%F-%H%M%S)"  >> "$logfile"
######## END MAIN EXECUTION ###############

xmlcat.py:

#!/usr/bin/env python
import sys
import subprocess
from lxml import etree
from io import BytesIO
ttv = subprocess.run(['/usr/share/mythtv/metadata/Television/ttvdb.py', '-N', sys.argv[1], sys.argv[2]], stdout=subprocess.PIPE)
for _, element in etree.iterparse(BytesIO(ttv.stdout), tag='season'):
     se = "S" + element.text
     element.clear()
for _, element in etree.iterparse(BytesIO(ttv.stdout), tag='episode'):
     ep = "E" + element.text
     element.clear()
print(se + ep)

I’m to lazy to rewrite the shell script in something else, like Python, or Ruby. Not smart enough either, you might need to understand Bash to do it.
mythtv-handbrake.tar.gz
Both of the files are in that archive.
I didn’t test the complete script, I just tested the code to get the filename. Put the related part in a separate shell script, and made it echo the $NAME.