From b7fb7251b14841d38aa27c5df7af41a5803289c4 Mon Sep 17 00:00:00 2001 From: niksedk Date: Sat, 20 Sep 2014 08:44:59 +0200 Subject: [PATCH] Working on FCP format --- .gitignore | 1 + .../SubtitleFormats/FinalCutProXml14Text.cs | 175 ++++++++++++++++++ src/Logic/SubtitleFormats/SubtitleFormat.cs | 1 + src/SubtitleEdit.csproj | 1 + 4 files changed, 178 insertions(+) create mode 100644 src/Logic/SubtitleFormats/FinalCutProXml14Text.cs diff --git a/.gitignore b/.gitignore index 2902cc17f..4392ddc50 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ SubtitleEdit-*-setup.exe /SubtitleEdit.tar /SubtitleEdit.tgz /tabspace.exe +/src/Languages/LanguageMaster.xml diff --git a/src/Logic/SubtitleFormats/FinalCutProXml14Text.cs b/src/Logic/SubtitleFormats/FinalCutProXml14Text.cs new file mode 100644 index 000000000..3391f4254 --- /dev/null +++ b/src/Logic/SubtitleFormats/FinalCutProXml14Text.cs @@ -0,0 +1,175 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; +using System.Xml; + +namespace Nikse.SubtitleEdit.Logic.SubtitleFormats +{ + public class FinalCutProXml14Text : SubtitleFormat + { + public double FrameRate { get; set; } + + public override string Extension + { + get { return ".fcpxml"; } + } + + public override string Name + { + get { return "Final Cut Pro Xml 1.4 Text"; } + } + + public override bool IsTimeBased + { + get { return true; } + } + + public override bool IsMine(List lines, string fileName) + { + var subtitle = new Subtitle(); + LoadSubtitle(subtitle, lines, fileName); + return subtitle.Paragraphs.Count > 0; + } + + public override string ToText(Subtitle subtitle, string title) + { + if (Configuration.Settings.General.CurrentFrameRate > 26) + FrameRate = 30; + else + FrameRate = 25; + + string xmlStructure = + "" + Environment.NewLine + + "" + Environment.NewLine + + Environment.NewLine + + "" + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + +// " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + " " + Environment.NewLine + + ""; + + string xmlClipStructure = + "" + Environment.NewLine + + " <param name=\"Position\" key=\"9999/999166631/999166633/1/100/101\" value=\"-1.67499 -470.934\"/>" + Environment.NewLine + + " <text>" + Environment.NewLine + + " <text-style ref=\"ts[NUMBER]\">THE NOISEMAKER</text-style>" + Environment.NewLine + + " </text>" + Environment.NewLine + + " <text-style-def id=\"ts[NUMBER]\">" + Environment.NewLine + + " <text-style font=\"Lucida Grande\" fontSize=\"36\" fontFace=\"Regular\" fontColor=\"0.793266 0.793391 0.793221 1\" baseline=\"29\" shadowColor=\"0 0 0 1\" shadowOffset=\"5 315\" alignment=\"center\"/>" + Environment.NewLine + + " </text-style-def>" + Environment.NewLine + + ""; + + var xml = new XmlDocument(); + xml.LoadXml(xmlStructure); + XmlNode videoNode = xml.DocumentElement.SelectSingleNode("//project/sequence/spine/gap"); + int number = 1; + foreach (Paragraph p in subtitle.Paragraphs) + { + XmlNode video = xml.CreateElement("video"); + video.InnerXml = xmlClipStructure.Replace("[NUMBER]", number.ToString(CultureInfo.InvariantCulture)).Replace("[TITLEID]", Utilities.RemoveHtmlTags(p.Text.Replace(Environment.NewLine," ").Replace(" ", " "), true)); + + XmlNode generatorNode = video.SelectSingleNode("title"); + generatorNode.Attributes["offset"].Value = Convert.ToInt64(p.StartTime.TotalSeconds * 2400000) + "/2400000s"; + generatorNode.Attributes["duration"].Value = Convert.ToInt64(p.Duration.TotalSeconds * 2400000) + "/2400000s"; + generatorNode.Attributes["start"].Value = Convert.ToInt64(p.StartTime.TotalSeconds * 2400000) + "/2400000s"; + + XmlNode param = video.SelectSingleNode("title/text/text-style"); + param.InnerText = Utilities.RemoveHtmlTags(p.Text); + + videoNode.AppendChild(generatorNode); + number++; + } + + string xmlAsText = ToUtf8XmlString(xml); + xmlAsText = xmlAsText.Replace("fcpxml[]", "fcpxml"); + xmlAsText = xmlAsText.Replace("fcpxml []", "fcpxml"); + return xmlAsText; + } + + public override void LoadSubtitle(Subtitle subtitle, List lines, string fileName) + { + _errorCount = 0; + FrameRate = Configuration.Settings.General.CurrentFrameRate; + + var sb = new StringBuilder(); + lines.ForEach(line => sb.AppendLine(line)); + string x = sb.ToString(); + if (!x.Contains("") && !x.Contains("")) + return; + + var xml = new XmlDocument(); + try + { + xml.LoadXml(x.Trim()); + + if (subtitle.Paragraphs.Count == 0) + { + foreach (XmlNode node in xml.SelectNodes("//project/sequence/spine/gap/title/text")) + { + try + { + string text = node.ParentNode.InnerText; + Paragraph p = new Paragraph(); + p.Text = text.Trim(); + p.StartTime = DecodeTime(node.ParentNode.Attributes["offset"]); + p.EndTime.TotalMilliseconds = p.StartTime.TotalMilliseconds + DecodeTime(node.ParentNode.Attributes["duration"]).TotalMilliseconds; + bool add = true; + if (subtitle.Paragraphs.Count > 0) + { + var prev = subtitle.Paragraphs[subtitle.Paragraphs.Count - 1]; + if (prev.Text == p.Text && prev.StartTime.TotalMilliseconds == p.StartTime.TotalMilliseconds) + add = false; + } + if (add) + subtitle.Paragraphs.Add(p); + } + catch + { + _errorCount++; + } + } + } + subtitle.Renumber(1); + } + catch + { + _errorCount = 1; + return; + } + } + + private static TimeCode DecodeTime(XmlAttribute duration) + { + // 220220/60000s + if (duration != null) + { + var arr = duration.Value.TrimEnd('s').Split('/'); + if (arr.Length == 2) + { + return TimeCode.FromSeconds(long.Parse(arr[0]) / double.Parse(arr[1])); + } + else if (arr.Length == 1) + { + return TimeCode.FromSeconds(float.Parse(arr[0])); + } + } + return new TimeCode(0, 0, 0, 0); + } + + } +} \ No newline at end of file diff --git a/src/Logic/SubtitleFormats/SubtitleFormat.cs b/src/Logic/SubtitleFormats/SubtitleFormat.cs index 479da25e3..a17b74858 100644 --- a/src/Logic/SubtitleFormats/SubtitleFormat.cs +++ b/src/Logic/SubtitleFormats/SubtitleFormat.cs @@ -65,6 +65,7 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats new FinalCutProXCM(), new FinalCutProXml13(), new FinalCutProXml14(), + new FinalCutProXml14Text(), new FinalCutProTestXml(), new FinalCutProTest2Xml(), new FlashXml(), diff --git a/src/SubtitleEdit.csproj b/src/SubtitleEdit.csproj index 1bab05b72..a08dfdb2b 100644 --- a/src/SubtitleEdit.csproj +++ b/src/SubtitleEdit.csproj @@ -889,6 +889,7 @@ +