Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using Nikse.SubtitleEdit.Core.Common;
- using System;
- using System.Collections.Generic;
- using System.Globalization;
- using System.Text;
- namespace Nikse.SubtitleEdit.Core.SubtitleFormats
- {
- public class RealTime : SubtitleFormat
- {
- private readonly StringBuilder _accumulator = new StringBuilder();
- public override string Extension => ".rt";
- public override string Name => "RealTime";
- private readonly ITimeParser _timeParser;
- public RealTime() : this(useStrictMode: true)
- {
- }
- public RealTime(bool useStrictMode) => _timeParser = useStrictMode ? (ITimeParser)new StrictTimeParser() : new RelaxTimeParser();
- public override string ToText(Subtitle subtitle, string title)
- {
- var sb = new StringBuilder();
- sb.AppendLine("<Window" + Environment.NewLine +
- " Width = \"640\"" + Environment.NewLine +
- " Height = \"480\"" + Environment.NewLine +
- " WordWrap = \"true\"" + Environment.NewLine +
- " Loop = \"true\"" + Environment.NewLine +
- " bgcolor = \"black\"" + Environment.NewLine +
- ">" + Environment.NewLine +
- "<Font" + Environment.NewLine +
- " Color = \"white\"" + Environment.NewLine +
- " Face = \"Arial\"" + Environment.NewLine +
- " Size = \"+2\"" + Environment.NewLine +
- ">" + Environment.NewLine +
- "<center>" + Environment.NewLine +
- "<b>" + Environment.NewLine);
- const string writeFormat = "<Time begin=\"{0}\" end=\"{1}\" /><clear/>{2}";
- foreach (Paragraph p in subtitle.Paragraphs)
- {
- //<Time begin="0:03:24.8" end="0:03:29.4" /><clear/>Man stjæler ikke fra Chavo, nej.
- sb.AppendLine(string.Format(writeFormat, EncodeTimeCode(p.StartTime), EncodeTimeCode(p.EndTime), p.Text.Replace(Environment.NewLine, " ")));
- }
- sb.AppendLine("</b>");
- sb.AppendLine("</center>");
- return sb.ToString();
- }
- private static string EncodeTimeCode(TimeCode time)
- {
- //0:03:24.8
- return $"{time.Hours:0}:{time.Minutes:00}:{time.Seconds:00}.{time.Milliseconds / 100:0}";
- }
- private Paragraph ParseLine(string line)
- {
- // <Time begin="1:19:04.2" end="1:19:08.6" /><clear/>I'm coming with you. You hear me, you ugly creature?
- var tokenizer = new Tokenizer(line);
- while (true)
- {
- var ch = tokenizer.GetNextChar();
- if (ch == '\"')
- {
- return StartTime(ref tokenizer);
- }
- else if (ch == char.MaxValue)
- {
- return null;
- }
- }
- }
- private Paragraph StartTime(ref Tokenizer tokenizer)
- {
- while (true)
- {
- var ch = tokenizer.GetNextChar();
- if (char.IsDigit(ch) || ch == ':' || ch == '.')
- {
- Append(ch);
- }
- else if (ch == '"' && _accumulator.Length > 0)
- {
- return EndTime(ref tokenizer, FlushAccumulator());
- }
- else if (ch == char.MaxValue)
- {
- return null;
- }
- }
- }
- private Paragraph EndTime(ref Tokenizer tokenizer, string st)
- {
- while (true)
- {
- var ch = tokenizer.GetNextChar();
- if (char.IsDigit(ch) || ch == ':' || ch == '.')
- {
- Append(ch);
- }
- else if (ch == '"' && _accumulator.Length > 0)
- {
- return Text(ref tokenizer, st, FlushAccumulator());
- }
- else if (ch == char.MaxValue)
- {
- return null;
- }
- }
- }
- private Paragraph Text(ref Tokenizer tokenizer, string st, string et)
- {
- // <Time begin="1:19:04.2" end="1:19:08.6" /><clear/>I'm coming with you. You hear me, you ugly creature?
- tokenizer.AdvanceIndex(" /><clear/>".Length);
- while (true)
- {
- var ch = tokenizer.GetNextChar();
- if (ch == char.MaxValue)
- {
- if (_timeParser.TryParse(st, out TimeSpan sts) && _timeParser.TryParse(et, out TimeSpan ets))
- {
- return new Paragraph(FlushAccumulator(), sts.TotalMilliseconds, ets.TotalMilliseconds);
- }
- }
- Append(ch);
- }
- }
- private void Append(char ch) => _accumulator.Append(ch);
- public override void LoadSubtitle(Subtitle subtitle, List<string> lines, string fileName)
- {
- //<Time begin="0:03:24.8" end="0:03:29.4" /><clear/>Man stjæler ikke fra Chavo, nej.
- subtitle.Paragraphs.Clear();
- _errorCount = 0;
- foreach (string line in lines)
- {
- try
- {
- if (!line.StartsWith("<time begin=", StringComparison.OrdinalIgnoreCase))
- {
- continue;
- }
- switch (ParseLine(line))
- {
- case Paragraph paragraph:
- subtitle.Paragraphs.Add(paragraph);
- break;
- case null:
- if (++_errorCount >= lines.Count / 2)
- {
- return;
- }
- break;
- }
- }
- catch
- {
- _errorCount++;
- }
- }
- subtitle.Renumber();
- }
- /// <summary>
- /// Clears the accumulated text from the internal StringBuilder and returns the cleared text.
- /// </summary>
- /// <returns>A string containing the accumulated text before it was cleared.</returns>
- private string FlushAccumulator()
- {
- var temp = _accumulator.ToString();
- _accumulator.Clear();
- return temp;
- }
- /// <summary>
- /// The <c>Tokenizer</c> struct is responsible for iterating through a string,
- /// character by character, and providing methods to advance the reading index.
- /// </summary>
- private struct Tokenizer
- {
- private readonly string _line;
- private int _index;
- public Tokenizer(string line) => (_index, _line) = (0, line);
- public char GetNextChar()
- {
- if (_index < _line.Length)
- {
- return _line[_index++];
- }
- return char.MaxValue;
- }
- public void AdvanceIndex(int indexIncrement) => _index += indexIncrement;
- }
- /// <summary>
- /// The <c>ITimeParser</c> interface defines a method for parsing time strings
- /// into <c>TimeSpan</c> objects.
- /// </summary>
- private interface ITimeParser
- {
- bool TryParse(string line, out TimeSpan time);
- }
- /// <summary>
- /// The <c>StrictTimeParser</c> class provides functionality to parse
- /// time strings into <c>TimeSpan</c> objects using a strict format.
- /// </summary>
- private class StrictTimeParser : ITimeParser
- {
- private const string TimeFormat = @"h\:mm\:ss\.f";
- public bool TryParse(string timeStamp, out TimeSpan ts)
- {
- return TimeSpan.TryParseExact(timeStamp, TimeFormat, CultureInfo.InvariantCulture, TimeSpanStyles.None, out ts);
- }
- }
- /// <summary>
- /// The <c>RelaxTimeParser</c> class provides functionality to parse time strings
- /// into <c>TimeSpan</c> objects using a relaxed format.
- /// </summary>
- private class RelaxTimeParser : ITimeParser
- {
- public bool TryParse(string timeStamp, out TimeSpan timeSpan)
- {
- return TimeSpan.TryParse(timeStamp, CultureInfo.InvariantCulture, out timeSpan);
- }
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement