private async Task QueryAsync() { QueryButton.IsEnabled = false; DownloadButton.IsEnabled = false; downloadInfo = await DownloadManager.GetDownloadInfoAsync(video.DownloadUrl); if (downloadInfo != null) { TitleTextBox.Text = downloadInfo.Info.Title; options = new DownloadOptions() { PreferredFormat = (SelectStreamFormat)PreferredFormatCombo.SelectedIndex, PreferredAudio = (SelectStreamFormat)PreferredAudioCombo.SelectedIndex, MaxQuality = (int)MaxDownloadQualityCombo.SelectedValue, SimultaneousDownloads = 2 }; BestFormatInfo StreamInfo = DownloadManager.SelectBestFormat(downloadInfo.Streams, options); DownloadVideoText.Text = GetStreamDescription(StreamInfo.BestVideo); DownloadAudioText.Text = GetStreamDescription(StreamInfo.BestAudio); bestFormat = StreamInfo; StreamOption_Click(null, null); } else { TitleTextBox.Text = "Invalid URL"; } QueryButton.IsEnabled = true; }
/// <summary> /// Returns whether the local file should be replaced by the YouTube version. /// </summary> /// <param name="serverFile">The information of the available server file.</param> /// <param name="localFile">A path to the local file.</param> /// <returns>True if the local file should be replaced.</returns> public async Task <VideoListItemStatusEnum> IsHigherQualityAvailable(BestFormatInfo serverFile, string localFile) { // If there is no local file, it should be downloaded. if (!File.Exists(localFile)) { return(VideoListItemStatusEnum.HigherQualityAvailable); } // Read local file info. string LocalFileExt = Path.GetExtension(localFile).ToLower(); FFmpegProcess InfoReader = await Task.Run(() => MediaInfo.GetFileInfo(localFile)); LastInfoReader = InfoReader; VideoListItemStatusEnum Result = IsHigherQualityAvailableInternal(serverFile, localFile, InfoReader); if (Result == VideoListItemStatusEnum.OK) { // Check if video has right container. string VFormat = InfoReader.VideoStream?.Format; string AFormat = InfoReader.AudioStream?.Format; VFormat = VFormat?.ToLower(); AFormat = AFormat?.ToLower(); if (VFormat == "h264" && (AFormat == null || AFormat == "aac") && LocalFileExt != ".mp4") { return(VideoListItemStatusEnum.WrongContainer); } else if (VFormat == "webm" && (AFormat == null || AFormat == "opus" || AFormat == "vorbis") && LocalFileExt != ".webm") { return(VideoListItemStatusEnum.WrongContainer); } else { return(VideoListItemStatusEnum.OK); } } else { return(Result); } }
public async Task StartScan(List <VideoListItem> selection, CancellationToken cancel) { await selection.ForEachAsync(5, cancel, async item => { Media VideoData = PlayerAccess.GetVideoById(item.MediaId.Value); if (VideoData != null && !item.IsBusy) { try { // Query the server for media info. SetStatus(item, VideoListItemStatusEnum.DownloadingInfo); VideoInfo VInfo = await DownloadManager.GetDownloadInfoAsync(VideoData.DownloadUrl); if (VInfo != null) { // Get the highest resolution format. BestFormatInfo VideoFormat = DownloadBusiness.SelectBestFormat(VInfo.Streams); if (VideoFormat == null || VideoFormat.BestVideo == null) { SetStatus(item, VideoListItemStatusEnum.Failed); } else { SetStatus(item, await IsHigherQualityAvailable(VideoFormat, Settings.NaturalGroundingFolder + VideoData.FileName)); } if (VideoFormat != null && !string.IsNullOrEmpty(VideoFormat.StatusText)) { SetStatus(item, item.Status, item.StatusText + string.Format(" ({0})", VideoFormat.StatusText)); } } else { SetStatus(item, VideoListItemStatusEnum.InvalidUrl); } } catch { SetStatus(item, VideoListItemStatusEnum.Failed); } } }); }
private async void QueryButton_Click(object sender, RoutedEventArgs e) { GridInfo.Visibility = Visibility.Visible; ErrorText.Visibility = Visibility.Hidden; QueryButton.IsEnabled = false; DownloadButton.IsEnabled = false; VideoUrl = DownloadUrl.Text; TitleText.Text = ""; VideoText.Text = ""; AudioText.Text = ""; ContainerText.Text = ""; Info = await DownloadManager.GetDownloadInfoAsync(VideoUrl); if (Info != null) { TitleText.Text = Info.Info.Title; TitleText.ToolTip = Info.Info.Title; GridInfo.Visibility = Visibility.Visible; Options = new DownloadOptions() { PreferredFormat = (SelectStreamFormat)PreferredFormatCombo.SelectedIndex, PreferredAudio = (SelectStreamFormat)PreferredAudioCombo.SelectedIndex, MaxQuality = (int)MaxDownloadQualityCombo.SelectedValue, SimultaneousDownloads = 2 }; BestFormatInfo StreamInfo = DownloadManager.SelectBestFormat(Info.Streams, Options); VideoText.Text = GetStreamDescription(StreamInfo.BestVideo); AudioText.Text = GetStreamDescription(StreamInfo.BestAudio); ContainerText.Text = DownloadManager.GetFinalExtension(StreamInfo.BestVideo, StreamInfo.BestAudio); DownloadButton.IsEnabled = true; } else { GridInfo.Visibility = Visibility.Hidden; ErrorText.Visibility = Visibility.Visible; } QueryButton.IsEnabled = true; }
public VideoListItemStatusEnum IsHigherQualityAvailableInternal(BestFormatInfo serverFile, string localFile, FFmpegProcess InfoReader) { string LocalFileExt = Path.GetExtension(localFile).ToLower(); // If local file is FLV and there's another format available, it should be downloaded. if (LocalFileExt == ".flv" && serverFile.BestVideo.Container != Container.Flv) { return(VideoListItemStatusEnum.HigherQualityAvailable); } // Original VCD files and files of unrecognized extensions should not be replaced. if (!DownloadManager.DownloadedExtensions.Contains(LocalFileExt) || InfoReader?.VideoStream?.Format == "mpeg1video") { serverFile.StatusText = "Not from YouTube"; return(VideoListItemStatusEnum.OK); } // For server file size, estimate 4% extra for audio. Estimate 30% advantage for VP9 format. non-DASH WebM is VP8 and doesn't have that bonus. long ServerFileSize = (long)(serverFile.BestVideo.Size * 1.04); if (DownloadManager.GetVideoEncoding(serverFile.BestVideo) == VideoEncoding.Vp9) { ServerFileSize = (long)(ServerFileSize * 1.3); } long LocalFileSize = new FileInfo(localFile).Length; if (InfoReader?.VideoStream?.Format == "vp9") { LocalFileSize = (long)(LocalFileSize * 1.3); } // If server resolution is better, download unless local file is bigger. int LocalFileHeight = InfoReader?.VideoStream?.Height ?? 0; if (DownloadManager.GetVideoHeight(serverFile.BestVideo) > LocalFileHeight) { if (ServerFileSize > LocalFileSize) { return(VideoListItemStatusEnum.HigherQualityAvailable); } else if (ServerFileSize != 0) { return(VideoListItemStatusEnum.OK); } } else if (DownloadManager.GetVideoHeight(serverFile.BestVideo) < LocalFileHeight) { // If local resolution is higher, keep. return(VideoListItemStatusEnum.OK); } // Choose whether to download only audio, only video, or both. bool DownloadVideo = false; bool DownloadAudio = false; // Is estimated server file size is at least 15% larger than local file (for same resolution), download. if (ServerFileSize > LocalFileSize * 1.15) { DownloadVideo = true; } // If PreferredFormat is set to a format, download that format. else if (Manager != null) { if (Manager.Options.PreferredFormat == SelectStreamFormat.MP4 && InfoReader.VideoStream?.Format == "vp9" && (DownloadManager.GetVideoEncoding(serverFile.BestVideo) == VideoEncoding.H264 || DownloadManager.GetVideoEncoding(serverFile.BestVideo) == VideoEncoding.H263)) { DownloadVideo = true; } else if (Manager.Options.PreferredFormat == SelectStreamFormat.VP9 && InfoReader.VideoStream?.Format == "h264" && (DownloadManager.GetVideoEncoding(serverFile.BestVideo) == VideoEncoding.Vp9 || DownloadManager.GetVideoEncoding(serverFile.BestVideo) == VideoEncoding.Vp8)) { DownloadVideo = true; } } if (InfoReader.AudioStream == null) { DownloadAudio = true; } // Can only upgrade is video length is same. else if (Math.Abs((InfoReader.FileDuration - serverFile.Duration).TotalSeconds) < 1) { // download audio and merge with local video. string LocalAudio = InfoReader.AudioStream.Format; AudioEncoding RemoteAudio = serverFile.BestAudio?.AudioEncoding ?? AudioEncoding.Aac; if (InfoReader.AudioStream.Bitrate == 0 && LocalAudio == "opus" || LocalAudio == "vorbis") { InfoReader.AudioStream.Bitrate = 160; // FFmpeg doesn't return bitrate of Opus and Vorbis audios, but it's 160. } if (InfoReader.AudioStream.Bitrate == 0) { InfoReader.AudioStream.Bitrate = GetAudioBitrateMuxe(localFile); } int LocalAudioBitRate = InfoReader.AudioStream.Bitrate; long ServerAudioBitRate = serverFile.BestAudio != null ? serverFile.BestAudio.Bitrate / 1024 : 0; // MediaInfo returns no bitrate for MKV containers with AAC audio. InfoReader.AudioStream.Bitrate = 160; if (LocalAudioBitRate > 0 || LocalFileExt != ".mkv") { if ((LocalAudioBitRate == 0 || LocalAudioBitRate < ServerAudioBitRate * .8)) { DownloadAudio = true; } } if ((LocalAudio == "opus" && RemoteAudio == AudioEncoding.Vorbis) || (LocalAudio == "vorbis" && RemoteAudio == AudioEncoding.Opus)) { DownloadAudio = true; } } else { DownloadAudio = DownloadVideo; } if (DownloadVideo && DownloadAudio) { return(VideoListItemStatusEnum.HigherQualityAvailable); } else if (DownloadVideo) { return(VideoListItemStatusEnum.BetterVideoAvailable); } else if (DownloadAudio) { return(VideoListItemStatusEnum.BetterAudioAvailable); } return(VideoListItemStatusEnum.OK); }