diff options
Diffstat (limited to 'MediaBrowser.Api/UserLibrary/ItemsService.cs')
| -rw-r--r-- | MediaBrowser.Api/UserLibrary/ItemsService.cs | 1385 |
1 files changed, 637 insertions, 748 deletions
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index 25821c213..cf9b0b438 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -7,15 +7,14 @@ using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using ServiceStack; using System; using System.Collections.Generic; using System.Globalization; -using System.IO; using System.Linq; +using System.Threading.Tasks; namespace MediaBrowser.Api.UserLibrary { @@ -47,13 +46,6 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "PersonTypes", Description = "Optional. If specified, along with Person, results will be filtered to include only those containing the specified person and PersonType. Allows multiple, comma-delimited", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] public string PersonTypes { get; set; } - /// <summary> - /// Limit results to items containing specific genres - /// </summary> - /// <value>The genres.</value> - [ApiMember(Name = "Genres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] - public string Genres { get; set; } - [ApiMember(Name = "AllGenres", Description = "Optional. If specified, results will be filtered based on genre. This allows multiple, pipe delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] public string AllGenres { get; set; } @@ -75,13 +67,6 @@ namespace MediaBrowser.Api.UserLibrary public string Albums { get; set; } /// <summary> - /// Limit results to items containing specific years - /// </summary> - /// <value>The years.</value> - [ApiMember(Name = "Years", Description = "Optional. If specified, results will be filtered based on production year. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)] - public string Years { get; set; } - - /// <summary> /// Gets or sets the item ids. /// </summary> /// <value>The item ids.</value> @@ -242,6 +227,33 @@ namespace MediaBrowser.Api.UserLibrary [ApiMember(Name = "CollapseBoxSetItems", Description = "Whether or not to hide items behind their boxsets.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] public bool? CollapseBoxSetItems { get; set; } + + public string[] GetAllGenres() + { + return (AllGenres ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); + } + + public string[] GetStudios() + { + return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries); + } + + public string[] GetPersonTypes() + { + return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); + } + + public IEnumerable<VideoType> GetVideoTypes() + { + var val = VideoTypes; + + if (string.IsNullOrEmpty(val)) + { + return new VideoType[] { }; + } + + return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)); + } } /// <summary> @@ -289,9 +301,9 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> /// <param name="request">The request.</param> /// <returns>System.Object.</returns> - public object Get(GetItems request) + public async Task<object> Get(GetItems request) { - var result = GetItems(request); + var result = await GetItems(request).ConfigureAwait(false); return ToOptimizedSerializedResultUsingCache(result); } @@ -301,16 +313,26 @@ namespace MediaBrowser.Api.UserLibrary /// </summary> /// <param name="request">The request.</param> /// <returns>Task{ItemsResult}.</returns> - private ItemsResult GetItems(GetItems request) + private async Task<ItemsResult> GetItems(GetItems request) { var parentItem = string.IsNullOrEmpty(request.ParentId) ? null : _libraryManager.GetItemById(request.ParentId); var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null; - var items = GetItemsToSerialize(request, user, parentItem); + var result = await GetItemsToSerialize(request, user, parentItem).ConfigureAwait(false); + + var isFiltered = result.Item2; + var dtoOptions = request.GetDtoOptions(); - items = items.AsParallel(); + if (isFiltered) + { + return new ItemsResult + { + TotalRecordCount = result.Item1.TotalRecordCount, + Items = result.Item1.Items.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray() + }; + } - items = ApplyAdditionalFilters(request, items, user); + var items = result.Item1.Items.Where(i => ApplyAdditionalFilters(request, i, user, false, _libraryManager)); // Apply filters // Run them starting with the ones that are likely to reduce the list the most @@ -319,32 +341,28 @@ namespace MediaBrowser.Api.UserLibrary items = ApplyFilter(items, filter, user, _userDataRepository); } - items = FilterVirtualEpisodes(request, items, user); + items = UserViewBuilder.FilterVirtualEpisodes(items, + request.IsMissing, + request.IsVirtualUnaired, + request.IsUnaired); - items = items.AsEnumerable(); + var internalQuery = GetItemsQuery(request, user); - if (CollapseBoxSetItems(request, parentItem, user)) - { - items = _collectionManager.CollapseItemsWithinBoxSets(items, user); - } + items = UserViewBuilder.CollapseBoxSetItemsIfNeeded(items, internalQuery, parentItem, user); - items = ApplyPostCollectionCollapseFilters(request, items, user); - - items = ApplySortOrder(request, items, user, _libraryManager); + items = _libraryManager.Sort(items, user, request.GetOrderBy(), request.SortOrder ?? SortOrder.Ascending); // This must be the last filter if (!string.IsNullOrEmpty(request.AdjacentTo)) { - items = FilterForAdjacency(items, request.AdjacentTo); + items = UserViewBuilder.FilterForAdjacency(items, request.AdjacentTo); } var itemsArray = items.ToList(); var pagedItems = ApplyPaging(request, itemsArray); - var fields = request.GetItemFields().ToList(); - - var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, fields, user)).ToArray(); + var returnItems = pagedItems.Select(i => _dtoService.GetBaseItemDto(i, dtoOptions, user)).ToArray(); return new ItemsResult { @@ -353,33 +371,6 @@ namespace MediaBrowser.Api.UserLibrary }; } - private bool CollapseBoxSetItems(GetItems request, BaseItem parentItem, User user) - { - // Could end up stuck in a loop like this - if (parentItem is BoxSet) - { - return false; - } - - var param = request.CollapseBoxSetItems; - - if (!param.HasValue) - { - if (user != null && !user.Configuration.GroupMoviesIntoBoxSets) - { - return false; - } - - if (!string.IsNullOrWhiteSpace(request.IncludeItemTypes) && - request.IncludeItemTypes.Split(',').Contains("Movie", StringComparer.OrdinalIgnoreCase)) - { - param = true; - } - } - - return param.HasValue && param.Value && AllowBoxSetCollapsing(request); - } - /// <summary> /// Gets the items to serialize. /// </summary> @@ -387,8 +378,7 @@ namespace MediaBrowser.Api.UserLibrary /// <param name="user">The user.</param> /// <param name="parentItem">The parent item.</param> /// <returns>IEnumerable{BaseItem}.</returns> - /// <exception cref="System.InvalidOperationException"></exception> - private IEnumerable<BaseItem> GetItemsToSerialize(GetItems request, User user, BaseItem parentItem) + private async Task<Tuple<QueryResult<BaseItem>, bool>> GetItemsToSerialize(GetItems request, User user, BaseItem parentItem) { var item = string.IsNullOrEmpty(request.ParentId) ? user == null ? _libraryManager.RootFolder : user.RootFolder : @@ -406,19 +396,40 @@ namespace MediaBrowser.Api.UserLibrary else if (request.Recursive) { - items = user == null ? - ((Folder)item).RecursiveChildren : - ((Folder)item).GetRecursiveChildren(user); + if (user == null) + { + items = ((Folder)item).RecursiveChildren; - items = _libraryManager.ReplaceVideosWithPrimaryVersions(items); + items = _libraryManager.ReplaceVideosWithPrimaryVersions(items); + } + else + { + var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)); + + return new Tuple<QueryResult<BaseItem>, bool>(result, true); + } } else { - items = user == null ? - ((Folder)item).Children : - ((Folder)item).GetChildren(user, true); + if (user == null) + { + items = ((Folder)item).Children; - items = _libraryManager.ReplaceVideosWithPrimaryVersions(items); + items = _libraryManager.ReplaceVideosWithPrimaryVersions(items); + } + else + { + var userRoot = item as UserRootFolder; + + if (userRoot == null) + { + var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)); + + return new Tuple<QueryResult<BaseItem>, bool>(result, true); + } + + items = ((Folder)item).GetChildren(user, true); + } } if (request.IncludeIndexContainers) @@ -430,25 +441,113 @@ namespace MediaBrowser.Api.UserLibrary list.AddRange(containers); - return list.Distinct(); + items = list.Distinct(); } - return items; + return new Tuple<QueryResult<BaseItem>, bool>(new QueryResult<BaseItem> + { + Items = items.ToArray() + + }, false); } - /// <summary> - /// Applies sort order - /// </summary> - /// <param name="request">The request.</param> - /// <param name="items">The items.</param> - /// <param name="user">The user.</param> - /// <param name="libraryManager">The library manager.</param> - /// <returns>IEnumerable{BaseItem}.</returns> - internal static IEnumerable<BaseItem> ApplySortOrder(BaseItemsRequest request, IEnumerable<BaseItem> items, User user, ILibraryManager libraryManager) + private InternalItemsQuery GetItemsQuery(GetItems request, User user) { - var orderBy = request.GetOrderBy().ToList(); + var query = new InternalItemsQuery + { + User = user, + IsPlayed = request.IsPlayed, + MediaTypes = request.GetMediaTypes(), + IncludeItemTypes = request.GetIncludeItemTypes(), + ExcludeItemTypes = request.GetExcludeItemTypes(), + Recursive = request.Recursive, + SortBy = request.GetOrderBy(), + SortOrder = request.SortOrder ?? SortOrder.Ascending, + + Filter = (i, u) => ApplyAdditionalFilters(request, i, u, true, _libraryManager), + + Limit = request.Limit, + StartIndex = request.StartIndex, + IsMissing = request.IsMissing, + IsVirtualUnaired = request.IsVirtualUnaired, + IsUnaired = request.IsUnaired, + CollapseBoxSetItems = request.CollapseBoxSetItems, + NameLessThan = request.NameLessThan, + NameStartsWith = request.NameStartsWith, + NameStartsWithOrGreater = request.NameStartsWithOrGreater, + HasImdbId = request.HasImdbId, + IsYearMismatched = request.IsYearMismatched, + IsUnidentified = request.IsUnidentified, + IsPlaceHolder = request.IsPlaceHolder, + IsLocked = request.IsLocked, + IsInBoxSet = request.IsInBoxSet, + IsHD = request.IsHD, + Is3D = request.Is3D, + HasTvdbId = request.HasTvdbId, + HasTmdbId = request.HasTmdbId, + HasOverview = request.HasOverview, + HasOfficialRating = request.HasOfficialRating, + HasParentalRating = request.HasParentalRating, + HasSpecialFeature = request.HasSpecialFeature, + HasSubtitles = request.HasSubtitles, + HasThemeSong = request.HasThemeSong, + HasThemeVideo = request.HasThemeVideo, + HasTrailer = request.HasTrailer, + Tags = request.GetTags(), + OfficialRatings = request.GetOfficialRatings(), + Genres = request.GetGenres(), + AllGenres = request.GetAllGenres(), + Studios = request.GetStudios(), + Person = request.Person, + PersonTypes = request.GetPersonTypes(), + Years = request.GetYears(), + ImageTypes = request.GetImageTypes().ToArray(), + VideoTypes = request.GetVideoTypes().ToArray(), + AdjacentTo = request.AdjacentTo + }; - return orderBy.Count == 0 ? items : libraryManager.Sort(items, user, orderBy, request.SortOrder ?? SortOrder.Ascending); + if (!string.IsNullOrWhiteSpace(request.Ids)) + { + query.CollapseBoxSetItems = false; + } + + foreach (var filter in request.GetFilters()) + { + switch (filter) + { + case ItemFilter.Dislikes: + query.IsLiked = false; + break; + case ItemFilter.IsFavorite: + query.IsFavorite = true; + break; + case ItemFilter.IsFavoriteOrLikes: + query.IsFavoriteOrLiked = true; + break; + case ItemFilter.IsFolder: + query.IsFolder = true; + break; + case ItemFilter.IsNotFolder: + query.IsFolder = false; + break; + case ItemFilter.IsPlayed: + query.IsPlayed = true; + break; + case ItemFilter.IsRecentlyAdded: + break; + case ItemFilter.IsResumable: + query.IsResumable = true; + break; + case ItemFilter.IsUnplayed: + query.IsPlayed = false; + break; + case ItemFilter.Likes: + query.IsLiked = true; + break; + } + } + + return query; } /// <summary> @@ -533,409 +632,266 @@ namespace MediaBrowser.Api.UserLibrary return items; } - private IEnumerable<BaseItem> FilterVirtualEpisodes(GetItems request, IEnumerable<BaseItem> items, User user) + private bool ApplyAdditionalFilters(GetItems request, BaseItem i, User user, bool isPreFiltered, ILibraryManager libraryManager) { - items = FilterVirtualSeasons(request, items, user); - - if (request.IsMissing.HasValue) + if (!isPreFiltered) { - var val = request.IsMissing.Value; - items = items.Where(i => + var mediaTypes = request.GetMediaTypes(); + if (mediaTypes.Length > 0) { - var e = i as Episode; - if (e != null) + if (!(!string.IsNullOrEmpty(i.MediaType) && mediaTypes.Contains(i.MediaType, StringComparer.OrdinalIgnoreCase))) { - return e.IsMissingEpisode == val; + return false; } - return true; - }); - } + } - if (request.IsUnaired.HasValue) - { - var val = request.IsUnaired.Value; - items = items.Where(i => + if (request.IsPlayed.HasValue) { - var e = i as Episode; - if (e != null) + var val = request.IsPlayed.Value; + if (i.IsPlayed(user) != val) { - return e.IsUnaired == val; + return false; } - return true; - }); - } + } - if (request.IsVirtualUnaired.HasValue) - { - var val = request.IsVirtualUnaired.Value; - items = items.Where(i => + // Exclude item types + var excluteItemTypes = request.GetExcludeItemTypes(); + if (excluteItemTypes.Length > 0 && excluteItemTypes.Contains(i.GetType().Name, StringComparer.OrdinalIgnoreCase)) { - var e = i as Episode; - if (e != null) - { - return e.IsVirtualUnaired == val; - } - return true; - }); - } - - return items; - } + return false; + } - private IEnumerable<BaseItem> FilterVirtualSeasons(GetItems request, IEnumerable<BaseItem> items, User user) - { - if (request.IsMissing.HasValue && request.IsVirtualUnaired.HasValue) - { - var isMissing = request.IsMissing.Value; - var isVirtualUnaired = request.IsVirtualUnaired.Value; + // Include item types + var includeItemTypes = request.GetIncludeItemTypes(); + if (includeItemTypes.Length > 0 && !includeItemTypes.Contains(i.GetType().Name, StringComparer.OrdinalIgnoreCase)) + { + return false; + } - if (!isMissing && !isVirtualUnaired) + if (request.IsInBoxSet.HasValue) { - return items.Where(i => + var val = request.IsInBoxSet.Value; + if (i.Parents.OfType<BoxSet>().Any() != val) { - var e = i as Season; - if (e != null) - { - return !e.IsMissingOrVirtualUnaired; - } - return true; - }); + return false; + } } - } - if (request.IsMissing.HasValue) - { - var val = request.IsMissing.Value; - items = items.Where(i => + // Filter by Video3DFormat + if (request.Is3D.HasValue) { - var e = i as Season; - if (e != null) + var val = request.Is3D.Value; + var video = i as Video; + + if (video == null || val != video.Video3DFormat.HasValue) { - return e.IsMissingSeason == val; + return false; } - return true; - }); - } + } - if (request.IsUnaired.HasValue) - { - var val = request.IsUnaired.Value; - items = items.Where(i => + if (request.IsHD.HasValue) { - var e = i as Season; - if (e != null) + var val = request.IsHD.Value; + var video = i as Video; + + if (video == null || val != video.IsHD) { - return e.IsUnaired == val; + return false; } - return true; - }); - } + } - if (request.IsVirtualUnaired.HasValue) - { - var val = request.IsVirtualUnaired.Value; - items = items.Where(i => + if (request.IsUnidentified.HasValue) { - var e = i as Season; - if (e != null) + var val = request.IsUnidentified.Value; + if (i.IsUnidentified != val) { - return e.IsVirtualUnaired == val; + return false; } - return true; - }); - } + } - return items; - } + if (request.IsLocked.HasValue) + { + var val = request.IsLocked.Value; + if (i.IsLocked != val) + { + return false; + } + } - /// <summary> - /// Applies the additional filters. - /// </summary> - /// <param name="request">The request.</param> - /// <param name="items">The items.</param> - /// <returns>IEnumerable{BaseItem}.</returns> - private IEnumerable<BaseItem> ApplyAdditionalFilters(GetItems request, IEnumerable<BaseItem> items, User user) - { - if (request.MinCommunityRating.HasValue) - { - var val = request.MinCommunityRating.Value; + if (request.HasOverview.HasValue) + { + var filterValue = request.HasOverview.Value; - items = items.Where(i => i.CommunityRating.HasValue && i.CommunityRating >= val); - } + var hasValue = !string.IsNullOrEmpty(i.Overview); - if (request.MinCriticRating.HasValue) - { - var val = request.MinCriticRating.Value; + if (hasValue != filterValue) + { + return false; + } + } - items = items.Where(i => + if (request.HasImdbId.HasValue) { - var hasCriticRating = i as IHasCriticRating; + var filterValue = request.HasImdbId.Value; - if (hasCriticRating != null) + var hasValue = !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Imdb)); + + if (hasValue != filterValue) { - return hasCriticRating.CriticRating.HasValue && hasCriticRating.CriticRating >= val; + return false; } + } - return false; - }); - } + if (request.HasTmdbId.HasValue) + { + var filterValue = request.HasTmdbId.Value; - // Artists - if (!string.IsNullOrEmpty(request.Artists)) - { - var artists = request.Artists.Split('|'); + var hasValue = !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb)); - items = items.Where(i => + if (hasValue != filterValue) + { + return false; + } + } + + if (request.HasTvdbId.HasValue) { - var audio = i as IHasArtist; + var filterValue = request.HasTvdbId.Value; - return audio != null && artists.Any(audio.HasArtist); - }); - } + var hasValue = !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)); - // Albums - if (!string.IsNullOrEmpty(request.Albums)) - { - var albums = request.Albums.Split('|'); + if (hasValue != filterValue) + { + return false; + } + } - items = items.Where(i => + if (request.IsYearMismatched.HasValue) { - var audio = i as Audio; + var filterValue = request.IsYearMismatched.Value; - if (audio != null) + if (UserViewBuilder.IsYearMismatched(i, libraryManager) != filterValue) { - return albums.Any(a => string.Equals(a, audio.Album, StringComparison.OrdinalIgnoreCase)); + return false; } + } - var album = i as MusicAlbum; + if (request.HasOfficialRating.HasValue) + { + var filterValue = request.HasOfficialRating.Value; - if (album != null) + var hasValue = !string.IsNullOrEmpty(i.OfficialRating); + + if (hasValue != filterValue) { - return albums.Any(a => string.Equals(a, album.Name, StringComparison.OrdinalIgnoreCase)); + return false; } + } - var musicVideo = i as MusicVideo; + if (request.IsPlaceHolder.HasValue) + { + var filterValue = request.IsPlaceHolder.Value; + + var isPlaceHolder = false; - if (musicVideo != null) + var hasPlaceHolder = i as ISupportsPlaceHolders; + + if (hasPlaceHolder != null) { - return albums.Any(a => string.Equals(a, musicVideo.Album, StringComparison.OrdinalIgnoreCase)); + isPlaceHolder = hasPlaceHolder.IsPlaceHolder; } - return false; - }); - } + if (isPlaceHolder != filterValue) + { + return false; + } + } - // Min index number - if (request.MinIndexNumber.HasValue) - { - items = items.Where(i => i.IndexNumber.HasValue && i.IndexNumber.Value >= request.MinIndexNumber.Value); - } + if (request.HasSpecialFeature.HasValue) + { + var filterValue = request.HasSpecialFeature.Value; - // Min official rating - if (!string.IsNullOrEmpty(request.MinOfficialRating)) - { - var level = _localization.GetRatingLevel(request.MinOfficialRating); + var movie = i as IHasSpecialFeatures; - if (level.HasValue) - { - items = items.Where(i => + if (movie != null) { - var rating = i.CustomRating; + var ok = filterValue + ? movie.SpecialFeatureIds.Count > 0 + : movie.SpecialFeatureIds.Count == 0; - if (string.IsNullOrEmpty(rating)) + if (!ok) { - rating = i.OfficialRating; + return false; } + } + else + { + return false; + } + } - if (string.IsNullOrEmpty(rating)) - { - return true; - } + if (request.HasSubtitles.HasValue) + { + var val = request.HasSubtitles.Value; - var itemLevel = _localization.GetRatingLevel(rating); + var video = i as Video; - return !itemLevel.HasValue || itemLevel.Value >= level.Value; - }); + if (video == null || val != video.HasSubtitles) + { + return false; + } } - } - // Max official rating - if (!string.IsNullOrEmpty(request.MaxOfficialRating)) - { - var level = _localization.GetRatingLevel(request.MaxOfficialRating); - - if (level.HasValue) + if (request.HasParentalRating.HasValue) { - items = items.Where(i => + var val = request.HasParentalRating.Value; + + var rating = i.CustomRating; + + if (string.IsNullOrEmpty(rating)) { - var rating = i.CustomRating; + rating = i.OfficialRating; + } + if (val) + { if (string.IsNullOrEmpty(rating)) { - rating = i.OfficialRating; + return false; } - - if (string.IsNullOrEmpty(rating)) + } + else + { + if (!string.IsNullOrEmpty(rating)) { - return true; + return false; } - - var itemLevel = _localization.GetRatingLevel(rating); - - return !itemLevel.HasValue || itemLevel.Value <= level.Value; - }); - } - } - - // Exclude item types - if (!string.IsNullOrEmpty(request.ExcludeItemTypes)) - { - var vals = request.ExcludeItemTypes.Split(','); - items = items.Where(f => !vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)); - } - - // Include item types - if (!string.IsNullOrEmpty(request.IncludeItemTypes)) - { - var vals = request.IncludeItemTypes.Split(','); - items = items.Where(f => vals.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)); - } - - // LocationTypes - if (!string.IsNullOrEmpty(request.LocationTypes)) - { - var vals = request.LocationTypes.Split(','); - items = items.Where(f => vals.Contains(f.LocationType.ToString(), StringComparer.OrdinalIgnoreCase)); - } - - // ExcludeLocationTypes - if (!string.IsNullOrEmpty(request.ExcludeLocationTypes)) - { - var vals = request.ExcludeLocationTypes.Split(','); - items = items.Where(f => !vals.Contains(f.LocationType.ToString(), StringComparer.OrdinalIgnoreCase)); - } - - if (!string.IsNullOrEmpty(request.AlbumArtistStartsWithOrGreater)) - { - items = items.OfType<IHasAlbumArtist>() - .Where(i => string.Compare(request.AlbumArtistStartsWithOrGreater, i.AlbumArtists.FirstOrDefault(), StringComparison.CurrentCultureIgnoreCase) < 1) - .Cast<BaseItem>(); - } - - // Filter by Series Status - if (!string.IsNullOrEmpty(request.SeriesStatus)) - { - var vals = request.SeriesStatus.Split(','); - - items = items.OfType<Series>().Where(i => i.Status.HasValue && vals.Contains(i.Status.Value.ToString(), StringComparer.OrdinalIgnoreCase)); - } - - // Filter by Series AirDays - if (!string.IsNullOrEmpty(request.AirDays)) - { - var days = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true)); - - items = items.OfType<Series>().Where(i => i.AirDays != null && days.Any(d => i.AirDays.Contains(d))); - } - - // Filter by Video3DFormat - if (request.Is3D.HasValue) - { - items = items.OfType<Video>().Where(i => request.Is3D.Value == i.Video3DFormat.HasValue); - } - - // Filter by VideoType - if (!string.IsNullOrEmpty(request.VideoTypes)) - { - var types = request.VideoTypes.Split(','); - - items = items.OfType<Video>().Where(i => types.Contains(i.VideoType.ToString(), StringComparer.OrdinalIgnoreCase)); - } - - if (!string.IsNullOrEmpty(request.MediaTypes)) - { - var types = request.MediaTypes.Split(','); - - items = items.Where(i => !string.IsNullOrEmpty(i.MediaType) && types.Contains(i.MediaType, StringComparer.OrdinalIgnoreCase)); - } - - var imageTypes = request.GetImageTypes().ToList(); - if (imageTypes.Count > 0) - { - items = items.Where(item => imageTypes.Any(imageType => HasImage(item, imageType))); - } - - // Apply genre filter - if (!string.IsNullOrEmpty(request.Genres)) - { - var vals = request.Genres.Split('|'); - items = items.Where(f => vals.Any(v => f.Genres.Contains(v, StringComparer.OrdinalIgnoreCase))); - } - - // Apply genre filter - if (!string.IsNullOrEmpty(request.AllGenres)) - { - var vals = request.AllGenres.Split('|'); - items = items.Where(f => vals.All(v => f.Genres.Contains(v, StringComparer.OrdinalIgnoreCase))); - } - - // Apply studio filter - if (!string.IsNullOrEmpty(request.Studios)) - { - var vals = request.Studios.Split('|'); - items = items.Where(f => vals.Any(v => f.Studios.Contains(v, StringComparer.OrdinalIgnoreCase))); - } - - // Apply year filter - if (!string.IsNullOrEmpty(request.Years)) - { - var vals = request.Years.Split(',').Select(int.Parse).ToList(); - items = items.Where(f => f.ProductionYear.HasValue && vals.Contains(f.ProductionYear.Value)); - } - - // Apply person filter - if (!string.IsNullOrEmpty(request.Person)) - { - var personTypes = request.PersonTypes; - - if (string.IsNullOrEmpty(personTypes)) - { - items = items.Where(item => item.People.Any(p => string.Equals(p.Name, request.Person, StringComparison.OrdinalIgnoreCase))); - } - else - { - var types = personTypes.Split(','); - - items = items.Where(item => - item.People != null && - item.People.Any(p => - p.Name.Equals(request.Person, StringComparison.OrdinalIgnoreCase) && (types.Contains(p.Type, StringComparer.OrdinalIgnoreCase) || types.Contains(p.Role, StringComparer.OrdinalIgnoreCase)))); + } } - } - if (request.HasTrailer.HasValue) - { - var val = request.HasTrailer.Value; - items = items.Where(i => + if (request.HasTrailer.HasValue) { + var val = request.HasTrailer.Value; var trailerCount = 0; var hasTrailers = i as IHasTrailers; if (hasTrailers != null) { - trailerCount = hasTrailers.LocalTrailerIds.Count; + trailerCount = hasTrailers.GetTrailerIds().Count; } - return val ? trailerCount > 0 : trailerCount == 0; - }); - } + var ok = val ? trailerCount > 0 : trailerCount == 0; - if (request.HasThemeSong.HasValue) - { - var filterValue = request.HasThemeSong.Value; + if (!ok) + { + return false; + } + } - items = items.Where(i => + if (request.HasThemeSong.HasValue) { + var filterValue = request.HasThemeSong.Value; + var themeCount = 0; var iHasThemeMedia = i as IHasThemeMedia; @@ -943,16 +899,18 @@ namespace MediaBrowser.Api.UserLibrary { themeCount = iHasThemeMedia.ThemeSongIds.Count; } - return filterValue ? themeCount > 0 : themeCount == 0; - }); - } + var ok = filterValue ? themeCount > 0 : themeCount == 0; - if (request.HasThemeVideo.HasValue) - { - var filterValue = request.HasThemeVideo.Value; + if (!ok) + { + return false; + } + } - items = items.Where(i => + if (request.HasThemeVideo.HasValue) { + var filterValue = request.HasThemeVideo.Value; + var themeCount = 0; var iHasThemeMedia = i as IHasThemeMedia; @@ -960,488 +918,419 @@ namespace MediaBrowser.Api.UserLibrary { themeCount = iHasThemeMedia.ThemeVideoIds.Count; } - return filterValue ? themeCount > 0 : themeCount == 0; - }); - } + var ok = filterValue ? themeCount > 0 : themeCount == 0; - if (request.MinPlayers.HasValue) - { - var filterValue = request.MinPlayers.Value; + if (!ok) + { + return false; + } + } - items = items.Where(i => + // Apply tag filter + var tags = request.GetTags(); + if (tags.Length > 0) { - var game = i as Game; - - if (game != null) + var hasTags = i as IHasTags; + if (hasTags == null) { - var players = game.PlayersSupported ?? 1; - - return players >= filterValue; + return false; } + if (!(tags.Any(v => hasTags.Tags.Contains(v, StringComparer.OrdinalIgnoreCase)))) + { + return false; + } + } + // Apply official rating filter + var officialRatings = request.GetOfficialRatings(); + if (officialRatings.Length > 0 && !officialRatings.Contains(i.OfficialRating ?? string.Empty)) + { return false; - }); - } - - if (request.MaxPlayers.HasValue) - { - var filterValue = request.MaxPlayers.Value; + } - items = items.Where(i => + // Apply genre filter + var genres = request.GetGenres(); + if (genres.Length > 0 && !(genres.Any(v => i.Genres.Contains(v, StringComparer.OrdinalIgnoreCase)))) { - var game = i as Game; - - if (game != null) - { - var players = game.PlayersSupported ?? 1; - - return players <= filterValue; - } - return false; - }); - } + } - if (request.HasSpecialFeature.HasValue) - { - var filterValue = request.HasSpecialFeature.Value; + // Apply genre filter + var allGenres = request.GetAllGenres(); + if (allGenres.Length > 0 && !allGenres.All(v => i.Genres.Contains(v, StringComparer.OrdinalIgnoreCase))) + { + return false; + } - items = items.Where(i => + // Filter by VideoType + if (!string.IsNullOrEmpty(request.VideoTypes)) { - var movie = i as Movie; + var types = request.VideoTypes.Split(','); - if (movie != null) + var video = i as Video; + if (video == null || !types.Contains(video.VideoType.ToString(), StringComparer.OrdinalIgnoreCase)) { - return filterValue - ? movie.SpecialFeatureIds.Count > 0 - : movie.SpecialFeatureIds.Count == 0; + return false; } + } - var series = i as Series; - - if (series != null) + var imageTypes = request.GetImageTypes().ToList(); + if (imageTypes.Count > 0) + { + if (!(imageTypes.Any(i.HasImage))) { - return filterValue - ? series.SpecialFeatureIds.Count > 0 - : series.SpecialFeatureIds.Count == 0; + return false; } + } + // Apply studio filter + var studios = request.GetStudios(); + if (studios.Length > 0 && !studios.Any(v => i.Studios.Contains(v, StringComparer.OrdinalIgnoreCase))) + { return false; - }); - } - - if (request.HasSubtitles.HasValue) - { - var val = request.HasSubtitles.Value; - - items = items.OfType<Video>().Where(i => val == i.HasSubtitles); - } + } - if (request.HasParentalRating.HasValue) - { - var val = request.HasParentalRating.Value; + // Apply year filter + var years = request.GetYears(); + if (years.Length > 0 && !(i.ProductionYear.HasValue && years.Contains(i.ProductionYear.Value))) + { + return false; + } - items = items.Where(i => + // Apply person filter + if (!string.IsNullOrEmpty(request.Person)) { - var rating = i.CustomRating; + var personTypes = request.GetPersonTypes(); - if (string.IsNullOrEmpty(rating)) + if (personTypes.Length == 0) { - rating = i.OfficialRating; + if (!(i.People.Any(p => string.Equals(p.Name, request.Person, StringComparison.OrdinalIgnoreCase)))) + { + return false; + } } - - if (val) + else { - return !string.IsNullOrEmpty(rating); - } - - return string.IsNullOrEmpty(rating); - }); - } + var types = personTypes; - if (request.IsHD.HasValue) - { - var val = request.IsHD.Value; - items = items.OfType<Video>().Where(i => i.IsHD == val); - } + var ok = new[] { i }.Any(item => + item.People != null && + item.People.Any(p => + p.Name.Equals(request.Person, StringComparison.OrdinalIgnoreCase) && (types.Contains(p.Type, StringComparer.OrdinalIgnoreCase) || types.Contains(p.Role, StringComparer.OrdinalIgnoreCase)))); - if (request.IsInBoxSet.HasValue) - { - var val = request.IsHD.Value; - items = items.Where(i => i.Parents.OfType<BoxSet>().Any() == val); + if (!ok) + { + return false; + } + } + } } - if (request.IsPlayed.HasValue) + if (request.MinCommunityRating.HasValue) { - var val = request.IsPlayed.Value; - items = items.Where(i => i.IsPlayed(user) == val); - } + var val = request.MinCommunityRating.Value; - if (request.IsUnidentified.HasValue) - { - var val = request.IsUnidentified.Value; - items = items.Where(i => i.IsUnidentified == val); + if (!(i.CommunityRating.HasValue && i.CommunityRating >= val)) + { + return false; + } } - if (request.IsLocked.HasValue) + if (request.MinCriticRating.HasValue) { - var val = request.IsLocked.Value; - items = items.Where(i => i.IsLocked == val); - } + var val = request.MinCriticRating.Value; - if (request.ParentIndexNumber.HasValue) - { - var filterValue = request.ParentIndexNumber.Value; + var hasCriticRating = i as IHasCriticRating; - items = items.Where(i => + if (hasCriticRating != null) { - var episode = i as Episode; - - if (episode != null) - { - return episode.ParentIndexNumber.HasValue && episode.ParentIndexNumber.Value == filterValue; - } - - var song = i as Audio; - - if (song != null) + if (!(hasCriticRating.CriticRating.HasValue && hasCriticRating.CriticRating >= val)) { - return song.ParentIndexNumber.HasValue && song.ParentIndexNumber.Value == filterValue; + return false; } - - return true; - }); - } - - if (request.AiredDuringSeason.HasValue) - { - items = Series.FilterEpisodesBySeason(items.OfType<Episode>(), request.AiredDuringSeason.Value, true); - } - - if (!string.IsNullOrEmpty(request.MinPremiereDate)) - { - var date = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); - - items = items.Where(i => i.PremiereDate.HasValue && i.PremiereDate.Value >= date); + } + else + { + return false; + } } - if (!string.IsNullOrEmpty(request.MaxPremiereDate)) + // Artists + if (!string.IsNullOrEmpty(request.Artists)) { - var date = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); - - items = items.Where(i => i.PremiereDate.HasValue && i.PremiereDate.Value <= date); - } + var artists = request.Artists.Split('|'); - if (request.HasOverview.HasValue) - { - var filterValue = request.HasOverview.Value; + var audio = i as IHasArtist; - items = items.Where(i => + if (!(audio != null && artists.Any(audio.HasArtist))) { - var hasValue = !string.IsNullOrEmpty(i.Overview); - - return hasValue == filterValue; - }); + return false; + } } - if (request.HasImdbId.HasValue) + // Albums + if (!string.IsNullOrEmpty(request.Albums)) { - var filterValue = request.HasImdbId.Value; - - items = items.Where(i => - { - var hasValue = !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Imdb)); - - return hasValue == filterValue; - }); - } + var albums = request.Albums.Split('|'); - if (request.HasTmdbId.HasValue) - { - var filterValue = request.HasTmdbId.Value; + var audio = i as Audio; - items = items.Where(i => + if (audio != null) { - var hasValue = !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tmdb)); - - return hasValue == filterValue; - }); - } + if (!albums.Any(a => string.Equals(a, audio.Album, StringComparison.OrdinalIgnoreCase))) + { + return false; + } + } - if (request.HasTvdbId.HasValue) - { - var filterValue = request.HasTvdbId.Value; + var album = i as MusicAlbum; - items = items.Where(i => + if (album != null) { - var hasValue = !string.IsNullOrEmpty(i.GetProviderId(MetadataProviders.Tvdb)); + if (!albums.Any(a => string.Equals(a, album.Name, StringComparison.OrdinalIgnoreCase))) + { + return false; + } + } - return hasValue == filterValue; - }); - } + var musicVideo = i as MusicVideo; - if (request.IsYearMismatched.HasValue) - { - var filterValue = request.IsYearMismatched.Value; + if (musicVideo != null) + { + if (!albums.Any(a => string.Equals(a, musicVideo.Album, StringComparison.OrdinalIgnoreCase))) + { + return false; + } + } - items = items.Where(i => IsYearMismatched(i) == filterValue); + return false; } - if (request.HasOfficialRating.HasValue) + // Min index number + if (request.MinIndexNumber.HasValue) { - var filterValue = request.HasOfficialRating.Value; - - items = items.Where(i => + if (!(i.IndexNumber.HasValue && i.IndexNumber.Value >= request.MinIndexNumber.Value)) { - var hasValue = !string.IsNullOrEmpty(i.OfficialRating); - - return hasValue == filterValue; - }); + return false; + } } - if (request.IsPlaceHolder.HasValue) + // Min official rating + if (!string.IsNullOrEmpty(request.MinOfficialRating)) { - var filterValue = request.IsPlaceHolder.Value; + var level = _localization.GetRatingLevel(request.MinOfficialRating); - items = items.Where(i => + if (level.HasValue) { - var isPlaceHolder = false; - - var hasPlaceHolder = i as ISupportsPlaceHolders; + var rating = i.CustomRating; - if (hasPlaceHolder != null) + if (string.IsNullOrEmpty(rating)) { - isPlaceHolder = hasPlaceHolder.IsPlaceHolder; + rating = i.OfficialRating; } - return isPlaceHolder == filterValue; - }); - } - - return items; - } - - private IEnumerable<BaseItem> ApplyPostCollectionCollapseFilters(GetItems 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(rating)) + { + var itemLevel = _localization.GetRatingLevel(rating); - if (!string.IsNullOrEmpty(request.NameLessThan)) - { - items = items.Where(i => string.Compare(request.NameLessThan, i.SortName, StringComparison.CurrentCultureIgnoreCase) == 1); + if (!(!itemLevel.HasValue || itemLevel.Value >= level.Value)) + { + return false; + } + } + } } - return items; - } - - private bool IsYearMismatched(BaseItem item) - { - if (item.ProductionYear.HasValue) + // Max official rating + if (!string.IsNullOrEmpty(request.MaxOfficialRating)) { - var path = item.Path; + var level = _localization.GetRatingLevel(request.MaxOfficialRating); - if (!string.IsNullOrEmpty(path)) + if (level.HasValue) { - int? yearInName; - string name; - NameParser.ParseName(Path.GetFileName(path), out name, out yearInName); + var rating = i.CustomRating; - // Go up a level if we didn't get a year - if (!yearInName.HasValue) + if (string.IsNullOrEmpty(rating)) { - NameParser.ParseName(Path.GetFileName(Path.GetDirectoryName(path)), out name, out yearInName); + rating = i.OfficialRating; } - if (yearInName.HasValue) + if (!string.IsNullOrEmpty(rating)) { - return yearInName.Value != item.ProductionYear.Value; + var itemLevel = _localization.GetRatingLevel(rating); + + if (!(!itemLevel.HasValue || itemLevel.Value <= level.Value)) + { + return false; + } } } } - return false; - } - - private bool AllowBoxSetCollapsing(GetItems request) - { - if (!string.IsNullOrWhiteSpace(request.Filters)) - { - return false; - } - - if (!string.IsNullOrWhiteSpace(request.AllGenres)) + // LocationTypes + if (!string.IsNullOrEmpty(request.LocationTypes)) { - return false; + var vals = request.LocationTypes.Split(','); + if (!vals.Contains(i.LocationType.ToString(), StringComparer.OrdinalIgnoreCase)) + { + return false; + } } - if (!string.IsNullOrWhiteSpace(request.Genres)) + // ExcludeLocationTypes + if (!string.IsNullOrEmpty(request.ExcludeLocationTypes)) { - return false; + var vals = request.ExcludeLocationTypes.Split(','); + if (vals.Contains(i.LocationType.ToString(), StringComparer.OrdinalIgnoreCase)) + { + return false; + } } - if (request.HasImdbId.HasValue) + if (!string.IsNullOrEmpty(request.AlbumArtistStartsWithOrGreater)) { - return false; - } + var ok = new[] { i }.OfType<IHasAlbumArtist>() + .Any(p => string.Compare(request.AlbumArtistStartsWithOrGreater, p.AlbumArtists.FirstOrDefault(), StringComparison.CurrentCultureIgnoreCase) < 1); - if (request.HasOfficialRating.HasValue) - { - return false; + if (!ok) + { + return false; + } } - if (request.HasOverview.HasValue) + // Filter by Series Status + if (!string.IsNullOrEmpty(request.SeriesStatus)) { - return false; - } + var vals = request.SeriesStatus.Split(','); - if (request.HasParentalRating.HasValue) - { - return false; - } + var ok = new[] { i }.OfType<Series>().Any(p => p.Status.HasValue && vals.Contains(p.Status.Value.ToString(), StringComparer.OrdinalIgnoreCase)); - if (request.HasSpecialFeature.HasValue) - { - return false; + if (!ok) + { + return false; + } } - if (request.HasSubtitles.HasValue) + // Filter by Series AirDays + if (!string.IsNullOrEmpty(request.AirDays)) { - return false; - } + var days = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true)); - if (request.HasThemeSong.HasValue) - { - return false; - } + var ok = new[] { i }.OfType<Series>().Any(p => p.AirDays != null && days.Any(d => p.AirDays.Contains(d))); - if (request.HasThemeVideo.HasValue) - { - return false; + if (!ok) + { + return false; + } } - if (request.HasTmdbId.HasValue) + if (request.MinPlayers.HasValue) { - return false; - } + var filterValue = request.MinPlayers.Value; - if (request.HasTrailer.HasValue) - { - return false; - } + var game = i as Game; - if (!string.IsNullOrWhiteSpace(request.Ids)) - { - return false; - } + if (game != null) + { + var players = game.PlayersSupported ?? 1; - if (!string.IsNullOrWhiteSpace(request.ImageTypes)) - { - return false; - } + var ok = players >= filterValue; - if (request.Is3D.HasValue) - { - return false; + if (!ok) + { + return false; + } + } + else + { + return false; + } } - if (request.IsHD.HasValue) + if (request.MaxPlayers.HasValue) { - return false; - } + var filterValue = request.MaxPlayers.Value; - if (request.IsInBoxSet.HasValue) - { - return false; - } + var game = i as Game; - if (request.IsLocked.HasValue) - { - return false; - } + if (game != null) + { + var players = game.PlayersSupported ?? 1; - if (request.IsPlaceHolder.HasValue) - { - return false; - } + var ok = players <= filterValue; - if (request.IsPlayed.HasValue) - { - return false; + if (!ok) + { + return false; + } + } + else + { + return false; + } } - if (request.IsUnidentified.HasValue) + if (request.ParentIndexNumber.HasValue) { - return false; - } + var filterValue = request.ParentIndexNumber.Value; - if (request.IsYearMismatched.HasValue) - { - return false; - } + var episode = i as Episode; - if (!string.IsNullOrWhiteSpace(request.Person)) - { - return false; - } + if (episode != null) + { + if (episode.ParentIndexNumber.HasValue && episode.ParentIndexNumber.Value != filterValue) + { + return false; + } + } - if (!string.IsNullOrWhiteSpace(request.Studios)) - { - return false; - } + var song = i as Audio; - if (!string.IsNullOrWhiteSpace(request.VideoTypes)) - { - return false; + if (song != null) + { + if (song.ParentIndexNumber.HasValue && song.ParentIndexNumber.Value != filterValue) + { + return false; + } + } } - if (!string.IsNullOrWhiteSpace(request.Years)) + if (request.AiredDuringSeason.HasValue) { - return false; - } + var episode = i as Episode; - return true; - } - - internal 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); + if (episode == null) + { + return false; + } - var previousId = Guid.Empty; - var nextId = Guid.Empty; + if (!Series.FilterEpisodesBySeason(new[] { episode }, request.AiredDuringSeason.Value, true).Any()) + { + return false; + } + } - if (index > 0) + if (!string.IsNullOrEmpty(request.MinPremiereDate)) { - previousId = list[index - 1].Id; + var date = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); + + if (!(i.PremiereDate.HasValue && i.PremiereDate.Value >= date)) + { + return false; + } } - if (index < list.Count - 1) + if (!string.IsNullOrEmpty(request.MaxPremiereDate)) { - nextId = list[index + 1].Id; - } + var date = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); - return list.Where(i => i.Id == previousId || i.Id == nextId || i.Id == adjacentToIdGuid); - } + if (!(i.PremiereDate.HasValue && i.PremiereDate.Value <= date)) + { + return false; + } + } - /// <summary> - /// Determines whether the specified item has image. - /// </summary> - /// <param name="item">The item.</param> - /// <param name="imageType">Type of the image.</param> - /// <returns><c>true</c> if the specified item has image; otherwise, <c>false</c>.</returns> - internal static bool HasImage(BaseItem item, ImageType imageType) - { - return item.HasImage(imageType); + return true; } /// <summary> |
