using System; using System.Collections.Generic; using System.Text; using System.Xml; namespace Nikse.SubtitleEdit.Core.SubtitleFormats { public class FinalCutProXml13 : SubtitleFormat { public double FrameRate { get; set; } public override string Extension { get { return ".fcpxml"; } } public override string Name { get { return "Final Cut Pro Xml 1.3"; } } 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 + ""; string xmlClipStructure = " "; var xml = new XmlDocument(); xml.LoadXml(xmlStructure); XmlNode videoNode = xml.DocumentElement.SelectSingleNode("project/sequence/spine"); int number = 1; foreach (Paragraph p in subtitle.Paragraphs) { XmlNode clip = xml.CreateElement("clip"); clip.InnerXml = xmlClipStructure; var attr = xml.CreateAttribute("name"); attr.Value = title; clip.Attributes.Append(attr); attr = xml.CreateAttribute("duration"); //attr.Value = "9529520/2400000s"; attr.Value = Convert.ToInt64(p.Duration.TotalSeconds * 2400000) + "/2400000s"; clip.Attributes.Append(attr); attr = xml.CreateAttribute("start"); //attr.Value = "1201200/2400000s"; attr.Value = Convert.ToInt64(p.StartTime.TotalSeconds * 2400000) + "/2400000s"; clip.Attributes.Append(attr); attr = xml.CreateAttribute("audioStart"); attr.Value = "0s"; clip.Attributes.Append(attr); attr = xml.CreateAttribute("audioDuration"); attr.Value = Convert.ToInt64(p.Duration.TotalSeconds * 2400000) + "/2400000s"; clip.Attributes.Append(attr); attr = xml.CreateAttribute("tcFormat"); attr.Value = "NDF"; clip.Attributes.Append(attr); XmlNode titleNode = clip.SelectSingleNode("video"); titleNode.Attributes["offset"].Value = Convert.ToInt64(p.StartTime.TotalSeconds * 60000) + "/60000s"; titleNode.Attributes["name"].Value = HtmlUtil.RemoveHtmlTags(p.Text); titleNode.Attributes["duration"].Value = Convert.ToInt64(p.Duration.TotalSeconds * 60000) + "/60000s"; titleNode.Attributes["start"].Value = Convert.ToInt64(p.StartTime.TotalSeconds * 60000) + "/60000s"; XmlNode param = clip.SelectSingleNode("video/param"); param.Attributes["value"].InnerText = HtmlUtil.RemoveHtmlTags(p.Text); videoNode.AppendChild(clip); 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(" 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(); } catch (Exception exception) { System.Diagnostics.Debug.WriteLine(exception.Message); _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); } } }