Pārlūkot izejas kodu

fix: remove Virtual episodes when their physical counterpart exists

cvium 2 gadi atpakaļ
vecāks
revīzija
56c81696d3

+ 2 - 6
MediaBrowser.Controller/Entities/TV/Series.cs

@@ -258,14 +258,10 @@ namespace MediaBrowser.Controller.Entities.TV
                 SeriesPresentationUniqueKey = seriesKey,
                 IncludeItemTypes = new[] { BaseItemKind.Episode, BaseItemKind.Season },
                 OrderBy = new[] { (ItemSortBy.SortName, SortOrder.Ascending) },
-                DtoOptions = options
+                DtoOptions = options,
+                IsMissing = user?.DisplayMissingEpisodes
             };
 
-            if (!user.DisplayMissingEpisodes)
-            {
-                query.IsMissing = false;
-            }
-
             var allItems = LibraryManager.GetItemList(query);
 
             var allSeriesEpisodes = allItems.OfType<Episode>().ToList();

+ 57 - 0
MediaBrowser.Providers/TV/SeriesMetadataService.cs

@@ -8,6 +8,7 @@ using System.Linq;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Controller.Configuration;
+using MediaBrowser.Controller.Dto;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Providers;
@@ -40,6 +41,7 @@ namespace MediaBrowser.Providers.TV
         {
             await base.AfterMetadataRefresh(item, refreshOptions, cancellationToken).ConfigureAwait(false);
 
+            RemoveObsoleteEpisodes(item);
             RemoveObsoleteSeasons(item);
             await FillInMissingSeasonsAsync(item, cancellationToken).ConfigureAwait(false);
         }
@@ -121,6 +123,61 @@ namespace MediaBrowser.Providers.TV
             }
         }
 
+        private void RemoveObsoleteEpisodes(Series series)
+        {
+            var episodes = series.GetEpisodes(null, new DtoOptions()).OfType<Episode>().ToList();
+            var numberOfEpisodes = episodes.Count;
+            // TODO: O(n^2), but can it be done faster without overcomplicating it?
+            for (var i = 0; i < numberOfEpisodes; i++)
+            {
+                var currentEpisode = episodes[i];
+                // The outer loop only examines virtual episodes
+                if (!currentEpisode.IsVirtualItem)
+                {
+                    continue;
+                }
+
+                // Virtual episodes without an episode number are practically orphaned and should be deleted
+                if (!currentEpisode.IndexNumber.HasValue)
+                {
+                    DeleteEpisode(currentEpisode);
+                    continue;
+                }
+
+                for (var j = i + 1; j < numberOfEpisodes; j++)
+                {
+                    var comparisonEpisode = episodes[j];
+                    // The inner loop is only for "physical" episodes
+                    if (comparisonEpisode.IsVirtualItem
+                        || currentEpisode.ParentIndexNumber != comparisonEpisode.ParentIndexNumber
+                        || !comparisonEpisode.ContainsEpisodeNumber(currentEpisode.IndexNumber.Value))
+                    {
+                        continue;
+                    }
+
+                    DeleteEpisode(currentEpisode);
+                    break;
+                }
+            }
+        }
+
+        private void DeleteEpisode(Episode episode)
+        {
+            Logger.LogInformation(
+                "Removing virtual episode S{SeasonNumber}E{EpisodeNumber} in series {SeriesName}",
+                episode.ParentIndexNumber,
+                episode.IndexNumber,
+                episode.SeriesName);
+
+            LibraryManager.DeleteItem(
+                episode,
+                new DeleteOptions
+                {
+                    DeleteFileLocation = true
+                },
+                false);
+        }
+
         /// <summary>
         /// Creates seasons for all episodes that aren't in a season folder.
         /// If no season number can be determined, a dummy season will be created.