| | 1 | | using System; |
| | 2 | | using System.ComponentModel.DataAnnotations; |
| | 3 | | using System.Linq; |
| | 4 | | using Jellyfin.Api.Extensions; |
| | 5 | | using Jellyfin.Api.Helpers; |
| | 6 | | using Jellyfin.Api.ModelBinders; |
| | 7 | | using Jellyfin.Data.Enums; |
| | 8 | | using Jellyfin.Database.Implementations.Entities; |
| | 9 | | using Jellyfin.Database.Implementations.Enums; |
| | 10 | | using Jellyfin.Extensions; |
| | 11 | | using MediaBrowser.Controller.Dto; |
| | 12 | | using MediaBrowser.Controller.Entities; |
| | 13 | | using MediaBrowser.Controller.Entities.Audio; |
| | 14 | | using MediaBrowser.Controller.Library; |
| | 15 | | using MediaBrowser.Model.Dto; |
| | 16 | | using MediaBrowser.Model.Entities; |
| | 17 | | using MediaBrowser.Model.Querying; |
| | 18 | | using Microsoft.AspNetCore.Authorization; |
| | 19 | | using Microsoft.AspNetCore.Http; |
| | 20 | | using Microsoft.AspNetCore.Mvc; |
| | 21 | |
|
| | 22 | | namespace Jellyfin.Api.Controllers; |
| | 23 | |
|
| | 24 | | /// <summary> |
| | 25 | | /// The music genres controller. |
| | 26 | | /// </summary> |
| | 27 | | [Authorize] |
| | 28 | | public class MusicGenresController : BaseJellyfinApiController |
| | 29 | | { |
| | 30 | | private readonly ILibraryManager _libraryManager; |
| | 31 | | private readonly IDtoService _dtoService; |
| | 32 | | private readonly IUserManager _userManager; |
| | 33 | |
|
| | 34 | | /// <summary> |
| | 35 | | /// Initializes a new instance of the <see cref="MusicGenresController"/> class. |
| | 36 | | /// </summary> |
| | 37 | | /// <param name="libraryManager">Instance of <see cref="ILibraryManager"/> interface.</param> |
| | 38 | | /// <param name="userManager">Instance of <see cref="IUserManager"/> interface.</param> |
| | 39 | | /// <param name="dtoService">Instance of <see cref="IDtoService"/> interface.</param> |
| 1 | 40 | | public MusicGenresController( |
| 1 | 41 | | ILibraryManager libraryManager, |
| 1 | 42 | | IUserManager userManager, |
| 1 | 43 | | IDtoService dtoService) |
| | 44 | | { |
| 1 | 45 | | _libraryManager = libraryManager; |
| 1 | 46 | | _userManager = userManager; |
| 1 | 47 | | _dtoService = dtoService; |
| 1 | 48 | | } |
| | 49 | |
|
| | 50 | | /// <summary> |
| | 51 | | /// Gets all music genres from a given item, folder, or the entire library. |
| | 52 | | /// </summary> |
| | 53 | | /// <param name="startIndex">Optional. The record index to start at. All items with a lower index will be dropped fr |
| | 54 | | /// <param name="limit">Optional. The maximum number of records to return.</param> |
| | 55 | | /// <param name="searchTerm">The search term.</param> |
| | 56 | | /// <param name="parentId">Specify this to localize the search to a specific item or folder. Omit to use the root.</ |
| | 57 | | /// <param name="fields">Optional. Specify additional fields of information to return in the output.</param> |
| | 58 | | /// <param name="excludeItemTypes">Optional. If specified, results will be filtered out based on item type. This all |
| | 59 | | /// <param name="includeItemTypes">Optional. If specified, results will be filtered in based on item type. This allo |
| | 60 | | /// <param name="isFavorite">Optional filter by items that are marked as favorite, or not.</param> |
| | 61 | | /// <param name="imageTypeLimit">Optional, the max number of images to return, per image type.</param> |
| | 62 | | /// <param name="enableImageTypes">Optional. The image types to include in the output.</param> |
| | 63 | | /// <param name="userId">User id.</param> |
| | 64 | | /// <param name="nameStartsWithOrGreater">Optional filter by items whose name is sorted equally or greater than a gi |
| | 65 | | /// <param name="nameStartsWith">Optional filter by items whose name is sorted equally than a given input string.</p |
| | 66 | | /// <param name="nameLessThan">Optional filter by items whose name is equally or lesser than a given input string.</ |
| | 67 | | /// <param name="sortBy">Optional. Specify one or more sort orders, comma delimited.</param> |
| | 68 | | /// <param name="sortOrder">Sort Order - Ascending,Descending.</param> |
| | 69 | | /// <param name="enableImages">Optional, include image information in output.</param> |
| | 70 | | /// <param name="enableTotalRecordCount">Optional. Include total record count.</param> |
| | 71 | | /// <response code="200">Music genres returned.</response> |
| | 72 | | /// <returns>An <see cref="OkResult"/> containing the queryresult of music genres.</returns> |
| | 73 | | [HttpGet] |
| | 74 | | [Obsolete("Use GetGenres instead")] |
| | 75 | | public ActionResult<QueryResult<BaseItemDto>> GetMusicGenres( |
| | 76 | | [FromQuery] int? startIndex, |
| | 77 | | [FromQuery] int? limit, |
| | 78 | | [FromQuery] string? searchTerm, |
| | 79 | | [FromQuery] Guid? parentId, |
| | 80 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemFields[] fields, |
| | 81 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] excludeItemTypes, |
| | 82 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] BaseItemKind[] includeItemTypes, |
| | 83 | | [FromQuery] bool? isFavorite, |
| | 84 | | [FromQuery] int? imageTypeLimit, |
| | 85 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ImageType[] enableImageTypes, |
| | 86 | | [FromQuery] Guid? userId, |
| | 87 | | [FromQuery] string? nameStartsWithOrGreater, |
| | 88 | | [FromQuery] string? nameStartsWith, |
| | 89 | | [FromQuery] string? nameLessThan, |
| | 90 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] ItemSortBy[] sortBy, |
| | 91 | | [FromQuery, ModelBinder(typeof(CommaDelimitedCollectionModelBinder))] SortOrder[] sortOrder, |
| | 92 | | [FromQuery] bool? enableImages = true, |
| | 93 | | [FromQuery] bool enableTotalRecordCount = true) |
| | 94 | | { |
| | 95 | | userId = RequestHelpers.GetUserId(User, userId); |
| | 96 | | var dtoOptions = new DtoOptions { Fields = fields } |
| | 97 | | .AddClientFields(User) |
| | 98 | | .AddAdditionalDtoOptions(enableImages, false, imageTypeLimit, enableImageTypes); |
| | 99 | |
|
| | 100 | | User? user = userId.IsNullOrEmpty() |
| | 101 | | ? null |
| | 102 | | : _userManager.GetUserById(userId.Value); |
| | 103 | |
|
| | 104 | | var parentItem = _libraryManager.GetParentItem(parentId, userId); |
| | 105 | |
|
| | 106 | | var query = new InternalItemsQuery(user) |
| | 107 | | { |
| | 108 | | ExcludeItemTypes = excludeItemTypes, |
| | 109 | | IncludeItemTypes = includeItemTypes, |
| | 110 | | StartIndex = startIndex, |
| | 111 | | Limit = limit, |
| | 112 | | IsFavorite = isFavorite, |
| | 113 | | NameLessThan = nameLessThan, |
| | 114 | | NameStartsWith = nameStartsWith, |
| | 115 | | NameStartsWithOrGreater = nameStartsWithOrGreater, |
| | 116 | | DtoOptions = dtoOptions, |
| | 117 | | SearchTerm = searchTerm, |
| | 118 | | EnableTotalRecordCount = enableTotalRecordCount, |
| | 119 | | OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder) |
| | 120 | | }; |
| | 121 | |
|
| | 122 | | if (parentId.HasValue) |
| | 123 | | { |
| | 124 | | if (parentItem is Folder) |
| | 125 | | { |
| | 126 | | query.AncestorIds = new[] { parentId.Value }; |
| | 127 | | } |
| | 128 | | else |
| | 129 | | { |
| | 130 | | query.ItemIds = new[] { parentId.Value }; |
| | 131 | | } |
| | 132 | | } |
| | 133 | |
|
| | 134 | | var result = _libraryManager.GetMusicGenres(query); |
| | 135 | |
|
| | 136 | | var shouldIncludeItemTypes = includeItemTypes.Length != 0; |
| | 137 | | return RequestHelpers.CreateQueryResult(result, dtoOptions, _dtoService, shouldIncludeItemTypes, user); |
| | 138 | | } |
| | 139 | |
|
| | 140 | | /// <summary> |
| | 141 | | /// Gets a music genre, by name. |
| | 142 | | /// </summary> |
| | 143 | | /// <param name="genreName">The genre name.</param> |
| | 144 | | /// <param name="userId">Optional. Filter by user id, and attach user data.</param> |
| | 145 | | /// <returns>An <see cref="OkResult"/> containing a <see cref="BaseItemDto"/> with the music genre.</returns> |
| | 146 | | [HttpGet("{genreName}")] |
| | 147 | | [ProducesResponseType(StatusCodes.Status200OK)] |
| | 148 | | public ActionResult<BaseItemDto> GetMusicGenre([FromRoute, Required] string genreName, [FromQuery] Guid? userId) |
| | 149 | | { |
| 1 | 150 | | userId = RequestHelpers.GetUserId(User, userId); |
| 1 | 151 | | var dtoOptions = new DtoOptions().AddClientFields(User); |
| | 152 | |
|
| | 153 | | MusicGenre? item; |
| | 154 | |
|
| 1 | 155 | | if (genreName.Contains(BaseItem.SlugChar, StringComparison.OrdinalIgnoreCase)) |
| | 156 | | { |
| 1 | 157 | | item = GetItemFromSlugName<MusicGenre>(_libraryManager, genreName, dtoOptions, BaseItemKind.MusicGenre); |
| | 158 | | } |
| | 159 | | else |
| | 160 | | { |
| 0 | 161 | | item = _libraryManager.GetMusicGenre(genreName); |
| | 162 | | } |
| | 163 | |
|
| 1 | 164 | | if (item is null) |
| | 165 | | { |
| 1 | 166 | | return NotFound(); |
| | 167 | | } |
| | 168 | |
|
| 0 | 169 | | if (!userId.IsNullOrEmpty()) |
| | 170 | | { |
| 0 | 171 | | var user = _userManager.GetUserById(userId.Value); |
| | 172 | |
|
| 0 | 173 | | return _dtoService.GetBaseItemDto(item, dtoOptions, user); |
| | 174 | | } |
| | 175 | |
|
| 0 | 176 | | return _dtoService.GetBaseItemDto(item, dtoOptions); |
| | 177 | | } |
| | 178 | |
|
| | 179 | | private T? GetItemFromSlugName<T>(ILibraryManager libraryManager, string name, DtoOptions dtoOptions, BaseItemKind b |
| | 180 | | where T : BaseItem, new() |
| | 181 | | { |
| 1 | 182 | | var result = libraryManager.GetItemList(new InternalItemsQuery |
| 1 | 183 | | { |
| 1 | 184 | | Name = name.Replace(BaseItem.SlugChar, '&'), |
| 1 | 185 | | IncludeItemTypes = new[] { baseItemKind }, |
| 1 | 186 | | DtoOptions = dtoOptions |
| 1 | 187 | | }).OfType<T>().FirstOrDefault(); |
| | 188 | |
|
| 1 | 189 | | result ??= libraryManager.GetItemList(new InternalItemsQuery |
| 1 | 190 | | { |
| 1 | 191 | | Name = name.Replace(BaseItem.SlugChar, '/'), |
| 1 | 192 | | IncludeItemTypes = new[] { baseItemKind }, |
| 1 | 193 | | DtoOptions = dtoOptions |
| 1 | 194 | | }).OfType<T>().FirstOrDefault(); |
| | 195 | |
|
| 1 | 196 | | result ??= libraryManager.GetItemList(new InternalItemsQuery |
| 1 | 197 | | { |
| 1 | 198 | | Name = name.Replace(BaseItem.SlugChar, '?'), |
| 1 | 199 | | IncludeItemTypes = new[] { baseItemKind }, |
| 1 | 200 | | DtoOptions = dtoOptions |
| 1 | 201 | | }).OfType<T>().FirstOrDefault(); |
| | 202 | |
|
| 1 | 203 | | return result; |
| | 204 | | } |
| | 205 | | } |