From 638cfa32abc3ffd61119f774ffc5a0f5a490d3e9 Mon Sep 17 00:00:00 2001 From: David Date: Tue, 2 Jun 2020 15:07:07 +0200 Subject: Move SearchService to new API endpoint --- Jellyfin.Api/Controllers/SearchController.cs | 266 +++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 Jellyfin.Api/Controllers/SearchController.cs (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs new file mode 100644 index 000000000..15a650bf9 --- /dev/null +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -0,0 +1,266 @@ +using System; +using System.ComponentModel; +using System.ComponentModel.DataAnnotations; +using System.Globalization; +using System.Linq; +using MediaBrowser.Controller.Drawing; +using MediaBrowser.Controller.Dto; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Net; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Search; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; + +namespace Jellyfin.Api.Controllers +{ + /// + /// Search controller. + /// + [Route("/Search/Hints")] + [Authenticated] + public class SearchController : BaseJellyfinApiController + { + private readonly ISearchEngine _searchEngine; + private readonly ILibraryManager _libraryManager; + private readonly IDtoService _dtoService; + private readonly IImageProcessor _imageProcessor; + + /// + /// Initializes a new instance of the class. + /// + /// Instance of interface. + /// Instance of interface. + /// Instance of interface. + /// Instance of interface. + public SearchController( + ISearchEngine searchEngine, + ILibraryManager libraryManager, + IDtoService dtoService, + IImageProcessor imageProcessor) + { + _searchEngine = searchEngine; + _libraryManager = libraryManager; + _dtoService = dtoService; + _imageProcessor = imageProcessor; + } + + /// + /// Gets the search hint result. + /// + /// The record index to start at. All items with a lower index will be dropped from the results. + /// The maximum number of records to return. + /// Supply a user id to search within a user's library or omit to search all. + /// The search term to filter on. + /// Optional filter whether to include people. + /// Optional filter whether to include media. + /// Optional filter whether to include genres. + /// Optional filter whether to include studios. + /// Optional filter whether to include artists. + /// If specified, only results with the specified item types are returned. This allows multiple, comma delimeted. + /// If specified, results with these item types are filtered out. This allows multiple, comma delimeted. + /// If specified, only results with the specified media types are returned. This allows multiple, comma delimeted. + /// If specified, only children of the parent are returned. + /// Optional filter for movies. + /// Optional filter for series. + /// Optional filter for news. + /// Optional filter for kids. + /// Optional filter for sports. + /// An with the results of the search. + [HttpGet] + [Description("Gets search hints based on a search term")] + [ProducesResponseType(StatusCodes.Status200OK)] + public ActionResult Get( + [FromQuery] int? startIndex, + [FromQuery] int? limit, + [FromQuery] Guid userId, + [FromQuery, Required] string searchTerm, + [FromQuery] bool includePeople, + [FromQuery] bool includeMedia, + [FromQuery] bool includeGenres, + [FromQuery] bool includeStudios, + [FromQuery] bool includeArtists, + [FromQuery] string includeItemTypes, + [FromQuery] string excludeItemTypes, + [FromQuery] string mediaTypes, + [FromQuery] string parentId, + [FromQuery] bool? isMovie, + [FromQuery] bool? isSeries, + [FromQuery] bool? isNews, + [FromQuery] bool? isKids, + [FromQuery] bool? isSports) + { + var result = _searchEngine.GetSearchHints(new SearchQuery + { + Limit = limit, + SearchTerm = searchTerm, + IncludeArtists = includeArtists, + IncludeGenres = includeGenres, + IncludeMedia = includeMedia, + IncludePeople = includePeople, + IncludeStudios = includeStudios, + StartIndex = startIndex, + UserId = userId, + IncludeItemTypes = Split(includeItemTypes, ',', true), + ExcludeItemTypes = Split(excludeItemTypes, ',', true), + MediaTypes = Split(mediaTypes, ',', true), + ParentId = parentId, + + IsKids = isKids, + IsMovie = isMovie, + IsNews = isNews, + IsSeries = isSeries, + IsSports = isSports + }); + + return Ok(new SearchHintResult + { + TotalRecordCount = result.TotalRecordCount, + SearchHints = result.Items.Select(GetSearchHintResult).ToArray() + }); + } + + /// + /// Gets the search hint result. + /// + /// The hint info. + /// SearchHintResult. + private SearchHint GetSearchHintResult(SearchHintInfo hintInfo) + { + var item = hintInfo.Item; + + var result = new SearchHint + { + Name = item.Name, + IndexNumber = item.IndexNumber, + ParentIndexNumber = item.ParentIndexNumber, + Id = item.Id, + Type = item.GetClientTypeName(), + MediaType = item.MediaType, + MatchedTerm = hintInfo.MatchedTerm, + RunTimeTicks = item.RunTimeTicks, + ProductionYear = item.ProductionYear, + ChannelId = item.ChannelId, + EndDate = item.EndDate + }; + + // legacy + result.ItemId = result.Id; + + if (item.IsFolder) + { + result.IsFolder = true; + } + + var primaryImageTag = _imageProcessor.GetImageCacheTag(item, ImageType.Primary); + + if (primaryImageTag != null) + { + result.PrimaryImageTag = primaryImageTag; + result.PrimaryImageAspectRatio = _dtoService.GetPrimaryImageAspectRatio(item); + } + + SetThumbImageInfo(result, item); + SetBackdropImageInfo(result, item); + + switch (item) + { + case IHasSeries hasSeries: + result.Series = hasSeries.SeriesName; + break; + case LiveTvProgram program: + result.StartDate = program.StartDate; + break; + case Series series: + if (series.Status.HasValue) + { + result.Status = series.Status.Value.ToString(); + } + + break; + case MusicAlbum album: + result.Artists = album.Artists; + result.AlbumArtist = album.AlbumArtist; + break; + case Audio song: + result.AlbumArtist = song.AlbumArtists?[0]; + result.Artists = song.Artists; + + MusicAlbum musicAlbum = song.AlbumEntity; + + if (musicAlbum != null) + { + result.Album = musicAlbum.Name; + result.AlbumId = musicAlbum.Id; + } + else + { + result.Album = song.Album; + } + + break; + } + + if (!item.ChannelId.Equals(Guid.Empty)) + { + var channel = _libraryManager.GetItemById(item.ChannelId); + result.ChannelName = channel?.Name; + } + + return result; + } + + private void SetThumbImageInfo(SearchHint hint, BaseItem item) + { + var itemWithImage = item.HasImage(ImageType.Thumb) ? item : null; + + if (itemWithImage == null && item is Episode) + { + itemWithImage = GetParentWithImage(item, ImageType.Thumb); + } + + if (itemWithImage == null) + { + itemWithImage = GetParentWithImage(item, ImageType.Thumb); + } + + if (itemWithImage != null) + { + var tag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Thumb); + + if (tag != null) + { + hint.ThumbImageTag = tag; + hint.ThumbImageItemId = itemWithImage.Id.ToString("N", CultureInfo.InvariantCulture); + } + } + } + + private void SetBackdropImageInfo(SearchHint hint, BaseItem item) + { + var itemWithImage = (item.HasImage(ImageType.Backdrop) ? item : null) + ?? GetParentWithImage(item, ImageType.Backdrop); + + if (itemWithImage != null) + { + var tag = _imageProcessor.GetImageCacheTag(itemWithImage, ImageType.Backdrop); + + if (tag != null) + { + hint.BackdropImageTag = tag; + hint.BackdropImageItemId = itemWithImage.Id.ToString("N", CultureInfo.InvariantCulture); + } + } + } + + private T GetParentWithImage(BaseItem item, ImageType type) + where T : BaseItem + { + return item.GetParents().OfType().FirstOrDefault(i => i.HasImage(type)); + } + } +} -- cgit v1.2.3 From f3029428cd118b34d73706fdd85cc3918b312a86 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 7 Jun 2020 15:33:54 +0200 Subject: Fix suggestions --- Jellyfin.Api/Controllers/SearchController.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 15a650bf9..2ee3ef25b 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -10,9 +10,9 @@ using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; -using MediaBrowser.Controller.Net; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Search; +using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; @@ -22,7 +22,7 @@ namespace Jellyfin.Api.Controllers /// Search controller. /// [Route("/Search/Hints")] - [Authenticated] + [Authorize] public class SearchController : BaseJellyfinApiController { private readonly ISearchEngine _searchEngine; @@ -52,9 +52,9 @@ namespace Jellyfin.Api.Controllers /// /// Gets the search hint result. /// - /// The record index to start at. All items with a lower index will be dropped from the results. - /// The maximum number of records to return. - /// Supply a user id to search within a user's library or omit to search all. + /// Optional. The record index to start at. All items with a lower index will be dropped from the results. + /// Optional. The maximum number of records to return. + /// Optional. Supply a user id to search within a user's library or omit to search all. /// The search term to filter on. /// Optional filter whether to include people. /// Optional filter whether to include media. @@ -117,11 +117,11 @@ namespace Jellyfin.Api.Controllers IsSports = isSports }); - return Ok(new SearchHintResult + return new SearchHintResult { TotalRecordCount = result.TotalRecordCount, SearchHints = result.Items.Select(GetSearchHintResult).ToArray() - }); + }; } /// -- cgit v1.2.3 From 7fa374f8a2560cd1c58584b3d5b0567c91ef4138 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 7 Jun 2020 15:41:49 +0200 Subject: Move Split method from BaseJellyfinApiController.cs to RequestHelpers.cs --- Jellyfin.Api/BaseJellyfinApiController.cs | 18 ----------------- Jellyfin.Api/Controllers/SearchController.cs | 7 ++++--- Jellyfin.Api/Helpers/RequestHelpers.cs | 29 ++++++++++++++++++++++++++++ 3 files changed, 33 insertions(+), 21 deletions(-) create mode 100644 Jellyfin.Api/Helpers/RequestHelpers.cs (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/BaseJellyfinApiController.cs b/Jellyfin.Api/BaseJellyfinApiController.cs index 6a9e48f8d..22b9c3fd6 100644 --- a/Jellyfin.Api/BaseJellyfinApiController.cs +++ b/Jellyfin.Api/BaseJellyfinApiController.cs @@ -10,23 +10,5 @@ namespace Jellyfin.Api [Route("[controller]")] public class BaseJellyfinApiController : ControllerBase { - /// - /// Splits a string at a seperating character into an array of substrings. - /// - /// The string to split. - /// The char that seperates the substrings. - /// Option to remove empty substrings from the array. - /// An array of the substrings. - internal static string[] Split(string value, char separator, bool removeEmpty) - { - if (string.IsNullOrWhiteSpace(value)) - { - return Array.Empty(); - } - - return removeEmpty - ? value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries) - : value.Split(separator); - } } } diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 2ee3ef25b..b6178e121 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Globalization; using System.Linq; +using Jellyfin.Api.Helpers; using MediaBrowser.Controller.Drawing; using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; @@ -105,9 +106,9 @@ namespace Jellyfin.Api.Controllers IncludeStudios = includeStudios, StartIndex = startIndex, UserId = userId, - IncludeItemTypes = Split(includeItemTypes, ',', true), - ExcludeItemTypes = Split(excludeItemTypes, ',', true), - MediaTypes = Split(mediaTypes, ',', true), + IncludeItemTypes = RequestHelpers.Split(includeItemTypes, ',', true), + ExcludeItemTypes = RequestHelpers.Split(excludeItemTypes, ',', true), + MediaTypes = RequestHelpers.Split(mediaTypes, ',', true), ParentId = parentId, IsKids = isKids, diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs new file mode 100644 index 000000000..6c661e2d3 --- /dev/null +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -0,0 +1,29 @@ +using System; + +namespace Jellyfin.Api.Helpers +{ + /// + /// Request Extensions. + /// + public static class RequestHelpers + { + /// + /// Splits a string at a seperating character into an array of substrings. + /// + /// The string to split. + /// The char that seperates the substrings. + /// Option to remove empty substrings from the array. + /// An array of the substrings. + internal static string[] Split(string value, char separator, bool removeEmpty) + { + if (string.IsNullOrWhiteSpace(value)) + { + return Array.Empty(); + } + + return removeEmpty + ? value.Split(new[] { separator }, StringSplitOptions.RemoveEmptyEntries) + : value.Split(separator); + } + } +} -- cgit v1.2.3 From cefa9d3c086fd01b6f05080fa272fcf1f76158f2 Mon Sep 17 00:00:00 2001 From: David Date: Sun, 7 Jun 2020 18:10:08 +0200 Subject: Add default values for parameters and fix spelling --- Jellyfin.Api/Controllers/SearchController.cs | 22 +++++++++++----------- Jellyfin.Api/Helpers/RequestHelpers.cs | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index b6178e121..411c19a59 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -57,11 +57,6 @@ namespace Jellyfin.Api.Controllers /// Optional. The maximum number of records to return. /// Optional. Supply a user id to search within a user's library or omit to search all. /// The search term to filter on. - /// Optional filter whether to include people. - /// Optional filter whether to include media. - /// Optional filter whether to include genres. - /// Optional filter whether to include studios. - /// Optional filter whether to include artists. /// If specified, only results with the specified item types are returned. This allows multiple, comma delimeted. /// If specified, results with these item types are filtered out. This allows multiple, comma delimeted. /// If specified, only results with the specified media types are returned. This allows multiple, comma delimeted. @@ -71,6 +66,11 @@ namespace Jellyfin.Api.Controllers /// Optional filter for news. /// Optional filter for kids. /// Optional filter for sports. + /// Optional filter whether to include people. + /// Optional filter whether to include media. + /// Optional filter whether to include genres. + /// Optional filter whether to include studios. + /// Optional filter whether to include artists. /// An with the results of the search. [HttpGet] [Description("Gets search hints based on a search term")] @@ -80,11 +80,6 @@ namespace Jellyfin.Api.Controllers [FromQuery] int? limit, [FromQuery] Guid userId, [FromQuery, Required] string searchTerm, - [FromQuery] bool includePeople, - [FromQuery] bool includeMedia, - [FromQuery] bool includeGenres, - [FromQuery] bool includeStudios, - [FromQuery] bool includeArtists, [FromQuery] string includeItemTypes, [FromQuery] string excludeItemTypes, [FromQuery] string mediaTypes, @@ -93,7 +88,12 @@ namespace Jellyfin.Api.Controllers [FromQuery] bool? isSeries, [FromQuery] bool? isNews, [FromQuery] bool? isKids, - [FromQuery] bool? isSports) + [FromQuery] bool? isSports, + [FromQuery] bool includePeople = true, + [FromQuery] bool includeMedia = true, + [FromQuery] bool includeGenres = true, + [FromQuery] bool includeStudios = true, + [FromQuery] bool includeArtists = true) { var result = _searchEngine.GetSearchHints(new SearchQuery { diff --git a/Jellyfin.Api/Helpers/RequestHelpers.cs b/Jellyfin.Api/Helpers/RequestHelpers.cs index 6c661e2d3..9f4d34f9c 100644 --- a/Jellyfin.Api/Helpers/RequestHelpers.cs +++ b/Jellyfin.Api/Helpers/RequestHelpers.cs @@ -8,10 +8,10 @@ namespace Jellyfin.Api.Helpers public static class RequestHelpers { /// - /// Splits a string at a seperating character into an array of substrings. + /// Splits a string at a separating character into an array of substrings. /// /// The string to split. - /// The char that seperates the substrings. + /// The char that separates the substrings. /// Option to remove empty substrings from the array. /// An array of the substrings. internal static string[] Split(string value, char separator, bool removeEmpty) -- cgit v1.2.3 From 1491e93d841a8c40ea1a9fed9d99427a64ccd66c Mon Sep 17 00:00:00 2001 From: David Ullmer Date: Tue, 9 Jun 2020 11:00:37 +0200 Subject: Add response code documentation --- Jellyfin.Api/Controllers/SearchController.cs | 1 + 1 file changed, 1 insertion(+) (limited to 'Jellyfin.Api/Controllers/SearchController.cs') diff --git a/Jellyfin.Api/Controllers/SearchController.cs b/Jellyfin.Api/Controllers/SearchController.cs index 411c19a59..ec05e4fb4 100644 --- a/Jellyfin.Api/Controllers/SearchController.cs +++ b/Jellyfin.Api/Controllers/SearchController.cs @@ -71,6 +71,7 @@ namespace Jellyfin.Api.Controllers /// Optional filter whether to include genres. /// Optional filter whether to include studios. /// Optional filter whether to include artists. + /// Search hint returned. /// An with the results of the search. [HttpGet] [Description("Gets search hints based on a search term")] -- cgit v1.2.3