Skip to content

Commit

Permalink
With yt-dlp, cancellation requires killing the child process
Browse files Browse the repository at this point in the history
  • Loading branch information
jnm2 committed Aug 12, 2023
1 parent 2ceb0c8 commit 885dc8d
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 1 deletion.
29 changes: 29 additions & 0 deletions src/YouTubeDownloadTool/Utils/Utils.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Diagnostics;
using System.IO;
using System.Reflection;

namespace YouTubeDownloadTool;

Expand Down Expand Up @@ -40,4 +42,31 @@ await using (var file = tempFile.OpenStream())

return fileLock;
}

private static readonly Func<Process, Process[]?, IReadOnlyList<Process>>? GetChildProcesses =
typeof(Process).GetMethod("GetChildProcesses", BindingFlags.NonPublic | BindingFlags.Instance, null, new[] { typeof(Process[]) }, null)
?.CreateDelegate<Func<Process, Process[]?, IReadOnlyList<Process>>>();

public static IReadOnlyList<Process>? TryFilterToChildProcesses(Process[] candidates, Process parentProcess)
{
return GetChildProcesses?.Invoke(parentProcess, candidates);
}

public static void TryKillImmediateChildrenWithProcessName(Process parentProcess, string childProcessName)
{
var allProcessesWithName = Process.GetProcessesByName(childProcessName);
try
{
if (TryFilterToChildProcesses(allProcessesWithName, parentProcess) is { } childProcesses)
{
foreach (var childProcess in childProcesses)
childProcess.Kill();
}
}
finally
{
foreach (var process in allProcessesWithName)
process.Dispose();
}
}
}
14 changes: 13 additions & 1 deletion src/YouTubeDownloadTool/YTDlpTool.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,19 @@ public YTDlpTool(string executablePath, string ffmpegDirectory)
process.BeginOutputReadLine();
process.BeginErrorReadLine();

await using (cancellationToken.Register(process.Kill))
void Cancel()
{
var processName = process.ProcessName; // This can't be accessed after Process.Kill

// Prevent from starting any future child processes
process.Kill();

// Unlike youtube-dl, yt-dlp starts a child process with the same name (yt-dlp). Once it's done this,
// killing the process we started doesn't cancel anything.
Utils.TryKillImmediateChildrenWithProcessName(parentProcess: process, childProcessName: processName);
}

await using (cancellationToken.Register(Cancel))
await process.WaitForExitAsync(CancellationToken.None);

cancellationToken.ThrowIfCancellationRequested();
Expand Down

0 comments on commit 885dc8d

Please sign in to comment.