1
0
mirror of https://github.com/mitb-archive/filebot synced 2025-03-10 06:20:27 -04:00

* unify GUI/CLI probable match selection

This commit is contained in:
Reinhard Pointner 2016-01-23 22:25:05 +00:00
parent 8de14a1b71
commit 40a98b08ae
4 changed files with 44 additions and 56 deletions

View File

@ -162,7 +162,8 @@ public final class WebServices {
}
}
}
return sortBySimilarity(results, singleton(query), getSeriesMatchMetric(), false);
return sortBySimilarity(results, singleton(query), getSeriesMatchMetric());
}
}
@ -209,7 +210,7 @@ public final class WebServices {
public synchronized List<SubtitleSearchResult> search(final String query) throws Exception {
List<SubtitleSearchResult> results = getLocalIndex().search(query);
return sortBySimilarity(results, singleton(query), new MetricAvg(getSeriesMatchMetric(), getMovieMatchMetric()), false);
return sortBySimilarity(results, singleton(query), new MetricAvg(getSeriesMatchMetric(), getMovieMatchMetric()));
}
}

View File

@ -55,10 +55,7 @@ import net.filebot.media.XattrMetaInfoProvider;
import net.filebot.similarity.CommonSequenceMatcher;
import net.filebot.similarity.EpisodeMatcher;
import net.filebot.similarity.Match;
import net.filebot.similarity.NameSimilarityMetric;
import net.filebot.similarity.SeriesNameMatcher;
import net.filebot.similarity.SimilarityComparator;
import net.filebot.similarity.SimilarityMetric;
import net.filebot.subtitle.SubtitleFormat;
import net.filebot.subtitle.SubtitleNaming;
import net.filebot.util.EntryList;
@ -908,36 +905,9 @@ public class CmdlineOperations implements CmdlineInterface {
return output;
}
public List<SearchResult> findProbableMatches(final String query, Collection<? extends SearchResult> searchResults, boolean strict) {
if (query == null) {
return new ArrayList<SearchResult>(searchResults);
}
// auto-select most probable search result
List<SearchResult> probableMatches = new ArrayList<SearchResult>();
// use name similarity metric
SimilarityMetric metric = new NameSimilarityMetric();
// find probable matches using name similarity > 0.8 (or > 0.6 in non-strict mode)
for (SearchResult result : searchResults) {
float f = metric.getSimilarity(query, result.getName());
if (f >= (strict && searchResults.size() > 1 ? 0.8 : 0.6) || ((f >= 0.5 || !strict) && (result.getName().toLowerCase().startsWith(query.toLowerCase())))) {
if (!probableMatches.contains(result)) {
probableMatches.add(result);
}
}
}
// sort results by similarity to query
sort(probableMatches, new SimilarityComparator(query));
return probableMatches;
}
@SuppressWarnings("unchecked")
public List<SearchResult> selectSearchResult(String query, Collection<? extends SearchResult> searchResults, boolean strict) throws Exception {
List<SearchResult> probableMatches = findProbableMatches(query, searchResults, strict);
List<SearchResult> probableMatches = getProbableMatches(query, searchResults, strict);
if (probableMatches.isEmpty() || (strict && probableMatches.size() != 1)) {
// allow single search results to just pass through in non-strict mode even if match confidence is low
@ -951,7 +921,7 @@ public class CmdlineOperations implements CmdlineInterface {
// just pick the best 5 matches
if (query != null) {
probableMatches = (List<SearchResult>) sortBySimilarity(searchResults, singleton(query), getSeriesMatchMetric(), false);
probableMatches = (List<SearchResult>) sortBySimilarity(searchResults, singleton(query), getSeriesMatchMetric());
}
}

View File

@ -714,19 +714,9 @@ public class MediaDetection {
return new MetricAvg(new SequenceMatchSimilarity(), new NameSimilarityMetric(), new SequenceMatchSimilarity(0, true));
}
public static <T> List<T> sortBySimilarity(Collection<T> options, Collection<String> terms, SimilarityMetric metric, boolean stripReleaseInfo) throws IOException {
Collection<String> paragon = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
// clean clutter tokens if required
if (stripReleaseInfo) {
paragon.addAll(stripReleaseInfo(terms, true));
paragon.addAll(stripReleaseInfo(terms, false));
} else {
paragon.addAll(terms);
}
public static <T> List<T> sortBySimilarity(Collection<T> options, Collection<String> terms, SimilarityMetric metric) {
// similarity comparator with multi-value support
SimilarityComparator comparator = new SimilarityComparator(metric, paragon.toArray()) {
SimilarityComparator comparator = new SimilarityComparator(metric, terms.toArray()) {
@Override
public float getMaxSimilarity(Object obj) {
@ -748,6 +738,20 @@ public class MediaDetection {
return result;
}
public static <T> List<T> sortBySimilarity(Collection<T> options, Collection<String> terms, SimilarityMetric metric, boolean stripReleaseInfo) throws IOException {
Collection<String> paragon = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
// clean clutter tokens if required
if (stripReleaseInfo) {
paragon.addAll(stripReleaseInfo(terms, true));
paragon.addAll(stripReleaseInfo(terms, false));
} else {
paragon.addAll(terms);
}
return sortBySimilarity(options, paragon, metric);
}
public static boolean isEpisodeNumberMatch(File f, Episode e) {
float similarity = EpisodeMetrics.EpisodeIdentifier.getSimilarity(f, e);
if (similarity >= 1) {
@ -1266,29 +1270,42 @@ public class MediaDetection {
return WebServices.TheTVDB.getSeriesInfo(thetvdbid, locale);
}
public static List<SearchResult> getProbableMatches(String query, Collection<SearchResult> options) {
public static List<SearchResult> getProbableMatches(String query, Collection<? extends SearchResult> options, boolean strict) {
if (query == null) {
return new ArrayList<SearchResult>(options);
}
// auto-select most probable search result
List<SearchResult> probableMatches = new LinkedList<SearchResult>();
List<SearchResult> probableMatches = new ArrayList<SearchResult>();
// use name similarity metric
SimilarityMetric metric = new NameSimilarityMetric();
float threshold = 0.85f;
float threshold = strict && options.size() > 1 ? 0.8f : 0.6f;
float sanity = strict && options.size() > 1 ? 0.5f : 0.2f;
// remove trailing braces, e.g. Doctor Who (2005) -> Doctor Who
query = removeTrailingBrackets(query);
// remove trailing braces, e.g. Doctor Who (2005) -> doctor who
query = removeTrailingBrackets(query).toLowerCase();
// find probable matches using name similarity >= 0.85
// find probable matches using name similarity > 0.8 (or > 0.6 in non-strict mode)
for (SearchResult option : options) {
float f = 0;
for (String n : option.getEffectiveNames()) {
f = Math.max(f, metric.getSimilarity(query, removeTrailingBrackets(n)));
n = removeTrailingBrackets(n).toLowerCase();
f = Math.max(f, metric.getSimilarity(query, n));
// boost matching beginnings
if (f >= sanity && n.startsWith(query)) {
f = 1;
break;
}
}
if (f >= threshold) {
if (f >= threshold && !probableMatches.contains(option)) {
probableMatches.add(option);
}
}
return probableMatches;
return sortBySimilarity(probableMatches, singleton(query), new NameSimilarityMetric());
}
public static class IndexEntry<T> implements Serializable {

View File

@ -70,7 +70,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher {
}
// auto-select most probable search result
List<SearchResult> probableMatches = getProbableMatches(query, searchResults);
List<SearchResult> probableMatches = getProbableMatches(query, searchResults, true);
// auto-select first and only probable search result
if (probableMatches.size() == 1) {