* SublightSubtitleClient: use parallel requests when looking up subtitles by video hash
This commit is contained in:
parent
ca3fb703b2
commit
4a22b9d684
|
@ -4,7 +4,6 @@ package net.sourceforge.filebot.ui.panel.subtitle;
|
|||
|
||||
import static javax.swing.BorderFactory.*;
|
||||
import static javax.swing.JOptionPane.*;
|
||||
import static net.sourceforge.filebot.ui.NotificationLogging.*;
|
||||
import static net.sourceforge.filebot.ui.panel.subtitle.SubtitleUtilities.*;
|
||||
|
||||
import java.awt.Color;
|
||||
|
@ -70,6 +69,7 @@ class VideoHashSubtitleDownloadDialog extends JDialog {
|
|||
|
||||
private final JTable subtitleMappingTable = createTable();
|
||||
|
||||
private ExecutorService queryService;
|
||||
private ExecutorService downloadService;
|
||||
|
||||
|
||||
|
@ -158,7 +158,9 @@ class VideoHashSubtitleDownloadDialog extends JDialog {
|
|||
public void startQuery(String languageName) {
|
||||
final SubtitleMappingTableModel mappingModel = (SubtitleMappingTableModel) subtitleMappingTable.getModel();
|
||||
|
||||
// query services concurrently
|
||||
// query services sequentially
|
||||
queryService = Executors.newFixedThreadPool(1);
|
||||
|
||||
for (VideoHashSubtitleServiceBean service : services) {
|
||||
QueryTask task = new QueryTask(service, mappingModel.getVideoFiles(), languageName) {
|
||||
|
||||
|
@ -179,13 +181,13 @@ class VideoHashSubtitleDownloadDialog extends JDialog {
|
|||
// make subtitle column visible
|
||||
mappingModel.setOptionColumnVisible(true);
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger(getClass().getName()).log(Level.WARNING, e.getMessage(), e);
|
||||
Logger.getLogger(VideoHashSubtitleDownloadDialog.class.getName()).log(Level.WARNING, e.getMessage());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// start background worker
|
||||
task.execute();
|
||||
queryService.submit(task);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -292,6 +294,10 @@ class VideoHashSubtitleDownloadDialog extends JDialog {
|
|||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent evt) {
|
||||
if (queryService != null) {
|
||||
queryService.shutdownNow();
|
||||
}
|
||||
|
||||
if (downloadService != null) {
|
||||
downloadService.shutdownNow();
|
||||
}
|
||||
|
@ -716,7 +722,7 @@ class VideoHashSubtitleDownloadDialog extends JDialog {
|
|||
|
||||
return destination;
|
||||
} catch (Exception e) {
|
||||
UILogger.log(Level.WARNING, e.getMessage(), e);
|
||||
Logger.getLogger(VideoHashSubtitleDownloadDialog.class.getName()).log(Level.WARNING, e.getMessage());
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -2,6 +2,9 @@
|
|||
package net.sourceforge.filebot.web;
|
||||
|
||||
|
||||
import static java.lang.Math.*;
|
||||
import static java.util.Collections.*;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
|
@ -11,7 +14,13 @@ import java.util.HashMap;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.xml.ws.Holder;
|
||||
|
@ -116,35 +125,74 @@ public class SublightSubtitleClient implements SubtitleProvider, VideoHashSubtit
|
|||
public Map<File, List<SubtitleDescriptor>> getSubtitleList(File[] files, final String languageName) throws Exception {
|
||||
Map<File, List<SubtitleDescriptor>> subtitles = new HashMap<File, List<SubtitleDescriptor>>(files.length);
|
||||
|
||||
for (final File file : files) {
|
||||
subtitles.put(file, getSubtitleList(file, languageName));
|
||||
}
|
||||
|
||||
return subtitles;
|
||||
}
|
||||
|
||||
|
||||
public List<SubtitleDescriptor> getSubtitleList(File videoFile, String languageName) throws WebServiceException, IOException {
|
||||
List<SubtitleDescriptor> subtitles = new ArrayList<SubtitleDescriptor>();
|
||||
ExecutorService executor = Executors.newFixedThreadPool(min(files.length, 10));
|
||||
List<Future<List<SubtitleDescriptor>>> requests = new ArrayList<Future<List<SubtitleDescriptor>>>();
|
||||
|
||||
try {
|
||||
// retrieve subtitles by video hash
|
||||
for (Subtitle subtitle : getSubtitleList(SublightVideoHasher.computeHash(videoFile), null, null, languageName)) {
|
||||
// only keep linked subtitles
|
||||
if (subtitle.isIsLinked()) {
|
||||
subtitles.add(new SublightSubtitleDescriptor(subtitle, this));
|
||||
// queue and execute requests
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
Future<List<SubtitleDescriptor>> request = null;
|
||||
|
||||
try {
|
||||
// make call interruptible
|
||||
if (Thread.interrupted())
|
||||
throw new InterruptedException();
|
||||
|
||||
// compute video hash and execute query in parallel
|
||||
final String videoHash = SublightVideoHasher.computeHash(files[i]);
|
||||
|
||||
request = executor.submit(new Callable<List<SubtitleDescriptor>>() {
|
||||
|
||||
@Override
|
||||
public List<SubtitleDescriptor> call() throws Exception {
|
||||
return getSubtitleList(videoHash, languageName);
|
||||
}
|
||||
});
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(SublightSubtitleClient.class.getName()).log(Level.WARNING, "Error computing video hash: " + e.getMessage());
|
||||
} catch (LinkageError e) {
|
||||
// MediaInfo native lib not available
|
||||
throw new UnsupportedOperationException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
requests.add(i, request);
|
||||
}
|
||||
|
||||
// collect results
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
List<SubtitleDescriptor> response = emptyList();
|
||||
|
||||
if (requests.get(i) != null) {
|
||||
response = requests.get(i).get();
|
||||
}
|
||||
|
||||
subtitles.put(files[i], response);
|
||||
}
|
||||
|
||||
return subtitles;
|
||||
} finally {
|
||||
// shutdown after all tasks are done or an exception was thrown
|
||||
executor.shutdownNow();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public List<SubtitleDescriptor> getSubtitleList(String videoHash, String languageName) throws WebServiceException {
|
||||
List<SubtitleDescriptor> subtitles = new ArrayList<SubtitleDescriptor>();
|
||||
|
||||
// retrieve subtitles by video hash
|
||||
for (Subtitle subtitle : getSubtitleList(videoHash, null, null, languageName)) {
|
||||
// only keep linked subtitles
|
||||
if (subtitle.isIsLinked()) {
|
||||
subtitles.add(new SublightSubtitleDescriptor(subtitle, this));
|
||||
}
|
||||
} catch (LinkageError e) {
|
||||
// MediaInfo native lib not available
|
||||
throw new UnsupportedOperationException(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return subtitles;
|
||||
}
|
||||
|
||||
|
||||
protected List<Subtitle> getSubtitleList(String videoHash, String name, Integer year, String languageName) throws WebServiceException {
|
||||
public List<Subtitle> getSubtitleList(String videoHash, String name, Integer year, String languageName) throws WebServiceException {
|
||||
// require login
|
||||
login();
|
||||
|
||||
|
@ -277,7 +325,7 @@ public class SublightSubtitleClient implements SubtitleProvider, VideoHashSubtit
|
|||
}
|
||||
|
||||
|
||||
protected byte[] getZipArchive(Subtitle subtitle) throws WebServiceException, InterruptedException {
|
||||
protected synchronized byte[] getZipArchive(Subtitle subtitle) throws WebServiceException, InterruptedException {
|
||||
// require login
|
||||
login();
|
||||
|
||||
|
|
|
@ -32,7 +32,6 @@ import net.sourceforge.filebot.mediainfo.MediaInfo.StreamKind;
|
|||
*/
|
||||
public final class SublightVideoHasher {
|
||||
|
||||
|
||||
public static String computeHash(File file) throws IOException, LinkageError {
|
||||
byte[][] hash = new byte[4][];
|
||||
|
||||
|
@ -92,6 +91,10 @@ public final class SublightVideoHasher {
|
|||
// close handle
|
||||
mediaInfo.close();
|
||||
|
||||
// sanity check
|
||||
if (duration.isEmpty())
|
||||
throw new IOException("Failed to read video duration");
|
||||
|
||||
// convert from milliseconds to given unit
|
||||
return unit.convert(Long.parseLong(duration), TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue