Commands/Get-Subtitle.ps1
|
function Get-Subtitle { <# .SYNOPSIS Gets subtitles .DESCRIPTION Gets subtitles from any input files or input text. Both SRT and VTT files are supported. In practice, any file that contains lines that look like SRT or VTT will be considered as having subtitles. .EXAMPLE Get-Childitem *.srt -Recurse | Get-Subtitle .EXAMPLE subtitle ./Examples/Example.srt .EXAMPLE vtt ./Examples/Example.vtt .LINK Export-Subtitle .LINK Search-Subtitle #> [Alias( 'Get-Subtitles', 'Import-Subtitle','Import-Subtitles', 'subtitle','subtitles', 'srt','vtt', 'gsub','imsub' )] param() $Patterns = @{ SRT = [Regex]::new( '(?<Subtitle_SRT> (?<=(?:[\r\n]|^))\d+ # SRT Files Contain an Index digit [\s\n\r]+ # Followed by whitespace and a newline (?<StartTime>[\d\:\,\.]+) # Followed by a Timespan, likely using comma as the separator \s\-\-\>\s # Followed by --> (with a space on each side) (?<EndTime>[\d\:\,\.]+) # Followed by another Timespan (?<Cue>(?:.|\s){0,}?(?=\z|(?<=[\r\n])\d+)) # Any text until the next marker is the subtitle text )', 'IgnoreCase,IgnorePatternWhitespace' ) VTT = [Regex]::new( ' (?<Subtitle_VTT> (?<StartTime>(?<=(?:[\r\n]|^))[\d\:\,\.]+) # VTT Subtitles start with a StartTime \s{1,}\-\-\>\s{1,} # Followed by --> (surrounded by a space) (?<EndTime>[\d\:\,\.]+) # Followed by an EndTime (?<Style>.+?(?=[\r\n])) # Anything until the end of the line is considered a style [\r\n]+ # Match the newline (?<Cue>(?:.|\s){0,}?(?=\z|([\r\n]{1,}[\d\:\,\.]+))) # Anything until the next timespan is a Cue ) ', 'IgnoreCase,IgnorePatternWhitespace' ) } $allInputAndArgs = @($input) + @(if ($args) { $args }) filter subTime { $in = $_ $original = "$in" # srt is originally French, and so uses commas instead of periods $in = $in -replace ',', '.' # and vtt omits hours, which need to be added if ($in -notlike '*:*:*') { $in = $in -replace '^', '00:' } $inTimespan = $in -as [timespan] if ($inTimespan) { $inTimespan } else { $original } } Update-TypeData -TypeName Subtitle -DefaultDisplayPropertySet StartTime,EndTime,Cue -Force foreach ($in in $allInputAndArgs) { if (Test-path $in -ErrorAction Ignore) { $in = Get-Item $in } $subtitleInfo = [Ordered]@{} if ($in -is [IO.FileInfo]) { $subtitleInfo.File = $in $in = Get-Content -LiteralPath $in.Fullname -Raw } $subtitleInfo.Text = "$in" foreach ($pattern in $patterns.Values) { $matched = $false foreach ($match in @($pattern.Matches( "$($subtitleInfo.Text)" ))) { $matched = $true [PSCustomObject]@{ PSTypeName = 'Subtitle' StartTime = $match.Groups['StartTime'].Value | subTime EndTime = $match.Groups['EndTime'].Value | subTime Cue = $match.Groups['Cue'].Value File = $subtitleInfo.File Match = $match } } if ($matched) { break } } } } |