UserViewBuilder.cs 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828
  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, InternalItemsQuery 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. case CollectionType.MusicFavorites:
  149. return await GetMusicFavorites(parent, user, query).ConfigureAwait(false);
  150. case CollectionType.MusicFavoriteAlbums:
  151. return GetFavoriteAlbums(parent, user, query);
  152. case CollectionType.MusicFavoriteArtists:
  153. return GetFavoriteArtists(parent, user, query);
  154. case CollectionType.MusicFavoriteSongs:
  155. return GetFavoriteSongs(parent, user, query);
  156. default:
  157. return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), query);
  158. }
  159. }
  160. private int GetSpecialItemsLimit()
  161. {
  162. return 50;
  163. }
  164. private async Task<QueryResult<BaseItem>> GetMusicFolders(Folder parent, User user, InternalItemsQuery query)
  165. {
  166. if (query.Recursive)
  167. {
  168. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }), query);
  169. }
  170. var list = new List<BaseItem>();
  171. var category = "music";
  172. list.Add(await GetUserView(category, CollectionType.MusicLatest, user, "0", parent).ConfigureAwait(false));
  173. list.Add(await GetUserView(category, CollectionType.MusicAlbums, user, "1", parent).ConfigureAwait(false));
  174. list.Add(await GetUserView(category, CollectionType.MusicAlbumArtists, user, "2", parent).ConfigureAwait(false));
  175. list.Add(await GetUserView(category, CollectionType.MusicSongs, user, "3", parent).ConfigureAwait(false));
  176. //list.Add(await GetUserView(CollectionType.MusicArtists, user, "3", parent).ConfigureAwait(false));
  177. //list.Add(await GetUserView(CollectionType.MusicGenres, user, "5", parent).ConfigureAwait(false));
  178. list.Add(await GetUserView(category, CollectionType.MusicFavorites, user, "6", parent).ConfigureAwait(false));
  179. return GetResult(list, query);
  180. }
  181. private async Task<QueryResult<BaseItem>> GetMusicFavorites(Folder parent, User user, InternalItemsQuery query)
  182. {
  183. var list = new List<BaseItem>();
  184. var category = "music";
  185. list.Add(await GetUserView(category, CollectionType.MusicFavoriteAlbums, user, "0", parent).ConfigureAwait(false));
  186. list.Add(await GetUserView(category, CollectionType.MusicFavoriteArtists, user, "1", parent).ConfigureAwait(false));
  187. list.Add(await GetUserView(category, CollectionType.MusicFavoriteSongs, user, "2", parent).ConfigureAwait(false));
  188. return GetResult(list, query);
  189. }
  190. private QueryResult<BaseItem> GetMusicAlbumArtists(Folder parent, User user, InternalItemsQuery query)
  191. {
  192. var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
  193. .Where(i => !i.IsFolder)
  194. .OfType<IHasAlbumArtist>()
  195. .SelectMany(i => i.AlbumArtists)
  196. .Distinct(StringComparer.OrdinalIgnoreCase)
  197. .Select(i =>
  198. {
  199. try
  200. {
  201. return _libraryManager.GetArtist(i);
  202. }
  203. catch
  204. {
  205. // Already logged at lower levels
  206. return null;
  207. }
  208. })
  209. .Where(i => i != null);
  210. return GetResult(artists, query);
  211. }
  212. private QueryResult<BaseItem> GetMusicArtists(Folder parent, User user, InternalItemsQuery query)
  213. {
  214. var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
  215. .Where(i => !i.IsFolder)
  216. .OfType<IHasArtist>()
  217. .SelectMany(i => i.Artists)
  218. .Distinct(StringComparer.OrdinalIgnoreCase)
  219. .Select(i =>
  220. {
  221. try
  222. {
  223. return _libraryManager.GetArtist(i);
  224. }
  225. catch
  226. {
  227. // Already logged at lower levels
  228. return null;
  229. }
  230. })
  231. .Where(i => i != null);
  232. return GetResult(artists, query);
  233. }
  234. private QueryResult<BaseItem> GetFavoriteArtists(Folder parent, User user, InternalItemsQuery query)
  235. {
  236. var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
  237. .Where(i => !i.IsFolder)
  238. .OfType<IHasAlbumArtist>()
  239. .SelectMany(i => i.AlbumArtists)
  240. .Distinct(StringComparer.OrdinalIgnoreCase)
  241. .Select(i =>
  242. {
  243. try
  244. {
  245. return _libraryManager.GetArtist(i);
  246. }
  247. catch
  248. {
  249. // Already logged at lower levels
  250. return null;
  251. }
  252. })
  253. .Where(i => i != null && _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).IsFavorite);
  254. return GetResult(artists, query);
  255. }
  256. private QueryResult<BaseItem> GetMusicAlbums(Folder parent, User user, InternalItemsQuery query)
  257. {
  258. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is MusicAlbum), query);
  259. }
  260. private QueryResult<BaseItem> GetMusicSongs(Folder parent, User user, InternalItemsQuery query)
  261. {
  262. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is Audio.Audio), query);
  263. }
  264. private QueryResult<BaseItem> GetMusicLatest(Folder parent, User user, InternalItemsQuery query)
  265. {
  266. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  267. query.SortOrder = SortOrder.Descending;
  268. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is MusicVideo || i is Audio.Audio), GetSpecialItemsLimit(), query);
  269. }
  270. private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, InternalItemsQuery query)
  271. {
  272. if (query.Recursive)
  273. {
  274. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie || i is BoxSet), query);
  275. }
  276. var list = new List<BaseItem>();
  277. var category = "movies";
  278. list.Add(await GetUserView(category, CollectionType.MovieResume, user, "0", parent).ConfigureAwait(false));
  279. list.Add(await GetUserView(category, CollectionType.MovieLatest, user, "1", parent).ConfigureAwait(false));
  280. list.Add(await GetUserView(category, CollectionType.MovieMovies, user, "2", parent).ConfigureAwait(false));
  281. list.Add(await GetUserView(category, CollectionType.MovieCollections, user, "3", parent).ConfigureAwait(false));
  282. list.Add(await GetUserView(category, CollectionType.MovieFavorites, user, "4", parent).ConfigureAwait(false));
  283. //list.Add(await GetUserView(CollectionType.MovieGenres, user, "5", parent).ConfigureAwait(false));
  284. return GetResult(list, query);
  285. }
  286. private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query)
  287. {
  288. query.IsFavorite = true;
  289. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query);
  290. }
  291. private QueryResult<BaseItem> GetFavoriteSeries(Folder parent, User user, InternalItemsQuery query)
  292. {
  293. query.IsFavorite = true;
  294. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series), query);
  295. }
  296. private QueryResult<BaseItem> GetFavoriteEpisodes(Folder parent, User user, InternalItemsQuery query)
  297. {
  298. query.IsFavorite = true;
  299. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Episode), query);
  300. }
  301. private QueryResult<BaseItem> GetFavoriteSongs(Folder parent, User user, InternalItemsQuery query)
  302. {
  303. query.IsFavorite = true;
  304. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is Audio.Audio), query);
  305. }
  306. private QueryResult<BaseItem> GetFavoriteAlbums(Folder parent, User user, InternalItemsQuery query)
  307. {
  308. query.IsFavorite = true;
  309. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is MusicAlbum), query);
  310. }
  311. private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, InternalItemsQuery query)
  312. {
  313. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query);
  314. }
  315. private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, InternalItemsQuery query)
  316. {
  317. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is BoxSet), query);
  318. }
  319. private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query)
  320. {
  321. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  322. query.SortOrder = SortOrder.Descending;
  323. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query);
  324. }
  325. private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query)
  326. {
  327. query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
  328. query.SortOrder = SortOrder.Descending;
  329. query.IsResumable = true;
  330. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query);
  331. }
  332. private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, InternalItemsQuery query)
  333. {
  334. var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty })
  335. .Where(i => i is Movie)
  336. .SelectMany(i => i.Genres)
  337. .Distinct(StringComparer.OrdinalIgnoreCase)
  338. .Select(i =>
  339. {
  340. try
  341. {
  342. return _libraryManager.GetGenre(i);
  343. }
  344. catch
  345. {
  346. // Full exception logged at lower levels
  347. _logger.Error("Error getting genre");
  348. return null;
  349. }
  350. })
  351. .Where(i => i != null);
  352. return GetResult(genres, query);
  353. }
  354. private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, InternalItemsQuery query)
  355. {
  356. if (query.Recursive)
  357. {
  358. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series || i is Season || i is Episode), query);
  359. }
  360. var list = new List<BaseItem>();
  361. var category = "tvshows";
  362. list.Add(await GetUserView(category, CollectionType.TvResume, user, "0", parent).ConfigureAwait(false));
  363. list.Add(await GetUserView(category, CollectionType.TvNextUp, user, "1", parent).ConfigureAwait(false));
  364. list.Add(await GetUserView(category, CollectionType.TvLatest, user, "2", parent).ConfigureAwait(false));
  365. list.Add(await GetUserView(category, CollectionType.TvShowSeries, user, "3", parent).ConfigureAwait(false));
  366. list.Add(await GetUserView(category, CollectionType.TvFavoriteSeries, user, "4", parent).ConfigureAwait(false));
  367. list.Add(await GetUserView(category, CollectionType.TvFavoriteEpisodes, user, "5", parent).ConfigureAwait(false));
  368. //list.Add(await GetUserView(CollectionType.TvGenres, user, "5", parent).ConfigureAwait(false));
  369. return GetResult(list, query);
  370. }
  371. private async Task<QueryResult<BaseItem>> GetGameView(User user, Folder parent, InternalItemsQuery query)
  372. {
  373. if (query.Recursive)
  374. {
  375. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }), query);
  376. }
  377. var list = new List<BaseItem>();
  378. var category = "games";
  379. list.Add(await GetUserView(category, CollectionType.LatestGames, user, "0", parent).ConfigureAwait(false));
  380. list.Add(await GetUserView(category, CollectionType.RecentlyPlayedGames, user, "1", parent).ConfigureAwait(false));
  381. list.Add(await GetUserView(category, CollectionType.GameFavorites, user, "2", parent).ConfigureAwait(false));
  382. list.Add(await GetUserView(category, CollectionType.GameSystems, user, "3", parent).ConfigureAwait(false));
  383. //list.Add(await GetUserView(CollectionType.GameGenres, user, "4", parent).ConfigureAwait(false));
  384. return GetResult(list, query);
  385. }
  386. private QueryResult<BaseItem> GetLatestGames(Folder parent, User user, InternalItemsQuery query)
  387. {
  388. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  389. query.SortOrder = SortOrder.Descending;
  390. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query);
  391. }
  392. private QueryResult<BaseItem> GetRecentlyPlayedGames(Folder parent, User user, InternalItemsQuery query)
  393. {
  394. query.IsPlayed = true;
  395. query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
  396. query.SortOrder = SortOrder.Descending;
  397. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query);
  398. }
  399. private QueryResult<BaseItem> GetFavoriteGames(Folder parent, User user, InternalItemsQuery query)
  400. {
  401. query.IsFavorite = true;
  402. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), query);
  403. }
  404. private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query)
  405. {
  406. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  407. query.SortOrder = SortOrder.Descending;
  408. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query);
  409. }
  410. private QueryResult<BaseItem> GetTvNextUp(Folder parent, InternalItemsQuery query)
  411. {
  412. var parentFolders = GetMediaFolders(parent, query.User, new[] { CollectionType.TvShows, string.Empty });
  413. var result = _tvSeriesManager.GetNextUp(new NextUpQuery
  414. {
  415. Limit = query.Limit,
  416. StartIndex = query.StartIndex,
  417. UserId = query.User.Id.ToString("N")
  418. }, parentFolders);
  419. return result;
  420. }
  421. private QueryResult<BaseItem> GetTvResume(Folder parent, User user, InternalItemsQuery query)
  422. {
  423. query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
  424. query.SortOrder = SortOrder.Descending;
  425. query.IsResumable = true;
  426. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query);
  427. }
  428. private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, InternalItemsQuery query)
  429. {
  430. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Series>(), query);
  431. }
  432. private QueryResult<BaseItem> GetTvGenres(Folder parent, User user, InternalItemsQuery query)
  433. {
  434. var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty })
  435. .OfType<Series>()
  436. .SelectMany(i => i.Genres)
  437. .Distinct(StringComparer.OrdinalIgnoreCase)
  438. .Select(i =>
  439. {
  440. try
  441. {
  442. return _libraryManager.GetGenre(i);
  443. }
  444. catch
  445. {
  446. // Full exception logged at lower levels
  447. _logger.Error("Error getting genre");
  448. return null;
  449. }
  450. })
  451. .Where(i => i != null);
  452. return GetResult(genres, query);
  453. }
  454. private QueryResult<BaseItem> GetGameSystems(Folder parent, User user, InternalItemsQuery query)
  455. {
  456. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<GameSystem>(), query);
  457. }
  458. private QueryResult<BaseItem> GetGameGenres(Folder parent, User user, InternalItemsQuery query)
  459. {
  460. var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Games })
  461. .OfType<Game>()
  462. .SelectMany(i => i.Genres)
  463. .Distinct(StringComparer.OrdinalIgnoreCase)
  464. .Select(i =>
  465. {
  466. try
  467. {
  468. return _libraryManager.GetGameGenre(i);
  469. }
  470. catch
  471. {
  472. // Full exception logged at lower levels
  473. _logger.Error("Error getting game genre");
  474. return null;
  475. }
  476. })
  477. .Where(i => i != null);
  478. return GetResult(genres, query);
  479. }
  480. private QueryResult<BaseItem> GetResult<T>(QueryResult<T> result)
  481. where T : BaseItem
  482. {
  483. return new QueryResult<BaseItem>
  484. {
  485. Items = result.Items,
  486. TotalRecordCount = result.TotalRecordCount
  487. };
  488. }
  489. private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
  490. InternalItemsQuery query)
  491. where T : BaseItem
  492. {
  493. return GetResult(items, null, query);
  494. }
  495. private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
  496. int? totalRecordLimit,
  497. InternalItemsQuery query)
  498. where T : BaseItem
  499. {
  500. return SortAndFilter(items, totalRecordLimit, query, _libraryManager, _userDataManager);
  501. }
  502. public static QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items,
  503. int? totalRecordLimit,
  504. InternalItemsQuery query,
  505. ILibraryManager libraryManager,
  506. IUserDataManager userDataManager)
  507. {
  508. var user = query.User;
  509. items = items.Where(i => Filter(i, user, query, userDataManager));
  510. return Sort(items, totalRecordLimit, query, libraryManager);
  511. }
  512. public static QueryResult<BaseItem> Sort(IEnumerable<BaseItem> items,
  513. int? totalRecordLimit,
  514. InternalItemsQuery query,
  515. ILibraryManager libraryManager)
  516. {
  517. var user = query.User;
  518. items = libraryManager.ReplaceVideosWithPrimaryVersions(items);
  519. if (query.SortBy.Length > 0)
  520. {
  521. items = libraryManager.Sort(items, user, query.SortBy, query.SortOrder);
  522. }
  523. var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
  524. var totalCount = itemsArray.Length;
  525. if (query.Limit.HasValue)
  526. {
  527. itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
  528. }
  529. else if (query.StartIndex.HasValue)
  530. {
  531. itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
  532. }
  533. return new QueryResult<BaseItem>
  534. {
  535. TotalRecordCount = totalCount,
  536. Items = itemsArray
  537. };
  538. }
  539. private static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager)
  540. {
  541. if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
  542. {
  543. return false;
  544. }
  545. if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase))
  546. {
  547. return false;
  548. }
  549. if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase))
  550. {
  551. return false;
  552. }
  553. if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
  554. {
  555. return false;
  556. }
  557. if (query.Filter != null && !query.Filter(item, user))
  558. {
  559. return false;
  560. }
  561. UserItemData userData = null;
  562. if (query.IsLiked.HasValue)
  563. {
  564. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  565. if (!userData.Likes.HasValue || userData.Likes != query.IsLiked.Value)
  566. {
  567. return false;
  568. }
  569. }
  570. if (query.IsFavoriteOrLiked.HasValue)
  571. {
  572. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  573. var isFavoriteOrLiked = userData.IsFavorite || (userData.Likes ?? false);
  574. if (isFavoriteOrLiked != query.IsFavoriteOrLiked.Value)
  575. {
  576. return false;
  577. }
  578. }
  579. if (query.IsFavorite.HasValue)
  580. {
  581. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  582. if (userData.IsFavorite != query.IsFavorite.Value)
  583. {
  584. return false;
  585. }
  586. }
  587. if (query.IsResumable.HasValue)
  588. {
  589. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  590. var isResumable = userData.PlaybackPositionTicks > 0;
  591. if (isResumable != query.IsResumable.Value)
  592. {
  593. return false;
  594. }
  595. }
  596. if (query.IsPlayed.HasValue)
  597. {
  598. if (item.IsPlayed(user) != query.IsPlayed.Value)
  599. {
  600. return false;
  601. }
  602. }
  603. return true;
  604. }
  605. private IEnumerable<Folder> GetMediaFolders(User user)
  606. {
  607. var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
  608. return user.RootFolder
  609. .GetChildren(user, true, true)
  610. .OfType<Folder>()
  611. .Where(i => !excludeFolderIds.Contains(i.Id) && !UserView.IsExcludedFromGrouping(i));
  612. }
  613. private IEnumerable<Folder> GetMediaFolders(User user, string[] viewTypes)
  614. {
  615. return GetMediaFolders(user)
  616. .Where(i =>
  617. {
  618. var folder = i as ICollectionFolder;
  619. return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
  620. });
  621. }
  622. private IEnumerable<Folder> GetMediaFolders(Folder parent, User user, string[] viewTypes)
  623. {
  624. if (parent == null || parent is UserView)
  625. {
  626. return GetMediaFolders(user, viewTypes);
  627. }
  628. return new[] { parent };
  629. }
  630. private IEnumerable<BaseItem> GetRecursiveChildren(Folder parent, User user, string[] viewTypes)
  631. {
  632. if (parent == null || parent is UserView)
  633. {
  634. return GetMediaFolders(user, viewTypes).SelectMany(i => i.GetRecursiveChildren(user));
  635. }
  636. return parent.GetRecursiveChildren(user);
  637. }
  638. private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user)
  639. {
  640. var list = new List<BaseItem>();
  641. list.Add(await _userViewManager.GetUserView("livetv", CollectionType.LiveTvNowPlaying, user, "0", CancellationToken.None).ConfigureAwait(false));
  642. list.Add(await _userViewManager.GetUserView("livetv", CollectionType.LiveTvChannels, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
  643. list.Add(await _userViewManager.GetUserView("livetv", CollectionType.LiveTvRecordingGroups, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
  644. return list;
  645. }
  646. private async Task<UserView> GetUserView(string category, string type, User user, string sortName, Folder parent)
  647. {
  648. var view = await _userViewManager.GetUserView(category, type, user, sortName, CancellationToken.None)
  649. .ConfigureAwait(false);
  650. if (parent.Id != view.ParentId)
  651. {
  652. view.ParentId = parent.Id;
  653. await view.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None)
  654. .ConfigureAwait(false);
  655. }
  656. return view;
  657. }
  658. }
  659. }