using System; using System.Collections.Generic; using System.Text; using System.Xml; namespace Nikse.SubtitleEdit.Core.SubtitleFormats { // // ... // // // // // // // ... public class TmpegEncXml : SubtitleFormat { public override string Extension => ".xsubtitle"; public override string Name => "TMPGEnc VME"; public override bool IsMine(List lines, string fileName) { var sb = new StringBuilder(); lines.ForEach(line => sb.AppendLine(line)); string xmlAsString = sb.ToString().Trim(); if ((xmlAsString.Contains("") || xmlAsString.Contains(" [Position] [FontHeight] 17588159451135 0 0 0 0 1 2 0 1 0.005 0 1 0 0.005 0 1 0 1000 0 1000 0 1 0 [Position] [FontHeight] 17588159451135 0 0 0 0 1 0 0 1 0.005 0 1 0 0.005 0 1 0 1000 0 1000 0 1 0 [Position] [FontHeight] 17588159451135 0 0 0 0 0 1 1 1 0.005 0 1 0 0.005 0 1 0 1000 0 1000 0 1 1 [Position] [FontHeight] 17588159451135 0 0 0 0 2 1 1 1 0.005 0 1 0 0.005 0 1 0 1000 0 1000 0 1 1 [Position] [FontHeight] 17588159451135 0 1 0 0 1 2 0 1 0.005 0 1 0 0.005 0 1 0 1000 0 1000 0 1 0 @ " .Replace("[FontName]", Configuration.Settings.SubtitleSettings.TmpegEncXmlFontName) .Replace("[FontHeight]", Configuration.Settings.SubtitleSettings.TmpegEncXmlFontHeight) .Replace("[Position]", Configuration.Settings.SubtitleSettings.TmpegEncXmlPosition); public override string ToText(Subtitle subtitle, string title) { var xmlStructure = Layout.Replace('\'', '"'); var xml = new XmlDocument(); xml.LoadXml(xmlStructure); XmlNode div = xml.DocumentElement.SelectSingleNode("Subtitle"); div.InnerXml = string.Empty; int no = 0; foreach (Paragraph p in subtitle.Paragraphs) { XmlNode paragraph = xml.CreateElement("SubtitleItem"); var text = HtmlUtil.RemoveHtmlTags(p.Text, true); paragraph.InnerText = text; paragraph.InnerXml = ""; XmlAttribute layoutIndex = xml.CreateAttribute("layoutindex"); if (p.Text.TrimStart().StartsWith("", StringComparison.OrdinalIgnoreCase) && p.Text.TrimEnd().EndsWith("", StringComparison.OrdinalIgnoreCase)) { layoutIndex.InnerText = "4"; } else { layoutIndex.InnerText = "0"; } paragraph.Attributes.Append(layoutIndex); XmlAttribute enable = xml.CreateAttribute("enable"); enable.InnerText = "1"; paragraph.Attributes.Append(enable); XmlAttribute start = xml.CreateAttribute("starttime"); start.InnerText = p.StartTime.ToString(); paragraph.Attributes.Append(start); XmlAttribute end = xml.CreateAttribute("endtime"); end.InnerText = p.EndTime.ToString(); paragraph.Attributes.Append(end); div.AppendChild(paragraph); no++; } string s = ToUtf8XmlString(xml); var startPos = s.IndexOf("", StringComparison.Ordinal) + 10; s = s.Substring(startPos, s.IndexOf("", StringComparison.Ordinal) - startPos).Trim(); return Layout.Replace("@", s); } public override void LoadSubtitle(Subtitle subtitle, List lines, string fileName) { LoadTMpeg(subtitle, lines, false); } internal void LoadTMpeg(Subtitle subtitle, List lines, bool mustHaveLineBreakAsEnd) { _errorCount = 0; double startSeconds = 0; var sb = new StringBuilder(); lines.ForEach(line => sb.AppendLine(line)); var xml = new XmlDocument { XmlResolver = null }; xml.LoadXml(sb.ToString().Trim()); var italicStyles = new List(); foreach (XmlNode node in xml.DocumentElement.SelectNodes("Layout/LayoutItem")) { XmlNode fontItalic = node.SelectSingleNode("FontItalic"); if (fontItalic != null && fontItalic.InnerText == "1") { italicStyles.Add(true); } else { italicStyles.Add(false); } } foreach (XmlNode node in xml.DocumentElement.SelectNodes("Subtitle/SubtitleItem")) { try { var pText = new StringBuilder(); foreach (XmlNode innerNode in node.SelectSingleNode("Text").ChildNodes) { if (innerNode.Name == "br") { pText.AppendLine(); } else { pText.Append(innerNode.InnerText.Trim()); } } var start = string.Empty; if (node.Attributes["starttime"] != null) { start = node.Attributes["starttime"].InnerText; } var end = string.Empty; if (node.Attributes["endtime"] != null) { end = node.Attributes["endtime"].InnerText; } var startCode = TimeCode.FromSeconds(startSeconds); if (start.Length > 0) { startCode = GetTimeCode(start); } TimeCode endCode; if (end.Length > 0) { endCode = GetTimeCode(end); } else { endCode = new TimeCode(startCode.TotalMilliseconds + 3000); } startSeconds = endCode.TotalSeconds; if (mustHaveLineBreakAsEnd) { if (!pText.ToString().EndsWith("\\n", StringComparison.Ordinal)) { _errorCount++; } } else { if (pText.ToString().EndsWith("\\n", StringComparison.Ordinal)) { _errorCount++; } } var p = new Paragraph(startCode, endCode, pText.ToString().Trim().Replace("", string.Empty).Replace("", string.Empty).Replace("\\n", Environment.NewLine).TrimEnd()); if (node.Attributes["layoutindex"] != null) { if (int.TryParse(node.Attributes["layoutindex"].InnerText, out var idx)) { if (idx >= 0 && idx < italicStyles.Count && italicStyles[idx]) { p.Text = "" + p.Text + ""; } } } subtitle.Paragraphs.Add(p); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); _errorCount++; } } subtitle.Renumber(); } private static TimeCode GetTimeCode(string s) { if (s.EndsWith('s')) { s = s.TrimEnd('s'); return TimeCode.FromSeconds(double.Parse(s)); } string[] parts = s.Split(':', '.', ','); return new TimeCode(int.Parse(parts[0]), int.Parse(parts[1]), int.Parse(parts[2]), int.Parse(parts[3])); } } }