Search code examples
powershellyoutube-dl

Powershell replacing : with #


I'm trying to download videos with a script into a predefined directory:

$save_dir = 'video'
$list_dir = "-o N:/$save_dir/%(upload_date)s_%(title)s_%(id)s.%(ext)s"
ForEach ($item in $list_dir) {
  Write-Host $item
  & yt-dlp $item `
  --cache-dir "$PSScriptRoot/bin/cache" `
  $(Get-Clipboard)
}

$list_dir being a single element array is a necessity (part of a larger script), hence the ForEach loop. Terminal output (note that you need to copy the video URL into clipboard first):

-o N:/video/%(upload_date)s_%(title)s_%(id)s.%(ext)s
[youtube] YbJOTdZBX1g: Downloading webpage
[info] YbJOTdZBX1g: Downloading 1 format(s): 248+251
[download] Destination:  N#\video\20181206_YouTube Rewind 2018 - Everyone Controls Rewind _ #YouTubeRewind_YbJOTdZBX1g.f248.webm

This ends up creating a directory called N# inside the directory the terminal is run from. Why is it replacing : after the drive letter with a #? It clearly knows it's a : based on the Write-Host ouput.


Solution

  • Why is it replacing : after the drive letter with a #?

    It isn't PowerShell that is performing this substitution; by process of elimination, it must be yt-dlb

    "-o N:/$save_dir/%(upload_date)s_%(title)s_%(id)s.%(ext)s"

    You cannot pass both an option and its argument as a single string - PowerShell will pass it as a single, double-quoted argument (double-quoted due to the presence of at least one space).

    The equivalent of passing & yt-dlp -o N:/$save_dir/%(upload_date)s_%(title)s_%(id)s.%(ext)s via a variable is to use an array variable, with the option name and its argument passed as separate elements:

    $arr = '-o', "N:/$save_dir/%(upload_date)s_%(title)s_%(id)s.%(ext)s"
    & yt-dlp $arr --cache-dir $PSScriptRoot/bin/cache (Get-Clipboard)
    

    Note: The above uses a single array for brevity. To define multiple arrays hosted in a single array you can easily define a jagged array (an array whose elements are arrays too); using the example of a jagged array containing just one nested array (option+argument) pair, constructed via the unary form of ,, the array constructor operator:

    $list_dir = , ('-o', "N:/$save_dir/%(upload_date)s_%(title)s_%(id)s.%(ext)s")
    ForEach ($item in $list_dir) {
      & yt-dlp $item --cache-dir $PSScriptRoot/bin/cache (Get-Clipboard)
    }
    

    For multi-element jagged arrays, place , between the sub-arrays
    ($list_dir = ('-o', 'foo'), ('-o', 'bar')).