/// <summary> /// Returns VideoInfo of the highest convertiable url of this youtube video /// </summary> public static async Task<VideoInfo> GetHighestAudioQualityDownloadUrlAsync(YoutubeContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); if (string.IsNullOrEmpty(context.Url)) throw new ArgumentNullException(nameof(context.Url)); var urls = (await GetDownloadUrlsAsync(context))._orderByQuality(); var video = urls.FirstOrDefault(); if (video?.RequiresDecryption == true) DecryptDownloadUrl(video); return video; }
/// <summary> /// Gets a list of <see cref="VideoInfo" />s for the specified URL. /// </summary> /// <param name="context">The context, must contain a url to the video in the Url property</param> /// <param name="decryptSignature"> /// A value indicating whether the video signatures should be decrypted or not. Decrypting /// consists of a HTTP request for each <see cref="VideoInfo" />, so you may want to set /// this to false and call <see cref="DecryptDownloadUrl" /> on your selected /// <see /// cref="VideoInfo" /> /// later. /// </param> /// <returns>A list of <see cref="VideoInfo" />s that can be used to download the video.</returns> /// <exception cref="VideoNotAvailableException">The video is not available.</exception> /// <exception cref="WebException"> /// An error occurred while downloading the YouTube page html. /// </exception> /// <exception cref="YoutubeParseException">The Youtube page could not be parsed.</exception> public static IEnumerable<VideoInfo> GetDownloadUrls(YoutubeContext context, bool decryptSignature = true) { if (context == null) throw new ArgumentNullException(nameof(context)); if (context.Url == null) throw new ArgumentNullException(nameof(context.Url)); context.OnProgresStateChanged(YoutubeStage.ProcessingUrls); string ytb; var isYoutubeUrl = TryNormalizeYoutubeUrl(context.Url, out ytb); context.Url = ytb; if (!isYoutubeUrl) throw new ArgumentException("URL is not a valid youtube URL!"); _retry: try { var rpf = new RetryableProcessFailed("ParseHtml5Version") {Tag = context.Url}; _redownload: var json = LoadJson(context.Url); var videoTitle = GetVideoTitle(json); var n = 0; var downloadUrls = ExtractDownloadUrls(json); var infos = GetVideoInfos(downloadUrls, videoTitle, context.Url).ToArray(); try { var htmlPlayerVersion = GetHtml5PlayerVersion(json); foreach (var info in infos) { info.HtmlPlayerVersion = htmlPlayerVersion; if (decryptSignature && info.RequiresDecryption) DecryptDownloadUrl(info); } return infos; } catch (Exception e) { rpf.Defaultize(e); context.OnDownloadFailed(rpf); Console.WriteLine(e); if (rpf.ShouldRetry) goto _redownload; return null; } } catch (Exception ex) when (ex.Message == "Result cannot be called on a failed Match.") { goto _retry; } catch (Exception ex) { if (ex is WebException || ex is VideoNotAvailableException) throw; ThrowYoutubeParseException(ex, context.Url); } //Message return null; // Will never happen, but the compiler requires it }
public YoutubeThumbnail(YoutubeContext context) : this(context.Url) { _thumbnail_task.ContinueWith(task => context.OnProgresStateChanged(YoutubeStage.ThumbnailFound)); }
/// <summary> /// Initializes a new instance of the <see cref="VideoDownloader" /> class. /// </summary> public VideoDownloader(YoutubeContext context, bool findBestVideoInfo = false) : base(context) { if (findBestVideoInfo) DownloadUrlResolver.FindHighestVideoQualityDownloadUrl(context); }
/// <summary> /// Returns VideoInfo of the highest convertiable url of this youtube video /// </summary> public static async Task FindHighestVideoQualityDownloadUrlAsync(YoutubeContext context, VideoType type = VideoType.Mp4) { if (context == null) throw new ArgumentNullException(nameof(context)); var urls = await DownloadUrlResolver.GetDownloadUrlsAsync(context); context.VideoInfo = urls.Where(vi=>vi.VideoType==type).OrderByDescending(info => info.Resolution).FirstOrDefault(); if (context.VideoInfo?.RequiresDecryption == true) DownloadUrlResolver.DecryptDownloadUrl(context.VideoInfo); }
/// <summary> /// Returns VideoInfo of the highest convertiable url of this youtube video /// </summary> public static async Task FindHighestAudioQualityDownloadUrlAsync(YoutubeContext context) { if (context == null) throw new ArgumentNullException(nameof(context)); var urls = await DownloadUrlResolver.GetDownloadUrlsAsync(context); context.VideoInfo = urls.Where(vid => vid.CanExtractAudio).OrderByDescending(info => info.AudioBitrate).FirstOrDefault(); if (context.VideoInfo?.RequiresDecryption == true) DownloadUrlResolver.DecryptDownloadUrl(context.VideoInfo); }
/// <summary> /// Gets a list of <see cref="VideoInfo" />s for the specified URL. /// </summary> /// <param name="context">The context, must contain a url to the video in the Url property</param> /// <param name="decryptSignature"> /// A value indicating whether the video signatures should be decrypted or not. Decrypting /// consists of a HTTP request for each <see cref="VideoInfo" />, so you may want to set /// this to false and call <see cref="DecryptDownloadUrl" /> on your selected /// <see /// cref="VideoInfo" /> /// later. /// </param> /// <returns>A list of <see cref="VideoInfo" />s that can be used to download the video.</returns> /// <exception cref="VideoNotAvailableException">The video is not available.</exception> /// <exception cref="WebException"> /// An error occurred while downloading the YouTube page html. /// </exception> /// <exception cref="YoutubeParseException">The Youtube page could not be parsed.</exception> public static async Task<IEnumerable<VideoInfo>> GetDownloadUrlsAsync(YoutubeContext context, bool decryptSignature = true) { if (context == null) throw new ArgumentNullException(nameof(context)); if (context.Url == null) throw new ArgumentNullException(nameof(context.Url)); context.OnProgresStateChanged(YoutubeStage.ProcessingUrls); string ytb; var isYoutubeUrl = TryNormalizeYoutubeUrl(context.Url, out ytb); context.Url = ytb; if (!isYoutubeUrl) throw new ArgumentException("URL is not a valid youtube URL!"); try { var rpf = new RetryableProcessFailed("ParseHtml5Version") {Tag = context.Url }; _redownload: var json = await LoadJsonAsync(context.Url); var videoTitle = GetVideoTitle(json); int n = 0; var downloadUrls = ExtractDownloadUrls(json); var infos = GetVideoInfos(downloadUrls, videoTitle, context.Url); string htmlPlayerVersion; try { htmlPlayerVersion = GetHtml5PlayerVersion(json); } catch (Exception e) { rpf.Defaultize(e); context.OnDownloadFailed(rpf); if (rpf.ShouldRetry) goto _redownload; return null; } foreach (var info in infos) { info.HtmlPlayerVersion = htmlPlayerVersion; if (decryptSignature && info.RequiresDecryption) await DecryptDownloadUrlAsync(info); } return infos; } catch (Exception ex) { if (ex is WebException || ex is VideoNotAvailableException) throw; ThrowYoutubeParseException(ex, context.Url); } return null; // Will never happen, but the compiler requires it }
protected bool Equals(YoutubeContext other) { return _contextid.Equals(other._contextid) && string.Equals(_url, other._url) && Equals(VideoInfo, other.VideoInfo); }
/// <summary> /// Initializes a new instance of the <see cref="AudioDownloader" /> class. /// </summary> /// <param name="context">The current context</param> /// <param name="findBestVideoInfo">Will execute FindBestQualityVideoInfo to the current context</param> public AudioDownloader(YoutubeContext context, bool findBestVideoInfo = false) : base(context) { if (findBestVideoInfo) context.FindHighestAudioQualityDownloadUrl(); }