Ytdlp.NET
2.0.1
dotnet add package Ytdlp.NET --version 2.0.1
NuGet\Install-Package Ytdlp.NET -Version 2.0.1
<PackageReference Include="Ytdlp.NET" Version="2.0.1" />
<PackageVersion Include="Ytdlp.NET" Version="2.0.1" />
<PackageReference Include="Ytdlp.NET" />
paket add Ytdlp.NET --version 2.0.1
#r "nuget: Ytdlp.NET, 2.0.1"
#:package Ytdlp.NET@2.0.1
#addin nuget:?package=Ytdlp.NET&version=2.0.1
#tool nuget:?package=Ytdlp.NET&version=2.0.1
Ytdlp.NET
Ytdlp.NET is a fluent, strongly-typed .NET wrapper around the powerful yt-dlp command-line tool. It provides an intuitive and customizable interface to download videos, extract audio, retrieve metadata, and process media from YouTube and hundreds of other supported platforms.
Importanant Note
External JS Scripts Setup Guide
- To download from YouTube, yt-dlp needs to solve JavaScript challenges presented by YouTube using an external JavaScript runtime.
- Supports downloading EJS script dependencies from npm (--remote-components ejs:npm)
To use this:
await ytdlp
.SetOutputFolder("c:\video")
.SetFormat("b")
.AddCustomCommand("--restrict-filenames")
.AddCustomCommand("--remote-components ejs:npm")
.ExecuteAsync(YoutubeUrl, cancellationToken);
π Features
- Fluent API: Easily construct
yt-dlpcommands with chainable methods. - Progress & Events: Real-time progress tracking, completion, and error callbacks.
- Format Listing: Retrieve and parse all available formats for any video.
- Batch Downloads: Download multiple videos with sequential or parallel execution.
- Custom Command Injection: Use
AddCustomCommandto include advanced or new options. - Validated Options: Rejects invalid yt-dlp commands with a built-in option whitelist.
- Cross-Platform: Works on Windows, macOS, and Linux (where
yt-dlpis supported). - Output Templates: Customize naming patterns with standard
yt-dlpplaceholders. - Update: Implements update method to update latest yt-dlp version.
New in v2.0
- Rich JSON metadata parsing via
GetVideoMetadataJsonAsync - Detailed format selection with
GetFormatsDetailedAsync - Convenience methods for best format auto-selection
- Improved cancellation handling
- Better progress parsing and event system
Thread Safety & Disposal
Ytdlp is not thread-safe
Do not use the same instance from multiple threads or concurrent tasks.
Always create a fresh instance per download operation when running in parallel.Safe example (concurrent batch):
var tasks = urls.Select(async url => { var y = new Ytdlp(); // new instance per task await y.SetFormat("best").ExecuteAsync(url); }); await Task.WhenAll(tasks);Unsafe (will cause race conditions):
var y = new Ytdlp(); // shared instance var tasks = urls.Select(u => y.SetFormat("best").ExecuteAsync(u)); await Task.WhenAll(tasks);Ytdlp is not thread-safe
In v2.0 the class does not implement IDisposable. Internal resources (e.g. child processes) are cleaned up automatically when the instance is garbage-collected. Proper Dispose support and an immutable builder pattern (for safe reuse) are planned for later.
Fetching Video Metadata
var ytdlp = new Ytdlp();
string url = "https://www.youtube.com/watch?v=Xt50Sodg7sA";
var metadata = await ytdlp.GetVideoMetadataJsonAsync(url);
if (metadata != null)
{
Console.WriteLine($"Title: {metadata.Title}");
Console.WriteLine($"Duration: {metadata.Duration} seconds");
Console.WriteLine($"Views: {metadata.ViewCount:N0}");
Console.WriteLine($"Thumbnail: {metadata.Thumbnail}");
}
Auto-Selecting Best Formats
// Get best audio-only format ID
string bestAudio = await ytdlp.GetBestAudioFormatIdAsync(url);
// β e.g. "251" (highest bitrate opus/webm)
// Get best video β€ 720p
string bestVideo = await ytdlp.GetBestVideoFormatIdAsync(url, maxHeight: 720);
// β e.g. "136" (720p mp4/avc1)
// Download best combination
await ytdlp
.SetFormat($"{bestVideo}+{bestAudio}/best")
.SetOutputFolder("./downloads")
.ExecuteAsync(url);
Full Metadata + Format Selection Example
var metadata = await ytdlp.GetVideoMetadataJsonAsync(url);
var best1080p = metadata.Formats?
.Where(f => f.Height == 1080 && f.Vcodec != "none")
.OrderByDescending(f => f.Fps ?? 0)
.FirstOrDefault();
if (best1080p != null)
{
Console.WriteLine($"Best 1080p format: {best1080p.FormatId} β {best1080p.Resolution} @ {best1080p.Fps} fps");
}
π¦ Prerequisites
Ytdlp.NET is a lightweight wrapper around yt-dlp β it does not include yt-dlp, FFmpeg, FFprobe or Deno itself.
You have two main ways to set up the required dependencies:
- .NET: .NET 8.0 or higher
- yt-dlp:
Recommended: Use companion NuGet packages (easiest & portable)
We provide official build packages that automatically download and manage the latest stable binaries:
<ItemGroup>
<PackageReference Include="Ytdlp.Stable.Build" Version="*" />
<PackageReference Include="Ytdlp.FFmpeg.Build" Version="*" />
<PackageReference Include="Ytdlp.FFprobe.Build" Version="*" />
</ItemGroup>
var ytdlp = new Ytdlp(ytDlpPath: @"\Tools\yt-dlp.exe");
β¨ Basic Usage
π½ Download a Single Video
Download a video with the best quality to a specified folder:
var ytdlp = new Ytdlp("yt-dlp", new ConsoleLogger());
await ytdlp
.SetFormat("best")
.SetOutputFolder("downloads")
.DownloadThumbnails()
.ExecuteAsync("https://www.youtube.com/watch?v=RGg-Qx1rL9U");
π΅ Extract Audio + Embed Metadata
await ytdlp
.ExtractAudio("mp3")
.EmbedMetadata()
.SetOutputFolder("audio")
.ExecuteAsync("https://www.youtube.com/watch?v=RGg-Qx1rL9U");
π§Ύ List Available Formats
var formats = await ytdlp.GetAvailableFormatsAsync("https://youtube.com/watch?v=abc123");
foreach (var f in formats)
{
Console.WriteLine($"ID: {f.ID}, Resolution: {f.Resolution}, VCodec: {f.VCodec}");
}
π§ͺ Get Video Metadata Only
var metadata = await ytdlp.GetVideoMetadataJsonAsync("https://youtube.com/watch?v=abc123");
Console.WriteLine($"Title: {metadata?.Title}, Duration: {metadata?.Duration}");
π¦ Batch Download
Sequential (one after another)
await ytdlp
.SetFormat("best")
.SetOutputFolder("batch")
.ExecuteBatchAsync(new[] {
"https://youtu.be/vid1", "https://youtu.be/vid2"
});
Parallel (max 3 at a time)
await ytdlp
.SetFormat("best")
.SetOutputFolder("batch")
.ExecuteBatchAsync(new[] {
"https://youtu.be/vid1", "https://youtu.be/vid2"
}, maxConcurrency: 3);
βοΈ Configuration & Options
β Common Fluent Methods
- .SetFormat(string format)
- .SetOutputFolder(string path)
- .ExtractAudio(string format)
- .EmbedMetadata()
- .DownloadThumbnails()
- .DownloadSubtitles("en")
- .UseCookies("cookies.txt")
- .SetUserAgent("MyApp/1.0")
- .Simulate()
- .DisableAds()
- .SetDownloadTimeout("30")
- .SetAuthentication(username, password)
- .PostProcessFiles("--audio-quality 0")
- .AddCustomCommand(string command)
π§© Add Custom yt-dlp Option
ytdlp.AddCustomCommand("--sponsorblock-mark all");
Will be validated against internal whitelist. Invalid commands will trigger error logging via ILogger.
π‘ Events
ytdlp.OnProgressMessage += (s, msg) => Console.WriteLine($"Progress: {msg}");
ytdlp.OnErrorMessage += (s, err) => Console.WriteLine($"Error: {err}");
ytdlp.OnCommandCompleted += (success, message) => Console.WriteLine($"Finished: {message}");
ytdlp.OnOutputMessage += (s, msg) => Console.WriteLine(msg);
ytdlp.OnPostProcessingComplete += (s, msg) => Console.WriteLine($"Postprocessing: {msg}");
π Output Template
You can customize file naming using yt-dlp placeholders:
ytdlp.SetOutputTemplate("%(title)s-%(id)s.%(ext)s");
π§ͺ Validation & Safety
All AddCustomCommand(...) calls are validated against a known safe set of yt-dlp options, minimizing the risk of malformed or unsupported commands.
To preview what command will run:
string preview = ytdlp.PreviewCommand();
Console.WriteLine(preview);
β Error Handling
All exceptions are wrapped in YtdlpException:
try
{
await ytdlp.ExecuteAsync("https://invalid-url");
}
catch (YtdlpException ex)
{
Console.WriteLine($"Error: {ex.Message}");
}
π§ͺ Version Check
string version = await ytdlp.GetVersionAsync();
Console.WriteLine($"yt-dlp version: {version}");
π‘ Tips
- For livestreams, use:
.DownloadLivestream(true) - To skip already-downloaded videos:
.SkipDownloaded()
π Custom Logging
Implement your own ILogger:
public class ConsoleLogger : ILogger
{
public void Log(LogType type, string message)
{
Console.WriteLine($"[{type}] {message}");
}
}
Future versions
IDisposablewith process cleanupYtdlpBuilderfor immutable instances- Persistent process pool for speed
- IAsyncDisposable for async cleanup
π€ Contributing
Contributions are welcome! Please submit issues or pull requests to the GitHub repository. Ensure code follows the projectβs style guidelines and includes unit tests.
π License
This project is licensed under the MIT License. See the LICENSE file for details.
| 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.
Upgraded to v2.0 with advanced features and fixes
- SponsorBlock
- Concurrent fragments
- Cancellation
- Rich metadata and format parsing
- Auto best-format helpers
- Improved cancellation and progress
- Many fixes and new features
- Event standardization (Fix)
- Enhanced format model (fix)