diff options
46 files changed, 435 insertions, 128 deletions
diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs index d11c7c99e..6236f86c4 100644 --- a/Emby.Naming/TV/SeasonPathParser.cs +++ b/Emby.Naming/TV/SeasonPathParser.cs @@ -60,7 +60,7 @@ namespace Emby.Naming.TV bool supportSpecialAliases, bool supportNumericSeasonFolders) { - var filename = Path.GetFileName(path) ?? string.Empty; + string filename = Path.GetFileName(path); if (supportSpecialAliases) { diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index e3ab0d6ea..54b18a8c8 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -249,7 +249,7 @@ namespace Emby.Server.Implementations.Dto var activeRecording = liveTvManager.GetActiveRecordingInfo(item.Path); if (activeRecording != null) { - dto.Type = "Recording"; + dto.Type = BaseItemKind.Recording; dto.CanDownload = false; dto.RunTimeTicks = null; @@ -904,7 +904,7 @@ namespace Emby.Server.Implementations.Dto } } - dto.Type = item.GetClientTypeName(); + dto.Type = item.GetBaseItemKind(); if ((item.CommunityRating ?? 0) > 0) { dto.CommunityRating = item.CommunityRating; diff --git a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs index e9e688fa6..60f82806f 100644 --- a/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs +++ b/Emby.Server.Implementations/Library/Resolvers/Audio/MusicArtistResolver.cs @@ -79,11 +79,6 @@ namespace Emby.Server.Implementations.Library.Resolvers.Audio return new MusicArtist(); } - if (_config.Configuration.EnableSimpleArtistDetection) - { - return null; - } - // Avoid mis-identifying top folders if (args.Parent.IsRoot) { diff --git a/Emby.Server.Implementations/Localization/Core/bg-BG.json b/Emby.Server.Implementations/Localization/Core/bg-BG.json index 7ff30df71..9db3b50d9 100644 --- a/Emby.Server.Implementations/Localization/Core/bg-BG.json +++ b/Emby.Server.Implementations/Localization/Core/bg-BG.json @@ -55,26 +55,26 @@ "NotificationOptionPluginInstalled": "Приставката е инсталирана", "NotificationOptionPluginUninstalled": "Приставката е деинсталирана", "NotificationOptionPluginUpdateInstalled": "Обновлението на приставката е инсталирано", - "NotificationOptionServerRestartRequired": "Нужно е повторно пускане на сървъра", + "NotificationOptionServerRestartRequired": "Сървърът трябва да се рестартира", "NotificationOptionTaskFailed": "Грешка в планирана задача", - "NotificationOptionUserLockedOut": "Потребителя е заключен", + "NotificationOptionUserLockedOut": "Потребителят е заключен", "NotificationOptionVideoPlayback": "Възпроизвеждането на видео започна", "NotificationOptionVideoPlaybackStopped": "Възпроизвеждането на видео е спряно", "Photos": "Снимки", "Playlists": "Списъци", "Plugin": "Приставка", - "PluginInstalledWithName": "{0} е инсталирано", - "PluginUninstalledWithName": "{0} е деинсталирано", - "PluginUpdatedWithName": "{0} е обновено", + "PluginInstalledWithName": "{0} е инсталиранa", + "PluginUninstalledWithName": "{0} е деинсталиранa", + "PluginUpdatedWithName": "{0} е обновенa", "ProviderValue": "Доставчик: {0}", "ScheduledTaskFailedWithName": "{0} се провали", "ScheduledTaskStartedWithName": "{0} започна", - "ServerNameNeedsToBeRestarted": "{0} е нужно да се рестартира", + "ServerNameNeedsToBeRestarted": "{0} трябва да се рестартира", "Shows": "Сериали", "Songs": "Песни", "StartupEmbyServerIsLoading": "Сървърът зарежда. Моля, опитайте отново след малко.", "SubtitleDownloadFailureForItem": "Неуспешно изтегляне на субтитри за {0}", - "SubtitleDownloadFailureFromForItem": "Поднадписите за {1} от {0} не можаха да се изтеглят", + "SubtitleDownloadFailureFromForItem": "Субтитрите за {1} от {0} не можаха да бъдат изтеглени", "Sync": "Синхронизиране", "System": "Система", "TvShows": "Телевизионни сериали", @@ -92,12 +92,12 @@ "ValueHasBeenAddedToLibrary": "{0} беше добавен във Вашата библиотека", "ValueSpecialEpisodeName": "Специални - {0}", "VersionNumber": "Версия {0}", - "TaskDownloadMissingSubtitlesDescription": "Търси Интернет за липсващи поднадписи, на база конфигурацията за мета-данни.", - "TaskDownloadMissingSubtitles": "Изтегляне на липсващи поднадписи", + "TaskDownloadMissingSubtitlesDescription": "Търси Интернет за липсващи субтитри, на база конфигурацията за мета-данни.", + "TaskDownloadMissingSubtitles": "Изтегляне на липсващи субтитри", "TaskRefreshChannelsDescription": "Обновява информацията за интернет канала.", "TaskRefreshChannels": "Обновяване на Канали", - "TaskCleanTranscodeDescription": "Изтрива прекодирани файлове по-стари от един ден.", - "TaskCleanTranscode": "Изчиства директорията за прекодиране", + "TaskCleanTranscodeDescription": "Изтрива транскодирани файлове по-стари от един ден.", + "TaskCleanTranscode": "Изчиства директорията за транскодиране", "TaskUpdatePluginsDescription": "Изтегля и инсталира актуализации за добавките, които са настроени за автоматична актуализация.", "TaskUpdatePlugins": "Актуализира добавките", "TaskRefreshPeopleDescription": "Актуализира мета-данните за артистите и режисьорите за Вашата медийна библиотека.", diff --git a/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs new file mode 100644 index 000000000..49b6689cd --- /dev/null +++ b/Jellyfin.Api/Attributes/AcceptsFileAttribute.cs @@ -0,0 +1,28 @@ +using System; + +namespace Jellyfin.Api.Attributes +{ + /// <summary> + /// Internal produces image attribute. + /// </summary> + [AttributeUsage(AttributeTargets.Method)] + public class AcceptsFileAttribute : Attribute + { + private readonly string[] _contentTypes; + + /// <summary> + /// Initializes a new instance of the <see cref="AcceptsFileAttribute"/> class. + /// </summary> + /// <param name="contentTypes">Content types this endpoint produces.</param> + public AcceptsFileAttribute(params string[] contentTypes) + { + _contentTypes = contentTypes; + } + + /// <summary> + /// Gets the configured content types. + /// </summary> + /// <returns>the configured content types.</returns> + public string[] GetContentTypes() => _contentTypes; + } +} diff --git a/Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs b/Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs new file mode 100644 index 000000000..001f27409 --- /dev/null +++ b/Jellyfin.Api/Attributes/AcceptsImageFileAttribute.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Api.Attributes +{ + /// <summary> + /// Produces file attribute of "image/*". + /// </summary> + public class AcceptsImageFileAttribute : AcceptsFileAttribute + { + private const string ContentType = "image/*"; + + /// <summary> + /// Initializes a new instance of the <see cref="AcceptsImageFileAttribute"/> class. + /// </summary> + public AcceptsImageFileAttribute() + : base(ContentType) + { + } + } +} diff --git a/Jellyfin.Api/Controllers/ArtistsController.cs b/Jellyfin.Api/Controllers/ArtistsController.cs index fed7ed3e5..4b2e5e7ea 100644 --- a/Jellyfin.Api/Controllers/ArtistsController.cs +++ b/Jellyfin.Api/Controllers/ArtistsController.cs @@ -3,8 +3,10 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; +using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -88,8 +90,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [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))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, @@ -127,8 +129,8 @@ namespace Jellyfin.Api.Controllers var query = new InternalItemsQuery(user) { - ExcludeItemTypes = excludeItemTypes, - IncludeItemTypes = includeItemTypes, + ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes), + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), MediaTypes = mediaTypes, StartIndex = startIndex, Limit = limit, @@ -287,8 +289,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [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))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, @@ -326,8 +328,8 @@ namespace Jellyfin.Api.Controllers var query = new InternalItemsQuery(user) { - ExcludeItemTypes = excludeItemTypes, - IncludeItemTypes = includeItemTypes, + ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes), + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), MediaTypes = mediaTypes, StartIndex = startIndex, Limit = limit, diff --git a/Jellyfin.Api/Controllers/CollectionController.cs b/Jellyfin.Api/Controllers/CollectionController.cs index 2a7b2b5c6..852d1e9cb 100644 --- a/Jellyfin.Api/Controllers/CollectionController.cs +++ b/Jellyfin.Api/Controllers/CollectionController.cs @@ -3,7 +3,6 @@ using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; -using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using MediaBrowser.Controller.Collections; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/DashboardController.cs b/Jellyfin.Api/Controllers/DashboardController.cs index ff7895373..b2baa9cea 100644 --- a/Jellyfin.Api/Controllers/DashboardController.cs +++ b/Jellyfin.Api/Controllers/DashboardController.cs @@ -7,17 +7,11 @@ using Jellyfin.Api.Attributes; using Jellyfin.Api.Models; using MediaBrowser.Common.Plugins; using MediaBrowser.Controller; -using MediaBrowser.Controller.Configuration; -using MediaBrowser.Controller.Extensions; -using MediaBrowser.Controller.Plugins; using MediaBrowser.Model.Net; using MediaBrowser.Model.Plugins; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.Extensions; using Microsoft.AspNetCore.Mvc; -using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; -using Microsoft.Net.Http.Headers; namespace Jellyfin.Api.Controllers { diff --git a/Jellyfin.Api/Controllers/DynamicHlsController.cs b/Jellyfin.Api/Controllers/DynamicHlsController.cs index 6e85737d2..e375645cf 100644 --- a/Jellyfin.Api/Controllers/DynamicHlsController.cs +++ b/Jellyfin.Api/Controllers/DynamicHlsController.cs @@ -15,7 +15,6 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.PlaybackDtos; using Jellyfin.Api.Models.StreamingDtos; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; diff --git a/Jellyfin.Api/Controllers/FilterController.cs b/Jellyfin.Api/Controllers/FilterController.cs index 9220b988f..223b2a2b6 100644 --- a/Jellyfin.Api/Controllers/FilterController.cs +++ b/Jellyfin.Api/Controllers/FilterController.cs @@ -1,13 +1,12 @@ using System; using System.Linq; using Jellyfin.Api.Constants; +using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; +using Jellyfin.Data.Enums; 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; @@ -51,7 +50,7 @@ namespace Jellyfin.Api.Controllers public ActionResult<QueryFiltersLegacy> GetQueryFiltersLegacy( [FromQuery] Guid? userId, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes) { var user = userId.HasValue && !userId.Equals(Guid.Empty) @@ -60,10 +59,10 @@ namespace Jellyfin.Api.Controllers BaseItem? item = null; if (includeItemTypes.Length != 1 - || !(string.Equals(includeItemTypes[0], nameof(BoxSet), StringComparison.OrdinalIgnoreCase) - || string.Equals(includeItemTypes[0], nameof(Playlist), StringComparison.OrdinalIgnoreCase) - || string.Equals(includeItemTypes[0], nameof(Trailer), StringComparison.OrdinalIgnoreCase) - || string.Equals(includeItemTypes[0], "Program", StringComparison.OrdinalIgnoreCase))) + || !(includeItemTypes[0] == BaseItemKind.BoxSet + || includeItemTypes[0] == BaseItemKind.Playlist + || includeItemTypes[0] == BaseItemKind.Trailer + || includeItemTypes[0] == BaseItemKind.Program)) { item = _libraryManager.GetParentItem(parentId, user?.Id); } @@ -72,7 +71,7 @@ namespace Jellyfin.Api.Controllers { User = user, MediaTypes = mediaTypes, - IncludeItemTypes = includeItemTypes, + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), Recursive = true, EnableTotalRecordCount = false, DtoOptions = new DtoOptions @@ -137,7 +136,7 @@ namespace Jellyfin.Api.Controllers public ActionResult<QueryFilters> GetQueryFilters( [FromQuery] Guid? userId, [FromQuery] Guid? parentId, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isAiring, [FromQuery] bool? isMovie, [FromQuery] bool? isSports, @@ -152,10 +151,10 @@ namespace Jellyfin.Api.Controllers BaseItem? parentItem = null; if (includeItemTypes.Length == 1 - && (string.Equals(includeItemTypes[0], nameof(BoxSet), StringComparison.OrdinalIgnoreCase) - || string.Equals(includeItemTypes[0], nameof(Playlist), StringComparison.OrdinalIgnoreCase) - || string.Equals(includeItemTypes[0], nameof(Trailer), StringComparison.OrdinalIgnoreCase) - || string.Equals(includeItemTypes[0], "Program", StringComparison.OrdinalIgnoreCase))) + && (includeItemTypes[0] == BaseItemKind.BoxSet + || includeItemTypes[0] == BaseItemKind.Playlist + || includeItemTypes[0] == BaseItemKind.Trailer + || includeItemTypes[0] == BaseItemKind.Program)) { parentItem = null; } @@ -167,7 +166,7 @@ namespace Jellyfin.Api.Controllers var filters = new QueryFilters(); var genreQuery = new InternalItemsQuery(user) { - IncludeItemTypes = includeItemTypes, + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), DtoOptions = new DtoOptions { Fields = Array.Empty<ItemFields>(), @@ -192,10 +191,10 @@ namespace Jellyfin.Api.Controllers } if (includeItemTypes.Length == 1 - && (string.Equals(includeItemTypes[0], nameof(MusicAlbum), StringComparison.OrdinalIgnoreCase) - || string.Equals(includeItemTypes[0], nameof(MusicVideo), StringComparison.OrdinalIgnoreCase) - || string.Equals(includeItemTypes[0], nameof(MusicArtist), StringComparison.OrdinalIgnoreCase) - || string.Equals(includeItemTypes[0], nameof(Audio), StringComparison.OrdinalIgnoreCase))) + && (includeItemTypes[0] == BaseItemKind.MusicAlbum + || includeItemTypes[0] == BaseItemKind.MusicVideo + || includeItemTypes[0] == BaseItemKind.MusicArtist + || includeItemTypes[0] == BaseItemKind.Audio)) { filters.Genres = _libraryManager.GetMusicGenres(genreQuery).Items.Select(i => new NameGuidPair { diff --git a/Jellyfin.Api/Controllers/GenresController.cs b/Jellyfin.Api/Controllers/GenresController.cs index b6755ed5e..7bcf4674c 100644 --- a/Jellyfin.Api/Controllers/GenresController.cs +++ b/Jellyfin.Api/Controllers/GenresController.cs @@ -6,6 +6,7 @@ using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -74,8 +75,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [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))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isFavorite, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, @@ -96,8 +97,8 @@ namespace Jellyfin.Api.Controllers var query = new InternalItemsQuery(user) { - ExcludeItemTypes = excludeItemTypes, - IncludeItemTypes = includeItemTypes, + ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes), + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, diff --git a/Jellyfin.Api/Controllers/HlsSegmentController.cs b/Jellyfin.Api/Controllers/HlsSegmentController.cs index f51987732..25abe73ed 100644 --- a/Jellyfin.Api/Controllers/HlsSegmentController.cs +++ b/Jellyfin.Api/Controllers/HlsSegmentController.cs @@ -2,13 +2,11 @@ using System; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Linq; using System.Threading.Tasks; using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Model.IO; diff --git a/Jellyfin.Api/Controllers/ImageController.cs b/Jellyfin.Api/Controllers/ImageController.cs index c606d327c..dc3634970 100644 --- a/Jellyfin.Api/Controllers/ImageController.cs +++ b/Jellyfin.Api/Controllers/ImageController.cs @@ -87,6 +87,7 @@ namespace Jellyfin.Api.Controllers /// <returns>A <see cref="NoContentResult"/>.</returns> [HttpPost("Users/{userId}/Images/{imageType}")] [Authorize(Policy = Policies.DefaultAuthorization)] + [AcceptsImageFile] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] @@ -133,6 +134,7 @@ namespace Jellyfin.Api.Controllers /// <returns>A <see cref="NoContentResult"/>.</returns> [HttpPost("Users/{userId}/Images/{imageType}/{index}")] [Authorize(Policy = Policies.DefaultAuthorization)] + [AcceptsImageFile] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status403Forbidden)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "imageType", Justification = "Imported from ServiceStack")] @@ -312,6 +314,7 @@ namespace Jellyfin.Api.Controllers /// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if item not found.</returns> [HttpPost("Items/{itemId}/Images/{imageType}")] [Authorize(Policy = Policies.RequiresElevation)] + [AcceptsImageFile] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] @@ -346,6 +349,7 @@ namespace Jellyfin.Api.Controllers /// <returns>A <see cref="NoContentResult"/> on success, or a <see cref="NotFoundResult"/> if item not found.</returns> [HttpPost("Items/{itemId}/Images/{imageType}/{imageIndex}")] [Authorize(Policy = Policies.RequiresElevation)] + [AcceptsImageFile] [ProducesResponseType(StatusCodes.Status204NoContent)] [ProducesResponseType(StatusCodes.Status404NotFound)] [SuppressMessage("Microsoft.Performance", "CA1801:ReviewUnusedParameters", MessageId = "index", Justification = "Imported from ServiceStack")] diff --git a/Jellyfin.Api/Controllers/InstantMixController.cs b/Jellyfin.Api/Controllers/InstantMixController.cs index 244625752..f061755c3 100644 --- a/Jellyfin.Api/Controllers/InstantMixController.cs +++ b/Jellyfin.Api/Controllers/InstantMixController.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.ModelBinders; diff --git a/Jellyfin.Api/Controllers/ItemLookupController.cs b/Jellyfin.Api/Controllers/ItemLookupController.cs index 6c38f77ce..dfc68ffce 100644 --- a/Jellyfin.Api/Controllers/ItemLookupController.cs +++ b/Jellyfin.Api/Controllers/ItemLookupController.cs @@ -2,8 +2,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.IO; -using System.Linq; -using System.Net.Mime; using System.Text.Json; using System.Threading; using System.Threading.Tasks; diff --git a/Jellyfin.Api/Controllers/ItemsController.cs b/Jellyfin.Api/Controllers/ItemsController.cs index 7d7747495..2c9760f6d 100644 --- a/Jellyfin.Api/Controllers/ItemsController.cs +++ b/Jellyfin.Api/Controllers/ItemsController.cs @@ -1,6 +1,5 @@ using System; using System.ComponentModel.DataAnnotations; -using System.Globalization; using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; @@ -178,8 +177,8 @@ namespace Jellyfin.Api.Controllers [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] 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))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, @@ -233,8 +232,8 @@ namespace Jellyfin.Api.Controllers .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); if (includeItemTypes.Length == 1 - && (includeItemTypes[0].Equals("Playlist", StringComparison.OrdinalIgnoreCase) - || includeItemTypes[0].Equals("BoxSet", StringComparison.OrdinalIgnoreCase))) + && (includeItemTypes[0] == BaseItemKind.Playlist + || includeItemTypes[0] == BaseItemKind.BoxSet)) { parentId = null; } @@ -251,7 +250,7 @@ namespace Jellyfin.Api.Controllers && string.Equals(hasCollectionType.CollectionType, CollectionType.Playlists, StringComparison.OrdinalIgnoreCase)) { recursive = true; - includeItemTypes = new[] { "Playlist" }; + includeItemTypes = new[] { BaseItemKind.Playlist }; } var enabledChannels = user!.GetPreferenceValues<Guid>(PreferenceKind.EnabledChannels); @@ -286,8 +285,8 @@ namespace Jellyfin.Api.Controllers { IsPlayed = isPlayed, MediaTypes = mediaTypes, - IncludeItemTypes = includeItemTypes, - ExcludeItemTypes = excludeItemTypes, + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), + ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes), Recursive = recursive ?? false, OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder), IsFavorite = isFavorite, @@ -611,8 +610,8 @@ namespace Jellyfin.Api.Controllers [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] 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))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, @@ -773,8 +772,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true) { @@ -810,8 +809,8 @@ namespace Jellyfin.Api.Controllers CollapseBoxSetItems = false, EnableTotalRecordCount = enableTotalRecordCount, AncestorIds = ancestorIds, - IncludeItemTypes = includeItemTypes, - ExcludeItemTypes = excludeItemTypes, + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), + ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes), SearchTerm = searchTerm }); diff --git a/Jellyfin.Api/Controllers/LibraryController.cs b/Jellyfin.Api/Controllers/LibraryController.cs index 28d359ac3..db4aa9668 100644 --- a/Jellyfin.Api/Controllers/LibraryController.cs +++ b/Jellyfin.Api/Controllers/LibraryController.cs @@ -11,7 +11,6 @@ using System.Threading.Tasks; using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; -using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.LibraryDtos; using Jellyfin.Data.Entities; diff --git a/Jellyfin.Api/Controllers/MusicGenresController.cs b/Jellyfin.Api/Controllers/MusicGenresController.cs index 2608a9cd0..7f7058b5e 100644 --- a/Jellyfin.Api/Controllers/MusicGenresController.cs +++ b/Jellyfin.Api/Controllers/MusicGenresController.cs @@ -6,6 +6,7 @@ using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; @@ -74,8 +75,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [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))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isFavorite, [FromQuery] int? imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, @@ -96,8 +97,8 @@ namespace Jellyfin.Api.Controllers var query = new InternalItemsQuery(user) { - ExcludeItemTypes = excludeItemTypes, - IncludeItemTypes = includeItemTypes, + ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes), + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, diff --git a/Jellyfin.Api/Controllers/PackageController.cs b/Jellyfin.Api/Controllers/PackageController.cs index c589f54ac..5dd49ef2f 100644 --- a/Jellyfin.Api/Controllers/PackageController.cs +++ b/Jellyfin.Api/Controllers/PackageController.cs @@ -4,7 +4,6 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using System.Threading.Tasks; using Jellyfin.Api.Constants; -using MediaBrowser.Common.Json; using MediaBrowser.Common.Updates; using MediaBrowser.Controller.Configuration; using MediaBrowser.Model.Updates; diff --git a/Jellyfin.Api/Controllers/PersonsController.cs b/Jellyfin.Api/Controllers/PersonsController.cs index 17e631197..70a94e27c 100644 --- a/Jellyfin.Api/Controllers/PersonsController.cs +++ b/Jellyfin.Api/Controllers/PersonsController.cs @@ -3,7 +3,6 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; -using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/PlaylistsController.cs b/Jellyfin.Api/Controllers/PlaylistsController.cs index a55e4ad2f..1667d6ede 100644 --- a/Jellyfin.Api/Controllers/PlaylistsController.cs +++ b/Jellyfin.Api/Controllers/PlaylistsController.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; -using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.PlaylistDtos; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/PluginsController.cs b/Jellyfin.Api/Controllers/PluginsController.cs index b73611c97..a5aa9bfca 100644 --- a/Jellyfin.Api/Controllers/PluginsController.cs +++ b/Jellyfin.Api/Controllers/PluginsController.cs @@ -1,10 +1,8 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Globalization; using System.IO; using System.Linq; -using System.Net.Mime; using System.Text.Json; using System.Threading.Tasks; using Jellyfin.Api.Attributes; @@ -300,9 +298,7 @@ namespace Jellyfin.Api.Controllers } var imagePath = Path.Combine(plugin.Path, plugin.Manifest.ImagePath ?? string.Empty); - if (((ServerConfiguration)_config.CommonConfiguration).DisablePluginImages - || plugin.Manifest.ImagePath == null - || !System.IO.File.Exists(imagePath)) + if (plugin.Manifest.ImagePath == null || !System.IO.File.Exists(imagePath)) { return NotFound(); } diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 08255ff8f..6c22050a7 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -6,6 +6,7 @@ using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -83,8 +84,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? limit, [FromQuery] Guid? userId, [FromQuery, Required] string searchTerm, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery] Guid? parentId, [FromQuery] bool? isMovie, @@ -109,8 +110,8 @@ namespace Jellyfin.Api.Controllers IncludeStudios = includeStudios, StartIndex = startIndex, UserId = userId ?? Guid.Empty, - IncludeItemTypes = includeItemTypes, - ExcludeItemTypes = excludeItemTypes, + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), + ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes), MediaTypes = mediaTypes, ParentId = parentId, diff --git a/Jellyfin.Api/Controllers/StudiosController.cs b/Jellyfin.Api/Controllers/StudiosController.cs index bb54c59f6..da8f8b199 100644 --- a/Jellyfin.Api/Controllers/StudiosController.cs +++ b/Jellyfin.Api/Controllers/StudiosController.cs @@ -5,6 +5,7 @@ using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Entities; +using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; @@ -73,8 +74,8 @@ namespace Jellyfin.Api.Controllers [FromQuery] string? searchTerm, [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))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isFavorite, [FromQuery] bool? enableUserData, [FromQuery] int? imageTypeLimit, @@ -96,8 +97,8 @@ namespace Jellyfin.Api.Controllers var query = new InternalItemsQuery(user) { - ExcludeItemTypes = excludeItemTypes, - IncludeItemTypes = includeItemTypes, + ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes), + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, diff --git a/Jellyfin.Api/Controllers/SuggestionsController.cs b/Jellyfin.Api/Controllers/SuggestionsController.cs index 9f1dec712..a55f13e66 100644 --- a/Jellyfin.Api/Controllers/SuggestionsController.cs +++ b/Jellyfin.Api/Controllers/SuggestionsController.cs @@ -3,7 +3,6 @@ using System.ComponentModel.DataAnnotations; using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; -using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Data.Enums; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/SyncPlayController.cs b/Jellyfin.Api/Controllers/SyncPlayController.cs index 82cbe58df..f878f2329 100644 --- a/Jellyfin.Api/Controllers/SyncPlayController.cs +++ b/Jellyfin.Api/Controllers/SyncPlayController.cs @@ -1,4 +1,3 @@ -using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Threading; diff --git a/Jellyfin.Api/Controllers/SystemController.cs b/Jellyfin.Api/Controllers/SystemController.cs index e67a27ae3..bbbe5fb8d 100644 --- a/Jellyfin.Api/Controllers/SystemController.cs +++ b/Jellyfin.Api/Controllers/SystemController.cs @@ -5,7 +5,6 @@ using System.IO; using System.Linq; using System.Net; using System.Net.Mime; -using System.Threading; using System.Threading.Tasks; using Jellyfin.Api.Attributes; using Jellyfin.Api.Constants; diff --git a/Jellyfin.Api/Controllers/TimeSyncController.cs b/Jellyfin.Api/Controllers/TimeSyncController.cs index c730ac12b..7df51c7af 100644 --- a/Jellyfin.Api/Controllers/TimeSyncController.cs +++ b/Jellyfin.Api/Controllers/TimeSyncController.cs @@ -1,5 +1,4 @@ using System; -using System.Globalization; using MediaBrowser.Model.SyncPlay; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; diff --git a/Jellyfin.Api/Controllers/TrailersController.cs b/Jellyfin.Api/Controllers/TrailersController.cs index 242b8f068..dd3836551 100644 --- a/Jellyfin.Api/Controllers/TrailersController.cs +++ b/Jellyfin.Api/Controllers/TrailersController.cs @@ -148,7 +148,7 @@ namespace Jellyfin.Api.Controllers [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, [FromQuery] Guid? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery] bool? isFavorite, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, @@ -194,7 +194,7 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool enableTotalRecordCount = true, [FromQuery] bool? enableImages = true) { - var includeItemTypes = new[] { "Trailer" }; + var includeItemTypes = new[] { BaseItemKind.Trailer }; return _itemsController .GetItems( diff --git a/Jellyfin.Api/Controllers/TvShowsController.cs b/Jellyfin.Api/Controllers/TvShowsController.cs index 223f58859..e1c67f830 100644 --- a/Jellyfin.Api/Controllers/TvShowsController.cs +++ b/Jellyfin.Api/Controllers/TvShowsController.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Globalization; using System.Linq; using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index 0e65591cc..1d70406ac 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -8,6 +8,7 @@ using Jellyfin.Api.Constants; using Jellyfin.Api.Extensions; using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; +using Jellyfin.Data.Enums; using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -269,7 +270,7 @@ namespace Jellyfin.Api.Controllers [FromRoute, Required] Guid userId, [FromQuery] Guid? parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, - [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] includeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery] bool? isPlayed, [FromQuery] bool? enableImages, [FromQuery] int? imageTypeLimit, @@ -296,7 +297,7 @@ namespace Jellyfin.Api.Controllers new LatestItemsQuery { GroupItems = groupItems, - IncludeItemTypes = includeItemTypes, + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), IsPlayed = isPlayed, Limit = limit, ParentId = parentId ?? Guid.Empty, diff --git a/Jellyfin.Api/Controllers/UserViewsController.cs b/Jellyfin.Api/Controllers/UserViewsController.cs index e1483ce9d..7bc5ecdf1 100644 --- a/Jellyfin.Api/Controllers/UserViewsController.cs +++ b/Jellyfin.Api/Controllers/UserViewsController.cs @@ -4,7 +4,6 @@ using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; using Jellyfin.Api.Extensions; -using Jellyfin.Api.Helpers; using Jellyfin.Api.ModelBinders; using Jellyfin.Api.Models.UserViewDtos; using MediaBrowser.Controller.Dto; diff --git a/Jellyfin.Api/Controllers/VideoHlsController.cs b/Jellyfin.Api/Controllers/VideoHlsController.cs index 7e743ee0c..ba51aa43e 100644 --- a/Jellyfin.Api/Controllers/VideoHlsController.cs +++ b/Jellyfin.Api/Controllers/VideoHlsController.cs @@ -12,7 +12,6 @@ using Jellyfin.Api.Helpers; using Jellyfin.Api.Models.PlaybackDtos; using Jellyfin.Api.Models.StreamingDtos; using MediaBrowser.Common.Configuration; -using MediaBrowser.Common.Extensions; using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Devices; using MediaBrowser.Controller.Dlna; diff --git a/Jellyfin.Api/Controllers/YearsController.cs b/Jellyfin.Api/Controllers/YearsController.cs index 7c27752f7..d6dc6650c 100644 --- a/Jellyfin.Api/Controllers/YearsController.cs +++ b/Jellyfin.Api/Controllers/YearsController.cs @@ -74,8 +74,8 @@ namespace Jellyfin.Api.Controllers [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] 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))] BaseItemKind[] excludeItemTypes, + [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy, [FromQuery] bool? enableUserData, @@ -101,8 +101,8 @@ namespace Jellyfin.Api.Controllers var query = new InternalItemsQuery(user) { - ExcludeItemTypes = excludeItemTypes, - IncludeItemTypes = includeItemTypes, + ExcludeItemTypes = RequestHelpers.GetItemTypeStrings(excludeItemTypes), + IncludeItemTypes = RequestHelpers.GetItemTypeStrings(includeItemTypes), MediaTypes = mediaTypes, DtoOptions = dtoOptions }; @@ -193,16 +193,17 @@ namespace Jellyfin.Api.Controllers return _dtoService.GetBaseItemDto(item, dtoOptions); } - private bool FilterItem(BaseItem f, IReadOnlyCollection<string> excludeItemTypes, IReadOnlyCollection<string> includeItemTypes, IReadOnlyCollection<string> mediaTypes) + private bool FilterItem(BaseItem f, IReadOnlyCollection<BaseItemKind> excludeItemTypes, IReadOnlyCollection<BaseItemKind> includeItemTypes, IReadOnlyCollection<string> mediaTypes) { + var baseItemKind = f.GetBaseItemKind(); // Exclude item types - if (excludeItemTypes.Count > 0 && excludeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)) + if (excludeItemTypes.Count > 0 && excludeItemTypes.Contains(baseItemKind)) { return false; } // Include item types - if (includeItemTypes.Count > 0 && !includeItemTypes.Contains(f.GetType().Name, StringComparer.OrdinalIgnoreCase)) + if (includeItemTypes.Count > 0 && !includeItemTypes.Contains(baseItemKind)) { return false; } diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs index db0ccc657..94856e03e 100644 --- a/Jellyfin.Api/Helpers/RequestHelpers.cs +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -129,5 +129,21 @@ namespace Jellyfin.Api.Helpers TotalRecordCount = result.TotalRecordCount }; } + + internal static string[] GetItemTypeStrings(IReadOnlyList<BaseItemKind> itemKinds) + { + if (itemKinds.Count == 0) + { + return Array.Empty<string>(); + } + + var itemTypes = new string[itemKinds.Count]; + for (var i = 0; i < itemKinds.Count; i++) + { + itemTypes[i] = itemKinds[i].ToString(); + } + + return itemTypes; + } } } diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index c2f4ab522..ef105fdce 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -38,4 +38,10 @@ <CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet> </PropertyGroup> + <ItemGroup> + <AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo"> + <_Parameter1>Jellyfin.Api.Tests</_Parameter1> + </AssemblyAttribute> + </ItemGroup> + </Project> diff --git a/Jellyfin.Data/Enums/BaseItemKind.cs b/Jellyfin.Data/Enums/BaseItemKind.cs new file mode 100644 index 000000000..aac30279e --- /dev/null +++ b/Jellyfin.Data/Enums/BaseItemKind.cs @@ -0,0 +1,190 @@ +namespace Jellyfin.Data.Enums +{ + /// <summary> + /// The base item kind. + /// </summary> + /// <remarks> + /// This enum is generated from all classes that inherit from <c>BaseItem</c>. + /// </remarks> + public enum BaseItemKind + { + /// <summary> + /// Item is aggregate folder. + /// </summary> + AggregateFolder, + + /// <summary> + /// Item is audio. + /// </summary> + Audio, + + /// <summary> + /// Item is audio book. + /// </summary> + AudioBook, + + /// <summary> + /// Item is base plugin folder. + /// </summary> + BasePluginFolder, + + /// <summary> + /// Item is book. + /// </summary> + Book, + + /// <summary> + /// Item is box set. + /// </summary> + BoxSet, + + /// <summary> + /// Item is channel. + /// </summary> + Channel, + + /// <summary> + /// Item is channel folder item. + /// </summary> + ChannelFolderItem, + + /// <summary> + /// Item is collection folder. + /// </summary> + CollectionFolder, + + /// <summary> + /// Item is episode. + /// </summary> + Episode, + + /// <summary> + /// Item is folder. + /// </summary> + Folder, + + /// <summary> + /// Item is genre. + /// </summary> + Genre, + + /// <summary> + /// Item is manual playlists folder. + /// </summary> + ManualPlaylistsFolder, + + /// <summary> + /// Item is movie. + /// </summary> + Movie, + + /// <summary> + /// Item is music album. + /// </summary> + MusicAlbum, + + /// <summary> + /// Item is music artist. + /// </summary> + MusicArtist, + + /// <summary> + /// Item is music genre. + /// </summary> + MusicGenre, + + /// <summary> + /// Item is music video. + /// </summary> + MusicVideo, + + /// <summary> + /// Item is person. + /// </summary> + Person, + + /// <summary> + /// Item is photo. + /// </summary> + Photo, + + /// <summary> + /// Item is photo album. + /// </summary> + PhotoAlbum, + + /// <summary> + /// Item is playlist. + /// </summary> + Playlist, + + /// <summary> + /// Item is program + /// </summary> + Program, + + /// <summary> + /// Item is recording. + /// </summary> + /// <remarks> + /// Manually added. + /// </remarks> + Recording, + + /// <summary> + /// Item is season. + /// </summary> + Season, + + /// <summary> + /// Item is series. + /// </summary> + Series, + + /// <summary> + /// Item is studio. + /// </summary> + Studio, + + /// <summary> + /// Item is trailer. + /// </summary> + Trailer, + + /// <summary> + /// Item is live tv channel. + /// </summary> + /// <remarks> + /// Type is overridden. + /// </remarks> + TvChannel, + + /// <summary> + /// Item is live tv program. + /// </summary> + /// <remarks> + /// Type is overridden. + /// </remarks> + TvProgram, + + /// <summary> + /// Item is user root folder. + /// </summary> + UserRootFolder, + + /// <summary> + /// Item is user view. + /// </summary> + UserView, + + /// <summary> + /// Item is video. + /// </summary> + Video, + + /// <summary> + /// Item is year. + /// </summary> + Year + } +}
\ No newline at end of file diff --git a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs index da4cc267b..545937207 100644 --- a/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs +++ b/Jellyfin.Server/Extensions/ApiServiceCollectionExtensions.cs @@ -316,6 +316,7 @@ namespace Jellyfin.Server.Extensions c.OperationFilter<SecurityRequirementsOperationFilter>(); c.OperationFilter<FileResponseFilter>(); + c.OperationFilter<FileRequestFilter>(); c.OperationFilter<ParameterObsoleteFilter>(); c.DocumentFilter<WebsocketModelFilter>(); }); diff --git a/Jellyfin.Server/Filters/FileRequestFilter.cs b/Jellyfin.Server/Filters/FileRequestFilter.cs new file mode 100644 index 000000000..69e10994f --- /dev/null +++ b/Jellyfin.Server/Filters/FileRequestFilter.cs @@ -0,0 +1,43 @@ +using System.Collections.Generic; +using Jellyfin.Api.Attributes; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace Jellyfin.Server.Filters +{ + /// <inheritdoc /> + public class FileRequestFilter : IOperationFilter + { + /// <inheritdoc /> + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + foreach (var attribute in context.ApiDescription.ActionDescriptor.EndpointMetadata) + { + if (attribute is AcceptsFileAttribute acceptsFileAttribute) + { + operation.RequestBody = GetRequestBody(acceptsFileAttribute.GetContentTypes()); + break; + } + } + } + + private static OpenApiRequestBody GetRequestBody(IEnumerable<string> contentTypes) + { + var body = new OpenApiRequestBody(); + var mediaType = new OpenApiMediaType + { + Schema = new OpenApiSchema + { + Type = "string", + Format = "binary" + } + }; + foreach (var contentType in contentTypes) + { + body.Content.Add(contentType, mediaType); + } + + return body; + } + } +} diff --git a/MediaBrowser.sln b/Jellyfin.sln index 4e6687cce..4e6687cce 100644 --- a/MediaBrowser.sln +++ b/Jellyfin.sln diff --git a/MediaBrowser.Common/Json/JsonDefaults.cs b/MediaBrowser.Common/Json/JsonDefaults.cs index 9a2ea6875..2ef24a884 100644 --- a/MediaBrowser.Common/Json/JsonDefaults.cs +++ b/MediaBrowser.Common/Json/JsonDefaults.cs @@ -31,7 +31,6 @@ namespace MediaBrowser.Common.Json WriteIndented = false, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, NumberHandling = JsonNumberHandling.AllowReadingFromString, - PropertyNameCaseInsensitive = true, Converters = { new JsonGuidConverter(), diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cbb02aabd..7598b29e6 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1998,6 +1998,11 @@ namespace MediaBrowser.Controller.Entities return GetType().Name; } + public BaseItemKind GetBaseItemKind() + { + return Enum.Parse<BaseItemKind>(GetClientTypeName()); + } + /// <summary> /// Gets the linked child. /// </summary> diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index 0f0ad0f9a..d1e999666 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -254,7 +254,7 @@ namespace MediaBrowser.Model.Configuration /// Gets or sets the preferred metadata language. /// </summary> /// <value>The preferred metadata language.</value> - public string PreferredMetadataLanguage { get; set; } = string.Empty; + public string PreferredMetadataLanguage { get; set; } = "en"; /// <summary> /// Gets or sets the metadata country code. @@ -418,8 +418,6 @@ namespace MediaBrowser.Model.Configuration public PathSubstitution[] PathSubstitutions { get; set; } = Array.Empty<PathSubstitution>(); - public bool EnableSimpleArtistDetection { get; set; } = false; - public string[] UninstalledPlugins { get; set; } = Array.Empty<string>(); /// <summary> @@ -461,10 +459,5 @@ namespace MediaBrowser.Model.Configuration /// Gets or sets a value indicating whether older plugins should automatically be deleted from the plugin folder. /// </summary> public bool RemoveOldPlugins { get; set; } - - /// <summary> - /// Gets or sets a value indicating whether plugin image should be disabled. - /// </summary> - public bool DisablePluginImages { get; set; } } } diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 3f7aac9cd..2f9f9d3cd 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using Jellyfin.Data.Enums; using MediaBrowser.Model.Drawing; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Library; @@ -276,7 +277,7 @@ namespace MediaBrowser.Model.Dto /// Gets or sets the type. /// </summary> /// <value>The type.</value> - public string Type { get; set; } + public BaseItemKind Type { get; set; } /// <summary> /// Gets or sets the people. diff --git a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs index 606041c7f..97e441b1d 100644 --- a/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs +++ b/tests/Jellyfin.Api.Tests/Helpers/RequestHelpersTests.cs @@ -6,11 +6,11 @@ using Xunit; namespace Jellyfin.Api.Tests.Helpers { - public class RequestHelpersTests + public static class RequestHelpersTests { [Theory] [MemberData(nameof(GetOrderBy_Success_TestData))] - public void GetOrderBy_Success(IReadOnlyList<string> sortBy, IReadOnlyList<SortOrder> requestedSortOrder, (string, SortOrder)[] expected) + public static void GetOrderBy_Success(IReadOnlyList<string> sortBy, IReadOnlyList<SortOrder> requestedSortOrder, (string, SortOrder)[] expected) { Assert.Equal(expected, RequestHelpers.GetOrderBy(sortBy, requestedSortOrder)); } @@ -55,5 +55,35 @@ namespace Jellyfin.Api.Tests.Helpers } }; } + + [Fact] + public static void GetItemTypeStrings_Empty_Empty() + { + Assert.Empty(RequestHelpers.GetItemTypeStrings(Array.Empty<BaseItemKind>())); + } + + [Fact] + public static void GetItemTypeStrings_Valid_Success() + { + BaseItemKind[] input = + { + BaseItemKind.AggregateFolder, + BaseItemKind.Audio, + BaseItemKind.BasePluginFolder, + BaseItemKind.CollectionFolder + }; + + string[] expected = + { + "AggregateFolder", + "Audio", + "BasePluginFolder", + "CollectionFolder" + }; + + var res = RequestHelpers.GetItemTypeStrings(input); + + Assert.Equal(expected, res); + } } } |
