diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index c5e60a73d..3702716f9 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -40,6 +40,7 @@ namespace MediaBrowser.Controller.Entities public string NameStartsWithOrGreater { get; set; } public string NameStartsWith { get; set; } public string NameLessThan { get; set; } + public string NameContains { get; set; } public string Person { get; set; } public string[] PersonIds { get; set; } diff --git a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs index 05dde5b3e..db8a2d4fd 100644 --- a/MediaBrowser.Server.Implementations/Library/SearchEngine.cs +++ b/MediaBrowser.Server.Implementations/Library/SearchEngine.cs @@ -37,26 +37,22 @@ namespace MediaBrowser.Server.Implementations.Library Func filter = i => !(i is ICollectionFolder); + User user = null; + if (string.IsNullOrWhiteSpace(query.UserId)) { inputItems = _libraryManager.RootFolder.GetRecursiveChildren(filter); } else { - var user = _userManager.GetUserById(query.UserId); + user = _userManager.GetUserById(query.UserId); inputItems = user.RootFolder.GetRecursiveChildren(user, filter); } inputItems = _libraryManager.ReplaceVideosWithPrimaryVersions(inputItems); - var results = await GetSearchHints(inputItems, query).ConfigureAwait(false); - - // Include item types - if (query.IncludeItemTypes.Length > 0) - { - results = results.Where(f => query.IncludeItemTypes.Contains(f.Item.GetType().Name, StringComparer.OrdinalIgnoreCase)); - } + var results = await GetSearchHints(inputItems, query, user).ConfigureAwait(false); var searchResultArray = results.ToArray(); results = searchResultArray; @@ -86,9 +82,10 @@ namespace MediaBrowser.Server.Implementations.Library /// /// The input items. /// The query. + /// The user. /// IEnumerable{SearchHintResult}. /// searchTerm - private Task> GetSearchHints(IEnumerable inputItems, SearchQuery query) + private Task> GetSearchHints(IEnumerable inputItems, SearchQuery query, User user) { var searchTerm = query.SearchTerm; @@ -98,7 +95,7 @@ namespace MediaBrowser.Server.Implementations.Library } searchTerm = searchTerm.RemoveDiacritics(); - + var terms = GetWords(searchTerm); var hints = new List>(); @@ -107,8 +104,25 @@ namespace MediaBrowser.Server.Implementations.Library if (query.IncludeMedia) { + var mediaItems = _libraryManager.GetItems(new InternalItemsQuery + { + NameContains = searchTerm, + ExcludeItemTypes = new[] + { + typeof (Person).Name, + typeof (Genre).Name, + typeof (MusicArtist).Name, + typeof (GameGenre).Name, + typeof (MusicGenre).Name, + typeof (Year).Name, + typeof (Studio).Name + }, + IncludeItemTypes = query.IncludeItemTypes + + }).Items; + // Add search hints based on item name - hints.AddRange(items.Where(i => !string.IsNullOrWhiteSpace(i.Name) && IncludeInSearch(i)).Select(item => + hints.AddRange(mediaItems.Where(i => (user == null || i.IsVisibleStandalone(user)) && !(i is CollectionFolder)).Select(item => { var index = GetIndex(item.Name, searchTerm, terms); diff --git a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs index 852fbd76c..788d12cbb 100644 --- a/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs +++ b/MediaBrowser.Server.Implementations/Persistence/SqliteItemRepository.cs @@ -1,5 +1,7 @@ using MediaBrowser.Common.Configuration; using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.Movies; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Controller.Persistence; @@ -867,7 +869,7 @@ namespace MediaBrowser.Server.Implementations.Persistence whereClauses.Add("type=@type"); cmd.Parameters.Add(cmd, "@type", DbType.String).Value = includeTypes[0]; } - if (includeTypes.Length > 1) + else if (includeTypes.Length > 1) { var inClause = string.Join(",", includeTypes.Select(i => "'" + i + "'").ToArray()); whereClauses.Add(string.Format("type in ({0})", inClause)); @@ -930,6 +932,12 @@ namespace MediaBrowser.Server.Implementations.Persistence cmd.Parameters.Add(cmd, "@PersonName", DbType.String).Value = query.Person; } + if (!string.IsNullOrWhiteSpace(query.NameContains)) + { + whereClauses.Add("Name like @NameContains"); + cmd.Parameters.Add(cmd, "@NameContains", DbType.String).Value = "%" + query.NameContains + "%"; + } + if (addPaging) { if (query.StartIndex.HasValue && query.StartIndex.Value > 0) @@ -947,16 +955,58 @@ namespace MediaBrowser.Server.Implementations.Persistence return whereClauses; } - // Not crazy about having this all the way down here, but at least it's in one place - readonly Dictionary _types = new Dictionary(StringComparer.OrdinalIgnoreCase) + private static readonly Type[] KnownTypes = + { + typeof(LiveTvProgram), + typeof(LiveTvChannel), + typeof(LiveTvVideoRecording), + typeof(LiveTvAudioRecording), + typeof(Series), + typeof(LiveTvAudioRecording), + typeof(LiveTvVideoRecording), + typeof(Audio), + typeof(MusicAlbum), + typeof(MusicArtist), + typeof(MusicGenre), + typeof(MusicVideo), + typeof(Movie), + typeof(BoxSet), + typeof(Episode), + typeof(Season), + typeof(Series), + typeof(Book), + typeof(CollectionFolder), + typeof(Folder), + typeof(Game), + typeof(GameGenre), + typeof(GameSystem), + typeof(Genre), + typeof(Person), + typeof(Photo), + typeof(PhotoAlbum), + typeof(Studio), + typeof(UserRootFolder), + typeof(UserView), + typeof(Video), + typeof(Year) + }; + + private static Dictionary GetTypeMapDictionary() + { + var dict = new Dictionary(); + + foreach (var t in KnownTypes) { - {typeof(LiveTvProgram).Name, new []{typeof(LiveTvProgram).FullName}}, - {typeof(LiveTvChannel).Name, new []{typeof(LiveTvChannel).FullName}}, - {typeof(LiveTvVideoRecording).Name, new []{typeof(LiveTvVideoRecording).FullName}}, - {typeof(LiveTvAudioRecording).Name, new []{typeof(LiveTvAudioRecording).FullName}}, - {typeof(Series).Name, new []{typeof(Series).FullName}}, - {"Recording", new []{typeof(LiveTvAudioRecording).FullName, typeof(LiveTvVideoRecording).FullName}} - }; + dict[t.Name] = new[] { t.FullName }; + } + + dict["Recording"] = new[] { typeof(LiveTvAudioRecording).FullName, typeof(LiveTvVideoRecording).FullName }; + + return dict; + } + + // Not crazy about having this all the way down here, but at least it's in one place + readonly Dictionary _types = GetTypeMapDictionary(); private IEnumerable MapIncludeItemTypes(string value) { @@ -1260,7 +1310,7 @@ namespace MediaBrowser.Server.Implementations.Persistence if (!string.IsNullOrWhiteSpace(query.NameContains)) { whereClauses.Add("Name like @NameContains"); - cmd.Parameters.Add(cmd, "@NameContains", DbType.String).Value = "%"+query.NameContains+"%"; + cmd.Parameters.Add(cmd, "@NameContains", DbType.String).Value = "%" + query.NameContains + "%"; } return whereClauses;