Ytdlp.NET
3.2.0
Prefix Reserved
dotnet add package Ytdlp.NET --version 3.2.0
NuGet\Install-Package Ytdlp.NET -Version 3.2.0
<PackageReference Include="Ytdlp.NET" Version="3.2.0" />
<PackageVersion Include="Ytdlp.NET" Version="3.2.0" />
<PackageReference Include="Ytdlp.NET" />
paket add Ytdlp.NET --version 3.2.0
#r "nuget: Ytdlp.NET, 3.2.0"
#:package Ytdlp.NET@3.2.0
#addin nuget:?package=Ytdlp.NET&version=3.2.0
#tool nuget:?package=Ytdlp.NET&version=3.2.0
Ytdlp.NET
v3.2
Ytdlp.NET is a fluent, strongly-typed .NET wrapper around yt-dlp. It provides a fully async, event-driven interface for downloading videos, extracting audio, retrieving metadata, and post-processing media from YouTube and hundreds of other platforms.
⚠️ Important Notes
- Namespace migrated:
ManuHub.Ytdlp.NET— update yourusingdirectives. - External JS runtime: yt-dlp requires an external JS runtime like deno.exe (from denoland/deno) for YouTube downloads with JS challenges.
- Required tools:
Tools/
├─ yt-dlp.exe
├─ deno.exe
├─ ffmpeg.exe
└─ ffprobe.exe
Recommended: Use companion NuGet packages:
ManuHub.YtdlpManuHub.DenoManuHub.FFmpegManuHub.FFprobe
Example path resolution in .NET:
var ytdlpPath = Path.Combine(AppContext.BaseDirectory, "tools", "yt-dlp.exe");
var ffmpegPath = Path.Combine(AppContext.BaseDirectory, "tools");
🌲 Deep Metadata Support
Ytdlp.NET now supports deep playlist extraction with full hierarchical structure support (seasons → episodes → nested playlists).
🔹 Flat Mode (default - no change)
var metadata = await ytdlp.GetMetadataAsync(url);
- Fast
- Returns only top-level items
- Fully backward compatible
🔹 Deep Mode (NEW)
var metadata = await ytdlp.GetDeepMetadataAsync(url);
- Returns full hierarchy
- Supports playlists → seasons → episodes
- Slightly slower but complete data
🔁 Traverse Nested Entries
Use this helper to read all items in deep mode:
foreach (var root in metadata.Entries ?? [])
{
foreach (var item in root.Traverse())
{
Console.WriteLine(item.Title);
}
}
🚀 New in v3.2
- New 'Traverse()' method for easy iteration over nested playlist entries.
- New
GetDeepMetadataAsync()method for comprehensive metadata extraction. - New
GetDeepMetadataRawAsync()for raw JSON metadata. - Improved
Metadatamodel with more fields and better parsing. - Improved UpdateAsync with specific version support.
- 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.
✨ Features
- 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).
🛠 Methods
VersionAsync(CancellationToken ct)UpdateAsync(UpdateChannel channel, string specificVersion, CancellationToken ct)ExtractorsAsync(CancellationToken ct, int bufferKb)GetMetadataAsync(string url, CancellationToken ct, int bufferKb)GetMetadataRawAsync(string url, CancellationToken ct, int bufferKb)GetDeepMetadataAsync(string url, CancellationToken ct = default, bool tuneProcess = true, int bufferKb = 256)GetDeepMetadataRawAsync(string url, CancellationToken ct = default, bool tuneProcess = true, int bufferKb = 256)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)
🔧 Thread Safety & Disposal
- Immutable & thread-safe: Each
WithXxx()call returns a new instance. - Async disposal:
YtdlpimplementsIAsyncDisposable.
Sequential download example:
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");
Parallel download example:
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);
Key points:
- Always create a new instance per download for parallel operations.
- Always use
await usingfor proper resource cleanup. - Attach events after the
WithXxx()call.
📦 Basic Usage
Download a Single Video
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");
Extract Audio
await using var ytdlp = new Ytdlp("tools\\yt-dlp.exe")
.WithExtractAudio(AudioFormat.Mp3, 5)
.WithOutputFolder("./audio")
.WithEmbedThumbnail()
.WithEmbedMetadata();
await ytdlp.DownloadAsync("https://www.youtube.com/watch?v=RGg-Qx1rL9U");
Fetch Metadata
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}");
Fetch Formats
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}");
Best Format Selection
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);
Batch Downloads
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);
Fluent Methods (v3.0)
General Options
.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()
Network Options
.WithProxy(string? proxy).WithSocketTimeout(TimeSpan timeout).WithForceIpv4().WithForceIpv6().WithEnableFileUrls()
Geo-restriction Options
.WithGeoVerificationProxy(string url).WithGeoBypassCountry(string countryCode)
Video Selection
.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()
Download Options
.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)
Filesystem Options
.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()
Thumbnail Options
.WithThumbnails(bool allSizes = false)
Verbosity and Simulation Options
.WithQuiet().WithNoWarnings().WithSimulate().WithNoSimulate().WithSkipDownload().WithVerbose()
Workgrounds
.WithAddHeader(string header, string value).WithSleepInterval(double seconds, double? maxSeconds = null).WithSleepSubtitles(double seconds)
Video Format Options
.WithFormat(string format).WithMergeOutputFormat(string format)
Subtitle Options
.WithSubtitles(string languages = "all", bool auto = false)
Authentication Options
.WithAuthentication(string username, string password).WithTwoFactor(string code)
Post-Processing Options
.WithExtractAudio(string format, int quality = 5).WithRemuxVideo(string format)usage 'mp4' or 'mp4>mkv'.WithRecodeVideo(string format, string? videoCodec = null, string? audioCodec = null).WithPostprocessorArgs(PostProcessors postprocessor, string args).WithKeepVideo().WithNoPostOverwrites().WithEmbedSubtitles().WithEmbedThumbnail().WithEmbedMetadata().WithEmbedChapters().WithEmbedInfoJson().WithNoEmbedInfoJson().WithReplaceInMetadata(string field, string regex, string replacement).WithConcatPlaylist(string policy = "always").WithFFmpegLocation(string? ffmpegPath).WithConvertSubtitles(string format = "none").WithConvertThumbnails(string format = "jpg").WithSplitChapters() => AddFlag("--split-chapters").WithRemoveChapters(string regex).WithForceKeyframesAtCuts().WithUsePostProcessor(PostProcessors postProcessor, string? postProcessorArgs = null)
SponsorBlock Options
.WithSponsorblockMark(string categories = "all").WithSponsorblockRemove(string categories = "all").WithNoSponsorblock()
Advanced Options
.AddFlag(string flag).AddOption(string key, string value)
Downloaders
.WithExternalDownloader(string downloaderName, string? downloaderArgs = null).WithAria2(int connections = 16).WithHlsNative().WithFfmpegAsLiveDownloader(string? extraFfmpegArgs = null)
AND MORE ...
Events
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.OnPostProcessingStart += (s, msg) => Console.WriteLine($"Post-processing-start: {msg}")
ytdlp.OnPostProcessingComplete += (s, msg) => Console.WriteLine($"Post-processing-complete: {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}");
🔄 Upgrade Guide (v2 → v3)
v3 introduces a new immutable fluent API.
Old mutable commands were removed.
❌ Old API (v2)
var ytdlp = new Ytdlp();
await ytdlp
.SetFormat("best")
.SetOutputFolder("./downloads")
.ExecuteAsync(url);
✅ New API (v3)
await using var ytdlp = new Ytdlp()
.WithFormat("best")
.WithOutputFolder("./downloads");
await ytdlp.DownloadAsync(url);
Method changes
| v2 | v3 |
|---|---|
SetFormat() |
WithFormat() |
SetOutputFolder() |
WithOutputFolder() |
SetTempFolder() |
WithTempFolder() |
SetOutputTemplate() |
WithOutputTemplate() |
SetFFMpegLocation() |
WithFFmpegLocation() |
ExtractAudio() |
WithExtractAudio() |
UseProxy() |
WithProxy() |
AddCustomCommand() |
AddFlag(string flag) or AddOption(string key, string value) |
Custom commands
AddFlag("--no-check-certificate");
AddOption("--external-downloader", "aria2c");
Important behavior changes
Instances are immutable
Every WithXxx() call returns a new instance.
var baseYtdlp = new Ytdlp();
var download = baseYtdlp
.WithFormat("best")
.WithOutputFolder("./downloads");
Event subscription
Attach events to the configured instance.
var download = baseYtdlp.WithFormat("best");
download.OnProgressDownload += ...
Proper disposal
Use await using for automatic cleanup.
await using var ytdlp = new Ytdlp();
✅ Notes
- 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.).
License
MIT License — see LICENSE
Author: Manojbabu (ManuHub)
Repository: Ytdlp.NET
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 3.2.0 | 35 | 5/25/2026 | |
| 3.1.1 | 42 | 5/24/2026 | |
| 3.1.0 | 117 | 5/16/2026 | |
| 3.0.4 | 141 | 5/3/2026 | |
| 3.0.3 | 246 | 4/10/2026 | |
| 3.0.2 | 145 | 4/4/2026 | |
| 3.0.1 | 163 | 4/3/2026 | |
| 3.0.0 | 187 | 3/22/2026 | |
| 2.2.0 | 130 | 3/17/2026 | |
| 2.1.1 | 158 | 3/17/2026 | |
| 2.1.0 | 153 | 3/16/2026 | |
| 2.0.2 | 134 | 3/14/2026 | |
| 2.0.1 | 198 | 2/19/2026 | |
| 2.0.0 | 135 | 2/18/2026 | |
| 2.0.0-preview1 | 133 | 2/15/2026 | |
| 1.4.0 | 481 | 11/24/2025 | |
| 1.3.0 | 278 | 11/15/2025 | |
| 1.2.3 | 277 | 10/19/2025 | |
| 1.2.2 | 351 | 8/8/2025 | |
| 1.2.1 | 323 | 8/5/2025 |
Ytdlp.NET v3.2 ✨ Minor update.
- Complete rewrite using an immutable, fluent API (`WithXxx()` methods).
- Added `IAsyncDisposable` support for proper async cleanup of processes.
- Thread-safe design: safe to run multiple instances in parallel.
- Rich event system: OnProgressDownload, OnProgressMessage, OnCompleteDownload,
OnPostProcessingComplete, OnErrorMessage, OnCommandCompleted.
- Improved cancellation handling for both downloads and metadata probing.
- Enhanced probe methods: GetMetadataAsync, GetAvailableFormatsAsync,
GetBestVideoFormatIdAsync, GetBestAudioFormatIdAsync.
- Better output templates, FFmpeg/Deno integration, and safe custom command support.
🛠 Improvements in this update
- Better internal DownloadRunner and ProbeRunner for heavy JSON output and cancellation safety.
- Safer process killing and stream handling to prevent potential hangs.
🚀 New Features
- Fully chainable fluent API for downloads, audio extraction, subtitles, post-processing and more.
- Batch download support (sequential or parallel execution).
- Real-time progress tracking via events.
- Automatic resource cleanup with `await using`.
- Cross-platform (Windows, macOS, Linux).
⚠️ Breaking Change
- Improve progress parsing and cancellation handling, which may require adjustments in event handling and cancellation token usage.
- All old command methods (SetFormat, SetOutputFolder, etc.) have been removed.
- Only the new fluent `WithXxx()` style remains.
- Namespace changed to `ManuHub.Ytdlp.NET`.
- Always use a fresh instance per download for parallel scenarios.
- Use `await using` for proper async disposal.
🛠 Notes
- Companion packages recommended: ManuHub.Ytdlp, ManuHub.FFmpeg, ManuHub.FFprobe, ManuHub.Deno.
- All examples and documentation updated for v3.0.
- This release greatly improves reliability, cancellation, and maintainability.
See the repository for the full migration guide.