diff options
| -rw-r--r-- | Emby.Naming/Video/VideoListResolver.cs | 42 | ||||
| -rw-r--r-- | tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs | 40 |
2 files changed, 64 insertions, 18 deletions
diff --git a/Emby.Naming/Video/VideoListResolver.cs b/Emby.Naming/Video/VideoListResolver.cs index 29330b132d..e16562774d 100644 --- a/Emby.Naming/Video/VideoListResolver.cs +++ b/Emby.Naming/Video/VideoListResolver.cs @@ -217,24 +217,7 @@ namespace Emby.Naming.Video for (var i = 0; i < videos.Count; i++) { var video = videos[i]; - var episodeResult = _episodePathParser.Parse(video.Files[0].Path, false); - string? key = null; - if (episodeResult.Success) - { - if (episodeResult.IsByDate - && episodeResult.Year.HasValue - && episodeResult.Month.HasValue - && episodeResult.Day.HasValue) - { - key = FormattableString.Invariant( - $"D{episodeResult.Year.Value}{episodeResult.Month.Value:D2}{episodeResult.Day.Value:D2}"); - } - else if (episodeResult.EpisodeNumber.HasValue) - { - key = FormattableString.Invariant( - $"S{episodeResult.SeasonNumber ?? 0}E{episodeResult.EpisodeNumber.Value}"); - } - } + var key = GetEpisodeVersionKey(video.Files[0].Path); if (key is null) { @@ -265,6 +248,29 @@ namespace Emby.Naming.Video return result; } + private string? GetEpisodeVersionKey(string path) + { + // Optimistic expressions are guesses, so they are not consulted here: merging is destructive, + // a file collapsed into the alternate versions of another one is no longer an episode of its own. + var episodeResult = _episodePathParser.Parse(path, false, isOptimistic: false, fillExtendedInfo: false); + if (!episodeResult.Success) + { + return null; + } + + if (episodeResult.IsByDate) + { + return episodeResult.Year.HasValue && episodeResult.Month.HasValue && episodeResult.Day.HasValue + ? FormattableString.Invariant( + $"D{episodeResult.Year.Value}{episodeResult.Month.Value:D2}{episodeResult.Day.Value:D2}") + : null; + } + + return episodeResult.SeasonNumber.HasValue && episodeResult.EpisodeNumber.HasValue + ? FormattableString.Invariant($"S{episodeResult.SeasonNumber.Value}E{episodeResult.EpisodeNumber.Value}") + : null; + } + private static VideoInfo OrganizeAlternateVersions( List<VideoInfo> videos, VideoInfo? primaryOverride = null, diff --git a/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs b/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs index b29c64f50d..62c1cf25d7 100644 --- a/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs +++ b/tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs @@ -1130,5 +1130,45 @@ namespace Jellyfin.Naming.Tests.Video Assert.Equal(2, result[0].Files.Count); Assert.Single(result[0].AlternateVersions); } + + [Fact] + public void TestMultiVersionEpisodeAbsoluteNumberingWithNumberInSeriesTitle() + { + // Every one of these parses as episode 2, because the expressions read the "2" of the + // series title as an absolute episode number. They are distinct episodes all the same. + var files = new[] + { + "/anime/IS Infinite Stratos 2/IS Infinite Stratos 2 - 01 - The Memory of a Summer (b6f40849).mkv", + "/anime/IS Infinite Stratos 2/IS Infinite Stratos 2 - 02 - Heart Pain Killer (d8c0896c).mkv", + "/anime/IS Infinite Stratos 2/IS Infinite Stratos 2 - 03 - Translucent Chord (4ecce3dd).mkv", + "/anime/IS Infinite Stratos 2/IS Infinite Stratos 2 - 04 - The Mysterious Lady (837a1909).mkv" + }; + + var result = _videoListResolver.Resolve( + files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(), + collectionType: CollectionType.tvshows).ToList(); + + Assert.Equal(4, result.Count); + Assert.All(result, r => Assert.Empty(r.AlternateVersions)); + } + + [Fact] + public void TestMultiVersionEpisodeAbsoluteNumberingDontCollapse() + { + // Plain absolute numbering: no season number is available, so the files stay separate. + var files = new[] + { + "/anime/Bleach/Bleach - 001 - The Day I Became a Shinigami.mkv", + "/anime/Bleach/Bleach - 002 - The Shinigami's Work.mkv", + "/anime/Bleach/Bleach - 003 - The Older Brother's Wish.mkv" + }; + + var result = _videoListResolver.Resolve( + files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(), + collectionType: CollectionType.tvshows).ToList(); + + Assert.Equal(3, result.Count); + Assert.All(result, r => Assert.Empty(r.AlternateVersions)); + } } } |
