示例#1
0
        /// <summary>
        /// Convert audio or video to mp3 and display progress dialog.
        /// </summary>
        private bool convertToMp3(string file, string stream, string progressText, DialogProgress dialogProgress,
                                  DateTime entireClipStartTime, DateTime entireClipEndTime, string tempMp3Filename)
        {
            bool status = true;

            DateTime entireClipDuration = UtilsSubs.getDurationTime(entireClipStartTime, entireClipEndTime);

            DialogProgress.updateProgressInvoke(dialogProgress, progressText);

            // Enable detail mode in progress dialog
            DialogProgress.enableDetailInvoke(dialogProgress, true);

            // Set the duration of the clip in the progress dialog  (for detail mode)
            DialogProgress.setDuration(dialogProgress, entireClipDuration);

            // Rip the audio to a temporary mp3 file
            UtilsAudio.ripAudioFromVideo(file,
                                         stream,
                                         entireClipStartTime, entireClipEndTime,
                                         Settings.Instance.AudioClips.Bitrate, tempMp3Filename, dialogProgress);

            DialogProgress.enableDetailInvoke(dialogProgress, false);

            FileInfo fileInfo = new FileInfo(tempMp3Filename);

            // Error if the temporary mp3 file doesn't exist or is zero bytes
            if (!File.Exists(tempMp3Filename) || fileInfo.Length == 0)
            {
                status = false;
            }

            return(status);
        }
示例#2
0
        /// <summary>
        /// Gets called when all subtitle processing is finished (or cancelled).
        /// </summary>
        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (dialogProgress != null)
            {
                dialogProgress.Hide();
                dialogProgress = null;
            }

            if (e.Error != null)
            {
                UtilsMsg.showErrMsg(e.Error.Message);
                return;
            }

            if (e.Cancelled)
            {
                MessageBox.Show("Action cancelled.", UtilsAssembly.Title, MessageBoxButtons.OK,
                                MessageBoxIcon.Exclamation);
                return;
            }

            TimeSpan   workerTotalTime = DateTime.Now - workerStartTime;
            WorkerVars workerVars      = e.Result as WorkerVars;
            string     srsFormat       = getSrsFormatList();
            string     endMessage      = $"Processing completed in {workerTotalTime.TotalMinutes:0.00} minutes.\n\n{srsFormat}";

            UtilsMsg.showInfoMsg(endMessage);
        }
        /// <summary>
        /// Called when the audio extraction thread completes.
        /// </summary>
        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (dialogProgress != null)
            {
                dialogProgress.Hide();
                dialogProgress = null;
            }

            if (e.Error != null)
            {
                UtilsMsg.showErrMsg(e.Error.Message);
                return;
            }

            if (e.Cancelled)
            {
                MessageBox.Show("Action cancelled.", UtilsAssembly.Title, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            TimeSpan workerTotalTime = DateTime.Now - this.workerStartTime;

            WorkerVars workerVars = e.Result as WorkerVars;
            string     endMessage = String.Format("Audio extraction completed in {0:0.00} minutes.",
                                                  workerTotalTime.TotalMinutes);

            UtilsMsg.showInfoMsg(endMessage);
        }
示例#4
0
        /// <summary>
        /// Gets called when all preview's subtitle processing is finished (or cancelled).
        /// </summary>
        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (dialogProgress != null)
            {
                dialogProgress.Hide();
                dialogProgress = null;
            }

            if (e.Error != null)
            {
                UtilsMsg.showErrMsg(e.Error.Message);
                return;
            }

            if (e.Cancelled)
            {
                return;
            }

            WorkerVars workerVars = e.Result as WorkerVars;

            previewWorkerVars = workerVars;

            updateStats();
            populateLinesListView(this.comboBoxEpisode.SelectedIndex);

            Logger.Instance.info("Preview: COMPLETED");
        }
示例#5
0
        /// <summary>
        /// Set the onlyNeededForContext flag for lines that are inactive but needed for context purposes.
        /// Call inactivateLines() before calling this routine.
        /// </summary>
        public List <List <InfoCombined> > markLinesOnlyNeededForContext(WorkerVars workerVars,
                                                                         DialogProgress dialogProgress)
        {
            int totalLines   = 0;
            int progessCount = 0;

            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                totalLines += combArray.Count;
            }

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                // For each line in episode
                for (int lineIdx = 0; lineIdx < combArray.Count; lineIdx++)
                {
                    InfoCombined comb = combArray[lineIdx];
                    progessCount++;

                    if (comb.Active)
                    {
                        // Leading
                        for (int i = Math.Max(0, lineIdx - Settings.Instance.ContextLeadingCount); i < lineIdx; i++)
                        {
                            if (!combArray[i].Active)
                            {
                                combArray[i].OnlyNeededForContext = true;
                            }
                        }

                        // Trailing
                        for (int i = Math.Min(combArray.Count - 1, lineIdx + 1);
                             i < Math.Min(combArray.Count - 1, lineIdx + Settings.Instance.ContextTrailingCount + 1);
                             i++)
                        {
                            if (!combArray[i].Active)
                            {
                                combArray[i].OnlyNeededForContext = true;
                            }
                        }
                    }

                    string progressText =
                        $"Find lines needed for context: {Convert.ToInt32(progessCount * (100.0 / totalLines))}%";

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    if (dialogProgress.Cancel)
                    {
                        return(null);
                    }
                }
            }

            return(workerVars.CombinedAll);
        }
示例#6
0
        /// <summary>
        /// Generate snapshots for all episodes.
        /// </summary>
        public bool genSnapshots(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int      progessCount  = 0;
            int      episodeCount  = 0;
            int      totalEpisodes = workerVars.CombinedAll.Count;
            int      totalLines    = UtilsSubs.getTotalLineCount(workerVars.CombinedAll);
            DateTime lastTime      = UtilsSubs.getLastTime(workerVars.CombinedAll);

            UtilsName name = new UtilsName(Settings.Instance.DeckName, totalEpisodes,
                                           totalLines, lastTime, Settings.Instance.VideoClips.Size.Width,
                                           Settings.Instance.VideoClips.Size.Height);

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                episodeCount++;

                // For each line in episode, generate a snapshot
                foreach (InfoCombined t in combArray)
                {
                    progessCount++;

                    string progressText = $"Generating snapshot: {progessCount.ToString()} of {totalLines.ToString()}";

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    // Update the progress dialog
                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    InfoCombined comb      = t;
                    DateTime     startTime = comb.Subs1.StartTime;
                    DateTime     endTime   = comb.Subs1.EndTime;
                    DateTime     midTime   = UtilsSubs.getMidpointTime(startTime, endTime);

                    string videoFileName = Settings.Instance.VideoClips.Files[episodeCount - 1];

                    // Create output filename
                    string nameStr = name.createName(ConstantSettings.SnapshotFilenameFormat,
                                                     (int)episodeCount + Settings.Instance.EpisodeStartNumber - 1,
                                                     progessCount, startTime, endTime, comb.Subs1.Text, comb.Subs2.Text);

                    string outFile = $"{workerVars.MediaDir}{Path.DirectorySeparatorChar}{nameStr}"; // {2}

                    // Generate snapshot
                    UtilsSnapshot.takeSnapshotFromVideo(videoFileName, midTime, Settings.Instance.Snapshots.Size,
                                                        Settings.Instance.Snapshots.Crop, outFile);

                    // Did the user press the cancel button?
                    if (dialogProgress.Cancel)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
示例#7
0
 public static void setDuration(DialogProgress dialogProgress, DateTime duration)
 {
     // Wait for thread to become avaiable
     if (dialogProgress.IsHandleCreated)
     {
         dialogProgress.Invoke((MethodInvoker) delegate()
         {
             dialogProgress.Duration = duration;
         });
     }
 }
示例#8
0
 public static void enableDetailInvoke(DialogProgress dialogProgress, bool enabled)
 {
     // Wait for thread to become avaiable
     if (dialogProgress.IsHandleCreated)
     {
         dialogProgress.Invoke((MethodInvoker) delegate()
         {
             dialogProgress.DetailedProgress = enabled;
         });
     }
 }
示例#9
0
 public static void updateProgressInvoke(DialogProgress dialogProgress, string text)
 {
     // Wait for thread to become avaiable
     if (dialogProgress.IsHandleCreated)
     {
         dialogProgress.Invoke((MethodInvoker) delegate()
         {
             dialogProgress.updateProgress(text);
         });
     }
 }
示例#10
0
 public static void updateDetailedProgressInvoke(DialogProgress dialogProgress, int progress, InfoFFmpegProgress ffmpegProgress)
 {
     // Wait for thread to become avaiable
     if (dialogProgress.IsHandleCreated)
     {
         dialogProgress.Invoke((MethodInvoker) delegate()
         {
             dialogProgress.updateDetailedProgress(progress, ffmpegProgress);
         });
     }
 }
示例#11
0
 public static void nextStepInvoke(DialogProgress dialogProgress, int step, string stepName)
 {
     // Wait for thread to become avaiable
     if (dialogProgress.IsHandleCreated)
     {
         dialogProgress.Invoke((MethodInvoker) delegate()
         {
             dialogProgress.StepName     = stepName;
             dialogProgress.StepsCurrent = step;
         });
     }
 }
示例#12
0
        public static DataReceivedEventHandler getFFmpegOutputHandler(DialogProgress dialogProgress)
        {
            DataReceivedEventHandler outHandler = null;

            // Wait for thread to become avaiable
            if (dialogProgress.IsHandleCreated)
            {
                dialogProgress.Invoke((MethodInvoker) delegate()
                {
                    outHandler = dialogProgress.FFmpegOutputHandler;
                });
            }

            return(outHandler);
        }
示例#13
0
        public static bool getCancelInvoke(DialogProgress dialogProgress)
        {
            bool cancelState = false;

            // Wait for thread to become avaiable
            if (dialogProgress.IsHandleCreated)
            {
                dialogProgress.Invoke((MethodInvoker) delegate()
                {
                    cancelState = dialogProgress.Cancel;
                });
            }

            return(cancelState);
        }
示例#14
0
        /// <summary>
        /// Start the processing in a seperate thread.
        /// If combinedAll is not null, use it rather then generating a new combinedAll.
        /// </summary>
        public void start(List <List <InfoCombined> > combinedAll)
        {
            // Create directory stucture
            try
            {
                createOutputDirStructure();
            }
            catch
            {
                UtilsMsg.showErrMsg("Cannot write to output directory. \nTry checking the directory's permissions.");
                return;
            }

            Logger.Instance.info("SubsProcessor.start");
            Logger.Instance.writeSettingsToLog();

            // Start the worker thread
            try
            {
                WorkerVars workerVars = new WorkerVars(combinedAll,
                                                       getMediaDir(Settings.Instance.OutputDir, Settings.Instance.DeckName),
                                                       WorkerVars.SubsProcessingType.Normal);

                // Create a background thread
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork             += new DoWorkEventHandler(bw_DoWork);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

                // Create a progress dialog on the UI thread
                dialogProgress            = new DialogProgress();
                currentStep               = 0;
                dialogProgress.StepsTotal = determineNumSteps(combinedAll);

                workerStartTime = DateTime.Now;
                bw.RunWorkerAsync(workerVars);

                // Lock up the UI with this modal progress form
                dialogProgress.ShowDialog();
                dialogProgress = null;
            }
            catch (Exception e1)
            {
                UtilsMsg.showErrMsg("Something went wrong before processing could start.\n" + e1);
                return;
            }
        }
示例#15
0
        public void ffmpegOutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            if (!String.IsNullOrEmpty(outLine.Data))
            {
                InfoFFmpegProgress ffmpegProgress = new InfoFFmpegProgress();

                bool parseSuccess = ffmpegProgress.parseFFmpegProgress(outLine.Data);

                if (parseSuccess)
                {
                    int progress = (int)((ffmpegProgress.Time.TimeOfDay.TotalMilliseconds / Math.Max(1, Duration.TimeOfDay.TotalMilliseconds)) * 100);

                    DialogProgress.updateDetailedProgressInvoke(this, progress, ffmpegProgress);

                    // Debug
                    //TextWriter writer = new StreamWriter("ffmpeg_output.txt", true, Encoding.UTF8);
                    //writer.WriteLine(outLine.Data);
                    //writer.WriteLine(String.Format("Progress: {0:00}", progress));
                    //writer.Close();
                }
            }
        }
        /// <summary>
        /// Extract the audio from the media.
        /// </summary>
        private void buttonExtract_Click(object sender, EventArgs e)
        {
            errorProvider1.Clear();

            if (validateForm())
            {
                updateSettings();

                Logger.Instance.info("Extract Audio From Media: GO!");
                Logger.Instance.writeSettingsToLog();

                // Start the worker thread
                try
                {
                    WorkerVars workerVars = new WorkerVars(null, Settings.Instance.OutputDir, WorkerVars.SubsProcessingType.Normal);

                    // Create a background thread
                    BackgroundWorker bw = new BackgroundWorker();
                    bw.DoWork             += new DoWorkEventHandler(splitAudio);
                    bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

                    // Create a progress dialog on the UI thread
                    dialogProgress = new DialogProgress();

                    this.workerStartTime = DateTime.Now;
                    bw.RunWorkerAsync(workerVars);

                    // Lock up the UI with this modal progress form
                    dialogProgress.ShowDialog();
                    dialogProgress = null;
                }
                catch (Exception e1)
                {
                    UtilsMsg.showErrMsg("Something went wrong before processing could start.\n" + e1);
                    return;
                }
            }
        }
示例#17
0
        /// <summary>
        /// Called when the Dueling Subtitles creation thread completes.
        /// </summary>
        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (dialogProgress != null)
            {
                dialogProgress.Hide();
                dialogProgress = null;
            }

            if (e.Error != null)
            {
                UtilsMsg.showErrMsg(e.Error.Message);
                return;
            }

            if (e.Cancelled)
            {
                MessageBox.Show("Action cancelled.", UtilsAssembly.Title, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                return;
            }

            WorkerVars workerVars = e.Result as WorkerVars;

            UtilsMsg.showInfoMsg("Dueling subtitles have been created successfully.");
        }
示例#18
0
        /// <summary>
        /// Pair lines from Subs1 to Subs2.
        ///
        /// Subs2srs takes a two-pass approach when it combines Subs1 and Subs2. The first pass matches a line from
        /// Subs1 to the closest line in Subs2. Closest here meaning the difference in start times. This will work fine
        /// assuming that both Subs1 and Subs2 have the exact same number of lines and that lines are similarly timed.
        /// Naturally, this is almost never the case. The result being that some lines will be skipped and others repeated.
        /// The second pass adds back in any lines that were skipped by combining them with others lines and doesn't allow
        /// the same line to be repeated.
        ///
        /// This is used by the Main Dialog, Preview, Dueling Subtitles tools, and Extract Audio from Media Tool.
        /// </summary>
        public List <List <InfoCombined> > combineAllSubs(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            List <List <InfoCombined> > combinedAll = new List <List <InfoCombined> >();
            int totalEpisodes = Settings.Instance.Subs[0].Files.Length;

            // For each episode
            for (int epIdx = 0; epIdx < totalEpisodes; epIdx++)
            {
                SubsParser      subs1Parser          = null;
                SubsParser      subs2Parser          = null;
                List <InfoLine> subs1LineInfos       = null;
                List <InfoLine> subs2LineInfos       = null;
                string          curSub1File          = Settings.Instance.Subs[0].Files[epIdx];
                string          curSub2File          = "";
                bool            subs1ContainsVobsubs = UtilsSubs.filePatternContainsVobsubs(Settings.Instance.Subs[0].FilePattern);
                bool            subs2ContainsVobsubs = UtilsSubs.filePatternContainsVobsubs(Settings.Instance.Subs[1].FilePattern);

                string progressText = $"Processing subtitles for episode {epIdx + 1} of {totalEpisodes}";

                if (subs1ContainsVobsubs || subs2ContainsVobsubs)
                {
                    progressText += "\nNote: Vobsubs (.idx/.sub) can take a few moments to process.";
                }

                int progress = Convert.ToInt32((epIdx + 1) * (100.0 / totalEpisodes));

                DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                int streamSubs1 = 0;
                int streamSubs2 = 0;

                // In the subtitles are in Vobsub format, get the stream to use
                if (subs1ContainsVobsubs)
                {
                    streamSubs1 = Convert.ToInt32(Settings.Instance.Subs[0].VobsubStream.Num);
                }

                if (subs2ContainsVobsubs)
                {
                    streamSubs2 = Convert.ToInt32(Settings.Instance.Subs[1].VobsubStream.Num);
                }

                // Parse Subs1
                subs1Parser = UtilsSubs.getSubtitleParserType(workerVars, curSub1File, streamSubs1,
                                                              epIdx + Settings.Instance.EpisodeStartNumber, 1,
                                                              Encoding.GetEncoding(Settings.Instance.Subs[0].Encoding));

                Logger.Instance.writeFileToLog(curSub1File, Encoding.GetEncoding(Settings.Instance.Subs[0].Encoding));

                subs1LineInfos = subs1Parser.parse();

                if (subs1LineInfos == null)
                {
                    return(null);
                }

                subs1LineInfos = removeIncorrectlyTimedLines(subs1LineInfos);

                if (Settings.Instance.Subs[0].JoinSentencesEnabled && !subs1ContainsVobsubs)
                {
                    subs1LineInfos = combinePartialLinesIntoSentence(subs1LineInfos,
                                                                     Settings.Instance.Subs[0].JoinSentencesCharList);
                }

                // Apply Subs1 time shift
                if (Settings.Instance.TimeShiftEnabled)
                {
                    foreach (InfoLine line in subs1LineInfos)
                    {
                        line.StartTime = UtilsSubs.shiftTiming(line.StartTime, Settings.Instance.Subs[0].TimeShift);
                        line.EndTime   = UtilsSubs.shiftTiming(line.EndTime, Settings.Instance.Subs[0].TimeShift);
                    }
                }

                // Parse Subs2 (if needed)
                if (Settings.Instance.Subs[1].Files.Length != 0)
                {
                    curSub2File = Settings.Instance.Subs[1].Files[epIdx];
                    subs2Parser = UtilsSubs.getSubtitleParserType(workerVars, curSub2File, streamSubs2,
                                                                  epIdx + Settings.Instance.EpisodeStartNumber, 2,
                                                                  Encoding.GetEncoding(Settings.Instance.Subs[1].Encoding));

                    Logger.Instance.writeFileToLog(curSub2File,
                                                   Encoding.GetEncoding(Settings.Instance.Subs[1].Encoding));

                    subs2LineInfos = subs2Parser.parse();

                    if (subs2LineInfos == null)
                    {
                        return(null);
                    }

                    subs2LineInfos = removeIncorrectlyTimedLines(subs2LineInfos);

                    if (Settings.Instance.Subs[1].JoinSentencesEnabled && !subs2ContainsVobsubs)
                    {
                        subs2LineInfos = combinePartialLinesIntoSentence(subs2LineInfos,
                                                                         Settings.Instance.Subs[1].JoinSentencesCharList);
                    }

                    // Apply Subs2 time shift
                    if (Settings.Instance.TimeShiftEnabled)
                    {
                        foreach (InfoLine line in subs2LineInfos)
                        {
                            line.StartTime = UtilsSubs.shiftTiming(line.StartTime, Settings.Instance.Subs[1].TimeShift);
                            line.EndTime   = UtilsSubs.shiftTiming(line.EndTime, Settings.Instance.Subs[1].TimeShift);
                        }
                    }
                }
                else
                {
                    subs2LineInfos = subs1LineInfos;
                }

                // Pass 1: Match each Subs1 to the closest Subs2
                List <InfoCombined> combinedSubs = pass1CombineSubs(subs1LineInfos, subs2LineInfos);

                if (dialogProgress.Cancel)
                {
                    return(null);
                }


                // Pass 2: Fix mismatches present after Pass 1.
                if (Settings.Instance.Subs[1].Files.Length != 0)
                {
                    combinedSubs = pass2FixMismatches(combinedSubs, subs2LineInfos);

                    if (dialogProgress.Cancel)
                    {
                        return(null);
                    }
                }

                // Adjust the timings based on user preference
                foreach (InfoCombined comb in combinedSubs)
                {
                    // Use Subs2 timings?
                    if (Settings.Instance.Subs[1].TimingsEnabled)
                    {
                        // Important Note:
                        // The rest of the software uses subs1 for timing, so just cram subs2 timings into subs1
                        comb.Subs1.StartTime = comb.Subs2.StartTime;
                        comb.Subs1.EndTime   = comb.Subs2.EndTime;
                    }
                }

                if (dialogProgress.Cancel)
                {
                    return(null);
                }

                // Add this episode's paired lines
                combinedAll.Add(combinedSubs);
            }

            return(combinedAll);
        }
示例#19
0
        /// <summary>
        /// Generate the preview in seperate thread.
        /// </summary>
        private void generatePreview()
        {
            // Fire event to tell MainForm to update the settings
            if (GeneretePreview != null)
            {
                GeneretePreview(this, EventArgs.Empty);
            }

            populateEpisodeComboBox();

            string tempPreviewDir = Path.GetTempPath() + ConstantSettings.TempPreviewDirName;

            if (Directory.Exists(tempPreviewDir))
            {
                try
                {
                    Directory.Delete(tempPreviewDir, true);
                }
                catch
                {
                    //UtilsMsg.showErrMsg("Unable to delete the temporary directory at:\n" + tempPreviewDir);
                }
            }

            // Create the temporary directory
            try
            {
                Directory.CreateDirectory(tempPreviewDir);
            }
            catch
            {
                UtilsMsg.showErrMsg("Cannot write to " + tempPreviewDir + "\nTry checking the directory's permissions.");
                return;
            }

            Logger.Instance.info("Preview: GO!");
            Logger.Instance.writeSettingsToLog();

            // Start the worker thread
            try
            {
                WorkerVars workerVars = new WorkerVars(null, tempPreviewDir, WorkerVars.SubsProcessingType.Preview);

                // Create a background thread
                BackgroundWorker bw = new BackgroundWorker();
                bw.DoWork             += new DoWorkEventHandler(bw_DoWork);
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

                // Create a progress dialog on the UI thread
                dialogProgress = new DialogProgress();

                bw.RunWorkerAsync(workerVars);

                // Lock up the UI with this modal progress form
                dialogProgress.ShowDialog();
                dialogProgress = null;
            }
            catch (Exception e1)
            {
                UtilsMsg.showErrMsg("Something went wrong before preview could be generated.\n" + e1);
                return;
            }
        }
示例#20
0
        /// <summary>
        /// Generate the SRS import file.
        /// </summary>
        public bool genSrs(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int episodeIdx    = -1;
            int totalEpisodes = workerVars.CombinedAll.Count;
            int lineIdx       = -1;
            int totalLines    = UtilsSubs.getTotalLineCount(workerVars.CombinedAll);

            lastTime = UtilsSubs.getLastTime(workerVars.CombinedAll);

            name = new UtilsName(Settings.Instance.DeckName, totalEpisodes,
                                 totalLines, lastTime, Settings.Instance.VideoClips.Size.Width,
                                 Settings.Instance.VideoClips.Size.Height);

            string nameStr = name.createName(ConstantSettings.SrsFilenameFormat, 0,
                                             0, new DateTime(), new DateTime(), "", "");

            // Create filename
            // Example: <outdir>\Toki_wo_Kakeru_Shoujo.tsv
            string     srsFilename = $"{Settings.Instance.OutputDir}{Path.DirectorySeparatorChar}{nameStr}";
            TextWriter srsWriter   = new StreamWriter(srsFilename, false, Encoding.UTF8);

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                episodeIdx++;
                lineIdx = -1;

                // For each line in episode, process
                foreach (InfoCombined comb in combArray)
                {
                    progessCount++;
                    lineIdx++;
                    mainComb = comb;

                    // Skip lines that are only needed for context
                    if (mainComb.OnlyNeededForContext)
                    {
                        continue;
                    }

                    string srsLine = "";

                    // Format the current import file line
                    srsLine = formatAll(workerVars.CombinedAll, episodeIdx, lineIdx, FormatType.Normal);

                    // Add leading context lines
                    if (Settings.Instance.ContextLeadingCount > 0)
                    {
                        for (int i = Settings.Instance.ContextLeadingCount; i > 0; i--)
                        {
                            int prevLineIdx = lineIdx - i;

                            if (prevLineIdx >= 0)
                            {
                                if (isLineInContextRange(combArray, lineIdx, prevLineIdx))
                                {
                                    srsLine += formatAll(workerVars.CombinedAll, episodeIdx, prevLineIdx,
                                                         FormatType.Leading);
                                }
                                else
                                {
                                    srsLine += formatContextPlaceholder(FormatType.Leading);
                                }
                            }
                            else
                            {
                                srsLine += formatContextPlaceholder(FormatType.Leading);
                            }
                        }
                    }

                    // Add trailing context lines
                    if (Settings.Instance.ContextTrailingCount > 0)
                    {
                        for (int i = 1; i <= Settings.Instance.ContextTrailingCount; i++)
                        {
                            int nextLineIdx = lineIdx + i;

                            if (nextLineIdx < combArray.Count)
                            {
                                if (isLineInContextRange(combArray, lineIdx, nextLineIdx))
                                {
                                    srsLine += formatAll(workerVars.CombinedAll, episodeIdx, nextLineIdx,
                                                         FormatType.Trailing);
                                }
                                else
                                {
                                    srsLine += formatContextPlaceholder(FormatType.Trailing);
                                }
                            }
                            else
                            {
                                srsLine += formatContextPlaceholder(FormatType.Trailing);
                            }
                        }
                    }

                    // Write line to file
                    srsWriter.WriteLine(srsLine);

                    string progressText =
                        $"Generating SRS (ex. Anki) import file: line {progessCount.ToString()} of {totalLines.ToString()}";

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    // Did the user press the cancel button?
                    if (dialogProgress.Cancel)
                    {
                        srsWriter.Close();
                        return(false);
                    }
                }
            }

            srsWriter.Close();

            return(true);
        }
示例#21
0
        /// <summary>
        /// Call ffmpeg with provided arguments and update the progress dialog.
        /// No windows will popup. If Cancel is pressed in the progress dialog, the process will be killed.
        /// </summary>
        static public void startFFmpegProgress(string ffmpegAudioProgArgs, DialogProgress dialogProgress)
        {
            Process ffmpegProcess   = new Process();
            bool    tryAgain        = true;
            bool    useShellExecute = false;
            bool    createNoWindow  = true;

            // Try several different ways of calling ffmpeg because of the dreaded
            // "System.ComponentModel.Win32Exception: The system cannot find the drive specified" exception

            // Try relative path from subs2srs.exe
            try
            {
                ffmpegProcess.StartInfo.FileName              = ConstantSettings.PathFFmpegExe;
                ffmpegProcess.StartInfo.Arguments             = ffmpegAudioProgArgs;
                ffmpegProcess.StartInfo.UseShellExecute       = useShellExecute;
                ffmpegProcess.StartInfo.CreateNoWindow        = createNoWindow;
                ffmpegProcess.StartInfo.RedirectStandardError = true;
                ffmpegProcess.ErrorDataReceived += new DataReceivedEventHandler(DialogProgress.getFFmpegOutputHandler(dialogProgress));
                ffmpegProcess.Start();
                ffmpegProcess.BeginErrorReadLine();

                // Loop until process has exited
                while (!ffmpegProcess.HasExited)
                {
                    Thread.Sleep(100);

                    // If the Cancel button was pressed
                    if (DialogProgress.getCancelInvoke(dialogProgress))
                    {
                        try
                        {
                            ffmpegProcess.Kill();
                        }
                        catch
                        {
                            // Don't care
                        }

                        break;
                    }
                }

                tryAgain = false;
            }
            catch
            {
                try
                {
                    ffmpegProcess.Kill();
                }
                catch
                {
                    // Dont care
                }

                tryAgain = true;
            }

            // Try absolute path to ffmpeg.exe
            if (tryAgain)
            {
                ffmpegProcess = new Process();

                try
                {
                    ffmpegProcess.StartInfo.FileName              = ConstantSettings.PathFFmpegFullExe;
                    ffmpegProcess.StartInfo.Arguments             = ffmpegAudioProgArgs;
                    ffmpegProcess.StartInfo.UseShellExecute       = useShellExecute;
                    ffmpegProcess.StartInfo.CreateNoWindow        = createNoWindow;
                    ffmpegProcess.StartInfo.RedirectStandardError = true;
                    ffmpegProcess.ErrorDataReceived += new DataReceivedEventHandler(DialogProgress.getFFmpegOutputHandler(dialogProgress));
                    ffmpegProcess.Start();
                    ffmpegProcess.BeginErrorReadLine();

                    // Loop until process has exited
                    while (!ffmpegProcess.HasExited)
                    {
                        Thread.Sleep(100);

                        // If the Cancel button was pressed
                        if (DialogProgress.getCancelInvoke(dialogProgress))
                        {
                            try
                            {
                                ffmpegProcess.Kill();
                            }
                            catch
                            {
                                // Don't care
                            }

                            break;
                        }
                    }

                    tryAgain = false;
                }
                catch (Exception)
                {
                    try
                    {
                        ffmpegProcess.Kill();
                    }
                    catch
                    {
                        // Dont care
                    }

                    tryAgain = true;
                }
            }

            // Try setting PATH to include the absolute path of ffmpeg.exe
            if (tryAgain)
            {
                try
                {
                    string oldPath   = Environment.GetEnvironmentVariable("Path");
                    string ffmpegDir = Path.GetDirectoryName(ConstantSettings.PathFFmpegFullExe);

                    if (!oldPath.Contains(ffmpegDir))
                    {
                        string newPath = oldPath + ";" + ffmpegDir;
                        Environment.SetEnvironmentVariable("Path", newPath);
                    }

                    ffmpegProcess = new Process();

                    ffmpegProcess.StartInfo.FileName              = ConstantSettings.ExeFFmpeg;
                    ffmpegProcess.StartInfo.Arguments             = ffmpegAudioProgArgs;
                    ffmpegProcess.StartInfo.UseShellExecute       = useShellExecute;
                    ffmpegProcess.StartInfo.CreateNoWindow        = createNoWindow;
                    ffmpegProcess.StartInfo.RedirectStandardError = true;
                    ffmpegProcess.ErrorDataReceived += new DataReceivedEventHandler(DialogProgress.getFFmpegOutputHandler(dialogProgress));
                    ffmpegProcess.Start();
                    ffmpegProcess.BeginErrorReadLine();

                    // Loop until process has exited
                    while (!ffmpegProcess.HasExited)
                    {
                        Thread.Sleep(100);

                        // If the Cancel button was pressed
                        if (DialogProgress.getCancelInvoke(dialogProgress))
                        {
                            try
                            {
                                ffmpegProcess.Kill();
                            }
                            catch
                            {
                                // Don't care
                            }

                            break;
                        }
                    }
                }
                catch
                {
                    // Don't care
                }
            }
        }
示例#22
0
        /// <summary>
        /// Rip (and re-encode) a portion of the audio from a video file.
        /// </summary>
        public static void ripAudioFromVideo(string inFile, string stream, DateTime startTime,
                                             DateTime endTime, int bitrate, string outFile, DialogProgress dialogProgress)
        {
            string audioBitrateArg = UtilsVideo.formatAudioBitrateArg(bitrate);
            string audioMapArg     = UtilsVideo.formatAudioMapArg(stream);
            string timeArg         = UtilsVideo.formatStartTimeAndDurationArg(startTime, endTime);

            string ffmpegAudioProgArgs = "";

            // Example format:
            // -vn -y -i "G:\Temp\inputs.mkv" -ac 2 -map 0:1 -ss 00:03:32.420 -t 00:02:03.650 -b:a 128k -threads 0 "output.mp3"
            ffmpegAudioProgArgs =
                $"-vn -y -i \"{inFile}\" -ac 2 {audioMapArg} {timeArg} {audioBitrateArg} -threads 0 \"{outFile}\""; // {4}

            if (dialogProgress == null)
            {
                UtilsCommon.startFFmpeg(ffmpegAudioProgArgs, false, true);
            }
            else
            {
                UtilsCommon.startFFmpegProgress(ffmpegAudioProgArgs, dialogProgress);
            }
        }
示例#23
0
        /// <summary>
        /// Rip (and re-encode) a portion of the audio from a video file.
        /// </summary>
        public static void ripAudioFromVideo(string inFile, string stream, DateTime startTime,
                                             DateTime endTime, int bitrate, string outFile, DialogProgress dialogProgress)
        {
            string audioBitrateArg = UtilsVideo.formatAudioBitrateArg(bitrate);
            string audioMapArg     = UtilsVideo.formatAudioMapArg(stream);
            string timeArg         = UtilsVideo.formatStartTimeAndDurationArg(startTime, endTime);

            string ffmpegAudioProgArgs = "";

            // Example format:
            // -vn -y -i "G:\Temp\inputs.mkv" -ac 2 -map 0:1 -ss 00:03:32.420 -t 00:02:03.650 -b:a 128k -threads 0 "output.mp3"
            ffmpegAudioProgArgs = String.Format("-vn -y -i \"{0}\" -ac 2 {1} {2} {3} -threads 0 \"{4}\"",
                                                                 // Video file
                                                inFile,          // {0}

                                                                 // Mapping
                                                audioMapArg,     // {1}

                                                                 // Time span
                                                timeArg,         // {2}

                                                                 // Bitrate
                                                audioBitrateArg, // {3}

                                                                 // Output file name
                                                outFile);        // {4}

            if (dialogProgress == null)
            {
                UtilsCommon.startFFmpeg(ffmpegAudioProgArgs, false, true);
            }
            else
            {
                UtilsCommon.startFFmpegProgress(ffmpegAudioProgArgs, dialogProgress);
            }
        }
示例#24
0
        /// <summary>
        /// Performs the work in the processing thread.
        /// </summary>
        private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            WorkerVars workerVars = e.Argument as WorkerVars;
            List <List <InfoCombined> > combinedAll = new List <List <InfoCombined> >();
            WorkerSubs subsWorker = new WorkerSubs();
            int        totalLines = 0;
            bool       needToGenerateCombinedAll = workerVars.CombinedAll == null;

            // Only generate a combinedAll if one if not provided
            if (needToGenerateCombinedAll)
            {
                // Parse and combine the subtitles
                try
                {
                    DialogProgress.nextStepInvoke(dialogProgress, ++currentStep, "Combine subs");

                    combinedAll = subsWorker.combineAllSubs(workerVars, dialogProgress);

                    if (combinedAll != null)
                    {
                        workerVars.CombinedAll = combinedAll;
                    }
                    else
                    {
                        e.Cancel = true;
                        return;
                    }
                }
                catch (Exception e1)
                {
                    UtilsMsg.showErrMsg("Something went wrong before processing could start.\n" + e1);
                    e.Cancel = true;
                    return;
                }

                foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
                {
                    totalLines += combArray.Count;
                }

                if (totalLines == 0)
                {
                    UtilsMsg.showErrMsg(
                        "No lines of dialog could be parsed from the subtitle files.\nPlease check that they are valid.");
                    e.Cancel = true;
                    return;
                }

                // Inactivate lines
                try
                {
                    DialogProgress.nextStepInvoke(dialogProgress, ++currentStep, "Inactivate lines");

                    combinedAll = subsWorker.inactivateLines(workerVars, dialogProgress);

                    if (combinedAll != null)
                    {
                        workerVars.CombinedAll = combinedAll;
                    }
                    else
                    {
                        e.Cancel = true;
                        return;
                    }
                }
                catch (Exception e1)
                {
                    UtilsMsg.showErrMsg("Something went wrong while setting active lines.\n" + e1);
                    e.Cancel = true;
                    return;
                }
            }

            // Find context lines
            if (Settings.Instance.ContextLeadingCount > 0 || Settings.Instance.ContextTrailingCount > 0)
            {
                try
                {
                    DialogProgress.nextStepInvoke(dialogProgress, ++currentStep, "Find context lines");

                    combinedAll = subsWorker.markLinesOnlyNeededForContext(workerVars, dialogProgress);

                    if (combinedAll != null)
                    {
                        workerVars.CombinedAll = combinedAll;
                    }
                    else
                    {
                        e.Cancel = true;
                        return;
                    }
                }
                catch (Exception e1)
                {
                    UtilsMsg.showErrMsg("Something went wrong while finding context lines.\n" + e1);
                    e.Cancel = true;
                    return;
                }
            }

            // Remove Inactive lines (unless they are needed for context)
            try
            {
                DialogProgress.nextStepInvoke(dialogProgress, ++currentStep, "Remove inactive lines");

                combinedAll = subsWorker.removeInactiveLines(workerVars, dialogProgress, true);

                if (combinedAll != null)
                {
                    workerVars.CombinedAll = combinedAll;
                }
                else
                {
                    e.Cancel = true;
                    return;
                }
            }
            catch (Exception e1)
            {
                UtilsMsg.showErrMsg("Something went wrong while removing inactive lines.\n" + e1);
                e.Cancel = true;
                return;
            }

            totalLines = 0;
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                totalLines += combArray.Count;
            }

            if (totalLines == 0)
            {
                UtilsMsg.showErrMsg(
                    "No lines will be processed. Please check your settings to make\nsure that you are not mistakenly pruning too many lines.");
                e.Cancel = true;
                return;
            }

            try
            {
                // Move vobsubs from preview dir to .media dir
                if (!needToGenerateCombinedAll)
                {
                    if (!subsWorker.copyVobsubsFromPreviewDirToMediaDir(workerVars, dialogProgress))
                    {
                        e.Cancel = true;
                        return;
                    }
                }
            }
            catch
            {
            }

            // Generate SRS import file
            try
            {
                DialogProgress.nextStepInvoke(dialogProgress, ++currentStep, "Generate import file");

                WorkerSrs srsWorker = new WorkerSrs();

                if (!srsWorker.genSrs(workerVars, dialogProgress))
                {
                    e.Cancel = true;
                    return;
                }
            }
            catch (Exception e1)
            {
                UtilsMsg.showErrMsg("Something went wrong while generating the SRS import file.\n" + e1);
                e.Cancel = true;
                return;
            }

            List <List <InfoCombined> > combinedAllWithContext =
                ObjectCopier.Clone <List <List <InfoCombined> > >(workerVars.CombinedAll);

            // Generate audio clips
            try
            {
                if (Settings.Instance.AudioClips.Enabled)
                {
                    DialogProgress.nextStepInvoke(dialogProgress, ++currentStep, "Generate audio clips");

                    if (Settings.Instance.ContextLeadingCount > 0 &&
                        Settings.Instance.ContextLeadingIncludeAudioClips ||
                        Settings.Instance.ContextTrailingCount > 0 &&
                        Settings.Instance.ContextTrailingIncludeAudioClips)
                    {
                        workerVars.CombinedAll = combinedAllWithContext;
                    }
                    else
                    {
                        workerVars.CombinedAll = subsWorker.removeContextOnlyLines(combinedAllWithContext);
                    }

                    WorkerAudio audioWorker = new WorkerAudio();

                    if (!audioWorker.genAudioClip(workerVars, dialogProgress))
                    {
                        e.Cancel = true;
                        return;
                    }
                }
            }
            catch (Exception e1)
            {
                UtilsMsg.showErrMsg("Something went wrong while generating the audio clips.\n" + e1);
                e.Cancel = true;
                return;
            }

            // Generate Snapshots
            try
            {
                if (Settings.Instance.Snapshots.Enabled)
                {
                    DialogProgress.nextStepInvoke(dialogProgress, ++currentStep, "Generate snapshots");

                    if (Settings.Instance.ContextLeadingCount > 0 &&
                        Settings.Instance.ContextLeadingIncludeSnapshots ||
                        Settings.Instance.ContextTrailingCount > 0 &&
                        Settings.Instance.ContextTrailingIncludeSnapshots)
                    {
                        workerVars.CombinedAll = combinedAllWithContext;
                    }
                    else
                    {
                        workerVars.CombinedAll = subsWorker.removeContextOnlyLines(combinedAllWithContext);
                    }

                    WorkerSnapshot snapshotWorker = new WorkerSnapshot();

                    if (!snapshotWorker.genSnapshots(workerVars, dialogProgress))
                    {
                        e.Cancel = true;
                        return;
                    }
                }
            }
            catch (Exception e1)
            {
                UtilsMsg.showErrMsg("Something went wrong while generating snapshots.\n" + e1);
                e.Cancel = true;
                return;
            }

            // Generate video clips
            try
            {
                if (Settings.Instance.VideoClips.Enabled)
                {
                    DialogProgress.nextStepInvoke(dialogProgress, ++currentStep, "Generate video clips");

                    if (Settings.Instance.ContextLeadingCount > 0 &&
                        Settings.Instance.ContextLeadingIncludeVideoClips ||
                        Settings.Instance.ContextTrailingCount > 0 &&
                        Settings.Instance.ContextTrailingIncludeVideoClips)
                    {
                        workerVars.CombinedAll = combinedAllWithContext;
                    }
                    else
                    {
                        workerVars.CombinedAll = subsWorker.removeContextOnlyLines(combinedAllWithContext);
                    }

                    WorkerVideo videoWorker = new WorkerVideo();

                    if (!videoWorker.genVideoClip(workerVars, dialogProgress))
                    {
                        e.Cancel = true;
                        return;
                    }
                }
            }
            catch (Exception e1)
            {
                UtilsMsg.showErrMsg("Something went wrong while generating the video clips.\n" + e1);
                e.Cancel = true;
                return;
            }

            e.Result = workerVars;
        }
        /// <summary>
        /// Performs the work of the audio extraction thread.
        /// </summary>
        private void splitAudio(object sender, DoWorkEventArgs e)
        {
            WorkerVars workerVars = e.Argument as WorkerVars;
            List <List <InfoCombined> > combinedAll = new List <List <InfoCombined> >();
            WorkerSubs subsWorker = new WorkerSubs();

            if (groupBoxCheckLyrics.Checked)
            {
                // Parse and combine the subtitles
                try
                {
                    combinedAll = subsWorker.combineAllSubs(workerVars, dialogProgress);

                    if (combinedAll != null)
                    {
                        workerVars.CombinedAll = combinedAll;
                    }
                    else
                    {
                        e.Cancel = true;
                        return;
                    }
                }
                catch (Exception e1)
                {
                    UtilsMsg.showErrMsg("Something went wrong before processing could start.\n" + e1);
                    e.Cancel = true;
                    return;
                }
            }

            DateTime mediaStartime = new DateTime();
            DateTime mediaEndtime  = new DateTime();
            DateTime mediaDuration = new DateTime();

            int episode = 0;

            DialogProgress.updateProgressInvoke(dialogProgress, 0, "Starting...");


            foreach (string file in mediaFiles)
            {
                episode++;

                try
                {
                    mediaEndtime = UtilsVideo.getVideoLength(file);
                }
                catch (Exception e1)
                {
                    UtilsMsg.showErrMsg("Something went wrong while determining duration of the media:\n" + e1);
                    return;
                }

                if (useSpan)
                {
                    mediaStartime = spanStart;

                    // If the span end time if not greater than the actual duration of the media
                    if (spanEnd < mediaEndtime)
                    {
                        mediaEndtime = spanEnd;
                    }
                }

                UtilsName name = new UtilsName(
                    deckName,
                    mediaFiles.Length, // Total number of episodes
                    1,                 // Total number of lines (Note: not filled out here)
                    mediaEndtime,      // Last time
                    0, 0               // Width and height (Note: not filled out anywhere)
                    );

                mediaDuration = UtilsSubs.getDurationTime(mediaStartime, mediaEndtime);

                string progressText = String.Format("Processing audio from media file {0} of {1}",
                                                    episode,
                                                    mediaFiles.Length);

                int progress = Convert.ToInt32((episode - 1) * (100.0 / mediaFiles.Length));

                DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                // Enable detail mode in progress dialog
                DialogProgress.enableDetailInvoke(dialogProgress, true);

                // Set the duration of the clip in the progress dialog  (for detail mode)
                DialogProgress.setDuration(dialogProgress, mediaDuration);


                string tempMp3Filename = Path.GetTempPath() + ConstantSettings.TempAudioFilename;

                UtilsAudio.ripAudioFromVideo(mediaFiles[episode - 1],
                                             audioStream.Num,
                                             mediaStartime, mediaEndtime,
                                             bitrate, tempMp3Filename, dialogProgress);

                DialogProgress.enableDetailInvoke(dialogProgress, false);

                if (dialogProgress.Cancel)
                {
                    e.Cancel = true;
                    File.Delete(tempMp3Filename);
                    return;
                }

                int numClips = 1;

                if (!isSingleFile)
                {
                    numClips = (int)Math.Ceiling((mediaDuration.TimeOfDay.TotalMilliseconds / (clipLength.TimeOfDay.TotalSeconds * 1000.0)));
                }

                for (int clipIdx = 0; clipIdx < numClips; clipIdx++)
                {
                    progressText = String.Format("Splitting segment {0} of {1} from media file {2} of {3}",
                                                 clipIdx + 1,
                                                 numClips,
                                                 episode,
                                                 mediaFiles.Length);

                    progress = Convert.ToInt32((episode - 1) * (100.0 / mediaFiles.Length));

                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);


                    if (dialogProgress.Cancel)
                    {
                        e.Cancel = true;
                        File.Delete(tempMp3Filename);
                        return;
                    }

                    // The start and end times used for processing
                    DateTime startTime = new DateTime();
                    DateTime endTime   = new DateTime();

                    if (isSingleFile)
                    {
                        endTime = mediaDuration;
                    }
                    else
                    {
                        startTime = startTime.AddSeconds((double)(clipLength.TimeOfDay.TotalSeconds * clipIdx));
                        endTime   = endTime.AddSeconds((double)(clipLength.TimeOfDay.TotalSeconds * (clipIdx + 1)));

                        if (endTime.TimeOfDay.TotalMilliseconds >= mediaDuration.TimeOfDay.TotalMilliseconds)
                        {
                            endTime = mediaDuration;
                        }
                    }

                    // The start and end times that will be displayed
                    DateTime startTimeName = startTime.AddMilliseconds(mediaStartime.TimeOfDay.TotalMilliseconds);
                    DateTime endTimeName   = endTime.AddMilliseconds(mediaStartime.TimeOfDay.TotalMilliseconds);

                    // Fill in the total number of lines with the total number of clips
                    name.TotalNumLines = numClips;

                    string nameStr = name.createName(ConstantSettings.ExtractMediaAudioFilenameFormat, episode + episodeStartNumber - 1,
                                                     clipIdx + 1, startTimeName, endTimeName, "", "");


                    string outName = String.Format("{0}{1}{2}",
                                                   outputDir,                   // {0}
                                                   Path.DirectorySeparatorChar, // {1}
                                                   nameStr);                    // {2}

                    UtilsAudio.cutAudio(tempMp3Filename, startTime, endTime, outName);

                    nameStr = name.createName(ConstantSettings.AudioId3Artist, episode + episodeStartNumber - 1,
                                              clipIdx + 1, startTimeName, endTimeName, "", "");

                    string tagArtist = String.Format("{0}",
                                                     nameStr); // {0}

                    nameStr = name.createName(ConstantSettings.AudioId3Album, episode + episodeStartNumber - 1,
                                              clipIdx + 1, startTimeName, endTimeName, "", "");

                    string tagAlbum = String.Format("{0}",
                                                    nameStr); // {0}

                    nameStr = name.createName(ConstantSettings.AudioId3Title, episode + episodeStartNumber - 1,
                                              clipIdx + 1, startTimeName, endTimeName, "", "");

                    string tagTitle = String.Format("{0}",
                                                    nameStr); // {0}

                    nameStr = name.createName(ConstantSettings.AudioId3Genre, episode + episodeStartNumber - 1,
                                              clipIdx + 1, startTimeName, endTimeName, "", "");

                    string tagGenre = String.Format("{0}",
                                                    nameStr); // {0}

                    string tagLyrics = "";

                    if (groupBoxCheckLyrics.Checked)
                    {
                        int totalLyricsLines = 0;
                        int curLyricsNum     = 1;

                        // Precount the number of lyrics lines
                        foreach (InfoCombined comb in combinedAll[episode - 1])
                        {
                            if (comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds >= startTimeName.TimeOfDay.TotalMilliseconds &&
                                comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds <= endTimeName.TimeOfDay.TotalMilliseconds)
                            {
                                totalLyricsLines++;
                            }
                        }

                        // Fill in the total number of lyrics lines
                        name.TotalNumLines = curLyricsNum;

                        // Foreach comb in the current episode, if the comb lies within the
                        // current clip, add it to the lryics tag
                        foreach (InfoCombined comb in combinedAll[episode - 1])
                        {
                            if (comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds >= startTimeName.TimeOfDay.TotalMilliseconds &&
                                comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds <= endTimeName.TimeOfDay.TotalMilliseconds)
                            {
                                tagLyrics += formatLyricsPair(comb, name, startTimeName, episode + episodeStartNumber - 1, curLyricsNum) + "\r\n";
                                curLyricsNum++;
                            }
                        }
                    }

                    UtilsAudio.tagAudio(outName,
                                        tagArtist,
                                        tagAlbum,
                                        tagTitle,
                                        tagGenre,
                                        tagLyrics,
                                        clipIdx + 1,
                                        numClips);
                }
            }

            return;
        }
示例#26
0
        /// <summary>
        /// Generate Audio clips for all episodes.
        /// </summary>
        public bool genAudioClip(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int      progessCount    = 0;
            int      episodeCount    = 0;
            int      totalEpisodes   = workerVars.CombinedAll.Count;
            int      curEpisodeCount = 0;
            int      totalLines      = UtilsSubs.getTotalLineCount(workerVars.CombinedAll);
            DateTime lastTime        = UtilsSubs.getLastTime(workerVars.CombinedAll);

            UtilsName name = new UtilsName(Settings.Instance.DeckName, totalEpisodes,
                                           totalLines, lastTime, Settings.Instance.VideoClips.Size.Width,
                                           Settings.Instance.VideoClips.Size.Height);

            DialogProgress.updateProgressInvoke(dialogProgress, 0, "Creating audio clips.");

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                episodeCount++;

                // It is possible for all lines in an episode to be set to inactive
                if (combArray.Count == 0)
                {
                    // Skip this episode
                    continue;
                }

                // Is the audio input an mp3 file?
                bool inputFileIsMp3 = Settings.Instance.AudioClips.Files.Length > 0 &&
                                      Path.GetExtension(Settings.Instance.AudioClips.Files[episodeCount - 1])
                                      .ToLower() == ".mp3";

                DateTime entireClipStartTime = combArray[0].Subs1.StartTime;
                DateTime entireClipEndTime   = combArray[combArray.Count - 1].Subs1.EndTime;
                string   tempMp3Filename     = Path.GetTempPath() + ConstantSettings.TempAudioFilename;

                // Apply pad to entire clip timings  (if requested)
                if (Settings.Instance.AudioClips.PadEnabled)
                {
                    entireClipStartTime =
                        UtilsSubs.applyTimePad(entireClipStartTime, -Settings.Instance.AudioClips.PadStart);
                    entireClipEndTime = UtilsSubs.applyTimePad(entireClipEndTime, Settings.Instance.AudioClips.PadEnd);
                }

                // Do we need to extract the audio from the video file?
                if (Settings.Instance.AudioClips.UseAudioFromVideo)
                {
                    string progressText = $"Extracting audio from video file {episodeCount} of {totalEpisodes}"; // {1}

                    bool success = convertToMp3(
                        Settings.Instance.VideoClips.Files[episodeCount - 1],
                        Settings.Instance.VideoClips.AudioStream.Num,
                        progressText,
                        dialogProgress,
                        entireClipStartTime,
                        entireClipEndTime,
                        tempMp3Filename);

                    if (!success)
                    {
                        UtilsMsg.showErrMsg("Failed to extract the audio from the video.\n" +
                                            "Make sure that the video does not have any DRM restrictions.");
                        return(false);
                    }
                }
                // If the reencode option is set or the input audio is not an mp3, reencode to mp3
                else if (ConstantSettings.ReencodeBeforeSplittingAudio || !inputFileIsMp3)
                {
                    string progressText = $"Reencoding audio file {episodeCount} of {totalEpisodes}";

                    bool success = convertToMp3(
                        Settings.Instance.AudioClips.Files[episodeCount - 1],
                        "0",
                        progressText,
                        dialogProgress,
                        entireClipStartTime,
                        entireClipEndTime,
                        tempMp3Filename);

                    if (!success)
                    {
                        UtilsMsg.showErrMsg("Failed to reencode the audio file.\n" +
                                            "Make sure that the audio file does not have any DRM restrictions.");
                        return(false);
                    }
                }

                curEpisodeCount = 0; // Reset

                // For each line in episode, generate an audio clip
                foreach (InfoCombined comb in combArray)
                {
                    progessCount++;
                    curEpisodeCount++;

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    string progressText =
                        $"Generating audio clip: {progessCount.ToString()} of {totalLines.ToString()}";

                    // Update the progress dialog
                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    // Did the user press the cancel button?
                    if (dialogProgress.Cancel)
                    {
                        File.Delete(tempMp3Filename);
                        return(false);
                    }

                    DateTime startTime         = comb.Subs1.StartTime;
                    DateTime endTime           = comb.Subs1.EndTime;
                    DateTime filenameStartTime = comb.Subs1.StartTime;
                    DateTime filenameEndTime   = comb.Subs1.EndTime;
                    string   fileToCut         = "";

                    if (Settings.Instance.AudioClips.UseAudioFromVideo ||
                        ConstantSettings.ReencodeBeforeSplittingAudio || !inputFileIsMp3)
                    {
                        startTime = UtilsSubs.shiftTiming(startTime,
                                                          -(int)entireClipStartTime.TimeOfDay.TotalMilliseconds);
                        endTime = UtilsSubs.shiftTiming(endTime,
                                                        -(int)entireClipStartTime.TimeOfDay.TotalMilliseconds);
                        fileToCut = tempMp3Filename;
                    }
                    else
                    {
                        fileToCut = Settings.Instance.AudioClips.Files[episodeCount - 1];
                    }

                    // Apply pad (if requested)
                    if (Settings.Instance.AudioClips.PadEnabled)
                    {
                        startTime         = UtilsSubs.applyTimePad(startTime, -Settings.Instance.AudioClips.PadStart);
                        endTime           = UtilsSubs.applyTimePad(endTime, Settings.Instance.AudioClips.PadEnd);
                        filenameStartTime = UtilsSubs.applyTimePad(comb.Subs1.StartTime,
                                                                   -Settings.Instance.AudioClips.PadStart);
                        filenameEndTime =
                            UtilsSubs.applyTimePad(comb.Subs1.EndTime, Settings.Instance.AudioClips.PadEnd);
                    }

                    string lyricSubs2 = "";

                    // Set the Subs2 lyric if it exists
                    if (Settings.Instance.Subs[1].Files.Length != 0)
                    {
                        lyricSubs2 = comb.Subs2.Text.Trim();
                    }

                    // Create output filename
                    string nameStr = name.createName(ConstantSettings.AudioFilenameFormat,
                                                     (int)episodeCount + Settings.Instance.EpisodeStartNumber - 1,
                                                     progessCount, filenameStartTime, filenameEndTime, comb.Subs1.Text, lyricSubs2);

                    string outName = $"{workerVars.MediaDir}{Path.DirectorySeparatorChar}{nameStr}"; // {2}

                    // Create audio clip
                    UtilsAudio.cutAudio(fileToCut, startTime, endTime, outName);

                    // Tag the audio clip
                    tagAudio(name, outName, episodeCount, curEpisodeCount, progessCount, combArray.Count,
                             filenameStartTime, filenameEndTime, comb.Subs1.Text, lyricSubs2);
                }

                File.Delete(tempMp3Filename);
            }

            // Normalize all mp3 files in the media directory
            if (Settings.Instance.AudioClips.Normalize)
            {
                DialogProgress.updateProgressInvoke(dialogProgress, -1, "Normalizing audio...");

                UtilsAudio.normalizeAudio(workerVars.MediaDir);
            }

            return(true);
        }
示例#27
0
        /// <summary>
        /// Generate video clips for all episodes.
        /// </summary>
        public bool genVideoClip(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int      progessCount  = 0;
            int      episodeCount  = 0;
            int      totalEpisodes = workerVars.CombinedAll.Count;
            int      totalLines    = UtilsSubs.getTotalLineCount(workerVars.CombinedAll);
            DateTime lastTime      = UtilsSubs.getLastTime(workerVars.CombinedAll);

            UtilsName name = new UtilsName(Settings.Instance.DeckName, totalEpisodes,
                                           totalLines, lastTime, Settings.Instance.VideoClips.Size.Width, Settings.Instance.VideoClips.Size.Height);

            DialogProgress.updateProgressInvoke(dialogProgress, 0, "Creating video clips.");

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                episodeCount++;

                // It is possible for all lines in an episode to be set to inactive
                if (combArray.Count == 0)
                {
                    // Skip this episode
                    continue;
                }

                string progressText = String.Format("Converting video file {0} of {1}",
                                                    episodeCount,
                                                    totalEpisodes);

                DialogProgress.updateProgressInvoke(dialogProgress, progressText);

                DateTime entireClipStartTime = combArray[0].Subs1.StartTime;
                DateTime entireClipEndTime   = combArray[combArray.Count - 1].Subs1.EndTime;

                // Apply pad to entire clip timings  (if requested)
                if (Settings.Instance.VideoClips.PadEnabled)
                {
                    entireClipStartTime = UtilsSubs.applyTimePad(entireClipStartTime, -Settings.Instance.VideoClips.PadStart);
                    entireClipEndTime   = UtilsSubs.applyTimePad(entireClipEndTime, Settings.Instance.VideoClips.PadEnd);
                }

                // Enable detail mode in progress dialog
                DialogProgress.enableDetailInvoke(dialogProgress, true);

                // Set the duration of the clip in the progress dialog  (for detail mode)
                DateTime entireClipDuration = UtilsSubs.getDurationTime(entireClipStartTime, entireClipEndTime);
                DialogProgress.setDuration(dialogProgress, entireClipDuration);

                string tempVideoFilename = Path.GetTempPath() + ConstantSettings.TempVideoFilename;
                string videoExtension    = ".avi";

                // Convert entire video (from first line to last line) based on user settings (size, crop, bitrate, etc).
                // It will be cut into smaller video clips later.
                if (Settings.Instance.VideoClips.IPodSupport)
                {
                    videoExtension     = ".mp4";
                    tempVideoFilename += videoExtension;

                    UtilsVideo.convertVideo(Settings.Instance.VideoClips.Files[episodeCount - 1],
                                            Settings.Instance.VideoClips.AudioStream.Num,
                                            entireClipStartTime, entireClipEndTime,
                                            Settings.Instance.VideoClips.Size, Settings.Instance.VideoClips.Crop,
                                            Settings.Instance.VideoClips.BitrateVideo, Settings.Instance.VideoClips.BitrateAudio,
                                            UtilsVideo.VideoCodec.h264, UtilsVideo.AudioCodec.AAC,
                                            UtilsVideo.Profilex264.IPod640, UtilsVideo.Presetx264.SuperFast,
                                            tempVideoFilename, dialogProgress);
                }
                else
                {
                    tempVideoFilename += videoExtension;

                    UtilsVideo.convertVideo(Settings.Instance.VideoClips.Files[episodeCount - 1],
                                            Settings.Instance.VideoClips.AudioStream.Num,
                                            entireClipStartTime, entireClipEndTime,
                                            Settings.Instance.VideoClips.Size, Settings.Instance.VideoClips.Crop,
                                            Settings.Instance.VideoClips.BitrateVideo, Settings.Instance.VideoClips.BitrateAudio,
                                            UtilsVideo.VideoCodec.MPEG4, UtilsVideo.AudioCodec.MP3,
                                            UtilsVideo.Profilex264.None, UtilsVideo.Presetx264.None,
                                            tempVideoFilename, dialogProgress);
                }

                DialogProgress.enableDetailInvoke(dialogProgress, false);

                // Generate a video clip for each line of the episode
                foreach (InfoCombined comb in combArray)
                {
                    progessCount++;

                    progressText = string.Format("Generating video clip: {0} of {1}",
                                                 progessCount.ToString(),
                                                 totalLines.ToString());

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    // Update the progress dialog
                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    // Did the user press the cancel button?
                    if (dialogProgress.Cancel)
                    {
                        File.Delete(tempVideoFilename);
                        return(false);
                    }

                    // Adjust timing to sync with the start of the converted video (which starts at the episode's first line of dialog)
                    DateTime startTime = UtilsSubs.shiftTiming(comb.Subs1.StartTime, -((int)entireClipStartTime.TimeOfDay.TotalMilliseconds));
                    DateTime endTime   = UtilsSubs.shiftTiming(comb.Subs1.EndTime, -((int)entireClipStartTime.TimeOfDay.TotalMilliseconds));

                    // Times used in the filename
                    DateTime filenameStartTime = comb.Subs1.StartTime;
                    DateTime filenameEndTime   = comb.Subs1.EndTime;

                    // Apply pad (if requested)
                    if (Settings.Instance.VideoClips.PadEnabled)
                    {
                        startTime         = UtilsSubs.applyTimePad(startTime, -Settings.Instance.VideoClips.PadStart);
                        endTime           = UtilsSubs.applyTimePad(endTime, Settings.Instance.VideoClips.PadEnd);
                        filenameStartTime = UtilsSubs.applyTimePad(comb.Subs1.StartTime, -Settings.Instance.VideoClips.PadStart);
                        filenameEndTime   = UtilsSubs.applyTimePad(comb.Subs1.EndTime, Settings.Instance.VideoClips.PadEnd);
                    }

                    // Create output filename
                    string nameStr = name.createName(ConstantSettings.VideoFilenameFormat, (int)episodeCount + Settings.Instance.EpisodeStartNumber - 1,
                                                     progessCount, filenameStartTime, filenameEndTime, comb.Subs1.Text, comb.Subs2.Text);

                    string outFile = string.Format("{0}{1}{2}{3}",
                                                   workerVars.MediaDir,         // {0}
                                                   Path.DirectorySeparatorChar, // {1}
                                                   nameStr,                     // {2}
                                                   videoExtension);             // {3}

                    // Cut video clip for current line
                    UtilsVideo.cutVideo(tempVideoFilename, startTime, endTime, outFile);
                }

                File.Delete(tempVideoFilename);
            }

            return(true);
        }
示例#28
0
        /// <summary>
        /// Get a list with the inactive lines removed from each episode.
        /// </summary>
        public List <List <InfoCombined> > removeInactiveLines(WorkerVars workerVars, DialogProgress dialogProgress,
                                                               bool dontRemoveContextLines)
        {
            int totalLines   = 0;
            int progessCount = 0;
            List <List <InfoCombined> > activeLines = new List <List <InfoCombined> >();

            bool subs1ContainsVobsubs = UtilsSubs.filePatternContainsVobsubs(Settings.Instance.Subs[0].FilePattern);
            bool subs2ContainsVobsubs = UtilsSubs.filePatternContainsVobsubs(Settings.Instance.Subs[1].FilePattern);

            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                totalLines += combArray.Count;
            }

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                List <InfoCombined> currentEpisodeActiveLines = new List <InfoCombined>();

                // For each line in episode
                foreach (InfoCombined comb in combArray)
                {
                    progessCount++;

                    if (comb.Active || dontRemoveContextLines && comb.OnlyNeededForContext)
                    {
                        currentEpisodeActiveLines.Add(comb);
                    }
                    else
                    {
                        if (subs1ContainsVobsubs)
                        {
                            try
                            {
                                // Multiple vobsub images can be shown in a single line, so extract each image and delete it
                                List <string> vobsubImages = UtilsSubs.extractVobsubFilesFromText(comb.Subs1.Text);

                                foreach (string vobsubImage in vobsubImages)
                                {
                                    File.Delete(workerVars.MediaDir + Path.DirectorySeparatorChar + vobsubImage);
                                }
                            }
                            catch
                            {
                                // Don't care
                            }
                        }

                        if (subs2ContainsVobsubs)
                        {
                            try
                            {
                                // Multiple vobsub image can be shown in a single line, so extract each image and delete it
                                List <string> vobsubImages = UtilsSubs.extractVobsubFilesFromText(comb.Subs2.Text);

                                foreach (string vobsubImage in vobsubImages)
                                {
                                    File.Delete(workerVars.MediaDir + Path.DirectorySeparatorChar + vobsubImage);
                                }
                            }
                            catch
                            {
                                // Don't care
                            }
                        }
                    }

                    string progressText =
                        $"Remove inactive lines: {Convert.ToInt32(progessCount * (100.0 / totalLines))}%";

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    if (dialogProgress.Cancel)
                    {
                        return(null);
                    }
                }

                activeLines.Add(currentEpisodeActiveLines);
            }

            return(activeLines);
        }
示例#29
0
        /// <summary>
        /// Copy the Vobsub image files from the temporary preview directory to the media directory.
        /// </summary>
        public bool copyVobsubsFromPreviewDirToMediaDir(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int totalLines   = 0;
            int progessCount = 0;

            bool   subs1ContainsVobsubs = UtilsSubs.filePatternContainsVobsubs(Settings.Instance.Subs[0].FilePattern);
            bool   subs2ContainsVobsubs = UtilsSubs.filePatternContainsVobsubs(Settings.Instance.Subs[1].FilePattern);
            string tempPreviewDir       = Path.GetTempPath() + ConstantSettings.TempPreviewDirName;

            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                totalLines += combArray.Count;
            }

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                // For each line in episode
                foreach (InfoCombined comb in combArray)
                {
                    progessCount++;

                    if (subs1ContainsVobsubs)
                    {
                        try
                        {
                            // Multiple vobsub image can be shown in a single line, so copy each of them
                            List <string> vobsubImages = UtilsSubs.extractVobsubFilesFromText(comb.Subs1.Text);

                            foreach (string vobsubImage in vobsubImages)
                            {
                                File.Copy(tempPreviewDir + Path.DirectorySeparatorChar + vobsubImage,
                                          workerVars.MediaDir + Path.DirectorySeparatorChar + vobsubImage);
                            }
                        }
                        catch
                        {
                            // Don't care
                        }
                    }

                    if (subs2ContainsVobsubs)
                    {
                        try
                        {
                            // Multiple vobsub image can be shown in a single line, so copy each of them
                            List <string> vobsubImages = UtilsSubs.extractVobsubFilesFromText(comb.Subs2.Text);

                            foreach (string vobsubImage in vobsubImages)
                            {
                                File.Copy(tempPreviewDir + Path.DirectorySeparatorChar + vobsubImage,
                                          workerVars.MediaDir + Path.DirectorySeparatorChar + vobsubImage);
                            }
                        }
                        catch
                        {
                            // Don't care
                        }
                    }

                    string progressText =
                        $"Copying vobsubs to .media directory: {Convert.ToInt32(progessCount * (100.0 / totalLines))}%";

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    if (dialogProgress.Cancel)
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
示例#30
0
        /// <summary>
        /// Inactivate lines from episodes based on include/exclude lists, duplicate lines, etc.
        /// Does not remove lines, only modifies their active flag.
        /// </summary>
        public List <List <InfoCombined> > inactivateLines(WorkerVars workerVars, DialogProgress dialogProgress)
        {
            int totalLines   = 0;
            int progessCount = 0;

            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                totalLines += combArray.Count;
            }

            bool checkIncludesExludes = Settings.Instance.Subs[0].IncludedWords.Length != 0 ||
                                        Settings.Instance.Subs[1].IncludedWords.Length != 0 ||
                                        Settings.Instance.Subs[0].ExcludedWords.Length != 0 ||
                                        Settings.Instance.Subs[1].ExcludedWords.Length != 0;

            Hashtable allLinesSoFarSubs1 = new Hashtable();
            Hashtable allLinesSoFarSubs2 = new Hashtable();
            bool      removeDupsSubs1    = Settings.Instance.Subs[0].ExcludeDuplicateLinesEnabled;
            bool      removeDupsSubs2    = Settings.Instance.Subs[1].ExcludeDuplicateLinesEnabled &&
                                           Settings.Instance.Subs[1].FilePattern != "";
            bool checkDups = removeDupsSubs1 || removeDupsSubs2;

            // For each episode
            foreach (List <InfoCombined> combArray in workerVars.CombinedAll)
            {
                List <InfoCombined> compArrayRemoved = new List <InfoCombined>();

                // For each line in episode
                foreach (InfoCombined comb in combArray)
                {
                    bool isExcluded = false;
                    progessCount++;

                    // Don't process if subtitles are vobsub
                    bool isSubs1Vobsub = UtilsSubs.filePatternContainsVobsubs(Settings.Instance.Subs[0].FilePattern);
                    bool isSubs2Vobsub = UtilsSubs.filePatternContainsVobsubs(Settings.Instance.Subs[1].FilePattern);

                    // Remove lines not in the span
                    if (Settings.Instance.SpanEnabled && !isExcluded)
                    {
                        DateTime spanStart = Settings.Instance.SpanStart;
                        DateTime spanEnd   = Settings.Instance.SpanEnd;

                        if (comb.Subs1.StartTime < spanStart || comb.Subs1.StartTime > spanEnd)
                        {
                            isExcluded = true;
                        }
                    }


                    bool passedIgnoreShorterThanTime = true;

                    // Make sure that line is at least the min amount of milliseconds as specified by user
                    if (Settings.Instance.Subs[0].ExcludeShorterThanTimeEnabled &&
                        Settings.Instance.Subs[0].TimingsEnabled)
                    {
                        passedIgnoreShorterThanTime =
                            Math.Abs((int)comb.Subs1.EndTime.TimeOfDay.TotalMilliseconds -
                                     (int)comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds) >=
                            Settings.Instance.Subs[0].ExcludeShorterThanTime;
                    }
                    else if (Settings.Instance.Subs[1].ExcludeShorterThanTimeEnabled &&
                             Settings.Instance.Subs[1].TimingsEnabled)
                    {
                        // Note: using Subs1 here is not a mistake because Subs2 timings will be placed into Subs1 in combineSubs().
                        passedIgnoreShorterThanTime =
                            Math.Abs((int)comb.Subs1.EndTime.TimeOfDay.TotalMilliseconds -
                                     (int)comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds) >=
                            Settings.Instance.Subs[1].ExcludeShorterThanTime;
                    }

                    if (!passedIgnoreShorterThanTime && !isExcluded)
                    {
                        isExcluded = true;
                    }


                    bool passedIgnoreLongerThanTime = true;

                    // Make sure that line is at least the min amount of milliseconds as specified by user
                    if (Settings.Instance.Subs[0].ExcludeLongerThanTimeEnabled &&
                        Settings.Instance.Subs[0].TimingsEnabled)
                    {
                        passedIgnoreLongerThanTime =
                            Math.Abs((int)comb.Subs1.EndTime.TimeOfDay.TotalMilliseconds -
                                     (int)comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds) <=
                            Settings.Instance.Subs[0].ExcludeLongerThanTime;
                    }
                    else if (Settings.Instance.Subs[1].ExcludeLongerThanTimeEnabled &&
                             Settings.Instance.Subs[1].TimingsEnabled)
                    {
                        // Note: using Subs1 here is not a mistake because Subs2 timings will be placed into Subs1 in combineSubs().
                        passedIgnoreLongerThanTime =
                            Math.Abs((int)comb.Subs1.EndTime.TimeOfDay.TotalMilliseconds -
                                     (int)comb.Subs1.StartTime.TimeOfDay.TotalMilliseconds) <=
                            Settings.Instance.Subs[1].ExcludeLongerThanTime;
                    }

                    if (!passedIgnoreLongerThanTime && !isExcluded)
                    {
                        isExcluded = true;
                    }


                    // Make sure that line is at least the min character length as specified by user
                    bool passedIgnoreFewerTestSubs1 =
                        isSubs1Vobsub ||
                        !Settings.Instance.Subs[0].ExcludeFewerEnabled ||
                        Settings.Instance.Subs[0].ExcludeFewerEnabled &&
                        comb.Subs1.Text.Length >= Settings.Instance.Subs[0].ExcludeFewerCount;

                    bool passedIgnoreFewerTestSubs2 = isSubs2Vobsub ||
                                                      !Settings.Instance.Subs[1].ExcludeFewerEnabled ||
                                                      Settings.Instance.Subs[1].ExcludeFewerEnabled &&
                                                      comb.Subs2.Text.Length >=
                                                      Settings.Instance.Subs[1].ExcludeFewerCount;

                    if ((!passedIgnoreFewerTestSubs1 || !passedIgnoreFewerTestSubs2) && !isExcluded)
                    {
                        isExcluded = true;
                    }


                    // Remove based on actors
                    if (Settings.Instance.ActorList.Count > 0 && !isExcluded)
                    {
                        bool actorFound = false;
                        foreach (string actor in Settings.Instance.ActorList)
                        {
                            if (Settings.Instance.Subs[0].ActorsEnabled)
                            {
                                if (comb.Subs1.Actor.Trim().ToLower() == actor.Trim().ToLower())
                                {
                                    actorFound = true;
                                    break;
                                }
                            }
                            else
                            {
                                if (comb.Subs2.Actor.Trim().ToLower() == actor.Trim().ToLower())
                                {
                                    actorFound = true;
                                    break;
                                }
                            }
                        }

                        isExcluded = !actorFound;
                    }


                    // Remove based on include/exclude lists
                    if (checkIncludesExludes && !isExcluded)
                    {
                        if (!isSubs1Vobsub && Settings.Instance.Subs[0].ExcludedWords.Length != 0)
                        {
                            foreach (string word in Settings.Instance.Subs[0].ExcludedWords)
                            {
                                if (comb.Subs1.Text.ToLower().Contains(word.ToLower()))
                                {
                                    isExcluded = true;
                                }
                            }
                        }

                        if (!isSubs2Vobsub && Settings.Instance.Subs[1].ExcludedWords.Length != 0 && !isExcluded)
                        {
                            foreach (string word in Settings.Instance.Subs[1].ExcludedWords)
                            {
                                if (comb.Subs2.Text.ToLower().Contains(word.ToLower()))
                                {
                                    isExcluded = true;
                                }
                            }
                        }

                        if (!isSubs1Vobsub && Settings.Instance.Subs[0].IncludedWords.Length != 0 && !isExcluded)
                        {
                            bool wordFound = false;
                            foreach (string word in Settings.Instance.Subs[0].IncludedWords)
                            {
                                if (comb.Subs1.Text.ToLower().Contains(word.ToLower()))
                                {
                                    wordFound = true;
                                    break;
                                }
                            }

                            isExcluded = !wordFound;
                        }

                        if (!isSubs2Vobsub && Settings.Instance.Subs[1].IncludedWords.Length != 0 && !isExcluded)
                        {
                            bool wordFound = false;
                            foreach (string word in Settings.Instance.Subs[1].IncludedWords)
                            {
                                if (comb.Subs2.Text.ToLower().Contains(word.ToLower()))
                                {
                                    wordFound = true;
                                    break;
                                }
                            }

                            isExcluded = !wordFound;
                        }
                    }


                    // Remove Duplicates
                    if (checkDups && !isExcluded)
                    {
                        if (!isSubs1Vobsub && removeDupsSubs1)
                        {
                            if (allLinesSoFarSubs1.Contains(comb.Subs1.Text.ToLower()))
                            {
                                isExcluded = true;
                            }
                            else
                            {
                                allLinesSoFarSubs1.Add(comb.Subs1.Text.ToLower(), comb);
                            }
                        }

                        if (!isSubs2Vobsub && removeDupsSubs2)
                        {
                            if (allLinesSoFarSubs2.Contains(comb.Subs2.Text.ToLower()))
                            {
                                isExcluded = true;
                            }
                            else
                            {
                                allLinesSoFarSubs2.Add(comb.Subs2.Text.ToLower(), comb);
                            }
                        }
                    }


                    // Remove lines without a kanji
                    if (Settings.Instance.LangaugeSpecific.KanjiLinesOnly && !isExcluded)
                    {
                        if (!isSubs1Vobsub && !UtilsLang.containsIdeograph(comb.Subs1.Text) && !isSubs2Vobsub && !UtilsLang.containsIdeograph(comb.Subs2.Text))
                        {
                            isExcluded = true;
                        }
                    }

                    // Unset the active flag
                    if (isExcluded)
                    {
                        comb.Active = false;
                    }

                    string progressText =
                        $"Setting active lines based on user specified rules: {Convert.ToInt32(progessCount * (100.0 / totalLines))}%";

                    int progress = Convert.ToInt32(progessCount * (100.0 / totalLines));

                    DialogProgress.updateProgressInvoke(dialogProgress, progress, progressText);

                    if (dialogProgress.Cancel)
                    {
                        return(null);
                    }
                }
            }

            return(workerVars.CombinedAll);
        }