**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.
✨ This library is used in [**YoutubeDownloader**](https://github.com/Tyrrrz/YoutubeDownloader) -- a desktop application for downloading YouTube videos.
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(...)`:
```csharp
// ...
// Get the actual stream
var stream = await youtube.Videos.Streams.GetAsync(streamInfo);
> ⚠ 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](https://nuget.org/packages/YoutubeExplode.Converter).
> ⚠ This package also relies on [FFmpeg](https://ffmpeg.org) CLI, which can be downloaded [here](https://ffbinaries.com/downloads).
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:
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(...)`:
```csharp
using YoutubeExplode;
using YoutubeExplode.Converter;
var youtube = new YoutubeClient();
await youtube.Videos.DownloadAsync("https://youtube.com/watch?v=u_yIGGhubZs", "video.mp4", o => o
You can get metadata associated with a YouTube playlist by calling `Playlists.GetAsync(...)` method:
```csharp
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(...)`:
```csharp
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:
```csharp
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:
```csharp
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:
```csharp
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(...)`:
```csharp
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(...)`:
```csharp
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:
```csharp
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(...)`:
```csharp
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(...)`:
```csharp
using YoutubeExplode;
var youtube = new YoutubeClient();
// Each batch corresponds to one request
await foreach (var batch in youtube.Search.GetResultBatchesAsync("blender tutorials"))
The "Explode" in **YoutubeExplode** comes from the name of a PHP function that splits up strings, [`explode()`](https://www.php.net/manual/en/function.explode.php). 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.