Ytdlp.NET
4.0.0-preview1
Prefix Reserved
See the version list below for details.
dotnet add package Ytdlp.NET --version 4.0.0-preview1
NuGet\Install-Package Ytdlp.NET -Version 4.0.0-preview1
<PackageReference Include="Ytdlp.NET" Version="4.0.0-preview1" />
<PackageVersion Include="Ytdlp.NET" Version="4.0.0-preview1" />
<PackageReference Include="Ytdlp.NET" />
paket add Ytdlp.NET --version 4.0.0-preview1
#r "nuget: Ytdlp.NET, 4.0.0-preview1"
#:package Ytdlp.NET@4.0.0-preview1
#addin nuget:?package=Ytdlp.NET&version=4.0.0-preview1&prerelease
#tool nuget:?package=Ytdlp.NET&version=4.0.0-preview1&prerelease
Ytdlp.NET
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.
β¨ Features
- Fluent API: Build yt-dlp commands with
WithXxx()methods. - Immutable & thread-safe: Each method returns a new instance, safe for parallel usage.
- 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).
π New in this release
- Add more WithXxx() methods for advanced options.
- New GetAdobePassListAsync() for Adobe Pass mso listing.
- New GetSubtitlesAsync() for subtitle extraction.
- New Traverse() method for easy iteration over nested playlist entries.
- New GetDeepMetadataAsync() method for comprehensive metadata extraction.
- New GetDeepMetadataRawAsync() for raw JSON metadata.
- Improved Metadata model with more fields and better parsing.
- Improved UpdateAsync with specific version support.
- Full support for IAsyncDisposable with await 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.
π§ Required Tools
β οΈ 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:
| Package | Description |
|---|---|
| ManuHub.Ytdlp | Core yt-dlp wrapper with fluent API and event handling. |
| ManuHub.Deno | Provides the required Deno runtime for yt-dlp for JavaScript challenges. |
| ManuHub.FFmpeg | Provides the required FFmpeg executable for post-processing. |
| ManuHub.FFprobe | Provides the required FFprobe executable for format probing. |
Example path resolution in .NET:
var ytdlpPath = Path.Combine(AppContext.BaseDirectory, "tools", "yt-dlp.exe");
var ffmpegPath = Path.Combine(AppContext.BaseDirectory, "tools");
π¨ No Disposal Required:
Ytdlp holds no unmanaged resources and does not implement IDisposable or IAsyncDisposable. Instances are plain configuration objects β create them, share them freely, and let the GC collect them when they go out of scope. All internal runners and parsers are created per-call and cleaned up automatically after each execution.
π Improved Secure Authentication Support
Implemented secure authentication handling for various scenarios, including standard username/password and Adobe Pass authentication.
- .WithAuthentication(string username, string password)
- .WithAdobePassAuthentication(string mso, string username, string password)
It securely handles credentials by passing them via standard input to the yt-dlp process, avoiding exposure in command-line arguments or logs. The library ensures that sensitive information is not stored in memory longer than necessary and is properly disposed of after use.
π² 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);
}
}
π§ Thread Safety
- Immutable & thread-safe: Each
WithXxx()call returns a new instance.
Sequential download example:
var ytdlp = new Ytdlp("tools\\yt-dlp.exe", new ConsoleLogger())
.WithFormat("best")
.WithOutputFolder("./downloads");
ytdlp.ProgressDownload += (s, e) => Console.WriteLine($"Progress: {e.Percent:F2}%");
ytdlp.DownloadCompleted += (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 =>
{
var ytdlp = new Ytdlp("tools\\yt-dlp.exe", new ConsoleLogger())
.WithFormat("best")
.WithOutputFolder("./batch");
ytdlp.ProgressDownload += (s, e) => Console.WriteLine($"[{url}] {e.Percent:F2}%");
ytdlp.DownloadCompleted += (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.
- No shared state between instances, so no need to worry about thread safety.
- Attach events after the
WithXxx()call.
π¦ Basic Usage
Download a Single Video
var ytdlp = new Ytdlp("tools\\yt-dlp.exe", new ConsoleLogger())
.WithFormat("best")
.WithOutputFolder("./downloads")
.WithEmbedMetadata()
.WithEmbedThumbnail();
ytdlp.rogressDownload += (s, e) => Console.WriteLine($"Progress: {e.Percent:F2}%");
ytdlp.DownloadCompleted += (s, msg) => Console.WriteLine($"Download complete: {msg}");
await ytdlp.DownloadAsync("https://www.youtube.com/watch?v=RGg-Qx1rL9U");
Extract Audio
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");
Download a Playlist
var ytdlp = new Ytdlp("tools\\yt-dlp.exe")
.WithFormat("best")
.WithOutputFolder("./playlists")
.WithPlaylistStart(1)
.WithPlaylistEnd(5)
.OutputTemplate("%(playlist)s/%(playlist_index)s - %(title)s.%(ext)s");
await ytdlp.DownloadAsync("https://www.youtube.com/playlist?list=PL12345");
π Monitor Progress & Events
ytdlp.ProgressDownload += (s, e) =>
Console.WriteLine($"{e.Percent:F1}% {e.Speed} ETA {e.ETA}");
ytdlp.DownloadCompleted += (s, msg) =>
Console.WriteLine($"Finished: {msg}");
ytdlp.ProgressMessage += (s, msg) => Console.WriteLine(msg);
ytdlp.PostProcessingStarted += (s, msg) =>
Console.WriteLine($"Post-processing-start: {msg}")
ytdlp.PostProcessingCompleted += (s, msg) =>
Console.WriteLine($"Post-processing-complete: {msg}");
ytdlp.ErrorMessage += (s, err) => Console.WriteLine($"Error: {err}");
ytdlp.OutputMessage += (s, msg) => Console.WriteLine(msg);
ytdlp.CommandCompleted += (s, e) =>
Console.WriteLine($"Command finished: {e.Command}");
Fetch Metadata
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
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
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);
Get Subtitles
var ytdlp = new Ytdlp("tools\\yt-dlp.exe");
var subtitles = await ytdlp.GetSubtitlesAsync("https://www.youtube.com/watch?v=abc123");
foreach (var sub in subtitles)
{
Console.WriteLine($"Language: {sub.Language}, Format: {sub.Format}, Url: {sub.Url}");
}
Get Adobe Pass MSO List
var msoList = await ytdlp.GetAdobePassListAsync();
Batch Downloads
var urls = new[] { "https://youtu.be/vid1", "https://youtu.be/vid2" };
var tasks = urls.Select(async url =>
{
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" };
var ytdlp = new Ytdlp("tools\\yt-dlp.exe")
.WithFormat("best")
.WithOutputFolder("./batch");
await ytdlp.DownloadBatchAsync(urls, maxConcurrency: 3);
π‘ Events
| Event | Description |
|---|---|
ProgressDownload |
Download progress |
ProgressMessage |
Informational messages |
DownloadCompleted |
File finished |
PostProcessingStarted |
Postβprocessing start |
PostProcessingCompleted |
Postβprocessing finished |
OutputMessage |
Raw output line |
ErrorMessage |
Error message |
CommandCompleted |
Process finished |
π Methods
VersionAsync()UpdateAsync(UpdateChannel channel, string specificVersion)GetExtractorsAsync()GetAdobePassListAsync()GetSubtitlesAsync(string url)GetMetadataAsync(string url)GetMetadataRawAsync(string url)GetDeepMetadataAsync(string url)GetDeepMetadataRawAsync(string url)GetFormatsAsync(string url)GetMetadataLiteAsync(string url)GetMetadataLiteAsync(string url, IEnumerable<string> fields)GetBestAudioFormatIdAsync(string url)GetBestVideoFormatIdAsync(string url, int maxHeight)ExecuteAsync(string url)ExecuteBatchAsync(IEnumerable<string> urls, int maxConcurrency)
Fluent Methods
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).WithVideoPassword(string password).WithAdobePassAuthentication(string mso, string username, string password)
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 ...
π Upgrade Guide (v3 β v4)
v4 introduces a new immutable fluent API.
Old mutable commands were removed.
β Old API (v3)
await using var ytdlp = new Ytdlp()
.WithFormat("best")
.WithOutputFolder("./downloads");
await ytdlp.DownloadAsync(url);
β New API (v4)
var ytdlp = new Ytdlp();
await ytdlp
.SetFormat("best")
.SetOutputFolder("./downloads")
.ExecuteAsync(url);
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.ProgressDownload += ...
No disposal required
Ytdlp holds no unmanaged resources and does not implement IDisposable or IAsyncDisposable.
var ytdlp = new Ytdlp();
β Notes
- All commands now start with
WithXxx(). - Immutable: no shared state; safe for parallel usage.
- No need to dispose intermediate instances.
- 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 | |
|---|---|---|---|
| 4.0.0 | 118 | 6/13/2026 | |
| 4.0.0-preview2 | 87 | 6/10/2026 | |
| 4.0.0-preview1 | 90 | 6/8/2026 | |
| 3.3.0 | 129 | 5/31/2026 | |
| 3.2.1 | 132 | 5/27/2026 | |
| 3.2.0 | 127 | 5/25/2026 | |
| 3.1.1 | 118 | 5/24/2026 | |
| 3.1.0 | 149 | 5/16/2026 | |
| 3.0.4 | 180 | 5/3/2026 | |
| 3.0.3 | 280 | 4/10/2026 | |
| 3.0.2 | 151 | 4/4/2026 | |
| 3.0.1 | 171 | 4/3/2026 | |
| 3.0.0 | 196 | 3/22/2026 | |
| 2.2.0 | 134 | 3/17/2026 | |
| 2.1.1 | 167 | 3/17/2026 | |
| 2.1.0 | 163 | 3/16/2026 | |
| 2.0.2 | 139 | 3/14/2026 | |
| 2.0.1 | 204 | 2/19/2026 | |
| 2.0.0 | 140 | 2/18/2026 | |
| 2.0.0-preview1 | 134 | 2/15/2026 |
Ytdlp.NET
β¨ Features
- No disposal required, Ytdlp holds no unmanaged resources.
- Added more Fluent methods and Probe methods.
- Enhanced security for authentication methods.
- Implemented file permission for Unix based system.
- Events renamed for better usage.
🛠 Notes
- Companion packages recommended: ManuHub.Ytdlp, ManuHub.FFmpeg, ManuHub.FFprobe, ManuHub.Deno.
- All examples and documentation updated.
- This release greatly improves reliability, cancellation, and maintainability.
See the repository for the full documentation and migration guide.