/* Public methods */ /// <summary>Creates new empty <see cref="Subtitles" />.</summary> /// <returns>The newly created subtitles.</returns> public Subtitles New() { SubtitleCollection collection = new SubtitleCollection(); SubtitleProperties properties = new SubtitleProperties(); return(new Subtitles(collection, properties)); }
/// <summary>Parses the specified text, using the specified format.</summary> /// <remarks>The created <see cref="SubtitleCollection" /> will have its <see cref="SubtitleProperties" /> property set to null. /// It is mandatory to use <see cref="SubtitleCollection.SetPropertiesForAll" /> after.</remarks> internal ParsingProperties Parse(string text, SubtitleFormat format, float inputFrameRate, out SubtitleCollection collection, out IncompleteSubtitleCollection incompleteSubtitles) { collection = new SubtitleCollection(); incompleteSubtitles = new IncompleteSubtitleCollection(); ParsingProperties properties = new ParsingProperties(); properties.InputFrameRate = inputFrameRate; Regex subtitleRegex = null; int bodyIndex = 0; text = ClearComments(text, format); /* Read the headers if available */ if (format.Mode == SubtitleMode.Both) { //Read headers to know if format is using Times or Frames bodyIndex = text.Length; int lastIndex = ReadHeaders(text, bodyIndex, format, properties); subtitleRegex = CreateSubtitleRegex(format, properties.TimingMode); /* Detect body index from matching the first subtitle or the end of headers */ bodyIndex = FindBodyIndex(text, format, subtitleRegex); if (lastIndex > bodyIndex) { bodyIndex = lastIndex; } } else { //End of headers is detected by start of subtitles' body properties.TimingMode = format.ModeAsTimingMode; subtitleRegex = CreateSubtitleRegex(format); bodyIndex = FindBodyIndex(text, format, subtitleRegex); ReadHeaders(text, bodyIndex, format, properties); } /* Get properties from the whole input, if available */ format.GlobalInputGetProperties(text, properties); int textLength = text.Length; /* Read the subtitles */ bodyIndex = ReadSubtitles(text, bodyIndex, textLength, subtitleRegex, format, properties, collection, incompleteSubtitles); /* Read the end text of the subtitles */ bodyIndex = ReadBodyEnd(text, bodyIndex, format, collection, incompleteSubtitles); /* Check if there's still text remaining */ if ((bodyIndex < textLength) && includeIncompleteSubtitles) { AddIncompleteSubtitle(incompleteSubtitles, text.Substring(bodyIndex), collection.Count); } return(properties); }
/// <summary>Parses the specified text.</summary> /// <remarks>The created <see cref="SubtitleCollection" /> will have its <see cref="SubtitleProperties" /> property set to null. /// It is mandatory to use <see cref="SubtitleCollection.SetPropertiesForAll" /> after.</remarks> internal ParsingProperties Parse(string text, TimingMode timingMode, Encoding encoding, out SubtitleCollection collection) { collection = new SubtitleCollection(); ParsingProperties properties = new ParsingProperties(); this.text = text; properties.TimingMode = timingMode; /* Read the subtitles */ ReadSubtitles(encoding, properties, collection); return(properties); }
private int ReadBodyEnd(string text, int bodyIndex, SubtitleFormat format, SubtitleCollection collection, IncompleteSubtitleCollection incompleteSubtitles) { Regex bodyEnd = new Regex(format.BodyEndIn + @"\s*", RegexOptions.IgnoreCase); Match bodyEndMatch = bodyEnd.Match(text, bodyIndex); if (bodyEndMatch.Success) { AddIncompleteSubtitleIfExists(text, bodyEndMatch, bodyIndex, collection.Count, incompleteSubtitles); bodyIndex = bodyEndMatch.Index + bodyEndMatch.Length; } return(bodyIndex); }
private void ReadSubtitles(Encoding encoding, ParsingProperties properties, SubtitleCollection collection) { string[] lines = text.Split(new char[] { '\n' }); for (int i = 0; i < lines.Length; i++) { SubtitleText stext = ParseSubtitleText(lines[i]); Style style = new Style(); if (!stext.IsEmpty) { Subtitle subtitle = new Subtitle(null, stext, style); collection.Add(subtitle); } } }
/// <summary>Searches backward for text using the specified search options.</summary> /// <param name="options">The search options.</param> /// <returns>The search results, or null in case no results were found.</returns> private SubtitleSearchResults FindBackward(SubtitleSearchOptions options) { SubtitleCollection collection = subtitles.Collection; if (collection.Count == 0) { return(null); } /* Search the subtitle starting at the startIndex */ SubtitleSearchResults results = FindInSubtitleFromIndex(options.StartSubtitle, options.LineBreak, options.Regex, options.StartIndex, options.TextType, options.Backwards); if (results != null) { return(results); } /* Iterate through the start of the collection */ for (int subtitleNumber = options.StartSubtitle - 1; subtitleNumber > 0; subtitleNumber--) { results = FindInSubtitle(subtitleNumber, options.LineBreak, options.Regex, options.Backwards); if (results != null) { return(results); } } if (options.Wrap) { /* Iterate from the end back to the subtitle */ for (int subtitleNumber = collection.Count - 1; subtitleNumber > options.StartSubtitle; subtitleNumber--) { results = FindInSubtitle(subtitleNumber, options.LineBreak, options.Regex, options.Backwards); if (results != null) { return(results); } } /* Search the subtitle ending at the startIndex */ results = FindInSubtitleTillIndex(options.StartSubtitle, options.LineBreak, options.Regex, options.StartIndex, options.TextType, options.Backwards); if (results != null) { return(results); } } /* Text not found */ return(null); }
/// <summary>Finds the subtitle containing the specified time.</summary> /// <param name="time">The time position.</param> /// <returns>The number of the subtitle that was found, or -1 if no subtitle was found.</returns> public int FindWithTime(TimeSpan time) { SubtitleCollection collection = subtitles.Collection; for (int subtitleNumber = 0; subtitleNumber < collection.Count; subtitleNumber++) { Subtitle subtitle = collection[subtitleNumber]; if ((time >= subtitle.Times.Start) && (time <= subtitle.Times.End)) { return(subtitleNumber); } } return(-1); // No subtitles were found }
/// <summary> /// Writes the specified filename. /// </summary> /// <param name="filename">The filename.</param> /// <param name="subs">The subs.</param> public void Write(string filename, SubtitleCollection subs) { using (FileStream fs = new FileStream(filename, FileMode.Create, FileAccess.Write)) { StreamWriter writer = new StreamWriter(fs, System.Text.Encoding.Default); foreach (SubtitleItem subtitle in subs) { writer.WriteLine(subtitle.Order); writer.WriteLine("{0} --> {1}", ToString(subtitle.Start), ToString(subtitle.End)); writer.WriteLine(subtitle.Content); writer.WriteLine(); } writer.Flush(); fs.Flush(); } }
/// <summary>Finds the subtitle nearer the specified time.</summary> /// <param name="time">The time position.</param> /// <returns>The number of the subtitle that was found, or -1 if no subtitle was found.</returns> public int FindNearTime(TimeSpan time) { SubtitleCollection collection = subtitles.Collection; if (collection.Count == 0) { return(-1); } /* Check if before the first subtitle */ if (time < collection[0].Times.Start) { return(0); } /* Iterate subtitles two by two - the last subtitle is handled in pair and individually afterwards */ for (int subtitleNumber = 0; subtitleNumber < collection.Count - 1; subtitleNumber++) { Subtitle subtitle = collection[subtitleNumber]; /* Continue iterating if didn't reach subtitle start yet */ TimeSpan start = subtitle.Times.Start; if (time < start) { continue; } /* Check if time is contained by the subtitle */ TimeSpan end = subtitle.Times.End; if (time <= end) { return(subtitleNumber); } /* Check if contained between this and the next subtitle, and which is nearest */ int nextSubtitleIndex = subtitleNumber + 1; Subtitle nextSubtitle = collection[nextSubtitleIndex]; TimeSpan nextSubtitleStart = nextSubtitle.Times.Start; if (time < nextSubtitleStart) { return(((time - end) < (nextSubtitleStart - time)) ? subtitleNumber : nextSubtitleIndex); } } /* If no rule matched before, time must be after last subtitle */ return(collection.Count - 1); }
private Subtitles ParsedSubtitlesPlain(string path, Encoding fileEncoding, string text, bool withCharacterNames, TimingMode timingMode, string lineSeparator) { SubtitleCollection collection = null; PlainTextParser plainParser = new PlainTextParser(withCharacterNames, lineSeparator); ParsingProperties parsingProperties = plainParser.Parse(text, timingMode, fileEncoding, out collection); SubtitleProperties subtitleProperties = new SubtitleProperties(parsingProperties); collection.SetPropertiesForAll(subtitleProperties); Subtitles subtitles = new Subtitles(collection, subtitleProperties); CompleteTimingsAfterParsing(subtitles, parsingProperties); fileProperties = new FileProperties(path, fileEncoding, parsingProperties.TimingMode); Logger.Info("[SubtitleFactory] Opened {0} with encoding {1}", path, fileEncoding); return(subtitles); }
/// <summary> /// Builds the specified filename. /// </summary> /// <param name="filename">The filename.</param> /// <returns></returns> public SubtitleCollection Build(string filename) { using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) { StreamReader reader = new StreamReader(fs, Encoding.Default, true); SubtitleCollection subs = new SubtitleCollection(); SrtSubtitleItem current = new SrtSubtitleItem(); do { string text = reader.ReadLine(); current.Load(text); if (current.Complected) { subs.Add(current); current = new SrtSubtitleItem(); } } while (!reader.EndOfStream); if (!current.Empty) { subs.Add(current); } return subs; } }
internal string Build(SubtitleCollection collection, SubtitleProperties subtitleProperties, FileProperties fileProperties) { this.subtitleProperties = subtitleProperties; StringBuilder output = new StringBuilder(); if (format.HasHeaders) { output.Append(format.HeadersToString(subtitleProperties, fileProperties)); } if (format.HasBodyBegin) { output.Append(format.BodyBeginOut); } string subtitleExpression = GetSubtitleExpression(format, subtitleProperties, fileProperties); Regex fieldExpression = new Regex(@"<<(?<Field>\w+)(,(?<Width>\d+))?>>"); MatchEvaluator matchEvaluator = new MatchEvaluator(this.FieldEvaluator); foreach (Subtitle currentSubtitle in collection) { subtitle = currentSubtitle; string outputSubtitle = fieldExpression.Replace(subtitleExpression, matchEvaluator); output.Append(outputSubtitle); output.Append("\n"); subtitleNumber++; previousSubtitle = subtitle; } if (format.HasBodyEnd) { output.Append(format.BodyEndOut); } subtitle = null; previousSubtitle = null; subtitleNumber = 1; ConvertNewlines(output, fileProperties); return(output.ToString()); }
/* Private members */ private Subtitles ParsedSubtitles(string path, Encoding fileEncoding, SubtitleFormat format, float inputFrameRate, string text) { SubtitleCollection collection = null; SubtitleParser subtitleParser = new SubtitleParser(includeIncompleteSubtitles); ParsingProperties parsingProperties = subtitleParser.Parse(text, format, inputFrameRate, out collection, out incompleteSubtitles); SubtitleProperties subtitleProperties = new SubtitleProperties(parsingProperties); collection.SetPropertiesForAll(subtitleProperties); Subtitles subtitles = new Subtitles(collection, subtitleProperties); CompleteTimingsAfterParsing(subtitles, parsingProperties); fileProperties = new FileProperties(path, fileEncoding, format.Type, parsingProperties.TimingMode); Logger.Info("[SubtitleFactory] Opened \"{0}\" with encoding \"{1}\", format \"{2}\", timing mode \"{3}\" and frame rate \"{4}\" (input frame rate was \"{5}\")", path, fileEncoding, format.Name, parsingProperties.TimingMode, subtitleProperties.CurrentFrameRate, inputFrameRate); return(subtitles); }
private int ReadSubtitles(string text, int bodyIndex, int textLength, Regex subtitleRegex, SubtitleFormat format, ParsingProperties properties, SubtitleCollection collection, IncompleteSubtitleCollection incompleteSubtitles) { Subtitle previousSubtitle = null; /* Read the subtitles. BodyIndex points to the start of the subtitles, skipping its possible beginning text*/ while (bodyIndex < textLength) { Match match = subtitleRegex.Match(text, bodyIndex); if (match.Success) { Subtitle subtitle = ParseSubtitle(match, format, properties, previousSubtitle); collection.Add(subtitle); AddIncompleteSubtitleIfExists(text, match, bodyIndex, collection.Count, incompleteSubtitles); bodyIndex = match.Index + match.Length; previousSubtitle = subtitle; } else { break; } } return(bodyIndex); }
private void ParseSubtitles(StreamReader reader, SubtitleCollection subtitleCollection) { var subtitleLines = new List<string>(); var subtitles = 0; Subtitle previousSubtitle = null; var startTime = new TimeSpan(); var readNextLine = true; var line = string.Empty; while (reader.Peek() >= 0) { if (readNextLine) line = reader.ReadLine(); switch (_state) { case State.EndHeader: if (!string.IsNullOrEmpty(line)) { if (line.Length > 0 && line[0].Equals('}')) { _state = State.BeginSubtitle; line = line.Substring(1, line.Length - 1); readNextLine = false; break; } } readNextLine = true; break; case State.BeginSubtitle: if (!string.IsNullOrEmpty(line)) { if (line.Length > 0 && line[0].Equals('{')) { _state = State.SubtitleStartTime; line = line.Substring(1, line.Length - 1); readNextLine = false; break; } } readNextLine = true; break; case State.SubtitleStartTime: readNextLine = ParseSubtitleStartTime(subtitleLines, ref line, ref startTime); break; case State.Subtitle: if (!string.IsNullOrEmpty(line)) { if (line.Length > 0) { if (line[0].Equals('}')) { _state = State.BeginSubtitle; line = line.Substring(1, line.Length - 1); readNextLine = false; if (previousSubtitle != null) { subtitleCollection.Add(new Subtitle(previousSubtitle.Number, previousSubtitle.Offset, startTime - previousSubtitle.Offset, previousSubtitle.Text)); previousSubtitle = null; } if (subtitleLines.Count > 0) { subtitles++; previousSubtitle = new Subtitle(subtitles, startTime, new TimeSpan(), subtitleLines.ToArray()); } break; } subtitleLines.Add(line); } } readNextLine = true; break; } } return; }
public Video(Author author, Medium medium, SubtitleCollection subtitles) { Medium = medium; Author = author; Subtitles = subtitles; }