OSDN Git Service

CLI: update the built in presets
[handbrake-jp/handbrake-jp-git.git] / win / C# / HandBrake.ApplicationServices / Services / Queue.cs
1 /*  Queue.cs $\r
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
5 \r
6 namespace HandBrake.ApplicationServices.Services\r
7 {\r
8     using System;\r
9     using System.Collections.Generic;\r
10     using System.Collections.ObjectModel;\r
11     using System.Diagnostics;\r
12     using System.IO;\r
13     using System.Linq;\r
14     using System.Threading;\r
15     using System.Windows.Forms;\r
16     using System.Xml.Serialization;\r
17 \r
18     using HandBrake.ApplicationServices.Functions;\r
19     using HandBrake.ApplicationServices.Model;\r
20     using HandBrake.ApplicationServices.Services.Interfaces;\r
21 \r
22     /// <summary>\r
23     /// The HandBrake Queue\r
24     /// </summary>\r
25     public class Queue : Encode, IQueue\r
26     {\r
27         /// <summary>\r
28         /// The Queue Job List\r
29         /// </summary>\r
30         private readonly List<Job> queue = new List<Job>();\r
31 \r
32         /// <summary>\r
33         /// An XML Serializer\r
34         /// </summary>\r
35         private static XmlSerializer serializer;\r
36 \r
37         /// <summary>\r
38         /// The Next Job ID\r
39         /// </summary>\r
40         private int nextJobId;\r
41 \r
42         #region Events\r
43         /// <summary>\r
44         /// Fires when the Queue has started\r
45         /// </summary>\r
46         public event EventHandler QueueStarted;\r
47 \r
48         /// <summary>\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
51         /// </summary>\r
52         public event EventHandler QueueListChanged;\r
53 \r
54         /// <summary>\r
55         /// Fires when a pause to the encode queue has been requested.\r
56         /// </summary>\r
57         public event EventHandler QueuePauseRequested;\r
58 \r
59         /// <summary>\r
60         /// Fires when the entire encode queue has completed.\r
61         /// </summary>\r
62         public event EventHandler QueueCompleted;\r
63         #endregion\r
64 \r
65         #region Properties\r
66         /// <summary>\r
67         /// Gets or sets the last encode that was processed.\r
68         /// </summary>\r
69         /// <returns></returns> \r
70         public Job LastEncode { get; set; }\r
71 \r
72         /// <summary>\r
73         /// Gets a value indicating whether Request Pause\r
74         /// </summary>\r
75         public bool Paused { get; private set; }\r
76 \r
77         /// <summary>\r
78         /// Gets the current state of the encode queue.\r
79         /// </summary>\r
80         public ReadOnlyCollection<Job> CurrentQueue\r
81         {\r
82             get { return this.queue.AsReadOnly(); }\r
83         }\r
84 \r
85         /// <summary>\r
86         /// Gets the number of items in the queue.\r
87         /// </summary>\r
88         public int Count\r
89         {\r
90             get { return this.queue.Count; }\r
91         }\r
92         #endregion\r
93 \r
94         #region Queue\r
95 \r
96         /// <summary>\r
97         /// Gets and removes the next job in the queue.\r
98         /// </summary>\r
99         /// <returns>The job that was removed from the queue.</returns>\r
100         private Job GetNextJob()\r
101         {\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
105 \r
106             this.SaveQueue();\r
107 \r
108             return job;\r
109         }\r
110 \r
111         /// <summary>\r
112         /// Adds an item to the queue.\r
113         /// </summary>\r
114         /// <param name="query">\r
115         /// The query that will be passed to the HandBrake CLI.\r
116         /// </param>\r
117         /// <param name="title">\r
118         /// The title.\r
119         /// </param>\r
120         /// <param name="source">\r
121         /// The location of the source video.\r
122         /// </param>\r
123         /// <param name="destination">\r
124         /// The location where the encoded video will be.\r
125         /// </param>\r
126         /// <param name="customJob">\r
127         /// Custom job\r
128         /// </param>\r
129         public void Add(string query, int title, string source, string destination, bool customJob)\r
130         {\r
131             Job newJob = new Job\r
132                              {\r
133                                  Id = this.nextJobId++,\r
134                                  Title = title,\r
135                                  Query = query,\r
136                                  Source = source,\r
137                                  Destination = destination,\r
138                                  CustomQuery = customJob\r
139                              };\r
140 \r
141             this.queue.Add(newJob);\r
142             this.SaveQueue();\r
143 \r
144             if (this.QueueListChanged != null)\r
145                 this.QueueListChanged(this, new EventArgs());\r
146         }\r
147 \r
148         /// <summary>\r
149         /// Removes an item from the queue.\r
150         /// </summary>\r
151         /// <param name="index">The zero-based location of the job in the queue.</param>\r
152         public void Remove(int index)\r
153         {\r
154             this.queue.RemoveAt(index);\r
155             this.SaveQueue();\r
156 \r
157             if (this.QueueListChanged != null)\r
158                 this.QueueListChanged(this, new EventArgs());\r
159         }\r
160 \r
161         /// <summary>\r
162         /// Retrieve a job from the queue\r
163         /// </summary>\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
167         {\r
168             if (this.queue.Count >= (index + 1))\r
169                 return this.queue[index];\r
170 \r
171             return new Job();\r
172         }\r
173 \r
174         /// <summary>\r
175         /// Moves an item up one position in the queue.\r
176         /// </summary>\r
177         /// <param name="index">The zero-based location of the job in the queue.</param>\r
178         public void MoveUp(int index)\r
179         {\r
180             if (index > 0)\r
181             {\r
182                 Job item = queue[index];\r
183 \r
184                 queue.RemoveAt(index);\r
185                 queue.Insert((index - 1), item);\r
186             }\r
187 \r
188             this.SaveQueue(); // Update the queue recovery file\r
189 \r
190             if (this.QueueListChanged != null)\r
191                 this.QueueListChanged(this, new EventArgs());\r
192         }\r
193 \r
194         /// <summary>\r
195         /// Moves an item down one position in the queue.\r
196         /// </summary>\r
197         /// <param name="index">The zero-based location of the job in the queue.</param>\r
198         public void MoveDown(int index)\r
199         {\r
200             if (index < this.queue.Count - 1)\r
201             {\r
202                 Job item = this.queue[index];\r
203 \r
204                 this.queue.RemoveAt(index);\r
205                 this.queue.Insert((index + 1), item);\r
206             }\r
207 \r
208             this.SaveQueue(); // Update the queue recovery file\r
209 \r
210             if (this.QueueListChanged != null)\r
211                 this.QueueListChanged(this, new EventArgs());\r
212         }\r
213         \r
214         /// <summary>\r
215         /// Save any updates to the main queue file.\r
216         /// </summary>\r
217         public void SaveQueue()\r
218         {\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
223         }\r
224 \r
225         /// <summary>\r
226         /// Writes the current state of the queue to a file.\r
227         /// </summary>\r
228         /// <param name="file">The location of the file to write the queue to.</param>\r
229         public void WriteQueueStateToFile(string file)\r
230         {\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
233 \r
234             try\r
235             {\r
236                 using (FileStream strm = new FileStream(tempPath, FileMode.Create, FileAccess.Write))\r
237                 {\r
238                     if (serializer == null)\r
239                         serializer = new XmlSerializer(typeof(List<Job>));\r
240                     serializer.Serialize(strm, queue);\r
241                     strm.Close();\r
242                     strm.Dispose();\r
243                 }\r
244             }\r
245             catch (Exception)\r
246             {\r
247                 return;\r
248             }\r
249         }\r
250 \r
251         /// <summary>\r
252         /// Writes the current state of the queue in the form of a batch (.bat) file.\r
253         /// </summary>\r
254         /// <param name="file">\r
255         /// The location of the file to write the batch file to.\r
256         /// </param>\r
257         /// <returns>\r
258         /// The write batch script to file.\r
259         /// </returns>\r
260         public bool WriteBatchScriptToFile(string file)\r
261         {\r
262             string queries = string.Empty;\r
263             foreach (Job queueItem in this.queue)\r
264             {\r
265                 string qItem = queueItem.Query;\r
266                 string fullQuery = '"' + Application.StartupPath + "\\HandBrakeCLI.exe" + '"' + qItem;\r
267 \r
268                 if (queries == string.Empty)\r
269                     queries = queries + fullQuery;\r
270                 else\r
271                     queries = queries + " && " + fullQuery;\r
272             }\r
273             string strCmdLine = queries;\r
274 \r
275             if (file != string.Empty)\r
276             {\r
277                 try\r
278                 {\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
282                     {\r
283                         line.WriteLine(strCmdLine);\r
284                     }\r
285 \r
286                     return true;\r
287                 }\r
288                 catch (Exception exc)\r
289                 {\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
291                 }\r
292             }\r
293             return false;\r
294         }\r
295 \r
296         /// <summary>\r
297         /// Reads a serialized XML file that represents a queue of encoding jobs.\r
298         /// </summary>\r
299         /// <param name="file">The location of the file to read the queue from.</param>\r
300         public void LoadQueueFromFile(string file)\r
301         {\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
304 \r
305             if (File.Exists(tempPath))\r
306             {\r
307                 using (FileStream strm = new FileStream(tempPath, FileMode.Open, FileAccess.Read))\r
308                 {\r
309                     if (strm.Length != 0)\r
310                     {\r
311                         if (serializer == null)\r
312                             serializer = new XmlSerializer(typeof(List<Job>));\r
313 \r
314                         List<Job> list = serializer.Deserialize(strm) as List<Job>;\r
315 \r
316                         if (list != null)\r
317                             foreach (Job item in list)\r
318                                 this.queue.Add(item);\r
319 \r
320                         if (!file.Contains("hb_queue_recovery"))\r
321                             this.SaveQueue();\r
322 \r
323                         if (this.QueueListChanged != null)\r
324                             this.QueueListChanged(this, new EventArgs());\r
325                     }\r
326                 }\r
327             }\r
328         }\r
329 \r
330         /// <summary>\r
331         /// Checks the current queue for an existing instance of the specified destination.\r
332         /// </summary>\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
336         {\r
337             return this.queue.Any(checkItem => checkItem.Destination.Contains(destination.Replace("\\\\", "\\")));\r
338         }\r
339 \r
340         #endregion\r
341 \r
342         #region Encoding\r
343 \r
344         /// <summary>\r
345         /// Starts encoding the first job in the queue and continues encoding until all jobs\r
346         /// have been encoded.\r
347         /// </summary>\r
348         public void Start()\r
349         {\r
350             if (this.Count != 0)\r
351             {\r
352                 if (this.Paused)\r
353                     this.Paused = false;\r
354                 else\r
355                 {\r
356                     this.Paused = false;\r
357                     try\r
358                     {\r
359                         Thread theQueue = new Thread(this.StartQueue) { IsBackground = true };\r
360                         theQueue.Start();\r
361 \r
362                         if (this.QueueStarted != null)\r
363                             this.QueueStarted(this, new EventArgs());\r
364                     }\r
365                     catch (Exception exc)\r
366                     {\r
367                         errorService.ShowError("Unable to Start Queue", exc.ToString());\r
368                     }\r
369                 }\r
370             }\r
371         }\r
372 \r
373         /// <summary>\r
374         /// Requests a pause of the encode queue.\r
375         /// </summary>\r
376         public void Pause()\r
377         {\r
378             this.Paused = true;\r
379 \r
380             if (this.QueuePauseRequested != null)\r
381                 this.QueuePauseRequested(this, new EventArgs());\r
382         }\r
383 \r
384         /// <summary>\r
385         /// Run through all the jobs on the queue.\r
386         /// </summary>\r
387         /// <param name="state">Object State</param>\r
388         private void StartQueue(object state)\r
389         {\r
390             // Run through each item on the queue\r
391             while (this.Count != 0)\r
392             {\r
393                 Job encJob = this.GetNextJob();\r
394                 this.SaveQueue(); // Update the queue recovery file\r
395 \r
396                 Run(encJob, true);\r
397 \r
398                 if (HbProcess == null)\r
399                 {\r
400                     return;\r
401                 }\r
402                 HbProcess.WaitForExit();\r
403 \r
404                 this.CopyLog(this.LastEncode.Destination);\r
405 \r
406                 HbProcess.Close();\r
407                 HbProcess.Dispose();\r
408 \r
409                 // Growl\r
410                 if (Init.GrowlEncode)\r
411                     GrowlCommunicator.Notify("Encode Completed",\r
412                                              "Put down that cocktail...\nyour Handbrake encode is done.");\r
413 \r
414                 while (this.Paused) // Need to find a better way of doing this.\r
415                 {\r
416                     Thread.Sleep(2000);\r
417                 }\r
418             }\r
419             this.LastEncode = new Job();\r
420 \r
421             if (this.QueueCompleted != null)\r
422                 this.QueueCompleted(this, new EventArgs());\r
423 \r
424             // After the encode is done, we may want to shutdown, suspend etc.\r
425             Finish();\r
426         }\r
427 \r
428         /// <summary>\r
429         /// Perform an action after an encode. e.g a shutdown, standby, restart etc.\r
430         /// </summary>\r
431         private void Finish()\r
432         {\r
433             // Growl\r
434             if (Init.GrowlQueue)\r
435                 GrowlCommunicator.Notify("Queue Completed", "Put down that cocktail...\nyour Handbrake queue is done.");\r
436 \r
437             // Do something whent he encode ends.\r
438             switch (Init.CompletionOption)\r
439             {\r
440                 case "Shutdown":\r
441                     Process.Start("Shutdown", "-s -t 60");\r
442                     break;\r
443                 case "Log Off":\r
444                     Win32.ExitWindowsEx(0, 0);\r
445                     break;\r
446                 case "Suspend":\r
447                     Application.SetSuspendState(PowerState.Suspend, true, true);\r
448                     break;\r
449                 case "Hibernate":\r
450                     Application.SetSuspendState(PowerState.Hibernate, true, true);\r
451                     break;\r
452                 case "Lock System":\r
453                     Win32.LockWorkStation();\r
454                     break;\r
455                 case "Quit HandBrake":\r
456                     Application.Exit();\r
457                     break;\r
458                 default:\r
459                     break;\r
460             }\r
461         }\r
462 \r
463         #endregion\r
464     }\r
465 }