namespace VideoBrowser.ViewModels { using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using System.Threading.Tasks; using System.Windows.Input; using VideoBrowser.Common; using VideoBrowser.Controls.CefSharpBrowser.ViewModels; using VideoBrowser.Core; using VideoBrowser.Extensions; using VideoBrowser.Helpers; /// /// Defines the . /// public class UrlEditorViewModel : NotifyPropertyChanged, IDisposable { #region Fields private string _duration; private string _fileName; private string _fileSize; private IList _formats; private string _imageUrl; private bool _isBusy; private bool _isDownloadable; private bool _isFocused; private bool _isFormatComboBoxVisible; private bool _isTextBoxFocused; private bool _isVisible; private string _navigateUrl; private VideoFormat _selectedFormat; private int _selectedFormatIndex; private string _url; private VideoInfo _videoInfo; #endregion Fields #region Constructors /// /// Initializes a new instance of the class. /// /// The reader. /// The settings. internal UrlEditorViewModel(UrlReader reader, SettingsViewModel settings) { this.UrlReader = reader; this.UrlReader.PropertyChanged += this.OnUrlReader_PropertyChanged; this.Settings = settings; this.DownloadCommand = new RelayCommand(this.OnDownload); } #endregion Constructors #region Properties /// /// Gets the DownloadCommand. /// public ICommand DownloadCommand { get; } /// /// Gets or sets the Duration. /// public string Duration { get => this._duration; internal set => this.Set(this.PropertyChangedHandler, ref this._duration, value); } /// /// Gets or sets the FileName. /// public string FileName { get => this._fileName; internal set => this.Set(this.PropertyChangedHandler, ref this._fileName, value); } /// /// Gets or sets the FileSize. /// public string FileSize { get => _fileSize; internal set => this.Set(this.PropertyChangedHandler, ref _fileSize, value); } /// /// Gets or sets the Formats. /// public IList Formats { get => this._formats; internal set => this.Set(this.PropertyChangedHandler, ref this._formats, value); } /// /// Gets the GetFolderCommand. /// public ICommand GetFolderCommand => this.Settings.GetFolderCommand; /// /// Gets or sets the ImageUrl. /// public string ImageUrl { get => this._imageUrl; set => this.Set(this.PropertyChangedHandler, ref this._imageUrl, value); } /// /// Gets or sets a value indicating whether IsBusy. /// public bool IsBusy { get => _isBusy; set => this.Set(this.PropertyChangedHandler, ref _isBusy, value); } /// /// Gets or sets a value indicating whether IsDownloadable. /// public bool IsDownloadable { get => _isDownloadable; set => this.Set(this.PropertyChangedHandler, ref _isDownloadable, value); } /// /// Gets or sets a value indicating whether IsFocused. /// public bool IsFocused { get => _isFocused; set { if (_isFocused == value) { return; } _isFocused = value; this.InvokePropertiesChanged(this.OnPropertyChanged, nameof(this.IsFocused), nameof(this.IsVisible)); } } /// /// Gets or sets a value indicating whether IsFormatComboBoxVisible. /// public bool IsFormatComboBoxVisible { get => _isFormatComboBoxVisible; set => this.Set(this.PropertyChangedHandler, ref _isFormatComboBoxVisible, value); } /// /// Gets or sets a value indicating whether IsTextBoxFocused. /// public bool IsTextBoxFocused { get => _isTextBoxFocused; set => this.Set(this.PropertyChangedHandler, ref _isTextBoxFocused, value); } /// /// Gets or sets a value indicating whether IsVisible. /// public bool IsVisible { get => this._isVisible && this.IsFocused; internal set => this.Set(this.PropertyChangedHandler, ref this._isVisible, value); } /// /// Gets or sets the NavigateUrl. /// public string NavigateUrl { get => this._navigateUrl; set { if (this._navigateUrl == value) { return; } this._navigateUrl = value; this.IsDownloadable = false; if (this.UrlReader.IsDownloadable) { this.IsBusy = true; Task.Run(() => { this.VideoInfo = YoutubeDl.GetVideoInfo(this.NavigateUrl); }).ContinueWith(this.LoadVideoInfo); } this.IsVisible = this.UrlReader.IsDownloadable; this.OnPropertyChanged(); } } /// /// Gets or sets the NavigateUrlCommand. /// public ICommand NavigateUrlCommand { get; internal set; } /// /// Gets or sets the SelectedFormat. /// public VideoFormat SelectedFormat { get => this._selectedFormat; set { if (!this.Set(this.PropertyChangedHandler, ref this._selectedFormat, value)) { return; } this.UpdateFileSize(); } } /// /// Gets or sets the SelectedFormatIndex. /// public int SelectedFormatIndex { get => _selectedFormatIndex; set => this.Set(this.PropertyChangedHandler, ref _selectedFormatIndex, value); } /// /// Gets the Settings. /// public SettingsViewModel Settings { get; } /// /// Gets or sets the Url. /// public string Url { get => this._url; set => this.Set(this.PropertyChangedHandler, ref this._url, value); } /// /// Gets the UrlReader. /// public UrlReader UrlReader { get; } /// /// Gets or sets the VideoInfo. /// public VideoInfo VideoInfo { get => this._videoInfo; set { if (this.VideoInfo != null) { this.VideoInfo.FileSizeUpdated -= this.OnVideoInfo_FileSizeUpdated; } this.Set(this.PropertyChangedHandler, ref this._videoInfo, value); } } /// /// Gets or sets the DownloadAction. /// internal Action DownloadAction { get; set; } /// /// Gets or sets the ShowMessageAsyncAction. /// internal Action ShowMessageAsyncAction { get; set; } #endregion Properties #region Methods /// /// The Dispose. /// public void Dispose() { this.UrlReader.PropertyChanged -= this.OnUrlReader_PropertyChanged; } /// /// The LoadVideoInfo. /// /// The task. private void LoadVideoInfo(Task task) { this.IsBusy = false; this.IsFocused = true; this.IsTextBoxFocused = true; this.IsDownloadable = false; this.IsFormatComboBoxVisible = false; if (this.VideoInfo.RequiresAuthentication) { ////var auth = Dialogs.LoginDialog.Show(this); } else if (this.VideoInfo.Failure) { var message = "Couldn't retrieve video. Reason:\n\n" + this.VideoInfo.FailureReason; this.ShowMessageAsyncAction.Invoke("The Video Not Downloadable", message); Logger.Info(message); return; } else { this.FileName = YoutubeHelper.FormatTitle(this.VideoInfo.Title); this.VideoInfo.FileSizeUpdated += this.OnVideoInfo_FileSizeUpdated; this.Duration = this.VideoInfo.Duration.FormatVideoLength(); this.Formats = YoutubeHelper.CheckFormats(this.VideoInfo.Formats); this.ImageUrl = this.VideoInfo.ThumbnailUrl; if (this.Formats.Any()) { this.SelectedFormatIndex = this.Formats.Count - 1; } else { return; } } this.IsFormatComboBoxVisible = this.VideoInfo.Formats.Count > 0; this.IsDownloadable = true; Properties.Settings.Default.LastUrl = this.NavigateUrl; } /// /// The OnDownload. /// /// The o. private void OnDownload(object o) { var format = this.SelectedFormat; var formatTitle = format.AudioOnly ? format.AudioBitRate.ToString() : format.Format.ToString(); this.FileName = FileHelper.GetValidFilename(this.FileName); var fileName = $"{this.FileName}-{formatTitle}.{format.Extension}"; var output = Path.Combine(this.Settings.OutputFolder, fileName); if (File.Exists(output)) { var message = $@"File ""{fileName}"" is already downloaded. If it was failed, delete it and try again."; this.ShowMessageAsyncAction("Download Canceled", message); return; } DownloadOperation operation = format.AudioOnly || format.HasAudioAndVideo ? new DownloadOperation(format, output) : new DownloadOperation(format, YoutubeHelper.GetAudioFormat(format), output); Task.Run(() => this.DownloadAction?.Invoke(operation)); } /// /// The OnUrlReader_PropertyChanged. /// /// The sender. /// The e. private void OnUrlReader_PropertyChanged(object sender, PropertyChangedEventArgs e) { switch (e.PropertyName) { case nameof(this.UrlReader.IsDownloadable): break; } } /// /// The OnVideoInfo_FileSizeUpdated. /// /// The sender. /// The e. private void OnVideoInfo_FileSizeUpdated(object sender, FileSizeUpdateEventArgs e) { this.FileSize = FormatString.FormatFileSize(e.VideoFormat.FileSize); } /// /// The UpdateFileSize. /// private void UpdateFileSize() { if (this.SelectedFormat == null) { this.FileSize = "Unkown size"; } else if (this.SelectedFormat.FileSize == 0) { this.FileSize = "Getting file size..."; } else { var total = this.SelectedFormat.FileSize; // If the format is VideoOnly, combine audio and video size. if (this.SelectedFormat.VideoOnly) { total += YoutubeHelper.GetAudioFormat(this.SelectedFormat).FileSize; } this.FileSize = FormatString.FormatFileSize(total); } } #endregion Methods } }