From 2757c18312943cbc17ce01b100f73b411f596a98 Mon Sep 17 00:00:00 2001 From: theguymadmax Date: Fri, 13 Feb 2026 11:52:10 -0500 Subject: [PATCH] Fix episodes appearing in Season Unknown incorrectly and prevent unnecessary virtual season creation --- MediaBrowser.Controller/Entities/TV/Series.cs | 3 +- .../TV/SeriesMetadataService.cs | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 6396631f99..b3956c8233 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -451,7 +451,8 @@ namespace MediaBrowser.Controller.Entities.TV if (!currentSeasonNumber.HasValue && !seasonNumber.HasValue && parentSeason.LocationType == LocationType.Virtual) { - return true; + var episodeSeason = episodeItem.Season; + return episodeSeason is null || episodeSeason.LocationType == LocationType.Virtual; } var season = episodeItem.Season; diff --git a/MediaBrowser.Providers/TV/SeriesMetadataService.cs b/MediaBrowser.Providers/TV/SeriesMetadataService.cs index c3a6ddd6ae..61a31fbfd6 100644 --- a/MediaBrowser.Providers/TV/SeriesMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeriesMetadataService.cs @@ -4,6 +4,7 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Threading.Tasks; +using Jellyfin.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -201,6 +202,26 @@ public class SeriesMetadataService : MetadataService false); } + private static bool NeedsVirtualSeason(Episode episode, HashSet physicalSeasonIds, HashSet physicalSeasonPaths) + { + // Episode has a known season number, needs a season + if (episode.ParentIndexNumber.HasValue) + { + return true; + } + + // Not yet processed + if (episode.SeasonId.IsEmpty()) + { + return false; + } + + // Episode has been processed, only needs a virtual season if it isn't + // already linked to a known physical season by ID or path + return !physicalSeasonIds.Contains(episode.SeasonId) + && !physicalSeasonPaths.Contains(System.IO.Path.GetDirectoryName(episode.Path) ?? string.Empty); + } + /// /// Creates seasons for all episodes if they don't exist. /// If no season number can be determined, a dummy season will be created. @@ -212,8 +233,20 @@ public class SeriesMetadataService : MetadataService { var seriesChildren = series.GetRecursiveChildren(i => i is Episode || i is Season); var seasons = seriesChildren.OfType().ToList(); + + var physicalSeasonIds = seasons + .Where(e => e.LocationType != LocationType.Virtual) + .Select(e => e.Id) + .ToHashSet(); + + var physicalSeasonPathSet = seasons + .Where(e => e.LocationType != LocationType.Virtual && !string.IsNullOrEmpty(e.Path)) + .Select(e => e.Path) + .ToHashSet(StringComparer.OrdinalIgnoreCase); + var uniqueSeasonNumbers = seriesChildren .OfType() + .Where(e => NeedsVirtualSeason(e, physicalSeasonIds, physicalSeasonPathSet)) .Select(e => e.ParentIndexNumber >= 0 ? e.ParentIndexNumber : null) .Distinct();