From ca1f7af4458feffa7b9800d536b536e544fc4b7c Mon Sep 17 00:00:00 2001 From: Shadowghost Date: Tue, 21 Jul 2026 20:27:04 +0200 Subject: Fix incorrect year on local trailers --- .../Library/Resolvers/ExtraResolver.cs | 4 +-- .../Library/Resolvers/GenericVideoResolver.cs | 13 ++++++- MediaBrowser.Controller/Entities/BaseItem.cs | 13 +++++++ .../Library/LibraryManager/FindExtrasTests.cs | 41 ++++++++++++++++++++++ 4 files changed, 68 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs b/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs index b9f9f29723..6ba4a7bce6 100644 --- a/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/ExtraResolver.cs @@ -32,8 +32,8 @@ namespace Emby.Server.Implementations.Library.Resolvers : base(logger, namingOptions, directoryService) { _namingOptions = namingOptions; - _trailerResolvers = new IItemResolver[] { new GenericVideoResolver(logger, namingOptions, directoryService) }; - _videoResolvers = new IItemResolver[] { this }; + _trailerResolvers = [new GenericVideoResolver(logger, namingOptions, directoryService, parseName: true)]; + _videoResolvers = [this]; } protected override Video Resolve(ItemResolveArgs args) diff --git a/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs index ba320266a4..b3bdea704a 100644 --- a/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/GenericVideoResolver.cs @@ -2,6 +2,7 @@ using Emby.Naming.Common; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers; using Microsoft.Extensions.Logging; @@ -14,15 +15,25 @@ namespace Emby.Server.Implementations.Library.Resolvers public class GenericVideoResolver : BaseVideoResolver where T : Video, new() { + private readonly bool _parseName; + /// /// Initializes a new instance of the class. /// /// The logger. /// The naming options. /// The directory service. - public GenericVideoResolver(ILogger logger, NamingOptions namingOptions, IDirectoryService directoryService) + /// Whether to parse the file name for metadata such as the year. + public GenericVideoResolver(ILogger logger, NamingOptions namingOptions, IDirectoryService directoryService, bool parseName = false) : base(logger, namingOptions, directoryService) { + _parseName = parseName; + } + + /// + protected override T Resolve(ItemResolveArgs args) + { + return ResolveVideo(args, _parseName); } } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 49a4ed4bf6..cc2a425a4d 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1557,6 +1557,19 @@ namespace MediaBrowser.Controller.Entities i.OwnerId = ownerId; i.ParentId = Guid.Empty; + + // Extras (e.g. trailers) frequently have no reliable date metadata of their own and + // would otherwise fall back to the file's container creation date. Inherit the owner's + // year/premiere date when the extra doesn't have one, so it stays consistent with the + // media it belongs to. Setting it before the refresh means the media info provider + // won't overwrite it from the file creation date. + if (!i.ProductionYear.HasValue && item.ProductionYear.HasValue) + { + i.ProductionYear = item.ProductionYear; + i.PremiereDate ??= item.PremiereDate; + subOptions.ForceSave = true; + } + return RefreshMetadataForOwnedItem(i, true, subOptions, cancellationToken); }); 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 @@ -305,6 +305,47 @@ public class FindExtrasTests Assert.Empty(extras); } + [Fact] + public void FindExtras_TrailerWithYearInFilename_SetsProductionYearFromFilename() + { + var owner = new Movie { Name = "Up", Path = "/movies/Up/Up.mkv" }; + var paths = new List + { + "/movies/Up/Up.mkv", + "/movies/Up/trailers" + }; + + _fileSystemMock.Setup(f => f.GetFiles( + "/movies/Up/trailers", + It.IsAny(), + false, + false)) + .Returns(new List + { + 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() { -- cgit v1.2.3