// -------------------------------------------------------------------------------------------------------------------- // // This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License. // // // The About View Model // // -------------------------------------------------------------------------------------------------------------------- namespace HandBrakeWPF.ViewModels { using System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Threading; using System.Windows; using HandBrake.ApplicationServices.Model; using HandBrake.ApplicationServices.Services.Encode.EventArgs; using HandBrake.ApplicationServices.Services.Encode.Interfaces; using HandBrake.ApplicationServices.Services.Encode.Model; using HandBrake.ApplicationServices.Services.Encode.Model.Models; using HandBrake.ApplicationServices.Services.Interfaces; using HandBrakeWPF.Factories; using HandBrakeWPF.Properties; using HandBrakeWPF.Services; using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.ViewModels.Interfaces; /// /// The About View Model /// public class PreviewViewModel : ViewModelBase, IPreviewViewModel { #region Constants and Fields /// /// Backing field for the encode service. /// private readonly IEncodeServiceWrapper encodeService; /// /// The error service /// private readonly IErrorService errorService; /// /// The user Setting Service /// private readonly IUserSettingService userSettingService; /// /// The percentage. /// private string percentage; /// /// The percentage value. /// private double percentageValue; /// /// The Backing field for IsEncoding /// private bool isEncoding; /// /// Backing field for use system default player /// private bool useSystemDefaultPlayer; #endregion #region Constructors and Destructors /// /// Initializes a new instance of the class. /// /// /// The error Service. /// /// /// The user Setting Service. /// public PreviewViewModel(IErrorService errorService, IUserSettingService userSettingService) { // Preview needs a seperate instance rather than the shared singleton. This could maybe do with being refactored at some point this.encodeService = new EncodeServiceWrapper(userSettingService); this.errorService = errorService; this.userSettingService = userSettingService; this.Title = "Preview"; this.Percentage = "0.00%"; this.PercentageValue = 0; this.StartAt = 1; this.Duration = 30; this.CanPlay = true; UseSystemDefaultPlayer = userSettingService.GetUserSetting(UserSettingConstants.DefaultPlayer); this.Duration = userSettingService.GetUserSetting(UserSettingConstants.LastPreviewDuration); } #endregion #region Properties /// /// Gets or sets Task. /// public EncodeTask Task { get; set; } /// /// Gets AvailableDurations. /// public IEnumerable AvailableDurations { get { return new List { 5, 10, 30, 45, 60, 75, 90, 105, 120, 150, 180, 210, 240 }; } } /// /// Gets or sets Duration. /// public int Duration { get; set; } /// /// Gets or sets Percentage. /// public string Percentage { get { return this.percentage; } set { this.percentage = value; this.NotifyOfPropertyChange(() => this.Percentage); } } /// /// Gets or sets PercentageValue. /// public double PercentageValue { get { return this.percentageValue; } set { this.percentageValue = value; this.NotifyOfPropertyChange(() => this.PercentageValue); } } /// /// Gets or sets StartAt. /// public int StartAt { get; set; } /// /// Gets StartPoints. /// public IEnumerable StartPoints { get { List startPoints = new List(); for (int i = 1; i <= this.UserSettingService.GetUserSetting(UserSettingConstants.PreviewScanCount); i++) { startPoints.Add(i); } return startPoints; } } /// /// Gets or sets a value indicating whether UseSystemDefaultPlayer. /// public bool UseSystemDefaultPlayer { get { return this.useSystemDefaultPlayer; } set { this.useSystemDefaultPlayer = value; this.NotifyOfPropertyChange(() => UseSystemDefaultPlayer); this.userSettingService.SetUserSetting(UserSettingConstants.DefaultPlayer, value); } } /// /// Gets or sets a value indicating whether IsEncoding. /// public bool IsEncoding { get { return this.isEncoding; } set { this.isEncoding = value; this.CanPlay = !value; this.NotifyOfPropertyChange(() => this.CanPlay); this.NotifyOfPropertyChange(() => this.IsEncoding); } } /// /// Gets or sets the Currently Playing / Encoding Filename. /// public string CurrentlyPlaying { get; set; } /// /// Gets or sets a value indicating whether can play. /// public bool CanPlay { get; set; } #endregion #region Public Methods /// /// Close this window. /// public void Close() { this.TryClose(); } /// /// Handle The Initialisation /// public override void OnLoad() { } /// /// Encode and play a sample /// public void Play() { try { this.IsEncoding = true; if (File.Exists(this.CurrentlyPlaying)) File.Delete(this.CurrentlyPlaying); } catch (Exception) { this.IsEncoding = false; this.errorService.ShowMessageBox("Unable to delete previous preview file. You may need to restart the application.", Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); } if (this.Task == null || string.IsNullOrEmpty(Task.Source)) { this.errorService.ShowMessageBox("You must first scan a source and setup your encode before creating a preview.", Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } EncodeTask encodeTask = new EncodeTask(this.Task) { PreviewDuration = this.Duration, PreviewStartAt = this.StartAt, PointToPointMode = PointToPointMode.Preview }; // Filename handling. if (string.IsNullOrEmpty(encodeTask.Destination)) { string filename = Path.ChangeExtension(Path.GetTempFileName(), encodeTask.OutputFormat == OutputFormat.Mkv ? "m4v" : "mkv"); encodeTask.Destination = filename; this.CurrentlyPlaying = filename; } else { string directory = Path.GetDirectoryName(encodeTask.Destination) ?? string.Empty; string filename = Path.GetFileNameWithoutExtension(encodeTask.Destination); string extension = Path.GetExtension(encodeTask.Destination); string previewFilename = string.Format("{0}_preview{1}", filename, extension); string previewFullPath = Path.Combine(directory, previewFilename); encodeTask.Destination = previewFullPath; this.CurrentlyPlaying = previewFullPath; } // Setup the encode task as a preview encode encodeTask.IsPreviewEncode = true; encodeTask.PreviewEncodeStartAt = this.StartAt.ToString(CultureInfo.InvariantCulture); encodeTask.PreviewEncodeDuration = this.Duration; QueueTask task = new QueueTask(encodeTask, HBConfigurationFactory.Create(false)); ThreadPool.QueueUserWorkItem(this.CreatePreview, task); } #endregion #region Private Methods /// /// Play the Encoded file /// private void PlayFile() { // Launch VLC and Play video. if (this.CurrentlyPlaying != string.Empty) { if (File.Exists(this.CurrentlyPlaying)) { string args = "\"" + this.CurrentlyPlaying + "\""; if (this.UseSystemDefaultPlayer) { Process.Start(args); } else { if (!File.Exists(UserSettingService.GetUserSetting(UserSettingConstants.VLCPath))) { // Attempt to find VLC if it doesn't exist in the default set location. string vlcPath; if (8 == IntPtr.Size || (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432")))) vlcPath = Environment.GetEnvironmentVariable("ProgramFiles(x86)"); else vlcPath = Environment.GetEnvironmentVariable("ProgramFiles"); if (!string.IsNullOrEmpty(vlcPath)) { vlcPath = Path.Combine(vlcPath, "VideoLAN\\VLC\\vlc.exe"); } if (File.Exists(vlcPath)) { UserSettingService.SetUserSetting(UserSettingConstants.VLCPath, vlcPath); } else { this.errorService.ShowMessageBox("Unable to detect VLC Player. \nPlease make sure VLC is installed and the directory specified in HandBrake's options is correct. (See: \"Tools Menu > Options > Picture Tab\")", Resources.Error, MessageBoxButton.OK, MessageBoxImage.Warning); } } if (File.Exists(UserSettingService.GetUserSetting(UserSettingConstants.VLCPath))) { ProcessStartInfo vlc = new ProcessStartInfo(UserSettingService.GetUserSetting(UserSettingConstants.VLCPath), args); Process.Start(vlc); } } } else { this.errorService.ShowMessageBox("Unable to find the preview file. Either the file was deleted or the encode failed. Check the activity log for details.", Resources.Error, MessageBoxButton.OK, MessageBoxImage.Warning); } } } /// /// Create the Preview. /// /// /// The state. /// private void CreatePreview(object state) { // Make sure we are not already encoding and if we are then display an error. if (encodeService.IsEncoding) { this.errorService.ShowMessageBox("Handbrake is already encoding a video! Only one file can be encoded at any one time.", Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error); return; } this.encodeService.EncodeCompleted += this.encodeService_EncodeCompleted; this.encodeService.EncodeStatusChanged += this.encodeService_EncodeStatusChanged; this.encodeService.Start((QueueTask)state); this.userSettingService.SetUserSetting(UserSettingConstants.LastPreviewDuration, this.Duration); } #endregion #region Event Handlers /// /// Handle Encode Progress Events /// /// /// The sender. /// /// /// The EncodeProgressEventArgs. /// private void encodeService_EncodeStatusChanged(object sender, EncodeProgressEventArgs e) { this.Percentage = string.Format("{0} %", Math.Round(e.PercentComplete, 2).ToString(CultureInfo.InvariantCulture)); this.PercentageValue = e.PercentComplete; } /// /// Handle the Encode Completed Event /// /// /// The sender. /// /// /// The EncodeCompletedEventArgs. /// private void encodeService_EncodeCompleted(object sender, EncodeCompletedEventArgs e) { this.Percentage = "0.00%"; this.PercentageValue = 0; this.IsEncoding = false; this.encodeService.EncodeCompleted -= this.encodeService_EncodeCompleted; this.encodeService.EncodeStatusChanged -= this.encodeService_EncodeStatusChanged; this.PlayFile(); } #endregion } }