Skip to content

Commit

Permalink
Revert "Backport pull request #8087 from jellyfin/release-10.8.z"
Browse files Browse the repository at this point in the history
This reverts commit 38eefbb.
  • Loading branch information
dannymichel authored and voaii committed Apr 18, 2023
1 parent b77cab5 commit 7bb1c1a
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 94 deletions.
3 changes: 1 addition & 2 deletions Emby.Server.Implementations/ApplicationHost.cs
Original file line number Diff line number Diff line change
Expand Up @@ -597,8 +597,7 @@ protected virtual void RegisterServices(IServiceCollection serviceCollection)
serviceCollection.AddSingleton<IAuthService, AuthService>();
serviceCollection.AddSingleton<IQuickConnect, QuickConnectManager>();

serviceCollection.AddSingleton<ISubtitleParser, SubtitleEditParser>();
serviceCollection.AddSingleton<ISubtitleEncoder, SubtitleEncoder>();
serviceCollection.AddSingleton<ISubtitleEncoder, MediaBrowser.MediaEncoding.Subtitles.SubtitleEncoder>();

serviceCollection.AddSingleton<IAttachmentExtractor, MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor>();

Expand Down
19 changes: 19 additions & 0 deletions MediaBrowser.MediaEncoding/Subtitles/AssParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.Extensions.Logging;
using Nikse.SubtitleEdit.Core.SubtitleFormats;

namespace MediaBrowser.MediaEncoding.Subtitles
{
/// <summary>
/// Advanced SubStation Alpha subtitle parser.
/// </summary>
public class AssParser : SubtitleEditParser<AdvancedSubStationAlpha>
{
/// <summary>
/// Initializes a new instance of the <see cref="AssParser"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
public AssParser(ILogger logger) : base(logger)
{
}
}
}
12 changes: 3 additions & 9 deletions MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma warning disable CS1591

using System.IO;
using System.Threading;
using MediaBrowser.Model.MediaInfo;

namespace MediaBrowser.MediaEncoding.Subtitles
Expand All @@ -11,15 +12,8 @@ public interface ISubtitleParser
/// Parses the specified stream.
/// </summary>
/// <param name="stream">The stream.</param>
/// <param name="fileExtension">The file extension.</param>
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>SubtitleTrackInfo.</returns>
SubtitleTrackInfo Parse(Stream stream, string fileExtension);

/// <summary>
/// Determines whether the file extension is supported by the parser.
/// </summary>
/// <param name="fileExtension">The file extension.</param>
/// <returns>A value indicating whether the file extension is supported.</returns>
bool SupportsFileExtension(string fileExtension);
SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken);
}
}
19 changes: 19 additions & 0 deletions MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.Extensions.Logging;
using Nikse.SubtitleEdit.Core.SubtitleFormats;

namespace MediaBrowser.MediaEncoding.Subtitles
{
/// <summary>
/// SubRip subtitle parser.
/// </summary>
public class SrtParser : SubtitleEditParser<SubRip>
{
/// <summary>
/// Initializes a new instance of the <see cref="SrtParser"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
public SrtParser(ILogger logger) : base(logger)
{
}
}
}
19 changes: 19 additions & 0 deletions MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Microsoft.Extensions.Logging;
using Nikse.SubtitleEdit.Core.SubtitleFormats;

namespace MediaBrowser.MediaEncoding.Subtitles
{
/// <summary>
/// SubStation Alpha subtitle parser.
/// </summary>
public class SsaParser : SubtitleEditParser<SubStationAlpha>
{
/// <summary>
/// Initializes a new instance of the <see cref="SsaParser"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
public SsaParser(ILogger logger) : base(logger)
{
}
}
}
83 changes: 13 additions & 70 deletions MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs
Original file line number Diff line number Diff line change
@@ -1,70 +1,44 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using Jellyfin.Extensions;
using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Logging;
using Nikse.SubtitleEdit.Core.Common;
using ILogger = Microsoft.Extensions.Logging.ILogger;
using SubtitleFormat = Nikse.SubtitleEdit.Core.SubtitleFormats.SubtitleFormat;

namespace MediaBrowser.MediaEncoding.Subtitles
{
/// <summary>
/// SubStation Alpha subtitle parser.
/// </summary>
public class SubtitleEditParser : ISubtitleParser
/// <typeparam name="T">The <see cref="SubtitleFormat" />.</typeparam>
public abstract class SubtitleEditParser<T> : ISubtitleParser
where T : SubtitleFormat, new()
{
private readonly ILogger<SubtitleEditParser> _logger;
private readonly Dictionary<string, SubtitleFormat[]> _subtitleFormats;
private readonly ILogger _logger;

/// <summary>
/// Initializes a new instance of the <see cref="SubtitleEditParser"/> class.
/// Initializes a new instance of the <see cref="SubtitleEditParser{T}"/> class.
/// </summary>
/// <param name="logger">The logger.</param>
public SubtitleEditParser(ILogger<SubtitleEditParser> logger)
protected SubtitleEditParser(ILogger logger)
{
_logger = logger;
_subtitleFormats = GetSubtitleFormats()
.Where(subtitleFormat => !string.IsNullOrEmpty(subtitleFormat.Extension))
.GroupBy(subtitleFormat => subtitleFormat.Extension.TrimStart('.'), StringComparer.OrdinalIgnoreCase)
.ToDictionary(g => g.Key, g => g.ToArray(), StringComparer.OrdinalIgnoreCase);
}

/// <inheritdoc />
public SubtitleTrackInfo Parse(Stream stream, string fileExtension)
public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken)
{
var subtitle = new Subtitle();
var subRip = new T();
var lines = stream.ReadAllLines().ToList();

if (!_subtitleFormats.TryGetValue(fileExtension, out var subtitleFormats))
{
throw new ArgumentException($"Unsupported file extension: {fileExtension}", nameof(fileExtension));
}

foreach (var subtitleFormat in subtitleFormats)
subRip.LoadSubtitle(subtitle, lines, "untitled");
if (subRip.ErrorCount > 0)
{
_logger.LogDebug(
"Trying to parse '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser",
fileExtension,
subtitleFormat.Name);
subtitleFormat.LoadSubtitle(subtitle, lines, fileExtension);
if (subtitleFormat.ErrorCount == 0)
{
break;
}

_logger.LogError(
"{ErrorCount} errors encountered while parsing '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser",
subtitleFormat.ErrorCount,
fileExtension,
subtitleFormat.Name);
}

if (subtitle.Paragraphs.Count == 0)
{
throw new ArgumentException("Unsupported format: " + fileExtension);
_logger.LogError("{ErrorCount} errors encountered while parsing subtitle", subRip.ErrorCount);
}

var trackInfo = new SubtitleTrackInfo();
Expand All @@ -83,36 +57,5 @@ public SubtitleTrackInfo Parse(Stream stream, string fileExtension)
trackInfo.TrackEvents = trackEvents;
return trackInfo;
}

/// <inheritdoc />
public bool SupportsFileExtension(string fileExtension)
=> _subtitleFormats.ContainsKey(fileExtension);

private IEnumerable<SubtitleFormat> GetSubtitleFormats()
{
var subtitleFormats = new List<SubtitleFormat>();
var assembly = typeof(SubtitleFormat).Assembly;

foreach (var type in assembly.GetTypes())
{
if (!type.IsSubclassOf(typeof(SubtitleFormat)) || type.IsAbstract)
{
continue;
}

try
{
// It shouldn't be null, but the exception is caught if it is
var subtitleFormat = (SubtitleFormat)Activator.CreateInstance(type, true)!;
subtitleFormats.Add(subtitleFormat);
}
catch (Exception ex)
{
_logger.LogWarning(ex, "Failed to create instance of the subtitle format {SubtitleFormatType}", type.Name);
}
}

return subtitleFormats;
}
}
}
45 changes: 38 additions & 7 deletions MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ public sealed class SubtitleEncoder : ISubtitleEncoder
private readonly IMediaEncoder _mediaEncoder;
private readonly IHttpClientFactory _httpClientFactory;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly ISubtitleParser _subtitleParser;

/// <summary>
/// The _semaphoreLocks.
Expand All @@ -49,16 +48,14 @@ public SubtitleEncoder(
IFileSystem fileSystem,
IMediaEncoder mediaEncoder,
IHttpClientFactory httpClientFactory,
IMediaSourceManager mediaSourceManager,
ISubtitleParser subtitleParser)
IMediaSourceManager mediaSourceManager)
{
_logger = logger;
_appPaths = appPaths;
_fileSystem = fileSystem;
_mediaEncoder = mediaEncoder;
_httpClientFactory = httpClientFactory;
_mediaSourceManager = mediaSourceManager;
_subtitleParser = subtitleParser;
}

private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles");
Expand All @@ -76,7 +73,8 @@ private Stream ConvertSubtitles(

try
{
var trackInfo = _subtitleParser.Parse(stream, inputFormat);
var reader = GetReader(inputFormat);
var trackInfo = reader.Parse(stream, cancellationToken);

FilterEvents(trackInfo, startTimeTicks, endTimeTicks, preserveOriginalTimestamps);

Expand Down Expand Up @@ -238,8 +236,7 @@ await ExtractTextSubtitle(mediaSource, subtitleStream, outputCodec, outputPath,
var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec)
.TrimStart('.');

// Fallback to ffmpeg conversion
if (!_subtitleParser.SupportsFileExtension(currentFormat))
if (!TryGetReader(currentFormat, out _))
{
// Convert
var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, ".srt");
Expand All @@ -265,6 +262,40 @@ await ExtractTextSubtitle(mediaSource, subtitleStream, outputCodec, outputPath,
};
}

private bool TryGetReader(string format, [NotNullWhen(true)] out ISubtitleParser? value)
{
if (string.Equals(format, SubtitleFormat.SRT, StringComparison.OrdinalIgnoreCase))
{
value = new SrtParser(_logger);
return true;
}

if (string.Equals(format, SubtitleFormat.SSA, StringComparison.OrdinalIgnoreCase))
{
value = new SsaParser(_logger);
return true;
}

if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase))
{
value = new AssParser(_logger);
return true;
}

value = null;
return false;
}

private ISubtitleParser GetReader(string format)
{
if (TryGetReader(format, out var reader))
{
return reader;
}

throw new ArgumentException("Unsupported format: " + format);
}

private bool TryGetWriter(string format, [NotNullWhen(true)] out ISubtitleWriter? value)
{
ArgumentException.ThrowIfNullOrEmpty(format);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public void Parse_Valid_Success()
{
using (var stream = File.OpenRead("Test Data/example.ass"))
{
var parsed = new SubtitleEditParser(new NullLogger<SubtitleEditParser>()).Parse(stream, "ass");
var parsed = new AssParser(new NullLogger<AssParser>()).Parse(stream, CancellationToken.None);
Assert.Single(parsed.TrackEvents);
var trackEvent = parsed.TrackEvents[0];

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public void Parse_Valid_Success()
{
using (var stream = File.OpenRead("Test Data/example.srt"))
{
var parsed = new SubtitleEditParser(new NullLogger<SubtitleEditParser>()).Parse(stream, "srt");
var parsed = new SrtParser(new NullLogger<SrtParser>()).Parse(stream, CancellationToken.None);
Assert.Equal(2, parsed.TrackEvents.Count);

var trackEvent1 = parsed.TrackEvents[0];
Expand All @@ -36,7 +36,7 @@ public void Parse_EmptyNewlineBetweenText_Success()
{
using (var stream = File.OpenRead("Test Data/example2.srt"))
{
var parsed = new SubtitleEditParser(new NullLogger<SubtitleEditParser>()).Parse(stream, "srt");
var parsed = new SrtParser(new NullLogger<SrtParser>()).Parse(stream, CancellationToken.None);
Assert.Equal(2, parsed.TrackEvents.Count);

var trackEvent1 = parsed.TrackEvents[0];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests
{
public class SsaParserTests
{
private readonly SubtitleEditParser _parser = new SubtitleEditParser(new NullLogger<SubtitleEditParser>());
private readonly SsaParser _parser = new SsaParser(new NullLogger<AssParser>());

[Theory]
[MemberData(nameof(Parse_MultipleDialogues_TestData))]
public void Parse_MultipleDialogues_Success(string ssa, IReadOnlyList<SubtitleTrackEvent> expectedSubtitleTrackEvents)
{
using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(ssa)))
{
SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, "ssa");
SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, CancellationToken.None);

Assert.Equal(expectedSubtitleTrackEvents.Count, subtitleTrackInfo.TrackEvents.Count);

Expand Down Expand Up @@ -75,7 +75,7 @@ public void Parse_Valid_Success()
{
using (var stream = File.OpenRead("Test Data/example.ssa"))
{
var parsed = _parser.Parse(stream, "ssa");
var parsed = _parser.Parse(stream, CancellationToken.None);
Assert.Single(parsed.TrackEvents);
var trackEvent = parsed.TrackEvents[0];

Expand Down

0 comments on commit 7bb1c1a

Please sign in to comment.