2019-01-13 20:01:16 +00:00
using System ;
2019-02-28 22:22:57 +00:00
using System.Globalization ;
2019-01-13 19:24:58 +00:00
using System.Linq ;
2019-11-17 22:05:39 +00:00
using MediaBrowser.Controller.Configuration ;
2017-08-24 19:52:19 +00:00
using MediaBrowser.Controller.Drawing ;
2013-04-26 19:20:53 +00:00
using MediaBrowser.Controller.Dto ;
using MediaBrowser.Controller.Entities ;
using MediaBrowser.Controller.Entities.Audio ;
using MediaBrowser.Controller.Entities.TV ;
using MediaBrowser.Controller.Library ;
2019-01-13 19:24:58 +00:00
using MediaBrowser.Controller.LiveTv ;
2014-07-02 18:34:08 +00:00
using MediaBrowser.Controller.Net ;
2013-04-26 19:20:53 +00:00
using MediaBrowser.Model.Entities ;
using MediaBrowser.Model.Search ;
2016-10-25 19:02:04 +00:00
using MediaBrowser.Model.Services ;
2019-11-17 22:05:39 +00:00
using Microsoft.Extensions.Logging ;
2013-04-26 19:20:53 +00:00
namespace MediaBrowser.Api
{
/// <summary>
/// Class GetSearchHints
/// </summary>
2014-03-23 19:36:25 +00:00
[Route("/Search/Hints", "GET", Summary = "Gets search hints based on a search term")]
2013-04-27 13:05:33 +00:00
public class GetSearchHints : IReturn < SearchHintResult >
2013-04-26 19:20:53 +00:00
{
/// <summary>
/// Skips over a given number of items within the results. Use for paging.
/// </summary>
/// <value>The start index.</value>
[ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? StartIndex { get ; set ; }
/// <summary>
/// The maximum number of items to return
/// </summary>
/// <value>The limit.</value>
[ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
public int? Limit { get ; set ; }
/// <summary>
/// Gets or sets the user id.
/// </summary>
/// <value>The user id.</value>
[ApiMember(Name = "UserId", Description = "Optional. Supply a user id to search within a user's library or omit to search all.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
2018-09-12 17:26:21 +00:00
public Guid UserId { get ; set ; }
2013-04-26 19:20:53 +00:00
/// <summary>
/// Search characters used to find items
/// </summary>
/// <value>The index by.</value>
[ApiMember(Name = "SearchTerm", Description = "The search term to filter on", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "GET")]
public string SearchTerm { get ; set ; }
2014-01-07 20:12:39 +00:00
[ApiMember(Name = "IncludePeople", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool IncludePeople { get ; set ; }
[ApiMember(Name = "IncludeMedia", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool IncludeMedia { get ; set ; }
[ApiMember(Name = "IncludeGenres", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool IncludeGenres { get ; set ; }
[ApiMember(Name = "IncludeStudios", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool IncludeStudios { get ; set ; }
[ApiMember(Name = "IncludeArtists", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
public bool IncludeArtists { get ; set ; }
2014-03-07 15:53:23 +00:00
[ApiMember(Name = "IncludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string IncludeItemTypes { get ; set ; }
2014-03-23 19:36:25 +00:00
2017-05-06 20:21:08 +00:00
[ApiMember(Name = "ExcludeItemTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string ExcludeItemTypes { get ; set ; }
[ApiMember(Name = "MediaTypes", Description = "Optional. If specified, results will be filtered based on item type. This allows multiple, comma delimeted.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET", AllowMultiple = true)]
public string MediaTypes { get ; set ; }
2017-05-01 20:03:27 +00:00
public string ParentId { get ; set ; }
2017-05-06 19:45:23 +00:00
[ApiMember(Name = "IsMovie", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsMovie { get ; set ; }
[ApiMember(Name = "IsSeries", Description = "Optional filter for movies.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsSeries { get ; set ; }
[ApiMember(Name = "IsNews", Description = "Optional filter for news.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsNews { get ; set ; }
[ApiMember(Name = "IsKids", Description = "Optional filter for kids.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsKids { get ; set ; }
[ApiMember(Name = "IsSports", Description = "Optional filter for sports.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET,POST")]
public bool? IsSports { get ; set ; }
2014-01-07 20:12:39 +00:00
public GetSearchHints ( )
{
IncludeArtists = true ;
IncludeGenres = true ;
IncludeMedia = true ;
IncludePeople = true ;
IncludeStudios = true ;
}
2013-04-26 19:20:53 +00:00
}
/// <summary>
/// Class SearchService
/// </summary>
2014-07-02 18:34:08 +00:00
[Authenticated]
2013-04-26 19:20:53 +00:00
public class SearchService : BaseApiService
{
/// <summary>
/// The _search engine
/// </summary>
2014-01-04 04:53:49 +00:00
private readonly ISearchEngine _searchEngine ;
2013-04-26 19:20:53 +00:00
private readonly ILibraryManager _libraryManager ;
2013-09-04 17:02:19 +00:00
private readonly IDtoService _dtoService ;
2013-09-18 18:49:06 +00:00
private readonly IImageProcessor _imageProcessor ;
2013-04-26 19:20:53 +00:00
/// <summary>
/// Initializes a new instance of the <see cref="SearchService" /> class.
/// </summary>
/// <param name="searchEngine">The search engine.</param>
/// <param name="libraryManager">The library manager.</param>
2014-01-07 20:12:39 +00:00
/// <param name="dtoService">The dto service.</param>
/// <param name="imageProcessor">The image processor.</param>
2019-11-17 22:05:39 +00:00
public SearchService (
ILogger < SearchService > logger ,
IServerConfigurationManager serverConfigurationManager ,
IHttpResultFactory httpResultFactory ,
ISearchEngine searchEngine ,
ILibraryManager libraryManager ,
IDtoService dtoService ,
IImageProcessor imageProcessor )
: base ( logger , serverConfigurationManager , httpResultFactory )
2013-04-26 19:20:53 +00:00
{
_searchEngine = searchEngine ;
_libraryManager = libraryManager ;
2013-09-04 17:02:19 +00:00
_dtoService = dtoService ;
2013-09-18 18:49:06 +00:00
_imageProcessor = imageProcessor ;
2013-04-26 19:20:53 +00:00
}
/// <summary>
/// Gets the specified request.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>System.Object.</returns>
2018-09-12 17:26:21 +00:00
public object Get ( GetSearchHints request )
2013-04-26 19:20:53 +00:00
{
2018-09-12 17:26:21 +00:00
var result = GetSearchHintsAsync ( request ) ;
2013-04-26 19:20:53 +00:00
2018-09-12 17:26:21 +00:00
return ToOptimizedResult ( result ) ;
2013-04-26 19:20:53 +00:00
}
/// <summary>
/// Gets the search hints async.
/// </summary>
/// <param name="request">The request.</param>
/// <returns>Task{IEnumerable{SearchHintResult}}.</returns>
2018-09-12 17:26:21 +00:00
private SearchHintResult GetSearchHintsAsync ( GetSearchHints request )
2013-04-26 19:20:53 +00:00
{
2018-09-12 17:26:21 +00:00
var result = _searchEngine . GetSearchHints ( new SearchQuery
2013-04-26 19:20:53 +00:00
{
2014-01-07 20:12:39 +00:00
Limit = request . Limit ,
SearchTerm = request . SearchTerm ,
IncludeArtists = request . IncludeArtists ,
IncludeGenres = request . IncludeGenres ,
IncludeMedia = request . IncludeMedia ,
IncludePeople = request . IncludePeople ,
IncludeStudios = request . IncludeStudios ,
StartIndex = request . StartIndex ,
2014-03-07 15:53:23 +00:00
UserId = request . UserId ,
2017-08-09 19:56:38 +00:00
IncludeItemTypes = ApiEntryPoint . Split ( request . IncludeItemTypes , ',' , true ) ,
ExcludeItemTypes = ApiEntryPoint . Split ( request . ExcludeItemTypes , ',' , true ) ,
MediaTypes = ApiEntryPoint . Split ( request . MediaTypes , ',' , true ) ,
2017-05-06 19:45:23 +00:00
ParentId = request . ParentId ,
IsKids = request . IsKids ,
IsMovie = request . IsMovie ,
IsNews = request . IsNews ,
IsSeries = request . IsSeries ,
IsSports = request . IsSports
2014-01-07 20:12:39 +00:00
2018-09-12 17:26:21 +00:00
} ) ;
2013-04-26 19:20:53 +00:00
2013-04-27 13:05:33 +00:00
return new SearchHintResult
{
2014-01-07 20:12:39 +00:00
TotalRecordCount = result . TotalRecordCount ,
2013-04-27 13:05:33 +00:00
2014-01-07 20:12:39 +00:00
SearchHints = result . Items . Select ( GetSearchHintResult ) . ToArray ( )
2013-04-27 13:05:33 +00:00
} ;
2013-04-26 19:20:53 +00:00
}
/// <summary>
/// Gets the search hint result.
/// </summary>
2013-04-27 13:05:33 +00:00
/// <param name="hintInfo">The hint info.</param>
2013-04-26 19:20:53 +00:00
/// <returns>SearchHintResult.</returns>
2013-04-27 13:05:33 +00:00
private SearchHint GetSearchHintResult ( SearchHintInfo hintInfo )
2013-04-26 19:20:53 +00:00
{
2013-04-27 13:05:33 +00:00
var item = hintInfo . Item ;
var result = new SearchHint
2013-04-26 19:20:53 +00:00
{
Name = item . Name ,
IndexNumber = item . IndexNumber ,
ParentIndexNumber = item . ParentIndexNumber ,
2018-09-12 17:26:21 +00:00
Id = item . Id ,
2013-11-21 20:48:26 +00:00
Type = item . GetClientTypeName ( ) ,
2013-04-27 13:05:33 +00:00
MediaType = item . MediaType ,
MatchedTerm = hintInfo . MatchedTerm ,
2013-12-27 17:12:23 +00:00
RunTimeTicks = item . RunTimeTicks ,
2017-05-03 21:53:33 +00:00
ProductionYear = item . ProductionYear ,
ChannelId = item . ChannelId ,
EndDate = item . EndDate
2013-04-26 19:20:53 +00:00
} ;
2018-09-12 17:26:21 +00:00
// legacy
result . ItemId = result . Id ;
if ( item . IsFolder )
{
result . IsFolder = true ;
}
2014-02-07 20:30:41 +00:00
var primaryImageTag = _imageProcessor . GetImageCacheTag ( item , ImageType . Primary ) ;
2014-05-08 20:09:53 +00:00
if ( primaryImageTag ! = null )
2013-04-26 19:20:53 +00:00
{
2014-05-08 20:09:53 +00:00
result . PrimaryImageTag = primaryImageTag ;
2016-01-16 05:01:57 +00:00
result . PrimaryImageAspectRatio = _dtoService . GetPrimaryImageAspectRatio ( item ) ;
2013-04-26 19:20:53 +00:00
}
2014-01-05 06:08:22 +00:00
SetThumbImageInfo ( result , item ) ;
SetBackdropImageInfo ( result , item ) ;
2020-04-05 18:44:14 +00:00
switch ( item )
2017-05-03 21:53:33 +00:00
{
2020-04-05 18:44:14 +00:00
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 ( ) ;
}
2017-11-23 15:46:16 +00:00
2020-04-05 18:44:14 +00:00
break ;
case MusicAlbum album :
result . Artists = album . Artists ;
result . AlbumArtist = album . AlbumArtist ;
break ;
case Audio song :
result . AlbumArtist = song . AlbumArtists . FirstOrDefault ( ) ;
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 ;
2013-04-26 19:20:53 +00:00
}
2018-09-12 17:26:21 +00:00
if ( ! item . ChannelId . Equals ( Guid . Empty ) )
2015-08-10 17:37:50 +00:00
{
var channel = _libraryManager . GetItemById ( item . ChannelId ) ;
2020-04-05 16:45:01 +00:00
result . ChannelName = channel ? . Name ;
2015-08-10 17:37:50 +00:00
}
2013-04-26 19:20:53 +00:00
return result ;
}
2014-01-05 06:08:22 +00:00
private void SetThumbImageInfo ( SearchHint hint , BaseItem item )
{
var itemWithImage = item . HasImage ( ImageType . Thumb ) ? item : null ;
2020-04-05 18:44:14 +00:00
if ( itemWithImage = = null & & item is Episode )
2014-01-05 06:08:22 +00:00
{
2020-04-05 18:44:14 +00:00
itemWithImage = GetParentWithImage < Series > ( item , ImageType . Thumb ) ;
2014-01-05 06:08:22 +00:00
}
if ( itemWithImage = = null )
{
itemWithImage = GetParentWithImage < BaseItem > ( item , ImageType . Thumb ) ;
}
if ( itemWithImage ! = null )
{
2014-02-07 20:30:41 +00:00
var tag = _imageProcessor . GetImageCacheTag ( itemWithImage , ImageType . Thumb ) ;
2014-05-08 20:09:53 +00:00
if ( tag ! = null )
2014-02-07 20:30:41 +00:00
{
2014-05-08 20:09:53 +00:00
hint . ThumbImageTag = tag ;
2019-02-28 22:22:57 +00:00
hint . ThumbImageItemId = itemWithImage . Id . ToString ( "N" , CultureInfo . InvariantCulture ) ;
2014-02-07 20:30:41 +00:00
}
2014-01-05 06:08:22 +00:00
}
}
private void SetBackdropImageInfo ( SearchHint hint , BaseItem item )
{
2020-04-05 16:45:01 +00:00
var itemWithImage = ( item . HasImage ( ImageType . Backdrop ) ? item : null )
? ? GetParentWithImage < BaseItem > ( item , ImageType . Backdrop ) ;
2014-01-05 06:08:22 +00:00
if ( itemWithImage ! = null )
{
2014-02-07 20:30:41 +00:00
var tag = _imageProcessor . GetImageCacheTag ( itemWithImage , ImageType . Backdrop ) ;
2014-05-08 20:09:53 +00:00
if ( tag ! = null )
2014-02-07 20:30:41 +00:00
{
2014-05-08 20:09:53 +00:00
hint . BackdropImageTag = tag ;
2019-02-28 22:22:57 +00:00
hint . BackdropImageItemId = itemWithImage . Id . ToString ( "N" , CultureInfo . InvariantCulture ) ;
2014-02-07 20:30:41 +00:00
}
2014-01-05 06:08:22 +00:00
}
}
private T GetParentWithImage < T > ( BaseItem item , ImageType type )
where T : BaseItem
{
2015-11-11 14:56:31 +00:00
return item . GetParents ( ) . OfType < T > ( ) . FirstOrDefault ( i = > i . HasImage ( type ) ) ;
2014-01-05 06:08:22 +00:00
}
2013-04-26 19:20:53 +00:00
}
}