aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoshua M. Boniface <joshua@boniface.me>2021-03-21 15:13:56 -0400
committerJoshua M. Boniface <joshua@boniface.me>2021-03-21 19:10:13 -0400
commit328bcadabf6d9bc4301912a8e05015b5a6886916 (patch)
treedccd6de9a242cf824dbeb02b263fae4df8c2f5d1
parent0f38b2ffb26241e5eb464584375c68feed94d440 (diff)
Merge pull request #5532 from cvium/fix_episode_extras_questionmark
(cherry picked from commit 890a490776a2fbdfba82ca0031f3c89e968d3620) Signed-off-by: Joshua M. Boniface <joshua@boniface.me>
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs4
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs2
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs208
-rw-r--r--Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs30
-rw-r--r--MediaBrowser.Controller/Resolvers/BaseItemResolver.cs2
-rw-r--r--tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs65
6 files changed, 189 insertions, 122 deletions
diff --git a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs b/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
index 2f5e46038..6e688693b 100644
--- a/Emby.Server.Implementations/Library/Resolvers/BaseVideoResolver.cs
+++ b/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();
diff --git a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
index 86242d137..0525c7e30 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Books/BookResolver.cs
+++ b/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();
diff --git a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
index 8ef7172de..714bc3a84 100644
--- a/Emby.Server.Implementations/Library/Resolvers/Movies/MovieResolver.cs
+++ b/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,
@@ -217,110 +321,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
}
/// <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>
/// <param name="item">The item.</param>
diff --git a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs b/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
index 2f7af60c0..9b4cd7a3d 100644
--- a/Emby.Server.Implementations/Library/Resolvers/TV/EpisodeResolver.cs
+++ b/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;
@@ -12,11 +13,20 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
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)
- {
- }
}
}
diff --git a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
index 67acdd9a3..25128a5cd 100644
--- a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs
+++ b/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;
}
diff --git a/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs b/tests/Jellyfin.Server.Implementations.Tests/Library/EpisodeResolverTest.cs
new file mode 100644
index 000000000..876519215
--- /dev/null
+++ b/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 ();
+ }
+ }
+}