From c8c5a5d75c93a9c88205ecf8bcea13ec57a5e07c Mon Sep 17 00:00:00 2001 From: Claude Toupin Date: Mon, 26 Oct 2026 22:32:28 -0400 Subject: [PATCH] Add .skip marker preservation to Create-Clip.ps1 by detecting and extracting '.skip' suffix from source basename before inserting "-Clip" so marker stays immediately before container extension (e.g. P01.skip.mp4 -> P01-Clip.skip.mp4), and refactor extra parameter forwarding from array to hashtable splatting to pass arguments by name instead of position, parsing -Name value pairs and standalone switches while validating parameter syntax, preventing positional binding issues like '-Size 720p' being interpreted as positional --- Create-Clip.ps1 | 58 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/Create-Clip.ps1 b/Create-Clip.ps1 index 167fd49..cf5a69b 100644 --- a/Create-Clip.ps1 +++ b/Create-Clip.ps1 @@ -2,6 +2,7 @@ .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. @@ -47,17 +48,60 @@ if (-not (Test-Path -LiteralPath $sourcePath)) { $sourceExt = [System.IO.Path]::GetExtension($sourcePath) $sourceBase = [System.IO.Path]::GetFileNameWithoutExtension($sourcePath) $sourceDir = [System.IO.Path]::GetDirectoryName($sourcePath) -$targetName = "$sourceBase-Clip$sourceExt" + +# 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 -$passThrough = @() -if ($ExtraArgs) { $passThrough += $ExtraArgs } -if ($PSBoundParameters.ContainsKey('WhatIf')) { $passThrough += '-WhatIf' } -if ($PSBoundParameters.ContainsKey('Confirm')) { $passThrough += '-Confirm' } +# 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) } -& $cloneVideoScript -Source $sourcePath -Frames $Frames -Target $targetPath @passThrough +$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