UserViewBuilder.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614
  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.TvSeries:
  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. default:
  135. return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), query);
  136. }
  137. }
  138. private int GetSpecialItemsLimit()
  139. {
  140. return 50;
  141. }
  142. private async Task<QueryResult<BaseItem>> GetMusicFolders(Folder parent, User user, UserItemsQuery query)
  143. {
  144. if (query.Recursive)
  145. {
  146. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }), query);
  147. }
  148. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).OfType<MusicArtist>(), query);
  149. }
  150. private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, UserItemsQuery query)
  151. {
  152. if (query.Recursive)
  153. {
  154. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie || i is BoxSet), query);
  155. }
  156. var list = new List<BaseItem>();
  157. list.Add(await GetUserView(CollectionType.MovieResume, user, "0", parent).ConfigureAwait(false));
  158. list.Add(await GetUserView(CollectionType.MovieLatest, user, "1", parent).ConfigureAwait(false));
  159. list.Add(await GetUserView(CollectionType.MovieMovies, user, "2", parent).ConfigureAwait(false));
  160. list.Add(await GetUserView(CollectionType.MovieCollections, user, "3", parent).ConfigureAwait(false));
  161. list.Add(await GetUserView(CollectionType.MovieFavorites, user, "4", parent).ConfigureAwait(false));
  162. //list.Add(await GetUserView(CollectionType.MovieGenres, user, "5", parent).ConfigureAwait(false));
  163. return GetResult(list, query);
  164. }
  165. private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, UserItemsQuery query)
  166. {
  167. query.IsFavorite = true;
  168. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query);
  169. }
  170. private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, UserItemsQuery query)
  171. {
  172. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query);
  173. }
  174. private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, UserItemsQuery query)
  175. {
  176. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is BoxSet), query);
  177. }
  178. private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, UserItemsQuery query)
  179. {
  180. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  181. query.SortOrder = SortOrder.Descending;
  182. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query);
  183. }
  184. private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, UserItemsQuery query)
  185. {
  186. query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
  187. query.SortOrder = SortOrder.Descending;
  188. query.IsResumable = true;
  189. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query);
  190. }
  191. private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, UserItemsQuery query)
  192. {
  193. var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty })
  194. .Where(i => i is Movie)
  195. .SelectMany(i => i.Genres)
  196. .Distinct(StringComparer.OrdinalIgnoreCase)
  197. .Select(i =>
  198. {
  199. try
  200. {
  201. return _libraryManager.GetGenre(i);
  202. }
  203. catch
  204. {
  205. // Full exception logged at lower levels
  206. _logger.Error("Error getting genre");
  207. return null;
  208. }
  209. })
  210. .Where(i => i != null);
  211. return GetResult(genres, query);
  212. }
  213. private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, UserItemsQuery query)
  214. {
  215. if (query.Recursive)
  216. {
  217. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series || i is Season || i is Episode), query);
  218. }
  219. var list = new List<BaseItem>();
  220. list.Add(await GetUserView(CollectionType.TvResume, user, "0", parent).ConfigureAwait(false));
  221. list.Add(await GetUserView(CollectionType.TvNextUp, user, "1", parent).ConfigureAwait(false));
  222. list.Add(await GetUserView(CollectionType.TvLatest, user, "2", parent).ConfigureAwait(false));
  223. list.Add(await GetUserView(CollectionType.TvSeries, user, "3", parent).ConfigureAwait(false));
  224. //list.Add(await GetUserView(CollectionType.TvFavorites, user, "4", parent).ConfigureAwait(false));
  225. //list.Add(await GetUserView(CollectionType.TvGenres, user, "5", parent).ConfigureAwait(false));
  226. return GetResult(list, query);
  227. }
  228. private async Task<QueryResult<BaseItem>> GetGameView(User user, Folder parent, UserItemsQuery query)
  229. {
  230. if (query.Recursive)
  231. {
  232. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }), query);
  233. }
  234. var list = new List<BaseItem>();
  235. list.Add(await GetUserView(CollectionType.LatestGames, user, "0", parent).ConfigureAwait(false));
  236. list.Add(await GetUserView(CollectionType.RecentlyPlayedGames, user, "1", parent).ConfigureAwait(false));
  237. list.Add(await GetUserView(CollectionType.GameFavorites, user, "2", parent).ConfigureAwait(false));
  238. list.Add(await GetUserView(CollectionType.GameSystems, user, "3", parent).ConfigureAwait(false));
  239. //list.Add(await GetUserView(CollectionType.GameGenres, user, "4", parent).ConfigureAwait(false));
  240. return GetResult(list, query);
  241. }
  242. private QueryResult<BaseItem> GetLatestGames(Folder parent, User user, UserItemsQuery query)
  243. {
  244. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  245. query.SortOrder = SortOrder.Descending;
  246. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query);
  247. }
  248. private QueryResult<BaseItem> GetRecentlyPlayedGames(Folder parent, User user, UserItemsQuery query)
  249. {
  250. query.IsPlayed = true;
  251. query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
  252. query.SortOrder = SortOrder.Descending;
  253. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query);
  254. }
  255. private QueryResult<BaseItem> GetFavoriteGames(Folder parent, User user, UserItemsQuery query)
  256. {
  257. query.IsFavorite = true;
  258. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), query);
  259. }
  260. private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, UserItemsQuery query)
  261. {
  262. query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName };
  263. query.SortOrder = SortOrder.Descending;
  264. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query);
  265. }
  266. private QueryResult<BaseItem> GetTvNextUp(Folder parent, UserItemsQuery query)
  267. {
  268. var parentFolders = GetMediaFolders(parent, query.User, new[] { CollectionType.TvShows, string.Empty });
  269. var result = _tvSeriesManager.GetNextUp(new NextUpQuery
  270. {
  271. Limit = query.Limit,
  272. StartIndex = query.StartIndex,
  273. UserId = query.User.Id.ToString("N")
  274. }, parentFolders);
  275. return result;
  276. }
  277. private QueryResult<BaseItem> GetTvResume(Folder parent, User user, UserItemsQuery query)
  278. {
  279. query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName };
  280. query.SortOrder = SortOrder.Descending;
  281. query.IsResumable = true;
  282. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query);
  283. }
  284. private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, UserItemsQuery query)
  285. {
  286. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Series>(), query);
  287. }
  288. private QueryResult<BaseItem> GetTvGenres(Folder parent, User user, UserItemsQuery query)
  289. {
  290. var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty })
  291. .OfType<Series>()
  292. .SelectMany(i => i.Genres)
  293. .Distinct(StringComparer.OrdinalIgnoreCase)
  294. .Select(i =>
  295. {
  296. try
  297. {
  298. return _libraryManager.GetGenre(i);
  299. }
  300. catch
  301. {
  302. // Full exception logged at lower levels
  303. _logger.Error("Error getting genre");
  304. return null;
  305. }
  306. })
  307. .Where(i => i != null);
  308. return GetResult(genres, query);
  309. }
  310. private QueryResult<BaseItem> GetGameSystems(Folder parent, User user, UserItemsQuery query)
  311. {
  312. return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<GameSystem>(), query);
  313. }
  314. private QueryResult<BaseItem> GetGameGenres(Folder parent, User user, UserItemsQuery query)
  315. {
  316. var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Games })
  317. .OfType<Game>()
  318. .SelectMany(i => i.Genres)
  319. .Distinct(StringComparer.OrdinalIgnoreCase)
  320. .Select(i =>
  321. {
  322. try
  323. {
  324. return _libraryManager.GetGameGenre(i);
  325. }
  326. catch
  327. {
  328. // Full exception logged at lower levels
  329. _logger.Error("Error getting game genre");
  330. return null;
  331. }
  332. })
  333. .Where(i => i != null);
  334. return GetResult(genres, query);
  335. }
  336. private QueryResult<BaseItem> GetResult<T>(QueryResult<T> result)
  337. where T : BaseItem
  338. {
  339. return new QueryResult<BaseItem>
  340. {
  341. Items = result.Items,
  342. TotalRecordCount = result.TotalRecordCount
  343. };
  344. }
  345. private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
  346. UserItemsQuery query)
  347. where T : BaseItem
  348. {
  349. return GetResult(items, null, query);
  350. }
  351. private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items,
  352. int? totalRecordLimit,
  353. UserItemsQuery query)
  354. where T : BaseItem
  355. {
  356. return SortAndFilter(items, totalRecordLimit, query, _libraryManager, _userDataManager);
  357. }
  358. public static QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items,
  359. int? totalRecordLimit,
  360. UserItemsQuery query,
  361. ILibraryManager libraryManager,
  362. IUserDataManager userDataManager)
  363. {
  364. var user = query.User;
  365. items = items.Where(i => Filter(i, user, query, userDataManager));
  366. return Sort(items, totalRecordLimit, query, libraryManager);
  367. }
  368. public static QueryResult<BaseItem> Sort(IEnumerable<BaseItem> items,
  369. int? totalRecordLimit,
  370. UserItemsQuery query,
  371. ILibraryManager libraryManager)
  372. {
  373. var user = query.User;
  374. items = libraryManager.ReplaceVideosWithPrimaryVersions(items);
  375. if (query.SortBy.Length > 0)
  376. {
  377. items = libraryManager.Sort(items, user, query.SortBy, query.SortOrder);
  378. }
  379. var itemsArray = totalRecordLimit.HasValue ? items.Take(totalRecordLimit.Value).ToArray() : items.ToArray();
  380. var totalCount = itemsArray.Length;
  381. if (query.Limit.HasValue)
  382. {
  383. itemsArray = itemsArray.Skip(query.StartIndex ?? 0).Take(query.Limit.Value).ToArray();
  384. }
  385. else if (query.StartIndex.HasValue)
  386. {
  387. itemsArray = itemsArray.Skip(query.StartIndex.Value).ToArray();
  388. }
  389. return new QueryResult<BaseItem>
  390. {
  391. TotalRecordCount = totalCount,
  392. Items = itemsArray
  393. };
  394. }
  395. private static bool Filter(BaseItem item, User user, UserItemsQuery query, IUserDataManager userDataManager)
  396. {
  397. if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase))
  398. {
  399. return false;
  400. }
  401. if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder)
  402. {
  403. return false;
  404. }
  405. if (query.Filter != null && !query.Filter(item, user))
  406. {
  407. return false;
  408. }
  409. UserItemData userData = null;
  410. if (query.IsFavorite.HasValue)
  411. {
  412. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  413. if (userData.IsFavorite != query.IsFavorite.Value)
  414. {
  415. return false;
  416. }
  417. }
  418. if (query.IsResumable.HasValue)
  419. {
  420. userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey());
  421. var isResumable = userData.PlaybackPositionTicks > 0;
  422. if (isResumable != query.IsResumable.Value)
  423. {
  424. return false;
  425. }
  426. }
  427. if (query.IsPlayed.HasValue)
  428. {
  429. if (item.IsPlayed(user) != query.IsPlayed.Value)
  430. {
  431. return false;
  432. }
  433. }
  434. return true;
  435. }
  436. private IEnumerable<Folder> GetMediaFolders(User user)
  437. {
  438. var excludeFolderIds = user.Configuration.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).ToList();
  439. return user.RootFolder
  440. .GetChildren(user, true, true)
  441. .OfType<Folder>()
  442. .Where(i => !excludeFolderIds.Contains(i.Id) && !UserView.IsExcludedFromGrouping(i));
  443. }
  444. private IEnumerable<Folder> GetMediaFolders(User user, string[] viewTypes)
  445. {
  446. return GetMediaFolders(user)
  447. .Where(i =>
  448. {
  449. var folder = i as ICollectionFolder;
  450. return folder != null && viewTypes.Contains(folder.CollectionType ?? string.Empty, StringComparer.OrdinalIgnoreCase);
  451. });
  452. }
  453. private IEnumerable<Folder> GetMediaFolders(Folder parent, User user, string[] viewTypes)
  454. {
  455. if (parent == null || parent is UserView)
  456. {
  457. return GetMediaFolders(user, viewTypes);
  458. }
  459. return new[] { parent };
  460. }
  461. private IEnumerable<BaseItem> GetRecursiveChildren(Folder parent, User user, string[] viewTypes)
  462. {
  463. if (parent == null || parent is UserView)
  464. {
  465. return GetMediaFolders(user, viewTypes).SelectMany(i => i.GetRecursiveChildren(user));
  466. }
  467. return parent.GetRecursiveChildren(user);
  468. }
  469. private async Task<IEnumerable<BaseItem>> GetLiveTvFolders(User user)
  470. {
  471. var list = new List<BaseItem>();
  472. list.Add(await _userViewManager.GetUserView(CollectionType.LiveTvNowPlaying, user, "0", CancellationToken.None).ConfigureAwait(false));
  473. list.Add(await _userViewManager.GetUserView(CollectionType.LiveTvChannels, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
  474. list.Add(await _userViewManager.GetUserView(CollectionType.LiveTvRecordingGroups, user, string.Empty, CancellationToken.None).ConfigureAwait(false));
  475. return list;
  476. }
  477. private async Task<UserView> GetUserView(string type, User user, string sortName, Folder parent)
  478. {
  479. var view = await _userViewManager.GetUserView(type, user, sortName, CancellationToken.None)
  480. .ConfigureAwait(false);
  481. if (parent.Id != view.ParentId)
  482. {
  483. view.ParentId = parent.Id;
  484. await view.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None)
  485. .ConfigureAwait(false);
  486. }
  487. return view;
  488. }
  489. }
  490. }