OSDN Git Service

WinGui:
[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.IO;\r
12     using System.Linq;\r
13     using System.Threading;\r
14     using System.Windows.Forms;\r
15     using System.Xml.Serialization;\r
16 \r
17     using HandBrake.ApplicationServices.Functions;\r
18     using HandBrake.ApplicationServices.Model;\r
19 \r
20     /// <summary>\r
21     /// The HandBrake Queue\r
22     /// </summary>\r
23     public class Queue : Encode\r
24     {\r
25         /// <summary>\r
26         /// The Queue Job List\r
27         /// </summary>\r
28         private readonly List<Job> queue = new List<Job>();\r
29 \r
30         /// <summary>\r
31         /// An XML Serializer\r
32         /// </summary>\r
33         private static XmlSerializer serializer;\r
34 \r
35         /// <summary>\r
36         /// The Next Job ID\r
37         /// </summary>\r
38         private int nextJobId;\r
39 \r
40         /// <summary>\r
41         /// Fires when the Queue has started\r
42         /// </summary>\r
43         public event EventHandler QueueStarted;\r
44 \r
45         /// <summary>\r
46         /// Fires when a job is Added, Removed or Re-Ordered.\r
47         /// Should be used for triggering an update of the Queue Window.\r
48         /// </summary>\r
49         public event EventHandler QueueListChanged;\r
50 \r
51         /// <summary>\r
52         /// Fires when a pause to the encode queue has been requested.\r
53         /// </summary>\r
54         public event EventHandler QueuePauseRequested;\r
55 \r
56         /// <summary>\r
57         /// Fires when the entire encode queue has completed.\r
58         /// </summary>\r
59         public event EventHandler QueueCompleted;\r
60 \r
61         #region Properties\r
62         /// <summary>\r
63         /// Gets or sets the last encode that was processed.\r
64         /// </summary>\r
65         /// <returns></returns> \r
66         public Job LastEncode { get; set; }\r
67 \r
68         /// <summary>\r
69         /// Gets a value indicating whether Request Pause\r
70         /// </summary>\r
71         public bool Paused { get; private set; }\r
72 \r
73         /// <summary>\r
74         /// Gets the current state of the encode queue.\r
75         /// </summary>\r
76         public ReadOnlyCollection<Job> CurrentQueue\r
77         {\r
78             get { return this.queue.AsReadOnly(); }\r
79         }\r
80 \r
81         /// <summary>\r
82         /// Gets the number of items in the queue.\r
83         /// </summary>\r
84         public int Count\r
85         {\r
86             get { return this.queue.Count; }\r
87         }\r
88         #endregion\r
89 \r
90         #region Queue\r
91 \r
92         /// <summary>\r
93         /// Gets and removes the next job in the queue.\r
94         /// </summary>\r
95         /// <returns>The job that was removed from the queue.</returns>\r
96         private Job GetNextJob()\r
97         {\r
98             Job job = this.queue[0];\r
99             this.LastEncode = job;\r
100             this.Remove(0); // Remove the item which we are about to pass out.\r
101 \r
102             this.WriteQueueStateToFile("hb_queue_recovery.xml");\r
103 \r
104             return job;\r
105         }\r
106 \r
107         /// <summary>\r
108         /// Adds an item to the queue.\r
109         /// </summary>\r
110         /// <param name="query">\r
111         /// The query that will be passed to the HandBrake CLI.\r
112         /// </param>\r
113         /// <param name="title">\r
114         /// The title.\r
115         /// </param>\r
116         /// <param name="source">\r
117         /// The location of the source video.\r
118         /// </param>\r
119         /// <param name="destination">\r
120         /// The location where the encoded video will be.\r
121         /// </param>\r
122         /// <param name="customJob">\r
123         /// Custom job\r
124         /// </param>\r
125         public void Add(string query, int title, string source, string destination, bool customJob)\r
126         {\r
127             Job newJob = new Job\r
128                              {\r
129                                  Id = this.nextJobId++,\r
130                                  Title = title,\r
131                                  Query = query,\r
132                                  Source = source,\r
133                                  Destination = destination,\r
134                                  CustomQuery = customJob\r
135                              };\r
136 \r
137             this.queue.Add(newJob);\r
138             this.WriteQueueStateToFile("hb_queue_recovery.xml");\r
139 \r
140             if (this.QueueListChanged != null)\r
141                 this.QueueListChanged(this, new EventArgs());\r
142         }\r
143 \r
144         /// <summary>\r
145         /// Removes an item from the queue.\r
146         /// </summary>\r
147         /// <param name="index">The zero-based location of the job in the queue.</param>\r
148         public void Remove(int index)\r
149         {\r
150             this.queue.RemoveAt(index);\r
151             this.WriteQueueStateToFile("hb_queue_recovery.xml");\r
152 \r
153             if (this.QueueListChanged != null)\r
154                 this.QueueListChanged(this, new EventArgs());\r
155         }\r
156 \r
157         /// <summary>\r
158         /// Retrieve a job from the queue\r
159         /// </summary>\r
160         /// <param name="index">the job id</param>\r
161         /// <returns>A job for the given index or blank job object</returns>\r
162         public Job GetJob(int index)\r
163         {\r
164             if (this.queue.Count >= (index + 1))\r
165                 return this.queue[index];\r
166 \r
167             return new Job();\r
168         }\r
169 \r
170         /// <summary>\r
171         /// Moves an item up one position in the queue.\r
172         /// </summary>\r
173         /// <param name="index">The zero-based location of the job in the queue.</param>\r
174         public void MoveUp(int index)\r
175         {\r
176             if (index > 0)\r
177             {\r
178                 Job item = queue[index];\r
179 \r
180                 queue.RemoveAt(index);\r
181                 queue.Insert((index - 1), item);\r
182             }\r
183 \r
184             WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file\r
185 \r
186             if (this.QueueListChanged != null)\r
187                 this.QueueListChanged(this, new EventArgs());\r
188         }\r
189 \r
190         /// <summary>\r
191         /// Moves an item down one position in the queue.\r
192         /// </summary>\r
193         /// <param name="index">The zero-based location of the job in the queue.</param>\r
194         public void MoveDown(int index)\r
195         {\r
196             if (index < this.queue.Count - 1)\r
197             {\r
198                 Job item = this.queue[index];\r
199 \r
200                 this.queue.RemoveAt(index);\r
201                 this.queue.Insert((index + 1), item);\r
202             }\r
203 \r
204             this.WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file\r
205 \r
206             if (this.QueueListChanged != null)\r
207                 this.QueueListChanged(this, new EventArgs());\r
208         }\r
209 \r
210         /// <summary>\r
211         /// Writes the current state of the queue to a file.\r
212         /// </summary>\r
213         /// <param name="file">The location of the file to write the queue to.</param>\r
214         public void WriteQueueStateToFile(string file)\r
215         {\r
216             string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),\r
217                                               @"HandBrake\hb_queue_recovery.xml");\r
218             string tempPath = file == "hb_queue_recovery.xml" ? appDataPath : file;\r
219 \r
220             try\r
221             {\r
222                 using (FileStream strm = new FileStream(tempPath, FileMode.Create, FileAccess.Write))\r
223                 {\r
224                     if (serializer == null)\r
225                         serializer = new XmlSerializer(typeof(List<Job>));\r
226                     serializer.Serialize(strm, queue);\r
227                     strm.Close();\r
228                     strm.Dispose();\r
229                 }\r
230             }\r
231             catch (Exception)\r
232             {\r
233                 return;\r
234             }\r
235         }\r
236 \r
237         /// <summary>\r
238         /// Writes the current state of the queue in the form of a batch (.bat) file.\r
239         /// </summary>\r
240         /// <param name="file">The location of the file to write the batch file to.</param>\r
241         public bool WriteBatchScriptToFile(string file)\r
242         {\r
243             string queries = string.Empty;\r
244             foreach (Job queueItem in this.queue)\r
245             {\r
246                 string qItem = queueItem.Query;\r
247                 string fullQuery = '"' + Application.StartupPath + "\\HandBrakeCLI.exe" + '"' + qItem;\r
248 \r
249                 if (queries == string.Empty)\r
250                     queries = queries + fullQuery;\r
251                 else\r
252                     queries = queries + " && " + fullQuery;\r
253             }\r
254             string strCmdLine = queries;\r
255 \r
256             if (file != string.Empty)\r
257             {\r
258                 try\r
259                 {\r
260                     // Create a StreamWriter and open the file, Write the batch file query to the file and \r
261                     // Close the stream\r
262                     using (StreamWriter line = new StreamWriter(file))\r
263                     {\r
264                         line.WriteLine(strCmdLine);\r
265                     }\r
266 \r
267                     return true;\r
268                 }\r
269                 catch (Exception exc)\r
270                 {\r
271                     Main.ShowExceptiowWindow("Unable to write to the file. Please make sure that the location has the correct permissions for file writing.", exc.ToString());\r
272                 }\r
273             }\r
274             return false;\r
275         }\r
276 \r
277         /// <summary>\r
278         /// Reads a serialized XML file that represents a queue of encoding jobs.\r
279         /// </summary>\r
280         /// <param name="file">The location of the file to read the queue from.</param>\r
281         public void LoadQueueFromFile(string file)\r
282         {\r
283             string appDataPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),\r
284                                               @"HandBrake\hb_queue_recovery.xml");\r
285             string tempPath = file == "hb_queue_recovery.xml" ? appDataPath : file;\r
286 \r
287             if (File.Exists(tempPath))\r
288             {\r
289                 using (FileStream strm = new FileStream(tempPath, FileMode.Open, FileAccess.Read))\r
290                 {\r
291                     if (strm.Length != 0)\r
292                     {\r
293                         if (serializer == null)\r
294                             serializer = new XmlSerializer(typeof(List<Job>));\r
295 \r
296                         List<Job> list = serializer.Deserialize(strm) as List<Job>;\r
297 \r
298                         if (list != null)\r
299                             foreach (Job item in list)\r
300                                 this.queue.Add(item);\r
301 \r
302                         if (file != "hb_queue_recovery.xml")\r
303                             this.WriteQueueStateToFile("hb_queue_recovery.xml");\r
304                     }\r
305                 }\r
306             }\r
307         }\r
308 \r
309         /// <summary>\r
310         /// Checks the current queue for an existing instance of the specified destination.\r
311         /// </summary>\r
312         /// <param name="destination">The destination of the encode.</param>\r
313         /// <returns>Whether or not the supplied destination is already in the queue.</returns>\r
314         public bool CheckForDestinationDuplicate(string destination)\r
315         {\r
316             return this.queue.Any(checkItem => checkItem.Destination.Contains(destination.Replace("\\\\", "\\")));\r
317         }\r
318 \r
319         #endregion\r
320 \r
321         #region Encoding\r
322 \r
323         /// <summary>\r
324         /// Starts encoding the first job in the queue and continues encoding until all jobs\r
325         /// have been encoded.\r
326         /// </summary>\r
327         public void Start()\r
328         {\r
329             if (this.Count != 0)\r
330             {\r
331                 if (this.Paused)\r
332                     this.Paused = false;\r
333                 else\r
334                 {\r
335                     this.Paused = false;\r
336                     try\r
337                     {\r
338                         Thread theQueue = new Thread(this.StartQueue) { IsBackground = true };\r
339                         theQueue.Start();\r
340 \r
341                         if (this.QueueStarted != null)\r
342                             this.QueueStarted(this, new EventArgs());\r
343                     }\r
344                     catch (Exception exc)\r
345                     {\r
346                         Main.ShowExceptiowWindow("Unable to Start Queue", exc.ToString());\r
347                     }\r
348                 }\r
349             }\r
350         }\r
351 \r
352         /// <summary>\r
353         /// Requests a pause of the encode queue.\r
354         /// </summary>\r
355         public void Pause()\r
356         {\r
357             this.Paused = true;\r
358 \r
359             if (this.QueuePauseRequested != null)\r
360                 this.QueuePauseRequested(this, new EventArgs());\r
361         }\r
362 \r
363         /// <summary>\r
364         /// Run through all the jobs on the queue.\r
365         /// </summary>\r
366         /// <param name="state">Object State</param>\r
367         private void StartQueue(object state)\r
368         {\r
369             // Run through each item on the queue\r
370             while (this.Count != 0)\r
371             {\r
372                 Job encJob = this.GetNextJob();\r
373                 this.WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file\r
374 \r
375                 Run(encJob, false);\r
376 \r
377                 if (HbProcess == null)\r
378                 {\r
379                     return;\r
380                 }\r
381                 HbProcess.WaitForExit();\r
382 \r
383                 AddCLIQueryToLog(encJob);\r
384                 this.CopyLog(this.LastEncode.Destination);\r
385 \r
386                 HbProcess.Close();\r
387                 HbProcess.Dispose();\r
388 \r
389                 // Growl\r
390                 if (Properties.Settings.Default.growlEncode)\r
391                     GrowlCommunicator.Notify("Encode Completed",\r
392                                              "Put down that cocktail...\nyour Handbrake encode is done.");\r
393 \r
394                 while (this.Paused) // Need to find a better way of doing this.\r
395                 {\r
396                     Thread.Sleep(2000);\r
397                 }\r
398             }\r
399             this.LastEncode = new Job();\r
400 \r
401             if (this.QueueCompleted != null)\r
402                 this.QueueCompleted(this, new EventArgs());\r
403 \r
404             // After the encode is done, we may want to shutdown, suspend etc.\r
405             Finish();\r
406         }\r
407 \r
408         #endregion\r
409     }\r
410 }