namespace VideoBrowser.Core { using Newtonsoft.Json.Linq; using System; using System.ComponentModel; using System.Net; using System.Runtime.CompilerServices; using System.Text.RegularExpressions; /// /// Defines the /// public class VideoFormat : INotifyPropertyChanged { #region Fields internal long _fileSize; private WebRequest request; #endregion Fields #region Constructors /// /// Initializes a new instance of the class. /// /// The videoInfo /// The token public VideoFormat(VideoInfo videoInfo, JToken token) { this.AudioBitRate = -1; this.VideoInfo = videoInfo; this.DeserializeJson(token); } #endregion Constructors #region Events /// /// Defines the PropertyChanged /// public event PropertyChangedEventHandler PropertyChanged; #endregion Events #region Properties /// /// Gets the ACodec /// public string ACodec { get; private set; } /// /// Gets the audio bit rate. Returns -1 if not defined. /// public double AudioBitRate { get; private set; } /// /// Gets a value indicating whether AudioOnly /// Gets whether the format is audio only. /// public bool AudioOnly { get; private set; } /// /// Gets a value indicating whether DASH /// Gets whether format is a DASH format. /// public bool DASH { get; private set; } /// /// Gets the download url. /// public string DownloadUrl { get; private set; } /// /// Gets the file extension, excluding the period. /// public string Extension { get; private set; } /// /// Gets the file size as bytes count. /// public long FileSize { get { return _fileSize; } private set { _fileSize = value; this.OnPropertyChanged(); } } /// /// Gets the format text. /// public string Format { get; private set; } /// /// Gets the format ID. /// public string FormatID { get; private set; } /// /// Gets the frames per second. Null if not defined. /// public string FPS { get; private set; } /// /// Gets a value indicating whether HasAudioAndVideo /// public bool HasAudioAndVideo => !this.AudioOnly && !this.VideoOnly; /// /// Gets the format title, displaying some basic information. /// public string Title => this.ToString(); /// /// Gets the VCodec /// public string VCodec { get; private set; } /// /// Gets the associated VideoInfo. /// public VideoInfo VideoInfo { get; private set; } /// /// Gets a value indicating whether VideoOnly /// public bool VideoOnly { get; private set; } #endregion Properties #region Methods /// /// Aborts request for file size. /// public void AbortUpdateFileSize() { if (request != null) { request.Abort(); } } /// /// The OnPropertyChanged /// /// The propertyName public void OnPropertyChanged([CallerMemberName] string propertyName = "") { this.OnPropertyChangedExplicit(propertyName); } /// /// The OnPropertyChangedExplicit /// /// The propertyName public void OnPropertyChangedExplicit(string propertyName) { this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } /// /// The ToString /// /// The public override string ToString() { var text = string.Empty; if (this.AudioOnly) { text = this.AudioBitRate > -1 ? string.Format("Audio Only - {0} kbps (.{1})", this.AudioBitRate, this.Extension) : string.Format("Audio Only (.{0})", this.Extension); } else { var fps = !string.IsNullOrEmpty(this.FPS) ? $" - {this.FPS}fps" : string.Empty; text = string.Format("{0}{1} (.{2})", this.Format, fps, this.Extension); } return text; } /// /// Starts a WebRequest to update the file size. /// public async void UpdateFileSizeAsync() { if (this.FileSize > 0) { // Probably already got the file size from .json file. this.VideoInfo.OnFileSizeUpdated(this); return; } WebResponse response = null; try { request = WebRequest.Create(this.DownloadUrl); request.Method = "HEAD"; response = await request.GetResponseAsync(); var bytes = response.ContentLength; this.FileSize = bytes; this.VideoInfo.OnFileSizeUpdated(this); } catch (OperationCanceledException e) { Console.WriteLine(e); Console.WriteLine("Canceled update file size"); } catch (Exception e) { Console.WriteLine(e); Console.WriteLine("Update file size error"); } finally { if (response != null) { response.Close(); } } } /// /// The DeserializeJson /// /// The token private void DeserializeJson(JToken token) { this.ACodec = token["acodec"]?.ToString(); this.VCodec = token["vcodec"]?.ToString(); this.DownloadUrl = token["url"].ToString(); var formatnote = token.SelectToken("format_note"); if (formatnote != null) { this.DASH = token["format_note"].ToString().ToLower().Contains("dash"); } this.Extension = token["ext"].ToString(); this.Format = Regex.Match(token["format"].ToString(), @".*-\s([^\(\n]*)").Groups[1].Value.Trim(); this.FormatID = token["format_id"].ToString(); // Check if format is audio only or video only this.AudioOnly = this.Format.Contains("audio only"); this.VideoOnly = this.ACodec == "none"; // Check for abr token (audio bit rate?) var abr = token.SelectToken("abr"); if (abr != null) { this.AudioBitRate = double.Parse(abr.ToString()); } // Check for filesize token var filesize = token.SelectToken("filesize"); if (filesize != null && !string.IsNullOrEmpty(filesize.ToString())) { this.FileSize = long.Parse(filesize.ToString()); } // Check for 60fps videos. If there is no 'fps' token, default to 30fps. var fps = token.SelectToken("fps", false); this.FPS = fps == null || fps.ToString() == "null" ? string.Empty : fps.ToString(); this.UpdateFileSizeAsync(); } #endregion Methods } }