using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Localization; using MediaBrowser.Controller.Net; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Querying; using ServiceStack; using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Threading.Tasks; namespace MediaBrowser.Api.UserLibrary { /// /// Class GetItems /// [Route("/Items", "GET", Summary = "Gets items based on a query.")] [Route("/Users/{UserId}/Items", "GET", Summary = "Gets items based on a query.")] public class GetItems : BaseItemsRequest, IReturn { } /// /// Class ItemsService /// [Authenticated] public class ItemsService : BaseApiService { /// /// The _user manager /// private readonly IUserManager _userManager; private readonly IUserDataManager _userDataRepository; /// /// The _library manager /// private readonly ILibraryManager _libraryManager; private readonly ILocalizationManager _localization; private readonly IDtoService _dtoService; private readonly ICollectionManager _collectionManager; /// /// Initializes a new instance of the class. /// /// The user manager. /// The library manager. /// The user data repository. /// The localization. /// The dto service. /// The collection manager. public ItemsService(IUserManager userManager, ILibraryManager libraryManager, IUserDataManager userDataRepository, ILocalizationManager localization, IDtoService dtoService, ICollectionManager collectionManager) { _userManager = userManager; _libraryManager = libraryManager; _userDataRepository = userDataRepository; _localization = localization; _dtoService = dtoService; _collectionManager = collectionManager; } /// /// Gets the specified request. /// /// The request. /// System.Object. public async Task Get(GetItems request) { var result = await GetItems(request).ConfigureAwait(false); return ToOptimizedSerializedResultUsingCache(result); } /// /// Gets the items. /// /// The request. /// Task{ItemsResult}. private async Task GetItems(GetItems request) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; var result = await GetItemsToSerialize(request, user).ConfigureAwait(false); var dtoOptions = GetDtoOptions(request); return new ItemsResult { TotalRecordCount = result.TotalRecordCount, Items = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user).ToArray() }; } /// /// Gets the items to serialize. /// /// The request. /// The user. /// IEnumerable{BaseItem}. private async Task> GetItemsToSerialize(GetItems request, User user) { var item = string.IsNullOrEmpty(request.ParentId) ? user == null ? _libraryManager.RootFolder : user.RootFolder : _libraryManager.GetItemById(request.ParentId); if (string.Equals(request.IncludeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase)) { //item = user == null ? _libraryManager.RootFolder : user.RootFolder; } else if (string.Equals(request.IncludeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase)) { item = user == null ? _libraryManager.RootFolder : user.RootFolder; } // Default list type = children if (!string.IsNullOrEmpty(request.Ids)) { request.Recursive = true; var query = GetItemsQuery(request, user); var result = await ((Folder)item).GetItems(query).ConfigureAwait(false); if (string.IsNullOrWhiteSpace(request.SortBy)) { var ids = query.ItemIds.ToList(); // Try to preserve order result.Items = result.Items.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToArray(); } return result; } if (request.Recursive) { var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); return result; } if (user == null) { var result = await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false); return result; } var userRoot = item as UserRootFolder; if (userRoot == null) { var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); return result; } IEnumerable items = ((Folder)item).GetChildren(user, true); var itemsArray = items.ToArray(); return new QueryResult { Items = itemsArray, TotalRecordCount = itemsArray.Length }; } private InternalItemsQuery GetItemsQuery(GetItems request, User user) { var query = new InternalItemsQuery(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 => ApplyAdditionalFilters(request, i, user, _libraryManager), IsFavorite = request.IsFavorite, 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, 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(), GenreIds = request.GetGenreIds(), Studios = request.GetStudios(), StudioIds = request.GetStudioIds(), Person = request.Person, PersonIds = request.GetPersonIds(), PersonTypes = request.GetPersonTypes(), Years = request.GetYears(), ImageTypes = request.GetImageTypes().ToArray(), VideoTypes = request.GetVideoTypes().ToArray(), AdjacentTo = request.AdjacentTo, ItemIds = request.GetItemIds(), MinPlayers = request.MinPlayers, MaxPlayers = request.MaxPlayers, MinCommunityRating = request.MinCommunityRating, MinCriticRating = request.MinCriticRating, ParentId = string.IsNullOrWhiteSpace(request.ParentId) ? (Guid?)null : new Guid(request.ParentId), ParentIndexNumber = request.ParentIndexNumber, AiredDuringSeason = request.AiredDuringSeason, AlbumArtistStartsWithOrGreater = request.AlbumArtistStartsWithOrGreater }; 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; } } if (!string.IsNullOrEmpty(request.MinPremiereDate)) { query.MinPremiereDate = DateTime.Parse(request.MinPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); } if (!string.IsNullOrEmpty(request.MaxPremiereDate)) { query.MaxPremiereDate = DateTime.Parse(request.MaxPremiereDate, null, DateTimeStyles.RoundtripKind).ToUniversalTime(); } // Filter by Series Status if (!string.IsNullOrEmpty(request.SeriesStatus)) { query.SeriesStatuses = request.SeriesStatus.Split(',').Select(d => (SeriesStatus)Enum.Parse(typeof(SeriesStatus), d, true)).ToArray(); } // Filter by Series AirDays if (!string.IsNullOrEmpty(request.AirDays)) { query.AirDays = request.AirDays.Split(',').Select(d => (DayOfWeek)Enum.Parse(typeof(DayOfWeek), d, true)).ToArray(); } // ExcludeLocationTypes if (!string.IsNullOrEmpty(request.ExcludeLocationTypes)) { query.ExcludeLocationTypes = request.ExcludeLocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray(); } if (!string.IsNullOrEmpty(request.LocationTypes)) { query.LocationTypes = request.LocationTypes.Split(',').Select(d => (LocationType)Enum.Parse(typeof(LocationType), d, true)).ToArray(); } return query; } private bool ApplyAdditionalFilters(GetItems request, BaseItem i, User user, ILibraryManager libraryManager) { // Artists if (!string.IsNullOrEmpty(request.ArtistIds)) { var artistIds = request.ArtistIds.Split(new[] { '|', ',' }); var audio = i as IHasArtist; if (!(audio != null && artistIds.Any(id => { var artistItem = libraryManager.GetItemById(id); return artistItem != null && audio.HasAnyArtist(artistItem.Name); }))) { return false; } } // Artists if (!string.IsNullOrEmpty(request.Artists)) { var artists = request.Artists.Split('|'); var audio = i as IHasArtist; if (!(audio != null && artists.Any(audio.HasAnyArtist))) { return false; } } // Albums if (!string.IsNullOrEmpty(request.Albums)) { var albums = request.Albums.Split('|'); var audio = i as Audio; if (audio != null) { if (!albums.Any(a => string.Equals(a, audio.Album, StringComparison.OrdinalIgnoreCase))) { return false; } } var album = i as MusicAlbum; if (album != null) { if (!albums.Any(a => string.Equals(a, album.Name, StringComparison.OrdinalIgnoreCase))) { return false; } } var musicVideo = i as MusicVideo; if (musicVideo != null) { if (!albums.Any(a => string.Equals(a, musicVideo.Album, StringComparison.OrdinalIgnoreCase))) { return false; } } return false; } // Min official rating if (!string.IsNullOrEmpty(request.MinOfficialRating)) { var level = _localization.GetRatingLevel(request.MinOfficialRating); if (level.HasValue) { var rating = i.CustomRating; if (string.IsNullOrEmpty(rating)) { rating = i.OfficialRating; } if (!string.IsNullOrEmpty(rating)) { var itemLevel = _localization.GetRatingLevel(rating); if (!(!itemLevel.HasValue || itemLevel.Value >= level.Value)) { return false; } } } } // Max official rating if (!string.IsNullOrEmpty(request.MaxOfficialRating)) { var level = _localization.GetRatingLevel(request.MaxOfficialRating); if (level.HasValue) { var rating = i.CustomRating; if (string.IsNullOrEmpty(rating)) { rating = i.OfficialRating; } if (!string.IsNullOrEmpty(rating)) { var itemLevel = _localization.GetRatingLevel(rating); if (!(!itemLevel.HasValue || itemLevel.Value <= level.Value)) { return false; } } } } return true; } } /// /// Class DateCreatedComparer /// public class DateCreatedComparer : IComparer { /// /// Compares the specified x. /// /// The x. /// The y. /// System.Int32. public int Compare(BaseItem x, BaseItem y) { return x.DateCreated.CompareTo(y.DateCreated); } } }