* SublightSubtitleClient: use parallel requests when looking up subtitles by video hash

This commit is contained in:
Reinhard Pointner 2011-08-26 14:18:04 +00:00
parent ca3fb703b2
commit 4a22b9d684
3 changed files with 83 additions and 26 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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);
}