mirror of
https://github.com/SubtitleEdit/subtitleedit.git
synced 2024-11-24 04:02:36 +01:00
479 lines
19 KiB
C#
479 lines
19 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Text;
|
|
using System.Xml;
|
|
|
|
namespace Nikse.SubtitleEdit.Core.SubtitleFormats
|
|
{
|
|
public abstract class SubtitleFormat
|
|
{
|
|
private static IList<SubtitleFormat> _allSubtitleFormats;
|
|
|
|
protected static readonly char[] SplitCharColon = { ':' };
|
|
|
|
/// <summary>
|
|
/// Text formats supported by Subtitle Edit
|
|
/// </summary>
|
|
public static IEnumerable<SubtitleFormat> AllSubtitleFormats
|
|
{
|
|
get
|
|
{
|
|
if (_allSubtitleFormats != null)
|
|
return _allSubtitleFormats;
|
|
|
|
_allSubtitleFormats = new List<SubtitleFormat>
|
|
{
|
|
new SubRip(),
|
|
new AbcIViewer(),
|
|
new AdobeAfterEffectsFTME(),
|
|
new AdobeEncore(),
|
|
new AdobeEncoreLineTabNewLine(),
|
|
new AdobeEncoreTabs(),
|
|
new AdobeEncoreWithLineNumbers(),
|
|
new AdobeEncoreWithLineNumbersNtsc(),
|
|
new AdvancedSubStationAlpha(),
|
|
new AQTitle(),
|
|
new AvidCaption(),
|
|
new AvidDvd(),
|
|
new BelleNuitSubtitler(),
|
|
new Cappella(),
|
|
new CaptionAssistant(),
|
|
new Captionate(),
|
|
new CaptionateMs(),
|
|
new CaraokeXml(),
|
|
new Csv(),
|
|
new Csv2(),
|
|
new Csv3(),
|
|
new Csv4(),
|
|
new Csv5(),
|
|
new CsvNuendo(),
|
|
new DCinemaInterop(),
|
|
new DCinemaSmpte2010(),
|
|
new DCinemaSmpte2007(),
|
|
new DigiBeta(),
|
|
new DvdStudioPro(),
|
|
new DvdStudioProSpaceOne(),
|
|
new DvdStudioProSpaceOneSemicolon(),
|
|
new DvdStudioProSpace(),
|
|
new DvdSubtitle(),
|
|
new DvdSubtitleSystem(),
|
|
new Ebu(),
|
|
new Edl(),
|
|
new Eeg708(),
|
|
new ElrPrint(),
|
|
new F4Text(),
|
|
new F4Rtf(),
|
|
new F4Xml(),
|
|
new FabSubtitler(),
|
|
new FilmEditXml(),
|
|
new FinalCutProXml(),
|
|
new FinalCutProXXml(),
|
|
new FinalCutProXmlGap(),
|
|
new FinalCutProXCM(),
|
|
new FinalCutProXml13(),
|
|
new FinalCutProXml14(),
|
|
new FinalCutProXml14Text(),
|
|
new FinalCutProXml15(),
|
|
new FinalCutProXml16(),
|
|
new FinalCutProXml17(),
|
|
new FinalCutProTestXml(),
|
|
new FinalCutProTest2Xml(),
|
|
new FlashXml(),
|
|
new FLVCoreCuePoints(),
|
|
new Footage(),
|
|
new GpacTtxt(),
|
|
new Gremots(),
|
|
new ImageLogicAutocaption(),
|
|
new IssXml(),
|
|
new ItunesTimedText(),
|
|
new JacoSub(),
|
|
new JsonTed(),
|
|
new Json(),
|
|
new JsonType2(),
|
|
new JsonType3(),
|
|
new JsonType4(),
|
|
new JsonType5(),
|
|
new JsonType6(),
|
|
new JsonType7(),
|
|
new JsonType8(),
|
|
new JsonType9(),
|
|
new JsonType10(),
|
|
new JsonType11(),
|
|
new JsonType12(),
|
|
new JsonType13(),
|
|
new KanopyHtml(),
|
|
new LambdaCap(),
|
|
new Lrc(),
|
|
new MacSub(),
|
|
new MediaTransData(),
|
|
new MicroDvd(),
|
|
new MidwayInscriberCGX(),
|
|
new MPlayer2(),
|
|
new NciTimedRollUpCaptions(),
|
|
new NetflixTimedText(),
|
|
new OpenDvt(),
|
|
new Oresme(),
|
|
new OresmeDocXDocument(),
|
|
new Pe2(),
|
|
new PhoenixSubtitle(),
|
|
new PinnacleImpression(),
|
|
new PListCaption(),
|
|
new QubeMasterImport(),
|
|
new QuickTimeText(),
|
|
new RealTime(),
|
|
new RhozetHarmonic(),
|
|
new Rtf1(),
|
|
new Rtf2(),
|
|
new Sami(),
|
|
new SamiAvDicPlayer(),
|
|
new SamiModern(),
|
|
new SamiYouTube(),
|
|
new Scenarist(),
|
|
new ScenaristClosedCaptions(),
|
|
new ScenaristClosedCaptionsDropFrame(),
|
|
new SmilTimesheetData(),
|
|
new SmpteTt2052(),
|
|
new SoftNiSub(),
|
|
new SoftNicolonSub(),
|
|
new SonyDVDArchitect(),
|
|
new SonyDVDArchitectExplicitDuration(),
|
|
new SonyDVDArchitectLineAndDuration(),
|
|
new SonyDVDArchitectLineDurationLength(),
|
|
new SonyDVDArchitectTabs(),
|
|
new SonyDVDArchitectWithLineNumbers(),
|
|
new Spruce(),
|
|
new SpruceWithSpace(),
|
|
new StructuredTitles(),
|
|
new SubStationAlpha(),
|
|
new SubtitleEditorProject(),
|
|
new SubUrbia(),
|
|
new SubViewer10(),
|
|
new SubViewer20(),
|
|
new SwiftInterchange2(),
|
|
new SwiftText(),
|
|
new SwiftTextLineNumber(),
|
|
new SwiftTextLineNOAndDur(),
|
|
new Tek(),
|
|
new TimeXml(),
|
|
new TimeXml2(),
|
|
new TimedText10(),
|
|
new TimedText200604(),
|
|
new TimedText200604CData(),
|
|
new TimedText(),
|
|
new TitleExchangePro(),
|
|
new Titra(),
|
|
new TmpegEncText(),
|
|
new TmpegEncAW5(),
|
|
new TmpegEncXml(),
|
|
new TMPlayer(),
|
|
new TranscriberXml(),
|
|
new Tmx14(),
|
|
new TurboTitler(),
|
|
new UniversalSubtitleFormat(),
|
|
new UTSubtitleXml(),
|
|
new Utx(),
|
|
new UtxFrames(),
|
|
new UleadSubtitleFormat(),
|
|
new VocapiaSplit(),
|
|
new WebVTT(),
|
|
new WebVTTFileWithLineNumber(),
|
|
new Xif(),
|
|
new YouTubeAnnotations(),
|
|
new YouTubeSbv(),
|
|
new YouTubeTranscript(),
|
|
new YouTubeTranscriptOneLine(),
|
|
new ZeroG(),
|
|
// new Idx(),
|
|
new UnknownSubtitle1(),
|
|
new UnknownSubtitle2(),
|
|
new UnknownSubtitle3(),
|
|
new UnknownSubtitle4(),
|
|
new UnknownSubtitle5(),
|
|
new UnknownSubtitle6(),
|
|
new UnknownSubtitle7(),
|
|
new UnknownSubtitle8(),
|
|
new UnknownSubtitle9(),
|
|
new UnknownSubtitle10(),
|
|
new UnknownSubtitle11(),
|
|
new UnknownSubtitle12(),
|
|
new UnknownSubtitle13(),
|
|
new UnknownSubtitle14(),
|
|
new UnknownSubtitle15(),
|
|
new UnknownSubtitle16(),
|
|
new UnknownSubtitle17(),
|
|
new UnknownSubtitle18(),
|
|
new UnknownSubtitle19(),
|
|
new UnknownSubtitle20(),
|
|
new UnknownSubtitle21(),
|
|
new UnknownSubtitle22(),
|
|
new UnknownSubtitle23(),
|
|
new UnknownSubtitle24(),
|
|
new UnknownSubtitle25(),
|
|
new UnknownSubtitle26(),
|
|
new UnknownSubtitle27(),
|
|
new UnknownSubtitle28(),
|
|
new UnknownSubtitle29(),
|
|
new UnknownSubtitle30(),
|
|
new UnknownSubtitle31(),
|
|
new UnknownSubtitle32(),
|
|
new UnknownSubtitle33(),
|
|
new UnknownSubtitle34(),
|
|
new UnknownSubtitle35(),
|
|
new UnknownSubtitle36(),
|
|
new UnknownSubtitle37(),
|
|
new UnknownSubtitle38(),
|
|
new UnknownSubtitle39(),
|
|
new UnknownSubtitle40(),
|
|
new UnknownSubtitle41(),
|
|
new UnknownSubtitle42(),
|
|
new UnknownSubtitle43(),
|
|
new UnknownSubtitle44(),
|
|
new UnknownSubtitle45(),
|
|
new UnknownSubtitle46(),
|
|
new UnknownSubtitle47(),
|
|
new UnknownSubtitle48(),
|
|
new UnknownSubtitle49(),
|
|
new UnknownSubtitle50(),
|
|
new UnknownSubtitle51(),
|
|
new UnknownSubtitle52(),
|
|
new UnknownSubtitle53(),
|
|
new UnknownSubtitle54(),
|
|
new UnknownSubtitle55(),
|
|
new UnknownSubtitle56(),
|
|
new UnknownSubtitle57(),
|
|
new UnknownSubtitle58(),
|
|
new UnknownSubtitle59(),
|
|
new UnknownSubtitle60(),
|
|
new UnknownSubtitle61(),
|
|
new UnknownSubtitle62(),
|
|
new UnknownSubtitle63(),
|
|
new UnknownSubtitle64(),
|
|
new UnknownSubtitle65(),
|
|
new UnknownSubtitle66(),
|
|
new UnknownSubtitle67(),
|
|
new UnknownSubtitle68(),
|
|
new UnknownSubtitle69(),
|
|
new UnknownSubtitle70(),
|
|
new UnknownSubtitle71(),
|
|
new UnknownSubtitle72(),
|
|
new UnknownSubtitle73(),
|
|
new UnknownSubtitle74(),
|
|
new UnknownSubtitle75(),
|
|
new UnknownSubtitle76(),
|
|
new UnknownSubtitle77(),
|
|
new UnknownSubtitle78(),
|
|
new UnknownSubtitle79(),
|
|
new UnknownSubtitle80(),
|
|
new UnknownSubtitle81(),
|
|
new UnknownSubtitle82(),
|
|
new UnknownSubtitle83(),
|
|
new UnknownSubtitle84(),
|
|
new UnknownSubtitle85(),
|
|
new UnknownSubtitle86(),
|
|
new UnknownSubtitle87(),
|
|
};
|
|
|
|
string path = Configuration.PluginsDirectory;
|
|
if (Directory.Exists(path))
|
|
{
|
|
foreach (string pluginFileName in Directory.EnumerateFiles(path, "*.DLL"))
|
|
{
|
|
try
|
|
{
|
|
var assembly = System.Reflection.Assembly.Load(FileUtil.ReadAllBytesShared(pluginFileName));
|
|
if (assembly != null)
|
|
{
|
|
foreach (var exportedType in assembly.GetExportedTypes())
|
|
{
|
|
try
|
|
{
|
|
object pluginObject = Activator.CreateInstance(exportedType);
|
|
var po = pluginObject as SubtitleFormat;
|
|
if (po != null)
|
|
_allSubtitleFormats.Insert(1, po);
|
|
}
|
|
catch
|
|
{
|
|
// ignored
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
// ignored
|
|
}
|
|
}
|
|
}
|
|
|
|
return _allSubtitleFormats;
|
|
}
|
|
}
|
|
|
|
protected int _errorCount;
|
|
|
|
public abstract string Extension
|
|
{
|
|
get;
|
|
}
|
|
|
|
public abstract string Name
|
|
{
|
|
get;
|
|
}
|
|
|
|
public virtual bool IsTimeBased => true;
|
|
|
|
public bool IsFrameBased => !IsTimeBased;
|
|
|
|
public string FriendlyName => $"{Name} ({Extension})";
|
|
|
|
public int ErrorCount => _errorCount;
|
|
|
|
public virtual bool IsMine(List<string> lines, string fileName)
|
|
{
|
|
var subtitle = new Subtitle();
|
|
var oldFrameRate = Configuration.Settings.General.CurrentFrameRate;
|
|
LoadSubtitle(subtitle, lines, fileName);
|
|
Configuration.Settings.General.CurrentFrameRate = oldFrameRate;
|
|
return subtitle.Paragraphs.Count > _errorCount;
|
|
}
|
|
|
|
public abstract string ToText(Subtitle subtitle, string title);
|
|
|
|
public abstract void LoadSubtitle(Subtitle subtitle, List<string> lines, string fileName);
|
|
|
|
public bool IsVobSubIndexFile => Extension.Equals(".idx", StringComparison.Ordinal);
|
|
|
|
public virtual void RemoveNativeFormatting(Subtitle subtitle, SubtitleFormat newFormat)
|
|
{
|
|
}
|
|
|
|
public virtual List<string> AlternateExtensions => new List<string>();
|
|
|
|
public static int MillisecondsToFrames(double milliseconds)
|
|
{
|
|
return (int)Math.Round(milliseconds / (TimeCode.BaseUnit / Configuration.Settings.General.CurrentFrameRate));
|
|
}
|
|
|
|
public static int MillisecondsToFramesMaxFrameRate(double milliseconds)
|
|
{
|
|
int frames = (int)Math.Round(milliseconds / (TimeCode.BaseUnit / Configuration.Settings.General.CurrentFrameRate));
|
|
if (frames >= Configuration.Settings.General.CurrentFrameRate)
|
|
frames = (int)(Configuration.Settings.General.CurrentFrameRate - 0.01);
|
|
return frames;
|
|
}
|
|
|
|
public static int FramesToMilliseconds(double frames)
|
|
{
|
|
return (int)Math.Round(frames * (TimeCode.BaseUnit / Configuration.Settings.General.CurrentFrameRate));
|
|
}
|
|
|
|
public static int FramesToMillisecondsMax999(double frames)
|
|
{
|
|
int ms = (int)Math.Round(frames * (TimeCode.BaseUnit / Configuration.Settings.General.CurrentFrameRate));
|
|
return Math.Min(ms, 999);
|
|
}
|
|
|
|
public virtual bool HasStyleSupport => false;
|
|
|
|
public bool BatchMode { get; set; }
|
|
public double? BatchSourceFrameRate { get; set; }
|
|
|
|
public static string ToUtf8XmlString(XmlDocument xml, bool omitXmlDeclaration = false)
|
|
{
|
|
var settings = new XmlWriterSettings
|
|
{
|
|
Indent = true,
|
|
OmitXmlDeclaration = omitXmlDeclaration,
|
|
};
|
|
var result = new StringBuilder();
|
|
|
|
using (var xmlWriter = XmlWriter.Create(result, settings))
|
|
{
|
|
xml.Save(xmlWriter);
|
|
}
|
|
|
|
return result.ToString().Replace(" encoding=\"utf-16\"", " encoding=\"utf-8\"").Trim();
|
|
}
|
|
|
|
public virtual bool IsTextBased => true;
|
|
|
|
protected TimeCode DecodeTimeCodeFramesTwoParts(string[] tokens)
|
|
{
|
|
if (tokens == null)
|
|
return new TimeCode();
|
|
if (tokens.Length != 2)
|
|
throw new InvalidOperationException();
|
|
// 00:00
|
|
return new TimeCode(0, 0, int.Parse(tokens[0]), FramesToMillisecondsMax999(int.Parse(tokens[1])));
|
|
}
|
|
|
|
protected TimeCode DecodeTimeCodeFramesThreeParts(string[] tokens)
|
|
{
|
|
if (tokens == null)
|
|
return new TimeCode();
|
|
if (tokens.Length != 3)
|
|
throw new InvalidOperationException();
|
|
// 00:00:00
|
|
return new TimeCode(0, int.Parse(tokens[0]), int.Parse(tokens[1]), FramesToMillisecondsMax999(int.Parse(tokens[2])));
|
|
}
|
|
|
|
protected TimeCode DecodeTimeCodeFramesFourParts(string[] tokens)
|
|
{
|
|
if (tokens == null)
|
|
return new TimeCode();
|
|
if (tokens.Length != 4)
|
|
throw new InvalidOperationException();
|
|
// 00:00:00:00
|
|
return new TimeCode(int.Parse(tokens[0]), int.Parse(tokens[1]), int.Parse(tokens[2]), FramesToMillisecondsMax999(int.Parse(tokens[3])));
|
|
}
|
|
|
|
protected TimeCode DecodeTimeCodeFrames(string timestamp, char[] splitChars)
|
|
{
|
|
return DecodeTimeCodeFramesFourParts(timestamp.Split(splitChars, StringSplitOptions.RemoveEmptyEntries));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Load subtitle type of 'formats' from file.
|
|
/// </summary>
|
|
/// <param name="formats">List of possible formats</param>
|
|
/// <param name="fileName">Name of subtitle file</param>
|
|
/// <param name="subtitle">Subtitle to load file into</param>
|
|
/// <returns>The format of the file, null of not format match found</returns>
|
|
public static SubtitleFormat LoadSubtitleFromFile(SubtitleFormat[] formats, string fileName, Subtitle subtitle)
|
|
{
|
|
if (formats == null || formats.Length == 0 || string.IsNullOrEmpty(fileName))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var list = new List<string>(File.ReadAllLines(fileName, LanguageAutoDetect.GetEncodingFromFile(fileName)));
|
|
foreach (var subtitleFormat in formats)
|
|
{
|
|
if (subtitleFormat.IsMine(list, fileName))
|
|
{
|
|
subtitleFormat.LoadSubtitle(subtitle, list, fileName);
|
|
return subtitleFormat;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public static SubtitleFormat[] BinaryFormats()
|
|
{
|
|
var formats = new SubtitleFormat[]
|
|
{
|
|
new FinalCutProImage(),
|
|
new SpuImage(),
|
|
new Ebu(),
|
|
new BdnXml(),
|
|
new Pac(),
|
|
new Cavena890(),
|
|
};
|
|
return formats;
|
|
}
|
|
}
|
|
}
|