Skip to content

Instantly share code, notes, and snippets.

@phyoewaipaing
Last active November 12, 2023 13:54
Show Gist options
  • Save phyoewaipaing/d2b67892aad9b6c5a040bd9518ebf653 to your computer and use it in GitHub Desktop.
Save phyoewaipaing/d2b67892aad9b6c5a040bd9518ebf653 to your computer and use it in GitHub Desktop.
Shift .srt Subtitle Time Track
<#
.SYNOPSIS
Script that will shift the offset time of movie subtile file.
.DESCRIPTION
This script will shift the time offset of movie subtitle file. This is useful when your video soundtrack is fast or lagged to your subtitle. If your video soundtrack is faster by 3.5 seconds,
then you need to forward the subtitle to 3 minutes and 500 milliseconds.
You can delay or advance the subtitle track in hour, minutes, seconds or even in milliseconds and all subtitle lines in the file will be automatically adjusted.
If destination file name is not specified, then it will use the source file name plus '(new)' as the destination file name.
This script need to be run in windows powershell. It will also show the time elapsed for conversion process. It supports subtitle files in plain text format such as .srt file and .txt files.
Author: Phyoe Wai Paing
Country: Myanmar(Burma)
Released Date: 05/11/2017
Example usage:
.\Shift-Subtitle -SourceFile The.Godfather.Part.I.1972.720p.BrRip.x264.YIFY.srt -DestFile The.God.Father.1972.srt -sec -5
It will delay the every subtitle line in the source file by 5 seconds and save to file The.God.Father.1972.srt
You need to put the minus sign (-) at the front of time value, if you want to adjust the subtitle time lagged to the soundtrack.
You can ignore or put the plus sign (+) at the front of time value, if you adjust the subtitle time fast over the soundtrack.
.EXAMPLE
.\Shift-Subtitle -SourceFile Gone-With-The-Wind-1939.srt -min +2 -sec +5 -ms 300
It will advance the every subtitle line in the source file by 2 minutes, 5 seconds and 300 milliseconds and save to file as 'Gone-With-The-Wind-1939(new).srt'
You can ignore the plus sign (+) for forward operations.
.PARAMETER -SourceFile
The name or the full path of the file you want to convert.
.PARAMETER -DestFile
The name of the destination file you want to save.
.PARAMETER -hr
The number of hours you want to move forward or backward. The maximum acceptable value is 10.
.PARAMETER -min
The number of minutes you want to move forward or backward. The maximum acceptable value is 600.
.PARAMETER -sec
The number of seconds you want to move forward or backward. The maximum acceptable value is 36000.
.PARAMETER -ms
The number of milliseconds you want to move forward or backward. The maximum acceptable value is 36000000.
.LINK
You can find this script and more at: https://www.scriptinghouse.com/
#>
param ([parameter(Mandatory=$True,Position=0)][string]$SourceFile,[parameter(Mandatory=$False,Position=1)][string]$DestFile,[int]$hr,[int]$min,[long]$sec,[long]$ms)
If ( $hr -gt 10 -OR $min -gt 600 -OR $sec -gt 36000 -OR $ms -gt 36000000)
{
Write-host -fore red "The Time Value is too large to accept. Time value limit has the following settings."
Write-host -fore yellow "The number of hours that can accept: 10 hr`nThe number of minutes that can accept: 600 min`nThe number of seconds that can accept:36000 sec `nThe number of milli-seconds that can accept: 36000000 ms"
}
elseif ( $SourceFile.Length -eq 0 )
{
Write-host -fore red "Source File path is empty. Please input the correct file."
}
elseif (-Not(Test-Path $SourceFile))
{
Write-host -fore red "File path is invalid. Please input the correct file location."
}
elseif ( !$hr -AND !$min -AND !$sec -AND !$ms)
{
Write-host -fore red "Please put at least one parameter for time offset. You can use the minus sign (-) for lagged time offset."
Write-host -fore yellow "eg: `n.\Shift_Subtitle -SourceFile -sec +2"
Write-host -fore yellow ".\Shift_Subtitle -SourceFile -sec -2"
Write-host -fore yellow ".\Shift_Subtitle -SourceFile -min 1 -sec 2"
}
elseif ( '.srt','.txt' -match (gci $SourceFile).Extension -AND (Get-Content $SourceFile).Length -gt10 )
{
$Job_ScriptBlock = {
param ([string]$SourceFile,[string]$DestFile,[system.timespan]$ToAddTimeSpan)
Function Get-FinalTime
{
param([string]$InitialTime,[system.timespan]$ToAddTimeSpan )
Try {
$FinalTime = "{0:HH:mm:ss,fff}" -f ( [datetime]([timespan]($InitialTime.replace(',','.')) + $ToAddTimeSpan).Ticks ) ## Create the timespan from current time string, add to another timespan and format the output
Return $FinalTime;
}
Catch
{
Write-host -fore Red "`nError: Cannot accept the lagged time larger than the initial value. Please input the lower value than -$InitialTime.";
Exit;
}
}
$Content = Get-Content $SourceFile
#### Get the Start Time and End time of the srt file ###
$StartTimeArray = $Content | foreach { If ($_ -match "^(\d){2}:(\d){2}:(\d){2},(\d){3}") { $Matches[0] } }
$EndTimeArray = $Content | foreach { If ($_ -match "(\d){2}:(\d){2}:(\d){2},(\d){3}$") { $Matches[0] } }
$StartTimeChangedContent = $Content | foreach {
### Loop each line & if the start-time (extracted from regular expression) matches one of the $StartTimeArray, then call the function to add the time-offset ###
If ( $StartTimeArray -match $(if ($_ -match "^(\d){2}:(\d){2}:(\d){2},(\d){3}") { $Matches[0] } ) )
{ $_.Replace( $Matches[0], (Get-FinalTime $Matches[0] $ToAddTimeSpan ) ) }
else
{$_ }
}
$EndTimeChangedContent = $StartTimeChangedContent | foreach {
### Loop each line & if the end-time (extracted from regular expression) matches one of the $EndTimeArray, then call the function to add the time-offset ###
If ( $EndTimeArray -match $(if ($_ -match "(\d){2}:(\d){2}:(\d){2},(\d){3}$") { $Matches[0] } ) )
{ $_.Replace( $Matches[0], (Get-FinalTime $Matches[0] $ToAddTimeSpan ) ) }
else
{$_ }
}
### Get Source File info to create the destination file ###
$FileInfo = gci $SourceFile
$FileDirectory = $FileInfo.Directory
$FileNameOnly = $FileInfo.BaseName
$FileExtension = $FileInfo.Extension
If ($DestFile -AND $DestFile.IndexOf('\') -eq -1)
{
## If the dest file exist and if dest file doesn't contain full path, then use the current source file directory ##
$EndTimeChangedContent | Out-File $FileDirectory\$DestFile
Write-host -fore green "`nCompleted and writing to file $FileDirectory\$DestFile"
}
elseif ($DestFile.IndexOf('\') -eq 2)
{
$EndTimeChangedContent | Out-File $DestFile
Write-host -fore green "`nCompleted and writing to file $DestFile"
}
else
{
$EndTimeChangedContent | Out-File "$FileDirectory\$FileNameOnly(New)$FileExtension"
Write-host -fore green "`nCompleted and writing to file $FileDirectory\$FileNameOnly(New)$FileExtension"
}
}
$ToAddTimeSpan = (New-TimeSpan -Hours $hr -Minutes $min -Seconds $sec) + [timespan]::FromMilliseconds($ms)
### Start Job with parameters source file path, destination path,and offset time
$job = Start-Job -ScriptBlock $Job_ScriptBlock -ArgumentList (gci $SourceFile).FullName,$DestFile,$ToAddTimeSpan
#### If the millisecond option is specified then put the decimal places ###
if ($ms -AND $ToAddTimeSpan.Milliseconds -ne 0)
{ $TimeOffsetDisplay = $ToAddTimeSpan.ToString() -replace ".{4}$" }
else
{ $TimeOffsetDisplay = $ToAddTimeSpan.tostring() }
$Direction = If ($ToAddTimeSpan.TotalMilliseconds -lt 0) { "Backward"} else { "Forward"} ## Put the direction variable depending on the sign of $ToAddTimeSpan ##
$Timer= [Diagnostics.Stopwatch]::StartNew() ## Start the timer to calculate the run time
write-host -fore yellow "`nShifting Subtitle Time $Direction ($TimeOffsetDisplay) in $SourceFile " -NoNewline;
### Display the dotted line and check the job status at 1 sec intervals ###
do { write-host "." -NoNewline; Start-Sleep 1 }
while ($job.State -ne "Completed");
$job | Receive-Job;
$Timer.stop()
Write-host "Total time elapsed: $($Timer.elapsed.seconds) sec"
Remove-Job $job;
}
else
{
Write-host -fore red "Source File Size is empty or has incorrect file extension. Please check the file."
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment