diff options
author | Scott <[email protected]> | 2020-04-29 19:06:11 +0100 |
---|---|---|
committer | GitHub <[email protected]> | 2020-04-29 19:06:11 +0100 |
commit | 91051b41df7f9e6da68d14c9e806968df61ef050 (patch) | |
tree | 90293ad067e14e9eff409ed7bf5d105df3697a45 /win/CS | |
parent | 565dae9f71330b87c5e7898a469052446c4592f0 (diff) |
WinGui: Enable multi-instance support. (#2797)
Diffstat (limited to 'win/CS')
25 files changed, 226 insertions, 196 deletions
diff --git a/win/CS/HandBrake.Interop/Interop/HandBrakeInstance.cs b/win/CS/HandBrake.Interop/Interop/HandBrakeInstance.cs index a5027f72f..5d4dd98ac 100644 --- a/win/CS/HandBrake.Interop/Interop/HandBrakeInstance.cs +++ b/win/CS/HandBrake.Interop/Interop/HandBrakeInstance.cs @@ -13,6 +13,7 @@ namespace HandBrake.Interop.Interop using System.Collections.Generic; using System.Diagnostics; using System.Linq; + using System.Runtime.CompilerServices; using System.Runtime.ExceptionServices; using System.Runtime.InteropServices; using System.Timers; @@ -73,10 +74,6 @@ namespace HandBrake.Interop.Interop /// </summary> public event EventHandler<EncodeCompletedEventArgs> EncodeCompleted; - /// <summary> - /// Gets the handle. - /// </summary> - internal IntPtr Handle { get; private set; } /// <summary> /// Gets the number of previews created during scan. @@ -108,6 +105,13 @@ namespace HandBrake.Interop.Interop /// </summary> public int Build => hbFunctions.hb_get_build(this.Handle); + public bool IsRemoteInstance => false; + + /// <summary> + /// Gets the handle. + /// </summary> + internal IntPtr Handle { get; private set; } + /// <summary> /// Initializes this instance. /// </summary> diff --git a/win/CS/HandBrake.Interop/Interop/Interfaces/IEncodeInstance.cs b/win/CS/HandBrake.Interop/Interop/Interfaces/IEncodeInstance.cs index 5a0957cb9..e7a52fbfa 100644 --- a/win/CS/HandBrake.Interop/Interop/Interfaces/IEncodeInstance.cs +++ b/win/CS/HandBrake.Interop/Interop/Interfaces/IEncodeInstance.cs @@ -27,6 +27,8 @@ namespace HandBrake.Interop.Interop.Interfaces /// </summary> event EventHandler<EncodeProgressEventArgs> EncodeProgress; + bool IsRemoteInstance { get; } + /// <summary> /// Initializes this instance. /// </summary> diff --git a/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs b/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs index a343a1afd..51ac11458 100644 --- a/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs +++ b/win/CS/HandBrakeWPF/Instance/HandBrakeInstanceManager.cs @@ -44,12 +44,6 @@ namespace HandBrakeWPF.Instance throw new Exception("Please call Init before Using!"); } - if (encodeInstance != null) - { - encodeInstance.Dispose(); - encodeInstance = null; - } - IEncodeInstance newInstance; if (userSettingService.GetUserSetting<bool>(UserSettingConstants.ProcessIsolationEnabled) && Portable.IsProcessIsolationEnabled()) @@ -58,16 +52,19 @@ namespace HandBrakeWPF.Instance } else { + if (encodeInstance != null && !encodeInstance.IsRemoteInstance) + { + encodeInstance.Dispose(); + encodeInstance = null; + } + newInstance = new HandBrakeInstance(); + HandBrakeUtils.SetDvdNav(!userSettingService.GetUserSetting<bool>(UserSettingConstants.DisableLibDvdNav)); + encodeInstance = newInstance; } newInstance.Initialize(verbosity, noHardware); - - encodeInstance = newInstance; - - HandBrakeUtils.SetDvdNav(!userSettingService.GetUserSetting<bool>(UserSettingConstants.DisableLibDvdNav)); - - return encodeInstance; + return newInstance; } /// <summary> diff --git a/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs b/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs index c2bae9c85..97abf671b 100644 --- a/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs +++ b/win/CS/HandBrakeWPF/Instance/RemoteInstance.cs @@ -31,6 +31,8 @@ namespace HandBrakeWPF.Instance using HandBrake.Worker.Routing.Commands; using HandBrakeWPF.Instance.Model; + using HandBrakeWPF.Model.Options; + using HandBrakeWPF.Services; using HandBrakeWPF.Services.Interfaces; using HandBrakeWPF.Services.Logging.Interfaces; using HandBrakeWPF.Utilities; @@ -62,6 +64,8 @@ namespace HandBrakeWPF.Instance public event EventHandler<EncodeProgressEventArgs> EncodeProgress; + public bool IsRemoteInstance => true; + public async void PauseEncode() { await this.MakeHttpGetRequest("PauseEncode"); @@ -74,13 +78,13 @@ namespace HandBrakeWPF.Instance this.MonitorEncodeProgress(); } - public async void StartEncode(JsonEncodeObject jobToStart) + public void StartEncode(JsonEncodeObject jobToStart) { InitCommand initCommand = new InitCommand { EnableDiskLogging = false, AllowDisconnectedWorker = false, - DisableLibDvdNav = this.userSettingService.GetUserSetting<bool>(UserSettingConstants.DisableLibDvdNav), + DisableLibDvdNav = !this.userSettingService.GetUserSetting<bool>(UserSettingConstants.DisableLibDvdNav), EnableHardwareAcceleration = true, LogDirectory = DirectoryUtilities.GetLogDirectory(), LogVerbosity = this.userSettingService.GetUserSetting<int>(UserSettingConstants.Verbosity) @@ -91,7 +95,8 @@ namespace HandBrakeWPF.Instance JsonSerializerSettings settings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }; string job = JsonConvert.SerializeObject(new EncodeCommand { InitialiseCommand = initCommand, EncodeJob = jobToStart }, Formatting.None, settings); - await this.MakeHttpJsonPostRequest("StartEncode", job); + var task = Task.Run(async () => await this.MakeHttpJsonPostRequest("StartEncode", job)); + task.Wait(); this.MonitorEncodeProgress(); } @@ -119,24 +124,14 @@ namespace HandBrakeWPF.Instance public void Initialize(int verbosityLvl, bool noHardwareMode) { - this.StartServer(); - } - - public void Dispose() - { - this.workerProcess?.Dispose(); - } - - private async void StartServer() - { if (this.workerProcess == null || this.workerProcess.HasExited) { var plainTextBytes = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()); this.base64Token = Convert.ToBase64String(plainTextBytes); workerProcess = new Process - { - StartInfo = + { + StartInfo = { FileName = "HandBrake.Worker.exe", Arguments = string.Format(" --port={0} --token={1}", port, this.base64Token), @@ -145,20 +140,44 @@ namespace HandBrakeWPF.Instance RedirectStandardError = true, CreateNoWindow = true } - }; + }; workerProcess.Exited += this.WorkerProcess_Exited; workerProcess.OutputDataReceived += this.WorkerProcess_OutputDataReceived; workerProcess.ErrorDataReceived += this.WorkerProcess_OutputDataReceived; - + workerProcess.Start(); workerProcess.BeginOutputReadLine(); workerProcess.BeginErrorReadLine(); + // Set Process Priority + switch ((ProcessPriority)this.userSettingService.GetUserSetting<int>(UserSettingConstants.ProcessPriorityInt)) + { + case ProcessPriority.High: + workerProcess.PriorityClass = ProcessPriorityClass.High; + break; + case ProcessPriority.AboveNormal: + workerProcess.PriorityClass = ProcessPriorityClass.AboveNormal; + break; + case ProcessPriority.Normal: + workerProcess.PriorityClass = ProcessPriorityClass.Normal; + break; + case ProcessPriority.Low: + workerProcess.PriorityClass = ProcessPriorityClass.Idle; + break; + default: + workerProcess.PriorityClass = ProcessPriorityClass.BelowNormal; + break; + } this.logService.LogMessage(string.Format("Worker Process started with Process ID: {0} and port: {1}", this.workerProcess.Id, port)); } } + public void Dispose() + { + this.workerProcess?.Dispose(); + } + private void WorkerProcess_OutputDataReceived(object sender, DataReceivedEventArgs e) { this.logService.LogMessage(e.Data); @@ -213,7 +232,10 @@ namespace HandBrakeWPF.Instance this.encodePollTimer?.Stop(); - this.workerProcess?.Kill(); + if (this.workerProcess != null && !this.workerProcess.HasExited) + { + this.workerProcess?.Kill(); + } return; } @@ -259,7 +281,7 @@ namespace HandBrakeWPF.Instance else if (taskState != null && taskState == TaskState.WorkDone) { this.encodePollTimer.Stop(); - if (!this.workerProcess.HasExited) + if (this.workerProcess != null && !this.workerProcess.HasExited) { this.workerProcess?.Kill(); } diff --git a/win/CS/HandBrakeWPF/Properties/Resources.Designer.cs b/win/CS/HandBrakeWPF/Properties/Resources.Designer.cs index 00d0044cd..876e5f43a 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.Designer.cs +++ b/win/CS/HandBrakeWPF/Properties/Resources.Designer.cs @@ -4916,15 +4916,6 @@ namespace HandBrakeWPF.Properties { } /// <summary> - /// Looks up a localized string similar to The Queue has been paused. The currently running job will run to completion and no further jobs will start.. - /// </summary> - public static string QueueViewModel_QueuePauseNotice { - get { - return ResourceManager.GetString("QueueViewModel_QueuePauseNotice", resourceCulture); - } - } - - /// <summary> /// Looks up a localized string similar to Queue Paused. /// </summary> public static string QueueViewModel_QueuePending { @@ -5250,6 +5241,15 @@ namespace HandBrakeWPF.Properties { } /// <summary> + /// Looks up a localized string similar to Cancel. + /// </summary> + public static string StaticPreviewView_CancelPreview { + get { + return ResourceManager.GetString("StaticPreviewView_CancelPreview", resourceCulture); + } + } + + /// <summary> /// Looks up a localized string similar to Duration:. /// </summary> public static string StaticPreviewView_Duration { diff --git a/win/CS/HandBrakeWPF/Properties/Resources.de.resx b/win/CS/HandBrakeWPF/Properties/Resources.de.resx index 69c9f01ff..a3f22724c 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.de.resx +++ b/win/CS/HandBrakeWPF/Properties/Resources.de.resx @@ -501,9 +501,6 @@ Bitte die Webseite auf Versionshinweise prüfen.</value> <data name="QueueViewModel_QueuePending" xml:space="preserve"> <value>Warteschlange angehalten</value> </data> - <data name="QueueViewModel_QueuePauseNotice" xml:space="preserve"> - <value>Die Warteschlange wurde angehalten. Die aktuelle Aufgabe wird noch fertig gestellt und danach keine weiteren Aufgaben gestartet.</value> - </data> <data name="QueueViewModel_DelSelectedJobConfirmation" xml:space="preserve"> <value>Sollen die ausgewählten Aufgaben wirklich gelöscht werden?</value> </data> diff --git a/win/CS/HandBrakeWPF/Properties/Resources.es.resx b/win/CS/HandBrakeWPF/Properties/Resources.es.resx index 8ad365676..eb0befdef 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.es.resx +++ b/win/CS/HandBrakeWPF/Properties/Resources.es.resx @@ -497,9 +497,6 @@ Puede encontrar más información en el registro de actividad.</value> <data name="QueueViewModel_QueuePending" xml:space="preserve"> <value>Cola pausada</value> </data> - <data name="QueueViewModel_QueuePauseNotice" xml:space="preserve"> - <value>La cola ha sido pausada. El trabajo activo terminará pero no se iniciaran nuevos.</value> - </data> <data name="QueueViewModel_DelSelectedJobConfirmation" xml:space="preserve"> <value>¿Está seguro que desea borrar los trabajos seleccionados?</value> </data> diff --git a/win/CS/HandBrakeWPF/Properties/Resources.fr.resx b/win/CS/HandBrakeWPF/Properties/Resources.fr.resx index 74d1af845..da93b5d98 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.fr.resx +++ b/win/CS/HandBrakeWPF/Properties/Resources.fr.resx @@ -498,9 +498,6 @@ Veuillez consulter le site Web pour les notes de version.</value> <data name="QueueViewModel_QueuePending" xml:space="preserve"> <value>File mise en pause</value> </data> - <data name="QueueViewModel_QueuePauseNotice" xml:space="preserve"> - <value>La file a été mise en pause. Le travail en cours sera exécuté en totalité et aucun autre travail ne commencera.</value> - </data> <data name="QueueViewModel_DelSelectedJobConfirmation" xml:space="preserve"> <value>Êtes-vous sûr de vouloir supprimer les travaux sélectionnés ?</value> </data> diff --git a/win/CS/HandBrakeWPF/Properties/Resources.ja.resx b/win/CS/HandBrakeWPF/Properties/Resources.ja.resx index d42b49f19..9566dbc84 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.ja.resx +++ b/win/CS/HandBrakeWPF/Properties/Resources.ja.resx @@ -497,9 +497,6 @@ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 021 <data name="QueueViewModel_QueuePending" xml:space="preserve"> <value>キュー一時停止</value> </data> - <data name="QueueViewModel_QueuePauseNotice" xml:space="preserve"> - <value>キューが一時停止されました。現在のジョブは完了まで実行され、それ以降のジョブは開始しません。</value> - </data> <data name="QueueViewModel_DelSelectedJobConfirmation" xml:space="preserve"> <value>選択したジョブを本当に削除しますか?</value> </data> diff --git a/win/CS/HandBrakeWPF/Properties/Resources.ko.resx b/win/CS/HandBrakeWPF/Properties/Resources.ko.resx index 977dbcb45..5704eeebd 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.ko.resx +++ b/win/CS/HandBrakeWPF/Properties/Resources.ko.resx @@ -497,9 +497,6 @@ Activity log에 추가 정보가 있습니다.</value> <data name="QueueViewModel_QueuePending" xml:space="preserve"> <value>대기열 일시 중지</value> </data> - <data name="QueueViewModel_QueuePauseNotice" xml:space="preserve"> - <value>대기열이 일시 중지되었습니다. 현재 실행 중인 작업은 완료될 때까지 실행되며 추가 작업은 실행되지 않습니다.</value> - </data> <data name="QueueViewModel_DelSelectedJobConfirmation" xml:space="preserve"> <value>선택된 작업을 삭제하시겠습니까?</value> </data> diff --git a/win/CS/HandBrakeWPF/Properties/Resources.resx b/win/CS/HandBrakeWPF/Properties/Resources.resx index 7ba7be44a..de06cc56c 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.resx +++ b/win/CS/HandBrakeWPF/Properties/Resources.resx @@ -498,9 +498,6 @@ The Activity log may have further information.</value> <data name="QueueViewModel_QueuePending" xml:space="preserve">
<value>Queue Paused</value>
</data>
- <data name="QueueViewModel_QueuePauseNotice" xml:space="preserve">
- <value>The Queue has been paused. The currently running job will run to completion and no further jobs will start.</value>
- </data>
<data name="QueueViewModel_DelSelectedJobConfirmation" xml:space="preserve">
<value>Are you sure you want to delete the selected jobs?</value>
</data>
@@ -2229,4 +2226,7 @@ Please choose a different preset.</value> <data name="OptionsView_SimultaneousEncodes" xml:space="preserve">
<value>Number of simultaneous encodes:</value>
</data>
+ <data name="StaticPreviewView_CancelPreview" xml:space="preserve">
+ <value>Cancel</value>
+ </data>
</root>
\ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Properties/Resources.ru.resx b/win/CS/HandBrakeWPF/Properties/Resources.ru.resx index eaa4d4317..f1f709888 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.ru.resx +++ b/win/CS/HandBrakeWPF/Properties/Resources.ru.resx @@ -500,9 +500,6 @@ Foreign Audio Preferred, else First - Если существует дорожк <data name="QueueViewModel_QueuePending" xml:space="preserve"> <value>Очередь приостановлена</value> </data> - <data name="QueueViewModel_QueuePauseNotice" xml:space="preserve"> - <value>Очередь была приостановлена. Текущее задание будет выполнено, а будущие - не начнутся.</value> - </data> <data name="QueueViewModel_DelSelectedJobConfirmation" xml:space="preserve"> <value>Вы уверены, что хотите удалить выбранные задания?</value> </data> diff --git a/win/CS/HandBrakeWPF/Properties/Resources.tr.resx b/win/CS/HandBrakeWPF/Properties/Resources.tr.resx index 42757b74b..0102da37f 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.tr.resx +++ b/win/CS/HandBrakeWPF/Properties/Resources.tr.resx @@ -500,9 +500,6 @@ Faaliyet günlüğü daha fazla bilgi içerebilir.</value> <data name="QueueViewModel_QueuePending" xml:space="preserve"> <value>Sıra Duraklatıldı</value> </data> - <data name="QueueViewModel_QueuePauseNotice" xml:space="preserve"> - <value>Sıra duraklatıldı. Halen çalışmakta olan iş tamamlanmaya devam eder ve başka iş başlatılmaz.</value> - </data> <data name="QueueViewModel_DelSelectedJobConfirmation" xml:space="preserve"> <value>Seçilen işleri silmek istediğinizden emin misiniz?</value> </data> diff --git a/win/CS/HandBrakeWPF/Properties/Resources.zh.resx b/win/CS/HandBrakeWPF/Properties/Resources.zh.resx index 189616dbe..213ff6e0d 100644 --- a/win/CS/HandBrakeWPF/Properties/Resources.zh.resx +++ b/win/CS/HandBrakeWPF/Properties/Resources.zh.resx @@ -493,9 +493,6 @@ Foreign Audio Preferred, else First - 如果存在外语轨道,则会将其烧 <data name="QueueViewModel_QueuePending" xml:space="preserve"> <value>列队已暂停</value> </data> - <data name="QueueViewModel_QueuePauseNotice" xml:space="preserve"> - <value>队列已暂停。当前正在运行的作业将运行完成,不会再启动其他作业。</value> - </data> <data name="QueueViewModel_DelSelectedJobConfirmation" xml:space="preserve"> <value>您确定要删除所选作业吗?</value> </data> diff --git a/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs b/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs index e6d8cb7c0..fdd2a01e5 100644 --- a/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs +++ b/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs @@ -40,6 +40,7 @@ namespace HandBrakeWPF.Services.Encode private readonly IUserSettingService userSettingService; private readonly ILogInstanceManager logInstanceManager; private readonly IHbFunctionsProvider hbFunctionsProvider; + private readonly object portLock = new object(); private IEncodeInstance instance; private DateTime startTime; private EncodeTask currentTask; @@ -107,19 +108,24 @@ namespace HandBrakeWPF.Services.Encode } int verbosity = this.userSettingService.GetUserSetting<int>(UserSettingConstants.Verbosity); - this.instance = task.IsPreviewEncode ? HandBrakeInstanceManager.GetPreviewInstance(verbosity, this.userSettingService) : HandBrakeInstanceManager.GetEncodeInstance(verbosity, configuration, this.encodeLogService, userSettingService); - - this.instance.EncodeCompleted += this.InstanceEncodeCompleted; - this.instance.EncodeProgress += this.InstanceEncodeProgress; - this.IsEncoding = true; - this.isPreviewInstance = task.IsPreviewEncode; + // Prevent port stealing if multiple jobs start at the same time. + lock (portLock) + { + this.instance = task.IsPreviewEncode ? HandBrakeInstanceManager.GetPreviewInstance(verbosity, this.userSettingService) : HandBrakeInstanceManager.GetEncodeInstance(verbosity, configuration, this.encodeLogService, userSettingService); + + this.instance.EncodeCompleted += this.InstanceEncodeCompleted; + this.instance.EncodeProgress += this.InstanceEncodeProgress; - // Verify the Destination Path Exists, and if not, create it. - this.VerifyEncodeDestinationPath(task); + this.IsEncoding = true; + this.isPreviewInstance = task.IsPreviewEncode; - // Get an EncodeJob object for the Interop Library - this.instance.StartEncode(EncodeTaskFactory.Create(task, configuration, hbFunctionsProvider.GetHbFunctionsWrapper())); + // Verify the Destination Path Exists, and if not, create it. + this.VerifyEncodeDestinationPath(task); + + // Get an EncodeJob object for the Interop Library + this.instance.StartEncode(EncodeTaskFactory.Create(task, configuration, hbFunctionsProvider.GetHbFunctionsWrapper())); + } // Fire the Encode Started Event this.InvokeEncodeStarted(System.EventArgs.Empty); diff --git a/win/CS/HandBrakeWPF/Services/Logging/LogInstanceManager.cs b/win/CS/HandBrakeWPF/Services/Logging/LogInstanceManager.cs index 4e1290024..16c9aa7dc 100644 --- a/win/CS/HandBrakeWPF/Services/Logging/LogInstanceManager.cs +++ b/win/CS/HandBrakeWPF/Services/Logging/LogInstanceManager.cs @@ -19,13 +19,26 @@ namespace HandBrakeWPF.Services.Logging public class LogInstanceManager : ILogInstanceManager { - private Dictionary<string, ILog> logInstances = new Dictionary<string, ILog>(); + private readonly IUserSettingService userSettingService; + private readonly object instanceLock = new object(); + private Dictionary<string, ILog> logInstances = new Dictionary<string, ILog>(); + private int maxInstances; public LogInstanceManager(IUserSettingService userSettingService) { - this.maxInstances = userSettingService.GetUserSetting<int>(UserSettingConstants.SimultaneousEncodes); + this.userSettingService = userSettingService; + this.maxInstances = this.userSettingService.GetUserSetting<int>(UserSettingConstants.SimultaneousEncodes); + userSettingService.SettingChanged += this.UserSettingService_SettingChanged; + } + + private void UserSettingService_SettingChanged(object sender, HandBrakeWPF.EventArgs.SettingChangedEventArgs e) + { + if (e.Key == UserSettingConstants.SimultaneousEncodes) + { + this.maxInstances = this.userSettingService.GetUserSetting<int>(UserSettingConstants.SimultaneousEncodes); + } } public event EventHandler NewLogInstanceRegistered; @@ -36,19 +49,22 @@ namespace HandBrakeWPF.Services.Logging public void RegisterLoggerInstance(string filename, ILog log, bool isMaster) { - if (string.IsNullOrEmpty(this.ApplicationAndScanLog)) + lock (this.instanceLock) { - // The application startup sets the initial log file. - this.ApplicationAndScanLog = filename; - } + if (string.IsNullOrEmpty(this.ApplicationAndScanLog)) + { + // The application startup sets the initial log file. + this.ApplicationAndScanLog = filename; + } - this.logInstances.Add(filename, log); + this.logInstances.Add(filename, log); - this.CleanupInstance(); + this.CleanupInstance(); - if (isMaster) - { - this.MasterLogInstance = log; + if (isMaster) + { + this.MasterLogInstance = log; + } } this.OnNewLogInstanceRegistered(); @@ -56,20 +72,26 @@ namespace HandBrakeWPF.Services.Logging public List<string> GetLogFiles() { - return this.logInstances.Keys.ToList(); + lock (this.instanceLock) + { + return this.logInstances.Keys.ToList(); + } } public ILog GetLogInstance(string filename) { - if (string.IsNullOrEmpty(filename)) + lock (this.instanceLock) { - return null; - } - - ILog logger; - if (this.logInstances.TryGetValue(filename, out logger)) - { - return logger; + if (string.IsNullOrEmpty(filename)) + { + return null; + } + + ILog logger; + if (this.logInstances.TryGetValue(filename, out logger)) + { + return logger; + } } return null; @@ -87,7 +109,7 @@ namespace HandBrakeWPF.Services.Logging if (encodeLogs.Count > this.maxInstances) { this.logInstances.Remove(removalKey); - } + } } } } diff --git a/win/CS/HandBrakeWPF/Services/Queue/Interfaces/IQueueService.cs b/win/CS/HandBrakeWPF/Services/Queue/Interfaces/IQueueService.cs index 1a2a04cce..5bf759917 100644 --- a/win/CS/HandBrakeWPF/Services/Queue/Interfaces/IQueueService.cs +++ b/win/CS/HandBrakeWPF/Services/Queue/Interfaces/IQueueService.cs @@ -63,6 +63,11 @@ namespace HandBrakeWPF.Services.Queue.Interfaces int ErrorCount { get; } /// <summary> + /// Gets the number of completed jobs. + /// </summary> + int CompletedCount { get; } + + /// <summary> /// Gets a value indicating whether IsProcessing. /// </summary> bool IsProcessing { get; } diff --git a/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs b/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs index 6cbf709e5..41cba661f 100644 --- a/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs +++ b/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs @@ -59,9 +59,12 @@ namespace HandBrakeWPF.Services.Queue private readonly ObservableCollection<QueueTask> queue = new ObservableCollection<QueueTask>(); private readonly string queueFile; + private readonly object queueFileLock = new object(); + private bool clearCompleted; private int allowedInstances; private int jobIdCounter = 0; + private bool processIsolationEnabled; public QueueService(IUserSettingService userSettingService, ILog logService, IErrorService errorService, ILogInstanceManager logInstanceManager, IHbFunctionsProvider hbFunctionsProvider) { @@ -75,6 +78,7 @@ namespace HandBrakeWPF.Services.Queue this.queueFile = string.Format("{0}{1}.json", QueueRecoveryHelper.QueueFileName, GeneralUtilities.ProcessId); this.allowedInstances = this.userSettingService.GetUserSetting<int>(UserSettingConstants.SimultaneousEncodes); + this.processIsolationEnabled = this.userSettingService.GetUserSetting<bool>(UserSettingConstants.ProcessIsolationEnabled); } public event EventHandler<QueueProgressEventArgs> JobProcessingStarted; @@ -105,6 +109,8 @@ namespace HandBrakeWPF.Services.Queue } } + public int CompletedCount => this.queue.Count(item => item.Status == QueueItemStatus.Completed); + public bool IsPaused { get; private set; } public bool IsProcessing { get; private set; } @@ -130,33 +136,31 @@ namespace HandBrakeWPF.Services.Queue public void BackupQueue(string exportPath) { - Stopwatch watch = Stopwatch.StartNew(); - - string appDataPath = DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()); - string tempPath = !string.IsNullOrEmpty(exportPath) - ? exportPath - : Path.Combine(appDataPath, string.Format(this.queueFile, string.Empty)); - - // Make a copy of the file before we replace it. This way, if we crash we can recover. - if (File.Exists(tempPath)) + lock (this.queueFileLock) { - File.Copy(tempPath, tempPath + ".last"); - } + string appDataPath = DirectoryUtilities.GetUserStoragePath(VersionHelper.IsNightly()); + string tempPath = !string.IsNullOrEmpty(exportPath) + ? exportPath + : Path.Combine(appDataPath, string.Format(this.queueFile, string.Empty)); - using (StreamWriter writer = new StreamWriter(tempPath)) - { - List<QueueTask> tasks = this.queue.Where(item => item.Status != QueueItemStatus.Completed).ToList(); - string queueJson = JsonConvert.SerializeObject(tasks, Formatting.Indented); - writer.Write(queueJson); - } + // Make a copy of the file before we replace it. This way, if we crash we can recover. + if (File.Exists(tempPath)) + { + File.Copy(tempPath, tempPath + ".last"); + } - if (File.Exists(tempPath + ".last")) - { - File.Delete(tempPath + ".last"); - } + using (StreamWriter writer = new StreamWriter(tempPath)) + { + List<QueueTask> tasks = this.queue.Where(item => item.Status != QueueItemStatus.Completed).ToList(); + string queueJson = JsonConvert.SerializeObject(tasks, Formatting.Indented); + writer.Write(queueJson); + } - watch.Stop(); - Debug.WriteLine("Queue Save (ms): " + watch.ElapsedMilliseconds); + if (File.Exists(tempPath + ".last")) + { + File.Delete(tempPath + ".last"); + } + } } public void ExportCliJson(string exportPath) @@ -447,6 +451,9 @@ namespace HandBrakeWPF.Services.Queue this.IsPaused = false; this.clearCompleted = isClearCompleted; + this.allowedInstances = this.userSettingService.GetUserSetting<int>(UserSettingConstants.SimultaneousEncodes); + this.processIsolationEnabled = this.userSettingService.GetUserSetting<bool>(UserSettingConstants.ProcessIsolationEnabled); + // Unpause all active jobs. foreach (ActiveJob job in this.activeJobs) { @@ -523,6 +530,11 @@ namespace HandBrakeWPF.Services.Queue private void ProcessNextJob() { + if (!this.processIsolationEnabled) + { + this.allowedInstances = 1; + } + if (this.activeJobs.Count >= this.allowedInstances) { return; @@ -555,8 +567,11 @@ namespace HandBrakeWPF.Services.Queue { this.BackupQueue(string.Empty); - // Fire the event to tell connected services. - this.InvokeQueueCompleted(new QueueCompletedEventArgs(false)); + if (!this.activeJobs.Any(a => a.IsEncoding)) + { + // Fire the event to tell connected services. + this.InvokeQueueCompleted(new QueueCompletedEventArgs(false)); + } } } diff --git a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs index f88adaded..c1124817e 100644 --- a/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/MainViewModel.cs @@ -62,8 +62,6 @@ namespace HandBrakeWPF.ViewModels /// </summary>
public class MainViewModel : ViewModelBase, IMainViewModel
{
- #region Private Variables and Services
-
private readonly IQueueService queueProcessor;
private readonly IPresetService presetService;
private readonly IErrorService errorService;
@@ -96,13 +94,6 @@ namespace HandBrakeWPF.ViewModels private bool isModifiedPreset;
private bool updateAvailable;
- #endregion
-
- /// <summary>
- /// Initializes a new instance of the <see cref="MainViewModel"/> class.
- /// The viewmodel for HandBrakes main window.
- /// </summary>
- /// <remarks>whenDoneService must be a serivce here!</remarks>
public MainViewModel(
IUserSettingService userSettingService,
IScan scanService,
@@ -1070,6 +1061,8 @@ namespace HandBrakeWPF.ViewModels }
}
+ public bool IsMultiProcess { get; set; }
+
#endregion
#region Commands
@@ -2495,6 +2488,7 @@ namespace HandBrakeWPF.ViewModels private void QueueCompleted(object sender, EventArgs e)
{
this.NotifyOfPropertyChange(() => this.IsEncoding);
+ this.NotifyOfPropertyChange(() => this.StartLabel);
Execute.OnUIThread(
() =>
@@ -2530,7 +2524,11 @@ namespace HandBrakeWPF.ViewModels Execute.OnUIThread(
() =>
{
- this.ProgramStatusLabel = string.Format(Resources.Main_XEncodesPending, this.queueProcessor.Count);
+ if (!this.queueProcessor.IsEncoding)
+ {
+ this.ProgramStatusLabel = string.Format(Resources.Main_XEncodesPending, this.queueProcessor.Count);
+ }
+
this.NotifyOfPropertyChange(() => this.QueueLabel);
this.NotifyOfPropertyChange(() => this.StartLabel);
this.NotifyOfPropertyChange(() => this.IsEncoding);
@@ -2545,15 +2543,20 @@ namespace HandBrakeWPF.ViewModels this.ProgramStatusLabel = Resources.Main_QueuePaused;
this.NotifyOfPropertyChange(() => this.QueueLabel);
this.NotifyOfPropertyChange(() => this.StartLabel);
+ this.NotifyOfPropertyChange(() => this.IsEncoding);
});
}
-
-
+
private void QueueProcessor_QueueJobStatusChanged(object sender, EventArgs e)
{
List<QueueProgressStatus> queueJobStatuses = this.queueProcessor.GetQueueProgressStatus();
string jobsPending = string.Format(Resources.Main_JobsPending_addon, this.queueProcessor.Count);
+ if (this.queueProcessor.IsPaused)
+ {
+ return;
+ }
+
Execute.OnUIThread(
() =>
{
@@ -2579,10 +2582,15 @@ namespace HandBrakeWPF.ViewModels this.WindowTitle = string.Format(Resources.WindowTitleStatus, Resources.HandBrake_Title, this.ProgressPercentage, status.Task, status.TaskCount);
this.notifyIconService.SetTooltip(string.Format(Resources.TaskTrayStatusTitle, Resources.HandBrake_Title, this.ProgressPercentage, status.Task, status.TaskCount, status.EstimatedTimeLeft));
}
+
+ this.IsMultiProcess = false;
+ this.NotifyOfPropertyChange(() => this.IsMultiProcess);
}
else if (queueJobStatuses.Count > 1)
{
- this.ProgramStatusLabel = "Multiple Jobs Running."; // TODO Implement later.
+ this.ProgramStatusLabel = string.Format("{0} jobs completed. {1}Working on {2} jobs with {3} waiting to be processed.", this.queueProcessor.CompletedCount, Environment.NewLine, queueJobStatuses.Count, this.queueProcessor.Count);
+ this.IsMultiProcess = true;
+ this.NotifyOfPropertyChange(() => this.IsMultiProcess);
}
else
{
@@ -2591,6 +2599,9 @@ namespace HandBrakeWPF.ViewModels this.WindowTitle = Resources.HandBrake_Title;
this.notifyIconService.SetTooltip(this.WindowTitle);
+ this.IsMultiProcess = false;
+ this.NotifyOfPropertyChange(() => this.IsMultiProcess);
+
if (this.windowsSeven.IsWindowsSeven)
{
this.windowsSeven.SetTaskBarProgressToNoProgress();
diff --git a/win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs index 1d3650264..2926e40e5 100644 --- a/win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/QueueViewModel.cs @@ -231,9 +231,6 @@ namespace HandBrakeWPF.ViewModels this.JobsPending = string.Format(Resources.QueueViewModel_JobsPending, this.queueProcessor.Count);
this.IsQueueRunning = false;
-
- this.errorService.ShowMessageBox(Resources.QueueViewModel_QueuePauseNotice, Resources.QueueViewModel_Queue,
- MessageBoxButton.OK, MessageBoxImage.Information);
}
public void PauseQueueToolbar()
diff --git a/win/CS/HandBrakeWPF/ViewModels/StaticPreviewViewModel.cs b/win/CS/HandBrakeWPF/ViewModels/StaticPreviewViewModel.cs index 996d93949..52d4bb4b3 100644 --- a/win/CS/HandBrakeWPF/ViewModels/StaticPreviewViewModel.cs +++ b/win/CS/HandBrakeWPF/ViewModels/StaticPreviewViewModel.cs @@ -41,9 +41,6 @@ namespace HandBrakeWPF.ViewModels using OutputFormat = HandBrakeWPF.Services.Encode.Model.Models.OutputFormat;
using PointToPointMode = HandBrakeWPF.Services.Encode.Model.Models.PointToPointMode;
- /// <summary>
- /// The Static Preview View Model
- /// </summary>
public class StaticPreviewViewModel : ViewModelBase, IStaticPreviewViewModel
{
private readonly IScan scanService;
@@ -61,8 +58,6 @@ namespace HandBrakeWPF.ViewModels private bool useSystemDefaultPlayer;
private bool previewRotateFlip;
- #region Constructors and Destructors
-
public StaticPreviewViewModel(IScan scanService, IUserSettingService userSettingService, IErrorService errorService, IHbFunctionsProvider hbFunctionsProvider, ILog logService, ILogInstanceManager logInstanceManager)
{
this.scanService = scanService;
@@ -86,11 +81,7 @@ namespace HandBrakeWPF.ViewModels this.previewRotateFlip = userSettingService.GetUserSetting<bool>(UserSettingConstants.PreviewRotationFlip);
this.NotifyOfPropertyChange(() => this.previewRotateFlip); // Don't want to trigger an Update, so setting the backing variable.
}
-
- #endregion
-
- #region Public Properties
-
+
/// <summary>
/// Gets or sets the height.
/// </summary>
@@ -233,10 +224,6 @@ namespace HandBrakeWPF.ViewModels }
}
- #endregion
-
- #region LivePreviewProperties
-
/// <summary>
/// Gets AvailableDurations.
/// </summary>
@@ -350,9 +337,8 @@ namespace HandBrakeWPF.ViewModels /// Gets or sets a value indicating whether can play.
/// </summary>
public bool CanPlay { get; set; }
- #endregion
- #region Public Methods and Operators
+ public bool IsOpen { get; set; }
/// <summary>
/// The update preview frame.
@@ -372,11 +358,6 @@ namespace HandBrakeWPF.ViewModels this.ScannedSource = scannedSource;
}
- /// <summary>
- /// Gets or sets a value indicating whether is open.
- /// </summary>
- public bool IsOpen { get; set; }
-
public void NextPreview()
{
int maxPreview = this.userSettingService.GetUserSetting<int>(UserSettingConstants.PreviewScanCount);
@@ -442,12 +423,6 @@ namespace HandBrakeWPF.ViewModels }
}
- /// <summary>
- /// The preview size changed.
- /// </summary>
- /// <param name="ea">
- /// The ea.
- /// </param>
public int FixWidth(int width)
{
Rect workArea = SystemParameters.WorkArea;
@@ -470,12 +445,6 @@ namespace HandBrakeWPF.ViewModels return height;
}
- #endregion
-
- #region Public Method - Live Preview
-
- #region Public Methods
-
/// <summary>
/// Close this window.
/// </summary>
@@ -500,19 +469,19 @@ namespace HandBrakeWPF.ViewModels {
this.IsEncoding = true;
if (File.Exists(this.CurrentlyPlaying))
+ {
File.Delete(this.CurrentlyPlaying);
+ }
}
catch (Exception)
{
this.IsEncoding = false;
- this.errorService.ShowMessageBox(Resources.StaticPreview_UnableToDeletePreview,
- Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
+ this.errorService.ShowMessageBox(Resources.StaticPreview_UnableToDeletePreview, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
}
if (this.Task == null || string.IsNullOrEmpty(Task.Source))
{
- this.errorService.ShowMessageBox(Resources.StaticPreviewViewModel_ScanFirst,
- Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
+ this.errorService.ShowMessageBox(Resources.StaticPreviewViewModel_ScanFirst, Resources.Error, MessageBoxButton.OK, MessageBoxImage.Error);
return;
}
@@ -540,6 +509,7 @@ namespace HandBrakeWPF.ViewModels formatExtension = "mkv";
break;
}
+
string filename = Path.ChangeExtension(Path.GetTempFileName(), formatExtension);
encodeTask.Destination = filename;
this.CurrentlyPlaying = filename;
@@ -579,9 +549,14 @@ namespace HandBrakeWPF.ViewModels ThreadPool.QueueUserWorkItem(this.CreatePreview, task);
}
- #endregion
+ public void CancelEncode()
+ {
+ if (this.encodeService.IsEncoding)
+ {
+ this.encodeService.Stop();
+ }
+ }
- #region Private Methods
/// <summary>
/// Play the Encoded file
@@ -665,10 +640,6 @@ namespace HandBrakeWPF.ViewModels this.userSettingService.SetUserSetting(UserSettingConstants.LastPreviewDuration, this.Duration);
}
- #endregion
-
- #region Event Handlers
-
/// <summary>
/// Handle Encode Progress Events
/// </summary>
@@ -702,9 +673,10 @@ namespace HandBrakeWPF.ViewModels this.encodeService.EncodeCompleted -= this.encodeService_EncodeCompleted;
this.encodeService.EncodeStatusChanged -= this.encodeService_EncodeStatusChanged;
- this.PlayFile();
+ if (e.ErrorInformation != "1")
+ {
+ this.PlayFile();
+ }
}
- #endregion
- #endregion
}
}
\ No newline at end of file diff --git a/win/CS/HandBrakeWPF/Views/MainView.xaml b/win/CS/HandBrakeWPF/Views/MainView.xaml index 10712ac05..df77fc923 100644 --- a/win/CS/HandBrakeWPF/Views/MainView.xaml +++ b/win/CS/HandBrakeWPF/Views/MainView.xaml @@ -797,10 +797,10 @@ </Controls:AlertPanel>
<!-- Status Bar -->
- <StatusBar Name="statusBar1" Height="32" Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
+ <StatusBar Name="statusBar" Grid.Row="2" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Bottom">
<StatusBarItem>
- <ProgressBar Value="{Binding ProgressPercentage}" Visibility="{Binding IsEncoding, Converter={StaticResource boolToVisConverter}}"
+ <ProgressBar Value="{Binding ProgressPercentage}" IsIndeterminate="{Binding IsMultiProcess}" Visibility="{Binding IsEncoding, Converter={StaticResource boolToVisConverter}}"
Width="100" Height="18" VerticalAlignment="Center" />
</StatusBarItem>
<StatusBarItem>
diff --git a/win/CS/HandBrakeWPF/Views/OptionsView.xaml b/win/CS/HandBrakeWPF/Views/OptionsView.xaml index 67d86bdee..baaadb5e5 100644 --- a/win/CS/HandBrakeWPF/Views/OptionsView.xaml +++ b/win/CS/HandBrakeWPF/Views/OptionsView.xaml @@ -416,8 +416,7 @@ <StackPanel Orientation="Horizontal" Margin="10,10,0,0" >
<TextBlock Text="{x:Static Properties:Resources.OptionsView_SimultaneousEncodes}" VerticalAlignment="Center"/>
- <ComboBox ItemsSource="{Binding SimultaneousEncodesList}" SelectedItem="{Binding SimultaneousEncodes}" IsEnabled="false" /> <!--IsEnabled="{Binding RemoteServiceEnabled}"-->
- <TextBlock Text="(Coming Soon!)" Margin="10,0,0,0" FontWeight="Bold" VerticalAlignment="Center" />
+ <ComboBox ItemsSource="{Binding SimultaneousEncodesList}" SelectedItem="{Binding SimultaneousEncodes}" IsEnabled="{Binding RemoteServiceEnabled}" />
</StackPanel>
</StackPanel>
diff --git a/win/CS/HandBrakeWPF/Views/ShellView.xaml b/win/CS/HandBrakeWPF/Views/ShellView.xaml index e7a6feba6..dfa3f6f24 100644 --- a/win/CS/HandBrakeWPF/Views/ShellView.xaml +++ b/win/CS/HandBrakeWPF/Views/ShellView.xaml @@ -7,9 +7,9 @@ xmlns:cal="http://www.caliburnproject.org"
Title="{Data:Binding Path=MainViewModel.WindowTitle}"
Width="1018"
- Height="650"
+ Height="660"
MinWidth="1018"
- MinHeight="650"
+ MinHeight="660"
AllowDrop="True"
SnapsToDevicePixels="True"
UseLayoutRounding="True"
diff --git a/win/CS/HandBrakeWPF/Views/StaticPreviewView.xaml b/win/CS/HandBrakeWPF/Views/StaticPreviewView.xaml index db622c247..584270569 100644 --- a/win/CS/HandBrakeWPF/Views/StaticPreviewView.xaml +++ b/win/CS/HandBrakeWPF/Views/StaticPreviewView.xaml @@ -43,7 +43,9 @@ <CheckBox IsChecked="{Binding PreviewRotateFlip}" Content="{x:Static Properties:Resources.StaticPreviewView_PreviewRotationFlip}" Foreground="White" Grid.Row="1" Margin="0,0,0,10" />
<StackPanel Orientation="Horizontal" Grid.Row="2" HorizontalAlignment="Left">
- <Button Content="{x:Static Properties:Resources.StaticPreviewView_LivePreview}" Padding="8,2" cal:Message.Attach="[Event Click] = [Action Play]" />
+ <Button Content="{x:Static Properties:Resources.StaticPreviewView_LivePreview}" Padding="8,2" cal:Message.Attach="[Event Click] = [Action Play]" Visibility="{Binding IsEncoding, Converter={StaticResource booleanToVisibilityConverter}, ConverterParameter=true}" />
+ <Button Content="{x:Static Properties:Resources.StaticPreviewView_CancelPreview}" Padding="8,2" cal:Message.Attach="[Event Click] = [Action CancelEncode]" Visibility="{Binding IsEncoding, Converter={StaticResource booleanToVisibilityConverter}, ConverterParameter=false}" />
+
<TextBlock Margin="10,0,5,0" VerticalAlignment="Center" Foreground="White" Text="{x:Static Properties:Resources.StaticPreviewView_Duration}" />
<ComboBox Width="60"
ItemsSource="{Binding AvailableDurations}"
|