Projects Blog

Batch Conversion of DVDs with Handbrake

I recently had a project to backup over 150 DVD titles to network storage. To save space, I decided to convert them all from DVD to h264. This cut the file sizes down from 4GB to about 1GB each. Processing each took around 20-30 minutes on my i7-4790k so I wanted to automate the process.

Below is the script I wrote to do everything for me. To use this yourself, just install Handbrake for Windows and set the user editable options seen at the top of the script and run it!

Download here

#
# Author: josh@blog.arrington.me
#
# This script will find all DVD ISOs and VOB files in a directory
# and convert them to MKV.
#
# By default, this script will only preserve the audio track and
# subtitles in the language specified by $DubLanguage.
#
# This script will convert every title from the DVD. Some titles
# may be extra crud that will need to be deleted.
#
# Every title will be placed into its own directory. VOB titles
# will be placed into a directory named after its parent folder.
# Because of this, all related VOB files should be in their own
# directory, separate from others. ISOs will use the name of the ISO
# file as its output directory.
#

##### Begin User Editable Options

# Location of the handbrake executable
$HandbrakeLocation = "C:\Program Files\Handbrake\"

# Language to rip. Must match the language text on the audio track
$DubLanguage = "English"

# Handbrake profile to use
$HandbrakePreset = "High Profile"

# Where are the files to convert?
$ConvertDir = "C:\TitlesToConvert"

# Where do put the results?
$OutputDir = "..\HandbrakeOutput"

##### End User Editable Options 

Function Write-Log ($message, $logfile=".\handbrake.log") {
    $time = (Get-Date -Format "yyyy-MM-dd hh:mm:ss")
    "$time - $message" | Out-File -Append $logfile
}

Function Get-NumberOfTitles ($file) {
    handbrakecli -i $file -t 0
    $numTitles = ($Error | Select-String -Pattern "scan thread found (?<numtitle>\d*) valid title" | select -ExpandProperty Matches | foreach {$_.groups["numtitle"].value} | select -first 1)

    return $numTitles
}

Function Convert-Titles ($files, $outputdir=".\") {

    $files |% {
        $numTitles = [int](Get-NumberOfTitles $_.FullName)[1]

        for ($t=1; $t -le $numTitles; $t++)
        {
            $todir = (Get-Item $outputdir).FullName

            # Get the name of the title
            # If the title folder is a Video_TS folder from a DVD
            # or if the title folder has VOB files in it
            if ( ((Get-ChildItem -path $_ *.vob | measure).count) -gt 0 -and (Test-Path $_ -PathType Container))
            {
                $temp = (Get-Item ($_ -split "VIDEO_TS")[0])
                $filename = $temp.BaseName + " Title $t.mkv"
                $todir = (Join-Path $todir $temp.BaseName)
                $newname = ( Join-Path $todir $filename)
            }
            # Otherwise, its probably an ISO. Go convert!
            else
            {
                $filename = $_.BaseName + " Title $t.mkv"
                $todir = (Join-Path $todir $_.BaseName)
                $newname = (Join-path $todir $filename)
            }

            # Have we already converted this title?
            if (Test-Path $newname)
            {
                Write-Log "Already converted, skipping: $newname"
                Continue
            }

            if (!(Test-Path $todir))
            {
                mkdir $todir
            }

            # Run the conversion
            Write-Log "Converting $_ to $newname"
            handbrakecli -i $_.FullName -o $newname --preset $HandbrakePreset --native-language "$DubLanguage" --native-dub -t $t

             Check for errors. Write them to the log
            if ($LASTEXITCODE -ne 0) {
                Write-Log "Converting failed: $newname"
                Write-Log $_.Exception.Message
            }

            Write-Log "Finished with $newname"
        }
    }
}

# Setup
$env:Path += ";$HandbrakeLocation"
cd $ConvertDir

if (!(Test-Path $OutputDir))
{
    mkdir $OutputDir
}

# Get all ISO titles
$TitlesToConvert = @()
$TitlesToConvert += (ls -Recurse "*.iso" | sort -unique | get-item)

# Get all VOB titles
$TitlesToConvert += (ls -Recurse "*.vob" |% { $_.DirectoryName } | sort -unique | get-item)

# Get to work!
Convert-Titles -files $TitlesToConvert -outputdir $OutputDir

Categorised as: Programming, Windows


Leave a Reply

Your email address will not be published. Required fields are marked *