From 937d27ae9d6aa571ab9327f138bfba1b84c158db Mon Sep 17 00:00:00 2001 From: LukePulverenti Luke Pulverenti luke pulverenti Date: Sun, 19 Aug 2012 16:38:31 -0400 Subject: One async call leads to another, and another, all the way up the call stack... --- MediaBrowser.Controller/IO/DirectoryWatchers.cs | 9 ++-- MediaBrowser.Controller/Kernel.cs | 42 +++++++++++++++ MediaBrowser.Controller/Library/ItemController.cs | 60 ++++++++++++---------- .../Providers/AudioInfoProvider.cs | 5 +- .../Providers/BaseMetadataProvider.cs | 23 +++++++-- .../Providers/FolderProviderFromXml.cs | 4 +- .../Providers/ImageFromMediaLocationProvider.cs | 9 +++- .../Providers/LocalTrailerProvider.cs | 11 +++- .../Resolvers/BaseItemResolver.cs | 24 +++------ .../Resolvers/FolderResolver.cs | 4 +- .../Resolvers/VirtualFolderResolver.cs | 4 +- MediaBrowser.Controller/Xml/BaseItemXmlParser.cs | 2 +- 12 files changed, 128 insertions(+), 69 deletions(-) (limited to 'MediaBrowser.Controller') diff --git a/MediaBrowser.Controller/IO/DirectoryWatchers.cs b/MediaBrowser.Controller/IO/DirectoryWatchers.cs index 1ca9cf0c8..e4eadbbd0 100644 --- a/MediaBrowser.Controller/IO/DirectoryWatchers.cs +++ b/MediaBrowser.Controller/IO/DirectoryWatchers.cs @@ -75,7 +75,7 @@ namespace MediaBrowser.Controller.IO } } - private void TimerStopped(object stateInfo) + private async void TimerStopped(object stateInfo) { updateTimer.Dispose(); updateTimer = null; @@ -83,7 +83,7 @@ namespace MediaBrowser.Controller.IO List paths = affectedPaths; affectedPaths = new List(); - //ProcessPathChanges(paths); + await ProcessPathChanges(paths); } private async Task ProcessPathChanges(IEnumerable paths) @@ -109,10 +109,7 @@ namespace MediaBrowser.Controller.IO } else { - /*Parallel.For(0, itemsToRefresh.Count, i => - { - Kernel.Instance.ReloadItem(itemsToRefresh[i]); - });*/ + await Task.WhenAll(itemsToRefresh.Select(i => Kernel.Instance.ReloadItem(i))); } } diff --git a/MediaBrowser.Controller/Kernel.cs b/MediaBrowser.Controller/Kernel.cs index b696abef5..57e30479b 100644 --- a/MediaBrowser.Controller/Kernel.cs +++ b/MediaBrowser.Controller/Kernel.cs @@ -248,5 +248,47 @@ namespace MediaBrowser.Controller return list; } + + internal async Task ExecuteMetadataProviders(BaseEntity item, ItemResolveEventArgs args) + { + 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)) + { + await provider.Fetch(item, args); + } + + var internetProviders = supportedProviders.Where(i => i.RequiresInternet); + + if (internetProviders.Any()) + { + // Now execute internet providers in parallel + await Task.WhenAll( + internetProviders.Select(i => i.Fetch(item, args)) + ); + } + } + + protected override void DisposeComposableParts() + { + base.DisposeComposableParts(); + + DisposeProviders(); + } + + /// + /// Disposes all providers + /// + private void DisposeProviders() + { + if (MetadataProviders != null) + { + foreach (var provider in MetadataProviders) + { + provider.Dispose(); + } + } + } } } diff --git a/MediaBrowser.Controller/Library/ItemController.cs b/MediaBrowser.Controller/Library/ItemController.cs index 4b0d9a983..bc5cea79b 100644 --- a/MediaBrowser.Controller/Library/ItemController.cs +++ b/MediaBrowser.Controller/Library/ItemController.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.IO; using System.Linq; @@ -217,49 +218,49 @@ namespace MediaBrowser.Controller.Library /// /// Gets a Person /// - public Person GetPerson(string name) + public async Task GetPerson(string name) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.PeoplePath, name); - return GetImagesByNameItem(path, name); + return await GetImagesByNameItem(path, name); } /// /// Gets a Studio /// - public Studio GetStudio(string name) + public async Task GetStudio(string name) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.StudioPath, name); - return GetImagesByNameItem(path, name); + return await GetImagesByNameItem(path, name); } /// /// Gets a Genre /// - public Genre GetGenre(string name) + public async Task GetGenre(string name) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.GenrePath, name); - return GetImagesByNameItem(path, name); + return await GetImagesByNameItem(path, name); } /// /// Gets a Year /// - public Year GetYear(int value) + public async Task GetYear(int value) { string path = Path.Combine(Kernel.Instance.ApplicationPaths.YearPath, value.ToString()); - return GetImagesByNameItem(path, value.ToString()); + return await GetImagesByNameItem(path, value.ToString()); } - private Dictionary ImagesByNameItemCache = new Dictionary(); + private ConcurrentDictionary ImagesByNameItemCache = new ConcurrentDictionary(); /// /// Generically retrieves an IBN item /// - private T GetImagesByNameItem(string path, string name) + private async Task GetImagesByNameItem(string path, string name) where T : BaseEntity, new() { string key = path.ToLower(); @@ -267,7 +268,9 @@ namespace MediaBrowser.Controller.Library // Look for it in the cache, if it's not there, create it if (!ImagesByNameItemCache.ContainsKey(key)) { - ImagesByNameItemCache[key] = CreateImagesByNameItem(path, name); + T obj = await CreateImagesByNameItem(path, name); + ImagesByNameItemCache[key] = obj; + return obj; } return ImagesByNameItemCache[key] as T; @@ -276,7 +279,7 @@ namespace MediaBrowser.Controller.Library /// /// Creates an IBN item based on a given path /// - private T CreateImagesByNameItem(string path, string name) + private async Task CreateImagesByNameItem(string path, string name) where T : BaseEntity, new() { T item = new T(); @@ -284,25 +287,28 @@ namespace MediaBrowser.Controller.Library item.Name = name; item.Id = Kernel.GetMD5(path); - if (Directory.Exists(path)) + if (!Directory.Exists(path)) { - item.DateCreated = Directory.GetCreationTime(path); - item.DateModified = Directory.GetLastAccessTime(path); - if (File.Exists(Path.Combine(path, "folder.jpg"))) - { - item.PrimaryImagePath = Path.Combine(path, "folder.jpg"); - } - else if (File.Exists(Path.Combine(path, "folder.png"))) - { - item.PrimaryImagePath = Path.Combine(path, "folder.png"); - } + Directory.CreateDirectory(path); } - else + + item.DateCreated = Directory.GetCreationTime(path); + item.DateModified = Directory.GetLastAccessTime(path); + + if (File.Exists(Path.Combine(path, "folder.jpg"))) + { + item.PrimaryImagePath = Path.Combine(path, "folder.jpg"); + } + else if (File.Exists(Path.Combine(path, "folder.png"))) { - DateTime now = DateTime.Now; + item.PrimaryImagePath = Path.Combine(path, "folder.png"); + } + + var b = false; - item.DateCreated = now; - item.DateModified = now; + if (b) + { + await Kernel.Instance.ExecuteMetadataProviders(item, null); } return item; diff --git a/MediaBrowser.Controller/Providers/AudioInfoProvider.cs b/MediaBrowser.Controller/Providers/AudioInfoProvider.cs index 934f082d5..70adb688f 100644 --- a/MediaBrowser.Controller/Providers/AudioInfoProvider.cs +++ b/MediaBrowser.Controller/Providers/AudioInfoProvider.cs @@ -12,12 +12,12 @@ namespace MediaBrowser.Controller.Providers [Export(typeof(BaseMetadataProvider))] public class AudioInfoProvider : BaseMetadataProvider { - public override bool Supports(BaseItem item) + public override bool Supports(BaseEntity item) { return item is Audio; } - public async override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { Audio audio = item as Audio; @@ -62,6 +62,7 @@ namespace MediaBrowser.Controller.Providers { base.Init(); + // Do this now so that we don't have to do this on every operation, which would require us to create a lock in order to maintain thread-safety for (int i = 0; i <= 9; i++) { EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, i.ToString())); diff --git a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs index 93d9ef10e..e40d30372 100644 --- a/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs +++ b/MediaBrowser.Controller/Providers/BaseMetadataProvider.cs @@ -1,10 +1,11 @@ -using System.Threading.Tasks; +using System; +using System.Threading.Tasks; using MediaBrowser.Controller.Events; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Providers { - public abstract class BaseMetadataProvider + public abstract class BaseMetadataProvider : IDisposable { /// /// If the provider needs any startup routines, add them here @@ -13,11 +14,23 @@ namespace MediaBrowser.Controller.Providers { } - public virtual bool Supports(BaseItem item) + /// + /// Disposes anything created during Init + /// + public virtual void Dispose() + { + } + + public abstract bool Supports(BaseEntity item); + + public virtual bool RequiresInternet { - return true; + get + { + return false; + } } - public abstract Task Fetch(BaseItem item, ItemResolveEventArgs args); + public abstract Task Fetch(BaseEntity item, ItemResolveEventArgs args); } } diff --git a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs index 14067dd20..2ef214237 100644 --- a/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs +++ b/MediaBrowser.Controller/Providers/FolderProviderFromXml.cs @@ -9,12 +9,12 @@ namespace MediaBrowser.Controller.Providers [Export(typeof(BaseMetadataProvider))] public class FolderProviderFromXml : BaseMetadataProvider { - public override bool Supports(BaseItem item) + public override bool Supports(BaseEntity item) { return item is Folder; } - public async override Task Fetch(BaseItem item, ItemResolveEventArgs args) + 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 2df07251a..5b086f795 100644 --- a/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs +++ b/MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs @@ -12,13 +12,18 @@ namespace MediaBrowser.Controller.Providers [Export(typeof(BaseMetadataProvider))] public class ImageFromMediaLocationProvider : BaseMetadataProvider { - public override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public override bool Supports(BaseEntity item) + { + return item is BaseItem; + } + + public override Task Fetch(BaseEntity item, ItemResolveEventArgs args) { return Task.Run(() => { if (args.IsFolder) { - PopulateImages(item, args); + PopulateImages(item as BaseItem, args); } }); } diff --git a/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs b/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs index 027c2f75d..9d909934d 100644 --- a/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs +++ b/MediaBrowser.Controller/Providers/LocalTrailerProvider.cs @@ -10,8 +10,15 @@ namespace MediaBrowser.Controller.Providers [Export(typeof(BaseMetadataProvider))] public class LocalTrailerProvider : BaseMetadataProvider { - public async override Task Fetch(BaseItem item, ItemResolveEventArgs args) + public override bool Supports(BaseEntity item) { + return item is BaseItem; + } + + public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args) + { + BaseItem baseItem = item as BaseItem; + var trailerPath = args.GetFolderByName("trailers"); if (trailerPath.HasValue) @@ -32,7 +39,7 @@ namespace MediaBrowser.Controller.Providers } } - item.LocalTrailers = localTrailers; + baseItem.LocalTrailers = localTrailers; } } } diff --git a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs index 75e516487..d8f6b61ce 100644 --- a/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs +++ b/MediaBrowser.Controller/Resolvers/BaseItemResolver.cs @@ -2,13 +2,12 @@ using System.IO; using System.Threading.Tasks; using MediaBrowser.Controller.Events; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.Resolvers { public abstract class BaseItemResolver : IBaseItemResolver - where T : BaseItem, new () + where T : BaseItem, new() { protected virtual T Resolve(ItemResolveEventArgs args) { @@ -18,7 +17,7 @@ namespace MediaBrowser.Controller.Resolvers /// /// Sets initial values on the newly resolved item /// - protected virtual void SetItemValues(T item, ItemResolveEventArgs args) + protected virtual void SetInitialItemValues(T item, ItemResolveEventArgs args) { // If the subclass didn't specify this if (string.IsNullOrEmpty(item.Path)) @@ -38,35 +37,24 @@ namespace MediaBrowser.Controller.Resolvers public async Task ResolvePath(ItemResolveEventArgs args) { T item = Resolve(args); - + if (item != null) { // Set initial values on the newly resolved item - SetItemValues(item, args); + SetInitialItemValues(item, args); // Make sure the item has a name EnsureName(item); // Make sure DateCreated and DateModified have values EnsureDates(item); - - await FetchMetadataFromProviders(item, args); + + await Kernel.Instance.ExecuteMetadataProviders(item, args); } return item; } - private async Task FetchMetadataFromProviders(T item, ItemResolveEventArgs args) - { - foreach (BaseMetadataProvider provider in Kernel.Instance.MetadataProviders) - { - if (provider.Supports(item)) - { - await provider.Fetch(item, args); - } - } - } - private void EnsureName(T item) { // If the subclass didn't supply a name, add it here diff --git a/MediaBrowser.Controller/Resolvers/FolderResolver.cs b/MediaBrowser.Controller/Resolvers/FolderResolver.cs index ff326669f..858b3bcd8 100644 --- a/MediaBrowser.Controller/Resolvers/FolderResolver.cs +++ b/MediaBrowser.Controller/Resolvers/FolderResolver.cs @@ -21,9 +21,9 @@ namespace MediaBrowser.Controller.Resolvers public abstract class BaseFolderResolver : BaseItemResolver where TItemType : Folder, new() { - protected override void SetItemValues(TItemType item, ItemResolveEventArgs args) + protected override void SetInitialItemValues(TItemType item, ItemResolveEventArgs args) { - base.SetItemValues(item, args); + base.SetInitialItemValues(item, args); item.IsRoot = args.Parent == null; } diff --git a/MediaBrowser.Controller/Resolvers/VirtualFolderResolver.cs b/MediaBrowser.Controller/Resolvers/VirtualFolderResolver.cs index 51478fd02..c81cb204a 100644 --- a/MediaBrowser.Controller/Resolvers/VirtualFolderResolver.cs +++ b/MediaBrowser.Controller/Resolvers/VirtualFolderResolver.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Resolvers return null; } - protected override void SetItemValues(VirtualFolder item, ItemResolveEventArgs args) + protected override void SetInitialItemValues(VirtualFolder item, ItemResolveEventArgs args) { // Set the name initially by stripping off the [CollectionType=...] // The name can always be overridden later by folder.xml @@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Resolvers item.CollectionType = pathName.Substring(index + srch.Length).TrimEnd(']'); } - base.SetItemValues(item, args); + base.SetInitialItemValues(item, args); } } diff --git a/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs b/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs index 0e514b8b2..6c7a265fa 100644 --- a/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs +++ b/MediaBrowser.Controller/Xml/BaseItemXmlParser.cs @@ -2,9 +2,9 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Threading.Tasks; using System.Xml; using MediaBrowser.Model.Entities; -using System.Threading.Tasks; namespace MediaBrowser.Controller.Xml { -- cgit v1.2.3