mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-31 21:08:27 +01:00
One async call leads to another, and another, all the way up the call stack...
This commit is contained in:
parent
64887fa743
commit
937d27ae9d
@@ -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<string> paths = affectedPaths;
|
||||
affectedPaths = new List<string>();
|
||||
|
||||
//ProcessPathChanges(paths);
|
||||
await ProcessPathChanges(paths);
|
||||
}
|
||||
|
||||
private async Task ProcessPathChanges(IEnumerable<string> 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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disposes all providers
|
||||
/// </summary>
|
||||
private void DisposeProviders()
|
||||
{
|
||||
if (MetadataProviders != null)
|
||||
{
|
||||
foreach (var provider in MetadataProviders)
|
||||
{
|
||||
provider.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
/// <summary>
|
||||
/// Gets a Person
|
||||
/// </summary>
|
||||
public Person GetPerson(string name)
|
||||
public async Task<Person> GetPerson(string name)
|
||||
{
|
||||
string path = Path.Combine(Kernel.Instance.ApplicationPaths.PeoplePath, name);
|
||||
|
||||
return GetImagesByNameItem<Person>(path, name);
|
||||
return await GetImagesByNameItem<Person>(path, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Studio
|
||||
/// </summary>
|
||||
public Studio GetStudio(string name)
|
||||
public async Task<Studio> GetStudio(string name)
|
||||
{
|
||||
string path = Path.Combine(Kernel.Instance.ApplicationPaths.StudioPath, name);
|
||||
|
||||
return GetImagesByNameItem<Studio>(path, name);
|
||||
return await GetImagesByNameItem<Studio>(path, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Genre
|
||||
/// </summary>
|
||||
public Genre GetGenre(string name)
|
||||
public async Task<Genre> GetGenre(string name)
|
||||
{
|
||||
string path = Path.Combine(Kernel.Instance.ApplicationPaths.GenrePath, name);
|
||||
|
||||
return GetImagesByNameItem<Genre>(path, name);
|
||||
return await GetImagesByNameItem<Genre>(path, name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a Year
|
||||
/// </summary>
|
||||
public Year GetYear(int value)
|
||||
public async Task<Year> GetYear(int value)
|
||||
{
|
||||
string path = Path.Combine(Kernel.Instance.ApplicationPaths.YearPath, value.ToString());
|
||||
|
||||
return GetImagesByNameItem<Year>(path, value.ToString());
|
||||
return await GetImagesByNameItem<Year>(path, value.ToString());
|
||||
}
|
||||
|
||||
private Dictionary<string, object> ImagesByNameItemCache = new Dictionary<string, object>();
|
||||
private ConcurrentDictionary<string, object> ImagesByNameItemCache = new ConcurrentDictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// Generically retrieves an IBN item
|
||||
/// </summary>
|
||||
private T GetImagesByNameItem<T>(string path, string name)
|
||||
private async Task<T> GetImagesByNameItem<T>(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<T>(path, name);
|
||||
T obj = await CreateImagesByNameItem<T>(path, name);
|
||||
ImagesByNameItemCache[key] = obj;
|
||||
return obj;
|
||||
}
|
||||
|
||||
return ImagesByNameItemCache[key] as T;
|
||||
@@ -276,7 +279,7 @@ namespace MediaBrowser.Controller.Library
|
||||
/// <summary>
|
||||
/// Creates an IBN item based on a given path
|
||||
/// </summary>
|
||||
private T CreateImagesByNameItem<T>(string path, string name)
|
||||
private async Task<T> CreateImagesByNameItem<T>(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
|
||||
{
|
||||
DateTime now = DateTime.Now;
|
||||
|
||||
item.DateCreated = now;
|
||||
item.DateModified = now;
|
||||
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");
|
||||
}
|
||||
|
||||
var b = false;
|
||||
|
||||
if (b)
|
||||
{
|
||||
await Kernel.Instance.ExecuteMetadataProviders(item, null);
|
||||
}
|
||||
|
||||
return item;
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// If the provider needs any startup routines, add them here
|
||||
@@ -13,11 +14,23 @@ namespace MediaBrowser.Controller.Providers
|
||||
{
|
||||
}
|
||||
|
||||
public virtual bool Supports(BaseItem item)
|
||||
/// <summary>
|
||||
/// Disposes anything created during Init
|
||||
/// </summary>
|
||||
public virtual void Dispose()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public abstract Task Fetch(BaseItem item, ItemResolveEventArgs args);
|
||||
public abstract bool Supports(BaseEntity item);
|
||||
|
||||
public virtual bool RequiresInternet
|
||||
{
|
||||
get
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract Task Fetch(BaseEntity item, ItemResolveEventArgs args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<T> : IBaseItemResolver
|
||||
where T : BaseItem, new ()
|
||||
where T : BaseItem, new()
|
||||
{
|
||||
protected virtual T Resolve(ItemResolveEventArgs args)
|
||||
{
|
||||
@@ -18,7 +17,7 @@ namespace MediaBrowser.Controller.Resolvers
|
||||
/// <summary>
|
||||
/// Sets initial values on the newly resolved item
|
||||
/// </summary>
|
||||
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<BaseItem> 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
|
||||
|
||||
@@ -21,9 +21,9 @@ namespace MediaBrowser.Controller.Resolvers
|
||||
public abstract class BaseFolderResolver<TItemType> : BaseItemResolver<TItemType>
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user