This commit is contained in:
LukePulverenti Luke Pulverenti luke pulverenti 2012-08-19 16:38:47 -04:00
commit 5b7063e7c6
38 changed files with 393 additions and 373 deletions

View File

@ -1,8 +1,7 @@
using System; using System;
using System.IO; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -21,7 +20,7 @@ namespace MediaBrowser.Api
return Kernel.Instance.GetItemById(guid); 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 includeChildren = true,
bool includePeople = true) bool includePeople = true)
{ {
@ -79,16 +78,16 @@ namespace MediaBrowser.Api
dto.UserData = item.GetUserData(user); dto.UserData = item.GetUserData(user);
AttachStudios(dto, item); await AttachStudios(dto, item);
if (includeChildren) if (includeChildren)
{ {
AttachChildren(dto, item, user); await AttachChildren(dto, item, user);
} }
if (includePeople) if (includePeople)
{ {
AttachPeople(dto, item); await AttachPeople(dto, item);
} }
Folder folder = item as Folder; Folder folder = item as Folder;
@ -104,18 +103,20 @@ namespace MediaBrowser.Api
return dto; 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) // Attach Studios by transforming them into BaseItemStudio (DTO)
if (item.Studios != null) 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 => dto.Studios = item.Studios.Select(s =>
{ {
BaseItemStudio baseItemStudio = new BaseItemStudio(); BaseItemStudio baseItemStudio = new BaseItemStudio();
baseItemStudio.Name = s; baseItemStudio.Name = s;
Studio ibnObject = Kernel.Instance.ItemController.GetStudio(s); Studio ibnObject = entities.First(i => i.Name.Equals(s, StringComparison.OrdinalIgnoreCase));
if (ibnObject != null) 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; var folder = item as Folder;
if (folder != null) 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; 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) // Attach People by transforming them into BaseItemPerson (DTO)
if (item.People != null) 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 => dto.People = item.People.Select(p =>
{ {
BaseItemPerson baseItemPerson = new BaseItemPerson(); BaseItemPerson baseItemPerson = new BaseItemPerson();
baseItemPerson.PersonInfo = p; 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) if (ibnObject != null)
{ {

View File

@ -5,7 +5,6 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Logging; using MediaBrowser.Common.Logging;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Common.Net.Handlers; 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()); 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) public override async Task ProcessRequest(HttpListenerContext ctx)

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers
/// </summary> /// </summary>
public class GenreHandler : BaseJsonHandler<IBNItem<Genre>> 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; Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]); Guid userId = Guid.Parse(QueryString["userid"]);
@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers
string name = QueryString["name"]; string name = QueryString["name"];
return GetGenre(parent, user, name); return await GetGenre(parent, user, name);
} }
/// <summary> /// <summary>
/// Gets a Genre /// Gets a Genre
/// </summary> /// </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; int count = 0;
@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers
// Get the original entity so that we can also supply the PrimaryImagePath // Get the original entity so that we can also supply the PrimaryImagePath
return new IBNItem<Genre>() return new IBNItem<Genre>()
{ {
Item = Kernel.Instance.ItemController.GetGenre(name), Item = await Kernel.Instance.ItemController.GetGenre(name),
BaseItemCount = count BaseItemCount = count
}; };
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
@ -10,20 +11,20 @@ namespace MediaBrowser.Api.HttpHandlers
{ {
public class GenresHandler : BaseJsonHandler<IEnumerable<IBNItem<Genre>>> 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; Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]); Guid userId = Guid.Parse(QueryString["userid"]);
User user = Kernel.Instance.Users.First(u => u.Id == userId); User user = Kernel.Instance.Users.First(u => u.Id == userId);
return GetAllGenres(parent, user); return await GetAllGenres(parent, user);
} }
/// <summary> /// <summary>
/// Gets all genres from all recursive children of a folder /// 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 /// The CategoryInfo class is used to keep track of the number of times each genres appears
/// </summary> /// </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>(); 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 IEnumerable<Genre> entities = await Task.WhenAll<Genre>(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetGenre(key); }));
List<IBNItem<Genre>> list = new List<IBNItem<Genre>>();
foreach (string key in data.Keys) return entities.Select(e => new IBNItem<Genre>() { Item = e, BaseItemCount = data[e.Name] });
{
// 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;
} }
} }
} }

View File

@ -13,39 +13,57 @@ namespace MediaBrowser.Api.HttpHandlers
public class ImageHandler : BaseHandler public class ImageHandler : BaseHandler
{ {
private string _ImagePath = null; private string _ImagePath = null;
private string ImagePath private async Task<string> GetImagePath()
{ {
get if (_ImagePath == null)
{ {
if (_ImagePath == null) _ImagePath = await DiscoverImagePath();
{
_ImagePath = GetImagePath();
}
return _ImagePath;
} }
return _ImagePath;
}
private async Task<string> DiscoverImagePath()
{
string path = QueryString["path"] ?? string.Empty;
if (!string.IsNullOrEmpty(path))
{
return path;
}
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 Stream _SourceStream = null;
private Stream SourceStream private async Task<Stream> GetSourceStream()
{ {
get await EnsureSourceStream();
{ return _SourceStream;
EnsureSourceStream();
return _SourceStream;
}
} }
private bool _SourceStreamEnsured = false; private bool _SourceStreamEnsured = false;
private void EnsureSourceStream() private async Task EnsureSourceStream()
{ {
if (!_SourceStreamEnsured) if (!_SourceStreamEnsured)
{ {
try try
{ {
_SourceStream = File.OpenRead(ImagePath); _SourceStream = File.OpenRead(await GetImagePath());
} }
catch (FileNotFoundException ex) catch (FileNotFoundException ex)
{ {
@ -68,20 +86,17 @@ namespace MediaBrowser.Api.HttpHandlers
} }
} }
} }
public override string ContentType
{
get
{
EnsureSourceStream();
if (SourceStream == null) public async override Task<string> GetContentType()
{ {
return null; await EnsureSourceStream();
}
if (await GetSourceStream() == null)
return MimeTypes.GetMimeType(ImagePath); {
return null;
} }
return MimeTypes.GetMimeType(await GetImagePath());
} }
public override TimeSpan CacheDuration 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 null;
} }
return File.GetLastWriteTime(ImagePath); return File.GetLastWriteTime(await GetImagePath());
} }
private int? Height 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(await GetSourceStream(), stream, Width, Height, MaxWidth, MaxHeight, Quality);
{
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);
} }
private string GetImagePathFromTypes(BaseItem item, ImageType imageType, int imageIndex) private string GetImagePathFromTypes(BaseItem item, ImageType imageType, int imageIndex)

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
@ -9,7 +10,7 @@ namespace MediaBrowser.Api.HttpHandlers
{ {
public class ItemHandler : BaseJsonHandler<DTOBaseItem> public class ItemHandler : BaseJsonHandler<DTOBaseItem>
{ {
protected sealed override DTOBaseItem GetObjectToSerialize() protected async override Task<DTOBaseItem> GetObjectToSerialize()
{ {
Guid userId = Guid.Parse(QueryString["userid"]); Guid userId = Guid.Parse(QueryString["userid"]);
User user = Kernel.Instance.Users.First(u => u.Id == userId); User user = Kernel.Instance.Users.First(u => u.Id == userId);
@ -21,7 +22,7 @@ namespace MediaBrowser.Api.HttpHandlers
return null; return null;
} }
return ApiService.GetDTOBaseItem(item, user); return await ApiService.GetDTOBaseItem(item, user);
} }
protected virtual BaseItem ItemToSerialize protected virtual BaseItem ItemToSerialize

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
@ -10,14 +11,14 @@ namespace MediaBrowser.Api.HttpHandlers
{ {
public class ItemListHandler : BaseJsonHandler<IEnumerable<DTOBaseItem>> 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); 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); return ApiService.GetDTOBaseItem(i, user, includeChildren: false, includePeople: false);
}); }));
} }
protected IEnumerable<BaseItem> ItemsToSerialize protected IEnumerable<BaseItem> ItemsToSerialize

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers
/// </summary> /// </summary>
public class PersonHandler : BaseJsonHandler<IBNItem<Person>> 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; Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]); Guid userId = Guid.Parse(QueryString["userid"]);
@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers
string name = QueryString["name"]; string name = QueryString["name"];
return GetPerson(parent, user, name); return await GetPerson(parent, user, name);
} }
/// <summary> /// <summary>
/// Gets a Person /// Gets a Person
/// </summary> /// </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; int count = 0;
@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers
// Get the original entity so that we can also supply the PrimaryImagePath // Get the original entity so that we can also supply the PrimaryImagePath
return new IBNItem<Person>() return new IBNItem<Person>()
{ {
Item = Kernel.Instance.ItemController.GetPerson(name), Item = await Kernel.Instance.ItemController.GetPerson(name),
BaseItemCount = count BaseItemCount = count
}; };
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.Plugins; using MediaBrowser.Model.Plugins;
@ -8,11 +9,14 @@ namespace MediaBrowser.Api.HttpHandlers
{ {
public class PluginConfigurationHandler : BaseJsonHandler<BasePluginConfiguration> 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;
});
} }
} }
} }

View File

@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
@ -11,26 +12,29 @@ namespace MediaBrowser.Api.HttpHandlers
/// </summary> /// </summary>
public class PluginsHandler : BaseJsonHandler<IEnumerable<PluginInfo>> 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, return new PluginInfo()
Name = p.Name, {
Enabled = p.Enabled, Path = p.Path,
DownloadToUI = p.DownloadToUI, Name = p.Name,
Version = p.Version Enabled = p.Enabled,
}; DownloadToUI = p.DownloadToUI,
Version = p.Version
};
});
if (QueryString["uionly"] == "1")
{
plugins = plugins.Where(p => p.DownloadToUI);
}
return plugins;
}); });
if (QueryString["uionly"] == "1")
{
plugins = plugins.Where(p => p.DownloadToUI);
}
return plugins;
} }
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers
/// </summary> /// </summary>
public class StudioHandler : BaseJsonHandler<IBNItem<Studio>> 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; Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]); Guid userId = Guid.Parse(QueryString["userid"]);
@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers
string name = QueryString["name"]; string name = QueryString["name"];
return GetStudio(parent, user, name); return await GetStudio(parent, user, name);
} }
/// <summary> /// <summary>
/// Gets a Studio /// Gets a Studio
/// </summary> /// </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; int count = 0;
@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers
// Get the original entity so that we can also supply the PrimaryImagePath // Get the original entity so that we can also supply the PrimaryImagePath
return new IBNItem<Studio>() return new IBNItem<Studio>()
{ {
Item = Kernel.Instance.ItemController.GetStudio(name), Item = await Kernel.Instance.ItemController.GetStudio(name),
BaseItemCount = count BaseItemCount = count
}; };
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
@ -10,20 +11,20 @@ namespace MediaBrowser.Api.HttpHandlers
{ {
public class StudiosHandler : BaseJsonHandler<IEnumerable<IBNItem<Studio>>> 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; Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]); Guid userId = Guid.Parse(QueryString["userid"]);
User user = Kernel.Instance.Users.First(u => u.Id == userId); User user = Kernel.Instance.Users.First(u => u.Id == userId);
return GetAllStudios(parent, user); return await GetAllStudios(parent, user);
} }
/// <summary> /// <summary>
/// Gets all studios from all recursive children of a folder /// 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 /// The CategoryInfo class is used to keep track of the number of times each studio appears
/// </summary> /// </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>(); 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 IEnumerable<Studio> entities = await Task.WhenAll<Studio>(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetStudio(key); }));
List<IBNItem<Studio>> list = new List<IBNItem<Studio>>();
foreach (string key in data.Keys) return entities.Select(e => new IBNItem<Studio>() { Item = e, BaseItemCount = data[e.Name] });
{
// 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;
} }
} }
} }

View File

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
@ -7,9 +8,12 @@ namespace MediaBrowser.Api.HttpHandlers
{ {
class UsersHandler : BaseJsonHandler<IEnumerable<User>> 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;
});
} }
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
@ -13,7 +14,7 @@ namespace MediaBrowser.Api.HttpHandlers
/// </summary> /// </summary>
public class YearHandler : BaseJsonHandler<IBNItem<Year>> 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; Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]); Guid userId = Guid.Parse(QueryString["userid"]);
@ -21,13 +22,13 @@ namespace MediaBrowser.Api.HttpHandlers
string year = QueryString["year"]; string year = QueryString["year"];
return GetYear(parent, user, int.Parse(year)); return await GetYear(parent, user, int.Parse(year));
} }
/// <summary> /// <summary>
/// Gets a Year /// Gets a Year
/// </summary> /// </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; int count = 0;
@ -45,7 +46,7 @@ namespace MediaBrowser.Api.HttpHandlers
// Get the original entity so that we can also supply the PrimaryImagePath // Get the original entity so that we can also supply the PrimaryImagePath
return new IBNItem<Year>() return new IBNItem<Year>()
{ {
Item = Kernel.Instance.ItemController.GetYear(year), Item = await Kernel.Instance.ItemController.GetYear(year),
BaseItemCount = count BaseItemCount = count
}; };
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using MediaBrowser.Common.Net.Handlers; using MediaBrowser.Common.Net.Handlers;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.DTO; using MediaBrowser.Model.DTO;
@ -10,20 +11,20 @@ namespace MediaBrowser.Api.HttpHandlers
{ {
public class YearsHandler : BaseJsonHandler<IEnumerable<IBNItem<Year>>> 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; Folder parent = ApiService.GetItemById(QueryString["id"]) as Folder;
Guid userId = Guid.Parse(QueryString["userid"]); Guid userId = Guid.Parse(QueryString["userid"]);
User user = Kernel.Instance.Users.First(u => u.Id == userId); User user = Kernel.Instance.Users.First(u => u.Id == userId);
return GetAllYears(parent, user); return await GetAllYears(parent, user);
} }
/// <summary> /// <summary>
/// Gets all years from all recursive children of a folder /// 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 /// The CategoryInfo class is used to keep track of the number of times each year appears
/// </summary> /// </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>(); 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 IEnumerable<Year> entities = await Task.WhenAll<Year>(data.Keys.Select(key => { return Kernel.Instance.ItemController.GetYear(key); }));
List<IBNItem<Year>> list = new List<IBNItem<Year>>();
foreach (int key in data.Keys) return entities.Select(e => new IBNItem<Year>() { Item = e, BaseItemCount = data[int.Parse(e.Name)] });
{
// 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;
} }
} }
} }

View File

@ -2,17 +2,16 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel.Composition; using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting; using System.ComponentModel.Composition.Hosting;
using System.Configuration;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Configuration;
using MediaBrowser.Common.Logging; using MediaBrowser.Common.Logging;
using MediaBrowser.Common.Net; using MediaBrowser.Common.Net;
using MediaBrowser.Common.Plugins; using MediaBrowser.Common.Plugins;
using MediaBrowser.Common.Serialization; using MediaBrowser.Common.Serialization;
using MediaBrowser.Model.Progress; using MediaBrowser.Model.Progress;
using System.Threading.Tasks;
namespace MediaBrowser.Common.Kernel namespace MediaBrowser.Common.Kernel
{ {
@ -93,6 +92,8 @@ namespace MediaBrowser.Common.Kernel
/// </summary> /// </summary>
protected void ReloadComposableParts() protected void ReloadComposableParts()
{ {
DisposeComposableParts();
// Gets all plugin assemblies by first reading all bytes of the .dll and calling Assembly.Load against that // 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 // 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)))); IEnumerable<Assembly> pluginAssemblies = Directory.GetFiles(ApplicationPaths.PluginsPath, "*.dll", SearchOption.AllDirectories).Select(f => Assembly.Load(File.ReadAllBytes((f))));
@ -203,10 +204,33 @@ namespace MediaBrowser.Common.Kernel
/// </summary> /// </summary>
public virtual void Dispose() public virtual void Dispose()
{ {
DisposeComposableParts();
DisposeHttpServer(); DisposeHttpServer();
DisposeLogger(); 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> /// <summary>
/// Disposes the current HttpServer /// Disposes the current HttpServer
/// </summary> /// </summary>

View File

@ -14,9 +14,9 @@ namespace MediaBrowser.Common.Net.Handlers
protected string ResourcePath { get; set; } protected string ResourcePath { get; set; }
public override string ContentType public override Task<string> GetContentType()
{ {
get return Task.Run(() =>
{ {
string extension = Path.GetExtension(ResourcePath); string extension = Path.GetExtension(ResourcePath);
@ -46,7 +46,7 @@ namespace MediaBrowser.Common.Net.Handlers
} }
return "text/plain; charset=utf-8"; return "text/plain; charset=utf-8";
} });
} }
protected override Task WriteResponseToOutputStream(Stream stream) protected override Task WriteResponseToOutputStream(Stream stream)

View File

@ -111,7 +111,7 @@ namespace MediaBrowser.Common.Net.Handlers
/// <summary> /// <summary>
/// Gets the MIME type to include in the response headers /// Gets the MIME type to include in the response headers
/// </summary> /// </summary>
public abstract string ContentType { get; } public abstract Task<string> GetContentType();
/// <summary> /// <summary>
/// Gets the status code to include in the response headers /// Gets the status code to include in the response headers
@ -129,31 +129,9 @@ namespace MediaBrowser.Common.Net.Handlers
} }
} }
private bool _LastDateModifiedDiscovered = false; public virtual bool ShouldCompressResponse(string contentType)
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
{ {
get return true;
{
if (!_LastDateModifiedDiscovered)
{
_LastDateModified = GetLastDateModified();
}
return _LastDateModified;
}
}
public virtual bool CompressResponse
{
get
{
return true;
}
} }
private bool ClientSupportsCompression 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 // When serving a range request, we need to return status code 206 to indicate a partial response body
StatusCode = SupportsByteRangeRequests && IsRangeRequest ? 206 : 200; StatusCode = SupportsByteRangeRequests && IsRangeRequest ? 206 : 200;
ctx.Response.ContentType = ContentType; ctx.Response.ContentType = await GetContentType();
TimeSpan cacheDuration = CacheDuration; TimeSpan cacheDuration = CacheDuration;
DateTime? lastDateModified = await GetLastDateModified();
if (ctx.Request.Headers.AllKeys.Contains("If-Modified-Since")) if (ctx.Request.Headers.AllKeys.Contains("If-Modified-Since"))
{ {
DateTime ifModifiedSince; 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 (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 the cache hasn't expired yet just return a 304
if (IsCacheValid(ifModifiedSince, cacheDuration, LastDateModified)) if (IsCacheValid(ifModifiedSince, cacheDuration, lastDateModified))
{ {
StatusCode = 304; StatusCode = 304;
} }
} }
} }
PrepareResponse(); await PrepareResponse();
if (IsResponseValid) if (IsResponseValid)
{ {
await ProcessUncachedRequest(ctx, cacheDuration); bool compressResponse = ShouldCompressResponse(ctx.Response.ContentType) && ClientSupportsCompression;
await ProcessUncachedRequest(ctx, compressResponse, cacheDuration, lastDateModified);
} }
else 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 // It might be too late if some response data has already been transmitted, but try to set this
ctx.Response.StatusCode = 500; ctx.Response.StatusCode = 500;
Logger.LogException(ex); Logger.LogException(ex);
} }
finally 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; long? totalContentLength = TotalContentLength;
@ -270,7 +252,7 @@ namespace MediaBrowser.Common.Net.Handlers
} }
// Add the compression header // Add the compression header
if (CompressResponse && ClientSupportsCompression) if (compressResponse)
{ {
ctx.Response.AddHeader("Content-Encoding", CompressionMethod); ctx.Response.AddHeader("Content-Encoding", CompressionMethod);
} }
@ -278,7 +260,7 @@ namespace MediaBrowser.Common.Net.Handlers
// Add caching headers // Add caching headers
if (cacheDuration.Ticks > 0) if (cacheDuration.Ticks > 0)
{ {
CacheResponse(ctx.Response, cacheDuration, LastDateModified); CacheResponse(ctx.Response, cacheDuration, lastDateModified);
} }
// Set the status code // Set the status code
@ -289,7 +271,7 @@ namespace MediaBrowser.Common.Net.Handlers
// Finally, write the response data // Finally, write the response data
Stream outputStream = ctx.Response.OutputStream; Stream outputStream = ctx.Response.OutputStream;
if (CompressResponse && ClientSupportsCompression) if (compressResponse)
{ {
if (CompressionMethod.Equals("deflate", StringComparison.OrdinalIgnoreCase)) if (CompressionMethod.Equals("deflate", StringComparison.OrdinalIgnoreCase))
{ {
@ -321,10 +303,11 @@ namespace MediaBrowser.Common.Net.Handlers
} }
/// <summary> /// <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> /// </summary>
protected virtual void PrepareResponse() protected virtual Task PrepareResponse()
{ {
return Task.Run(() => { });
} }
protected abstract Task WriteResponseToOutputStream(Stream stream); protected abstract Task WriteResponseToOutputStream(Stream stream);
@ -372,9 +355,11 @@ namespace MediaBrowser.Common.Net.Handlers
return null; 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 private bool IsResponseValid

View File

@ -6,19 +6,22 @@ namespace MediaBrowser.Common.Net.Handlers
{ {
public abstract class BaseJsonHandler<T> : BaseHandler 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 bool _ObjectToSerializeEnsured = false;
private T _ObjectToSerialize; private T _ObjectToSerialize;
private void EnsureObjectToSerialize() private async Task EnsureObjectToSerialize()
{ {
if (!_ObjectToSerializeEnsured) if (!_ObjectToSerializeEnsured)
{ {
_ObjectToSerialize = GetObjectToSerialize(); _ObjectToSerialize = await GetObjectToSerialize();
if (_ObjectToSerialize == null) if (_ObjectToSerialize == null)
{ {
@ -29,30 +32,18 @@ namespace MediaBrowser.Common.Net.Handlers
} }
} }
private T ObjectToSerialize protected abstract Task<T> GetObjectToSerialize();
protected override async Task PrepareResponse()
{ {
get await EnsureObjectToSerialize();
{
EnsureObjectToSerialize();
return _ObjectToSerialize;
}
} }
protected abstract T GetObjectToSerialize(); protected async override Task WriteResponseToOutputStream(Stream stream)
protected override void PrepareResponse()
{ {
base.PrepareResponse(); await EnsureObjectToSerialize();
EnsureObjectToSerialize(); JsonSerializer.SerializeToStream<T>(_ObjectToSerialize, stream);
}
protected override Task WriteResponseToOutputStream(Stream stream)
{
return Task.Run(() =>
{
JsonSerializer.SerializeToStream<T>(ObjectToSerialize, stream);
});
} }
} }
} }

View File

@ -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;
}
// It will take some work to support compression within this handler
return false; return false;
} }
// 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() protected override long? GetTotalContentLength()
@ -105,31 +100,32 @@ namespace MediaBrowser.Common.Net.Handlers
return SourceStream.Length; return SourceStream.Length;
} }
protected override DateTime? GetLastDateModified() protected override Task<DateTime?> GetLastDateModified()
{ {
EnsureSourceStream(); return Task.Run<DateTime?>(() =>
if (SourceStream == null)
{ {
return null; EnsureSourceStream();
}
return File.GetLastWriteTime(Path); if (SourceStream == null)
{
return null;
}
return File.GetLastWriteTime(Path);
});
} }
public override string ContentType public override Task<string> GetContentType()
{ {
get return Task.Run(() =>
{ {
return MimeTypes.GetMimeType(Path); return MimeTypes.GetMimeType(Path);
} });
} }
protected override void PrepareResponse() protected override Task PrepareResponse()
{ {
base.PrepareResponse(); return Task.Run(() => { EnsureSourceStream(); });
EnsureSourceStream();
} }
protected async override Task WriteResponseToOutputStream(Stream stream) protected async override Task WriteResponseToOutputStream(Stream stream)

View File

@ -75,7 +75,7 @@ namespace MediaBrowser.Controller.IO
} }
} }
private void TimerStopped(object stateInfo) private async void TimerStopped(object stateInfo)
{ {
updateTimer.Dispose(); updateTimer.Dispose();
updateTimer = null; updateTimer = null;
@ -83,7 +83,7 @@ namespace MediaBrowser.Controller.IO
List<string> paths = affectedPaths; List<string> paths = affectedPaths;
affectedPaths = new List<string>(); affectedPaths = new List<string>();
//ProcessPathChanges(paths); await ProcessPathChanges(paths);
} }
private async Task ProcessPathChanges(IEnumerable<string> paths) private async Task ProcessPathChanges(IEnumerable<string> paths)
@ -109,10 +109,7 @@ namespace MediaBrowser.Controller.IO
} }
else else
{ {
/*Parallel.For(0, itemsToRefresh.Count, i => await Task.WhenAll(itemsToRefresh.Select(i => Kernel.Instance.ReloadItem(i)));
{
Kernel.Instance.ReloadItem(itemsToRefresh[i]);
});*/
} }
} }

View File

@ -248,5 +248,47 @@ namespace MediaBrowser.Controller
return list; 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();
}
}
}
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -217,49 +218,49 @@ namespace MediaBrowser.Controller.Library
/// <summary> /// <summary>
/// Gets a Person /// Gets a Person
/// </summary> /// </summary>
public Person GetPerson(string name) public async Task<Person> GetPerson(string name)
{ {
string path = Path.Combine(Kernel.Instance.ApplicationPaths.PeoplePath, name); string path = Path.Combine(Kernel.Instance.ApplicationPaths.PeoplePath, name);
return GetImagesByNameItem<Person>(path, name); return await GetImagesByNameItem<Person>(path, name);
} }
/// <summary> /// <summary>
/// Gets a Studio /// Gets a Studio
/// </summary> /// </summary>
public Studio GetStudio(string name) public async Task<Studio> GetStudio(string name)
{ {
string path = Path.Combine(Kernel.Instance.ApplicationPaths.StudioPath, name); string path = Path.Combine(Kernel.Instance.ApplicationPaths.StudioPath, name);
return GetImagesByNameItem<Studio>(path, name); return await GetImagesByNameItem<Studio>(path, name);
} }
/// <summary> /// <summary>
/// Gets a Genre /// Gets a Genre
/// </summary> /// </summary>
public Genre GetGenre(string name) public async Task<Genre> GetGenre(string name)
{ {
string path = Path.Combine(Kernel.Instance.ApplicationPaths.GenrePath, name); string path = Path.Combine(Kernel.Instance.ApplicationPaths.GenrePath, name);
return GetImagesByNameItem<Genre>(path, name); return await GetImagesByNameItem<Genre>(path, name);
} }
/// <summary> /// <summary>
/// Gets a Year /// Gets a Year
/// </summary> /// </summary>
public Year GetYear(int value) public async Task<Year> GetYear(int value)
{ {
string path = Path.Combine(Kernel.Instance.ApplicationPaths.YearPath, value.ToString()); 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> /// <summary>
/// Generically retrieves an IBN item /// Generically retrieves an IBN item
/// </summary> /// </summary>
private T GetImagesByNameItem<T>(string path, string name) private async Task<T> GetImagesByNameItem<T>(string path, string name)
where T : BaseEntity, new() where T : BaseEntity, new()
{ {
string key = path.ToLower(); 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 // Look for it in the cache, if it's not there, create it
if (!ImagesByNameItemCache.ContainsKey(key)) 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; return ImagesByNameItemCache[key] as T;
@ -276,7 +279,7 @@ namespace MediaBrowser.Controller.Library
/// <summary> /// <summary>
/// Creates an IBN item based on a given path /// Creates an IBN item based on a given path
/// </summary> /// </summary>
private T CreateImagesByNameItem<T>(string path, string name) private async Task<T> CreateImagesByNameItem<T>(string path, string name)
where T : BaseEntity, new() where T : BaseEntity, new()
{ {
T item = new T(); T item = new T();
@ -284,25 +287,28 @@ namespace MediaBrowser.Controller.Library
item.Name = name; item.Name = name;
item.Id = Kernel.GetMD5(path); item.Id = Kernel.GetMD5(path);
if (Directory.Exists(path)) if (!Directory.Exists(path))
{ {
item.DateCreated = Directory.GetCreationTime(path); Directory.CreateDirectory(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");
}
} }
else
{
DateTime now = DateTime.Now;
item.DateCreated = now; item.DateCreated = Directory.GetCreationTime(path);
item.DateModified = now; 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; return item;

View File

@ -12,12 +12,12 @@ namespace MediaBrowser.Controller.Providers
[Export(typeof(BaseMetadataProvider))] [Export(typeof(BaseMetadataProvider))]
public class AudioInfoProvider : BaseMetadataProvider public class AudioInfoProvider : BaseMetadataProvider
{ {
public override bool Supports(BaseItem item) public override bool Supports(BaseEntity item)
{ {
return item is Audio; 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; Audio audio = item as Audio;
@ -62,6 +62,7 @@ namespace MediaBrowser.Controller.Providers
{ {
base.Init(); 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++) for (int i = 0; i <= 9; i++)
{ {
EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, i.ToString())); EnsureDirectory(Path.Combine(Kernel.Instance.ApplicationPaths.FFProbeAudioCacheDirectory, i.ToString()));

View File

@ -1,10 +1,11 @@
using System.Threading.Tasks; using System;
using System.Threading.Tasks;
using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Providers namespace MediaBrowser.Controller.Providers
{ {
public abstract class BaseMetadataProvider public abstract class BaseMetadataProvider : IDisposable
{ {
/// <summary> /// <summary>
/// If the provider needs any startup routines, add them here /// 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);
} }
} }

View File

@ -9,12 +9,12 @@ namespace MediaBrowser.Controller.Providers
[Export(typeof(BaseMetadataProvider))] [Export(typeof(BaseMetadataProvider))]
public class FolderProviderFromXml : BaseMetadataProvider public class FolderProviderFromXml : BaseMetadataProvider
{ {
public override bool Supports(BaseItem item) public override bool Supports(BaseEntity item)
{ {
return item is Folder; 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"); var metadataFile = args.GetFileByName("folder.xml");

View File

@ -12,13 +12,18 @@ namespace MediaBrowser.Controller.Providers
[Export(typeof(BaseMetadataProvider))] [Export(typeof(BaseMetadataProvider))]
public class ImageFromMediaLocationProvider : 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(() => return Task.Run(() =>
{ {
if (args.IsFolder) if (args.IsFolder)
{ {
PopulateImages(item, args); PopulateImages(item as BaseItem, args);
} }
}); });
} }

View File

@ -10,8 +10,15 @@ namespace MediaBrowser.Controller.Providers
[Export(typeof(BaseMetadataProvider))] [Export(typeof(BaseMetadataProvider))]
public class LocalTrailerProvider : 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"); var trailerPath = args.GetFolderByName("trailers");
if (trailerPath.HasValue) if (trailerPath.HasValue)
@ -32,7 +39,7 @@ namespace MediaBrowser.Controller.Providers
} }
} }
item.LocalTrailers = localTrailers; baseItem.LocalTrailers = localTrailers;
} }
} }
} }

View File

@ -2,13 +2,12 @@
using System.IO; using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using MediaBrowser.Controller.Events; using MediaBrowser.Controller.Events;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
namespace MediaBrowser.Controller.Resolvers namespace MediaBrowser.Controller.Resolvers
{ {
public abstract class BaseItemResolver<T> : IBaseItemResolver public abstract class BaseItemResolver<T> : IBaseItemResolver
where T : BaseItem, new () where T : BaseItem, new()
{ {
protected virtual T Resolve(ItemResolveEventArgs args) protected virtual T Resolve(ItemResolveEventArgs args)
{ {
@ -18,7 +17,7 @@ namespace MediaBrowser.Controller.Resolvers
/// <summary> /// <summary>
/// Sets initial values on the newly resolved item /// Sets initial values on the newly resolved item
/// </summary> /// </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 the subclass didn't specify this
if (string.IsNullOrEmpty(item.Path)) if (string.IsNullOrEmpty(item.Path))
@ -38,35 +37,24 @@ namespace MediaBrowser.Controller.Resolvers
public async Task<BaseItem> ResolvePath(ItemResolveEventArgs args) public async Task<BaseItem> ResolvePath(ItemResolveEventArgs args)
{ {
T item = Resolve(args); T item = Resolve(args);
if (item != null) if (item != null)
{ {
// Set initial values on the newly resolved item // Set initial values on the newly resolved item
SetItemValues(item, args); SetInitialItemValues(item, args);
// Make sure the item has a name // Make sure the item has a name
EnsureName(item); EnsureName(item);
// Make sure DateCreated and DateModified have values // Make sure DateCreated and DateModified have values
EnsureDates(item); EnsureDates(item);
await FetchMetadataFromProviders(item, args); await Kernel.Instance.ExecuteMetadataProviders(item, args);
} }
return item; 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) private void EnsureName(T item)
{ {
// If the subclass didn't supply a name, add it here // If the subclass didn't supply a name, add it here

View File

@ -21,9 +21,9 @@ namespace MediaBrowser.Controller.Resolvers
public abstract class BaseFolderResolver<TItemType> : BaseItemResolver<TItemType> public abstract class BaseFolderResolver<TItemType> : BaseItemResolver<TItemType>
where TItemType : Folder, new() 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; item.IsRoot = args.Parent == null;
} }

View File

@ -18,7 +18,7 @@ namespace MediaBrowser.Controller.Resolvers
return null; 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=...] // Set the name initially by stripping off the [CollectionType=...]
// The name can always be overridden later by folder.xml // 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(']'); item.CollectionType = pathName.Substring(index + srch.Length).TrimEnd(']');
} }
base.SetItemValues(item, args); base.SetInitialItemValues(item, args);
} }
} }

View File

@ -2,9 +2,9 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Xml; using System.Xml;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using System.Threading.Tasks;
namespace MediaBrowser.Controller.Xml namespace MediaBrowser.Controller.Xml
{ {

View File

@ -11,12 +11,12 @@ namespace MediaBrowser.Movies.Providers
[Export(typeof(BaseMetadataProvider))] [Export(typeof(BaseMetadataProvider))]
public class MovieProviderFromXml : BaseMetadataProvider public class MovieProviderFromXml : BaseMetadataProvider
{ {
public override bool Supports(BaseItem item) public override bool Supports(BaseEntity item)
{ {
return item is Movie; 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"); var metadataFile = args.GetFileByName("movie.xml");

View File

@ -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); PopulateBonusFeatures(item, args);
} }

View File

@ -2,10 +2,9 @@
using System.Diagnostics; using System.Diagnostics;
using System.Windows; using System.Windows;
using MediaBrowser.Common.Logging; using MediaBrowser.Common.Logging;
using MediaBrowser.Common.UI;
using MediaBrowser.Controller; using MediaBrowser.Controller;
using MediaBrowser.Model.Progress; using MediaBrowser.Model.Progress;
using System.Threading.Tasks;
using MediaBrowser.Common.UI;
namespace MediaBrowser.ServerApplication namespace MediaBrowser.ServerApplication
{ {

View File

@ -13,22 +13,24 @@ namespace MediaBrowser.TV.Providers
[Export(typeof(BaseMetadataProvider))] [Export(typeof(BaseMetadataProvider))]
public class EpisodeImageFromMediaLocationProvider : BaseMetadataProvider public class EpisodeImageFromMediaLocationProvider : BaseMetadataProvider
{ {
public override bool Supports(BaseItem item) public override bool Supports(BaseEntity item)
{ {
return item is Episode; return item is Episode;
} }
public override Task Fetch(BaseItem item, ItemResolveEventArgs args) public override Task Fetch(BaseEntity item, ItemResolveEventArgs args)
{ {
return Task.Run(() => return Task.Run(() =>
{ {
Episode episode = item as Episode;
string metadataFolder = Path.Combine(args.Parent.Path, "metadata"); 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; Season season = args.Parent as Season;
SetPrimaryImagePath(item as Episode, season, metadataFolder, episodeFileName); SetPrimaryImagePath(episode, season, metadataFolder, episodeFileName);
}); });
} }

View File

@ -14,20 +14,22 @@ namespace MediaBrowser.TV.Providers
[Export(typeof(BaseMetadataProvider))] [Export(typeof(BaseMetadataProvider))]
public class EpisodeProviderFromXml : BaseMetadataProvider public class EpisodeProviderFromXml : BaseMetadataProvider
{ {
public override bool Supports(BaseItem item) public override bool Supports(BaseEntity item)
{ {
return item is Episode; 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 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")); 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) private async Task FetchMetadata(Episode item, Season season, string metadataFile)

View File

@ -11,12 +11,12 @@ namespace MediaBrowser.TV.Providers
[Export(typeof(BaseMetadataProvider))] [Export(typeof(BaseMetadataProvider))]
public class SeriesProviderFromXml : BaseMetadataProvider public class SeriesProviderFromXml : BaseMetadataProvider
{ {
public override bool Supports(BaseItem item) public override bool Supports(BaseEntity item)
{ {
return item is Series; 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"); var metadataFile = args.GetFileByName("series.xml");