Ytdlp.NET
4.0.0-preview2
Prefix Reserved
See the version list below for details.
dotnet add package Ytdlp.NET --version 4.0.0-preview2
NuGet\Install-Package Ytdlp.NET -Version 4.0.0-preview2
<PackageReference Include="Ytdlp.NET" Version="4.0.0-preview2" />
<PackageVersion Include="Ytdlp.NET" Version="4.0.0-preview2" />
<PackageReference Include="Ytdlp.NET" />
paket add Ytdlp.NET --version 4.0.0-preview2
#r "nuget: Ytdlp.NET, 4.0.0-preview2"
#:package Ytdlp.NET@4.0.0-preview2
#addin nuget:?package=Ytdlp.NET&version=4.0.0-preview2&prerelease
#tool nuget:?package=Ytdlp.NET&version=4.0.0-preview2&prerelease
Ytdlp.NET
Ytdlp.NET is a fluent, strongly-typed, and immutable .NET wrapper around
yt-dlp. It provides a fully asynchronous, event-driven interface for downloading, metadata extraction, and media processing 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.
🚀 New in v4.0.0
- Lifecycle Refinement: No disposal required. The library no longer implements
IDisposableorIAsyncDisposable. Instances are plain configuration objects. - Deep Metadata Support: Added
GetDeepMetadataAsync()andGetDeepMetadataRawAsync()for full hierarchical structure (playlists → seasons → episodes). - Traverse Helper: New
Traverse()method for easy iteration over nested playlist entries. - Improved Auth: Enhanced
WithAdobePassAuthentication()andWithAuthentication()handling. - Subtitle Extraction: New
GetSubtitlesAsync()for streamlined subtitle retrieval. - MSO Listing: New
GetAdobePassListAsync()for Adobe Pass mso listing. - Robust Core: Modernized
ProcessRunnerandProcessFactoryfor efficient, isolated execution
🔧 Required Tools
- Namespace:
ManuHub.Ytdlp.NET - External JS runtime: yt-dlp requires an external JS runtime like deno.exe (from denoland/deno) for YouTube downloads with JS challenges.
- Recommended: Use companion NuGet packages:
| Package | Description |
|---|---|
| ManuHub.Ytdlp | Core download engine |
| ManuHub.Deno | JavaScript challenge resolution |
| ManuHub.FFmpeg | Post-processing, merging, and conversion |
| ManuHub.FFprobe | Format probing and metadata extraction |
Example path resolution in .NET:
var ytdlpPath = Path.Combine(AppContext.BaseDirectory, "tools", "yt-dlp.exe");
var ffmpegPath = Path.Combine(AppContext.BaseDirectory, "tools");
🧬 Core Concepts
No Disposal Required
Ytdlp holds no unmanaged resources. Create instances, share them, and let the GC collect them. All internal runners are created per-call.
Immutable Fluent API
Every configuration method (e.g., WithOutputFolder, WithFormat) returns a new instance, ensuring the original is never modified. This makes branching configurations safe and clean.
Thread Safety
A single Ytdlp instance can be shared across threads. Each execution creates isolated internal runners, allowing concurrent downloads without synchronization.
Secure Authentication
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.
🚀 Quick Start
1. Basic Download
var ytdlp = new Ytdlp("yt-dlp.exe")
.WithOutputFolder("./downloads")
.WithBestVideoPlusBestAudio()
.WithEmbedMetadata();
// Subscribe to events
ytdlp.ProgressDownload += (s, e) => Console.WriteLine($"Progress: {e.Percent:F2}%");
ytdlp.DownloadCompleted += (s, msg) => Console.WriteLine($"Finished: {msg}");
// Execute
await ytdlp.DownloadAsync("https://www.youtube.com/watch?v=XXX");
2. Immutable Configuration Branching
// Define a shared base configuration
var baseConfig = new Ytdlp("yt-dlp.exe").WithOutputFolder("./media");
// Create specialized versions
var audioOnly = baseConfig.WithBestAudioOnly();
var highRes = baseConfig.WithMaxHeightOrBest(1080);
// baseConfig, audioOnly, and highRes are independent, thread-safe instances
await Task.WhenAll(
audioOnly.DownloadAsync(url1),
highRes.DownloadAsync(url2)
);
📦 Usage Examples
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}");
Deep Metadata Extraction
var metadata = await ytdlp.GetDeepMetadataAsync(url);
foreach (var root in metadata.Entries ?? [])
{
foreach (var item in root.Traverse())
{
Console.WriteLine(item.Title);
}
}
Parallel Execution
var ytdlp = new Ytdlp("tools\\yt-dlp.exe")
.WithFormat("best")
.WithOutputFolder("./batch");
var urls = new[] { "https://youtu.be/vid1", "https://youtu.be/vid2" };
// Safe: Concurrent usage of the same instance
await ytdlp.DownloadBatchAsync(urls, maxConcurrency: 3);
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");
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();
📡 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 |
Example
// Progress events
ytdlp.ProgressDownload += (s, e) => Console.WriteLine($"{e.Percent:F1}% {e.Speed} ETA {e.ETA}");
ytdlp.ProgressMessage += (s, msg) => Console.WriteLine(msg);
// Output events
ytdlp.ErrorMessage += (s, err) => Console.WriteLine($"Error: {err}");
ytdlp.OutputMessage += (s, msg) => Console.WriteLine(msg);
// Lifecycle events
ytdlp.DownloadCompleted += (s, msg) => Console.WriteLine($"Finished: {msg}");
ytdlp.CommandCompleted += (s, e) => Console.WriteLine($"Command finished: {e.Command}");
// Post-Processing events
ytdlp.PostProcessingStarted += (s, msg) => Console.WriteLine($"Post-processing-start: {msg}");
ytdlp.PostProcessingCompleted += (s, msg) => Console.WriteLine($"Post-processing-complete: {msg}");
🛠 Methods
Probe
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)
Download
DownloadAsync(string url)DownloadBatchAsync(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)
⚙️ Customization
If you need specific arguments not covered by the fluent API:
ytdlp.AddFlag("--no-check-certificate")
.AddOption("--external-downloader", "aria2c")
.DownloadAsync(url);
🔄 Migration Guide: Upgrading to v4
Version 4.0.0 is a major release that refines the API for better maintainability and removes the overhead of manual lifecycle management.
Note: The primary breaking change is the removal of
IDisposable/IAsyncDisposable. You no longer need to dispose of yourYtdlpinstances.
1. Key Changes at a Glance
| Feature | v3.x | v4.x |
|---|---|---|
| Lifecycle | Required IAsyncDisposable |
No disposal required |
| Architecture | Immutable Fluent API | Immutable Fluent API (Refactored) |
| Core Process | ProcessFactory |
ProcessFactory (Refactored) |
| Core Runner | ProbeRunner DownloadRunner |
ProcessRunner |
2. Side-by-Side Comparison
❌ Legacy API (v3)
// Previously required disposal
await using var ytdlp = new Ytdlp()
.WithFormat("best")
.WithOutputFolder("./downloads");
await ytdlp.DownloadAsync(url);
✅ New API (v4)
// Cleaner: No disposal required
var ytdlp = new Ytdlp()
.WithFormat("best")
.WithOutputFolder("./downloads");
await ytdlp.DownloadAsync(url);
3. Why the change?
We have streamlined the Ytdlp lifecycle. Because the instance does not hold unmanaged resources that require explicit cleanup, we have removed the IDisposable and IAsyncDisposable interfaces.
- Cleaner Code: Your codebase is now free of
await usingorusingstatements forYtdlpinstances. - Refactored Core: The internal
ProcessFactoryhas been updated and introduceProcessRunnerto handle process execution more efficiently without needing to manage the object lifecycle manually.
4. Migration Checklist
- Remove
await usingorusing: Simply delete the disposal keywords where you instantiateYtdlp. - Verify Events: Ensure event subscriptions are attached to the instance used for the specific execution.
💡 Notes
- Dependencies: Ensure
yt-dlp(and optionallyFFmpeg/FFprobe) are available on your system path or point to their specific locations viaWithFfmpegLocation()(if configured). - Performance:
tuneProcess: true(default) is enabled for download methods to optimize output buffer management.
📜 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 | 51 | 6/13/2026 | |
| 4.0.0-preview2 | 77 | 6/10/2026 | |
| 4.0.0-preview1 | 89 | 6/8/2026 | |
| 3.3.0 | 126 | 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 | 148 | 5/16/2026 | |
| 3.0.4 | 177 | 5/3/2026 | |
| 3.0.3 | 276 | 4/10/2026 | |
| 3.0.2 | 151 | 4/4/2026 | |
| 3.0.1 | 170 | 4/3/2026 | |
| 3.0.0 | 194 | 3/22/2026 | |
| 2.2.0 | 134 | 3/17/2026 | |
| 2.1.1 | 166 | 3/17/2026 | |
| 2.1.0 | 162 | 3/16/2026 | |
| 2.0.2 | 138 | 3/14/2026 | |
| 2.0.1 | 202 | 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.