Kaynağa Gözat

Merge pull request #7960 from Shadowghost/subrip-encoder-fix

(cherry picked from commit ae79bbc34cb3ecc297b0f21fcf474b6c359a3a33)
Signed-off-by: Joshua Boniface <joshua@boniface.me>
Joshua M. Boniface 3 yıl önce
ebeveyn
işleme
e61c80fed7

+ 54 - 0
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
+{
+    /// <summary>
+    /// ASS subtitle writer.
+    /// </summary>
+    public class AssWriter : ISubtitleWriter
+    {
+        /// <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 = Regex.Replace(trackEvent.Text, @"\n", "\\n", RegexOptions.IgnoreCase);
+
+                    writer.WriteLine(
+                        "Dialogue: 0,{0},{1},Default,{2}",
+                        startTime,
+                        endTime,
+                        text);
+                }
+            }
+        }
+    }
+}

+ 54 - 0
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
+{
+    /// <summary>
+    /// SSA subtitle writer.
+    /// </summary>
+    public class SsaWriter : ISubtitleWriter
+    {
+        /// <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 = Regex.Replace(trackEvent.Text, @"\n", "\\n", RegexOptions.IgnoreCase);
+
+                    writer.WriteLine(
+                        "Dialogue: 0,{0},{1},Default,{2}",
+                        startTime,
+                        endTime,
+                        text);
+                }
+            }
+        }
+    }
+}

+ 13 - 1
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));
@@ -294,12 +300,18 @@ 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,SubtitleFormat.SUBRIP, StringComparison.OrdinalIgnoreCase))
             {
                 value = new SrtWriter();
                 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();

+ 1 - 0
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";