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 using HandBrake.ApplicationServices.Services;
\r
8 namespace Handbrake.Functions
\r
11 using System.Collections.Generic;
\r
12 using System.Diagnostics;
\r
17 using System.Text.RegularExpressions;
\r
18 using System.Threading;
\r
19 using System.Windows.Forms;
\r
20 using System.Xml.Serialization;
\r
21 using HandBrake.ApplicationServices.Model;
\r
22 using HandBrake.ApplicationServices.Parsing;
\r
23 using HandBrake.ApplicationServices.Services.Interfaces;
\r
27 /// Useful functions which various screens can use.
\r
29 public static class Main
\r
32 /// The Error Service
\r
34 private static readonly IErrorService errorService = new ErrorService();
\r
37 /// The XML Serializer
\r
39 private static readonly XmlSerializer Ser = new XmlSerializer(typeof(List<Job>));
\r
42 /// Calculate the duration of the selected title and chapters
\r
44 /// <param name="chapterStart">
\r
45 /// The chapter Start.
\r
47 /// <param name="chapterEnd">
\r
48 /// The chapter End.
\r
50 /// <param name="selectedTitle">
\r
51 /// The selected Title.
\r
54 /// The calculated duration.
\r
56 public static TimeSpan CalculateDuration(int chapterStart, int chapterEnd, Title selectedTitle)
\r
58 TimeSpan duration = TimeSpan.FromSeconds(0.0);
\r
61 if (chapterStart != 0 && chapterEnd != 0 && chapterEnd <= selectedTitle.Chapters.Count)
\r
63 for (int i = chapterStart; i <= chapterEnd; i++)
\r
64 duration += selectedTitle.Chapters[i - 1].Duration;
\r
71 /// Set's up the DataGridView on the Chapters tab (frmMain)
\r
73 /// <param name="dataChpt">
\r
74 /// The DataGridView Control
\r
76 /// <param name="chapterEnd">
\r
77 /// The chapter End.
\r
80 /// The chapter naming.
\r
82 public static DataGridView ChapterNaming(DataGridView dataChpt, string chapterEnd)
\r
84 int i = 0, finish = 0;
\r
86 if (chapterEnd != "Auto")
\r
87 int.TryParse(chapterEnd, out finish);
\r
91 int n = dataChpt.Rows.Add();
\r
92 dataChpt.Rows[n].Cells[0].Value = i + 1;
\r
93 dataChpt.Rows[n].Cells[1].Value = "Chapter " + (i + 1);
\r
94 dataChpt.Rows[n].Cells[0].ValueType = typeof(int);
\r
95 dataChpt.Rows[n].Cells[1].ValueType = typeof(string);
\r
103 /// Import a CSV file which contains Chapter Names
\r
105 /// <param name="dataChpt">
\r
106 /// The DataGridView Control
\r
108 /// <param name="filename">
\r
109 /// The filepath and name
\r
111 /// <returns>A Populated DataGridView</returns>
\r
112 public static DataGridView ImportChapterNames(DataGridView dataChpt, string filename)
\r
114 IDictionary<int, string> chapterMap = new Dictionary<int, string>();
\r
117 StreamReader sr = new StreamReader(filename);
\r
118 string csv = sr.ReadLine();
\r
119 while (csv != null)
\r
121 if (csv.Trim() != string.Empty)
\r
123 csv = csv.Replace("\\,", "<!comma!>");
\r
124 string[] contents = csv.Split(',');
\r
126 int.TryParse(contents[0], out chapter);
\r
127 chapterMap.Add(chapter, contents[1].Replace("<!comma!>", ","));
\r
129 csv = sr.ReadLine();
\r
137 foreach (DataGridViewRow item in dataChpt.Rows)
\r
140 chapterMap.TryGetValue((int)item.Cells[0].Value, out name);
\r
141 item.Cells[1].Value = name ?? "Chapter " + item.Cells[0].Value;
\r
148 /// Create a CSV file with the data from the Main Window Chapters tab
\r
150 /// <param name="mainWindow">Main Window</param>
\r
151 /// <param name="filePathName">Path to save the csv file</param>
\r
152 /// <returns>True if successful </returns>
\r
153 public static bool SaveChapterMarkersToCsv(frmMain mainWindow, string filePathName)
\r
157 string csv = string.Empty;
\r
159 foreach (DataGridViewRow row in mainWindow.data_chpt.Rows)
\r
161 csv += row.Cells[0].Value.ToString();
\r
163 csv += row.Cells[1].Value.ToString().Replace(",", "\\,");
\r
164 csv += Environment.NewLine;
\r
166 StreamWriter file = new StreamWriter(filePathName);
\r
172 catch (Exception exc)
\r
174 ShowExceptiowWindow("Unable to save Chapter Makrers file! \nChapter marker names will NOT be saved in your encode", exc.ToString());
\r
180 /// Function which generates the filename and path automatically based on
\r
181 /// the Source Name, DVD title and DVD Chapters
\r
183 /// <param name="mainWindow">
\r
184 /// The main Window.
\r
187 /// The Generated FileName
\r
189 public static string AutoName(frmMain mainWindow)
\r
191 string autoNamePath = string.Empty;
\r
192 if (mainWindow.drp_dvdtitle.Text != "Automatic")
\r
194 // Get the Source Name and remove any invalid characters
\r
195 string sourceName = Path.GetInvalidFileNameChars().Aggregate(mainWindow.SourceName, (current, character) => current.Replace(character.ToString(), string.Empty));
\r
197 if (Properties.Settings.Default.AutoNameRemoveUnderscore)
\r
198 sourceName = sourceName.Replace("_", " ");
\r
200 if (Properties.Settings.Default.AutoNameTitleCase)
\r
201 sourceName = TitleCase(sourceName);
\r
203 // Get the Selected Title Number
\r
204 string[] titlesplit = mainWindow.drp_dvdtitle.Text.Split(' ');
\r
205 string dvdTitle = titlesplit[0].Replace("Automatic", string.Empty);
\r
207 // Get the Chapter Start and Chapter End Numbers
\r
208 string chapterStart = mainWindow.drop_chapterStart.Text.Replace("Auto", string.Empty);
\r
209 string chapterFinish = mainWindow.drop_chapterFinish.Text.Replace("Auto", string.Empty);
\r
210 string combinedChapterTag = chapterStart;
\r
211 if (chapterFinish != chapterStart && chapterFinish != string.Empty)
\r
212 combinedChapterTag = chapterStart + "-" + chapterFinish;
\r
214 // Get the destination filename.
\r
215 string destinationFilename;
\r
216 if (Properties.Settings.Default.autoNameFormat != string.Empty)
\r
218 destinationFilename = Properties.Settings.Default.autoNameFormat;
\r
219 destinationFilename = destinationFilename.Replace("{source}", sourceName)
\r
220 .Replace("{title}", dvdTitle)
\r
221 .Replace("{chapters}", combinedChapterTag);
\r
224 destinationFilename = sourceName + "_T" + dvdTitle + "_C" + combinedChapterTag;
\r
226 // Add the appropriate file extension
\r
227 if (mainWindow.drop_format.SelectedIndex == 0)
\r
229 destinationFilename += Properties.Settings.Default.useM4v || mainWindow.Check_ChapterMarkers.Checked ||
\r
230 mainWindow.AudioSettings.RequiresM4V() || mainWindow.Subtitles.RequiresM4V()
\r
234 else if (mainWindow.drop_format.SelectedIndex == 1)
\r
235 destinationFilename += ".mkv";
\r
237 // Now work out the path where the file will be stored.
\r
238 // First case: If the destination box doesn't already contain a path, make one.
\r
239 if (!mainWindow.text_destination.Text.Contains(Path.DirectorySeparatorChar.ToString()))
\r
241 // If there is an auto name path, use it...
\r
242 if (Properties.Settings.Default.autoNamePath.Trim() == "{source}" && !string.IsNullOrEmpty(mainWindow.sourcePath))
\r
244 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.sourcePath), destinationFilename);
\r
245 if (autoNamePath == mainWindow.sourcePath)
\r
247 // Append out_ to files that already exist or is the source file
\r
248 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.sourcePath), "output_" + destinationFilename);
\r
251 else if (Properties.Settings.Default.autoNamePath.Trim() != string.Empty && Properties.Settings.Default.autoNamePath.Trim() != "Click 'Browse' to set the default location")
\r
253 autoNamePath = Path.Combine(Properties.Settings.Default.autoNamePath, destinationFilename);
\r
255 else // ...otherwise, output to the source directory
\r
256 autoNamePath = null;
\r
258 else // Otherwise, use the path that is already there.
\r
260 // Use the path and change the file extension to match the previous destination
\r
261 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.text_destination.Text), destinationFilename);
\r
263 if (Path.HasExtension(mainWindow.text_destination.Text))
\r
264 autoNamePath = Path.ChangeExtension(autoNamePath,
\r
265 Path.GetExtension(mainWindow.text_destination.Text));
\r
269 return autoNamePath;
\r
273 /// Get's HandBrakes version data from the CLI.
\r
275 public static void SetCliVersionData()
\r
279 // 0 = SVN Build / Version
\r
281 DateTime lastModified = File.GetLastWriteTime("HandBrakeCLI.exe");
\r
283 if (Properties.Settings.Default.hb_build != 0 && Properties.Settings.Default.cliLastModified == lastModified)
\r
288 Properties.Settings.Default.cliLastModified = lastModified;
\r
290 Process cliProcess = new Process();
\r
291 ProcessStartInfo handBrakeCli = new ProcessStartInfo("HandBrakeCLI.exe", " -u -v0")
\r
293 UseShellExecute = false,
\r
294 RedirectStandardError = true,
\r
295 RedirectStandardOutput = true,
\r
296 CreateNoWindow = true
\r
298 cliProcess.StartInfo = handBrakeCli;
\r
302 cliProcess.Start();
\r
304 // Retrieve standard output and report back to parent thread until the process is complete
\r
305 TextReader stdOutput = cliProcess.StandardError;
\r
307 while (!cliProcess.HasExited)
\r
309 line = stdOutput.ReadLine() ?? string.Empty;
\r
310 Match m = Regex.Match(line, @"HandBrake ([svnM0-9.]*) \(([0-9]*)\)");
\r
311 Match platform = Regex.Match(line, @"- ([A-Za-z0-9\s ]*) -");
\r
315 string version = m.Groups[1].Success ? m.Groups[1].Value : string.Empty;
\r
316 string build = m.Groups[2].Success ? m.Groups[2].Value : string.Empty;
\r
319 int.TryParse(build, out buildValue);
\r
321 Properties.Settings.Default.hb_build = buildValue;
\r
322 Properties.Settings.Default.hb_version = version;
\r
325 if (platform.Success)
\r
327 Properties.Settings.Default.hb_platform = platform.Value.Replace("-", string.Empty).Trim();
\r
330 if (cliProcess.TotalProcessorTime.Seconds > 10) // Don't wait longer than 10 seconds.
\r
332 Process cli = Process.GetProcessById(cliProcess.Id);
\r
333 if (!cli.HasExited)
\r
340 Properties.Settings.Default.Save();
\r
342 catch (Exception e)
\r
344 Properties.Settings.Default.hb_build = 0;
\r
345 Properties.Settings.Default.Save();
\r
347 ShowExceptiowWindow("Unable to retrieve version information from the CLI.", e.ToString());
\r
352 /// Check if the queue recovery file contains records.
\r
353 /// If it does, it means the last queue did not complete before HandBrake closed.
\r
354 /// So, return a boolean if true.
\r
357 /// True if there is a queue to recover.
\r
359 public static List<string> CheckQueueRecovery()
\r
363 string tempPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");
\r
364 List<string> queueFiles = new List<string>();
\r
366 DirectoryInfo info = new DirectoryInfo(tempPath);
\r
367 FileInfo[] logFiles = info.GetFiles("*.xml");
\r
368 foreach (FileInfo file in logFiles)
\r
370 if (!file.Name.Contains("hb_queue_recovery"))
\r
373 using (FileStream strm = new FileStream(Path.Combine(file.DirectoryName, file.Name), FileMode.Open, FileAccess.Read))
\r
375 List<Job> list = Ser.Deserialize(strm) as List<Job>;
\r
378 if (list.Count != 0)
\r
380 queueFiles.Add(file.Name);
\r
390 return new List<string>(); // Keep quiet about the error.
\r
395 /// Recover a queue from file.
\r
397 /// <param name="encodeQueue">
\r
398 /// The encode Queue.
\r
400 public static void RecoverQueue(IQueue encodeQueue)
\r
402 DialogResult result = DialogResult.None;
\r
403 List<string> queueFiles = CheckQueueRecovery();
\r
404 if (queueFiles.Count == 1)
\r
406 result = MessageBox.Show(
\r
407 "HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?",
\r
408 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
410 else if (queueFiles.Count > 1)
\r
412 result = MessageBox.Show(
\r
413 "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
414 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
417 if (result == DialogResult.Yes)
\r
419 foreach (string file in queueFiles)
\r
421 encodeQueue.LoadQueueFromFile(file); // Start Recovery
\r
426 if (IsMultiInstance) return; // Don't tamper with the files if we are multi instance
\r
428 string tempPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");
\r
429 foreach (string file in queueFiles)
\r
431 if (File.Exists(Path.Combine(tempPath, file)))
\r
432 File.Delete(Path.Combine(tempPath, file));
\r
438 /// Gets a value indicating whether HandBrake is running in multi instance mode
\r
440 /// <returns>True if the UI has another instance running</returns>
\r
441 public static bool IsMultiInstance
\r
445 return Process.GetProcessesByName("HandBrake").Length > 0 ? true : false;
\r
450 /// Clear all the encode log files.
\r
452 public static void ClearLogs()
\r
454 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
455 if (Directory.Exists(logDir))
\r
457 DirectoryInfo info = new DirectoryInfo(logDir);
\r
458 FileInfo[] logFiles = info.GetFiles("*.txt");
\r
459 foreach (FileInfo file in logFiles)
\r
461 if (!file.Name.Contains("last_scan_log") && !file.Name.Contains("last_encode_log"))
\r
462 File.Delete(file.FullName);
\r
468 /// Clear old log files x days in the past
\r
470 public static void ClearOldLogs()
\r
472 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
473 if (Directory.Exists(logDir))
\r
475 DirectoryInfo info = new DirectoryInfo(logDir);
\r
476 FileInfo[] logFiles = info.GetFiles("*.txt");
\r
478 foreach (FileInfo file in logFiles)
\r
480 if (file.LastWriteTime < DateTime.Now.AddDays(-30))
\r
482 if (!file.Name.Contains("last_scan_log.txt") && !file.Name.Contains("last_encode_log.txt"))
\r
483 File.Delete(file.FullName);
\r
490 /// Begins checking for an update to HandBrake.
\r
492 /// <param name="callback">The method that will be called when the check is finished.</param>
\r
493 /// <param name="debug">Whether or not to execute this in debug mode.</param>
\r
494 public static void BeginCheckForUpdates(AsyncCallback callback, bool debug)
\r
496 ThreadPool.QueueUserWorkItem(new WaitCallback(delegate
\r
500 // Is this a stable or unstable build?
\r
502 Properties.Settings.Default.hb_build.ToString()
\r
504 ? Properties.Settings.Default.
\r
506 : Properties.Settings.Default.appcast;
\r
508 // Initialize variables
\r
509 WebRequest request = WebRequest.Create(url);
\r
510 WebResponse response = request.GetResponse();
\r
511 AppcastReader reader = new AppcastReader();
\r
513 // Get the data, convert it to a string, and parse it into the AppcastReader
\r
515 new StreamReader(response.GetResponseStream())
\r
518 // Further parse the information
\r
519 string build = reader.Build;
\r
521 int latest = int.Parse(build);
\r
522 int current = Properties.Settings.Default.hb_build;
\r
523 int skip = Properties.Settings.Default.skipversion;
\r
525 // If the user wanted to skip this version, don't report the update
\r
526 if (latest == skip)
\r
528 UpdateCheckInformation info =
\r
529 new UpdateCheckInformation
\r
531 NewVersionAvailable = false,
\r
532 BuildInformation = null
\r
534 callback(new UpdateCheckResult(debug, info));
\r
538 // Set when the last update was
\r
539 Properties.Settings.Default.lastUpdateCheckDate =
\r
541 Properties.Settings.Default.Save();
\r
543 UpdateCheckInformation info2 =
\r
544 new UpdateCheckInformation
\r
546 NewVersionAvailable = latest > current,
\r
547 BuildInformation = reader
\r
549 callback(new UpdateCheckResult(debug, info2));
\r
551 catch (Exception exc)
\r
553 callback(new UpdateCheckResult(debug, new UpdateCheckInformation { Error = exc }));
\r
559 /// End Check for Updates
\r
561 /// <param name="result">
\r
565 /// Update Check information
\r
567 public static UpdateCheckInformation EndCheckForUpdates(IAsyncResult result)
\r
569 UpdateCheckResult checkResult = (UpdateCheckResult)result;
\r
570 return checkResult.Result;
\r
574 /// Map languages and their iso639_2 value into a IDictionary
\r
576 /// <returns>A Dictionary containing the language and iso code</returns>
\r
577 public static IDictionary<string, string> MapLanguages()
\r
579 IDictionary<string, string> languageMap = new Dictionary<string, string>
\r
583 {"Abkhazian", "abk"},
\r
584 {"Afrikaans", "afr"},
\r
586 {"Albanian", "sqi"},
\r
587 {"Amharic", "amh"},
\r
588 {"Arabic", "ara"},
\r
589 {"Aragonese", "arg"},
\r
590 {"Armenian", "hye"},
\r
591 {"Assamese", "asm"},
\r
592 {"Avaric", "ava"},
\r
593 {"Avestan", "ave"},
\r
594 {"Aymara", "aym"},
\r
595 {"Azerbaijani", "aze"},
\r
596 {"Bashkir", "bak"},
\r
597 {"Bambara", "bam"},
\r
598 {"Basque", "eus"},
\r
599 {"Belarusian", "bel"},
\r
600 {"Bengali", "ben"},
\r
601 {"Bihari", "bih"},
\r
602 {"Bislama", "bis"},
\r
603 {"Bosnian", "bos"},
\r
604 {"Breton", "bre"},
\r
605 {"Bulgarian", "bul"},
\r
606 {"Burmese", "mya"},
\r
607 {"Catalan", "cat"},
\r
608 {"Chamorro", "cha"},
\r
609 {"Chechen", "che"},
\r
610 {"Chinese", "zho"},
\r
611 {"Church Slavic", "chu"},
\r
612 {"Chuvash", "chv"},
\r
613 {"Cornish", "cor"},
\r
614 {"Corsican", "cos"},
\r
618 {"Divehi", "div"},
\r
619 {"Nederlands", "nld"},
\r
620 {"Dzongkha", "dzo"},
\r
621 {"English", "eng"},
\r
622 {"Esperanto", "epo"},
\r
623 {"Estonian", "est"},
\r
625 {"Faroese", "fao"},
\r
626 {"Fijian", "fij"},
\r
628 {"Francais", "fra"},
\r
629 {"Western Frisian", "fry"},
\r
631 {"Georgian", "kat"},
\r
632 {"Deutsch", "deu"},
\r
633 {"Gaelic (Scots)", "gla"},
\r
635 {"Galician", "glg"},
\r
637 {"Greek Modern", "ell"},
\r
638 {"Guarani", "grn"},
\r
639 {"Gujarati", "guj"},
\r
640 {"Haitian", "hat"},
\r
642 {"Hebrew", "heb"},
\r
643 {"Herero", "her"},
\r
645 {"Hiri Motu", "hmo"},
\r
646 {"Magyar", "hun"},
\r
648 {"Islenska", "isl"},
\r
650 {"Sichuan Yi", "iii"},
\r
651 {"Inuktitut", "iku"},
\r
652 {"Interlingue", "ile"},
\r
653 {"Interlingua", "ina"},
\r
654 {"Indonesian", "ind"},
\r
655 {"Inupiaq", "ipk"},
\r
656 {"Italiano", "ita"},
\r
657 {"Javanese", "jav"},
\r
658 {"Japanese", "jpn"},
\r
659 {"Kalaallisut", "kal"},
\r
660 {"Kannada", "kan"},
\r
661 {"Kashmiri", "kas"},
\r
662 {"Kanuri", "kau"},
\r
663 {"Kazakh", "kaz"},
\r
664 {"Central Khmer", "khm"},
\r
665 {"Kikuyu", "kik"},
\r
666 {"Kinyarwanda", "kin"},
\r
667 {"Kirghiz", "kir"},
\r
670 {"Korean", "kor"},
\r
671 {"Kuanyama", "kua"},
\r
672 {"Kurdish", "kur"},
\r
675 {"Latvian", "lav"},
\r
676 {"Limburgan", "lim"},
\r
677 {"Lingala", "lin"},
\r
678 {"Lithuanian", "lit"},
\r
679 {"Luxembourgish", "ltz"},
\r
680 {"Luba-Katanga", "lub"},
\r
682 {"Macedonian", "mkd"},
\r
683 {"Marshallese", "mah"},
\r
684 {"Malayalam", "mal"},
\r
686 {"Marathi", "mar"},
\r
688 {"Malagasy", "mlg"},
\r
689 {"Maltese", "mlt"},
\r
690 {"Moldavian", "mol"},
\r
691 {"Mongolian", "mon"},
\r
693 {"Navajo", "nav"},
\r
694 {"Ndebele, South", "nbl"},
\r
695 {"Ndebele, North", "nde"},
\r
696 {"Ndonga", "ndo"},
\r
697 {"Nepali", "nep"},
\r
698 {"Norwegian Nynorsk", "nno"},
\r
699 {"Norwegian Bokmål", "nob"},
\r
701 {"Chichewa; Nyanja", "nya"},
\r
702 {"Occitan", "oci"},
\r
703 {"Ojibwa", "oji"},
\r
706 {"Ossetian", "oss"},
\r
707 {"Panjabi", "pan"},
\r
708 {"Persian", "fas"},
\r
710 {"Polish", "pol"},
\r
711 {"Portugues", "por"},
\r
712 {"Pushto", "pus"},
\r
713 {"Quechua", "que"},
\r
714 {"Romansh", "roh"},
\r
715 {"Romanian", "ron"},
\r
717 {"Russian", "rus"},
\r
719 {"Sanskrit", "san"},
\r
720 {"Serbian", "srp"},
\r
721 {"Hrvatski", "hrv"},
\r
722 {"Sinhala", "sin"},
\r
723 {"Slovak", "slk"},
\r
724 {"Slovenian", "slv"},
\r
725 {"Northern Sami", "sme"},
\r
726 {"Samoan", "smo"},
\r
728 {"Sindhi", "snd"},
\r
729 {"Somali", "som"},
\r
730 {"Sotho Southern", "sot"},
\r
731 {"Espanol", "spa"},
\r
732 {"Sardinian", "srd"},
\r
734 {"Sundanese", "sun"},
\r
735 {"Swahili", "swa"},
\r
736 {"Svenska", "swe"},
\r
737 {"Tahitian", "tah"},
\r
740 {"Telugu", "tel"},
\r
742 {"Tagalog", "tgl"},
\r
744 {"Tibetan", "bod"},
\r
745 {"Tigrinya", "tir"},
\r
747 {"Tswana", "tsn"},
\r
748 {"Tsonga", "tso"},
\r
749 {"Turkmen", "tuk"},
\r
750 {"Turkish", "tur"},
\r
752 {"Uighur", "uig"},
\r
753 {"Ukrainian", "ukr"},
\r
757 {"Vietnamese", "vie"},
\r
758 {"Volapük", "vol"},
\r
760 {"Walloon", "wln"},
\r
763 {"Yiddish", "yid"},
\r
764 {"Yoruba", "yor"},
\r
765 {"Zhuang", "zha"},
\r
768 return languageMap;
\r
772 /// Get a list of available DVD drives which are ready and contain DVD content.
\r
774 /// <returns>A List of Drives with their details</returns>
\r
775 public static List<DriveInformation> GetDrives()
\r
777 List<DriveInformation> drives = new List<DriveInformation>();
\r
778 DriveInfo[] theCollectionOfDrives = DriveInfo.GetDrives();
\r
780 foreach (DriveInfo curDrive in theCollectionOfDrives)
\r
782 if (curDrive.DriveType == DriveType.CDRom && curDrive.IsReady &&
\r
783 File.Exists(curDrive.RootDirectory + "VIDEO_TS\\VIDEO_TS.IFO"))
\r
785 drives.Add(new DriveInformation
\r
788 VolumeLabel = curDrive.VolumeLabel,
\r
789 RootDirectory = curDrive.RootDirectory + "VIDEO_TS"
\r
798 /// Change a string to Title Case/
\r
800 /// <param name="input">
\r
804 /// A string in title case.
\r
806 public static string TitleCase(string input)
\r
808 string[] tokens = input.Split(' ');
\r
809 StringBuilder sb = new StringBuilder(input.Length);
\r
810 foreach (string s in tokens)
\r
812 sb.Append(s[0].ToString().ToUpper());
\r
813 sb.Append(s.Substring(1).ToLower());
\r
817 return sb.ToString().Trim();
\r
821 /// Show the Exception Window
\r
823 /// <param name="shortError">
\r
824 /// The short error.
\r
826 /// <param name="longError">
\r
827 /// The long error.
\r
829 public static void ShowExceptiowWindow(string shortError, string longError)
\r
831 errorService.ShowError(shortError, longError);
\r
835 /// Get The Source from the CLI Query
\r
837 /// <param name="query">Full CLI Query</param>
\r
838 /// <returns>The Source Path</returns>
\r
839 public static string GetSourceFromQuery(string query)
\r
841 int startIndex = query.IndexOf("-i \"");
\r
842 if (startIndex != -1)
\r
844 string input = query.Substring(startIndex).Replace("-i \"", string.Empty).Trim();
\r
846 int closeIndex = input.IndexOf('"');
\r
848 return closeIndex == -1 ? "Unknown" : input.Substring(0, closeIndex);
\r
855 /// Get the Destination from the CLI Query
\r
857 /// <param name="query">Full CLI Query</param>
\r
858 /// <returns>The Destination path</returns>
\r
859 public static string GetDestinationFromQuery(string query)
\r
861 int startIndex = query.IndexOf("-o \"");
\r
862 if (startIndex != -1)
\r
864 string output = query.Substring(startIndex).Replace("-o \"", string.Empty).Trim();
\r
866 int closeIndex = output.IndexOf('"');
\r
868 return closeIndex == -1 ? "Unknown" : output.Substring(0, closeIndex);
\r