search hints progress

pull/702/head
Luke Pulverenti 11 years ago
parent 3eaf25132c
commit 0bfb755a38

@ -20,7 +20,7 @@ namespace MediaBrowser.Api
/// </summary>
[Route("/Search/Hints", "GET")]
[Api(Description = "Gets search hints based on a search term")]
public class GetSearchHints : IReturn<List<SearchHintResult>>
public class GetSearchHints : IReturn<SearchHintResult>
{
/// <summary>
/// Skips over a given number of items within the results. Use for paging.
@ -96,7 +96,7 @@ namespace MediaBrowser.Api
/// </summary>
/// <param name="request">The request.</param>
/// <returns>Task{IEnumerable{SearchHintResult}}.</returns>
private async Task<IEnumerable<SearchHintResult>> GetSearchHintsAsync(GetSearchHints request)
private async Task<SearchHintResult> GetSearchHintsAsync(GetSearchHints request)
{
IEnumerable<BaseItem> inputItems;
@ -113,34 +113,48 @@ namespace MediaBrowser.Api
var results = await _searchEngine.GetSearchHints(inputItems, request.SearchTerm).ConfigureAwait(false);
var searchResultArray = results.ToArray();
IEnumerable<SearchHintInfo> returnResults = searchResultArray;
if (request.StartIndex.HasValue)
{
results = results.Skip(request.StartIndex.Value);
returnResults = returnResults.Skip(request.StartIndex.Value);
}
if (request.Limit.HasValue)
{
results = results.Take(request.Limit.Value);
returnResults = returnResults.Take(request.Limit.Value);
}
return results.Select(GetSearchHintResult);
return new SearchHintResult
{
TotalRecordCount = searchResultArray.Length,
SearchHints = returnResults.Select(GetSearchHintResult).ToArray()
};
}
/// <summary>
/// Gets the search hint result.
/// </summary>
/// <param name="item">The item.</param>
/// <param name="hintInfo">The hint info.</param>
/// <returns>SearchHintResult.</returns>
private SearchHintResult GetSearchHintResult(BaseItem item)
private SearchHint GetSearchHintResult(SearchHintInfo hintInfo)
{
var result = new SearchHintResult
var item = hintInfo.Item;
var result = new SearchHint
{
Name = item.Name,
IndexNumber = item.IndexNumber,
ParentIndexNumber = item.ParentIndexNumber,
ItemId = DtoBuilder.GetClientItemId(item),
Type = item.GetType().Name,
MediaType = item.MediaType
MediaType = item.MediaType,
MatchedTerm = hintInfo.MatchedTerm,
DisplayMediaType = item.DisplayMediaType,
RunTimeTicks = item.RunTimeTicks
};
if (item.HasImage(ImageType.Primary))
@ -160,14 +174,25 @@ namespace MediaBrowser.Api
if (season != null)
{
result.Series = season.Series.Name;
result.EpisodeCount = season.RecursiveChildren.OfType<Episode>().Count();
}
var series = item as Series;
if (series != null)
{
result.EpisodeCount = series.RecursiveChildren.OfType<Episode>().Count();
}
var album = item as MusicAlbum;
if (album != null)
{
var songs = album.Children.OfType<Audio>().ToList();
var songs = album.RecursiveChildren.OfType<Audio>().ToList();
result.SongCount = songs.Count;
result.Artists = songs
.Select(i => i.Artist)
.Where(i => !string.IsNullOrEmpty(i))

@ -431,7 +431,7 @@ namespace MediaBrowser.Controller.Dto
if (album != null)
{
var songs = album.Children.OfType<Audio>().ToList();
var songs = album.RecursiveChildren.OfType<Audio>().ToList();
dto.AlbumArtist = songs.Select(i => i.AlbumArtist).FirstOrDefault(i => !string.IsNullOrEmpty(i));

@ -96,5 +96,17 @@ namespace MediaBrowser.Controller.Entities.Audio
{
return string.Equals(Artist, name, StringComparison.OrdinalIgnoreCase) || string.Equals(AlbumArtist, name, StringComparison.OrdinalIgnoreCase);
}
public override string DisplayMediaType
{
get
{
return "Song";
}
set
{
base.DisplayMediaType = value;
}
}
}
}

@ -147,7 +147,19 @@ namespace MediaBrowser.Controller.Entities.Audio
/// <returns><c>true</c> if the specified artist has artist; otherwise, <c>false</c>.</returns>
public bool HasArtist(string artist)
{
return Children.OfType<Audio>().Any(i => i.HasArtist(artist));
return RecursiveChildren.OfType<Audio>().Any(i => i.HasArtist(artist));
}
public override string DisplayMediaType
{
get
{
return "Album";
}
set
{
base.DisplayMediaType = value;
}
}
}
}

@ -23,7 +23,7 @@ namespace MediaBrowser.Controller.Library
/// </summary>
/// <param name="inputItems">The input items.</param>
/// <param name="searchTerm">The search term.</param>
/// <returns>Task{IEnumerable{BaseItem}}.</returns>
Task<IEnumerable<BaseItem>> GetSearchHints(IEnumerable<BaseItem> inputItems, string searchTerm);
/// <returns>Task{IEnumerable{SearchHintInfo}}.</returns>
Task<IEnumerable<SearchHintInfo>> GetSearchHints(IEnumerable<BaseItem> inputItems, string searchTerm);
}
}

@ -0,0 +1,22 @@
using MediaBrowser.Controller.Entities;
namespace MediaBrowser.Controller.Library
{
/// <summary>
/// Class SearchHintInfo
/// </summary>
public class SearchHintInfo
{
/// <summary>
/// Gets or sets the item.
/// </summary>
/// <value>The item.</value>
public BaseItem Item { get; set; }
/// <summary>
/// Gets or sets the matched term.
/// </summary>
/// <value>The matched term.</value>
public string MatchedTerm { get; set; }
}
}

@ -112,6 +112,7 @@
<Compile Include="IServerApplicationPaths.cs" />
<Compile Include="Library\ChildrenChangedEventArgs.cs" />
<Compile Include="Dto\DtoBuilder.cs" />
<Compile Include="Library\SearchHintInfo.cs" />
<Compile Include="Providers\IProviderManager.cs" />
<Compile Include="Providers\MediaInfo\MediaEncoderHelpers.cs" />
<Compile Include="Providers\MetadataProviderPriority.cs" />

@ -167,7 +167,11 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
if (!string.IsNullOrEmpty(val))
{
audio.AddStudios(val.Split(new[] { '/', '|' }, StringSplitOptions.RemoveEmptyEntries));
var studios =
val.Split(new[] {'/', '|'}, StringSplitOptions.RemoveEmptyEntries)
.Where(i => !string.Equals(i, audio.Artist, StringComparison.OrdinalIgnoreCase) && !string.Equals(i, audio.AlbumArtist, StringComparison.OrdinalIgnoreCase));
audio.AddStudios(studios);
}
}

@ -65,7 +65,7 @@ namespace MediaBrowser.Controller.Providers.Music
var folder = (Folder)item;
// Get each song, distinct by the combination of AlbumArtist and Album
var songs = folder.Children.OfType<Audio>().DistinctBy(i => (i.AlbumArtist ?? string.Empty) + (i.Album ?? string.Empty), StringComparer.OrdinalIgnoreCase).ToList();
var songs = folder.RecursiveChildren.OfType<Audio>().DistinctBy(i => (i.AlbumArtist ?? string.Empty) + (i.Album ?? string.Empty), StringComparer.OrdinalIgnoreCase).ToList();
foreach (var song in songs.Where(song => !string.IsNullOrEmpty(song.Album) && !string.IsNullOrEmpty(song.AlbumArtist)))
{

@ -86,6 +86,7 @@
<Compile Include="Net\NetworkShareType.cs" />
<Compile Include="Querying\PersonsQuery.cs" />
<Compile Include="Querying\ThemeSongsResult.cs" />
<Compile Include="Search\SearchHint.cs" />
<Compile Include="Search\SearchHintResult.cs" />
<Compile Include="Serialization\IJsonSerializer.cs" />
<Compile Include="Serialization\IXmlSerializer.cs" />

@ -0,0 +1,106 @@
using System;
namespace MediaBrowser.Model.Search
{
/// <summary>
/// Class SearchHintResult
/// </summary>
public class SearchHint
{
/// <summary>
/// Gets or sets the item id.
/// </summary>
/// <value>The item id.</value>
public string ItemId { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the matched term.
/// </summary>
/// <value>The matched term.</value>
public string MatchedTerm { get; set; }
/// <summary>
/// Gets or sets the index number.
/// </summary>
/// <value>The index number.</value>
public int? IndexNumber { get; set; }
/// <summary>
/// Gets or sets the parent index number.
/// </summary>
/// <value>The parent index number.</value>
public int? ParentIndexNumber { get; set; }
/// <summary>
/// Gets or sets the image tag.
/// </summary>
/// <value>The image tag.</value>
public Guid? PrimaryImageTag { get; set; }
/// <summary>
/// Gets or sets the type.
/// </summary>
/// <value>The type.</value>
public string Type { get; set; }
/// <summary>
/// Gets or sets the run time ticks.
/// </summary>
/// <value>The run time ticks.</value>
public long? RunTimeTicks { get; set; }
/// <summary>
/// Gets or sets the type of the media.
/// </summary>
/// <value>The type of the media.</value>
public string MediaType { get; set; }
/// <summary>
/// Gets or sets the display type of the media.
/// </summary>
/// <value>The display type of the media.</value>
public string DisplayMediaType { get; set; }
/// <summary>
/// Gets or sets the series.
/// </summary>
/// <value>The series.</value>
public string Series { get; set; }
/// <summary>
/// Gets or sets the album.
/// </summary>
/// <value>The album.</value>
public string Album { get; set; }
/// <summary>
/// Gets or sets the album artist.
/// </summary>
/// <value>The album artist.</value>
public string AlbumArtist { get; set; }
/// <summary>
/// Gets or sets the artists.
/// </summary>
/// <value>The artists.</value>
public string[] Artists { get; set; }
/// <summary>
/// Gets or sets the song count.
/// </summary>
/// <value>The song count.</value>
public int? SongCount { get; set; }
/// <summary>
/// Gets or sets the episode count.
/// </summary>
/// <value>The episode count.</value>
public int? EpisodeCount { get; set; }
}
}

@ -1,5 +1,4 @@
using System;

namespace MediaBrowser.Model.Search
{
/// <summary>
@ -8,69 +7,15 @@ namespace MediaBrowser.Model.Search
public class SearchHintResult
{
/// <summary>
/// Gets or sets the item id.
/// </summary>
/// <value>The item id.</value>
public string ItemId { get; set; }
/// <summary>
/// Gets or sets the name.
/// </summary>
/// <value>The name.</value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the index number.
/// </summary>
/// <value>The index number.</value>
public int? IndexNumber { get; set; }
/// <summary>
/// Gets or sets the parent index number.
/// </summary>
/// <value>The parent index number.</value>
public int? ParentIndexNumber { get; set; }
/// <summary>
/// Gets or sets the image tag.
/// </summary>
/// <value>The image tag.</value>
public Guid? PrimaryImageTag { get; set; }
/// <summary>
/// Gets or sets the type.
/// </summary>
/// <value>The type.</value>
public string Type { get; set; }
/// <summary>
/// Gets or sets the type of the media.
/// </summary>
/// <value>The type of the media.</value>
public string MediaType { get; set; }
/// <summary>
/// Gets or sets the series.
/// </summary>
/// <value>The series.</value>
public string Series { get; set; }
/// <summary>
/// Gets or sets the album.
/// </summary>
/// <value>The album.</value>
public string Album { get; set; }
/// <summary>
/// Gets or sets the album artist.
/// Gets or sets the search hints.
/// </summary>
/// <value>The album artist.</value>
public string AlbumArtist { get; set; }
/// <value>The search hints.</value>
public SearchHint[] SearchHints { get; set; }
/// <summary>
/// Gets or sets the artists.
/// Gets or sets the total record count.
/// </summary>
/// <value>The artists.</value>
public string[] Artists { get; set; }
/// <value>The total record count.</value>
public int TotalRecordCount { get; set; }
}
}

@ -97,24 +97,26 @@ namespace MediaBrowser.Server.Implementations.Library
/// <param name="searchTerm">The search term.</param>
/// <returns>IEnumerable{SearchHintResult}.</returns>
/// <exception cref="System.ArgumentNullException">searchTerm</exception>
public async Task<IEnumerable<BaseItem>> GetSearchHints(IEnumerable<BaseItem> inputItems, string searchTerm)
public async Task<IEnumerable<SearchHintInfo>> GetSearchHints(IEnumerable<BaseItem> inputItems, string searchTerm)
{
if (string.IsNullOrEmpty(searchTerm))
{
throw new ArgumentNullException("searchTerm");
}
var hints = new List<Tuple<BaseItem, int>>();
var terms = GetWords(searchTerm);
var hints = new List<Tuple<BaseItem, string, int>>();
var items = inputItems.Where(i => !(i is MusicArtist)).ToList();
foreach (var item in items)
{
var index = IndexOf(item.Name, searchTerm);
var index = GetIndex(item.Name, searchTerm, terms);
if (index != -1)
if (index.Item2 != -1)
{
hints.Add(new Tuple<BaseItem, int>(item, index));
hints.Add(new Tuple<BaseItem, string, int>(item, index.Item1, index.Item2));
}
}
@ -127,16 +129,23 @@ namespace MediaBrowser.Server.Implementations.Library
foreach (var item in artists)
{
var index = IndexOf(item, searchTerm);
var index = GetIndex(item, searchTerm, terms);
if (index != -1)
if (index.Item2 != -1)
{
var artist = await _libraryManager.GetArtist(item).ConfigureAwait(false);
try
{
var artist = await _libraryManager.GetArtist(item).ConfigureAwait(false);
hints.Add(new Tuple<BaseItem, int>(artist, index));
hints.Add(new Tuple<BaseItem, string, int>(artist, index.Item1, index.Item2));
}
catch (Exception ex)
{
_logger.ErrorException("Error getting {0}", ex, item);
}
}
}
// Find genres
var genres = items.SelectMany(i => i.Genres)
.Where(i => !string.IsNullOrEmpty(i))
@ -145,13 +154,20 @@ namespace MediaBrowser.Server.Implementations.Library
foreach (var item in genres)
{
var index = IndexOf(item, searchTerm);
var index = GetIndex(item, searchTerm, terms);
if (index != -1)
if (index.Item2 != -1)
{
var genre = await _libraryManager.GetGenre(item).ConfigureAwait(false);
try
{
var genre = await _libraryManager.GetGenre(item).ConfigureAwait(false);
hints.Add(new Tuple<BaseItem, int>(genre, index));
hints.Add(new Tuple<BaseItem, string, int>(genre, index.Item1, index.Item2));
}
catch (Exception ex)
{
_logger.ErrorException("Error getting {0}", ex, item);
}
}
}
@ -163,13 +179,20 @@ namespace MediaBrowser.Server.Implementations.Library
foreach (var item in studios)
{
var index = IndexOf(item, searchTerm);
var index = GetIndex(item, searchTerm, terms);
if (index != -1)
if (index.Item2 != -1)
{
var studio = await _libraryManager.GetStudio(item).ConfigureAwait(false);
try
{
var studio = await _libraryManager.GetStudio(item).ConfigureAwait(false);
hints.Add(new Tuple<BaseItem, int>(studio, index));
hints.Add(new Tuple<BaseItem, string, int>(studio, index.Item1, index.Item2));
}
catch (Exception ex)
{
_logger.ErrorException("Error getting {0}", ex, item);
}
}
}
@ -182,52 +205,93 @@ namespace MediaBrowser.Server.Implementations.Library
foreach (var item in persons)
{
var index = IndexOf(item, searchTerm);
var index = GetIndex(item, searchTerm, terms);
if (index != -1)
if (index.Item2 != -1)
{
var person = await _libraryManager.GetPerson(item).ConfigureAwait(false);
try
{
var person = await _libraryManager.GetPerson(item).ConfigureAwait(false);
hints.Add(new Tuple<BaseItem, int>(person, index));
hints.Add(new Tuple<BaseItem, string, int>(person, index.Item1, index.Item2));
}
catch (Exception ex)
{
_logger.ErrorException("Error getting {0}", ex, item);
}
}
}
return hints.OrderBy(i => i.Item2).Select(i => i.Item1);
}
/// <summary>
/// Gets the words.
/// </summary>
/// <param name="term">The term.</param>
/// <returns>System.String[][].</returns>
private string[] GetWords(string term)
{
// TODO: Improve this to be more accurate and respect culture
var words = term.Split(' ');
return words;
return hints.OrderBy(i => i.Item3).Select(i => new SearchHintInfo
{
Item = i.Item1,
MatchedTerm = i.Item2
});
}
/// <summary>
/// Indexes the of.
/// Gets the index.
/// </summary>
/// <param name="input">The input.</param>
/// <param name="term">The term.</param>
/// <param name="searchInput">The search input.</param>
/// <param name="searchWords">The search input.</param>
/// <returns>System.Int32.</returns>
private int IndexOf(string input, string term)
private Tuple<string, int> GetIndex(string input, string searchInput, string[] searchWords)
{
var index = 0;
if (string.Equals(input, searchInput, StringComparison.OrdinalIgnoreCase))
{
return new Tuple<string, int>(searchInput, 0);
}
var index = input.IndexOf(searchInput, StringComparison.OrdinalIgnoreCase);
foreach (var word in GetWords(input))
if (index == 0)
{
if (word.IndexOf(term, StringComparison.OrdinalIgnoreCase) != -1)
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.Length; i++)
{
var searchTerm = searchWords[i];
for (var j = 0; j < items.Length; j++)
{
return index;
}
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);
index++;
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 -1;
return new Tuple<string, int>(null, -1);
}
/// <summary>
/// Gets the words.
/// </summary>
/// <param name="term">The term.</param>
/// <returns>System.String[][].</returns>
private string[] GetWords(string term)
{
return term.Split().Where(i => !string.IsNullOrWhiteSpace(i)).ToArray();
}
}

@ -93,6 +93,21 @@
<Content Include="dashboard-ui\css\images\bgflip.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\items\searchhints\film.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\items\searchhints\game.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\items\searchhints\music.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\items\searchhints\person.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\items\searchhints\tv.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="dashboard-ui\css\images\searchbutton.png">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>

Loading…
Cancel
Save