示例#1
0
        public ActionResult <QueryResult <BaseItemDto> > GetItems(
            [FromRoute] Guid?uId,
            [FromQuery] Guid?userId,
            [FromQuery] string?maxOfficialRating,
            [FromQuery] bool?hasThemeSong,
            [FromQuery] bool?hasThemeVideo,
            [FromQuery] bool?hasSubtitles,
            [FromQuery] bool?hasSpecialFeature,
            [FromQuery] bool?hasTrailer,
            [FromQuery] string?adjacentTo,
            [FromQuery] int?parentIndexNumber,
            [FromQuery] bool?hasParentalRating,
            [FromQuery] bool?isHd,
            [FromQuery] bool?is4K,
            [FromQuery] string?locationTypes,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] LocationType[] excludeLocationTypes,
            [FromQuery] bool?isMissing,
            [FromQuery] bool?isUnaired,
            [FromQuery] double?minCommunityRating,
            [FromQuery] double?minCriticRating,
            [FromQuery] DateTime?minPremiereDate,
            [FromQuery] DateTime?minDateLastSaved,
            [FromQuery] DateTime?minDateLastSavedForUser,
            [FromQuery] DateTime?maxPremiereDate,
            [FromQuery] bool?hasOverview,
            [FromQuery] bool?hasImdbId,
            [FromQuery] bool?hasTmdbId,
            [FromQuery] bool?hasTvdbId,
            [FromQuery] string?excludeItemIds,
            [FromQuery] int?startIndex,
            [FromQuery] int?limit,
            [FromQuery] bool?recursive,
            [FromQuery] string?searchTerm,
            [FromQuery] string?sortOrder,
            [FromQuery] string?parentId,
            [FromQuery] string?fields,
            [FromQuery] string?excludeItemTypes,
            [FromQuery] string?includeItemTypes,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters,
            [FromQuery] bool?isFavorite,
            [FromQuery] string?mediaTypes,
            [FromQuery] ImageType[] imageTypes,
            [FromQuery] string?sortBy,
            [FromQuery] bool?isPlayed,
            [FromQuery] string?genres,
            [FromQuery] string?officialRatings,
            [FromQuery] string?tags,
            [FromQuery] string?years,
            [FromQuery] bool?enableUserData,
            [FromQuery] int?imageTypeLimit,
            [FromQuery] ImageType[] enableImageTypes,
            [FromQuery] string?person,
            [FromQuery] string?personIds,
            [FromQuery] string?personTypes,
            [FromQuery] string?studios,
            [FromQuery] string?artists,
            [FromQuery] string?excludeArtistIds,
            [FromQuery] string?artistIds,
            [FromQuery] string?albumArtistIds,
            [FromQuery] string?contributingArtistIds,
            [FromQuery] string?albums,
            [FromQuery] string?albumIds,
            [FromQuery] string?ids,
            [FromQuery] string?videoTypes,
            [FromQuery] string?minOfficialRating,
            [FromQuery] bool?isLocked,
            [FromQuery] bool?isPlaceHolder,
            [FromQuery] bool?hasOfficialRating,
            [FromQuery] bool?collapseBoxSetItems,
            [FromQuery] int?minWidth,
            [FromQuery] int?minHeight,
            [FromQuery] int?maxWidth,
            [FromQuery] int?maxHeight,
            [FromQuery] bool?is3D,
            [FromQuery] string?seriesStatus,
            [FromQuery] string?nameStartsWithOrGreater,
            [FromQuery] string?nameStartsWith,
            [FromQuery] string?nameLessThan,
            [FromQuery] string?studioIds,
            [FromQuery] string?genreIds,
            [FromQuery] bool enableTotalRecordCount = true,
            [FromQuery] bool?enableImages           = true)
        {
            // use user id route parameter over query parameter
            userId = uId ?? userId;

            var user = userId.HasValue && !userId.Equals(Guid.Empty)
                ? _userManager.GetUserById(userId.Value)
                : null;
            var dtoOptions = new DtoOptions()
                             .AddItemFields(fields)
                             .AddClientFields(Request)
                             .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);

            if (string.Equals(includeItemTypes, "Playlist", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(includeItemTypes, "BoxSet", StringComparison.OrdinalIgnoreCase))
            {
                parentId = null;
            }

            BaseItem?item = null;
            QueryResult <BaseItem> result;

            if (!string.IsNullOrEmpty(parentId))
            {
                item = _libraryManager.GetItemById(parentId);
            }

            item ??= _libraryManager.GetUserRootFolder();

            if (!(item is Folder folder))
            {
                folder = _libraryManager.GetUserRootFolder();
            }

            if (folder is IHasCollectionType hasCollectionType &&
                string.Equals(hasCollectionType.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase))
            {
                recursive        = true;
                includeItemTypes = "Playlist";
            }

            bool isInEnabledFolder = user !.GetPreference(PreferenceKind.EnabledFolders).Any(i => new Guid(i) == item.Id)
                                     // Assume all folders inside an EnabledChannel are enabled
                                     || user.GetPreference(PreferenceKind.EnabledChannels).Any(i => new Guid(i) == item.Id)
                                     // Assume all items inside an EnabledChannel are enabled
                                     || user.GetPreference(PreferenceKind.EnabledChannels).Any(i => new Guid(i) == item.ChannelId);

            var collectionFolders = _libraryManager.GetCollectionFolders(item);

            foreach (var collectionFolder in collectionFolders)
            {
                if (user.GetPreference(PreferenceKind.EnabledFolders).Contains(
                        collectionFolder.Id.ToString("N", CultureInfo.InvariantCulture),
                        StringComparer.OrdinalIgnoreCase))
                {
                    isInEnabledFolder = true;
                }
            }

            if (!(item is UserRootFolder) &&
                !isInEnabledFolder &&
                !user.HasPermission(PermissionKind.EnableAllFolders) &&
                !user.HasPermission(PermissionKind.EnableAllChannels))
            {
                _logger.LogWarning("{UserName} is not permitted to access Library {ItemName}.", user.Username, item.Name);
                return(Unauthorized($"{user.Username} is not permitted to access Library {item.Name}."));
            }

            if ((recursive.HasValue && recursive.Value) || !string.IsNullOrEmpty(ids) || !(item is UserRootFolder))
            {
                var query = new InternalItemsQuery(user !)
                {
                    IsPlayed                = isPlayed,
                    MediaTypes              = RequestHelpers.Split(mediaTypes, ',', true),
                    IncludeItemTypes        = RequestHelpers.Split(includeItemTypes, ',', true),
                    ExcludeItemTypes        = RequestHelpers.Split(excludeItemTypes, ',', true),
                    Recursive               = recursive ?? false,
                    OrderBy                 = RequestHelpers.GetOrderBy(sortBy, sortOrder),
                    IsFavorite              = isFavorite,
                    Limit                   = limit,
                    StartIndex              = startIndex,
                    IsMissing               = isMissing,
                    IsUnaired               = isUnaired,
                    CollapseBoxSetItems     = collapseBoxSetItems,
                    NameLessThan            = nameLessThan,
                    NameStartsWith          = nameStartsWith,
                    NameStartsWithOrGreater = nameStartsWithOrGreater,
                    HasImdbId               = hasImdbId,
                    IsPlaceHolder           = isPlaceHolder,
                    IsLocked                = isLocked,
                    MinWidth                = minWidth,
                    MinHeight               = minHeight,
                    MaxWidth                = maxWidth,
                    MaxHeight               = maxHeight,
                    Is3D                    = is3D,
                    HasTvdbId               = hasTvdbId,
                    HasTmdbId               = hasTmdbId,
                    HasOverview             = hasOverview,
                    HasOfficialRating       = hasOfficialRating,
                    HasParentalRating       = hasParentalRating,
                    HasSpecialFeature       = hasSpecialFeature,
                    HasSubtitles            = hasSubtitles,
                    HasThemeSong            = hasThemeSong,
                    HasThemeVideo           = hasThemeVideo,
                    HasTrailer              = hasTrailer,
                    IsHD                    = isHd,
                    Is4K                    = is4K,
                    Tags                    = RequestHelpers.Split(tags, '|', true),
                    OfficialRatings         = RequestHelpers.Split(officialRatings, '|', true),
                    Genres                  = RequestHelpers.Split(genres, '|', true),
                    ArtistIds               = RequestHelpers.GetGuids(artistIds),
                    AlbumArtistIds          = RequestHelpers.GetGuids(albumArtistIds),
                    ContributingArtistIds   = RequestHelpers.GetGuids(contributingArtistIds),
                    GenreIds                = RequestHelpers.GetGuids(genreIds),
                    StudioIds               = RequestHelpers.GetGuids(studioIds),
                    Person                  = person,
                    PersonIds               = RequestHelpers.GetGuids(personIds),
                    PersonTypes             = RequestHelpers.Split(personTypes, ',', true),
                    Years                   = RequestHelpers.Split(years, ',', true).Select(int.Parse).ToArray(),
                    ImageTypes              = imageTypes,
                    VideoTypes              = RequestHelpers.Split(videoTypes, ',', true).Select(v => Enum.Parse <VideoType>(v, true)).ToArray(),
                    AdjacentTo              = adjacentTo,
                    ItemIds                 = RequestHelpers.GetGuids(ids),
                    MinCommunityRating      = minCommunityRating,
                    MinCriticRating         = minCriticRating,
                    ParentId                = string.IsNullOrWhiteSpace(parentId) ? Guid.Empty : new Guid(parentId),
                    ParentIndexNumber       = parentIndexNumber,
                    EnableTotalRecordCount  = enableTotalRecordCount,
                    ExcludeItemIds          = RequestHelpers.GetGuids(excludeItemIds),
                    DtoOptions              = dtoOptions,
                    SearchTerm              = searchTerm,
                    MinDateLastSaved        = minDateLastSaved?.ToUniversalTime(),
                    MinDateLastSavedForUser = minDateLastSavedForUser?.ToUniversalTime(),
                    MinPremiereDate         = minPremiereDate?.ToUniversalTime(),
                    MaxPremiereDate         = maxPremiereDate?.ToUniversalTime(),
                };

                if (!string.IsNullOrWhiteSpace(ids) || !string.IsNullOrWhiteSpace(searchTerm))
                {
                    query.CollapseBoxSetItems = false;
                }

                foreach (var filter in filters)
                {
                    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.IsResumable:
                        query.IsResumable = true;
                        break;

                    case ItemFilter.IsUnplayed:
                        query.IsPlayed = false;
                        break;

                    case ItemFilter.Likes:
                        query.IsLiked = true;
                        break;
                    }
                }

                // Filter by Series Status
                if (!string.IsNullOrEmpty(seriesStatus))
                {
                    query.SeriesStatuses = seriesStatus.Split(',').Select(d => (SeriesStatus)Enum.Parse(typeof(SeriesStatus), d, true)).ToArray();
                }

                // ExcludeLocationTypes
                if (excludeLocationTypes.Any(t => t == LocationType.Virtual))
                {
                    query.IsVirtualItem = false;
                }

                if (!string.IsNullOrEmpty(locationTypes))
                {
                    var requestedLocationTypes = locationTypes.Split(',');
                    if (requestedLocationTypes.Length > 0 && requestedLocationTypes.Length < 4)
                    {
                        query.IsVirtualItem = requestedLocationTypes.Contains(LocationType.Virtual.ToString());
                    }
                }

                // Min official rating
                if (!string.IsNullOrWhiteSpace(minOfficialRating))
                {
                    query.MinParentalRating = _localization.GetRatingLevel(minOfficialRating);
                }

                // Max official rating
                if (!string.IsNullOrWhiteSpace(maxOfficialRating))
                {
                    query.MaxParentalRating = _localization.GetRatingLevel(maxOfficialRating);
                }

                // Artists
                if (!string.IsNullOrEmpty(artists))
                {
                    query.ArtistIds = artists.Split('|').Select(i =>
                    {
                        try
                        {
                            return(_libraryManager.GetArtist(i, new DtoOptions(false)));
                        }
                        catch
                        {
                            return(null);
                        }
                    }).Where(i => i != null).Select(i => i !.Id).ToArray();
                }

                // ExcludeArtistIds
                if (!string.IsNullOrWhiteSpace(excludeArtistIds))
                {
                    query.ExcludeArtistIds = RequestHelpers.GetGuids(excludeArtistIds);
                }

                if (!string.IsNullOrWhiteSpace(albumIds))
                {
                    query.AlbumIds = RequestHelpers.GetGuids(albumIds);
                }

                // Albums
                if (!string.IsNullOrEmpty(albums))
                {
                    query.AlbumIds = albums.Split('|').SelectMany(i =>
                    {
                        return(_libraryManager.GetItemIds(new InternalItemsQuery {
                            IncludeItemTypes = new[] { nameof(MusicAlbum) }, Name = i, Limit = 1
                        }));
                    }).ToArray();
                }

                // Studios
                if (!string.IsNullOrEmpty(studios))
                {
                    query.StudioIds = studios.Split('|').Select(i =>
                    {
                        try
                        {
                            return(_libraryManager.GetStudio(i));
                        }
                        catch
                        {
                            return(null);
                        }
                    }).Where(i => i != null).Select(i => i !.Id).ToArray();
                }

                // Apply default sorting if none requested
                if (query.OrderBy.Count == 0)
                {
                    // Albums by artist
                    if (query.ArtistIds.Length > 0 && query.IncludeItemTypes.Length == 1 && string.Equals(query.IncludeItemTypes[0], "MusicAlbum", StringComparison.OrdinalIgnoreCase))
                    {
                        query.OrderBy = new[] { new ValueTuple <string, SortOrder>(ItemSortBy.ProductionYear, SortOrder.Descending), new ValueTuple <string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) };
                    }
                }

                result = folder.GetItems(query);
            }
            else
            {
                var itemsArray = folder.GetChildren(user, true);
                result = new QueryResult <BaseItem> {
                    Items = itemsArray, TotalRecordCount = itemsArray.Count, StartIndex = 0
                };
            }

            return(new QueryResult <BaseItemDto> {
                StartIndex = startIndex.GetValueOrDefault(), TotalRecordCount = result.TotalRecordCount, Items = _dtoService.GetBaseItemDtos(result.Items, dtoOptions, user)
            });
        }
示例#2
0
        public ActionResult <QueryResult <BaseItemDto> > GetYears(
            [FromQuery] int?startIndex,
            [FromQuery] int?limit,
            [FromQuery] string?sortOrder,
            [FromQuery] Guid?parentId,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes,
            [FromQuery] string?sortBy,
            [FromQuery] bool?enableUserData,
            [FromQuery] int?imageTypeLimit,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
            [FromQuery] Guid?userId,
            [FromQuery] bool recursive    = true,
            [FromQuery] bool?enableImages = true)
        {
            var dtoOptions = new DtoOptions {
                Fields = fields
            }
            .AddClientFields(Request)
            .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);

            User?    user       = null;
            BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);

            if (userId.HasValue && !userId.Equals(Guid.Empty))
            {
                user = _userManager.GetUserById(userId.Value);
            }

            IList <BaseItem> items;

            var query = new InternalItemsQuery(user)
            {
                ExcludeItemTypes = excludeItemTypes,
                IncludeItemTypes = includeItemTypes,
                MediaTypes       = mediaTypes,
                DtoOptions       = dtoOptions
            };

            bool Filter(BaseItem i) => FilterItem(i, excludeItemTypes, includeItemTypes, mediaTypes);

            if (parentItem.IsFolder)
            {
                var folder = (Folder)parentItem;

                if (!userId.Equals(Guid.Empty))
                {
                    items = recursive ? folder.GetRecursiveChildren(user, query).ToList() : folder.GetChildren(user, true).Where(Filter).ToList();
                }
                else
                {
                    items = recursive ? folder.GetRecursiveChildren(Filter) : folder.Children.Where(Filter).ToList();
                }
            }
            else
            {
                items = new[] { parentItem }.Where(Filter).ToList();
            }

            var extractedItems = GetAllItems(items);

            var filteredItems = _libraryManager.Sort(extractedItems, user, RequestHelpers.GetOrderBy(sortBy, sortOrder));

            var ibnItemsArray = filteredItems.ToList();

            IEnumerable <BaseItem> ibnItems = ibnItemsArray;

            var result = new QueryResult <BaseItemDto> {
                TotalRecordCount = ibnItemsArray.Count
            };

            if (startIndex.HasValue || limit.HasValue)
            {
                if (startIndex.HasValue)
                {
                    ibnItems = ibnItems.Skip(startIndex.Value);
                }

                if (limit.HasValue)
                {
                    ibnItems = ibnItems.Take(limit.Value);
                }
            }

            var tuples = ibnItems.Select(i => new Tuple <BaseItem, List <BaseItem> >(i, new List <BaseItem>()));

            var dtos = tuples.Select(i => _dtoService.GetItemByNameDto(i.Item1, dtoOptions, i.Item2, user));

            result.Items = dtos.Where(i => i != null).ToArray();

            return(result);
        }
示例#3
0
        public ActionResult <QueryResult <BaseItemDto> > GetMusicGenres(
            [FromQuery] int?startIndex,
            [FromQuery] int?limit,
            [FromQuery] string?searchTerm,
            [FromQuery] Guid?parentId,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
            [FromQuery] bool?isFavorite,
            [FromQuery] int?imageTypeLimit,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
            [FromQuery] Guid?userId,
            [FromQuery] string?nameStartsWithOrGreater,
            [FromQuery] string?nameStartsWith,
            [FromQuery] string?nameLessThan,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
            [FromQuery] bool?enableImages           = true,
            [FromQuery] bool enableTotalRecordCount = true)
        {
            var dtoOptions = new DtoOptions {
                Fields = fields
            }
            .AddClientFields(Request)
            .AddAdditionalDtoOptions(enableImages, false, imageTypeLimit, enableImageTypes);

            User?user = userId.HasValue && userId != Guid.Empty ? _userManager.GetUserById(userId.Value) : null;

            var parentItem = _libraryManager.GetParentItem(parentId, userId);

            var query = new InternalItemsQuery(user)
            {
                ExcludeItemTypes        = excludeItemTypes,
                IncludeItemTypes        = includeItemTypes,
                StartIndex              = startIndex,
                Limit                   = limit,
                IsFavorite              = isFavorite,
                NameLessThan            = nameLessThan,
                NameStartsWith          = nameStartsWith,
                NameStartsWithOrGreater = nameStartsWithOrGreater,
                DtoOptions              = dtoOptions,
                SearchTerm              = searchTerm,
                EnableTotalRecordCount  = enableTotalRecordCount,
                OrderBy                 = RequestHelpers.GetOrderBy(sortBy, sortOrder)
            };

            if (parentId.HasValue)
            {
                if (parentItem is Folder)
                {
                    query.AncestorIds = new[] { parentId.Value };
                }
                else
                {
                    query.ItemIds = new[] { parentId.Value };
                }
            }

            var result = _libraryManager.GetMusicGenres(query);

            var shouldIncludeItemTypes = includeItemTypes.Length != 0;

            return(RequestHelpers.CreateQueryResult(result, dtoOptions, _dtoService, shouldIncludeItemTypes, user));
        }
示例#4
0
        public async Task <ActionResult <QueryResult <BaseItemDto> > > GetChannelItems(
            [FromRoute] Guid channelId,
            [FromQuery] Guid?folderId,
            [FromQuery] Guid?userId,
            [FromQuery] int?startIndex,
            [FromQuery] int?limit,
            [FromQuery] string?sortOrder,
            [FromQuery] string?filters,
            [FromQuery] string?sortBy,
            [FromQuery] string?fields)
        {
            var user = userId.HasValue && !userId.Equals(Guid.Empty)
                ? _userManager.GetUserById(userId.Value)
                : null;

            var query = new InternalItemsQuery(user)
            {
                Limit      = limit,
                StartIndex = startIndex,
                ChannelIds = new[] { channelId },
                ParentId   = folderId ?? Guid.Empty,
                OrderBy    = RequestHelpers.GetOrderBy(sortBy, sortOrder),
                DtoOptions = new DtoOptions()
                             .AddItemFields(fields)
            };

            foreach (var filter in RequestHelpers.GetFilters(filters))
            {
                switch (filter)
                {
                case ItemFilter.IsFolder:
                    query.IsFolder = true;
                    break;

                case ItemFilter.IsNotFolder:
                    query.IsFolder = false;
                    break;

                case ItemFilter.IsUnplayed:
                    query.IsPlayed = false;
                    break;

                case ItemFilter.IsPlayed:
                    query.IsPlayed = true;
                    break;

                case ItemFilter.IsFavorite:
                    query.IsFavorite = true;
                    break;

                case ItemFilter.IsResumable:
                    query.IsResumable = true;
                    break;

                case ItemFilter.Likes:
                    query.IsLiked = true;
                    break;

                case ItemFilter.Dislikes:
                    query.IsLiked = false;
                    break;

                case ItemFilter.IsFavoriteOrLikes:
                    query.IsFavoriteOrLiked = true;
                    break;
                }
            }

            return(await _channelManager.GetChannelItems(query, CancellationToken.None).ConfigureAwait(false));
        }
示例#5
0
        public ActionResult <QueryResult <BaseItemDto> > GetArtists(
            [FromQuery] double?minCommunityRating,
            [FromQuery] int?startIndex,
            [FromQuery] int?limit,
            [FromQuery] string?searchTerm,
            [FromQuery] Guid?parentId,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters,
            [FromQuery] bool?isFavorite,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes,
            [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds,
            [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings,
            [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years,
            [FromQuery] bool?enableUserData,
            [FromQuery] int?imageTypeLimit,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes,
            [FromQuery] string?person,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes,
            [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] studios,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds,
            [FromQuery] Guid?userId,
            [FromQuery] string?nameStartsWithOrGreater,
            [FromQuery] string?nameStartsWith,
            [FromQuery] string?nameLessThan,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy,
            [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder,
            [FromQuery] bool?enableImages           = true,
            [FromQuery] bool enableTotalRecordCount = true)
        {
            var dtoOptions = new DtoOptions {
                Fields = fields
            }
            .AddClientFields(Request)
            .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes);

            User?    user       = null;
            BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId);

            if (userId.HasValue && !userId.Equals(Guid.Empty))
            {
                user = _userManager.GetUserById(userId.Value);
            }

            var query = new InternalItemsQuery(user)
            {
                ExcludeItemTypes        = excludeItemTypes,
                IncludeItemTypes        = includeItemTypes,
                MediaTypes              = mediaTypes,
                StartIndex              = startIndex,
                Limit                   = limit,
                IsFavorite              = isFavorite,
                NameLessThan            = nameLessThan,
                NameStartsWith          = nameStartsWith,
                NameStartsWithOrGreater = nameStartsWithOrGreater,
                Tags                   = tags,
                OfficialRatings        = officialRatings,
                Genres                 = genres,
                GenreIds               = genreIds,
                StudioIds              = studioIds,
                Person                 = person,
                PersonIds              = personIds,
                PersonTypes            = personTypes,
                Years                  = years,
                MinCommunityRating     = minCommunityRating,
                DtoOptions             = dtoOptions,
                SearchTerm             = searchTerm,
                EnableTotalRecordCount = enableTotalRecordCount,
                OrderBy                = RequestHelpers.GetOrderBy(sortBy, sortOrder)
            };

            if (parentId.HasValue)
            {
                if (parentItem is Folder)
                {
                    query.AncestorIds = new[] { parentId.Value };
                }
                else
                {
                    query.ItemIds = new[] { parentId.Value };
                }
            }

            // Studios
            if (studios.Length != 0)
            {
                query.StudioIds = studios.Select(i =>
                {
                    try
                    {
                        return(_libraryManager.GetStudio(i));
                    }
                    catch
                    {
                        return(null);
                    }
                }).Where(i => i != null).Select(i => i !.Id).ToArray();
            }

            foreach (var filter in filters)
            {
                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.IsResumable:
                    query.IsResumable = true;
                    break;

                case ItemFilter.IsUnplayed:
                    query.IsPlayed = false;
                    break;

                case ItemFilter.Likes:
                    query.IsLiked = true;
                    break;
                }
            }

            var result = _libraryManager.GetArtists(query);

            var dtos = result.Items.Select(i =>
            {
                var(baseItem, itemCounts) = i;
                var dto = _dtoService.GetItemByNameDto(baseItem, dtoOptions, null, user);

                if (includeItemTypes.Length != 0)
                {
                    dto.ChildCount   = itemCounts.ItemCount;
                    dto.ProgramCount = itemCounts.ProgramCount;
                    dto.SeriesCount  = itemCounts.SeriesCount;
                    dto.EpisodeCount = itemCounts.EpisodeCount;
                    dto.MovieCount   = itemCounts.MovieCount;
                    dto.TrailerCount = itemCounts.TrailerCount;
                    dto.AlbumCount   = itemCounts.AlbumCount;
                    dto.SongCount    = itemCounts.SongCount;
                    dto.ArtistCount  = itemCounts.ArtistCount;
                }

                return(dto);
            });

            return(new QueryResult <BaseItemDto>
            {
                Items = dtos.ToArray(),
                TotalRecordCount = result.TotalRecordCount
            });
        }