using System; using System.Diagnostics.CodeAnalysis; using System.Linq; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Playlists; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Querying; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; namespace Jellyfin.Api.Controllers { /// /// Filters controller. /// [Authorize] public class FilterController : BaseJellyfinApiController { private readonly ILibraryManager _libraryManager; private readonly IUserManager _userManager; /// /// Initializes a new instance of the class. /// /// Instance of the interface. /// Instance of the interface. public FilterController(ILibraryManager libraryManager, IUserManager userManager) { _libraryManager = libraryManager; _userManager = userManager; } /// /// Gets legacy query filters. /// /// Optional. User id. /// Optional. Parent id. /// Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. /// Optional. Filter by MediaType. Allows multiple, comma delimited. /// Legacy filters retrieved. /// Legacy query filters. [HttpGet("/Items/Filters")] [ProducesResponseType(StatusCodes.Status200OK)] public ActionResult GetQueryFiltersLegacy( [FromQuery] Guid? userId, [FromQuery] string? parentId, [FromQuery] string? includeItemTypes, [FromQuery] string? mediaTypes) { var parentItem = string.IsNullOrEmpty(parentId) ? null : _libraryManager.GetItemById(parentId); var user = userId == null || userId == Guid.Empty ? null : _userManager.GetUserById(userId.Value); if (string.Equals(includeItemTypes, nameof(BoxSet), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(Playlist), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(Trailer), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, "Program", StringComparison.OrdinalIgnoreCase)) { parentItem = null; } var item = string.IsNullOrEmpty(parentId) ? user == null ? _libraryManager.RootFolder : _libraryManager.GetUserRootFolder() : parentItem; var query = new InternalItemsQuery { User = user, MediaTypes = (mediaTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), IncludeItemTypes = (includeItemTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), Recursive = true, EnableTotalRecordCount = false, DtoOptions = new DtoOptions { Fields = new[] { ItemFields.Genres, ItemFields.Tags }, EnableImages = false, EnableUserData = false } }; var itemList = ((Folder)item!).GetItemList(query); return new QueryFiltersLegacy { Years = itemList.Select(i => i.ProductionYear ?? -1) .Where(i => i > 0) .Distinct() .OrderBy(i => i) .ToArray(), Genres = itemList.SelectMany(i => i.Genres) .DistinctNames() .OrderBy(i => i) .ToArray(), Tags = itemList .SelectMany(i => i.Tags) .Distinct(StringComparer.OrdinalIgnoreCase) .OrderBy(i => i) .ToArray(), OfficialRatings = itemList .Select(i => i.OfficialRating) .Where(i => !string.IsNullOrWhiteSpace(i)) .Distinct(StringComparer.OrdinalIgnoreCase) .OrderBy(i => i) .ToArray() }; } /// /// Gets query filters. /// /// Optional. User id. /// Optional. Specify this to localize the search to a specific item or folder. Omit to use the root. /// Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited. /// [Unused] Optional. Filter by MediaType. Allows multiple, comma delimited. /// Optional. Is item airing. /// Optional. Is item movie. /// Optional. Is item sports. /// Optional. Is item kids. /// Optional. Is item news. /// Optional. Is item series. /// Optional. Search recursive. /// Filters retrieved. /// Query filters. [HttpGet("/Items/Filters2")] [ProducesResponseType(StatusCodes.Status200OK)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "mediaTypes", Justification = "Imported from ServiceStack")] public ActionResult GetQueryFilters( [FromQuery] Guid? userId, [FromQuery] string? parentId, [FromQuery] string? includeItemTypes, [FromQuery] string? mediaTypes, [FromQuery] bool? isAiring, [FromQuery] bool? isMovie, [FromQuery] bool? isSports, [FromQuery] bool? isKids, [FromQuery] bool? isNews, [FromQuery] bool? isSeries, [FromQuery] bool? recursive) { var parentItem = string.IsNullOrEmpty(parentId) ? null : _libraryManager.GetItemById(parentId); var user = userId == null || userId == Guid.Empty ? null : _userManager.GetUserById(userId.Value); if (string.Equals(includeItemTypes, nameof(BoxSet), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(Playlist), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(Trailer), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, "Program", StringComparison.OrdinalIgnoreCase)) { parentItem = null; } var filters = new QueryFilters(); var genreQuery = new InternalItemsQuery(user) { IncludeItemTypes = (includeItemTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries), DtoOptions = new DtoOptions { Fields = Array.Empty(), EnableImages = false, EnableUserData = false }, IsAiring = isAiring, IsMovie = isMovie, IsSports = isSports, IsKids = isKids, IsNews = isNews, IsSeries = isSeries }; if ((recursive ?? true) || parentItem is UserView || parentItem is ICollectionFolder) { genreQuery.AncestorIds = parentItem == null ? Array.Empty() : new[] { parentItem.Id }; } else { genreQuery.Parent = parentItem; } if (string.Equals(includeItemTypes, nameof(MusicAlbum), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(MusicVideo), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(MusicArtist), StringComparison.OrdinalIgnoreCase) || string.Equals(includeItemTypes, nameof(Audio), StringComparison.OrdinalIgnoreCase)) { filters.Genres = _libraryManager.GetMusicGenres(genreQuery).Items.Select(i => new NameGuidPair { Name = i.Item1.Name, Id = i.Item1.Id }).ToArray(); } else { filters.Genres = _libraryManager.GetGenres(genreQuery).Items.Select(i => new NameGuidPair { Name = i.Item1.Name, Id = i.Item1.Id }).ToArray(); } return filters; } } }