clippy.ps1

<#PSScriptInfo
 
.VERSION 1.7
 
.GUID dce65b3a-d917-425b-9090-d82b368e12fa
 
.AUTHOR Read Stanton (Decimation)
 
.COMPANYNAME
 
.COPYRIGHT
 
.TAGS Downloader yt-dlp ffmpeg clip youtube media
 
.LICENSEURI
 
.PROJECTURI https://github.com/Decimation/PowerShell-Library
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES PSKantan,RoughDraft
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
.PRIVATEDATA
 
#>


<#
.DESCRIPTION
Downloads clips from sites supported by yt-dlp
.PARAMETER Url
Url
.PARAMETER Start
Start time
.PARAMETER End
End time
.PARAMETER Args1
Extra yt-dlp args
.PARAMETER Args2
Extra ffmpeg args
.LINK
https://github.com/Decimation/PowerShell-Library
.EXAMPLE
& "clippy.ps1" -Url "https://www.youtube.com/watch?v=SNgNBsCI4EA" -Start '1:10' -End "1:26"
.EXAMPLE
& "clippy.ps1" -Url "https://youtu.be/YPqYvll6XD0" -Start '10:52' -End "11:38" -Args2 @('-preset','veryfast')
.EXAMPLE
& "clippy.ps1" -u "https://youtu.be/YPqYvll6XD0" -s '1:00' -e "2:00" -Args2 @('-preset','ultrafast')
.EXAMPLE
& "clippy.ps1" -Url "https://www.youtube.com/watch?v=lGJBUauU-CE" -Start 1:00 -End 3:00 -Args2 @('-c','copy')
.EXAMPLE
Clip 00:00:13 to the end:
& "clippy.ps1" -Url "https://www.youtube.com/watch?v=IV_H7wsdWFY" -Start 13
 
#>

param (
    [Parameter(Mandatory)]
    [alias('u')]
    $Url, 
    
    [Parameter(Mandatory)]
    [Alias('s')]
    $Start = '0:0:0', 
    
    [Parameter(Mandatory)]
    [alias('e')]
    $End,

    [Parameter(Mandatory = $false)]
    $Output = $null,

    # yt-dlp args
    [Parameter(Mandatory = $false)]
    $Args1,

    # ffmpeg args
    [Parameter(Mandatory = $false)]
    $Args2 = @('-y', '-preset', 'veryfast'),

    [Alias('cf')]
    [switch]$Confirm
)

#$ErrorActionPreference = 'Abort'
# region Functions

function private:Get-SanitizedFilename {
    param (
        $origFileName, 
        $repl = ''
    )

    $invalids = [System.IO.Path]::GetInvalidFileNameChars()
    $newName = [String]::Join($repl, $origFileName.Split($invalids, 
            [System.StringSplitOptions]::RemoveEmptyEntries)).TrimEnd('.')
    
    return $newName
}

function script:Get-ParsedTime {
    [Outputtype([timespan])]
    param ([string]$t)

    $st = $t.Split(':')

    switch ($st.Length) {
        1 {
            $t = [TimeSpan]::FromSeconds($t)
            return $t;
        }
        2 {
            $t = "0:" + $t
        }
        
    }
    
    try {
        $t = [timespan]::ParseExact($t, "g", [cultureinfo]::CurrentCulture)    
    }
    catch {
        $t = ([timespan]::Parse($t))
    }

    return [timespan] $t
}


function script:Read-Confirmation {
    
    if ($Confirm) {
        switch (Read-Host "Continue? [y/n] (or press enter)") {
            default {
                
            }
            'y' {
                
            }
            'n' {
                exit
            }
        }
    }

}
function script:Find-MediaCommand {
    
    param($c)
    $c2 = (Get-Command $c -ErrorAction SilentlyContinue -CommandType All)
    if (-not $c2) {
        throw "$c not found"
        return
    }
    Write-Host "$c : $($c2.Path)" -ForegroundColor 'DarkGray'
return $c2
}

# endregion

$Start = [timespan] (Get-ParsedTime($Start))
$End = [timespan] (Get-ParsedTime($End))

Write-Host "Start: $Start" -ForegroundColor 'Cyan'
Write-Host "End: $End" -ForegroundColor 'Cyan'

$e_ffmpeg = 'ffmpeg'
$e_ytdlp = 'yt-dlp'

$c_ytdlp = script:Find-MediaCommand $e_ytdlp
$c_ffmpeg = script:Find-MediaCommand $e_ffmpeg


# $tf = "hh\.mm\.ss"
$tf = "hh\hmm\mss\s"

$fs = $Start.ToString($tf)
$fe = $End.ToString($tf)

# $arg2 = @($Url, '--print', 'id')
$arg2 = @($Url, '--print', 'title')

<# $il = [System.IO.Path]::GetInvalidFileNameChars()
$il | ForEach-Object { $s2 = $s -replace ([regex]::Escape($_)), '' } #>


$n1 = "$(& $c_ytdlp @arg2) ($fs - $fe)"

$Output ??= $n1
$Output = Get-SanitizedFilename $Output

Write-Host "Output filename: $Output" -ForegroundColor 'Green'

if (Test-Path $Output) {
    $yn = Read-Host -Prompt "$Output already exists. Remove? [y/n/a]"
    switch ($yn) {
        'y' {
            Remove-Item $Output
        }
        'n' {
            
        }
        'a' {
            return
        }
    }
}


script:Read-Confirmation

# yt-dlp args


$duration = $End - $Start
$ts = "*$Start-$End"
$x2Args += $Args1 + @($Url, `
        '--download-sections', $ts, `
        '--postprocessor-args', "ffmpeg:$Args2") `
    + @('-o', "`"$Output.mp4`"")

Write-Host "Duration: ($duration)" -ForegroundColor 'DarkGray'
Write-Host "final args: $($x2Args -join ' ')" -ForegroundColor 'Cyan'

script:Read-Confirmation

$o_ytdlp = & $c_ytdlp @x2Args

Write-Host "Output: $Output" -ForegroundColor 'Green'

<# $p = Start-Process -FilePath 'ffmpeg.exe' -RedirectStandardOutput:$true `
    -ArgumentList $ffArgs -NoNewWindow -PassThru
 
return $p #>