aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.MediaEncoding
diff options
context:
space:
mode:
authorBond-009 <bond.009@outlook.com>2026-06-01 19:43:57 +0200
committerGitHub <noreply@github.com>2026-06-01 19:43:57 +0200
commit54463929d0d63ec42a1246565ddbe896a1393e55 (patch)
treee22008b63142ce3ec77f5f73b16b7dc123424f97 /MediaBrowser.MediaEncoding
parentab15371d866739244f7b0bd6d1f9396f8ebb7d62 (diff)
parent1dd02b0e30938ea4874da700aad048cc7ada637c (diff)
Write subtitles using SubtitleEdit (#16805)
* Write subtitles using SubtitleEdit We've been using SubtitleEdit to parse since 2021 https://github.com/jellyfin/jellyfin/pull/4984 I think it's time we start using it to write too * Clean up ConvertSubtitles * Add JsonWriter back
Diffstat (limited to 'MediaBrowser.MediaEncoding')
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs57
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs20
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs72
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs49
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs57
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs80
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs60
-rw-r--r--MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs53
8 files changed, 79 insertions, 369 deletions
diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs
deleted file mode 100644
index 7d7b80e99d..0000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- /// <summary>
- /// ASS subtitle writer.
- /// </summary>
- public partial class AssWriter : ISubtitleWriter
- {
- [GeneratedRegex(@"\n", RegexOptions.IgnoreCase)]
- private static partial Regex NewLineRegex();
-
- /// <inheritdoc />
- public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
- {
- using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
- {
- var trackEvents = info.TrackEvents;
- var timeFormat = @"hh\:mm\:ss\.ff";
-
- // Write ASS header
- writer.WriteLine("[Script Info]");
- writer.WriteLine("Title: Jellyfin transcoded ASS subtitle");
- writer.WriteLine("ScriptType: v4.00+");
- writer.WriteLine();
- writer.WriteLine("[V4+ Styles]");
- writer.WriteLine("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding");
- writer.WriteLine("Style: Default,Arial,20,&H00FFFFFF,&H00FFFFFF,&H19333333,&H910E0807,0,0,0,0,100,100,0,0,0,1,0,2,10,10,10,1");
- writer.WriteLine();
- writer.WriteLine("[Events]");
- writer.WriteLine("Format: Layer, Start, End, Style, Text");
-
- for (int i = 0; i < trackEvents.Count; i++)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var trackEvent = trackEvents[i];
- var startTime = TimeSpan.FromTicks(trackEvent.StartPositionTicks).ToString(timeFormat, CultureInfo.InvariantCulture);
- var endTime = TimeSpan.FromTicks(trackEvent.EndPositionTicks).ToString(timeFormat, CultureInfo.InvariantCulture);
- var text = NewLineRegex().Replace(trackEvent.Text, "\\n");
-
- writer.WriteLine(
- "Dialogue: 0,{0},{1},Default,{2}",
- startTime,
- endTime,
- text);
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs
deleted file mode 100644
index dec714121d..0000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleWriter.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using System.IO;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- /// <summary>
- /// Interface ISubtitleWriter.
- /// </summary>
- public interface ISubtitleWriter
- {
- /// <summary>
- /// Writes the specified information.
- /// </summary>
- /// <param name="info">The information.</param>
- /// <param name="stream">The stream.</param>
- /// <param name="cancellationToken">The cancellation token.</param>
- void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken);
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs
index 1b452b0cec..0e40181016 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs
@@ -1,44 +1,58 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
using System.IO;
+using System.Text;
using System.Text.Json;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
+using Nikse.SubtitleEdit.Core.Common;
+using Nikse.SubtitleEdit.Core.SubtitleFormats;
-namespace MediaBrowser.MediaEncoding.Subtitles
+namespace MediaBrowser.MediaEncoding.Subtitles;
+
+/// <summary>
+/// JSON subtitle writer.
+/// </summary>
+public class JsonWriter : SubtitleFormat
{
- /// <summary>
- /// JSON subtitle writer.
- /// </summary>
- public class JsonWriter : ISubtitleWriter
+ /// <inheritdoc />
+ public override string Extension => ".json";
+
+ /// <inheritdoc />
+ public override string Name => "JSON Jellyfin";
+
+ /// <inheritdoc />
+ public override string ToText(Subtitle subtitle, string title)
{
- /// <inheritdoc />
- public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
+ using var ms = new MemoryStream();
+ using (var writer = new Utf8JsonWriter(ms))
{
- using (var writer = new Utf8JsonWriter(stream))
+ var trackevents = subtitle.Paragraphs;
+ writer.WriteStartObject();
+ writer.WriteStartArray("TrackEvents");
+
+ for (int i = 0; i < trackevents.Count; i++)
{
- var trackevents = info.TrackEvents;
+ var current = trackevents[i];
writer.WriteStartObject();
- writer.WriteStartArray("TrackEvents");
-
- for (int i = 0; i < trackevents.Count; i++)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var current = trackevents[i];
- writer.WriteStartObject();
- writer.WriteString("Id", current.Id);
- writer.WriteString("Text", current.Text);
- writer.WriteNumber("StartPositionTicks", current.StartPositionTicks);
- writer.WriteNumber("EndPositionTicks", current.EndPositionTicks);
+ writer.WriteString("Id", current.Number.ToString(CultureInfo.InvariantCulture));
+ writer.WriteString("Text", current.Text);
+ writer.WriteNumber("StartPositionTicks", current.StartTime.TimeSpan.Ticks);
+ writer.WriteNumber("EndPositionTicks", current.EndTime.TimeSpan.Ticks);
- writer.WriteEndObject();
- }
-
- writer.WriteEndArray();
writer.WriteEndObject();
-
- writer.Flush();
}
+
+ writer.WriteEndArray();
+ writer.WriteEndObject();
+
+ writer.Flush();
}
+
+ return Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Length);
}
+
+ /// <inheritdoc />
+ public override void LoadSubtitle(Subtitle subtitle, List<string> lines, string fileName)
+ => throw new NotImplementedException();
}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs
deleted file mode 100644
index 86f77aa067..0000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/SrtWriter.cs
+++ /dev/null
@@ -1,49 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- /// <summary>
- /// SRT subtitle writer.
- /// </summary>
- public partial class SrtWriter : ISubtitleWriter
- {
- [GeneratedRegex(@"\\n", RegexOptions.IgnoreCase)]
- private static partial Regex NewLineEscapedRegex();
-
- /// <inheritdoc />
- public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
- {
- using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
- {
- var trackEvents = info.TrackEvents;
-
- for (int i = 0; i < trackEvents.Count; i++)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var trackEvent = trackEvents[i];
-
- writer.WriteLine((i + 1).ToString(CultureInfo.InvariantCulture));
- writer.WriteLine(
- @"{0:hh\:mm\:ss\,fff} --> {1:hh\:mm\:ss\,fff}",
- TimeSpan.FromTicks(trackEvent.StartPositionTicks),
- TimeSpan.FromTicks(trackEvent.EndPositionTicks));
-
- var text = trackEvent.Text;
-
- // TODO: Not sure how to handle these
- text = NewLineEscapedRegex().Replace(text, " ");
-
- writer.WriteLine(text);
- writer.WriteLine();
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs
deleted file mode 100644
index b5fd1ed935..0000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs
+++ /dev/null
@@ -1,57 +0,0 @@
-using System;
-using System.Globalization;
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- /// <summary>
- /// SSA subtitle writer.
- /// </summary>
- public partial class SsaWriter : ISubtitleWriter
- {
- [GeneratedRegex(@"\n", RegexOptions.IgnoreCase)]
- private static partial Regex NewLineRegex();
-
- /// <inheritdoc />
- public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
- {
- using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
- {
- var trackEvents = info.TrackEvents;
- var timeFormat = @"hh\:mm\:ss\.ff";
-
- // Write SSA header
- writer.WriteLine("[Script Info]");
- writer.WriteLine("Title: Jellyfin transcoded SSA subtitle");
- writer.WriteLine("ScriptType: v4.00");
- writer.WriteLine();
- writer.WriteLine("[V4 Styles]");
- writer.WriteLine("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding");
- writer.WriteLine("Style: Default,Arial,20,&H00FFFFFF,&H00FFFFFF,&H19333333,&H19333333,0,0,0,1,0,2,10,10,10,0,1");
- writer.WriteLine();
- writer.WriteLine("[Events]");
- writer.WriteLine("Format: Layer, Start, End, Style, Text");
-
- for (int i = 0; i < trackEvents.Count; i++)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var trackEvent = trackEvents[i];
- var startTime = TimeSpan.FromTicks(trackEvent.StartPositionTicks).ToString(timeFormat, CultureInfo.InvariantCulture);
- var endTime = TimeSpan.FromTicks(trackEvent.EndPositionTicks).ToString(timeFormat, CultureInfo.InvariantCulture);
- var text = NewLineRegex().Replace(trackEvent.Text, "\\n");
-
- writer.WriteLine(
- "Dialogue: 0,{0},{1},Default,{2}",
- startTime,
- endTime,
- text);
- }
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
index 8d237473a3..ddb078127b 100644
--- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
+++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
@@ -26,7 +26,10 @@ using MediaBrowser.Model.Entities;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Logging;
+using Nikse.SubtitleEdit.Core.Common;
+using Nikse.SubtitleEdit.Core.SubtitleFormats;
using UtfUnknown;
+using SubtitleFormat = MediaBrowser.Model.MediaInfo.SubtitleFormat;
namespace MediaBrowser.MediaEncoding.Subtitles
{
@@ -72,55 +75,42 @@ namespace MediaBrowser.MediaEncoding.Subtitles
private MemoryStream ConvertSubtitles(
Stream stream,
- string inputFormat,
+ SubtitleInfo inputInfo,
string outputFormat,
long startTimeTicks,
long endTimeTicks,
- bool preserveOriginalTimestamps,
- CancellationToken cancellationToken)
+ bool preserveOriginalTimestamps)
{
- var ms = new MemoryStream();
-
- try
- {
- var trackInfo = _subtitleParser.Parse(stream, inputFormat);
+ var subtitle = Subtitle.Parse(stream, Path.GetExtension(inputInfo.Path));
- FilterEvents(trackInfo, startTimeTicks, endTimeTicks, preserveOriginalTimestamps);
+ FilterEvents(subtitle, startTimeTicks, endTimeTicks, preserveOriginalTimestamps);
- var writer = GetWriter(outputFormat);
+ var formatter = GetWriter(outputFormat);
- writer.Write(trackInfo, ms, cancellationToken);
- ms.Position = 0;
- }
- catch
- {
- ms.Dispose();
- throw;
- }
+ var text = formatter.ToText(subtitle, "untitled");
+ var bytes = Encoding.UTF8.GetBytes(text);
- return ms;
+ return new MemoryStream(bytes, 0, bytes.Length, false, true);
}
- internal void FilterEvents(SubtitleTrackInfo track, long startPositionTicks, long endTimeTicks, bool preserveTimestamps)
+ internal void FilterEvents(Subtitle track, long startPositionTicks, long endTimeTicks, bool preserveTimestamps)
{
// Drop subs that have fully elapsed before the requested start position
- track.TrackEvents = track.TrackEvents
- .SkipWhile(i => (i.StartPositionTicks - startPositionTicks) < 0 && (i.EndPositionTicks - startPositionTicks) < 0)
- .ToArray();
+ track.Paragraphs
+ .RemoveAll(i => (i.StartTime.TimeSpan.Ticks - startPositionTicks) < 0 && (i.EndTime.TimeSpan.Ticks - startPositionTicks) < 0);
if (endTimeTicks > 0)
{
- track.TrackEvents = track.TrackEvents
- .TakeWhile(i => i.StartPositionTicks <= endTimeTicks)
- .ToArray();
+ track.Paragraphs
+ .RemoveAll(i => i.StartTime.TimeSpan.Ticks > endTimeTicks);
}
if (!preserveTimestamps)
{
- foreach (var trackEvent in track.TrackEvents)
+ foreach (var trackEvent in track.Paragraphs)
{
- trackEvent.EndPositionTicks = Math.Max(0, trackEvent.EndPositionTicks - startPositionTicks);
- trackEvent.StartPositionTicks = Math.Max(0, trackEvent.StartPositionTicks - startPositionTicks);
+ trackEvent.StartTime = new TimeCode(TimeSpan.FromTicks(Math.Max(0, trackEvent.StartTime.TimeSpan.Ticks - startPositionTicks)));
+ trackEvent.EndTime = new TimeCode(TimeSpan.FromTicks(Math.Max(0, trackEvent.EndTime.TimeSpan.Ticks - startPositionTicks)));
}
}
}
@@ -142,14 +132,14 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var subtitleStream = mediaSource.MediaStreams
.First(i => i.Type == MediaStreamType.Subtitle && i.Index == subtitleStreamIndex);
- var (stream, inputFormat) = await GetSubtitleStream(mediaSource, subtitleStream, cancellationToken)
+ var (stream, info) = await GetSubtitleStream(mediaSource, subtitleStream, cancellationToken)
.ConfigureAwait(false);
// Return the original if the same format is being requested
// Character encoding was already handled in GetSubtitleStream
// ASS is a superset of SSA, skipping the conversion and preserving the styles
- if (string.Equals(inputFormat, outputFormat, StringComparison.OrdinalIgnoreCase)
- || (string.Equals(inputFormat, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase)
+ if (string.Equals(info.Format, outputFormat, StringComparison.OrdinalIgnoreCase)
+ || (string.Equals(info.Format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase)
&& string.Equals(outputFormat, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase)))
{
return stream;
@@ -157,11 +147,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles
using (stream)
{
- return ConvertSubtitles(stream, inputFormat, outputFormat, startTimeTicks, endTimeTicks, preserveOriginalTimestamps, cancellationToken);
+ return ConvertSubtitles(stream, info, outputFormat, startTimeTicks, endTimeTicks, preserveOriginalTimestamps);
}
}
- private async Task<(Stream Stream, string Format)> GetSubtitleStream(
+ private async Task<(Stream Stream, SubtitleInfo Info)> GetSubtitleStream(
MediaSourceInfo mediaSource,
MediaStream subtitleStream,
CancellationToken cancellationToken)
@@ -170,7 +160,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
var stream = await GetSubtitleStream(fileInfo, cancellationToken).ConfigureAwait(false);
- return (stream, fileInfo.Format);
+ return (stream, fileInfo);
}
private async Task<Stream> GetSubtitleStream(SubtitleInfo fileInfo, CancellationToken cancellationToken)
@@ -266,13 +256,13 @@ namespace MediaBrowser.MediaEncoding.Subtitles
};
}
- private bool TryGetWriter(string format, [NotNullWhen(true)] out ISubtitleWriter? value)
+ private bool TryGetWriter(string format, [NotNullWhen(true)] out Nikse.SubtitleEdit.Core.SubtitleFormats.SubtitleFormat? value)
{
ArgumentException.ThrowIfNullOrEmpty(format);
if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase))
{
- value = new AssWriter();
+ value = new AdvancedSubStationAlpha();
return true;
}
@@ -282,27 +272,29 @@ namespace MediaBrowser.MediaEncoding.Subtitles
return true;
}
- if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase) || string.Equals(format, SubtitleFormat.SUBRIP, StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase)
+ || string.Equals(format, SubtitleFormat.SUBRIP, StringComparison.OrdinalIgnoreCase))
{
- value = new SrtWriter();
+ value = new SubRip();
return true;
}
if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase))
{
- value = new SsaWriter();
+ value = new SubStationAlpha();
return true;
}
- if (string.Equals(format, SubtitleFormat.VTT, StringComparison.OrdinalIgnoreCase) || string.Equals(format, SubtitleFormat.WEBVTT, StringComparison.OrdinalIgnoreCase))
+ if (string.Equals(format, SubtitleFormat.VTT, StringComparison.OrdinalIgnoreCase)
+ || string.Equals(format, SubtitleFormat.WEBVTT, StringComparison.OrdinalIgnoreCase))
{
- value = new VttWriter();
+ value = new WebVTT();
return true;
}
if (string.Equals(format, SubtitleFormat.TTML, StringComparison.OrdinalIgnoreCase))
{
- value = new TtmlWriter();
+ value = new TimedText10();
return true;
}
@@ -310,7 +302,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles
return false;
}
- private ISubtitleWriter GetWriter(string format)
+ private Nikse.SubtitleEdit.Core.SubtitleFormats.SubtitleFormat GetWriter(string format)
{
if (TryGetWriter(format, out var writer))
{
diff --git a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs
deleted file mode 100644
index ea45f2070a..0000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/TtmlWriter.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- /// <summary>
- /// TTML subtitle writer.
- /// </summary>
- public partial class TtmlWriter : ISubtitleWriter
- {
- [GeneratedRegex(@"\\n", RegexOptions.IgnoreCase)]
- private static partial Regex NewLineEscapeRegex();
-
- /// <inheritdoc />
- public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
- {
- // Example: https://github.com/zmalltalker/ttml2vtt/blob/master/data/sample.xml
- // Parser example: https://github.com/mozilla/popcorn-js/blob/master/parsers/parserTTML/popcorn.parserTTML.js
-
- using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
- {
- writer.WriteLine("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
- writer.WriteLine("<tt xmlns=\"http://www.w3.org/ns/ttml\" xmlns:tts=\"http://www.w3.org/2006/04/ttaf1#styling\" lang=\"no\">");
-
- writer.WriteLine("<head>");
- writer.WriteLine("<styling>");
- writer.WriteLine("<style id=\"italic\" tts:fontStyle=\"italic\" />");
- writer.WriteLine("<style id=\"left\" tts:textAlign=\"left\" />");
- writer.WriteLine("<style id=\"center\" tts:textAlign=\"center\" />");
- writer.WriteLine("<style id=\"right\" tts:textAlign=\"right\" />");
- writer.WriteLine("</styling>");
- writer.WriteLine("</head>");
-
- writer.WriteLine("<body>");
- writer.WriteLine("<div>");
-
- foreach (var trackEvent in info.TrackEvents)
- {
- var text = trackEvent.Text;
-
- text = NewLineEscapeRegex().Replace(text, "<br/>");
-
- writer.WriteLine(
- "<p begin=\"{0}\" dur=\"{1}\">{2}</p>",
- trackEvent.StartPositionTicks,
- trackEvent.EndPositionTicks - trackEvent.StartPositionTicks,
- text);
- }
-
- writer.WriteLine("</div>");
- writer.WriteLine("</body>");
-
- writer.WriteLine("</tt>");
- }
- }
- }
-}
diff --git a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs
deleted file mode 100644
index 3e0f47b5ae..0000000000
--- a/MediaBrowser.MediaEncoding/Subtitles/VttWriter.cs
+++ /dev/null
@@ -1,53 +0,0 @@
-using System;
-using System.IO;
-using System.Text;
-using System.Text.RegularExpressions;
-using System.Threading;
-using MediaBrowser.Model.MediaInfo;
-
-namespace MediaBrowser.MediaEncoding.Subtitles
-{
- /// <summary>
- /// Subtitle writer for the WebVTT format.
- /// </summary>
- public partial class VttWriter : ISubtitleWriter
- {
- [GeneratedRegex(@"\\n", RegexOptions.IgnoreCase)]
- private static partial Regex NewlineEscapeRegex();
-
- /// <inheritdoc />
- public void Write(SubtitleTrackInfo info, Stream stream, CancellationToken cancellationToken)
- {
- using (var writer = new StreamWriter(stream, Encoding.UTF8, 1024, true))
- {
- writer.WriteLine("WEBVTT");
- writer.WriteLine();
- writer.WriteLine("Region: id:subtitle width:80% lines:3 regionanchor:50%,100% viewportanchor:50%,90%");
- writer.WriteLine();
- foreach (var trackEvent in info.TrackEvents)
- {
- cancellationToken.ThrowIfCancellationRequested();
-
- var startTime = TimeSpan.FromTicks(trackEvent.StartPositionTicks);
- var endTime = TimeSpan.FromTicks(trackEvent.EndPositionTicks);
-
- // make sure the start and end times are different and sequential
- if (endTime.TotalMilliseconds <= startTime.TotalMilliseconds)
- {
- endTime = startTime.Add(TimeSpan.FromMilliseconds(1));
- }
-
- writer.WriteLine(@"{0:hh\:mm\:ss\.fff} --> {1:hh\:mm\:ss\.fff} region:subtitle line:90%", startTime, endTime);
-
- var text = trackEvent.Text;
-
- // TODO: Not sure how to handle these
- text = NewlineEscapeRegex().Replace(text, " ");
-
- writer.WriteLine(text);
- writer.WriteLine();
- }
- }
- }
- }
-}