[InlineData(InvariantDialoguePrefix + "start {\\fnFont Name}text1 {\\fs10}text2{\\fs}{\\fn} {\\1c&H112233}text3{\\1c} end", "start <font face=\"Font Name\">text1 <font size=\"10\">text2</font></font> <font color=\"#332211\">text3</font> end")] // nested formatting public void Parse(string ssa, string expectedText) { using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(ssa))) { SubtitleTrackInfo subtitleTrackInfo = parser.Parse(stream, CancellationToken.None); SubtitleTrackEvent actual = subtitleTrackInfo.TrackEvents[0]; Assert.Equal(expectedText, actual.Text); } }
public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) { var trackInfo = new SubtitleTrackInfo(); using ( var reader = new StreamReader(stream)) { string line; while ((line = reader.ReadLine()) != null) { cancellationToken.ThrowIfCancellationRequested(); if (string.IsNullOrWhiteSpace(line)) { continue; } var subEvent = new SubtitleTrackEvent {Id = line}; line = reader.ReadLine(); if (string.IsNullOrWhiteSpace(line)) { continue; } var time = Regex.Split(line, @"[\t ]*-->[\t ]*"); if (time.Length < 2) { // This occurs when subtitle text has an empty line as part of the text. // Need to adjust the break statement below to resolve this. _logger.Warn("Unrecognized line in srt: {0}", line); continue; } subEvent.StartPositionTicks = GetTicks(time[0]); var endTime = time[1]; var idx = endTime.IndexOf(" ", StringComparison.Ordinal); if (idx > 0) endTime = endTime.Substring(0, idx); subEvent.EndPositionTicks = GetTicks(endTime); var multiline = new List<string>(); while ((line = reader.ReadLine()) != null) { if (string.IsNullOrEmpty(line)) { break; } multiline.Add(line); } subEvent.Text = string.Join(ParserValues.NewLine, multiline); subEvent.Text = subEvent.Text.Replace(@"\N", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, "<", "<", RegexOptions.IgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, ">", ">", RegexOptions.IgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, "<(\\/?(font|b|u|i|s))((\\s+(\\w|\\w[\\w\\-]*\\w)(\\s*=\\s*(?:\\\".*?\\\"|'.*?'|[^'\\\">\\s]+))?)+\\s*|\\s*)(\\/?)>", "<$1$3$7>", RegexOptions.IgnoreCase); trackInfo.TrackEvents.Add(subEvent); } } return trackInfo; }
public void Parse_MultipleDialogues(string ssa, IReadOnlyList <SubtitleTrackEvent> expectedSubtitleTrackEvents) { using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(ssa))) { SubtitleTrackInfo subtitleTrackInfo = parser.Parse(stream, CancellationToken.None); Assert.Equal(expectedSubtitleTrackEvents.Count, subtitleTrackInfo.TrackEvents.Count); for (int i = 0; i < expectedSubtitleTrackEvents.Count; ++i) { SubtitleTrackEvent expected = expectedSubtitleTrackEvents[i]; SubtitleTrackEvent actual = subtitleTrackInfo.TrackEvents[i]; Assert.Equal(expected.StartPositionTicks, actual.StartPositionTicks); Assert.Equal(expected.EndPositionTicks, actual.EndPositionTicks); Assert.Equal(expected.Text, actual.Text); } } }
public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) { var trackInfo = new SubtitleTrackInfo(); var eventIndex = 1; using (var reader = new StreamReader(stream)) { string line; while (reader.ReadLine() != "[Events]") {} var headers = ParseFieldHeaders(reader.ReadLine()); while ((line = reader.ReadLine()) != null) { cancellationToken.ThrowIfCancellationRequested(); if (string.IsNullOrWhiteSpace(line)) { continue; } if(line.StartsWith("[")) break; if(string.IsNullOrEmpty(line)) continue; var subEvent = new SubtitleTrackEvent { Id = eventIndex.ToString(_usCulture) }; eventIndex++; var sections = line.Substring(10).Split(','); subEvent.StartPositionTicks = GetTicks(sections[headers["Start"]]); subEvent.EndPositionTicks = GetTicks(sections[headers["End"]]); subEvent.Text = string.Join(",", sections.Skip(headers["Text"])); RemoteNativeFormatting(subEvent); subEvent.Text = subEvent.Text.Replace("\\n", ParserValues.NewLine, StringComparison.OrdinalIgnoreCase); subEvent.Text = Regex.Replace(subEvent.Text, @"\{(\\[\w]+\(?([\w\d]+,?)+\)?)+\}", string.Empty, RegexOptions.IgnoreCase); trackInfo.TrackEvents.Add(subEvent); } } return trackInfo; }
/// <summary> /// Credit: https://github.com/SubtitleEdit/subtitleedit/blob/master/src/Logic/SubtitleFormats/AdvancedSubStationAlpha.cs /// </summary> private void RemoteNativeFormatting(SubtitleTrackEvent p) { int indexOfBegin = p.Text.IndexOf('{'); string pre = string.Empty; while (indexOfBegin >= 0 && p.Text.IndexOf('}') > indexOfBegin) { string s = p.Text.Substring(indexOfBegin); if (s.StartsWith("{\\an1}", StringComparison.Ordinal) || s.StartsWith("{\\an2}", StringComparison.Ordinal) || s.StartsWith("{\\an3}", StringComparison.Ordinal) || s.StartsWith("{\\an4}", StringComparison.Ordinal) || s.StartsWith("{\\an5}", StringComparison.Ordinal) || s.StartsWith("{\\an6}", StringComparison.Ordinal) || s.StartsWith("{\\an7}", StringComparison.Ordinal) || s.StartsWith("{\\an8}", StringComparison.Ordinal) || s.StartsWith("{\\an9}", StringComparison.Ordinal)) { pre = s.Substring(0, 6); } else if (s.StartsWith("{\\an1\\", StringComparison.Ordinal) || s.StartsWith("{\\an2\\", StringComparison.Ordinal) || s.StartsWith("{\\an3\\", StringComparison.Ordinal) || s.StartsWith("{\\an4\\", StringComparison.Ordinal) || s.StartsWith("{\\an5\\", StringComparison.Ordinal) || s.StartsWith("{\\an6\\", StringComparison.Ordinal) || s.StartsWith("{\\an7\\", StringComparison.Ordinal) || s.StartsWith("{\\an8\\", StringComparison.Ordinal) || s.StartsWith("{\\an9\\", StringComparison.Ordinal)) { pre = s.Substring(0, 5) + "}"; } int indexOfEnd = p.Text.IndexOf('}'); p.Text = p.Text.Remove(indexOfBegin, (indexOfEnd - indexOfBegin) + 1); indexOfBegin = p.Text.IndexOf('{'); } p.Text = pre + p.Text; }
public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) { var trackInfo = new SubtitleTrackInfo(); using (var reader = new StreamReader(stream)) { bool eventsStarted = false; string[] format = "Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text".Split(','); int indexLayer = 0; int indexStart = 1; int indexEnd = 2; int indexStyle = 3; int indexName = 4; int indexEffect = 8; int indexText = 9; int lineNumber = 0; var header = new StringBuilder(); string line; while ((line = reader.ReadLine()) != null) { cancellationToken.ThrowIfCancellationRequested(); lineNumber++; if (!eventsStarted) header.AppendLine(line); if (line.Trim().ToLower() == "[events]") { eventsStarted = true; } else if (!string.IsNullOrEmpty(line) && line.Trim().StartsWith(";")) { // skip comment lines } else if (eventsStarted && line.Trim().Length > 0) { string s = line.Trim().ToLower(); if (s.StartsWith("format:")) { if (line.Length > 10) { format = line.ToLower().Substring(8).Split(','); for (int i = 0; i < format.Length; i++) { if (format[i].Trim().ToLower() == "layer") indexLayer = i; else if (format[i].Trim().ToLower() == "start") indexStart = i; else if (format[i].Trim().ToLower() == "end") indexEnd = i; else if (format[i].Trim().ToLower() == "text") indexText = i; else if (format[i].Trim().ToLower() == "effect") indexEffect = i; else if (format[i].Trim().ToLower() == "style") indexStyle = i; } } } else if (!string.IsNullOrEmpty(s)) { string text = string.Empty; string start = string.Empty; string end = string.Empty; string style = string.Empty; string layer = string.Empty; string effect = string.Empty; string name = string.Empty; string[] splittedLine; if (s.StartsWith("dialogue:")) splittedLine = line.Substring(10).Split(','); else splittedLine = line.Split(','); for (int i = 0; i < splittedLine.Length; i++) { if (i == indexStart) start = splittedLine[i].Trim(); else if (i == indexEnd) end = splittedLine[i].Trim(); else if (i == indexLayer) layer = splittedLine[i]; else if (i == indexEffect) effect = splittedLine[i]; else if (i == indexText) text = splittedLine[i]; else if (i == indexStyle) style = splittedLine[i]; else if (i == indexName) name = splittedLine[i]; else if (i > indexText) text += "," + splittedLine[i]; } try { var p = new SubtitleTrackEvent(); p.StartPositionTicks = GetTimeCodeFromString(start); p.EndPositionTicks = GetTimeCodeFromString(end); p.Text = GetFormattedText(text); trackInfo.TrackEvents.Add(p); } catch { } } } } //if (header.Length > 0) //subtitle.Header = header.ToString(); //subtitle.Renumber(1); } return trackInfo; }