//Global BackgroundWorker ProgressChanged.
        private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            ProgressState progressState = e.UserState as ProgressState;

            progressBar1.Value = e.ProgressPercentage;
            progressBar2.Value = progressState.progressPercent;

            this.Text        = "Processing " + e.ProgressPercentage.ToString() + "%...";
            this.label1.Text = "Processing " + progressState.listName.TruncateLast(60) + " (" + e.ProgressPercentage.ToString() + "%)...";

            this.label2.Text      = "Processing " + progressState.fileName.TruncateLast(60) + " (" + progressState.progressPercent.ToString() + "%)";
            this.detailLabel.Text = progressState.progressDetail;
        }
        /// <summary>
        /// Main Convert process.
        /// </summary>
        /// <param name="fileList">The FileObjectCollection to process.</param>
        public void Convert(FileObjectCollection fileList, int fileListPercent = 100)
        {
            InitializeConfiguration();

            ProgressState progressState = new ProgressState();

            progressState.listName = fileList.name;

            progress       = 1;
            processPercent = 0;

            if (!Config.Configure.sourceOutputFolder)
            {
                outputPath = Program.defaultPath;
                if (!Directory.Exists(Path.Combine(outputPath, "converted")))
                {
                    Directory.CreateDirectory(Path.Combine(outputPath, "converted"));
                }
            }

            //Main Loop
            foreach (FileObject file in fileList.fileList)
            {
                //Set Required Variables
                string ffmpegArgs        = "";
                string fileVfilter       = "";
                string fileVfilterArg    = "";
                string fileFFmpegOptions = ffmpegOptions;

                List <string> fileVfilters = new List <string>();

                List <string> fileFilterChains = new List <string>();

                foreach (string vfilteritem in vfilters)
                {
                    fileVfilters.Add(vfilteritem);
                }

                //Escape Filter Patterns
                string firstLevel  = @"([:\\'])";
                string secondLevel = @"([\[\],;\\'])";

                //Input/Output programmatic patterns
                string custInputPat  = @"\(inputfile\)";
                string custOutputPat = @"\(outputname\)";

                //Progress Reporting
                progressState.fileName = file.filename;

                processPercent = progress.ToPercentage(fileList.fileList.Count);
                progressState.progressPercent = processPercent;

                progressState.progressDetail = "Building conversion arguments...";
                this.backgroundWorker.ReportProgress(fileListPercent, progressState);

                if (Config.Configure.sourceOutputFolder)
                {
                    outputPath = file.directoryname;
                }

                if (!Directory.Exists(Path.Combine(outputPath, "converted")))
                {
                    Directory.CreateDirectory(Path.Combine(outputPath, "converted"));
                }

                //Output File Argument
                string outputFile = outputPath + "\\converted\\" + ConvConfig.newfileprefix + file.filenameNoExtension + ConvConfig.newfilesuffix;

                //Fix_subtitle_duration
                if (ConvConfig.fixsubduration)
                {
                    ffmpegArgs += @"-fix_sub_duration ";
                }

                //Subtitles
                //Subfilter
                if (ConvConfig.useSubFilter)
                {
                    //Escape any special characters
                    string fileitem = file.fullpath;
                    fileitem = Regex.Replace(fileitem, firstLevel, m =>
                    {
                        var escapedChars = m.Groups[1].Value;
                        return(@"\" + escapedChars);
                    });

                    fileitem = Regex.Replace(fileitem, secondLevel, n =>
                    {
                        var escapedChars = n.Groups[1].Value;
                        return(@"\" + escapedChars);
                    });

                    fileVfilter = @"subtitles=" + fileitem + @":si=" + ConvConfig.subindex.ToString();
                    fileVfilters.Add(fileVfilter);
                }



                //Video Filter
                //Custom Video Filter
                if (!String.IsNullOrWhiteSpace(ConvConfig.customvfilter))
                {
                    fileVfilterArg = ConvConfig.customvfilter;
                }
                else
                {
                    //filefilterchain.Add(String.Join(",", vfilters.ToArray()));

                    fileVfilterArg = String.Join(", ", fileVfilters.ToArray());
                }

                //Diagnostic purposes only
                //fileVfilterArg = "subtitles=D:\\backup\\anime_archive\\[Coalgirls]_Ookami-san,_to;_Shichinin_no_'Nakama-tachi'_(1280x720_Blu-ray_FLAC)\\[Coalgirls]_Ookami-san_to_Shichinin_no_Nakama-tachi_01_(1280x720_Blu-ray_FLAC)_[F9495BFE].mkv:si=0";

                if (!String.IsNullOrWhiteSpace(fileVfilterArg))
                {
                    fileVfilterArg     = " -vf \"" + fileVfilterArg + "\""; //Placeholder
                    fileFFmpegOptions += fileVfilterArg;
                }

                //Custom ffmpeg options
                if (!String.IsNullOrWhiteSpace(ConvConfig.customffmpegarg))
                {
                    string customData = ConvConfig.customffmpegarg;

                    //Replace (inputfile) and (outputname) with input and output variables accordingly.
                    customData = Regex.Replace(customData, custInputPat, m => { return(file.fullpath); });
                    customData = Regex.Replace(customData, custOutputPat, m => { return(outputFile); });

                    ffmpegArgs = customData;
                }
                else
                {
                    //Set final ffmpegArgs
                    ffmpegArgs += "-i \"" + file.fullpath + "\"" + fileFFmpegOptions + " \"" + outputFile + "." + ConvConfig.format + "\"";
                }

                currentCommand = ffmpegArgs;

                /*
                 * Routine before converting
                 * Checks if current backgroundWorker operation is cancelled
                 * Stops this program if true
                 *
                 * Process cancelling should be changed as this currently waits for previous conversion to complete;
                 * Conversion can take a lot of time for cancellation to wait.
                 *
                 * Native threading would be used.
                 *
                 * */
                if (this.backgroundWorker.CancellationPending)
                {
                    return;
                }

                if (ConvConfig.showCommands)
                {
                    Program.Message("Current command:\r\n\r\n" + currentCommand, "Diagnostics");
                }

                //Main process
                ProcessStartInfo convertProcess = new ProcessStartInfo();

                convertProcess.FileName  = Program.ffmpegExe;
                convertProcess.Arguments = ffmpegArgs;

                convertProcess.UseShellExecute = false;

                if (!Config.Configure.ConvertConfigure.showFFmpegWindow) //Added check for diagnostics
                {
                    convertProcess.CreateNoWindow        = true;
                    convertProcess.WindowStyle           = ProcessWindowStyle.Hidden;
                    convertProcess.RedirectStandardInput = true; //Preparation for an eminent interactive ffmpeg thread.
                }
                else
                {
                    convertProcess.CreateNoWindow = false;
                }
                convertProcess.WorkingDirectory = file.directoryname;

                progressState.progressDetail = "Converting...";
                this.backgroundWorker.ReportProgress(fileListPercent, progressState);

                using (Process process = Process.Start(convertProcess))
                {
                    process.WaitForExit();
                }


                //If External subs are set to true.
                if (ConvConfig.externalsubs)
                {
                    ffmpegArgs = "-i \"" + file.fullpath + "\" \"" + outputFile + "." + ConvConfig.externalsubsext + "\"";

                    currentCommand = ffmpegArgs;

                    if (ConvConfig.showCommands)
                    {
                        Program.Message("Current command:\r\n\r\n" + currentCommand, "Diagnostics");
                    }

                    convertProcess.Arguments = ffmpegArgs;

                    progressState.progressDetail = "Creating external subtitles...";
                    this.backgroundWorker.ReportProgress(fileListPercent, progressState);

                    using (Process process = Process.Start(convertProcess))
                    {
                        process.WaitForExit();
                    }
                }

                progress++;
                //End of Main process
            }

            if (!Analyze.outputGroups.Contains(outputPath))
            {
                Analyze.outputGroups.Add(outputPath + "\\converted");
            }
        }
        /// <summary>
        /// Processes files to create File Objects for the main tasks of this program.
        /// Every tasks are denoted on each comment lines inside the method.
        /// </summary>
        /// <param name="list">The list that contains the fullpaths of the actual files.</param>
        /// <param name="listname">Name for the FileObjectCollection to be created.</param>
        /// <param name="processor">The Analyze object for progression report.</param>
        /// <param name="path">The path used as a working directory merge commands.</param>
        /// <param name="totalArguments">Optional. For progress report. The total number of lists to process.</param>
        public void processList(List<string> list, string listname, Analyze processor, string path = "C:\\", int totalArguments = 0)
        {
            FileObjectCollection fileList = new FileObjectCollection();
              TrackLister tracklist = new TrackLister();
              MakeFile makeFile = new MakeFile();
              ChapterGenerator chapterGet = new ChapterGenerator();
              ProgressState progressState = new ProgressState();

              fileList.folderPath = path;
              fileList.name = listname;

              progressState.listName = fileList.name;

              progress = 1;
              processPercent = 0;

              foreach (string s in list)
              {

            progressState.progressDetail = "Creating file entry...";

            Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

            FileObject file = new FileObject(s);

            processPercent = progress.ToPercentage(list.Count);
            progressState.progressPercent = processPercent;
            progressState.fileName = file.filename;
            Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

              //Routine after splitting
              //Checks if current backgroundWorker operation is cancelled
              //Stops this program if true
            if (Analyze.backgroundWorker.CancellationPending)
            {
              return;
            }

            if (file.extension == ".mkv")
            {
              try
              {
            file = InfoDumper.infoDump(file);
              }
              catch (Exception ex)
              {
            Program.Message("Error:\r\n\r\n" + ex.Message, "Error");
              }

              progressState.progressDetail = "Dumping MKV info...";

              Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

              file = chapterGet.chapterDump(file);

              if (!Config.Configure.includeMkvInfoOnFiles)
            file.mkvInfo = null;

              if (!Config.Configure.includeMediaInfoOnFiles)
            file.ffInfo = null;

              progressState.progressDetail = "Getting chapters' info...";

              Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

              fileList.hasMKV = true;
            }

            if (Program.hasFFmpeg)
            {

              progressState.progressDetail = "Dumping media info...";

              Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

              try
              {
            file = InfoDumper.ffInfoDump(file);
              }
              catch (Exception ex)
              {
            Program.Message("Error:\r\n\r\n" + ex.Message, "Error");
              }

              if (!String.IsNullOrEmpty(file.ffInfo)) file = chapterGet.mediaDump(file);

            }

            fileList.addFile(file);

            progress++;
              }

              if (fileList.hasMKV)
              {
            SuidLister suidList = CreateSuidLister(fileList);

            progressState.progressDetail = "Creating SUID list...";
            Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

            fileList = tracklist.arrangeTrack(fileList, suidList, processor);

            progressState.progressDetail = "Arranging new tracklist for every file...";
            Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

            //For Diagnostic purposes only
            if (Config.Configure.diagnose >= 30)
            {
              foreach (Suid suid in suidList.suidList)
              {

            {
              Console.WriteLine("SUID filename: " + suid.fileName);
              Console.WriteLine("SUID: " + suid.suid);
              Console.WriteLine("\n");
            }
              }

              Console.WriteLine("fileList.fileList.Count: " + fileList.fileList.Count + "\n");

              foreach (FileObject file in fileList.fileList)
              {

            //Console.WriteLine("Merge Argument count: {0}\n", file.mergeArgument.Count);

            foreach (MergeArgument merge in file.mergeArgument)
            {

              Console.WriteLine("Merge Argument:\nFile name: {0}\nTime Code: {1}\nFile Argument: {2}\nChapter Number: {3}\n",
                  file.filename,
                  merge.timeCode,
                  merge.fileName,
                  merge.chapterNum);

            }

            foreach (TimeCode time in file.timeCode)
            {
              Console.WriteLine("Time Code Argument: {0}\n", time.timeCode);
            }

            foreach (DelArgument del in file.delArgument)
            {
              Console.WriteLine("Del Argument: {0}\n", del.fileName);
            }

              }
            }

            if (Config.Configure.doMakeScript)
            {
              makeFile.makeFile(fileList, processor);

              progressState.progressDetail = "Creating Merge Script...";
              Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);
            }

              }

              if (Config.Configure.doMakeXml)
              {
            makeFile.makeXML(fileList, processor);

            progressState.progressDetail = "Dumping XML file...";
            Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);
              }

              processor.fileLists.Add(fileList);
        }
        /// <summary>
        /// Processes files to create File Objects for the main tasks of this program.
        /// Every tasks are denoted on each comment lines inside the method.
        /// </summary>
        /// <param name="list">The list that contains the fullpaths of the actual files.</param>
        /// <param name="listname">Name for the FileObjectCollection to be created.</param>
        /// <param name="processor">The Analyze object for progression report.</param>
        /// <param name="path">The path used as a working directory merge commands.</param>
        /// <param name="totalArguments">Optional. For progress report. The total number of lists to process.</param>
        public void processList(List <string> list, string listname, Analyze processor, string path = "C:\\", int totalArguments = 0)
        {
            FileObjectCollection fileList      = new FileObjectCollection();
            TrackLister          tracklist     = new TrackLister();
            MakeFile             makeFile      = new MakeFile();
            ChapterGenerator     chapterGet    = new ChapterGenerator();
            ProgressState        progressState = new ProgressState();

            fileList.folderPath = path;
            fileList.name       = listname;

            progressState.listName = fileList.name;

            progress       = 1;
            processPercent = 0;

            foreach (string s in list)
            {
                progressState.progressDetail = "Creating file entry...";

                Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

                FileObject file = new FileObject(s);

                processPercent = progress.ToPercentage(list.Count);
                progressState.progressPercent = processPercent;
                progressState.fileName        = file.filename;
                Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

                //Routine after splitting
                //Checks if current backgroundWorker operation is cancelled
                //Stops this program if true
                if (Analyze.backgroundWorker.CancellationPending)
                {
                    return;
                }

                if (file.extension == ".mkv")
                {
                    try
                    {
                        file = InfoDumper.infoDump(file);
                    }
                    catch (Exception ex)
                    {
                        Program.Message("Error:\r\n\r\n" + ex.Message, "Error");
                    }

                    progressState.progressDetail = "Dumping MKV info...";

                    Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

                    file = chapterGet.chapterDump(file);

                    if (!Config.Configure.includeMkvInfoOnFiles)
                    {
                        file.mkvInfo = null;
                    }

                    if (!Config.Configure.includeMediaInfoOnFiles)
                    {
                        file.ffInfo = null;
                    }

                    progressState.progressDetail = "Getting chapters' info...";

                    Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

                    fileList.hasMKV = true;
                }

                if (Program.hasFFmpeg)
                {
                    progressState.progressDetail = "Dumping media info...";

                    Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

                    try
                    {
                        file = InfoDumper.ffInfoDump(file);
                    }
                    catch (Exception ex)
                    {
                        Program.Message("Error:\r\n\r\n" + ex.Message, "Error");
                    }

                    if (!String.IsNullOrEmpty(file.ffInfo))
                    {
                        file = chapterGet.mediaDump(file);
                    }
                }

                fileList.addFile(file);

                progress++;
            }

            if (fileList.hasMKV)
            {
                SuidLister suidList = CreateSuidLister(fileList);

                progressState.progressDetail = "Creating SUID list...";
                Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

                fileList = tracklist.arrangeTrack(fileList, suidList, processor);

                progressState.progressDetail = "Arranging new tracklist for every file...";
                Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);

                //For Diagnostic purposes only
                if (Config.Configure.diagnose >= 30)
                {
                    foreach (Suid suid in suidList.suidList)
                    {
                        {
                            Console.WriteLine("SUID filename: " + suid.fileName);
                            Console.WriteLine("SUID: " + suid.suid);
                            Console.WriteLine("\n");
                        }
                    }

                    Console.WriteLine("fileList.fileList.Count: " + fileList.fileList.Count + "\n");

                    foreach (FileObject file in fileList.fileList)
                    {
                        //Console.WriteLine("Merge Argument count: {0}\n", file.mergeArgument.Count);

                        foreach (MergeArgument merge in file.mergeArgument)
                        {
                            Console.WriteLine("Merge Argument:\nFile name: {0}\nTime Code: {1}\nFile Argument: {2}\nChapter Number: {3}\n",
                                              file.filename,
                                              merge.timeCode,
                                              merge.fileName,
                                              merge.chapterNum);
                        }

                        foreach (TimeCode time in file.timeCode)
                        {
                            Console.WriteLine("Time Code Argument: {0}\n", time.timeCode);
                        }

                        foreach (DelArgument del in file.delArgument)
                        {
                            Console.WriteLine("Del Argument: {0}\n", del.fileName);
                        }
                    }
                }

                if (Config.Configure.doMakeScript)
                {
                    makeFile.makeFile(fileList, processor);

                    progressState.progressDetail = "Creating Merge Script...";
                    Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);
                }
            }

            if (Config.Configure.doMakeXml)
            {
                makeFile.makeXML(fileList, processor);

                progressState.progressDetail = "Dumping XML file...";
                Analyze.backgroundWorker.ReportProgress(processor.progressArg, progressState);
            }

            processor.fileLists.Add(fileList);
        }
Exemple #5
0
        /// <summary>
        /// Executes merge arguments after ListProcessor has done its job.
        /// </summary>
        /// <param name="fileList">The FileObjectCollection processed by TrackLister.</param>
        /// <param name="processor">The Analyze object for progress reporting.</param>
        /// <param name="useCmd">Deprecated - sets whether to use cmd or not for merge execution.</param>
        /// <param name="fileListPercent">The percentage of File Lists processed. Used for progress reporting.</param>
        public void Merge(FileObjectCollection fileList, Analyze processor, bool useCmd = false, int fileListPercent = 100)
        {
            List <string> cmdCommand    = new List <string>();
            string        splitArgument = "";
            string        mergeArgument = "";
            string        outputPath    = "";

            ProgressState progressState = new ProgressState();

            progressState.listName = fileList.name;

            progress       = 1;
            processPercent = 0;

            /*
             * Legacy code - since the command was just repeated twice below!
             *
             * if (fileList.hasOrdered)
             * {
             * Directory.CreateDirectory(Path.Combine(fileList.folderPath, "output"));
             * }
             *
             * */

            if (!Config.Configure.sourceOutputFolder)
            {
                outputPath = Program.defaultPath;
                if (!Directory.Exists(Path.Combine(outputPath, "merged")))
                {
                    Directory.CreateDirectory(Path.Combine(outputPath, "merged"));
                }
            }

            foreach (FileObject file in fileList.fileList)
            {
                //Routine after merging
                //Checks if current backgroundWorker operation is cancelled
                //Stops this program if true
                if (this.backgroundWorker.CancellationPending)
                {
                    return;
                }

                if (Config.Configure.sourceOutputFolder)
                {
                    outputPath = file.directoryname;
                }

                if (!Directory.Exists(Path.Combine(outputPath, "merged")))
                {
                    Directory.CreateDirectory(Path.Combine(outputPath, "merged"));
                }

                List <string> timeCodeList      = new List <string>();
                List <string> delArgumentList   = new List <string>();
                List <string> mergeArgumentList = new List <string>();
                List <string> chapterInfo       = new List <string>();

                progressState.fileName = file.filename;

                processPercent = progress.ToPercentage(fileList.fileList.Count);
                progressState.progressPercent = processPercent;

                progressState.progressDetail = "";
                this.backgroundWorker.ReportProgress(fileListPercent, progressState);



                /*
                 * Main process
                 * */
                if (file.mergeArgument.Count > 1)
                {
                    foreach (MergeArgument merge in file.mergeArgument)
                    {
                        if (merge.isExternalSuid)
                        {
                            mergeArgumentList.Add("\"" + merge.fullPath + "\"");
                        }
                        else
                        {
                            if (file.splitCount > 1)
                            {
                                mergeArgumentList.Add("\"" + Path.Combine(outputPath, merge.fileName) + "\"");
                            }
                            else
                            {
                                mergeArgumentList.Add("\"" + merge.originalFullPath + "\"");
                            }
                        }
                    }

                    foreach (TimeCode time in file.timeCode)
                    {
                        timeCodeList.Add(time.timeCode);
                    }

                    foreach (DelArgument del in file.delArgument)
                    {
                        delArgumentList.Add("\"" + del.fullPath + "\"");
                    }

                    string[] timeCode     = timeCodeList.ToArray();
                    string[] delString    = delArgumentList.ToArray();
                    string[] mergeString  = mergeArgumentList.ToArray();
                    string[] chaptersInfo = chapterInfo.ToArray();

                    string tempFileName     = "\"" + Config.Configure.tempfileprefix + file.filenameNoExtension + Config.Configure.tempfilesuffix + ".mkv\"";
                    string newFileName      = "\"merged\\" + Config.Configure.newfileprefix + file.filenameNoExtension + Config.Configure.newfilesuffix + ".mkv\"";
                    string originalFileName = "\"" + file.fullpath + "\"";

                    if (file.shouldJoin)
                    {
                        //processor.orderedGroups.Add(outputPath); //should be inside a check outside this loop, else it would add needless duplicates of outputPath


                        if (file.splitCount > 1)
                        {
                            splitArgument = "--no-chapters --split timecodes:" + String.Join(",", timeCode) + " -o " + tempFileName + " " + originalFileName;
                        }

                        mergeArgument = "--no-chapters -o " + newFileName + " " + String.Join(" +", mergeString);
                    }

                    progressState.progressDetail = "Building merge arguments...";
                    this.backgroundWorker.ReportProgress(fileListPercent, progressState);
                }

                //Routine after merge arguments
                //Checks if current backgroundWorker operation is cancelled
                //Stops this program if true
                if (this.backgroundWorker.CancellationPending)
                {
                    return;
                }

                if (file.shouldJoin)
                {
                    ProcessStartInfo mergeProcess = new ProcessStartInfo();

                    mergeProcess.FileName         = Program.mergeExe;
                    mergeProcess.UseShellExecute  = false;
                    mergeProcess.CreateNoWindow   = true;
                    mergeProcess.WorkingDirectory = file.directoryname;
                    mergeProcess.WindowStyle      = ProcessWindowStyle.Hidden;
                    //mergeProcess.RedirectStandardOutput = true;

                    if (file.splitCount > 1)
                    {
                        progressState.progressDetail = "Splitting file...";
                        this.backgroundWorker.ReportProgress(fileListPercent, progressState);

                        mergeProcess.Arguments = splitArgument;

                        using (Process process = Process.Start(mergeProcess))
                        {
                            process.WaitForExit();
                        }
                    }

                    //Routine after splitting
                    //Checks if current backgroundWorker operation is cancelled
                    //Stops this program if true
                    if (this.backgroundWorker.CancellationPending)
                    {
                        foreach (DelArgument del in file.delArgument)
                        {
                            File.Delete(del.fullPath);
                        }

                        return;
                    }

                    progressState.progressDetail = "Merging file...";
                    this.backgroundWorker.ReportProgress(fileListPercent, progressState);

                    mergeProcess.Arguments = mergeArgument;

                    using (Process process = Process.Start(mergeProcess))
                    {
                        process.WaitForExit();
                    }

                    progressState.progressDetail = "Deleting temporary files...";
                    this.backgroundWorker.ReportProgress(fileListPercent, progressState);

                    foreach (DelArgument del in file.delArgument)
                    {
                        File.Delete(del.fullPath);
                    }
                }

                progress++;
            }

            if (fileList.hasOrdered && !Analyze.outputGroups.Contains(outputPath))
            {
                Analyze.outputGroups.Add(outputPath + "\\merged");
            }
        }
        /// <summary>
        /// Main Convert process.
        /// </summary>
        /// <param name="fileList">The FileObjectCollection to process.</param>
        public void Convert(FileObjectCollection fileList, int fileListPercent = 100)
        {
            InitializeConfiguration();

              ProgressState progressState = new ProgressState();
              progressState.listName = fileList.name;

              progress = 1;
              processPercent = 0;

              if (!Config.Configure.sourceOutputFolder)
              {
            outputPath = Program.defaultPath;
            if (!Directory.Exists(Path.Combine(outputPath, "converted")))
              Directory.CreateDirectory(Path.Combine(outputPath, "converted"));
              }

            //Main Loop
              foreach (FileObject file in fileList.fileList)
              {

              //Set Required Variables
            string ffmpegArgs = "";
            string fileVfilter = "";
            string fileVfilterArg = "";
            string fileFFmpegOptions = ffmpegOptions;

            List<string> fileVfilters = new List<string>();

            List<string> fileFilterChains = new List<string>();

            foreach (string vfilteritem in vfilters)
              fileVfilters.Add(vfilteritem);

              //Escape Filter Patterns
            string firstLevel = @"([:\\'])";
            string secondLevel = @"([\[\],;\\'])";

              //Input/Output programmatic patterns
            string custInputPat = @"\(inputfile\)";
            string custOutputPat = @"\(outputname\)";

              //Progress Reporting
            progressState.fileName = file.filename;

            processPercent = progress.ToPercentage(fileList.fileList.Count);
            progressState.progressPercent = processPercent;

            progressState.progressDetail = "Building conversion arguments...";
            this.backgroundWorker.ReportProgress(fileListPercent, progressState);

            if (Config.Configure.sourceOutputFolder)
            {
              outputPath = file.directoryname;
            }

            if (!Directory.Exists(Path.Combine(outputPath, "converted")))
              Directory.CreateDirectory(Path.Combine(outputPath, "converted"));

              //Output File Argument
            string outputFile = outputPath + "\\converted\\" + ConvConfig.newfileprefix + file.filenameNoExtension + ConvConfig.newfilesuffix;

              //Fix_subtitle_duration
            if (ConvConfig.fixsubduration)
              ffmpegArgs += @"-fix_sub_duration ";

              //Subtitles
            //Subfilter
            if (ConvConfig.useSubFilter)
            {
            //Escape any special characters
              string fileitem = file.fullpath;
              fileitem = Regex.Replace(fileitem, firstLevel, m =>
              {
            var escapedChars = m.Groups[1].Value;
            return @"\" + escapedChars;
              });

              fileitem = Regex.Replace(fileitem, secondLevel, n =>
              {
            var escapedChars = n.Groups[1].Value;
            return @"\" + escapedChars;
              });

              fileVfilter = @"subtitles=" + fileitem + @":si=" + ConvConfig.subindex.ToString();
              fileVfilters.Add(fileVfilter);
            }

              //Video Filter
              //Custom Video Filter
            if (!String.IsNullOrWhiteSpace(ConvConfig.customvfilter))
            {
              fileVfilterArg = ConvConfig.customvfilter;
            }
            else
            {
              //filefilterchain.Add(String.Join(",", vfilters.ToArray()));

              fileVfilterArg = String.Join(", ", fileVfilters.ToArray());
            }

            //Diagnostic purposes only
            //fileVfilterArg = "subtitles=D:\\backup\\anime_archive\\[Coalgirls]_Ookami-san,_to;_Shichinin_no_'Nakama-tachi'_(1280x720_Blu-ray_FLAC)\\[Coalgirls]_Ookami-san_to_Shichinin_no_Nakama-tachi_01_(1280x720_Blu-ray_FLAC)_[F9495BFE].mkv:si=0";

            if (!String.IsNullOrWhiteSpace(fileVfilterArg))
            {
              fileVfilterArg = " -vf \"" + fileVfilterArg + "\"";   //Placeholder
              fileFFmpegOptions += fileVfilterArg;
            }

              //Custom ffmpeg options
            if (!String.IsNullOrWhiteSpace(ConvConfig.customffmpegarg))
            {
              string customData = ConvConfig.customffmpegarg;

              //Replace (inputfile) and (outputname) with input and output variables accordingly.
              customData = Regex.Replace(customData, custInputPat, m => { return file.fullpath; });
              customData = Regex.Replace(customData, custOutputPat, m => { return outputFile; });

              ffmpegArgs = customData;
            }
            else
              //Set final ffmpegArgs
              ffmpegArgs += "-i \"" + file.fullpath + "\"" + fileFFmpegOptions + " \"" + outputFile + "." + ConvConfig.format + "\"";

            currentCommand = ffmpegArgs;

             /*
              * Routine before converting
              * Checks if current backgroundWorker operation is cancelled
              * Stops this program if true
              *
              * Process cancelling should be changed as this currently waits for previous conversion to complete;
              * Conversion can take a lot of time for cancellation to wait.
              *
              * Native threading would be used.
              *
              * */
            if (this.backgroundWorker.CancellationPending)
            {
              return;
            }

            if (ConvConfig.showCommands)
            {
              Program.Message("Current command:\r\n\r\n" + currentCommand, "Diagnostics");
            }

              //Main process
            ProcessStartInfo convertProcess = new ProcessStartInfo();

            convertProcess.FileName = Program.ffmpegExe;
            convertProcess.Arguments = ffmpegArgs;

            convertProcess.UseShellExecute = false;

            if (!Config.Configure.ConvertConfigure.showFFmpegWindow) //Added check for diagnostics
            {
              convertProcess.CreateNoWindow = true;
              convertProcess.WindowStyle = ProcessWindowStyle.Hidden;
              convertProcess.RedirectStandardInput = true;  //Preparation for an eminent interactive ffmpeg thread.
            }
            else
            {
              convertProcess.CreateNoWindow = false;
            }
            convertProcess.WorkingDirectory = file.directoryname;

            progressState.progressDetail = "Converting...";
            this.backgroundWorker.ReportProgress(fileListPercent, progressState);

            using (Process process = Process.Start(convertProcess))
            {
              process.WaitForExit();
            }

            //If External subs are set to true.
            if (ConvConfig.externalsubs)
            {
              ffmpegArgs = "-i \"" + file.fullpath + "\" \"" + outputFile + "." + ConvConfig.externalsubsext + "\"";

              currentCommand = ffmpegArgs;

              if (ConvConfig.showCommands)
              {
            Program.Message("Current command:\r\n\r\n" + currentCommand, "Diagnostics");
              }

              convertProcess.Arguments = ffmpegArgs;

              progressState.progressDetail = "Creating external subtitles...";
              this.backgroundWorker.ReportProgress(fileListPercent, progressState);

              using (Process process = Process.Start(convertProcess))
              {
            process.WaitForExit();
              }

            }

            progress++;
              //End of Main process
              }

              if (!Analyze.outputGroups.Contains(outputPath))
              {
            Analyze.outputGroups.Add(outputPath + "\\converted");
              }
        }
        /// <summary>
        /// Executes merge arguments after ListProcessor has done its job.
        /// </summary>
        /// <param name="fileList">The FileObjectCollection processed by TrackLister.</param>
        /// <param name="processor">The Analyze object for progress reporting.</param>
        /// <param name="useCmd">Deprecated - sets whether to use cmd or not for merge execution.</param>
        /// <param name="fileListPercent">The percentage of File Lists processed. Used for progress reporting.</param>
        public void Merge(FileObjectCollection fileList, Analyze processor, bool useCmd = false, int fileListPercent = 100)
        {
            List<string> cmdCommand = new List<string>();
              string splitArgument = "";
              string mergeArgument = "";
              string outputPath = "";

              ProgressState progressState = new ProgressState();
              progressState.listName = fileList.name;

              progress = 1;
              processPercent = 0;

              /*
               * Legacy code - since the command was just repeated twice below!
               *
              if (fileList.hasOrdered)
              {
            Directory.CreateDirectory(Path.Combine(fileList.folderPath, "output"));
              }
               *
               * */

              if (!Config.Configure.sourceOutputFolder)
              {
            outputPath = Program.defaultPath;
            if (!Directory.Exists(Path.Combine(outputPath, "merged")))
              Directory.CreateDirectory(Path.Combine(outputPath, "merged"));
              }

              foreach (FileObject file in fileList.fileList)
              {

              //Routine after merging
              //Checks if current backgroundWorker operation is cancelled
              //Stops this program if true
            if (this.backgroundWorker.CancellationPending)
            {
              return;
            }

            if (Config.Configure.sourceOutputFolder)
            {
              outputPath = file.directoryname;
            }

            if (!Directory.Exists(Path.Combine(outputPath, "merged")))
              Directory.CreateDirectory(Path.Combine(outputPath, "merged"));

            List<string> timeCodeList = new List<string>();
            List<string> delArgumentList = new List<string>();
            List<string> mergeArgumentList = new List<string>();
            List<string> chapterInfo = new List<string>();

            progressState.fileName = file.filename;

            processPercent = progress.ToPercentage(fileList.fileList.Count);
            progressState.progressPercent = processPercent;

            progressState.progressDetail = "";
            this.backgroundWorker.ReportProgress(fileListPercent, progressState);

            /*
              * Main process
              * */
            if (file.mergeArgument.Count > 1)
            {

              foreach (MergeArgument merge in file.mergeArgument)
              {

            if (merge.isExternalSuid)
              mergeArgumentList.Add("\"" + merge.fullPath + "\"");
            else
            {
              if (file.splitCount > 1)
              {
                mergeArgumentList.Add("\"" + Path.Combine(outputPath, merge.fileName) + "\"");
              }
              else
                mergeArgumentList.Add("\"" + merge.originalFullPath + "\"");

            }

              }

              foreach (TimeCode time in file.timeCode)
              {
            timeCodeList.Add(time.timeCode);
              }

              foreach (DelArgument del in file.delArgument)
              {
            delArgumentList.Add("\"" + del.fullPath + "\"");
              }

              string[] timeCode = timeCodeList.ToArray();
              string[] delString = delArgumentList.ToArray();
              string[] mergeString = mergeArgumentList.ToArray();
              string[] chaptersInfo = chapterInfo.ToArray();

              string tempFileName = "\"" + Config.Configure.tempfileprefix + file.filenameNoExtension + Config.Configure.tempfilesuffix + ".mkv\"";
              string newFileName = "\"merged\\" + Config.Configure.newfileprefix + file.filenameNoExtension + Config.Configure.newfilesuffix + ".mkv\"";
              string originalFileName = "\"" + file.fullpath + "\"";

              if (file.shouldJoin)
              {

            //processor.orderedGroups.Add(outputPath); //should be inside a check outside this loop, else it would add needless duplicates of outputPath

            if (file.splitCount > 1)
            {
              splitArgument = "--no-chapters --split timecodes:" + String.Join(",", timeCode) + " -o " + tempFileName + " " + originalFileName;

            }

            mergeArgument = "--no-chapters -o " + newFileName + " " + String.Join(" +", mergeString);

              }

              progressState.progressDetail = "Building merge arguments...";
              this.backgroundWorker.ReportProgress(fileListPercent, progressState);

            }

              //Routine after merge arguments
              //Checks if current backgroundWorker operation is cancelled
              //Stops this program if true
            if (this.backgroundWorker.CancellationPending)
            {
              return;
            }

            if (file.shouldJoin)
            {
              ProcessStartInfo mergeProcess = new ProcessStartInfo();

              mergeProcess.FileName = Program.mergeExe;
              mergeProcess.UseShellExecute = false;
              mergeProcess.CreateNoWindow = true;
              mergeProcess.WorkingDirectory = file.directoryname;
              mergeProcess.WindowStyle = ProcessWindowStyle.Hidden;
              //mergeProcess.RedirectStandardOutput = true;

              if (file.splitCount > 1)
              {
            progressState.progressDetail = "Splitting file...";
            this.backgroundWorker.ReportProgress(fileListPercent, progressState);

            mergeProcess.Arguments = splitArgument;

            using (Process process = Process.Start(mergeProcess))
            {
              process.WaitForExit();
            }

              }

            //Routine after splitting
            //Checks if current backgroundWorker operation is cancelled
            //Stops this program if true
              if (this.backgroundWorker.CancellationPending)
              {
            foreach (DelArgument del in file.delArgument)
              File.Delete(del.fullPath);

            return;
              }

              progressState.progressDetail = "Merging file...";
              this.backgroundWorker.ReportProgress(fileListPercent, progressState);

              mergeProcess.Arguments = mergeArgument;

              using (Process process = Process.Start(mergeProcess))
              {
            process.WaitForExit();
              }

              progressState.progressDetail = "Deleting temporary files...";
              this.backgroundWorker.ReportProgress(fileListPercent, progressState);

              foreach (DelArgument del in file.delArgument)
            File.Delete(del.fullPath);

            }

            progress++;

              }

              if (fileList.hasOrdered && !Analyze.outputGroups.Contains(outputPath))
              {
            Analyze.outputGroups.Add(outputPath + "\\merged");
              }
        }