diff options
Diffstat (limited to 'tests')
5 files changed, 248 insertions, 5 deletions
diff --git a/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs b/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs index de109c8d65..258cf326ca 100644 --- a/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs +++ b/tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs @@ -6,6 +6,7 @@ using System.Threading; using Jellyfin.Database.Implementations.Entities; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.MediaSegments; @@ -366,4 +367,80 @@ public class BaseItemTests Assert.Contains(alt2.Id, ids); } } + + [Fact] + public void InheritDatesFromOwner_OwnerHasDates_OverwritesOwnedItemDates() + { + var owner = new Movie + { + ProductionYear = 1982, + PremiereDate = new DateTime(1982, 6, 25, 0, 0, 0, DateTimeKind.Utc) + }; + + // 2016 is what the container creation date of a re-encoded trailer would have yielded. + var trailer = new Trailer + { + ExtraType = ExtraType.Trailer, + ProductionYear = 2016, + PremiereDate = new DateTime(2016, 5, 4, 0, 0, 0, DateTimeKind.Utc) + }; + + Assert.True(BaseItem.InheritDatesFromOwner(owner, trailer)); + Assert.Equal(owner.ProductionYear, trailer.ProductionYear); + Assert.Equal(owner.PremiereDate, trailer.PremiereDate); + } + + [Fact] + public void InheritDatesFromOwner_OwnerHasNoDates_KeepsOwnedItemDates() + { + var owner = new Movie(); + var trailer = new Trailer + { + ExtraType = ExtraType.Trailer, + ProductionYear = 1982, + PremiereDate = new DateTime(1982, 6, 25, 0, 0, 0, DateTimeKind.Utc) + }; + + Assert.False(BaseItem.InheritDatesFromOwner(owner, trailer)); + Assert.Equal(1982, trailer.ProductionYear); + Assert.Equal(new DateTime(1982, 6, 25, 0, 0, 0, DateTimeKind.Utc), trailer.PremiereDate); + } + + [Fact] + public void InheritDatesFromOwner_DatesAlreadyMatch_ReportsNoChange() + { + var owner = new Movie + { + ProductionYear = 1982, + PremiereDate = new DateTime(1982, 6, 25, 0, 0, 0, DateTimeKind.Utc) + }; + + var trailer = new Trailer + { + ExtraType = ExtraType.Trailer, + ProductionYear = owner.ProductionYear, + PremiereDate = owner.PremiereDate + }; + + Assert.False(BaseItem.InheritDatesFromOwner(owner, trailer)); + } + + [Fact] + public void InheritDatesFromOwner_OwnedItemHasNoDates_TakesOwnerDates() + { + var owner = new Movie + { + ProductionYear = 1982, + PremiereDate = new DateTime(1982, 6, 25, 0, 0, 0, DateTimeKind.Utc) + }; + + var trailer = new Trailer + { + ExtraType = ExtraType.Trailer + }; + + Assert.True(BaseItem.InheritDatesFromOwner(owner, trailer)); + Assert.Equal(1982, trailer.ProductionYear); + Assert.Equal(new DateTime(1982, 6, 25, 0, 0, 0, DateTimeKind.Utc), trailer.PremiereDate); + } } diff --git a/tests/Jellyfin.Naming.Tests/TV/MultiEpisodeTests.cs b/tests/Jellyfin.Naming.Tests/TV/MultiEpisodeTests.cs index b441e49b19..7e708c681d 100644 --- a/tests/Jellyfin.Naming.Tests/TV/MultiEpisodeTests.cs +++ b/tests/Jellyfin.Naming.Tests/TV/MultiEpisodeTests.cs @@ -69,6 +69,11 @@ namespace Jellyfin.Naming.Tests.TV [InlineData("Season 1/series-s09e14-720i.mkv", null)] [InlineData("Season 1/MOONLIGHTING_s01e01-e04.mkv", 4)] [InlineData("Season 1/MOONLIGHTING_s01e01-e04", 4)] + // Hyphenated numbers in the episode title must not be read as an episode range + [InlineData("Season 1/S01E01 The 6-10 to Lubbock [WEBRip-1080p][AV1 Opus].mkv", null)] + [InlineData("Season 5/S05E23 11-59 [HDTV-1080p][x265 AC3].mkv", null)] + [InlineData("Season 5/S05E23 11-59 [HDTV-1080p][HEVC AC3].mkv", null)] + [InlineData("Season 1/S01E01 1-23-45 [Bluray-1080p][AV1 Opus].mkv", null)] public void TestGetEndingEpisodeNumberFromFile(string filename, int? endingEpisodeNumber) { var result = _episodePathParser.Parse(filename, false); diff --git a/tests/Jellyfin.Providers.Tests/MediaInfo/FFProbeVideoInfoTests.cs b/tests/Jellyfin.Providers.Tests/MediaInfo/FFProbeVideoInfoTests.cs index 2438ef06d1..59d3f42edf 100644 --- a/tests/Jellyfin.Providers.Tests/MediaInfo/FFProbeVideoInfoTests.cs +++ b/tests/Jellyfin.Providers.Tests/MediaInfo/FFProbeVideoInfoTests.cs @@ -3,7 +3,9 @@ using AutoFixture; using AutoFixture.AutoMoq; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; +using MediaBrowser.Model.Entities; using MediaBrowser.Providers.MediaInfo; using Moq; using Xunit; @@ -75,4 +77,62 @@ public class FFProbeVideoInfoTests Assert.All(chapters, chapter => Assert.True(chapter.StartPositionTicks < runtime)); } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void FetchEmbeddedInfo_NoExtra_AppliesContainerDates(bool replaceAllMetadata) + { + var video = new Video(); + + _fFProbeVideoInfo.FetchEmbeddedInfo(video, CreateMediaInfoWithDates(), CreateRefreshOptions(replaceAllMetadata), new LibraryOptions()); + + Assert.Equal(2016, video.ProductionYear); + Assert.Equal(new DateTime(2016, 5, 4, 0, 0, 0, DateTimeKind.Utc), video.PremiereDate); + } + + [Theory] + [InlineData(false)] + [InlineData(true)] + public void FetchEmbeddedInfo_Extra_IgnoresContainerDates(bool replaceAllMetadata) + { + var video = new Video + { + ExtraType = ExtraType.Trailer, + ProductionYear = 1982, + PremiereDate = new DateTime(1982, 6, 25, 0, 0, 0, DateTimeKind.Utc) + }; + + _fFProbeVideoInfo.FetchEmbeddedInfo(video, CreateMediaInfoWithDates(), CreateRefreshOptions(replaceAllMetadata), new LibraryOptions()); + + Assert.Equal(1982, video.ProductionYear); + Assert.Equal(new DateTime(1982, 6, 25, 0, 0, 0, DateTimeKind.Utc), video.PremiereDate); + } + + [Fact] + public void FetchEmbeddedInfo_ExtraWithoutDates_StaysWithoutDates() + { + var video = new Video + { + ExtraType = ExtraType.Trailer + }; + + _fFProbeVideoInfo.FetchEmbeddedInfo(video, CreateMediaInfoWithDates(), CreateRefreshOptions(false), new LibraryOptions()); + + Assert.Null(video.ProductionYear); + Assert.Null(video.PremiereDate); + } + + private static MediaBrowser.Model.MediaInfo.MediaInfo CreateMediaInfoWithDates() + => new() + { + ProductionYear = 2016, + PremiereDate = new DateTime(2016, 5, 4, 0, 0, 0, DateTimeKind.Utc) + }; + + private static MetadataRefreshOptions CreateRefreshOptions(bool replaceAllMetadata) + => new(Mock.Of<IDirectoryService>()) + { + ReplaceAllMetadata = replaceAllMetadata + }; } diff --git a/tests/Jellyfin.Server.Implementations.Tests/Dto/DtoServiceImageInheritanceTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Dto/DtoServiceImageInheritanceTests.cs index 96625ae670..6b6240e116 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Dto/DtoServiceImageInheritanceTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Dto/DtoServiceImageInheritanceTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using Emby.Server.Implementations.Dto; using Emby.Server.Implementations.Playlists; using Jellyfin.Data.Enums; @@ -7,9 +8,9 @@ using MediaBrowser.Controller.Chapters; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.Trickplay; using MediaBrowser.Model.Entities; @@ -99,9 +100,72 @@ public class DtoServiceImageInheritanceTests Assert.Equal("/images/generated.png", dto.ImageTags[ImageType.Primary]); } + [Fact] + public void GetBaseItemDtos_MusicAlbums_ResolveInheritedThumbFromArtistBatch_WithoutPerAlbumLookup() + { + var artist = new MusicArtist + { + Id = Guid.NewGuid(), + Name = "Some Artist", + ImageInfos = + [ + new ItemImageInfo + { + Type = ImageType.Thumb, + Path = "/images/artist-thumb.jpg", + DateModified = new DateTime(2026, 1, 1, 0, 0, 0, DateTimeKind.Utc) + } + ] + }; + + static MusicAlbum MakeAlbum() => new MusicAlbum + { + Id = Guid.NewGuid(), + Name = "Album", + AlbumArtists = ["Some Artist"], + ImageInfos = [] + }; + + var libraryManager = new Mock<ILibraryManager>(); + + // DtoService resolves every album-artist name in ONE batch (GetArtists). The album's inherited + // Thumb/Backdrop images must come from that batch, not a per-album GetArtist/GetItemList lookup + // (the N+1). GetArtist is intentionally left unset: a regression to the per-album path would + // resolve no artist and fail the assertions below. + libraryManager + .Setup(x => x.GetArtists(It.IsAny<IReadOnlyList<string>>())) + .Returns(new Dictionary<string, MusicArtist[]>(StringComparer.OrdinalIgnoreCase) + { + ["Some Artist"] = [artist] + }); + + var dtoService = BuildDtoService(libraryManager); + + var dtos = dtoService.GetBaseItemDtos([MakeAlbum(), MakeAlbum()], new DtoOptions(false)); + + Assert.Equal(2, dtos.Count); + foreach (var dto in dtos) + { + Assert.Equal(artist.Id, dto.ParentThumbItemId); + Assert.Equal("/images/artist-thumb.jpg", dto.ParentThumbImageTag); + } + + // The artist lookup is batched once for the whole set, never once per album. + libraryManager.Verify(x => x.GetArtists(It.IsAny<IReadOnlyList<string>>()), Times.Once); + libraryManager.Verify(x => x.GetArtist(It.IsAny<string>(), It.IsAny<DtoOptions>()), Times.Never); + } + private static DtoService BuildDtoService(BaseItem displayParent) { var libraryManager = new Mock<ILibraryManager>(); + libraryManager + .Setup(x => x.GetItemById(displayParent.Id)) + .Returns(displayParent); + return BuildDtoService(libraryManager); + } + + private static DtoService BuildDtoService(Mock<ILibraryManager> libraryManager) + { var userDataManager = new Mock<IUserDataManager>(); var imageProcessor = new Mock<IImageProcessor>(); var providerManager = new Mock<IProviderManager>(); @@ -113,10 +177,6 @@ public class DtoServiceImageInheritanceTests var chapterManager = new Mock<IChapterManager>(); var logger = new Mock<Microsoft.Extensions.Logging.ILogger<DtoService>>(); - libraryManager - .Setup(x => x.GetItemById(displayParent.Id)) - .Returns(displayParent); - imageProcessor .Setup(x => x.GetImageCacheTag(It.IsAny<BaseItem>(), It.IsAny<ItemImageInfo>())) .Returns<BaseItem, ItemImageInfo>((_, image) => image.Path); diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs index 562711337f..07c537aee1 100644 --- a/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs +++ b/tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs @@ -306,6 +306,47 @@ public class FindExtrasTests } [Fact] + public void FindExtras_TrailerWithYearInFilename_SetsProductionYearFromFilename() + { + var owner = new Movie { Name = "Up", Path = "/movies/Up/Up.mkv" }; + var paths = new List<string> + { + "/movies/Up/Up.mkv", + "/movies/Up/trailers" + }; + + _fileSystemMock.Setup(f => f.GetFiles( + "/movies/Up/trailers", + It.IsAny<string[]>(), + false, + false)) + .Returns(new List<FileSystemMetadata> + { + new() + { + FullName = "/movies/Up/trailers/Trailer 1 (2013).mkv", + Name = "Trailer 1 (2013).mkv", + IsDirectory = false + } + }).Verifiable(); + + var files = paths.Select(p => new FileSystemMetadata + { + FullName = p, + Name = Path.GetFileName(p), + IsDirectory = !Path.HasExtension(p) + }).ToList(); + + var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).ToList(); + + _fileSystemMock.Verify(); + var trailer = Assert.Single(extras); + Assert.Equal(ExtraType.Trailer, trailer.ExtraType); + Assert.Equal(typeof(Trailer), trailer.GetType()); + Assert.Equal(2013, trailer.ProductionYear); + } + + [Fact] public void FindExtras_SeriesWithTrailers_FindsCorrectExtras() { var owner = new Series { Name = "Dexter", Path = "/series/Dexter" }; |
