private static ProcessingState ProcessJsonString(ProgressReporter progressReporter, List <DiskTitle> diskTitles, StringBuilder json, HandBrakeJsonType jsonType, ProcessingState processingState, Stopwatch stopwatch)
        {
            if (json == null)
            {
                return(processingState);
            }
            switch (jsonType)
            {
            case HandBrakeJsonType.Version:
                HBVersion jVersion = JsonSerializer.Deserialize <HBVersion>(json.ToString());
                //JToken jVersion = JToken.Parse(json.ToString());
                progressReporter.AppendLog($"Using {jVersion.Name} {jVersion.VersionString} {jVersion.Arch}", LogEntryType.Debug);
                break;

            case HandBrakeJsonType.Progress:
                // process
                HBProgress jProgress = JsonSerializer.Deserialize <HBProgress>(json.ToString());
                if (jProgress.State == "WORKING")
                {
                    if (processingState != ProcessingState.Encoding)
                    {
                        progressReporter.CurrentTask = "Encoding";
                        processingState = ProcessingState.Encoding;
                    }
                }
                else if (jProgress.State == "SCANNING")
                {
                    if (processingState != ProcessingState.Scanning)
                    {
                        progressReporter.CurrentTask = "Scanning";
                        processingState = ProcessingState.Scanning;
                    }
                }
                else if (jProgress.State == "MUXING")
                {
                    if (processingState != ProcessingState.Muxing)
                    {
                        progressReporter.CurrentTask = "Muxing";
                        processingState = ProcessingState.Muxing;
                    }
                    // TODO Remove
                    Debug.WriteLine(json.ToString());
                }
                else
                {
                    // TODO Remove
                    Debug.WriteLine(json.ToString());
                }
                if (stopwatch.ElapsedMilliseconds > 1000)
                {
                    progressReporter.CurrentProgress = (jProgress.GetCurrentProgress() * 100);
                    progressReporter.Remaining       = jProgress.GetETAString();
                    stopwatch.Restart();
                }
                break;

            case HandBrakeJsonType.TitleSet:
                HBTitleSet jTitleSet   = JsonSerializer.Deserialize <HBTitleSet>(json.ToString());
                int        mainFeature = jTitleSet.MainFeature;
                foreach (HBTitleSet.TitleListData jTitle in jTitleSet.TitleList)
                {
                    DiskTitle diskTitle = new DiskTitle
                    {
                        TitleName   = jTitle.Name,
                        FullMKVPath = jTitle.Path
                    };
                    diskTitle.FileName   = Path.GetFileName(diskTitle.FullMKVPath);
                    diskTitle.TitleIndex = jTitle.Index;
                    if (mainFeature == -1 || diskTitle.TitleIndex == mainFeature)
                    {
                        diskTitle.MainMovie = true;
                    }
                    diskTitle.HorizontalResolution = jTitle.Geometry.Height;
                    diskTitle.VerticalResolution   = jTitle.Geometry.Width;
                    diskTitle.VideoCodec           = jTitle.VideoCodec;
                    diskTitle.Seconds  = (jTitle.Duration.Hours * 60 * 60) + (jTitle.Duration.Minutes * 60) + jTitle.Duration.Seconds;
                    diskTitle.Chapters = jTitle.ChapterList.Length;
                    diskTitles.Add(diskTitle);
                }
                break;
            }

            return(processingState);
        }
        internal bool Encode(string inputFile, int titleIndex, string outputFile, ProgressReporter progressReporter)
        {
            bool success = false;

            StopRunningProcess();
            wasKilled = false;

            string outputFormat = MovieOutputType == OutputType.MP4 ? "av_mp4" : "av_mkv";
            string subtitles    = ForceSubtitles == true ? "--subtitle scan --subtitle-forced" : "";

            string cmdParams = $"--preset-import-file \"{HandBrakeProfileFile}\" -i \"{inputFile}\" -o \"{outputFile}\" --format {outputFormat} {subtitles} --json";

            if (titleIndex != 0)
            {
                cmdParams += $" --title {titleIndex}";
            }

            handBrakeProcess = new Process
            {
                StartInfo = new ProcessStartInfo(HandBrakeCliExePath, cmdParams)
                {
                    CreateNoWindow         = true,
                    RedirectStandardOutput = true,
                    RedirectStandardInput  = true,
                    RedirectStandardError  = true,
                    UseShellExecute        = false
                },
                EnableRaisingEvents = true
            };

            StringBuilder error = new StringBuilder();

            List <DiskTitle>  diskTitles      = new List <DiskTitle>();
            StringBuilder     json            = null;
            HandBrakeJsonType jsonType        = HandBrakeJsonType.Version;
            ProcessingState   processingState = ProcessingState.None;
            Stopwatch         stopwatch       = new Stopwatch();

            stopwatch.Start();
            handBrakeProcess.OutputDataReceived += new DataReceivedEventHandler(
                delegate(object sender, DataReceivedEventArgs e)
            {
                // append the new data to the data already read-in
                string line = e.Data;
                if (line == null)
                {
                    return;
                }

                ProcessJson(progressReporter, diskTitles, ref json, ref jsonType, ref processingState, stopwatch, line);
            }
                );

            handBrakeProcess.ErrorDataReceived += new DataReceivedEventHandler(
                delegate(object sender, DataReceivedEventArgs e)
            {
                error.Append(e.Data);
                error.Append("\r\n");

                progressReporter.AppendLog(e.Data, LogEntryType.Trace);
            }
                );
            handBrakeProcess.Start();
            handBrakeProcess.BeginOutputReadLine();
            handBrakeProcess.BeginErrorReadLine();
            handBrakeProcess.WaitForExit();
            if (handBrakeProcess != null)
            {
                handBrakeProcess.CancelOutputRead();
                handBrakeProcess.CancelErrorRead();
                success = handBrakeProcess.ExitCode == 0;
            }

            ProcessJsonString(progressReporter, diskTitles, json, jsonType, processingState, stopwatch);
            if (!success)
            {
                if (!wasKilled)
                {
                    progressReporter.AppendLog($"Output from Handbrake\r\n{error}", LogEntryType.Debug);
                }
                File.Delete(outputFile);
            }
            return(success);
        }
        private static void ProcessJson(ProgressReporter progressReporter, List <DiskTitle> diskTitles, ref StringBuilder json, ref HandBrakeJsonType jsonType, ref ProcessingState processingState, Stopwatch stopwatch, string line)
        {
            Match match = Regex.Match(line, "^(\\S.+):\\s*{");

            if (match.Success)
            {
                // check the old version
                if (json != null)
                {
                    processingState = ProcessJsonString(progressReporter, diskTitles, json, jsonType, processingState, stopwatch);
                }
                // start of json
                json = new StringBuilder();
                json.Append("{ ");
                string type = match.Groups[1].Value;
                switch (type)
                {
                case "Version":
                    jsonType = HandBrakeJsonType.Version;
                    break;

                case "Progress":
                    jsonType = HandBrakeJsonType.Progress;
                    break;

                case "JSON Title Set":
                    jsonType = HandBrakeJsonType.TitleSet;
                    break;
                }
            }
            else if (json != null)
            {
                json.Append(line);
            }
        }
        internal List <DiskTitle> Scan(string file, int titleIndex, bool allTitles, ProgressReporter progressReporter)
        {
            List <DiskTitle> diskTitles = new List <DiskTitle>();

            StopRunningProcess();
            wasKilled = false;

            string cmdParams = $"-i \"{file}\" --scan --no-dvdnav --json";

            if (!allTitles)
            {
                cmdParams += " --main-feature";
            }
            else
            {
                cmdParams += $" --title {titleIndex}";
            }
            handBrakeProcess = new Process
            {
                StartInfo = new ProcessStartInfo(HandBrakeCliExePath, cmdParams)
                {
                    CreateNoWindow         = true,
                    RedirectStandardOutput = true,
                    RedirectStandardError  = true,
                    UseShellExecute        = false
                },
                EnableRaisingEvents = true
            };


            bool              success         = false;
            StringBuilder     json            = null;
            HandBrakeJsonType jsonType        = HandBrakeJsonType.Version;
            ProcessingState   processingState = ProcessingState.None;
            Stopwatch         stopwatch       = new Stopwatch();

            stopwatch.Start();

            handBrakeProcess.OutputDataReceived += new DataReceivedEventHandler(
                delegate(object sender, DataReceivedEventArgs e)
            {
                string line = e.Data;
                if (line == null)
                {
                    return;
                }

                ProcessJson(progressReporter, diskTitles, ref json, ref jsonType, ref processingState, stopwatch, line);
            }
                );

            StringBuilder error = new StringBuilder();

            handBrakeProcess.ErrorDataReceived += new DataReceivedEventHandler(
                delegate(object sender, DataReceivedEventArgs e)
            {
                error.Append(e.Data);
                error.Append("\r\n");

                progressReporter.AppendLog(e.Data, LogEntryType.Trace);
            }
                );
            handBrakeProcess.Start();
            handBrakeProcess.BeginOutputReadLine();
            handBrakeProcess.BeginErrorReadLine();
            handBrakeProcess.WaitForExit();
            if (handBrakeProcess != null)
            {
                handBrakeProcess.CancelOutputRead();
                handBrakeProcess.CancelErrorRead();
                success = handBrakeProcess.ExitCode == 0;
            }

            ProcessJsonString(progressReporter, diskTitles, json, jsonType, processingState, stopwatch);

            if (!success && !wasKilled)
            {
                progressReporter.AppendLog($"Output from Handbrake\r\n{error}", LogEntryType.Debug);
            }
            return(diskTitles);
        }