UserViewBuilder.cs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733
  1. using MediaBrowser.Controller.Channels;
  2. using MediaBrowser.Controller.Entities.Audio;
  3. using MediaBrowser.Controller.Entities.Movies;
  4. using MediaBrowser.Controller.Entities.TV;
  5. using MediaBrowser.Controller.Library;
  6. using MediaBrowser.Controller.LiveTv;
  7. using MediaBrowser.Controller.TV;
  8. using MediaBrowser.Model.Channels;
  9. using MediaBrowser.Model.Entities;
  10. using MediaBrowser.Model.LiveTv;
  11. using MediaBrowser.Model.Logging;
  12. using MediaBrowser.Model.Querying;
  13. using System;
  14. using System.Collections.Generic;
  15. using System.Linq;
  16. using System.Threading;
  17. using System.Threading.Tasks;
  18. namespace MediaBrowser.Controller.Entities
  19. {
  20. public class UserViewBuilder
  21. {
  22. private readonly IChannelManager _channelManager;
  23. private readonly ILiveTvManager _liveTvManager;
  24. private readonly IUserViewManager _userViewManager;
  25. private readonly ILibraryManager _libraryManager;
  26. private readonly ILogger _logger;
  27. private readonly IUserDataManager _userDataManager;
  28. private readonly ITVSeriesManager _tvSeriesManager;
  29. public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager)
  30. {
  31. _userViewManager = userViewManager;
  32. _liveTvManager = liveTvManager;
  33. _channelManager = channelManager;
  34. _libraryManager = libraryManager;
  35. _logger = logger;
  36. _userDataManager = userDataManager;
  37. _tvSeriesManager = tvSeriesManager;
  38. }
  39. public async Task<QueryResult<BaseItem>> GetUserItems(Folder parent, string viewType, UserItemsQuery query)
  40. {
  41. var user = query.User;
  42. switch (viewType)
  43. {
  44. case CollectionType.Channels:
  45. {
  46. var result = await _channelManager.GetChannelsInternal(new ChannelQuery
  47. {
  48. UserId = user.Id.ToString("N"),
  49. Limit = query.Limit,
  50. StartIndex = query.StartIndex
  51. }, CancellationToken.None).ConfigureAwait(false);
  52. return GetResult(result);
  53. }
  54. case CollectionType.LiveTvChannels:
  55. {
  56. var result = await _liveTvManager.GetInternalChannels(new LiveTvChannelQuery
  57. {
  58. UserId = query.User.Id.ToString("N"),
  59. Limit = query.Limit,
  60. StartIndex = query.StartIndex
  61. }, CancellationToken.None).ConfigureAwait(false);
  62. return GetResult(result);
  63. }
  64. case CollectionType.LiveTvNowPlaying:
  65. {
  66. var result = await _liveTvManager.GetRecommendedProgramsInternal(new RecommendedProgramQuery
  67. {
  68. UserId = query.User.Id.ToString("N"),
  69. Limit = query.Limit,
  70. IsAiring = true
  71. }, CancellationToken.None).ConfigureAwait(false);
  72. return GetResult(result);
  73. }
  74. case CollectionType.LiveTvRecordingGroups:
  75. {
  76. var result = await _liveTvManager.GetInternalRecordings(new RecordingQuery
  77. {
  78. UserId = query.User.Id.ToString("N"),
  79. Status = RecordingStatus.Completed,
  80. Limit = query.Limit,
  81. StartIndex = query.StartIndex
  82. }, CancellationToken.None).ConfigureAwait(false);
  83. return GetResult(result);
  84. }
  85. case CollectionType.LiveTv:
  86. {
  87. var result = await GetLiveTvFolders(user).ConfigureAwait(false);
  88. return GetResult(result, query);
  89. }
  90. case CollectionType.Folders:
  91. return GetResult(user.RootFolder.GetChildren(user, true), query);
  92. case CollectionType.Games:
  93. return await GetGameView(user, parent, query).ConfigureAwait(false);
  94. case CollectionType.BoxSets:
  95. return GetResult(GetMediaFolders(user).SelectMany(i => i.GetRecursiveChildren(user)).OfType<BoxSet>(), query);
  96. case CollectionType.TvShows:
  97. return await GetTvView(parent, user, query).ConfigureAwait(false);
  98. case CollectionType.Music:
  99. return await GetMusicFolders(parent, user, query).ConfigureAwait(false);
  100. case CollectionType.Movies:
  101. return await GetMovieFolders(parent, user, query).ConfigureAwait(false);
  102. case CollectionType.GameGenres:
  103. return GetGameGenres(parent, user, query);
  104. case CollectionType.GameSystems:
  105. return GetGameSystems(parent, user, query);
  106. case CollectionType.LatestGames:
  107. return GetLatestGames(parent, user, query);
  108. case CollectionType.RecentlyPlayedGames:
  109. return GetRecentlyPlayedGames(parent, user, query);
  110. case CollectionType.GameFavorites:
  111. return GetFavoriteGames(parent, user, query);
  112. case CollectionType.TvShowSeries:
  113. return GetTvSeries(parent, user, query);
  114. case CollectionType.TvGenres:
  115. return GetTvGenres(parent, user, query);
  116. case CollectionType.TvResume:
  117. return GetTvResume(parent, user, query);
  118. case CollectionType.TvNextUp:
  119. return GetTvNextUp(parent, query);
  120. case CollectionType.TvLatest:
  121. return GetTvLatest(parent, user, query);
  122. case CollectionType.MovieFavorites:
  123. return GetFavoriteMovies(parent, user, query);
  124. case CollectionType.MovieLatest:
  125. return GetMovieLatest(parent, user, query);
  126. case CollectionType.MovieGenres:
  127. return GetMovieGenres(parent, user, query);
  128. case CollectionType.MovieResume:
  129. return GetMovieResume(parent, user, query);
  130. case CollectionType.MovieMovies:
  131. return GetMovieMovies(parent, user, query);
  132. case CollectionType.MovieCollections:
  133. return GetMovieCollections(parent, user, query);
  134. case CollectionType.MusicLatest:
  135. return GetMusicLatest(parent, user, query);
  136. case CollectionType.MusicAlbums:
  137. return GetMusicAlbums(parent, user, query);
  138. case CollectionType.MusicAlbumArtists:
  139. return GetMusicAlbumArtists(parent, user, query);
  140. case CollectionType.MusicArtists:
  141. return GetMusicArtists(parent, user, query);
  142. case CollectionType.MusicSongs:
  143. return GetMusicSongs(parent, user, query);
  144. case CollectionType.TvFavoriteEpisodes:
  145. return GetFavoriteEpisodes(parent, user, query);
  146. case CollectionType.TvFavoriteSeries:
  147. return GetFavoriteSeries(parent, user, query);
  148. default:
  149. return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), query);
  150. }
  151. }
  152. private int GetSpecialItemsLimit()
  153. {
  154. return 50;
  155. }
  156. private async Task<QueryResult<BaseItem>> GetMusicFolders(Folder parent, User user, UserItemsQuery query)
  157. {
  158. if (query.Recursive)
  159. {
  160. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }), query);
  161. }
  162. var list = new List<BaseItem>();
  163. var category = "music";
  164. list.Add(await GetUserView(category, CollectionType.MusicLatest, user, "0", parent).ConfigureAwait(false));
  165. list.Add(await GetUserView(category, CollectionType.MusicAlbums, user, "1", parent).ConfigureAwait(false));
  166. list.Add(await GetUserView(category, CollectionType.MusicAlbumArtists, user, "2", parent).ConfigureAwait(false));
  167. list.Add(await GetUserView(category, CollectionType.MusicSongs, user, "3", parent).ConfigureAwait(false));
  168. //list.Add(await GetUserView(CollectionType.MusicArtists, user, "3", parent).ConfigureAwait(false));
  169. //list.Add(await GetUserView(CollectionType.MusicGenres, user, "5", parent).ConfigureAwait(false));
  170. return GetResult(list, query);
  171. }
  172. private QueryResult<BaseItem> GetMusicAlbumArtists(Folder parent, User user, UserItemsQuery query)
  173. {
  174. var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music })
  175. .Where(i => !i.IsFolder)
  176. .OfType<IHasAlbumArtist>()
  177. .SelectMany(i => i.AlbumArtists)
  178. .Distinct(StringComparer.OrdinalIgnoreCase)
  179. .Select(i =>
  180. {
  181. try
  182. {
  183. return _libraryManager.GetArtist(i);
  184. }
  185. catch
  186. {
  187. // Already logged at lower levels
  188. return null;
  189. }
  190. })
  191. .Where(i => i != null);
  192. return GetResult(artists, query);
  193. }
  194. private QueryResult<BaseItem> GetMusicArtists(Folder parent, User user, UserItemsQuery query)
  195. {
  196. var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music })
  197. .Where(i => !i.IsFolder)
  198. .OfType<IHasArtist>()
  199. .SelectMany(i => i.Artists)
  200. .Distinct(StringComparer.OrdinalIgnoreCase)
  201. .Select(i =>
  202. {
  203. try
  204. {
  205. return _libraryManager.GetArtist(i);
  206. }
  207. catch
  208. {
  209. // Already logged at lower levels
  210. return null;
  211. }
  212. })
  213. .Where(i => i != null);
  214. return GetResult(artists, query);
  215. }
  216. private QueryResult<BaseItem> GetMusicAlbums(Folder parent, User user, UserItemsQuery query)
  217. {
  218. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is MusicAlbum), query);
  219. }
  220. private QueryResult<BaseItem> GetMusicSongs(Folder parent, User user, UserItemsQuery query)
  221. {
  222. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is Audio.Audio), query);
  223. }
  224. private QueryResult<BaseItem> GetMusicLatest(Folder parent, User user, UserItemsQuery query)
  225. {
  226. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  227. query.SortOrder = SortOrder.Descending;
  228. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is MusicVideo || i is Audio.Audio), GetSpecialItemsLimit(), query);
  229. }
  230. private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, UserItemsQuery query)
  231. {
  232. if (query.Recursive)
  233. {
  234. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie || i is BoxSet), query);
  235. }
  236. var list = new List<BaseItem>();
  237. var category = "movies";
  238. list.Add(await GetUserView(category, CollectionType.MovieResume, user, "0", parent).ConfigureAwait(false));
  239. list.Add(await GetUserView(category, CollectionType.MovieLatest, user, "1", parent).ConfigureAwait(false));
  240. list.Add(await GetUserView(category, CollectionType.MovieMovies, user, "2", parent).ConfigureAwait(false));
  241. list.Add(await GetUserView(category, CollectionType.MovieCollections, user, "3", parent).ConfigureAwait(false));
  242. list.Add(await GetUserView(category, CollectionType.MovieFavorites, user, "4", parent).ConfigureAwait(false));
  243. //list.Add(await GetUserView(CollectionType.MovieGenres, user, "5", parent).ConfigureAwait(false));
  244. return GetResult(list, query);
  245. }
  246. private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, UserItemsQuery query)
  247. {
  248. query.IsFavorite = true;
  249. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query);
  250. }
  251. private QueryResult<BaseItem> GetFavoriteSeries(Folder parent, User user, UserItemsQuery query)
  252. {
  253. query.IsFavorite = true;
  254. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series), query);
  255. }
  256. private QueryResult<BaseItem> GetFavoriteEpisodes(Folder parent, User user, UserItemsQuery query)
  257. {
  258. query.IsFavorite = true;
  259. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Episode), query);
  260. }
  261. private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, UserItemsQuery query)
  262. {
  263. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query);
  264. }
  265. private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, UserItemsQuery query)
  266. {
  267. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is BoxSet), query);
  268. }
  269. private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, UserItemsQuery query)
  270. {
  271. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  272. query.SortOrder = SortOrder.Descending;
  273. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query);
  274. }
  275. private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, UserItemsQuery query)
  276. {
  277. query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
  278. query.SortOrder = SortOrder.Descending;
  279. query.IsResumable = true;
  280. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query);
  281. }
  282. private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, UserItemsQuery query)
  283. {
  284. var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty })
  285. .Where(i => i is Movie)
  286. .SelectMany(i => i.Genres)
  287. .Distinct(StringComparer.OrdinalIgnoreCase)
  288. .Select(i =>
  289. {
  290. try
  291. {
  292. return _libraryManager.GetGenre(i);
  293. }
  294. catch
  295. {
  296. // Full exception logged at lower levels
  297. _logger.Error("Error getting genre");
  298. return null;
  299. }
  300. })
  301. .Where(i => i != null);
  302. return GetResult(genres, query);
  303. }
  304. private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, UserItemsQuery query)
  305. {
  306. if (query.Recursive)
  307. {
  308. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series || i is Season || i is Episode), query);
  309. }
  310. var list = new List<BaseItem>();
  311. var category = "tv";
  312. list.Add(await GetUserView(category, CollectionType.TvResume, user, "0", parent).ConfigureAwait(false));
  313. list.Add(await GetUserView(category, CollectionType.TvNextUp, user, "1", parent).ConfigureAwait(false));
  314. list.Add(await GetUserView(category, CollectionType.TvLatest, user, "2", parent).ConfigureAwait(false));
  315. list.Add(await GetUserView(category, CollectionType.TvShowSeries, user, "3", parent).ConfigureAwait(false));
  316. list.Add(await GetUserView(category, CollectionType.TvFavoriteSeries, user, "4", parent).ConfigureAwait(false));
  317. list.Add(await GetUserView(category, CollectionType.TvFavoriteEpisodes, user, "5", parent).ConfigureAwait(false));
  318. //list.Add(await GetUserView(CollectionType.TvGenres, user, "5", parent).ConfigureAwait(false));
  319. return GetResult(list, query);
  320. }
  321. private async Task<QueryResult<BaseItem>> GetGameView(User user, Folder parent, UserItemsQuery query)
  322. {
  323. if (query.Recursive)
  324. {
  325. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }), query);
  326. }
  327. var list = new List<BaseItem>();
  328. var category = "games";
  329. list.Add(await GetUserView(category, CollectionType.LatestGames, user, "0", parent).ConfigureAwait(false));
  330. list.Add(await GetUserView(category, CollectionType.RecentlyPlayedGames, user, "1", parent).ConfigureAwait(false));
  331. list.Add(await GetUserView(category, CollectionType.GameFavorites, user, "2", parent).ConfigureAwait(false));
  332. list.Add(await GetUserView(category, CollectionType.GameSystems, user, "3", parent).ConfigureAwait(false));
  333. //list.Add(await GetUserView(CollectionType.GameGenres, user, "4", parent).ConfigureAwait(false));
  334. return GetResult(list, query);
  335. }
  336. private QueryResult<BaseItem> GetLatestGames(Folder parent, User user, UserItemsQuery query)
  337. {
  338. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  339. query.SortOrder = SortOrder.Descending;
  340. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query);
  341. }
  342. private QueryResult<BaseItem> GetRecentlyPlayedGames(Folder parent, User user, UserItemsQuery query)
  343. {
  344. query.IsPlayed = true;
  345. query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
  346. query.SortOrder = SortOrder.Descending;
  347. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query);
  348. }
  349. private QueryResult<BaseItem> GetFavoriteGames(Folder parent, User user, UserItemsQuery query)
  350. {
  351. query.IsFavorite = true;
  352. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), query);
  353. }
  354. private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, UserItemsQuery query)
  355. {
  356. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  357. query.SortOrder = SortOrder.Descending;
  358. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query);
  359. }
  360. private QueryResult<BaseItem> GetTvNextUp(Folder parent, UserItemsQuery query)
  361. {
  362. var parentFolders = GetMediaFolders(parent, query.User, new[] { CollectionType.TvShows, string.Empty });
  363. var result = _tvSeriesManager.GetNextUp(new NextUpQuery
  364. {
  365. Limit = query.Limit,
  366. StartIndex = query.StartIndex,
  367. UserId = query.User.Id.ToString("N")
  368. }, parentFolders);
  369. return result;
  370. }
  371. private QueryResult<BaseItem> GetTvResume(Folder parent, User user, UserItemsQuery query)
  372. {
  373. query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
  374. query.SortOrder = SortOrder.Descending;
  375. query.IsResumable = true;
  376. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query);
  377. }
  378. private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, UserItemsQuery query)
  379. {
  380. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Series>(), query);
  381. }
  382. private QueryResult<BaseItem> GetTvGenres(Folder parent, User user, UserItemsQuery query)
  383. {
  384. var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty })
  385. .OfType<Series>()
  386. .SelectMany(i => i.Genres)
  387. .Distinct(StringComparer.OrdinalIgnoreCase)
  388. .Select(i =>
  389. {
  390. try
  391. {
  392. return _libraryManager.GetGenre(i);
  393. }
  394. catch
  395. {
  396. // Full exception logged at lower levels
  397. _logger.Error("Error getting genre");
  398. return null;
  399. }
  400. })
  401. .Where(i => i != null);
  402. return GetResult(genres, query);
  403. }
  404. private QueryResult<BaseItem> GetGameSystems(Folder parent, User user, UserItemsQuery query)
  405. {
  406. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<GameSystem>(), query);
  407. }
  408. private QueryResult<BaseItem> GetGameGenres(Folder parent, User user, UserItemsQuery query)
  409. {
  410. var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Games })
  411. .OfType<Game>()
  412. .SelectMany(i => i.Genres)
  413. .Distinct(StringComparer.OrdinalIgnoreCase)
  414. .Select(i =>
  415. {
  416. try
  417. {
  418. return _libraryManager.GetGameGenre(i);
  419. }
  420. catch
  421. {
  422. // Full exception logged at lower levels
  423. _logger.Error("Error getting game genre");
  424. return null;
  425. }
  426. })
  427. .Where(i => i != null);
  428. return GetResult(genres, query);
  429. }
  430. private QueryResult<BaseItem> GetResult<T>(QueryResult<T> result)
  431. where T : BaseItem
  432. {
  433. return new QueryResult<BaseItem>
  434. {
  435. Items = result.Items,
  436. TotalRecordCount = result.TotalRecordCount
  437. };
  438. }
  439. private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
  440. UserItemsQuery query)
  441. where T : BaseItem
  442. {
  443. return GetResult(items, null, query);
  444. }
  445. private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
  446. int? totalRecordLimit,
  447. UserItemsQuery query)
  448. where T : BaseItem
  449. {
  450. return SortAndFilter(items, totalRecordLimit, query, _libraryManager, _userDataManager);
  451. }
  452. public static QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items,
  453. int? totalRecordLimit,
  454. UserItemsQuery query,
  455. ILibraryManager libraryManager,
  456. IUserDataManager userDataManager)
  457. {
  458. var user = query.User;
  459. items = items.Where(i => Filter(i, user, query, userDataManager));
  460. return Sort(items, totalRecordLimit, query, libraryManager);
  461. }
  462. public static QueryResult<BaseItem> Sort(IEnumerable<BaseItem> items,
  463. int? totalRecordLimit,
  464. UserItemsQuery query,
  465. ILibraryManager libraryManager)
  466. {
  467. var user = query.User;
  468. items = libraryManager.ReplaceVideosWithPrimaryVersions(items);
  469. if (query.SortBy.Length > 0)
  470. {
  471. items = libraryManager.Sort(items, user, query.SortBy, query.SortOrder);
  472. }
  473. var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
  474. var totalCount = itemsArray.Length;
  475. if (query.Limit.HasValue)
  476. {
  477. itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
  478. }
  479. else if (query.StartIndex.HasValue)
  480. {
  481. itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
  482. }
  483. return new QueryResult<BaseItem>
  484. {
  485. TotalRecordCount = totalCount,
  486. Items = itemsArray
  487. };
  488. }
  489. private static bool Filter(BaseItem item, User user, UserItemsQuery query, IUserDataManager userDataManager)
  490. {
  491. if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
  492. {
  493. return false;
  494. }
  495. if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
  496. {
  497. return false;
  498. }
  499. if (query.Filter != null && !query.Filter(item, user))
  500. {
  501. return false;
  502. }
  503. UserItemData userData = null;
  504. if (query.IsFavorite.HasValue)
  505. {
  506. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  507. if (userData.IsFavorite != query.IsFavorite.Value)
  508. {
  509. return false;
  510. }
  511. }
  512. if (query.IsResumable.HasValue)
  513. {
  514. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  515. var isResumable = userData.PlaybackPositionTicks > 0;
  516. if (isResumable != query.IsResumable.Value)
  517. {
  518. return false;
  519. }
  520. }
  521. if (query.IsPlayed.HasValue)
  522. {
  523. if (item.IsPlayed(user) != query.IsPlayed.Value)
  524. {
  525. return false;
  526. }
  527. }
  528. return true;
  529. }
  530. private IEnumerable<Folder> GetMediaFolders(User user)
  531. {
  532. var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
  533. return user.RootFolder
  534. .GetChildren(user, true, true)
  535. .OfType<Folder>()
  536. .Where(i => !excludeFolderIds.Contains(i.Id) && !UserView.IsExcludedFromGrouping(i));
  537. }
  538. private IEnumerable<Folder> GetMediaFolders(User user, string[] viewTypes)
  539. {
  540. return GetMediaFolders(user)
  541. .Where(i =>
  542. {
  543. var folder = i as ICollectionFolder;
  544. return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
  545. });
  546. }
  547. private IEnumerable<Folder> GetMediaFolders(Folder parent, User user, string[] viewTypes)
  548. {
  549. if (parent == null || parent is UserView)
  550. {
  551. return GetMediaFolders(user, viewTypes);
  552. }
  553. return new[] { parent };
  554. }
  555. private IEnumerable<BaseItem> GetRecursiveChildren(Folder parent, User user, string[] viewTypes)
  556. {
  557. if (parent == null || parent is UserView)
  558. {
  559. return GetMediaFolders(user, viewTypes).SelectMany(i => i.GetRecursiveChildren(user));
  560. }
  561. return parent.GetRecursiveChildren(user);
  562. }
  563. private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user)
  564. {
  565. var list = new List<BaseItem>();
  566. list.Add(await _userViewManager.GetUserView("livetv", CollectionType.LiveTvNowPlaying, user, "0", CancellationToken.None).ConfigureAwait(false));
  567. list.Add(await _userViewManager.GetUserView("livetv", CollectionType.LiveTvChannels, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
  568. list.Add(await _userViewManager.GetUserView("livetv", CollectionType.LiveTvRecordingGroups, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
  569. return list;
  570. }
  571. private async Task<UserView> GetUserView(string category, string type, User user, string sortName, Folder parent)
  572. {
  573. var view = await _userViewManager.GetUserView(category, type, user, sortName, CancellationToken.None)
  574. .ConfigureAwait(false);
  575. if (parent.Id != view.ParentId)
  576. {
  577. view.ParentId = parent.Id;
  578. await view.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None)
  579. .ConfigureAwait(false);
  580. }
  581. return view;
  582. }
  583. }
  584. }