using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
namespace Nikse.SubtitleEdit.Core.SubtitleFormats
{
///
/// SoftNi - http://www.softni.com/
///
public class SoftNicolonSub : SubtitleFormat
{
private static readonly Regex regexTimeCodes = new Regex(@"^\d\d:\d\d:\d\d:\d\d\\\d\d:\d\d:\d\d:\d\d$", RegexOptions.Compiled);
public override string Extension
{
get { return ".sub"; }
}
public override string Name
{
get { return "SoftNi colon sub"; }
}
public override bool IsTimeBased
{
get { return true; }
}
public override bool IsMine(List lines, string fileName)
{
var subtitle = new Subtitle();
DoLoadSubtitle(subtitle, lines);
return subtitle.Paragraphs.Count > _errorCount;
}
public override string ToText(Subtitle subtitle, string title)
{
var sb = new StringBuilder();
var lineSb = new StringBuilder();
sb.AppendLine("*PART 1*");
sb.AppendLine("00:00:00:00\\00:00:00:00");
foreach (Paragraph p in subtitle.Paragraphs)
{
string text = p.Text;
bool positionTop = false;
// If text starts with {\an8}, subtitle appears at the top
if (text.StartsWith("{\\an8}", StringComparison.Ordinal))
{
positionTop = true;
// Remove the tag {\an8}.
text = text.Remove(0, 6);
}
// Split lines (split a subtitle into its lines)
var lines = text.SplitToLines();
int count = 0;
lineSb.Clear();
string tempLine = string.Empty;
bool nextLineInItalics = false;
foreach (string line in lines)
{
// Append line break in every line except the first one
if (count > 0)
lineSb.Append(Environment.NewLine);
tempLine = line;
// This line should be in italics (it was detected in previous line)
if (nextLineInItalics)
{
tempLine = "" + tempLine;
nextLineInItalics = false;
}
if (tempLine.StartsWith("") && tempLine.EndsWith(""))
{
// Whole line is in italics
// Remove from the beginning
tempLine = tempLine.Remove(0, 3);
// Remove from the end
tempLine = tempLine.Remove(tempLine.Length - 4, 4);
// Add new italics tag at the beginning
tempLine = "[" + tempLine;
}
else if (tempLine.StartsWith("") && Utilities.CountTagInText(tempLine, "") > Utilities.CountTagInText(tempLine, ""))
{
// Line starts with but italics are not closed. So the next line should be in italics
nextLineInItalics = true;
}
lineSb.Append(tempLine);
count++;
text = lineSb.ToString();
// Replace remaining italics tags
text = text.Replace("", @"[");
text = text.Replace("", @"]");
text = HtmlUtil.RemoveHtmlTags(text);
}
// Add top-position SoftNI marker "}" at the beginning of first line.
if (positionTop)
text = "}" + text;
sb.AppendLine(string.Format("{0}{1}{2}\\{3}", text, Environment.NewLine, p.StartTime.ToHHMMSSPeriodFF().Replace(".", ":"), p.EndTime.ToHHMMSSPeriodFF().Replace(".", ":")));
}
sb.AppendLine(@"*END*");
sb.AppendLine(@"...........\...........");
sb.AppendLine(@"*CODE*");
sb.AppendLine(@"0000000000000000");
sb.AppendLine(@"*CAST*");
sb.AppendLine(@"*GENERATOR*");
sb.AppendLine(@"*FONTS*");
sb.AppendLine(@"*READ*");
sb.AppendLine(@"0,300 15,000 130,000 100,000 25,000");
sb.AppendLine(@"*TIMING*");
sb.AppendLine(@"1 25 0");
sb.AppendLine(@"*TIMED BACKUP NAME*");
sb.AppendLine(@"C:\");
sb.AppendLine(@"*FORMAT SAMPLE ÅåÉéÌìÕõÛûÿ*");
sb.AppendLine(@"*READ ADVANCED*");
sb.AppendLine(@"< > 1 1 0,300");
sb.AppendLine(@"*MARKERS*");
return sb.ToString();
}
public override void LoadSubtitle(Subtitle subtitle, List lines, string fileName)
{
DoLoadSubtitle(subtitle, lines);
}
private void DoLoadSubtitle(Subtitle subtitle, List lines)
{
//—Peter.
//—Estoy de licencia.
//01:48:50.07\01:48:52.01
var sb = new StringBuilder();
var lineSb = new StringBuilder();
Paragraph p = null;
subtitle.Paragraphs.Clear();
char[] splitChars = { ':', '.' };
foreach (string line in lines)
{
string s = line.Trim();
if (regexTimeCodes.IsMatch(s))
{
// Start and end time separated by "\"
var temp = s.Split('\\');
if (temp.Length > 1)
{
string start = temp[0];
string end = temp[1];
string[] startParts = start.Split(splitChars, StringSplitOptions.RemoveEmptyEntries);
string[] endParts = end.Split(splitChars, StringSplitOptions.RemoveEmptyEntries);
if (startParts.Length == 4 && endParts.Length == 4)
{
try
{
p = new Paragraph();
p.StartTime = DecodeTimeCode(startParts);
p.EndTime = DecodeTimeCode(endParts);
string text = sb.ToString().Trim();
bool positionTop = false;
// If text starts with "}", subtitle appears at the top
if (text.StartsWith('}'))
{
positionTop = true;
// Remove the tag "}"
text = text.Remove(0, 1);
}
// Replace tags
text = text.Replace("[", @"");
text = text.Replace("]", @"");
// Split subtitle lines (one subtitle has one or more lines)
var subtitleLines = text.SplitToLines();
int count = 0;
lineSb.Clear();
string tempLine = string.Empty;
foreach (string subtitleLine in subtitleLines)
{
// Append line break in every line except the first one
if (count > 0)
lineSb.Append(Environment.NewLine);
tempLine = subtitleLine;
// Close italics in every line (if next line is in italics, SoftNI will use "[" at the beginning)
if (Utilities.CountTagInText(tempLine, "") > Utilities.CountTagInText(tempLine, ""))
tempLine = tempLine + "";
lineSb.Append(tempLine);
count++;
}
text = lineSb.ToString();
// Replace "line break" with just a line break (SubRip does not need to close italics and open them again in the next line).
text = text.Replace("" + Environment.NewLine + "", Environment.NewLine);
// Subtitle appears at the top (add tag)
if (positionTop)
text = "{\\an8}" + text;
p.Text = text;
if (text.Length > 0)
subtitle.Paragraphs.Add(p);
sb.Clear();
}
catch (Exception exception)
{
_errorCount++;
System.Diagnostics.Debug.WriteLine(exception.Message);
}
}
}
}
else if (string.IsNullOrWhiteSpace(line) || line.StartsWith('*'))
{
// skip empty lines or start
}
else if (p != null)
{
sb.AppendLine(line);
}
}
subtitle.Renumber();
}
private static TimeCode DecodeTimeCode(string[] parts)
{
//00:00:07:12
var hour = int.Parse(parts[0]);
var minutes = int.Parse(parts[1]);
var seconds = int.Parse(parts[2]);
var frames = int.Parse(parts[3]);
return new TimeCode(hour, minutes, seconds, FramesToMillisecondsMax999(frames));
}
}
}