Merge pull request #7960 from Shadowghost/subrip-encoder-fix
(cherry picked from commit ae79bbc34cb3ecc297b0f21fcf474b6c359a3a33) Signed-off-by: Joshua Boniface <joshua@boniface.me>
This commit is contained in:
parent
c0e4a33a0b
commit
e61c80fed7
54
MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs
Normal file
54
MediaBrowser.MediaEncoding/Subtitles/AssWriter.cs
Normal file
|
@ -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
MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs
Normal file
54
MediaBrowser.MediaEncoding/Subtitles/SsaWriter.cs
Normal file
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -283,6 +283,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
|
|
||||||
private bool TryGetWriter(string format, [NotNullWhen(true)] out ISubtitleWriter? value)
|
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))
|
if (string.IsNullOrEmpty(format))
|
||||||
{
|
{
|
||||||
throw new ArgumentNullException(nameof(format));
|
throw new ArgumentNullException(nameof(format));
|
||||||
|
@ -294,12 +300,18 @@ namespace MediaBrowser.MediaEncoding.Subtitles
|
||||||
return true;
|
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();
|
value = new SrtWriter();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
value = new SsaWriter();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (string.Equals(format, SubtitleFormat.VTT, StringComparison.OrdinalIgnoreCase))
|
if (string.Equals(format, SubtitleFormat.VTT, StringComparison.OrdinalIgnoreCase))
|
||||||
{
|
{
|
||||||
value = new VttWriter();
|
value = new VttWriter();
|
||||||
|
|
|
@ -5,6 +5,7 @@ namespace MediaBrowser.Model.MediaInfo
|
||||||
public static class SubtitleFormat
|
public static class SubtitleFormat
|
||||||
{
|
{
|
||||||
public const string SRT = "srt";
|
public const string SRT = "srt";
|
||||||
|
public const string SUBRIP = "subrip";
|
||||||
public const string SSA = "ssa";
|
public const string SSA = "ssa";
|
||||||
public const string ASS = "ass";
|
public const string ASS = "ass";
|
||||||
public const string VTT = "vtt";
|
public const string VTT = "vtt";
|
||||||
|
|
Loading…
Reference in New Issue
Block a user