-
Notifications
You must be signed in to change notification settings - Fork 2
v3.x.x
Manojbabu edited this page Mar 24, 2026
·
1 revision
-
Fluent API: Build yt-dlp commands with
WithXxx()methods. - Immutable & thread-safe: Each method returns a new instance, safe for parallel usage.
- Async & IAsyncDisposable: Automatic cleanup of child processes.
- Progress & Events: Real-time progress tracking and post-processing notifications.
- Format Listing: Retrieve and parse available formats.
- Batch Downloads: Sequential or parallel execution.
- Output Templates: Flexible naming with yt-dlp placeholders.
- Custom Command Injection: Add extra yt-dlp options safely.
- Cross-platform: Windows, macOS, Linux (where yt-dlp is supported).
- Full support for
IAsyncDisposablewithawait using. - Immutable builder (
WithXxx) for safe instance reuse. - Updated examples for event-driven downloads.
- Simplified metadata fetching & format selection.
- High-performance probe methods with optional buffer size.
- Improved cancellation & error handling.
VersionAsync(CancellationToken ct)UpdateAsync(UpdateChannel channel, CancellationToken ct)ExtractorsAsync(CancellationToken ct, int bufferKb)GetMetadataAsync(string url, CancellationToken ct, int bufferKb)GetMetadataRawAsync(string url, CancellationToken ct, int bufferKb)GetFormatsAsync(string url, CancellationToken ct, int bufferKb)GetMetadataLiteAsync(string url, CancellationToken ct, int bufferKb)GetMetadataLiteAsync(string url, IEnumerable<string> fields, CancellationToken ct, int bufferKb)GetBestAudioFormatIdAsync(string url, CancellationToken ct, int bufferKb)GetBestVideoFormatIdAsync(string url, int maxHeight, CancellationToken ct, int bufferKb)ExecuteAsync(string url, CancellationToken ct)ExecuteBatchAsync(IEnumerable<string> urls, int maxConcurrency, CancellationToken ct)
-
Immutable & thread-safe: Each
WithXxx()call returns a new instance. -
Async disposal:
YtdlpimplementsIAsyncDisposable.
await using var ytdlp = new Ytdlp("tools\\yt-dlp.exe", new ConsoleLogger())
.WithFormat("best")
.WithOutputFolder("./downloads");
ytdlp.OnProgressDownload += (s, e) => Console.WriteLine($"Progress: {e.Percent:F2}%");
ytdlp.OnCompleteDownload += (s, msg) => Console.WriteLine($"Download complete: {msg}");
await ytdlp.DownloadAsync("https://www.youtube.com/watch?v=RGg-Qx1rL9U");var urls = new[] { "https://youtu.be/video1", "https://youtu.be/video2" };
var tasks = urls.Select(async url =>
{
await using var ytdlp = new Ytdlp("tools\\yt-dlp.exe", new ConsoleLogger())
.WithFormat("best")
.WithOutputFolder("./batch");
ytdlp.OnProgressDownload += (s, e) => Console.WriteLine($"[{url}] {e.Percent:F2}%");
ytdlp.OnCompleteDownload += (s, msg) => Console.WriteLine($"[{url}] Download complete: {msg}");
await ytdlp.DownloadAsync(url);
});
await Task.WhenAll(tasks);- Always create a new instance per download for parallel operations.
- Always use
await usingfor proper resource cleanup. - Attach events after the
WithXxx()call.
await using var ytdlp = new Ytdlp("tools\\yt-dlp.exe", new ConsoleLogger())
.WithFormat("best")
.WithOutputFolder("./downloads")
.WithEmbedMetadata()
.WithEmbedThumbnail();
ytdlp.OnProgressDownload += (s, e) => Console.WriteLine($"Progress: {e.Percent:F2}%");
ytdlp.OnCompleteDownload += (s, msg) => Console.WriteLine($"Download complete: {msg}");
await ytdlp.DownloadAsync("https://www.youtube.com/watch?v=RGg-Qx1rL9U");await using var ytdlp = new Ytdlp("tools\\yt-dlp.exe")
.WithExtractAudio("mp3")
.WithOutputFolder("./audio")
.WithEmbedMetadata();
await ytdlp.DownloadAsync("https://www.youtube.com/watch?v=RGg-Qx1rL9U");await using var ytdlp = new Ytdlp("tools\\yt-dlp.exe");
var metadata = await ytdlp.GetMetadataAsync("https://www.youtube.com/watch?v=abc123");
Console.WriteLine($"Title: {metadata?.Title}, Duration: {metadata?.Duration}");await using var ytdlp = new Ytdlp("tools\\yt-dlp.exe");
var formats = await ytdlp.GetFormatsAsync("https://www.youtube.com/watch?v=abc123");
foreach(var format in formats)
Console.WriteLine($"Id: {metadata?.Id}, Extension: {metadata?.Extension}");await using var ytdlp = new Ytdlp("tools\\yt-dlp.exe");
string bestAudio = await ytdlp.GetBestAudioFormatIdAsync(url);
string bestVideo = await ytdlp.GetBestVideoFormatIdAsync(url, maxHeight: 720);
await ytdlp
.WithFormat($"{bestVideo}+{bestAudio}/best")
.WithOutputFolder("./downloads")
.DownloadAsync(url);var urls = new[] { "https://youtu.be/vid1", "https://youtu.be/vid2" };
var tasks = urls.Select(async url =>
{
await using var ytdlp = new Ytdlp("tools\\yt-dlp.exe")
.WithFormat("best")
.WithOutputFolder("./batch");
await ytdlp.DownloadAsync(url);
});
await Task.WhenAll(tasks);OR
var urls = new[] { "https://youtu.be/vid1", "https://youtu.be/vid2" };
await using var ytdlp = new Ytdlp("tools\\yt-dlp.exe")
.WithFormat("best")
.WithOutputFolder("./batch");
await ytdlp.DownloadBatchAsync(urls, maxConcurrency: 3);.WithIgnoreErrors().WithAbortOnError().WithIgnoreConfig().WithConfigLocations(string path).WithPluginDirs(string path).WithNoPluginDirs(string path).WithJsRuntime(Runtime runtime, string runtimePath).WithNoJsRuntime().WithFlatPlaylist()WithLiveFromStart().WithWaitForVideo(TimeSpan? maxWait = null).WithMarkWatched()
.WithProxy(string? proxy).WithSocketTimeout(TimeSpan timeout).WithForceIpv4().WithForceIpv6().WithEnableFileUrls()
.WithGeoVerificationProxy(string url).WithGeoBypassCountry(string countryCode)
.WithPlaylistItems(string items).WithMinFileSize(string size).WithMaxFileSize(string size).WithDate(string date).WithDateBefore(string date).WithDateAfter(string date).WithMatchFilter(string filterExpression).WithNoPlaylist().WithYesPlaylist().WithAgeLimit(int years).WithDownloadArchive(string archivePath = "archive.txt").WithMaxDownloads(int count).WithBreakOnExisting()
.WithConcurrentFragments(int count = 8).WithLimitRate(string rate).WithThrottledRate(string rate).WithRetries(int maxRetries).WithFileAccessRetries(int maxRetries).WithFragmentRetries(int retries).WithSkipUnavailableFragments().WithAbortOnUnavailableFragments().WithKeepFragments().WithBufferSize(string size).WithNoResizeBuffer().WithPlaylistRandom().WithHlsUseMpegts().WithNoHlsUseMpegts().WithDownloadSections(string regex)
.WithHomeFolder(string path).WithTempFolder(string path).WithOutputFolder(string path).WithFFmpegLocation(string path).WithOutputTemplate(string template).WithRestrictFilenames().WithWindowsFilenames().WithTrimFilenames(int length).WithNoOverwrites().WithForceOverwrites().WithNoContinue().WithNoPart().WithMtime().WithWriteDescription().WithWriteInfoJson().WithNoWritePlaylistMetafiles().WithNoCleanInfoJson().WriteComments().WithNoWriteComments().WithLoadInfoJson(string path).WithCookiesFile(string path).WithCookiesFromBrowser(string browser).WithNoCacheDir().WithRemoveCacheDir()
.WithThumbnails(bool allSizes = false)
.WithQuiet().WithNoWarnings().WithSimulate().WithNoSimulate().WithSkipDownload().WithVerbose()
.WithAddHeader(string header, string value).WithSleepInterval(double seconds, double? maxSeconds = null).WithSleepSubtitles(double seconds)
.WithFormat(string format).WithMergeOutputFormat(string format)
.WithSubtitles(string languages = "all", bool auto = false)
.WithAuthentication(string username, string password).WithTwoFactor(string code)
.WithExtractAudio(string format = "mp3", int quality = 5).WithRemuxVideo(MediaFormat format = MediaFormat.Mp4).WithRecodeVideo(MediaFormat format = MediaFormat.Mp4, string? videoCodec = null, string? audioCodec = null).WithPostprocessorArgs(PostProcessors postprocessor, string args).WithKeepVideo().WithNoPostOverwrites().WithEmbedSubtitles(string languages = "all", string? convertTo = null).WithEmbedThumbnail().WithEmbedMetadata().WithEmbedChapters().WithEmbedInfoJson().WithNoEmbedInfoJson().WithReplaceInMetadata(string field, string regex, string replacement).WithConcatPlaylist(string policy = "always").WithFFmpegLocation(string? ffmpegPath).WithConvertThumbnails(string format = "jpg").WithForceKeyframesAtCuts()
.WithSponsorblockMark(string categories = "all").WithSponsorblockRemove(string categories = "all").WithNoSponsorblock()
.AddFlag(string flag).AddOption(string key, string value)
.WithExternalDownloader(string downloaderName, string? downloaderArgs = null).WithAria2(int connections = 16).WithHlsNative().WithFfmpegAsLiveDownloader(string? extraFfmpegArgs = null)
AND MORE ...
ytdlp.OnProgressDownload += (s, e) => Console.WriteLine($"Progress: {e.Percent:F2}%");
ytdlp.OnProgressMessage += (s, msg) => Console.WriteLine(msg);
ytdlp.OnCompleteDownload += (s, msg) => Console.WriteLine($"Done: {msg}");
ytdlp.OnPostProcessingComplete += (s, msg) => Console.WriteLine($"Post-processing: {msg}");
ytdlp.OnErrorMessage += (s, err) => Console.WriteLine($"Error: {err}");
ytdlp.OnOutputMessage += (s, msg) => Console.WriteLine(msg);
ytdlp.OnCommandCompleted += (s, e) => Console.WriteLine($"Command finished: {e.Command}");v3 introduces a new immutable fluent API.
Old mutable commands were removed.
var ytdlp = new Ytdlp();
await ytdlp
.SetFormat("best")
.SetOutputFolder("./downloads")
.ExecuteAsync(url);await using var ytdlp = new Ytdlp()
.WithFormat("best")
.WithOutputFolder("./downloads");
await ytdlp.DownloadAsync(url);| v2 | v3 |
|---|---|
SetFormat() |
WithFormat() |
SetOutputFolder() |
WithOutputFolder() |
SetTempFolder() |
WithTempFolder() |
SetOutputTemplate() |
WithOutputTemplate() |
SetFFMpegLocation() |
WithFFmpegLocation() |
ExtractAudio() |
WithExtractAudio() |
UseProxy() |
WithProxy() |
Every WithXxx() call returns a new instance.
var baseYtdlp = new Ytdlp();
var download = baseYtdlp
.WithFormat("best")
.WithOutputFolder("./downloads");Attach events to the configured instance.
var download = baseYtdlp.WithFormat("best");
download.OnProgressDownload += ...Use await using for automatic cleanup.
await using var ytdlp = new Ytdlp();- All commands now start with
WithXxx(). - Immutable: no shared state; safe for parallel usage.
- Always
await usingfor proper disposal. - Deprecated old methods removed.
- Probe methods remain the same (
GetMetadataAsync,GetFormatsAsync,GetBestVideoFormatIdAsync, etc.).
MIT License — see LICENSE
Author: Manojbabu (ManuHub)
Repository: Ytdlp.NET
Copyright (C) 2025-2026 Manojbabu, Manuhub