aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Api/ApiService.cs31
-rw-r--r--MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs14
-rw-r--r--MediaBrowser.Api/HttpHandlers/GenreHandler.cs9
-rw-r--r--MediaBrowser.Api/HttpHandlers/GenresHandler.cs27
-rw-r--r--MediaBrowser.Api/HttpHandlers/ImageHandler.cs106
-rw-r--r--MediaBrowser.Api/HttpHandlers/ItemHandler.cs5
-rw-r--r--MediaBrowser.Api/HttpHandlers/ItemListHandler.cs7
-rw-r--r--MediaBrowser.Api/HttpHandlers/PersonHandler.cs9
-rw-r--r--MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs10
-rw-r--r--MediaBrowser.Api/HttpHandlers/PluginsHandler.cs34
-rw-r--r--MediaBrowser.Api/HttpHandlers/StudioHandler.cs9
-rw-r--r--MediaBrowser.Api/HttpHandlers/StudiosHandler.cs27
-rw-r--r--MediaBrowser.Api/HttpHandlers/UsersHandler.cs8
-rw-r--r--MediaBrowser.Api/HttpHandlers/YearHandler.cs9
-rw-r--r--MediaBrowser.Api/HttpHandlers/YearsHandler.cs27
-rw-r--r--MediaBrowser.Common/Kernel/BaseKernel.cs28
-rw-r--r--MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs6
-rw-r--r--MediaBrowser.Common/Net/Handlers/BaseHandler.cs61
-rw-r--r--MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs37
-rw-r--r--MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs56
-rw-r--r--MediaBrowser.Controller/IO/DirectoryWatchers.cs9
-rw-r--r--MediaBrowser.Controller/Kernel.cs42
-rw-r--r--MediaBrowser.Controller/Library/ItemController.cs60
-rw-r--r--MediaBrowser.Controller/Providers/AudioInfoProvider.cs5
-rw-r--r--MediaBrowser.Controller/Providers/BaseMetadataProvider.cs23
-rw-r--r--MediaBrowser.Controller/Providers/FolderProviderFromXml.cs4
-rw-r--r--MediaBrowser.Controller/Providers/ImageFromMediaLocationProvider.cs9
-rw-r--r--MediaBrowser.Controller/Providers/LocalTrailerProvider.cs11
-rw-r--r--MediaBrowser.Controller/Resolvers/BaseItemResolver.cs24
-rw-r--r--MediaBrowser.Controller/Resolvers/FolderResolver.cs4
-rw-r--r--MediaBrowser.Controller/Resolvers/VirtualFolderResolver.cs4
-rw-r--r--MediaBrowser.Controller/Xml/BaseItemXmlParser.cs2
-rw-r--r--MediaBrowser.Movies/Providers/MovieProviderFromXml.cs4
-rw-r--r--MediaBrowser.Movies/Resolvers/MovieResolver.cs4
-rw-r--r--MediaBrowser.ServerApplication/MainWindow.xaml.cs3
-rw-r--r--MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs10
-rw-r--r--MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs10
-rw-r--r--MediaBrowser.TV/Providers/SeriesProviderFromXml.cs4
38 files changed, 386 insertions, 366 deletions
diff --git a/MediaBrowser.Api/ApiService.cs b/MediaBrowser.Api/ApiService.cs
index 4d764f3e3..765c6af1a 100644
--- a/MediaBrowser.Api/ApiService.cs
+++ b/MediaBrowser.Api/ApiService.cs
@@ -1,8 +1,7 @@
using System;
-using System.IO;
+using System.Collections.Generic;
using System.Linq;
-using System.Reflection;
-using MediaBrowser.Common.Configuration;
+using System.Threading.Tasks;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities;
@@ -21,7 +20,7 @@ namespace MediaBrowser.Api
return Kernel.Instance.GetItemById(guid);
}
- public static DTOBaseItem GetDTOBaseItem(BaseItem item, User user,
+ public async static Task<DTOBaseItem> GetDTOBaseItem(BaseItem item, User user,
bool includeChildren = true,
bool includePeople = true)
{
@@ -79,16 +78,16 @@ namespace MediaBrowser.Api
dto.UserData = item.GetUserData(user);
- AttachStudios(dto, item);
+ await AttachStudios(dto, item);
if (includeChildren)
{
- AttachChildren(dto, item, user);
+ await AttachChildren(dto, item, user);
}
if (includePeople)
{
- AttachPeople(dto, item);
+ await AttachPeople(dto, item);
}
Folder folder = item as Folder;
@@ -104,18 +103,20 @@ namespace MediaBrowser.Api
return dto;
}
- private static void AttachStudios(DTOBaseItem dto, BaseItem item)
+ private static async Task AttachStudios(DTOBaseItem dto, BaseItem item)
{
// Attach Studios by transforming them into BaseItemStudio (DTO)
if (item.Studios != null)
{
+ IEnumerable<Studio> entities = await Task.WhenAll<Studio>(item.Studios.Select(c => Kernel.Instance.ItemController.GetStudio(c)));
+
dto.Studios = item.Studios.Select(s =>
{
BaseItemStudio baseItemStudio = new BaseItemStudio();
baseItemStudio.Name = s;
- Studio ibnObject = Kernel.Instance.ItemController.GetStudio(s);
+ Studio ibnObject = entities.First(i => i.Name.Equals(s, StringComparison.OrdinalIgnoreCase));
if (ibnObject != null)
{
@@ -127,30 +128,34 @@ namespace MediaBrowser.Api
}
}
- private static void AttachChildren(DTOBaseItem dto, BaseItem item, User user)
+ private static async Task AttachChildren(DTOBaseItem dto, BaseItem item, User user)
{
var folder = item as Folder;
if (folder != null)
{
- dto.Children = folder.GetParentalAllowedChildren(user).Select(c => GetDTOBaseItem(c, user, false, false));
+ IEnumerable<BaseItem> children = folder.GetParentalAllowedChildren(user);
+
+ dto.Children = await Task.WhenAll<DTOBaseItem>(children.Select(c => GetDTOBaseItem(c, user, false, false)));
}
dto.LocalTrailers = item.LocalTrailers;
}
- private static void AttachPeople(DTOBaseItem dto, BaseItem item)
+ private static async Task AttachPeople(DTOBaseItem dto, BaseItem item)
{
// Attach People by transforming them into BaseItemPerson (DTO)
if (item.People != null)
{
+ IEnumerable<Person> entities = await Task.WhenAll<Person>(item.People.Select(c => Kernel.Instance.ItemController.GetPerson(c.Name)));
+
dto.People = item.People.Select(p =>
{
BaseItemPerson baseItemPerson = new BaseItemPerson();
baseItemPerson.PersonInfo = p;
- Person ibnObject = Kernel.Instance.ItemController.GetPerson(p.Name);
+ Person ibnObject = entities.First(i => i.Name.Equals(p.Name, StringComparison.OrdinalIgnoreCase));
if (ibnObject != null)
{
diff --git a/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs b/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs
index ffdbab65e..d2dbd699d 100644
--- a/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/BaseMediaHandler.cs
@@ -5,7 +5,6 @@ using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
-using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Logging;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Net.Handlers;
@@ -91,20 +90,17 @@ namespace MediaBrowser.Api.HttpHandlers
}
}
- public override string ContentType
+ public override Task<string> GetContentType()
{
- get
+ return Task.Run(() =>
{
return MimeTypes.GetMimeType("." + GetConversionOutputFormat());
- }
+ });
}
- public override bool CompressResponse
+ public override bool ShouldCompressResponse(string contentType)
{
- get
- {
- return false;
- }
+ return false;
}
public override async Task ProcessRequest(HttpListenerContext ctx)
diff --git a/MediaBrowser.Api/HttpHandlers/GenreHandler.cs b/MediaBrowser.Api/HttpHandlers/GenreHandler.cs
index 2b0d1c57d..c4198b028 100644
--- a/MediaBrowser.Api/HttpHandlers/GenreHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/GenreHandler.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
@@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers
/// </summary>
public class GenreHandler : BaseJsonHandler<IBNItem<Genre>>
{
- protected override IBNItem<Genre> GetObjectToSerialize()
+ protected override async Task<IBNItem<Genre>> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]);
@@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers
string name = QueryString["name"];
- return GetGenre(parent, user, name);
+ return await GetGenre(parent, user, name);
}
/// <summary>
/// Gets a Genre
/// </summary>
- private IBNItem<Genre> GetGenre(Folder parent, User user, string name)
+ private async Task<IBNItem<Genre>> GetGenre(Folder parent, User user, string name)
{
int count = 0;
@@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers
// Get the original entity so that we can also supply the PrimaryImagePath
return new IBNItem<Genre>()
{
- Item = Kernel.Instance.ItemController.GetGenre(name),
+ Item = await Kernel.Instance.ItemController.GetGenre(name),
BaseItemCount = count
};
}
diff --git a/MediaBrowser.Api/HttpHandlers/GenresHandler.cs b/MediaBrowser.Api/HttpHandlers/GenresHandler.cs
index 1134eb568..cd68f1eaa 100644
--- a/MediaBrowser.Api/HttpHandlers/GenresHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/GenresHandler.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
@@ -10,20 +11,20 @@ namespace MediaBrowser.Api.HttpHandlers
{
public class GenresHandler : BaseJsonHandler<IEnumerable<IBNItem<Genre>>>
{
- protected override IEnumerable<IBNItem<Genre>> GetObjectToSerialize()
+ protected override async Task<IEnumerable<IBNItem<Genre>>> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]);
User user = Kernel.Instance.Users.First(u => u.Id == userId);
- return GetAllGenres(parent, user);
+ return await GetAllGenres(parent, user);
}
/// <summary>
/// Gets all genres from all recursive children of a folder
/// The CategoryInfo class is used to keep track of the number of times each genres appears
/// </summary>
- private IEnumerable<IBNItem<Genre>> GetAllGenres(Folder parent, User user)
+ private async Task<IEnumerable<IBNItem<Genre>>> GetAllGenres(Folder parent, User user)
{
Dictionary<string, int> data = new Dictionary<string, int>();
@@ -52,25 +53,9 @@ namespace MediaBrowser.Api.HttpHandlers
}
}
- // Now go through the dictionary and create a Category for each genre
- List<IBNItem<Genre>> list = new List<IBNItem<Genre>>();
+ IEnumerable<Genre> entities = await Task.WhenAll<Genre>(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetGenre(key); }));
- foreach (string key in data.Keys)
- {
- // Get the original entity so that we can also supply the PrimaryImagePath
- Genre entity = Kernel.Instance.ItemController.GetGenre(key);
-
- if (entity != null)
- {
- list.Add(new IBNItem<Genre>()
- {
- Item = entity,
- BaseItemCount = data[key]
- });
- }
- }
-
- return list;
+ return entities.Select(e => new IBNItem<Genre>() { Item = e, BaseItemCount = data[e.Name] });
}
}
}
diff --git a/MediaBrowser.Api/HttpHandlers/ImageHandler.cs b/MediaBrowser.Api/HttpHandlers/ImageHandler.cs
index 826438098..4a6b2a481 100644
--- a/MediaBrowser.Api/HttpHandlers/ImageHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/ImageHandler.cs
@@ -13,39 +13,57 @@ namespace MediaBrowser.Api.HttpHandlers
public class ImageHandler : BaseHandler
{
private string _ImagePath = null;
- private string ImagePath
+ private async Task<string> GetImagePath()
{
- get
+ if (_ImagePath == null)
{
- if (_ImagePath == null)
- {
- _ImagePath = GetImagePath();
- }
-
- return _ImagePath;
+ _ImagePath = await DiscoverImagePath();
}
+
+ return _ImagePath;
}
- private Stream _SourceStream = null;
- private Stream SourceStream
+ private async Task<string> DiscoverImagePath()
{
- get
+ string path = QueryString["path"] ?? string.Empty;
+
+ if (!string.IsNullOrEmpty(path))
{
- EnsureSourceStream();
+ return path;
+ }
- return _SourceStream;
+ string personName = QueryString["personname"];
+
+ if (!string.IsNullOrEmpty(personName))
+ {
+ Person person = await Kernel.Instance.ItemController.GetPerson(personName);
+
+ return person.PrimaryImagePath;
}
+
+ BaseItem item = ApiService.GetItemById(QueryString["id"]);
+
+ string imageIndex = QueryString["index"];
+ int index = string.IsNullOrEmpty(imageIndex) ? 0 : int.Parse(imageIndex);
+
+ return GetImagePathFromTypes(item, ImageType, index);
}
+ private Stream _SourceStream = null;
+ private async Task<Stream> GetSourceStream()
+ {
+ await EnsureSourceStream();
+ return _SourceStream;
+ }
private bool _SourceStreamEnsured = false;
- private void EnsureSourceStream()
+ private async Task EnsureSourceStream()
{
if (!_SourceStreamEnsured)
{
try
{
- _SourceStream = File.OpenRead(ImagePath);
+ _SourceStream = File.OpenRead(await GetImagePath());
}
catch (FileNotFoundException ex)
{
@@ -68,20 +86,17 @@ namespace MediaBrowser.Api.HttpHandlers
}
}
}
-
- public override string ContentType
+
+ public async override Task<string> GetContentType()
{
- get
- {
- EnsureSourceStream();
+ await EnsureSourceStream();
- if (SourceStream == null)
- {
- return null;
- }
-
- return MimeTypes.GetMimeType(ImagePath);
+ if (await GetSourceStream() == null)
+ {
+ return null;
}
+
+ return MimeTypes.GetMimeType(await GetImagePath());
}
public override TimeSpan CacheDuration
@@ -92,16 +107,16 @@ namespace MediaBrowser.Api.HttpHandlers
}
}
- protected override DateTime? GetLastDateModified()
+ protected async override Task<DateTime?> GetLastDateModified()
{
- EnsureSourceStream();
+ await EnsureSourceStream();
- if (SourceStream == null)
+ if (await GetSourceStream() == null)
{
return null;
}
- return File.GetLastWriteTime(ImagePath);
+ return File.GetLastWriteTime(await GetImagePath());
}
private int? Height
@@ -194,36 +209,9 @@ namespace MediaBrowser.Api.HttpHandlers
}
}
- protected override Task WriteResponseToOutputStream(Stream stream)
+ protected override async Task WriteResponseToOutputStream(Stream stream)
{
- return Task.Run(() =>
- {
- ImageProcessor.ProcessImage(SourceStream, stream, Width, Height, MaxWidth, MaxHeight, Quality);
- });
- }
-
- private string GetImagePath()
- {
- string path = QueryString["path"] ?? string.Empty;
-
- if (!string.IsNullOrEmpty(path))
- {
- return path;
- }
-
- string personName = QueryString["personname"];
-
- if (!string.IsNullOrEmpty(personName))
- {
- return Kernel.Instance.ItemController.GetPerson(personName).PrimaryImagePath;
- }
-
- BaseItem item = ApiService.GetItemById(QueryString["id"]);
-
- string imageIndex = QueryString["index"];
- int index = string.IsNullOrEmpty(imageIndex) ? 0 : int.Parse(imageIndex);
-
- return GetImagePathFromTypes(item, ImageType, index);
+ ImageProcessor.ProcessImage(await GetSourceStream(), stream, Width, Height, MaxWidth, MaxHeight, Quality);
}
private string GetImagePathFromTypes(BaseItem item, ImageType imageType, int imageIndex)
diff --git a/MediaBrowser.Api/HttpHandlers/ItemHandler.cs b/MediaBrowser.Api/HttpHandlers/ItemHandler.cs
index dcbdf2a90..ac27633b7 100644
--- a/MediaBrowser.Api/HttpHandlers/ItemHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/ItemHandler.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
@@ -9,7 +10,7 @@ namespace MediaBrowser.Api.HttpHandlers
{
public class ItemHandler : BaseJsonHandler<DTOBaseItem>
{
- protected sealed override DTOBaseItem GetObjectToSerialize()
+ protected async override Task<DTOBaseItem> GetObjectToSerialize()
{
Guid userId = Guid.Parse(QueryString["userid"]);
User user = Kernel.Instance.Users.First(u => u.Id == userId);
@@ -21,7 +22,7 @@ namespace MediaBrowser.Api.HttpHandlers
return null;
}
- return ApiService.GetDTOBaseItem(item, user);
+ return await ApiService.GetDTOBaseItem(item, user);
}
protected virtual BaseItem ItemToSerialize
diff --git a/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs b/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs
index 84141a6bf..6e4a42081 100644
--- a/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/ItemListHandler.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
@@ -10,14 +11,14 @@ namespace MediaBrowser.Api.HttpHandlers
{
public class ItemListHandler : BaseJsonHandler<IEnumerable<DTOBaseItem>>
{
- protected override IEnumerable<DTOBaseItem> GetObjectToSerialize()
+ protected override async Task<IEnumerable<DTOBaseItem>> GetObjectToSerialize()
{
User user = Kernel.Instance.Users.First(u => u.Id == UserId);
- return ItemsToSerialize.Select(i =>
+ return await Task.WhenAll<DTOBaseItem>(ItemsToSerialize.Select(i =>
{
return ApiService.GetDTOBaseItem(i, user, includeChildren: false, includePeople: false);
- });
+ }));
}
protected IEnumerable<BaseItem> ItemsToSerialize
diff --git a/MediaBrowser.Api/HttpHandlers/PersonHandler.cs b/MediaBrowser.Api/HttpHandlers/PersonHandler.cs
index 75cccfac6..f095a3a47 100644
--- a/MediaBrowser.Api/HttpHandlers/PersonHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/PersonHandler.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
@@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers
/// </summary>
public class PersonHandler : BaseJsonHandler<IBNItem<Person>>
{
- protected override IBNItem<Person> GetObjectToSerialize()
+ protected async override Task<IBNItem<Person>> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]);
@@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers
string name = QueryString["name"];
- return GetPerson(parent, user, name);
+ return await GetPerson(parent, user, name);
}
/// <summary>
/// Gets a Person
/// </summary>
- private IBNItem<Person> GetPerson(Folder parent, User user, string name)
+ private async Task<IBNItem<Person>> GetPerson(Folder parent, User user, string name)
{
int count = 0;
@@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers
// Get the original entity so that we can also supply the PrimaryImagePath
return new IBNItem<Person>()
{
- Item = Kernel.Instance.ItemController.GetPerson(name),
+ Item = await Kernel.Instance.ItemController.GetPerson(name),
BaseItemCount = count
};
}
diff --git a/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs b/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs
index 0e19aecd5..109440e98 100644
--- a/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/PluginConfigurationHandler.cs
@@ -1,5 +1,6 @@
using System;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.Plugins;
@@ -8,11 +9,14 @@ namespace MediaBrowser.Api.HttpHandlers
{
public class PluginConfigurationHandler : BaseJsonHandler<BasePluginConfiguration>
{
- protected override BasePluginConfiguration GetObjectToSerialize()
+ protected override Task<BasePluginConfiguration> GetObjectToSerialize()
{
- string pluginName = QueryString["name"];
+ return Task.Run(() =>
+ {
+ string pluginName = QueryString["name"];
- return Kernel.Instance.Plugins.First(p => p.Name.Equals(pluginName, StringComparison.OrdinalIgnoreCase)).Configuration;
+ return Kernel.Instance.Plugins.First(p => p.Name.Equals(pluginName, StringComparison.OrdinalIgnoreCase)).Configuration;
+ });
}
}
}
diff --git a/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs b/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs
index c3c1b4049..f451832dd 100644
--- a/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/PluginsHandler.cs
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
@@ -11,26 +12,29 @@ namespace MediaBrowser.Api.HttpHandlers
/// </summary>
public class PluginsHandler : BaseJsonHandler<IEnumerable<PluginInfo>>
{
- protected override IEnumerable<PluginInfo> GetObjectToSerialize()
+ protected override Task<IEnumerable<PluginInfo>> GetObjectToSerialize()
{
- var plugins = Kernel.Instance.Plugins.Select(p =>
+ return Task.Run(() =>
{
- return new PluginInfo()
+ var plugins = Kernel.Instance.Plugins.Select(p =>
{
- Path = p.Path,
- Name = p.Name,
- Enabled = p.Enabled,
- DownloadToUI = p.DownloadToUI,
- Version = p.Version
- };
- });
+ return new PluginInfo()
+ {
+ Path = p.Path,
+ Name = p.Name,
+ Enabled = p.Enabled,
+ DownloadToUI = p.DownloadToUI,
+ Version = p.Version
+ };
+ });
- if (QueryString["uionly"] == "1")
- {
- plugins = plugins.Where(p => p.DownloadToUI);
- }
+ if (QueryString["uionly"] == "1")
+ {
+ plugins = plugins.Where(p => p.DownloadToUI);
+ }
- return plugins;
+ return plugins;
+ });
}
}
}
diff --git a/MediaBrowser.Api/HttpHandlers/StudioHandler.cs b/MediaBrowser.Api/HttpHandlers/StudioHandler.cs
index 40daadc70..b44970ea5 100644
--- a/MediaBrowser.Api/HttpHandlers/StudioHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/StudioHandler.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
@@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers
/// </summary>
public class StudioHandler : BaseJsonHandler<IBNItem<Studio>>
{
- protected override IBNItem<Studio> GetObjectToSerialize()
+ protected async override Task<IBNItem<Studio>> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]);
@@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers
string name = QueryString["name"];
- return GetStudio(parent, user, name);
+ return await GetStudio(parent, user, name);
}
/// <summary>
/// Gets a Studio
/// </summary>
- private IBNItem<Studio> GetStudio(Folder parent, User user, string name)
+ private async Task<IBNItem<Studio>> GetStudio(Folder parent, User user, string name)
{
int count = 0;
@@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers
// Get the original entity so that we can also supply the PrimaryImagePath
return new IBNItem<Studio>()
{
- Item = Kernel.Instance.ItemController.GetStudio(name),
+ Item = await Kernel.Instance.ItemController.GetStudio(name),
BaseItemCount = count
};
}
diff --git a/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs b/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs
index bef381000..d379b45fb 100644
--- a/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/StudiosHandler.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
@@ -10,20 +11,20 @@ namespace MediaBrowser.Api.HttpHandlers
{
public class StudiosHandler : BaseJsonHandler<IEnumerable<IBNItem<Studio>>>
{
- protected override IEnumerable<IBNItem<Studio>> GetObjectToSerialize()
+ protected override async Task<IEnumerable<IBNItem<Studio>>> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]);
User user = Kernel.Instance.Users.First(u => u.Id == userId);
- return GetAllStudios(parent, user);
+ return await GetAllStudios(parent, user);
}
/// <summary>
/// Gets all studios from all recursive children of a folder
/// The CategoryInfo class is used to keep track of the number of times each studio appears
/// </summary>
- private IEnumerable<IBNItem<Studio>> GetAllStudios(Folder parent, User user)
+ private async Task<IEnumerable<IBNItem<Studio>>> GetAllStudios(Folder parent, User user)
{
Dictionary<string, int> data = new Dictionary<string, int>();
@@ -52,25 +53,9 @@ namespace MediaBrowser.Api.HttpHandlers
}
}
- // Now go through the dictionary and create a Category for each studio
- List<IBNItem<Studio>> list = new List<IBNItem<Studio>>();
+ IEnumerable<Studio> entities = await Task.WhenAll<Studio>(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetStudio(key); }));
- foreach (string key in data.Keys)
- {
- // Get the original entity so that we can also supply the PrimaryImagePath
- Studio entity = Kernel.Instance.ItemController.GetStudio(key);
-
- if (entity != null)
- {
- list.Add(new IBNItem<Studio>()
- {
- Item = entity,
- BaseItemCount = data[key]
- });
- }
- }
-
- return list;
+ return entities.Select(e => new IBNItem<Studio>() { Item = e, BaseItemCount = data[e.Name] });
}
}
}
diff --git a/MediaBrowser.Api/HttpHandlers/UsersHandler.cs b/MediaBrowser.Api/HttpHandlers/UsersHandler.cs
index e1fe638ca..136873574 100644
--- a/MediaBrowser.Api/HttpHandlers/UsersHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/UsersHandler.cs
@@ -1,4 +1,5 @@
using System.Collections.Generic;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.Entities;
@@ -7,9 +8,12 @@ namespace MediaBrowser.Api.HttpHandlers
{
class UsersHandler : BaseJsonHandler<IEnumerable<User>>
{
- protected override IEnumerable<User> GetObjectToSerialize()
+ protected override Task<IEnumerable<User>> GetObjectToSerialize()
{
- return Kernel.Instance.Users;
+ return Task.Run(() =>
+ {
+ return Kernel.Instance.Users;
+ });
}
}
}
diff --git a/MediaBrowser.Api/HttpHandlers/YearHandler.cs b/MediaBrowser.Api/HttpHandlers/YearHandler.cs
index 89cde9943..dfde600e7 100644
--- a/MediaBrowser.Api/HttpHandlers/YearHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/YearHandler.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
@@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers
/// </summary>
public class YearHandler : BaseJsonHandler<IBNItem<Year>>
{
- protected override IBNItem<Year> GetObjectToSerialize()
+ protected override async Task<IBNItem<Year>> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]);
@@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers
string year = QueryString["year"];
- return GetYear(parent, user, int.Parse(year));
+ return await GetYear(parent, user, int.Parse(year));
}
/// <summary>
/// Gets a Year
/// </summary>
- private IBNItem<Year> GetYear(Folder parent, User user, int year)
+ private async Task<IBNItem<Year>> GetYear(Folder parent, User user, int year)
{
int count = 0;
@@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers
// Get the original entity so that we can also supply the PrimaryImagePath
return new IBNItem<Year>()
{
- Item = Kernel.Instance.ItemController.GetYear(year),
+ Item = await Kernel.Instance.ItemController.GetYear(year),
BaseItemCount = count
};
}
diff --git a/MediaBrowser.Api/HttpHandlers/YearsHandler.cs b/MediaBrowser.Api/HttpHandlers/YearsHandler.cs
index 3d9ae59f2..6ce087f85 100644
--- a/MediaBrowser.Api/HttpHandlers/YearsHandler.cs
+++ b/MediaBrowser.Api/HttpHandlers/YearsHandler.cs
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
+using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller;
using MediaBrowser.Model.DTO;
@@ -10,20 +11,20 @@ namespace MediaBrowser.Api.HttpHandlers
{
public class YearsHandler : BaseJsonHandler<IEnumerable<IBNItem<Year>>>
{
- protected override IEnumerable<IBNItem<Year>> GetObjectToSerialize()
+ protected override async Task<IEnumerable<IBNItem<Year>>> GetObjectToSerialize()
{
Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]);
User user = Kernel.Instance.Users.First(u => u.Id == userId);
- return GetAllYears(parent, user);
+ return await GetAllYears(parent, user);
}
/// <summary>
/// Gets all years from all recursive children of a folder
/// The CategoryInfo class is used to keep track of the number of times each year appears
/// </summary>
- private IEnumerable<IBNItem<Year>> GetAllYears(Folder parent, User user)
+ private async Task<IEnumerable<IBNItem<Year>>> GetAllYears(Folder parent, User user)
{
Dictionary<int, int> data = new Dictionary<int, int>();
@@ -49,25 +50,9 @@ namespace MediaBrowser.Api.HttpHandlers
}
}
- // Now go through the dictionary and create a Category for each studio
- List<IBNItem<Year>> list = new List<IBNItem<Year>>();
+ IEnumerable<Year> entities = await Task.WhenAll<Year>(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetYear(key); }));
- foreach (int key in data.Keys)
- {
- // Get the original entity so that we can also supply the PrimaryImagePath
- Year entity = Kernel.Instance.ItemController.GetYear(key);
-
- if (entity != null)
- {
- list.Add(new IBNItem<Year>()
- {
- Item = entity,
- BaseItemCount = data[key]
- });
- }
- }
-
- return list;
+ return entities.Select(e => new IBNItem<Year>() { Item = e, BaseItemCount = data[int.Parse(e.Name)] });
}
}
}
diff --git a/MediaBrowser.Common/Kernel/BaseKernel.cs b/MediaBrowser.Common/Kernel/BaseKernel.cs
index 7b6f6844c..5b2f97ced 100644
--- a/MediaBrowser.Common/Kernel/BaseKernel.cs
+++ b/MediaBrowser.Common/Kernel/BaseKernel.cs
@@ -2,17 +2,16 @@
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
-using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
+using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Logging;
using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Serialization;
using MediaBrowser.Model.Progress;
-using System.Threading.Tasks;
namespace MediaBrowser.Common.Kernel
{
@@ -93,6 +92,8 @@ namespace MediaBrowser.Common.Kernel
/// </summary>
protected void ReloadComposableParts()
{
+ DisposeComposableParts();
+
// Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that
// This will prevent the .dll file from getting locked, and allow us to replace it when needed
IEnumerable<Assembly> pluginAssemblies = Directory.GetFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.AllDirectories).Select(f => Assembly.Load(File.ReadAllBytes((f))));
@@ -203,11 +204,34 @@ namespace MediaBrowser.Common.Kernel
/// </summary>
public virtual void Dispose()
{
+ DisposeComposableParts();
DisposeHttpServer();
DisposeLogger();
}
/// <summary>
+ /// Disposes all objects gathered through MEF composable parts
+ /// </summary>
+ protected virtual void DisposeComposableParts()
+ {
+ DisposePlugins();
+ }
+
+ /// <summary>
+ /// Disposes all plugins
+ /// </summary>
+ private void DisposePlugins()
+ {
+ if (Plugins != null)
+ {
+ foreach (BasePlugin plugin in Plugins)
+ {
+ plugin.Dispose();
+ }
+ }
+ }
+
+ /// <summary>
/// Disposes the current HttpServer
/// </summary>
private void DisposeHttpServer()
diff --git a/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs
index 2fcead05b..a8c7090f7 100644
--- a/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs
+++ b/MediaBrowser.Common/Net/Handlers/BaseEmbeddedResourceHandler.cs
@@ -14,9 +14,9 @@ namespace MediaBrowser.Common.Net.Handlers
protected string ResourcePath { get; set; }
- public override string ContentType
+ public override Task<string> GetContentType()
{
- get
+ return Task.Run(() =>
{
string extension = Path.GetExtension(ResourcePath);
@@ -46,7 +46,7 @@ namespace MediaBrowser.Common.Net.Handlers
}
return "text/plain; charset=utf-8";
- }
+ });
}
protected override Task WriteResponseToOutputStream(Stream stream)
diff --git a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs
index f9ef065ec..7a4efdaf2 100644
--- a/MediaBrowser.Common/Net/Handlers/BaseHandler.cs
+++ b/MediaBrowser.Common/Net/Handlers/BaseHandler.cs
@@ -111,7 +111,7 @@ namespace MediaBrowser.Common.Net.Handlers
/// <summary>
/// Gets the MIME type to include in the response headers
/// </summary>
- public abstract string ContentType { get; }
+ public abstract Task<string> GetContentType();
/// <summary>
/// Gets the status code to include in the response headers
@@ -129,31 +129,9 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
- private bool _LastDateModifiedDiscovered = false;
- private DateTime? _LastDateModified = null;
- /// <summary>
- /// Gets the last date modified of the content being returned, if this can be determined.
- /// This will be used to invalidate the cache, so it's not needed if CacheDuration is 0.
- /// </summary>
- public DateTime? LastDateModified
+ public virtual bool ShouldCompressResponse(string contentType)
{
- get
- {
- if (!_LastDateModifiedDiscovered)
- {
- _LastDateModified = GetLastDateModified();
- }
-
- return _LastDateModified;
- }
- }
-
- public virtual bool CompressResponse
- {
- get
- {
- return true;
- }
+ return true;
}
private bool ClientSupportsCompression
@@ -207,10 +185,12 @@ namespace MediaBrowser.Common.Net.Handlers
// When serving a range request, we need to return status code 206 to indicate a partial response body
StatusCode = SupportsByteRangeRequests && IsRangeRequest ? 206 : 200;
- ctx.Response.ContentType = ContentType;
+ ctx.Response.ContentType = await GetContentType();
TimeSpan cacheDuration = CacheDuration;
+ DateTime? lastDateModified = await GetLastDateModified();
+
if (ctx.Request.Headers.AllKeys.Contains("If-Modified-Since"))
{
DateTime ifModifiedSince;
@@ -218,18 +198,20 @@ namespace MediaBrowser.Common.Net.Handlers
if (DateTime.TryParse(ctx.Request.Headers["If-Modified-Since"].Replace(" GMT", string.Empty), out ifModifiedSince))
{
// If the cache hasn't expired yet just return a 304
- if (IsCacheValid(ifModifiedSince, cacheDuration, LastDateModified))
+ if (IsCacheValid(ifModifiedSince, cacheDuration, lastDateModified))
{
StatusCode = 304;
}
}
}
- PrepareResponse();
+ await PrepareResponse();
if (IsResponseValid)
{
- await ProcessUncachedRequest(ctx, cacheDuration);
+ bool compressResponse = ShouldCompressResponse(ctx.Response.ContentType) && ClientSupportsCompression;
+
+ await ProcessUncachedRequest(ctx, compressResponse, cacheDuration, lastDateModified);
}
else
{
@@ -241,7 +223,7 @@ namespace MediaBrowser.Common.Net.Handlers
{
// It might be too late if some response data has already been transmitted, but try to set this
ctx.Response.StatusCode = 500;
-
+
Logger.LogException(ex);
}
finally
@@ -250,7 +232,7 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
- private async Task ProcessUncachedRequest(HttpListenerContext ctx, TimeSpan cacheDuration)
+ private async Task ProcessUncachedRequest(HttpListenerContext ctx, bool compressResponse, TimeSpan cacheDuration, DateTime? lastDateModified)
{
long? totalContentLength = TotalContentLength;
@@ -270,7 +252,7 @@ namespace MediaBrowser.Common.Net.Handlers
}
// Add the compression header
- if (CompressResponse && ClientSupportsCompression)
+ if (compressResponse)
{
ctx.Response.AddHeader("Content-Encoding", CompressionMethod);
}
@@ -278,7 +260,7 @@ namespace MediaBrowser.Common.Net.Handlers
// Add caching headers
if (cacheDuration.Ticks > 0)
{
- CacheResponse(ctx.Response, cacheDuration, LastDateModified);
+ CacheResponse(ctx.Response, cacheDuration, lastDateModified);
}
// Set the status code
@@ -289,7 +271,7 @@ namespace MediaBrowser.Common.Net.Handlers
// Finally, write the response data
Stream outputStream = ctx.Response.OutputStream;
- if (CompressResponse && ClientSupportsCompression)
+ if (compressResponse)
{
if (CompressionMethod.Equals("deflate", StringComparison.OrdinalIgnoreCase))
{
@@ -321,10 +303,11 @@ namespace MediaBrowser.Common.Net.Handlers
}
/// <summary>
- /// Gives subclasses a chance to do and prep work, and also to validate data and set an error status code, if needed
+ /// Gives subclasses a chance to do any prep work, and also to validate data and set an error status code, if needed
/// </summary>
- protected virtual void PrepareResponse()
+ protected virtual Task PrepareResponse()
{
+ return Task.Run(() => { });
}
protected abstract Task WriteResponseToOutputStream(Stream stream);
@@ -372,9 +355,11 @@ namespace MediaBrowser.Common.Net.Handlers
return null;
}
- protected virtual DateTime? GetLastDateModified()
+ protected virtual Task<DateTime?> GetLastDateModified()
{
- return null;
+ DateTime? value = null;
+
+ return Task.Run<DateTime?>(() => { return value; });
}
private bool IsResponseValid
diff --git a/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs b/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs
index a35af9231..a3a47a4a3 100644
--- a/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs
+++ b/MediaBrowser.Common/Net/Handlers/BaseJsonHandler.cs
@@ -6,19 +6,22 @@ namespace MediaBrowser.Common.Net.Handlers
{
public abstract class BaseJsonHandler<T> : BaseHandler
{
- public override string ContentType
+ public override Task<string> GetContentType()
{
- get { return MimeTypes.JsonMimeType; }
+ return Task.Run(() =>
+ {
+ return MimeTypes.JsonMimeType;
+ });
}
private bool _ObjectToSerializeEnsured = false;
private T _ObjectToSerialize;
- private void EnsureObjectToSerialize()
+ private async Task EnsureObjectToSerialize()
{
if (!_ObjectToSerializeEnsured)
{
- _ObjectToSerialize = GetObjectToSerialize();
+ _ObjectToSerialize = await GetObjectToSerialize();
if (_ObjectToSerialize == null)
{
@@ -29,30 +32,18 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
- private T ObjectToSerialize
- {
- get
- {
- EnsureObjectToSerialize();
- return _ObjectToSerialize;
- }
- }
+ protected abstract Task<T> GetObjectToSerialize();
- protected abstract T GetObjectToSerialize();
-
- protected override void PrepareResponse()
+ protected override async Task PrepareResponse()
{
- base.PrepareResponse();
-
- EnsureObjectToSerialize();
+ await EnsureObjectToSerialize();
}
- protected override Task WriteResponseToOutputStream(Stream stream)
+ protected async override Task WriteResponseToOutputStream(Stream stream)
{
- return Task.Run(() =>
- {
- JsonSerializer.SerializeToStream<T>(ObjectToSerialize, stream);
- });
+ await EnsureObjectToSerialize();
+
+ JsonSerializer.SerializeToStream<T>(_ObjectToSerialize, stream);
}
}
}
diff --git a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs
index 5656f9273..d8971dd97 100644
--- a/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs
+++ b/MediaBrowser.Common/Net/Handlers/StaticFileHandler.cs
@@ -77,27 +77,22 @@ namespace MediaBrowser.Common.Net.Handlers
}
}
- public override bool CompressResponse
+ public override bool ShouldCompressResponse(string contentType)
{
- get
+ // Can't compress these
+ if (IsRangeRequest)
{
- // Can't compress these
- if (IsRangeRequest)
- {
- return false;
- }
-
- string contentType = ContentType;
-
- // Don't compress media
- if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
- {
- return false;
- }
+ return false;
+ }
- // It will take some work to support compression within this handler
+ // Don't compress media
+ if (contentType.StartsWith("audio/", StringComparison.OrdinalIgnoreCase) || contentType.StartsWith("video/", StringComparison.OrdinalIgnoreCase))
+ {
return false;
}
+
+ // It will take some work to support compression within this handler
+ return false;
}
protected override long? GetTotalContentLength()
@@ -105,31 +100,32 @@ namespace MediaBrowser.Common.Net.Handlers
return SourceStream.Length;
}
- protected override DateTime? GetLastDateModified()
+ protected override Task<DateTime?> GetLastDateModified()
{
- EnsureSourceStream();
-
- if (SourceStream == null)
+ return Task.Run<DateTime?>(() =>
{
- return null;
- }
+ EnsureSourceStream();
+
+ if (SourceStream == null)
+ {
+ return null;
+ }
- return File.GetLastWriteTime(Path);
+ return File.GetLastWriteTime(Path);
+ });
}
- public override string ContentType
+ public override Task<string> GetContentType()
{
- get
+ return Task.Run(() =>
{
return MimeTypes.GetMimeType(Path);
- }
+ });
}
- protected override void PrepareResponse()
+ protected override Task PrepareResponse()
{
- base.PrepareResponse();
-
- EnsureSourceStream();
+ return Task.Run(() => { EnsureSourceStream(); });
}
protected async override Task WriteResponseToOutputStream(Stream stream)
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<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)));
}
}
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();
+ }
+
+ /// <summary>
+ /// Disposes all providers
+ /// </summary>
+ 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
/// <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
+
+ 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
{
/// <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()
+ {
+ }
+
+ 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<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
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<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;
}
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
{
diff --git a/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs b/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs
index 4e0bacb05..03c081454 100644
--- a/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs
+++ b/MediaBrowser.Movies/Providers/MovieProviderFromXml.cs
@@ -11,12 +11,12 @@ namespace MediaBrowser.Movies.Providers
[Export(typeof(BaseMetadataProvider))]
public class MovieProviderFromXml : BaseMetadataProvider
{
- public override bool Supports(BaseItem item)
+ public override bool Supports(BaseEntity item)
{
return item is Movie;
}
- public async override Task Fetch(BaseItem item, ItemResolveEventArgs args)
+ public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args)
{
var metadataFile = args.GetFileByName("movie.xml");
diff --git a/MediaBrowser.Movies/Resolvers/MovieResolver.cs b/MediaBrowser.Movies/Resolvers/MovieResolver.cs
index 36fbecf68..498597c97 100644
--- a/MediaBrowser.Movies/Resolvers/MovieResolver.cs
+++ b/MediaBrowser.Movies/Resolvers/MovieResolver.cs
@@ -88,9 +88,9 @@ namespace MediaBrowser.Movies.Resolvers
}
}
- protected override void SetItemValues(Movie item, ItemResolveEventArgs args)
+ protected override void SetInitialItemValues(Movie item, ItemResolveEventArgs args)
{
- base.SetItemValues(item, args);
+ base.SetInitialItemValues(item, args);
PopulateBonusFeatures(item, args);
}
diff --git a/MediaBrowser.ServerApplication/MainWindow.xaml.cs b/MediaBrowser.ServerApplication/MainWindow.xaml.cs
index abca9149f..67e20b2a2 100644
--- a/MediaBrowser.ServerApplication/MainWindow.xaml.cs
+++ b/MediaBrowser.ServerApplication/MainWindow.xaml.cs
@@ -2,10 +2,9 @@
using System.Diagnostics;
using System.Windows;
using MediaBrowser.Common.Logging;
+using MediaBrowser.Common.UI;
using MediaBrowser.Controller;
using MediaBrowser.Model.Progress;
-using System.Threading.Tasks;
-using MediaBrowser.Common.UI;
namespace MediaBrowser.ServerApplication
{
diff --git a/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs b/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs
index 61525dc79..8babcec63 100644
--- a/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs
+++ b/MediaBrowser.TV/Providers/EpisodeImageFromMediaLocationProvider.cs
@@ -13,22 +13,24 @@ namespace MediaBrowser.TV.Providers
[Export(typeof(BaseMetadataProvider))]
public class EpisodeImageFromMediaLocationProvider : BaseMetadataProvider
{
- public override bool Supports(BaseItem item)
+ public override bool Supports(BaseEntity item)
{
return item is Episode;
}
- public override Task Fetch(BaseItem item, ItemResolveEventArgs args)
+ public override Task Fetch(BaseEntity item, ItemResolveEventArgs args)
{
return Task.Run(() =>
{
+ Episode episode = item as Episode;
+
string metadataFolder = Path.Combine(args.Parent.Path, "metadata");
- string episodeFileName = Path.GetFileName(item.Path);
+ string episodeFileName = Path.GetFileName(episode.Path);
Season season = args.Parent as Season;
- SetPrimaryImagePath(item as Episode, season, metadataFolder, episodeFileName);
+ SetPrimaryImagePath(episode, season, metadataFolder, episodeFileName);
});
}
diff --git a/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs b/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs
index 4c6c58459..c92b1c475 100644
--- a/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs
+++ b/MediaBrowser.TV/Providers/EpisodeProviderFromXml.cs
@@ -14,20 +14,22 @@ namespace MediaBrowser.TV.Providers
[Export(typeof(BaseMetadataProvider))]
public class EpisodeProviderFromXml : BaseMetadataProvider
{
- public override bool Supports(BaseItem item)
+ public override bool Supports(BaseEntity item)
{
return item is Episode;
}
- public async override Task Fetch(BaseItem item, ItemResolveEventArgs args)
+ public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args)
{
string metadataFolder = Path.Combine(args.Parent.Path, "metadata");
- string episodeFileName = Path.GetFileName(item.Path);
+ Episode episode = item as Episode;
+
+ string episodeFileName = Path.GetFileName(episode.Path);
string metadataFile = Path.Combine(metadataFolder, Path.ChangeExtension(episodeFileName, ".xml"));
- await FetchMetadata(item as Episode, args.Parent as Season, metadataFile);
+ await FetchMetadata(episode, args.Parent as Season, metadataFile);
}
private async Task FetchMetadata(Episode item, Season season, string metadataFile)
diff --git a/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs b/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs
index 7adfb0483..02d5ce178 100644
--- a/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs
+++ b/MediaBrowser.TV/Providers/SeriesProviderFromXml.cs
@@ -11,12 +11,12 @@ namespace MediaBrowser.TV.Providers
[Export(typeof(BaseMetadataProvider))]
public class SeriesProviderFromXml : BaseMetadataProvider
{
- public override bool Supports(BaseItem item)
+ public override bool Supports(BaseEntity item)
{
return item is Series;
}
- public async override Task Fetch(BaseItem item, ItemResolveEventArgs args)
+ public async override Task Fetch(BaseEntity item, ItemResolveEventArgs args)
{
var metadataFile = args.GetFileByName("series.xml");