Browse Source

Fix extras folders

cvium 3 năm trước cách đây
mục cha
commit
83a94aa612

+ 28 - 1
Emby.Naming/Common/NamingOptions.cs

@@ -1,6 +1,7 @@
 #pragma warning disable CA1819
 #pragma warning disable CA1819
 
 
 using System;
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
 using Emby.Naming.Video;
 using Emby.Naming.Video;
@@ -475,6 +476,12 @@ namespace Emby.Naming.Common
                     "theme",
                     "theme",
                     MediaType.Audio),
                     MediaType.Audio),
 
 
+                new ExtraRule(
+                    ExtraType.ThemeSong,
+                    ExtraRuleType.DirectoryName,
+                    "theme-music",
+                    MediaType.Audio),
+
                 new ExtraRule(
                 new ExtraRule(
                     ExtraType.Scene,
                     ExtraType.Scene,
                     ExtraRuleType.Suffix,
                     ExtraRuleType.Suffix,
@@ -569,7 +576,7 @@ namespace Emby.Naming.Common
                     ExtraType.Unknown,
                     ExtraType.Unknown,
                     ExtraRuleType.DirectoryName,
                     ExtraRuleType.DirectoryName,
                     "extras",
                     "extras",
-                    MediaType.Video),
+                    MediaType.Video)
             };
             };
 
 
             Format3DRules = new[]
             Format3DRules = new[]
@@ -681,9 +688,29 @@ namespace Emby.Naming.Common
                 .Distinct(StringComparer.OrdinalIgnoreCase)
                 .Distinct(StringComparer.OrdinalIgnoreCase)
                 .ToArray();
                 .ToArray();
 
 
+            AllExtrasTypesFolderNames = new Dictionary<string, ExtraType>(StringComparer.OrdinalIgnoreCase)
+            {
+                ["trailers"] = ExtraType.Trailer,
+                ["theme-music"] = ExtraType.ThemeSong,
+                ["backdrops"] = ExtraType.ThemeVideo,
+                ["extras"] = ExtraType.Unknown,
+                ["behind the scenes"] = ExtraType.BehindTheScenes,
+                ["deleted scenes"] = ExtraType.DeletedScene,
+                ["interviews"] = ExtraType.Interview,
+                ["scenes"] = ExtraType.Scene,
+                ["samples"] = ExtraType.Sample,
+                ["shorts"] = ExtraType.Clip,
+                ["featurettes"] = ExtraType.Clip
+            };
+
             Compile();
             Compile();
         }
         }
 
 
+        /// <summary>
+        /// Gets or sets the folder name to extra types mapping.
+        /// </summary>
+        public Dictionary<string, ExtraType> AllExtrasTypesFolderNames { get; set; }
+
         /// <summary>
         /// <summary>
         /// Gets or sets list of audio file extensions.
         /// Gets or sets list of audio file extensions.
         /// </summary>
         /// </summary>

+ 1 - 6
Emby.Naming/Video/VideoListResolver.cs

@@ -21,13 +21,8 @@ namespace Emby.Naming.Video
         /// <param name="supportMultiVersion">Indication we should consider multi-versions of content.</param>
         /// <param name="supportMultiVersion">Indication we should consider multi-versions of content.</param>
         /// <param name="parseName">Whether to parse the name or use the filename.</param>
         /// <param name="parseName">Whether to parse the name or use the filename.</param>
         /// <returns>Returns enumerable of <see cref="VideoInfo"/> which groups files together when related.</returns>
         /// <returns>Returns enumerable of <see cref="VideoInfo"/> which groups files together when related.</returns>
-        public static IReadOnlyList<VideoInfo> Resolve(IEnumerable<FileSystemMetadata> files, NamingOptions namingOptions, bool supportMultiVersion = true, bool parseName = true)
+        public static IReadOnlyList<VideoInfo> Resolve(IReadOnlyList<VideoFileInfo> videoInfos, NamingOptions namingOptions, bool supportMultiVersion = true, bool parseName = true)
         {
         {
-            var videoInfos = files
-                .Select(i => VideoResolver.Resolve(i.FullName, i.IsDirectory, namingOptions, parseName))
-                .OfType<VideoFileInfo>()
-                .ToList();
-
             // Filter out all extras, otherwise they could cause stacks to not be resolved
             // Filter out all extras, otherwise they could cause stacks to not be resolved
             // See the unit test TestStackedWithTrailer
             // See the unit test TestStackedWithTrailer
             var nonExtras = videoInfos
             var nonExtras = videoInfos

+ 4 - 14
Emby.Server.Implementations/Library/CoreResolutionIgnoreRule.cs

@@ -54,20 +54,10 @@ namespace Emby.Server.Implementations.Library
             {
             {
                 if (parent != null)
                 if (parent != null)
                 {
                 {
-                    // Ignore trailer folders but allow it at the collection level
-                    if (string.Equals(filename, BaseItem.TrailersFolderName, StringComparison.OrdinalIgnoreCase)
-                        && !(parent is AggregateFolder)
-                        && !(parent is UserRootFolder))
-                    {
-                        return true;
-                    }
-
-                    if (string.Equals(filename, BaseItem.ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
-                    {
-                        return true;
-                    }
-
-                    if (string.Equals(filename, BaseItem.ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
+                    // Ignore extras folders but allow it at the collection level
+                    if (_namingOptions.AllExtrasTypesFolderNames.ContainsKey(filename)
+                        && parent is not AggregateFolder
+                        && parent is not UserRootFolder)
                     {
                     {
                         return true;
                         return true;
                     }
                     }

+ 57 - 10
Emby.Server.Implementations/Library/LibraryManager.cs

@@ -531,8 +531,8 @@ namespace Emby.Server.Implementations.Library
             return key.GetMD5();
             return key.GetMD5();
         }
         }
 
 
-        public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null)
-            => ResolvePath(fileInfo, new DirectoryService(_fileSystem), null, parent);
+        public BaseItem ResolvePath(FileSystemMetadata fileInfo, Folder parent = null, IDirectoryService directoryService = null)
+            => ResolvePath(fileInfo, directoryService ?? new DirectoryService(_fileSystem), null, parent);
 
 
         private BaseItem ResolvePath(
         private BaseItem ResolvePath(
             FileSystemMetadata fileInfo,
             FileSystemMetadata fileInfo,
@@ -652,7 +652,7 @@ namespace Emby.Server.Implementations.Library
             return !args.ContainsFileSystemEntryByName(".ignore");
             return !args.ContainsFileSystemEntryByName(".ignore");
         }
         }
 
 
-        public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, Folder parent, LibraryOptions libraryOptions, string collectionType)
+        public IEnumerable<BaseItem> ResolvePaths(IEnumerable<FileSystemMetadata> files, IDirectoryService directoryService, Folder parent, LibraryOptions libraryOptions, string collectionType = null)
         {
         {
             return ResolvePaths(files, directoryService, parent, libraryOptions, collectionType, EntityResolvers);
             return ResolvePaths(files, directoryService, parent, libraryOptions, collectionType, EntityResolvers);
         }
         }
@@ -2683,7 +2683,7 @@ namespace Emby.Server.Implementations.Library
             };
             };
         }
         }
 
 
-        public IEnumerable<Video> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren)
+        public IEnumerable<BaseItem> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
         {
         {
             var ownerVideoInfo = VideoResolver.Resolve(owner.Path, owner.IsFolder, _namingOptions);
             var ownerVideoInfo = VideoResolver.Resolve(owner.Path, owner.IsFolder, _namingOptions);
             if (ownerVideoInfo == null)
             if (ownerVideoInfo == null)
@@ -2692,17 +2692,36 @@ namespace Emby.Server.Implementations.Library
             }
             }
 
 
             var count = fileSystemChildren.Count;
             var count = fileSystemChildren.Count;
-            var files = new List<FileSystemMetadata>();
+            var files = new List<VideoFileInfo>();
+            var nonVideoFiles = new List<FileSystemMetadata>();
             for (var i = 0; i < count; i++)
             for (var i = 0; i < count; i++)
             {
             {
                 var current = fileSystemChildren[i];
                 var current = fileSystemChildren[i];
-                if (current.IsDirectory && BaseItem.AllExtrasTypesFolderNames.ContainsKey(current.Name))
+                if (current.IsDirectory && _namingOptions.AllExtrasTypesFolderNames.ContainsKey(current.Name))
                 {
                 {
-                    files.AddRange(_fileSystem.GetFiles(current.FullName, _namingOptions.VideoFileExtensions, false, false));
+                    var filesInSubFolder = _fileSystem.GetFiles(current.FullName, _namingOptions.VideoFileExtensions, false, false);
+                    foreach (var file in filesInSubFolder)
+                    {
+                        var videoInfo = VideoResolver.Resolve(file.FullName, file.IsDirectory, _namingOptions);
+                        if (videoInfo == null)
+                        {
+                            nonVideoFiles.Add(file);
+                            continue;
+                        }
+
+                        files.Add(videoInfo);
+                    }
                 }
                 }
                 else if (!current.IsDirectory)
                 else if (!current.IsDirectory)
                 {
                 {
-                    files.Add(current);
+                    var videoInfo = VideoResolver.Resolve(current.FullName, current.IsDirectory, _namingOptions);
+                    if (videoInfo == null)
+                    {
+                        nonVideoFiles.Add(current);
+                        continue;
+                    }
+
+                    files.Add(videoInfo);
                 }
                 }
             }
             }
 
 
@@ -2714,11 +2733,10 @@ namespace Emby.Server.Implementations.Library
             var videos = VideoListResolver.Resolve(files, _namingOptions);
             var videos = VideoListResolver.Resolve(files, _namingOptions);
             // owner video info cannot be null as that implies it has no path
             // owner video info cannot be null as that implies it has no path
             var extras = ExtraResolver.GetExtras(videos, ownerVideoInfo, _namingOptions.VideoFlagDelimiters);
             var extras = ExtraResolver.GetExtras(videos, ownerVideoInfo, _namingOptions.VideoFlagDelimiters);
-
             for (var i = 0; i < extras.Count; i++)
             for (var i = 0; i < extras.Count; i++)
             {
             {
                 var currentExtra = extras[i];
                 var currentExtra = extras[i];
-                var resolved = ResolvePath(_fileSystem.GetFileInfo(currentExtra.Path));
+                var resolved = ResolvePath(_fileSystem.GetFileInfo(currentExtra.Path), null, directoryService);
                 if (resolved is not Video video)
                 if (resolved is not Video video)
                 {
                 {
                     continue;
                     continue;
@@ -2735,6 +2753,35 @@ namespace Emby.Server.Implementations.Library
                 video.OwnerId = owner.Id;
                 video.OwnerId = owner.Id;
                 yield return video;
                 yield return video;
             }
             }
+
+            // TODO: theme songs must be handled "manually" (but should we?) since they aren't video files
+            for (var i = 0; i < nonVideoFiles.Count; i++)
+            {
+                var current = nonVideoFiles[i];
+                var extraInfo = ExtraResolver.GetExtraInfo(current.FullName, _namingOptions);
+                if (extraInfo.ExtraType != ExtraType.ThemeSong)
+                {
+                    continue;
+                }
+
+                var resolved = ResolvePath(current, null, directoryService);
+                if (resolved is not Audio themeSong)
+                {
+                    continue;
+                }
+
+                // Try to retrieve it from the db. If we don't find it, use the resolved version
+                if (GetItemById(themeSong.Id) is Audio dbItem)
+                {
+                    themeSong = dbItem;
+                }
+
+                themeSong.ExtraType = ExtraType.ThemeSong;
+                themeSong.OwnerId = owner.Id;
+                themeSong.ParentId = Guid.Empty;
+
+                yield return themeSong;
+            }
         }
         }
 
 
         public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem)
         public string GetPathAfterNetworkSubstitution(string path, BaseItem ownerItem)

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

@@ -261,7 +261,12 @@ namespace Emby.Server.Implementations.Library.Resolvers.Movies
                 }
                 }
             }
             }
 
 
-            var resolverResult = VideoListResolver.Resolve(files, NamingOptions, supportMultiEditions, parseName);
+            var videoInfos = files
+                .Select(i => VideoResolver.Resolve(i.FullName, i.IsDirectory, NamingOptions, parseName))
+                .Where(f => f != null)
+                .ToList();
+
+            var resolverResult = VideoListResolver.Resolve(videoInfos, NamingOptions, supportMultiEditions, parseName);
 
 
             var result = new MultiItemResolverResult
             var result = new MultiItemResolverResult
             {
             {

+ 2 - 91
MediaBrowser.Controller/Entities/BaseItem.cs

@@ -13,7 +13,6 @@ using System.Threading.Tasks;
 using Diacritics.Extensions;
 using Diacritics.Extensions;
 using Jellyfin.Data.Entities;
 using Jellyfin.Data.Entities;
 using Jellyfin.Data.Enums;
 using Jellyfin.Data.Enums;
-using Jellyfin.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Common.Extensions;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Channels;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
@@ -22,7 +21,6 @@ using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Persistence;
 using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Providers;
-using MediaBrowser.Model.Configuration;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Dto;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Globalization;
 using MediaBrowser.Model.Globalization;
@@ -42,11 +40,7 @@ namespace MediaBrowser.Controller.Entities
     {
     {
         private BaseItemKind? _baseItemKind;
         private BaseItemKind? _baseItemKind;
 
 
-        public const string TrailerFileName = "trailer";
-        public const string TrailersFolderName = "trailers";
-        public const string ThemeSongsFolderName = "theme-music";
         public const string ThemeSongFileName = "theme";
         public const string ThemeSongFileName = "theme";
-        public const string ThemeVideosFolderName = "backdrops";
 
 
         /// <summary>
         /// <summary>
         /// The supported image extensions.
         /// The supported image extensions.
@@ -83,21 +77,6 @@ namespace MediaBrowser.Controller.Entities
             Model.Entities.ExtraType.Scene
             Model.Entities.ExtraType.Scene
         };
         };
 
 
-        /// <summary>
-        /// The supported extra folder names and types. See <see cref="Emby.Naming.Common.NamingOptions" />.
-        /// </summary>
-        public static readonly Dictionary<string, ExtraType> AllExtrasTypesFolderNames = new Dictionary<string, ExtraType>(StringComparer.OrdinalIgnoreCase)
-        {
-            ["extras"] = MediaBrowser.Model.Entities.ExtraType.Unknown,
-            ["behind the scenes"] = MediaBrowser.Model.Entities.ExtraType.BehindTheScenes,
-            ["deleted scenes"] = MediaBrowser.Model.Entities.ExtraType.DeletedScene,
-            ["interviews"] = MediaBrowser.Model.Entities.ExtraType.Interview,
-            ["scenes"] = MediaBrowser.Model.Entities.ExtraType.Scene,
-            ["samples"] = MediaBrowser.Model.Entities.ExtraType.Sample,
-            ["shorts"] = MediaBrowser.Model.Entities.ExtraType.Clip,
-            ["featurettes"] = MediaBrowser.Model.Entities.ExtraType.Clip
-        };
-
         private string _sortName;
         private string _sortName;
 
 
         private string _forcedSortName;
         private string _forcedSortName;
@@ -1275,74 +1254,6 @@ namespace MediaBrowser.Controller.Entities
             return string.Join('/', terms);
             return string.Join('/', terms);
         }
         }
 
 
-        /// <summary>
-        /// Loads the theme songs.
-        /// </summary>
-        /// <returns>List{Audio.Audio}.</returns>
-        private static Audio.Audio[] LoadThemeSongs(List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
-        {
-            var files = fileSystemChildren.Where(i => i.IsDirectory)
-                .Where(i => string.Equals(i.Name, ThemeSongsFolderName, StringComparison.OrdinalIgnoreCase))
-                .SelectMany(i => FileSystem.GetFiles(i.FullName))
-                .ToList();
-
-            // Support plex/xbmc convention
-            files.AddRange(fileSystemChildren
-                .Where(i => !i.IsDirectory && System.IO.Path.GetFileNameWithoutExtension(i.FullName.AsSpan()).Equals(ThemeSongFileName, StringComparison.OrdinalIgnoreCase)));
-
-            return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
-                .OfType<Audio.Audio>()
-                .Select(audio =>
-                {
-                    // Try to retrieve it from the db. If we don't find it, use the resolved version
-                    if (LibraryManager.GetItemById(audio.Id) is Audio.Audio dbItem)
-                    {
-                        audio = dbItem;
-                    }
-                    else
-                    {
-                        // item is new
-                        audio.ExtraType = MediaBrowser.Model.Entities.ExtraType.ThemeSong;
-                    }
-
-                    return audio;
-
-                    // Sort them so that the list can be easily compared for changes
-                }).OrderBy(i => i.Path).ToArray();
-        }
-
-        /// <summary>
-        /// Loads the video backdrops.
-        /// </summary>
-        /// <returns>List{Video}.</returns>
-        private static Video[] LoadThemeVideos(IEnumerable<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService)
-        {
-            var files = fileSystemChildren.Where(i => i.IsDirectory)
-                .Where(i => string.Equals(i.Name, ThemeVideosFolderName, StringComparison.OrdinalIgnoreCase))
-                .SelectMany(i => FileSystem.GetFiles(i.FullName));
-
-            return LibraryManager.ResolvePaths(files, directoryService, null, new LibraryOptions())
-                .OfType<Video>()
-                .Select(item =>
-                {
-                    // Try to retrieve it from the db. If we don't find it, use the resolved version
-
-                    if (LibraryManager.GetItemById(item.Id) is Video dbItem)
-                    {
-                        item = dbItem;
-                    }
-                    else
-                    {
-                        // item is new
-                        item.ExtraType = Model.Entities.ExtraType.ThemeVideo;
-                    }
-
-                    return item;
-
-                    // Sort them so that the list can be easily compared for changes
-                }).OrderBy(i => i.Path).ToArray();
-        }
-
         public Task RefreshMetadata(CancellationToken cancellationToken)
         public Task RefreshMetadata(CancellationToken cancellationToken)
         {
         {
             return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(FileSystem)), cancellationToken);
             return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(FileSystem)), cancellationToken);
@@ -1453,7 +1364,7 @@ namespace MediaBrowser.Controller.Entities
         /// <returns><c>true</c> if any items have changed, else <c>false</c>.</returns>
         /// <returns><c>true</c> if any items have changed, else <c>false</c>.</returns>
         protected virtual async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         protected virtual async Task<bool> RefreshedOwnedItems(MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
         {
-            if (!IsFileProtocol || !SupportsOwnedItems || IsInMixedFolder || this is ICollectionFolder || this.GetType() == typeof(Folder))
+            if (!IsFileProtocol || !SupportsOwnedItems || IsInMixedFolder || this is ICollectionFolder or UserRootFolder or AggregateFolder || this.GetType() == typeof(Folder))
             {
             {
                 return false;
                 return false;
             }
             }
@@ -1470,7 +1381,7 @@ namespace MediaBrowser.Controller.Entities
 
 
         private async Task<bool> RefreshExtras(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         private async Task<bool> RefreshExtras(BaseItem item, MetadataRefreshOptions options, List<FileSystemMetadata> fileSystemChildren, CancellationToken cancellationToken)
         {
         {
-            var extras = LibraryManager.FindExtras(item, fileSystemChildren).ToArray();
+            var extras = LibraryManager.FindExtras(item, fileSystemChildren, options.DirectoryService).ToArray();
             var newExtraIds = extras.Select(i => i.Id).ToArray();
             var newExtraIds = extras.Select(i => i.Id).ToArray();
             var extrasChanged = !item.ExtraIds.SequenceEqual(newExtraIds);
             var extrasChanged = !item.ExtraIds.SequenceEqual(newExtraIds);
 
 

+ 6 - 5
MediaBrowser.Controller/Library/ILibraryManager.cs

@@ -58,10 +58,12 @@ namespace MediaBrowser.Controller.Library
         /// </summary>
         /// </summary>
         /// <param name="fileInfo">The file information.</param>
         /// <param name="fileInfo">The file information.</param>
         /// <param name="parent">The parent.</param>
         /// <param name="parent">The parent.</param>
+        /// <param name="directoryService">An instance of <see cref="IDirectoryService"/>.</param>
         /// <returns>BaseItem.</returns>
         /// <returns>BaseItem.</returns>
         BaseItem ResolvePath(
         BaseItem ResolvePath(
             FileSystemMetadata fileInfo,
             FileSystemMetadata fileInfo,
-            Folder parent = null);
+            Folder parent = null,
+            IDirectoryService directoryService = null);
 
 
         /// <summary>
         /// <summary>
         /// Resolves a set of files into a list of BaseItem.
         /// Resolves a set of files into a list of BaseItem.
@@ -430,10 +432,9 @@ namespace MediaBrowser.Controller.Library
         /// </summary>
         /// </summary>
         /// <param name="owner">The owner.</param>
         /// <param name="owner">The owner.</param>
         /// <param name="fileSystemChildren">The file system children.</param>
         /// <param name="fileSystemChildren">The file system children.</param>
-        /// <returns>IEnumerable&lt;Video&gt;.</returns>
-        IEnumerable<Video> FindExtras(
-            BaseItem owner,
-            List<FileSystemMetadata> fileSystemChildren);
+        /// <param name="directoryService">An instance of <see cref="IDirectoryService"/>.</param>
+        /// <returns>IEnumerable&lt;BaseItem&gt;.</returns>
+        IEnumerable<BaseItem> FindExtras(BaseItem owner, List<FileSystemMetadata> fileSystemChildren, IDirectoryService directoryService);
 
 
         /// <summary>
         /// <summary>
         /// Gets the collection folders.
         /// Gets the collection folders.

+ 2 - 1
MediaBrowser.LocalMetadata/Images/LocalImageProvider.cs

@@ -3,6 +3,7 @@ using System.Collections.Generic;
 using System.Globalization;
 using System.Globalization;
 using System.IO;
 using System.IO;
 using System.Linq;
 using System.Linq;
+using Jellyfin.Extensions;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Audio;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.Movies;
@@ -120,7 +121,7 @@ namespace MediaBrowser.LocalMetadata.Images
             return directoryService.GetFileSystemEntries(path)
             return directoryService.GetFileSystemEntries(path)
                 .Where(i =>
                 .Where(i =>
                     (includeDirectories && i.IsDirectory)
                     (includeDirectories && i.IsDirectory)
-                    || Array.FindIndex(BaseItem.SupportedImageExtensions, ext => string.Equals(ext, i.Extension, StringComparison.OrdinalIgnoreCase)) != -1)
+                    || BaseItem.SupportedImageExtensions.Contains(i.Extension, StringComparison.OrdinalIgnoreCase))
                 .OrderBy(i => Array.IndexOf(BaseItem.SupportedImageExtensions, i.Extension ?? string.Empty));
                 .OrderBy(i => Array.IndexOf(BaseItem.SupportedImageExtensions, i.Extension ?? string.Empty));
         }
         }
 
 

+ 18 - 86
tests/Jellyfin.Naming.Tests/Video/MultiVersionTests.cs

@@ -23,11 +23,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result.Where(v => v.ExtraType == null));
             Assert.Single(result.Where(v => v.ExtraType == null));
@@ -46,11 +42,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result.Where(v => v.ExtraType == null));
             Assert.Single(result.Where(v => v.ExtraType == null));
@@ -68,11 +60,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -94,11 +82,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(7, result.Count);
             Assert.Equal(7, result.Count);
@@ -121,11 +105,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -149,11 +129,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(9, result.Count);
             Assert.Equal(9, result.Count);
@@ -173,11 +149,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(5, result.Count);
             Assert.Equal(5, result.Count);
@@ -199,11 +171,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(5, result.Count);
             Assert.Equal(5, result.Count);
@@ -226,11 +194,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -256,11 +220,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -280,11 +240,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);
@@ -305,11 +261,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(7, result.Count);
             Assert.Equal(7, result.Count);
@@ -331,11 +283,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(5, result.Count);
             Assert.Equal(5, result.Count);
@@ -352,11 +300,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -373,11 +317,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -394,11 +334,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -415,11 +351,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);
@@ -428,7 +360,7 @@ namespace Jellyfin.Naming.Tests.Video
         [Fact]
         [Fact]
         public void TestEmptyList()
         public void TestEmptyList()
         {
         {
-            var result = VideoListResolver.Resolve(new List<FileSystemMetadata>(), _namingOptions).ToList();
+            var result = VideoListResolver.Resolve(new List<VideoFileInfo>(), _namingOptions).ToList();
 
 
             Assert.Empty(result);
             Assert.Empty(result);
         }
         }

+ 20 - 100
tests/Jellyfin.Naming.Tests/Video/VideoListResolverTests.cs

@@ -42,11 +42,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(11, result.Count);
             Assert.Equal(11, result.Count);
@@ -80,11 +76,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -100,11 +92,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);
@@ -122,11 +110,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);
@@ -145,11 +129,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(3, result.Count);
             Assert.Equal(3, result.Count);
@@ -169,11 +149,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(3, result.Count);
             Assert.Equal(3, result.Count);
@@ -192,11 +168,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);
@@ -218,11 +190,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(5, result.Count);
             Assert.Equal(5, result.Count);
@@ -238,11 +206,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = true,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, true, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -259,11 +223,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = true,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, true, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);
@@ -281,11 +241,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(3, result.Count);
             Assert.Equal(3, result.Count);
@@ -306,11 +262,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(4, result.Count);
             Assert.Equal(4, result.Count);
@@ -332,11 +284,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);
@@ -351,11 +299,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -370,11 +314,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -390,11 +330,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Single(result);
             Assert.Single(result);
@@ -410,11 +346,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);
@@ -430,11 +362,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);
@@ -452,11 +380,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);
@@ -474,11 +398,7 @@ namespace Jellyfin.Naming.Tests.Video
             };
             };
 
 
             var result = VideoListResolver.Resolve(
             var result = VideoListResolver.Resolve(
-                files.Select(i => new FileSystemMetadata
-                {
-                    IsDirectory = false,
-                    FullName = i
-                }).ToList(),
+                files.Select(i => VideoResolver.Resolve(i, false, _namingOptions)).OfType<VideoFileInfo>().ToList(),
                 _namingOptions).ToList();
                 _namingOptions).ToList();
 
 
             Assert.Equal(2, result.Count);
             Assert.Equal(2, result.Count);

+ 66 - 12
tests/Jellyfin.Server.Implementations.Tests/Library/LibraryManager/FindExtrasTests.cs

@@ -5,11 +5,13 @@ using AutoFixture;
 using AutoFixture.AutoMoq;
 using AutoFixture.AutoMoq;
 using Emby.Naming.Common;
 using Emby.Naming.Common;
 using Emby.Server.Implementations.Library.Resolvers;
 using Emby.Server.Implementations.Library.Resolvers;
+using Emby.Server.Implementations.Library.Resolvers.Audio;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Configuration;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.Movies;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Entities.TV;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.Library;
+using MediaBrowser.Controller.Providers;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.Resolvers;
 using MediaBrowser.Controller.Sorting;
 using MediaBrowser.Controller.Sorting;
 using MediaBrowser.Model.Entities;
 using MediaBrowser.Model.Entities;
@@ -22,6 +24,7 @@ namespace Jellyfin.Server.Implementations.Tests.Library.LibraryManager;
 public class FindExtrasTests
 public class FindExtrasTests
 {
 {
     private readonly Emby.Server.Implementations.Library.LibraryManager _libraryManager;
     private readonly Emby.Server.Implementations.Library.LibraryManager _libraryManager;
+    private readonly Mock<IFileSystem> _fileSystemMock;
 
 
     public FindExtrasTests()
     public FindExtrasTests()
     {
     {
@@ -29,11 +32,11 @@ public class FindExtrasTests
         fixture.Register(() => new NamingOptions());
         fixture.Register(() => new NamingOptions());
         var configMock = fixture.Freeze<Mock<IServerConfigurationManager>>();
         var configMock = fixture.Freeze<Mock<IServerConfigurationManager>>();
         configMock.Setup(c => c.ApplicationPaths.ProgramDataPath).Returns("/data");
         configMock.Setup(c => c.ApplicationPaths.ProgramDataPath).Returns("/data");
-        var fileSystemMock = fixture.Freeze<Mock<IFileSystem>>();
-        fileSystemMock.Setup(f => f.GetFileInfo(It.IsAny<string>())).Returns<string>(path => new FileSystemMetadata { FullName = path });
+        _fileSystemMock = fixture.Freeze<Mock<IFileSystem>>();
+        _fileSystemMock.Setup(f => f.GetFileInfo(It.IsAny<string>())).Returns<string>(path => new FileSystemMetadata { FullName = path });
         _libraryManager = fixture.Build<Emby.Server.Implementations.Library.LibraryManager>().Do(s => s.AddParts(
         _libraryManager = fixture.Build<Emby.Server.Implementations.Library.LibraryManager>().Do(s => s.AddParts(
                 fixture.Create<IEnumerable<IResolverIgnoreRule>>(),
                 fixture.Create<IEnumerable<IResolverIgnoreRule>>(),
-                new List<IItemResolver> { new GenericVideoResolver<Video>(fixture.Create<NamingOptions>()) },
+                new List<IItemResolver> { new GenericVideoResolver<Video>(fixture.Create<NamingOptions>()), new AudioResolver(fixture.Create<NamingOptions>()) },
                 fixture.Create<IEnumerable<IIntroProvider>>(),
                 fixture.Create<IEnumerable<IIntroProvider>>(),
                 fixture.Create<IEnumerable<IBaseItemComparer>>(),
                 fixture.Create<IEnumerable<IBaseItemComparer>>(),
                 fixture.Create<IEnumerable<ILibraryPostScanTask>>()))
                 fixture.Create<IEnumerable<ILibraryPostScanTask>>()))
@@ -62,7 +65,7 @@ public class FindExtrasTests
             IsDirectory = false
             IsDirectory = false
         }).ToList();
         }).ToList();
 
 
-        var extras = _libraryManager.FindExtras(owner, files).OrderBy(e => e.ExtraType).ToList();
+        var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
 
 
         Assert.Equal(2, extras.Count);
         Assert.Equal(2, extras.Count);
         Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);
         Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);
@@ -77,26 +80,77 @@ public class FindExtrasTests
         {
         {
             "/movies/Up/Up.mkv",
             "/movies/Up/Up.mkv",
             "/movies/Up/Up - trailer.mkv",
             "/movies/Up/Up - trailer.mkv",
-            "/movies/Up/trailers/some trailer.mkv",
-            "/movies/Up/behind the scenes/the making of Up.mkv",
+            "/movies/Up/trailers",
+            "/movies/Up/theme-music",
+            "/movies/Up/theme.mp3",
+            "/movies/Up/not a theme.mp3",
+            "/movies/Up/behind the scenes",
             "/movies/Up/behind the scenes.mkv",
             "/movies/Up/behind the scenes.mkv",
             "/movies/Up/Up - sample.mkv",
             "/movies/Up/Up - sample.mkv",
             "/movies/Up/Up something else.mkv"
             "/movies/Up/Up something else.mkv"
         };
         };
 
 
+        _fileSystemMock.Setup(f => f.GetFiles(
+                "/movies/Up/trailers",
+                It.IsAny<string[]>(),
+                false,
+                false))
+            .Returns(new List<FileSystemMetadata>
+            {
+                new ()
+                {
+                    FullName = "/movies/Up/trailers/some trailer.mkv",
+                    Name = "some trailer.mkv",
+                    IsDirectory = false
+                }
+            });
+
+        _fileSystemMock.Setup(f => f.GetFiles(
+                "/movies/Up/behind the scenes",
+                It.IsAny<string[]>(),
+                false,
+                false))
+            .Returns(new List<FileSystemMetadata>
+            {
+                new ()
+                {
+                    FullName = "/movies/Up/behind the scenes/the making of Up.mkv",
+                    Name = "the making of Up.mkv",
+                    IsDirectory = false
+                }
+            });
+
+        _fileSystemMock.Setup(f => f.GetFiles(
+                "/movies/Up/theme-music",
+                It.IsAny<string[]>(),
+                false,
+                false))
+            .Returns(new List<FileSystemMetadata>
+            {
+                new ()
+                {
+                    FullName = "/movies/Up/theme-music/theme2.mp3",
+                    Name = "theme2.mp3",
+                    IsDirectory = false
+                }
+            });
+
         var files = paths.Select(p => new FileSystemMetadata
         var files = paths.Select(p => new FileSystemMetadata
         {
         {
             FullName = p,
             FullName = p,
-            IsDirectory = false
+            Name = Path.GetFileName(p),
+            IsDirectory = string.IsNullOrEmpty(Path.GetExtension(p))
         }).ToList();
         }).ToList();
 
 
-        var extras = _libraryManager.FindExtras(owner, files).OrderBy(e => e.ExtraType).ToList();
+        var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
 
 
-        Assert.Equal(4, extras.Count);
+        Assert.Equal(6, extras.Count);
         Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);
         Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);
         Assert.Equal(ExtraType.Trailer, extras[1].ExtraType);
         Assert.Equal(ExtraType.Trailer, extras[1].ExtraType);
         Assert.Equal(ExtraType.BehindTheScenes, extras[2].ExtraType);
         Assert.Equal(ExtraType.BehindTheScenes, extras[2].ExtraType);
         Assert.Equal(ExtraType.Sample, extras[3].ExtraType);
         Assert.Equal(ExtraType.Sample, extras[3].ExtraType);
+        Assert.Equal(ExtraType.ThemeSong, extras[4].ExtraType);
+        Assert.Equal(ExtraType.ThemeSong, extras[5].ExtraType);
     }
     }
 
 
     [Fact]
     [Fact]
@@ -116,7 +170,7 @@ public class FindExtrasTests
             IsDirectory = false
             IsDirectory = false
         }).ToList();
         }).ToList();
 
 
-        var extras = _libraryManager.FindExtras(owner, files).OrderBy(e => e.ExtraType).ToList();
+        var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
 
 
         Assert.Single(extras);
         Assert.Single(extras);
         Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);
         Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);
@@ -142,7 +196,7 @@ public class FindExtrasTests
             IsDirectory = false
             IsDirectory = false
         }).ToList();
         }).ToList();
 
 
-        var extras = _libraryManager.FindExtras(owner, files).OrderBy(e => e.ExtraType).ToList();
+        var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
 
 
         Assert.Single(extras);
         Assert.Single(extras);
         Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);
         Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);
@@ -167,7 +221,7 @@ public class FindExtrasTests
             IsDirectory = string.IsNullOrEmpty(Path.GetExtension(p))
             IsDirectory = string.IsNullOrEmpty(Path.GetExtension(p))
         }).ToList();
         }).ToList();
 
 
-        var extras = _libraryManager.FindExtras(owner, files).OrderBy(e => e.ExtraType).ToList();
+        var extras = _libraryManager.FindExtras(owner, files, new DirectoryService(_fileSystemMock.Object)).OrderBy(e => e.ExtraType).ToList();
 
 
         Assert.Equal(2, extras.Count);
         Assert.Equal(2, extras.Count);
         Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);
         Assert.Equal(ExtraType.Trailer, extras[0].ExtraType);