Exemplo n.º 1
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);
        }