* optimize subtitle lookup
This commit is contained in:
parent
a8b28ac8cd
commit
0ebf4b0a45
|
@ -7,6 +7,7 @@ import static net.filebot.media.MediaDetection.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -211,12 +212,17 @@ public final class WebServices {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized List<SearchResult> search(final String query) throws Exception {
|
public synchronized List<SearchResult> search(final String query, final boolean byMovie, final boolean bySeries) throws Exception {
|
||||||
Callable<List<? extends SearchResult>> seriesSearch = () -> seriesIndex.search(query, Locale.ENGLISH);
|
List<Callable<List<? extends SearchResult>>> queries = new ArrayList<>(2);
|
||||||
Callable<List<? extends SearchResult>> movieSearch = () -> movieIndex.searchMovie(query, Locale.ENGLISH);
|
if (byMovie) {
|
||||||
|
queries.add(() -> movieIndex.searchMovie(query, Locale.ENGLISH));
|
||||||
|
}
|
||||||
|
if (bySeries) {
|
||||||
|
queries.add(() -> seriesIndex.search(query, Locale.ENGLISH));
|
||||||
|
}
|
||||||
|
|
||||||
Set<SearchResult> results = new LinkedHashSet<SearchResult>();
|
Set<SearchResult> results = new LinkedHashSet<SearchResult>();
|
||||||
for (Future<List<? extends SearchResult>> resultSet : requestThreadPool.invokeAll(asList(seriesSearch, movieSearch))) {
|
for (Future<List<? extends SearchResult>> resultSet : requestThreadPool.invokeAll(queries)) {
|
||||||
try {
|
try {
|
||||||
results.addAll(resultSet.get());
|
results.addAll(resultSet.get());
|
||||||
} catch (ExecutionException e) {
|
} catch (ExecutionException e) {
|
||||||
|
|
|
@ -65,14 +65,18 @@ public final class SubtitleUtilities {
|
||||||
throw new InterruptedException();
|
throw new InterruptedException();
|
||||||
|
|
||||||
// auto-detect query and search for subtitles
|
// auto-detect query and search for subtitles
|
||||||
|
boolean searchByMovie = false, searchBySeries = false;
|
||||||
Collection<String> querySet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
|
Collection<String> querySet = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
|
||||||
List<File> files = bySeries.getValue();
|
List<File> files = bySeries.getValue();
|
||||||
|
|
||||||
if (forceQuery != null && forceQuery.length() > 0) {
|
if (forceQuery != null && forceQuery.length() > 0) {
|
||||||
querySet.add(forceQuery);
|
querySet.add(forceQuery);
|
||||||
|
searchByMovie = true;
|
||||||
|
searchBySeries = true;
|
||||||
} else if (bySeries.getKey().length() > 0) {
|
} else if (bySeries.getKey().length() > 0) {
|
||||||
// use auto-detected series name as query
|
// use auto-detected series name as query
|
||||||
querySet.add(bySeries.getKey());
|
querySet.add(bySeries.getKey());
|
||||||
|
searchBySeries = true;
|
||||||
} else {
|
} else {
|
||||||
for (File f : files) {
|
for (File f : files) {
|
||||||
List<String> queries = new ArrayList<String>();
|
List<String> queries = new ArrayList<String>();
|
||||||
|
@ -88,11 +92,18 @@ public final class SubtitleUtilities {
|
||||||
queries.add(stripReleaseInfo(getName(f)));
|
queries.add(stripReleaseInfo(getName(f)));
|
||||||
}
|
}
|
||||||
|
|
||||||
querySet.addAll(queries);
|
if (queries.size() > 0) {
|
||||||
|
querySet.addAll(queries);
|
||||||
|
searchByMovie = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Set<SubtitleDescriptor> subtitles = findSubtitles(service, querySet, languageName);
|
if (!searchByMovie && !searchBySeries)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// search for subtitles online using the auto-detected or forced query information
|
||||||
|
Set<SubtitleDescriptor> subtitles = findSubtitles(service, querySet, searchByMovie, searchBySeries, languageName);
|
||||||
|
|
||||||
// allow early abort
|
// allow early abort
|
||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
|
@ -175,13 +186,13 @@ public final class SubtitleUtilities {
|
||||||
return subtitleByVideo;
|
return subtitleByVideo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Set<SubtitleDescriptor> findSubtitles(SubtitleProvider service, Collection<String> querySet, String languageName) throws Exception {
|
public static Set<SubtitleDescriptor> findSubtitles(SubtitleProvider service, Collection<String> querySet, boolean searchByMovie, boolean searchBySeries, String languageName) throws Exception {
|
||||||
Set<SubtitleDescriptor> subtitles = new LinkedHashSet<SubtitleDescriptor>();
|
Set<SubtitleDescriptor> subtitles = new LinkedHashSet<SubtitleDescriptor>();
|
||||||
|
|
||||||
// search for and automatically select movie / show entry
|
// search for and automatically select movie / show entry
|
||||||
Set<SearchResult> resultSet = new HashSet<SearchResult>();
|
Set<SearchResult> resultSet = new HashSet<SearchResult>();
|
||||||
for (String query : querySet) {
|
for (String query : querySet) {
|
||||||
resultSet.addAll(findProbableSearchResults(query, service.search(query), querySet.size() == 1 ? 4 : 2));
|
resultSet.addAll(findProbableSearchResults(query, service.search(query, searchByMovie, searchBySeries), querySet.size() == 1 ? 4 : 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
// fetch subtitles for all search results
|
// fetch subtitles for all search results
|
||||||
|
|
|
@ -51,6 +51,7 @@ import javax.swing.JOptionPane;
|
||||||
import javax.swing.JPanel;
|
import javax.swing.JPanel;
|
||||||
import javax.swing.JScrollPane;
|
import javax.swing.JScrollPane;
|
||||||
import javax.swing.JTable;
|
import javax.swing.JTable;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import javax.swing.SwingWorker;
|
import javax.swing.SwingWorker;
|
||||||
import javax.swing.SwingWorker.StateValue;
|
import javax.swing.SwingWorker.StateValue;
|
||||||
import javax.swing.border.Border;
|
import javax.swing.border.Border;
|
||||||
|
@ -169,7 +170,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void addSubtitleService(final SubtitleServiceBean service, final JPanel servicePanel) {
|
protected void addSubtitleService(final SubtitleServiceBean service, final JPanel servicePanel) {
|
||||||
final LinkButton component = new LinkButton(service.getName(), null, ResourceManager.getIcon("database"), service.getLink());
|
final LinkButton component = new LinkButton(service.getDescription(), null, ResourceManager.getIcon("database"), service.getLink());
|
||||||
component.setBorder(BorderFactory.createEmptyBorder());
|
component.setBorder(BorderFactory.createEmptyBorder());
|
||||||
component.setVisible(false);
|
component.setVisible(false);
|
||||||
|
|
||||||
|
@ -184,7 +185,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
component.setVisible(true);
|
component.setVisible(true);
|
||||||
component.setToolTipText(service.getError() == null ? null : service.getError().getMessage());
|
component.setToolTipText(String.format("%s: %s", service.getName(), service.getError() == null ? service.getState().toString().toLowerCase() : service.getError().getMessage()));
|
||||||
servicePanel.setVisible(true);
|
servicePanel.setVisible(true);
|
||||||
servicePanel.getParent().revalidate();
|
servicePanel.getParent().revalidate();
|
||||||
}
|
}
|
||||||
|
@ -216,6 +217,11 @@ class SubtitleAutoMatchDialog extends JDialog {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
SwingUtilities.invokeLater(() -> mappingModel.fireTableStructureChanged()); // make sure UI is refershed after completion
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
queryService = Executors.newFixedThreadPool(1);
|
queryService = Executors.newFixedThreadPool(1);
|
||||||
|
@ -842,7 +848,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
||||||
private final URI link;
|
private final URI link;
|
||||||
|
|
||||||
private StateValue state = StateValue.PENDING;
|
private StateValue state = StateValue.PENDING;
|
||||||
private Throwable error = null;
|
private Exception error = null;
|
||||||
|
|
||||||
public SubtitleServiceBean(String name, Icon icon, URI link) {
|
public SubtitleServiceBean(String name, Icon icon, URI link) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
|
@ -862,6 +868,8 @@ class SubtitleAutoMatchDialog extends JDialog {
|
||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public abstract String getDescription();
|
||||||
|
|
||||||
public abstract float getMatchProbabilty(File videoFile, SubtitleDescriptor descriptor);
|
public abstract float getMatchProbabilty(File videoFile, SubtitleDescriptor descriptor);
|
||||||
|
|
||||||
protected abstract Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, String languageName, Component parent) throws Exception;
|
protected abstract Map<File, List<SubtitleDescriptor>> getSubtitleList(Collection<File> files, String languageName, Component parent) throws Exception;
|
||||||
|
@ -872,11 +880,7 @@ class SubtitleAutoMatchDialog extends JDialog {
|
||||||
try {
|
try {
|
||||||
return getSubtitleList(files, languageName, parent);
|
return getSubtitleList(files, languageName, parent);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// remember error
|
throw (error = e);
|
||||||
error = e;
|
|
||||||
|
|
||||||
// rethrow error
|
|
||||||
throw e;
|
|
||||||
} finally {
|
} finally {
|
||||||
setState(StateValue.DONE);
|
setState(StateValue.DONE);
|
||||||
}
|
}
|
||||||
|
@ -906,8 +910,8 @@ class SubtitleAutoMatchDialog extends JDialog {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getDescription() {
|
||||||
return String.format("%s [via hash]", service.getName());
|
return "Exact Search";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -923,18 +927,16 @@ class SubtitleAutoMatchDialog extends JDialog {
|
||||||
|
|
||||||
protected static class SubtitleProviderBean extends SubtitleServiceBean {
|
protected static class SubtitleProviderBean extends SubtitleServiceBean {
|
||||||
|
|
||||||
private SubtitleAutoMatchDialog inputProvider;
|
|
||||||
private SubtitleProvider service;
|
private SubtitleProvider service;
|
||||||
|
|
||||||
public SubtitleProviderBean(SubtitleProvider service, SubtitleAutoMatchDialog inputProvider) {
|
public SubtitleProviderBean(SubtitleProvider service, SubtitleAutoMatchDialog inputProvider) {
|
||||||
super(service.getName(), service.getIcon(), service.getLink());
|
super(service.getName(), service.getIcon(), service.getLink());
|
||||||
this.service = service;
|
this.service = service;
|
||||||
this.inputProvider = inputProvider;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getDescription() {
|
||||||
return String.format("%s [via name]", service.getName());
|
return "Fuzzy Search";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -214,7 +214,7 @@ public class SubtitlePanel extends AbstractSearchPanel<SubtitleProvider, Subtitl
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<SearchResult> search() throws Exception {
|
public Collection<SearchResult> search() throws Exception {
|
||||||
return request.getProvider().search(request.getSearchText());
|
return request.getProvider().search(request.getSearchText(), true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -90,8 +90,8 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized List<SearchResult> search(String query) throws Exception {
|
public synchronized List<SearchResult> search(String query, boolean byMovie, boolean bySeries) throws Exception {
|
||||||
throw new UnsupportedOperationException("SearchMoviesOnIMDB is not allowed due to abuse");
|
throw new UnsupportedOperationException(); // XMLRPC::SearchMoviesOnIMDB is not allowed due to abuse
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -499,7 +499,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
|
||||||
List<String> languages = xmlrpc.detectLanguage(data);
|
List<String> languages = xmlrpc.detectLanguage(data);
|
||||||
|
|
||||||
// return first language
|
// return first language
|
||||||
language = languages.size() > 0 ? languages.get(0) : "";
|
language = languages.size() > 0 ? languages.get(0) : "";
|
||||||
getCache().putData("detectLanguage", md5(data), Locale.ROOT, language);
|
getCache().putData("detectLanguage", md5(data), Locale.ROOT, language);
|
||||||
return new Locale(language);
|
return new Locale(language);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,30 +1,22 @@
|
||||||
|
|
||||||
package net.filebot.web;
|
package net.filebot.web;
|
||||||
|
|
||||||
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
|
|
||||||
public interface SubtitleProvider {
|
public interface SubtitleProvider {
|
||||||
|
|
||||||
public List<SearchResult> search(String query) throws Exception;
|
public List<SearchResult> search(String query, boolean byMovie, boolean bySeries) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
public List<SubtitleDescriptor> getSubtitleList(SearchResult searchResult, String languageName) throws Exception;
|
public List<SubtitleDescriptor> getSubtitleList(SearchResult searchResult, String languageName) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
public URI getSubtitleListLink(SearchResult searchResult, String languageName);
|
public URI getSubtitleListLink(SearchResult searchResult, String languageName);
|
||||||
|
|
||||||
|
|
||||||
public String getName();
|
public String getName();
|
||||||
|
|
||||||
|
|
||||||
public URI getLink();
|
public URI getLink();
|
||||||
|
|
||||||
|
|
||||||
public Icon getIcon();
|
public Icon getIcon();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue