using System; using System.Collections.Generic; using System.Text; using System.Text.RegularExpressions; namespace Nikse.SubtitleEdit.Core.SubtitleFormats { /// /// MicroDVD with time codes...? /// public class UnknownSubtitle11 : SubtitleFormat { private static readonly Regex RegexMicroDvdLine = new Regex(@"^\{-?\d+:\d+:\d+}\{-?\d+:\d+:\d+}.*$", RegexOptions.Compiled); public override string Extension => ".sub"; public override string Name => "Unknown 11"; public override bool IsMine(List lines, string fileName) { var trimmedLines = new List(); int errors = 0; foreach (string line in lines) { if (line.Contains('{')) { string s = RemoveIllegalSpacesAndFixEmptyCodes(line); if (RegexMicroDvdLine.IsMatch(s)) { trimmedLines.Add(s); } else { errors++; } } else { errors++; } } return trimmedLines.Count > errors; } private static string RemoveIllegalSpacesAndFixEmptyCodes(string line) { int index = line.IndexOf('}'); if (index >= 0 && index < line.Length) { index = line.IndexOf('}', index + 1); if (index >= 0 && index + 1 < line.Length) { var indexOfBrackets = line.IndexOf("{}", StringComparison.Ordinal); if (indexOfBrackets >= 0 && indexOfBrackets < index) { line = line.Insert(indexOfBrackets + 1, "0"); // set empty time codes to zero index++; } while (line.Contains(' ') && line.IndexOf(' ') < index) { line = line.Remove(line.IndexOf(' '), 1); index--; } } } return line; } private static string MakeTimeCode(TimeCode tc) { return string.Format("{0}:{1:00}:{2:00}", tc.Hours, tc.Minutes, tc.Seconds); } public override string ToText(Subtitle subtitle, string title) { var sb = new StringBuilder(); foreach (Paragraph p in subtitle.Paragraphs) { sb.Append('{'); sb.Append(MakeTimeCode(p.StartTime)); sb.Append("}{"); sb.Append(MakeTimeCode(p.EndTime)); sb.Append('}'); //{y:b} is italics for single line //{Y:b} is italics for both lines var parts = p.Text.SplitToLines(); int count = 0; bool italicOn = false; bool boldOn = false; bool underlineOn = false; var lineSb = new StringBuilder(); foreach (string line in parts) { if (count > 0) { lineSb.Append('|'); } if (line.StartsWith("") || italicOn) { italicOn = true; boldOn = false; underlineOn = false; lineSb.Append("{y:i}"); // italic single line } else if (line.StartsWith("") || boldOn) { italicOn = false; boldOn = true; underlineOn = false; lineSb.Append("{y:b}"); // bold single line } else if (line.StartsWith("") || underlineOn) { italicOn = false; boldOn = false; underlineOn = true; lineSb.Append("{y:u}"); // underline single line } if (line.Contains("")) { italicOn = false; } if (line.Contains("")) { boldOn = false; } if (line.Contains("")) { underlineOn = false; } lineSb.Append(HtmlUtil.RemoveHtmlTags(line)); count++; } string text = lineSb.ToString(); int noOfLines = Utilities.CountTagInText(text, '|') + 1; if (noOfLines > 1 && Utilities.CountTagInText(text, "{y:i}") == noOfLines) { text = "{Y:i}" + text.Replace("{y:i}", string.Empty); } else if (noOfLines > 1 && Utilities.CountTagInText(text, "{y:b}") == noOfLines) { text = "{Y:b}" + text.Replace("{y:b}", string.Empty); } else if (noOfLines > 1 && Utilities.CountTagInText(text, "{y:u}") == noOfLines) { text = "{Y:u}" + text.Replace("{y:u}", string.Empty); } sb.AppendLine(HtmlUtil.RemoveHtmlTags(text)); } return sb.ToString().Trim(); } private static TimeCode DecodeTimeCode(string timeCode) { string[] arr = timeCode.Split(SplitCharColon, StringSplitOptions.RemoveEmptyEntries); return new TimeCode(int.Parse(arr[0]), int.Parse(arr[1]), int.Parse(arr[2]), 0); } public override void LoadSubtitle(Subtitle subtitle, List lines, string fileName) { _errorCount = 0; foreach (string line in lines) { string s = RemoveIllegalSpacesAndFixEmptyCodes(line); if (RegexMicroDvdLine.IsMatch(s)) { try { int textIndex = GetTextStartIndex(s); if (textIndex < s.Length) { string text = s.Substring(textIndex); string temp = s.Substring(0, textIndex - 1); string[] frames = temp.Replace("}{", ";").Replace("{", string.Empty).Replace("}", string.Empty).Split(';'); TimeCode startTime = DecodeTimeCode(frames[0]); TimeCode endTime = DecodeTimeCode(frames[1]); string post = string.Empty; string[] parts = text.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); int count = 0; var lineSb = new StringBuilder(); foreach (string s2 in parts) { if (count > 0) { lineSb.AppendLine(); } s = s2.Trim(); if (s.StartsWith("{Y:i}")) { s = "" + s.Replace("{Y:i}", string.Empty); post += ""; } else if (s.StartsWith("{Y:b}")) { s = "" + s.Replace("{Y:b}", string.Empty); post += ""; } else if (s.StartsWith("{Y:u}")) { s = "" + s.Replace("{Y:u}", string.Empty); post += ""; } else if (s.StartsWith("{y:i}")) { s = "" + s.Replace("{y:i}", string.Empty) + ""; } else if (s.StartsWith("{y:b}")) { s = "" + s.Replace("{y:b}", string.Empty) + ""; } else if (s.StartsWith("{y:u}")) { s = "" + s.Replace("{y:u}", string.Empty) + ""; } s = s.Replace("{Y:i}", string.Empty).Replace("{y:i}", string.Empty); s = s.Replace("{Y:b}", string.Empty).Replace("{y:b}", string.Empty); s = s.Replace("{Y:u}", string.Empty).Replace("{y:u}", string.Empty); lineSb.Append(s); count++; } text = lineSb + post; subtitle.Paragraphs.Add(new Paragraph(startTime, endTime, text)); } } catch { _errorCount++; } } else { _errorCount++; } } int i = 0; foreach (Paragraph p in subtitle.Paragraphs) { Paragraph previous = subtitle.GetParagraphOrDefault(i - 1); if (p.StartTime.TotalMilliseconds == 0 && previous != null) { p.StartTime.TotalMilliseconds = previous.EndTime.TotalMilliseconds + 1; } if (p.EndTime.TotalMilliseconds == 0) { p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds; } i++; } subtitle.Renumber(); } private static int GetTextStartIndex(string line) { int i = 0; int tagCount = 0; while (i < line.Length && tagCount < 4) { if (line[i] == '{' || line[i] == '}') { tagCount++; } i++; } return i; } } }