Ytdlp.NET 2.0.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package Ytdlp.NET --version 2.0.0
                    
NuGet\Install-Package Ytdlp.NET -Version 2.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Ytdlp.NET" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ytdlp.NET" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Ytdlp.NET" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Ytdlp.NET --version 2.0.0
                    
#r "nuget: Ytdlp.NET, 2.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Ytdlp.NET@2.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Ytdlp.NET&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Ytdlp.NET&version=2.0.0
                    
Install as a Cake Tool

Static Badge NuGet Version NuGet Downloads .NET

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-dlp commands 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 AddCustomCommand to 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-dlp is supported).
  • Output Templates: Customize naming patterns with standard yt-dlp placeholders.
  • 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:

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

  • IDisposable with process cleanup
  • YtdlpBuilder for 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • 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
2.0.1 113 2/19/2026
2.0.0 90 2/18/2026
2.0.0-preview1 89 2/15/2026
1.4.0 433 11/24/2025
1.3.0 234 11/15/2025
1.2.3 237 10/19/2025
1.2.2 306 8/8/2025
1.2.1 289 8/5/2025
1.2.0 280 8/5/2025
1.1.0 223 7/13/2025
1.0.0 148 7/5/2025

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)