Table of Contents
Examples of how to automate things
[[TOC]]
MKVToolNix contains several command line tools that are designed to be scriptable. You can automate pretty much any type of processing when you combine those tools with a scripting language of your choice.
This page lists a couple of examples of how to do this. Most of them are written in the scripting language Ruby which is available for all operating systems out there. The examples are simple enough that they can be translated easily into other scripting languages such as Python or Perl.
You can even do a lot of work with a shell such as bash
or zsh
(for Windows you can use the one from mingw or
git). I highly recommend the jq
utility for processing JSON from the
shell.
In general automation boils down to the following steps:
- loop over all affected files,
- query
mkvmerge
about the content of the file (this will be output in JSON and can therefore be processed quite easily with any language), - analyze
mkvmerge
's output and build a new command line for the tool you want to work with (command line documentation:mkvmerge
,mkvpropedit
), - execute
mkvmerge
ormkvpropedit
with that new command line.
mtxlib.rb
— common Ruby routines
The following contains a couple of common routines used by the other examples. You'll have to save this content as a file called mtxlib.rb
in the same directory as the other examples.
#!/usr/bin/env ruby
# version 2019-01-24-01
require "json"
require "tempfile"
def identify_file file_name
Tempfile.create(["mkvmerge-arguments", ".json"], nil, :encoding => "utf-8") do |file|
file.puts JSON.dump([ "--identification-format", "json", "--identify", file_name ])
file.close
return JSON.load(`mkvmerge @#{file.path}`)
end
end
def multiplex_file arguments
Tempfile.create(["mkvmerge-arguments", ".json"], nil, :encoding => "utf-8") do |file|
file.puts JSON.dump(arguments)
file.close
system "mkvmerge @#{file.path}"
end
end
def edit_file_properties arguments
Tempfile.create(["mkvpropedit-arguments", ".json"], nil, :encoding => "utf-8") do |file|
file.puts JSON.dump(arguments)
file.close
system "mkvpropedit @#{file.path}"
end
end
Example 1: multiplex files, change audio language, remove subtitle track
Here's an example in Ruby that loops over all files in an input directory, sets the second audio track's language to ger
(if there's one)
and de-selects the third subtitle track (if there's one). It uses option
files instead of listing all arguments on the command line in order to
avoid character set issues and maximum command line length limits.
This example is written in Ruby and requires the mtxlib.rb
file from
above.
#!/usr/bin/env ruby
# coding: utf-8
require_relative "mtxlib"
input_dir = "input" # Mux all MKVs from this sub-directory…
output_dir = "output" # …into this sub-directory
Dir.glob("#{input_dir}/*.mkv").each do |input_file|
json = identify_file input_file
tracks_by_type = Hash.new
arguments = [
"-o",
"#{output_dir}/" + input_file.gsub(%r{.*[/\\]}, '')
]
json["tracks"].each do |track|
tracks_by_type[track["type"]] ||= 0
tracks_by_type[track["type"]] += 1
if (track["type"] == "audio") && (tracks_by_type["audio"] == 2)
arguments += [ "--language", "#{track["id"]}:ger" ]
elsif (track["type"] == "subtitles") && (tracks_by_type["subtitles"] == 3)
arguments += [ "--stracks", "!#{track["id"]}" ]
end
end
arguments << input_file
multiplex_file arguments
end
Example 2: remove 'default track' flag from all subtitle tracks
This example processes all files in a sub-directory. It uses mkvpropedit
in order to clear the "default track" flag for all subtitle
tracks that have the flag set.
This example is written in Ruby and requires the mtxlib.rb
file from
above.
#!/usr/bin/env ruby
# coding: utf-8
require_relative "mtxlib"
files_dir = "files" # Process all MKVs in this sub-directory
Dir.glob("#{files_dir}/*.mkv").each do |file|
json = identify_file file
arguments = [ ]
json["tracks"].each do |track|
if (track["type"] == "subtitles") and (track["properties"]["default_track"] == true)
arguments += [ "--edit", "track:=#{track["properties"]["uid"]}", "--set", "flag-default=0" ]
end
end
if !arguments.empty?
puts "Editing #{file}"
edit_file_properties [ file ] + arguments
end
end
Example 3: set title to the name of the file
This example processes all files with the extension .mkv
or .webm
in the current directory. For each file it takes its name without the
extension and sets that as the new title for the file.
This example is written in shell (bash
or zsh
) and requires the jq
utility.
for FILE in *.mkv *.webm ; do
TITLE="$(mkvmerge -J "$FILE" | jq -r '.container.properties.title // ""')"
if [[ -z $TITLE ]]; then
TITLE="${FILE##*/}"
TITLE="${TITLE%.mkv}"
TITLE="${TITLE%.webm}"
mkvpropedit "$FILE" --set "title=$TITLE"
fi
done
Example 4: combine MP4 files with similarly named subtitle files
Often you might have a lot of MP4 files lying around with subtitle files that are similarly named: only the extension differs
(e.g. Wonderful Movie.mp4
and Wonderful Movie.srt
). The following example iterates over all MP4 files in the current directory. It looks
for SRT and VobSub subtitle files in the same directory that have the same base name (both are used if both are found). Then it multiplexes
all of them together into a Matroska file.
This example is written in shell (bash
or zsh
) and doesn't have any other requirements.
# an array for the arguments
declare -a args
# loop over all MP4 files
for mp4 in *.mp4 ; do
base="${mp4%mp4}"
args=(-o "output/${base}mkv" "${mp4}")
# look for subtitles with the same base name
if [[ -f "${base}srt" ]]; then
args=("${args[@]}" "${base}srt")
fi
if [[ -f "${base}idx" ]]; then
args=("${args[@]}" "${base}idx")
fi
# create output file
mkvmerge "${args[@]}"
done