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
6 namespace Handbrake.Functions
\r
9 using System.Collections.Generic;
\r
10 using System.Diagnostics;
\r
15 using System.Text.RegularExpressions;
\r
16 using System.Threading;
\r
17 using System.Windows.Forms;
\r
18 using System.Xml.Serialization;
\r
19 using HandBrake.ApplicationServices.Model;
\r
20 using HandBrake.ApplicationServices.Parsing;
\r
21 using HandBrake.ApplicationServices.Services.Interfaces;
\r
23 using HandBrake.ApplicationServices.Services;
\r
26 /// Useful functions which various screens can use.
\r
28 public static class Main
\r
31 /// The Error Service
\r
33 private static readonly IErrorService errorService = new ErrorService();
\r
36 /// The XML Serializer
\r
38 private static readonly XmlSerializer Ser = new XmlSerializer(typeof(List<Job>));
\r
41 /// Calculate the duration of the selected title and chapters
\r
43 /// <param name="chapterStart">
\r
44 /// The chapter Start.
\r
46 /// <param name="chapterEnd">
\r
47 /// The chapter End.
\r
49 /// <param name="selectedTitle">
\r
50 /// The selected Title.
\r
53 /// The calculated duration.
\r
55 public static TimeSpan CalculateDuration(int chapterStart, int chapterEnd, Title selectedTitle)
\r
57 TimeSpan duration = TimeSpan.FromSeconds(0.0);
\r
60 if (chapterStart != 0 && chapterEnd != 0 && chapterEnd <= selectedTitle.Chapters.Count)
\r
62 for (int i = chapterStart; i <= chapterEnd; i++)
\r
63 duration += selectedTitle.Chapters[i - 1].Duration;
\r
70 /// Set's up the DataGridView on the Chapters tab (frmMain)
\r
72 /// <param name="dataChpt">
\r
73 /// The DataGridView Control
\r
75 /// <param name="chapterEnd">
\r
76 /// The chapter End.
\r
79 /// The chapter naming.
\r
81 public static DataGridView ChapterNaming(DataGridView dataChpt, string chapterEnd)
\r
83 int i = 0, finish = 0;
\r
85 if (chapterEnd != "Auto")
\r
86 int.TryParse(chapterEnd, out finish);
\r
90 int n = dataChpt.Rows.Add();
\r
91 dataChpt.Rows[n].Cells[0].Value = i + 1;
\r
92 dataChpt.Rows[n].Cells[1].Value = "Chapter " + (i + 1);
\r
93 dataChpt.Rows[n].Cells[0].ValueType = typeof(int);
\r
94 dataChpt.Rows[n].Cells[1].ValueType = typeof(string);
\r
102 /// Import a CSV file which contains Chapter Names
\r
104 /// <param name="dataChpt">
\r
105 /// The DataGridView Control
\r
107 /// <param name="filename">
\r
108 /// The filepath and name
\r
110 /// <returns>A Populated DataGridView</returns>
\r
111 public static DataGridView ImportChapterNames(DataGridView dataChpt, string filename)
\r
113 IDictionary<int, string> chapterMap = new Dictionary<int, string>();
\r
116 StreamReader sr = new StreamReader(filename);
\r
117 string csv = sr.ReadLine();
\r
118 while (csv != null)
\r
120 if (csv.Trim() != string.Empty)
\r
122 csv = csv.Replace("\\,", "<!comma!>");
\r
123 string[] contents = csv.Split(',');
\r
125 int.TryParse(contents[0], out chapter);
\r
126 chapterMap.Add(chapter, contents[1].Replace("<!comma!>", ","));
\r
128 csv = sr.ReadLine();
\r
136 foreach (DataGridViewRow item in dataChpt.Rows)
\r
139 chapterMap.TryGetValue((int)item.Cells[0].Value, out name);
\r
140 item.Cells[1].Value = name ?? "Chapter " + item.Cells[0].Value;
\r
147 /// Create a CSV file with the data from the Main Window Chapters tab
\r
149 /// <param name="mainWindow">Main Window</param>
\r
150 /// <param name="filePathName">Path to save the csv file</param>
\r
151 /// <returns>True if successful </returns>
\r
152 public static bool SaveChapterMarkersToCsv(frmMain mainWindow, string filePathName)
\r
156 string csv = string.Empty;
\r
158 foreach (DataGridViewRow row in mainWindow.data_chpt.Rows)
\r
160 csv += row.Cells[0].Value.ToString();
\r
162 csv += row.Cells[1].Value.ToString().Replace(",", "\\,");
\r
163 csv += Environment.NewLine;
\r
165 StreamWriter file = new StreamWriter(filePathName);
\r
171 catch (Exception exc)
\r
173 ShowExceptiowWindow("Unable to save Chapter Makrers file! \nChapter marker names will NOT be saved in your encode", exc.ToString());
\r
179 /// Function which generates the filename and path automatically based on
\r
180 /// the Source Name, DVD title and DVD Chapters
\r
182 /// <param name="mainWindow">
\r
183 /// The main Window.
\r
186 /// The Generated FileName
\r
188 public static string AutoName(frmMain mainWindow)
\r
190 string autoNamePath = string.Empty;
\r
191 if (mainWindow.drp_dvdtitle.Text != "Automatic")
\r
193 // Get the Source Name and remove any invalid characters
\r
194 string sourceName = Path.GetInvalidFileNameChars().Aggregate(mainWindow.SourceName, (current, character) => current.Replace(character.ToString(), string.Empty));
\r
196 if (Properties.Settings.Default.AutoNameRemoveUnderscore)
\r
197 sourceName = sourceName.Replace("_", " ");
\r
199 if (Properties.Settings.Default.AutoNameTitleCase)
\r
200 sourceName = TitleCase(sourceName);
\r
202 // Get the Selected Title Number
\r
203 string[] titlesplit = mainWindow.drp_dvdtitle.Text.Split(' ');
\r
204 string dvdTitle = titlesplit[0].Replace("Automatic", string.Empty);
\r
206 // Get the Chapter Start and Chapter End Numbers
\r
207 string chapterStart = mainWindow.drop_chapterStart.Text.Replace("Auto", string.Empty);
\r
208 string chapterFinish = mainWindow.drop_chapterFinish.Text.Replace("Auto", string.Empty);
\r
209 string combinedChapterTag = chapterStart;
\r
210 if (chapterFinish != chapterStart && chapterFinish != string.Empty)
\r
211 combinedChapterTag = chapterStart + "-" + chapterFinish;
\r
213 // Get the destination filename.
\r
214 string destinationFilename;
\r
215 if (Properties.Settings.Default.autoNameFormat != string.Empty)
\r
217 destinationFilename = Properties.Settings.Default.autoNameFormat;
\r
218 destinationFilename = destinationFilename.Replace("{source}", sourceName)
\r
219 .Replace("{title}", dvdTitle)
\r
220 .Replace("{chapters}", combinedChapterTag);
\r
223 destinationFilename = sourceName + "_T" + dvdTitle + "_C" + combinedChapterTag;
\r
225 // Add the appropriate file extension
\r
226 if (mainWindow.drop_format.SelectedIndex == 0)
\r
228 destinationFilename += Properties.Settings.Default.useM4v || mainWindow.Check_ChapterMarkers.Checked ||
\r
229 mainWindow.AudioSettings.RequiresM4V() || mainWindow.Subtitles.RequiresM4V()
\r
233 else if (mainWindow.drop_format.SelectedIndex == 1)
\r
234 destinationFilename += ".mkv";
\r
236 // Now work out the path where the file will be stored.
\r
237 // First case: If the destination box doesn't already contain a path, make one.
\r
238 if (!mainWindow.text_destination.Text.Contains(Path.DirectorySeparatorChar.ToString()))
\r
240 // If there is an auto name path, use it...
\r
241 if (Properties.Settings.Default.autoNamePath.Trim() == "{source}" && !string.IsNullOrEmpty(mainWindow.sourcePath))
\r
243 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.sourcePath), destinationFilename);
\r
244 if (autoNamePath == mainWindow.sourcePath)
\r
246 // Append out_ to files that already exist or is the source file
\r
247 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.sourcePath), "output_" + destinationFilename);
\r
250 else if (Properties.Settings.Default.autoNamePath.Trim() != string.Empty && Properties.Settings.Default.autoNamePath.Trim() != "Click 'Browse' to set the default location")
\r
252 autoNamePath = Path.Combine(Properties.Settings.Default.autoNamePath, destinationFilename);
\r
254 else // ...otherwise, output to the source directory
\r
255 autoNamePath = null;
\r
257 else // Otherwise, use the path that is already there.
\r
259 // Use the path and change the file extension to match the previous destination
\r
260 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.text_destination.Text), destinationFilename);
\r
262 if (Path.HasExtension(mainWindow.text_destination.Text))
\r
263 autoNamePath = Path.ChangeExtension(autoNamePath,
\r
264 Path.GetExtension(mainWindow.text_destination.Text));
\r
268 return autoNamePath;
\r
272 /// Get's HandBrakes version data from the CLI.
\r
274 public static void SetCliVersionData()
\r
278 // 0 = SVN Build / Version
\r
280 DateTime lastModified = File.GetLastWriteTime("HandBrakeCLI.exe");
\r
282 if (Properties.Settings.Default.hb_build != 0 && Properties.Settings.Default.cliLastModified == lastModified)
\r
287 Properties.Settings.Default.cliLastModified = lastModified;
\r
289 Process cliProcess = new Process();
\r
290 ProcessStartInfo handBrakeCli = new ProcessStartInfo("HandBrakeCLI.exe", " -u -v0")
\r
292 UseShellExecute = false,
\r
293 RedirectStandardError = true,
\r
294 RedirectStandardOutput = true,
\r
295 CreateNoWindow = true
\r
297 cliProcess.StartInfo = handBrakeCli;
\r
301 cliProcess.Start();
\r
303 // Retrieve standard output and report back to parent thread until the process is complete
\r
304 TextReader stdOutput = cliProcess.StandardError;
\r
306 while (!cliProcess.HasExited)
\r
308 line = stdOutput.ReadLine() ?? string.Empty;
\r
309 Match m = Regex.Match(line, @"HandBrake ([svnM0-9.]*) \(([0-9]*)\)");
\r
310 Match platform = Regex.Match(line, @"- ([A-Za-z0-9\s ]*) -");
\r
314 string version = m.Groups[1].Success ? m.Groups[1].Value : string.Empty;
\r
315 string build = m.Groups[2].Success ? m.Groups[2].Value : string.Empty;
\r
318 int.TryParse(build, out buildValue);
\r
320 Properties.Settings.Default.hb_build = buildValue;
\r
321 Properties.Settings.Default.hb_version = version;
\r
324 if (platform.Success)
\r
326 Properties.Settings.Default.hb_platform = platform.Value.Replace("-", string.Empty).Trim();
\r
329 if (cliProcess.TotalProcessorTime.Seconds > 10) // Don't wait longer than 10 seconds.
\r
331 Process cli = Process.GetProcessById(cliProcess.Id);
\r
332 if (!cli.HasExited)
\r
339 Properties.Settings.Default.Save();
\r
341 catch (Exception e)
\r
343 Properties.Settings.Default.hb_build = 0;
\r
344 Properties.Settings.Default.Save();
\r
346 ShowExceptiowWindow("Unable to retrieve version information from the CLI.", e.ToString());
\r
351 /// Check if the queue recovery file contains records.
\r
352 /// If it does, it means the last queue did not complete before HandBrake closed.
\r
353 /// So, return a boolean if true.
\r
356 /// True if there is a queue to recover.
\r
358 public static List<string> CheckQueueRecovery()
\r
362 string tempPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");
\r
363 List<string> queueFiles = new List<string>();
\r
365 DirectoryInfo info = new DirectoryInfo(tempPath);
\r
366 FileInfo[] logFiles = info.GetFiles("*.xml");
\r
367 foreach (FileInfo file in logFiles)
\r
369 if (!file.Name.Contains("hb_queue_recovery"))
\r
372 using (FileStream strm = new FileStream(Path.Combine(file.DirectoryName, file.Name), FileMode.Open, FileAccess.Read))
\r
374 List<Job> list = Ser.Deserialize(strm) as List<Job>;
\r
377 if (list.Count != 0)
\r
379 queueFiles.Add(file.Name);
\r
389 return new List<string>(); // Keep quiet about the error.
\r
394 /// Recover a queue from file.
\r
396 /// <param name="encodeQueue">
\r
397 /// The encode Queue.
\r
399 public static void RecoverQueue(IQueue encodeQueue)
\r
401 DialogResult result = DialogResult.None;
\r
402 List<string> queueFiles = CheckQueueRecovery();
\r
403 if (queueFiles.Count == 1)
\r
405 result = MessageBox.Show(
\r
406 "HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?",
\r
407 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
409 else if (queueFiles.Count > 1)
\r
411 result = MessageBox.Show(
\r
412 "HandBrake has detected multiple unfinished queue files. These will be from multiple instances of HandBrake running. Would you like to recover all unfinished jobs?",
\r
413 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
416 if (result == DialogResult.Yes)
\r
418 foreach (string file in queueFiles)
\r
420 encodeQueue.LoadQueueFromFile(file); // Start Recovery
\r
425 if (IsMultiInstance) return; // Don't tamper with the files if we are multi instance
\r
427 string tempPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");
\r
428 foreach (string file in queueFiles)
\r
430 if (File.Exists(Path.Combine(tempPath, file)))
\r
431 File.Delete(Path.Combine(tempPath, file));
\r
437 /// Gets a value indicating whether HandBrake is running in multi instance mode
\r
439 /// <returns>True if the UI has another instance running</returns>
\r
440 public static bool IsMultiInstance
\r
444 return Process.GetProcessesByName("HandBrake").Length > 0 ? true : false;
\r
449 /// Clear all the encode log files.
\r
451 public static void ClearLogs()
\r
453 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
454 if (Directory.Exists(logDir))
\r
456 DirectoryInfo info = new DirectoryInfo(logDir);
\r
457 FileInfo[] logFiles = info.GetFiles("*.txt");
\r
458 foreach (FileInfo file in logFiles)
\r
460 if (!file.Name.Contains("last_scan_log") && !file.Name.Contains("last_encode_log"))
\r
461 File.Delete(file.FullName);
\r
467 /// Clear old log files x days in the past
\r
469 public static void ClearOldLogs()
\r
471 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
472 if (Directory.Exists(logDir))
\r
474 DirectoryInfo info = new DirectoryInfo(logDir);
\r
475 FileInfo[] logFiles = info.GetFiles("*.txt");
\r
477 foreach (FileInfo file in logFiles)
\r
479 if (file.LastWriteTime < DateTime.Now.AddDays(-30))
\r
481 if (!file.Name.Contains("last_scan_log.txt") && !file.Name.Contains("last_encode_log.txt"))
\r
482 File.Delete(file.FullName);
\r
489 /// Begins checking for an update to HandBrake.
\r
491 /// <param name="callback">The method that will be called when the check is finished.</param>
\r
492 /// <param name="debug">Whether or not to execute this in debug mode.</param>
\r
493 public static void BeginCheckForUpdates(AsyncCallback callback, bool debug)
\r
495 ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
\r
499 // Is this a stable or unstable build?
\r
501 Properties.Settings.Default.hb_build.ToString()
\r
503 ? Properties.Settings.Default.
\r
505 : Properties.Settings.Default.appcast;
\r
507 // Initialize variables
\r
508 WebRequest request = WebRequest.Create(url);
\r
509 WebResponse response = request.GetResponse();
\r
510 AppcastReader reader = new AppcastReader();
\r
512 // Get the data, convert it to a string, and parse it into the AppcastReader
\r
514 new StreamReader(response.GetResponseStream())
\r
517 // Further parse the information
\r
518 string build = reader.Build;
\r
520 int latest = int.Parse(build);
\r
521 int current = Properties.Settings.Default.hb_build;
\r
522 int skip = Properties.Settings.Default.skipversion;
\r
524 // If the user wanted to skip this version, don't report the update
\r
525 if (latest == skip)
\r
527 UpdateCheckInformation info =
\r
528 new UpdateCheckInformation
\r
530 NewVersionAvailable = false,
\r
531 BuildInformation = null
\r
533 callback(new UpdateCheckResult(debug, info));
\r
537 // Set when the last update was
\r
538 Properties.Settings.Default.lastUpdateCheckDate =
\r
540 Properties.Settings.Default.Save();
\r
542 UpdateCheckInformation info2 =
\r
543 new UpdateCheckInformation
\r
545 NewVersionAvailable = latest > current,
\r
546 BuildInformation = reader
\r
548 callback(new UpdateCheckResult(debug, info2));
\r
550 catch (Exception exc)
\r
552 callback(new UpdateCheckResult(debug, new UpdateCheckInformation { Error = exc }));
\r
558 /// End Check for Updates
\r
560 /// <param name="result">
\r
564 /// Update Check information
\r
566 public static UpdateCheckInformation EndCheckForUpdates(IAsyncResult result)
\r
568 UpdateCheckResult checkResult = (UpdateCheckResult)result;
\r
569 return checkResult.Result;
\r
573 /// Map languages and their iso639_2 value into a IDictionary
\r
575 /// <returns>A Dictionary containing the language and iso code</returns>
\r
576 public static IDictionary<string, string> MapLanguages()
\r
578 IDictionary<string, string> languageMap = new Dictionary<string, string>
\r
582 {"Abkhazian", "abk"},
\r
583 {"Afrikaans", "afr"},
\r
585 {"Albanian", "sqi"},
\r
586 {"Amharic", "amh"},
\r
587 {"Arabic", "ara"},
\r
588 {"Aragonese", "arg"},
\r
589 {"Armenian", "hye"},
\r
590 {"Assamese", "asm"},
\r
591 {"Avaric", "ava"},
\r
592 {"Avestan", "ave"},
\r
593 {"Aymara", "aym"},
\r
594 {"Azerbaijani", "aze"},
\r
595 {"Bashkir", "bak"},
\r
596 {"Bambara", "bam"},
\r
597 {"Basque", "eus"},
\r
598 {"Belarusian", "bel"},
\r
599 {"Bengali", "ben"},
\r
600 {"Bihari", "bih"},
\r
601 {"Bislama", "bis"},
\r
602 {"Bosnian", "bos"},
\r
603 {"Breton", "bre"},
\r
604 {"Bulgarian", "bul"},
\r
605 {"Burmese", "mya"},
\r
606 {"Catalan", "cat"},
\r
607 {"Chamorro", "cha"},
\r
608 {"Chechen", "che"},
\r
609 {"Chinese", "zho"},
\r
610 {"Church Slavic", "chu"},
\r
611 {"Chuvash", "chv"},
\r
612 {"Cornish", "cor"},
\r
613 {"Corsican", "cos"},
\r
617 {"Divehi", "div"},
\r
618 {"Nederlands", "nld"},
\r
619 {"Dzongkha", "dzo"},
\r
620 {"English", "eng"},
\r
621 {"Esperanto", "epo"},
\r
622 {"Estonian", "est"},
\r
624 {"Faroese", "fao"},
\r
625 {"Fijian", "fij"},
\r
627 {"Francais", "fra"},
\r
628 {"Western Frisian", "fry"},
\r
630 {"Georgian", "kat"},
\r
631 {"Deutsch", "deu"},
\r
632 {"Gaelic (Scots)", "gla"},
\r
634 {"Galician", "glg"},
\r
636 {"Greek Modern", "ell"},
\r
637 {"Guarani", "grn"},
\r
638 {"Gujarati", "guj"},
\r
639 {"Haitian", "hat"},
\r
641 {"Hebrew", "heb"},
\r
642 {"Herero", "her"},
\r
644 {"Hiri Motu", "hmo"},
\r
645 {"Magyar", "hun"},
\r
647 {"Islenska", "isl"},
\r
649 {"Sichuan Yi", "iii"},
\r
650 {"Inuktitut", "iku"},
\r
651 {"Interlingue", "ile"},
\r
652 {"Interlingua", "ina"},
\r
653 {"Indonesian", "ind"},
\r
654 {"Inupiaq", "ipk"},
\r
655 {"Italiano", "ita"},
\r
656 {"Javanese", "jav"},
\r
657 {"Japanese", "jpn"},
\r
658 {"Kalaallisut", "kal"},
\r
659 {"Kannada", "kan"},
\r
660 {"Kashmiri", "kas"},
\r
661 {"Kanuri", "kau"},
\r
662 {"Kazakh", "kaz"},
\r
663 {"Central Khmer", "khm"},
\r
664 {"Kikuyu", "kik"},
\r
665 {"Kinyarwanda", "kin"},
\r
666 {"Kirghiz", "kir"},
\r
669 {"Korean", "kor"},
\r
670 {"Kuanyama", "kua"},
\r
671 {"Kurdish", "kur"},
\r
674 {"Latvian", "lav"},
\r
675 {"Limburgan", "lim"},
\r
676 {"Lingala", "lin"},
\r
677 {"Lithuanian", "lit"},
\r
678 {"Luxembourgish", "ltz"},
\r
679 {"Luba-Katanga", "lub"},
\r
681 {"Macedonian", "mkd"},
\r
682 {"Marshallese", "mah"},
\r
683 {"Malayalam", "mal"},
\r
685 {"Marathi", "mar"},
\r
687 {"Malagasy", "mlg"},
\r
688 {"Maltese", "mlt"},
\r
689 {"Moldavian", "mol"},
\r
690 {"Mongolian", "mon"},
\r
692 {"Navajo", "nav"},
\r
693 {"Ndebele, South", "nbl"},
\r
694 {"Ndebele, North", "nde"},
\r
695 {"Ndonga", "ndo"},
\r
696 {"Nepali", "nep"},
\r
697 {"Norwegian Nynorsk", "nno"},
\r
698 {"Norwegian Bokmål", "nob"},
\r
700 {"Chichewa; Nyanja", "nya"},
\r
701 {"Occitan", "oci"},
\r
702 {"Ojibwa", "oji"},
\r
705 {"Ossetian", "oss"},
\r
706 {"Panjabi", "pan"},
\r
707 {"Persian", "fas"},
\r
709 {"Polish", "pol"},
\r
710 {"Portugues", "por"},
\r
711 {"Pushto", "pus"},
\r
712 {"Quechua", "que"},
\r
713 {"Romansh", "roh"},
\r
714 {"Romanian", "ron"},
\r
716 {"Russian", "rus"},
\r
718 {"Sanskrit", "san"},
\r
719 {"Serbian", "srp"},
\r
720 {"Hrvatski", "hrv"},
\r
721 {"Sinhala", "sin"},
\r
722 {"Slovak", "slk"},
\r
723 {"Slovenian", "slv"},
\r
724 {"Northern Sami", "sme"},
\r
725 {"Samoan", "smo"},
\r
727 {"Sindhi", "snd"},
\r
728 {"Somali", "som"},
\r
729 {"Sotho Southern", "sot"},
\r
730 {"Espanol", "spa"},
\r
731 {"Sardinian", "srd"},
\r
733 {"Sundanese", "sun"},
\r
734 {"Swahili", "swa"},
\r
735 {"Svenska", "swe"},
\r
736 {"Tahitian", "tah"},
\r
739 {"Telugu", "tel"},
\r
741 {"Tagalog", "tgl"},
\r
743 {"Tibetan", "bod"},
\r
744 {"Tigrinya", "tir"},
\r
746 {"Tswana", "tsn"},
\r
747 {"Tsonga", "tso"},
\r
748 {"Turkmen", "tuk"},
\r
749 {"Turkish", "tur"},
\r
751 {"Uighur", "uig"},
\r
752 {"Ukrainian", "ukr"},
\r
756 {"Vietnamese", "vie"},
\r
757 {"Volapük", "vol"},
\r
759 {"Walloon", "wln"},
\r
762 {"Yiddish", "yid"},
\r
763 {"Yoruba", "yor"},
\r
764 {"Zhuang", "zha"},
\r
767 return languageMap;
\r
771 /// Get a list of available DVD drives which are ready and contain DVD content.
\r
773 /// <returns>A List of Drives with their details</returns>
\r
774 public static List<DriveInformation> GetDrives()
\r
776 List<DriveInformation> drives = new List<DriveInformation>();
\r
777 DriveInfo[] theCollectionOfDrives = DriveInfo.GetDrives();
\r
779 foreach (DriveInfo curDrive in theCollectionOfDrives)
\r
781 if (curDrive.DriveType == DriveType.CDRom && curDrive.IsReady &&
\r
782 File.Exists(curDrive.RootDirectory + "VIDEO_TS\\VIDEO_TS.IFO"))
\r
784 drives.Add(new DriveInformation
\r
787 VolumeLabel = curDrive.VolumeLabel,
\r
788 RootDirectory = curDrive.RootDirectory + "VIDEO_TS"
\r
797 /// Change a string to Title Case/
\r
799 /// <param name="input">
\r
803 /// A string in title case.
\r
805 public static string TitleCase(string input)
\r
807 string[] tokens = input.Split(' ');
\r
808 StringBuilder sb = new StringBuilder(input.Length);
\r
809 foreach (string s in tokens)
\r
811 sb.Append(s[0].ToString().ToUpper());
\r
812 sb.Append(s.Substring(1).ToLower());
\r
816 return sb.ToString().Trim();
\r
820 /// Show the Exception Window
\r
822 /// <param name="shortError">
\r
823 /// The short error.
\r
825 /// <param name="longError">
\r
826 /// The long error.
\r
828 public static void ShowExceptiowWindow(string shortError, string longError)
\r
830 errorService.ShowError(shortError, longError);
\r
834 /// Get The Source from the CLI Query
\r
836 /// <param name="query">Full CLI Query</param>
\r
837 /// <returns>The Source Path</returns>
\r
838 public static string GetSourceFromQuery(string query)
\r
840 int startIndex = query.IndexOf("-i \"");
\r
841 if (startIndex != -1)
\r
843 string input = query.Substring(startIndex).Replace("-i \"", string.Empty).Trim();
\r
845 int closeIndex = input.IndexOf('"');
\r
847 return closeIndex == -1 ? "Unknown" : input.Substring(0, closeIndex);
\r
854 /// Get the Destination from the CLI Query
\r
856 /// <param name="query">Full CLI Query</param>
\r
857 /// <returns>The Destination path</returns>
\r
858 public static string GetDestinationFromQuery(string query)
\r
860 int startIndex = query.IndexOf("-o \"");
\r
861 if (startIndex != -1)
\r
863 string output = query.Substring(startIndex).Replace("-o \"", string.Empty).Trim();
\r
865 int closeIndex = output.IndexOf('"');
\r
867 return closeIndex == -1 ? "Unknown" : output.Substring(0, closeIndex);
\r