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
8 using System.Windows.Forms;
\r
10 using System.Diagnostics;
\r
11 using System.Text.RegularExpressions;
\r
12 using System.Collections.Generic;
\r
13 using System.Xml.Serialization;
\r
14 using System.Threading;
\r
15 using Handbrake.EncodeQueue;
\r
18 namespace Handbrake.Functions
\r
22 // Private Variables
\r
23 private static readonly XmlSerializer ser = new XmlSerializer(typeof(List<Job>));
\r
26 /// Calculate the duration of the selected title and chapters
\r
28 public static TimeSpan calculateDuration(string chapter_start, string chapter_end, Parsing.Title selectedTitle)
\r
30 TimeSpan Duration = TimeSpan.FromSeconds(0.0);
\r
32 // Get the durations between the 2 chapter points and add them together.
\r
33 if (chapter_start != "Auto" && chapter_end != "Auto")
\r
35 int start_chapter, end_chapter;
\r
36 int.TryParse(chapter_start, out start_chapter);
\r
37 int.TryParse(chapter_end, out end_chapter);
\r
39 int position = start_chapter - 1;
\r
41 if (start_chapter <= end_chapter)
\r
43 if (end_chapter > selectedTitle.Chapters.Count)
\r
44 end_chapter = selectedTitle.Chapters.Count;
\r
46 while (position != end_chapter)
\r
48 TimeSpan dur = selectedTitle.Chapters[position].Duration;
\r
49 Duration = Duration + dur;
\r
58 /// Select the longest title in the DVD title dropdown menu on frmMain
\r
60 public static Parsing.Title selectLongestTitle(ComboBox drp_dvdtitle)
\r
62 int current_largest = 0;
\r
63 Parsing.Title title2Select;
\r
65 // Check if there are titles in the DVD title dropdown menu and make sure, it's not just "Automatic"
\r
66 if (drp_dvdtitle.Items[0].ToString() != "Automatic")
\r
67 title2Select = (Parsing.Title)drp_dvdtitle.Items[0];
\r
69 title2Select = null;
\r
71 // So, If there are titles in the DVD Title dropdown menu, lets select the longest.
\r
72 if (title2Select != null)
\r
74 foreach (Parsing.Title x in drp_dvdtitle.Items)
\r
76 string title = x.ToString();
\r
77 if (title != "Automatic")
\r
79 string[] y = title.Split(' ');
\r
80 string time = y[1].Replace("(", "").Replace(")", "");
\r
81 string[] z = time.Split(':');
\r
83 int hours = int.Parse(z[0]) * 60 * 60;
\r
84 int minutes = int.Parse(z[1]) * 60;
\r
85 int seconds = int.Parse(z[2]);
\r
86 int total_sec = hours + minutes + seconds;
\r
88 if (current_largest == 0)
\r
90 current_largest = hours + minutes + seconds;
\r
95 if (total_sec > current_largest)
\r
97 current_largest = total_sec;
\r
104 return title2Select;
\r
108 /// Set's up the DataGridView on the Chapters tab (frmMain)
\r
110 public static DataGridView chapterNaming(DataGridView data_chpt, string chapter_end)
\r
112 int i = 0, finish = 0;
\r
114 if (chapter_end != "Auto")
\r
115 int.TryParse(chapter_end, out finish);
\r
119 int n = data_chpt.Rows.Add();
\r
120 data_chpt.Rows[n].Cells[0].Value = (i + 1);
\r
121 data_chpt.Rows[n].Cells[1].Value = "Chapter " + (i + 1);
\r
122 data_chpt.Rows[n].Cells[0].ValueType = typeof(int);
\r
123 data_chpt.Rows[n].Cells[1].ValueType = typeof(string);
\r
131 /// Function which generates the filename and path automatically based on
\r
132 /// the Source Name, DVD title and DVD Chapters
\r
134 public static string autoName(ComboBox drp_dvdtitle, string chapter_start, string chatper_end, string source, string dest, int format)
\r
136 string AutoNamePath = string.Empty;
\r
137 if (drp_dvdtitle.Text != "Automatic")
\r
139 // Get the Source Name
\r
140 string sourceName = Path.GetFileNameWithoutExtension(source);
\r
142 // Get the Selected Title Number
\r
143 string[] titlesplit = drp_dvdtitle.Text.Split(' ');
\r
144 string dvdTitle = titlesplit[0].Replace("Automatic", "");
\r
146 // Get the Chapter Start and Chapter End Numbers
\r
147 string chapterStart = chapter_start.Replace("Auto", "");
\r
148 string chapterFinish = chatper_end.Replace("Auto", "");
\r
149 string combinedChapterTag = chapterStart;
\r
150 if (chapterFinish != chapterStart && chapterFinish != "")
\r
151 combinedChapterTag = chapterStart + "-" + chapterFinish;
\r
153 // Get the destination filename.
\r
154 string destination_filename;
\r
155 if (Properties.Settings.Default.autoNameFormat != "")
\r
157 destination_filename = Properties.Settings.Default.autoNameFormat;
\r
158 destination_filename = destination_filename.Replace("{source}", sourceName).Replace("{title}", dvdTitle).Replace("{chapters}", combinedChapterTag);
\r
161 destination_filename = sourceName + "_T" + dvdTitle + "_C" + combinedChapterTag;
\r
163 // Add the appropriate file extension
\r
166 if (Properties.Settings.Default.useM4v)
\r
167 destination_filename += ".m4v";
\r
169 destination_filename += ".mp4";
\r
171 else if (format == 1)
\r
172 destination_filename += ".mkv";
\r
174 // Now work out the path where the file will be stored.
\r
175 // First case: If the destination box doesn't already contain a path, make one.
\r
176 if (!dest.Contains(Path.DirectorySeparatorChar.ToString()))
\r
178 // If there is an auto name path, use it...
\r
179 if (Properties.Settings.Default.autoNamePath.Trim() != "" && Properties.Settings.Default.autoNamePath.Trim() != "Click 'Browse' to set the default location")
\r
180 AutoNamePath = Path.Combine(Properties.Settings.Default.autoNamePath, destination_filename);
\r
181 else // ...otherwise, output to the source directory
\r
182 AutoNamePath = null;
\r
184 else // Otherwise, use the path that is already there.
\r
186 // Use the path and change the file extension to match the previous destination
\r
187 AutoNamePath = Path.Combine(Path.GetDirectoryName(dest), destination_filename);
\r
188 AutoNamePath = Path.ChangeExtension(AutoNamePath, Path.GetExtension(dest));
\r
192 return AutoNamePath;
\r
196 /// Get's HandBrakes version data from the CLI.
\r
198 /// <returns>Arraylist of Version Data. 0 = hb_version 1 = hb_build</returns>
\r
199 public static void setCliVersionData()
\r
203 // 0 = SVN Build / Version
\r
205 Process cliProcess = new Process();
\r
206 ProcessStartInfo handBrakeCLI = new ProcessStartInfo("HandBrakeCLI.exe", " -u")
\r
208 UseShellExecute = false,
\r
209 RedirectStandardError = true,
\r
210 RedirectStandardOutput = true,
\r
211 CreateNoWindow = true
\r
213 cliProcess.StartInfo = handBrakeCLI;
\r
217 cliProcess.Start();
\r
218 // Retrieve standard output and report back to parent thread until the process is complete
\r
219 TextReader stdOutput = cliProcess.StandardError;
\r
221 while (!cliProcess.HasExited)
\r
223 line = stdOutput.ReadLine() ?? "";
\r
224 Match m = Regex.Match(line, @"HandBrake ([0-9.]*)(svn[0-9M]*) \([0-9]*\)");
\r
228 string data = line.Replace("(", "").Replace(")", "").Replace("HandBrake ", "");
\r
229 string[] arr = data.Split(' ');
\r
231 Properties.Settings.Default.hb_build = int.Parse(arr[1]);
\r
232 Properties.Settings.Default.hb_version = arr[0];
\r
234 if (cliProcess.TotalProcessorTime.Seconds > 10) // Don't wait longer than 10 seconds.
\r
236 Process cli = Process.GetProcessById(cliProcess.Id);
\r
237 if (!cli.HasExited)
\r
242 catch (Exception e)
\r
244 MessageBox.Show("Unable to retrieve version information from the CLI. \nError:\n" + e);
\r
249 /// Check if the queue recovery file contains records.
\r
250 /// If it does, it means the last queue did not complete before HandBrake closed.
\r
251 /// So, return a boolean if true.
\r
253 public static Boolean check_queue_recovery()
\r
257 string tempPath = Path.Combine(Path.GetTempPath(), "hb_queue_recovery.xml");
\r
258 if (File.Exists(tempPath))
\r
260 using (FileStream strm = new FileStream(tempPath, FileMode.Open, FileAccess.Read))
\r
262 List<Job> list = ser.Deserialize(strm) as List<Job>;
\r
264 if (list.Count != 0)
\r
272 return false; // Keep quiet about the error.
\r
277 /// Get the Process ID of HandBrakeCLI for the current instance.
\r
279 /// <param name="before">List of processes before the new process was started</param>
\r
280 /// <returns>Int - Process ID</returns>
\r
281 public static int getCliProcess(Process[] before)
\r
283 // This is a bit of a cludge. Maybe someone has a better idea on how to impliment this.
\r
284 // Since we used CMD to start HandBrakeCLI, we don't get the process ID from hbProc.
\r
285 // Instead we take the processes before and after, and get the ID of HandBrakeCLI.exe
\r
286 // avoiding any previous instances of HandBrakeCLI.exe in before.
\r
287 // Kill the current process.
\r
289 Process[] hbProcesses = Process.GetProcessesByName("HandBrakeCLI");
\r
291 // Another hack. We maybe need to wait a few seconds for HandBrakeCLI to launch
\r
292 if (hbProcesses.Length == 0)
\r
294 Thread.Sleep(2000);
\r
295 hbProcesses = Process.GetProcessesByName("HandBrakeCLI");
\r
298 Process hbProcess = null;
\r
299 if (hbProcesses.Length > 0)
\r
300 foreach (Process process in hbProcesses)
\r
302 Boolean found = false;
\r
303 // Check if the current CLI instance was running before we started the current one
\r
304 foreach (Process bprocess in before)
\r
306 if (process.Id == bprocess.Id)
\r
310 // If it wasn't running before, we found the process we want.
\r
313 hbProcess = process;
\r
317 if (hbProcess != null)
\r
318 return hbProcess.Id;
\r
324 /// Clear all the encode log files.
\r
326 public static void clearLogs()
\r
328 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
329 if (Directory.Exists(logDir))
\r
331 DirectoryInfo info = new DirectoryInfo(logDir);
\r
332 FileInfo[] logFiles = info.GetFiles("*.txt");
\r
333 foreach (FileInfo file in logFiles)
\r
335 if (!file.Name.Contains("last_scan_log") && !file.Name.Contains("last_encode_log") && !file.Name.Contains("tmp_appReadable_log.txt"))
\r
337 File.Delete(file.FullName);
\r
344 /// Begins checking for an update to HandBrake.
\r
346 /// <param name="callback">The method that will be called when the check is finished.</param>
\r
347 /// <param name="debug">Whether or not to execute this in debug mode.</param>
\r
348 public static void BeginCheckForUpdates(AsyncCallback callback, bool debug)
\r
350 ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
\r
354 // Is this a stable or unstable build?
\r
355 string url = Properties.Settings.Default.hb_build.ToString().EndsWith("1") ? Properties.Settings.Default.appcast_unstable : Properties.Settings.Default.appcast;
\r
357 // Initialize variables
\r
358 WebRequest request = WebRequest.Create(url);
\r
359 WebResponse response = request.GetResponse();
\r
360 AppcastReader reader = new AppcastReader();
\r
362 // Get the data, convert it to a string, and parse it into the AppcastReader
\r
363 reader.getInfo(new StreamReader(response.GetResponseStream()).ReadToEnd());
\r
365 // Further parse the information
\r
366 string build = reader.build;
\r
368 int latest = int.Parse(build);
\r
369 int current = Properties.Settings.Default.hb_build;
\r
370 int skip = Properties.Settings.Default.skipversion;
\r
372 // If the user wanted to skip this version, don't report the update
\r
373 if (latest == skip)
\r
375 UpdateCheckInformation info = new UpdateCheckInformation() { NewVersionAvailable = false, BuildInformation = null };
\r
376 callback(new UpdateCheckResult(debug, info));
\r
380 // Set when the last update was
\r
381 Properties.Settings.Default.lastUpdateCheckDate = DateTime.Now;
\r
382 Properties.Settings.Default.Save();
\r
384 UpdateCheckInformation info2 = new UpdateCheckInformation() { NewVersionAvailable = latest > current, BuildInformation = reader };
\r
385 callback(new UpdateCheckResult(debug, info2));
\r
387 catch (Exception exc)
\r
389 callback(new UpdateCheckResult(debug, new UpdateCheckInformation() { Error = exc }));
\r
397 /// <param name="result"></param>
\r
398 /// <returns></returns>
\r
399 public static UpdateCheckInformation EndCheckForUpdates(IAsyncResult result)
\r
401 UpdateCheckResult checkResult = (UpdateCheckResult)result;
\r
402 return checkResult.Result;
\r
406 /// Used in EndUpdateCheck() for update checking and the IAsyncResult design pattern.
\r
408 private class UpdateCheckResult : IAsyncResult
\r
410 public UpdateCheckResult(object asyncState, UpdateCheckInformation info)
\r
412 AsyncState = asyncState;
\r
417 /// Gets whether the check was executed in debug mode.
\r
419 public object AsyncState { get; private set; }
\r
422 /// Gets the result of the update check.
\r
424 public UpdateCheckInformation Result { get; private set; }
\r
426 public WaitHandle AsyncWaitHandle { get { throw new NotImplementedException(); } }
\r
427 public bool CompletedSynchronously { get { throw new NotImplementedException(); } }
\r
428 public bool IsCompleted { get { throw new NotImplementedException(); } }
\r
432 /// Map languages and their iso639_2 value into a IDictionary
\r
434 /// <returns></returns>
\r
435 public static IDictionary<string, string> mapLanguages()
\r
437 IDictionary<string, string> languageMap = new Dictionary<string, string>
\r
441 {"Abkhazian", "abk"},
\r
442 {"Afrikaans", "afr"},
\r
444 {"Albanian", "sqi"},
\r
445 {"Amharic", "amh"},
\r
447 {"Aragonese", "arg"},
\r
448 {"Armenian", "hye"},
\r
449 {"Assamese", "asm"},
\r
451 {"Avestan", "ave"},
\r
453 {"Azerbaijani", "aze"},
\r
454 {"Bashkir", "bak"},
\r
455 {"Bambara", "bam"},
\r
457 {"Belarusian", "bel"},
\r
458 {"Bengali", "ben"},
\r
460 {"Bislama", "bis"},
\r
461 {"Bosnian", "bos"},
\r
463 {"Bulgarian", "bul"},
\r
464 {"Burmese", "mya"},
\r
465 {"Catalan", "cat"},
\r
466 {"Chamorro", "cha"},
\r
467 {"Chechen", "che"},
\r
468 {"Chinese", "zho"},
\r
469 {"Church Slavic", "chu"},
\r
470 {"Chuvash", "chv"},
\r
471 {"Cornish", "cor"},
\r
472 {"Corsican", "cos"},
\r
478 {"Dzongkha", "dzo"},
\r
479 {"English", "eng"},
\r
480 {"Esperanto", "epo"},
\r
481 {"Estonian", "est"},
\r
483 {"Faroese", "fao"},
\r
485 {"Finnish", "fin"},
\r
487 {"Western Frisian", "fry"},
\r
489 {"Georgian", "kat"},
\r
491 {"Gaelic (Scots)", "gla"},
\r
493 {"Galician", "glg"},
\r
495 {"Greek Modern", "ell"},
\r
496 {"Guarani", "grn"},
\r
497 {"Gujarati", "guj"},
\r
498 {"Haitian", "hat"},
\r
503 {"Hiri Motu", "hmo"},
\r
504 {"Hungarian", "hun"},
\r
506 {"Icelandic", "isl"},
\r
508 {"Sichuan Yi", "iii"},
\r
509 {"Inuktitut", "iku"},
\r
510 {"Interlingue", "ile"},
\r
511 {"Interlingua", "ina"},
\r
512 {"Indonesian", "ind"},
\r
513 {"Inupiaq", "ipk"},
\r
514 {"Italian", "ita"},
\r
515 {"Javanese", "jav"},
\r
516 {"Japanese", "jpn"},
\r
517 {"Kalaallisut", "kal"},
\r
518 {"Kannada", "kan"},
\r
519 {"Kashmiri", "kas"},
\r
522 {"Central Khmer", "khm"},
\r
524 {"Kinyarwanda", "kin"},
\r
525 {"Kirghiz", "kir"},
\r
529 {"Kuanyama", "kua"},
\r
530 {"Kurdish", "kur"},
\r
533 {"Latvian", "lav"},
\r
534 {"Limburgan", "lim"},
\r
535 {"Lingala", "lin"},
\r
536 {"Lithuanian", "lit"},
\r
537 {"Luxembourgish", "ltz"},
\r
538 {"Luba-Katanga", "lub"},
\r
540 {"Macedonian", "mkd"},
\r
541 {"Marshallese", "mah"},
\r
542 {"Malayalam", "mal"},
\r
544 {"Marathi", "mar"},
\r
546 {"Malagasy", "mlg"},
\r
547 {"Maltese", "mlt"},
\r
548 {"Moldavian", "mol"},
\r
549 {"Mongolian", "mon"},
\r
552 {"Ndebele, South", "nbl"},
\r
553 {"Ndebele, North", "nde"},
\r
556 {"Norwegian Nynorsk", "nno"},
\r
557 {"Norwegian Bokmål", "nob"},
\r
558 {"Norwegian", "nor"},
\r
559 {"Chichewa; Nyanja", "nya"},
\r
560 {"Occitan", "oci"},
\r
564 {"Ossetian", "oss"},
\r
565 {"Panjabi", "pan"},
\r
566 {"Persian", "fas"},
\r
569 {"Portuguese", "por"},
\r
571 {"Quechua", "que"},
\r
572 {"Romansh", "roh"},
\r
573 {"Romanian", "ron"},
\r
575 {"Russian", "rus"},
\r
577 {"Sanskrit", "san"},
\r
578 {"Serbian", "srp"},
\r
579 {"Croatian", "hrv"},
\r
580 {"Sinhala", "sin"},
\r
582 {"Slovenian", "slv"},
\r
583 {"Northern Sami", "sme"},
\r
588 {"Sotho Southern", "sot"},
\r
589 {"Spanish", "spa"},
\r
590 {"Sardinian", "srd"},
\r
592 {"Sundanese", "sun"},
\r
593 {"Swahili", "swa"},
\r
594 {"Swedish", "swe"},
\r
595 {"Tahitian", "tah"},
\r
600 {"Tagalog", "tgl"},
\r
602 {"Tibetan", "bod"},
\r
603 {"Tigrinya", "tir"},
\r
607 {"Turkmen", "tuk"},
\r
608 {"Turkish", "tur"},
\r
611 {"Ukrainian", "ukr"},
\r
615 {"Vietnamese", "vie"},
\r
616 {"Volapük", "vol"},
\r
618 {"Walloon", "wln"},
\r
621 {"Yiddish", "yid"},
\r
626 return languageMap;
\r