Extracting Subtitles from MKV Files

I’m not certain whether it’s linked to being an expat living in the Netherlands trying to understand what’s being said on their television channels, or just that my hearing isn’t is what it used to be, but it’s quite rare for me to watch anything without subtitles, whatever the language…. Often though, it’s the case that my TV is not able to use the subtitles embedded within an MKV file. Instead, I need to extract the subtitles data stream to a separate SRT file, and ensure the filename matches the MKV one, apart from the suffic.

This post follows on from one of a couple of weeks ago about getting MKV file information, and goes into how we can also extract the subtitles for one of these files.

The script is posted below. As you’ll probably already have noticed, it’s quite similar to the cmdlet from the earlier post. We’re accepting ‘FullName’ as an alias of the Path, and we’re constructing the command to be executed dynamically by combining the command parameters with the values that have been passed in. Also, the filename of the SRT file is matched to the original MKV file so we don’t need to change it after.

function Get-MKVSubtitles            
        [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)][Alias('FullName')] [string] $Path,            
        [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)] [string] $Track                   
        $Destination = ($Path.Substring(0,$Path.Length - 4)) + '.srt'            
        $command = "D:portablemkvtoolnixmkvextract.exe tracks -q `"$Path`" $Track`:`"$Destination`""            
        Write-Verbose -Message "Path        : $Path"            
        Write-Verbose -Message "Track       : $Track"            
        Write-Verbose -Message "Destination : $Destination"            
        Write-Verbose -Message "Command     : $command"            
        Invoke-Expression -Command $command                     

If we have one file, we can use the cmdlet like this:

Get-MKVSubtitles -Path C:DataVideosMyMovie.mkv -Track 0

PowerShell’s pipeline functionality comes into great effect if we have multiple MKV files with subtitles in a directory.  We could use a combination of Get-ChildItem, and Get-MKVTrackInfo with Get-MKVSubtitles :

Get-ChildItem -Filter *.mkv | Get-MKVTrackInfo | Where-Object -Property TrackType -EQ -Value 'Subtitles' | Get-MKVSubtitles

If your MKV files were spread over a series of sub-directories, you could even add the -recurse parameter to Get-ChildItem, since FullName is passed through the pipeline to Get-MKVInfo.


Saving all functions in a module to separate files

I like to keep functions in separate files. I figured I’d have a go at extracting all the functions from my recently downloaded PowerShellCookbook module into separate files. I also wanted to make sure that the filenames generated would match the function names.

Here’s what I came up with. It’s basically a one liner ‘steroided‘ (take a look if you don’t know what I mean) to make it more readable. The only caveat really is that the module needs to be loaded into memory, as it uses the Function PS Provider to obtain the information.

If you wanted to, you could completely omit the Where-Object filter to dump all currently loaded functions into separate files.

#requires -Version 3
Get-ChildItem -Path Function:\  |
Where-Object -Property ModuleName -EQ -Value ‘PowerShellCookbook’ |
Select-Object -Property Name, ScriptBlock |
ForEach-Object -Process {
Add-Content -Path “d:\temp\$($psitem.Name).ps1″ -Value $psitem.ScriptBlock