|
|
|
@ -6,7 +6,10 @@ |
|
|
|
|
package moe.nekojimi.musicsearcher.providers; |
|
|
|
|
|
|
|
|
|
import com.amihaiemil.eoyaml.YamlMapping; |
|
|
|
|
import java.util.Collections; |
|
|
|
|
import java.util.HashSet; |
|
|
|
|
import java.util.List; |
|
|
|
|
import java.util.Set; |
|
|
|
|
import java.util.concurrent.CompletableFuture; |
|
|
|
|
import java.util.concurrent.ExecutionException; |
|
|
|
|
import java.util.concurrent.ForkJoinPool; |
|
|
|
@ -15,62 +18,97 @@ import java.util.concurrent.TimeoutException; |
|
|
|
|
import moe.nekojimi.musicsearcher.Query; |
|
|
|
|
import moe.nekojimi.musicsearcher.QueryFieldUnsupportedException; |
|
|
|
|
import moe.nekojimi.musicsearcher.Result; |
|
|
|
|
import org.apache.commons.lang3.StringUtils; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* |
|
|
|
|
* @author jim |
|
|
|
|
*/ |
|
|
|
|
public abstract class Searcher |
|
|
|
|
public abstract class Searcher |
|
|
|
|
{ |
|
|
|
|
final String name; |
|
|
|
|
protected final String name; |
|
|
|
|
protected String abbr; |
|
|
|
|
private final ForkJoinPool executor; |
|
|
|
|
|
|
|
|
|
public Searcher(String name) |
|
|
|
|
public Searcher(String name) |
|
|
|
|
{ |
|
|
|
|
this.name = name; |
|
|
|
|
this.abbr = name.substring(0, 2); |
|
|
|
|
this.executor = new ForkJoinPool(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Searcher(YamlMapping yaml) |
|
|
|
|
{ |
|
|
|
|
this(yaml.string("name")); |
|
|
|
|
abbr = yaml.string("abbr"); |
|
|
|
|
assert yaml.string("type").equals(this.getClass().getSimpleName()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public String getName() |
|
|
|
|
public String getName() |
|
|
|
|
{ |
|
|
|
|
return name; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public List<Result> searchAndWait(Query query) throws InterruptedException, ExecutionException |
|
|
|
|
{ |
|
|
|
|
try |
|
|
|
|
try |
|
|
|
|
{ |
|
|
|
|
return searchAndWait(query, Long.MAX_VALUE, TimeUnit.DAYS); |
|
|
|
|
} catch (TimeoutException ex) |
|
|
|
|
} catch (TimeoutException ex) |
|
|
|
|
{ |
|
|
|
|
throw new RuntimeException("This should never happen!",ex); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public List<Result> searchAndWait(Query query, long limit, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException |
|
|
|
|
{ |
|
|
|
|
return search(query).get(limit, unit); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public CompletableFuture<List<Result>> search(Query query) |
|
|
|
|
{ |
|
|
|
|
CompletableFuture<List<Result>> future = new CompletableFuture<>(); |
|
|
|
|
future.completeAsync(()->doSearch(query), executor); |
|
|
|
|
future.completeAsync(() -> searchWrapper(query), executor); |
|
|
|
|
return future; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected List<Result> searchWrapper(Query query) |
|
|
|
|
{ |
|
|
|
|
List<Result> results = doSearch(query); |
|
|
|
|
|
|
|
|
|
for (Result result : results) |
|
|
|
|
{ |
|
|
|
|
double artistScore = 1; |
|
|
|
|
double titleScore = 1; |
|
|
|
|
double albumScore = 1; |
|
|
|
|
double fullTextScore = 0; |
|
|
|
|
|
|
|
|
|
Set<String> toCompare = new HashSet<>(); |
|
|
|
|
toCompare.add(result.getAlbum()); |
|
|
|
|
toCompare.add(result.getArtist()); |
|
|
|
|
toCompare.add(result.getTitle()); |
|
|
|
|
|
|
|
|
|
for (String comparison : toCompare) |
|
|
|
|
{ |
|
|
|
|
if (comparison == null) |
|
|
|
|
continue; |
|
|
|
|
double score = StringUtils.getJaroWinklerDistance(query.getTextSearch(), comparison); |
|
|
|
|
if (score > fullTextScore) |
|
|
|
|
fullTextScore = score; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
result.setScore(albumScore * artistScore * titleScore * fullTextScore); |
|
|
|
|
} |
|
|
|
|
Collections.sort(results, Collections.reverseOrder()); |
|
|
|
|
return results; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
protected abstract List<Result> doSearch(Query query) throws QueryFieldUnsupportedException; |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public String toString() { |
|
|
|
|
return this.getClass().getSimpleName() + "{" + "name=" + name + '}'; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|