108 lines
4.6 KiB
PowerShell
108 lines
4.6 KiB
PowerShell
<#
|
|
.SYNOPSIS
|
|
Creates a new clipped video file using Clone-Video.ps1, requiring the -Source and -Frames parameters from that script.
|
|
The filename used for the -Target parameter is automatically derived from the -Source filename, with "-Clip" inserted before the video file extension (e.g., P01.mp4 becomes P01-Clip.mp4).
|
|
When the source name carries a '.skip' marker before its extension, "-Clip" is inserted before that marker so it stays last (e.g., P01.skip.mp4 becomes P01-Clip.skip.mp4).
|
|
Any extra parameters will be pass directly to Clone-Video.ps1, except for parameters -Source, -Frames and -Target.
|
|
.PARAMETER Source
|
|
Path to the input video file. Can be absolute or relative to current directory. If the path has no extension, .mp4, .webm and .mkv are tried in turn.
|
|
.PARAMETER Frames
|
|
0-based frames index to extract. Supports the following formats:
|
|
- start-end: Extract frames from start to end (e.g., "100-200")
|
|
- positive_number: Extract frames from 0 to that number (e.g., "50")
|
|
- -negative_number: Extract last N frames (e.g., "-10")
|
|
- %: Represents the last frame index. Can be used alone or in ranges (e.g., "%", "10-%", "-%")
|
|
- all: Extract all frames (same as "0-%")
|
|
#>
|
|
[CmdletBinding(SupportsShouldProcess)]
|
|
param(
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Source,
|
|
|
|
[Parameter(Mandatory = $true)]
|
|
[string]$Frames,
|
|
|
|
[Parameter(ValueFromRemainingArguments)]
|
|
[object[]]$ExtraArgs
|
|
)
|
|
|
|
Set-StrictMode -Version Latest
|
|
$ErrorActionPreference = 'Stop'
|
|
|
|
$sourcePath = $Source
|
|
|
|
# Resolve source path: accept .mp4, .webm or .mkv. If the path doesn't exist as-is,
|
|
# try appending each supported extension in turn (same logic as Clone-Video.ps1).
|
|
$supportedSourceExts = @('.mp4', '.webm', '.mkv')
|
|
if (-not (Test-Path -LiteralPath $sourcePath)) {
|
|
foreach ($ext in $supportedSourceExts) {
|
|
$candidate = "$sourcePath$ext"
|
|
if (Test-Path -LiteralPath $candidate) {
|
|
$sourcePath = $candidate
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
# Derive the -Target path: insert "-Clip" before the file extension (e.g., P01.mp4 -> P01-Clip.mp4)
|
|
$sourceExt = [System.IO.Path]::GetExtension($sourcePath)
|
|
$sourceBase = [System.IO.Path]::GetFileNameWithoutExtension($sourcePath)
|
|
$sourceDir = [System.IO.Path]::GetDirectoryName($sourcePath)
|
|
|
|
# A '.skip' marker must stay immediately before the container extension, so "-Clip" is
|
|
# inserted before it rather than after (e.g., P01.skip.mp4 -> P01-Clip.skip.mp4).
|
|
# The marker's original casing is preserved.
|
|
$skipMarker = ''
|
|
if ($sourceBase -match '^(.*)(\.skip)$') {
|
|
$sourceBase = $Matches[1]
|
|
$skipMarker = $Matches[2]
|
|
}
|
|
|
|
$targetName = "$sourceBase-Clip$skipMarker$sourceExt"
|
|
$targetPath = if ([string]::IsNullOrEmpty($sourceDir)) { $targetName } else { Join-Path $sourceDir $targetName }
|
|
|
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$cloneVideoScript = Join-Path $scriptDir 'Clone-Video.ps1'
|
|
|
|
# Forward extra args plus common parameters to Clone-Video.ps1.
|
|
# The remaining arguments are turned into a hashtable and splatted by name: PowerShell
|
|
# passes the elements of a splatted *array* as positional arguments, so forwarding
|
|
# @('-Size', '720p') that way would bind '-Size' to Clone-Video.ps1's [int]$StartFrame
|
|
# instead of naming its -Size parameter.
|
|
# Assigned in two steps: an empty array returned from an if-statement block is enumerated
|
|
# away by PowerShell, which would leave $extra as $null.
|
|
$extra = @()
|
|
if ($ExtraArgs) { $extra = @($ExtraArgs) }
|
|
|
|
$forwarded = @{}
|
|
$index = 0
|
|
while ($index -lt $extra.Count) {
|
|
$token = [string]$extra[$index]
|
|
|
|
if ($token -notmatch '^-{1,2}([A-Za-z]\w*)$') {
|
|
Write-Error ("Unexpected argument '{0}'. Extra parameters must be passed by name (e.g. -Size 720p)." -f $token)
|
|
exit 1
|
|
}
|
|
$name = $Matches[1]
|
|
|
|
$next = if (($index + 1) -lt $extra.Count) { [string]$extra[$index + 1] } else { $null }
|
|
|
|
# The next token is this parameter's value unless it is itself a parameter name.
|
|
# A '-' followed by a digit is a value, not a name (e.g. -CRF -1).
|
|
if ($null -ne $next -and (($next -notmatch '^-{1,2}[A-Za-z]') -or ($next -match '^-\d'))) {
|
|
$forwarded[$name] = $extra[$index + 1]
|
|
$index += 2
|
|
}
|
|
else {
|
|
# No value follows, so this is a switch (e.g. -NoAudio, -Reverse, -LTX).
|
|
$forwarded[$name] = $true
|
|
$index++
|
|
}
|
|
}
|
|
|
|
if ($PSBoundParameters.ContainsKey('WhatIf')) { $forwarded['WhatIf'] = [bool]$PSBoundParameters['WhatIf'] }
|
|
if ($PSBoundParameters.ContainsKey('Confirm')) { $forwarded['Confirm'] = [bool]$PSBoundParameters['Confirm'] }
|
|
|
|
& $cloneVideoScript -Source $sourcePath -Frames $Frames -Target $targetPath @forwarded
|
|
exit $LASTEXITCODE
|