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.