2 This file is part of the HandBrake source code.
\r
3 Homepage: <http://handbrake.fr/>.
\r
4 It may be used under the terms of the GNU General Public License. */
\r
6 namespace HandBrake.ApplicationServices.Services
\r
9 using System.Collections.Generic;
\r
10 using System.Collections.ObjectModel;
\r
11 using System.Diagnostics;
\r
14 using System.Threading;
\r
15 using System.Windows.Forms;
\r
16 using System.Xml.Serialization;
\r
18 using HandBrake.ApplicationServices.Functions;
\r
19 using HandBrake.ApplicationServices.Model;
\r
20 using HandBrake.ApplicationServices.Services.Interfaces;
\r
23 /// The HandBrake Queue
\r
25 public class Queue : Encode, IQueue
\r
28 /// The Queue Job List
\r
30 private readonly List<Job> queue = new List<Job>();
\r
33 /// An XML Serializer
\r
35 private static XmlSerializer serializer;
\r
40 private int nextJobId;
\r
44 /// Fires when the Queue has started
\r
46 public event EventHandler QueueStarted;
\r
49 /// Fires when a job is Added, Removed or Re-Ordered.
\r
50 /// Should be used for triggering an update of the Queue Window.
\r
52 public event EventHandler QueueListChanged;
\r
55 /// Fires when a pause to the encode queue has been requested.
\r
57 public event EventHandler QueuePauseRequested;
\r
60 /// Fires when the entire encode queue has completed.
\r
62 public event EventHandler QueueCompleted;
\r
67 /// Gets or sets the last encode that was processed.
\r
69 /// <returns></returns>
\r
70 public Job LastEncode { get; set; }
\r
73 /// Gets a value indicating whether Request Pause
\r
75 public bool Paused { get; private set; }
\r
78 /// Gets the current state of the encode queue.
\r
80 public ReadOnlyCollection<Job> CurrentQueue
\r
82 get { return this.queue.AsReadOnly(); }
\r
86 /// Gets the number of items in the queue.
\r
90 get { return this.queue.Count; }
\r
97 /// Gets and removes the next job in the queue.
\r
99 /// <returns>The job that was removed from the queue.</returns>
\r
100 private Job GetNextJob()
\r
102 Job job = this.queue[0];
\r
103 this.LastEncode = job;
\r
104 this.Remove(0); // Remove the item which we are about to pass out.
\r
112 /// Adds an item to the queue.
\r
114 /// <param name="query">
\r
115 /// The query that will be passed to the HandBrake CLI.
\r
117 /// <param name="title">
\r
120 /// <param name="source">
\r
121 /// The location of the source video.
\r
123 /// <param name="destination">
\r
124 /// The location where the encoded video will be.
\r
126 /// <param name="customJob">
\r
129 public void Add(string query, int title, string source, string destination, bool customJob)
\r
131 Job newJob = new Job
\r
133 Id = this.nextJobId++,
\r
137 Destination = destination,
\r
138 CustomQuery = customJob
\r
141 this.queue.Add(newJob);
\r
144 if (this.QueueListChanged != null)
\r
145 this.QueueListChanged(this, new EventArgs());
\r
149 /// Removes an item from the queue.
\r
151 /// <param name="index">The zero-based location of the job in the queue.</param>
\r
152 public void Remove(int index)
\r
154 this.queue.RemoveAt(index);
\r
157 if (this.QueueListChanged != null)
\r
158 this.QueueListChanged(this, new EventArgs());
\r
162 /// Retrieve a job from the queue
\r
164 /// <param name="index">the job id</param>
\r
165 /// <returns>A job for the given index or blank job object</returns>
\r
166 public Job GetJob(int index)
\r
168 if (this.queue.Count >= (index + 1))
\r
169 return this.queue[index];
\r
175 /// Moves an item up one position in the queue.
\r
177 /// <param name="index">The zero-based location of the job in the queue.</param>
\r
178 public void MoveUp(int index)
\r
182 Job item = queue[index];
\r
184 queue.RemoveAt(index);
\r
185 queue.Insert((index - 1), item);
\r
188 this.SaveQueue(); // Update the queue recovery file
\r
190 if (this.QueueListChanged != null)
\r
191 this.QueueListChanged(this, new EventArgs());
\r
195 /// Moves an item down one position in the queue.
\r
197 /// <param name="index">The zero-based location of the job in the queue.</param>
\r
198 public void MoveDown(int index)
\r
200 if (index < this.queue.Count - 1)
\r
202 Job item = this.queue[index];
\r
204 this.queue.RemoveAt(index);
\r
205 this.queue.Insert((index + 1), item);
\r
208 this.SaveQueue(); // Update the queue recovery file
\r
210 if (this.QueueListChanged != null)
\r
211 this.QueueListChanged(this, new EventArgs());
\r
215 /// Save any updates to the main queue file.
\r
217 public void SaveQueue()
\r
219 string file = Init.InstanceId == 0
\r
220 ? "hb_queue_recovery.xml"
\r
221 : string.Format("hb_queue_recovery{0}.xml", Init.InstanceId);
\r
222 this.WriteQueueStateToFile(file);
\r
226 /// Writes the current state of the queue to a file.
\r
228 /// <param name="file">The location of the file to write the queue to.</param>
\r
229 public void WriteQueueStateToFile(string file)
\r
231 string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");
\r
232 string tempPath = file.Contains("hb_queue_recovery") ? appDataPath + file : file;
\r
236 using (FileStream strm = new FileStream(tempPath, FileMode.Create, FileAccess.Write))
\r
238 if (serializer == null)
\r
239 serializer = new XmlSerializer(typeof(List<Job>));
\r
240 serializer.Serialize(strm, queue);
\r
252 /// Writes the current state of the queue in the form of a batch (.bat) file.
\r
254 /// <param name="file">
\r
255 /// The location of the file to write the batch file to.
\r
258 /// The write batch script to file.
\r
260 public bool WriteBatchScriptToFile(string file)
\r
262 string queries = string.Empty;
\r
263 foreach (Job queueItem in this.queue)
\r
265 string qItem = queueItem.Query;
\r
266 string fullQuery = '"' + Application.StartupPath + "\\HandBrakeCLI.exe" + '"' + qItem;
\r
268 if (queries == string.Empty)
\r
269 queries = queries + fullQuery;
\r
271 queries = queries + " && " + fullQuery;
\r
273 string strCmdLine = queries;
\r
275 if (file != string.Empty)
\r
279 // Create a StreamWriter and open the file, Write the batch file query to the file and
\r
280 // Close the stream
\r
281 using (StreamWriter line = new StreamWriter(file))
\r
283 line.WriteLine(strCmdLine);
\r
288 catch (Exception exc)
\r
290 errorService.ShowError("Unable to write to the file. Please make sure that the location has the correct permissions for file writing.", exc.ToString());
\r
297 /// Reads a serialized XML file that represents a queue of encoding jobs.
\r
299 /// <param name="file">The location of the file to read the queue from.</param>
\r
300 public void LoadQueueFromFile(string file)
\r
302 string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");
\r
303 string tempPath = file.Contains("hb_queue_recovery") ? appDataPath + file : file;
\r
305 if (File.Exists(tempPath))
\r
307 using (FileStream strm = new FileStream(tempPath, FileMode.Open, FileAccess.Read))
\r
309 if (strm.Length != 0)
\r
311 if (serializer == null)
\r
312 serializer = new XmlSerializer(typeof(List<Job>));
\r
314 List<Job> list = serializer.Deserialize(strm) as List<Job>;
\r
317 foreach (Job item in list)
\r
318 this.queue.Add(item);
\r
320 if (!file.Contains("hb_queue_recovery"))
\r
323 if (this.QueueListChanged != null)
\r
324 this.QueueListChanged(this, new EventArgs());
\r
331 /// Checks the current queue for an existing instance of the specified destination.
\r
333 /// <param name="destination">The destination of the encode.</param>
\r
334 /// <returns>Whether or not the supplied destination is already in the queue.</returns>
\r
335 public bool CheckForDestinationDuplicate(string destination)
\r
337 return this.queue.Any(checkItem => checkItem.Destination.Contains(destination.Replace("\\\\", "\\")));
\r
345 /// Starts encoding the first job in the queue and continues encoding until all jobs
\r
346 /// have been encoded.
\r
348 public void Start()
\r
350 if (this.Count != 0)
\r
353 this.Paused = false;
\r
356 this.Paused = false;
\r
359 Thread theQueue = new Thread(this.StartQueue) { IsBackground = true };
\r
362 if (this.QueueStarted != null)
\r
363 this.QueueStarted(this, new EventArgs());
\r
365 catch (Exception exc)
\r
367 errorService.ShowError("Unable to Start Queue", exc.ToString());
\r
374 /// Requests a pause of the encode queue.
\r
376 public void Pause()
\r
378 this.Paused = true;
\r
380 if (this.QueuePauseRequested != null)
\r
381 this.QueuePauseRequested(this, new EventArgs());
\r
385 /// Run through all the jobs on the queue.
\r
387 /// <param name="state">Object State</param>
\r
388 private void StartQueue(object state)
\r
390 // Run through each item on the queue
\r
391 while (this.Count != 0)
\r
393 Job encJob = this.GetNextJob();
\r
394 this.SaveQueue(); // Update the queue recovery file
\r
398 if (HbProcess == null)
\r
402 HbProcess.WaitForExit();
\r
404 this.CopyLog(this.LastEncode.Destination);
\r
407 HbProcess.Dispose();
\r
410 if (Init.GrowlEncode)
\r
411 GrowlCommunicator.Notify("Encode Completed",
\r
412 "Put down that cocktail...\nyour Handbrake encode is done.");
\r
414 while (this.Paused) // Need to find a better way of doing this.
\r
416 Thread.Sleep(2000);
\r
419 this.LastEncode = new Job();
\r
421 if (this.QueueCompleted != null)
\r
422 this.QueueCompleted(this, new EventArgs());
\r
424 // After the encode is done, we may want to shutdown, suspend etc.
\r
429 /// Perform an action after an encode. e.g a shutdown, standby, restart etc.
\r
431 private void Finish()
\r
434 if (Init.GrowlQueue)
\r
435 GrowlCommunicator.Notify("Queue Completed", "Put down that cocktail...\nyour Handbrake queue is done.");
\r
437 // Do something whent he encode ends.
\r
438 switch (Init.CompletionOption)
\r
441 Process.Start("Shutdown", "-s -t 60");
\r
444 Win32.ExitWindowsEx(0, 0);
\r
447 Application.SetSuspendState(PowerState.Suspend, true, true);
\r
450 Application.SetSuspendState(PowerState.Hibernate, true, true);
\r
452 case "Lock System":
\r
453 Win32.LockWorkStation();
\r
455 case "Quit HandBrake":
\r
456 Application.Exit();
\r