BaseItemsByNameService.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. using MediaBrowser.Controller.Dto;
  2. using MediaBrowser.Controller.Entities;
  3. using MediaBrowser.Controller.Entities.Audio;
  4. using MediaBrowser.Controller.Entities.Movies;
  5. using MediaBrowser.Controller.Entities.TV;
  6. using MediaBrowser.Controller.Library;
  7. using MediaBrowser.Controller.Persistence;
  8. using MediaBrowser.Model.Dto;
  9. using MediaBrowser.Model.Entities;
  10. using MediaBrowser.Model.Querying;
  11. using ServiceStack.ServiceHost;
  12. using System;
  13. using System.Collections.Generic;
  14. using System.IO;
  15. using System.Linq;
  16. using System.Threading.Tasks;
  17. namespace MediaBrowser.Api.UserLibrary
  18. {
  19. /// <summary>
  20. /// Class BaseItemsByNameService
  21. /// </summary>
  22. /// <typeparam name="TItemType">The type of the T item type.</typeparam>
  23. public abstract class BaseItemsByNameService<TItemType> : BaseApiService
  24. where TItemType : BaseItem
  25. {
  26. /// <summary>
  27. /// The _user manager
  28. /// </summary>
  29. protected readonly IUserManager UserManager;
  30. /// <summary>
  31. /// The library manager
  32. /// </summary>
  33. protected readonly ILibraryManager LibraryManager;
  34. protected readonly IUserDataRepository UserDataRepository;
  35. /// <summary>
  36. /// Initializes a new instance of the <see cref="BaseItemsByNameService{TItemType}" /> class.
  37. /// </summary>
  38. /// <param name="userManager">The user manager.</param>
  39. /// <param name="libraryManager">The library manager.</param>
  40. /// <param name="userDataRepository">The user data repository.</param>
  41. protected BaseItemsByNameService(IUserManager userManager, ILibraryManager libraryManager, IUserDataRepository userDataRepository)
  42. {
  43. UserManager = userManager;
  44. LibraryManager = libraryManager;
  45. UserDataRepository = userDataRepository;
  46. }
  47. /// <summary>
  48. /// Gets the specified request.
  49. /// </summary>
  50. /// <param name="request">The request.</param>
  51. /// <returns>Task{ItemsResult}.</returns>
  52. protected async Task<ItemsResult> GetResult(GetItemsByName request)
  53. {
  54. var user = UserManager.GetUserById(request.UserId);
  55. var item = string.IsNullOrEmpty(request.ParentId) ? user.RootFolder : DtoBuilder.GetItemByClientId(request.ParentId, UserManager, LibraryManager, user.Id);
  56. IEnumerable<BaseItem> items;
  57. if (item.IsFolder)
  58. {
  59. var folder = (Folder)item;
  60. items = request.Recursive ? folder.GetRecursiveChildren(user) : folder.GetChildren(user);
  61. }
  62. else
  63. {
  64. items = new[] { item };
  65. }
  66. items = FilterItems(request, items, user);
  67. var extractedItems = GetAllItems(request, items, user);
  68. extractedItems = FilterItems(request, extractedItems, user);
  69. extractedItems = SortItems(request, extractedItems);
  70. var ibnItemsArray = extractedItems.ToArray();
  71. IEnumerable<IbnStub<TItemType>> ibnItems = ibnItemsArray;
  72. var result = new ItemsResult
  73. {
  74. TotalRecordCount = ibnItemsArray.Length
  75. };
  76. if (request.StartIndex.HasValue || request.Limit.HasValue)
  77. {
  78. if (request.StartIndex.HasValue)
  79. {
  80. ibnItems = ibnItems.Skip(request.StartIndex.Value);
  81. }
  82. if (request.Limit.HasValue)
  83. {
  84. ibnItems = ibnItems.Take(request.Limit.Value);
  85. }
  86. }
  87. var fields = request.GetItemFields().ToList();
  88. var tasks = ibnItems.Select(i => GetDto(i, user, fields));
  89. var resultItems = await Task.WhenAll(tasks).ConfigureAwait(false);
  90. result.Items = resultItems.Where(i => i != null).ToArray();
  91. return result;
  92. }
  93. /// <summary>
  94. /// Filters the items.
  95. /// </summary>
  96. /// <param name="request">The request.</param>
  97. /// <param name="items">The items.</param>
  98. /// <param name="user">The user.</param>
  99. /// <returns>IEnumerable{IbnStub}.</returns>
  100. private IEnumerable<IbnStub<TItemType>> FilterItems(GetItemsByName request, IEnumerable<IbnStub<TItemType>> items, User user)
  101. {
  102. var filters = request.GetFilters().ToList();
  103. if (filters.Count == 0)
  104. {
  105. return items;
  106. }
  107. items = items.AsParallel();
  108. if (filters.Contains(ItemFilter.Dislikes))
  109. {
  110. items = items.Where(i =>
  111. {
  112. var userdata = i.GetUserItemData(UserDataRepository, user.Id).Result;
  113. return userdata != null && userdata.Likes.HasValue && !userdata.Likes.Value;
  114. });
  115. }
  116. if (filters.Contains(ItemFilter.Likes))
  117. {
  118. items = items.Where(i =>
  119. {
  120. var userdata = i.GetUserItemData(UserDataRepository, user.Id).Result;
  121. return userdata != null && userdata.Likes.HasValue && userdata.Likes.Value;
  122. });
  123. }
  124. if (filters.Contains(ItemFilter.IsFavorite))
  125. {
  126. items = items.Where(i =>
  127. {
  128. var userdata = i.GetUserItemData(UserDataRepository, user.Id).Result;
  129. return userdata != null && userdata.Likes.HasValue && userdata.IsFavorite;
  130. });
  131. }
  132. return items.AsEnumerable();
  133. }
  134. /// <summary>
  135. /// Sorts the items.
  136. /// </summary>
  137. /// <param name="request">The request.</param>
  138. /// <param name="items">The items.</param>
  139. /// <returns>IEnumerable{BaseItem}.</returns>
  140. private IEnumerable<IbnStub<TItemType>> SortItems(GetItemsByName request, IEnumerable<IbnStub<TItemType>> items)
  141. {
  142. if (string.Equals(request.SortBy, "SortName", StringComparison.OrdinalIgnoreCase))
  143. {
  144. if (request.SortOrder.HasValue && request.SortOrder.Value == Model.Entities.SortOrder.Descending)
  145. {
  146. items = items.OrderByDescending(i => i.Name);
  147. }
  148. else
  149. {
  150. items = items.OrderBy(i => i.Name);
  151. }
  152. }
  153. return items;
  154. }
  155. /// <summary>
  156. /// Filters the items.
  157. /// </summary>
  158. /// <param name="request">The request.</param>
  159. /// <param name="items">The items.</param>
  160. /// <param name="user">The user.</param>
  161. /// <returns>IEnumerable{BaseItem}.</returns>
  162. private IEnumerable<BaseItem> FilterItems(GetItemsByName request, IEnumerable<BaseItem> items, User user)
  163. {
  164. // Exclude item types
  165. if (!string.IsNullOrEmpty(request.ExcludeItemTypes))
  166. {
  167. var vals = request.ExcludeItemTypes.Split(',');
  168. items = items.Where(f => !vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
  169. }
  170. // Include item types
  171. if (!string.IsNullOrEmpty(request.IncludeItemTypes))
  172. {
  173. var vals = request.IncludeItemTypes.Split(',');
  174. items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase));
  175. }
  176. return items;
  177. }
  178. /// <summary>
  179. /// Gets all items.
  180. /// </summary>
  181. /// <param name="request">The request.</param>
  182. /// <param name="items">The items.</param>
  183. /// <param name="user">The user.</param>
  184. /// <returns>IEnumerable{Tuple{System.StringFunc{System.Int32}}}.</returns>
  185. protected abstract IEnumerable<IbnStub<TItemType>> GetAllItems(GetItemsByName request, IEnumerable<BaseItem> items, User user);
  186. /// <summary>
  187. /// Gets the dto.
  188. /// </summary>
  189. /// <param name="stub">The stub.</param>
  190. /// <param name="user">The user.</param>
  191. /// <param name="fields">The fields.</param>
  192. /// <returns>Task{DtoBaseItem}.</returns>
  193. private async Task<BaseItemDto> GetDto(IbnStub<TItemType> stub, User user, List<ItemFields> fields)
  194. {
  195. BaseItem item;
  196. try
  197. {
  198. item = await stub.GetItem().ConfigureAwait(false);
  199. }
  200. catch (IOException ex)
  201. {
  202. Logger.ErrorException("Error getting IBN item {0}", ex, stub.Name);
  203. return null;
  204. }
  205. var dto = await new DtoBuilder(Logger, LibraryManager, UserDataRepository).GetBaseItemDto(item, user, fields).ConfigureAwait(false);
  206. if (fields.Contains(ItemFields.ItemCounts))
  207. {
  208. var items = stub.Items;
  209. dto.ChildCount = items.Count;
  210. dto.RecentlyAddedItemCount = items.Count(i => i.IsRecentlyAdded(user));
  211. }
  212. return dto;
  213. }
  214. }
  215. /// <summary>
  216. /// Class GetItemsByName
  217. /// </summary>
  218. public class GetItemsByName : BaseItemsRequest, IReturn<ItemsResult>
  219. {
  220. /// <summary>
  221. /// What to sort the results by
  222. /// </summary>
  223. /// <value>The sort by.</value>
  224. [ApiMember(Name = "SortBy", Description = "Optional. Options: SortName", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
  225. public string SortBy { get; set; }
  226. }
  227. public class IbnStub<T>
  228. where T : BaseItem
  229. {
  230. private readonly Func<IEnumerable<BaseItem>> _childItemsFunction;
  231. private List<BaseItem> _childItems;
  232. private readonly Func<string,Task<T>> _itemFunction;
  233. private Task<T> _itemTask;
  234. public string Name;
  235. public BaseItem Item;
  236. private Task<UserItemData> _userData;
  237. public List<BaseItem> Items
  238. {
  239. get { return _childItems ?? (_childItems = _childItemsFunction().ToList()); }
  240. }
  241. public Task<T> GetItem()
  242. {
  243. return _itemTask ?? (_itemTask = _itemFunction(Name));
  244. }
  245. public async Task<UserItemData> GetUserItemData(IUserDataRepository repo, Guid userId)
  246. {
  247. var item = await GetItem().ConfigureAwait(false);
  248. if (_userData == null)
  249. {
  250. _userData = repo.GetUserData(userId, item.GetUserDataKey());
  251. }
  252. return await _userData.ConfigureAwait(false);
  253. }
  254. public IbnStub(string name, Func<IEnumerable<BaseItem>> childItems, Func<string,Task<T>> item)
  255. {
  256. Name = name;
  257. _childItemsFunction = childItems;
  258. _itemFunction = item;
  259. }
  260. }
  261. }