- Fixed an issue where calling
ClosedCaptionsClient.GetManifestAsync(...)
failed with 404 HTTP error due to recent YouTube changes.
- Fixed an issue where
StreamClient.GetHttpLiveStreamUrlAsync(...)
threw exceptions when called on valid live streams. - Fixed an issue where the version of YoutubeExplode targeting .NET 5 unnecessarily had
System.Text.Json
listed as a dependency.
- Fixed an issue where trying to get stream or closed caption manifest failed on some videos with 404 HTTP error due to recent YouTube changes.
- Fixed an issue where some videos contained incorrect video quality labels.
Known issues: StreamClient.GetHttpLiveStreamUrlAsync(...)
does not work and throws exceptions on every video, including valid livestreams (#566).
- Fixed an issue where trying to get stream manifest of videos with HDR streams failed with exception.
- Fixed an issue where trying to get stream manifest failed on some videos with 404 HTTP error due to recent YouTube changes.
- Fixed an issue where trying to get stream manifest occasionally resulted in a
FormatException
. - Fixed an issue where some required cookies were not passed along with requests, which caused them to fail.
- Fixed an issue where an attempt to get playlist metadata or playlist videos resulted in an exception, due to YouTube's recent changes.
- Fixed an issue where an attempt to get videos returned by a search query resulted in an exception, due to YouTube's recent changes.
- Fixed an issue where an attempt to get video metadata resulted in an exception, due to YouTube's recent changes.
- Fixed an issue where some age-restricted videos were reported as unplayable, due to YouTube's recent changes.
- Fixed an issue where
av01
-encoded video-only streams were occasionally missing from the resolved stream manifest. - Fixed many other issues brought on by recent YouTube changes.
- Changes to videos:
- Changed
Video.Duration
to a nullable property. It may benull
on videos that haven't finished yet (i.e. ongoing livestreams). - Changed
Video.Author
type fromstring
toAuthor
object, which encapsulates both channel ID and channel title. RemovedVideo.ChannelId
. - Changed
Video.Thumbnails
type fromThumbnailSet
toIReadOnlyList<Thumbnail>
. - Removed public constructor from
VideoId
. To create an instance ofVideoId
, useVideoId.Parse(...)
,VideoId.TryParse(...)
, or the implicit conversion fromstring
toVideoId
. - Changes to streams:
- Removed
IStreamInfo.Tag
property. - Reworked
VideoQuality
into a struct (from an enum) which encapsulates video quality label, maximum height, and framerate. RemovedIVideoStreamInfo.VideoQualityLabel
andIVideoStreamInfo.Framerate
in favor of this new consolidated type. - Renamed extension method
WithHighestBitrate(...)
toTryGetWithHighestBitrate(...)
. Also addedGetWithHighestBitrate(...)
which does not returnnull
, but instead throws if the source sequence is empty. - Renamed extension method
WithHighestVideoQuality(...)
toTryGetWithHighestVideoQuality(...)
. Also addedGetWithHighestVideoQuality(...)
which does not returnnull
, but instead throws if the source sequence is empty. - Changed the behavior of
TryGetWithHighestVideoQuality(...)
andGetWithHighestVideoQuality(...)
extension methods so that they now also take into account the framerate of the stream. - Removed
GetAllVideoQualityLabels(...)
extension method.
- Removed
- Changes to closed captions:
- Added
ClosedCaptionManifest.GetByLanguage(...)
. It works likeClosedCaptionManifest.TryGetByLanguage(...)
but throws an exception in case of failure instead of returningnull
. - Added
ClosedCaptionTrack.GetByTime(...)
. It works likeClosedCaptionTrack.TryGetByTime(...)
but throws an exception in case of failure instead of returningnull
. - Added
ClosedCaption.GetPartByTime(...)
. It works likeClosedCaption.TryGetPartByTime(...)
but throws an exception in case of failure instead of returningnull
.
- Added
- Changed
- Changes to playlists:
- Changed
Playlist.Author
type toAuthor
. Note that this property is nullable because auto-generated playlists (mixed, topics, etc.) don't have an author. - Changed
Playlist.Thumbnails
type fromThumbnailSet
toIReadOnlyList<Thumbnail>
. - Videos contained within playlists are now of type
PlaylistVideo
instead ofVideo
. PlaylistVideo
implementsIVideo
interface, which outlines properties shared withVideo
.PlaylistVideo
no longer contains some of the properties available onVideo
, specifically:UploadDate
,Description
,Keywords
, andEngagement
.- Changed
PlaylistVideo.Author
type toAuthor
. - Added
PlaylistClient.GetVideoBatchesAsync(...)
which returns videos in batches, each encompassing one response from YouTube. - Removed the previously available parameters for specifying starting page and page count on
PlaylistClient.GetVideosAsync(...)
. It is no longer possible to specify the starting page altogether because the new endpoint used by YoutubeExplode does not have the concept of pages. If you need manual control over how many requests you make, usePlaylistClient.GetVideoBatchesAsync(...)
instead. - Removed public constructor from
PlaylistId
. To create an instance ofPlaylistId
, usePlaylistId.Parse(...)
,PlaylistId.TryParse(...)
, or the implicit conversion fromstring
toPlaylistId
.
- Changed
- Changes to search:
- Search functionality is now using a different endpoint, which also returns channels and playlists in addition to just videos.
- Added
VideoSearchResult
,PlaylistSearchResult
, andChannelSearchResult
to represent the different possible result types. They implementIVideo
,IPlaylist
, andIChannel
respectively. - Added
SearchClient.GetResultsAsync(...)
which returns instances ofISearchResult
. You will need to match the instance with one of its possible implementations (VideoSearchResult
,PlaylistSearchResult
, orChannelSearchResult
) to extract detailed information. - Added
SearchClient.GetResultBatchesAsync(...)
that provides more granular control over how many requests are sent to YouTube, similar toPlaylistClient.GetVideoBatchesAsync(...)
. - Added additional methods to filter results by type:
SearchClient.GetVideosAsync(...)
,SearchClient.GetChannelsAsync(...)
, andSearchClient.GetPlaylistsAsync(...)
. Under the hood, these methods callSearchClient.GetResultsAsync(...)
.
- Changes to channels:
- Removed
Channel.LogoUrl
in favor ofChannel.Thumbnails
of typeIReadOnlyList<Thumbnail>
. - Removed public constructor from
ChannelId
. To create an instance ofChannelId
, useChannelId.Parse(...)
,ChannelId.TryParse(...)
, or the implicit conversion fromstring
toChannelId
. - Removed public constructor from
UserName
. To create an instance ofUserName
, useUserName.Parse(...)
,UserName.TryParse(...)
, or the implicit conversion fromstring
toUserName
.
- Removed
- Renamed
VideoResolution
toResolution
and moved it fromYoutubeExplode.Video.Streams
namespace toYoutubeExplode.Common
. This type is now also used inThumbnail
to specify the size of the thumbnail image. - Added
TryGetWithHighestResolution(...)
andGetWithHighestResolution(...)
extension methods onIEnumerable<Thumbnail>
. These methods return the thumbnail with the highest resolution by area (width multiplied by height). - Moved extension methods that enable
await
expressions on certainIAsyncEnumerable<T>
instances fromYoutubeExplode
namespace toYoutubeExplode.Common
. Remember to add corresponding using directive for this namespace when working with playlists or search. - Renamed
BufferAsync(...)
extension method toCollectAsync(...)
. - Added
CancellationToken
parameter to all asynchronous client methods where it was previously missing. - Consolidated exceptions into fewer types.
Thanks to @d4n3436, @Benjamin K., and @Baimbekka who helped find workarounds for recent YouTube breakages by submitting pull requests. Your contribution is very appreciated!
- Fixed an issue where some age-restricted videos were reported as unplayable, due to YouTube's recent changes.
- Fixed an issue where trying to get stream manifest resulted in an exception sometimes.
- Fixed numerous issues related to stream extraction caused by recent YouTube changes.
- Improved memory usage when downloading streams.
- Updated package icon. (Thanks @Khalid Abuhakmeh)
- Added a specialized
PlaylistUnavailableException
that gets thrown when the requested playlist is private, doesn't exist, or otherwise unavailable. (Thanks @Brandon Wood) - Fixed an issue where streams without rate-limiting did not properly support seeking. (Thanks @Johnson Pan)
- Fixed an issue where some age-restricted videos were reported as unplayable, due to YouTube's recent changes.
- Fixed an issue with player config extraction for some videos.
- Fixed an issue where an exception was thrown when using video search. (Thanks @Mattia & @Unreal852)
- Fixed an issue where some age-restricted videos could not be played, due to a change in the way STS (signature timestamp) is formatted in the player source.
- Improved performance in
VideoClient.GetAsync
. (Thanks @SnGmng) - Fixed an issue where an exception "Could not find signature decipherer definition body" was thrown, due to recent YouTube changes. (Thanks @Tymoteusz Jankowski and @OMANSAK)
- Added overload for
SearchClient.GetVideosAsync()
that can be used to specify starting page and page count, if you only want a subset of results. (Thanks @Tom PoLáKoSz) - Fixed an issue where an exception "Could not find signature decipherer definition body" was thrown, due to recent YouTube changes.
- Fixed an issue where age-restricted videos could not be downloaded.
- Fixed an issue where
PlatformNotSupportedException
was thrown when targeting Blazor WASM.
- Added
ChannelId
property to theVideo
object. (Thanks @Tom PoLáKoSz) - Added
Thumbnails
property to thePlaylist
object. The playlist's thumbnail is the same as the thumbnail of its first video. If the playlist is empty, then this property isnull
. (Thanks @Halil)
- Fixed an issue where sometimes the content length of a stream was equal to
1
due to an error in parsing. - Fixed an issue where an exception was thrown on videos that contained unplayable media streams. These streams are now ignored.
- Fixed an issue where trying to get stream manifest on 360° videos resulted in an exception.
- Fixed an issue where
Engagement.ToString()
was incorrectly formatting likes and dislikes. (Thanks @bcook254)
- Fixed an issue where the search query was not correctly escaped in
SearchClient
. (Thanks @Calle) - Fixed an issue where an exception "The given key was not present in the dictionary" was thrown when trying to get streams for some videos, due to recent YouTube changes.
- Fixed an issue where streams couldn't be extracted for some videos.
- Added
TryParse
static method toChannelId
,UserName
,PlaylistId
,VideoId
objects. - Added an extension method to make it simpler to buffer an asynchronous list of videos in-memory. You can now do
var videos = await youtube.Playlist.GetVideosAsync(...)
on top of enumerating it withawait foreach
. The readme has been updated with new usage examples. - Simplified exception messages.
- Extended
ClosedCaption
withParts
property that contains separate parts of a caption, along with their individual timings. Note that not all tracks contain this information. - Fixed an issue where searching for videos sometimes failed with an exception.
- Added missing operators for
FileSize
,Bitrate
,Framerate
,VideoResolution
,Container
,Language
,VideoId
,PlaylistId
,ChannelId
,UserName
.
- Reworked the entire library from the ground up.
- Video, playlist, channel IDs and usernames are now encapsulated in corresponding domain objects. This means that you no longer have to parse IDs manually -- e.g. if a method accepts a parameter of type
VideoId
, you can either specify an ID (bnsUkE8i0tU
) or a URL (https://youtube.com/watch?v=bnsUkE8i0tU
). - Playlist videos and search results are now returned as
IAsyncEnumerable
so you can enumerate through them without worrying about making too many or too few requests. If you want to buffer them in-memory, you can use an extension method calledBufferAsync()
. - Improved exceptions, exception messages, and everything related to exceptions. Additionally, all exception types now derive from
YoutubeExplodeException
, making them easier to catch. - Added built-in retry mechanisms to work around transient errors on YouTube's side.
- Improved resilience of the library in general.
- Fixed an issue where attempts to download some videos were periodically causing 403 Forbidden.
- Fixed a metric ton of YouTube-related issues.
- Many, many others improvements that I didn't think to mention.
- Dropped .NET Framework v4.5 target in favor of v4.6.1 and .NET Standard v1.1 target in favor of v2.0.
- Fixed an issue where attempts to download some videos were periodically causing 403 Forbidden.
- Fixed some issues revolving around videos marked with "content warning".
- Fixed an issue where
GetMediaStreamAsync
andDownloadMediaStreamAsync
threw an exception due to recent YouTube changes. As a side effect, age-restricted videos may no longer work, at least until a new workaround is found.
- Fixed an issue where
GetPlaylistAsync
only returned 200 videos for some larger playlists. Thanks @polynoman.
- Fixed an issue where some playlist IDs were incorrectly considered invalid.
- Fixed an issue where
GetVideoMediaStreamInfosAsync
sometimes returned a set without any streams due to recent YouTube changes. - Fixed an issue where "my mix" playlists were considered invalid.
- Added nullable reference type annotations and removed ReSharper annotations.
- Fixed an issue where
GetVideoMediaStreamInfosAsync
threw an exception due to recent YouTube changes.
- Updated signature deciphering to match recent YouTube changes.
- Fixed an issue where
UploadDate
was incorrect on videos returned fromGetPlaylistAsync
,SearchVideosAsync
andGetChannelUploadsAsync
.
- Fixed an issue where most methods threw
VideoUnavailableException
on all videos due to recent YouTube changes.
- Fixed an issue where
GetVideoMediaStreamInfosAsync
threw an exception due to recent YouTube changes. - Fixed how error reason is extracted from the watch page when a video is unavailable.
- Dropped dependency on AngleSharp and replaced it with LtGt.
- Fixed an issue where
GetChannelUploadsAsync
always returned empty result.
- Updated how videos in a playlist are resolved to match recent YouTube changes.
- Updated signature deciphering to match recent YouTube changes.
- Fixed an issue where
ArgumentException
was thrown on some videos due to recent YouTube changes. - Improved exception messages to make them slightly more user-friendly.
- Improved exception messages for cases when a video is blocked in user's country or is age-restricted and unembeddable.
- Fixed an issue where YoutubeExplode always failed to extract media streams due to recent YouTube changes.
- Improved performance in
GetVideoAsync
by optimizing description parser.
- Fixed some more inconsistencies with how links in video descriptions are rendered.
- Fixed an issue where
JsonReaderException
was thrown when downloading videos that were blocked on copyright grounds.
- Fixed an issue where parser methods for channel ID and username failed if the URL contained query parameters.
- Fixed some inconsistencies with how links in video descriptions are rendered.
- Pinned AngleSharp dependency to version 0.9.11 because newer versions contain breaking changes that are currently incompatible with YoutubeExplode.
- Improved the implementation of
GetChannelAsync
so that it's more fast and works on channels without any uploaded videos.
- Fixed an issue where closed caption tracks were sometimes missing whitespace between words in auto-generated tracks.
- Added an extension method to get all distinct video quality labels from a set --
MediaStreamInfoSet.GetAllVideoQualityLabels
.
- Fixed an issue where
GetVideoMediaStreamInfosAsync
returned empty for live stream recording videos.
- Fixed sporadic failures in
GetVideoAuthorChannelAsync
andGetChannelIdAsync
. - Re-added
VideoRequiresPurchaseException
as a child ofVideoUnplayableException
.
- Switched majority of video-related parsing to a new approach, which allows circumventing signature deciphering, provides more info, and is marginally faster and more consistent. This makes
GetVideoMediaStreamInfosAsync
complete twice as fast, on average. - Switched from itag-based property mapping to manual string parsing, which should be more stable in the long run.
- Added
MediaStreamInfoSet.ValidUntil
property which can be used to determine when the contained streams will expire. - Fixed an issue where controversial videos could not be parsed.
- Removed
User-Agent
header from default request headers. - Removed
VideoQuality.GetVideoQualityLabel
extension method. - Removed
MediaStreamInfo.GetUrlExpiryDate
extension method. - Removed
VideoRequiresPurchaseException
and replaced it withVideoUnplayableException
which covers a wider spectrum of errors. VideoUnavailableException
no longer has properties for error code and error reason. Error code was basically useless so it was removed, error reason is now part of theMessage
property.- Removed
ParseException
entirely. - Some enum values in
AudioEncoding
,VideoEncoding
andContainer
types were marked as obsolete because they are no longer used by YouTube.
- Fixed an issue where signature decipherer was throwing an exception due to recent YouTube changes.
- Fixed an issue where
GetVideoAsync
was throwing an exception due to recent YouTube changes.
- Fixed an issue where
GetVideoMediaStreamInfosAsync
was sometimes returning adaptive streams that were not working. There are very rare cases where it still might happen.
- Fixed an issue where external links were truncated in
Video.Description
if they are too long. - Added support for seeking in
MediaStream
.
- Improved
GetVideoAsync
,GetVideoAuthorChannelAsync
andGetVideoClosedCaptionTrackInfosAsync
so that they don't fail on unavailable videos. - Added extra result validation to
GetChannelIdAsync
to verify that the extracted value is indeed a valid channel ID. - Added static methods to parse and validate YouTube usernames.
- Fixed an issue where
JsonReaderException
was thrown on all videos due to recent YouTube changes. - Added support for itag 394.
- Added
GetChannelIdAsync
method that retrieves channel ID from username. - Added support for OL playlists.
- Added support for AV1 video codec.
- Fixed an issue where
ParseException
was thrown on signature-protected videos due to recent YouTube changes.
- Fixed an issue where retrieving some streams may throw a 403 HTTP error due to recent YouTube changes.
- Reworked
GetMediaStreamAsync
so that it implements the workaround for rate-limited streams, which was originally only available inDownloadMediaStreamAsync
. This is achieved by returning a stream that internally sends multiple segmented requests in a sequence. - Fixed
MediaStream.ReadAsync
not using theReadAsync
of the underlying stream. - Fixed
GetVideoQualityLabel
so that it displays the framerate as rounded up to the nearest 10, instead of always displaying it as '60'.
- Fixed an issue where some non-embeddable videos could not be processed.
- Fixed an issue where non-embeddable age-restricted videos could not be processed.
- Fixed exception messages not being shown in Visual Studio's exception popup.
- Fixed xml docs on
Playlist.Type
property.
- Fixed an issue where
VideoUnavailableException
would always be thrown for non-embeddable videos due to recent YouTube changes.
- Relaxed validation rules for all playlist IDs because there are even more variations than expected.
- Fixed an issue where
GetVideoAuthorChannelAsync
would always throw an exception due to recent YouTube changes.
- Added an extension method to parse
MediaStreamInfo.Url
expiry date --MediaStreamInfo.GetUrlExpiryDate
. - Replaced instances of
DateTime
withDateTimeOffset
. - Relaxed validation rules for RD playlist IDs because there are simply too many possible variations.
- Fixed some playlist IDs being considered invalid even though they aren't.
- Fixed an
OutOfMemoryException
issue that would occur when executingGetVideoMediaStreamInfosAsync
on a large video.
- Added overloads for
DownloadMediaStreamAsync
andDownloadClosedCaptionTrackAsync
that acceptStream
as output. - Removed
IHttpService
,HttpService
in favor of using unwrappedHttpClient
. - Added
IYoutubeClient
to aid in testing.
- Fixed an issue where
GetClosedCaptionTrackAsync
would throw on some malformed automatic captions. - Fixed an issue where some video qualities were not correctly identified due to itag inconsistency.
- Added support for 2880p video quality.
- Implemented segmented downloading for rate-limited media streams. This fixes slow download speed of
DownloadMediaStreamAsync
caused by YouTube changes. - Added
SearchVideosAsync
method toYoutubeClient
. Can be used to search for videos using given query. The method returnsVideo
objects but not all properties have valid values, due to how this internal API functions. - Added
HlsLiveStreamUrl
toMediaStreamInfoSet
which can be used to extract URL of M3U8 playlists for livestream videos. - Added
UploadDate
toVideo
. - Fixed incorrect return value in
GetVideoQualityLabel
/VideoQualityLabel
in cases where FPS was below 60 but above 30. - Renamed
GetRegularUrl
extension methods toGetUrl
. - Added some useful extension methods for models.
- Added some ReSharper annotations.
- Reworked
YoutubeClient
API by splitting workflows into separate methods. What was done solely byGetVideoAsync
is now done byGetVideoAsync
,GetVideoMediaStreamInfosAsync
,GetVideoClosedCaptionTrackInfosAsync
,GetVideoAuthorChannelAsync
. - Media stream and closed caption track information is no longer part of the
Video
model. Extended channel information was also removed. PlaylistVideo
has been removed as it now shares the same property set withVideo
. Existing usages ofPlaylistVideo
have been replaced withVideo
.- Order of some parameters in
Playlist
constructor has been changed. Be careful if you initialize it yourself. - Removed some properties from
Channel
that are no longer accessible due to YouTube changes. - Exception messages now provide more information, without needing to check inside properties.
ValidatePlaylistId
and(Try)ParsePlaylistId
are now more strict and check the first two characters in the ID as well.- Added a lot of useful extensions methods. Refactored some existing methods to extensions.
- Fixed incompatibility with age-restricted videos due to YouTube changes.
- Fixed other issues that prevented the library from being usable due to YouTube changes.
- Added dependency on
Newtonsoft.Json
andAngleSharp
.
This version has a lot of breaking changes and the migration isn't very straightforward. The readme has been updated with new usage examples and demo projects have been changed to work with new API.