aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/Jellyfin.Controller.Tests/Entities/BaseItemTests.cs77
-rw-r--r--tests/Jellyfin.Naming.Tests/TV/MultiEpisodeTests.cs5
-rw-r--r--tests/Jellyfin.Providers.Tests/MediaInfo/FFProbeVideoInfoTests.cs60
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Dto/DtoServiceImageInheritanceTests.cs70
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs41
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" };