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
14 using System.Text.RegularExpressions;
\r
15 using System.Windows.Forms;
\r
16 using System.Xml.Serialization;
\r
18 using HandBrake.Framework.Services;
\r
19 using HandBrake.Framework.Services.Interfaces;
\r
20 using HandBrake.ApplicationServices.Model;
\r
21 using HandBrake.ApplicationServices.Parsing;
\r
22 using HandBrake.ApplicationServices.Services.Interfaces;
\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="title">
\r
73 /// The currently selected title object.
\r
74 /// This will be used to get chapter names if they exist.
\r
76 /// <param name="dataChpt">
\r
77 /// The DataGridView Control
\r
79 /// <param name="chapterEnd">
\r
80 /// The chapter End.
\r
83 /// The chapter naming.
\r
85 public static DataGridView ChapterNaming(Title title, DataGridView dataChpt, string chapterEnd)
\r
87 int i = 0, finish = 0;
\r
89 if (chapterEnd != "Auto")
\r
90 int.TryParse(chapterEnd, out finish);
\r
94 string chapterName = string.Empty;
\r
97 if (title.Chapters.Count <= i && title.Chapters[i] != null)
\r
99 chapterName = title.Chapters[i].ChapterName;
\r
103 int n = dataChpt.Rows.Add();
\r
104 dataChpt.Rows[n].Cells[0].Value = i + 1;
\r
105 dataChpt.Rows[n].Cells[1].Value = string.IsNullOrEmpty(chapterName) ? "Chapter " + (i + 1) : chapterName;
\r
106 dataChpt.Rows[n].Cells[0].ValueType = typeof(int);
\r
107 dataChpt.Rows[n].Cells[1].ValueType = typeof(string);
\r
115 /// Import a CSV file which contains Chapter Names
\r
117 /// <param name="dataChpt">
\r
118 /// The DataGridView Control
\r
120 /// <param name="filename">
\r
121 /// The filepath and name
\r
123 /// <returns>A Populated DataGridView</returns>
\r
124 public static DataGridView ImportChapterNames(DataGridView dataChpt, string filename)
\r
126 IDictionary<int, string> chapterMap = new Dictionary<int, string>();
\r
129 StreamReader sr = new StreamReader(filename);
\r
130 string csv = sr.ReadLine();
\r
131 while (csv != null)
\r
133 if (csv.Trim() != string.Empty)
\r
135 csv = csv.Replace("\\,", "<!comma!>");
\r
136 string[] contents = csv.Split(',');
\r
138 int.TryParse(contents[0], out chapter);
\r
139 chapterMap.Add(chapter, contents[1].Replace("<!comma!>", ","));
\r
141 csv = sr.ReadLine();
\r
149 foreach (DataGridViewRow item in dataChpt.Rows)
\r
152 chapterMap.TryGetValue((int)item.Cells[0].Value, out name);
\r
153 item.Cells[1].Value = name ?? "Chapter " + item.Cells[0].Value;
\r
160 /// Create a CSV file with the data from the Main Window Chapters tab
\r
162 /// <param name="mainWindow">Main Window</param>
\r
163 /// <param name="filePathName">Path to save the csv file</param>
\r
164 /// <returns>True if successful </returns>
\r
165 public static bool SaveChapterMarkersToCsv(frmMain mainWindow, string filePathName)
\r
169 string csv = string.Empty;
\r
171 foreach (DataGridViewRow row in mainWindow.data_chpt.Rows)
\r
173 csv += row.Cells[0].Value.ToString();
\r
175 csv += row.Cells[1].Value.ToString().Replace(",", "\\,");
\r
176 csv += Environment.NewLine;
\r
178 StreamWriter file = new StreamWriter(filePathName);
\r
184 catch (Exception exc)
\r
186 ShowExceptiowWindow("Unable to save Chapter Makrers file! \nChapter marker names will NOT be saved in your encode", exc.ToString());
\r
192 /// Function which generates the filename and path automatically based on
\r
193 /// the Source Name, DVD title and DVD Chapters
\r
195 /// <param name="mainWindow">
\r
196 /// The main Window.
\r
199 /// The Generated FileName
\r
201 public static string AutoName(frmMain mainWindow)
\r
203 string autoNamePath = string.Empty;
\r
204 if (mainWindow.drp_dvdtitle.Text != "Automatic")
\r
206 // Get the Source Name and remove any invalid characters
\r
207 string sourceName = Path.GetInvalidFileNameChars().Aggregate(mainWindow.SourceName, (current, character) => current.Replace(character.ToString(), string.Empty));
\r
209 if (Properties.Settings.Default.AutoNameRemoveUnderscore)
\r
210 sourceName = sourceName.Replace("_", " ");
\r
212 if (Properties.Settings.Default.AutoNameTitleCase)
\r
213 sourceName = TitleCase(sourceName);
\r
215 // Get the Selected Title Number
\r
216 string[] titlesplit = mainWindow.drp_dvdtitle.Text.Split(' ');
\r
217 string dvdTitle = titlesplit[0].Replace("Automatic", string.Empty);
\r
219 // Get the Chapter Start and Chapter End Numbers
\r
220 string chapterStart = mainWindow.drop_chapterStart.Text.Replace("Auto", string.Empty);
\r
221 string chapterFinish = mainWindow.drop_chapterFinish.Text.Replace("Auto", string.Empty);
\r
222 string combinedChapterTag = chapterStart;
\r
223 if (chapterFinish != chapterStart && chapterFinish != string.Empty)
\r
224 combinedChapterTag = chapterStart + "-" + chapterFinish;
\r
226 // Get the destination filename.
\r
227 string destinationFilename;
\r
228 if (Properties.Settings.Default.autoNameFormat != string.Empty)
\r
230 destinationFilename = Properties.Settings.Default.autoNameFormat;
\r
231 destinationFilename = destinationFilename.Replace("{source}", sourceName)
\r
232 .Replace("{title}", dvdTitle)
\r
233 .Replace("{chapters}", combinedChapterTag);
\r
236 destinationFilename = sourceName + "_T" + dvdTitle + "_C" + combinedChapterTag;
\r
238 // Add the appropriate file extension
\r
239 if (mainWindow.drop_format.SelectedIndex == 0)
\r
241 destinationFilename += Properties.Settings.Default.useM4v || mainWindow.Check_ChapterMarkers.Checked ||
\r
242 mainWindow.AudioSettings.RequiresM4V() || mainWindow.Subtitles.RequiresM4V()
\r
246 else if (mainWindow.drop_format.SelectedIndex == 1)
\r
247 destinationFilename += ".mkv";
\r
249 // Now work out the path where the file will be stored.
\r
250 // First case: If the destination box doesn't already contain a path, make one.
\r
251 if (!mainWindow.text_destination.Text.Contains(Path.DirectorySeparatorChar.ToString()))
\r
253 // If there is an auto name path, use it...
\r
254 if (Properties.Settings.Default.autoNamePath.Trim() == "{source_path}" && !string.IsNullOrEmpty(mainWindow.sourcePath))
\r
256 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.sourcePath), destinationFilename);
\r
257 if (autoNamePath == mainWindow.sourcePath)
\r
259 // Append out_ to files that already exist or is the source file
\r
260 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.sourcePath), "output_" + destinationFilename);
\r
263 else if (Properties.Settings.Default.autoNamePath.Trim() != string.Empty && Properties.Settings.Default.autoNamePath.Trim() != "Click 'Browse' to set the default location")
\r
265 autoNamePath = Path.Combine(Properties.Settings.Default.autoNamePath, destinationFilename);
\r
267 else // ...otherwise, output to the source directory
\r
268 autoNamePath = null;
\r
270 else // Otherwise, use the path that is already there.
\r
272 // Use the path and change the file extension to match the previous destination
\r
273 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.text_destination.Text), destinationFilename);
\r
275 if (Path.HasExtension(mainWindow.text_destination.Text))
\r
276 autoNamePath = Path.ChangeExtension(autoNamePath,
\r
277 Path.GetExtension(mainWindow.text_destination.Text));
\r
281 return autoNamePath;
\r
285 /// Get's HandBrakes version data from the CLI.
\r
287 public static void SetCliVersionData()
\r
291 // 0 = SVN Build / Version
\r
293 DateTime lastModified = File.GetLastWriteTime("HandBrakeCLI.exe");
\r
295 if (Properties.Settings.Default.hb_build != 0 && Properties.Settings.Default.cliLastModified == lastModified)
\r
300 Properties.Settings.Default.cliLastModified = lastModified;
\r
302 Process cliProcess = new Process();
\r
303 ProcessStartInfo handBrakeCli = new ProcessStartInfo("HandBrakeCLI.exe", " -u -v0")
\r
305 UseShellExecute = false,
\r
306 RedirectStandardError = true,
\r
307 RedirectStandardOutput = true,
\r
308 CreateNoWindow = true
\r
310 cliProcess.StartInfo = handBrakeCli;
\r
314 cliProcess.Start();
\r
316 // Retrieve standard output and report back to parent thread until the process is complete
\r
317 TextReader stdOutput = cliProcess.StandardError;
\r
319 while (!cliProcess.HasExited)
\r
321 line = stdOutput.ReadLine() ?? string.Empty;
\r
322 Match m = Regex.Match(line, @"HandBrake ([svnM0-9.]*) \(([0-9]*)\)");
\r
323 Match platform = Regex.Match(line, @"- ([A-Za-z0-9\s ]*) -");
\r
327 string version = m.Groups[1].Success ? m.Groups[1].Value : string.Empty;
\r
328 string build = m.Groups[2].Success ? m.Groups[2].Value : string.Empty;
\r
331 int.TryParse(build, out buildValue);
\r
333 Properties.Settings.Default.hb_build = buildValue;
\r
334 Properties.Settings.Default.hb_version = version;
\r
337 if (platform.Success)
\r
339 Properties.Settings.Default.hb_platform = platform.Value.Replace("-", string.Empty).Trim();
\r
342 if (cliProcess.TotalProcessorTime.Seconds > 10) // Don't wait longer than 10 seconds.
\r
344 Process cli = Process.GetProcessById(cliProcess.Id);
\r
345 if (!cli.HasExited)
\r
352 Properties.Settings.Default.Save();
\r
354 catch (Exception e)
\r
356 Properties.Settings.Default.hb_build = 0;
\r
357 Properties.Settings.Default.Save();
\r
359 ShowExceptiowWindow("Unable to retrieve version information from the CLI.", e.ToString());
\r
364 /// Check if the queue recovery file contains records.
\r
365 /// If it does, it means the last queue did not complete before HandBrake closed.
\r
366 /// So, return a boolean if true.
\r
369 /// True if there is a queue to recover.
\r
371 public static List<string> CheckQueueRecovery()
\r
375 string tempPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");
\r
376 List<string> queueFiles = new List<string>();
\r
378 DirectoryInfo info = new DirectoryInfo(tempPath);
\r
379 FileInfo[] logFiles = info.GetFiles("*.xml");
\r
380 foreach (FileInfo file in logFiles)
\r
382 if (!file.Name.Contains("hb_queue_recovery"))
\r
385 using (FileStream strm = new FileStream(Path.Combine(file.DirectoryName, file.Name), FileMode.Open, FileAccess.Read))
\r
387 List<Job> list = Ser.Deserialize(strm) as List<Job>;
\r
390 if (list.Count != 0)
\r
392 queueFiles.Add(file.Name);
\r
402 return new List<string>(); // Keep quiet about the error.
\r
407 /// Recover a queue from file.
\r
409 /// <param name="encodeQueue">
\r
410 /// The encode Queue.
\r
412 public static void RecoverQueue(IQueue encodeQueue)
\r
414 DialogResult result = DialogResult.None;
\r
415 List<string> queueFiles = CheckQueueRecovery();
\r
416 if (queueFiles.Count == 1)
\r
418 result = MessageBox.Show(
\r
419 "HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?",
\r
420 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
422 else if (queueFiles.Count > 1)
\r
424 result = MessageBox.Show(
\r
425 "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
426 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
429 if (result == DialogResult.Yes)
\r
431 foreach (string file in queueFiles)
\r
433 encodeQueue.LoadQueueFromFile(file); // Start Recovery
\r
438 if (IsMultiInstance) return; // Don't tamper with the files if we are multi instance
\r
440 string tempPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");
\r
441 foreach (string file in queueFiles)
\r
443 if (File.Exists(Path.Combine(tempPath, file)))
\r
444 File.Delete(Path.Combine(tempPath, file));
\r
450 /// Gets a value indicating whether HandBrake is running in multi instance mode
\r
452 /// <returns>True if the UI has another instance running</returns>
\r
453 public static bool IsMultiInstance
\r
457 return Process.GetProcessesByName("HandBrake").Length > 0 ? true : false;
\r
462 /// Clear all the encode log files.
\r
464 public static void ClearLogs()
\r
466 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
467 if (Directory.Exists(logDir))
\r
469 DirectoryInfo info = new DirectoryInfo(logDir);
\r
470 FileInfo[] logFiles = info.GetFiles("*.txt");
\r
471 foreach (FileInfo file in logFiles)
\r
473 if (!file.Name.Contains("last_scan_log") && !file.Name.Contains("last_encode_log"))
\r
474 File.Delete(file.FullName);
\r
480 /// Clear old log files x days in the past
\r
482 public static void ClearOldLogs()
\r
484 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
485 if (Directory.Exists(logDir))
\r
487 DirectoryInfo info = new DirectoryInfo(logDir);
\r
488 FileInfo[] logFiles = info.GetFiles("*.txt");
\r
490 foreach (FileInfo file in logFiles)
\r
492 if (file.LastWriteTime < DateTime.Now.AddDays(-30))
\r
494 if (!file.Name.Contains("last_scan_log.txt") && !file.Name.Contains("last_encode_log.txt"))
\r
495 File.Delete(file.FullName);
\r
502 /// Map languages and their iso639_2 value into a IDictionary
\r
504 /// <returns>A Dictionary containing the language and iso code</returns>
\r
505 public static IDictionary<string, string> MapLanguages()
\r
507 IDictionary<string, string> languageMap = new Dictionary<string, string>
\r
511 {"Abkhazian", "abk"},
\r
512 {"Afrikaans", "afr"},
\r
514 {"Albanian", "sqi"},
\r
515 {"Amharic", "amh"},
\r
516 {"Arabic", "ara"},
\r
517 {"Aragonese", "arg"},
\r
518 {"Armenian", "hye"},
\r
519 {"Assamese", "asm"},
\r
520 {"Avaric", "ava"},
\r
521 {"Avestan", "ave"},
\r
522 {"Aymara", "aym"},
\r
523 {"Azerbaijani", "aze"},
\r
524 {"Bashkir", "bak"},
\r
525 {"Bambara", "bam"},
\r
526 {"Basque", "eus"},
\r
527 {"Belarusian", "bel"},
\r
528 {"Bengali", "ben"},
\r
529 {"Bihari", "bih"},
\r
530 {"Bislama", "bis"},
\r
531 {"Bosnian", "bos"},
\r
532 {"Breton", "bre"},
\r
533 {"Bulgarian", "bul"},
\r
534 {"Burmese", "mya"},
\r
535 {"Catalan", "cat"},
\r
536 {"Chamorro", "cha"},
\r
537 {"Chechen", "che"},
\r
538 {"Chinese", "zho"},
\r
539 {"Church Slavic", "chu"},
\r
540 {"Chuvash", "chv"},
\r
541 {"Cornish", "cor"},
\r
542 {"Corsican", "cos"},
\r
546 {"Divehi", "div"},
\r
547 {"Nederlands", "nld"},
\r
548 {"Dzongkha", "dzo"},
\r
549 {"English", "eng"},
\r
550 {"Esperanto", "epo"},
\r
551 {"Estonian", "est"},
\r
553 {"Faroese", "fao"},
\r
554 {"Fijian", "fij"},
\r
556 {"Francais", "fra"},
\r
557 {"Western Frisian", "fry"},
\r
559 {"Georgian", "kat"},
\r
560 {"Deutsch", "deu"},
\r
561 {"Gaelic (Scots)", "gla"},
\r
563 {"Galician", "glg"},
\r
565 {"Greek Modern", "ell"},
\r
566 {"Guarani", "grn"},
\r
567 {"Gujarati", "guj"},
\r
568 {"Haitian", "hat"},
\r
570 {"Hebrew", "heb"},
\r
571 {"Herero", "her"},
\r
573 {"Hiri Motu", "hmo"},
\r
574 {"Magyar", "hun"},
\r
576 {"Islenska", "isl"},
\r
578 {"Sichuan Yi", "iii"},
\r
579 {"Inuktitut", "iku"},
\r
580 {"Interlingue", "ile"},
\r
581 {"Interlingua", "ina"},
\r
582 {"Indonesian", "ind"},
\r
583 {"Inupiaq", "ipk"},
\r
584 {"Italiano", "ita"},
\r
585 {"Javanese", "jav"},
\r
586 {"Japanese", "jpn"},
\r
587 {"Kalaallisut", "kal"},
\r
588 {"Kannada", "kan"},
\r
589 {"Kashmiri", "kas"},
\r
590 {"Kanuri", "kau"},
\r
591 {"Kazakh", "kaz"},
\r
592 {"Central Khmer", "khm"},
\r
593 {"Kikuyu", "kik"},
\r
594 {"Kinyarwanda", "kin"},
\r
595 {"Kirghiz", "kir"},
\r
598 {"Korean", "kor"},
\r
599 {"Kuanyama", "kua"},
\r
600 {"Kurdish", "kur"},
\r
603 {"Latvian", "lav"},
\r
604 {"Limburgan", "lim"},
\r
605 {"Lingala", "lin"},
\r
606 {"Lithuanian", "lit"},
\r
607 {"Luxembourgish", "ltz"},
\r
608 {"Luba-Katanga", "lub"},
\r
610 {"Macedonian", "mkd"},
\r
611 {"Marshallese", "mah"},
\r
612 {"Malayalam", "mal"},
\r
614 {"Marathi", "mar"},
\r
616 {"Malagasy", "mlg"},
\r
617 {"Maltese", "mlt"},
\r
618 {"Moldavian", "mol"},
\r
619 {"Mongolian", "mon"},
\r
621 {"Navajo", "nav"},
\r
622 {"Ndebele, South", "nbl"},
\r
623 {"Ndebele, North", "nde"},
\r
624 {"Ndonga", "ndo"},
\r
625 {"Nepali", "nep"},
\r
626 {"Norwegian Nynorsk", "nno"},
\r
627 {"Norwegian Bokmål", "nob"},
\r
629 {"Chichewa; Nyanja", "nya"},
\r
630 {"Occitan", "oci"},
\r
631 {"Ojibwa", "oji"},
\r
634 {"Ossetian", "oss"},
\r
635 {"Panjabi", "pan"},
\r
636 {"Persian", "fas"},
\r
638 {"Polish", "pol"},
\r
639 {"Portugues", "por"},
\r
640 {"Pushto", "pus"},
\r
641 {"Quechua", "que"},
\r
642 {"Romansh", "roh"},
\r
643 {"Romanian", "ron"},
\r
645 {"Russian", "rus"},
\r
647 {"Sanskrit", "san"},
\r
648 {"Serbian", "srp"},
\r
649 {"Hrvatski", "hrv"},
\r
650 {"Sinhala", "sin"},
\r
651 {"Slovak", "slk"},
\r
652 {"Slovenian", "slv"},
\r
653 {"Northern Sami", "sme"},
\r
654 {"Samoan", "smo"},
\r
656 {"Sindhi", "snd"},
\r
657 {"Somali", "som"},
\r
658 {"Sotho Southern", "sot"},
\r
659 {"Espanol", "spa"},
\r
660 {"Sardinian", "srd"},
\r
662 {"Sundanese", "sun"},
\r
663 {"Swahili", "swa"},
\r
664 {"Svenska", "swe"},
\r
665 {"Tahitian", "tah"},
\r
668 {"Telugu", "tel"},
\r
670 {"Tagalog", "tgl"},
\r
672 {"Tibetan", "bod"},
\r
673 {"Tigrinya", "tir"},
\r
675 {"Tswana", "tsn"},
\r
676 {"Tsonga", "tso"},
\r
677 {"Turkmen", "tuk"},
\r
678 {"Turkish", "tur"},
\r
680 {"Uighur", "uig"},
\r
681 {"Ukrainian", "ukr"},
\r
685 {"Vietnamese", "vie"},
\r
686 {"Volapük", "vol"},
\r
688 {"Walloon", "wln"},
\r
691 {"Yiddish", "yid"},
\r
692 {"Yoruba", "yor"},
\r
693 {"Zhuang", "zha"},
\r
696 return languageMap;
\r
700 /// Get a list of available DVD drives which are ready and contain DVD content.
\r
702 /// <returns>A List of Drives with their details</returns>
\r
703 public static List<DriveInformation> GetDrives()
\r
705 List<DriveInformation> drives = new List<DriveInformation>();
\r
706 DriveInfo[] theCollectionOfDrives = DriveInfo.GetDrives();
\r
708 foreach (DriveInfo curDrive in theCollectionOfDrives)
\r
710 if (curDrive.DriveType == DriveType.CDRom && curDrive.IsReady &&
\r
711 File.Exists(curDrive.RootDirectory + "VIDEO_TS\\VIDEO_TS.IFO"))
\r
713 drives.Add(new DriveInformation
\r
716 VolumeLabel = curDrive.VolumeLabel,
\r
717 RootDirectory = curDrive.RootDirectory + "VIDEO_TS"
\r
726 /// Change a string to Title Case/
\r
728 /// <param name="input">
\r
732 /// A string in title case.
\r
734 public static string TitleCase(string input)
\r
736 string[] tokens = input.Split(' ');
\r
737 StringBuilder sb = new StringBuilder(input.Length);
\r
738 foreach (string s in tokens)
\r
740 if (!string.IsNullOrEmpty(s))
\r
742 sb.Append(s[0].ToString().ToUpper());
\r
743 sb.Append(s.Substring(1).ToLower());
\r
748 return sb.ToString().Trim();
\r
752 /// Show the Exception Window
\r
754 /// <param name="shortError">
\r
755 /// The short error.
\r
757 /// <param name="longError">
\r
758 /// The long error.
\r
760 public static void ShowExceptiowWindow(string shortError, string longError)
\r
762 errorService.ShowError(shortError, longError);
\r
766 /// Get The Source from the CLI Query
\r
768 /// <param name="query">Full CLI Query</param>
\r
769 /// <returns>The Source Path</returns>
\r
770 public static string GetSourceFromQuery(string query)
\r
772 int startIndex = query.IndexOf("-i \"");
\r
773 if (startIndex != -1)
\r
775 string input = query.Substring(startIndex).Replace("-i \"", string.Empty).Trim();
\r
777 int closeIndex = input.IndexOf('"');
\r
779 return closeIndex == -1 ? "Unknown" : input.Substring(0, closeIndex);
\r
786 /// Get the Destination from the CLI Query
\r
788 /// <param name="query">Full CLI Query</param>
\r
789 /// <returns>The Destination path</returns>
\r
790 public static string GetDestinationFromQuery(string query)
\r
792 int startIndex = query.IndexOf("-o \"");
\r
793 if (startIndex != -1)
\r
795 string output = query.Substring(startIndex).Replace("-o \"", string.Empty).Trim();
\r
797 int closeIndex = output.IndexOf('"');
\r
799 return closeIndex == -1 ? "Unknown" : output.Substring(0, closeIndex);
\r