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
208 string sourceName = Path.GetInvalidFileNameChars().Aggregate(Path.GetFileNameWithoutExtension(mainWindow.SourceName), (current, character) => current.Replace(character.ToString(), string.Empty));
\r
210 if (Properties.Settings.Default.AutoNameRemoveUnderscore)
\r
211 sourceName = sourceName.Replace("_", " ");
\r
213 if (Properties.Settings.Default.AutoNameTitleCase)
\r
214 sourceName = TitleCase(sourceName);
\r
216 // Get the Selected Title Number
\r
217 string[] titlesplit = mainWindow.drp_dvdtitle.Text.Split(' ');
\r
218 string dvdTitle = titlesplit[0].Replace("Automatic", string.Empty);
\r
220 // Get the Chapter Start and Chapter End Numbers
\r
221 string chapterStart = mainWindow.drop_chapterStart.Text.Replace("Auto", string.Empty);
\r
222 string chapterFinish = mainWindow.drop_chapterFinish.Text.Replace("Auto", string.Empty);
\r
223 string combinedChapterTag = chapterStart;
\r
224 if (chapterFinish != chapterStart && chapterFinish != string.Empty)
\r
225 combinedChapterTag = chapterStart + "-" + chapterFinish;
\r
227 // Get the destination filename.
\r
228 string destinationFilename;
\r
229 if (Properties.Settings.Default.autoNameFormat != string.Empty)
\r
231 destinationFilename = Properties.Settings.Default.autoNameFormat;
\r
232 destinationFilename = destinationFilename.Replace("{source}", sourceName)
\r
233 .Replace("{title}", dvdTitle)
\r
234 .Replace("{chapters}", combinedChapterTag);
\r
237 destinationFilename = sourceName + "_T" + dvdTitle + "_C" + combinedChapterTag;
\r
239 // Add the appropriate file extension
\r
240 if (mainWindow.drop_format.SelectedIndex == 0)
\r
242 destinationFilename += Properties.Settings.Default.useM4v || mainWindow.Check_ChapterMarkers.Checked ||
\r
243 mainWindow.AudioSettings.RequiresM4V() || mainWindow.Subtitles.RequiresM4V()
\r
247 else if (mainWindow.drop_format.SelectedIndex == 1)
\r
248 destinationFilename += ".mkv";
\r
250 // Now work out the path where the file will be stored.
\r
251 // First case: If the destination box doesn't already contain a path, make one.
\r
252 if (!mainWindow.text_destination.Text.Contains(Path.DirectorySeparatorChar.ToString()))
\r
254 // If there is an auto name path, use it...
\r
255 if (Properties.Settings.Default.autoNamePath.Trim() == "{source_path}" && !string.IsNullOrEmpty(mainWindow.sourcePath))
\r
257 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.sourcePath), destinationFilename);
\r
258 if (autoNamePath == mainWindow.sourcePath)
\r
260 // Append out_ to files that already exist or is the source file
\r
261 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.sourcePath), "output_" + destinationFilename);
\r
264 else if (Properties.Settings.Default.autoNamePath.Trim() != string.Empty && Properties.Settings.Default.autoNamePath.Trim() != "Click 'Browse' to set the default location")
\r
266 autoNamePath = Path.Combine(Properties.Settings.Default.autoNamePath, destinationFilename);
\r
268 else // ...otherwise, output to the source directory
\r
269 autoNamePath = null;
\r
271 else // Otherwise, use the path that is already there.
\r
273 // Use the path and change the file extension to match the previous destination
\r
274 autoNamePath = Path.Combine(Path.GetDirectoryName(mainWindow.text_destination.Text), destinationFilename);
\r
276 if (Path.HasExtension(mainWindow.text_destination.Text))
\r
277 autoNamePath = Path.ChangeExtension(autoNamePath,
\r
278 Path.GetExtension(mainWindow.text_destination.Text));
\r
282 return autoNamePath;
\r
286 /// Get's HandBrakes version data from the CLI.
\r
288 public static void SetCliVersionData()
\r
292 // 0 = SVN Build / Version
\r
294 DateTime lastModified = File.GetLastWriteTime("HandBrakeCLI.exe");
\r
296 if (Properties.Settings.Default.hb_build != 0 && Properties.Settings.Default.cliLastModified == lastModified)
\r
301 Properties.Settings.Default.cliLastModified = lastModified;
\r
303 Process cliProcess = new Process();
\r
304 ProcessStartInfo handBrakeCli = new ProcessStartInfo("HandBrakeCLI.exe", " -u -v0")
\r
306 UseShellExecute = false,
\r
307 RedirectStandardError = true,
\r
308 RedirectStandardOutput = true,
\r
309 CreateNoWindow = true
\r
311 cliProcess.StartInfo = handBrakeCli;
\r
315 cliProcess.Start();
\r
317 // Retrieve standard output and report back to parent thread until the process is complete
\r
318 TextReader stdOutput = cliProcess.StandardError;
\r
320 while (!cliProcess.HasExited)
\r
322 line = stdOutput.ReadLine() ?? string.Empty;
\r
323 Match m = Regex.Match(line, @"HandBrake ([svnM0-9.]*) \(([0-9]*)\)");
\r
324 Match platform = Regex.Match(line, @"- ([A-Za-z0-9\s ]*) -");
\r
328 string version = m.Groups[1].Success ? m.Groups[1].Value : string.Empty;
\r
329 string build = m.Groups[2].Success ? m.Groups[2].Value : string.Empty;
\r
332 int.TryParse(build, out buildValue);
\r
334 Properties.Settings.Default.hb_build = buildValue;
\r
335 Properties.Settings.Default.hb_version = version;
\r
338 if (platform.Success)
\r
340 Properties.Settings.Default.hb_platform = platform.Value.Replace("-", string.Empty).Trim();
\r
343 if (cliProcess.TotalProcessorTime.Seconds > 10) // Don't wait longer than 10 seconds.
\r
345 Process cli = Process.GetProcessById(cliProcess.Id);
\r
346 if (!cli.HasExited)
\r
353 Properties.Settings.Default.Save();
\r
355 catch (Exception e)
\r
357 Properties.Settings.Default.hb_build = 0;
\r
358 Properties.Settings.Default.Save();
\r
360 ShowExceptiowWindow("Unable to retrieve version information from the CLI.", e.ToString());
\r
365 /// Check if the queue recovery file contains records.
\r
366 /// If it does, it means the last queue did not complete before HandBrake closed.
\r
367 /// So, return a boolean if true.
\r
370 /// True if there is a queue to recover.
\r
372 public static List<string> CheckQueueRecovery()
\r
376 string tempPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");
\r
377 List<string> queueFiles = new List<string>();
\r
379 DirectoryInfo info = new DirectoryInfo(tempPath);
\r
380 FileInfo[] logFiles = info.GetFiles("*.xml");
\r
381 foreach (FileInfo file in logFiles)
\r
383 if (!file.Name.Contains("hb_queue_recovery"))
\r
386 using (FileStream strm = new FileStream(Path.Combine(file.DirectoryName, file.Name), FileMode.Open, FileAccess.Read))
\r
388 List<Job> list = Ser.Deserialize(strm) as List<Job>;
\r
391 if (list.Count != 0)
\r
393 queueFiles.Add(file.Name);
\r
403 return new List<string>(); // Keep quiet about the error.
\r
408 /// Recover a queue from file.
\r
410 /// <param name="encodeQueue">
\r
411 /// The encode Queue.
\r
413 public static void RecoverQueue(IQueue encodeQueue)
\r
415 DialogResult result = DialogResult.None;
\r
416 List<string> queueFiles = CheckQueueRecovery();
\r
417 if (queueFiles.Count == 1)
\r
419 result = MessageBox.Show(
\r
420 "HandBrake has detected unfinished items on the queue from the last time the application was launched. Would you like to recover these?",
\r
421 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
423 else if (queueFiles.Count > 1)
\r
425 result = MessageBox.Show(
\r
426 "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
427 "Queue Recovery Possible", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
\r
430 if (result == DialogResult.Yes)
\r
432 foreach (string file in queueFiles)
\r
434 encodeQueue.LoadQueueFromFile(file); // Start Recovery
\r
439 if (IsMultiInstance) return; // Don't tamper with the files if we are multi instance
\r
441 string tempPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), @"HandBrake\");
\r
442 foreach (string file in queueFiles)
\r
444 if (File.Exists(Path.Combine(tempPath, file)))
\r
445 File.Delete(Path.Combine(tempPath, file));
\r
451 /// Gets a value indicating whether HandBrake is running in multi instance mode
\r
453 /// <returns>True if the UI has another instance running</returns>
\r
454 public static bool IsMultiInstance
\r
458 return Process.GetProcessesByName("HandBrake").Length > 0 ? true : false;
\r
463 /// Clear all the encode log files.
\r
465 public static void ClearLogs()
\r
467 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
468 if (Directory.Exists(logDir))
\r
470 DirectoryInfo info = new DirectoryInfo(logDir);
\r
471 FileInfo[] logFiles = info.GetFiles("*.txt");
\r
472 foreach (FileInfo file in logFiles)
\r
474 if (!file.Name.Contains("last_scan_log") && !file.Name.Contains("last_encode_log"))
\r
475 File.Delete(file.FullName);
\r
481 /// Clear old log files x days in the past
\r
483 public static void ClearOldLogs()
\r
485 string logDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + "\\HandBrake\\logs";
\r
486 if (Directory.Exists(logDir))
\r
488 DirectoryInfo info = new DirectoryInfo(logDir);
\r
489 FileInfo[] logFiles = info.GetFiles("*.txt");
\r
491 foreach (FileInfo file in logFiles)
\r
493 if (file.LastWriteTime < DateTime.Now.AddDays(-30))
\r
495 if (!file.Name.Contains("last_scan_log.txt") && !file.Name.Contains("last_encode_log.txt"))
\r
496 File.Delete(file.FullName);
\r
503 /// Map languages and their iso639_2 value into a IDictionary
\r
505 /// <returns>A Dictionary containing the language and iso code</returns>
\r
506 public static IDictionary<string, string> MapLanguages()
\r
508 IDictionary<string, string> languageMap = new Dictionary<string, string>
\r
512 {"Abkhazian", "abk"},
\r
513 {"Afrikaans", "afr"},
\r
515 {"Albanian", "sqi"},
\r
516 {"Amharic", "amh"},
\r
517 {"Arabic", "ara"},
\r
518 {"Aragonese", "arg"},
\r
519 {"Armenian", "hye"},
\r
520 {"Assamese", "asm"},
\r
521 {"Avaric", "ava"},
\r
522 {"Avestan", "ave"},
\r
523 {"Aymara", "aym"},
\r
524 {"Azerbaijani", "aze"},
\r
525 {"Bashkir", "bak"},
\r
526 {"Bambara", "bam"},
\r
527 {"Basque", "eus"},
\r
528 {"Belarusian", "bel"},
\r
529 {"Bengali", "ben"},
\r
530 {"Bihari", "bih"},
\r
531 {"Bislama", "bis"},
\r
532 {"Bosnian", "bos"},
\r
533 {"Breton", "bre"},
\r
534 {"Bulgarian", "bul"},
\r
535 {"Burmese", "mya"},
\r
536 {"Catalan", "cat"},
\r
537 {"Chamorro", "cha"},
\r
538 {"Chechen", "che"},
\r
539 {"Chinese", "zho"},
\r
540 {"Church Slavic", "chu"},
\r
541 {"Chuvash", "chv"},
\r
542 {"Cornish", "cor"},
\r
543 {"Corsican", "cos"},
\r
547 {"Divehi", "div"},
\r
548 {"Nederlands", "nld"},
\r
549 {"Dzongkha", "dzo"},
\r
550 {"English", "eng"},
\r
551 {"Esperanto", "epo"},
\r
552 {"Estonian", "est"},
\r
554 {"Faroese", "fao"},
\r
555 {"Fijian", "fij"},
\r
557 {"Francais", "fra"},
\r
558 {"Western Frisian", "fry"},
\r
560 {"Georgian", "kat"},
\r
561 {"Deutsch", "deu"},
\r
562 {"Gaelic (Scots)", "gla"},
\r
564 {"Galician", "glg"},
\r
566 {"Greek Modern", "ell"},
\r
567 {"Guarani", "grn"},
\r
568 {"Gujarati", "guj"},
\r
569 {"Haitian", "hat"},
\r
571 {"Hebrew", "heb"},
\r
572 {"Herero", "her"},
\r
574 {"Hiri Motu", "hmo"},
\r
575 {"Magyar", "hun"},
\r
577 {"Islenska", "isl"},
\r
579 {"Sichuan Yi", "iii"},
\r
580 {"Inuktitut", "iku"},
\r
581 {"Interlingue", "ile"},
\r
582 {"Interlingua", "ina"},
\r
583 {"Indonesian", "ind"},
\r
584 {"Inupiaq", "ipk"},
\r
585 {"Italiano", "ita"},
\r
586 {"Javanese", "jav"},
\r
587 {"Japanese", "jpn"},
\r
588 {"Kalaallisut", "kal"},
\r
589 {"Kannada", "kan"},
\r
590 {"Kashmiri", "kas"},
\r
591 {"Kanuri", "kau"},
\r
592 {"Kazakh", "kaz"},
\r
593 {"Central Khmer", "khm"},
\r
594 {"Kikuyu", "kik"},
\r
595 {"Kinyarwanda", "kin"},
\r
596 {"Kirghiz", "kir"},
\r
599 {"Korean", "kor"},
\r
600 {"Kuanyama", "kua"},
\r
601 {"Kurdish", "kur"},
\r
604 {"Latvian", "lav"},
\r
605 {"Limburgan", "lim"},
\r
606 {"Lingala", "lin"},
\r
607 {"Lithuanian", "lit"},
\r
608 {"Luxembourgish", "ltz"},
\r
609 {"Luba-Katanga", "lub"},
\r
611 {"Macedonian", "mkd"},
\r
612 {"Marshallese", "mah"},
\r
613 {"Malayalam", "mal"},
\r
615 {"Marathi", "mar"},
\r
617 {"Malagasy", "mlg"},
\r
618 {"Maltese", "mlt"},
\r
619 {"Moldavian", "mol"},
\r
620 {"Mongolian", "mon"},
\r
622 {"Navajo", "nav"},
\r
623 {"Ndebele, South", "nbl"},
\r
624 {"Ndebele, North", "nde"},
\r
625 {"Ndonga", "ndo"},
\r
626 {"Nepali", "nep"},
\r
627 {"Norwegian Nynorsk", "nno"},
\r
628 {"Norwegian Bokmål", "nob"},
\r
630 {"Chichewa; Nyanja", "nya"},
\r
631 {"Occitan", "oci"},
\r
632 {"Ojibwa", "oji"},
\r
635 {"Ossetian", "oss"},
\r
636 {"Panjabi", "pan"},
\r
637 {"Persian", "fas"},
\r
639 {"Polish", "pol"},
\r
640 {"Portugues", "por"},
\r
641 {"Pushto", "pus"},
\r
642 {"Quechua", "que"},
\r
643 {"Romansh", "roh"},
\r
644 {"Romanian", "ron"},
\r
646 {"Russian", "rus"},
\r
648 {"Sanskrit", "san"},
\r
649 {"Serbian", "srp"},
\r
650 {"Hrvatski", "hrv"},
\r
651 {"Sinhala", "sin"},
\r
652 {"Slovak", "slk"},
\r
653 {"Slovenian", "slv"},
\r
654 {"Northern Sami", "sme"},
\r
655 {"Samoan", "smo"},
\r
657 {"Sindhi", "snd"},
\r
658 {"Somali", "som"},
\r
659 {"Sotho Southern", "sot"},
\r
660 {"Espanol", "spa"},
\r
661 {"Sardinian", "srd"},
\r
663 {"Sundanese", "sun"},
\r
664 {"Swahili", "swa"},
\r
665 {"Svenska", "swe"},
\r
666 {"Tahitian", "tah"},
\r
669 {"Telugu", "tel"},
\r
671 {"Tagalog", "tgl"},
\r
673 {"Tibetan", "bod"},
\r
674 {"Tigrinya", "tir"},
\r
676 {"Tswana", "tsn"},
\r
677 {"Tsonga", "tso"},
\r
678 {"Turkmen", "tuk"},
\r
679 {"Turkish", "tur"},
\r
681 {"Uighur", "uig"},
\r
682 {"Ukrainian", "ukr"},
\r
686 {"Vietnamese", "vie"},
\r
687 {"Volapük", "vol"},
\r
689 {"Walloon", "wln"},
\r
692 {"Yiddish", "yid"},
\r
693 {"Yoruba", "yor"},
\r
694 {"Zhuang", "zha"},
\r
697 return languageMap;
\r
701 /// Get a list of available DVD drives which are ready and contain DVD content.
\r
703 /// <returns>A List of Drives with their details</returns>
\r
704 public static List<DriveInformation> GetDrives()
\r
706 List<DriveInformation> drives = new List<DriveInformation>();
\r
707 DriveInfo[] theCollectionOfDrives = DriveInfo.GetDrives();
\r
709 foreach (DriveInfo curDrive in theCollectionOfDrives)
\r
711 if (curDrive.DriveType == DriveType.CDRom && curDrive.IsReady &&
\r
712 File.Exists(curDrive.RootDirectory + "VIDEO_TS\\VIDEO_TS.IFO"))
\r
714 drives.Add(new DriveInformation
\r
717 VolumeLabel = curDrive.VolumeLabel,
\r
718 RootDirectory = curDrive.RootDirectory + "VIDEO_TS"
\r
727 /// Change a string to Title Case/
\r
729 /// <param name="input">
\r
733 /// A string in title case.
\r
735 public static string TitleCase(string input)
\r
737 string[] tokens = input.Split(' ');
\r
738 StringBuilder sb = new StringBuilder(input.Length);
\r
739 foreach (string s in tokens)
\r
741 if (!string.IsNullOrEmpty(s))
\r
743 sb.Append(s[0].ToString().ToUpper());
\r
744 sb.Append(s.Substring(1).ToLower());
\r
749 return sb.ToString().Trim();
\r
753 /// Show the Exception Window
\r
755 /// <param name="shortError">
\r
756 /// The short error.
\r
758 /// <param name="longError">
\r
759 /// The long error.
\r
761 public static void ShowExceptiowWindow(string shortError, string longError)
\r
763 errorService.ShowError(shortError, longError);
\r
767 /// Get The Source from the CLI Query
\r
769 /// <param name="query">Full CLI Query</param>
\r
770 /// <returns>The Source Path</returns>
\r
771 public static string GetSourceFromQuery(string query)
\r
773 int startIndex = query.IndexOf("-i \"");
\r
774 if (startIndex != -1)
\r
776 string input = query.Substring(startIndex).Replace("-i \"", string.Empty).Trim();
\r
778 int closeIndex = input.IndexOf('"');
\r
780 return closeIndex == -1 ? "Unknown" : input.Substring(0, closeIndex);
\r
787 /// Get the Destination from the CLI Query
\r
789 /// <param name="query">Full CLI Query</param>
\r
790 /// <returns>The Destination path</returns>
\r
791 public static string GetDestinationFromQuery(string query)
\r
793 int startIndex = query.IndexOf("-o \"");
\r
794 if (startIndex != -1)
\r
796 string output = query.Substring(startIndex).Replace("-o \"", string.Empty).Trim();
\r
798 int closeIndex = output.IndexOf('"');
\r
800 return closeIndex == -1 ? "Unknown" : output.Substring(0, closeIndex);
\r