/// <summary>
        /// Gets an instance asynchronously of the <see cref="YoutubeSongInfo"/> class.
        /// </summary>
        /// <param name="Source">The URL of the video</param>
        /// <returns>A <see cref="YoutubeSongInfo"/> instance.</returns>
        public static async Task <YoutubeSongInfo> GetVideoInfoAsync(string Source)
        {
            YoutubeDl d = new YoutubeDl("youtube-dl.exe", App.Path)
            {
                VideoID = YoutubeUri.GetVideoID(Source)
            };

            YoutubeMediaInfo r = await d.GetVideoInfo();

            var Result = new YoutubeSongInfo(
                Source: Source,
                Title: r.RecognizedMedia?.Title ?? r.Title,
                Artist: r.RecognizedMedia?.Artist,
                DurationInSeconds: r.Duration.TotalSeconds
                )
            {
                Formats = r.MediaFormats
            };

            if (App.Config.YoutubeDownloadThumbnail)
            {
                Result.AlbumImage = await r.Thumbnails.FirstOrDefault()?.DownloadAsImageAsync();
            }

            return(Result);
        }
        /// <summary>
        /// Downloads a video asynchronously with youtube-dl.
        /// </summary>
        /// <param name="SongInfo">A <see cref="ISongInfo"/> instance that holds the URI of the media to download</param>
        /// <returns>
        ///		A <see cref="Task"/> for an <see cref="IPlaybackManager"/> instance
        ///		that can play the YouTube media. Null is returned when the download
        ///		fails.
        /// </returns>
        /// <exception cref="ArgumentNullException">when <paramref name="SongInfo"/> is null</exception>
        /// <exception cref="ArgumentException">when <see cref="ISongInfo.Source"/> is not a valid YouTube URI</exception>
        public static async Task <IPlaybackManager> DownloadVideoAsync(ISongInfo SongInfo, IProgress <LongOperationProgress> Progress)
        {
            #region Error checking
            if (SongInfo == null)
            {
                throw new ArgumentNullException(nameof(SongInfo));
            }

            if (!YoutubeUri.IsValidYoutubeUri(SongInfo.Source))
            {
                throw new ArgumentException("Not a valid YouTube URI");
            }
            #endregion

            string MediaFilename = Path.ChangeExtension(Path.GetTempFileName(), "mp3");

            #region Cleanup
            if (File.Exists(MediaFilename))
            {
                File.Delete(MediaFilename);
            }
            #endregion

            MediaFormat Format = (SongInfo as YoutubeSongInfo)?.GetBestAudioFormat();

            try {
                YoutubeDl Downloader = new YoutubeDl("youtube-dl.exe", App.Path)
                {
                    AudioFileFormat = YoutubeDlAudioFormat.mp3,
                    Filename        = MediaFilename,
                    VideoID         = YoutubeUri.GetVideoID(SongInfo.Source)
                };

                Progress <YoutubeDownloadProgress> YTProgress = new Progress <YoutubeDownloadProgress>();
                YTProgress.ProgressChanged += (po, pe) => Progress?.Report(pe.ToLongOperationProgress());

                //When download fails and youtube-dl reports that an update is required, update it and retry.
                Downloader.UpdateRequired += async(o, e) => {
                    Progress.Report(
                        new YoutubeDownloadProgress(YoutubeDownloadStatus.Updating, 0).ToLongOperationProgress()
                        );
                    await Downloader.UpdateAsync();



                    await Downloader.DownloadAudioAsync(YTProgress);
                };

                await Downloader.DownloadAudioAsync(YTProgress, Format);
            }
            catch (Exception e) {
                Trace.WriteLine(e.Message);
                return(null);
            }

            if (File.Exists(MediaFilename))
            {
                using (Stream s = File.OpenRead(MediaFilename)) {
                    Progress <LongOperationProgress> OpenMediaProgress = new Progress <LongOperationProgress>();
                    OpenMediaProgress.ProgressChanged += (o, e) => Progress?.Report(e);

                    return(new YoutubePlayback(
                               SongInfo,
                               await UnmanagedStream.CreateFromStream(s, OpenMediaProgress),
                               MediaFilename
                               ));
                }
            }
            else
            {
                return(null);
            }
        }