summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--win/C#/Services/Encode.cs537
-rw-r--r--win/C#/Services/Queue.cs387
-rw-r--r--win/C#/Services/Scan.cs265
3 files changed, 1189 insertions, 0 deletions
diff --git a/win/C#/Services/Encode.cs b/win/C#/Services/Encode.cs
new file mode 100644
index 000000000..d73a4a6ec
--- /dev/null
+++ b/win/C#/Services/Encode.cs
@@ -0,0 +1,537 @@
+/* Encode.cs $
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+
+namespace Handbrake.Services
+{
+ using System;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Text;
+ using System.Threading;
+ using System.Windows.Forms;
+ using Functions;
+ using Model;
+ using Properties;
+ using Timer = System.Threading.Timer;
+
+ /// <summary>
+ /// Class which handles the CLI
+ /// </summary>
+ public class Encode
+ {
+ /// <summary>
+ /// An Encode Job
+ /// </summary>
+ private Job job;
+
+ /// <summary>
+ /// The Log Buffer
+ /// </summary>
+ private StringBuilder logBuffer;
+
+ /// <summary>
+ /// The line number thats been read to in the log file
+ /// </summary>
+ private int logFilePosition;
+
+ /// <summary>
+ /// A Timer for this window
+ /// </summary>
+ private Timer windowTimer;
+
+ /// <summary>
+ /// Fires when a new CLI Job starts
+ /// </summary>
+ public event EventHandler EncodeStarted;
+
+ /// <summary>
+ /// Fires when a CLI job finishes.
+ /// </summary>
+ public event EventHandler EncodeEnded;
+
+ /// <summary>
+ /// Gets or sets The HB Process
+ /// </summary>
+ public Process HbProcess { get; set; }
+
+ /// <summary>
+ /// Gets or sets The Process Handle
+ /// </summary>
+ public IntPtr ProcessHandle { get; set; }
+
+ /// <summary>
+ /// Gets or sets a value indicating whether HandBrakeCLI.exe is running
+ /// </summary>
+ public bool IsEncoding { get; set; }
+
+ /// <summary>
+ /// Gets or sets the Process ID
+ /// </summary>
+ public int ProcessID { get; set; }
+
+ /// <summary>
+ /// Gets ActivityLog.
+ /// </summary>
+ public string ActivityLog
+ {
+ get
+ {
+ if (logBuffer != null)
+ return logBuffer.ToString();
+
+ return string.Empty;
+ }
+ }
+
+ /// <summary>
+ /// Create a preview sample video
+ /// </summary>
+ /// <param name="query">
+ /// The CLI Query
+ /// </param>
+ public void CreatePreviewSample(string query)
+ {
+ Job job = new Job {Query = query};
+ this.Run(job);
+ }
+
+ /// <summary>
+ /// Kill the CLI process
+ /// </summary>
+ public void Stop()
+ {
+ if (this.HbProcess != null)
+ this.HbProcess.Kill();
+
+ Process[] list = Process.GetProcessesByName("HandBrakeCLI");
+ foreach (Process process in list)
+ process.Kill();
+
+ if (this.EncodeEnded != null)
+ this.EncodeEnded(this, new EventArgs());
+
+ IsEncoding = false;
+ }
+
+ /// <summary>
+ /// Attempt to Safely kill a DirectRun() CLI
+ /// NOTE: This will not work with a MinGW CLI
+ /// Note: http://www.cygwin.com/ml/cygwin/2006-03/msg00330.html
+ /// </summary>
+ public void SafelyClose()
+ {
+ if ((int)this.ProcessHandle == 0)
+ return;
+
+ // Allow the CLI to exit cleanly
+ Win32.SetForegroundWindow((int)this.ProcessHandle);
+ SendKeys.Send("^C");
+ SendKeys.Flush();
+
+ // HbProcess.StandardInput.AutoFlush = true;
+ // HbProcess.StandardInput.WriteLine("^C");
+
+ IsEncoding = false;
+ }
+
+ /// <summary>
+ /// Execute a HandBrakeCLI process.
+ /// </summary>
+ /// <param name="encJob">
+ /// The enc Job.
+ /// </param>
+ protected void Run(Job encJob)
+ {
+ this.job = encJob;
+ try
+ {
+ if (this.EncodeStarted != null)
+ this.EncodeStarted(this, new EventArgs());
+
+ IsEncoding = true;
+
+ ResetLogReader();
+
+ string handbrakeCLIPath = Path.Combine(Application.StartupPath, "HandBrakeCLI.exe");
+ string logPath =
+ Path.Combine(
+ Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs",
+ "last_encode_log.txt");
+ string strCmdLine = String.Format(@" /C """"{0}"" {1} 2>""{2}"" """, handbrakeCLIPath, encJob.Query, logPath);
+ var cliStart = new ProcessStartInfo("CMD.exe", strCmdLine);
+
+ if (Settings.Default.enocdeStatusInGui)
+ {
+ cliStart.RedirectStandardOutput = true;
+ cliStart.UseShellExecute = false;
+ if (!Settings.Default.showCliForInGuiEncodeStatus)
+ cliStart.CreateNoWindow = true;
+ }
+ if (Settings.Default.cli_minimized)
+ cliStart.WindowStyle = ProcessWindowStyle.Minimized;
+
+ Process[] before = Process.GetProcesses(); // Get a list of running processes before starting.
+ this.HbProcess = Process.Start(cliStart);
+ this.ProcessID = Main.GetCliProcess(before);
+
+
+ if (this.HbProcess != null)
+ this.ProcessHandle = this.HbProcess.MainWindowHandle; // Set the process Handle
+
+ // Start the Log Monitor
+ windowTimer = new Timer(new TimerCallback(ReadFile), null, 1000, 1000);
+
+ // Set the process Priority
+ Process hbCliProcess = null;
+ if (this.ProcessID != -1)
+ hbCliProcess = Process.GetProcessById(this.ProcessID);
+
+ if (hbCliProcess != null)
+ switch (Settings.Default.processPriority)
+ {
+ case "Realtime":
+ hbCliProcess.PriorityClass = ProcessPriorityClass.RealTime;
+ break;
+ case "High":
+ hbCliProcess.PriorityClass = ProcessPriorityClass.High;
+ break;
+ case "Above Normal":
+ hbCliProcess.PriorityClass = ProcessPriorityClass.AboveNormal;
+ break;
+ case "Normal":
+ hbCliProcess.PriorityClass = ProcessPriorityClass.Normal;
+ break;
+ case "Low":
+ hbCliProcess.PriorityClass = ProcessPriorityClass.Idle;
+ break;
+ default:
+ hbCliProcess.PriorityClass = ProcessPriorityClass.BelowNormal;
+ break;
+ }
+ }
+ catch (Exception exc)
+ {
+ MessageBox.Show(
+ "It would appear that HandBrakeCLI has not started correctly. You should take a look at the Activity log as it may indicate the reason why.\n\nDetailed Error Information: error occured in runCli()\n\n" +
+ exc,
+ "Error",
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Error);
+ }
+ }
+
+ /// <summary>
+ /// Function to run the CLI directly rather than via CMD
+ /// TODO: Code to handle the Log data has yet to be written.
+ /// TODO: Code to handle the % / ETA info has to be written.
+ /// </summary>
+ /// <param name="query">
+ /// The query.
+ /// </param>
+ protected void DirectRun(string query)
+ {
+ try
+ {
+ if (this.EncodeStarted != null)
+ this.EncodeStarted(this, new EventArgs());
+
+ IsEncoding = true;
+ ResetLogReader();
+
+ // Setup the job
+ string handbrakeCLIPath = Path.Combine(Environment.CurrentDirectory, "HandBrakeCLI.exe");
+ HbProcess = new Process
+ {
+ StartInfo =
+ {
+ FileName = handbrakeCLIPath,
+ Arguments = query,
+ UseShellExecute = false,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ RedirectStandardInput = true,
+ CreateNoWindow = false,
+ WindowStyle = ProcessWindowStyle.Minimized
+ }
+ };
+
+ // Setup event handlers for rediected data
+ HbProcess.ErrorDataReceived += new DataReceivedEventHandler(HbProcErrorDataReceived);
+ HbProcess.OutputDataReceived += new DataReceivedEventHandler(HbProcOutputDataReceived);
+
+ // Start the process
+ HbProcess.Start();
+
+ // Setup the asynchronous reading of stdin and stderr
+ HbProcess.BeginErrorReadLine();
+ HbProcess.BeginOutputReadLine();
+
+ // Set the Process Priority);
+ switch (Settings.Default.processPriority)
+ {
+ case "Realtime":
+ HbProcess.PriorityClass = ProcessPriorityClass.RealTime;
+ break;
+ case "High":
+ HbProcess.PriorityClass = ProcessPriorityClass.High;
+ break;
+ case "Above Normal":
+ HbProcess.PriorityClass = ProcessPriorityClass.AboveNormal;
+ break;
+ case "Normal":
+ HbProcess.PriorityClass = ProcessPriorityClass.Normal;
+ break;
+ case "Low":
+ HbProcess.PriorityClass = ProcessPriorityClass.Idle;
+ break;
+ default:
+ HbProcess.PriorityClass = ProcessPriorityClass.BelowNormal;
+ break;
+ }
+
+ // Set the class items
+ this.ProcessID = HbProcess.Id;
+ this.ProcessHandle = HbProcess.Handle;
+ }
+ catch (Exception exc)
+ {
+ Console.WriteLine(exc);
+ }
+ }
+
+ /// <summary>
+ /// Perform an action after an encode. e.g a shutdown, standby, restart etc.
+ /// </summary>
+ protected void Finish()
+ {
+ if (this.EncodeEnded != null)
+ this.EncodeEnded(this, new EventArgs());
+
+ IsEncoding = false;
+
+ if (!IsEncoding)
+ {
+ windowTimer.Dispose();
+ ReadFile(null);
+ }
+
+ // Growl
+ if (Settings.Default.growlQueue)
+ GrowlCommunicator.Notify("Queue Completed", "Put down that cocktail...\nyour Handbrake queue is done.");
+
+ // Do something whent he encode ends.
+ switch (Settings.Default.CompletionOption)
+ {
+ case "Shutdown":
+ Process.Start("Shutdown", "-s -t 60");
+ break;
+ case "Log Off":
+ Win32.ExitWindowsEx(0, 0);
+ break;
+ case "Suspend":
+ Application.SetSuspendState(PowerState.Suspend, true, true);
+ break;
+ case "Hibernate":
+ Application.SetSuspendState(PowerState.Hibernate, true, true);
+ break;
+ case "Lock System":
+ Win32.LockWorkStation();
+ break;
+ case "Quit HandBrake":
+ Application.Exit();
+ break;
+ default:
+ break;
+ }
+ }
+
+ /// <summary>
+ /// Add the CLI Query to the Log File.
+ /// </summary>
+ /// <param name="encJob">
+ /// The Encode Job Object
+ /// </param>
+ protected void AddCLIQueryToLog(Job encJob)
+ {
+ try
+ {
+ string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
+ string logPath = Path.Combine(logDir, "last_encode_log.txt");
+
+ var reader = new StreamReader(File.Open(logPath, FileMode.Open, FileAccess.Read, FileShare.Read));
+ string log = reader.ReadToEnd();
+ reader.Close();
+
+ var writer = new StreamWriter(File.Create(logPath));
+
+ writer.WriteLine("### CLI Query: " + encJob.Query);
+ writer.WriteLine("### User Query: " + encJob.CustomQuery);
+ writer.WriteLine("#########################################");
+ writer.WriteLine(log);
+ writer.Flush();
+ writer.Close();
+ }
+ catch (Exception)
+ {
+ return;
+ }
+ }
+
+ /// <summary>
+ /// Save a copy of the log to the users desired location or a default location
+ /// if this feature is enabled in options.
+ /// </summary>
+ /// <param name="destination">
+ /// The Destination File Path
+ /// </param>
+ protected void CopyLog(string destination)
+ {
+ try
+ {
+ string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) +
+ "\\HandBrake\\logs";
+ string tempLogFile = Path.Combine(logDir, "last_encode_log.txt");
+
+ string encodeDestinationPath = Path.GetDirectoryName(destination);
+ string destinationFile = Path.GetFileName(destination);
+ string encodeLogFile = destinationFile + " " +
+ DateTime.Now.ToString().Replace("/", "-").Replace(":", "-") + ".txt";
+
+ // Make sure the log directory exists.
+ if (!Directory.Exists(logDir))
+ Directory.CreateDirectory(logDir);
+
+ // Copy the Log to HandBrakes log folder in the users applciation data folder.
+ File.Copy(tempLogFile, Path.Combine(logDir, encodeLogFile));
+
+ // Save a copy of the log file in the same location as the enocde.
+ if (Settings.Default.saveLogWithVideo)
+ File.Copy(tempLogFile, Path.Combine(encodeDestinationPath, encodeLogFile));
+
+ // Save a copy of the log file to a user specified location
+ if (Directory.Exists(Settings.Default.saveLogPath))
+ if (Settings.Default.saveLogPath != String.Empty && Settings.Default.saveLogToSpecifiedPath)
+ File.Copy(tempLogFile, Path.Combine(Settings.Default.saveLogPath, encodeLogFile));
+ }
+ catch (Exception exc)
+ {
+ MessageBox.Show(
+ "Something went a bit wrong trying to copy your log file.\nError Information:\n\n" + exc,
+ "Error",
+ MessageBoxButtons.OK,
+ MessageBoxIcon.Error);
+ }
+ }
+
+ /// <summary>
+ /// Read the log file
+ /// </summary>
+ /// <param name="n">
+ /// The object.
+ /// </param>
+ private void ReadFile(object n)
+ {
+ lock (logBuffer)
+ {
+ // last_encode_log.txt is the primary log file. Since .NET can't read this file whilst the CLI is outputing to it (Not even in read only mode),
+ // we'll need to make a copy of it.
+ string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
+ string logFile = Path.Combine(logDir, "last_encode_log.txt");
+ string logFile2 = Path.Combine(logDir, "tmp_appReadable_log.txt");
+
+ try
+ {
+ // Make sure the application readable log file does not already exist. FileCopy fill fail if it does.
+ if (File.Exists(logFile2))
+ File.Delete(logFile2);
+
+ // Copy the log file.
+ if (File.Exists(logFile))
+ File.Copy(logFile, logFile2, true);
+ else
+ {
+ ResetLogReader();
+ return;
+ }
+
+ // Put the Query and User Generated Query Flag on the log.
+ if (logFilePosition == 0)
+ {
+ logBuffer.AppendLine("### CLI Query: " + job.Query);
+ logBuffer.AppendLine("### User Query: " + job.CustomQuery);
+ logBuffer.AppendLine("#########################################");
+ }
+
+ // Start the Reader
+ // Only use text which continues on from the last read line
+ StreamReader sr = new StreamReader(logFile2);
+ string line;
+ int i = 1;
+ while ((line = sr.ReadLine()) != null)
+ {
+ if (i > logFilePosition)
+ {
+ logBuffer.AppendLine(line);
+ logFilePosition++;
+ }
+ i++;
+ }
+ sr.Close();
+ sr.Dispose();
+ }
+ catch (Exception)
+ {
+ ResetLogReader();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Reset the Log Reader
+ /// </summary>
+ private void ResetLogReader()
+ {
+ logFilePosition = 0;
+ logBuffer = new StringBuilder();
+ }
+
+ /// <summary>
+ /// Recieve the Standard Error information and process it
+ /// </summary>
+ /// <param name="sender">
+ /// The Sender Object
+ /// </param>
+ /// <param name="e">
+ /// DataReceived EventArgs
+ /// </param>
+ private void HbProcErrorDataReceived(object sender, DataReceivedEventArgs e)
+ {
+ if (!String.IsNullOrEmpty(e.Data))
+ {
+ lock (logBuffer)
+ logBuffer.AppendLine(e.Data);
+ }
+ }
+
+ /// <summary>
+ /// Standard Input Data Recieved from the CLI
+ /// </summary>
+ /// <param name="sender">
+ /// The Sender Object
+ /// </param>
+ /// <param name="e">
+ /// DataReceived EventArgs
+ /// </param>
+ private void HbProcOutputDataReceived(object sender, DataReceivedEventArgs e)
+ {
+ if (!String.IsNullOrEmpty(e.Data))
+ {
+ lock (logBuffer)
+ logBuffer.AppendLine(e.Data);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/win/C#/Services/Queue.cs b/win/C#/Services/Queue.cs
new file mode 100644
index 000000000..59b1437d5
--- /dev/null
+++ b/win/C#/Services/Queue.cs
@@ -0,0 +1,387 @@
+/* Queue.cs $
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr/>.
+ It may be used under the terms of the GNU General Public License. */
+
+
+namespace Handbrake.Services
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.IO;
+ using System.Threading;
+ using System.Windows.Forms;
+ using System.Xml.Serialization;
+ using Functions;
+ using Model;
+
+ /// <summary>
+ /// The HandBrake Queue
+ /// </summary>
+ public class Queue : Encode
+ {
+ /// <summary>
+ /// An XML Serializer
+ /// </summary>
+ private static XmlSerializer serializer;
+
+ /// <summary>
+ /// The Queue Job List
+ /// </summary>
+ private readonly List<Job> queue = new List<Job>();
+
+ /// <summary>
+ /// The Next Job ID
+ /// </summary>
+ private int nextJobId;
+
+ /// <summary>
+ /// Fires when a pause to the encode queue has been requested.
+ /// </summary>
+ public event EventHandler QueuePauseRequested;
+
+ /// <summary>
+ /// Fires when the entire encode queue has completed.
+ /// </summary>
+ public event EventHandler QueueCompleted;
+
+ #region Queue
+
+ /// <summary>
+ /// Gets and removes the next job in the queue.
+ /// </summary>
+ /// <returns>The job that was removed from the queue.</returns>
+ private Job GetNextJob()
+ {
+ Job job = this.queue[0];
+ this.LastEncode = job;
+ this.Remove(0); // Remove the item which we are about to pass out.
+
+ this.WriteQueueStateToFile("hb_queue_recovery.xml");
+
+ return job;
+ }
+
+ /// <summary>
+ /// Gets the current state of the encode queue.
+ /// </summary>
+ public ReadOnlyCollection<Job> CurrentQueue
+ {
+ get { return this.queue.AsReadOnly(); }
+ }
+
+ /// <summary>
+ /// Gets the number of items in the queue.
+ /// </summary>
+ public int Count
+ {
+ get { return this.queue.Count; }
+ }
+
+ /// <summary>
+ /// Adds an item to the queue.
+ /// </summary>
+ /// <param name="query">
+ /// The query that will be passed to the HandBrake CLI.
+ /// </param>
+ /// <param name="source">
+ /// The location of the source video.
+ /// </param>
+ /// <param name="destination">
+ /// The location where the encoded video will be.
+ /// </param>
+ /// <param name="customJob">
+ /// Custom job
+ /// </param>
+ public void Add(string query, string source, string destination, bool customJob)
+ {
+ Job newJob = new Job
+ {
+ Id = this.nextJobId++,
+ Query = query,
+ Source = source,
+ Destination = destination,
+ CustomQuery = customJob
+ };
+
+ this.queue.Add(newJob);
+ this.WriteQueueStateToFile("hb_queue_recovery.xml");
+ }
+
+ /// <summary>
+ /// Removes an item from the queue.
+ /// </summary>
+ /// <param name="index">The zero-based location of the job in the queue.</param>
+ public void Remove(int index)
+ {
+ this.queue.RemoveAt(index);
+ this.WriteQueueStateToFile("hb_queue_recovery.xml");
+ }
+
+ /// <summary>
+ /// Retrieve a job from the queue
+ /// </summary>
+ /// <param name="index">the job id</param>
+ /// <returns>A job for the given index or blank job object</returns>
+ public Job GetJob(int index)
+ {
+ if (this.queue.Count >= (index + 1))
+ return this.queue[index];
+
+ return new Job();
+ }
+
+ /// <summary>
+ /// Moves an item up one position in the queue.
+ /// </summary>
+ /// <param name="index">The zero-based location of the job in the queue.</param>
+ public void MoveUp(int index)
+ {
+ if (index > 0)
+ {
+ Job item = queue[index];
+
+ queue.RemoveAt(index);
+ queue.Insert((index - 1), item);
+ }
+
+ WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file
+ }
+
+ /// <summary>
+ /// Moves an item down one position in the queue.
+ /// </summary>
+ /// <param name="index">The zero-based location of the job in the queue.</param>
+ public void MoveDown(int index)
+ {
+ if (index < this.queue.Count - 1)
+ {
+ Job item = this.queue[index];
+
+ this.queue.RemoveAt(index);
+ this.queue.Insert((index + 1), item);
+ }
+
+ this.WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file
+ }
+
+ /// <summary>
+ /// Writes the current state of the queue to a file.
+ /// </summary>
+ /// <param name="file">The location of the file to write the queue to.</param>
+ public void WriteQueueStateToFile(string file)
+ {
+ string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ @"HandBrake\hb_queue_recovery.xml");
+ string tempPath = file == "hb_queue_recovery.xml" ? appDataPath : file;
+
+ try
+ {
+ using (FileStream strm = new FileStream(tempPath, FileMode.Create, FileAccess.Write))
+ {
+ if (serializer == null)
+ serializer = new XmlSerializer(typeof (List<Job>));
+ serializer.Serialize(strm, queue);
+ strm.Close();
+ strm.Dispose();
+ }
+ }
+ catch (Exception)
+ {
+ return;
+ }
+ }
+
+ /// <summary>
+ /// Writes the current state of the queue in the form of a batch (.bat) file.
+ /// </summary>
+ /// <param name="file">The location of the file to write the batch file to.</param>
+ public void WriteBatchScriptToFile(string file)
+ {
+ string queries = string.Empty;
+ foreach (Job queueItem in this.queue)
+ {
+ string qItem = queueItem.Query;
+ string fullQuery = '"' + Application.StartupPath + "\\HandBrakeCLI.exe" + '"' + qItem;
+
+ if (queries == string.Empty)
+ queries = queries + fullQuery;
+ else
+ queries = queries + " && " + fullQuery;
+ }
+ string strCmdLine = queries;
+
+ if (file != string.Empty)
+ {
+ try
+ {
+ // Create a StreamWriter and open the file, Write the batch file query to the file and
+ // Close the stream
+ using (StreamWriter line = new StreamWriter(file))
+ {
+ line.WriteLine(strCmdLine);
+ }
+
+ MessageBox.Show("Your batch script has been sucessfully saved.", "Status", MessageBoxButtons.OK,
+ MessageBoxIcon.Asterisk);
+ }
+ catch (Exception)
+ {
+ MessageBox.Show(
+ "Unable to write to the file. Please make sure that the location has the correct permissions for file writing.",
+ "Error", MessageBoxButtons.OK, MessageBoxIcon.Hand);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Reads a serialized XML file that represents a queue of encoding jobs.
+ /// </summary>
+ /// <param name="file">The location of the file to read the queue from.</param>
+ public void LoadQueueFromFile(string file)
+ {
+ string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
+ @"HandBrake\hb_queue_recovery.xml");
+ string tempPath = file == "hb_queue_recovery.xml" ? appDataPath : file;
+
+ if (File.Exists(tempPath))
+ {
+ using (FileStream strm = new FileStream(tempPath, FileMode.Open, FileAccess.Read))
+ {
+ if (strm.Length != 0)
+ {
+ if (serializer == null)
+ serializer = new XmlSerializer(typeof (List<Job>));
+
+ List<Job> list = serializer.Deserialize(strm) as List<Job>;
+
+ if (list != null)
+ foreach (Job item in list)
+ this.queue.Add(item);
+
+ if (file != "hb_queue_recovery.xml")
+ this.WriteQueueStateToFile("hb_queue_recovery.xml");
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Checks the current queue for an existing instance of the specified destination.
+ /// </summary>
+ /// <param name="destination">The destination of the encode.</param>
+ /// <returns>Whether or not the supplied destination is already in the queue.</returns>
+ public bool CheckForDestinationDuplicate(string destination)
+ {
+ foreach (Job checkItem in this.queue)
+ {
+ if (checkItem.Destination.Contains(destination.Replace("\\\\", "\\")))
+ return true;
+ }
+
+ return false;
+ }
+
+ #endregion
+
+ #region Encoding
+
+ /// <summary>
+ /// Gets or sets the last encode that was processed.
+ /// </summary>
+ /// <returns></returns>
+ public Job LastEncode { get; set; }
+
+ /// <summary>
+ /// Gets a value indicating whether Request Pause
+ /// </summary>
+ public bool PauseRequested { get; private set; }
+
+ /// <summary>
+ /// Starts encoding the first job in the queue and continues encoding until all jobs
+ /// have been encoded.
+ /// </summary>
+ public void Start()
+ {
+ if (this.Count != 0)
+ {
+ if (this.PauseRequested)
+ this.PauseRequested = false;
+ else
+ {
+ this.PauseRequested = false;
+ try
+ {
+ Thread theQueue = new Thread(this.StartQueue) {IsBackground = true};
+ theQueue.Start();
+ }
+ catch (Exception exc)
+ {
+ MessageBox.Show(exc.ToString());
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Requests a pause of the encode queue.
+ /// </summary>
+ public void Pause()
+ {
+ this.PauseRequested = true;
+
+ if (this.QueuePauseRequested != null)
+ this.QueuePauseRequested(this, new EventArgs());
+ }
+
+ /// <summary>
+ /// Run through all the jobs on the queue.
+ /// </summary>
+ /// <param name="state">Object State</param>
+ private void StartQueue(object state)
+ {
+ // Run through each item on the queue
+ while (this.Count != 0)
+ {
+ Job encJob = this.GetNextJob();
+ this.WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file
+
+ Run(encJob);
+
+ if (HbProcess == null)
+ {
+ return;
+ }
+ HbProcess.WaitForExit();
+
+ AddCLIQueryToLog(encJob);
+ this.CopyLog(this.LastEncode.Destination);
+
+ HbProcess.Close();
+ HbProcess.Dispose();
+
+ IsEncoding = false;
+
+ // Growl
+ if (Properties.Settings.Default.growlEncode)
+ GrowlCommunicator.Notify("Encode Completed",
+ "Put down that cocktail...\nyour Handbrake encode is done.");
+
+ while (this.PauseRequested) // Need to find a better way of doing this.
+ {
+ Thread.Sleep(2000);
+ }
+ }
+ this.LastEncode = new Job();
+
+ if (this.QueueCompleted != null)
+ this.QueueCompleted(this, new EventArgs());
+
+ // After the encode is done, we may want to shutdown, suspend etc.
+ Finish();
+ }
+
+ #endregion
+ }
+} \ No newline at end of file
diff --git a/win/C#/Services/Scan.cs b/win/C#/Services/Scan.cs
new file mode 100644
index 000000000..aae87a0d1
--- /dev/null
+++ b/win/C#/Services/Scan.cs
@@ -0,0 +1,265 @@
+/* Scan.cs $
+ This file is part of the HandBrake source code.
+ Homepage: <http://handbrake.fr>.
+ It may be used under the terms of the GNU General Public License. */
+
+namespace Handbrake.Services
+{
+ using System;
+ using System.Diagnostics;
+ using System.IO;
+ using System.Text;
+ using System.Threading;
+ using System.Windows.Forms;
+ using Parsing;
+
+ /// <summary>
+ /// Scan a Source
+ /// </summary>
+ public class Scan
+ {
+ /// <summary>
+ /// The information for this source
+ /// </summary>
+ private DVD thisDvd;
+
+ /// <summary>
+ /// The CLI data parser
+ /// </summary>
+ private Parser readData;
+
+ /// <summary>
+ /// The Log Buffer
+ /// </summary>
+ private StringBuilder logBuffer;
+
+ static object locker = new object();
+
+ /// <summary>
+ /// The line number thats been read to in the log file
+ /// </summary>
+ private int logFilePosition;
+
+ /// <summary>
+ /// The Process belonging to the CLI
+ /// </summary>
+ private Process hbProc;
+
+ /// <summary>
+ /// The Progress of the scan
+ /// </summary>
+ private string scanProgress;
+
+ /// <summary>
+ /// Scan has Started
+ /// </summary>
+ public event EventHandler ScanStared;
+
+ /// <summary>
+ /// Scan has completed
+ /// </summary>
+ public event EventHandler ScanCompleted;
+
+ /// <summary>
+ /// Scan process has changed to a new title
+ /// </summary>
+ public event EventHandler ScanStatusChanged;
+
+ /// <summary>
+ /// Gets or sets a value indicating whether IsScanning.
+ /// </summary>
+ public bool IsScanning { get; set; }
+
+ /// <summary>
+ /// Gets ActivityLog.
+ /// </summary>
+ public string ActivityLog
+ {
+ get
+ {
+ if (IsScanning)
+ return readData.Buffer;
+
+ ReadFile();
+ return logBuffer.ToString();
+ }
+ }
+
+ /// <summary>
+ /// Scan a Source Path.
+ /// Title 0: scan all
+ /// </summary>
+ /// <param name="sourcePath">Path to the file to scan</param>
+ /// <param name="title">int title number. 0 for scan all</param>
+ public void ScanSource(string sourcePath, int title)
+ {
+ Thread t = new Thread(unused => this.RunScan(sourcePath, title));
+ t.Start();
+ }
+
+ /// <summary>
+ /// Object containing the information parsed in the scan.
+ /// </summary>
+ /// <returns>The DVD object containing the scan information</returns>
+ public DVD SouceData()
+ {
+ return this.thisDvd;
+ }
+
+ /// <summary>
+ /// Progress of the scan.
+ /// </summary>
+ /// <returns>The progress of the scan</returns>
+ public string ScanStatus()
+ {
+ return this.scanProgress;
+ }
+
+ /// <summary>
+ /// The Scan Process
+ /// </summary>
+ /// <returns>The CLI process</returns>
+ public Process ScanProcess()
+ {
+ return this.hbProc;
+ }
+
+ /// <summary>
+ /// Start a scan for a given source path and title
+ /// </summary>
+ /// <param name="sourcePath">Path to the source file</param>
+ /// <param name="title">the title number to look at</param>
+ private void RunScan(object sourcePath, int title)
+ {
+ try
+ {
+ IsScanning = true;
+ if (this.ScanStared != null)
+ this.ScanStared(this, new EventArgs());
+
+ ResetLogReader();
+
+ string handbrakeCLIPath = Path.Combine(Application.StartupPath, "HandBrakeCLI.exe");
+ string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
+ string dvdInfoPath = Path.Combine(logDir, "last_scan_log.txt");
+
+ // Make we don't pick up a stale last_encode_log.txt (and that we have rights to the file)
+ if (File.Exists(dvdInfoPath))
+ File.Delete(dvdInfoPath);
+
+ string dvdnav = string.Empty;
+ if (Properties.Settings.Default.noDvdNav)
+ dvdnav = " --no-dvdnav";
+
+ this.hbProc = new Process
+ {
+ StartInfo =
+ {
+ FileName = handbrakeCLIPath,
+ Arguments =
+ String.Format(@" -i ""{0}"" -t{1} {2} -v ", sourcePath, title, dvdnav),
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ CreateNoWindow = true
+ }
+ };
+
+ // Start the Scan
+ this.hbProc.Start();
+
+ this.readData = new Parser(this.hbProc.StandardError.BaseStream);
+ this.readData.OnScanProgress += new ScanProgressEventHandler(this.OnScanProgress);
+ this.thisDvd = DVD.Parse(this.readData);
+
+ // Write the Buffer out to file.
+ StreamWriter scanLog = new StreamWriter(dvdInfoPath);
+ scanLog.Write(this.readData.Buffer);
+ scanLog.Flush();
+ scanLog.Close();
+
+ if (this.ScanCompleted != null)
+ this.ScanCompleted(this, new EventArgs());
+ IsScanning = false;
+ }
+ catch (Exception exc)
+ {
+ Console.WriteLine("frmMain.cs - scanProcess() " + exc);
+ }
+ }
+
+ /// <summary>
+ /// Read the log file
+ /// </summary>
+ private void ReadFile()
+ {
+ lock (locker)
+ {
+ // last_encode_log.txt is the primary log file. Since .NET can't read this file whilst the CLI is outputing to it (Not even in read only mode),
+ // we'll need to make a copy of it.
+ string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
+ string logFile = Path.Combine(logDir, "last_scan_log.txt");
+ string logFile2 = Path.Combine(logDir, "tmp_appReadable_log.txt");
+
+ try
+ {
+ // Make sure the application readable log file does not already exist. FileCopy fill fail if it does.
+ if (File.Exists(logFile2))
+ File.Delete(logFile2);
+
+ // Copy the log file.
+ if (File.Exists(logFile))
+ File.Copy(logFile, logFile2, true);
+ else
+ {
+ ResetLogReader();
+ return;
+ }
+
+ // Start the Reader
+ // Only use text which continues on from the last read line
+ StreamReader sr = new StreamReader(logFile2);
+ string line;
+ int i = 1;
+ while ((line = sr.ReadLine()) != null)
+ {
+ if (i > logFilePosition)
+ {
+ logBuffer.AppendLine(line);
+ logFilePosition++;
+ }
+ i++;
+ }
+ sr.Close();
+ sr.Dispose();
+ }
+ catch (Exception)
+ {
+ ResetLogReader();
+ }
+ }
+ }
+
+ /// <summary>
+ /// Reset the Log Reader
+ /// </summary>
+ private void ResetLogReader()
+ {
+ logFilePosition = 0;
+ logBuffer = new StringBuilder();
+ }
+
+ /// <summary>
+ /// Fire an event when the scan process progresses
+ /// </summary>
+ /// <param name="sender">the sender</param>
+ /// <param name="currentTitle">the current title being scanned</param>
+ /// <param name="titleCount">the total number of titles</param>
+ private void OnScanProgress(object sender, int currentTitle, int titleCount)
+ {
+ this.scanProgress = string.Format("Processing Title: {0} of {1}", currentTitle, titleCount);
+ if (this.ScanStatusChanged != null)
+ this.ScanStatusChanged(this, new EventArgs());
+ }
+ }
+} \ No newline at end of file