소스 검색

Merge pull request #5532 from cvium/fix_episode_extras_questionmark

(cherry picked from commit 890a490776a2fbdfba82ca0031f3c89e968d3620)
Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
Joshua M. Boniface 4 년 전
부모
커밋
328bcadabf

+ 2 - 2
Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs

@@ -30,7 +30,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
         /// </summary>
         /// <param name="args">The args.</param>
         /// <returns>`0.</returns>
-        protected override T Resolve(ItemResolveArgs args)
+        public override T Resolve(ItemResolveArgs args)
         {
             return ResolveVideo<T>(args, false);
         }
@@ -42,7 +42,7 @@ namespace Emby.Server.Implementations.Library.Resolvers
         /// <param name="args">The args.</param>
         /// <param name="parseName">if set to <c>true</c> [parse name].</param>
         /// <returns>``0.</returns>
-        protected TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName)
+        protected virtual TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName)
               where TVideoType : Video, new()
         {
             var namingOptions = ((LibraryManager)LibraryManager).GetNamingOptions();

+ 1 - 1
Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs

@@ -13,7 +13,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
     {
         private readonly string[] _validExtensions = { ".azw", ".azw3", ".cb7", ".cbr", ".cbt", ".cbz", ".epub", ".mobi", ".pdf" };
 
-        protected override Book Resolve(ItemResolveArgs args)
+        public override Book Resolve(ItemResolveArgs args)
         {
             var collectionType = args.GetCollectionType();
 

+ 104 - 104
Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs

@@ -69,6 +69,110 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
             return result;
         }
 
+        /// <summary>
+        /// Resolves the specified args.
+        /// </summary>
+        /// <param name="args">The args.</param>
+        /// <returns>Video.</returns>
+        public override Video Resolve(ItemResolveArgs args)
+        {
+            var collectionType = args.GetCollectionType();
+
+            // Find movies with their own folders
+            if (args.IsDirectory)
+            {
+                if (IsInvalid(args.Parent, collectionType))
+                {
+                    return null;
+                }
+
+                var files = args.FileSystemChildren
+                    .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
+                    .ToList();
+
+                if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
+                {
+                    return FindMovie<MusicVideo>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
+                }
+
+                if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
+                {
+                    return FindMovie<Video>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
+                }
+
+                if (string.IsNullOrEmpty(collectionType))
+                {
+                    // Owned items will be caught by the plain video resolver
+                    if (args.Parent == null)
+                    {
+                        // return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
+                        return null;
+                    }
+
+                    if (args.HasParent<Series>())
+                    {
+                        return null;
+                    }
+
+                    {
+                        return FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
+                    }
+                }
+
+                if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
+                {
+                    return FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
+                }
+
+                return null;
+            }
+
+            // Handle owned items
+            if (args.Parent == null)
+            {
+                return base.Resolve(args);
+            }
+
+            if (IsInvalid(args.Parent, collectionType))
+            {
+                return null;
+            }
+
+            Video item = null;
+
+            if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
+            {
+                item = ResolveVideo<MusicVideo>(args, false);
+            }
+
+            // To find a movie file, the collection type must be movies or boxsets
+            else if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
+            {
+                item = ResolveVideo<Movie>(args, true);
+            }
+            else if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
+                string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
+            {
+                item = ResolveVideo<Video>(args, false);
+            }
+            else if (string.IsNullOrEmpty(collectionType))
+            {
+                if (args.HasParent<Series>())
+                {
+                    return null;
+                }
+
+                item = ResolveVideo<Video>(args, false);
+            }
+
+            if (item != null)
+            {
+                item.IsInMixedFolder = true;
+            }
+
+            return item;
+        }
+
         private MultiItemResolverResult ResolveMultipleInternal(
             Folder parent,
             List<FileSystemMetadata> files,
@@ -216,110 +320,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
             return string.Equals(result.Path, file.FullName, StringComparison.OrdinalIgnoreCase);
         }
 
-        /// <summary>
-        /// Resolves the specified args.
-        /// </summary>
-        /// <param name="args">The args.</param>
-        /// <returns>Video.</returns>
-        protected override Video Resolve(ItemResolveArgs args)
-        {
-            var collectionType = args.GetCollectionType();
-
-            // Find movies with their own folders
-            if (args.IsDirectory)
-            {
-                if (IsInvalid(args.Parent, collectionType))
-                {
-                    return null;
-                }
-
-                var files = args.FileSystemChildren
-                    .Where(i => !LibraryManager.IgnoreFile(i, args.Parent))
-                    .ToList();
-
-                if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
-                {
-                    return FindMovie<MusicVideo>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
-                }
-
-                if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase))
-                {
-                    return FindMovie<Video>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, false);
-                }
-
-                if (string.IsNullOrEmpty(collectionType))
-                {
-                    // Owned items will be caught by the plain video resolver
-                    if (args.Parent == null)
-                    {
-                        // return FindMovie<Video>(args.Path, args.Parent, files, args.DirectoryService, collectionType);
-                        return null;
-                    }
-
-                    if (args.HasParent<Series>())
-                    {
-                        return null;
-                    }
-
-                    {
-                        return FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
-                    }
-                }
-
-                if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
-                {
-                    return FindMovie<Movie>(args, args.Path, args.Parent, files, args.DirectoryService, collectionType, true);
-                }
-
-                return null;
-            }
-
-            // Handle owned items
-            if (args.Parent == null)
-            {
-                return base.Resolve(args);
-            }
-
-            if (IsInvalid(args.Parent, collectionType))
-            {
-                return null;
-            }
-
-            Video item = null;
-
-            if (string.Equals(collectionType, CollectionType.MusicVideos, StringComparison.OrdinalIgnoreCase))
-            {
-                item = ResolveVideo<MusicVideo>(args, false);
-            }
-
-            // To find a movie file, the collection type must be movies or boxsets
-            else if (string.Equals(collectionType, CollectionType.Movies, StringComparison.OrdinalIgnoreCase))
-            {
-                item = ResolveVideo<Movie>(args, true);
-            }
-            else if (string.Equals(collectionType, CollectionType.HomeVideos, StringComparison.OrdinalIgnoreCase) ||
-                string.Equals(collectionType, CollectionType.Photos, StringComparison.OrdinalIgnoreCase))
-            {
-                item = ResolveVideo<Video>(args, false);
-            }
-            else if (string.IsNullOrEmpty(collectionType))
-            {
-                if (args.HasParent<Series>())
-                {
-                    return null;
-                }
-
-                item = ResolveVideo<Video>(args, false);
-            }
-
-            if (item != null)
-            {
-                item.IsInMixedFolder = true;
-            }
-
-            return item;
-        }
-
         /// <summary>
         /// Sets the initial item values.
         /// </summary>

+ 16 - 14
Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Linq;
+using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Model.Entities;
@@ -11,12 +12,21 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
     /// </summary>
     public class EpisodeResolver : BaseVideoResolver<Episode>
     {
+        /// <summary>
+        /// Initializes a new instance of the <see cref="EpisodeResolver"/> class.
+        /// </summary>
+        /// <param name="libraryManager">The library manager.</param>
+        public EpisodeResolver(ILibraryManager libraryManager)
+            : base(libraryManager)
+        {
+        }
+
         /// <summary>
         /// Resolves the specified args.
         /// </summary>
         /// <param name="args">The args.</param>
         /// <returns>Episode.</returns>
-        protected override Episode Resolve(ItemResolveArgs args)
+        public override Episode Resolve(ItemResolveArgs args)
         {
             var parent = args.Parent;
 
@@ -34,11 +44,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
                 season = parent.GetParents().OfType<Season>().FirstOrDefault();
             }
 
-            // If the parent is a Season or Series, then this is an Episode if the VideoResolver returns something
+            // If the parent is a Season or Series and the parent is not an extras folder, then this is an Episode if the VideoResolver returns something
             // Also handle flat tv folders
-            if (season != null ||
-                string.Equals(args.GetCollectionType(), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) ||
-                args.HasParent<Series>())
+            if ((season != null ||
+                 string.Equals(args.GetCollectionType(), CollectionType.TvShows, StringComparison.OrdinalIgnoreCase) ||
+                 args.HasParent<Series>())
+                && (parent is Series || !BaseItem.AllExtrasTypesFolderNames.Contains(parent.Name, StringComparer.OrdinalIgnoreCase)))
             {
                 var episode = ResolveVideo<Episode>(args, false);
 
@@ -74,14 +85,5 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
 
             return null;
         }
-
-        /// <summary>
-        /// Initializes a new instance of the <see cref="EpisodeResolver"/> class.
-        /// </summary>
-        /// <param name="libraryManager">The library manager.</param>
-        public EpisodeResolver(ILibraryManager libraryManager)
-            : base(libraryManager)
-        {
-        }
     }
 }

+ 1 - 1
MediaBrowser.Controller/Resolvers/BaseItemResolver.cs

@@ -15,7 +15,7 @@ namespace MediaBrowser.Controller.Resolvers
         /// </summary>
         /// <param name="args">The args.</param>
         /// <returns>`0.</returns>
-        protected virtual T Resolve(ItemResolveArgs args)
+        public virtual T Resolve(ItemResolveArgs args)
         {
             return null;
         }

+ 65 - 0
tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs

@@ -0,0 +1,65 @@
+using System;
+using Emby.Server.Implementations.Library.Resolvers.TV;
+using MediaBrowser.Controller;
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.TV;
+using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
+using MediaBrowser.Model.Entities;
+using Moq;
+using Xunit;
+
+namespace Jellyfin.Server.Implementations.Tests.Library
+{
+    public class EpisodeResolverTest
+    {
+        [Fact]
+        public void Resolve_GivenVideoInExtrasFolder_DoesNotResolveToEpisode()
+        {
+            var season = new Season { Name = "Season 1" };
+            var parent = new Folder { Name = "extras" };
+            var libraryManagerMock = new Mock<ILibraryManager>();
+            libraryManagerMock.Setup(x => x.GetItemById(It.IsAny<Guid>())).Returns(season);
+
+            var episodeResolver = new EpisodeResolver(libraryManagerMock.Object);
+            var itemResolveArgs = new ItemResolveArgs(
+                Mock.Of<IServerApplicationPaths>(),
+                Mock.Of<IDirectoryService>())
+            {
+                Parent = parent,
+                CollectionType = CollectionType.TvShows,
+                Path = "All My Children/Season 01/Extras/All My Children S01E01 - Behind The Scenes.mkv"
+            };
+
+            Assert.Null(episodeResolver.Resolve(itemResolveArgs));
+        }
+
+        [Fact]
+        public void Resolve_GivenVideoInExtrasSeriesFolder_ResolvesToEpisode()
+        {
+            var series = new Series { Name = "Extras" };
+
+            // Have to create a mock because of moq proxies not being castable to a concrete implementation
+            // https://github.com/jellyfin/jellyfin/blob/ab0cff8556403e123642dc9717ba778329554634/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs#L48
+            var episodeResolver = new EpisodeResolverMock(Mock.Of<ILibraryManager>());
+            var itemResolveArgs = new ItemResolveArgs(
+                Mock.Of<IServerApplicationPaths>(),
+                Mock.Of<IDirectoryService>())
+            {
+                Parent = series,
+                CollectionType = CollectionType.TvShows,
+                Path = "Extras/Extras S01E01.mkv"
+            };
+            Assert.NotNull(episodeResolver.Resolve(itemResolveArgs));
+        }
+
+        private class EpisodeResolverMock : EpisodeResolver
+        {
+            public EpisodeResolverMock(ILibraryManager libraryManager) : base(libraryManager)
+            {
+            }
+
+            protected override TVideoType ResolveVideo<TVideoType>(ItemResolveArgs args, bool parseName) => new ();
+        }
+    }
+}