From 1db748399cfad140c28e92cd44a5ea630a0bd5ea Mon Sep 17 00:00:00 2001 From: cvium Date: Fri, 8 Jul 2022 19:44:15 +0200 Subject: [PATCH 1/9] feat: make subtitleeditparser generic --- .../Subtitles/AssParser.cs | 19 ------------ .../Subtitles/ISubtitleParser.cs | 5 ++-- .../Subtitles/SrtParser.cs | 19 ------------ .../Subtitles/SsaParser.cs | 19 ------------ .../Subtitles/SubtitleEditParser.cs | 29 ++++++++++--------- .../Subtitles/SubtitleEncoder.cs | 24 ++------------- .../Subtitles/AssParserTests.cs | 2 +- .../Subtitles/SrtParserTests.cs | 4 +-- .../Subtitles/SsaParserTests.cs | 6 ++-- 9 files changed, 27 insertions(+), 100 deletions(-) delete mode 100644 MediaBrowser.MediaEncoding/Subtitles/AssParser.cs delete mode 100644 MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs delete mode 100644 MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs diff --git a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs b/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs deleted file mode 100644 index 08ee5c72e..000000000 --- a/MediaBrowser.MediaEncoding/Subtitles/AssParser.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.Logging; -using Nikse.SubtitleEdit.Core.SubtitleFormats; - -namespace MediaBrowser.MediaEncoding.Subtitles -{ - /// - /// Advanced SubStation Alpha subtitle parser. - /// - public class AssParser : SubtitleEditParser - { - /// - /// Initializes a new instance of the class. - /// - /// The logger. - public AssParser(ILogger logger) : base(logger) - { - } - } -} diff --git a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs index c0023ebf2..66d1776a4 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs @@ -1,7 +1,6 @@ #pragma warning disable CS1591 using System.IO; -using System.Threading; using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.MediaEncoding.Subtitles @@ -12,8 +11,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// Parses the specified stream. /// /// The stream. - /// The cancellation token. + /// The file extension. /// SubtitleTrackInfo. - SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken); + SubtitleTrackInfo Parse(Stream stream, string fileExtension); } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs deleted file mode 100644 index 78d54ca51..000000000 --- a/MediaBrowser.MediaEncoding/Subtitles/SrtParser.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.Logging; -using Nikse.SubtitleEdit.Core.SubtitleFormats; - -namespace MediaBrowser.MediaEncoding.Subtitles -{ - /// - /// SubRip subtitle parser. - /// - public class SrtParser : SubtitleEditParser - { - /// - /// Initializes a new instance of the class. - /// - /// The logger. - public SrtParser(ILogger logger) : base(logger) - { - } - } -} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs deleted file mode 100644 index 17c2ae40e..000000000 --- a/MediaBrowser.MediaEncoding/Subtitles/SsaParser.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Microsoft.Extensions.Logging; -using Nikse.SubtitleEdit.Core.SubtitleFormats; - -namespace MediaBrowser.MediaEncoding.Subtitles -{ - /// - /// SubStation Alpha subtitle parser. - /// - public class SsaParser : SubtitleEditParser - { - /// - /// Initializes a new instance of the class. - /// - /// The logger. - public SsaParser(ILogger logger) : base(logger) - { - } - } -} diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index 52c1b6467..da57e6f2a 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -1,7 +1,7 @@ +using System; using System.Globalization; using System.IO; using System.Linq; -using System.Threading; using Jellyfin.Extensions; using MediaBrowser.Model.MediaInfo; using Microsoft.Extensions.Logging; @@ -14,31 +14,34 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// /// SubStation Alpha subtitle parser. /// - /// The . - public abstract class SubtitleEditParser : ISubtitleParser - where T : SubtitleFormat, new() + public class SubtitleEditParser : ISubtitleParser { private readonly ILogger _logger; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The logger. - protected SubtitleEditParser(ILogger logger) + public SubtitleEditParser(ILogger logger) { _logger = logger; } /// - public SubtitleTrackInfo Parse(Stream stream, CancellationToken cancellationToken) + public SubtitleTrackInfo Parse(Stream stream, string fileExtension) { - var subtitle = new Subtitle(); - var subRip = new T(); - var lines = stream.ReadAllLines().ToList(); - subRip.LoadSubtitle(subtitle, lines, "untitled"); - if (subRip.ErrorCount > 0) + var subtitleFormat = SubtitleFormat.AllSubtitleFormats.FirstOrDefault(asf => asf.Extension.Equals(fileExtension, StringComparison.OrdinalIgnoreCase)); + if (subtitleFormat == null) { - _logger.LogError("{ErrorCount} errors encountered while parsing subtitle", subRip.ErrorCount); + throw new ArgumentException("Unsupported format: " + fileExtension); + } + + var lines = stream.ReadAllLines().ToList(); + var subtitle = new Subtitle(); + subtitleFormat.LoadSubtitle(subtitle, lines, fileExtension); + if (subtitleFormat.ErrorCount > 0) + { + _logger.LogError("{ErrorCount} errors encountered while parsing subtitle", subtitleFormat.ErrorCount); } var trackInfo = new SubtitleTrackInfo(); diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index 7091af734..a0709d1e7 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -74,7 +74,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { var reader = GetReader(inputFormat); - var trackInfo = reader.Parse(stream, cancellationToken); + var trackInfo = reader.Parse(stream, $".{inputFormat}"); FilterEvents(trackInfo, startTimeTicks, endTimeTicks, preserveOriginalTimestamps); @@ -249,26 +249,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles 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; + value = new SubtitleEditParser(_logger); + return true; } private ISubtitleParser GetReader(string format) diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs index 3775555de..395dfa309 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs @@ -15,7 +15,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example.ass")) { - var parsed = new AssParser(new NullLogger()).Parse(stream, CancellationToken.None); + var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, ".ass"); Assert.Single(parsed.TrackEvents); var trackEvent = parsed.TrackEvents[0]; diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs index c07c9ea7d..e9745f17d 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs @@ -15,7 +15,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example.srt")) { - var parsed = new SrtParser(new NullLogger()).Parse(stream, CancellationToken.None); + var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, ".srt"); Assert.Equal(2, parsed.TrackEvents.Count); var trackEvent1 = parsed.TrackEvents[0]; @@ -37,7 +37,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example2.srt")) { - var parsed = new SrtParser(new NullLogger()).Parse(stream, CancellationToken.None); + var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, ".srt"); Assert.Equal(2, parsed.TrackEvents.Count); var trackEvent1 = parsed.TrackEvents[0]; diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs index 56649db8f..bb6ed22eb 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs @@ -13,7 +13,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { public class SsaParserTests { - private readonly SsaParser _parser = new SsaParser(new NullLogger()); + private readonly SubtitleEditParser _parser = new SubtitleEditParser(new NullLogger()); [Theory] [MemberData(nameof(Parse_MultipleDialogues_TestData))] @@ -21,7 +21,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(ssa))) { - SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, CancellationToken.None); + SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, ".ssa"); Assert.Equal(expectedSubtitleTrackEvents.Count, subtitleTrackInfo.TrackEvents.Count); @@ -76,7 +76,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example.ssa")) { - var parsed = _parser.Parse(stream, CancellationToken.None); + var parsed = _parser.Parse(stream, ".ssa"); Assert.Single(parsed.TrackEvents); var trackEvent = parsed.TrackEvents[0]; From 78f437401b836edc8fc535eb5d46506e58a64329 Mon Sep 17 00:00:00 2001 From: cvium Date: Fri, 8 Jul 2022 20:11:00 +0200 Subject: [PATCH 2/9] loop over all compatible SubtitleFormats --- .../Subtitles/SubtitleEditParser.cs | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index da57e6f2a..c487f9ac4 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -30,17 +30,23 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// public SubtitleTrackInfo Parse(Stream stream, string fileExtension) { - var subtitleFormat = SubtitleFormat.AllSubtitleFormats.FirstOrDefault(asf => asf.Extension.Equals(fileExtension, StringComparison.OrdinalIgnoreCase)); - if (subtitleFormat == null) - { - throw new ArgumentException("Unsupported format: " + fileExtension); - } - - var lines = stream.ReadAllLines().ToList(); var subtitle = new Subtitle(); - subtitleFormat.LoadSubtitle(subtitle, lines, fileExtension); - if (subtitleFormat.ErrorCount > 0) + var lines = stream.ReadAllLines().ToList(); + + var subtitleFormats = SubtitleFormat.AllSubtitleFormats.Where(asf => asf.Extension.Equals(fileExtension, StringComparison.OrdinalIgnoreCase)); + foreach (var subtitleFormat in subtitleFormats) { + if (subtitleFormat == null) + { + throw new ArgumentException("Unsupported format: " + fileExtension); + } + + subtitleFormat.LoadSubtitle(subtitle, lines, fileExtension); + if (subtitleFormat.ErrorCount == 0) + { + break; + } + _logger.LogError("{ErrorCount} errors encountered while parsing subtitle", subtitleFormat.ErrorCount); } From dbfa0f30276054b63402e95867ed9a9f1b1cca08 Mon Sep 17 00:00:00 2001 From: cvium Date: Fri, 8 Jul 2022 20:12:00 +0200 Subject: [PATCH 3/9] fix unsupported --- .../Subtitles/SubtitleEditParser.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index c487f9ac4..4e6403e98 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -36,11 +36,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles var subtitleFormats = SubtitleFormat.AllSubtitleFormats.Where(asf => asf.Extension.Equals(fileExtension, StringComparison.OrdinalIgnoreCase)); foreach (var subtitleFormat in subtitleFormats) { - if (subtitleFormat == null) - { - throw new ArgumentException("Unsupported format: " + fileExtension); - } - subtitleFormat.LoadSubtitle(subtitle, lines, fileExtension); if (subtitleFormat.ErrorCount == 0) { @@ -50,6 +45,11 @@ namespace MediaBrowser.MediaEncoding.Subtitles _logger.LogError("{ErrorCount} errors encountered while parsing subtitle", subtitleFormat.ErrorCount); } + if (subtitle.Paragraphs.Count == 0) + { + throw new ArgumentException("Unsupported format: " + fileExtension); + } + var trackInfo = new SubtitleTrackInfo(); int len = subtitle.Paragraphs.Count; var trackEvents = new SubtitleTrackEvent[len]; From 126da94020385952cbba08dad76a575452b76aa8 Mon Sep 17 00:00:00 2001 From: cvium Date: Mon, 25 Jul 2022 09:47:21 +0200 Subject: [PATCH 4/9] use reflection to get all subtitle formats without causing libse configuration loading --- .../ApplicationHost.cs | 4 +- .../Subtitles/ISubtitleParser.cs | 7 ++ .../Subtitles/SubtitleEditParser.cs | 118 +++++++++++++++++- .../Subtitles/SubtitleEncoder.cs | 29 ++--- 4 files changed, 131 insertions(+), 27 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 32289625f..2f47d4398 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -83,6 +83,7 @@ using MediaBrowser.Controller.SyncPlay; using MediaBrowser.Controller.TV; using MediaBrowser.LocalMetadata.Savers; using MediaBrowser.MediaEncoding.BdInfo; +using MediaBrowser.MediaEncoding.Subtitles; using MediaBrowser.Model.Cryptography; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Globalization; @@ -634,7 +635,8 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(); serviceCollection.AddSingleton(); diff --git a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs index 66d1776a4..bd13437fb 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/ISubtitleParser.cs @@ -14,5 +14,12 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// The file extension. /// SubtitleTrackInfo. SubtitleTrackInfo Parse(Stream stream, string fileExtension); + + /// + /// Determines whether the file extension is supported by the parser. + /// + /// The file extension. + /// A value indicating whether the file extension is supported. + bool SupportsFileExtension(string fileExtension); } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index 4e6403e98..c94242b4b 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -1,12 +1,14 @@ using System; +using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using System.Reflection; using Jellyfin.Extensions; using MediaBrowser.Model.MediaInfo; using Microsoft.Extensions.Logging; using Nikse.SubtitleEdit.Core.Common; -using ILogger = Microsoft.Extensions.Logging.ILogger; +using Nikse.SubtitleEdit.Core.SubtitleFormats; using SubtitleFormat = Nikse.SubtitleEdit.Core.SubtitleFormats.SubtitleFormat; namespace MediaBrowser.MediaEncoding.Subtitles @@ -16,15 +18,20 @@ namespace MediaBrowser.MediaEncoding.Subtitles /// public class SubtitleEditParser : ISubtitleParser { - private readonly ILogger _logger; + private readonly ILogger _logger; + private readonly Dictionary _subtitleFormats; /// /// Initializes a new instance of the class. /// /// The logger. - public SubtitleEditParser(ILogger logger) + public 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); } /// @@ -33,16 +40,28 @@ namespace MediaBrowser.MediaEncoding.Subtitles var subtitle = new Subtitle(); var lines = stream.ReadAllLines().ToList(); - var subtitleFormats = SubtitleFormat.AllSubtitleFormats.Where(asf => asf.Extension.Equals(fileExtension, StringComparison.OrdinalIgnoreCase)); + if (!_subtitleFormats.TryGetValue(fileExtension, out var subtitleFormats)) + { + throw new ArgumentException($"Unsupported file extension: {fileExtension}", nameof(fileExtension)); + } + foreach (var subtitleFormat in subtitleFormats) { + _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 subtitle", subtitleFormat.ErrorCount); + _logger.LogError( + "{ErrorCount} errors encountered while parsing '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser", + subtitleFormat.ErrorCount, + fileExtension, + subtitleFormat.Name); } if (subtitle.Paragraphs.Count == 0) @@ -66,5 +85,94 @@ namespace MediaBrowser.MediaEncoding.Subtitles trackInfo.TrackEvents = trackEvents; return trackInfo; } + + /// + public bool SupportsFileExtension(string fileExtension) + => _subtitleFormats.ContainsKey(fileExtension); + + private IEnumerable GetSubtitleFormats() + { + var subtitleFormats = new List(); + var assembly = Assembly.GetAssembly(typeof(SubtitleFormat)); + if (assembly == null) + { + _logger.LogError("Missing assembly containing {SubtitleFormatName}", nameof(SubtitleFormat)); + return GetFallbackSubtitleFormats(); + } + + foreach (var type in assembly.GetTypes()) + { + if (!type.IsSubclassOf(typeof(SubtitleFormat))) + { + 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; + } + + private static IEnumerable GetFallbackSubtitleFormats() + => new SubtitleFormat[] + { + // Preferred and likely more common formats + new SubRip(), + new WebVTT(), + new WebVTTFileWithLineNumber(), + new AdvancedSubStationAlpha(), + new SubStationAlpha(), + new Sami(), + new SamiAvDicPlayer(), + new SamiModern(), + new SamiYouTube(), + new DvdSubtitle(), + new DvdSubtitleSystem(), + new JsonAeneas(), + new JsonTed(), + new Json(), + new JsonType2(), + new JsonType3(), + new JsonType4(), + new JsonType5(), + new JsonType6(), + new JsonType7(), + new JsonType8(), + new JsonType8b(), + new JsonType9(), + new JsonType10(), + new JsonType11(), + new JsonType12(), + new JsonType13(), + new JsonType14(), + new JsonType15(), + new JsonType16(), + new JsonType17(), + new JsonType18(), + new JsonType19(), + new JsonType20(), + new ItunesTimedText(), + new FLVCoreCuePoints(), + new Csv(), + new Csv2(), + new Csv3(), + new Csv4(), + new Csv5(), + new Ebu(), + new NetflixImsc11Japanese(), + new NetflixTimedText(), + new QuickTimeText(), + new RealTime(), + new SmpteTt2052() + }; } } diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs index a0709d1e7..50c4d9210 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEncoder.cs @@ -35,6 +35,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles private readonly IMediaEncoder _mediaEncoder; private readonly IHttpClientFactory _httpClientFactory; private readonly IMediaSourceManager _mediaSourceManager; + private readonly ISubtitleParser _subtitleParser; /// /// The _semaphoreLocks. @@ -48,7 +49,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles IFileSystem fileSystem, IMediaEncoder mediaEncoder, IHttpClientFactory httpClientFactory, - IMediaSourceManager mediaSourceManager) + IMediaSourceManager mediaSourceManager, + ISubtitleParser subtitleParser) { _logger = logger; _appPaths = appPaths; @@ -56,6 +58,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles _mediaEncoder = mediaEncoder; _httpClientFactory = httpClientFactory; _mediaSourceManager = mediaSourceManager; + _subtitleParser = subtitleParser; } private string SubtitleCachePath => Path.Combine(_appPaths.DataPath, "subtitles"); @@ -73,8 +76,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles try { - var reader = GetReader(inputFormat); - var trackInfo = reader.Parse(stream, $".{inputFormat}"); + var trackInfo = _subtitleParser.Parse(stream, inputFormat); FilterEvents(trackInfo, startTimeTicks, endTimeTicks, preserveOriginalTimestamps); @@ -233,7 +235,8 @@ namespace MediaBrowser.MediaEncoding.Subtitles var currentFormat = (Path.GetExtension(subtitleStream.Path) ?? subtitleStream.Codec) .TrimStart('.'); - if (!TryGetReader(currentFormat, out _)) + // Fallback to ffmpeg conversion + if (!_subtitleParser.SupportsFileExtension(currentFormat)) { // Convert var outputPath = GetSubtitleCachePath(mediaSource, subtitleStream.Index, ".srt"); @@ -243,26 +246,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles return new SubtitleInfo(outputPath, MediaProtocol.File, "srt", true); } - // It's possbile that the subtitleStream and mediaSource don't share the same protocol (e.g. .STRM file with local subs) + // It's possible that the subtitleStream and mediaSource don't share the same protocol (e.g. .STRM file with local subs) return new SubtitleInfo(subtitleStream.Path, _mediaSourceManager.GetPathProtocol(subtitleStream.Path), currentFormat, true); } - private bool TryGetReader(string format, [NotNullWhen(true)] out ISubtitleParser? value) - { - value = new SubtitleEditParser(_logger); - return true; - } - - 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) { if (string.Equals(format, SubtitleFormat.ASS, StringComparison.OrdinalIgnoreCase)) From 3b69f38a1f6c5c9e1ccfa148980180900a10aa85 Mon Sep 17 00:00:00 2001 From: cvium Date: Mon, 25 Jul 2022 09:51:03 +0200 Subject: [PATCH 5/9] fix tests --- .../Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs | 2 +- .../Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs | 4 ++-- .../Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs index 395dfa309..e14850eed 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/AssParserTests.cs @@ -15,7 +15,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example.ass")) { - var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, ".ass"); + var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, "ass"); Assert.Single(parsed.TrackEvents); var trackEvent = parsed.TrackEvents[0]; diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs index e9745f17d..0038b1873 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SrtParserTests.cs @@ -15,7 +15,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example.srt")) { - var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, ".srt"); + var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, "srt"); Assert.Equal(2, parsed.TrackEvents.Count); var trackEvent1 = parsed.TrackEvents[0]; @@ -37,7 +37,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example2.srt")) { - var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, ".srt"); + var parsed = new SubtitleEditParser(new NullLogger()).Parse(stream, "srt"); Assert.Equal(2, parsed.TrackEvents.Count); var trackEvent1 = parsed.TrackEvents[0]; diff --git a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs index bb6ed22eb..3b9a71690 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs +++ b/tests/Jellyfin.MediaEncoding.Tests/Subtitles/SsaParserTests.cs @@ -21,7 +21,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (Stream stream = new MemoryStream(Encoding.UTF8.GetBytes(ssa))) { - SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, ".ssa"); + SubtitleTrackInfo subtitleTrackInfo = _parser.Parse(stream, "ssa"); Assert.Equal(expectedSubtitleTrackEvents.Count, subtitleTrackInfo.TrackEvents.Count); @@ -76,7 +76,7 @@ namespace Jellyfin.MediaEncoding.Subtitles.Tests { using (var stream = File.OpenRead("Test Data/example.ssa")) { - var parsed = _parser.Parse(stream, ".ssa"); + var parsed = _parser.Parse(stream, "ssa"); Assert.Single(parsed.TrackEvents); var trackEvent = parsed.TrackEvents[0]; From b0b4068ddfaeed023d20c0c96ffa992bcaaee505 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Sat, 30 Jul 2022 14:59:00 +0200 Subject: [PATCH 6/9] Update MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs Co-authored-by: Bond-009 --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index c94242b4b..e95cb12d2 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -102,7 +102,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles foreach (var type in assembly.GetTypes()) { - if (!type.IsSubclassOf(typeof(SubtitleFormat))) + if (!type.IsSubclassOf(typeof(SubtitleFormat)) || type.IsAbstract) { continue; } From f2c7bccb891293cec9ca814e285ea1bb7f6c1155 Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Sat, 30 Jul 2022 14:59:28 +0200 Subject: [PATCH 7/9] Update MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs Co-authored-by: Bond-009 --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index e95cb12d2..ef8888271 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -93,7 +93,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles private IEnumerable GetSubtitleFormats() { var subtitleFormats = new List(); - var assembly = Assembly.GetAssembly(typeof(SubtitleFormat)); + var assembly = typeof(SubtitleFormat).Assembly; if (assembly == null) { _logger.LogError("Missing assembly containing {SubtitleFormatName}", nameof(SubtitleFormat)); From a380153f92969b151fc0bc26948b6b8d96475846 Mon Sep 17 00:00:00 2001 From: cvium Date: Sat, 30 Jul 2022 21:54:03 +0200 Subject: [PATCH 8/9] remove redundant null check --- MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index ef8888271..87863549c 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -94,11 +94,6 @@ namespace MediaBrowser.MediaEncoding.Subtitles { var subtitleFormats = new List(); var assembly = typeof(SubtitleFormat).Assembly; - if (assembly == null) - { - _logger.LogError("Missing assembly containing {SubtitleFormatName}", nameof(SubtitleFormat)); - return GetFallbackSubtitleFormats(); - } foreach (var type in assembly.GetTypes()) { From d258a87fdaf58c3a16602301f7e9079ac42200ab Mon Sep 17 00:00:00 2001 From: Claus Vium Date: Mon, 1 Aug 2022 18:30:32 +0200 Subject: [PATCH 9/9] Update MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs Co-authored-by: Bond-009 --- .../Subtitles/SubtitleEditParser.cs | 53 ------------------- 1 file changed, 53 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs index 87863549c..eb8ff9624 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/SubtitleEditParser.cs @@ -116,58 +116,5 @@ namespace MediaBrowser.MediaEncoding.Subtitles return subtitleFormats; } - - private static IEnumerable GetFallbackSubtitleFormats() - => new SubtitleFormat[] - { - // Preferred and likely more common formats - new SubRip(), - new WebVTT(), - new WebVTTFileWithLineNumber(), - new AdvancedSubStationAlpha(), - new SubStationAlpha(), - new Sami(), - new SamiAvDicPlayer(), - new SamiModern(), - new SamiYouTube(), - new DvdSubtitle(), - new DvdSubtitleSystem(), - new JsonAeneas(), - new JsonTed(), - new Json(), - new JsonType2(), - new JsonType3(), - new JsonType4(), - new JsonType5(), - new JsonType6(), - new JsonType7(), - new JsonType8(), - new JsonType8b(), - new JsonType9(), - new JsonType10(), - new JsonType11(), - new JsonType12(), - new JsonType13(), - new JsonType14(), - new JsonType15(), - new JsonType16(), - new JsonType17(), - new JsonType18(), - new JsonType19(), - new JsonType20(), - new ItunesTimedText(), - new FLVCoreCuePoints(), - new Csv(), - new Csv2(), - new Csv3(), - new Csv4(), - new Csv5(), - new Ebu(), - new NetflixImsc11Japanese(), - new NetflixTimedText(), - new QuickTimeText(), - new RealTime(), - new SmpteTt2052() - }; } }