diff --git a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs index dd4a5f061..ba284187e 100644 --- a/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs +++ b/MediaBrowser.Providers/MediaInfo/SubtitleResolver.cs @@ -1,7 +1,3 @@ -#nullable disable - -#pragma warning disable CA1002, CS1591 - using System; using System.Collections.Generic; using System.IO; @@ -12,15 +8,30 @@ using MediaBrowser.Model.Globalization; namespace MediaBrowser.Providers.MediaInfo { + /// + /// Resolves external subtitles for videos. + /// public class SubtitleResolver { private readonly ILocalizationManager _localization; + /// + /// Initializes a new instance of the class. + /// + /// The localization manager. public SubtitleResolver(ILocalizationManager localization) { _localization = localization; } + /// + /// Retrieves the external subtitle streams for the provided video. + /// + /// The video to search from. + /// The stream index to start adding subtitle streams at. + /// The directory service to search for files. + /// True if the directory service cache should be cleared before searching. + /// The external subtitle streams located. public List GetExternalSubtitleStreams( Video video, int startIndex, @@ -56,6 +67,13 @@ namespace MediaBrowser.Providers.MediaInfo return streams; } + /// + /// Locates the external subtitle files for the provided video. + /// + /// The video to search from. + /// The directory service to search for files. + /// True if the directory service cache should be cleared before searching. + /// The external subtitle file paths located. public IEnumerable GetExternalSubtitleFiles( Video video, IDirectoryService directoryService, @@ -74,6 +92,13 @@ namespace MediaBrowser.Providers.MediaInfo } } + /// + /// Extracts the subtitle files from the provided list and adds them to the list of streams. + /// + /// The list of streams to add external subtitles to. + /// The path to the video file. + /// The stream index to start adding subtitle streams at. + /// The files to add if they are subtitles. public void AddExternalSubtitleStreams( List streams, string videoPath, @@ -120,6 +145,12 @@ namespace MediaBrowser.Providers.MediaInfo while (languageSpan.Length > 0) { var lastDot = languageSpan.LastIndexOf('.'); + if (lastDot < videoFileNameWithoutExtension.Length) + { + languageSpan = ReadOnlySpan.Empty; + break; + } + var currentSlice = languageSpan[lastDot..]; if (currentSlice.Equals(".default", StringComparison.OrdinalIgnoreCase) || currentSlice.Equals(".forced", StringComparison.OrdinalIgnoreCase) @@ -133,12 +164,19 @@ namespace MediaBrowser.Providers.MediaInfo break; } - // Try to translate to three character code - // Be flexible and check against both the full and three character versions var language = languageSpan.ToString(); - var culture = _localization.FindLanguageInfo(language); + if (string.IsNullOrWhiteSpace(language)) + { + language = null; + } + else + { + // Try to translate to three character code + // Be flexible and check against both the full and three character versions + var culture = _localization.FindLanguageInfo(language); - language = culture == null ? language : culture.ThreeLetterISOLanguageName; + language = culture == null ? language : culture.ThreeLetterISOLanguageName; + } mediaStream = new MediaStream { diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs index c289a7112..33da277e3 100644 --- a/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/SubtitleResolverTests.cs @@ -80,6 +80,37 @@ namespace Jellyfin.Providers.Tests.MediaInfo } } + [Theory] + [InlineData("/video/My Video.mkv", "/video/My Video.srt", "srt", null, false, false)] + [InlineData("/video/My.Video.mkv", "/video/My.Video.srt", "srt", null, false, false)] + [InlineData("/video/My.Video.mkv", "/video/My.Video.foreign.srt", "srt", null, true, false)] + [InlineData("/video/My Video.mkv", "/video/My Video.forced.srt", "srt", null, true, false)] + [InlineData("/video/My.Video.mkv", "/video/My.Video.default.srt", "srt", null, false, true)] + [InlineData("/video/My.Video.mkv", "/video/My.Video.forced.default.srt", "srt", null, true, true)] + [InlineData("/video/My.Video.mkv", "/video/My.Video.en.srt", "srt", "en", false, false)] + [InlineData("/video/My.Video.mkv", "/video/My.Video.default.en.srt", "srt", "en", false, true)] + [InlineData("/video/My.Video.mkv", "/video/My.Video.default.forced.en.srt", "srt", "en", true, true)] + [InlineData("/video/My.Video.mkv", "/video/My.Video.en.default.forced.srt", "srt", "en", true, true)] + public void AddExternalSubtitleStreams_GivenSingleFile_ReturnsExpectedSubtitle(string videoPath, string file, string codec, string? language, bool isForced, bool isDefault) + { + var streams = new List(); + var expected = CreateMediaStream(file, codec, language, 0, isForced, isDefault); + + new SubtitleResolver(Mock.Of()).AddExternalSubtitleStreams(streams, videoPath, 0, new[] { file }); + + Assert.Single(streams); + + var actual = streams[0]; + + Assert.Equal(expected.Index, actual.Index); + Assert.Equal(expected.Type, actual.Type); + Assert.Equal(expected.IsExternal, actual.IsExternal); + Assert.Equal(expected.Path, actual.Path); + Assert.Equal(expected.IsDefault, actual.IsDefault); + Assert.Equal(expected.IsForced, actual.IsForced); + Assert.Equal(expected.Language, actual.Language); + } + private static MediaStream CreateMediaStream(string path, string codec, string? language, int index, bool isForced = false, bool isDefault = false) { return new ()