// Methods ------------------------------------------------------------- public List<SubtitleItem> ParseStream(Stream subStream, Encoding encoding) { // seek the beginning of the stream subStream.Position = 0; var reader = new StreamReader(subStream, encoding, true); var firstLine = reader.ReadLine(); if (firstLine == FirstLine) { var line = reader.ReadLine(); var lineNumber = 2; while (line != null && lineNumber <= MaxLineNumberForItems && !IsTimestampLine(line)) { line = reader.ReadLine(); lineNumber++; } if (line != null && lineNumber <= MaxLineNumberForItems && IsTimestampLine(line)) { // we parse all the lines var items = new List<SubtitleItem>(); var timeCodeLine = line; var textLine = reader.ReadLine(); var separatorLine = reader.ReadLine(); while (IsTimestampLine(timeCodeLine) && !string.IsNullOrEmpty(textLine)) { // parse current line var timeCodes = ParseTimecodeLine(timeCodeLine); var lines = new List<string>(textLine.Split(_lineSeparator, StringSplitOptions.RemoveEmptyEntries)); var item = new SubtitleItem() { StartTime = timeCodes.Item1, EndTime = timeCodes.Item2, Lines = lines }; items.Add(item); // read next lines timeCodeLine = reader.ReadLine(); textLine = reader.ReadLine(); separatorLine = reader.ReadLine(); } return items; } else { var message = string.Format("Couldn't find the first timestamp line in the current sub file. " + "Last line read: '{0}', line number #{1}", line, lineNumber); throw new ArgumentException(message); } } else { throw new ArgumentException("Wrong subtitles format for the SubViewerSubParser"); } }
// Methods ------------------------------------------------------------------ public List<SubtitleItem> ParseStream(Stream ssaStream, Encoding encoding) { // test if stream if readable and seekable (just a check, should be good) if (!ssaStream.CanRead || !ssaStream.CanSeek) { var message = string.Format("Stream must be seekable and readable in a subtitles parser. " + "Operation interrupted; isSeekable: {0} - isReadable: {1}", ssaStream.CanSeek, ssaStream.CanSeek); throw new ArgumentException(message); } // seek the beginning of the stream ssaStream.Position = 0; var reader = new StreamReader(ssaStream, encoding, true); var line = reader.ReadLine(); if (line == FirstLine) { var lineNumber = 1; // read the line until the [Events] section while (line != null && line != EventLine && lineNumber <= MaxLineNumberForEventSection) { line = reader.ReadLine(); lineNumber++; } if (line != null && lineNumber <= MaxLineNumberForEventSection) { // we are at the event section var headerLine = reader.ReadLine(); if (!string.IsNullOrEmpty(headerLine)) { var columnHeaders = headerLine.Split(Separator).Select(head => head.Trim()).ToList(); var startIndexColumn = columnHeaders.IndexOf(StartColumn); var endIndexColumn = columnHeaders.IndexOf(EndColumn); var textIndexColumn = columnHeaders.IndexOf(TextColumn); if (startIndexColumn > 0 && endIndexColumn > 0 && textIndexColumn > 0) { var items = new List<SubtitleItem>(); line = reader.ReadLine(); while (line != null) { var columns = line.Split(Separator); var startText = columns[startIndexColumn]; var endText = columns[endIndexColumn]; var textLine = columns[textIndexColumn]; var start = ParseSsaTimecode(startText); var end = ParseSsaTimecode(endText); // TODO: split text line? var item = new SubtitleItem() { StartTime = start, EndTime = end, Lines = new List<string>() {textLine} }; items.Add(item); line = reader.ReadLine(); } return items; } else { var message = string.Format("Couldn't find all the necessary columns " + "headers ({0}, {1}, {2}) in header line {3}", StartColumn, EndColumn, TextColumn, headerLine); throw new ArgumentException(message); } } else { var message = string.Format("The header line after the line '{0}' was null -> " + "no need to continue parsing", line); throw new ArgumentException(message); } } else { var message = string.Format("We reached line '{0}' with line number #{1} without finding to " + "Event section ({2})", line, lineNumber, EventLine); throw new ArgumentException(message); } } else { var message = string.Format("First subtitle line '{0}' was different from the one expected " + "for a SSA file ({1}). We stop the parsing here.", line, FirstLine); throw new ArgumentException(message); } }
/// <summary> /// Parses one line of the .sub file /// /// ex: /// {0}{180}PIRATES OF THE CARIBBEAN|English subtitlez by tHe.b0dY /// </summary> /// <param name="line">The .sub file line</param> /// <param name="frameRate">The frame rate with which the .sub file was created</param> /// <returns>The corresponding SubtitleItem</returns> private SubtitleItem ParseLine(string line, float frameRate) { const string regex = @"^[{\[](\d+)[}\]][{\[](\d+)[}\]](.*)"; var match = Regex.Match(line, regex); if (match.Success && match.Groups.Count > 2) { var startFrame = match.Groups[1].Value; var start = (int)(1000 * double.Parse(startFrame) / frameRate); var endTime = match.Groups[2].Value; var end = (int)(1000 * double.Parse(endTime) / frameRate); var text = match.Groups[match.Groups.Count - 1].Value; var lines = text.Split(_lineSeparators); var nonEmptyLines = lines.Where(l => !string.IsNullOrEmpty(l)).ToList(); var item = new SubtitleItem { Lines = nonEmptyLines, StartTime = start, EndTime = end }; return item; } else { var message = string.Format("The subtitle file line {0} is " + "not in the .sub format. We stop the process.", line); Console.WriteLine(message); throw new InvalidDataException(message); } }