diff options
Diffstat (limited to 'MediaBrowser.Controller/Entities/UserViewBuilder.cs')
| -rw-r--r-- | MediaBrowser.Controller/Entities/UserViewBuilder.cs | 1298 |
1 files changed, 1099 insertions, 199 deletions
diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index 587cfae95..166d56c51 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -1,9 +1,11 @@ using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Providers; using MediaBrowser.Controller.TV; using MediaBrowser.Model.Channels; using MediaBrowser.Model.Entities; @@ -12,6 +14,7 @@ using MediaBrowser.Model.Logging; using MediaBrowser.Model.Querying; using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -27,8 +30,9 @@ namespace MediaBrowser.Controller.Entities private readonly ILogger _logger; private readonly IUserDataManager _userDataManager; private readonly ITVSeriesManager _tvSeriesManager; + private readonly ICollectionManager _collectionManager; - public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager) + public UserViewBuilder(IUserViewManager userViewManager, ILiveTvManager liveTvManager, IChannelManager channelManager, ILibraryManager libraryManager, ILogger logger, IUserDataManager userDataManager, ITVSeriesManager tvSeriesManager, ICollectionManager collectionManager) { _userViewManager = userViewManager; _liveTvManager = liveTvManager; @@ -37,9 +41,10 @@ namespace MediaBrowser.Controller.Entities _logger = logger; _userDataManager = userDataManager; _tvSeriesManager = tvSeriesManager; + _collectionManager = collectionManager; } - public async Task<QueryResult<BaseItem>> GetUserItems(Folder parent, string viewType, UserItemsQuery query) + public async Task<QueryResult<BaseItem>> GetUserItems(Folder queryParent, Folder displayParent, string viewType, InternalItemsQuery query) { var user = query.User; @@ -58,7 +63,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(result); } - case CollectionType.LiveTvChannels: + case SpecialFolder.LiveTvChannels: { var result = await _liveTvManager.GetInternalChannels(new LiveTvChannelQuery { @@ -71,7 +76,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(result); } - case CollectionType.LiveTvNowPlaying: + case SpecialFolder.LiveTvNowPlaying: { var result = await _liveTvManager.GetRecommendedProgramsInternal(new RecommendedProgramQuery { @@ -84,7 +89,7 @@ namespace MediaBrowser.Controller.Entities return GetResult(result); } - case CollectionType.LiveTvRecordingGroups: + case SpecialFolder.LiveTvRecordingGroups: { var result = await _liveTvManager.GetInternalRecordings(new RecordingQuery { @@ -102,110 +107,125 @@ namespace MediaBrowser.Controller.Entities { var result = await GetLiveTvFolders(user).ConfigureAwait(false); - return GetResult(result, query); + return GetResult(result, queryParent, query); } case CollectionType.Folders: - return GetResult(user.RootFolder.GetChildren(user, true), query); + return GetResult(user.RootFolder.GetChildren(user, true), queryParent, query); case CollectionType.Games: - return await GetGameView(user, parent, query).ConfigureAwait(false); + return await GetGameView(user, queryParent, query).ConfigureAwait(false); case CollectionType.BoxSets: - return GetResult(GetMediaFolders(user).SelectMany(i => i.GetRecursiveChildren(user)).OfType<BoxSet>(), query); + return GetResult(GetMediaFolders(user).SelectMany(i => i.GetRecursiveChildren(user)).OfType<BoxSet>(), queryParent, query); case CollectionType.TvShows: - return await GetTvView(parent, user, query).ConfigureAwait(false); + return await GetTvView(queryParent, user, query).ConfigureAwait(false); case CollectionType.Music: - return await GetMusicFolders(parent, user, query).ConfigureAwait(false); + return await GetMusicFolders(queryParent, user, query).ConfigureAwait(false); case CollectionType.Movies: - return await GetMovieFolders(parent, user, query).ConfigureAwait(false); + return await GetMovieFolders(queryParent, user, query).ConfigureAwait(false); - case CollectionType.GameGenres: - return GetGameGenres(parent, user, query); + case SpecialFolder.MusicGenres: + return await GetMusicGenres(queryParent, user, query).ConfigureAwait(false); - case CollectionType.GameSystems: - return GetGameSystems(parent, user, query); + case SpecialFolder.MusicGenre: + return await GetMusicGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false); - case CollectionType.LatestGames: - return GetLatestGames(parent, user, query); + case SpecialFolder.GameGenres: + return await GetGameGenres(queryParent, user, query).ConfigureAwait(false); - case CollectionType.RecentlyPlayedGames: - return GetRecentlyPlayedGames(parent, user, query); + case SpecialFolder.GameGenre: + return await GetGameGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false); - case CollectionType.GameFavorites: - return GetFavoriteGames(parent, user, query); + case SpecialFolder.GameSystems: + return GetGameSystems(queryParent, user, query); - case CollectionType.TvShowSeries: - return GetTvSeries(parent, user, query); + case SpecialFolder.LatestGames: + return GetLatestGames(queryParent, user, query); - case CollectionType.TvGenres: - return GetTvGenres(parent, user, query); + case SpecialFolder.RecentlyPlayedGames: + return GetRecentlyPlayedGames(queryParent, user, query); - case CollectionType.TvResume: - return GetTvResume(parent, user, query); + case SpecialFolder.GameFavorites: + return GetFavoriteGames(queryParent, user, query); - case CollectionType.TvNextUp: - return GetTvNextUp(parent, query); + case SpecialFolder.TvShowSeries: + return GetTvSeries(queryParent, user, query); - case CollectionType.TvLatest: - return GetTvLatest(parent, user, query); + case SpecialFolder.TvGenres: + return await GetTvGenres(queryParent, user, query).ConfigureAwait(false); - case CollectionType.MovieFavorites: - return GetFavoriteMovies(parent, user, query); + case SpecialFolder.TvGenre: + return await GetTvGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false); - case CollectionType.MovieLatest: - return GetMovieLatest(parent, user, query); + case SpecialFolder.TvResume: + return GetTvResume(queryParent, user, query); - case CollectionType.MovieGenres: - return GetMovieGenres(parent, user, query); + case SpecialFolder.TvNextUp: + return GetTvNextUp(queryParent, query); - case CollectionType.MovieResume: - return GetMovieResume(parent, user, query); + case SpecialFolder.TvLatest: + return GetTvLatest(queryParent, user, query); - case CollectionType.MovieMovies: - return GetMovieMovies(parent, user, query); + case SpecialFolder.MovieFavorites: + return GetFavoriteMovies(queryParent, user, query); - case CollectionType.MovieCollections: - return GetMovieCollections(parent, user, query); + case SpecialFolder.MovieLatest: + return GetMovieLatest(queryParent, user, query); - case CollectionType.MusicLatest: - return GetMusicLatest(parent, user, query); + case SpecialFolder.MovieGenres: + return await GetMovieGenres(queryParent, user, query).ConfigureAwait(false); - case CollectionType.MusicAlbums: - return GetMusicAlbums(parent, user, query); + case SpecialFolder.MovieGenre: + return await GetMovieGenreItems(queryParent, displayParent, user, query).ConfigureAwait(false); - case CollectionType.MusicAlbumArtists: - return GetMusicAlbumArtists(parent, user, query); + case SpecialFolder.MovieResume: + return GetMovieResume(queryParent, user, query); - case CollectionType.MusicArtists: - return GetMusicArtists(parent, user, query); + case SpecialFolder.MovieMovies: + return GetMovieMovies(queryParent, user, query); - case CollectionType.MusicSongs: - return GetMusicSongs(parent, user, query); + case SpecialFolder.MovieCollections: + return GetMovieCollections(queryParent, user, query); - case CollectionType.TvFavoriteEpisodes: - return GetFavoriteEpisodes(parent, user, query); + case SpecialFolder.MusicLatest: + return GetMusicLatest(queryParent, user, query); - case CollectionType.TvFavoriteSeries: - return GetFavoriteSeries(parent, user, query); + case SpecialFolder.MusicAlbums: + return GetMusicAlbums(queryParent, user, query); - case CollectionType.MusicFavorites: - return await GetMusicFavorites(parent, user, query).ConfigureAwait(false); + case SpecialFolder.MusicAlbumArtists: + return GetMusicAlbumArtists(queryParent, user, query); - case CollectionType.MusicFavoriteAlbums: - return GetFavoriteAlbums(parent, user, query); + case SpecialFolder.MusicArtists: + return GetMusicArtists(queryParent, user, query); - case CollectionType.MusicFavoriteArtists: - return GetFavoriteArtists(parent, user, query); + case SpecialFolder.MusicSongs: + return GetMusicSongs(queryParent, user, query); - case CollectionType.MusicFavoriteSongs: - return GetFavoriteSongs(parent, user, query); + case SpecialFolder.TvFavoriteEpisodes: + return GetFavoriteEpisodes(queryParent, user, query); + + case SpecialFolder.TvFavoriteSeries: + return GetFavoriteSeries(queryParent, user, query); + + case SpecialFolder.MusicFavorites: + return await GetMusicFavorites(queryParent, user, query).ConfigureAwait(false); + + case SpecialFolder.MusicFavoriteAlbums: + return GetFavoriteAlbums(queryParent, user, query); + + case SpecialFolder.MusicFavoriteArtists: + return GetFavoriteArtists(queryParent, user, query); + + case SpecialFolder.MusicFavoriteSongs: + return GetFavoriteSongs(queryParent, user, query); default: - return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), query); + return GetResult(GetMediaFolders(user).SelectMany(i => i.GetChildren(user, true)), queryParent, query); } } @@ -214,44 +234,93 @@ namespace MediaBrowser.Controller.Entities return 50; } - private async Task<QueryResult<BaseItem>> GetMusicFolders(Folder parent, User user, UserItemsQuery query) + private async Task<QueryResult<BaseItem>> GetMusicFolders(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }), parent, query); } var list = new List<BaseItem>(); - var category = "music"; + list.Add(await GetUserView(SpecialFolder.MusicLatest, user, "0", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MusicAlbums, user, "1", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MusicAlbumArtists, user, "2", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MusicArtists, user, "3", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MusicSongs, user, "4", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MusicGenres, user, "5", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MusicFavorites, user, "6", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MusicLatest, user, "0", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MusicAlbums, user, "1", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MusicAlbumArtists, user, "2", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MusicSongs, user, "3", parent).ConfigureAwait(false)); - //list.Add(await GetUserView(CollectionType.MusicArtists, user, "3", parent).ConfigureAwait(false)); - //list.Add(await GetUserView(CollectionType.MusicGenres, user, "5", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MusicFavorites, user, "6", parent).ConfigureAwait(false)); - - return GetResult(list, query); + return GetResult(list, parent, query); } - private async Task<QueryResult<BaseItem>> GetMusicFavorites(Folder parent, User user, UserItemsQuery query) + private async Task<QueryResult<BaseItem>> GetMusicFavorites(Folder parent, User user, InternalItemsQuery query) { var list = new List<BaseItem>(); - var category = "music"; + list.Add(await GetUserView(SpecialFolder.MusicFavoriteAlbums, user, "0", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MusicFavoriteArtists, user, "1", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MusicFavoriteSongs, user, "2", parent).ConfigureAwait(false)); + + return GetResult(list, parent, query); + } + + private async Task<QueryResult<BaseItem>> GetMusicGenres(Folder parent, User user, InternalItemsQuery query) + { + var tasks = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }) + .Where(i => !i.IsFolder) + .SelectMany(i => i.Genres) + .Distinct(StringComparer.OrdinalIgnoreCase) + .Select(i => + { + try + { + return _libraryManager.GetMusicGenre(i); + } + catch + { + // Full exception logged at lower levels + _logger.Error("Error getting genre"); + return null; + } + + }) + .Where(i => i != null) + .Select(i => GetUserView(i.Name, SpecialFolder.MusicGenre, user, i.SortName, parent)); + + var genres = await Task.WhenAll(tasks).ConfigureAwait(false); - list.Add(await GetUserView(category, CollectionType.MusicFavoriteAlbums, user, "0", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MusicFavoriteArtists, user, "1", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MusicFavoriteSongs, user, "2", parent).ConfigureAwait(false)); + return GetResult(genres, parent, query); + } + + private async Task<QueryResult<BaseItem>> GetMusicGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) + { + var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }) + .Where(i => !i.IsFolder) + .Where(i => i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase)) + .OfType<IHasAlbumArtist>() + .SelectMany(i => i.AlbumArtists) + .Distinct(StringComparer.OrdinalIgnoreCase) + .Select(i => + { + try + { + return _libraryManager.GetArtist(i); + } + catch + { + // Already logged at lower levels + return null; + } + }) + .Where(i => i != null); - return GetResult(list, query); + return GetResult(items, queryParent, query); } - private QueryResult<BaseItem> GetMusicAlbumArtists(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetMusicAlbumArtists(Folder parent, User user, InternalItemsQuery query) { - var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }) + var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }) .Where(i => !i.IsFolder) .OfType<IHasAlbumArtist>() .SelectMany(i => i.AlbumArtists) @@ -270,12 +339,12 @@ namespace MediaBrowser.Controller.Entities }) .Where(i => i != null); - return GetResult(artists, query); + return GetResult(artists, parent, query); } - private QueryResult<BaseItem> GetMusicArtists(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetMusicArtists(Folder parent, User user, InternalItemsQuery query) { - var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }) + var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }) .Where(i => !i.IsFolder) .OfType<IHasArtist>() .SelectMany(i => i.Artists) @@ -294,12 +363,12 @@ namespace MediaBrowser.Controller.Entities }) .Where(i => i != null); - return GetResult(artists, query); + return GetResult(artists, parent, query); } - private QueryResult<BaseItem> GetFavoriteArtists(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetFavoriteArtists(Folder parent, User user, InternalItemsQuery query) { - var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music }) + var artists = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }) .Where(i => !i.IsFolder) .OfType<IHasAlbumArtist>() .SelectMany(i => i.AlbumArtists) @@ -318,113 +387,111 @@ namespace MediaBrowser.Controller.Entities }) .Where(i => i != null && _userDataManager.GetUserData(user.Id, i.GetUserDataKey()).IsFavorite); - return GetResult(artists, query); + return GetResult(artists, parent, query); } - private QueryResult<BaseItem> GetMusicAlbums(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetMusicAlbums(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is MusicAlbum), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is MusicAlbum), parent, query); } - private QueryResult<BaseItem> GetMusicSongs(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetMusicSongs(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is Audio.Audio), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is Audio.Audio), parent, query); } - private QueryResult<BaseItem> GetMusicLatest(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetMusicLatest(Folder parent, User user, InternalItemsQuery query) { query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is MusicVideo || i is Audio.Audio), GetSpecialItemsLimit(), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }).Where(i => i is MusicVideo || i is Audio.Audio), parent, GetSpecialItemsLimit(), query); } - private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, UserItemsQuery query) + private async Task<QueryResult<BaseItem>> GetMovieFolders(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie || i is BoxSet), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie || i is BoxSet), parent, query); } var list = new List<BaseItem>(); - var category = "movies"; - - list.Add(await GetUserView(category, CollectionType.MovieResume, user, "0", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MovieLatest, user, "1", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MovieMovies, user, "2", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MovieCollections, user, "3", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.MovieFavorites, user, "4", parent).ConfigureAwait(false)); - //list.Add(await GetUserView(CollectionType.MovieGenres, user, "5", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MovieResume, user, "0", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MovieLatest, user, "1", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MovieMovies, user, "2", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MovieCollections, user, "3", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MovieFavorites, user, "4", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.MovieGenres, user, "5", parent).ConfigureAwait(false)); - return GetResult(list, query); + return GetResult(list, parent, query); } - private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetFavoriteMovies(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, query); } - private QueryResult<BaseItem> GetFavoriteSeries(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetFavoriteSeries(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series), parent, query); } - private QueryResult<BaseItem> GetFavoriteEpisodes(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetFavoriteEpisodes(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Episode), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Episode), parent, query); } - private QueryResult<BaseItem> GetFavoriteSongs(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetFavoriteSongs(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is Audio.Audio), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is Audio.Audio), parent, query); } - private QueryResult<BaseItem> GetFavoriteAlbums(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetFavoriteAlbums(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is MusicAlbum), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Music }).Where(i => i is MusicAlbum), parent, query); } - private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetMovieMovies(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, query); } - private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetMovieCollections(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is BoxSet), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is BoxSet), parent, query); } - private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetMovieLatest(Folder parent, User user, InternalItemsQuery query) { query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, GetSpecialItemsLimit(), query); } - private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetMovieResume(Folder parent, User user, InternalItemsQuery query) { query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; query.IsResumable = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), GetSpecialItemsLimit(), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }).Where(i => i is Movie), parent, GetSpecialItemsLimit(), query); } - private QueryResult<BaseItem> GetMovieGenres(Folder parent, User user, UserItemsQuery query) + private async Task<QueryResult<BaseItem>> GetMovieGenres(Folder parent, User user, InternalItemsQuery query) { - var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }) + var tasks = GetRecursiveChildren(parent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }) .Where(i => i is Movie) .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) @@ -442,86 +509,94 @@ namespace MediaBrowser.Controller.Entities } }) - .Where(i => i != null); + .Where(i => i != null) + .Select(i => GetUserView(i.Name, SpecialFolder.MovieGenre, user, i.SortName, parent)); + + var genres = await Task.WhenAll(tasks).ConfigureAwait(false); + + return GetResult(genres, parent, query); + } + + private async Task<QueryResult<BaseItem>> GetMovieGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) + { + var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Movies, CollectionType.BoxSets, string.Empty }) + .Where(i => i is Movie) + .Where(i => i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase)); - return GetResult(genres, query); + return GetResult(items, queryParent, query); } - private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, UserItemsQuery query) + private async Task<QueryResult<BaseItem>> GetTvView(Folder parent, User user, InternalItemsQuery query) { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series || i is Season || i is Episode), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).Where(i => i is Series || i is Season || i is Episode), parent, query); } var list = new List<BaseItem>(); - var category = "tvshows"; - - list.Add(await GetUserView(category, CollectionType.TvResume, user, "0", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.TvNextUp, user, "1", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.TvLatest, user, "2", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.TvShowSeries, user, "3", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.TvFavoriteSeries, user, "4", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.TvFavoriteEpisodes, user, "5", parent).ConfigureAwait(false)); - //list.Add(await GetUserView(CollectionType.TvGenres, user, "5", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.TvResume, user, "0", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.TvNextUp, user, "1", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.TvLatest, user, "2", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.TvShowSeries, user, "3", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.TvFavoriteSeries, user, "4", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.TvFavoriteEpisodes, user, "5", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.TvGenres, user, "6", parent).ConfigureAwait(false)); - return GetResult(list, query); + return GetResult(list, parent, query); } - private async Task<QueryResult<BaseItem>> GetGameView(User user, Folder parent, UserItemsQuery query) + private async Task<QueryResult<BaseItem>> GetGameView(User user, Folder parent, InternalItemsQuery query) { if (query.Recursive) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }), parent, query); } var list = new List<BaseItem>(); - var category = "games"; - - list.Add(await GetUserView(category, CollectionType.LatestGames, user, "0", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.RecentlyPlayedGames, user, "1", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.GameFavorites, user, "2", parent).ConfigureAwait(false)); - list.Add(await GetUserView(category, CollectionType.GameSystems, user, "3", parent).ConfigureAwait(false)); - //list.Add(await GetUserView(CollectionType.GameGenres, user, "4", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.LatestGames, user, "0", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.RecentlyPlayedGames, user, "1", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.GameFavorites, user, "2", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.GameSystems, user, "3", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.GameGenres, user, "4", parent).ConfigureAwait(false)); - return GetResult(list, query); + return GetResult(list, parent, query); } - private QueryResult<BaseItem> GetLatestGames(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetLatestGames(Folder parent, User user, InternalItemsQuery query) { query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), parent, GetSpecialItemsLimit(), query); } - private QueryResult<BaseItem> GetRecentlyPlayedGames(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetRecentlyPlayedGames(Folder parent, User user, InternalItemsQuery query) { query.IsPlayed = true; query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), GetSpecialItemsLimit(), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), parent, GetSpecialItemsLimit(), query); } - private QueryResult<BaseItem> GetFavoriteGames(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetFavoriteGames(Folder parent, User user, InternalItemsQuery query) { query.IsFavorite = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<Game>(), parent, query); } - private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetTvLatest(Folder parent, User user, InternalItemsQuery query) { query.SortBy = new[] { ItemSortBy.DateCreated, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), parent, GetSpecialItemsLimit(), query); } - private QueryResult<BaseItem> GetTvNextUp(Folder parent, UserItemsQuery query) + private QueryResult<BaseItem> GetTvNextUp(Folder parent, InternalItemsQuery query) { var parentFolders = GetMediaFolders(parent, query.User, new[] { CollectionType.TvShows, string.Empty }); @@ -536,23 +611,23 @@ namespace MediaBrowser.Controller.Entities return result; } - private QueryResult<BaseItem> GetTvResume(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetTvResume(Folder parent, User user, InternalItemsQuery query) { query.SortBy = new[] { ItemSortBy.DatePlayed, ItemSortBy.SortName }; query.SortOrder = SortOrder.Descending; query.IsResumable = true; - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), GetSpecialItemsLimit(), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Episode>(), parent, GetSpecialItemsLimit(), query); } - private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetTvSeries(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Series>(), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }).OfType<Series>(), parent, query); } - private QueryResult<BaseItem> GetTvGenres(Folder parent, User user, UserItemsQuery query) + private async Task<QueryResult<BaseItem>> GetTvGenres(Folder parent, User user, InternalItemsQuery query) { - var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }) + var tasks = GetRecursiveChildren(parent, user, new[] { CollectionType.TvShows, string.Empty }) .OfType<Series>() .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) @@ -570,19 +645,40 @@ namespace MediaBrowser.Controller.Entities } }) - .Where(i => i != null); + .Where(i => i != null) + .Select(i => GetUserView(i.Name, SpecialFolder.TvGenre, user, i.SortName, parent)); + + var genres = await Task.WhenAll(tasks).ConfigureAwait(false); + + return GetResult(genres, parent, query); + } + + private async Task<QueryResult<BaseItem>> GetTvGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) + { + var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.TvShows, string.Empty }) + .Where(i => i is Series) + .Where(i => i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase)); - return GetResult(genres, query); + return GetResult(items, queryParent, query); } - private QueryResult<BaseItem> GetGameSystems(Folder parent, User user, UserItemsQuery query) + private QueryResult<BaseItem> GetGameSystems(Folder parent, User user, InternalItemsQuery query) { - return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<GameSystem>(), query); + return GetResult(GetRecursiveChildren(parent, user, new[] { CollectionType.Games }).OfType<GameSystem>(), parent, query); } - private QueryResult<BaseItem> GetGameGenres(Folder parent, User user, UserItemsQuery query) + private async Task<QueryResult<BaseItem>> GetGameGenreItems(Folder queryParent, Folder displayParent, User user, InternalItemsQuery query) { - var genres = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }) + var items = GetRecursiveChildren(queryParent, user, new[] { CollectionType.Games }) + .OfType<Game>() + .Where(i => i.Genres.Contains(displayParent.Name, StringComparer.OrdinalIgnoreCase)); + + return GetResult(items, queryParent, query); + } + + private async Task<QueryResult<BaseItem>> GetGameGenres(Folder parent, User user, InternalItemsQuery query) + { + var tasks = GetRecursiveChildren(parent, user, new[] { CollectionType.Games }) .OfType<Game>() .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) @@ -600,9 +696,12 @@ namespace MediaBrowser.Controller.Entities } }) - .Where(i => i != null); + .Where(i => i != null) + .Select(i => GetUserView(i.Name, SpecialFolder.GameGenre, user, i.SortName, parent)); + + var genres = await Task.WhenAll(tasks).ConfigureAwait(false); - return GetResult(genres, query); + return GetResult(genres, parent, query); } private QueryResult<BaseItem> GetResult<T>(QueryResult<T> result) @@ -616,36 +715,401 @@ namespace MediaBrowser.Controller.Entities } private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items, - UserItemsQuery query) + BaseItem queryParent, + InternalItemsQuery query) where T : BaseItem { - return GetResult(items, null, query); + return GetResult(items, queryParent, null, query); } private QueryResult<BaseItem> GetResult<T>(IEnumerable<T> items, + BaseItem queryParent, int? totalRecordLimit, - UserItemsQuery query) + InternalItemsQuery query) where T : BaseItem { - return SortAndFilter(items, totalRecordLimit, query, _libraryManager, _userDataManager); + return SortAndFilter(items, queryParent, totalRecordLimit, query, _libraryManager, _userDataManager); } public static QueryResult<BaseItem> SortAndFilter(IEnumerable<BaseItem> items, + BaseItem queryParent, int? totalRecordLimit, - UserItemsQuery query, + InternalItemsQuery query, ILibraryManager libraryManager, IUserDataManager userDataManager) { var user = query.User; - items = items.Where(i => Filter(i, user, query, userDataManager)); + items = items.Where(i => Filter(i, user, query, userDataManager, libraryManager)); + + items = FilterVirtualEpisodes(items, + query.IsMissing, + query.IsVirtualUnaired, + query.IsUnaired); + + items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user); + + // This must be the last filter + if (!string.IsNullOrEmpty(query.AdjacentTo)) + { + items = FilterForAdjacency(items, query.AdjacentTo); + } return Sort(items, totalRecordLimit, query, libraryManager); } + public static IEnumerable<BaseItem> CollapseBoxSetItemsIfNeeded(IEnumerable<BaseItem> items, + InternalItemsQuery query, + BaseItem queryParent, + User user) + { + if (CollapseBoxSetItems(query, queryParent, user)) + { + items = BaseItem.CollectionManager.CollapseItemsWithinBoxSets(items, user); + } + + items = ApplyPostCollectionCollapseFilters(query, items, user); + + return items; + } + + private static IEnumerable<BaseItem> ApplyPostCollectionCollapseFilters(InternalItemsQuery request, + IEnumerable<BaseItem> items, + User user) + { + if (!string.IsNullOrEmpty(request.NameStartsWithOrGreater)) + { + items = items.Where(i => string.Compare(request.NameStartsWithOrGreater, i.SortName, StringComparison.CurrentCultureIgnoreCase) < 1); + } + if (!string.IsNullOrEmpty(request.NameStartsWith)) + { + items = items.Where(i => string.Compare(request.NameStartsWith, i.SortName.Substring(0, 1), StringComparison.CurrentCultureIgnoreCase) == 0); + } + + if (!string.IsNullOrEmpty(request.NameLessThan)) + { + items = items.Where(i => string.Compare(request.NameLessThan, i.SortName, StringComparison.CurrentCultureIgnoreCase) == 1); + } + + return items; + } + + private static bool CollapseBoxSetItems(InternalItemsQuery query, + BaseItem queryParent, + User user) + { + // Could end up stuck in a loop like this + if (queryParent is BoxSet) + { + return false; + } + + var param = query.CollapseBoxSetItems; + + if (!param.HasValue) + { + if (user != null && !user.Configuration.GroupMoviesIntoBoxSets) + { + return false; + } + + if (query.IncludeItemTypes.Contains("Movie", StringComparer.OrdinalIgnoreCase)) + { + param = true; + } + } + + return param.HasValue && param.Value && AllowBoxSetCollapsing(query); + } + + private static bool AllowBoxSetCollapsing(InternalItemsQuery request) + { + if (request.IsFavorite.HasValue) + { + return false; + } + if (request.IsFavoriteOrLiked.HasValue) + { + return false; + } + if (request.IsLiked.HasValue) + { + return false; + } + if (request.IsPlayed.HasValue) + { + return false; + } + if (request.IsResumable.HasValue) + { + return false; + } + if (request.IsFolder.HasValue) + { + return false; + } + + if (request.AllGenres.Length > 0) + { + return false; + } + + if (request.Genres.Length > 0) + { + return false; + } + + if (request.HasImdbId.HasValue) + { + return false; + } + + if (request.HasOfficialRating.HasValue) + { + return false; + } + + if (request.HasOverview.HasValue) + { + return false; + } + + if (request.HasParentalRating.HasValue) + { + return false; + } + + if (request.HasSpecialFeature.HasValue) + { + return false; + } + + if (request.HasSubtitles.HasValue) + { + return false; + } + + if (request.HasThemeSong.HasValue) + { + return false; + } + + if (request.HasThemeVideo.HasValue) + { + return false; + } + + if (request.HasTmdbId.HasValue) + { + return false; + } + + if (request.HasTrailer.HasValue) + { + return false; + } + + if (request.ImageTypes.Length > 0) + { + return false; + } + + if (request.Is3D.HasValue) + { + return false; + } + + if (request.IsHD.HasValue) + { + return false; + } + + if (request.IsInBoxSet.HasValue) + { + return false; + } + + if (request.IsLocked.HasValue) + { + return false; + } + + if (request.IsPlaceHolder.HasValue) + { + return false; + } + + if (request.IsPlayed.HasValue) + { + return false; + } + + if (request.IsUnidentified.HasValue) + { + return false; + } + + if (request.IsYearMismatched.HasValue) + { + return false; + } + + if (!string.IsNullOrWhiteSpace(request.Person)) + { + return false; + } + + if (request.Studios.Length > 0) + { + return false; + } + + if (request.VideoTypes.Length > 0) + { + return false; + } + + if (request.Years.Length > 0) + { + return false; + } + + if (request.Tags.Length > 0) + { + return false; + } + + if (request.OfficialRatings.Length > 0) + { + return false; + } + + return true; + } + + public static IEnumerable<BaseItem> FilterVirtualEpisodes( + IEnumerable<BaseItem> items, + bool? isMissing, + bool? isVirtualUnaired, + bool? isUnaired) + { + items = FilterVirtualSeasons(items, isMissing, isVirtualUnaired, isUnaired); + + if (isMissing.HasValue) + { + var val = isMissing.Value; + items = items.Where(i => + { + var e = i as Episode; + if (e != null) + { + return e.IsMissingEpisode == val; + } + return true; + }); + } + + if (isUnaired.HasValue) + { + var val = isUnaired.Value; + items = items.Where(i => + { + var e = i as Episode; + if (e != null) + { + return e.IsUnaired == val; + } + return true; + }); + } + + if (isVirtualUnaired.HasValue) + { + var val = isVirtualUnaired.Value; + items = items.Where(i => + { + var e = i as Episode; + if (e != null) + { + return e.IsVirtualUnaired == val; + } + return true; + }); + } + + return items; + } + + private static IEnumerable<BaseItem> FilterVirtualSeasons( + IEnumerable<BaseItem> items, + bool? isMissing, + bool? isVirtualUnaired, + bool? isUnaired) + { + if (isMissing.HasValue && isVirtualUnaired.HasValue) + { + if (!isMissing.Value && !isVirtualUnaired.Value) + { + return items.Where(i => + { + var e = i as Season; + if (e != null) + { + return !e.IsMissingOrVirtualUnaired; + } + return true; + }); + } + } + + if (isMissing.HasValue) + { + var val = isMissing.Value; + items = items.Where(i => + { + var e = i as Season; + if (e != null) + { + return e.IsMissingSeason == val; + } + return true; + }); + } + + if (isUnaired.HasValue) + { + var val = isUnaired.Value; + items = items.Where(i => + { + var e = i as Season; + if (e != null) + { + return e.IsUnaired == val; + } + return true; + }); + } + + if (isVirtualUnaired.HasValue) + { + var val = isVirtualUnaired.Value; + items = items.Where(i => + { + var e = i as Season; + if (e != null) + { + return e.IsVirtualUnaired == val; + } + return true; + }); + } + + return items; + } + public static QueryResult<BaseItem> Sort(IEnumerable<BaseItem> items, int? totalRecordLimit, - UserItemsQuery query, + InternalItemsQuery query, ILibraryManager libraryManager) { var user = query.User; @@ -676,13 +1140,23 @@ namespace MediaBrowser.Controller.Entities }; } - private static bool Filter(BaseItem item, User user, UserItemsQuery query, IUserDataManager userDataManager) + private static bool Filter(BaseItem item, User user, InternalItemsQuery query, IUserDataManager userDataManager, ILibraryManager libraryManager) { if (query.MediaTypes.Length > 0 && !query.MediaTypes.Contains(item.MediaType ?? string.Empty, StringComparer.OrdinalIgnoreCase)) { return false; } + if (query.IncludeItemTypes.Length > 0 && !query.IncludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase)) + { + return false; + } + + if (query.ExcludeItemTypes.Length > 0 && query.ExcludeItemTypes.Contains(item.GetClientTypeName(), StringComparer.OrdinalIgnoreCase)) + { + return false; + } + if (query.IsFolder.HasValue && query.IsFolder.Value != item.IsFolder) { return false; @@ -695,6 +1169,27 @@ namespace MediaBrowser.Controller.Entities UserItemData userData = null; + if (query.IsLiked.HasValue) + { + userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey()); + + if (!userData.Likes.HasValue || userData.Likes != query.IsLiked.Value) + { + return false; + } + } + + if (query.IsFavoriteOrLiked.HasValue) + { + userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey()); + var isFavoriteOrLiked = userData.IsFavorite || (userData.Likes ?? false); + + if (isFavoriteOrLiked != query.IsFavoriteOrLiked.Value) + { + return false; + } + } + if (query.IsFavorite.HasValue) { userData = userData ?? userDataManager.GetUserData(user.Id, item.GetUserDataKey()); @@ -724,6 +1219,355 @@ namespace MediaBrowser.Controller.Entities } } + if (query.IsInBoxSet.HasValue) + { + var val = query.IsInBoxSet.Value; + if (item.Parents.OfType<BoxSet>().Any() != val) + { + return false; + } + } + + // Filter by Video3DFormat + if (query.Is3D.HasValue) + { + var val = query.Is3D.Value; + var video = item as Video; + + if (video == null || val != video.Video3DFormat.HasValue) + { + return false; + } + } + + if (query.IsHD.HasValue) + { + var val = query.IsHD.Value; + var video = item as Video; + + if (video == null || val != video.IsHD) + { + return false; + } + } + + if (query.IsUnidentified.HasValue) + { + var val = query.IsUnidentified.Value; + if (item.IsUnidentified != val) + { + return false; + } + } + + if (query.IsLocked.HasValue) + { + var val = query.IsLocked.Value; + if (item.IsLocked != val) + { + return false; + } + } + + if (query.HasOverview.HasValue) + { + var filterValue = query.HasOverview.Value; + + var hasValue = !string.IsNullOrEmpty(item.Overview); + + if (hasValue != filterValue) + { + return false; + } + } + + if (query.HasImdbId.HasValue) + { + var filterValue = query.HasImdbId.Value; + + var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Imdb)); + + if (hasValue != filterValue) + { + return false; + } + } + + if (query.HasTmdbId.HasValue) + { + var filterValue = query.HasTmdbId.Value; + + var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tmdb)); + + if (hasValue != filterValue) + { + return false; + } + } + + if (query.HasTvdbId.HasValue) + { + var filterValue = query.HasTvdbId.Value; + + var hasValue = !string.IsNullOrEmpty(item.GetProviderId(MetadataProviders.Tvdb)); + + if (hasValue != filterValue) + { + return false; + } + } + + if (query.IsYearMismatched.HasValue) + { + var filterValue = query.IsYearMismatched.Value; + + if (IsYearMismatched(item, libraryManager) != filterValue) + { + return false; + } + } + + if (query.HasOfficialRating.HasValue) + { + var filterValue = query.HasOfficialRating.Value; + + var hasValue = !string.IsNullOrEmpty(item.OfficialRating); + + if (hasValue != filterValue) + { + return false; + } + } + + if (query.IsPlaceHolder.HasValue) + { + var filterValue = query.IsPlaceHolder.Value; + + var isPlaceHolder = false; + + var hasPlaceHolder = item as ISupportsPlaceHolders; + + if (hasPlaceHolder != null) + { + isPlaceHolder = hasPlaceHolder.IsPlaceHolder; + } + + if (isPlaceHolder != filterValue) + { + return false; + } + } + + if (query.HasSpecialFeature.HasValue) + { + var filterValue = query.HasSpecialFeature.Value; + + var movie = item as IHasSpecialFeatures; + + if (movie != null) + { + var ok = filterValue + ? movie.SpecialFeatureIds.Count > 0 + : movie.SpecialFeatureIds.Count == 0; + + if (!ok) + { + return false; + } + } + else + { + return false; + } + } + + if (query.HasSubtitles.HasValue) + { + var val = query.HasSubtitles.Value; + + var video = item as Video; + + if (video == null || val != video.HasSubtitles) + { + return false; + } + } + + if (query.HasParentalRating.HasValue) + { + var val = query.HasParentalRating.Value; + + var rating = item.CustomRating; + + if (string.IsNullOrEmpty(rating)) + { + rating = item.OfficialRating; + } + + if (val) + { + if (string.IsNullOrEmpty(rating)) + { + return false; + } + } + else + { + if (!string.IsNullOrEmpty(rating)) + { + return false; + } + } + } + + if (query.HasTrailer.HasValue) + { + var val = query.HasTrailer.Value; + var trailerCount = 0; + + var hasTrailers = item as IHasTrailers; + if (hasTrailers != null) + { + trailerCount = hasTrailers.GetTrailerIds().Count; + } + + var ok = val ? trailerCount > 0 : trailerCount == 0; + + if (!ok) + { + return false; + } + } + + if (query.HasThemeSong.HasValue) + { + var filterValue = query.HasThemeSong.Value; + + var themeCount = 0; + var iHasThemeMedia = item as IHasThemeMedia; + + if (iHasThemeMedia != null) + { + themeCount = iHasThemeMedia.ThemeSongIds.Count; + } + var ok = filterValue ? themeCount > 0 : themeCount == 0; + + if (!ok) + { + return false; + } + } + + if (query.HasThemeVideo.HasValue) + { + var filterValue = query.HasThemeVideo.Value; + + var themeCount = 0; + var iHasThemeMedia = item as IHasThemeMedia; + + if (iHasThemeMedia != null) + { + themeCount = iHasThemeMedia.ThemeVideoIds.Count; + } + var ok = filterValue ? themeCount > 0 : themeCount == 0; + + if (!ok) + { + return false; + } + } + + // Apply genre filter + if (query.Genres.Length > 0 && !(query.Genres.Any(v => item.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))) + { + return false; + } + + // Apply genre filter + if (query.AllGenres.Length > 0 && !query.AllGenres.All(v => item.Genres.Contains(v, StringComparer.OrdinalIgnoreCase))) + { + return false; + } + + // Filter by VideoType + if (query.VideoTypes.Length > 0) + { + var video = item as Video; + if (video == null || !query.VideoTypes.Contains(video.VideoType)) + { + return false; + } + } + + if (query.ImageTypes.Length > 0 && !query.ImageTypes.Any(item.HasImage)) + { + return false; + } + + // Apply studio filter + if (query.Studios.Length > 0 && !query.Studios.Any(v => item.Studios.Contains(v, StringComparer.OrdinalIgnoreCase))) + { + return false; + } + + // Apply year filter + if (query.Years.Length > 0) + { + if (!(item.ProductionYear.HasValue && query.Years.Contains(item.ProductionYear.Value))) + { + return false; + } + } + + // Apply official rating filter + if (query.OfficialRatings.Length > 0 && !query.OfficialRatings.Contains(item.OfficialRating ?? string.Empty)) + { + return false; + } + + // Apply person filter + if (!string.IsNullOrEmpty(query.Person)) + { + var personTypes = query.PersonTypes; + + if (personTypes.Length == 0) + { + if (!(item.People.Any(p => string.Equals(p.Name, query.Person, StringComparison.OrdinalIgnoreCase)))) + { + return false; + } + } + else + { + var types = personTypes; + + var ok = new[] { item }.Any(i => + i.People != null && + i.People.Any(p => + p.Name.Equals(query.Person, StringComparison.OrdinalIgnoreCase) && (types.Contains(p.Type, StringComparer.OrdinalIgnoreCase) || types.Contains(p.Role, StringComparer.OrdinalIgnoreCase)))); + + if (!ok) + { + return false; + } + } + } + + // Apply tag filter + var tags = query.Tags; + if (tags.Length > 0) + { + var hasTags = item as IHasTags; + if (hasTags == null) + { + return false; + } + if (!(tags.Any(v => hasTags.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))) + { + return false; + } + } + return true; } @@ -737,7 +1581,7 @@ namespace MediaBrowser.Controller.Entities .Where(i => !excludeFolderIds.Contains(i.Id) && !UserView.IsExcludedFromGrouping(i)); } - private IEnumerable<Folder> GetMediaFolders(User user, string[] viewTypes) + private IEnumerable<Folder> GetMediaFolders(User user, IEnumerable<string> viewTypes) { return GetMediaFolders(user) .Where(i => @@ -748,7 +1592,7 @@ namespace MediaBrowser.Controller.Entities }); } - private IEnumerable<Folder> GetMediaFolders(Folder parent, User user, string[] viewTypes) + private IEnumerable<Folder> GetMediaFolders(Folder parent, User user, IEnumerable<string> viewTypes) { if (parent == null || parent is UserView) { @@ -758,7 +1602,7 @@ namespace MediaBrowser.Controller.Entities return new[] { parent }; } - private IEnumerable<BaseItem> GetRecursiveChildren(Folder parent, User user, string[] viewTypes) + private IEnumerable<BaseItem> GetRecursiveChildren(Folder parent, User user, IEnumerable<string> viewTypes) { if (parent == null || parent is UserView) { @@ -772,26 +1616,82 @@ namespace MediaBrowser.Controller.Entities { var list = new List<BaseItem>(); - list.Add(await _userViewManager.GetUserView("livetv", CollectionType.LiveTvNowPlaying, user, "0", CancellationToken.None).ConfigureAwait(false)); - list.Add(await _userViewManager.GetUserView("livetv", CollectionType.LiveTvChannels, user, string.Empty, CancellationToken.None).ConfigureAwait(false)); - list.Add(await _userViewManager.GetUserView("livetv", CollectionType.LiveTvRecordingGroups, user, string.Empty, CancellationToken.None).ConfigureAwait(false)); + var parent = user.RootFolder; + + //list.Add(await GetUserView(SpecialFolder.LiveTvNowPlaying, user, "0", parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.LiveTvChannels, user, string.Empty, parent).ConfigureAwait(false)); + list.Add(await GetUserView(SpecialFolder.LiveTvRecordingGroups, user, string.Empty, parent).ConfigureAwait(false)); return list; } - private async Task<UserView> GetUserView(string category, string type, User user, string sortName, Folder parent) + private async Task<UserView> GetUserView(string name, string type, User user, string sortName, BaseItem parent) { - var view = await _userViewManager.GetUserView(category, type, user, sortName, CancellationToken.None) + var view = await _userViewManager.GetUserView(name, parent.Id.ToString("N"), type, user, sortName, CancellationToken.None) .ConfigureAwait(false); - if (parent.Id != view.ParentId) - { - view.ParentId = parent.Id; - await view.UpdateToRepository(ItemUpdateType.MetadataImport, CancellationToken.None) + return view; + } + + private async Task<UserView> GetUserView(string type, User user, string sortName, BaseItem parent) + { + var view = await _userViewManager.GetUserView(parent.Id.ToString("N"), type, user, sortName, CancellationToken.None) .ConfigureAwait(false); - } return view; } + + public static bool IsYearMismatched(BaseItem item, ILibraryManager libraryManager) + { + if (item.ProductionYear.HasValue) + { + var path = item.Path; + + if (!string.IsNullOrEmpty(path)) + { + var info = libraryManager.ParseName(Path.GetFileName(path)); + var yearInName = info.Year; + + // Go up a level if we didn't get a year + if (!yearInName.HasValue) + { + info = libraryManager.ParseName(Path.GetFileName(Path.GetDirectoryName(path))); + yearInName = info.Year; + } + + if (yearInName.HasValue) + { + return yearInName.Value != item.ProductionYear.Value; + } + } + } + + return false; + } + + public static IEnumerable<BaseItem> FilterForAdjacency(IEnumerable<BaseItem> items, string adjacentToId) + { + var list = items.ToList(); + + var adjacentToIdGuid = new Guid(adjacentToId); + var adjacentToItem = list.FirstOrDefault(i => i.Id == adjacentToIdGuid); + + var index = list.IndexOf(adjacentToItem); + + var previousId = Guid.Empty; + var nextId = Guid.Empty; + + if (index > 0) + { + previousId = list[index - 1].Id; + } + + if (index < list.Count - 1) + { + nextId = list[index + 1].Id; + } + + return list.Where(i => i.Id == previousId || i.Id == nextId || i.Id == adjacentToIdGuid); + } } } |
