OSDN Git Service

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