1 /* EncodeAndQueueHandler.cs $
\r
3 This file is part of the HandBrake source code.
\r
4 Homepage: <http://handbrake.fr/>.
\r
5 It may be used under the terms of the GNU General Public License. */
\r
8 using System.Collections.Generic;
\r
9 using System.Collections.ObjectModel;
\r
10 using System.Diagnostics;
\r
12 using System.Threading;
\r
13 using System.Windows.Forms;
\r
14 using System.Xml.Serialization;
\r
15 using Handbrake.Functions;
\r
17 namespace Handbrake.EncodeQueue
\r
19 public class EncodeAndQueueHandler
\r
21 private static XmlSerializer serializer;
\r
22 private List<Job> queue = new List<Job>();
\r
23 private int nextJobId;
\r
25 #region Event Handlers
\r
27 /// Fires when an encode job has been started.
\r
29 public event EventHandler NewJobStarted;
\r
32 /// Fires when a pause to the encode queue has been requested.
\r
34 public event EventHandler QueuePauseRequested;
\r
37 /// Fires when an encode job has been completed.
\r
39 public event EventHandler CurrentJobCompleted;
\r
42 /// Fires when the entire encode queue has completed.
\r
44 public event EventHandler QueueCompleted;
\r
49 /// Gets and removes the next job in the queue.
\r
51 /// <returns>The job that was removed from the queue.</returns>
\r
52 private Job GetNextJob()
\r
56 RemoveJob(0); // Remove the item which we are about to pass out.
\r
58 WriteQueueStateToFile("hb_queue_recovery.xml");
\r
64 /// Gets the current state of the encode queue.
\r
66 public ReadOnlyCollection<Job> CurrentQueue
\r
68 get { return queue.AsReadOnly(); }
\r
72 /// Gets the number of items in the queue.
\r
76 get { return queue.Count; }
\r
80 /// Adds an item to the queue.
\r
82 /// <param name="query">The query that will be passed to the HandBrake CLI.</param>
\r
83 /// <param name="source">The location of the source video.</param>
\r
84 /// <param name="destination">The location where the encoded video will be.</param>
\r
85 /// <param name="customJob"></param>
\r
86 public void AddJob(string query, string source, string destination, bool customJob)
\r
88 Job newJob = new Job { Id = nextJobId++, Query = query, Source = source, Destination = destination, CustomQuery = customJob };
\r
91 WriteQueueStateToFile("hb_queue_recovery.xml");
\r
95 /// Removes an item from the queue.
\r
97 /// <param name="index">The zero-based location of the job in the queue.</param>
\r
98 public void RemoveJob(int index)
\r
100 queue.RemoveAt(index);
\r
101 WriteQueueStateToFile("hb_queue_recovery.xml");
\r
105 /// Moves an item up one position in the queue.
\r
107 /// <param name="index">The zero-based location of the job in the queue.</param>
\r
108 public void MoveUp(int index)
\r
112 Job item = queue[index];
\r
114 queue.RemoveAt(index);
\r
115 queue.Insert((index - 1), item);
\r
118 WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file
\r
122 /// Moves an item down one position in the queue.
\r
124 /// <param name="index">The zero-based location of the job in the queue.</param>
\r
125 public void MoveDown(int index)
\r
127 if (index < queue.Count - 1)
\r
129 Job item = queue[index];
\r
131 queue.RemoveAt(index);
\r
132 queue.Insert((index + 1), item);
\r
135 WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file
\r
139 /// Writes the current state of the queue to a file.
\r
141 /// <param name="file">The location of the file to write the queue to.</param>
\r
142 public void WriteQueueStateToFile(string file)
\r
144 string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\hb_queue_recovery.xml");
\r
145 string tempPath = file == "hb_queue_recovery.xml" ? appDataPath : file;
\r
149 using (FileStream strm = new FileStream(tempPath, FileMode.Create, FileAccess.Write))
\r
151 if (serializer == null)
\r
152 serializer = new XmlSerializer(typeof(List<Job>));
\r
153 serializer.Serialize(strm, queue);
\r
160 // Any Errors will be out of diskspace/permissions problems.
\r
161 // Don't report them as they'll annoy the user.
\r
166 /// Writes the current state of the queue in the form of a batch (.bat) file.
\r
168 /// <param name="file">The location of the file to write the batch file to.</param>
\r
169 public void WriteBatchScriptToFile(string file)
\r
171 string queries = "";
\r
172 foreach (Job queue_item in queue)
\r
174 string q_item = queue_item.Query;
\r
175 string fullQuery = '"' + Application.StartupPath + "\\HandBrakeCLI.exe" + '"' + q_item;
\r
177 if (queries == string.Empty)
\r
178 queries = queries + fullQuery;
\r
180 queries = queries + " && " + fullQuery;
\r
182 string strCmdLine = queries;
\r
188 // Create a StreamWriter and open the file, Write the batch file query to the file and
\r
189 // Close the stream
\r
190 using (StreamWriter line = new StreamWriter(file))
\r
192 line.WriteLine(strCmdLine);
\r
195 MessageBox.Show("Your batch script has been sucessfully saved.", "Status", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
\r
199 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);
\r
206 /// Reads a serialized XML file that represents a queue of encoding jobs.
\r
208 /// <param name="file">The location of the file to read the queue from.</param>
\r
209 public void LoadQueueFromFile(string file)
\r
211 string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\hb_queue_recovery.xml");
\r
212 string tempPath = file == "hb_queue_recovery.xml" ? appDataPath : file;
\r
214 if (File.Exists(tempPath))
\r
216 using (FileStream strm = new FileStream(tempPath, FileMode.Open, FileAccess.Read))
\r
218 if (strm.Length != 0)
\r
220 if (serializer == null)
\r
221 serializer = new XmlSerializer(typeof(List<Job>));
\r
223 List<Job> list = serializer.Deserialize(strm) as List<Job>;
\r
226 foreach (Job item in list)
\r
229 if (file != "hb_queue_recovery.xml")
\r
230 WriteQueueStateToFile("hb_queue_recovery.xml");
\r
237 /// Checks the current queue for an existing instance of the specified destination.
\r
239 /// <param name="destination">The destination of the encode.</param>
\r
240 /// <returns>Whether or not the supplied destination is already in the queue.</returns>
\r
241 public bool CheckForDestinationDuplicate(string destination)
\r
243 foreach (Job checkItem in queue)
\r
245 if (checkItem.Destination.Contains(destination.Replace("\\\\", "\\")))
\r
257 /// Gets the last encode that was processed.
\r
259 /// <returns></returns>
\r
260 public Job LastEncode { get; set; }
\r
265 public Boolean PauseRequested { get; private set; }
\r
268 /// Starts encoding the first job in the queue and continues encoding until all jobs
\r
269 /// have been encoded.
\r
271 public void StartEncodeQueue()
\r
273 if (this.Count != 0)
\r
275 if (PauseRequested)
\r
276 PauseRequested = false;
\r
279 PauseRequested = false;
\r
282 Thread theQueue = new Thread(startProcess) { IsBackground = true };
\r
285 catch (Exception exc)
\r
287 MessageBox.Show(exc.ToString());
\r
294 /// Requests a pause of the encode queue.
\r
296 public void RequestPause()
\r
298 PauseRequested = true;
\r
300 if (QueuePauseRequested != null)
\r
301 QueuePauseRequested(this, new EventArgs());
\r
305 /// Stops the current job.
\r
307 public void EndEncodeJob()
\r
312 private void startProcess(object state)
\r
314 // Run through each item on the queue
\r
315 while (this.Count != 0)
\r
317 Job encJob = GetNextJob();
\r
318 string query = encJob.Query;
\r
319 WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file
\r
323 if (NewJobStarted != null)
\r
324 NewJobStarted(this, new EventArgs());
\r
326 hbProcess.WaitForExit();
\r
328 AddCLIQueryToLog(encJob);
\r
329 CopyLog(LastEncode.Destination);
\r
332 hbProcess.Dispose();
\r
334 isEncoding = false;
\r
337 if (Properties.Settings.Default.growlEncode)
\r
338 GrowlCommunicator.Notify("Encode Completed", "Put down that cocktail...\nyour Handbrake encode is done.");
\r
340 if (CurrentJobCompleted != null)
\r
341 CurrentJobCompleted(this, new EventArgs());
\r
343 while (PauseRequested) // Need to find a better way of doing this.
\r
345 Thread.Sleep(5000);
\r
348 LastEncode = new Job();
\r
350 if (QueueCompleted != null)
\r
351 QueueCompleted(this, new EventArgs());
\r
353 // After the encode is done, we may want to shutdown, suspend etc.
\r
354 AfterEncodeAction();
\r
359 #region CLI and Log Handling
\r
360 public Process hbProcess { get; set; }
\r
361 public int processID { get; set; }
\r
362 public IntPtr processHandle { get; set; }
\r
363 public String currentQuery { get; set; }
\r
364 public Boolean isEncoding { get; set; }
\r
367 /// Execute a HandBrakeCLI process.
\r
369 /// <param name="query">The CLI Query</param>
\r
370 public void RunCli(string query)
\r
376 string handbrakeCLIPath = Path.Combine(Application.StartupPath, "HandBrakeCLI.exe");
\r
377 string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs", "last_encode_log.txt");
\r
378 string strCmdLine = String.Format(@" /C """"{0}"" {1} 2>""{2}"" """, handbrakeCLIPath, query, logPath);
\r
379 ProcessStartInfo cliStart = new ProcessStartInfo("CMD.exe", strCmdLine);
\r
381 if (Properties.Settings.Default.enocdeStatusInGui)
\r
383 cliStart.RedirectStandardOutput = true;
\r
384 cliStart.UseShellExecute = false;
\r
386 if (Properties.Settings.Default.cli_minimized)
\r
387 cliStart.WindowStyle = ProcessWindowStyle.Minimized;
\r
389 Process[] before = Process.GetProcesses(); // Get a list of running processes before starting.
\r
390 hbProcess = Process.Start(cliStart);
\r
391 processID = Main.GetCliProcess(before);
\r
392 currentQuery = query;
\r
393 if (hbProcess != null)
\r
394 processHandle = hbProcess.MainWindowHandle; // Set the process Handle
\r
396 // Set the process Priority
\r
397 Process hbCliProcess = null;
\r
398 if (processID != -1)
\r
399 hbCliProcess = Process.GetProcessById(processID);
\r
401 if (hbCliProcess != null)
\r
402 switch (Properties.Settings.Default.processPriority)
\r
405 hbCliProcess.PriorityClass = ProcessPriorityClass.RealTime;
\r
408 hbCliProcess.PriorityClass = ProcessPriorityClass.High;
\r
410 case "Above Normal":
\r
411 hbCliProcess.PriorityClass = ProcessPriorityClass.AboveNormal;
\r
414 hbCliProcess.PriorityClass = ProcessPriorityClass.Normal;
\r
417 hbCliProcess.PriorityClass = ProcessPriorityClass.Idle;
\r
420 hbCliProcess.PriorityClass = ProcessPriorityClass.BelowNormal;
\r
424 catch (Exception exc)
\r
426 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\n Detailed Error Information: error occured in runCli()\n\n" + exc, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
\r
431 /// Kill the CLI process
\r
433 private void CloseCLI()
\r
436 isEncoding = false;
\r
440 /// Perform an action after an encode. e.g a shutdown, standby, restart etc.
\r
442 private void AfterEncodeAction()
\r
444 isEncoding = false;
\r
445 currentQuery = String.Empty;
\r
448 if (Properties.Settings.Default.growlQueue)
\r
449 GrowlCommunicator.Notify("Queue Completed", "Put down that cocktail...\nyour Handbrake queue is done.");
\r
451 // Do something whent he encode ends.
\r
452 switch (Properties.Settings.Default.CompletionOption)
\r
455 Process.Start("Shutdown", "-s -t 60");
\r
458 Win32.ExitWindowsEx(0, 0);
\r
461 Application.SetSuspendState(PowerState.Suspend, true, true);
\r
464 Application.SetSuspendState(PowerState.Hibernate, true, true);
\r
466 case "Lock System":
\r
467 Win32.LockWorkStation();
\r
469 case "Quit HandBrake":
\r
470 Application.Exit();
\r
478 /// Append the CLI query to the start of the log file.
\r
480 /// <param name="query"></param>
\r
481 private static void AddCLIQueryToLog(Job encJob)
\r
483 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
484 string logPath = Path.Combine(logDir, "last_encode_log.txt");
\r
486 StreamReader reader = new StreamReader(File.Open(logPath, FileMode.Open, FileAccess.Read, FileShare.Read));
\r
487 String log = reader.ReadToEnd();
\r
490 StreamWriter writer = new StreamWriter(File.Create(logPath));
\r
492 writer.Write("### CLI Query: " + encJob.Query + "\n\n");
\r
493 writer.Write("### User Query: " + encJob.CustomQuery + "\n\n");
\r
494 writer.Write("#########################################\n\n");
\r
495 writer.WriteLine(log);
\r
501 /// Save a copy of the log to the users desired location or a default location
\r
502 /// if this feature is enabled in options.
\r
504 /// <param name="destination"></param>
\r
505 private static void CopyLog(string destination)
\r
509 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
510 string tempLogFile = Path.Combine(logDir, "last_encode_log.txt");
\r
512 string encodeDestinationPath = Path.GetDirectoryName(destination);
\r
513 String destinationFile = Path.GetFileName(destination);
\r
514 string encodeLogFile = destinationFile + " " + DateTime.Now.ToString().Replace("/", "-").Replace(":", "-") + ".txt";
\r
516 // Make sure the log directory exists.
\r
517 if (!Directory.Exists(logDir))
\r
518 Directory.CreateDirectory(logDir);
\r
520 // Copy the Log to HandBrakes log folder in the users applciation data folder.
\r
521 File.Copy(tempLogFile, Path.Combine(logDir, encodeLogFile));
\r
523 // Save a copy of the log file in the same location as the enocde.
\r
524 if (Properties.Settings.Default.saveLogWithVideo)
\r
525 File.Copy(tempLogFile, Path.Combine(encodeDestinationPath, encodeLogFile));
\r
527 // Save a copy of the log file to a user specified location
\r
528 if (Directory.Exists(Properties.Settings.Default.saveLogPath))
\r
529 if (Properties.Settings.Default.saveLogPath != String.Empty && Properties.Settings.Default.saveLogToSpecifiedPath)
\r
530 File.Copy(tempLogFile, Path.Combine(Properties.Settings.Default.saveLogPath, encodeLogFile));
\r
532 catch (Exception exc)
\r
534 MessageBox.Show("Something went a bit wrong trying to copy your log file.\nError Information:\n\n" + exc, "Error",
\r
535 MessageBoxButtons.OK, MessageBoxIcon.Error);
\r