From d8d5352c51696306f4d34377e7e12526d026cdaf Mon Sep 17 00:00:00 2001 From: Nikolaj Olsson Date: Mon, 13 Jul 2015 20:38:31 +0200 Subject: [PATCH] Added Timeline footage ascii format --- src/Forms/BatchConvert.cs | 8 + src/Forms/Compare.cs | 8 + src/Forms/Main.cs | 15 ++ src/Logic/SubtitleFormats/Footage.cs | 10 +- src/Logic/SubtitleFormats/TimelineAscii.cs | 17 ++ .../SubtitleFormats/TimelineFootageAscii.cs | 213 ++++++++++++++++++ src/Logic/SubtitleFormats/TimelineMvt.cs | 2 +- src/SubtitleEdit.csproj | 1 + 8 files changed, 270 insertions(+), 4 deletions(-) create mode 100644 src/Logic/SubtitleFormats/TimelineFootageAscii.cs diff --git a/src/Forms/BatchConvert.cs b/src/Forms/BatchConvert.cs index e7373c5ce..5b8f28666 100644 --- a/src/Forms/BatchConvert.cs +++ b/src/Forms/BatchConvert.cs @@ -358,6 +358,14 @@ namespace Nikse.SubtitleEdit.Forms format = asc; } } + if (format == null) + { + var asc = new TimeLineFootageAscii(); + if (asc.IsMine(null, fileName)) + { + format = asc; + } + } } if (format == null) diff --git a/src/Forms/Compare.cs b/src/Forms/Compare.cs index c49dc143a..5cee82b7c 100644 --- a/src/Forms/Compare.cs +++ b/src/Forms/Compare.cs @@ -157,6 +157,14 @@ namespace Nikse.SubtitleEdit.Forms asc.LoadSubtitle(_subtitle1, null, openFileDialog1.FileName); } } + if (format == null) + { + var asc = new TimeLineFootageAscii(); + if (asc.IsMine(null, openFileDialog1.FileName)) + { + asc.LoadSubtitle(_subtitle1, null, openFileDialog1.FileName); + } + } subtitleListView1.Fill(_subtitle1); subtitleListView1.SelectIndexAndEnsureVisible(0); subtitleListView2.SelectIndexAndEnsureVisible(0); diff --git a/src/Forms/Main.cs b/src/Forms/Main.cs index 139a15495..6c57d0cbc 100644 --- a/src/Forms/Main.cs +++ b/src/Forms/Main.cs @@ -2133,6 +2133,21 @@ namespace Nikse.SubtitleEdit.Forms } } + if (format == null) + { + var asc = new TimeLineFootageAscii(); + if (asc.IsMine(null, fileName)) + { + asc.LoadSubtitle(_subtitle, null, fileName); + _oldSubtitleFormat = asc; + SetCurrentFormat(Configuration.Settings.General.DefaultSubtitleFormat); + SetEncoding(Configuration.Settings.General.DefaultEncoding); + encoding = GetCurrentEncoding(); + justConverted = true; + format = GetCurrentSubtitleFormat(); + } + } + if (format == null) { var mtv = new TimeLineMvt(); diff --git a/src/Logic/SubtitleFormats/Footage.cs b/src/Logic/SubtitleFormats/Footage.cs index 957cbd145..ac34eb807 100644 --- a/src/Logic/SubtitleFormats/Footage.cs +++ b/src/Logic/SubtitleFormats/Footage.cs @@ -36,6 +36,10 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats public override bool IsMine(List lines, string fileName) { + var asc = new TimeLineFootageAscii(); + if (fileName != null && asc.IsMine(null, fileName)) + return false; + var subtitle = new Subtitle(); LoadSubtitle(subtitle, lines, fileName); return subtitle.Paragraphs.Count > _errorCount; @@ -157,9 +161,9 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats private static TimeCode DecodeTimeCode(string[] parts) { - string frames16 = parts[0]; - string frames = parts[1]; - return new TimeCode(0, 0, 0, FramesToMilliseconds(16 * int.Parse(frames16) + int.Parse(frames))); + int frames16 = int.Parse(parts[0]); + int frames = int.Parse(parts[1]); + return new TimeCode(0, 0, 0, FramesToMilliseconds(16 * frames16 + frames)); } } diff --git a/src/Logic/SubtitleFormats/TimelineAscii.cs b/src/Logic/SubtitleFormats/TimelineAscii.cs index aac95a66b..7c5f0f028 100644 --- a/src/Logic/SubtitleFormats/TimelineAscii.cs +++ b/src/Logic/SubtitleFormats/TimelineAscii.cs @@ -71,6 +71,8 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats Paragraph paragraph = null; var expecting = ExpectingLine.Number; _errorCount = 0; + byte firstLineCode = 0; + byte secondLineCode = 0; subtitle.Paragraphs.Clear(); IEnumerable byteLines = SplitBytesToLines(File.ReadAllBytes(fileName)); @@ -140,6 +142,21 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats _errorCount += 100; return; } + + if (paragraph.Text.Contains(Environment.NewLine)) + { + if (secondLineCode == 0) + secondLineCode = bytes[0]; + if (secondLineCode != bytes[0]) + _errorCount++; + } + else + { + if (firstLineCode == 0) + firstLineCode = bytes[0]; + if (firstLineCode != bytes[0]) + _errorCount++; + } } } } diff --git a/src/Logic/SubtitleFormats/TimelineFootageAscii.cs b/src/Logic/SubtitleFormats/TimelineFootageAscii.cs new file mode 100644 index 000000000..c5c2154ef --- /dev/null +++ b/src/Logic/SubtitleFormats/TimelineFootageAscii.cs @@ -0,0 +1,213 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; +using Nikse.SubtitleEdit.Core; + +namespace Nikse.SubtitleEdit.Logic.SubtitleFormats +{ + /// + /// Timeline Ascii export - THE MOVIE TITRE EDITOR - http://www.pld.ttu.ee/~priidu/timeline/ by priidu@pld.ttu.ee + /// + /// Sample: + /// 1. + /// 41,10 + /// 46,10 + /// ±NE/SEVÎ + /// ³ÂÍÅ/ÑÅÁß + /// + /// 2. + /// 49,05 + /// 51,09 + /// ±Viòð ir klât. + /// ³Îí ïðèøåë. + /// + public class TimeLineFootageAscii : SubtitleFormat + { + + private static readonly Regex RegexTimeCode = new Regex(@"^\s*\d+,\d\d$", RegexOptions.Compiled); + + private enum ExpectingLine + { + Number, + TimeStart, + TimeEnd, + Text + } + + public override string Extension + { + get { return ".asc"; } + } + + public override string Name + { + get { return "Timeline footage ascii"; } + } + + public override bool IsTimeBased + { + get { return true; } + } + + public override bool IsMine(List lines, string fileName) + { + if (fileName == null || !fileName.EndsWith(Extension, StringComparison.OrdinalIgnoreCase)) + return false; + + var subtitle = new Subtitle(); + LoadSubtitle(subtitle, lines, fileName); + return subtitle.Paragraphs.Count > _errorCount; + } + + public override string ToText(Subtitle subtitle, string title) + { + return string.Empty; + } + + public override void LoadSubtitle(Subtitle subtitle, List lines, string fileName) + { + Paragraph paragraph = null; + var expecting = ExpectingLine.Number; + _errorCount = 0; + byte firstLineCode = 0; + byte secondLineCode = 0; + + subtitle.Paragraphs.Clear(); + IEnumerable byteLines = SplitBytesToLines(File.ReadAllBytes(fileName)); + foreach (byte[] bytes in byteLines) + { + var line = Encoding.ASCII.GetString(bytes); + if (line.EndsWith('.') && Utilities.IsInteger(line.TrimEnd('.'))) + { + if (paragraph != null && !string.IsNullOrEmpty(paragraph.Text)) + subtitle.Paragraphs.Add(paragraph); + paragraph = new Paragraph(); + expecting = ExpectingLine.TimeStart; + } + else if (paragraph != null && expecting == ExpectingLine.TimeStart && RegexTimeCode.IsMatch(line)) + { + string[] parts = line.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length == 2) + { + try + { + var tc = DecodeTimeCode(parts); + paragraph.StartTime = tc; + expecting = ExpectingLine.TimeEnd; + } + catch + { + _errorCount++; + expecting = ExpectingLine.Number; + } + } + } + else if (paragraph != null && expecting == ExpectingLine.TimeEnd && RegexTimeCode.IsMatch(line)) + { + string[] parts = line.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + if (parts.Length == 2) + { + try + { + var tc = DecodeTimeCode(parts); + paragraph.EndTime = tc; + expecting = ExpectingLine.Text; + } + catch + { + _errorCount++; + expecting = ExpectingLine.Number; + } + } + } + else + { + if (paragraph != null && expecting == ExpectingLine.Text) + { + if (bytes.Length > 1) + { + // get text from encoding + var enc = GetEncodingFromLanguage(bytes[0]); + string s = enc.GetString(bytes, 1, bytes.Length - 1).Trim(); + + // italic text + if (s.StartsWith('#')) + s = "" + s.Remove(0, 1) + ""; + + paragraph.Text = (paragraph.Text + Environment.NewLine + s).Trim(); + if (paragraph.Text.Length > 2000) + { + _errorCount += 100; + return; + } + + if (paragraph.Text.Contains(Environment.NewLine)) + { + if (secondLineCode == 0) + secondLineCode = bytes[0]; + if (secondLineCode != bytes[0]) + _errorCount++; + } + else + { + if (firstLineCode == 0) + firstLineCode = bytes[0]; + if (firstLineCode != bytes[0]) + _errorCount++; + } + } + } + } + } + if (paragraph != null && !string.IsNullOrEmpty(paragraph.Text)) + subtitle.Paragraphs.Add(paragraph); + + subtitle.Renumber(); + } + + private IEnumerable SplitBytesToLines(byte[] bytes) + { + var list = new List(); + int start = 0; + int index = 0; + while (index < bytes.Length) + { + if (bytes[index] == 13) + { + int length = index - start; + var lineBytes = new byte[length]; + Array.Copy(bytes, start, lineBytes, 0, length); + list.Add(lineBytes); + index += 2; + start = index; + } + else + { + index++; + } + } + return list; + } + + private static TimeCode DecodeTimeCode(string[] parts) + { + int frames16 = int.Parse(parts[0]); + int frames = int.Parse(parts[1]); + return new TimeCode(0, 0, 0, FramesToMilliseconds(16 * frames16 + frames)); + } + + private Encoding GetEncodingFromLanguage(byte language) + { + if (language == 179) // Russian + return Encoding.GetEncoding(1251); + + if (language == 177) // Baltic + return Encoding.GetEncoding(1257); + + return Encoding.GetEncoding(1252); + } + + } +} \ No newline at end of file diff --git a/src/Logic/SubtitleFormats/TimelineMvt.cs b/src/Logic/SubtitleFormats/TimelineMvt.cs index ee7bb33a8..055f20e6a 100644 --- a/src/Logic/SubtitleFormats/TimelineMvt.cs +++ b/src/Logic/SubtitleFormats/TimelineMvt.cs @@ -150,6 +150,7 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats private double GetTimeCode(byte[] bytes, int timeCodeIndex) { + //TODO: figure out how to get time code from these 7 bytes! if (bytes == null || bytes.Length < timeCodeIndex + 8) return 0; Console.WriteLine(bytes[timeCodeIndex + 0].ToString("X2") + " " + @@ -160,7 +161,6 @@ namespace Nikse.SubtitleEdit.Logic.SubtitleFormats bytes[timeCodeIndex + 5].ToString("X2") + " " + bytes[timeCodeIndex + 6].ToString("X2")); return ((bytes[timeCodeIndex + 5] << 24) + (bytes[timeCodeIndex + 4] << 16) + (bytes[timeCodeIndex + 3] << 8) + (bytes[timeCodeIndex + 2])) / 1800.0; -// return (bytes[timeCodeIndex + 5] << 16) + (bytes[timeCodeIndex + 4] << 8) + (bytes[timeCodeIndex + 3]); } private Encoding GetEncodingFromLanguage(string language) diff --git a/src/SubtitleEdit.csproj b/src/SubtitleEdit.csproj index b757c7902..30ac7cc89 100644 --- a/src/SubtitleEdit.csproj +++ b/src/SubtitleEdit.csproj @@ -902,6 +902,7 @@ +