UserViewBuilder.cs 54 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554
  1. using MediaBrowser.Controller.Channels;
  2. using MediaBrowser.Controller.Collections;
  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.LiveTv;
  8. using MediaBrowser.Controller.Providers;
  9. using MediaBrowser.Controller.TV;
  10. using MediaBrowser.Model.Channels;
  11. using MediaBrowser.Model.Entities;
  12. using MediaBrowser.Model.LiveTv;
  13. using MediaBrowser.Model.Logging;
  14. using MediaBrowser.Model.Querying;
  15. using System;
  16. using System.Collections.Generic;
  17. using System.IO;
  18. using System.Linq;
  19. using System.Threading;
  20. using System.Threading.Tasks;
  21. namespace MediaBrowser.Controller.Entities
  22. {
  23. public class UserViewBuilder
  24. {
  25. private readonly IChannelManager _channelManager;
  26. private readonly ILiveTvManager _liveTvManager;
  27. private readonly IUserViewManager _userViewManager;
  28. private readonly ILibraryManager _libraryManager;
  29. private readonly ILogger _logger;
  30. private readonly IUserDataManager _userDataManager;
  31. private readonly ITVSeriesManager _tvSeriesManager;
  32. private readonly ICollectionManager _collectionManager;
  33. public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, ICollectionManager collectionManager)
  34. {
  35. _userViewManager = userViewManager;
  36. _liveTvManager = liveTvManager;
  37. _channelManager = channelManager;
  38. _libraryManager = libraryManager;
  39. _logger = logger;
  40. _userDataManager = userDataManager;
  41. _tvSeriesManager = tvSeriesManager;
  42. _collectionManager = collectionManager;
  43. }
  44. public async Task<QueryResult<BaseItem>> GetUserItems(Folder parent, string viewType, InternalItemsQuery query)
  45. {
  46. var user = query.User;
  47. switch (viewType)
  48. {
  49. case CollectionType.Channels:
  50. {
  51. var result = await _channelManager.GetChannelsInternal(new ChannelQuery
  52. {
  53. UserId = user.Id.ToString("N"),
  54. Limit = query.Limit,
  55. StartIndex = query.StartIndex
  56. }, CancellationToken.None).ConfigureAwait(false);
  57. return GetResult(result);
  58. }
  59. case SpecialFolder.LiveTvChannels:
  60. {
  61. var result = await _liveTvManager.GetInternalChannels(new LiveTvChannelQuery
  62. {
  63. UserId = query.User.Id.ToString("N"),
  64. Limit = query.Limit,
  65. StartIndex = query.StartIndex
  66. }, CancellationToken.None).ConfigureAwait(false);
  67. return GetResult(result);
  68. }
  69. case SpecialFolder.LiveTvNowPlaying:
  70. {
  71. var result = await _liveTvManager.GetRecommendedProgramsInternal(new RecommendedProgramQuery
  72. {
  73. UserId = query.User.Id.ToString("N"),
  74. Limit = query.Limit,
  75. IsAiring = true
  76. }, CancellationToken.None).ConfigureAwait(false);
  77. return GetResult(result);
  78. }
  79. case SpecialFolder.LiveTvRecordingGroups:
  80. {
  81. var result = await _liveTvManager.GetInternalRecordings(new RecordingQuery
  82. {
  83. UserId = query.User.Id.ToString("N"),
  84. Status = RecordingStatus.Completed,
  85. Limit = query.Limit,
  86. StartIndex = query.StartIndex
  87. }, CancellationToken.None).ConfigureAwait(false);
  88. return GetResult(result);
  89. }
  90. case CollectionType.LiveTv:
  91. {
  92. var result = await GetLiveTvFolders(user).ConfigureAwait(false);
  93. return GetResult(result, parent, query);
  94. }
  95. case CollectionType.Folders:
  96. return GetResult(user.RootFolder.GetChildren(user, true), parent, query);
  97. case CollectionType.Games:
  98. return await GetGameView(user, parent, query).ConfigureAwait(false);
  99. case CollectionType.BoxSets:
  100. return GetResult(GetMediaFolders(user).SelectMany(i => i.GetRecursiveChildren(user)).OfType<BoxSet>(), parent, query);
  101. case CollectionType.TvShows:
  102. return await GetTvView(parent, user, query).ConfigureAwait(false);
  103. case CollectionType.Music:
  104. return await GetMusicFolders(parent, user, query).ConfigureAwait(false);
  105. case CollectionType.Movies:
  106. return await GetMovieFolders(parent, user, query).ConfigureAwait(false);
  107. case SpecialFolder.GameGenres:
  108. return GetGameGenres(parent, user, query);
  109. case SpecialFolder.GameSystems:
  110. return GetGameSystems(parent, user, query);
  111. case SpecialFolder.LatestGames:
  112. return GetLatestGames(parent, user, query);
  113. case SpecialFolder.RecentlyPlayedGames:
  114. return GetRecentlyPlayedGames(parent, user, query);
  115. case SpecialFolder.GameFavorites:
  116. return GetFavoriteGames(parent, user, query);
  117. case SpecialFolder.TvShowSeries:
  118. return GetTvSeries(parent, user, query);
  119. case SpecialFolder.TvGenres:
  120. return GetTvGenres(parent, user, query);
  121. case SpecialFolder.TvResume:
  122. return GetTvResume(parent, user, query);
  123. case SpecialFolder.TvNextUp:
  124. return GetTvNextUp(parent, query);
  125. case SpecialFolder.TvLatest:
  126. return GetTvLatest(parent, user, query);
  127. case SpecialFolder.MovieFavorites:
  128. return GetFavoriteMovies(parent, user, query);
  129. case SpecialFolder.MovieLatest:
  130. return GetMovieLatest(parent, user, query);
  131. case SpecialFolder.MovieGenres:
  132. return GetMovieGenres(parent, user, query);
  133. case SpecialFolder.MovieResume:
  134. return GetMovieResume(parent, user, query);
  135. case SpecialFolder.MovieMovies:
  136. return GetMovieMovies(parent, user, query);
  137. case SpecialFolder.MovieCollections:
  138. return GetMovieCollections(parent, user, query);
  139. case SpecialFolder.MusicLatest:
  140. return GetMusicLatest(parent, user, query);
  141. case SpecialFolder.MusicAlbums:
  142. return GetMusicAlbums(parent, user, query);
  143. case SpecialFolder.MusicAlbumArtists:
  144. return GetMusicAlbumArtists(parent, user, query);
  145. case SpecialFolder.MusicArtists:
  146. return GetMusicArtists(parent, user, query);
  147. case SpecialFolder.MusicSongs:
  148. return GetMusicSongs(parent, user, query);
  149. case SpecialFolder.TvFavoriteEpisodes:
  150. return GetFavoriteEpisodes(parent, user, query);
  151. case SpecialFolder.TvFavoriteSeries:
  152. return GetFavoriteSeries(parent, user, query);
  153. case SpecialFolder.MusicFavorites:
  154. return await GetMusicFavorites(parent, user, query).ConfigureAwait(false);
  155. case SpecialFolder.MusicFavoriteAlbums:
  156. return GetFavoriteAlbums(parent, user, query);
  157. case SpecialFolder.MusicFavoriteArtists:
  158. return GetFavoriteArtists(parent, user, query);
  159. case SpecialFolder.MusicFavoriteSongs:
  160. return GetFavoriteSongs(parent, user, query);
  161. default:
  162. return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), parent, query);
  163. }
  164. }
  165. private int GetSpecialItemsLimit()
  166. {
  167. return 50;
  168. }
  169. private async Task<QueryResult<BaseItem>> GetMusicFolders(Folder parent, User user, InternalItemsQuery query)
  170. {
  171. if (query.Recursive)
  172. {
  173. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }), parent, query);
  174. }
  175. var list = new List<BaseItem>();
  176. list.Add(await GetUserView(SpecialFolder.MusicLatest, user, "0", parent).ConfigureAwait(false));
  177. list.Add(await GetUserView(SpecialFolder.MusicAlbums, user, "1", parent).ConfigureAwait(false));
  178. list.Add(await GetUserView(SpecialFolder.MusicAlbumArtists, user, "2", parent).ConfigureAwait(false));
  179. list.Add(await GetUserView(SpecialFolder.MusicSongs, user, "3", parent).ConfigureAwait(false));
  180. //list.Add(await GetUserView(SpecialFolder.MusicArtists, user, "3", parent).ConfigureAwait(false));
  181. //list.Add(await GetUserView(SpecialFolder.MusicGenres, user, "5", parent).ConfigureAwait(false));
  182. list.Add(await GetUserView(SpecialFolder.MusicFavorites, user, "6", parent).ConfigureAwait(false));
  183. return GetResult(list, parent, query);
  184. }
  185. private async Task<QueryResult<BaseItem>> GetMusicFavorites(Folder parent, User user, InternalItemsQuery query)
  186. {
  187. var list = new List<BaseItem>();
  188. list.Add(await GetUserView(SpecialFolder.MusicFavoriteAlbums, user, "0", parent).ConfigureAwait(false));
  189. list.Add(await GetUserView(SpecialFolder.MusicFavoriteArtists, user, "1", parent).ConfigureAwait(false));
  190. list.Add(await GetUserView(SpecialFolder.MusicFavoriteSongs, user, "2", parent).ConfigureAwait(false));
  191. return GetResult(list, parent, query);
  192. }
  193. private QueryResult<BaseItem> GetMusicAlbumArtists(Folder parent, User user, InternalItemsQuery query)
  194. {
  195. var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
  196. .Where(i => !i.IsFolder)
  197. .OfType<IHasAlbumArtist>()
  198. .SelectMany(i => i.AlbumArtists)
  199. .Distinct(StringComparer.OrdinalIgnoreCase)
  200. .Select(i =>
  201. {
  202. try
  203. {
  204. return _libraryManager.GetArtist(i);
  205. }
  206. catch
  207. {
  208. // Already logged at lower levels
  209. return null;
  210. }
  211. })
  212. .Where(i => i != null);
  213. return GetResult(artists, parent, query);
  214. }
  215. private QueryResult<BaseItem> GetMusicArtists(Folder parent, User user, InternalItemsQuery query)
  216. {
  217. var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
  218. .Where(i => !i.IsFolder)
  219. .OfType<IHasArtist>()
  220. .SelectMany(i => i.Artists)
  221. .Distinct(StringComparer.OrdinalIgnoreCase)
  222. .Select(i =>
  223. {
  224. try
  225. {
  226. return _libraryManager.GetArtist(i);
  227. }
  228. catch
  229. {
  230. // Already logged at lower levels
  231. return null;
  232. }
  233. })
  234. .Where(i => i != null);
  235. return GetResult(artists, parent, query);
  236. }
  237. private QueryResult<BaseItem> GetFavoriteArtists(Folder parent, User user, InternalItemsQuery query)
  238. {
  239. var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos })
  240. .Where(i => !i.IsFolder)
  241. .OfType<IHasAlbumArtist>()
  242. .SelectMany(i => i.AlbumArtists)
  243. .Distinct(StringComparer.OrdinalIgnoreCase)
  244. .Select(i =>
  245. {
  246. try
  247. {
  248. return _libraryManager.GetArtist(i);
  249. }
  250. catch
  251. {
  252. // Already logged at lower levels
  253. return null;
  254. }
  255. })
  256. .Where(i => i != null && _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).IsFavorite);
  257. return GetResult(artists, parent, query);
  258. }
  259. private QueryResult<BaseItem> GetMusicAlbums(Folder parent, User user, InternalItemsQuery query)
  260. {
  261. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is MusicAlbum), parent, query);
  262. }
  263. private QueryResult<BaseItem> GetMusicSongs(Folder parent, User user, InternalItemsQuery query)
  264. {
  265. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is Audio.Audio), parent, query);
  266. }
  267. private QueryResult<BaseItem> GetMusicLatest(Folder parent, User user, InternalItemsQuery query)
  268. {
  269. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  270. query.SortOrder = SortOrder.Descending;
  271. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is MusicVideo || i is Audio.Audio), parent, GetSpecialItemsLimit(), query);
  272. }
  273. private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, InternalItemsQuery query)
  274. {
  275. if (query.Recursive)
  276. {
  277. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie || i is BoxSet), parent, query);
  278. }
  279. var list = new List<BaseItem>();
  280. list.Add(await GetUserView(SpecialFolder.MovieResume, user, "0", parent).ConfigureAwait(false));
  281. list.Add(await GetUserView(SpecialFolder.MovieLatest, user, "1", parent).ConfigureAwait(false));
  282. list.Add(await GetUserView(SpecialFolder.MovieMovies, user, "2", parent).ConfigureAwait(false));
  283. list.Add(await GetUserView(SpecialFolder.MovieCollections, user, "3", parent).ConfigureAwait(false));
  284. list.Add(await GetUserView(SpecialFolder.MovieFavorites, user, "4", parent).ConfigureAwait(false));
  285. //list.Add(await GetUserView(CollectionType.MovieGenres, user, "5", parent).ConfigureAwait(false));
  286. return GetResult(list, parent, query);
  287. }
  288. private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query)
  289. {
  290. query.IsFavorite = true;
  291. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, query);
  292. }
  293. private QueryResult<BaseItem> GetFavoriteSeries(Folder parent, User user, InternalItemsQuery query)
  294. {
  295. query.IsFavorite = true;
  296. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series), parent, query);
  297. }
  298. private QueryResult<BaseItem> GetFavoriteEpisodes(Folder parent, User user, InternalItemsQuery query)
  299. {
  300. query.IsFavorite = true;
  301. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Episode), parent, query);
  302. }
  303. private QueryResult<BaseItem> GetFavoriteSongs(Folder parent, User user, InternalItemsQuery query)
  304. {
  305. query.IsFavorite = true;
  306. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is Audio.Audio), parent, query);
  307. }
  308. private QueryResult<BaseItem> GetFavoriteAlbums(Folder parent, User user, InternalItemsQuery query)
  309. {
  310. query.IsFavorite = true;
  311. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is MusicAlbum), parent, query);
  312. }
  313. private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, InternalItemsQuery query)
  314. {
  315. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, query);
  316. }
  317. private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, InternalItemsQuery query)
  318. {
  319. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is BoxSet), parent, query);
  320. }
  321. private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query)
  322. {
  323. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  324. query.SortOrder = SortOrder.Descending;
  325. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, GetSpecialItemsLimit(), query);
  326. }
  327. private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query)
  328. {
  329. query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
  330. query.SortOrder = SortOrder.Descending;
  331. query.IsResumable = true;
  332. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, GetSpecialItemsLimit(), query);
  333. }
  334. private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, InternalItemsQuery query)
  335. {
  336. var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty })
  337. .Where(i => i is Movie)
  338. .SelectMany(i => i.Genres)
  339. .Distinct(StringComparer.OrdinalIgnoreCase)
  340. .Select(i =>
  341. {
  342. try
  343. {
  344. return _libraryManager.GetGenre(i);
  345. }
  346. catch
  347. {
  348. // Full exception logged at lower levels
  349. _logger.Error("Error getting genre");
  350. return null;
  351. }
  352. })
  353. .Where(i => i != null);
  354. return GetResult(genres, parent, query);
  355. }
  356. private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, InternalItemsQuery query)
  357. {
  358. if (query.Recursive)
  359. {
  360. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series || i is Season || i is Episode), parent, query);
  361. }
  362. var list = new List<BaseItem>();
  363. list.Add(await GetUserView(SpecialFolder.TvResume, user, "0", parent).ConfigureAwait(false));
  364. list.Add(await GetUserView(SpecialFolder.TvNextUp, user, "1", parent).ConfigureAwait(false));
  365. list.Add(await GetUserView(SpecialFolder.TvLatest, user, "2", parent).ConfigureAwait(false));
  366. list.Add(await GetUserView(SpecialFolder.TvShowSeries, user, "3", parent).ConfigureAwait(false));
  367. list.Add(await GetUserView(SpecialFolder.TvFavoriteSeries, user, "4", parent).ConfigureAwait(false));
  368. list.Add(await GetUserView(SpecialFolder.TvFavoriteEpisodes, user, "5", parent).ConfigureAwait(false));
  369. //list.Add(await GetUserView(SpecialFolder.TvGenres, user, "5", parent).ConfigureAwait(false));
  370. return GetResult(list, parent, query);
  371. }
  372. private async Task<QueryResult<BaseItem>> GetGameView(User user, Folder parent, InternalItemsQuery query)
  373. {
  374. if (query.Recursive)
  375. {
  376. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }), parent, query);
  377. }
  378. var list = new List<BaseItem>();
  379. list.Add(await GetUserView(SpecialFolder.LatestGames, user, "0", parent).ConfigureAwait(false));
  380. list.Add(await GetUserView(SpecialFolder.RecentlyPlayedGames, user, "1", parent).ConfigureAwait(false));
  381. list.Add(await GetUserView(SpecialFolder.GameFavorites, user, "2", parent).ConfigureAwait(false));
  382. list.Add(await GetUserView(SpecialFolder.GameSystems, user, "3", parent).ConfigureAwait(false));
  383. //list.Add(await GetUserView(SpecialFolder.GameGenres, user, "4", parent).ConfigureAwait(false));
  384. return GetResult(list, parent, 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>(), parent, 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>(), parent, 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>(), parent, 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>(), parent, 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>(), parent, 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>(), parent, 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, parent, 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>(), parent, 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, parent, 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. BaseItem parentItem,
  491. InternalItemsQuery query)
  492. where T : BaseItem
  493. {
  494. return GetResult(items, parentItem, null, query);
  495. }
  496. private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
  497. BaseItem parentItem,
  498. int? totalRecordLimit,
  499. InternalItemsQuery query)
  500. where T : BaseItem
  501. {
  502. return SortAndFilter(items, parentItem, totalRecordLimit, query, _libraryManager, _userDataManager);
  503. }
  504. public static QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items,
  505. BaseItem parentItem,
  506. int? totalRecordLimit,
  507. InternalItemsQuery query,
  508. ILibraryManager libraryManager,
  509. IUserDataManager userDataManager)
  510. {
  511. var user = query.User;
  512. items = items.Where(i => Filter(i, user, query, userDataManager));
  513. items = FilterVirtualEpisodes(items,
  514. query.IsMissing,
  515. query.IsVirtualUnaired,
  516. query.IsUnaired);
  517. items = CollapseBoxSetItemsIfNeeded(items, query, parentItem, user);
  518. // This must be the last filter
  519. if (!string.IsNullOrEmpty(query.AdjacentTo))
  520. {
  521. items = FilterForAdjacency(items, query.AdjacentTo);
  522. }
  523. return Sort(items, totalRecordLimit, query, libraryManager);
  524. }
  525. public static IEnumerable<BaseItem> CollapseBoxSetItemsIfNeeded(IEnumerable<BaseItem> items,
  526. InternalItemsQuery query,
  527. BaseItem parentItem,
  528. User user)
  529. {
  530. if (CollapseBoxSetItems(query, parentItem, user))
  531. {
  532. items = BaseItem.CollectionManager.CollapseItemsWithinBoxSets(items, user);
  533. }
  534. items = ApplyPostCollectionCollapseFilters(query, items, user);
  535. return items;
  536. }
  537. private static IEnumerable<BaseItem> ApplyPostCollectionCollapseFilters(InternalItemsQuery request,
  538. IEnumerable<BaseItem> items,
  539. User user)
  540. {
  541. if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater))
  542. {
  543. items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1);
  544. }
  545. if (!string.IsNullOrEmpty(request.NameStartsWith))
  546. {
  547. items = items.Where(i => string.Compare(request.NameStartsWith, i.SortName.Substring(0, 1), StringComparison.CurrentCultureIgnoreCase) == 0);
  548. }
  549. if (!string.IsNullOrEmpty(request.NameLessThan))
  550. {
  551. items = items.Where(i => string.Compare(request.NameLessThan, i.SortName, StringComparison.CurrentCultureIgnoreCase) == 1);
  552. }
  553. return items;
  554. }
  555. private static bool CollapseBoxSetItems(InternalItemsQuery query,
  556. BaseItem parentItem,
  557. User user)
  558. {
  559. // Could end up stuck in a loop like this
  560. if (parentItem is BoxSet)
  561. {
  562. return false;
  563. }
  564. var param = query.CollapseBoxSetItems;
  565. if (!param.HasValue)
  566. {
  567. if (user != null && !user.Configuration.GroupMoviesIntoBoxSets)
  568. {
  569. return false;
  570. }
  571. if (query.IncludeItemTypes.Contains("Movie", StringComparer.OrdinalIgnoreCase))
  572. {
  573. param = true;
  574. }
  575. }
  576. return param.HasValue && param.Value && AllowBoxSetCollapsing(query);
  577. }
  578. private static bool AllowBoxSetCollapsing(InternalItemsQuery request)
  579. {
  580. if (request.IsFavorite.HasValue)
  581. {
  582. return false;
  583. }
  584. if (request.IsFavoriteOrLiked.HasValue)
  585. {
  586. return false;
  587. }
  588. if (request.IsLiked.HasValue)
  589. {
  590. return false;
  591. }
  592. if (request.IsPlayed.HasValue)
  593. {
  594. return false;
  595. }
  596. if (request.IsResumable.HasValue)
  597. {
  598. return false;
  599. }
  600. if (request.IsFolder.HasValue)
  601. {
  602. return false;
  603. }
  604. if (request.AllGenres.Length > 0)
  605. {
  606. return false;
  607. }
  608. if (request.Genres.Length > 0)
  609. {
  610. return false;
  611. }
  612. if (request.HasImdbId.HasValue)
  613. {
  614. return false;
  615. }
  616. if (request.HasOfficialRating.HasValue)
  617. {
  618. return false;
  619. }
  620. if (request.HasOverview.HasValue)
  621. {
  622. return false;
  623. }
  624. if (request.HasParentalRating.HasValue)
  625. {
  626. return false;
  627. }
  628. if (request.HasSpecialFeature.HasValue)
  629. {
  630. return false;
  631. }
  632. if (request.HasSubtitles.HasValue)
  633. {
  634. return false;
  635. }
  636. if (request.HasThemeSong.HasValue)
  637. {
  638. return false;
  639. }
  640. if (request.HasThemeVideo.HasValue)
  641. {
  642. return false;
  643. }
  644. if (request.HasTmdbId.HasValue)
  645. {
  646. return false;
  647. }
  648. if (request.HasTrailer.HasValue)
  649. {
  650. return false;
  651. }
  652. if (request.ImageTypes.Length > 0)
  653. {
  654. return false;
  655. }
  656. if (request.Is3D.HasValue)
  657. {
  658. return false;
  659. }
  660. if (request.IsHD.HasValue)
  661. {
  662. return false;
  663. }
  664. if (request.IsInBoxSet.HasValue)
  665. {
  666. return false;
  667. }
  668. if (request.IsLocked.HasValue)
  669. {
  670. return false;
  671. }
  672. if (request.IsPlaceHolder.HasValue)
  673. {
  674. return false;
  675. }
  676. if (request.IsPlayed.HasValue)
  677. {
  678. return false;
  679. }
  680. if (request.IsUnidentified.HasValue)
  681. {
  682. return false;
  683. }
  684. if (request.IsYearMismatched.HasValue)
  685. {
  686. return false;
  687. }
  688. if (!string.IsNullOrWhiteSpace(request.Person))
  689. {
  690. return false;
  691. }
  692. if (request.Studios.Length > 0)
  693. {
  694. return false;
  695. }
  696. if (request.VideoTypes.Length > 0)
  697. {
  698. return false;
  699. }
  700. if (request.Years.Length > 0)
  701. {
  702. return false;
  703. }
  704. return true;
  705. }
  706. public static IEnumerable<BaseItem> FilterVirtualEpisodes(
  707. IEnumerable<BaseItem> items,
  708. bool? isMissing,
  709. bool? isVirtualUnaired,
  710. bool? isUnaired)
  711. {
  712. items = FilterVirtualSeasons(items, isMissing, isVirtualUnaired, isUnaired);
  713. if (isMissing.HasValue)
  714. {
  715. var val = isMissing.Value;
  716. items = items.Where(i =>
  717. {
  718. var e = i as Episode;
  719. if (e != null)
  720. {
  721. return e.IsMissingEpisode == val;
  722. }
  723. return true;
  724. });
  725. }
  726. if (isUnaired.HasValue)
  727. {
  728. var val = isUnaired.Value;
  729. items = items.Where(i =>
  730. {
  731. var e = i as Episode;
  732. if (e != null)
  733. {
  734. return e.IsUnaired == val;
  735. }
  736. return true;
  737. });
  738. }
  739. if (isVirtualUnaired.HasValue)
  740. {
  741. var val = isVirtualUnaired.Value;
  742. items = items.Where(i =>
  743. {
  744. var e = i as Episode;
  745. if (e != null)
  746. {
  747. return e.IsVirtualUnaired == val;
  748. }
  749. return true;
  750. });
  751. }
  752. return items;
  753. }
  754. private static IEnumerable<BaseItem> FilterVirtualSeasons(
  755. IEnumerable<BaseItem> items,
  756. bool? isMissing,
  757. bool? isVirtualUnaired,
  758. bool? isUnaired)
  759. {
  760. if (isMissing.HasValue && isVirtualUnaired.HasValue)
  761. {
  762. if (!isMissing.Value && !isVirtualUnaired.Value)
  763. {
  764. return items.Where(i =>
  765. {
  766. var e = i as Season;
  767. if (e != null)
  768. {
  769. return !e.IsMissingOrVirtualUnaired;
  770. }
  771. return true;
  772. });
  773. }
  774. }
  775. if (isMissing.HasValue)
  776. {
  777. var val = isMissing.Value;
  778. items = items.Where(i =>
  779. {
  780. var e = i as Season;
  781. if (e != null)
  782. {
  783. return e.IsMissingSeason == val;
  784. }
  785. return true;
  786. });
  787. }
  788. if (isUnaired.HasValue)
  789. {
  790. var val = isUnaired.Value;
  791. items = items.Where(i =>
  792. {
  793. var e = i as Season;
  794. if (e != null)
  795. {
  796. return e.IsUnaired == val;
  797. }
  798. return true;
  799. });
  800. }
  801. if (isVirtualUnaired.HasValue)
  802. {
  803. var val = isVirtualUnaired.Value;
  804. items = items.Where(i =>
  805. {
  806. var e = i as Season;
  807. if (e != null)
  808. {
  809. return e.IsVirtualUnaired == val;
  810. }
  811. return true;
  812. });
  813. }
  814. return items;
  815. }
  816. public static QueryResult<BaseItem> Sort(IEnumerable<BaseItem> items,
  817. int? totalRecordLimit,
  818. InternalItemsQuery query,
  819. ILibraryManager libraryManager)
  820. {
  821. var user = query.User;
  822. items = libraryManager.ReplaceVideosWithPrimaryVersions(items);
  823. if (query.SortBy.Length > 0)
  824. {
  825. items = libraryManager.Sort(items, user, query.SortBy, query.SortOrder);
  826. }
  827. var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
  828. var totalCount = itemsArray.Length;
  829. if (query.Limit.HasValue)
  830. {
  831. itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
  832. }
  833. else if (query.StartIndex.HasValue)
  834. {
  835. itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
  836. }
  837. return new QueryResult<BaseItem>
  838. {
  839. TotalRecordCount = totalCount,
  840. Items = itemsArray
  841. };
  842. }
  843. private static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager)
  844. {
  845. if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
  846. {
  847. return false;
  848. }
  849. if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase))
  850. {
  851. return false;
  852. }
  853. if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase))
  854. {
  855. return false;
  856. }
  857. if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
  858. {
  859. return false;
  860. }
  861. if (query.Filter != null && !query.Filter(item, user))
  862. {
  863. return false;
  864. }
  865. UserItemData userData = null;
  866. if (query.IsLiked.HasValue)
  867. {
  868. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  869. if (!userData.Likes.HasValue || userData.Likes != query.IsLiked.Value)
  870. {
  871. return false;
  872. }
  873. }
  874. if (query.IsFavoriteOrLiked.HasValue)
  875. {
  876. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  877. var isFavoriteOrLiked = userData.IsFavorite || (userData.Likes ?? false);
  878. if (isFavoriteOrLiked != query.IsFavoriteOrLiked.Value)
  879. {
  880. return false;
  881. }
  882. }
  883. if (query.IsFavorite.HasValue)
  884. {
  885. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  886. if (userData.IsFavorite != query.IsFavorite.Value)
  887. {
  888. return false;
  889. }
  890. }
  891. if (query.IsResumable.HasValue)
  892. {
  893. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  894. var isResumable = userData.PlaybackPositionTicks > 0;
  895. if (isResumable != query.IsResumable.Value)
  896. {
  897. return false;
  898. }
  899. }
  900. if (query.IsPlayed.HasValue)
  901. {
  902. if (item.IsPlayed(user) != query.IsPlayed.Value)
  903. {
  904. return false;
  905. }
  906. }
  907. if (query.IsInBoxSet.HasValue)
  908. {
  909. var val = query.IsInBoxSet.Value;
  910. if (item.Parents.OfType<BoxSet>().Any() != val)
  911. {
  912. return false;
  913. }
  914. }
  915. // Filter by Video3DFormat
  916. if (query.Is3D.HasValue)
  917. {
  918. var val = query.Is3D.Value;
  919. var video = item as Video;
  920. if (video == null || val != video.Video3DFormat.HasValue)
  921. {
  922. return false;
  923. }
  924. }
  925. if (query.IsHD.HasValue)
  926. {
  927. var val = query.IsHD.Value;
  928. var video = item as Video;
  929. if (video == null || val != video.IsHD)
  930. {
  931. return false;
  932. }
  933. }
  934. if (query.IsUnidentified.HasValue)
  935. {
  936. var val = query.IsUnidentified.Value;
  937. if (item.IsUnidentified != val)
  938. {
  939. return false;
  940. }
  941. }
  942. if (query.IsLocked.HasValue)
  943. {
  944. var val = query.IsLocked.Value;
  945. if (item.IsLocked != val)
  946. {
  947. return false;
  948. }
  949. }
  950. if (query.HasOverview.HasValue)
  951. {
  952. var filterValue = query.HasOverview.Value;
  953. var hasValue = !string.IsNullOrEmpty(item.Overview);
  954. if (hasValue != filterValue)
  955. {
  956. return false;
  957. }
  958. }
  959. if (query.HasImdbId.HasValue)
  960. {
  961. var filterValue = query.HasImdbId.Value;
  962. var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Imdb));
  963. if (hasValue != filterValue)
  964. {
  965. return false;
  966. }
  967. }
  968. if (query.HasTmdbId.HasValue)
  969. {
  970. var filterValue = query.HasTmdbId.Value;
  971. var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tmdb));
  972. if (hasValue != filterValue)
  973. {
  974. return false;
  975. }
  976. }
  977. if (query.HasTvdbId.HasValue)
  978. {
  979. var filterValue = query.HasTvdbId.Value;
  980. var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tvdb));
  981. if (hasValue != filterValue)
  982. {
  983. return false;
  984. }
  985. }
  986. if (query.IsYearMismatched.HasValue)
  987. {
  988. var filterValue = query.IsYearMismatched.Value;
  989. if (IsYearMismatched(item) != filterValue)
  990. {
  991. return false;
  992. }
  993. }
  994. if (query.HasOfficialRating.HasValue)
  995. {
  996. var filterValue = query.HasOfficialRating.Value;
  997. var hasValue = !string.IsNullOrEmpty(item.OfficialRating);
  998. if (hasValue != filterValue)
  999. {
  1000. return false;
  1001. }
  1002. }
  1003. if (query.IsPlaceHolder.HasValue)
  1004. {
  1005. var filterValue = query.IsPlaceHolder.Value;
  1006. var isPlaceHolder = false;
  1007. var hasPlaceHolder = item as ISupportsPlaceHolders;
  1008. if (hasPlaceHolder != null)
  1009. {
  1010. isPlaceHolder = hasPlaceHolder.IsPlaceHolder;
  1011. }
  1012. if (isPlaceHolder != filterValue)
  1013. {
  1014. return false;
  1015. }
  1016. }
  1017. if (query.HasSpecialFeature.HasValue)
  1018. {
  1019. var filterValue = query.HasSpecialFeature.Value;
  1020. var movie = item as IHasSpecialFeatures;
  1021. if (movie != null)
  1022. {
  1023. var ok = filterValue
  1024. ? movie.SpecialFeatureIds.Count > 0
  1025. : movie.SpecialFeatureIds.Count == 0;
  1026. if (!ok)
  1027. {
  1028. return false;
  1029. }
  1030. }
  1031. else
  1032. {
  1033. return false;
  1034. }
  1035. }
  1036. if (query.HasSubtitles.HasValue)
  1037. {
  1038. var val = query.HasSubtitles.Value;
  1039. var video = item as Video;
  1040. if (video == null || val != video.HasSubtitles)
  1041. {
  1042. return false;
  1043. }
  1044. }
  1045. if (query.HasParentalRating.HasValue)
  1046. {
  1047. var val = query.HasParentalRating.Value;
  1048. var rating = item.CustomRating;
  1049. if (string.IsNullOrEmpty(rating))
  1050. {
  1051. rating = item.OfficialRating;
  1052. }
  1053. if (val)
  1054. {
  1055. if (string.IsNullOrEmpty(rating))
  1056. {
  1057. return false;
  1058. }
  1059. }
  1060. else
  1061. {
  1062. if (!string.IsNullOrEmpty(rating))
  1063. {
  1064. return false;
  1065. }
  1066. }
  1067. }
  1068. if (query.HasTrailer.HasValue)
  1069. {
  1070. var val = query.HasTrailer.Value;
  1071. var trailerCount = 0;
  1072. var hasTrailers = item as IHasTrailers;
  1073. if (hasTrailers != null)
  1074. {
  1075. trailerCount = hasTrailers.LocalTrailerIds.Count;
  1076. }
  1077. var ok = val ? trailerCount > 0 : trailerCount == 0;
  1078. if (!ok)
  1079. {
  1080. return false;
  1081. }
  1082. }
  1083. if (query.HasThemeSong.HasValue)
  1084. {
  1085. var filterValue = query.HasThemeSong.Value;
  1086. var themeCount = 0;
  1087. var iHasThemeMedia = item as IHasThemeMedia;
  1088. if (iHasThemeMedia != null)
  1089. {
  1090. themeCount = iHasThemeMedia.ThemeSongIds.Count;
  1091. }
  1092. var ok = filterValue ? themeCount > 0 : themeCount == 0;
  1093. if (!ok)
  1094. {
  1095. return false;
  1096. }
  1097. }
  1098. if (query.HasThemeVideo.HasValue)
  1099. {
  1100. var filterValue = query.HasThemeVideo.Value;
  1101. var themeCount = 0;
  1102. var iHasThemeMedia = item as IHasThemeMedia;
  1103. if (iHasThemeMedia != null)
  1104. {
  1105. themeCount = iHasThemeMedia.ThemeVideoIds.Count;
  1106. }
  1107. var ok = filterValue ? themeCount > 0 : themeCount == 0;
  1108. if (!ok)
  1109. {
  1110. return false;
  1111. }
  1112. }
  1113. // Apply genre filter
  1114. if (query.Genres.Length > 0 && !(query.Genres.Any(v => item.Genres.Contains(v, StringComparer.OrdinalIgnoreCase))))
  1115. {
  1116. return false;
  1117. }
  1118. // Apply genre filter
  1119. if (query.AllGenres.Length > 0 && !query.AllGenres.All(v => item.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))
  1120. {
  1121. return false;
  1122. }
  1123. // Filter by VideoType
  1124. if (query.VideoTypes.Length > 0)
  1125. {
  1126. var video = item as Video;
  1127. if (video == null || !query.VideoTypes.Contains(video.VideoType))
  1128. {
  1129. return false;
  1130. }
  1131. }
  1132. if (query.ImageTypes.Length > 0 && !query.ImageTypes.Any(item.HasImage))
  1133. {
  1134. return false;
  1135. }
  1136. // Apply studio filter
  1137. if (query.Studios.Length > 0 && !query.Studios.Any(v => item.Studios.Contains(v, StringComparer.OrdinalIgnoreCase)))
  1138. {
  1139. return false;
  1140. }
  1141. // Apply year filter
  1142. if (query.Years.Length > 0)
  1143. {
  1144. if (!(item.ProductionYear.HasValue && query.Years.Contains(item.ProductionYear.Value)))
  1145. {
  1146. return false;
  1147. }
  1148. }
  1149. // Apply person filter
  1150. if (!string.IsNullOrEmpty(query.Person))
  1151. {
  1152. var personTypes = query.PersonTypes;
  1153. if (personTypes.Length == 0)
  1154. {
  1155. if (!(item.People.Any(p => string.Equals(p.Name, query.Person, StringComparison.OrdinalIgnoreCase))))
  1156. {
  1157. return false;
  1158. }
  1159. }
  1160. else
  1161. {
  1162. var types = personTypes;
  1163. var ok = new[] { item }.Any(i =>
  1164. i.People != null &&
  1165. i.People.Any(p =>
  1166. p.Name.Equals(query.Person, StringComparison.OrdinalIgnoreCase) && (types.Contains(p.Type, StringComparer.OrdinalIgnoreCase) || types.Contains(p.Role, StringComparer.OrdinalIgnoreCase))));
  1167. if (!ok)
  1168. {
  1169. return false;
  1170. }
  1171. }
  1172. }
  1173. return true;
  1174. }
  1175. private IEnumerable<Folder> GetMediaFolders(User user)
  1176. {
  1177. var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
  1178. return user.RootFolder
  1179. .GetChildren(user, true, true)
  1180. .OfType<Folder>()
  1181. .Where(i => !excludeFolderIds.Contains(i.Id) && !UserView.IsExcludedFromGrouping(i));
  1182. }
  1183. private IEnumerable<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes)
  1184. {
  1185. return GetMediaFolders(user)
  1186. .Where(i =>
  1187. {
  1188. var folder = i as ICollectionFolder;
  1189. return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
  1190. });
  1191. }
  1192. private IEnumerable<Folder> GetMediaFolders(Folder parent, User user, string[] viewTypes)
  1193. {
  1194. if (parent == null || parent is UserView)
  1195. {
  1196. return GetMediaFolders(user, viewTypes);
  1197. }
  1198. return new[] { parent };
  1199. }
  1200. private IEnumerable<BaseItem> GetRecursiveChildren(Folder parent, User user, string[] viewTypes)
  1201. {
  1202. if (parent == null || parent is UserView)
  1203. {
  1204. return GetMediaFolders(user, viewTypes).SelectMany(i => i.GetRecursiveChildren(user));
  1205. }
  1206. return parent.GetRecursiveChildren(user);
  1207. }
  1208. private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user)
  1209. {
  1210. var list = new List<BaseItem>();
  1211. var parent = user.RootFolder;
  1212. list.Add(await GetUserView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false));
  1213. list.Add(await GetUserView(SpecialFolder.LiveTvChannels, user, string.Empty, parent).ConfigureAwait(false));
  1214. list.Add(await GetUserView(SpecialFolder.LiveTvRecordingGroups, user, string.Empty, parent).ConfigureAwait(false));
  1215. return list;
  1216. }
  1217. private async Task<UserView> GetUserView(string type, User user, string sortName, Folder parent)
  1218. {
  1219. var view = await _userViewManager.GetUserView(parent.Id.ToString("N"), type, user, sortName, CancellationToken.None)
  1220. .ConfigureAwait(false);
  1221. return view;
  1222. }
  1223. public static bool IsYearMismatched(BaseItem item)
  1224. {
  1225. if (item.ProductionYear.HasValue)
  1226. {
  1227. var path = item.Path;
  1228. if (!string.IsNullOrEmpty(path))
  1229. {
  1230. int? yearInName;
  1231. string name;
  1232. NameParser.ParseName(Path.GetFileName(path), out name, out yearInName);
  1233. // Go up a level if we didn't get a year
  1234. if (!yearInName.HasValue)
  1235. {
  1236. NameParser.ParseName(Path.GetFileName(Path.GetDirectoryName(path)), out name, out yearInName);
  1237. }
  1238. if (yearInName.HasValue)
  1239. {
  1240. return yearInName.Value != item.ProductionYear.Value;
  1241. }
  1242. }
  1243. }
  1244. return false;
  1245. }
  1246. public static IEnumerable<BaseItem> FilterForAdjacency(IEnumerable<BaseItem> items, string adjacentToId)
  1247. {
  1248. var list = items.ToList();
  1249. var adjacentToIdGuid = new Guid(adjacentToId);
  1250. var adjacentToItem = list.FirstOrDefault(i => i.Id == adjacentToIdGuid);
  1251. var index = list.IndexOf(adjacentToItem);
  1252. var previousId = Guid.Empty;
  1253. var nextId = Guid.Empty;
  1254. if (index > 0)
  1255. {
  1256. previousId = list[index - 1].Id;
  1257. }
  1258. if (index < list.Count - 1)
  1259. {
  1260. nextId = list[index + 1].Id;
  1261. }
  1262. return list.Where(i => i.Id == previousId || i.Id == nextId || i.Id == adjacentToIdGuid);
  1263. }
  1264. }
  1265. }