diff --git a/src/Forms/BatchConvert.cs b/src/Forms/BatchConvert.cs
index 0c335314d..e7373c5ce 100644
--- a/src/Forms/BatchConvert.cs
+++ b/src/Forms/BatchConvert.cs
@@ -342,7 +342,6 @@ namespace Nikse.SubtitleEdit.Forms
format = nciCaption;
}
}
-
if (format == null)
{
var avidStl = new AvidStl();
@@ -351,6 +350,14 @@ namespace Nikse.SubtitleEdit.Forms
format = avidStl;
}
}
+ if (format == null)
+ {
+ var asc = new TimeLineAscii();
+ if (asc.IsMine(null, fileName))
+ {
+ format = asc;
+ }
+ }
}
if (format == null)
diff --git a/src/Forms/Main.cs b/src/Forms/Main.cs
index 570ff4dc3..139a15495 100644
--- a/src/Forms/Main.cs
+++ b/src/Forms/Main.cs
@@ -2118,6 +2118,21 @@ namespace Nikse.SubtitleEdit.Forms
}
}
+ if (format == null)
+ {
+ var asc = new TimeLineAscii();
+ 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/TimelineAscii.cs b/src/Logic/SubtitleFormats/TimelineAscii.cs
new file mode 100644
index 000000000..aac95a66b
--- /dev/null
+++ b/src/Logic/SubtitleFormats/TimelineAscii.cs
@@ -0,0 +1,198 @@
+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.
+ /// 00:00:43.02
+ /// 00:00:47.03
+ /// ±NE/SEVÎ
+ /// ³ÂÍÅ/ÑÅÁß
+ ///
+ /// 2.
+ /// 00:01:36.00
+ /// 00:01:37.00
+ /// ±Viòð ir klât.
+ /// ³Îí ïðèøåë.
+ ///
+ public class TimeLineAscii : SubtitleFormat
+ {
+
+ private static readonly Regex RegexTimeCode = new Regex(@"^\d\d:\d\d:\d\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 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;
+
+ 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 == 4)
+ {
+ 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 == 4)
+ {
+ 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 != 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 hours = int.Parse(parts[0]);
+ int minutes = int.Parse(parts[1]);
+ int seconds = int.Parse(parts[2]);
+ int frames = int.Parse(parts[3]);
+ return new TimeCode(hours, minutes, seconds, FramesToMillisecondsMax999(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/SubtitleEdit.csproj b/src/SubtitleEdit.csproj
index 59179a4f5..b757c7902 100644
--- a/src/SubtitleEdit.csproj
+++ b/src/SubtitleEdit.csproj
@@ -902,6 +902,7 @@
+