Skip to content

Instantly share code, notes, and snippets.

@Ferfalk
Created August 4, 2025 14:55
Show Gist options
  • Save Ferfalk/819ed0d52c7c260b533b56553a62b2ad to your computer and use it in GitHub Desktop.
Save Ferfalk/819ed0d52c7c260b533b56553a62b2ad to your computer and use it in GitHub Desktop.
Extract MKV subtitles
# This script searches for all MKV files in a folder and its subfolders,
# then extracts the first English subtitle track found.
# ---------------------------------------------------------------------
# CONFIGURATION (EDIT THE PATHS BELOW)
# ---------------------------------------------------------------------
# Path to the folder containing your MKV files
$mkv_folder = "\\truenas.local\Plex\Series\Example"
# Path to the folder where extracted subtitles will be saved
$output_folder = "\\truenas.local\Plex\Series\Example\Subtitles"
# Full path to mkvextract.exe
$mkvextract_path = "C:\Program Files\MKVToolNix\mkvextract.exe"
# Full path to mkvinfo.exe
$mkvinfo_path = "C:\Program Files\MKVToolNix\mkvinfo.exe"
# ---------------------------------------------------------------------
# SCRIPT START
# ---------------------------------------------------------------------
Write-Host "Starting English subtitle extraction..."
Get-ChildItem -Path $mkv_folder -Recurse -Filter "*.mkv" | ForEach-Object {
$mkv_file = $_.FullName
$base_name = $_.BaseName
Write-Host ""
Write-Host "Processing file: '$mkv_file'"
# Execute mkvinfo to get subtitle tracks and their languages
$mkv_info = & $mkvinfo_path "$mkv_file"
$track_id = ""
$language = ""
$codec_id = ""
$is_subtitle_track = $false
$found_eng_subtitle = $false
# Loop through mkvinfo output to find the English subtitle track
for ($i = 0; $i -lt $mkv_info.Count; $i++) {
$line = $mkv_info[$i].Trim()
# Find the track ID at the start of a new block
if ($line -like "*Track ID for mkvmerge & mkvextract*") {
$track_id_match = $line | Select-String -Pattern "track ID for mkvmerge & mkvextract: (\d+)"
if ($track_id_match) {
$track_id = $track_id_match.Matches.Groups[1].Value
$language = ""
$codec_id = ""
$is_subtitle_track = $false
}
}
# Look for "subtitles" to identify the track type
if ($line -like "*Track type: subtitles*") {
$is_subtitle_track = $true
}
# Look for the language
if ($line -like "*Language: eng*") {
$language = "eng"
}
# Look for the Codec ID
if ($line -like "*Codec ID:*") {
$codec_id_match = $line | Select-String -Pattern "Codec ID: (.+)"
if ($codec_id_match) {
$codec_id = $codec_id_match.Matches.Groups[1].Value.Trim()
}
}
# If all information for an English subtitle track has been found
if ($is_subtitle_track -and $language -eq "eng" -and $codec_id -ne "") {
# Map the Codec ID to the file extension
$extension = ""
switch -Wildcard ($codec_id) {
'S_TEXT/UTF8' { $extension = 'srt' }
'S_TEXT/SSA' { $extension = 'ass' }
'S_ASS' { $extension = 'ass' }
'S_TEXT/ASS' { $extension = 'ass' }
'S_VOBSUB' { $extension = 'sub' }
default {
$extension = 'dat'
Write-Host " - WARNING: Unknown subtitle format ($codec_id). Using '.dat' extension."
}
}
$output_file = Join-Path -Path $output_folder -ChildPath "$($base_name).eng.$($extension)"
Write-Host " - English subtitle found (ID: '$track_id', Format: '$codec_id')"
Write-Host " - Extracting to: '$output_file'"
# Execute mkvextract to extract the subtitle
& $mkvextract_path "$mkv_file" tracks "$($track_id):$output_file"
$found_eng_subtitle = $true
break # Exit the inner loop after finding and extracting the first subtitle
}
}
if (-not $found_eng_subtitle) {
Write-Host " - No English subtitle track found in this file."
}
}
Write-Host ""
Write-Host "Subtitle extraction complete."
Read-Host -Prompt "Press Enter to exit"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment