Remote-Search: Suppress duplicates when agregating results from multiple providers

This is a revision to pull request #1205 which tries to avoid returning
duplicate results from multiple providers.

Duplicates are eliminated in two stages:
* Check for duplicate provider ids
* In case of movies and series: Also remove duplicates by title/year
combination

The second stage is required because search results of themoviedb and
thetvdb  do not contain external ids and performing separate queries for
each individual result would be too expensive. This is not an ideal
solution, but Name/Year is anyway just exactly that information which is
presented to the client in the results - apart from the image, of
course.

Images are only aggregated on matching provider ids, though. To allow
image aggregation over all search results, the breaking condition once
the result list is full has been removed..
This commit is contained in:
softworkz 2015-10-06 00:03:58 +02:00
parent e5fdf31ec4
commit 54177fbd60

View File

@ -700,7 +700,7 @@ namespace MediaBrowser.Providers.Manager
// Manual edit occurred
// Even if save local is off, save locally anyway if the metadata file already exists
if (fileSaver == null || !isEnabledFor || !_fileSystem.FileExists(fileSaver.GetSavePath(item)))
if (fileSaver == null || !isEnabledFor || !_fileSystem.FileExists(fileSaver.GetSavePath(item)))
{
return false;
}
@ -759,6 +759,8 @@ namespace MediaBrowser.Providers.Manager
}
var resultList = new List<RemoteSearchResult>();
var foundProviderIds = new Dictionary<Tuple<string, string>, RemoteSearchResult>();
var foundTitleYearStrings = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
foreach (var provider in providers)
{
@ -766,16 +768,50 @@ namespace MediaBrowser.Providers.Manager
{
var results = await GetSearchResults(provider, searchInfo.SearchInfo, cancellationToken).ConfigureAwait(false);
var list = results.ToList();
if (list.Count > 0)
foreach (var result in results)
{
resultList.AddRange(list.Take(maxResults - resultList.Count));
}
var bFound = false;
if (resultList.Count >= maxResults)
{
return resultList;
// This check prevents duplicate search results by comparing provider ids
foreach (var providerId in result.ProviderIds)
{
var idTuple = new Tuple<string, string>(providerId.Key.ToLower(), providerId.Value.ToLower());
if (!foundProviderIds.ContainsKey(idTuple))
{
foundProviderIds.Add(idTuple, result);
}
else
{
bFound = true;
var existingResult = foundProviderIds[idTuple];
if (string.IsNullOrEmpty(existingResult.ImageUrl) && !string.IsNullOrEmpty(result.ImageUrl))
{
existingResult.ImageUrl = result.ImageUrl;
}
}
}
// This is a workaround duplicate check for movies, where intersecting provider ids are not always available
if (typeof(TItemType) == typeof(Movie) || typeof(TItemType) == typeof(Series))
{
var titleYearString = string.Format("{0} ({1})", result.Name, result.ProductionYear);
if (foundTitleYearStrings.Contains(titleYearString))
{
bFound = true;
}
else
{
foundTitleYearStrings.Add(titleYearString);
}
}
if (!bFound && resultList.Count < maxResults)
{
resultList.Add(result);
}
}
}
catch (Exception ex)