Intentar escribir un script básico de Powershell que extraerá videos de las URL y los cortará con FFmpeg si lo desea.
Una cosa que debo hacer por adelantado es extraer las opciones de descarga del sitio para ver si quiero usar -f best o -f bestvideo+bestaudio . Así que necesito ejecutar youtube-dl -F [url] y devolver el resultado, pero parece que no puedo hacerlo sin colgar:
param( [string]$url = "https://www.youtube.com/watch?v=njX2bu-_Vw4" ) $YTDLinfo = New-Object System.Diagnostics.ProcessStartInfo $YTDLinfo.FileName = "youtube-dl" $YTDLinfo.RedirectStandardError = $false $YTDLinfo.RedirectStandardOutput = $true $YTDLinfo.UseShellExecute = $false $YTDLinfo.Arguments = "-F $url" $YTDL = New-Object System.Diagnostics.Process $YTDL.StartInfo = $YTDLinfo $YTDL.Start() | Out-Null $YTDL.WaitForExit() $YTDLStdOut = $YTDL.StandardOutput.ReadToEnd().split([Environment]::NewLine) Write-Host $YTDLStdOut Si cambio $YTDLinfo.RedirectStandardOutput a $false , funciona y devuelve el resultado directamente a la consola, pero necesito el resultado en una variable. También vale la pena mencionar que si ejecuto lo anterior pero sin pasar el proceso ningún argumento ( $YTDLinfo.Arguments = "" ) también funciona, incluso con $YTDLinfo.RedirectStandardOutput establecido en $true , y solo devuelve alguna jerga de youtube-dl sobre cómo necesita una url.
Un poco confuso de explicar, pero solo se bloquea cuando se redirige la salida estándar y se le proporciona -F [url] . ¿Algunas ideas?
Su problema inmediato es que está esperando que el proceso finalice sin asegurarse de haber consumido completamente su salida estándar redirigida primero .
Es decir, su llamada .WaitForExit() puede esperar indefinidamente , es decir, si el proceso crea más de un búfer de salida de datos estándar, lo que bloquea el proceso hasta que la persona que llama lea más datos.
Por lo tanto, llame a $YTDL.StandardOuput.ReadToEnd() antes $YTDL.WaitForExit() .
Sin embargo, vale la pena dar un paso atrás :
Para ejecutar aplicaciones de consola (como youtube-dl ) desde PowerShell , sincrónicamente , con sus flujos stdout y stderr conectados a los flujos de salida equivalentes de PowerShell , invóquelos directamente , como lo haría en cualquier shell :
# Directly captures youtube-dl's stdout output as an *array of lines*. $YTDLStdOut = youtube-dl -F $url Utilice la redirección 2> para capturar la salida de stderr en un archivo .
Alternativamente, use 2>&1 para capturar stdout y stderr combinados en una variable, y diferenciar qué línea de salida vino de qué flujo más tarde: -is [string] implica stdout - vea esta respuesta .
Consulte esta respuesta para obtener una descripción general completa de la captura de stdout y stderr a través de la invocación directa de los programas de la consola.
Específicamente, las siguientes técnicas generalmente deben evitarse para invocar aplicaciones de consola:
No use Start-Process (excepto en escenarios inusuales); consulte esta respuesta .
Start-Process es esencialmente un contenedor compatible con PowerShell en torno a la API System.Diagnostics.Process .NET que está utilizando. No use Invoke-Expression , que debe evitarse en general; consulte esta respuesta .