fixes #530 - Add ability to sort movie genres/studios/people by movie or trailer count

This commit is contained in:
Luke Pulverenti 2013-09-10 15:57:38 -04:00
parent 9d7b3fdda6
commit 06298d489c
14 changed files with 212 additions and 133 deletions

View File

@ -110,7 +110,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<IbnStub<Artist>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
protected override IEnumerable<Task<Artist>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
var itemsList = items.OfType<Audio>().ToList();
@ -128,7 +128,7 @@ namespace MediaBrowser.Api.UserLibrary
return list;
})
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name => new IbnStub<Artist>(name, GetEntity));
.Select(name => LibraryManager.GetArtist(name));
}
/// <summary>

View File

@ -3,12 +3,10 @@ using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Querying;
using ServiceStack.ServiceHost;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
@ -92,14 +90,16 @@ namespace MediaBrowser.Api.UserLibrary
items = FilterItems(request, items);
var extractedItems = GetAllItems(request, items);
var ibnItemTasks = GetAllItems(request, items);
var extractedItems = await Task.WhenAll(ibnItemTasks).ConfigureAwait(false);
extractedItems = FilterItems(request, extractedItems, user);
extractedItems = SortItems(request, extractedItems);
var filteredItems = FilterItems(request, extractedItems, user);
var ibnItemsArray = extractedItems.ToArray();
filteredItems = ItemsService.ApplySortOrder(request, filteredItems, user, LibraryManager).Cast<TItemType>();
IEnumerable<IbnStub<TItemType>> ibnItems = ibnItemsArray;
var ibnItemsArray = filteredItems.ToArray();
IEnumerable<TItemType> ibnItems = ibnItemsArray;
var result = new ItemsResult
{
@ -137,8 +137,8 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <param name="user">The user.</param>
/// <returns>IEnumerable{IbnStub}.</returns>
private IEnumerable<IbnStub<TItemType>> FilterItems(GetItemsByName request, IEnumerable<IbnStub<TItemType>> items, User user)
/// <returns>IEnumerable{`0}.</returns>
private IEnumerable<TItemType> FilterItems(GetItemsByName request, IEnumerable<TItemType> items, User user)
{
if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater))
{
@ -148,7 +148,7 @@ namespace MediaBrowser.Api.UserLibrary
var imageTypes = request.GetImageTypes().ToArray();
if (imageTypes.Length > 0)
{
items = items.Where(item => imageTypes.Any(imageType => ItemsService.HasImage(item.GetItem().Result, imageType)));
items = items.Where(item => imageTypes.Any(imageType => ItemsService.HasImage(item, imageType)));
}
var filters = request.GetFilters().ToList();
@ -164,8 +164,7 @@ namespace MediaBrowser.Api.UserLibrary
{
items = items.Where(i =>
{
var item = i.GetItem().Result;
var userdata = UserDataRepository.GetUserData(user.Id, item.GetUserDataKey());
var userdata = UserDataRepository.GetUserData(user.Id, i.GetUserDataKey());
return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value;
});
@ -175,8 +174,7 @@ namespace MediaBrowser.Api.UserLibrary
{
items = items.Where(i =>
{
var item = i.GetItem().Result;
var userdata = UserDataRepository.GetUserData(user.Id, item.GetUserDataKey());
var userdata = UserDataRepository.GetUserData(user.Id, i.GetUserDataKey());
return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value;
});
@ -186,8 +184,7 @@ namespace MediaBrowser.Api.UserLibrary
{
items = items.Where(i =>
{
var item = i.GetItem().Result;
var userdata = UserDataRepository.GetUserData(user.Id, item.GetUserDataKey());
var userdata = UserDataRepository.GetUserData(user.Id, i.GetUserDataKey());
var likes = userdata.Likes ?? false;
var favorite = userdata.IsFavorite;
@ -200,8 +197,7 @@ namespace MediaBrowser.Api.UserLibrary
{
items = items.Where(i =>
{
var item = i.GetItem().Result;
var userdata = UserDataRepository.GetUserData(user.Id, item.GetUserDataKey());
var userdata = UserDataRepository.GetUserData(user.Id, i.GetUserDataKey());
return userdata != null && userdata.Likes.HasValue && userdata.IsFavorite;
});
@ -210,40 +206,6 @@ namespace MediaBrowser.Api.UserLibrary
return items.AsEnumerable();
}
/// <summary>
/// Sorts the items.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
private IEnumerable<IbnStub<TItemType>> SortItems(GetItemsByName request, IEnumerable<IbnStub<TItemType>> items)
{
if (string.Equals(request.SortBy, "SortName", StringComparison.OrdinalIgnoreCase))
{
if (request.SortOrder.HasValue && request.SortOrder.Value == SortOrder.Descending)
{
items = items.OrderByDescending(i => i.Name);
}
else
{
items = items.OrderBy(i => i.Name);
}
}
else if (string.Equals(request.SortBy, "Random", StringComparison.OrdinalIgnoreCase))
{
if (request.SortOrder.HasValue && request.SortOrder.Value == SortOrder.Descending)
{
items = items.OrderByDescending(i => Guid.NewGuid());
}
else
{
items = items.OrderBy(i => Guid.NewGuid());
}
}
return items;
}
/// <summary>
/// Filters the items.
/// </summary>
@ -282,30 +244,18 @@ namespace MediaBrowser.Api.UserLibrary
/// </summary>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected abstract IEnumerable<IbnStub<TItemType>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items);
/// <returns>IEnumerable{Task{`0}}.</returns>
protected abstract IEnumerable<Task<TItemType>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items);
/// <summary>
/// Gets the dto.
/// </summary>
/// <param name="stub">The stub.</param>
/// <param name="item">The item.</param>
/// <param name="user">The user.</param>
/// <param name="fields">The fields.</param>
/// <returns>Task{DtoBaseItem}.</returns>
private async Task<BaseItemDto> GetDto(IbnStub<TItemType> stub, User user, List<ItemFields> fields)
private async Task<BaseItemDto> GetDto(TItemType item, User user, List<ItemFields> fields)
{
TItemType item;
try
{
item = await stub.GetItem().ConfigureAwait(false);
}
catch (IOException ex)
{
Logger.ErrorException("Error getting IBN item {0}", ex, stub.Name);
return null;
}
var dto = user == null ? await DtoService.GetBaseItemDto(item, fields).ConfigureAwait(false) :
await DtoService.GetBaseItemDto(item, fields, user).ConfigureAwait(false);
@ -345,36 +295,9 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "NameStartsWithOrGreater", Description = "Optional filter by items whose name is sorted equally or greater than a given input string.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string NameStartsWithOrGreater { get; set; }
/// <summary>
/// What to sort the results by
/// </summary>
/// <value>The sort by.</value>
[ApiMember(Name = "SortBy", Description = "Optional. Options: SortName", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string SortBy { get; set; }
public GetItemsByName()
{
Recursive = true;
}
}
public class IbnStub<T>
where T : BaseItem
{
private readonly Func<string, Task<T>> _itemFunction;
private Task<T> _itemTask;
public string Name;
public Task<T> GetItem()
{
return _itemTask ?? (_itemTask = _itemFunction(Name));
}
public IbnStub(string name, Func<string, Task<T>> item)
{
Name = name;
_itemFunction = item;
}
}
}

View File

@ -86,6 +86,13 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "ImageTypes", Description = "Optional. If specified, results will be filtered based on those containing image types. This allows multiple, comma delimited.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string ImageTypes { get; set; }
/// <summary>
/// What to sort the results by
/// </summary>
/// <value>The sort by.</value>
[ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string SortBy { get; set; }
/// <summary>
/// Gets the filters.
/// </summary>
@ -143,5 +150,21 @@ namespace MediaBrowser.Api.UserLibrary
return val.Split(',').Select(v => (ImageType)Enum.Parse(typeof(ImageType), v, true));
}
/// <summary>
/// Gets the order by.
/// </summary>
/// <returns>IEnumerable{ItemSortBy}.</returns>
public IEnumerable<string> GetOrderBy()
{
var val = SortBy;
if (string.IsNullOrEmpty(val))
{
return new string[] { };
}
return val.Split(',');
}
}
}

View File

@ -101,14 +101,14 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<IbnStub<GameGenre>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
protected override IEnumerable<Task<GameGenre>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
var itemsList = items.Where(i => i.Genres != null).ToList();
return itemsList
.SelectMany(i => i.Genres)
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name => new IbnStub<GameGenre>(name, GetEntity));
.Select(name => LibraryManager.GetGameGenre(name));
}
/// <summary>

View File

@ -105,14 +105,14 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<IbnStub<Genre>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
protected override IEnumerable<Task<Genre>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
var itemsList = items.Where(i => i.Genres != null).ToList();
return itemsList
.SelectMany(i => i.Genres)
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name => new IbnStub<Genre>(name, GetEntity));
.Select(name => LibraryManager.GetGenre(name));
}
/// <summary>

View File

@ -37,13 +37,6 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "Person", Description = "Optional. If specified, results will be filtered to include only those containing the specified person.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public string Person { get; set; }
/// <summary>
/// What to sort the results by
/// </summary>
/// <value>The sort by.</value>
[ApiMember(Name = "SortBy", Description = "Optional. Specify one or more sort orders, comma delimeted. Options: Album, AlbumArtist, Artist, Budget, CommunityRating, CriticRating, DateCreated, DatePlayed, PlayCount, PremiereDate, ProductionYear, SortName, Random, Revenue, Runtime", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string SortBy { get; set; }
/// <summary>
/// If the Person filter is used, this can also be used to restrict to a specific person type
/// </summary>
@ -170,22 +163,6 @@ namespace MediaBrowser.Api.UserLibrary
[ApiMember(Name = "MinIndexNumber", Description = "Optional filter index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? MinIndexNumber { get; set; }
/// <summary>
/// Gets the order by.
/// </summary>
/// <returns>IEnumerable{ItemSortBy}.</returns>
public IEnumerable<string> GetOrderBy()
{
var val = SortBy;
if (string.IsNullOrEmpty(val))
{
return new string[] { };
}
return val.Split(',');
}
}
/// <summary>
@ -316,7 +293,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="user">The user.</param>
/// <param name="libraryManager">The library manager.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
internal static IEnumerable<BaseItem> ApplySortOrder(GetItems request, IEnumerable<BaseItem> items, User user, ILibraryManager libraryManager)
internal static IEnumerable<BaseItem> ApplySortOrder(BaseItemsRequest request, IEnumerable<BaseItem> items, User user, ILibraryManager libraryManager)
{
var orderBy = request.GetOrderBy().ToArray();

View File

@ -101,14 +101,14 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<IbnStub<MusicGenre>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
protected override IEnumerable<Task<MusicGenre>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
var itemsList = items.ToList();
return itemsList
.SelectMany(i => i.Genres)
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name => new IbnStub<MusicGenre>(name, GetEntity));
.Select(name => LibraryManager.GetMusicGenre(name));
}
/// <summary>

View File

@ -117,7 +117,7 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<IbnStub<Person>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
protected override IEnumerable<Task<Person>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
var inputPersonTypes = ((GetPersons)request).PersonTypes;
var personTypes = string.IsNullOrEmpty(inputPersonTypes) ? new string[] { } : inputPersonTypes.Split(',');
@ -131,7 +131,7 @@ namespace MediaBrowser.Api.UserLibrary
.Select(i => i.Name)
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name => new IbnStub<Person>(name, GetEntity)
.Select(name => LibraryManager.GetPerson(name)
);
}

View File

@ -105,14 +105,14 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<IbnStub<Studio>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
protected override IEnumerable<Task<Studio>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
var itemsList = items.Where(i => i.Studios != null).ToList();
return itemsList
.SelectMany(i => i.Studios)
.Distinct(StringComparer.OrdinalIgnoreCase)
.Select(name => new IbnStub<Studio>(name, GetEntity));
.Select(name => LibraryManager.GetStudio(name));
}
/// <summary>

View File

@ -111,14 +111,14 @@ namespace MediaBrowser.Api.UserLibrary
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
protected override IEnumerable<IbnStub<Year>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
protected override IEnumerable<Task<Year>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items)
{
var itemsList = items.Where(i => i.ProductionYear != null).ToList();
return itemsList
.Select(i => i.ProductionYear.Value)
.Distinct()
.Select(year => new IbnStub<Year>(year.ToString(UsCulture), GetEntity));
.Select(year => LibraryManager.GetYear(year));
}
/// <summary>

View File

@ -76,5 +76,7 @@ namespace MediaBrowser.Model.Querying
public const string IsPlayed = "IsPlayed";
public const string TrailerCount = "TrailerCount";
public const string MovieCount = "MovieCount";
public const string SeriesCount = "SeriesCount";
public const string EpisodeCount = "EpisodeCount";
}
}

View File

@ -187,6 +187,7 @@
<Compile Include="Sorting\CriticRatingComparer.cs" />
<Compile Include="Sorting\DateCreatedComparer.cs" />
<Compile Include="Sorting\DatePlayedComparer.cs" />
<Compile Include="Sorting\EpisodeCountComparer.cs" />
<Compile Include="Sorting\IsFolderComparer.cs" />
<Compile Include="Sorting\IsUnplayedComparer.cs" />
<Compile Include="Sorting\MovieCountComparer.cs" />
@ -198,6 +199,7 @@
<Compile Include="Sorting\RandomComparer.cs" />
<Compile Include="Sorting\RevenueComparer.cs" />
<Compile Include="Sorting\RuntimeComparer.cs" />
<Compile Include="Sorting\SeriesCountComparer.cs" />
<Compile Include="Sorting\SortNameComparer.cs" />
<Compile Include="Persistence\SqliteDisplayPreferencesRepository.cs" />
<Compile Include="Persistence\SqliteItemRepository.cs" />

View File

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Server.Implementations.Sorting
{
class EpisodeCountComparer : IUserBaseItemComparer
{
/// <summary>
/// Gets or sets the user.
/// </summary>
/// <value>The user.</value>
public User User { get; set; }
/// <summary>
/// Gets or sets the user manager.
/// </summary>
/// <value>The user manager.</value>
public IUserManager UserManager { get; set; }
/// <summary>
/// Gets or sets the user data repository.
/// </summary>
/// <value>The user data repository.</value>
public IUserDataRepository UserDataRepository { get; set; }
/// <summary>
/// Compares the specified x.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
public int Compare(BaseItem x, BaseItem y)
{
return GetValue(x).CompareTo(GetValue(y));
}
/// <summary>
/// Gets the date.
/// </summary>
/// <param name="x">The x.</param>
/// <returns>DateTime.</returns>
private int GetValue(BaseItem x)
{
var itemByName = x as IItemByName;
if (itemByName != null)
{
var counts = itemByName.GetItemByNameCounts(User);
if (counts != null)
{
return counts.EpisodeCount;
}
}
return 0;
}
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public string Name
{
get { return ItemSortBy.EpisodeCount; }
}
}
}

View File

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Controller.Sorting;
using MediaBrowser.Model.Querying;
namespace MediaBrowser.Server.Implementations.Sorting
{
class SeriesCountComparer : IUserBaseItemComparer
{
/// <summary>
/// Gets or sets the user.
/// </summary>
/// <value>The user.</value>
public User User { get; set; }
/// <summary>
/// Gets or sets the user manager.
/// </summary>
/// <value>The user manager.</value>
public IUserManager UserManager { get; set; }
/// <summary>
/// Gets or sets the user data repository.
/// </summary>
/// <value>The user data repository.</value>
public IUserDataRepository UserDataRepository { get; set; }
/// <summary>
/// Compares the specified x.
/// </summary>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <returns>System.Int32.</returns>
public int Compare(BaseItem x, BaseItem y)
{
return GetValue(x).CompareTo(GetValue(y));
}
/// <summary>
/// Gets the date.
/// </summary>
/// <param name="x">The x.</param>
/// <returns>DateTime.</returns>
private int GetValue(BaseItem x)
{
var itemByName = x as IItemByName;
if (itemByName != null)
{
var counts = itemByName.GetItemByNameCounts(User);
if (counts != null)
{
return counts.SeriesCount;
}
}
return 0;
}
/// <summary>
/// Gets the name.
/// </summary>
/// <value>The name.</value>
public string Name
{
get { return ItemSortBy.SeriesCount; }
}
}
}