Correctly combine local and api search results

This commit is contained in:
Reinhard Pointner 2016-02-09 09:37:37 +00:00
parent 7a4f0eb9e2
commit 38b17a467a

View File

@ -8,12 +8,9 @@ import static net.filebot.util.FileUtilities.*;
import static net.filebot.util.StringUtilities.*; import static net.filebot.util.StringUtilities.*;
import java.io.IOException; import java.io.IOException;
import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.Future; import java.util.concurrent.Future;
@ -25,6 +22,7 @@ import net.filebot.similarity.MetricAvg;
import net.filebot.web.AcoustIDClient; import net.filebot.web.AcoustIDClient;
import net.filebot.web.AnidbClient; import net.filebot.web.AnidbClient;
import net.filebot.web.AnidbSearchResult; import net.filebot.web.AnidbSearchResult;
import net.filebot.web.Datasource;
import net.filebot.web.EpisodeListProvider; import net.filebot.web.EpisodeListProvider;
import net.filebot.web.FanartTVClient; import net.filebot.web.FanartTVClient;
import net.filebot.web.ID3Lookup; import net.filebot.web.ID3Lookup;
@ -42,6 +40,7 @@ import net.filebot.web.TVMazeClient;
import net.filebot.web.TheTVDBClient; import net.filebot.web.TheTVDBClient;
import net.filebot.web.TheTVDBSearchResult; import net.filebot.web.TheTVDBSearchResult;
import net.filebot.web.VideoHashSubtitleService; import net.filebot.web.VideoHashSubtitleService;
import one.util.streamex.StreamEx;
/** /**
* Reuse the same web service client so login, cache, etc. can be shared. * Reuse the same web service client so login, cache, etc. can be shared.
@ -92,27 +91,19 @@ public final class WebServices {
} }
public static EpisodeListProvider getEpisodeListProvider(String name) { public static EpisodeListProvider getEpisodeListProvider(String name) {
for (EpisodeListProvider it : WebServices.getEpisodeListProviders()) { return getService(name, getEpisodeListProviders());
if (it.getName().equalsIgnoreCase(name))
return it;
}
return null; // default
} }
public static MovieIdentificationService getMovieIdentificationService(String name) { public static MovieIdentificationService getMovieIdentificationService(String name) {
for (MovieIdentificationService it : getMovieIdentificationServices()) { return getService(name, getMovieIdentificationServices());
if (it.getName().equalsIgnoreCase(name))
return it;
}
return null; // default
} }
public static MusicIdentificationService getMusicIdentificationService(String name) { public static MusicIdentificationService getMusicIdentificationService(String name) {
for (MusicIdentificationService it : getMusicIdentificationServices()) { return getService(name, getMusicIdentificationServices());
if (it.getName().equalsIgnoreCase(name)) }
return it;
} private static <T extends Datasource> T getService(String name, T[] services) {
return null; // default return StreamEx.of(services).findFirst(it -> it.getName().equalsIgnoreCase(name)).orElse(null);
} }
public static final ExecutorService requestThreadPool = Executors.newCachedThreadPool(); public static final ExecutorService requestThreadPool = Executors.newCachedThreadPool();
@ -149,21 +140,20 @@ public final class WebServices {
@Override @Override
public List<SearchResult> fetchSearchResult(final String query, final Locale locale) throws Exception { public List<SearchResult> fetchSearchResult(final String query, final Locale locale) throws Exception {
Callable<List<SearchResult>> localSearch = () -> getLocalIndex().search(query); // run local search and API search in parallel
Callable<List<SearchResult>> apiSearch = () -> TheTVDBClientWithLocalSearch.super.fetchSearchResult(query, locale); Future<List<SearchResult>> apiSearch = requestThreadPool.submit(() -> TheTVDBClientWithLocalSearch.super.fetchSearchResult(query, locale));
Future<List<SearchResult>> localSearch = requestThreadPool.submit(() -> getLocalIndex().search(query));
Set<SearchResult> results = new LinkedHashSet<SearchResult>(); // combine alias names into a single search results, and keep API search name as primary name
for (Future<List<SearchResult>> resultSet : requestThreadPool.invokeAll(asList(localSearch, apiSearch))) { SearchResult[] result = StreamEx.of(apiSearch.get()).append(localSearch.get()).groupingBy(SearchResult::getId).values().stream().map(group -> {
try { int id = group.get(0).getId();
results.addAll(resultSet.get()); String name = group.get(0).getName();
} catch (ExecutionException e) { String[] aliasNames = StreamEx.of(group).flatMap(it -> stream(it.getAliasNames())).remove(name::equals).distinct().toArray(String[]::new);
if (e.getCause() instanceof Exception) {
throw (Exception) e.getCause(); // unwrap cause
}
}
}
return sortBySimilarity(results, singleton(query), getSeriesMatchMetric()); return new TheTVDBSearchResult(name, aliasNames, id);
}).toArray(TheTVDBSearchResult[]::new);
return sortBySimilarity(asList(result), singleton(query), getSeriesMatchMetric());
} }
} }