2013-04-13 11:02:30 -07:00
using MediaBrowser.Controller.Dto ;
2013-04-12 17:42:51 -07:00
using MediaBrowser.Controller.Entities ;
2013-02-20 18:33:05 -07:00
using MediaBrowser.Controller.Library ;
2013-04-13 11:02:30 -07:00
using MediaBrowser.Controller.Persistence ;
2013-02-21 10:50:46 -07:00
using MediaBrowser.Model.Dto ;
2013-03-09 22:36:39 -07:00
using MediaBrowser.Model.Querying ;
2013-02-20 18:33:05 -07:00
using ServiceStack.ServiceHost ;
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Threading.Tasks ;
namespace MediaBrowser.Api.UserLibrary
{
/// <summary>
/// Class BaseItemsByNameService
/// </summary>
/// <typeparam name="TItemType">The type of the T item type.</typeparam>
2013-03-15 22:52:33 -07:00
public abstract class BaseItemsByNameService < TItemType > : BaseApiService
2013-02-20 18:33:05 -07:00
where TItemType : BaseItem
{
2013-02-27 13:25:45 -07:00
/// <summary>
/// The _user manager
/// </summary>
protected readonly IUserManager UserManager ;
2013-03-10 22:06:55 -07:00
/// <summary>
/// The library manager
/// </summary>
2013-02-28 12:32:41 -07:00
protected readonly ILibraryManager LibraryManager ;
2013-04-13 11:02:30 -07:00
protected readonly IUserDataRepository UserDataRepository ;
2013-02-27 13:25:45 -07:00
/// <summary>
/// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class.
/// </summary>
/// <param name="userManager">The user manager.</param>
2013-03-10 22:06:55 -07:00
/// <param name="libraryManager">The library manager.</param>
2013-04-13 11:02:30 -07:00
/// <param name="userDataRepository">The user data repository.</param>
protected BaseItemsByNameService ( IUserManager userManager , ILibraryManager libraryManager , IUserDataRepository userDataRepository )
2013-02-27 13:25:45 -07:00
{
UserManager = userManager ;
2013-02-28 12:32:41 -07:00
LibraryManager = libraryManager ;
2013-04-13 11:02:30 -07:00
UserDataRepository = userDataRepository ;
2013-02-27 13:25:45 -07:00
}
2013-02-20 18:33:05 -07:00
/// <summary>
/// Gets the specified request.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>Task{ItemsResult}.</returns>
protected async Task < ItemsResult > GetResult ( GetItemsByName request )
{
2013-04-21 21:38:03 -07:00
User user = null ;
BaseItem item ;
2013-02-20 18:33:05 -07:00
2013-04-21 21:38:03 -07:00
if ( request . UserId . HasValue )
{
user = UserManager . GetUserById ( request . UserId . Value ) ;
item = string . IsNullOrEmpty ( request . ParentId ) ? user . RootFolder : DtoBuilder . GetItemByClientId ( request . ParentId , UserManager , LibraryManager , user . Id ) ;
}
else
{
item = string . IsNullOrEmpty ( request . ParentId ) ? LibraryManager . RootFolder : DtoBuilder . GetItemByClientId ( request . ParentId , UserManager , LibraryManager ) ;
}
2013-02-20 18:33:05 -07:00
IEnumerable < BaseItem > items ;
if ( item . IsFolder )
{
var folder = ( Folder ) item ;
2013-04-21 21:38:03 -07:00
if ( request . UserId . HasValue )
{
items = request . Recursive ? folder . GetRecursiveChildren ( user ) : folder . GetChildren ( user ) ;
}
else
{
items = request . Recursive ? folder . RecursiveChildren : folder . Children ;
}
2013-02-20 18:33:05 -07:00
}
else
{
items = new [ ] { item } ;
}
2013-04-21 21:38:03 -07:00
items = FilterItems ( request , items ) ;
2013-04-11 12:36:50 -07:00
2013-04-21 21:38:03 -07:00
var extractedItems = GetAllItems ( request , items ) ;
2013-04-13 14:49:16 -07:00
extractedItems = FilterItems ( request , extractedItems , user ) ;
extractedItems = SortItems ( request , extractedItems ) ;
var ibnItemsArray = extractedItems . ToArray ( ) ;
IEnumerable < IbnStub < TItemType > > ibnItems = ibnItemsArray ;
2013-02-20 18:33:05 -07:00
var result = new ItemsResult
{
TotalRecordCount = ibnItemsArray . Length
} ;
2013-03-08 14:56:07 -07:00
if ( request . StartIndex . HasValue | | request . Limit . HasValue )
2013-02-20 18:33:05 -07:00
{
if ( request . StartIndex . HasValue )
{
ibnItems = ibnItems . Skip ( request . StartIndex . Value ) ;
}
2013-03-08 14:56:07 -07:00
if ( request . Limit . HasValue )
2013-02-20 18:33:05 -07:00
{
2013-03-08 14:56:07 -07:00
ibnItems = ibnItems . Take ( request . Limit . Value ) ;
2013-02-20 18:33:05 -07:00
}
}
2013-04-11 12:36:50 -07:00
var fields = request . GetItemFields ( ) . ToList ( ) ;
2013-03-02 00:16:52 -07:00
var tasks = ibnItems . Select ( i = > GetDto ( i , user , fields ) ) ;
2013-02-20 18:33:05 -07:00
var resultItems = await Task . WhenAll ( tasks ) . ConfigureAwait ( false ) ;
2013-03-05 16:11:45 -07:00
result . Items = resultItems . Where ( i = > i ! = null ) . ToArray ( ) ;
2013-02-20 18:33:05 -07:00
return result ;
}
2013-04-13 14:49:16 -07:00
/// <summary>
/// Filters the items.
/// </summary>
/// <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 )
{
2013-05-16 20:24:41 -07:00
if ( ! string . IsNullOrEmpty ( request . NameStartsWithOrGreater ) )
2013-05-16 13:46:18 -07:00
{
2013-05-17 11:05:49 -07:00
items = items . Where ( i = > string . Compare ( request . NameStartsWithOrGreater , i . Name , StringComparison . CurrentCultureIgnoreCase ) < 1 ) ;
2013-05-16 13:46:18 -07:00
}
2013-04-13 14:49:16 -07:00
var filters = request . GetFilters ( ) . ToList ( ) ;
if ( filters . Count = = 0 )
{
return items ;
}
items = items . AsParallel ( ) ;
if ( filters . Contains ( ItemFilter . Dislikes ) )
{
items = items . Where ( i = >
{
var userdata = i . GetUserItemData ( UserDataRepository , user . Id ) . Result ;
return userdata ! = null & & userdata . Likes . HasValue & & ! userdata . Likes . Value ;
} ) ;
}
if ( filters . Contains ( ItemFilter . Likes ) )
{
items = items . Where ( i = >
{
var userdata = i . GetUserItemData ( UserDataRepository , user . Id ) . Result ;
return userdata ! = null & & userdata . Likes . HasValue & & userdata . Likes . Value ;
} ) ;
}
if ( filters . Contains ( ItemFilter . IsFavorite ) )
{
items = items . Where ( i = >
{
var userdata = i . GetUserItemData ( UserDataRepository , user . Id ) . Result ;
return userdata ! = null & & userdata . Likes . HasValue & & userdata . IsFavorite ;
} ) ;
}
return items . AsEnumerable ( ) ;
}
2013-04-11 20:50:47 -07:00
/// <summary>
/// Sorts the items.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
2013-04-13 14:49:16 -07:00
private IEnumerable < IbnStub < TItemType > > SortItems ( GetItemsByName request , IEnumerable < IbnStub < TItemType > > items )
2013-04-11 20:50:47 -07:00
{
if ( string . Equals ( request . SortBy , "SortName" , StringComparison . OrdinalIgnoreCase ) )
{
if ( request . SortOrder . HasValue & & request . SortOrder . Value = = Model . Entities . SortOrder . Descending )
{
2013-04-13 14:49:16 -07:00
items = items . OrderByDescending ( i = > i . Name ) ;
2013-04-11 20:50:47 -07:00
}
else
{
2013-04-13 14:49:16 -07:00
items = items . OrderBy ( i = > i . Name ) ;
2013-04-11 20:50:47 -07:00
}
}
return items ;
}
2013-03-02 00:16:52 -07:00
/// <summary>
2013-04-11 12:36:50 -07:00
/// Filters the items.
2013-03-02 00:16:52 -07:00
/// </summary>
/// <param name="request">The request.</param>
2013-04-11 12:36:50 -07:00
/// <param name="items">The items.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
2013-04-24 07:30:12 -07:00
protected virtual IEnumerable < BaseItem > FilterItems ( GetItemsByName request , IEnumerable < BaseItem > items )
2013-03-02 00:16:52 -07:00
{
2013-04-13 11:02:30 -07:00
// Exclude item types
if ( ! string . IsNullOrEmpty ( request . ExcludeItemTypes ) )
2013-03-02 00:16:52 -07:00
{
2013-04-13 11:02:30 -07:00
var vals = request . ExcludeItemTypes . Split ( ',' ) ;
items = items . Where ( f = > ! vals . Contains ( f . GetType ( ) . Name , StringComparer . OrdinalIgnoreCase ) ) ;
2013-03-02 00:16:52 -07:00
}
2013-04-13 11:02:30 -07:00
// Include item types
if ( ! string . IsNullOrEmpty ( request . IncludeItemTypes ) )
{
var vals = request . IncludeItemTypes . Split ( ',' ) ;
items = items . Where ( f = > vals . Contains ( f . GetType ( ) . Name , StringComparer . OrdinalIgnoreCase ) ) ;
}
2013-04-11 12:36:50 -07:00
2013-04-24 13:28:42 -07:00
// Include MediaTypes
if ( ! string . IsNullOrEmpty ( request . MediaTypes ) )
{
var vals = request . MediaTypes . Split ( ',' ) ;
items = items . Where ( f = > vals . Contains ( f . MediaType ? ? string . Empty , StringComparer . OrdinalIgnoreCase ) ) ;
}
2013-05-16 13:46:18 -07:00
2013-04-11 12:36:50 -07:00
return items ;
2013-03-02 00:16:52 -07:00
}
2013-02-20 18:33:05 -07:00
/// <summary>
/// Gets all items.
/// </summary>
/// <param name="request">The request.</param>
/// <param name="items">The items.</param>
/// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
2013-04-21 21:38:03 -07:00
protected abstract IEnumerable < IbnStub < TItemType > > GetAllItems ( GetItemsByName request , IEnumerable < BaseItem > items ) ;
2013-02-20 18:33:05 -07:00
/// <summary>
/// Gets the dto.
/// </summary>
/// <param name="stub">The stub.</param>
/// <param name="user">The user.</param>
/// <param name="fields">The fields.</param>
/// <returns>Task{DtoBaseItem}.</returns>
2013-04-13 14:49:16 -07:00
private async Task < BaseItemDto > GetDto ( IbnStub < TItemType > stub , User user , List < ItemFields > fields )
2013-02-20 18:33:05 -07:00
{
BaseItem item ;
try
{
2013-04-13 14:49:16 -07:00
item = await stub . GetItem ( ) . ConfigureAwait ( false ) ;
2013-02-20 18:33:05 -07:00
}
catch ( IOException ex )
{
2013-04-13 14:49:16 -07:00
Logger . ErrorException ( "Error getting IBN item {0}" , ex , stub . Name ) ;
2013-02-20 18:33:05 -07:00
return null ;
}
2013-04-21 21:38:03 -07:00
var dto = user = = null ? await new DtoBuilder ( Logger , LibraryManager , UserDataRepository ) . GetBaseItemDto ( item , fields ) . ConfigureAwait ( false ) :
2013-05-15 09:56:38 -07:00
await new DtoBuilder ( Logger , LibraryManager , UserDataRepository ) . GetBaseItemDto ( item , fields , user ) . ConfigureAwait ( false ) ;
2013-02-20 18:33:05 -07:00
2013-04-11 15:09:08 -07:00
if ( fields . Contains ( ItemFields . ItemCounts ) )
{
2013-04-13 14:49:16 -07:00
var items = stub . Items ;
2013-04-11 15:09:08 -07:00
dto . ChildCount = items . Count ;
2013-04-21 21:38:03 -07:00
dto . RecentlyAddedItemCount = items . Count ( i = > i . IsRecentlyAdded ( ) ) ;
2013-04-11 15:09:08 -07:00
}
2013-02-20 18:33:05 -07:00
return dto ;
}
2013-04-21 21:38:03 -07:00
/// <summary>
/// Gets the items.
/// </summary>
/// <param name="userId">The user id.</param>
/// <returns>IEnumerable{BaseItem}.</returns>
protected IEnumerable < BaseItem > GetItems ( Guid ? userId )
{
if ( userId . HasValue )
{
var user = UserManager . GetUserById ( userId . Value ) ;
return UserManager . GetUserById ( userId . Value ) . RootFolder . GetRecursiveChildren ( user ) ;
}
return LibraryManager . RootFolder . RecursiveChildren ;
}
2013-02-20 18:33:05 -07:00
}
/// <summary>
/// Class GetItemsByName
/// </summary>
2013-03-10 22:06:55 -07:00
public class GetItemsByName : BaseItemsRequest , IReturn < ItemsResult >
2013-02-20 18:33:05 -07:00
{
2013-04-21 21:38:03 -07:00
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public Guid ? UserId { get ; set ; }
2013-05-16 20:24:41 -07:00
[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 ; }
2013-05-16 13:46:18 -07:00
2013-04-11 20:50:47 -07:00
/// <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 ; }
2013-04-21 21:38:03 -07:00
public GetItemsByName ( )
{
Recursive = true ;
}
2013-02-20 18:33:05 -07:00
}
2013-04-13 14:49:16 -07:00
public class IbnStub < T >
where T : BaseItem
{
private readonly Func < IEnumerable < BaseItem > > _childItemsFunction ;
private List < BaseItem > _childItems ;
private readonly Func < string , Task < T > > _itemFunction ;
private Task < T > _itemTask ;
public string Name ;
public BaseItem Item ;
2013-06-17 13:35:43 -07:00
private UserItemData _userData ;
2013-04-13 14:49:16 -07:00
public List < BaseItem > Items
{
get { return _childItems ? ? ( _childItems = _childItemsFunction ( ) . ToList ( ) ) ; }
}
public Task < T > GetItem ( )
{
return _itemTask ? ? ( _itemTask = _itemFunction ( Name ) ) ;
}
public async Task < UserItemData > GetUserItemData ( IUserDataRepository repo , Guid userId )
{
var item = await GetItem ( ) . ConfigureAwait ( false ) ;
2013-06-17 13:35:43 -07:00
return _userData ? ? ( _userData = repo . GetUserData ( userId , item . GetUserDataKey ( ) ) ) ;
2013-04-13 14:49:16 -07:00
}
public IbnStub ( string name , Func < IEnumerable < BaseItem > > childItems , Func < string , Task < T > > item )
{
Name = name ;
_childItemsFunction = childItems ;
_itemFunction = item ;
}
}
2013-02-20 18:33:05 -07:00
}