From 8f024e81996b14a9e6a440a601d0f6c0694f7ab8 Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Mon, 20 Aug 2012 11:55:05 -0400 Subject: [PATCH] Fully async'd xml parsing process as well as added resolver and provider priorities --- MediaBrowser.Common/Kernel/BaseKernel.cs | 7 +- MediaBrowser.Controller/Kernel.cs | 74 +++--- .../Library/ItemController.cs | 39 +++- .../Providers/AudioInfoProvider.cs | 5 + .../Providers/BaseMetadataProvider.cs | 17 ++ .../Providers/FolderProviderFromXml.cs | 5 + .../ImageFromMediaLocationProvider.cs | 7 +- .../Providers/LocalTrailerProvider.cs | 5 + .../Resolvers/AudioResolver.cs | 5 + .../Resolvers/BaseItemResolver.cs | 17 ++ .../Resolvers/FolderResolver.cs | 5 + .../Resolvers/VideoResolver.cs | 4 + .../Resolvers/VirtualFolderResolver.cs | 5 + .../Xml/BaseItemXmlParser.cs | 215 +++++++++--------- MediaBrowser.Controller/Xml/XmlExtensions.cs | 17 +- .../Providers/MovieProviderFromXml.cs | 5 + MediaBrowser.TV/Metadata/EpisodeXmlParser.cs | 13 +- MediaBrowser.TV/Metadata/SeriesXmlParser.cs | 15 +- .../EpisodeImageFromMediaLocationProvider.cs | 5 + .../Providers/EpisodeProviderFromXml.cs | 5 + .../Providers/SeriesProviderFromXml.cs | 5 + 21 files changed, 295 insertions(+), 180 deletions(-) diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs index 15ab687f31..d3b7f6522c 100644 --- a/MediaBrowser.Common/Kernel/BaseKernel.cs +++ b/MediaBrowser.Common/Kernel/BaseKernel.cs @@ -99,8 +99,13 @@ namespace MediaBrowser.Common.Kernel IEnumerable pluginAssemblies = Directory.GetFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.AllDirectories).Select(f => Assembly.Load(File.ReadAllBytes((f)))); var catalog = new AggregateCatalog(pluginAssemblies.Select(a => new AssemblyCatalog(a))); + + // Include composable parts in the Common assembly + // Uncomment this if it's ever needed //catalog.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly())); - //catalog.Catalogs.Add(new AssemblyCatalog(GetType().Assembly)); + + // Include composable parts in the subclass assembly + catalog.Catalogs.Add(new AssemblyCatalog(GetType().Assembly)); var container = new CompositionContainer(catalog); diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index da0263f6f8..9e31a5d6cd 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -86,42 +86,10 @@ namespace MediaBrowser.Controller protected override void OnComposablePartsLoaded() { - AddCoreResolvers(); - AddCoreProviders(); - // The base class will start up all the plugins base.OnComposablePartsLoaded(); - } - - private void AddCoreResolvers() - { - List list = EntityResolvers.ToList(); - - // Add the core resolvers - list.AddRange(new IBaseItemResolver[]{ - new AudioResolver(), - new VideoResolver(), - new VirtualFolderResolver(), - new FolderResolver() - }); - - EntityResolvers = list; - } - - private void AddCoreProviders() - { - List list = MetadataProviders.ToList(); - - // Add the core resolvers - list.InsertRange(0, new BaseMetadataProvider[]{ - new ImageFromMediaLocationProvider(), - new LocalTrailerProvider(), - new AudioInfoProvider(), - new FolderProviderFromXml() - }); - - MetadataProviders = list; - + + // Initialize the metadata providers Parallel.ForEach(MetadataProviders, provider => { provider.Init(); @@ -264,19 +232,43 @@ namespace MediaBrowser.Controller // Get all supported providers var supportedProviders = Kernel.Instance.MetadataProviders.Where(i => i.Supports(item)); - // Start with non-internet providers. Run them sequentially - foreach (BaseMetadataProvider provider in supportedProviders.Where(i => !i.RequiresInternet)) + // First priority providers + var providers = supportedProviders.Where(i => !i.RequiresInternet && i.Priority == MetadataProviderPriority.First); + + if (providers.Any()) { - await provider.Fetch(item, args); + await Task.WhenAll( + providers.Select(i => i.Fetch(item, args)) + ); } - var internetProviders = supportedProviders.Where(i => i.RequiresInternet); + // Second priority providers + providers = supportedProviders.Where(i => !i.RequiresInternet && i.Priority == MetadataProviderPriority.Second); - if (internetProviders.Any()) + if (providers.Any()) { - // Now execute internet providers in parallel await Task.WhenAll( - internetProviders.Select(i => i.Fetch(item, args)) + providers.Select(i => i.Fetch(item, args)) + ); + } + + // 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)) + ); + } + + // Execute internet providers + providers = supportedProviders.Where(i => i.RequiresInternet); + + if (providers.Any()) + { + await Task.WhenAll( + providers.Select(i => i.Fetch(item, args)) ); } } diff --git a/MediaBrowser.Controller/Library/ItemController.cs b/MediaBrowser.Controller/Library/ItemController.cs index eb767d9a14..0f9b859b6f 100644 --- a/MediaBrowser.Controller/Library/ItemController.cs +++ b/MediaBrowser.Controller/Library/ItemController.cs @@ -59,8 +59,8 @@ namespace MediaBrowser.Controller.Library private async Task ResolveItem(ItemResolveEventArgs args) { - // If that didn't pan out, try the slow ones - foreach (IBaseItemResolver resolver in Kernel.Instance.EntityResolvers) + // Try first priority resolvers + foreach (IBaseItemResolver resolver in Kernel.Instance.EntityResolvers.Where(p => p.Priority == ResolverPriority.First)) { var item = await resolver.ResolvePath(args); @@ -70,6 +70,39 @@ namespace MediaBrowser.Controller.Library } } + // Try second priority resolvers + foreach (IBaseItemResolver resolver in Kernel.Instance.EntityResolvers.Where(p => p.Priority == ResolverPriority.Second)) + { + var item = await 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 = await 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 = await resolver.ResolvePath(args); + + if (item != null) + { + return item; + } + } + return null; } @@ -153,7 +186,7 @@ namespace MediaBrowser.Controller.Library } BaseItem[] baseItemChildren = await Task.WhenAll(tasks); - + // Sort them folder.Children = baseItemChildren.Where(i => i != null).OrderBy(f => { diff --git a/MediaBrowser.Controller/Providers/AudioInfoProvider.cs b/MediaBrowser.Controller/Providers/AudioInfoProvider.cs index 6d2287b2d6..8894f87ed6 100644 --- a/MediaBrowser.Controller/Providers/AudioInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/AudioInfoProvider.cs @@ -18,6 +18,11 @@ namespace MediaBrowser.Controller.Providers return item is Audio; } + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.First; } + } + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { Audio audio = item as Audio; diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs index e40d30372d..03684e8ee1 100644 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs @@ -32,5 +32,22 @@ namespace MediaBrowser.Controller.Providers } public abstract Task Fetch(BaseEntity item, ItemResolveEventArgs args); + + public abstract MetadataProviderPriority Priority { get; } + } + + /// + /// Determines when a provider should execute, relative to others + /// + public enum MetadataProviderPriority + { + // Run this provider at the beginning + First, + + // Run this provider after all first priority providers + Second, + + // Run this provider last + Last } } diff --git a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs index 2ef2142375..9b1b424b18 100644 --- a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs +++ b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs @@ -14,6 +14,11 @@ namespace MediaBrowser.Controller.Providers return item is Folder; } + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.First; } + } + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { var metadataFile = args.GetFileByName("folder.xml"); diff --git a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs index 06b573ed0e..0abdba29db 100644 --- a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs +++ b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs @@ -16,7 +16,12 @@ namespace MediaBrowser.Controller.Providers { return true; } - + + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.First; } + } + public override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { return Task.Run(() => diff --git a/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs b/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs index 9d909934d4..d546f6043a 100644 --- a/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs +++ b/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs @@ -15,6 +15,11 @@ namespace MediaBrowser.Controller.Providers return item is BaseItem; } + public override MetadataProviderPriority Priority + { + get { return MetadataProviderPriority.First; } + } + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { BaseItem baseItem = item as BaseItem; diff --git a/MediaBrowser.Controller/Resolvers/AudioResolver.cs b/MediaBrowser.Controller/Resolvers/AudioResolver.cs index 956af95f05..11f8729b4e 100644 --- a/MediaBrowser.Controller/Resolvers/AudioResolver.cs +++ b/MediaBrowser.Controller/Resolvers/AudioResolver.cs @@ -8,6 +8,11 @@ namespace MediaBrowser.Controller.Resolvers [Export(typeof(IBaseItemResolver))] public class AudioResolver : BaseItemResolver