OSDN Git Service

MacGUI: rename PictureController.mm too
[handbrake-jp/handbrake-jp-git.git] / win / C# / EncodeQueue / EncodeAndQueueHandler.cs
1 /*  EncodeAndQueueHandler.cs $\r
2         \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
6 \r
7 using System;\r
8 using System.Collections.Generic;\r
9 using System.Collections.ObjectModel;\r
10 using System.Diagnostics;\r
11 using System.IO;\r
12 using System.Threading;\r
13 using System.Windows.Forms;\r
14 using System.Xml.Serialization;\r
15 using Handbrake.Functions;\r
16 \r
17 namespace Handbrake.EncodeQueue\r
18 {\r
19     public class EncodeAndQueueHandler\r
20     {\r
21         private static XmlSerializer serializer = new XmlSerializer(typeof(List<Job>));\r
22         private List<Job> queue = new List<Job>();\r
23         private int nextJobId;\r
24 \r
25         #region Event Handlers\r
26         /// <summary>\r
27         /// Fires when an encode job has been started.\r
28         /// </summary>\r
29         public event EventHandler NewJobStarted;\r
30 \r
31         /// <summary>\r
32         /// Fires when a pause to the encode queue has been requested.\r
33         /// </summary>\r
34         public event EventHandler QueuePauseRequested;\r
35 \r
36         /// <summary>\r
37         /// Fires when an encode job has been completed.\r
38         /// </summary>\r
39         public event EventHandler CurrentJobCompleted;\r
40 \r
41         /// <summary>\r
42         /// Fires when the entire encode queue has completed.\r
43         /// </summary>\r
44         public event EventHandler QueueCompleted;\r
45         #endregion\r
46 \r
47         #region Queue\r
48         /// <summary>\r
49         /// Gets and removes the next job in the queue.\r
50         /// </summary>\r
51         /// <returns>The job that was removed from the queue.</returns>\r
52         private Job GetNextJob()\r
53         {\r
54             Job job = queue[0];\r
55             LastEncode = job;\r
56             RemoveJob(0); // Remove the item which we are about to pass out.\r
57 \r
58             WriteQueueStateToFile("hb_queue_recovery.xml");\r
59 \r
60             return job;\r
61         }\r
62 \r
63         /// <summary>\r
64         /// Gets the current state of the encode queue.\r
65         /// </summary>\r
66         public ReadOnlyCollection<Job> CurrentQueue\r
67         {\r
68             get { return queue.AsReadOnly(); }\r
69         }\r
70 \r
71         /// <summary>\r
72         /// Gets the number of items in the queue.\r
73         /// </summary>\r
74         public int Count\r
75         {\r
76             get { return queue.Count; }\r
77         }\r
78 \r
79         /// <summary>\r
80         /// Adds an item to the queue.\r
81         /// </summary>\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         public void AddJob(string query, string source, string destination)\r
86         {\r
87             Job newJob = new Job { Id = nextJobId++, Query = query, Source = source, Destination = destination };\r
88 \r
89             queue.Add(newJob);\r
90             WriteQueueStateToFile("hb_queue_recovery.xml");\r
91         }\r
92 \r
93         /// <summary>\r
94         /// Removes an item from the queue.\r
95         /// </summary>\r
96         /// <param name="index">The zero-based location of the job in the queue.</param>\r
97         public void RemoveJob(int index)\r
98         {\r
99             queue.RemoveAt(index);\r
100             WriteQueueStateToFile("hb_queue_recovery.xml");\r
101         }\r
102 \r
103         /// <summary>\r
104         /// Moves an item up one position in the queue.\r
105         /// </summary>\r
106         /// <param name="index">The zero-based location of the job in the queue.</param>\r
107         public void MoveUp(int index)\r
108         {\r
109             if (index > 0)\r
110             {\r
111                 Job item = queue[index];\r
112 \r
113                 queue.RemoveAt(index);\r
114                 queue.Insert((index - 1), item);\r
115             }\r
116 \r
117             WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file\r
118         }\r
119 \r
120         /// <summary>\r
121         /// Moves an item down one position in the queue.\r
122         /// </summary>\r
123         /// <param name="index">The zero-based location of the job in the queue.</param>\r
124         public void MoveDown(int index)\r
125         {\r
126             if (index < queue.Count - 1)\r
127             {\r
128                 Job item = queue[index];\r
129 \r
130                 queue.RemoveAt(index);\r
131                 queue.Insert((index + 1), item);\r
132             }\r
133 \r
134             WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file\r
135         }\r
136 \r
137         /// <summary>\r
138         /// Writes the current state of the queue to a file.\r
139         /// </summary>\r
140         /// <param name="file">The location of the file to write the queue to.</param>\r
141         public void WriteQueueStateToFile(string file)\r
142         {\r
143             string tempPath = file == "hb_queue_recovery.xml" ? Path.Combine(Path.GetTempPath(), "hb_queue_recovery.xml") : file;\r
144 \r
145             try\r
146             {\r
147                 using (FileStream strm = new FileStream(tempPath, FileMode.Create, FileAccess.Write))\r
148                 {\r
149                     serializer.Serialize(strm, queue);\r
150                     strm.Close();\r
151                     strm.Dispose();\r
152                 }\r
153             }\r
154             catch (Exception)\r
155             {\r
156                 // Any Errors will be out of diskspace/permissions problems. \r
157                 // Don't report them as they'll annoy the user.\r
158             }\r
159         }\r
160 \r
161         /// <summary>\r
162         /// Writes the current state of the queue in the form of a batch (.bat) file.\r
163         /// </summary>\r
164         /// <param name="file">The location of the file to write the batch file to.</param>\r
165         public void WriteBatchScriptToFile(string file)\r
166         {\r
167             string queries = "";\r
168             foreach (Job queue_item in queue)\r
169             {\r
170                 string q_item = queue_item.Query;\r
171                 string fullQuery = '"' + Application.StartupPath + "\\HandBrakeCLI.exe" + '"' + q_item;\r
172 \r
173                 if (queries == string.Empty)\r
174                     queries = queries + fullQuery;\r
175                 else\r
176                     queries = queries + " && " + fullQuery;\r
177             }\r
178             string strCmdLine = queries;\r
179 \r
180             if (file != "")\r
181             {\r
182                 try\r
183                 {\r
184                     // Create a StreamWriter and open the file, Write the batch file query to the file and \r
185                     // Close the stream\r
186                     using (StreamWriter line = new StreamWriter(file))\r
187                     {\r
188                         line.WriteLine(strCmdLine);\r
189                     }\r
190 \r
191                     MessageBox.Show("Your batch script has been sucessfully saved.", "Status", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);\r
192                 }\r
193                 catch (Exception)\r
194                 {\r
195                     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
196                 }\r
197 \r
198             }\r
199         }\r
200 \r
201         /// <summary>\r
202         /// Reads a serialized XML file that represents a queue of encoding jobs.\r
203         /// </summary>\r
204         /// <param name="file">The location of the file to read the queue from.</param>\r
205         public void LoadQueueFromFile(string file)\r
206         {\r
207             string tempPath = file == "hb_queue_recovery.xml" ? Path.Combine(Path.GetTempPath(), "hb_queue_recovery.xml") : file;\r
208 \r
209             if (File.Exists(tempPath))\r
210             {\r
211                 using (FileStream strm = new FileStream(tempPath, FileMode.Open, FileAccess.Read))\r
212                 {\r
213                     if (strm.Length != 0)\r
214                     {\r
215                         List<Job> list = serializer.Deserialize(strm) as List<Job>;\r
216 \r
217                         if (list != null)\r
218                             foreach (Job item in list)\r
219                                 queue.Add(item);\r
220 \r
221                         if (file != "hb_queue_recovery.xml")\r
222                             WriteQueueStateToFile("hb_queue_recovery.xml");\r
223                     }\r
224                 }\r
225             }\r
226         }\r
227 \r
228         /// <summary>\r
229         /// Checks the current queue for an existing instance of the specified destination.\r
230         /// </summary>\r
231         /// <param name="destination">The destination of the encode.</param>\r
232         /// <returns>Whether or not the supplied destination is already in the queue.</returns>\r
233         public bool CheckForDestinationDuplicate(string destination)\r
234         {\r
235             foreach (Job checkItem in queue)\r
236             {\r
237                 if (checkItem.Destination.Contains(destination.Replace("\\\\", "\\")))\r
238                     return true;\r
239             }\r
240 \r
241             return false;\r
242         }\r
243 \r
244         #endregion\r
245 \r
246         #region Encoding\r
247 \r
248         /// <summary>\r
249         /// Gets the last encode that was processed.\r
250         /// </summary>\r
251         /// <returns></returns> \r
252         public Job LastEncode { get; set; }\r
253 \r
254         /// <summary>\r
255         /// Request Pause\r
256         /// </summary>\r
257         public Boolean PauseRequested { get; private set; }\r
258 \r
259         /// <summary>\r
260         /// Starts encoding the first job in the queue and continues encoding until all jobs\r
261         /// have been encoded.\r
262         /// </summary>\r
263         public void StartEncodeQueue()\r
264         {\r
265             if (this.Count != 0)\r
266             {\r
267                 if (PauseRequested)\r
268                     PauseRequested = false;\r
269                 else\r
270                 {\r
271                     PauseRequested = false;\r
272                     try\r
273                     {\r
274                         Thread theQueue = new Thread(startProcess) { IsBackground = true };\r
275                         theQueue.Start();\r
276                     }\r
277                     catch (Exception exc)\r
278                     {\r
279                         MessageBox.Show(exc.ToString());\r
280                     }\r
281                 }\r
282             }\r
283         }\r
284 \r
285         /// <summary>\r
286         /// Requests a pause of the encode queue.\r
287         /// </summary>\r
288         public void RequestPause()\r
289         {\r
290             PauseRequested = true;\r
291 \r
292             if (QueuePauseRequested != null)\r
293                 QueuePauseRequested(this, new EventArgs());\r
294         }\r
295 \r
296         /// <summary>\r
297         /// Stops the current job.\r
298         /// </summary>\r
299         public void EndEncodeJob()\r
300         {\r
301             CloseCLI();\r
302         }\r
303 \r
304         private void startProcess(object state)\r
305         {\r
306             // Run through each item on the queue\r
307             while (this.Count != 0)\r
308             {\r
309                 string query = GetNextJob().Query;\r
310                 WriteQueueStateToFile("hb_queue_recovery.xml"); // Update the queue recovery file\r
311 \r
312                 RunCli(query);\r
313 \r
314                 if (NewJobStarted != null)\r
315                     NewJobStarted(this, new EventArgs());\r
316 \r
317                 hbProcess.WaitForExit();\r
318 \r
319                 AddCLIQueryToLog(query);\r
320                 CopyLog(LastEncode.Destination);\r
321 \r
322                 hbProcess.Close();\r
323                 hbProcess.Dispose();\r
324                 \r
325                 isEncoding = false;\r
326 \r
327                 //Growl\r
328                 if (Properties.Settings.Default.growlEncode)\r
329                     GrowlCommunicator.Notify("Encode Completed", "Put down that cocktail...\nyour Handbrake encode is done.");\r
330 \r
331                 if (CurrentJobCompleted != null)\r
332                     CurrentJobCompleted(this, new EventArgs());\r
333 \r
334                 while (PauseRequested) // Need to find a better way of doing this.\r
335                 {\r
336                     Thread.Sleep(5000);\r
337                 }\r
338             }\r
339 \r
340             if (QueueCompleted != null)\r
341                 QueueCompleted(this, new EventArgs());\r
342 \r
343             // After the encode is done, we may want to shutdown, suspend etc.\r
344             AfterEncodeAction();\r
345         }\r
346 \r
347         #endregion\r
348 \r
349         #region CLI and Log Handling\r
350         public Process hbProcess { get; set; }\r
351         public int processID { get; set; }\r
352         public IntPtr processHandle { get; set; }\r
353         public String currentQuery { get; set; }\r
354         public Boolean isEncoding { get; set; }\r
355 \r
356         /// <summary>\r
357         /// Execute a HandBrakeCLI process.\r
358         /// </summary>\r
359         /// <param name="query">The CLI Query</param>\r
360         public void RunCli(string query)\r
361         {\r
362             try\r
363             {\r
364                 string handbrakeCLIPath = Path.Combine(Application.StartupPath, "HandBrakeCLI.exe");\r
365                 string logPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs", "last_encode_log.txt");\r
366                 string strCmdLine = String.Format(@" /C """"{0}"" {1} 2>""{2}"" """, handbrakeCLIPath, query, logPath);\r
367                 ProcessStartInfo cliStart = new ProcessStartInfo("CMD.exe", strCmdLine);\r
368 \r
369                 if (Properties.Settings.Default.enocdeStatusInGui)\r
370                 {\r
371                     cliStart.RedirectStandardOutput = true;\r
372                     cliStart.UseShellExecute = false;\r
373                 }\r
374                 if (Properties.Settings.Default.cli_minimized)\r
375                     cliStart.WindowStyle = ProcessWindowStyle.Minimized;\r
376 \r
377                 Process[] before = Process.GetProcesses(); // Get a list of running processes before starting.\r
378                 hbProcess = Process.Start(cliStart);\r
379                 processID = Main.getCliProcess(before);\r
380                 isEncoding = true;\r
381                 currentQuery = query;\r
382                 if (hbProcess != null)\r
383                     processHandle = hbProcess.MainWindowHandle; // Set the process Handle\r
384 \r
385                 // Set the process Priority\r
386                 Process hbCliProcess = null;\r
387                 if (processID != -1)\r
388                     hbCliProcess = Process.GetProcessById(processID);\r
389 \r
390                 if (hbCliProcess != null)\r
391                     switch (Properties.Settings.Default.processPriority)\r
392                     {\r
393                         case "Realtime":\r
394                             hbCliProcess.PriorityClass = ProcessPriorityClass.RealTime;\r
395                             break;\r
396                         case "High":\r
397                             hbCliProcess.PriorityClass = ProcessPriorityClass.High;\r
398                             break;\r
399                         case "Above Normal":\r
400                             hbCliProcess.PriorityClass = ProcessPriorityClass.AboveNormal;\r
401                             break;\r
402                         case "Normal":\r
403                             hbCliProcess.PriorityClass = ProcessPriorityClass.Normal;\r
404                             break;\r
405                         case "Low":\r
406                             hbCliProcess.PriorityClass = ProcessPriorityClass.Idle;\r
407                             break;\r
408                         default:\r
409                             hbCliProcess.PriorityClass = ProcessPriorityClass.BelowNormal;\r
410                             break;\r
411                     }\r
412             }\r
413             catch (Exception exc)\r
414             {\r
415                 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
416             }\r
417 \r
418         }\r
419 \r
420         /// <summary>\r
421         /// Kill the CLI process\r
422         /// </summary>\r
423         private void CloseCLI()\r
424         {\r
425             hbProcess.Kill();\r
426             isEncoding = false;\r
427         }\r
428 \r
429         /// <summary>\r
430         /// Perform an action after an encode. e.g a shutdown, standby, restart etc.\r
431         /// </summary>\r
432         private void AfterEncodeAction()\r
433         {\r
434             isEncoding = false;\r
435             currentQuery = String.Empty;\r
436 \r
437             //Growl\r
438             if (Properties.Settings.Default.growlQueue)\r
439                 GrowlCommunicator.Notify("Queue Completed", "Put down that cocktail...\nyour Handbrake queue is done.");\r
440 \r
441             // Do something whent he encode ends.\r
442             switch (Properties.Settings.Default.CompletionOption)\r
443             {\r
444                 case "Shutdown":\r
445                     Process.Start("Shutdown", "-s -t 60");\r
446                     break;\r
447                 case "Log Off":\r
448                     Win32.ExitWindowsEx(0, 0);\r
449                     break;\r
450                 case "Suspend":\r
451                     Application.SetSuspendState(PowerState.Suspend, true, true);\r
452                     break;\r
453                 case "Hibernate":\r
454                     Application.SetSuspendState(PowerState.Hibernate, true, true);\r
455                     break;\r
456                 case "Lock System":\r
457                     Win32.LockWorkStation();\r
458                     break;\r
459                 case "Quit HandBrake":\r
460                     Application.Exit();\r
461                     break;\r
462                 default:\r
463                     break;\r
464             }\r
465         }\r
466 \r
467         /// <summar>\r
468         /// Append the CLI query to the start of the log file.\r
469         /// </summary>\r
470         /// <param name="query"></param>\r
471         private static void AddCLIQueryToLog(string query)\r
472         {\r
473             string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";\r
474             string logPath = Path.Combine(logDir, "last_encode_log.txt");\r
475 \r
476             StreamReader reader = new StreamReader(File.Open(logPath, FileMode.Open, FileAccess.Read, FileShare.Read));\r
477             String log = reader.ReadToEnd();\r
478             reader.Close();\r
479 \r
480             StreamWriter writer = new StreamWriter(File.Create(logPath));\r
481 \r
482             writer.Write("### CLI Query: " + query + "\n\n");\r
483             writer.Write("#########################################\n\n");\r
484             writer.WriteLine(log);\r
485             writer.Flush();\r
486             writer.Close();\r
487         }\r
488 \r
489         /// <summary>\r
490         /// Save a copy of the log to the users desired location or a default location\r
491         /// if this feature is enabled in options.\r
492         /// </summary>\r
493         /// <param name="destination"></param>\r
494         private static void CopyLog(string destination)\r
495         {\r
496             try\r
497             {\r
498                 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";\r
499                 string tempLogFile = Path.Combine(logDir, "last_encode_log.txt");\r
500 \r
501                 string encodeDestinationPath = Path.GetDirectoryName(destination);\r
502                 String destinationFile = Path.GetFileName(destination);\r
503                 string encodeLogFile = destinationFile + " " + DateTime.Now.ToString().Replace("/", "-").Replace(":", "-") + ".txt";\r
504 \r
505                 // Make sure the log directory exists.\r
506                 if (!Directory.Exists(logDir))\r
507                     Directory.CreateDirectory(logDir);\r
508 \r
509                 // Copy the Log to HandBrakes log folder in the users applciation data folder.\r
510                 File.Copy(tempLogFile, Path.Combine(logDir, encodeLogFile));\r
511 \r
512                 // Save a copy of the log file in the same location as the enocde.\r
513                 if (Properties.Settings.Default.saveLogWithVideo)\r
514                     File.Copy(tempLogFile, Path.Combine(encodeDestinationPath, encodeLogFile));\r
515 \r
516                 // Save a copy of the log file to a user specified location\r
517                 if (Directory.Exists(Properties.Settings.Default.saveLogPath))\r
518                     if (Properties.Settings.Default.saveLogPath != String.Empty && Properties.Settings.Default.saveLogToSpecifiedPath)\r
519                         File.Copy(tempLogFile, Path.Combine(Properties.Settings.Default.saveLogPath, encodeLogFile));\r
520             }\r
521             catch (Exception exc)\r
522             {\r
523                 MessageBox.Show("Something went a bit wrong trying to copy your log file.\nError Information:\n\n" + exc, "Error",\r
524                                 MessageBoxButtons.OK, MessageBoxIcon.Error);\r
525             }\r
526         }\r
527         #endregion\r
528     }\r
529 }