diff --git a/MediaBrowser.Controller/Events/ItemResolveEventArgs.cs b/MediaBrowser.Controller/Events/ItemResolveEventArgs.cs index 2f9cd374bc..5efdfdb70a 100644 --- a/MediaBrowser.Controller/Events/ItemResolveEventArgs.cs +++ b/MediaBrowser.Controller/Events/ItemResolveEventArgs.cs @@ -11,7 +11,7 @@ namespace MediaBrowser.Controller.Events /// public class ItemResolveEventArgs : PreBeginResolveEventArgs { - public IEnumerable> FileSystemChildren { get; set; } + public KeyValuePair[] FileSystemChildren { get; set; } public KeyValuePair? GetFileSystemEntry(string path, bool? isFolder) { diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index e07b436e30..2738e3c82f 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -42,13 +42,14 @@ namespace MediaBrowser.Controller /// Gets the list of currently registered metadata prvoiders /// [ImportMany(typeof(BaseMetadataProvider))] - public BaseMetadataProvider[] MetadataProviders { get; private set; } + public IEnumerable MetadataProviders { get; private set; } /// /// Gets the list of currently registered entity resolvers /// [ImportMany(typeof(IBaseItemResolver))] - public IBaseItemResolver[] EntityResolvers { get; private set; } + private IEnumerable EntityResolversEnumerable { get; set; } + internal IBaseItemResolver[] EntityResolvers { get; private set; } /// /// Creates a kernel based on a Data path, which is akin to our current programdata path @@ -88,6 +89,12 @@ namespace MediaBrowser.Controller { // The base class will start up all the plugins base.OnComposablePartsLoaded(); + + // Sort the resolvers by priority + EntityResolvers = EntityResolversEnumerable.OrderBy(e => e.Priority).ToArray(); + + // Sort the providers by priority + MetadataProviders = MetadataProviders.OrderBy(e => e.Priority); // Initialize the metadata providers Parallel.ForEach(MetadataProviders, provider => @@ -149,7 +156,7 @@ namespace MediaBrowser.Controller DirectoryWatchers.Stop(); - RootFolder = await ItemController.GetItem(null, MediaRootFolderPath).ConfigureAwait(false) as Folder; + RootFolder = await ItemController.GetItem(MediaRootFolderPath).ConfigureAwait(false) as Folder; DirectoryWatchers.Start(); } @@ -178,7 +185,7 @@ namespace MediaBrowser.Controller return; } - BaseItem newItem = await ItemController.GetItem(item.Parent, item.Path).ConfigureAwait(false); + BaseItem newItem = await ItemController.GetItem(item.Path, item.Parent).ConfigureAwait(false); List children = item.Parent.Children.ToList(); @@ -229,56 +236,14 @@ namespace MediaBrowser.Controller internal async Task ExecuteMetadataProviders(BaseEntity item, ItemResolveEventArgs args) { // Get all supported providers - var supportedProviders = Kernel.Instance.MetadataProviders.Where(i => i.Supports(item)); + BaseMetadataProvider[] supportedProviders = Kernel.Instance.MetadataProviders.Where(i => i.Supports(item)).ToArray(); - // First priority providers - var providers = supportedProviders.Where(i => !i.RequiresInternet && i.Priority == MetadataProviderPriority.First); - - if (providers.Any()) + // Run them + for (int i = 0; i < supportedProviders.Length; i++) { - await Task.WhenAll( - providers.Select(i => i.Fetch(item, args)) - ).ConfigureAwait(false); - } + var provider = supportedProviders[i]; - // Second priority providers - providers = supportedProviders.Where(i => !i.RequiresInternet && i.Priority == MetadataProviderPriority.Second); - - if (providers.Any()) - { - await Task.WhenAll( - providers.Select(i => i.Fetch(item, args)) - ).ConfigureAwait(false); - } - - // Third priority providers - providers = supportedProviders.Where(i => !i.RequiresInternet && i.Priority == MetadataProviderPriority.Third); - - if (providers.Any()) - { - await Task.WhenAll( - providers.Select(i => i.Fetch(item, args)) - ).ConfigureAwait(false); - } - - // Lowest priority providers - providers = supportedProviders.Where(i => !i.RequiresInternet && i.Priority == MetadataProviderPriority.Last); - - if (providers.Any()) - { - await Task.WhenAll( - providers.Select(i => i.Fetch(item, args)) - ).ConfigureAwait(false); - } - - // Execute internet providers - providers = supportedProviders.Where(i => i.RequiresInternet); - - if (providers.Any()) - { - await Task.WhenAll( - providers.Select(i => i.Fetch(item, args)) - ).ConfigureAwait(false); + await provider.Fetch(item, args); } } diff --git a/MediaBrowser.Controller/Library/ItemController.cs b/MediaBrowser.Controller/Library/ItemController.cs index 92af513c5f..208be8f0d5 100644 --- a/MediaBrowser.Controller/Library/ItemController.cs +++ b/MediaBrowser.Controller/Library/ItemController.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Threading.Tasks; using MediaBrowser.Controller.Events; using MediaBrowser.Controller.IO; -using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Library @@ -60,42 +59,9 @@ namespace MediaBrowser.Controller.Library private BaseItem ResolveItem(ItemResolveEventArgs args) { // Try first priority resolvers - foreach (IBaseItemResolver resolver in Kernel.Instance.EntityResolvers.Where(p => p.Priority == ResolverPriority.First)) + for (int i = 0; i < Kernel.Instance.EntityResolvers.Length; i++) { - var item = resolver.ResolvePath(args); - - if (item != null) - { - return item; - } - } - - // Try second priority resolvers - foreach (IBaseItemResolver resolver in Kernel.Instance.EntityResolvers.Where(p => p.Priority == ResolverPriority.Second)) - { - var item = resolver.ResolvePath(args); - - if (item != null) - { - return item; - } - } - - // Try third priority resolvers - foreach (IBaseItemResolver resolver in Kernel.Instance.EntityResolvers.Where(p => p.Priority == ResolverPriority.Third)) - { - var item = resolver.ResolvePath(args); - - if (item != null) - { - return item; - } - } - - // Try last priority resolvers - foreach (IBaseItemResolver resolver in Kernel.Instance.EntityResolvers.Where(p => p.Priority == ResolverPriority.Last)) - { - var item = resolver.ResolvePath(args); + var item = Kernel.Instance.EntityResolvers[i].ResolvePath(args); if (item != null) { @@ -109,29 +75,21 @@ namespace MediaBrowser.Controller.Library /// /// Resolves a path into a BaseItem /// - public async Task GetItem(Folder parent, string path) + public async Task GetItem(string path, Folder parent = null, WIN32_FIND_DATA? fileInfo = null) { - WIN32_FIND_DATA fileData = FileData.GetFileData(path); + WIN32_FIND_DATA fileData = fileInfo ?? FileData.GetFileData(path); - return await GetItemInternal(parent, path, fileData).ConfigureAwait(false); - } - - /// - /// Resolves a path into a BaseItem - /// - private async Task GetItemInternal(Folder parent, string path, WIN32_FIND_DATA fileData) - { if (!OnPreBeginResolvePath(parent, path, fileData)) { return null; } - IEnumerable> fileSystemChildren; + KeyValuePair[] fileSystemChildren; // Gather child folder and files if (fileData.IsDirectory) { - fileSystemChildren = Directory.GetFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly).Select(f => new KeyValuePair(f, FileData.GetFileData(f))); + fileSystemChildren = ConvertFileSystemEntries(Directory.GetFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly)); bool isVirtualFolder = parent != null && parent.IsRoot; fileSystemChildren = FilterChildFileSystemEntries(fileSystemChildren, isVirtualFolder); @@ -177,19 +135,17 @@ namespace MediaBrowser.Controller.Library /// /// Finds child BaseItems for a given Folder /// - private async Task AttachChildren(Folder folder, IEnumerable> fileSystemChildren) + private async Task AttachChildren(Folder folder, KeyValuePair[] fileSystemChildren) { - KeyValuePair[] fileSystemChildrenArray = fileSystemChildren.ToArray(); - - int count = fileSystemChildrenArray.Length; + int count = fileSystemChildren.Length; Task[] tasks = new Task[count]; for (int i = 0; i < count; i++) { - var child = fileSystemChildrenArray[i]; + var child = fileSystemChildren[i]; - tasks[i] = GetItemInternal(folder, child.Key, child.Value); + tasks[i] = GetItem(child.Key, folder, child.Value); } BaseItem[] baseItemChildren = await Task.WhenAll(tasks).ConfigureAwait(false); @@ -199,25 +155,25 @@ namespace MediaBrowser.Controller.Library { return string.IsNullOrEmpty(f.SortName) ? f.Name : f.SortName; - }).ToArray(); + }); } /// /// Transforms shortcuts into their actual paths /// - private List> FilterChildFileSystemEntries(IEnumerable> fileSystemChildren, bool flattenShortcuts) + private KeyValuePair[] FilterChildFileSystemEntries(KeyValuePair[] fileSystemChildren, bool flattenShortcuts) { - List> returnFiles = new List>(); + KeyValuePair[] returnArray = new KeyValuePair[fileSystemChildren.Length]; + List> resolvedShortcuts = new List>(); - // Loop through each file - foreach (KeyValuePair file in fileSystemChildren) + for (int i = 0; i < fileSystemChildren.Length; i++) { - // Folders + KeyValuePair file = fileSystemChildren[i]; + if (file.Value.IsDirectory) { - returnFiles.Add(file); + returnArray[i] = file; } - // If it's a shortcut, resolve it else if (Shortcut.IsShortcut(file.Key)) { @@ -225,34 +181,42 @@ namespace MediaBrowser.Controller.Library WIN32_FIND_DATA newPathData = FileData.GetFileData(newPath); // Find out if the shortcut is pointing to a directory or file - if (newPathData.IsDirectory) { // If we're flattening then get the shortcut's children if (flattenShortcuts) { - IEnumerable> newChildren = Directory.GetFileSystemEntries(newPath, "*", SearchOption.TopDirectoryOnly).Select(f => new KeyValuePair(f, FileData.GetFileData(f))); + returnArray[i] = file; + KeyValuePair[] newChildren = ConvertFileSystemEntries(Directory.GetFileSystemEntries(newPath, "*", SearchOption.TopDirectoryOnly)); - returnFiles.AddRange(FilterChildFileSystemEntries(newChildren, false)); + resolvedShortcuts.AddRange(FilterChildFileSystemEntries(newChildren, false)); } else { - returnFiles.Add(new KeyValuePair(newPath, newPathData)); + returnArray[i] = new KeyValuePair(newPath, newPathData); } } else { - returnFiles.Add(new KeyValuePair(newPath, newPathData)); + returnArray[i] = new KeyValuePair(newPath, newPathData); } } else { - returnFiles.Add(file); + returnArray[i] = file; } } - return returnFiles; + if (resolvedShortcuts.Count > 0) + { + resolvedShortcuts.InsertRange(0, returnArray); + return resolvedShortcuts.ToArray(); + } + else + { + return returnArray; + } } /// @@ -338,11 +302,25 @@ namespace MediaBrowser.Controller.Library ItemResolveEventArgs args = new ItemResolveEventArgs(); args.Path = path; args.FileData = FileData.GetFileData(path); - args.FileSystemChildren = Directory.GetFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly).Select(f => new KeyValuePair(f, FileData.GetFileData(f))); + args.FileSystemChildren = ConvertFileSystemEntries(Directory.GetFileSystemEntries(path, "*", SearchOption.TopDirectoryOnly)); await Kernel.Instance.ExecuteMetadataProviders(item, args).ConfigureAwait(false); return item; } + + private KeyValuePair[] ConvertFileSystemEntries(string[] files) + { + KeyValuePair[] items = new KeyValuePair[files.Length]; + + for (int i = 0; i < files.Length; i++) + { + string file = files[i]; + + items[i] = new KeyValuePair(file, FileData.GetFileData(file)); + } + + return items; + } } } diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs index 0cd7c08d0b..6222eec5f7 100644 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs @@ -42,15 +42,15 @@ namespace MediaBrowser.Controller.Providers public enum MetadataProviderPriority { // Run this provider at the beginning - First, + First = 1, // Run this provider after all first priority providers - Second, + Second = 2, // Run this provider after all second priority providers - Third, + Third = 3, // Run this provider last - Last + Last = 4 } } diff --git a/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs b/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs index 30ddc140ec..e7e0bd8283 100644 --- a/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs +++ b/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Providers foreach (string file in allFiles) { - BaseItem child = await Kernel.Instance.ItemController.GetItem(null, file).ConfigureAwait(false); + BaseItem child = await Kernel.Instance.ItemController.GetItem(file).ConfigureAwait(false); Video video = child as Video; diff --git a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs index acaaf32294..de967daa94 100644 --- a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs +++ b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs @@ -117,9 +117,9 @@ namespace MediaBrowser.Controller.Resolvers public enum ResolverPriority { - First, - Second, - Third, - Last + First = 1, + Second = 2, + Third = 3, + Last = 4 } } diff --git a/MediaBrowser.Model/Entities/Folder.cs b/MediaBrowser.Model/Entities/Folder.cs index c42845611f..5f28a9b8fa 100644 --- a/MediaBrowser.Model/Entities/Folder.cs +++ b/MediaBrowser.Model/Entities/Folder.cs @@ -16,7 +16,7 @@ namespace MediaBrowser.Model.Entities public bool IsRoot { get; set; } - public BaseItem[] Children { get; set; } + public IEnumerable Children { get; set; } /// /// Gets allowed children of an item diff --git a/MediaBrowser.Movies/Resolvers/MovieResolver.cs b/MediaBrowser.Movies/Resolvers/MovieResolver.cs index 9b19de2895..9602c24752 100644 --- a/MediaBrowser.Movies/Resolvers/MovieResolver.cs +++ b/MediaBrowser.Movies/Resolvers/MovieResolver.cs @@ -85,7 +85,7 @@ namespace MediaBrowser.Movies.Resolvers { string[] allFiles = Directory.GetFileSystemEntries(trailerPath.Value.Key, "*", SearchOption.TopDirectoryOnly); - item.SpecialFeatures = allFiles.Select(f => Kernel.Instance.ItemController.GetItem(null, f)).OfType