diff options
| author | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-01-07 15:12:39 -0500 |
|---|---|---|
| committer | Luke Pulverenti <luke.pulverenti@gmail.com> | 2014-01-07 15:12:39 -0500 |
| commit | 650dc0ccac5bbb372f644d6c383fbc88af4f4e7b (patch) | |
| tree | 58e8393f10ca4071fe7f5b61fd8ed7dd7aee3b7e | |
| parent | 5392ff4da4794a0c4268baa61572a8cd881db379 (diff) | |
added new search params
| -rw-r--r-- | MediaBrowser.Api/SearchService.cs | 74 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Library/ISearchEngine.cs | 9 | ||||
| -rw-r--r-- | MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj | 3 | ||||
| -rw-r--r-- | MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj | 3 | ||||
| -rw-r--r-- | MediaBrowser.Model/ApiClient/IApiClient.cs | 11 | ||||
| -rw-r--r-- | MediaBrowser.Model/MediaBrowser.Model.csproj | 1 | ||||
| -rw-r--r-- | MediaBrowser.Model/Search/SearchQuery.cs | 45 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/Library/LuceneSearchEngine.cs | 292 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/Library/SearchEngine.cs | 339 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj | 2 | ||||
| -rw-r--r-- | MediaBrowser.ServerApplication/ApplicationHost.cs | 2 | ||||
| -rw-r--r-- | Nuget/MediaBrowser.Common.Internal.nuspec | 4 | ||||
| -rw-r--r-- | Nuget/MediaBrowser.Common.nuspec | 2 | ||||
| -rw-r--r-- | Nuget/MediaBrowser.Server.Core.nuspec | 4 |
14 files changed, 450 insertions, 341 deletions
diff --git a/MediaBrowser.Api/SearchService.cs b/MediaBrowser.Api/SearchService.cs index f83c0a771..8626709a3 100644 --- a/MediaBrowser.Api/SearchService.cs +++ b/MediaBrowser.Api/SearchService.cs @@ -7,9 +7,6 @@ using MediaBrowser.Controller.Library; using MediaBrowser.Model.Entities; using MediaBrowser.Model.Search; using ServiceStack; -using System; -using System.Collections; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; @@ -41,7 +38,7 @@ namespace MediaBrowser.Api /// </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")] - public Guid? UserId { get; set; } + public string UserId { get; set; } /// <summary> /// Search characters used to find items @@ -49,6 +46,31 @@ namespace MediaBrowser.Api /// <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; } + + + [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; } + + public GetSearchHints() + { + IncludeArtists = true; + IncludeGenres = true; + IncludeMedia = true; + IncludePeople = true; + IncludeStudios = true; + } } /// <summary> @@ -57,10 +79,6 @@ namespace MediaBrowser.Api public class SearchService : BaseApiService { /// <summary> - /// The _user manager - /// </summary> - private readonly IUserManager _userManager; - /// <summary> /// The _search engine /// </summary> private readonly ISearchEngine _searchEngine; @@ -71,12 +89,12 @@ namespace MediaBrowser.Api /// <summary> /// Initializes a new instance of the <see cref="SearchService" /> class. /// </summary> - /// <param name="userManager">The user manager.</param> /// <param name="searchEngine">The search engine.</param> /// <param name="libraryManager">The library manager.</param> - public SearchService(IUserManager userManager, ISearchEngine searchEngine, ILibraryManager libraryManager, IDtoService dtoService, IImageProcessor imageProcessor) + /// <param name="dtoService">The dto service.</param> + /// <param name="imageProcessor">The image processor.</param> + public SearchService(ISearchEngine searchEngine, ILibraryManager libraryManager, IDtoService dtoService, IImageProcessor imageProcessor) { - _userManager = userManager; _searchEngine = searchEngine; _libraryManager = libraryManager; _dtoService = dtoService; @@ -102,29 +120,25 @@ namespace MediaBrowser.Api /// <returns>Task{IEnumerable{SearchHintResult}}.</returns> private async Task<SearchHintResult> GetSearchHintsAsync(GetSearchHints request) { - var inputItems = GetAllLibraryItems(request.UserId, _userManager, _libraryManager); - - var results = await _searchEngine.GetSearchHints(inputItems, request.SearchTerm).ConfigureAwait(false); - - var searchResultArray = results.ToList(); - - IEnumerable<SearchHintInfo> returnResults = searchResultArray; - - if (request.StartIndex.HasValue) + var result = await _searchEngine.GetSearchHints(new SearchQuery { - returnResults = returnResults.Skip(request.StartIndex.Value); - } - - if (request.Limit.HasValue) - { - returnResults = returnResults.Take(request.Limit.Value); - } + Limit = request.Limit, + SearchTerm = request.SearchTerm, + IncludeArtists = request.IncludeArtists, + IncludeGenres = request.IncludeGenres, + IncludeMedia = request.IncludeMedia, + IncludePeople = request.IncludePeople, + IncludeStudios = request.IncludeStudios, + StartIndex = request.StartIndex, + UserId = request.UserId + + }).ConfigureAwait(false); return new SearchHintResult { - TotalRecordCount = searchResultArray.Count, + TotalRecordCount = result.TotalRecordCount, - SearchHints = returnResults.Select(GetSearchHintResult).ToArray() + SearchHints = result.Items.Select(GetSearchHintResult).ToArray() }; } @@ -189,7 +203,7 @@ namespace MediaBrowser.Api var songs = album.GetRecursiveChildren().OfType<Audio>().ToList(); result.SongCount = songs.Count; - + result.Artists = _libraryManager.GetAllArtists(songs) .ToArray(); diff --git a/MediaBrowser.Controller/Library/ISearchEngine.cs b/MediaBrowser.Controller/Library/ISearchEngine.cs index 807d21302..dcf3be9ef 100644 --- a/MediaBrowser.Controller/Library/ISearchEngine.cs +++ b/MediaBrowser.Controller/Library/ISearchEngine.cs @@ -1,5 +1,5 @@ -using MediaBrowser.Controller.Entities; -using System.Collections.Generic; +using MediaBrowser.Model.Querying; +using MediaBrowser.Model.Search; using System.Threading.Tasks; namespace MediaBrowser.Controller.Library @@ -12,9 +12,8 @@ namespace MediaBrowser.Controller.Library /// <summary> /// Gets the search hints. /// </summary> - /// <param name="inputItems">The input items.</param> - /// <param name="searchTerm">The search term.</param> + /// <param name="query">The query.</param> /// <returns>Task{IEnumerable{SearchHintInfo}}.</returns> - Task<IEnumerable<SearchHintInfo>> GetSearchHints(IEnumerable<BaseItem> inputItems, string searchTerm); + Task<QueryResult<SearchHintInfo>> GetSearchHints(SearchQuery query); } } diff --git a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj index f8b12da9e..40c71ec3c 100644 --- a/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj +++ b/MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj @@ -374,6 +374,9 @@ <Compile Include="..\MediaBrowser.Model\Search\SearchHintResult.cs"> <Link>Search\SearchHintResult.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Search\SearchQuery.cs"> + <Link>Search\SearchQuery.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Serialization\IJsonSerializer.cs"> <Link>Serialization\IJsonSerializer.cs</Link> </Compile> diff --git a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj index d69cf56c6..c03b87243 100644 --- a/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj +++ b/MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj @@ -361,6 +361,9 @@ <Compile Include="..\MediaBrowser.Model\Search\SearchHintResult.cs"> <Link>Search\SearchHintResult.cs</Link> </Compile> + <Compile Include="..\MediaBrowser.Model\Search\SearchQuery.cs"> + <Link>Search\SearchQuery.cs</Link> + </Compile> <Compile Include="..\MediaBrowser.Model\Serialization\IJsonSerializer.cs"> <Link>Serialization\IJsonSerializer.cs</Link> </Compile> diff --git a/MediaBrowser.Model/ApiClient/IApiClient.cs b/MediaBrowser.Model/ApiClient/IApiClient.cs index 9fdcf9150..c5b5311b2 100644 --- a/MediaBrowser.Model/ApiClient/IApiClient.cs +++ b/MediaBrowser.Model/ApiClient/IApiClient.cs @@ -107,13 +107,9 @@ namespace MediaBrowser.Model.ApiClient /// <summary> /// Gets the search hints async. /// </summary> - /// <param name="userId">The user id.</param> - /// <param name="searchTerm">The search term.</param> - /// <param name="startIndex">The start index.</param> - /// <param name="limit">The limit.</param> + /// <param name="query">The query.</param> /// <returns>Task{SearchHintResult}.</returns> - Task<SearchHintResult> GetSearchHintsAsync(string userId, string searchTerm, int? startIndex = null, - int? limit = null); + Task<SearchHintResult> GetSearchHintsAsync(SearchQuery query); /// <summary> /// Gets the theme videos async. @@ -682,8 +678,9 @@ namespace MediaBrowser.Model.ApiClient /// <typeparam name="T"></typeparam> /// <param name="url">The URL.</param> /// <param name="args">The args.</param> + /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task{``0}.</returns> - Task<T> PostAsync<T>(string url, Dictionary<string, string> args) + Task<T> PostAsync<T>(string url, Dictionary<string, string> args, CancellationToken cancellationToken) where T : class; /// <summary> diff --git a/MediaBrowser.Model/MediaBrowser.Model.csproj b/MediaBrowser.Model/MediaBrowser.Model.csproj index ab91416b7..fff999172 100644 --- a/MediaBrowser.Model/MediaBrowser.Model.csproj +++ b/MediaBrowser.Model/MediaBrowser.Model.csproj @@ -115,6 +115,7 @@ <Compile Include="Querying\SessionQuery.cs" /> <Compile Include="Querying\SimilarItemsQuery.cs" /> <Compile Include="Querying\UserQuery.cs" /> + <Compile Include="Search\SearchQuery.cs" /> <Compile Include="Session\BrowseRequest.cs" /> <Compile Include="Session\MessageCommand.cs" /> <Compile Include="Session\PlayRequest.cs" /> diff --git a/MediaBrowser.Model/Search/SearchQuery.cs b/MediaBrowser.Model/Search/SearchQuery.cs new file mode 100644 index 000000000..87ff7af66 --- /dev/null +++ b/MediaBrowser.Model/Search/SearchQuery.cs @@ -0,0 +1,45 @@ + +namespace MediaBrowser.Model.Search +{ + public class SearchQuery + { + /// <summary> + /// The user to localize search results for + /// </summary> + /// <value>The user id.</value> + public string UserId { get; set; } + + /// <summary> + /// Gets or sets the search term. + /// </summary> + /// <value>The search term.</value> + public string SearchTerm { get; set; } + + /// <summary> + /// Skips over a given number of items within the results. Use for paging. + /// </summary> + /// <value>The start index.</value> + public int? StartIndex { get; set; } + + /// <summary> + /// The maximum number of items to return + /// </summary> + /// <value>The limit.</value> + public int? Limit { get; set; } + + public bool IncludePeople { get; set; } + public bool IncludeMedia { get; set; } + public bool IncludeGenres { get; set; } + public bool IncludeStudios { get; set; } + public bool IncludeArtists { get; set; } + + public SearchQuery() + { + IncludeArtists = true; + IncludeGenres = true; + IncludeMedia = true; + IncludePeople = true; + IncludeStudios = true; + } + } +} diff --git a/MediaBrowser.Server.Implementations/Library/LuceneSearchEngine.cs b/MediaBrowser.Server.Implementations/Library/LuceneSearchEngine.cs deleted file mode 100644 index 2a3a4cdfd..000000000 --- a/MediaBrowser.Server.Implementations/Library/LuceneSearchEngine.cs +++ /dev/null @@ -1,292 +0,0 @@ -using MediaBrowser.Controller; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Library; -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace MediaBrowser.Server.Implementations.Library -{ - /// <summary> - /// Class LuceneSearchEngine - /// http://www.codeproject.com/Articles/320219/Lucene-Net-ultra-fast-search-for-MVC-or-WebForms - /// </summary> - public class LuceneSearchEngine : ISearchEngine, IDisposable - { - private readonly ILibraryManager _libraryManager; - private readonly ILogger _logger; - - public LuceneSearchEngine(IServerApplicationPaths serverPaths, ILogManager logManager, ILibraryManager libraryManager) - { - _libraryManager = libraryManager; - - _logger = logManager.GetLogger("Lucene"); - } - - public void Dispose() - { - } - - /// <summary> - /// Gets the search hints. - /// </summary> - /// <param name="inputItems">The input items.</param> - /// <param name="searchTerm">The search term.</param> - /// <returns>IEnumerable{SearchHintResult}.</returns> - /// <exception cref="System.ArgumentNullException">searchTerm</exception> - public Task<IEnumerable<SearchHintInfo>> GetSearchHints(IEnumerable<BaseItem> inputItems, string searchTerm) - { - if (string.IsNullOrEmpty(searchTerm)) - { - throw new ArgumentNullException("searchTerm"); - } - - var terms = GetWords(searchTerm); - - var hints = new List<Tuple<BaseItem, string, int>>(); - - var items = inputItems.Where(i => !(i is MusicArtist)).ToList(); - - // Add search hints based on item name - hints.AddRange(items.Where(i => !string.IsNullOrEmpty(i.Name)).Select(item => - { - var index = GetIndex(item.Name, searchTerm, terms); - - return new Tuple<BaseItem, string, int>(item, index.Item1, index.Item2); - })); - - // Find artists - var artists = _libraryManager.GetAllArtists(items) - .ToList(); - - foreach (var item in artists) - { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var artist = _libraryManager.GetArtist(item); - - hints.Add(new Tuple<BaseItem, string, int>(artist, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } - } - - // Find genres, from non-audio items - var genres = items.Where(i => !(i is IHasMusicGenres) && !(i is Game)) - .SelectMany(i => i.Genres) - .Where(i => !string.IsNullOrEmpty(i)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - foreach (var item in genres) - { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var genre = _libraryManager.GetGenre(item); - - hints.Add(new Tuple<BaseItem, string, int>(genre, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } - } - - // Find music genres - var musicGenres = items.Where(i => i is IHasMusicGenres) - .SelectMany(i => i.Genres) - .Where(i => !string.IsNullOrEmpty(i)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - foreach (var item in musicGenres) - { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var genre = _libraryManager.GetMusicGenre(item); - - hints.Add(new Tuple<BaseItem, string, int>(genre, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } - } - - // Find music genres - var gameGenres = items.OfType<Game>() - .SelectMany(i => i.Genres) - .Where(i => !string.IsNullOrEmpty(i)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - foreach (var item in gameGenres) - { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var genre = _libraryManager.GetGameGenre(item); - - hints.Add(new Tuple<BaseItem, string, int>(genre, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } - } - - // Find studios - var studios = items.SelectMany(i => i.Studios) - .Where(i => !string.IsNullOrEmpty(i)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - foreach (var item in studios) - { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var studio = _libraryManager.GetStudio(item); - - hints.Add(new Tuple<BaseItem, string, int>(studio, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } - } - - // Find persons - var persons = items.SelectMany(i => i.People) - .Select(i => i.Name) - .Where(i => !string.IsNullOrEmpty(i)) - .Distinct(StringComparer.OrdinalIgnoreCase) - .ToList(); - - foreach (var item in persons) - { - var index = GetIndex(item, searchTerm, terms); - - if (index.Item2 != -1) - { - try - { - var person = _libraryManager.GetPerson(item); - - hints.Add(new Tuple<BaseItem, string, int>(person, index.Item1, index.Item2)); - } - catch (Exception ex) - { - _logger.ErrorException("Error getting {0}", ex, item); - } - } - } - - var returnValue = hints.Where(i => i.Item3 >= 0).OrderBy(i => i.Item3).Select(i => new SearchHintInfo - { - Item = i.Item1, - MatchedTerm = i.Item2 - }); - - return Task.FromResult(returnValue); - } - - /// <summary> - /// Gets the index. - /// </summary> - /// <param name="input">The input.</param> - /// <param name="searchInput">The search input.</param> - /// <param name="searchWords">The search input.</param> - /// <returns>System.Int32.</returns> - private Tuple<string, int> GetIndex(string input, string searchInput, List<string> searchWords) - { - if (string.IsNullOrEmpty(input)) - { - throw new ArgumentNullException("input"); - } - - if (string.Equals(input, searchInput, StringComparison.OrdinalIgnoreCase)) - { - return new Tuple<string, int>(searchInput, 0); - } - - var index = input.IndexOf(searchInput, StringComparison.OrdinalIgnoreCase); - - if (index == 0) - { - return new Tuple<string, int>(searchInput, 1); - } - if (index > 0) - { - return new Tuple<string, int>(searchInput, 2); - } - - var items = GetWords(input); - - for (var i = 0; i < searchWords.Count; i++) - { - var searchTerm = searchWords[i]; - - for (var j = 0; j < items.Count; j++) - { - var item = items[j]; - - if (string.Equals(item, searchTerm, StringComparison.OrdinalIgnoreCase)) - { - return new Tuple<string, int>(searchTerm, 3 + (i + 1) * (j + 1)); - } - - index = item.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase); - - if (index == 0) - { - return new Tuple<string, int>(searchTerm, 4 + (i + 1) * (j + 1)); - } - if (index > 0) - { - return new Tuple<string, int>(searchTerm, 5 + (i + 1) * (j + 1)); - } - } - } - return new Tuple<string, int>(null, -1); - } - - /// <summary> - /// Gets the words. - /// </summary> - /// <param name="term">The term.</param> - /// <returns>System.String[][].</returns> - private List<string> GetWords(string term) - { - return term.Split().Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); - } - } -} diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs new file mode 100644 index 000000000..91112b409 --- /dev/null +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -0,0 +1,339 @@ +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Library; +using MediaBrowser.Model.Logging; +using MediaBrowser.Model.Querying; +using MediaBrowser.Model.Search; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace MediaBrowser.Server.Implementations.Library +{ + /// <summary> + /// Class LuceneSearchEngine + /// http://www.codeproject.com/Articles/320219/Lucene-Net-ultra-fast-search-for-MVC-or-WebForms + /// </summary> + public class SearchEngine : ISearchEngine + { + private readonly ILibraryManager _libraryManager; + private readonly IUserManager _userManager; + private readonly ILogger _logger; + + public SearchEngine(ILogManager logManager, ILibraryManager libraryManager, IUserManager userManager) + { + _libraryManager = libraryManager; + _userManager = userManager; + + _logger = logManager.GetLogger("Lucene"); + } + + public async Task<QueryResult<SearchHintInfo>> GetSearchHints(SearchQuery query) + { + var user = _userManager.GetUserById(new Guid(query.UserId)); + + var inputItems = user.RootFolder.GetRecursiveChildren(user, null); + + var results = await GetSearchHints(inputItems, query).ConfigureAwait(false); + + var searchResultArray = results.ToArray(); + results = searchResultArray; + + var count = searchResultArray.Length; + + if (query.StartIndex.HasValue) + { + results = results.Skip(query.StartIndex.Value); + } + + if (query.Limit.HasValue) + { + results = results.Take(query.Limit.Value); + } + + return new QueryResult<SearchHintInfo> + { + TotalRecordCount = count, + + Items = results.ToArray() + }; + } + + /// <summary> + /// Gets the search hints. + /// </summary> + /// <param name="inputItems">The input items.</param> + /// <param name="query">The query.</param> + /// <returns>IEnumerable{SearchHintResult}.</returns> + /// <exception cref="System.ArgumentNullException">searchTerm</exception> + private Task<IEnumerable<SearchHintInfo>> GetSearchHints(IEnumerable<BaseItem> inputItems, SearchQuery query) + { + var searchTerm = query.SearchTerm; + + if (string.IsNullOrEmpty(searchTerm)) + { + throw new ArgumentNullException("searchTerm"); + } + + var terms = GetWords(searchTerm); + + var hints = new List<Tuple<BaseItem, string, int>>(); + + var items = inputItems.Where(i => !(i is MusicArtist)).ToList(); + + if (query.IncludeMedia) + { + // Add search hints based on item name + hints.AddRange(items.Where(i => !string.IsNullOrEmpty(i.Name)).Select(item => + { + var index = GetIndex(item.Name, searchTerm, terms); + + return new Tuple<BaseItem, string, int>(item, index.Item1, index.Item2); + })); + } + + if (query.IncludeArtists) + { + // Find artists + var artists = _libraryManager.GetAllArtists(items) + .ToList(); + + foreach (var item in artists) + { + var index = GetIndex(item, searchTerm, terms); + + if (index.Item2 != -1) + { + try + { + var artist = _libraryManager.GetArtist(item); + + hints.Add(new Tuple<BaseItem, string, int>(artist, index.Item1, index.Item2)); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting {0}", ex, item); + } + } + } + } + + if (query.IncludeGenres) + { + // Find genres, from non-audio items + var genres = items.Where(i => !(i is IHasMusicGenres) && !(i is Game)) + .SelectMany(i => i.Genres) + .Where(i => !string.IsNullOrEmpty(i)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + foreach (var item in genres) + { + var index = GetIndex(item, searchTerm, terms); + + if (index.Item2 != -1) + { + try + { + var genre = _libraryManager.GetGenre(item); + + hints.Add(new Tuple<BaseItem, string, int>(genre, index.Item1, index.Item2)); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting {0}", ex, item); + } + } + } + + // Find music genres + var musicGenres = items.Where(i => i is IHasMusicGenres) + .SelectMany(i => i.Genres) + .Where(i => !string.IsNullOrEmpty(i)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + foreach (var item in musicGenres) + { + var index = GetIndex(item, searchTerm, terms); + + if (index.Item2 != -1) + { + try + { + var genre = _libraryManager.GetMusicGenre(item); + + hints.Add(new Tuple<BaseItem, string, int>(genre, index.Item1, index.Item2)); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting {0}", ex, item); + } + } + } + + // Find music genres + var gameGenres = items.OfType<Game>() + .SelectMany(i => i.Genres) + .Where(i => !string.IsNullOrEmpty(i)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + foreach (var item in gameGenres) + { + var index = GetIndex(item, searchTerm, terms); + + if (index.Item2 != -1) + { + try + { + var genre = _libraryManager.GetGameGenre(item); + + hints.Add(new Tuple<BaseItem, string, int>(genre, index.Item1, index.Item2)); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting {0}", ex, item); + } + } + } + } + + if (query.IncludeStudios) + { + // Find studios + var studios = items.SelectMany(i => i.Studios) + .Where(i => !string.IsNullOrEmpty(i)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + foreach (var item in studios) + { + var index = GetIndex(item, searchTerm, terms); + + if (index.Item2 != -1) + { + try + { + var studio = _libraryManager.GetStudio(item); + + hints.Add(new Tuple<BaseItem, string, int>(studio, index.Item1, index.Item2)); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting {0}", ex, item); + } + } + } + } + + if (query.IncludePeople) + { + // Find persons + var persons = items.SelectMany(i => i.People) + .Select(i => i.Name) + .Where(i => !string.IsNullOrEmpty(i)) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + foreach (var item in persons) + { + var index = GetIndex(item, searchTerm, terms); + + if (index.Item2 != -1) + { + try + { + var person = _libraryManager.GetPerson(item); + + hints.Add(new Tuple<BaseItem, string, int>(person, index.Item1, index.Item2)); + } + catch (Exception ex) + { + _logger.ErrorException("Error getting {0}", ex, item); + } + } + } + } + + var returnValue = hints.Where(i => i.Item3 >= 0).OrderBy(i => i.Item3).Select(i => new SearchHintInfo + { + Item = i.Item1, + MatchedTerm = i.Item2 + }); + + return Task.FromResult(returnValue); + } + + /// <summary> + /// Gets the index. + /// </summary> + /// <param name="input">The input.</param> + /// <param name="searchInput">The search input.</param> + /// <param name="searchWords">The search input.</param> + /// <returns>System.Int32.</returns> + private Tuple<string, int> GetIndex(string input, string searchInput, List<string> searchWords) + { + if (string.IsNullOrEmpty(input)) + { + throw new ArgumentNullException("input"); + } + + if (string.Equals(input, searchInput, StringComparison.OrdinalIgnoreCase)) + { + return new Tuple<string, int>(searchInput, 0); + } + + var index = input.IndexOf(searchInput, StringComparison.OrdinalIgnoreCase); + + if (index == 0) + { + return new Tuple<string, int>(searchInput, 1); + } + if (index > 0) + { + return new Tuple<string, int>(searchInput, 2); + } + + var items = GetWords(input); + + for (var i = 0; i < searchWords.Count; i++) + { + var searchTerm = searchWords[i]; + + for (var j = 0; j < items.Count; j++) + { + var item = items[j]; + + if (string.Equals(item, searchTerm, StringComparison.OrdinalIgnoreCase)) + { + return new Tuple<string, int>(searchTerm, 3 + (i + 1) * (j + 1)); + } + + index = item.IndexOf(searchTerm, StringComparison.OrdinalIgnoreCase); + + if (index == 0) + { + return new Tuple<string, int>(searchTerm, 4 + (i + 1) * (j + 1)); + } + if (index > 0) + { + return new Tuple<string, int>(searchTerm, 5 + (i + 1) * (j + 1)); + } + } + } + return new Tuple<string, int>(null, -1); + } + + /// <summary> + /// Gets the words. + /// </summary> + /// <param name="term">The term.</param> + /// <returns>System.String[][].</returns> + private List<string> GetWords(string term) + { + return term.Split().Where(i => !string.IsNullOrWhiteSpace(i)).ToList(); + } + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 0efd3c236..b8d54c79d 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -127,7 +127,7 @@ <Compile Include="IO\DirectoryWatchers.cs" /> <Compile Include="Library\CoreResolutionIgnoreRule.cs" /> <Compile Include="Library\LibraryManager.cs" /> - <Compile Include="Library\LuceneSearchEngine.cs" /> + <Compile Include="Library\SearchEngine.cs" /> <Compile Include="Library\ResolverHelper.cs" /> <Compile Include="Library\Resolvers\Audio\AudioResolver.cs" /> <Compile Include="Library\Resolvers\Audio\MusicAlbumResolver.cs" /> diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index e02772883..13328d622 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/MediaBrowser.ServerApplication/ApplicationHost.cs @@ -257,7 +257,7 @@ namespace MediaBrowser.ServerApplication ProviderManager = new ProviderManager(HttpClient, ServerConfigurationManager, DirectoryWatchers, LogManager, FileSystemManager, ItemRepository); RegisterSingleInstance(ProviderManager); - RegisterSingleInstance<ISearchEngine>(() => new LuceneSearchEngine(ApplicationPaths, LogManager, LibraryManager)); + RegisterSingleInstance<ISearchEngine>(() => new SearchEngine(LogManager, LibraryManager, UserManager)); SessionManager = new SessionManager(UserDataManager, ServerConfigurationManager, Logger, UserRepository, LibraryManager, UserManager); RegisterSingleInstance(SessionManager); diff --git a/Nuget/MediaBrowser.Common.Internal.nuspec b/Nuget/MediaBrowser.Common.Internal.nuspec index fdc38e0a1..534957de6 100644 --- a/Nuget/MediaBrowser.Common.Internal.nuspec +++ b/Nuget/MediaBrowser.Common.Internal.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MediaBrowser.Common.Internal</id> - <version>3.0.297</version> + <version>3.0.298</version> <title>MediaBrowser.Common.Internal</title> <authors>Luke</authors> <owners>ebr,Luke,scottisafool</owners> @@ -12,7 +12,7 @@ <description>Contains common components shared by Media Browser Theater and Media Browser Server. Not intended for plugin developer consumption.</description> <copyright>Copyright © Media Browser 2013</copyright> <dependencies> - <dependency id="MediaBrowser.Common" version="3.0.297" /> + <dependency id="MediaBrowser.Common" version="3.0.298" /> <dependency id="NLog" version="2.1.0" /> <dependency id="SimpleInjector" version="2.4.0" /> <dependency id="sharpcompress" version="0.10.2" /> diff --git a/Nuget/MediaBrowser.Common.nuspec b/Nuget/MediaBrowser.Common.nuspec index 250c0780b..e6792e1df 100644 --- a/Nuget/MediaBrowser.Common.nuspec +++ b/Nuget/MediaBrowser.Common.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd"> <metadata> <id>MediaBrowser.Common</id> - <version>3.0.297</version> + <version>3.0.298</version> <title>MediaBrowser.Common</title> <authors>Media Browser Team</authors> <owners>ebr,Luke,scottisafool</owners> diff --git a/Nuget/MediaBrowser.Server.Core.nuspec b/Nuget/MediaBrowser.Server.Core.nuspec index 7d0478e5c..db48a2891 100644 --- a/Nuget/MediaBrowser.Server.Core.nuspec +++ b/Nuget/MediaBrowser.Server.Core.nuspec @@ -2,7 +2,7 @@ <package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd"> <metadata> <id>MediaBrowser.Server.Core</id> - <version>3.0.297</version> + <version>3.0.298</version> <title>Media Browser.Server.Core</title> <authors>Media Browser Team</authors> <owners>ebr,Luke,scottisafool</owners> @@ -12,7 +12,7 @@ <description>Contains core components required to build plugins for Media Browser Server.</description> <copyright>Copyright © Media Browser 2013</copyright> <dependencies> - <dependency id="MediaBrowser.Common" version="3.0.297" /> + <dependency id="MediaBrowser.Common" version="3.0.298" /> </dependencies> </metadata> <files> |
