From a64e21f57a2998363fd1216b5d09d56cbdfefe55 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Fri, 17 Jun 2022 23:17:23 +0200 Subject: [PATCH 1/3] Fix subtitle encoder if subrip is requested --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 49bc2d775b..49173b3d0a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -294,7 +294,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles return true; } - if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase)) + if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase) || string.Equals(format, "subrip", StringComparison.OrdinalIgnoreCase)) { value = new SrtWriter(); return true; From 24c56328f28f19e8442c7f4db85a89c78730b4c4 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 18 Jun 2022 01:20:05 +0200 Subject: [PATCH 2/3] Add subrip to SubtitleFormat --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs | 2 +- MediaBrowser.Model/MediaInfo/SubtitleFormat.cs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 49173b3d0a..c54cd37605 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -294,7 +294,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles return true; } - if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase) || string.Equals(format, "subrip", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase) || string.Equals(format,SubtitleFormat.SUBRIP, StringComparison.OrdinalIgnoreCase)) { value = new SrtWriter(); return true; diff --git a/MediaBrowser.Model/MediaInfo/SubtitleFormat.cs b/MediaBrowser.Model/MediaInfo/SubtitleFormat.cs index 9bc5c31f62..85de916940 100644 --- a/MediaBrowser.Model/MediaInfo/SubtitleFormat.cs +++ b/MediaBrowser.Model/MediaInfo/SubtitleFormat.cs @@ -5,6 +5,7 @@ namespace MediaBrowser.Model.MediaInfo public static class SubtitleFormat { public const string SRT = "srt"; + public const string SUBRIP = "subrip"; public const string SSA = "ssa"; public const string ASS = "ass"; public const string VTT = "vtt"; From b60905f991e3fac3ad293addd2ceb417243e8934 Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Sat, 18 Jun 2022 01:21:20 +0200 Subject: [PATCH 3/3] Add barebone ASS/SSA writers to SubtitleEncoder --- .../Subtitles/AssWriter.cs | 54 +++++++++++++++++++ .../Subtitles/SsaWriter.cs | 54 +++++++++++++++++++ .../Subtitles/SubtitleEncoder.cs | 12 +++++ 3 files changed, 120 insertions(+) create mode 100644 MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs create mode 100644 MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs new file mode 100644 index 0000000000..0d1cf6e258 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs @@ -0,0 +1,54 @@ +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 +{ + /// + /// ASS subtitle writer. + /// + public class AssWriter : ISubtitleWriter + { + /// + 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 = Regex.Replace(trackEvent.Text, @"\n", "\\n", RegexOptions.IgnoreCase); + + writer.WriteLine( + "Dialogue: 0,{0},{1},Default,{2}", + startTime, + endTime, + text); + } + } + } + } +} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs new file mode 100644 index 0000000000..6761cd3099 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs @@ -0,0 +1,54 @@ +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 +{ + /// + /// SSA subtitle writer. + /// + public class SsaWriter : ISubtitleWriter + { + /// + 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 = Regex.Replace(trackEvent.Text, @"\n", "\\n", RegexOptions.IgnoreCase); + + 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 c54cd37605..b9b8a89eba 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -283,6 +283,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles private bool TryGetWriter(string format, [NotNullWhen(true)] out ISubtitleWriter? value) { + if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase)) + { + value = new AssWriter(); + return true; + } + if (string.IsNullOrEmpty(format)) { throw new ArgumentNullException(nameof(format)); @@ -300,6 +306,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles return true; } + if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase)) + { + value = new SsaWriter(); + return true; + } + if (string.Equals(format, SubtitleFormat.VTT, StringComparison.OrdinalIgnoreCase)) { value = new VttWriter();