YoutubeExplode 6.0.8

There is a newer version of this package available.
See the version list below for details.
dotnet add package YoutubeExplode --version 6.0.8                
NuGet\Install-Package YoutubeExplode -Version 6.0.8                
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="YoutubeExplode" Version="6.0.8" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add YoutubeExplode --version 6.0.8                
#r "nuget: YoutubeExplode, 6.0.8"                
#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.
// Install YoutubeExplode as a Cake Addin
#addin nuget:?package=YoutubeExplode&version=6.0.8

// Install YoutubeExplode as a Cake Tool
#tool nuget:?package=YoutubeExplode&version=6.0.8                

YoutubeExplode

Build Coverage Version Downloads Discord Donate

⚠️ Project status: maintenance mode. What does it mean?

YoutubeExplode is a library that provides an interface to query metadata of YouTube videos, playlists and channels, as well as to resolve and download video streams and closed caption tracks. Behind a layer of abstraction, the library parses raw page content and uses reverse-engineered requests to retrieve information. As it doesn't use the official API, there's also no need for an API key and there are no usage quotas.

✨ This library is used in YoutubeDownloader -- a desktop application for downloading YouTube videos.

💬 If you want to chat, join my Discord server.

Download

  • 📦 NuGet: dotnet add package YoutubeExplode (main package)
  • 📦 NuGet: dotnet add package YoutubeExplode.Converter (FFmpeg integration)

Screenshots

demo

Usage

YoutubeExplode exposes its functionality through a single entry point -- the YoutubeClient class. Create an instance of this class and use the provided operations on Videos, Playlists, Channels, and Search properties to send requests.

Videos

Retrieving video metadata

To retrieve metadata associated with a YouTube video, call Videos.GetAsync(...):

using YoutubeExplode;

var youtube = new YoutubeClient();

// You can specify both video ID or URL
var video = await youtube.Videos.GetAsync("https://youtube.com/watch?v=u_yIGGhubZs");

var title = video.Title; // "Collections - Blender 2.80 Fundamentals"
var author = video.Author.Title; // "Blender"
var duration = video.Duration; // 00:07:20
Downloading video streams

Every YouTube video has a number of streams available, differing in containers, video quality, bitrate, framerate, and other properties. Additionally, depending on the content of the stream, the streams are further divided into 3 categories:

  • Muxed streams -- contain both video and audio
  • Audio-only streams -- contain only audio
  • Video-only streams -- contain only video

You can request the manifest that lists all available streams for a particular video by calling Videos.Streams.GetManifestAsync(...):

using YoutubeExplode;

var youtube = new YoutubeClient();

var streamManifest = await youtube.Videos.Streams.GetManifestAsync("u_yIGGhubZs");

Once you get the manifest, you can filter through the streams and select the ones you're interested in:

using YoutubeExplode;
using YoutubeExplode.Videos.Streams;

// ...

// Get highest quality muxed stream
var streamInfo = streamManifest.GetMuxedStreams().GetWithHighestVideoQuality();

// ...or highest bitrate audio-only stream
var streamInfo = streamManifest.GetAudioOnlyStreams().GetWithHighestBitrate();

// ...or highest quality MP4 video-only stream
var streamInfo = streamManifest
    .GetVideoOnlyStreams()
    .Where(s => s.Container == Container.Mp4)
    .GetWithHighestVideoQuality()

Finally, you can resolve the actual stream represented by the specified metadata using Videos.Streams.GetAsync(...) or download it directly to a file with Videos.Streams.DownloadAsync(...):

// ...

// Get the actual stream
var stream = await youtube.Videos.Streams.GetAsync(streamInfo);

// Download the stream to a file
await youtube.Videos.Streams.DownloadAsync(streamInfo, $"video.{streamInfo.Container}");

⚠ While it may be tempting to always rely on muxed streams, given that they contain both audio and video, it's important to note that they are very limited in quality (up to 720p30). If you want to download a video in highest available quality, you need to resolve the best audio-only and video-only streams separately and then mux them together, which can be accomplished by using the YoutubeExplode.Converter package (see below).

Downloading video with muxing or conversion

⚠ Downloading with muxing or conversion requires YoutubeExplode.Converter.

⚠ This package also relies on FFmpeg CLI, which can be downloaded here. Ensure that the FFmpeg binary is located in your application's probe directory or on the system's PATH, or use one of the overloads to provide a custom location directly.

You can download a video with muxing or conversion through one of the extension methods provided on VideoClient. For example, to download a video in the specified format using highest quality streams, simply call DownloadAsync(...) with the video ID and the destination file path:

using YoutubeExplode;
using YoutubeExplode.Converter;

var youtube = new YoutubeClient();
await youtube.Videos.DownloadAsync("https://youtube.com/watch?v=u_yIGGhubZs", "video.mp4");

Under the hood, this resolves the video's media streams and selects the best candidates based on format, bitrate, quality, and framerate. If the specified output format is a known audio-only container (e.g. mp3 or ogg) then only the audio stream is downloaded.

⚠ Stream muxing is a CPU-heavy process. You can reduce resource usage and execution time by using streams that don't require transcoding to the output format (e.g. mp4 audio/video streams for mp4 output format). Currently, YouTube only provides adaptive streams in mp4 or webm containers, with highest quality video streams (e.g. 4K) only available in webm.

To configure various aspects related to the conversion process, use one of the overloads of DownloadAsync(...):

using YoutubeExplode;
using YoutubeExplode.Converter;

var youtube = new YoutubeClient();

await youtube.Videos.DownloadAsync("https://youtube.com/watch?v=u_yIGGhubZs", "video.mp4", o => o
    .SetFormat("webm") // override format
    .SetPreset(ConversionPreset.UltraFast) // change preset
    .SetFFmpegPath("path/to/ffmpeg") // custom FFmpeg location
);

If you need precise control over which streams are used for muxing, you can also provide them yourself:

using YoutubeExplode;
using YoutubeExplode.Videos.Streams;
using YoutubeExplode.Converter;

var youtube = new YoutubeClient();

// Get stream manifest
var streamManifest = await youtube.Videos.Streams.GetManifestAsync("u_yIGGhubZs");

// Select streams (1080p60 / highest bitrate audio)
var audioStreamInfo = streamManifest.GetAudioStreams().GetWithHighestBitrate();
var videoStreamInfo = streamManifest.GetVideoStreams().First(s => s.VideoQuality.Label == "1080p60");
var streamInfos = new IStreamInfo[] { audioStreamInfo, videoStreamInfo };

// Download and process them into one file
await youtube.Videos.DownloadAsync(streamInfos, new ConversionRequestBuilder("video.mp4").Build());
Downloading closed captions

Closed captions can be downloaded in a similar way to media streams. To get the list of available closed caption tracks, call Videos.ClosedCaptions.GetManifestAsync(...):

using YoutubeExplode;

var youtube = new YoutubeClient();

var trackManifest = await youtube.Videos.ClosedCaptions.GetManifestAsync("u_yIGGhubZs");

Then retrieve metadata for a particular track:

// ...

// Find closed caption track in English
var trackInfo = trackManifest.GetByLanguage("en");

Finally, use Videos.ClosedCaptions.GetAsync(...) to get the actual content of the track:

// ...

var track = await youtube.Videos.ClosedCaptions.GetAsync(trackInfo);

// Get the caption displayed at 0:35
var caption = track.GetByTime(TimeSpan.FromSeconds(35));
var text = caption.Text; // "collection acts as the parent collection"

You can also download the closed caption track in SRT file format with Videos.ClosedCaptions.DownloadAsync(...):

// ...

await youtube.Videos.ClosedCaptions.DownloadAsync(trackInfo, "cc_track.srt");

Playlists

Retrieving playlist metadata

You can get metadata associated with a YouTube playlist by calling Playlists.GetAsync(...) method:

using YoutubeExplode;

var youtube = new YoutubeClient();

var playlist = await youtube.Playlists.GetAsync("PLa1F2ddGya_-UvuAqHAksYnB0qL9yWDO6");

var title = playlist.Title; // "First Steps - Blender 2.80 Fundamentals"
var author = playlist.Author.Title; // "Blender"
Getting videos included in a playlist

To get the videos included in a playlist, call Playlists.GetVideosAsync(...):

using YoutubeExplode;
using YoutubeExplode.Common;

var youtube = new YoutubeClient();

// Get all playlist videos
var videos = await youtube.Playlists.GetVideosAsync("PLa1F2ddGya_-UvuAqHAksYnB0qL9yWDO6");

// Get the first 20 playlist videos
var videosSubset = await youtube.Playlists
    .GetVideosAsync(playlist.Id)
    .CollectAsync(20);

You can also enumerate videos lazily without waiting for the whole list to load:

using YoutubeExplode;

var youtube = new YoutubeClient();

await foreach (var video in youtube.Playlists.GetVideosAsync("PLa1F2ddGya_-UvuAqHAksYnB0qL9yWDO6"))
{
    var title = video.Title;
    var author = video.Author;
}

If you need precise control over how many requests you send to YouTube, use Playlists.GetVideoBatchesAsync(...) which returns videos wrapped in batches:

using YoutubeExplode;

var youtube = new YoutubeClient();

// Each batch corresponds to one request
await foreach (var batch in youtube.Playlists.GetVideoBatchesAsync("PLa1F2ddGya_-UvuAqHAksYnB0qL9yWDO6"))
{
    foreach (var video in batch.Items)
    {
        var title = video.Title;
        var author = video.Author;
    }
}

Channels

Retrieving channel metadata

You can get metadata associated with a YouTube channel by calling Channels.GetAsync(...) method:

using YoutubeExplode;

var youtube = new YoutubeClient();

var channel = await youtube.Channels.GetAsync("UCSMOQeBJ2RAnuFungnQOxLg");

var title = channel.Title; // "Blender"

You can also get channel metadata by username with Channels.GetByUserAsync(...):

using YoutubeExplode;

var youtube = new YoutubeClient();

var channel = await youtube.Channels.GetByUserAsync("Blender");

var id = channel.Id; // "UCSMOQeBJ2RAnuFungnQOxLg"
Getting channel uploads

To get a list of videos uploaded by a channel, call Channels.GetUploadsAsync(...):

using YoutubeExplode;
using YoutubeExplode.Common;

var youtube = new YoutubeClient();

var videos = await youtube.Channels.GetUploadsAsync("UCSMOQeBJ2RAnuFungnQOxLg");

Searching

You can execute a search query and get the results by calling Search.GetResultsAsync(...). Each result may represent either a video, a playlist, or a channel, so you need to use pattern matching to handle corresponding cases:

using YoutubeExplode;

var youtube = new YoutubeClient();

await foreach (var result in youtube.Search.GetResultsAsync("blender tutorials"))
{
    // Use pattern matching to handle different results (videos, playlists, channels)
    switch (result)
    {
        case VideoSearchResult videoResult:
        {
            var id = videoResult.Id;
            var title = videoResult.Title;
            var duration = videoResult.Duration;
            break;
        }
        case PlaylistSearchResult playlistResult:
        {
            var id = playlistResult.Id;
            var title = playlistResult.Title;
            break;
        }
        case ChannelSearchResult channelResult:
        {
            var id = channelResult.Id;
            var title = channelResult.Title;
            break;
        }
    }
}

To limit results to a specific type, use Search.GetVideosAsync(...), Search.GetPlaylistsAsync(...), or Search.GetChannelsAsync(...):

using YoutubeExplode;
using YoutubeExplode.Common;

var youtube = new YoutubeClient();

var videos = await youtube.Search.GetVideosAsync("blender tutorials");
var playlists = await youtube.Search.GetPlaylistsAsync("blender tutorials");
var channels = await youtube.Search.GetChannelsAsync("blender tutorials");

Similarly to playlists, you can also enumerate results in batches by calling Search.GetResultBatchesAsync(...):

using YoutubeExplode;

var youtube = new YoutubeClient();

// Each batch corresponds to one request
await foreach (var batch in youtube.Search.GetResultBatchesAsync("blender tutorials"))
{
    foreach (var result in batch.Items)
    {
        switch (result)
        {
            case VideoSearchResult videoResult:
            {
                // ...
            }
            case PlaylistSearchResult playlistResult:
            {
                // ...
            }
            case ChannelSearchResult channelResult:
            {
                // ...
            }
        }
    }
}

Etymology

The "Explode" in YoutubeExplode comes from the name of a PHP function that splits up strings, explode(). When I was just starting development on this library, most of the reference source code I read was written in PHP, hence the inspiration for the name.

Product Compatible and additional computed target framework versions.
.NET net5.0 is compatible.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  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. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 is compatible.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 is compatible. 
.NET Framework net461 is compatible.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (13)

Showing the top 5 NuGet packages that depend on YoutubeExplode:

Package Downloads
YoutubeExplode.Converter

Extension for YoutubeExplode that provides an interface to download and convert videos using FFmpeg

Soenneker.YouTube.Client

An async thread-safe singleton for the YouTube client YouTubeExplode

N3O.Umbraco.Video.YouTube

TODO

SpiderSharp

Web Crawling and Scraping Framework

StaticSharp.Core

Package Description

GitHub repositories (16)

Showing the top 5 popular GitHub repositories that depend on YoutubeExplode:

Repository Stars
Tyrrrz/YoutubeDownloader
Downloads videos and playlists from YouTube
Tyrrrz/DiscordChatExporter
Exports Discord chat logs to a file
shaked6540/YoutubePlaylistDownloader
A tool to download whole playlists, channels or single videos from youtube and also optionally convert them to almost any format you would like
Rise-Software/Rise-Media-Player
One media player for everything you own or stream; whether it's music or videos, online or offline Rise Media Player does it all. And it's beautiful and native with the latest version of WinUI.
MediaPortal/MediaPortal-2
Development of MediaPortal 2
Version Downloads Last updated
6.4.4 1,705 11/13/2024
6.4.3 10,991 10/3/2024
6.4.2 4,846 9/27/2024
6.4.1 3,080 9/18/2024
6.4.0 17,552 7/25/2024
6.3.16 20,662 5/21/2024
6.3.15 809 5/18/2024
6.3.14 9,164 4/27/2024
6.3.13 19,395 2/22/2024
6.3.12 16,399 1/18/2024
6.3.11 4,516 1/4/2024
6.3.10 3,766 12/27/2023
6.3.9 5,570 11/29/2023
6.3.8 3,903 11/23/2023
6.3.7 4,499 11/9/2023
6.3.6 6,127 10/17/2023
6.3.5 4,599 9/28/2023
6.3.4 8,220 9/6/2023
6.3.3 3,872 8/31/2023
6.3.2 7,445 8/18/2023
6.3.2-alpha1 1,474 7/30/2023
6.3.1 12,481 7/23/2023
6.3.0 1,902 7/20/2023
6.3.0-alpha1 968 7/15/2023
6.2.17 3,765 7/12/2023
6.2.16 4,556 6/28/2023
6.2.15 10,072 5/25/2023
6.2.14 19,592 5/2/2023
6.2.13 22,805 4/27/2023
6.1.0 117,016 2/19/2022
6.0.8 16,162 2/10/2022
6.0.7 129,545 12/10/2021
6.0.6 5,512 12/9/2021
6.0.5 21,514 7/28/2021
6.0.4 2,873 7/2/2021
6.0.3 2,460 6/21/2021
6.0.2 7,965 5/28/2021
6.0.1 2,946 5/21/2021
6.0.0 347,821 4/17/2021
6.0.0-alpha2 292,570 4/1/2021
6.0.0-alpha 1,698 2/25/2021
5.1.9 31,337 11/28/2020
5.1.8 13,154 10/25/2020
5.1.7 2,952 10/12/2020
5.1.6 2,880 9/29/2020
5.1.5 3,079 9/12/2020
5.1.4 3,938 8/14/2020
5.1.3 3,157 7/29/2020
5.1.2 2,212 7/21/2020
5.1.1 6,082 6/21/2020
5.1.0 2,408 6/14/2020
5.0.5 2,720 5/23/2020
5.0.4 2,392 5/10/2020
5.0.3 2,043 5/1/2020
5.0.2 1,710 4/24/2020
5.0.1 3,299 4/13/2020
5.0.0 2,256 4/12/2020
4.7.16 8,082 3/16/2020
4.7.15 2,598 3/11/2020
4.7.14 1,479 3/10/2020
4.7.13 3,603 2/10/2020
4.7.12 7,929 12/29/2019
4.7.11 2,517 12/15/2019
4.7.10 7,813 9/24/2019
4.7.9 13,284 8/15/2019
4.7.8 2,131 8/8/2019
4.7.7 2,113 7/30/2019
4.7.6 3,423 7/10/2019
4.7.5 1,646 7/4/2019
4.7.4 1,713 6/24/2019
4.7.3 1,602 6/21/2019
4.7.2 1,774 6/13/2019
4.7.1 2,498 5/16/2019
4.7.0 2,552 5/12/2019
4.7.0-beta2 1,271 5/6/2019
4.7.0-beta 1,369 4/25/2019
4.7.0-alpha 1,348 4/21/2019
4.6.8 2,748 3/30/2019
4.6.7 1,886 3/16/2019
4.6.6 2,987 2/24/2019
4.6.5 1,767 2/16/2019
4.6.4 3,734 1/16/2019
4.6.3 1,700 1/13/2019
4.6.2 3,320 1/4/2019
4.6.1 3,417 12/3/2018
4.6.0 1,937 11/22/2018
4.5.3 18,739 11/7/2018
4.5.2 1,831 11/2/2018
4.5.1 3,183 10/24/2018
4.5.0 1,762 10/20/2018
4.4.0 1,511 10/20/2018
4.3.4 1,769 10/16/2018
4.3.3 2,190 9/26/2018
4.3.2 2,145 9/10/2018
4.3.1 1,921 8/28/2018
4.3.0 16,309 7/25/2018
4.2.8 6,151 6/14/2018
4.2.7 1,960 6/9/2018
4.2.6 1,835 6/9/2018
4.2.5 2,209 5/20/2018
4.2.4 2,115 5/2/2018
4.2.3 1,966 4/22/2018
4.2.2 2,239 3/31/2018
4.2.1 1,799 3/28/2018
4.2.0 2,066 3/24/2018
4.1.1 2,860 2/20/2018
4.1.0 6,703 2/2/2018
4.1.0-alpha4 1,731 1/29/2018
4.1.0-alpha3 1,618 1/28/2018
4.1.0-alpha2 1,936 12/24/2017
4.1.0-alpha 1,818 12/16/2017
4.0.0 3,344 12/15/2017
4.0.0-alpha 1,923 12/10/2017
3.4.0-workaround404 1,591 11/28/2017
3.3.0 3,660 10/19/2017
3.2.5 2,275 8/29/2017
3.2.4 1,894 8/28/2017
3.2.3 2,204 8/11/2017
3.2.2 1,871 8/8/2017
3.2.1 1,870 8/5/2017
3.2.0 2,319 7/4/2017
3.1.1 2,234 6/8/2017
3.1.0 2,039 6/1/2017
3.0.2 1,933 5/12/2017
3.0.1 1,813 5/8/2017
3.0.0 1,830 4/24/2017
2.5.0 1,866 3/26/2017
2.4.0 1,702 3/24/2017
2.3.0 1,790 3/10/2017
2.2.2 1,687 3/8/2017
2.2.1 1,691 3/7/2017
2.2.0 1,691 3/6/2017
2.1.3 1,776 3/5/2017
2.1.2 1,695 3/3/2017
2.1.1 1,647 3/3/2017
2.1.0 1,741 3/2/2017
2.0.1 1,707 3/2/2017
2.0.0 1,680 3/2/2017
1.1.0 1,853 2/24/2017
1.0.4 1,731 2/19/2017
1.0.3 1,698 2/2/2017
1.0.2 1,752 1/28/2017
1.0.1 1,726 1/26/2017
1.0.0 2,034 1/25/2017