Getting MKV Stream Data Information with PowerShell and the MKVToolnix Toolkit

I often want to get information about an MKV file, usually to find out if it has one or more subtitle tracks. MKVToolNix is my toolset of choice for this. Automation of this process turned out to be relatively straight forward with PowerShell (naturally!) and one of their tools, mkvinfo.

Before we go into the cmdlet details, you will need to download and install the MKVToolNix toolset if you do not already have it already You can get this by visiting the site of the author, Moritz Bunkus, at https://www.bunkus.org/videotools/mkvtoolnix/

A word of warning. We’re using ‘Prayer Based Parsing’. If a future revision of mkvinfo changes the format of output, there’s a good chance our script will cease to work. Iā€™m pretty certain more RegEx aware gurus will be able to tighten the parsing a bit to lessen the chance of this, but it’s still something to think about.

Looking at the code, ‘FullName’ is defined as an alias for Path in the cmdlet, to allow the use of pipeline output from cmdlets such as Get-ChildItem. That way, track information from multiple files can be obtained quite simply.

Also remember to change the path in the code below to where your mkvinfo.exe file exists.

Once you’ve loaded the function into memory, it can be used simply the following way :

PS C:\temp> Get-MKVTrackInfo -Path C:\temp\movie.mkv

An example, also showing how we can combine it with Get-ChildItem is below.

Get-MKVInfoChildItemIn the next post, we’ll make use of another MKVToolnix tool and PowerShell to allow us to extract subtitle files from MKV files.

Any feedback, comments, errata always welcome. šŸ™‚

#requires -Version 2

function Get-MKVTrackInfo
{
    [CmdletBinding()]
    
    Param
    (
        [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True)][Alias('FullName')] [string] $Path
    )
    
    Process
    {
        $info = & 'C:\Program Files\MKVToolNix\mkvinfo.exe' $Path  | Where-Object -FilterScript {
            ($_ -like '*Track number*') -or ($_ -like '*Track type*')
        }
        $info = $info | ForEach-Object -Process {
            $_.replace('|  + ','')
        }
        $info = $info | ForEach-Object -Process {
            $_.replace('(track ID for mkvmerge & mkvextract: ',':')
        } 
        $info = $info | ForEach-Object -Process {
            $_.replace(')','')
        }
        $info = $info | ForEach-Object -Process {
            $_.replace(': ',':')
        }
        $info = $info | ForEach-Object -Process {
            $_.replace(' :',':')
        }
        $info = $info | ForEach-Object -Process {
            $_.replace('Track number:','')
        }
        $info = $info | ForEach-Object -Process {
            $_.replace('Track type:','')
        }
        For ($index = 0;$index -lt $info.count;$index = $index + 2) 
        {
            $tmpArray = $info[$index].Split(':')

            $hash = @{
                Track     = $tmpArray[1]
                TrackType = $info[$index+1]
                Path      = (Get-ChildItem -Path $Path).FullName
            }
        
            New-Object -TypeName PsObject -Property $hash
        }
    }
}
Advertisements

URL Shortening

Love it or loathe it, URL shortening has been with us a while now and can certainly be handy. TinyURL are one such company to offer this service. Nicely for us, we do not need to register in order to use their API, and yet nicer still is that we can use it simply by entering a standard format of URL.

Before we see how we can use PowerShell to automate this process, let’s take a look at the format of URL that we need to use with TinyURL.

http://tinyurl.com/api-create.php?url=targetaddress

Where targetaddress refers to the URL that you wish to shorten.

And that’s it.

Let’s say we wanted share a link containing information about this years PowerShell Summit Europe event in Stockholm. The full length URL for this is :

http://powershell.org/wp/community-events/summit/powershell-summit-europe-2015/

If we wanted to get the TinyURL equivalent of this, we’d use the following URL, pasting it into the address bar of our browser.

http://tinyurl.com/api-create.php?url=http://powershell.org/wp/community-events/summit/powershell-summit-europe-2015/

TinyURLExample

For making this happen via PowerShell, Invoke-WebRequest is our friend. All we need to do is provide the required address via the Uri parameter, and the Content property of the returned HtmlWebResponseObject will contain its shortened equivalent.

So for the case of the above we’d be using a command (note the pipeline symbol) of the type :

Invoke-WebRequest -Uri 'http://tinyurl.com/api-create.php?url=http://powershell.org/wp/community-events/summit/powershell-summit-europe-2015/' |
Select-Object -ExpandProperty Content

And can expect to get :

InvokeWebRequest

I’ve put together a cmdlet called Get-TinyURL for doing this. At its simplest, you can run it with the Uri parameter, and it will return a PSObject containing the original full address and its shortened equivalent.

Get-TinyURL -Uri 'http://powershell.org/wp/community-events/summit/powershell-summit-europe-2015/'

GetTinyURL

It’s also been bulked out a bit to give some extra functionality, such as being able to read from and write to the clipboard if we want. With both options enabled, we can copy a full address into the clipboard, run the cmdlet, and automatically have the shortened URL available for pasting wherever we want it next.

pseufull
Navigate to desired URL and copy it to the clipboard

Get-TinyURL -ReadClipboard -WriteClipboard

GetTinyClipboard
Run the required command

pseuemail Paste where required

The code used is listed below, and will also be posted on GitHub in due course.

function Get-TinyURL
{
    [CmdletBinding()]
    
    Param
    (
        [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True,ParameterSetName = 'URI')] [string] $Uri,
        [Parameter(Mandatory = $True, ValueFromPipelineByPropertyName = $True,ParameterSetName = 'ReadClipboard')] [switch] $ReadClipboard,
        [Parameter(Mandatory = $False, ValueFromPipelineByPropertyName = $True)] [switch] $WriteClipboard = $False

    )
    
    Process
    {

        If ($ReadClipboard -or $WriteClipboard) 
        {
            $null = Add-Type -AssemblyName System.Windows.Forms
        }

        If ($ReadClipboard) 
        {
            $Uri = [system.windows.forms.clipboard]::GetData('System.String')
        }
        

        $tinyURL = Invoke-WebRequest -Uri "http://tinyurl.com/api-create.php?url=$Uri" | 
        Select-Object -ExpandProperty Content


        If ($WriteClipboard) 
        {
            [system.windows.forms.clipboard]::SetData('System.String',$tinyURL)
        }

        $hash = @{
            Uri     = $Uri
            TinyURL = $tinyURL
        }
        
        New-Object -TypeName PsObject -Property $hash
    }
}