aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Pulverenti <luke.pulverenti@gmail.com>2014-01-07 15:12:39 -0500
committerLuke Pulverenti <luke.pulverenti@gmail.com>2014-01-07 15:12:39 -0500
commit650dc0ccac5bbb372f644d6c383fbc88af4f4e7b (patch)
tree58e8393f10ca4071fe7f5b61fd8ed7dd7aee3b7e
parent5392ff4da4794a0c4268baa61572a8cd881db379 (diff)
added new search params
-rw-r--r--MediaBrowser.Api/SearchService.cs74
-rw-r--r--MediaBrowser.Controller/Library/ISearchEngine.cs9
-rw-r--r--MediaBrowser.Model.Portable/MediaBrowser.Model.Portable.csproj3
-rw-r--r--MediaBrowser.Model.net35/MediaBrowser.Model.net35.csproj3
-rw-r--r--MediaBrowser.Model/ApiClient/IApiClient.cs11
-rw-r--r--MediaBrowser.Model/MediaBrowser.Model.csproj1
-rw-r--r--MediaBrowser.Model/Search/SearchQuery.cs45
-rw-r--r--MediaBrowser.Server.Implementations/Library/LuceneSearchEngine.cs292
-rw-r--r--MediaBrowser.Server.Implementations/Library/SearchEngine.cs339
-rw-r--r--MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj2
-rw-r--r--MediaBrowser.ServerApplication/ApplicationHost.cs2
-rw-r--r--Nuget/MediaBrowser.Common.Internal.nuspec4
-rw-r--r--Nuget/MediaBrowser.Common.nuspec2
-rw-r--r--Nuget/MediaBrowser.Server.Core.nuspec4
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>