/// <summary> /// Replace arguments with the given job information. /// </summary> /// <param name="nameFormat">The name format to use.</param> /// <param name="picker">The picker.</param> /// <param name="jobViewModel">The job to pick information from.</param> /// <returns>The string with arguments replaced.</returns> public string ReplaceArguments(string nameFormat, Picker picker, EncodeJobViewModel jobViewModel) { // The jobViewModel might have null VideoSource and VideoSourceMetadata from an earlier version < 4.17. VCJob job = jobViewModel.Job; SourceTitle title = jobViewModel.VideoSource?.Titles.Single(t => t.Index == job.Title); string sourceName = jobViewModel.VideoSourceMetadata != null ? jobViewModel.VideoSourceMetadata.Name : string.Empty; TimeSpan titleDuration = title?.Duration.ToSpan() ?? TimeSpan.Zero; int chapterCount = title?.ChapterList.Count ?? 0; bool hasMultipleTitles = jobViewModel.VideoSource != null && jobViewModel.VideoSource.Titles.Count > 1; return(this.ReplaceArguments( job.SourcePath, sourceName, job.Title, titleDuration, job.RangeType, job.ChapterStart, job.ChapterEnd, chapterCount, TimeSpan.FromSeconds(job.SecondsStart), TimeSpan.FromSeconds(job.SecondsEnd), job.FramesStart, job.FramesEnd, nameFormat, hasMultipleTitles, picker)); }
public Main() { Ioc.Container.RegisterSingleton <Main>(() => this); this.InitializeComponent(); this.sourceRow.Height = new GridLength(Config.SourcePaneHeightStar, GridUnitType.Star); this.queueRow.Height = new GridLength(Config.QueuePaneHeightStar, GridUnitType.Star); this.Activated += (sender, args) => { DispatchUtilities.BeginInvoke(async() => { // Need to yield here for some reason, otherwise the activation is blocked. await Task.Yield(); this.toastNotificationService.Clear(); }); }; this.notifyIcon = new NotifyIcon { Visible = false }; this.notifyIcon.Click += (sender, args) => { this.RestoreWindow(); }; this.notifyIcon.DoubleClick += (sender, args) => { this.RestoreWindow(); }; StreamResourceInfo streamResourceInfo = System.Windows.Application.GetResourceStream(new Uri("pack://application:,,,/VidCoder_icon.ico")); if (streamResourceInfo != null) { Stream iconStream = streamResourceInfo.Stream; this.notifyIcon.Icon = new Icon(iconStream); } this.RefreshQueueColumns(); this.LoadCompletedColumnWidths(); #if DEBUG var debugDropDown = new DropDownButton { Header = "Debug" }; var loadScanFromJsonItem = new Fluent.MenuItem { Header = "Load scan from JSON..." }; loadScanFromJsonItem.Click += (sender, args) => { DebugJsonDialog dialog = new DebugJsonDialog("Debug Scan JSON"); dialog.ShowDialog(); if (!string.IsNullOrWhiteSpace(dialog.Json)) { try { var scanObject = JsonConvert.DeserializeObject <JsonScanObject>(dialog.Json); this.viewModel.UpdateFromNewVideoSource(new VideoSource { Titles = scanObject.TitleList, FeatureTitle = scanObject.MainFeature }); } catch (Exception exception) { MessageBox.Show(this, "Could not parse scan JSON:" + Environment.NewLine + Environment.NewLine + exception.ToString()); } } }; debugDropDown.Items.Add(loadScanFromJsonItem); var queueFromJsonItem = new Fluent.MenuItem { Header = "Queue job from JSON..." }; queueFromJsonItem.Click += (sender, args) => { if (!this.viewModel.HasVideoSource) { StaticResolver.Resolve <IMessageBoxService>().Show("Must open source before adding queue job from JSON"); return; } EncodeJobViewModel jobViewModel = this.viewModel.CreateEncodeJobVM(); DebugJsonDialog dialog = new DebugJsonDialog("Debug Encode JSON"); dialog.ShowDialog(); if (!string.IsNullOrWhiteSpace(dialog.Json)) { try { JsonEncodeObject encodeObject = JsonConvert.DeserializeObject <JsonEncodeObject>(dialog.Json); jobViewModel.DebugEncodeJsonOverride = dialog.Json; jobViewModel.Job.FinalOutputPath = encodeObject.Destination.File; jobViewModel.Job.SourcePath = encodeObject.Source.Path; this.processingService.Queue(jobViewModel); } catch (Exception exception) { MessageBox.Show(this, "Could not parse encode JSON:" + Environment.NewLine + Environment.NewLine + exception.ToString()); } } }; debugDropDown.Items.Add(queueFromJsonItem); var throwExceptionItem = new Fluent.MenuItem { Header = "Throw exception" }; throwExceptionItem.Click += (sender, args) => { throw new InvalidOperationException("Rats."); }; debugDropDown.Items.Add(throwExceptionItem); var addLogItem = new Fluent.MenuItem { Header = "Add 1 log item" }; addLogItem.Click += (sender, args) => { StaticResolver.Resolve <IAppLogger>().Log("This is a log item"); }; debugDropDown.Items.Add(addLogItem); var addTenLogItems = new Fluent.MenuItem { Header = "Add 10 log items" }; addTenLogItems.Click += (sender, args) => { for (int i = 0; i < 10; i++) { StaticResolver.Resolve <IAppLogger>().Log("This is a log item"); } }; debugDropDown.Items.Add(addTenLogItems); var addLongLogItem = new Fluent.MenuItem { Header = "Add long log item" }; addLongLogItem.Click += (sender, args) => { StaticResolver.Resolve <IAppLogger>().Log("This is a log item\r\nthat is split into multiple lines\r\nOh yes indeed"); }; debugDropDown.Items.Add(addLongLogItem); var doAnActionItem = new Fluent.MenuItem { Header = "Perform action" }; doAnActionItem.Click += (sender, args) => { var app = (App)System.Windows.Application.Current; app.ChangeTheme(new Uri("/Themes/Dark.xaml", UriKind.Relative)); }; debugDropDown.Items.Add(doAnActionItem); this.toolsRibbonGroupBox.Items.Add(debugDropDown); #endif this.DataContextChanged += this.OnDataContextChanged; TheDispatcher = this.Dispatcher; this.statusText.Opacity = 0.0; NameScope.SetNameScope(this, new NameScope()); this.RegisterName("StatusText", this.statusText); var storyboard = (Storyboard)this.FindResource("StatusTextStoryboard"); storyboard.Completed += (sender, args) => { this.statusText.Visibility = Visibility.Collapsed; }; this.presetTreeViewContainer.PresetTreeView.OnHierarchyMouseUp += (sender, args) => { this.presetButton.IsDropDownOpen = false; }; this.presetButton.DropDownOpened += (sender, args) => { var item = UIUtilities.FindDescendant <TreeViewItem>(this.presetTreeViewContainer.PresetTreeView, viewItem => { return(viewItem.Header == this.viewModel.PresetsService.SelectedPreset); }); if (item != null) { UIUtilities.BringIntoView(item); } }; this.Loaded += (e, o) => { this.RestoredWindowState = this.WindowState; }; this.statusService.MessageShown += (o, e) => { this.ShowStatusMessage(e.Value); }; this.queueView.SelectionChanged += this.QueueView_SelectionChanged; }
public Main() { Ioc.Container.RegisterInstance(typeof(Main), this, new ContainerControlledLifetimeManager()); this.InitializeComponent(); this.RefreshQueueColumns(); this.LoadCompletedColumnWidths(); if (CommonUtilities.DebugMode) { MenuItem queueFromJsonItem = new MenuItem { Header = "Queue job from JSON..." }; queueFromJsonItem.Click += (sender, args) => { EncodeJobViewModel jobViewModel = this.viewModel.CreateEncodeJobVM(); DebugEncodeJsonDialog dialog = new DebugEncodeJsonDialog(); dialog.ShowDialog(); if (!string.IsNullOrWhiteSpace(dialog.EncodeJson)) { try { JsonEncodeObject encodeObject = JsonConvert.DeserializeObject <JsonEncodeObject>(dialog.EncodeJson); jobViewModel.DebugEncodeJsonOverride = dialog.EncodeJson; jobViewModel.Job.OutputPath = encodeObject.Destination.File; jobViewModel.Job.SourcePath = encodeObject.Source.Path; this.processingService.Queue(jobViewModel); } catch (Exception exception) { MessageBox.Show(this, "Could not parse encode JSON:" + Environment.NewLine + Environment.NewLine + exception.ToString()); } } }; this.toolsMenu.Items.Add(new Separator()); this.toolsMenu.Items.Add(queueFromJsonItem); } this.DataContextChanged += this.OnDataContextChanged; TheDispatcher = this.Dispatcher; this.presetGlowEffect.Opacity = 0.0; this.pickerGlowEffect.Opacity = 0.0; this.statusText.Opacity = 0.0; NameScope.SetNameScope(this, new NameScope()); this.RegisterName("PresetGlowEffect", this.presetGlowEffect); this.RegisterName("PickerGlowEffect", this.pickerGlowEffect); this.RegisterName("StatusText", this.statusText); var storyboard = (Storyboard)this.FindResource("statusTextStoryboard"); storyboard.Completed += (sender, args) => { this.statusText.Visibility = Visibility.Collapsed; }; var presetGlowFadeUp = new DoubleAnimation { From = 0.0, To = 1.0, Duration = new Duration(TimeSpan.FromSeconds(0.1)) }; var presetGlowFadeDown = new DoubleAnimation { From = 1.0, To = 0.0, BeginTime = TimeSpan.FromSeconds(0.1), Duration = new Duration(TimeSpan.FromSeconds(1.6)) }; this.presetGlowStoryboard = new Storyboard(); this.presetGlowStoryboard.Children.Add(presetGlowFadeUp); this.presetGlowStoryboard.Children.Add(presetGlowFadeDown); Storyboard.SetTargetName(presetGlowFadeUp, "PresetGlowEffect"); Storyboard.SetTargetProperty(presetGlowFadeUp, new PropertyPath("Opacity")); Storyboard.SetTargetName(presetGlowFadeDown, "PresetGlowEffect"); Storyboard.SetTargetProperty(presetGlowFadeDown, new PropertyPath("Opacity")); var pickerGlowFadeUp = new DoubleAnimation { From = 0.0, To = 1.0, Duration = new Duration(TimeSpan.FromSeconds(0.1)) }; var pickerGlowFadeDown = new DoubleAnimation { From = 1.0, To = 0.0, BeginTime = TimeSpan.FromSeconds(0.1), Duration = new Duration(TimeSpan.FromSeconds(1.6)) }; this.pickerGlowStoryboard = new Storyboard(); this.pickerGlowStoryboard.Children.Add(pickerGlowFadeUp); this.pickerGlowStoryboard.Children.Add(pickerGlowFadeDown); Storyboard.SetTargetName(pickerGlowFadeUp, "PickerGlowEffect"); Storyboard.SetTargetProperty(pickerGlowFadeUp, new PropertyPath("Opacity")); Storyboard.SetTargetName(pickerGlowFadeDown, "PickerGlowEffect"); Storyboard.SetTargetProperty(pickerGlowFadeDown, new PropertyPath("Opacity")); this.Loaded += (e, o) => { this.RestoredWindowState = this.WindowState; }; this.statusService.MessageShown += (o, e) => { this.ShowStatusMessage(e.Value); }; }
/// <summary> /// Adds the given source to the encode queue. /// </summary> /// <param name="source">The path to the source file to encode.</param> /// <param name="destination">The destination path for the encoded file.</param> /// <param name="presetName">The name of the preset to use to encode.</param> /// <returns>True if the item was successfully queued for processing.</returns> public void Process(string source, string destination, string presetName) { if (string.IsNullOrWhiteSpace(source)) { throw new ArgumentException("source cannot be null or empty."); } if (string.IsNullOrWhiteSpace(destination) && !this.EnsureDefaultOutputFolderSet()) { throw new ArgumentException("If destination is not set, the default output folder must be set."); } if (destination != null && !Utilities.IsValidFullPath(destination)) { throw new ArgumentException("Destination path is not valid: " + destination); } VCProfile profile = this.presetsViewModel.GetProfileByName(presetName); if (profile == null) { throw new ArgumentException("Cannot find preset: " + presetName); } var jobVM = new EncodeJobViewModel(new VCJob { SourcePath = source, SourceType = Utilities.GetSourceType(source), Title = 1, RangeType = VideoRangeType.All, EncodingProfile = profile, ChosenAudioTracks = new List<int> { 1 }, OutputPath = destination, UseDefaultChapterNames = true }); jobVM.PresetName = presetName; jobVM.ManualOutputPath = !string.IsNullOrWhiteSpace(destination); var scanMultipleDialog = new ScanMultipleDialogViewModel(new List<EncodeJobViewModel>{ jobVM }); WindowManager.OpenDialog(scanMultipleDialog, this.main); VCJob job = jobVM.Job; Title title = jobVM.HandBrakeInstance.Titles.SingleOrDefault(t => t.TitleNumber == job.Title); if (title == null) { title = jobVM.HandBrakeInstance.Titles[0]; } // Choose the correct audio/subtitle tracks based on settings this.AutoPickAudio(job, title); this.AutoPickSubtitles(job, title); // Now that we have the title and subtitles we can determine the final output file name if (string.IsNullOrWhiteSpace(destination)) { // Exclude all current queued files if overwrite is disabled HashSet<string> excludedPaths; if (CustomConfig.WhenFileExistsBatch == WhenFileExists.AutoRename) { excludedPaths = this.GetQueuedFiles(); } else { excludedPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase); } string pathToQueue = job.SourcePath; excludedPaths.Add(pathToQueue); string outputFolder = this.outputVM.GetOutputFolder(pathToQueue); string outputFileName = this.outputVM.BuildOutputFileName(pathToQueue, Utilities.GetSourceName(pathToQueue), job.Title, title.Duration, title.Chapters.Count, usesScan: false); string outputExtension = this.outputVM.GetOutputExtension(); string queueOutputPath = Path.Combine(outputFolder, outputFileName + outputExtension); queueOutputPath = this.outputVM.ResolveOutputPathConflicts(queueOutputPath, excludedPaths, isBatch: true); job.OutputPath = queueOutputPath; } this.Queue(jobVM); if (!this.Encoding) { this.StartEncodeQueue(); } }
public void RemoveQueueJob(EncodeJobViewModel job) { this.EncodeQueue.Remove(job); if (this.Encoding) { this.totalTasks--; this.totalQueueCost -= job.Cost; if (this.totalTasks == 1) { this.EncodeQueue[0].IsOnlyItem = true; } } this.RaisePropertyChanged(() => this.QueuedTabHeader); }
// Queues a list of files or video folders. public void QueueMultiple(IEnumerable<SourcePath> sourcePaths) { if (!this.EnsureDefaultOutputFolderSet()) { return; } // Exclude all current queued files if overwrite is disabled HashSet<string> excludedPaths; if (CustomConfig.WhenFileExistsBatch == WhenFileExists.AutoRename) { excludedPaths = this.GetQueuedFiles(); } else { excludedPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase); } var itemsToQueue = new List<EncodeJobViewModel>(); foreach (SourcePath sourcePath in sourcePaths) { var job = new VCJob { SourcePath = sourcePath.Path, EncodingProfile = this.presetsViewModel.SelectedPreset.Preset.EncodingProfile.Clone(), Title = 1, RangeType = VideoRangeType.All, UseDefaultChapterNames = true }; if (sourcePath.SourceType == SourceType.None) { if (Directory.Exists(sourcePath.Path)) { job.SourceType = SourceType.VideoFolder; } else if (File.Exists(sourcePath.Path)) { job.SourceType = SourceType.File; } } else { job.SourceType = sourcePath.SourceType; } if (job.SourceType != SourceType.None) { var jobVM = new EncodeJobViewModel(job); jobVM.SourceParentFolder = sourcePath.ParentFolder; jobVM.ManualOutputPath = false; jobVM.PresetName = this.presetsViewModel.SelectedPreset.DisplayName; itemsToQueue.Add(jobVM); } } // This dialog will scan the items in the list, calculating length. var scanMultipleDialog = new ScanMultipleDialogViewModel(itemsToQueue); WindowManager.OpenDialog(scanMultipleDialog, this.main); var failedFiles = new List<string>(); foreach (EncodeJobViewModel jobVM in itemsToQueue) { // Skip over any cancelled jobs if (jobVM.HandBrakeInstance == null) { continue; } // Only queue items with a successful scan if (jobVM.HandBrakeInstance.Titles.Count > 0) { VCJob job = jobVM.Job; Title title = jobVM.HandBrakeInstance.Titles.SingleOrDefault(t => t.TitleNumber == job.Title); if (title == null) { title = jobVM.HandBrakeInstance.Titles[0]; } // Choose the correct audio/subtitle tracks based on settings this.AutoPickAudio(job, title); this.AutoPickSubtitles(job, title); // Now that we have the title and subtitles we can determine the final output file name string fileToQueue = job.SourcePath; excludedPaths.Add(fileToQueue); string outputFolder = this.outputVM.GetOutputFolder(fileToQueue, jobVM.SourceParentFolder); string outputFileName = this.outputVM.BuildOutputFileName(fileToQueue, Utilities.GetSourceNameFile(fileToQueue), job.Title, title.Duration, title.Chapters.Count, usesScan: false); string outputExtension = this.outputVM.GetOutputExtension(); string queueOutputPath = Path.Combine(outputFolder, outputFileName + outputExtension); queueOutputPath = this.outputVM.ResolveOutputPathConflicts(queueOutputPath, excludedPaths, isBatch: true); job.OutputPath = queueOutputPath; excludedPaths.Add(queueOutputPath); this.Queue(jobVM); } else { failedFiles.Add(jobVM.Job.SourcePath); } } if (failedFiles.Count > 0) { Utilities.MessageBox.Show( string.Format(MainRes.QueueMultipleScanErrorMessage, string.Join(Environment.NewLine, failedFiles)), MainRes.QueueMultipleScanErrorTitle, MessageBoxButton.OK, MessageBoxImage.Warning); } }
/// <summary> /// Queues the given Job. Assumed that the job has an associated HandBrake instance and populated Length. /// </summary> /// <param name="encodeJobVM">The job to add.</param> public void Queue(EncodeJobViewModel encodeJobVM) { if (this.Encoding) { if (this.totalTasks == 1) { this.EncodeQueue[0].IsOnlyItem = false; } this.totalTasks++; this.totalQueueCost += encodeJobVM.Cost; } this.EncodeQueue.Add(encodeJobVM); this.profileEditedSinceLastQueue = false; this.RaisePropertyChanged(() => this.QueuedTabHeader); // Select the Queued tab. if (this.SelectedTabIndex != QueuedTabIndex) { this.SelectedTabIndex = QueuedTabIndex; } }