2020-06-19 14:49:42 +00:00
|
|
|
|
using System;
|
2020-06-08 04:04:59 +00:00
|
|
|
|
using System.Linq;
|
2020-06-22 13:44:11 +00:00
|
|
|
|
using Jellyfin.Api.Constants;
|
2020-06-08 04:04:59 +00:00
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Filters controller.
|
|
|
|
|
/// </summary>
|
2020-08-04 18:48:53 +00:00
|
|
|
|
[Route("")]
|
2020-06-22 13:44:11 +00:00
|
|
|
|
[Authorize(Policy = Policies.DefaultAuthorization)]
|
2020-06-08 04:04:59 +00:00
|
|
|
|
public class FilterController : BaseJellyfinApiController
|
|
|
|
|
{
|
|
|
|
|
private readonly ILibraryManager _libraryManager;
|
|
|
|
|
private readonly IUserManager _userManager;
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Initializes a new instance of the <see cref="FilterController"/> class.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="libraryManager">Instance of the <see cref="ILibraryManager"/> interface.</param>
|
|
|
|
|
/// <param name="userManager">Instance of the <see cref="IUserManager"/> interface.</param>
|
|
|
|
|
public FilterController(ILibraryManager libraryManager, IUserManager userManager)
|
|
|
|
|
{
|
|
|
|
|
_libraryManager = libraryManager;
|
|
|
|
|
_userManager = userManager;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets legacy query filters.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="userId">Optional. User id.</param>
|
|
|
|
|
/// <param name="parentId">Optional. Parent id.</param>
|
|
|
|
|
/// <param name="includeItemTypes">Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.</param>
|
|
|
|
|
/// <param name="mediaTypes">Optional. Filter by MediaType. Allows multiple, comma delimited.</param>
|
2020-06-08 13:37:16 +00:00
|
|
|
|
/// <response code="200">Legacy filters retrieved.</response>
|
2020-06-08 04:04:59 +00:00
|
|
|
|
/// <returns>Legacy query filters.</returns>
|
2020-08-04 18:48:53 +00:00
|
|
|
|
[HttpGet("Items/Filters")]
|
2020-06-08 04:04:59 +00:00
|
|
|
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
|
|
|
public ActionResult<QueryFiltersLegacy> GetQueryFiltersLegacy(
|
|
|
|
|
[FromQuery] Guid? userId,
|
|
|
|
|
[FromQuery] string? parentId,
|
|
|
|
|
[FromQuery] string? includeItemTypes,
|
|
|
|
|
[FromQuery] string? mediaTypes)
|
|
|
|
|
{
|
|
|
|
|
var parentItem = string.IsNullOrEmpty(parentId)
|
|
|
|
|
? null
|
|
|
|
|
: _libraryManager.GetItemById(parentId);
|
|
|
|
|
|
2020-07-07 15:10:51 +00:00
|
|
|
|
var user = userId.HasValue && !userId.Equals(Guid.Empty)
|
|
|
|
|
? _userManager.GetUserById(userId.Value)
|
|
|
|
|
: null;
|
2020-06-08 04:04:59 +00:00
|
|
|
|
|
2020-06-10 15:23:27 +00:00
|
|
|
|
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))
|
2020-06-08 04:04:59 +00:00
|
|
|
|
{
|
|
|
|
|
parentItem = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var item = string.IsNullOrEmpty(parentId)
|
|
|
|
|
? user == null
|
|
|
|
|
? _libraryManager.RootFolder
|
|
|
|
|
: _libraryManager.GetUserRootFolder()
|
|
|
|
|
: parentItem;
|
|
|
|
|
|
|
|
|
|
var query = new InternalItemsQuery
|
|
|
|
|
{
|
|
|
|
|
User = user,
|
2020-11-14 15:28:49 +00:00
|
|
|
|
MediaTypes = (mediaTypes ?? string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries),
|
|
|
|
|
IncludeItemTypes = (includeItemTypes ?? string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries),
|
2020-06-08 04:04:59 +00:00
|
|
|
|
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()
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// Gets query filters.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <param name="userId">Optional. User id.</param>
|
|
|
|
|
/// <param name="parentId">Optional. Specify this to localize the search to a specific item or folder. Omit to use the root.</param>
|
|
|
|
|
/// <param name="includeItemTypes">Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimited.</param>
|
|
|
|
|
/// <param name="isAiring">Optional. Is item airing.</param>
|
|
|
|
|
/// <param name="isMovie">Optional. Is item movie.</param>
|
|
|
|
|
/// <param name="isSports">Optional. Is item sports.</param>
|
|
|
|
|
/// <param name="isKids">Optional. Is item kids.</param>
|
|
|
|
|
/// <param name="isNews">Optional. Is item news.</param>
|
|
|
|
|
/// <param name="isSeries">Optional. Is item series.</param>
|
|
|
|
|
/// <param name="recursive">Optional. Search recursive.</param>
|
2020-06-08 13:37:16 +00:00
|
|
|
|
/// <response code="200">Filters retrieved.</response>
|
2020-06-08 04:04:59 +00:00
|
|
|
|
/// <returns>Query filters.</returns>
|
2020-08-04 18:48:53 +00:00
|
|
|
|
[HttpGet("Items/Filters2")]
|
2020-06-08 04:04:59 +00:00
|
|
|
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
|
|
|
|
public ActionResult<QueryFilters> GetQueryFilters(
|
|
|
|
|
[FromQuery] Guid? userId,
|
|
|
|
|
[FromQuery] string? parentId,
|
|
|
|
|
[FromQuery] string? includeItemTypes,
|
|
|
|
|
[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);
|
|
|
|
|
|
2020-07-07 15:10:51 +00:00
|
|
|
|
var user = userId.HasValue && !userId.Equals(Guid.Empty)
|
|
|
|
|
? _userManager.GetUserById(userId.Value)
|
|
|
|
|
: null;
|
2020-06-08 04:04:59 +00:00
|
|
|
|
|
2020-06-17 16:41:40 +00:00
|
|
|
|
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))
|
2020-06-08 04:04:59 +00:00
|
|
|
|
{
|
|
|
|
|
parentItem = null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var filters = new QueryFilters();
|
|
|
|
|
var genreQuery = new InternalItemsQuery(user)
|
|
|
|
|
{
|
|
|
|
|
IncludeItemTypes =
|
2020-11-14 15:28:49 +00:00
|
|
|
|
(includeItemTypes ?? string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries),
|
2020-06-08 04:04:59 +00:00
|
|
|
|
DtoOptions = new DtoOptions
|
|
|
|
|
{
|
|
|
|
|
Fields = Array.Empty<ItemFields>(),
|
|
|
|
|
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<Guid>() : new[] { parentItem.Id };
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
genreQuery.Parent = parentItem;
|
|
|
|
|
}
|
|
|
|
|
|
2020-06-10 15:23:20 +00:00
|
|
|
|
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))
|
2020-06-08 04:04:59 +00:00
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-10 15:23:20 +00:00
|
|
|
|
}
|