summaryrefslogtreecommitdiffstats
path: root/win/CS/HandBrakeWPF/Services
diff options
context:
space:
mode:
Diffstat (limited to 'win/CS/HandBrakeWPF/Services')
-rw-r--r--win/CS/HandBrakeWPF/Services/Encode/EncodeBase.cs12
-rw-r--r--win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs100
-rw-r--r--win/CS/HandBrakeWPF/Services/Logging/Interfaces/ILog.cs20
-rw-r--r--win/CS/HandBrakeWPF/Services/Logging/Interfaces/ILogInstanceManager.cs50
-rw-r--r--win/CS/HandBrakeWPF/Services/Logging/LogInstanceManager.cs93
-rw-r--r--win/CS/HandBrakeWPF/Services/Logging/LogService.cs117
-rw-r--r--win/CS/HandBrakeWPF/Services/PrePostActionService.cs39
-rw-r--r--win/CS/HandBrakeWPF/Services/Queue/ActiveJob.cs131
-rw-r--r--win/CS/HandBrakeWPF/Services/Queue/Interfaces/IQueueService.cs51
-rw-r--r--win/CS/HandBrakeWPF/Services/Queue/JobEventArgs/ActiveJobCompletedEventArgs.cs25
-rw-r--r--win/CS/HandBrakeWPF/Services/Queue/Model/QueueItemStatus.cs3
-rw-r--r--win/CS/HandBrakeWPF/Services/Queue/Model/QueueProgressStatus.cs133
-rw-r--r--win/CS/HandBrakeWPF/Services/Queue/Model/QueueTask.cs9
-rw-r--r--win/CS/HandBrakeWPF/Services/Queue/QueueService.cs273
-rw-r--r--win/CS/HandBrakeWPF/Services/SystemService.cs24
-rw-r--r--win/CS/HandBrakeWPF/Services/UserSettingService.cs1
16 files changed, 725 insertions, 356 deletions
diff --git a/win/CS/HandBrakeWPF/Services/Encode/EncodeBase.cs b/win/CS/HandBrakeWPF/Services/Encode/EncodeBase.cs
index 6d34a2efd..5563c2ed5 100644
--- a/win/CS/HandBrakeWPF/Services/Encode/EncodeBase.cs
+++ b/win/CS/HandBrakeWPF/Services/Encode/EncodeBase.cs
@@ -14,10 +14,8 @@ namespace HandBrakeWPF.Services.Encode
using System.Globalization;
using System.IO;
- using HandBrake.Interop.Interop.EventArgs;
using HandBrake.Interop.Model;
- using HandBrakeWPF.Services.Encode.Interfaces;
using HandBrakeWPF.Services.Interfaces;
using HandBrakeWPF.Utilities;
@@ -28,20 +26,18 @@ namespace HandBrakeWPF.Services.Encode
using EncodeTask = HandBrakeWPF.Services.Encode.Model.EncodeTask;
using GeneralApplicationException = HandBrakeWPF.Exceptions.GeneralApplicationException;
using ILog = HandBrakeWPF.Services.Logging.Interfaces.ILog;
- using LogService = HandBrakeWPF.Services.Logging.LogService;
/// <summary>
/// A Base Class for the Encode Services.
/// </summary>
public class EncodeBase
{
- private readonly ILog logService;
+ protected ILog encodeLogService;
private readonly IUserSettingService userSettingService;
-
- public EncodeBase(ILog logService, IUserSettingService userSettingService)
+
+ public EncodeBase(IUserSettingService userSettingService)
{
- this.logService = logService;
this.userSettingService = userSettingService;
}
@@ -136,7 +132,7 @@ namespace HandBrakeWPF.Services.Encode
string encodeDestinationPath = Path.GetDirectoryName(destination);
string destinationFile = Path.GetFileName(destination);
string encodeLogFile = destinationFile + " " + DateTime.Now.ToString(CultureInfo.InvariantCulture).Replace("/", "-").Replace(":", "-") + ".txt";
- string logContent = this.logService.GetFullLog();
+ string logContent = this.encodeLogService.GetFullLog();
// Make sure the log directory exists.
if (!Directory.Exists(logDir))
diff --git a/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs b/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs
index b71d06d3f..e6d8cb7c0 100644
--- a/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs
+++ b/win/CS/HandBrakeWPF/Services/Encode/LibEncode.cs
@@ -12,9 +12,9 @@ namespace HandBrakeWPF.Services.Encode
using System;
using System.Diagnostics;
using System.IO;
+ using System.Windows.Forms.VisualStyles;
using HandBrake.Interop.Interop.EventArgs;
- using HandBrake.Interop.Interop.HbLib;
using HandBrake.Interop.Interop.Interfaces;
using HandBrake.Interop.Interop.Json.State;
using HandBrake.Interop.Interop.Providers.Interfaces;
@@ -24,11 +24,12 @@ namespace HandBrakeWPF.Services.Encode
using HandBrakeWPF.Properties;
using HandBrakeWPF.Services.Encode.Factories;
using HandBrakeWPF.Services.Interfaces;
+ using HandBrakeWPF.Services.Logging.Interfaces;
+ using HandBrakeWPF.Utilities;
using EncodeTask = Model.EncodeTask;
using HandBrakeInstanceManager = Instance.HandBrakeInstanceManager;
using IEncode = Interfaces.IEncode;
- using ILog = Logging.Interfaces.ILog;
using LogService = Logging.LogService;
/// <summary>
@@ -36,40 +37,27 @@ namespace HandBrakeWPF.Services.Encode
/// </summary>
public class LibEncode : EncodeBase, IEncode
{
- #region Private Variables
-
- private readonly ILog log;
private readonly IUserSettingService userSettingService;
+ private readonly ILogInstanceManager logInstanceManager;
private readonly IHbFunctionsProvider hbFunctionsProvider;
private IEncodeInstance instance;
private DateTime startTime;
private EncodeTask currentTask;
private HBConfiguration currentConfiguration;
private bool isPreviewInstance;
+ private bool isLoggingInitialised;
+ private int encodeCounter;
- #endregion
-
- public LibEncode(IHbFunctionsProvider hbFunctionsProvider, ILog logService, IUserSettingService userSettingService) : base(logService, userSettingService)
+ public LibEncode(IHbFunctionsProvider hbFunctionsProvider, IUserSettingService userSettingService, ILogInstanceManager logInstanceManager, int encodeCounter) : base(userSettingService)
{
- this.log = logService;
this.userSettingService = userSettingService;
+ this.logInstanceManager = logInstanceManager;
this.hbFunctionsProvider = hbFunctionsProvider;
+ this.encodeCounter = encodeCounter;
}
- /// <summary>
- /// Gets a value indicating whether is pasued.
- /// </summary>
public bool IsPasued { get; private set; }
- /// <summary>
- /// Start with a LibHb EncodeJob Object
- /// </summary>
- /// <param name="task">
- /// The task.
- /// </param>
- /// <param name="configuration">
- /// The configuration.
- /// </param>
public void Start(EncodeTask task, HBConfiguration configuration, string basePresetName)
{
try
@@ -85,10 +73,17 @@ namespace HandBrakeWPF.Services.Encode
this.currentTask = task;
this.currentConfiguration = configuration;
- // Create a new HandBrake instance
- // Setup the HandBrake Instance
- this.log.Reset(); // Reset so we have a clean log for the start of the encode.
+ if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.ProcessIsolationEnabled))
+ {
+ this.InitLogging(task.IsPreviewEncode);
+ }
+ else
+ {
+ this.encodeLogService = this.logInstanceManager.MasterLogInstance;
+ this.encodeLogService.Reset();
+ }
+
if (this.instance != null)
{
// Cleanup
@@ -112,7 +107,7 @@ 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.log, userSettingService);
+ 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;
@@ -138,9 +133,6 @@ namespace HandBrakeWPF.Services.Encode
}
}
- /// <summary>
- /// Pause the currently running encode.
- /// </summary>
public void Pause()
{
if (this.instance != null)
@@ -151,9 +143,6 @@ namespace HandBrakeWPF.Services.Encode
}
}
- /// <summary>
- /// Resume the currently running encode.
- /// </summary>
public void Resume()
{
if (this.instance != null)
@@ -164,9 +153,6 @@ namespace HandBrakeWPF.Services.Encode
}
}
- /// <summary>
- /// Kill the process
- /// </summary>
public void Stop()
{
try
@@ -188,38 +174,23 @@ namespace HandBrakeWPF.Services.Encode
{
if (this.currentTask != null)
{
- EncodeTask task = new EncodeTask(this.currentTask); // Decouple our current copy.
+ EncodeTask task = new EncodeTask(this.currentTask); // Shallow copy our current instance.
return task;
}
return null;
}
- #region HandBrakeInstance Event Handlers.
-
- /// <summary>
- /// Service Log Message.
- /// </summary>
- /// <param name="message">Log message content</param>
protected void ServiceLogMessage(string message)
{
- this.log.LogMessage(string.Format("{0}# {1}", Environment.NewLine, message));
+ this.encodeLogService.LogMessage(string.Format("{0}# {1}", Environment.NewLine, message));
}
protected void TimedLogMessage(string message)
{
- this.log.LogMessage(string.Format("[{0}] {1}", DateTime.Now.ToString("hh:mm:ss"), message));
+ this.encodeLogService.LogMessage(string.Format("[{0}] {1}", DateTime.Now.ToString("hh:mm:ss"), message));
}
- /// <summary>
- /// Encode Progress Event Handler
- /// </summary>
- /// <param name="sender">
- /// The sender.
- /// </param>
- /// <param name="e">
- /// The Interop.EncodeProgressEventArgs.
- /// </param>
private void InstanceEncodeProgress(object sender, EncodeProgressEventArgs e)
{
EventArgs.EncodeProgressEventArgs args = new EventArgs.EncodeProgressEventArgs
@@ -238,16 +209,7 @@ namespace HandBrakeWPF.Services.Encode
this.InvokeEncodeStatusChanged(args);
}
-
- /// <summary>
- /// Encode Completed Event Handler
- /// </summary>
- /// <param name="sender">
- /// The sender.
- /// </param>
- /// <param name="e">
- /// The e.
- /// </param>
+
private void InstanceEncodeCompleted(object sender, EncodeCompletedEventArgs e)
{
this.IsEncoding = false;
@@ -304,6 +266,18 @@ namespace HandBrakeWPF.Services.Encode
return 0;
}
- #endregion
+ private void InitLogging(bool isPreview)
+ {
+ if (!isLoggingInitialised)
+ {
+ string logType = isPreview ? "preview" : "encode";
+ string filename = string.Format("activity_log.{0}.{1}.{2}.txt", encodeCounter, logType, GeneralUtilities.ProcessId);
+ string logFile = Path.Combine(DirectoryUtilities.GetLogDirectory(), filename);
+ this.encodeLogService = new LogService();
+ this.encodeLogService.ConfigureLogging(logFile);
+ this.logInstanceManager.RegisterLoggerInstance(filename, this.encodeLogService, false);
+ isLoggingInitialised = true;
+ }
+ }
}
}
diff --git a/win/CS/HandBrakeWPF/Services/Logging/Interfaces/ILog.cs b/win/CS/HandBrakeWPF/Services/Logging/Interfaces/ILog.cs
index d82a1ed0d..57594528a 100644
--- a/win/CS/HandBrakeWPF/Services/Logging/Interfaces/ILog.cs
+++ b/win/CS/HandBrakeWPF/Services/Logging/Interfaces/ILog.cs
@@ -12,17 +12,14 @@ namespace HandBrakeWPF.Services.Logging.Interfaces
using System;
using System.Collections.Generic;
- using HandBrake.Worker.Logging.Interfaces;
using HandBrake.Worker.Logging.Models;
- using HandBrakeWPF.Services.Logging.Model;
-
using LogEventArgs = HandBrakeWPF.Services.Logging.EventArgs.LogEventArgs;
/// <summary>
/// The Log interface.
/// </summary>
- public interface ILog : ILogHandler
+ public interface ILog
{
/// <summary>
/// The message logged.
@@ -37,13 +34,13 @@ namespace HandBrakeWPF.Services.Logging.Interfaces
/// <summary>
/// Enable logging for this worker process.
/// </summary>
- /// <param name="config">
- /// Configuration for the logger.
+ /// <param name="filename">
+ /// The filename.
/// </param>
/// <remarks>
/// If this is not called, all log messages from libhb will be ignored.
/// </remarks>
- void ConfigureLogging(LogHandlerConfig config);
+ void ConfigureLogging(string filename);
/// <summary>
/// Log a message.
@@ -52,5 +49,14 @@ namespace HandBrakeWPF.Services.Logging.Interfaces
/// The content of the log message,
/// </param>
void LogMessage(string content);
+
+ string GetFullLog();
+
+ List<LogMessage> GetLogMessages();
+
+ /// <summary>
+ /// Empty the log cache and reset the log handler to defaults.
+ /// </summary>
+ void Reset();
}
} \ No newline at end of file
diff --git a/win/CS/HandBrakeWPF/Services/Logging/Interfaces/ILogInstanceManager.cs b/win/CS/HandBrakeWPF/Services/Logging/Interfaces/ILogInstanceManager.cs
new file mode 100644
index 000000000..c8af64601
--- /dev/null
+++ b/win/CS/HandBrakeWPF/Services/Logging/Interfaces/ILogInstanceManager.cs
@@ -0,0 +1,50 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="ILogInstanceManager.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// Defines the ILogInstanceManager type.
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Services.Logging.Interfaces
+{
+ using System;
+ using System.Collections.Generic;
+
+ public interface ILogInstanceManager
+ {
+ event EventHandler NewLogInstanceRegistered;
+
+ string ApplicationAndScanLog { get; }
+
+ ILog MasterLogInstance { get; }
+
+ /// <summary>
+ /// Register an ILog instance.
+ /// </summary>
+ /// <param name="filename">
+ /// This is the key associated with the log instance.
+ /// </param>
+ /// <param name="log">
+ /// The ILog instance
+ /// </param>
+ /// <param name="isMaster">
+ /// True indicates it's the log instance for the parent handbrake process.
+ /// </param>
+ void RegisterLoggerInstance(string filename, ILog log, bool isMaster);
+
+ /// <summary>
+ /// Gets a list of files without their associated ILog instances.
+ /// </summary>
+ /// <returns>List of filenames being logged</returns>
+ List<string> GetLogFiles();
+
+ /// <summary>
+ /// Get the ILog instance for a given filename key
+ /// </summary>
+ /// <param name="filename">The key of the log instance</param>
+ /// <returns>An ILog instance or null if invalid key</returns>
+ ILog GetLogInstance(string filename);
+ }
+}
diff --git a/win/CS/HandBrakeWPF/Services/Logging/LogInstanceManager.cs b/win/CS/HandBrakeWPF/Services/Logging/LogInstanceManager.cs
new file mode 100644
index 000000000..4e1290024
--- /dev/null
+++ b/win/CS/HandBrakeWPF/Services/Logging/LogInstanceManager.cs
@@ -0,0 +1,93 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="LogInstanceManager.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Services.Logging
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ using HandBrakeWPF.Services.Interfaces;
+ using HandBrakeWPF.Services.Logging.Interfaces;
+
+ using Microsoft.Win32.SafeHandles;
+
+ public class LogInstanceManager : ILogInstanceManager
+ {
+ private Dictionary<string, ILog> logInstances = new Dictionary<string, ILog>();
+
+ private int maxInstances;
+
+ public LogInstanceManager(IUserSettingService userSettingService)
+ {
+ this.maxInstances = userSettingService.GetUserSetting<int>(UserSettingConstants.SimultaneousEncodes);
+ }
+
+ public event EventHandler NewLogInstanceRegistered;
+
+ public string ApplicationAndScanLog { get; private set; }
+
+ public ILog MasterLogInstance { get; private set; }
+
+ public void RegisterLoggerInstance(string filename, ILog log, bool isMaster)
+ {
+ if (string.IsNullOrEmpty(this.ApplicationAndScanLog))
+ {
+ // The application startup sets the initial log file.
+ this.ApplicationAndScanLog = filename;
+ }
+
+ this.logInstances.Add(filename, log);
+
+ this.CleanupInstance();
+
+ if (isMaster)
+ {
+ this.MasterLogInstance = log;
+ }
+
+ this.OnNewLogInstanceRegistered();
+ }
+
+ public List<string> GetLogFiles()
+ {
+ return this.logInstances.Keys.ToList();
+ }
+
+ public ILog GetLogInstance(string filename)
+ {
+ if (string.IsNullOrEmpty(filename))
+ {
+ return null;
+ }
+
+ ILog logger;
+ if (this.logInstances.TryGetValue(filename, out logger))
+ {
+ return logger;
+ }
+
+ return null;
+ }
+
+ protected virtual void OnNewLogInstanceRegistered()
+ {
+ this.NewLogInstanceRegistered?.Invoke(this, System.EventArgs.Empty);
+ }
+
+ private void CleanupInstance()
+ {
+ List<string> encodeLogs = this.logInstances.Keys.Where(f => f.Contains(".encode.")).ToList();
+ string removalKey = this.logInstances.Keys.OrderBy(k => k).FirstOrDefault(w => w.Contains(".encode."));
+ if (encodeLogs.Count > this.maxInstances)
+ {
+ this.logInstances.Remove(removalKey);
+ }
+ }
+ }
+}
diff --git a/win/CS/HandBrakeWPF/Services/Logging/LogService.cs b/win/CS/HandBrakeWPF/Services/Logging/LogService.cs
index 738cb2b3a..18a8ffaee 100644
--- a/win/CS/HandBrakeWPF/Services/Logging/LogService.cs
+++ b/win/CS/HandBrakeWPF/Services/Logging/LogService.cs
@@ -18,47 +18,30 @@ namespace HandBrakeWPF.Services.Logging
using System.IO;
using System.Linq;
using System.Text;
- using System.Timers;
- using HandBrake.Interop.Interop;
- using HandBrake.Interop.Interop.EventArgs;
- using HandBrake.Worker.Logging.Interfaces;
using HandBrake.Worker.Logging.Models;
- using HandBrakeWPF.Instance;
- using HandBrakeWPF.Instance.Model;
- using HandBrakeWPF.Services.Interfaces;
- using HandBrakeWPF.Services.Logging.Model;
using HandBrakeWPF.Utilities;
- using Newtonsoft.Json;
-
using ILog = Interfaces.ILog;
using LogEventArgs = EventArgs.LogEventArgs;
- public class LogService : ILog
+ public class LogService : ILog, IDisposable
{
- // TODO List.
- // Maybe make the event weak?
- // Make this class Thread Safe.
- private static ILog loggerInstance;
private readonly object lockObject = new object();
private readonly object fileWriterLock = new object();
private readonly StringBuilder logBuilder = new StringBuilder();
-
+ private readonly List<LogMessage> logMessages = new List<LogMessage>();
+
private bool isLoggingEnabled;
- private List<LogMessage> logMessages = new List<LogMessage>();
private int messageIndex;
private string diskLogPath;
- private bool deleteLogFirst;
private bool isDiskLoggingEnabled;
private StreamWriter fileWriter;
private string logHeader;
- public LogService(IUserSettingService userSettingService)
+ public LogService()
{
- HandBrakeUtils.MessageLogged += this.HandBrakeUtils_MessageLogged;
- HandBrakeUtils.ErrorLogged += this.HandBrakeUtils_ErrorLogged;
}
public event EventHandler<LogEventArgs> MessageLogged;
@@ -86,7 +69,7 @@ namespace HandBrakeWPF.Services.Logging
LogMessage msg = new LogMessage(content, this.messageIndex);
lock (this.lockObject)
{
- this.messageIndex = this.messageIndex + 1;
+ this.messageIndex = this.messageIndex + 1;
this.logMessages.Add(msg);
this.logBuilder.AppendLine(msg.Content);
this.LogMessageToDisk(msg);
@@ -106,22 +89,19 @@ namespace HandBrakeWPF.Services.Logging
this.OnMessageLogged(msg); // Must be outside lock to be thread safe.
}
- public void ConfigureLogging(LogHandlerConfig config)
+ public void ConfigureLogging(string filename)
{
this.isLoggingEnabled = true;
- if (config.EnableDiskLogging)
+ if (!string.IsNullOrEmpty(filename) && !Directory.Exists(Path.GetDirectoryName(filename)))
{
- if (!string.IsNullOrEmpty(config.LogFile) && !Directory.Exists(Path.GetDirectoryName(config.LogFile)))
- {
- Directory.CreateDirectory(Path.GetDirectoryName(config.LogFile));
- }
-
- this.EnableLoggingToDisk(config.LogFile, config.DeleteCurrentLogFirst);
+ Directory.CreateDirectory(Path.GetDirectoryName(filename));
}
- this.logHeader = config.Header;
- this.LogMessage(config.Header);
+ this.EnableLoggingToDisk(filename);
+
+ this.logHeader = GeneralUtilities.CreateLogHeader().ToString();
+ this.LogMessage(logHeader);
}
public string GetFullLog()
@@ -155,14 +135,6 @@ namespace HandBrakeWPF.Services.Logging
return log;
}
- public long GetLatestLogIndex()
- {
- lock (this.lockObject)
- {
- return this.messageIndex;
- }
- }
-
public async void Reset()
{
lock (this.lockObject)
@@ -170,30 +142,13 @@ namespace HandBrakeWPF.Services.Logging
this.logMessages.Clear();
this.logBuilder.Clear();
this.messageIndex = 0;
-
- try
- {
- lock (this.fileWriterLock)
- {
- if (this.fileWriter != null)
- {
- this.fileWriter.Flush();
- this.fileWriter.Close();
- this.fileWriter.Dispose();
- }
-
- this.fileWriter = null;
- }
- }
- catch (Exception exc)
- {
- Debug.WriteLine(exc);
- }
+
+ this.ShutdownFileWriter();
if (this.fileWriter == null)
{
this.isDiskLoggingEnabled = false;
- this.EnableLoggingToDisk(this.diskLogPath, this.deleteLogFirst);
+ this.EnableLoggingToDisk(this.diskLogPath);
}
if (!string.IsNullOrEmpty(this.logHeader))
@@ -205,16 +160,18 @@ namespace HandBrakeWPF.Services.Logging
}
}
+ public void Dispose()
+ {
+ this.ShutdownFileWriter();
+ }
+
protected virtual void OnMessageLogged(LogMessage msg)
{
var onMessageLogged = this.MessageLogged;
- if (onMessageLogged != null)
- {
- onMessageLogged.Invoke(this, new LogEventArgs(msg));
- }
+ onMessageLogged?.Invoke(this, new LogEventArgs(msg));
}
- protected void ShutdownFileWriter()
+ private void ShutdownFileWriter()
{
try
{
@@ -241,7 +198,7 @@ namespace HandBrakeWPF.Services.Logging
this.LogReset?.Invoke(this, System.EventArgs.Empty);
}
- private void EnableLoggingToDisk(string logFile, bool deleteCurrentLogFirst)
+ private void EnableLoggingToDisk(string logFile)
{
if (this.isDiskLoggingEnabled)
{
@@ -255,14 +212,13 @@ namespace HandBrakeWPF.Services.Logging
throw new Exception("Log Directory does not exist. This service will not create it for you!");
}
- if (deleteCurrentLogFirst && File.Exists(logFile))
+ if (File.Exists(logFile))
{
File.Delete(logFile);
}
this.diskLogPath = logFile;
this.isDiskLoggingEnabled = true;
- this.deleteLogFirst = deleteCurrentLogFirst;
lock (this.fileWriterLock)
{
@@ -313,30 +269,5 @@ namespace HandBrakeWPF.Services.Logging
Debug.WriteLine(exc); // This exception doesn't warrant user interaction, but it should be logged
}
}
-
- private void HandBrakeUtils_ErrorLogged(object sender, MessageLoggedEventArgs e)
- {
- if (e == null || string.IsNullOrEmpty(e.Message))
- {
- return;
- }
-
- this.LogMessage(e.Message);
- }
-
- private void HandBrakeUtils_MessageLogged(object sender, MessageLoggedEventArgs e)
- {
- if (e == null || string.IsNullOrEmpty(e.Message))
- {
- return;
- }
-
- this.LogMessage(e.Message);
- }
-
- void ILogHandler.ShutdownFileWriter()
- {
- throw new NotImplementedException();
- }
}
}
diff --git a/win/CS/HandBrakeWPF/Services/PrePostActionService.cs b/win/CS/HandBrakeWPF/Services/PrePostActionService.cs
index e8118f2a3..2eba7b38c 100644
--- a/win/CS/HandBrakeWPF/Services/PrePostActionService.cs
+++ b/win/CS/HandBrakeWPF/Services/PrePostActionService.cs
@@ -34,7 +34,6 @@ namespace HandBrakeWPF.Services
public class PrePostActionService : IPrePostActionService
{
private readonly ILog log;
- private readonly IQueueService queueProcessor;
private readonly IUserSettingService userSettingService;
private readonly IWindowManager windowManager;
private readonly IScan scanService;
@@ -42,14 +41,26 @@ namespace HandBrakeWPF.Services
public PrePostActionService(IQueueService queueProcessor, IUserSettingService userSettingService, IWindowManager windowManager, IScan scanService, ILog logService)
{
this.log = logService;
- this.queueProcessor = queueProcessor;
this.userSettingService = userSettingService;
this.windowManager = windowManager;
this.scanService = scanService;
- this.queueProcessor.QueueCompleted += this.QueueProcessorQueueCompleted;
- this.queueProcessor.EncodeService.EncodeCompleted += this.EncodeService_EncodeCompleted;
- this.queueProcessor.EncodeService.EncodeStarted += this.EncodeService_EncodeStarted;
+ queueProcessor.QueueCompleted += this.QueueProcessorQueueCompleted;
+ queueProcessor.QueuePaused += this.QueueProcessor_QueuePaused;
+ queueProcessor.EncodeCompleted += this.EncodeService_EncodeCompleted;
+ queueProcessor.JobProcessingStarted += this.EncodeService_EncodeStarted;
+ }
+
+ private void QueueProcessor_QueuePaused(object sender, EventArgs e)
+ {
+ // Allow the system to sleep again.
+ Execute.OnUIThread(() =>
+ {
+ if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PreventSleep))
+ {
+ Win32.AllowSleep();
+ }
+ });
}
/// <summary>
@@ -90,15 +101,6 @@ namespace HandBrakeWPF.Services
{
this.PlayWhenDoneSound();
}
-
- // Allow the system to sleep again.
- Execute.OnUIThread(() =>
- {
- if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PreventSleep))
- {
- Win32.AllowSleep();
- }
- });
}
/// <summary>
@@ -172,6 +174,15 @@ namespace HandBrakeWPF.Services
break;
}
}
+
+ // Allow the system to sleep again.
+ Execute.OnUIThread(() =>
+ {
+ if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PreventSleep))
+ {
+ Win32.AllowSleep();
+ }
+ });
}
private void SendToApplication(string source, string destination)
diff --git a/win/CS/HandBrakeWPF/Services/Queue/ActiveJob.cs b/win/CS/HandBrakeWPF/Services/Queue/ActiveJob.cs
new file mode 100644
index 000000000..10fffcbf0
--- /dev/null
+++ b/win/CS/HandBrakeWPF/Services/Queue/ActiveJob.cs
@@ -0,0 +1,131 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="ActiveJob.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// Defines the ActiveJob type.
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Services.Queue
+{
+ using System;
+
+ using HandBrake.Interop.Interop.Providers.Interfaces;
+
+ using HandBrakeWPF.Services.Encode;
+ using HandBrakeWPF.Services.Encode.EventArgs;
+ using HandBrakeWPF.Services.Encode.Interfaces;
+ using HandBrakeWPF.Services.Interfaces;
+ using HandBrakeWPF.Services.Logging.Interfaces;
+ using HandBrakeWPF.Services.Queue.JobEventArgs;
+ using HandBrakeWPF.Services.Queue.Model;
+
+ public class ActiveJob : IDisposable
+ {
+ private readonly QueueTask job;
+ private readonly IEncode encodeService;
+
+ public ActiveJob(QueueTask task, IHbFunctionsProvider hbFunctionsProvider, IUserSettingService userSettingService, ILogInstanceManager logInstanceManager, int jobId)
+ {
+ this.job = task;
+ this.encodeService = new LibEncode(hbFunctionsProvider, userSettingService, logInstanceManager, jobId);
+ }
+
+ public event EventHandler<ActiveJobCompletedEventArgs> JobFinished;
+
+ public event EventHandler<EncodeProgressEventArgs> JobStatusUpdated;
+
+ public QueueTask Job => this.job;
+
+ public bool IsPaused { get; private set; }
+
+ public bool IsEncoding { get; set; }
+
+ public void Start()
+ {
+ this.IsPaused = false;
+ this.IsEncoding = true;
+
+ if (this.encodeService.IsPasued)
+ {
+ this.encodeService.Resume();
+ this.job.Statistics.SetPaused(false);
+ this.job.Status = QueueItemStatus.InProgress;
+ }
+ else if (!this.encodeService.IsEncoding)
+ {
+ this.job.Status = QueueItemStatus.InProgress;
+ this.job.Statistics.StartTime = DateTime.Now;
+
+ this.encodeService.EncodeCompleted += this.EncodeServiceEncodeCompleted;
+ this.encodeService.EncodeStatusChanged += this.EncodeStatusChanged;
+ this.encodeService.Start(this.job.Task, this.job.Configuration, this.job.SelectedPresetKey);
+ }
+ }
+
+ public void Pause()
+ {
+ if (this.encodeService.IsEncoding && !this.encodeService.IsPasued)
+ {
+ this.IsPaused = true;
+ this.encodeService.Pause();
+ this.job.Statistics.SetPaused(true);
+ this.job.Status = QueueItemStatus.Paused;
+ this.IsEncoding = false;
+ }
+ }
+
+ public void Stop()
+ {
+ if (this.encodeService.IsEncoding)
+ {
+ this.encodeService.Stop();
+ }
+
+ this.IsEncoding = false;
+ this.IsPaused = false;
+ this.encodeService.EncodeStatusChanged -= this.EncodeStatusChanged;
+ }
+
+ public void Dispose()
+ {
+ this.encodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted;
+ this.encodeService.EncodeStatusChanged -= this.EncodeStatusChanged;
+ }
+
+ private void EncodeStatusChanged(object sender, EncodeProgressEventArgs e)
+ {
+ this.job?.JobProgress.Update(e);
+ this.OnJobStatusUpdated(e);
+ }
+
+ private void EncodeServiceEncodeCompleted(object sender, EncodeCompletedEventArgs e)
+ {
+ this.IsEncoding = false;
+ this.IsPaused = false;
+
+ this.job.Status = !e.Successful ? QueueItemStatus.Error : QueueItemStatus.Completed;
+ this.job.Statistics.EndTime = DateTime.Now;
+ this.job.Statistics.CompletedActivityLogPath = e.ActivityLogPath;
+ this.job.Statistics.FinalFileSize = e.FinalFilesizeInBytes;
+
+ this.job.JobProgress.ClearStatusDisplay();
+
+ this.encodeService.EncodeStatusChanged -= this.EncodeStatusChanged;
+ this.encodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted;
+
+ this.OnJobFinished(e);
+ }
+
+ private void OnJobFinished(EncodeCompletedEventArgs e)
+ {
+ this.JobFinished?.Invoke(this, new ActiveJobCompletedEventArgs(this, e));
+ }
+
+ private void OnJobStatusUpdated(EncodeProgressEventArgs e)
+ {
+ this.JobStatusUpdated?.Invoke(this, e);
+ }
+ }
+}
diff --git a/win/CS/HandBrakeWPF/Services/Queue/Interfaces/IQueueService.cs b/win/CS/HandBrakeWPF/Services/Queue/Interfaces/IQueueService.cs
index 1bab4f01d..1a2a04cce 100644
--- a/win/CS/HandBrakeWPF/Services/Queue/Interfaces/IQueueService.cs
+++ b/win/CS/HandBrakeWPF/Services/Queue/Interfaces/IQueueService.cs
@@ -10,24 +10,29 @@
namespace HandBrakeWPF.Services.Queue.Interfaces
{
using System;
+ using System.Collections.Generic;
using System.Collections.ObjectModel;
- using System.ComponentModel;
- using HandBrakeWPF.Services.Queue.Model;
- using IEncode = Encode.Interfaces.IEncode;
+ using HandBrakeWPF.EventArgs;
+ using HandBrakeWPF.Services.Encode.EventArgs;
+ using HandBrakeWPF.Services.Encode.Interfaces;
+ using HandBrakeWPF.Services.Queue.Model;
/// <summary>
/// The Queue Processor
/// </summary>
public interface IQueueService
{
- #region Events
-
/// <summary>
/// Fires when the Queue has started
/// </summary>
- event QueueService.QueueProgressStatus JobProcessingStarted;
+ event EventHandler<QueueProgressEventArgs> JobProcessingStarted;
+
+ /// <summary>
+ /// Fires when the status of any running job changes on the queue. Including progress.
+ /// </summary>
+ event EventHandler QueueJobStatusChanged;
/// <summary>
/// Fires when a job is Added, Removed or Re-Ordered.
@@ -38,16 +43,14 @@ namespace HandBrakeWPF.Services.Queue.Interfaces
/// <summary>
/// Fires when the entire encode queue has completed.
/// </summary>
- event QueueService.QueueCompletedEventDelegate QueueCompleted;
+ event EventHandler<QueueCompletedEventArgs> QueueCompleted;
/// <summary>
/// Fires when a pause to the encode queue has been requested.
/// </summary>
event EventHandler QueuePaused;
- #endregion
-
- #region Properties
+ event EventHandler<EncodeCompletedEventArgs> EncodeCompleted;
/// <summary>
/// Gets the number of jobs in the queue
@@ -60,30 +63,19 @@ namespace HandBrakeWPF.Services.Queue.Interfaces
int ErrorCount { get; }
/// <summary>
- /// Gets the IEncodeService instance.
- /// </summary>
- IEncode EncodeService { get; }
-
- /// <summary>
/// Gets a value indicating whether IsProcessing.
/// </summary>
bool IsProcessing { get; }
- /// <summary>
- /// Gets or sets Last Processed Job.
- /// This is set when the job is poped of the queue by GetNextJobForProcessing();
- /// </summary>
- QueueTask LastProcessedJob { get; set; }
+ bool IsEncoding { get; }
+
+ bool IsPaused { get; }
/// <summary>
/// Gets The current queue.
/// </summary>
ObservableCollection<QueueTask> Queue { get; }
- #endregion
-
- #region Public Methods
-
/// <summary>
/// Add a job to the Queue.
/// This method is Thread Safe.
@@ -223,12 +215,15 @@ namespace HandBrakeWPF.Services.Queue.Interfaces
/// Pause the queue but allow the current encode to complete.
/// </summary>
void Pause();
-
+
/// <summary>
- /// Pause and Encode and the Queue.
+ /// Get the status of all running queue jobs.
/// </summary>
- void PauseEncode();
+ /// <returns>
+ /// A list of QueueProgressStatus items
+ /// </returns>
+ List<QueueProgressStatus> GetQueueProgressStatus();
- #endregion
+ List<string> GetActiveJobDestinationDirectories();
}
} \ No newline at end of file
diff --git a/win/CS/HandBrakeWPF/Services/Queue/JobEventArgs/ActiveJobCompletedEventArgs.cs b/win/CS/HandBrakeWPF/Services/Queue/JobEventArgs/ActiveJobCompletedEventArgs.cs
new file mode 100644
index 000000000..dae67e640
--- /dev/null
+++ b/win/CS/HandBrakeWPF/Services/Queue/JobEventArgs/ActiveJobCompletedEventArgs.cs
@@ -0,0 +1,25 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="ActiveJobCompletedEventArgs.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Services.Queue.JobEventArgs
+{
+ using System;
+
+ using HandBrakeWPF.Services.Encode.EventArgs;
+
+ public class ActiveJobCompletedEventArgs : EventArgs
+ {
+ public ActiveJobCompletedEventArgs(ActiveJob job, EncodeCompletedEventArgs encodeCompletedEventArgs)
+ {
+ this.EncodeEventArgs = encodeCompletedEventArgs;
+ this.Job = job;
+ }
+
+ public ActiveJob Job { get; private set; }
+
+ public EncodeCompletedEventArgs EncodeEventArgs { get; private set; }
+ }
+}
diff --git a/win/CS/HandBrakeWPF/Services/Queue/Model/QueueItemStatus.cs b/win/CS/HandBrakeWPF/Services/Queue/Model/QueueItemStatus.cs
index c398e6a32..d7d0dbce2 100644
--- a/win/CS/HandBrakeWPF/Services/Queue/Model/QueueItemStatus.cs
+++ b/win/CS/HandBrakeWPF/Services/Queue/Model/QueueItemStatus.cs
@@ -27,5 +27,8 @@ namespace HandBrakeWPF.Services.Queue.Model
[DisplayName("Error")]
Error,
+
+ [DisplayName("Paused")]
+ Paused,
}
}
diff --git a/win/CS/HandBrakeWPF/Services/Queue/Model/QueueProgressStatus.cs b/win/CS/HandBrakeWPF/Services/Queue/Model/QueueProgressStatus.cs
new file mode 100644
index 000000000..f759dfeb8
--- /dev/null
+++ b/win/CS/HandBrakeWPF/Services/Queue/Model/QueueProgressStatus.cs
@@ -0,0 +1,133 @@
+// --------------------------------------------------------------------------------------------------------------------
+// <copyright file="QueueProgressStatus.cs" company="HandBrake Project (http://handbrake.fr)">
+// This file is part of the HandBrake source code - It may be used under the terms of the GNU General Public License.
+// </copyright>
+// <summary>
+// Defines the QueueProgressStatus type.
+// </summary>
+// --------------------------------------------------------------------------------------------------------------------
+
+namespace HandBrakeWPF.Services.Queue.Model
+{
+ using System;
+ using System.Xaml;
+
+ using Caliburn.Micro;
+
+ using HandBrakeWPF.Properties;
+ using HandBrakeWPF.Services.Encode.EventArgs;
+
+ public class QueueProgressStatus : PropertyChangedBase
+ {
+ private string jobStatus;
+ private bool intermediateProgress;
+ private double progressValue;
+
+ private EncodeProgressEventArgs progressEventArgs;
+
+ public QueueProgressStatus()
+ {
+ }
+
+ public string JobStatus
+ {
+ get
+ {
+ return this.jobStatus;
+ }
+
+ set
+ {
+ this.jobStatus = value;
+ this.NotifyOfPropertyChange(() => this.JobStatus);
+ }
+ }
+
+ public bool IntermediateProgress
+ {
+ get => this.intermediateProgress;
+ set
+ {
+ if (value == this.intermediateProgress) return;
+ this.intermediateProgress = value;
+ this.NotifyOfPropertyChange(() => this.IntermediateProgress);
+ }
+ }
+
+ public double ProgressValue
+ {
+ get => this.progressValue;
+ set
+ {
+ if (value == this.progressValue) return;
+ this.progressValue = value;
+ this.NotifyOfPropertyChange(() => this.ProgressValue);
+ }
+ }
+
+ public int? Task => this.progressEventArgs?.Task ?? 0;
+
+ public int? TaskCount => this.progressEventArgs?.TaskCount ?? 0;
+
+ public TimeSpan? EstimatedTimeLeft => this.progressEventArgs?.EstimatedTimeLeft ?? null;
+
+ public void Update(EncodeProgressEventArgs e)
+ {
+ progressEventArgs = e;
+ this.IntermediateProgress = false;
+
+ string totalHrsLeft = e.EstimatedTimeLeft.Days >= 1 ? string.Format(@"{0:d\:hh\:mm\:ss}", e.EstimatedTimeLeft) : string.Format(@"{0:hh\:mm\:ss}", e.EstimatedTimeLeft);
+ string elapsedTimeHrs = e.ElapsedTime.Days >= 1 ? string.Format(@"{0:d\:hh\:mm\:ss}", e.ElapsedTime) : string.Format(@"{0:hh\:mm\:ss}", e.ElapsedTime);
+
+ if (e.IsSubtitleScan)
+ {
+ this.JobStatus = string.Format(Resources.MainViewModel_EncodeStatusChanged_SubScan_StatusLabel,
+ e.Task,
+ e.TaskCount,
+ e.PercentComplete,
+ totalHrsLeft,
+ elapsedTimeHrs,
+ null);
+
+ this.ProgressValue = e.PercentComplete;
+ }
+ else if (e.IsMuxing)
+ {
+ this.JobStatus = Resources.MainView_Muxing;
+ this.IntermediateProgress = true;
+ }
+ else if (e.IsSearching)
+ {
+ this.JobStatus = string.Format(Resources.MainView_ProgressStatusWithTask, Resources.MainView_Searching, e.PercentComplete, e.EstimatedTimeLeft, null);
+ this.ProgressValue = e.PercentComplete;
+ }
+ else
+ {
+ this.JobStatus =
+ string.Format(Resources.QueueViewModel_EncodeStatusChanged_StatusLabel,
+ e.Task,
+ e.TaskCount,
+ e.PercentComplete,
+ e.CurrentFrameRate,
+ e.AverageFrameRate,
+ totalHrsLeft,
+ elapsedTimeHrs,
+ null);
+ this.ProgressValue = e.PercentComplete;
+ }
+ }
+
+ public void SetPaused()
+ {
+ this.ClearStatusDisplay();
+ this.JobStatus = Resources.QueueViewModel_QueuePaused;
+ }
+
+ public void ClearStatusDisplay()
+ {
+ this.JobStatus = string.Empty;
+ this.ProgressValue = 0;
+ this.IntermediateProgress = false;
+ }
+ }
+}
diff --git a/win/CS/HandBrakeWPF/Services/Queue/Model/QueueTask.cs b/win/CS/HandBrakeWPF/Services/Queue/Model/QueueTask.cs
index 3ee126ce9..208c721e4 100644
--- a/win/CS/HandBrakeWPF/Services/Queue/Model/QueueTask.cs
+++ b/win/CS/HandBrakeWPF/Services/Queue/Model/QueueTask.cs
@@ -35,6 +35,7 @@ namespace HandBrakeWPF.Services.Queue.Model
id = id + 1;
this.Id = string.Format("{0}.{1}", GeneralUtilities.ProcessId, id);
this.Statistics = new QueueStats();
+ this.JobProgress = new QueueProgressStatus();
}
public QueueTask(EncodeTask task, HBConfiguration configuration, string scannedSourcePath, Preset currentPreset, bool isPresetModified)
@@ -57,6 +58,7 @@ namespace HandBrakeWPF.Services.Queue.Model
this.Statistics = new QueueStats();
this.TaskId = Guid.NewGuid().ToString();
+ this.JobProgress = new QueueProgressStatus();
}
[JsonProperty]
@@ -81,6 +83,7 @@ namespace HandBrakeWPF.Services.Queue.Model
this.status = value;
this.NotifyOfPropertyChange(() => this.Status);
this.NotifyOfPropertyChange(() => this.ShowEncodeProgress);
+ this.NotifyOfPropertyChange(() => this.IsJobStatusVisible);
}
}
@@ -94,6 +97,12 @@ namespace HandBrakeWPF.Services.Queue.Model
public QueueStats Statistics { get; set; }
[JsonIgnore]
+ public QueueProgressStatus JobProgress { get; set; }
+
+ [JsonIgnore]
+ public bool IsJobStatusVisible => this.Status == QueueItemStatus.InProgress;
+
+ [JsonIgnore]
public string SelectedPresetKey
{
get
diff --git a/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs b/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs
index 9ebd4d33b..6cbf709e5 100644
--- a/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs
+++ b/win/CS/HandBrakeWPF/Services/Queue/QueueService.cs
@@ -12,12 +12,10 @@ namespace HandBrakeWPF.Services.Queue
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
- using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Windows;
- using System.Windows.Media.Imaging;
using Caliburn.Micro;
@@ -33,6 +31,9 @@ namespace HandBrakeWPF.Services.Queue
using HandBrakeWPF.Services.Encode.Factories;
using HandBrakeWPF.Services.Encode.Model;
using HandBrakeWPF.Services.Interfaces;
+ using HandBrakeWPF.Services.Logging.Interfaces;
+ using HandBrakeWPF.Services.Queue.Interfaces;
+ using HandBrakeWPF.Services.Queue.JobEventArgs;
using HandBrakeWPF.Services.Queue.Model;
using HandBrakeWPF.Utilities;
@@ -41,46 +42,53 @@ namespace HandBrakeWPF.Services.Queue
using EncodeCompletedEventArgs = HandBrakeWPF.Services.Encode.EventArgs.EncodeCompletedEventArgs;
using Execute = Caliburn.Micro.Execute;
using GeneralApplicationException = HandBrakeWPF.Exceptions.GeneralApplicationException;
- using IEncode = HandBrakeWPF.Services.Encode.Interfaces.IEncode;
using ILog = HandBrakeWPF.Services.Logging.Interfaces.ILog;
- using LogService = HandBrakeWPF.Services.Logging.LogService;
using QueueCompletedEventArgs = HandBrakeWPF.EventArgs.QueueCompletedEventArgs;
using QueueProgressEventArgs = HandBrakeWPF.EventArgs.QueueProgressEventArgs;
- public class QueueService : Interfaces.IQueueService
+ public class QueueService : IQueueService
{
private static readonly object QueueLock = new object();
+
+ private readonly List<ActiveJob> activeJobs = new List<ActiveJob>();
private readonly IUserSettingService userSettingService;
private readonly ILog logService;
private readonly IErrorService errorService;
+ private readonly ILogInstanceManager logInstanceManager;
+ private readonly IHbFunctionsProvider hbFunctionsProvider;
private readonly ObservableCollection<QueueTask> queue = new ObservableCollection<QueueTask>();
private readonly string queueFile;
private bool clearCompleted;
+ private int allowedInstances;
+ private int jobIdCounter = 0;
- public QueueService(IEncode encodeService, IUserSettingService userSettingService, ILog logService, IErrorService errorService)
+ public QueueService(IUserSettingService userSettingService, ILog logService, IErrorService errorService, ILogInstanceManager logInstanceManager, IHbFunctionsProvider hbFunctionsProvider)
{
this.userSettingService = userSettingService;
this.logService = logService;
this.errorService = errorService;
- this.EncodeService = encodeService;
+ this.logInstanceManager = logInstanceManager;
+ this.hbFunctionsProvider = hbFunctionsProvider;
// If this is the first instance, just use the main queue file, otherwise add the instance id to the filename.
this.queueFile = string.Format("{0}{1}.json", QueueRecoveryHelper.QueueFileName, GeneralUtilities.ProcessId);
- }
- public delegate void QueueProgressStatus(object sender, QueueProgressEventArgs e);
-
- public delegate void QueueCompletedEventDelegate(object sender, QueueCompletedEventArgs e);
+ this.allowedInstances = this.userSettingService.GetUserSetting<int>(UserSettingConstants.SimultaneousEncodes);
+ }
- public event QueueProgressStatus JobProcessingStarted;
+ public event EventHandler<QueueProgressEventArgs> JobProcessingStarted;
public event EventHandler QueueChanged;
- public event QueueCompletedEventDelegate QueueCompleted;
+ public event EventHandler<QueueCompletedEventArgs> QueueCompleted;
public event EventHandler QueuePaused;
+ public event EventHandler QueueJobStatusChanged;
+
+ public event EventHandler<EncodeCompletedEventArgs> EncodeCompleted;
+
public int Count
{
get
@@ -97,11 +105,11 @@ namespace HandBrakeWPF.Services.Queue
}
}
- public IEncode EncodeService { get; private set; }
+ public bool IsPaused { get; private set; }
public bool IsProcessing { get; private set; }
- public QueueTask LastProcessedJob { get; set; }
+ public bool IsEncoding => this.activeJobs.Any(service => service.IsEncoding);
public ObservableCollection<QueueTask> Queue
{
@@ -110,8 +118,7 @@ namespace HandBrakeWPF.Services.Queue
return this.queue;
}
}
-
-
+
public void Add(QueueTask job)
{
lock (QueueLock)
@@ -227,7 +234,7 @@ namespace HandBrakeWPF.Services.Queue
foreach (QueueTask task in reloadedQueue)
{
// Reset the imported jobs that were running in a previous session.
- if (task.Status == QueueItemStatus.InProgress)
+ if (task.Status == QueueItemStatus.InProgress || task.Status == QueueItemStatus.Paused)
{
task.Status = QueueItemStatus.Waiting;
task.Statistics.Reset();
@@ -249,8 +256,7 @@ namespace HandBrakeWPF.Services.Queue
}
}
}
-
-
+
public bool CheckForDestinationPathDuplicates(string destination)
{
foreach (QueueTask job in this.queue)
@@ -396,7 +402,7 @@ namespace HandBrakeWPF.Services.Queue
if (item.Status != QueueItemStatus.Completed)
{
// Reset InProgress/Error to Waiting so it can be processed
- if (item.Status == QueueItemStatus.InProgress)
+ if (item.Status == QueueItemStatus.InProgress || item.Status == QueueItemStatus.Paused)
{
item.Status = QueueItemStatus.Error;
}
@@ -418,19 +424,17 @@ namespace HandBrakeWPF.Services.Queue
public void Pause()
{
- this.IsProcessing = false;
- this.InvokeQueuePaused(EventArgs.Empty);
- }
-
- public void PauseEncode()
- {
- if (this.EncodeService.IsEncoding && !this.EncodeService.IsPasued)
+ foreach (ActiveJob job in this.activeJobs)
{
- this.EncodeService.Pause();
- this.LastProcessedJob.Statistics.SetPaused(true);
+ if (job.IsEncoding && !job.IsPaused)
+ {
+ job.Pause();
+ }
}
-
- this.Pause();
+
+ this.IsProcessing = false;
+ this.IsPaused = true;
+ this.InvokeQueuePaused(EventArgs.Empty);
}
public void Start(bool isClearCompleted)
@@ -440,89 +444,63 @@ namespace HandBrakeWPF.Services.Queue
return;
}
+ this.IsPaused = false;
this.clearCompleted = isClearCompleted;
- this.EncodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted;
- this.EncodeService.EncodeCompleted += this.EncodeServiceEncodeCompleted;
-
- if (this.EncodeService.IsPasued)
+ // Unpause all active jobs.
+ foreach (ActiveJob job in this.activeJobs)
{
- this.EncodeService.Resume();
- this.IsProcessing = true;
- this.InvokeJobProcessingStarted(new QueueProgressEventArgs(this.LastProcessedJob));
- this.LastProcessedJob.Statistics.SetPaused(false);
+ job.Start();
+ this.InvokeJobProcessingStarted(new QueueProgressEventArgs(job.Job));
}
- if (!this.EncodeService.IsEncoding)
- {
- this.ProcessNextJob();
- }
- else
- {
- this.IsProcessing = true;
- }
+ this.ProcessNextJob();
+ this.IsProcessing = true;
}
public void Stop()
{
- if (this.EncodeService.IsEncoding)
+ foreach (ActiveJob job in this.activeJobs)
{
- this.EncodeService.Stop();
+ if (job.IsEncoding || job.IsPaused)
+ {
+ job.Stop();
+ }
}
this.IsProcessing = false;
- this.InvokeQueuePaused(EventArgs.Empty);
+ this.IsPaused = false;
+ this.InvokeQueueChanged(EventArgs.Empty);
+ this.InvokeQueueCompleted(new QueueCompletedEventArgs(true));
}
- protected virtual void OnQueueCompleted(QueueCompletedEventArgs e)
+ public List<QueueProgressStatus> GetQueueProgressStatus()
{
- QueueCompletedEventDelegate handler = this.QueueCompleted;
- if (handler != null)
+ // TODO make thread safe.
+ List<QueueProgressStatus> statuses = new List<QueueProgressStatus>();
+ foreach (ActiveJob job in this.activeJobs)
{
- handler(this, e);
+ statuses.Add(job.Job.JobProgress);
}
- this.IsProcessing = false;
+ return statuses;
}
- private void EncodeServiceEncodeCompleted(object sender, EncodeCompletedEventArgs e)
+ public List<string> GetActiveJobDestinationDirectories()
{
- this.LastProcessedJob.Status = QueueItemStatus.Completed;
- this.LastProcessedJob.Statistics.EndTime = DateTime.Now;
- this.LastProcessedJob.Statistics.CompletedActivityLogPath = e.ActivityLogPath;
- this.LastProcessedJob.Statistics.FinalFileSize = e.FinalFilesizeInBytes;
-
- // Clear the completed item of the queue if the setting is set.
- if (this.clearCompleted)
- {
- this.ClearCompleted();
- }
-
- if (!e.Successful)
+ // TODO need to make thread safe.
+ List<string> directories = new List<string>();
+ foreach (ActiveJob job in this.activeJobs)
{
- this.LastProcessedJob.Status = QueueItemStatus.Error;
+ directories.Add(job.Job.Task.Destination);
}
- // Move onto the next job.
- if (this.IsProcessing)
- {
- this.ProcessNextJob();
- }
- else
- {
- this.EncodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted;
- this.BackupQueue(string.Empty);
- this.OnQueueCompleted(new QueueCompletedEventArgs(true));
- }
+ return directories;
}
private void InvokeJobProcessingStarted(QueueProgressEventArgs e)
{
- QueueProgressStatus handler = this.JobProcessingStarted;
- if (handler != null)
- {
- handler(this, e);
- }
+ this.JobProcessingStarted?.Invoke(this, e);
}
private void InvokeQueueChanged(EventArgs e)
@@ -542,73 +520,90 @@ namespace HandBrakeWPF.Services.Queue
handler(this, e);
}
}
-
- private void InvokeQueuePaused(EventArgs e)
+
+ private void ProcessNextJob()
{
- this.IsProcessing = false;
-
- EventHandler handler = this.QueuePaused;
- if (handler != null)
+ if (this.activeJobs.Count >= this.allowedInstances)
{
- handler(this, e);
+ return;
}
- }
- private void ProcessNextJob()
- {
QueueTask job = this.GetNextJobForProcessing();
if (job != null)
{
- if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PauseOnLowDiskspace) && !DriveUtilities.HasMinimumDiskSpace(job.Task.Destination, this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseQueueOnLowDiskspaceLevel)))
+ if (CheckDiskSpace(job))
{
- this.logService.LogMessage(Resources.PauseOnLowDiskspace);
- job.Status = QueueItemStatus.Waiting;
- this.Pause();
- this.BackupQueue(string.Empty);
return; // Don't start the next job.
}
- job.Status = QueueItemStatus.InProgress;
- job.Statistics.StartTime = DateTime.Now;
- this.LastProcessedJob = job;
+ this.jobIdCounter = this.jobIdCounter + 1;
+ ActiveJob activeJob = new ActiveJob(job, this.hbFunctionsProvider, this.userSettingService, this.logInstanceManager, this.jobIdCounter);
+ activeJob.JobFinished += this.ActiveJob_JobFinished;
+ activeJob.JobStatusUpdated += this.ActiveJob_JobStatusUpdated;
+ this.activeJobs.Add(activeJob);
+
+ activeJob.Start();
+
this.IsProcessing = true;
this.InvokeQueueChanged(EventArgs.Empty);
this.InvokeJobProcessingStarted(new QueueProgressEventArgs(job));
-
- if (!Directory.Exists(Path.GetDirectoryName(job.Task.Destination)))
- {
- this.EncodeServiceEncodeCompleted(null, new EncodeCompletedEventArgs(false, null, "Destination Directory Missing", null, null, null, 0));
- this.BackupQueue(string.Empty);
- return;
- }
-
- this.EncodeService.Start(job.Task, job.Configuration, job.SelectedPresetKey);
this.BackupQueue(string.Empty);
+
+ this.ProcessNextJob();
}
else
{
- // No more jobs to process, so unsubscribe the event
- this.EncodeService.EncodeCompleted -= this.EncodeServiceEncodeCompleted;
-
this.BackupQueue(string.Empty);
// Fire the event to tell connected services.
- this.OnQueueCompleted(new QueueCompletedEventArgs(false));
- }
- }
-
- /// <summary>
- /// For a given set of tasks, return the Queue JSON that can be used for the CLI.
- /// </summary>
- /// <param name="tasks">
- /// The tasks.
- /// </param>
- /// <param name="configuration">
- /// The configuration.
- /// </param>
- /// <returns>
- /// The <see cref="string"/>.
- /// </returns>
+ this.InvokeQueueCompleted(new QueueCompletedEventArgs(false));
+ }
+ }
+
+ private void ActiveJob_JobStatusUpdated(object sender, Encode.EventArgs.EncodeProgressEventArgs e)
+ {
+ this.OnQueueJobStatusChanged();
+ }
+
+ private void ActiveJob_JobFinished(object sender, ActiveJobCompletedEventArgs e)
+ {
+ this.activeJobs.Remove(e.Job);
+ this.OnEncodeCompleted(e.EncodeEventArgs);
+
+ if (!this.IsPaused && this.IsProcessing)
+ {
+ this.ProcessNextJob();
+ }
+ }
+
+ private void InvokeQueueCompleted(QueueCompletedEventArgs e)
+ {
+ this.IsProcessing = false;
+ this.QueueCompleted?.Invoke(this, e);
+ }
+
+ private void OnQueueJobStatusChanged()
+ {
+ // TODO add support for delayed notificaitons here to avoid overloading the UI when we run multiple encodes.
+ this.QueueJobStatusChanged?.Invoke(this, EventArgs.Empty);
+ }
+
+ private void OnEncodeCompleted(EncodeCompletedEventArgs e)
+ {
+ this.EncodeCompleted?.Invoke(this, e);
+ }
+
+ private void InvokeQueuePaused(EventArgs e)
+ {
+ this.IsProcessing = false;
+
+ EventHandler handler = this.QueuePaused;
+ if (handler != null)
+ {
+ handler(this, e);
+ }
+ }
+
private string GetQueueJson(List<EncodeTask> tasks, HBConfiguration configuration)
{
JsonSerializerSettings settings = new JsonSerializerSettings
@@ -628,5 +623,19 @@ namespace HandBrakeWPF.Services.Queue
return JsonConvert.SerializeObject(queueJobs, Formatting.Indented, settings);
}
+
+ private bool CheckDiskSpace(QueueTask job)
+ {
+ if (this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PauseOnLowDiskspace) && !DriveUtilities.HasMinimumDiskSpace(job.Task.Destination, this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseQueueOnLowDiskspaceLevel)))
+ {
+ this.logService.LogMessage(Resources.PauseOnLowDiskspace);
+ job.Status = QueueItemStatus.Waiting;
+ this.Pause();
+ this.BackupQueue(string.Empty);
+ return true; // Don't start the next job.
+ }
+
+ return false;
+ }
}
} \ No newline at end of file
diff --git a/win/CS/HandBrakeWPF/Services/SystemService.cs b/win/CS/HandBrakeWPF/Services/SystemService.cs
index d9fa46716..e07281b3b 100644
--- a/win/CS/HandBrakeWPF/Services/SystemService.cs
+++ b/win/CS/HandBrakeWPF/Services/SystemService.cs
@@ -13,7 +13,6 @@ namespace HandBrakeWPF.Services
using System.Timers;
using HandBrakeWPF.Properties;
- using HandBrakeWPF.Services.Encode.Interfaces;
using HandBrakeWPF.Services.Interfaces;
using HandBrakeWPF.Services.Logging.Interfaces;
using HandBrakeWPF.Services.Queue.Interfaces;
@@ -22,23 +21,20 @@ namespace HandBrakeWPF.Services
public class SystemService : ISystemService
{
private readonly IUserSettingService userSettingService;
- private readonly IEncode encodeService;
- private readonly ILog log = null;
private readonly IQueueService queueService;
+ private readonly ILog log;
private Timer pollTimer;
- private bool criticalStateHit = false;
private bool lowStateHit = false;
private bool lowPowerPause = false;
private bool storageLowPause = false;
- public SystemService(IUserSettingService userSettingService, IEncode encodeService, ILog logService, IQueueService queueService)
+ public SystemService(IUserSettingService userSettingService, ILog logService, IQueueService queueService)
{
this.log = logService;
this.queueService = queueService;
this.userSettingService = userSettingService;
- this.encodeService = encodeService;
}
public void Start()
@@ -64,8 +60,15 @@ namespace HandBrakeWPF.Services
private void StorageCheck()
{
- string directory = this.encodeService.GetActiveJob()?.Destination;
- if (!string.IsNullOrEmpty(directory) && this.encodeService.IsEncoding)
+ foreach (string directory in this.queueService.GetActiveJobDestinationDirectories())
+ {
+ this.CheckDiskSpaceForDirectory(directory);
+ }
+ }
+
+ private void CheckDiskSpaceForDirectory(string directory)
+ {
+ if (!string.IsNullOrEmpty(directory) && this.queueService.IsEncoding)
{
long lowLevel = this.userSettingService.GetUserSetting<long>(UserSettingConstants.PauseQueueOnLowDiskspaceLevel);
if (!this.storageLowPause && this.userSettingService.GetUserSetting<bool>(UserSettingConstants.PauseOnLowDiskspace) && !DriveUtilities.HasMinimumDiskSpace(directory, lowLevel))
@@ -98,7 +101,7 @@ namespace HandBrakeWPF.Services
if (state.ACLineStatus == Win32.ACLineStatus.Offline && state.BatteryLifePercent <= lowBatteryLevel && !this.lowStateHit)
{
- if (this.encodeService.IsEncoding && !this.encodeService.IsPasued)
+ if (this.queueService.IsEncoding && !this.queueService.IsPaused)
{
this.lowPowerPause = true;
this.queueService.Pause();
@@ -113,14 +116,13 @@ namespace HandBrakeWPF.Services
// Reset the flags when we start charging.
if (state.ACLineStatus == Win32.ACLineStatus.Online)
{
- if (this.lowPowerPause && this.encodeService.IsPasued)
+ if (this.lowPowerPause && this.queueService.IsPaused)
{
this.queueService.Start(this.userSettingService.GetUserSetting<bool>(UserSettingConstants.ClearCompletedFromQueue));
this.ServiceLogMessage(string.Format(Resources.SystemService_ACMains, state.BatteryLifePercent));
}
this.lowPowerPause = false;
- this.criticalStateHit = false;
this.lowStateHit = false;
}
}
diff --git a/win/CS/HandBrakeWPF/Services/UserSettingService.cs b/win/CS/HandBrakeWPF/Services/UserSettingService.cs
index 91ef1e5b7..095e6f819 100644
--- a/win/CS/HandBrakeWPF/Services/UserSettingService.cs
+++ b/win/CS/HandBrakeWPF/Services/UserSettingService.cs
@@ -306,6 +306,7 @@ namespace HandBrakeWPF.Services
// Experimental
defaults.Add(UserSettingConstants.ProcessIsolationEnabled, true);
defaults.Add(UserSettingConstants.ProcessIsolationPort, 8037);
+ defaults.Add(UserSettingConstants.SimultaneousEncodes, 1);
// Misc
defaults.Add(UserSettingConstants.ShowPresetPanel, false);