#!/bin/bash
# hb.sh uses HandBrakeCLI to convert whole DVDs automatically.
# Copyright (C) 2007 Brian Beardmore
# Copyright (C) 2008 Chris Pepper
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# This script requires HandBrakeCLI .
# This script searches the entire input directory directory tree looking
# for TS_VIDEO directories looking for DVDs to encode. The output mp4
# filename is the DVD volume name. When multiple tracks are to encoded
# from a DVD, the output filename is appended with the track number.
# For example, 'Monsters, Inc.' DVD has both standard and wide screen tracks
# so there are 'Monsters, Inc.1.mp4' & 'Monsters, Inc.10.mp4' files created.
# For addition information on this script contact the script's original author,
# Brian Beardmore at medfk(at)realisticsoftware(dot)com or
# http://www.realisticsoftware.com
# Or contact Chris Pepper .
# Examples
# $ ./appletv.sh
# [ encodes all DVDs mounted and encodes any tracks longer than 60min ]
# [ to the mp4 folder in the users Movies folder ]
# $ appletv.sh -i ~/Movies -o toPod -b 1000 -w 576 --minGetTime 50
# [ encodes all DVDs found in the users Movies folder and encodes any ]
# [ tracks longer than 50min, with a 1000kb/s bitrate and scales the output ]
# [ movie to a width of 576 pixels and puts the resulting mp4 files in the ]
# [ toPod folder in the current directory that the command was executed from ]
# Syntax: HandBrakeCLI [options] -i -o
#
# ### General Handbrake Options------------------------------------------------
#
# -h, --help Print help
# -u, --update Check for updates and exit
# -v, --verbose <#> Be verbose (optional argument: logging level)
# -C, --cpu Set CPU count (default: autodetected)
# -Z. --preset Use a built-in preset. Capitalization matters, and
# if the preset name has spaces, surround it with
# double quotation marks
# -z, --preset-list See a list of available built-in presets
#
# ### Source Options-----------------------------------------------------------
#
# -i, --input Set input device
# -t, --title Select a title to encode (0 to scan only,
# default: 1)
# -L, --longest Select the longest title
# -c, --chapters Select chapters (e.g. "1-3" for chapters
# 1 to 3, or "3" for chapter 3 only,
# default: all chapters)
#
# ### Destination Options------------------------------------------------------
#
# -o, --output Set output file name
# -f, --format Set output format (avi/mp4/ogm/mkv, default:
# autodetected from file name)
# -m, --markers Add chapter markers (mp4 and mkv output formats only)
# -4, --large-file Use 64-bit mp4 files that can hold more than
# 4 GB. Note: Breaks iPod, PS3 compatibility.
# -O, --optimize Optimize mp4 files for HTTP streaming
# -I, --ipod-atom Mark mp4 files so 5.5G iPods will accept them
#
# ### Video Options------------------------------------------------------------
#
# -e, --encoder Set video library encoder (ffmpeg,xvid,
# x264,theora default: ffmpeg)
# -x, --x264opts Specify advanced x264 options in the
# same style as mencoder:
# option1=value1:option2=value2
# -q, --quality Set video quality (0.0..1.0)
# -Q, --cqp Use with -q for CQP instead of CRF
# -S, --size Set target size
# -b, --vb Set video bitrate (default: 1000)
# -2, --two-pass Use two-pass mode
# -T, --turbo When using 2-pass use the turbo options
# on the first pass to improve speed
# (only works with x264, affects PSNR by about 0.05dB,
# and increases first pass speed two to four times)
# -r, --rate Set video framerate (5/10/12/15/23.976/24/25/29.97)
# Be aware that not specifying a framerate lets
# HandBrake preserve a source's time stamps,
# potentially creating variable framerate video
#
# ### Audio Options-----------------------------------------------------------
#
# -a, --audio Select audio track(s), separated by commas
# More than one output track can be used for one
# input.
# ("none" for no audio, "1,2,3" for multiple
# tracks, default: first one)
# -E, --aencoder Audio encoder(s) (faac/lame/vorbis/ac3)
# ac3 meaning passthrough
# Separated by commas for more than one audio track.
# (default: guessed)
# -B, --ab Set audio bitrate(s) (default: 160)
# Separated by commas for more than one audio track.
# -6, --mixdown Format(s) for surround sound downmixing
# Separated by commas for more than one audio track.
# (mono/stereo/dpl1/dpl2/6ch, default: dpl2)
# -R, --arate Set audio samplerate(s) (22.05/24/32/44.1/48 kHz)
# Separated by commas for more than one audio track.
# -D, --drc Apply extra dynamic range compression to the audio,
# making soft sounds louder. Range is 1.0 to 4.0
# (too loud), with 1.5 - 2.5 being a useful range.
# Separated by commas for more than one audio track.
# -A, --aname Audio track name(s),
# Separated by commas for more than one audio track.
#
# ### Picture Settings---------------------------------------------------------
#
# -w, --width Set picture width
# -l, --height Set picture height
# --crop Set cropping values (default: autocrop)
# -Y, --maxHeight <#> Set maximum height
# -X, --maxWidth <#> Set maximum width
# -p, --pixelratio Store pixel aspect ratio in video stream
# -P, --loosePixelratio Store pixel aspect ratio with specified width
# Takes as optional arguments what number you want
# the dimensions to divide cleanly by (default 16)
# and the pixel ratio to use (default autodetected)
# -M --color-matrix Set the color space signaled by the output
# <601 or 709> (Bt.601 is mostly for SD content, Bt.709 for HD,
# default: set by resolution)
#
# ### Filters---------------------------------------------------------
#
# -d, --deinterlace Deinterlace video with yadif/mcdeint filter
# (default 0:-1:-1:1)
# or
#
# -5, --decomb Selectively deinterlaces when it detects combing
# (default: 1:2:6:9:80:16:16)
# -9, --detelecine Detelecine (ivtc) video with pullup filter
# Note: this filter drops duplicate frames to
# restore the pre-telecine framerate, unless you
# specify a constant framerate (--rate 29.97)
# (default 1:1:4:4:0:0)
# -8, --denoise Denoise video with hqdn3d filter
# (default 4:3:6:4.5)
# or
#
# -7, --deblock Deblock video with pp7 filter
# (default 5:2)
# -g, --grayscale Grayscale encoding
#
# ### Subtitle Options------------------------------------------------------------
#
# -s, --subtitle Select subtitle (default: none)
# -U, --subtitle-scan Scan for subtitles in an extra 1st pass, and choose
# the one that's only used 10 percent of the time
# or less. This should locate subtitles for short
# foreign language segments. Best used in conjunction
# with --subtitle-forced.
# -F, --subtitle-forced Only display subtitles from the selected stream if
# the subtitle has the forced flag set. May be used in
# conjunction with --subtitle-scan to auto-select
# a stream if it contains forced subtitles.
# -N, --native-language Select subtitles with this language if it does not
# match the Audio language. Provide the language's
# iso639-2 code (fre, eng, spa, dut, et cetera)
# Revision history:
# 1.0.7, 2008/12 -- Update for HandBrake 0.9.3, and use presets.
# 1.0.6 -- never released.
# 1.0.5, 2008/08 -- Require bash, per ebb.
# 1.0.4, 2008/06 -- Use different suffices so different flavors can coexist.
# 1.0.3, 2008/05 -- Add basic argument processing, so "appletv" and "iphone" as argument #1 produce different output.
# 1.0.2, 2008/05 -- hacks by Pepper to use HandBrakeCLI and optimize for AppleTV.
# 1.0.1, 2008/02/24 -- hacks by Pepper to use HandBrakeCLI and optimize for iPhone.
# 0.20070329.0 - initial release
#############################################################################
# globals
# const global variables
scriptName=`basename "$0"`
scriptVers="1.0.7"
scriptPID=$$
saveDVDinfo=1 # the DVD track info is also saved as .txt file when set
skipDuplicates=1 # if this option is off, overwrite existing files
E_BADARGS=65
if [[ $# = 0 ]]
then
myArgs='$HANDBRAKE_ARGS -Z AppleTV'
elif [[ $1 = "appletv" ]]
then
myArgs='$HANDBRAKE_ARGS -Z AppleTV'
mySuffix=AppleTV
elif [[ $1 = "AppleTV" ]]
then
myArgs='$HANDBRAKE_ARGS -Z AppleTV'
mySuffix=AppleTV
elif [[ $1 = "iphone" ]]
then
myArgs='$HANDBRAKE_ARGS -Z "iPhone & iPod Touch"'
mySuffix=iPhone
elif [[ $1 = "iPhone" ]]
then
myArgs='$HANDBRAKE_ARGS -Z "iPhone & iPod Touch"'
mySuffix=iPhone
else
echo "Unknown format -- aborting!"
exit 1
fi
# set the global variables to defaults
toolName="HandBrakeCLI"
toolPath="$HOME/bin/$toolName"
toolTrackArgs="-t 0"
toolArgs="-v"
inputSearchDir="$HOME/tivo-inspector/input/$mySuffix"
outputDir="$HOME/tivo-inspector/output"
minTrackTime="3" # in minutes
# Pepper's sometime options:
# -s 1 # first subtitle
# -a 2 # second audio track ??
# For example (best within screen): HANDBRAKE_ARGS="-s1 -t11" iphone.sh
#############################################################################
# functions
parseProcessInArgs()
{
if [ -z "$1" ]; then
return
fi
toolArgs=""
while [ ! -z "$1" ]
do
case "$1" in
-h) displayUsageExit ;;
--help) displayUsageExit ;;
-i) inputSearchDir=$2
shift ;;
--input) inputSearchDir=$2
shift ;;
-o) outputDir=$2
shift ;;
--output) outputDir=$2
shift ;;
--minGetTime) minTrackTime=$2
shift ;;
*) toolArgs="$toolArgs $1" ;;
esac
shift
done
}
verifyFindCLTool()
{
# attempt to find the HandBrakeCLI if the script toolPath is not good
if [ ! -x "$toolPath" ];
then
toolPathTMP=`PATH=.:/Applications:/:/usr/bin:/usr/local/bin:$HOME:$PATH which $toolName | sed '/^[^\/]/d' | sed 's/\S//g'`
if [ ! -z $toolPathTMP ]; then
toolPath=$toolPathTMP
fi
fi
}
displayUsageExit()
{
echo "Usage: $scriptName [options]"
echo ""
echo " -h, --help Print help"
echo " -i, --input Set input directory to process all DVDs in it (default: /Volumes/)"
echo " -o, --output Set output directory for all output files (default: ~/Movies/mp4/)"
echo " --minGetTime Set the minimum time (mins) of the track/s to encode (default: 60)"
if [ -x "$toolPath" ];
then
echo " $toolName possible options"
hBrakeHelp=`$toolPath --help 2>&1`
hBrakeHelpPt=`printf "$hBrakeHelp" | egrep -v '( --input| --output| --help|Syntax: |^$)'`
printf "$hBrakeHelpPt\n"
else
echo " The options available to HandBrakeCLI except -o and -i"
if [ -e "$toolPath" ];
then
echo " ERROR: $toolName command tool is not set up to execute"
echo " ERROR: attempting to use tool at $toolPath"
else
echo " ERROR: $toolName command tool could not be found"
echo " ERROR: $toolName can be installed in ./ /usr/local/bin/ /usr/bin/ ~/ or /Applications/"
fi
fi
echo ""
exit $E_BADARGS
}
getTrackListLongerThan()
{
# Two input arguments are are need.
# arg1 is the time in minutes selector
# arg2 is the raw text stream from the track 0 call to HandBrake
# returns: a list of track numbers of tracks longer than the selector
if [ $# -lt 2 ]; then
return ""
fi
minTime="$1"
shift
allTrackText="$*"
aReturn=""
trackList=`eval "echo \"$allTrackText\" | egrep '(^\+ title |\+ duration\:)' | sed -e 's/^[^+]*+ //'g -e 's/title \([0-9]*\):/\1-/'g -e 's/duration: //'g"`
trackNumber=""
for aline in $trackList
do
trackLineFlag=`echo $aline | sed 's/[0-9]*-$/-/'`
if [ $trackLineFlag = "-" ];
then
trackNumber=`echo $aline | sed 's/\([0-9]*\)-/\1/'`
else
set -- `echo $aline | sed -e 's/(^[:0-9])//g' -e 's/:/ /g'`
if [ $3 -gt 29 ];
then let trackTime=($1*60)+$2+1
else let trackTime=($1*60)+$2
fi
if [ $trackTime -gt $minTime ];
then aReturn="$aReturn $trackNumber"
fi
fi
done
echo "$aReturn"
}
makeFullPath()
{
aReturn=""
currentPath=`pwd`
if [ $# -gt 0 ]; then
inPath="$*"
# put full path in front of path if needed
aReturn=`echo "$inPath" | sed -e "s!~!$currentPath/!" -e "s!^./!$currentPath/!" -e "s!^\([^/]\)!$currentPath/\1!" -e "s!^../!$currentPath/../!"`
# remove ../ from path - only goes 4 deep
aReturn=`echo "$aReturn" | sed -e 's!/[^\.^/]*/\.\./!/!g' | sed -e 's!/[^\.^/]*/\.\./!/!g' | sed -e 's!/[^\.^/]*/\.\./!/!g' | sed -e 's!/[^\.^/]*/\.\./!/!g'`
# cleanup by removing //
aReturn=`echo "$aReturn" | sed -e 's!//!/!g'`
fi
echo "$aReturn"
}
isPIDRunning()
{
aResult=0
if [ $# -gt 0 ]; then
txtResult="`ps ax | egrep \"^[ \t]*$1\" | sed -e 's/.*/1/'`"
if [ -z "$txtResult" ];
then aResult=0
else aResult=1
fi
fi
echo $aResult
}
#############################################################################
# MAIN SCRIPT
# initialization functions
verifyFindCLTool
parseProcessInArgs $*
# see if the output directory needs to be created
if [ ! -e $outputDir ]; then
mkdir -p "$outputDir"
fi
# sanity checks
if [[ ! -x $toolPath || ! -d $inputSearchDir || ! -d $outputDir || -z "$toolArgs" ]]
then
if [[ ! -x $toolPath ]]
then echo "ERROR: $toolPath is not executable!"
fi
if [[ ! -d $inputSearchDir ]]
then echo "ERROR: $inputSearchDir is not a valid input directory!"
fi
if [[ ! -d $outputDir ]]
then echo "ERROR: $outputDir is not a valid output directory!"
fi
if [[ ! -z "$toolArgs" ]]
then echo "ERROR: $toolArgs is unset!"
fi
displayUsageExit
fi
# fix input and output paths to be full paths
inputSearchDir=`makeFullPath $inputSearchDir`
outputDir=`makeFullPath $outputDir`
# display the basic setup information
echo "$scriptName v$scriptVers"
echo " Start: `date`"
echo " Input directory: $inputSearchDir"
echo " Output directory: $outputDir"
echo " Minimum get track time: $minTrackTime mins"
echo " Tool path: $toolPath"
echo " Tool args: $toolArgs"
echo " My args: $myArgs"
echo " - - - - - - - - - - - - - - - -"
# find all the DVD videos in the input search directory tree
# spaces in file path temporarily become /008 and paths are separated with spaces
dvdTSVidList=`find $inputSearchDir -name VIDEO_TS -print0 | tr ' ' '\007' | tr '\000' ' '`
# process each DVD video found
for dvdTSDir in $dvdTSVidList
do
# correct the tmp char back to spaces in the DVD file paths
dvdTSDir=`echo $dvdTSDir | tr '\007' ' '`
# get the DVD's name and path to root of the DVD
dvdVolPath=`dirname "$dvdTSDir"`
dvdName=`basename "$dvdVolPath"`
dvdNameALNUM=`basename "$dvdVolPath" | sed 's/[^[:alnum:]^-^_]//g'`
# display information
echo " * Processing DVD '$dvdName'"
# create tmp link to the dvdVolPath to workaround a problem that
# the HandBrakeCLI tool has a problem with spaces in the input
# file paths in a script
tmpNoSpacePath="/tmp/dvdVol-$dvdNameALNUM-$scriptPID"
ln -s "$dvdVolPath" $tmpNoSpacePath
# get the track list information from the DVD
cmd="$toolPath -i $tmpNoSpacePath $toolTrackArgs /dev/null 2>&1"
dvdTrackInfo=`eval $cmd`
# save the DVD info
outputFilePath="$outputDir/${dvdName}.txt"
if [ $saveDVDinfo -eq 1 ]; then
if [[ ! -e $outputFilePath || skipDuplicates -eq 0 ]]; then
echo "$dvdTrackInfo" | egrep '[ \t]*\+' > "$outputFilePath"
fi
fi
# get the track number of tracks which are longer then the time desired
trackFetchList=`getTrackListLongerThan $minTrackTime "$dvdTrackInfo"`
if [ ! -z "$trackFetchList" ];
then
echo " Will encode the following tracks: `echo $trackFetchList | sed 's/ /, /g'` "
else
echo " No tracks on this DVD are longer than the minimum track time setting"
fi
trackCount=`echo $trackFetchList | wc -w`
for aTrack in $trackFetchList
do
if [ $trackCount -gt 1 ]
then outputFilePath="$outputDir/${dvdName}-${aTrack}.$mySuffix.m4v"
else outputFilePath="$outputDir/${dvdName}.$mySuffix.m4v"
# .m4v is important for AppleTV
fi
cmd="$toolPath $myArgs -i $tmpNoSpacePath $toolArgs -t $aTrack -o \"$outputFilePath\" > /tmp/${dvdNameALNUM}Results.txt 2>&1"
if [[ ! -e $outputFilePath || skipDuplicates -eq 0 ]];
then
# simple command execution
#ripResult=`eval $cmd`
# background command execution with some status
echo "Command is: $cmd"
eval $cmd &
cmdPID=$!
while [ `isPIDRunning $cmdPID` -eq 1 ]; do
cmdStatusTxt="`tail -n 1 /tmp/${dvdNameALNUM}Results.txt | grep 'Encoding: '`"
if [ ! -z "$cmdStatusTxt" ]; then
echo -n "$cmdStatusTxt"
fi
sleep 1s
done
echo ""
wait $cmdPID
else
echo " Output file SKIPPED because it ALREADY EXISTS"
fi
if [ -e /tmp/${dvdNameALNUM}Results.txt ]; then
rm /tmp/${dvdNameALNUM}Results.txt
fi
done
rm $tmpNoSpacePath
done
echo " - - - - - - - - - - - - - - - -"
echo " End: `date`"
exit 0