A LONG time ago, somebody on here created an amazing bat file for me to extract subs from .mov files. I used the power of ChatGPT and augmented it.
The reason I did this was because I needed .srt files created from a bunch of .mov files, and then take all of those and combine them into a "master.mkv" file.
Your original files won't be harmed during this entire process. I found this very useful and am sharing it with the class in case anyone else is ever looking for the same thing.
Here's a crude breakdown of what it does.
1) It finds all the .mov files in your folder and goes through them and creates corresponding srt files with Y-M-D hh:mm format that displays every second
2) It creates new mov files (*.subtitled.mov) by embedding their srt track from step 1 into each, individual mov file
3) The last step, it takes all the newly created *.subtitled.mov files and combines them into a single, master.mkv
I intentionally decided to not use .mov in the "master" file and make it output a mkv file instead.
You MUST have ffmpeg and ffprobe in your path (example; c:\ffmpeg\bin)
Save this as.... combo.ps1 (or whatever name you want) and place it in your folder with the mov files and execute it from that folder within Powershell.Code:# combo mkv # 1) Extract SRT files with local 12-hour timestamps (no seconds in text) from all .mov files # 2) Mux each .mov + .srt into *_subtitled.mkv (with embedded subrip subtitles) # 3) Concatenate all *_subtitled.mkv into master.mkv # # Requires ffprobe and ffmpeg in PATH, or adjust $ffprobe and $ffmpeg below. $ffprobe = "ffprobe" $ffmpeg = "ffmpeg" function Get-VideoInfo { param( [string]$Path ) $args = @( "-v", "error", "-select_streams", "v:0", "-show_entries", "format=duration:format_tags=creation_time", "-of", "default=noprint_wrappers=1:nokey=1", "$Path" ) $output = & $ffprobe @args 2>$null if (-not $output) { return $null } $lines = $output -split "`n" # Expecting: duration on first line, creation_time (if present) on second $duration = [double]$lines[0] $creationTime = $null if ($lines.Count -gt 1 -and $lines[1] -ne "") { try { # Parse as DateTimeOffset so we respect UTC/offset $dto = [DateTimeOffset]::Parse($lines[1]) # Convert to local computer timezone $creationTime = $dto.ToLocalTime().DateTime } catch { # If parsing fails, fall back to file system timestamp } } if (-not $creationTime) { # Fallback to file system timestamp (already local) $fi = Get-Item -LiteralPath $Path $creationTime = $fi.CreationTime } return [PSCustomObject]@{ Duration = $duration CreationTime = $creationTime } } function Format-SrtTime { param( [double]$Seconds ) if ($Seconds -lt 0) { $Seconds = 0 } $ts = [TimeSpan]::FromSeconds($Seconds) return ("{0:00}:{1:00}:{2:00},{3:000}" -f ` [int]$ts.Hours, ` [int]$ts.Minutes, ` [int]$ts.Seconds, ` [int]($ts.Milliseconds)) } Write-Host "Processing .mov files in: $(Get-Location)`n" $movFiles = Get-ChildItem -LiteralPath . -Filter "*.mov" | Sort-Object Name if (-not $movFiles) { Write-Host "No .mov files found." return } # ------------------------------------------------- # PHASE 1: Generate SRT files for each .mov # ------------------------------------------------- Write-Host "=== PHASE 1: Extracting SRT files from MOV metadata ===`n" $step = 1 # seconds between subtitles foreach ($mov in $movFiles) { Write-Host "Processing $($mov.Name)..." $info = Get-VideoInfo -Path $mov.FullName if (-not $info) { Write-Warning " Could not read info for $($mov.Name). Skipping." continue } $durationSeconds = [double]$info.Duration $creationTime = [DateTime]$info.CreationTime # already local time $srtPath = [System.IO.Path]::ChangeExtension($mov.FullName, ".srt") $lines = New-Object System.Collections.Generic.List[string] $index = 1 for ($t = 0.0; $t -lt $durationSeconds; $t += $step) { $start = $t $end = [Math]::Min($t + $step, $durationSeconds - 0.001) $startSrt = Format-SrtTime -Seconds $start $endSrt = Format-SrtTime -Seconds $end # Text: local creation time + offset t, 12h AM/PM format, NO seconds $currentTime = $creationTime.AddSeconds([int][Math]::Round($t)) $text = $currentTime.ToString("yyyy-MM-dd hh:mm tt") $lines.Add("$index") $lines.Add("$startSrt --> $endSrt") $lines.Add($text) $lines.Add("") # blank line between entries $index++ } Set-Content -LiteralPath $srtPath -Value $lines -Encoding UTF8 Write-Host " Created SRT: $([System.IO.Path]::GetFileName($srtPath))" } Write-Host "`n=== PHASE 1 complete ===`n" # ------------------------------------------------- # PHASE 2: Create *_subtitled.mkv for each .mov+.srt pair # ------------------------------------------------- Write-Host "=== PHASE 2: Creating *_subtitled.mkv files ===`n" foreach ($mov in $movFiles) { $baseName = [System.IO.Path]::GetFileNameWithoutExtension($mov.Name) $srtPath = [System.IO.Path]::ChangeExtension($mov.FullName, ".srt") $outPath = Join-Path $mov.DirectoryName ($baseName + "_subtitled.mkv") if (-not (Test-Path -LiteralPath $srtPath)) { Write-Warning " No matching SRT for $($mov.Name). Skipping mux." continue } Write-Host "Muxing $($mov.Name) + $(Split-Path $srtPath -Leaf) -> $(Split-Path $outPath -Leaf)" $ffmpegArgs = @( "-y", "-i", $mov.FullName, "-i", $srtPath, "-c:v", "copy", "-c:a", "copy", "-c:s", "srt", # embed subtitles as subrip, ideal for MKV $outPath ) & $ffmpeg @ffmpegArgs if ($LASTEXITCODE -ne 0) { Write-Warning " ffmpeg failed for $($mov.Name)." } else { Write-Host " Created: $(Split-Path $outPath -Leaf)" } } Write-Host "`n=== PHASE 2 complete ===`n" # ------------------------------------------------- # PHASE 3: Concatenate *_subtitled.mkv into master.mkv # ------------------------------------------------- Write-Host "=== PHASE 3: Building master.mkv from *_subtitled.mkv ===`n" $subtitledFiles = Get-ChildItem -LiteralPath . -Filter "*_subtitled.mkv" | Sort-Object Name if (-not $subtitledFiles) { Write-Warning "No *_subtitled.mkv files found. master.mkv will not be created." Write-Host "`nAll done." return } $listPath = Join-Path (Get-Location) "list.txt" $listLines = @() foreach ($f in $subtitledFiles) { # Use relative names; escape single quotes for ffmpeg concat $escapedName = $f.Name.Replace("'", "''") $listLines += "file '$escapedName'" } # Write list.txt without BOM so ffmpeg concat doesn't choke Set-Content -LiteralPath $listPath -Value $listLines -Encoding ASCII Write-Host "Created list.txt with $($subtitledFiles.Count) entries." $concatArgs = @( "-y", "-f", "concat", "-safe", "0", "-i", $listPath, "-map", "0", "-c", "copy", "master.mkv" ) & $ffmpeg @concatArgs if ($LASTEXITCODE -ne 0) { Write-Warning "ffmpeg concat failed. master.mkv was not created." } else { Write-Host "Created master.mkv" } Write-Host "`nAll done."
+ Reply to Thread
Results 1 to 1 of 1
Similar Threads
-
WKS KEY PowerShell script
By nadya86 in forum Video Streaming DownloadingReplies: 28Last Post: 2nd Sep 2025, 13:44 -
Possible to extract date time from MOV files and put that into an SRT?
By roadhazard in forum Newbie / General discussionsReplies: 18Last Post: 2nd Jun 2025, 16:02 -
How to PROPERLY extract embedded subs from a vob file
By imkira3 in forum SubtitleReplies: 4Last Post: 11th Jun 2024, 10:01 -
How to extract subs with batch file
By pouki in forum SubtitleReplies: 5Last Post: 29th Nov 2022, 18:01 -
how to delete file in powershell only if exist
By marcorocchini in forum Newbie / General discussionsReplies: 3Last Post: 22nd Mar 2022, 00:25



Quote