/// <summary>
        /// Returns whether the local file should be replaced by the YouTube version.
        /// </summary>
        /// <param name="localFile">A path to the local file.</param>
        /// <param name="serverFile">The information of the available server file.</param>
        /// <returns>True if the local file should be replaced.</returns>
        public async Task<VideoListItemStatusEnum> IsHigherQualityAvailable(string localFile, BestFormatInfo serverFile) {
            // If there is no local file, it should be downloaded.
            if (!File.Exists(localFile))
                return VideoListItemStatusEnum.HigherQualityAvailable;

            // If local file is FLV and there's another format available, it should be downloaded.
            string LocalFileExt = Path.GetExtension(localFile).ToLower();
            if (LocalFileExt == ".flv" && serverFile.BestVideo.VideoType != VideoType.Flash)
                return VideoListItemStatusEnum.HigherQualityAvailable;

            // Original VCD files and files of unrecognized extensions should not be replaced.
            MediaInfoReader InfoReader = new MediaInfoReader();
            await InfoReader.LoadInfoAsync(localFile);
            if (!DownloadBusiness.DownloadedExtensions.Contains(LocalFileExt) || InfoReader.VideoFormat == "MPEG Video") {
                serverFile.StatusText = "Not from YouTube";
                return VideoListItemStatusEnum.OK;
            }

            // For server file size, estimate 10% extra for audio. Estimate 35% advantage for VP9 format. non-DASH WebM is VP8 and doesn't have that bonus.
            long ServerFileSize = (long)(serverFile.BestVideo.FileSize * 1.1);
            if (serverFile.BestVideo.VideoType == VideoType.WebM && serverFile.BestVideo.AdaptiveType == AdaptiveType.Video)
                ServerFileSize = (long)(ServerFileSize * 1.35);
            long LocalFileSize = new FileInfo(localFile).Length;
            if (InfoReader.VideoFormat == "VP9")
                LocalFileSize = (long)(LocalFileSize * 1.35);

            // If server resolution is better, download unless local file is bigger.
            int LocalFileHeight = InfoReader.Height ?? 0;
            if (serverFile.BestVideo.Resolution > LocalFileHeight) {
                if (ServerFileSize > LocalFileSize)
                    return VideoListItemStatusEnum.HigherQualityAvailable;
                else if (ServerFileSize != 0) {
                    // non-DASH videos have no file size specified, and we won't replace local video with non-DASH video.
                    serverFile.StatusText = "Local file larger";
                    return VideoListItemStatusEnum.OK;
                }
            }

            // Is estimated server file size is at least 15% larger than local file (for same resolution), download.
            if (ServerFileSize > LocalFileSize * 1.15)
                return VideoListItemStatusEnum.HigherQualityAvailable;

            // download audio and merge with local video. (that didn't work, ffmpeg failed to merge back)
            int? LocalAudioBitRate = InfoReader.AudioBitRate;
            int ServerAudioBitRate = serverFile.BestAudio != null ? serverFile.BestAudio.AudioBitrate : serverFile.BestVideo.AudioBitrate;
            // Fix a bug where MediaInfo returns no bitrate for MKV containers with AAC audio.
            if (LocalAudioBitRate != null || LocalFileExt != ".mkv") {
                if ((LocalAudioBitRate == null || LocalAudioBitRate < ServerAudioBitRate * .8) && serverFile.BestVideo.Resolution == LocalFileHeight) {
                    // Only redownload for audio if video file size is similar. Videos with AdaptiveType=None don't have file size.
                    if (ServerFileSize > LocalFileSize * .9 && serverFile.BestVideo.AdaptiveType == AdaptiveType.Video) {
                        serverFile.StatusText = "Audio";
                        return VideoListItemStatusEnum.HigherQualityAvailable;
                    } else {
                        serverFile.StatusText = "";
                        return VideoListItemStatusEnum.BetterAudioAvailable;
                    }
                }
            }

            return VideoListItemStatusEnum.OK;
        }
        /// <summary>
        /// Returns the best format from the list in this order of availability: WebM, Mp4 or Flash.
        /// Mp4 will be chosen if WebM is over 35% smaller.
        /// </summary>
        /// <param name="list">The list of videos to chose from.</param>
        /// <returns>The best format available.</returns>
        public static BestFormatInfo SelectBestFormat(IEnumerable<VideoInfo> list) {
            var MaxResolutionList = (from v in list
                                     where (Settings.SavedFile.MaxDownloadQuality == 0 || v.Resolution <= Settings.SavedFile.MaxDownloadQuality)
                                        && v.AdaptiveType != AdaptiveType.Audio
                                     orderby v.Resolution descending
                                     select v).ToList();
            MaxResolutionList = MaxResolutionList.Where(v => v.Resolution == MaxResolutionList.First().Resolution).ToList();

            // If for the maximum resolution, only some formats have a file size, the other ones must be queried.
            if (MaxResolutionList.Any(v => v.FileSize == 0) && MaxResolutionList.Any(v => v.FileSize > 0)) {
                foreach (VideoInfo item in MaxResolutionList.Where(v => v.FileSize == 0)) {
                    DownloadUrlResolver.QueryStreamSize(item);
                }
            }

            VideoInfo BestVideo = (from v in MaxResolutionList
                                   // WebM VP9 encodes ~35% better. non-DASH is VP8 and isn't better than MP4.
                                   let Preference = (int)((v.VideoType == VideoType.WebM && v.AdaptiveType == AdaptiveType.Video) ? v.FileSize * 1.35 : v.FileSize)
                                   where v.Resolution == MaxResolutionList.First().Resolution
                                   orderby Preference descending
                                   select v).FirstOrDefault();

            if (BestVideo != null) {
                BestFormatInfo Result = new BestFormatInfo();
                Result.BestVideo = BestVideo;
                // Even for non-DASH videos, we still want to know what audio is available even though it may not be downloaded.
                Result.BestAudio = SelectBestAudio(from v in list
                                                   where (v.CanExtractAudio || v.AdaptiveType == AdaptiveType.Audio)
                                                   orderby v.AudioBitrate descending
                                                   select v);
                return Result;
            } else
                return null;
        }