Ytdlp.NET 4.0.0-preview1

Prefix Reserved
This is a prerelease version of Ytdlp.NET.
There is a newer version of this package available.
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
                    
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="4.0.0-preview1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ytdlp.NET" Version="4.0.0-preview1" />
                    
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 4.0.0-preview1
                    
#r "nuget: Ytdlp.NET, 4.0.0-preview1"
                    
#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@4.0.0-preview1
                    
#: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=4.0.0-preview1&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Ytdlp.NET&version=4.0.0-preview1&prerelease
                    
Install as a Cake Tool

Static Badge NuGet Version NuGet Downloads

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 your using directives.
  • 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:

  1. Always create a new instance per download for parallel operations.
  2. No shared state between instances, so no need to worry about thread safety.
  3. 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 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.

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.