From 4390752fc0788d892c1a3e319979a7b82bca1d83 Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Wed, 9 Mar 2016 19:26:03 +0000 Subject: [PATCH] Experiment with new CachedResource framework --- source/net/filebot/Cache.java | 36 -- .../filebot/ui/rename/EpisodeListMatcher.java | 7 +- source/net/filebot/web/AcoustIDClient.java | 30 +- .../net/filebot/web/OpenSubtitlesClient.java | 570 +++++------------- .../net/filebot/web/OpenSubtitlesXmlRpc.java | 52 +- source/net/filebot/web/ShooterSubtitles.java | 34 +- test/net/filebot/web/AcoustIDClientTest.java | 4 +- .../filebot/web/OpenSubtitlesXmlRpcTest.java | 8 +- 8 files changed, 226 insertions(+), 515 deletions(-) diff --git a/source/net/filebot/Cache.java b/source/net/filebot/Cache.java index fdfab325..7a329070 100644 --- a/source/net/filebot/Cache.java +++ b/source/net/filebot/Cache.java @@ -6,10 +6,8 @@ import static java.util.stream.Collectors.*; import static net.filebot.CachedResource.*; import static net.filebot.Logging.*; -import java.io.Serializable; import java.net.URL; import java.time.Duration; -import java.util.Arrays; import java.util.List; import java.util.function.Function; import java.util.function.Predicate; @@ -168,38 +166,4 @@ public class Cache { } } - @Deprecated - public T get(Object key, Class type) { - return type.cast(get(key)); - } - - @Deprecated - public static class Key implements Serializable { - - protected Object[] fields; - - public Key(Object... fields) { - this.fields = fields; - } - - @Override - public int hashCode() { - return Arrays.hashCode(fields); - } - - @Override - public boolean equals(Object other) { - if (other instanceof Key) { - return Arrays.equals(this.fields, ((Key) other).fields); - } - - return false; - } - - @Override - public String toString() { - return Arrays.toString(fields); - } - } - } diff --git a/source/net/filebot/ui/rename/EpisodeListMatcher.java b/source/net/filebot/ui/rename/EpisodeListMatcher.java index 8dc54320..7009f0ac 100644 --- a/source/net/filebot/ui/rename/EpisodeListMatcher.java +++ b/source/net/filebot/ui/rename/EpisodeListMatcher.java @@ -39,6 +39,7 @@ import javax.swing.Action; import javax.swing.SwingUtilities; import net.filebot.Cache; +import net.filebot.Cache.TypedCache; import net.filebot.CacheType; import net.filebot.Settings; import net.filebot.similarity.CommonSequenceMatcher; @@ -58,7 +59,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher { private boolean useSeriesIndex; // remember user selections - private Cache persistentSelectionMemory; + private TypedCache persistentSelectionMemory; // only allow one fetch session at a time so later requests can make use of cached results private final Object providerLock = new Object(); @@ -67,7 +68,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher { this.provider = provider; this.useSeriesIndex = useSeriesIndex; this.useAnimeIndex = useAnimeIndex; - this.persistentSelectionMemory = Cache.getCache("selection_" + provider.getName(), CacheType.Persistent); + this.persistentSelectionMemory = Cache.getCache("selection_" + provider.getName(), CacheType.Persistent).cast(SearchResult.class); } protected SearchResult selectSearchResult(final String query, final List searchResults, Map selectionMemory, boolean autodetection, final Component parent) throws Exception { @@ -132,7 +133,7 @@ class EpisodeListMatcher implements AutoCompleteMatcher { // check persistent memory if (autodetection) { - SearchResult persistentSelection = persistentSelectionMemory.get(query, SearchResult.class); + SearchResult persistentSelection = persistentSelectionMemory.get(query); if (persistentSelection != null) { return persistentSelection; } diff --git a/source/net/filebot/web/AcoustIDClient.java b/source/net/filebot/web/AcoustIDClient.java index 9077655c..4a93b475 100644 --- a/source/net/filebot/web/AcoustIDClient.java +++ b/source/net/filebot/web/AcoustIDClient.java @@ -76,34 +76,24 @@ public class AcoustIDClient implements MusicIdentificationService { return results; } - public String lookup(int duration, String fingerprint) throws IOException, InterruptedException { + public String lookup(int duration, String fingerprint) throws Exception { Map postParam = new LinkedHashMap(); postParam.put("duration", String.valueOf(duration)); postParam.put("fingerprint", fingerprint); - String cacheKey = postParam.toString(); - Cache cache = getCache(); - String response = cache.get(cacheKey, String.class); - if (response != null) { - return response; - } - - // respect rate limit - REQUEST_LIMIT.acquirePermit(); - + // e.g. // http://api.acoustid.org/v2/lookup?client=8XaBELgH&meta=recordings+releasegroups+compress&duration=641&fingerprint=AQABz0qUkZK4oOfhL-CPc4e5C_wW2H2QH9uDL4cvoT8UNQ-eHtsE8cceeFJx-LiiHT-aPzhxoc-Opj_eI5d2hOFyMJRzfDk-QSsu7fBxqZDMHcfxPfDIoPWxv9C1o3yg44d_3Df2GJaUQeeR-cb2HfaPNsdxHj2PJnpwPMN3aPcEMzd-_MeB_Ej4D_CLP8ghHjkJv_jh_UDuQ8xnILwunPg6hF2R8HgzvLhxHVYP_ziJX0eKPnIE1UePMByDJyg7wz_6yELsB8n4oDmDa0Gv40hf6D3CE3_wH6HFaxCPUD9-hNeF5MfWEP3SCGym4-SxnXiGs0mRjEXD6fgl4LmKWrSChzzC33ge9PB3otyJMk-IVC6R8MTNwD9qKQ_CC8kPv4THzEGZS8GPI3x0iGVUxC1hRSizC5VzoamYDi-uR7iKPhGSI82PkiWeB_eHijvsaIWfBCWH5AjjCfVxZ1TQ3CvCTclGnEMfHbnZFA8pjD6KXwd__Cn-Y8e_I9cq6CR-4S9KLXqQcsxxoWh3eMxiHI6TIzyPv0M43YHz4yte-Cv-4D16Hv9F9C9SPUdyGtZRHV-OHEeeGD--BKcjVLOK_NCDXMfx44dzHEiOZ0Z44Rf6DH5R3uiPj4d_PKolJNyRJzyu4_CTD2WOvzjKH9GPb4cUP1Av9EuQd8fGCFee4JlRHi18xQh96NLxkCgfWFKOH6WGeoe4I3za4c5hTscTPEZTES1x8kE-9MQPjT8a8gh5fPgQZtqCFj9MDvp6fDx6NCd07bjx7MLR9AhtnFnQ70GjOcV0opmm4zpY3SOa7HiwdTtyHa6NC4e-HN-OfC5-OP_gLe2QDxfUCz_0w9l65HiPAz9-IaGOUA7-4MZ5CWFOlIfe4yUa6AiZGxf6w0fFxsjTOdC6Itbh4mGD63iPH9-RFy909XAMj7mC5_BvlDyO6kGTZKJxHUd4NDwuZUffw_5RMsde5CWkJAgXnDReNEaP6DTOQ65yaD88HoeX8fge-DSeHo9Qa8cTHc80I-_RoHxx_UHeBxrJw62Q34Kd7MEfpCcu6BLeB1ePw6OO4sOF_sHhmB504WWDZiEu8sKPpkcfCT9xfej0o0lr4T5yNJeOvjmu40w-TDmqHXmYgfFhFy_M7tD1o0cO_B2ms2j-ACEEQgQgAIwzTgAGmBIKIImNQAABwgQATAlhDGCCEIGIIM4BaBgwQBogEBIOESEIA8ARI5xAhxEFmAGAMCKAURKQQpQzRAAkCCBQEAKkQYIYIQQxCixCDADCABMAE0gpJIgyxhEDiCKCCIGAEIgJIQByAhFgGACCACMRQEyBAoxQiHiCBCFOECQFAIgAABR2QAgFjCDMA0AUMIoAIMChQghChASGEGeYEAIAIhgBSErnJPPEGWYAMgw05AhiiGHiBBBGGSCQcQgwRYJwhDDhgCSCSSEIQYwILoyAjAIigBFEUQK8gAYAQ5BCAAjkjCCAEEMZAUQAZQCjCCkpCgFMCCiIcVIAZZgilAQAiSHQECOcQAQIc4QClAHAjDDGkAGAMUoBgyhihgEChFCAAWEIEYwIJYwViAAlHCBIGEIEAEIQAoBwwgwiEBAEEEOoEwBY4wRwxAhBgAcKAESIQAwwIowRFhoBhAE - URL url = new URL("http://api.acoustid.org/v2/lookup?client=" + apikey + "&meta=recordings+releases+releasegroups+tracks+compress"); - // enable compression for request and response - Map requestParam = new HashMap(); - requestParam.put("Content-Encoding", "gzip"); - requestParam.put("Accept-Encoding", "gzip"); + return (String) getCache().computeIf(postParam.toString(), Cache.isAbsent(), it -> { + REQUEST_LIMIT.acquirePermit(); - // submit - response = UTF_8.decode(post(url, postParam, requestParam)).toString(); + URL url = new URL("http://api.acoustid.org/v2/lookup?client=" + apikey + "&meta=recordings+releases+releasegroups+tracks+compress"); + Map requestParam = new HashMap(); + requestParam.put("Content-Encoding", "gzip"); + requestParam.put("Accept-Encoding", "gzip"); - cache.put(cacheKey, response); - return response; + return UTF_8.decode(post(url, postParam, requestParam)).toString(); + }); } public AudioTrack parseResult(String json, final int targetDuration) throws IOException { diff --git a/source/net/filebot/web/OpenSubtitlesClient.java b/source/net/filebot/web/OpenSubtitlesClient.java index 2a76bdf9..019ff5e7 100644 --- a/source/net/filebot/web/OpenSubtitlesClient.java +++ b/source/net/filebot/web/OpenSubtitlesClient.java @@ -1,35 +1,32 @@ package net.filebot.web; -import static java.lang.Math.*; import static java.util.Arrays.*; import static java.util.Collections.*; import static java.util.stream.Collectors.*; +import static net.filebot.Logging.*; import static net.filebot.util.FileUtilities.*; import static net.filebot.web.OpenSubtitlesHasher.*; import java.io.File; import java.io.IOException; import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.function.Function; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.Icon; import net.filebot.Cache; -import net.filebot.Cache.Key; +import net.filebot.Cache.TypedCache; import net.filebot.CacheType; import net.filebot.ResourceManager; import net.filebot.media.MediaDetection; @@ -58,6 +55,21 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS this.xmlrpc = new OpenSubtitlesXmlRpcWithRetryAndFloodLimit(String.format("%s v%s", name, version), 2, 3000); } + @Override + public String getName() { + return "OpenSubtitles"; + } + + @Override + public Icon getIcon() { + return ResourceManager.getIcon("search.opensubtitles"); + } + + @Override + public URI getLink() { + return URI.create("http://www.opensubtitles.org"); + } + public synchronized void setUser(String username, String password_md5) { // cancel previous session this.logout(); @@ -71,51 +83,46 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS } @Override - public String getName() { - return "OpenSubtitles"; + public List search(String query) throws Exception { + throw new UnsupportedOperationException("XMLRPC::SearchMoviesOnIMDB has been banned due to abuse"); } @Override - public URI getLink() { - return URI.create("http://www.opensubtitles.org"); - } - - @Override - public Icon getIcon() { - return ResourceManager.getIcon("search.opensubtitles"); - } - - public ResultCache getCache() { - return new ResultCache(getName(), Cache.getCache(getName(), CacheType.Daily)); - } - - @Override - public synchronized List search(String query) throws Exception { - throw new UnsupportedOperationException(); // XMLRPC::SearchMoviesOnIMDB is not allowed due to abuse + public List searchMovie(String query, Locale locale) throws Exception { + throw new UnsupportedOperationException("XMLRPC::SearchMoviesOnIMDB has been banned due to abuse"); } @Override public synchronized List guess(String tag) throws Exception { - List subtitles = getCache().getSearchResult("guess", tag); - if (subtitles != null) { - return subtitles; - } - // require login - login(); - - subtitles = xmlrpc.guessMovie(singleton(tag)).getOrDefault(tag, emptyList()); - - getCache().putSearchResult("guess", tag, subtitles); - return subtitles; + return getSearchCache("tag").computeIf(tag, Cache.isAbsent(), it -> { + login(); + return xmlrpc.guessMovie(singleton(tag)).getOrDefault(tag, emptyList()); + }); } - public synchronized List getSubtitleList(SubtitleSearchResult searchResult, String languageName) throws Exception { + public synchronized List searchIMDB(String query) throws Exception { + // require login + return getSearchCache("query").computeIf(query, Cache.isAbsent(), it -> { + login(); + return xmlrpc.searchMoviesOnIMDB(query); + }); + } + + public synchronized List getSubtitleList(Query query) throws Exception { + // require login + return getSubtitlesCache().computeIf(query, Cache.isAbsent(), it -> { + login(); + return xmlrpc.searchSubtitles(singleton(query)); + }); + } + + public List getSubtitleList(SubtitleSearchResult searchResult, String languageName) throws Exception { return getSubtitleList(searchResult, -1, -1, languageName); } @Override - public synchronized List getSubtitleList(SubtitleSearchResult searchResult, int[][] episodeFilter, String languageName) throws Exception { + public List getSubtitleList(SubtitleSearchResult searchResult, int[][] episodeFilter, String languageName) throws Exception { // no filter if (episodeFilter == null || episodeFilter.length == 0) { return getSubtitleList(searchResult, -1, -1, languageName); @@ -156,41 +163,31 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS } public synchronized List getSubtitleList(SubtitleSearchResult searchResult, int season, int episode, String languageName) throws Exception { - int imdbid = ((Movie) searchResult).getImdbId(); - String[] languageFilter = languageName != null ? new String[] { getSubLanguageID(languageName, true) } : new String[0]; - - Query query = Query.forImdbId(imdbid, season, episode, languageFilter); - - List subtitles = getCache().getSubtitleDescriptorList(query); - if (subtitles != null) { - return subtitles; - } + Query query = Query.forImdbId(searchResult.getImdbId(), season, episode, getLanguageFilter(languageName)); // require login - login(); - - // get subtitle list - subtitles = asList(xmlrpc.searchSubtitles(imdbid, season, episode, languageFilter).toArray(new SubtitleDescriptor[0])); - - getCache().putSubtitleDescriptorList(query, subtitles); - return subtitles; + return getSubtitlesCache().computeIf(query, Cache.isAbsent(), it -> { + login(); + return xmlrpc.searchSubtitles(singleton(query)); + }); } @Override public Map> getSubtitleList(File[] files, String languageName) throws Exception { Map> results = new HashMap>(files.length); - Set remainingFiles = new LinkedHashSet(asList(files)); + Set remainingFiles = new HashSet(asList(files)); // lookup subtitles by hash if (remainingFiles.size() > 0) { results.putAll(getSubtitleListByHash(remainingFiles.toArray(new File[0]), languageName)); } - for (Entry> it : results.entrySet()) { - if (it.getValue().size() > 0) { - remainingFiles.remove(it.getKey()); + // remove files for which subtitles have already been found + results.forEach((k, v) -> { + if (v.size() > 0) { + remainingFiles.remove(k); } - } + }); // lookup subtitles by tag if (remainingFiles.size() > 0) { @@ -200,149 +197,51 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS return results; } - // max numbers of queries to submit in a single XML-RPC request, but currently only batchSize == 1 is supported - private final int batchSize = 1; + protected Map> getSubtitleList(File[] files, Function queryMapper) throws Exception { + Map> results = new HashMap>(files.length); - public synchronized Map> getSubtitleListByHash(File[] files, String languageName) throws Exception { - // singleton array with or empty array - String[] languageFilter = languageName != null ? new String[] { getSubLanguageID(languageName, true) } : new String[0]; - - // remember hash for each file - Map hashMap = new HashMap(files.length); - Map> resultMap = new HashMap>(files.length); - - // create hash query for each file - List hashQueryList = new ArrayList(files.length); - - for (File file : files) { - Query query = file.length() > HASH_CHUNK_SIZE ? Query.forHash(computeHash(file), file.length(), languageFilter) : null; - - // DEBUG - // query = Query.forHash("b4a91d8384a92269", 1178926184, languageFilter); - - // add hash query + // dispatch query for all hashes + for (File f : files) { + Query query = queryMapper.apply(f); if (query != null) { - List cachedResults = getCache().getSubtitleDescriptorList(query); - if (cachedResults == null) { - hashQueryList.add(query); - hashMap.put(query, file); - } else { - resultMap.put(file, cachedResults); - } - } - - // prepare result map - if (resultMap.get(file) == null) { - resultMap.put(file, new LinkedList()); + results.put(f, getSubtitleList(query)); + } else { + results.put(f, emptyList()); } } - if (hashQueryList.size() > 0) { - // require login - login(); - - // dispatch query for all hashes - for (int bn = 0; bn < ceil((float) hashQueryList.size() / batchSize); bn++) { - List batch = hashQueryList.subList(bn * batchSize, min((bn * batchSize) + batchSize, hashQueryList.size())); - - // submit query and map results to given files - for (OpenSubtitlesSubtitleDescriptor subtitle : xmlrpc.searchSubtitles(batch)) { - // get file for hash - File file = hashMap.get((batch.get(0))); - - // add subtitle - if (file != null) { - resultMap.get(file).add(subtitle); - } else { - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Unable to map hash to file: " + subtitle.getMovieHash()); - } - } - - for (Query query : batch) { - getCache().putSubtitleDescriptorList(query, resultMap.get(hashMap.get(query))); - } - } - } - - return resultMap; + return results; } - public synchronized Map> getSubtitleListByTag(File[] files, String languageName) throws Exception { - // singleton array with or empty array - String[] languageFilter = languageName != null ? new String[] { getSubLanguageID(languageName, true) } : new String[0]; - - // remember tag for each file - Map tagMap = new HashMap(files.length); - Map> resultMap = new HashMap>(files.length); - - // create tag query for each file - List tagQueryList = new ArrayList(files.length); - - for (File file : files) { - // add tag query - String tag = getNameWithoutExtension(file.getName()); - Query query = Query.forTag(tag, languageFilter); - - // check tag - List cachedResults = getCache().getSubtitleDescriptorList(query); - if (cachedResults == null) { - tagQueryList.add(query); - tagMap.put(query, file); - } else { - resultMap.put(file, cachedResults); - } - - // prepare result map - if (resultMap.get(file) == null) { - resultMap.put(file, new LinkedList()); - } - } - - if (tagQueryList.size() > 0) { - // require login - login(); - - // dispatch query for all hashes - for (int bn = 0; bn < ceil((float) tagQueryList.size() / batchSize); bn++) { - List batch = tagQueryList.subList(bn * batchSize, min((bn * batchSize) + batchSize, tagQueryList.size())); - - // submit query and map results to given files - for (OpenSubtitlesSubtitleDescriptor subtitle : xmlrpc.searchSubtitles(batch)) { - // get file for tag - File file = tagMap.get(batch.get(0)); - - // add subtitle - if (file != null) { - resultMap.get(file).add(subtitle); - } else { - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Unable to map release name to file: " + subtitle.getMovieReleaseName()); - } - } - - for (Query query : batch) { - getCache().putSubtitleDescriptorList(query, resultMap.get(tagMap.get(query))); + public Map> getSubtitleListByHash(File[] files, String language) throws Exception { + return getSubtitleList(files, f -> { + if (f.length() > HASH_CHUNK_SIZE) { + try { + String hash = computeHash(f); + return Query.forHash(hash, f.length(), getLanguageFilter(language)); + } catch (Exception e) { + debug.log(Level.SEVERE, "Failed to compute hash", e); } } - } + return null; + }); + } - return resultMap; + public Map> getSubtitleListByTag(File[] files, String language) throws Exception { + return getSubtitleList(files, f -> { + String tag = getNameWithoutExtension(f.getName()); + return Query.forTag(tag, getLanguageFilter(language)); + }); } @Override public synchronized CheckResult checkSubtitle(File videoFile, File subtitleFile) throws Exception { - // subhash (md5 of subtitles), subfilename, moviehash, moviebytesize, moviefilename - SubFile sub = new SubFile(); - sub.setSubHash(md5(readFile(subtitleFile))); - sub.setSubFileName(subtitleFile.getName()); - sub.setMovieHash(computeHash(videoFile)); - sub.setMovieByteSize(videoFile.length()); - sub.setMovieFileName(videoFile.getName()); - // require login login(); // check if subs already exist in DB - TryUploadResponse response = xmlrpc.tryUploadSubtitles(sub); + SubFile subFile = getSubFile(videoFile, subtitleFile, false); + TryUploadResponse response = xmlrpc.tryUploadSubtitles(subFile); // TryUploadResponse: false => [{HashWasAlreadyInDb=1, MovieKind=movie, IDSubtitle=3167446, MoviefilenameWasAlreadyInDb=1, ISO639=en, MovieYear=2007, SubLanguageID=eng, MovieName=Blades of Glory, MovieNameEng=, IDMovieImdb=445934}] boolean exists = !response.isUploadRequired(); @@ -361,7 +260,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS String year = fields.get("MovieYear"); identity = new Movie(name, Integer.parseInt(year), Integer.parseInt(imdb), -1); } catch (Exception e) { - Logger.getLogger(getClass().getName()).log(Level.WARNING, e.getMessage()); + debug.log(Level.SEVERE, "Failed to upload subtitles", e); } } @@ -371,11 +270,13 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS @Override public synchronized void uploadSubtitle(Object identity, Locale language, File[] videoFile, File[] subtitleFile) throws Exception { - if (!(identity instanceof Movie && ((Movie) identity).getImdbId() > 0)) { + int imdbid = -1; + try { + imdbid = ((Movie) identity).getImdbId(); + } catch (Exception e) { throw new IllegalArgumentException("Illegal Movie ID: " + identity); } - int imdbid = ((Movie) identity).getImdbId(); String subLanguageID = getSubLanguageID(language.getDisplayName(Locale.ENGLISH), false); BaseInfo info = new BaseInfo(); @@ -384,7 +285,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS SubFile[] subFiles = new SubFile[videoFile.length]; for (int i = 0; i < subFiles.length; i++) { - subFiles[i] = getSubFile(info, videoFile[i], subtitleFile[i]); + subFiles[i] = getSubFile(videoFile[i], subtitleFile[i], true); } // require login @@ -393,7 +294,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS xmlrpc.uploadSubtitles(info, subFiles); } - private SubFile getSubFile(BaseInfo info, File videoFile, File subtitleFile) throws IOException { + protected SubFile getSubFile(File videoFile, File subtitleFile, boolean content) throws IOException { // subhash (md5 of subtitles), subfilename, moviehash, moviebytesize, moviefilename SubFile sub = new SubFile(); sub.setSubHash(md5(readFile(subtitleFile))); @@ -403,66 +304,32 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS sub.setMovieFileName(videoFile.getName()); // encode subtitle contents - sub.setSubContent(readFile(subtitleFile)); + if (content) { + sub.setSubContent(readFile(subtitleFile)); + } - try { - MediaInfo mi = new MediaInfo(); + try (MediaInfo mi = new MediaInfo()) { mi.open(videoFile); sub.setMovieFPS(mi.get(StreamKind.Video, 0, "FrameRate")); sub.setMovieTimeMS(mi.get(StreamKind.General, 0, "Duration")); - mi.close(); } catch (Throwable e) { - Logger.getLogger(getClass().getName()).log(Level.WARNING, e.getMessage(), e); + debug.log(Level.SEVERE, "Failed to read media info", e); } return sub; } - @Override - public List searchMovie(String query, Locale locale) throws Exception { - throw new UnsupportedOperationException(); - } - - public synchronized List searchIMDB(String query) throws Exception { - // search for movies and series - List result = getCache().getSearchResult("search", query); - if (result != null) { - return result; - } - - // require login - login(); - - try { - // search for movies / series - result = xmlrpc.searchMoviesOnIMDB(query); - } catch (ClassCastException e) { - // unexpected xmlrpc responses (e.g. error messages instead of results) will trigger this - throw new XmlRpcException("Illegal XMLRPC response on searchMoviesOnIMDB"); - } - - getCache().putSearchResult("search", query, result); - return result; - } - @Override public synchronized Movie getMovieDescriptor(Movie id, Locale locale) throws Exception { if (id.getImdbId() <= 0) { - throw new IllegalArgumentException("id must not be " + id.getImdbId()); - } - - Movie result = getCache().getData("getMovieDescriptor", id.getImdbId(), locale, Movie.class); - if (result != null) { - return result; + throw new IllegalArgumentException("Illegal IMDbID ID: " + id.getImdbId()); } // require login - login(); - - Movie movie = xmlrpc.getIMDBMovieDetails(id.getImdbId()); - - getCache().putData("getMovieDescriptor", id.getImdbId(), locale, movie); - return movie; + return getLookupCache(locale).computeIf(id.getImdbId(), Cache.isAbsent(), it -> { + login(); + return xmlrpc.getIMDBMovieDetails(id.getImdbId()); + }); } public Movie getMovieDescriptor(File movieFile, Locale locale) throws Exception { @@ -472,55 +339,24 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS @Override public synchronized Map getMovieDescriptors(Collection movieFiles, Locale locale) throws Exception { // create result array - Map result = new HashMap(); + Map results = new HashMap(); - // compute movie hashes - Map hashMap = new HashMap(movieFiles.size()); + // make sure we don't get mismatches by making sure the hash has not been confirmed numerous times + int minSeenCount = 20; - for (File file : movieFiles) { - if (file.length() > HASH_CHUNK_SIZE) { - String hash = computeHash(file); + for (File f : movieFiles) { + if (f.length() > HASH_CHUNK_SIZE) { + String hash = computeHash(f); - Movie entry = getCache().getData("getMovieDescriptor", hash, locale, Movie.class); - if (entry == null) { - hashMap.put(hash, file); // map file by hash - } else if (entry.getName().length() > 0) { - result.put(file, entry); - } + Movie match = getLookupCache(locale).computeIf(hash, Cache.isAbsent(), it -> { + return xmlrpc.checkMovieHash(singleton(hash), minSeenCount).get(hash); + }); + + results.put(f, match); } } - if (hashMap.size() > 0) { - // require login - login(); - - // dispatch query for all hashes - List hashes = new ArrayList(hashMap.keySet()); - int batchSize = 50; - for (int bn = 0; bn < ceil((float) hashes.size() / batchSize); bn++) { - List batch = hashes.subList(bn * batchSize, min((bn * batchSize) + batchSize, hashes.size())); - Set unmatchedHashes = new HashSet(batch); - - int minSeenCount = 20; // make sure we don't get mismatches by making sure the hash has not been confirmed numerous times - for (Entry it : xmlrpc.checkMovieHash(batch, minSeenCount).entrySet()) { - String hash = it.getKey(); - Movie movie = it.getValue(); - - result.put(hashMap.get(hash), movie); - getCache().putData("getMovieDescriptor", hash, locale, movie); - - unmatchedHashes.remove(hash); - } - - // note hashes that are not matched to any items so we can ignore them in the future - for (String hash : unmatchedHashes) { - getCache().putData("getMovieDescriptor", hash, locale, new Movie("", -1, -1, -1)); - } - } - - } - - return result; + return results; } @Override @@ -541,24 +377,16 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS public synchronized Locale detectLanguage(byte[] data) throws Exception { if (data.length < 256) { - throw new IllegalArgumentException("data is not enough"); - } - - String language = getCache().getData("detectLanguage", md5(data), Locale.ROOT, String.class); - if (language != null) { - return language.isEmpty() ? null : new Locale(language); + throw new IllegalArgumentException("Data is too small: " + data.length); } // require login - login(); + List languages = getCache("detect").castList(String.class).computeIf(md5(data), Cache.isAbsent(), it -> { + login(); + return xmlrpc.detectLanguage(data); + }); - // detect language - List languages = xmlrpc.detectLanguage(data); - - // return first language - language = languages.size() > 0 ? languages.get(0) : ""; - getCache().putData("detectLanguage", md5(data), Locale.ROOT, language); - return new Locale(language); + return languages.size() > 0 ? new Locale(languages.get(0)) : Locale.ROOT; } public synchronized void login() throws Exception { @@ -574,7 +402,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS try { xmlrpc.logout(); } catch (Exception e) { - Logger.getLogger(getClass().getName()).log(Level.WARNING, "Logout failed", e); + debug.log(Level.WARNING, "Failed to log out", e); } } logoutTimer.cancel(); @@ -602,57 +430,54 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS /** * SubLanguageID by English language name */ - @SuppressWarnings("unchecked") - protected synchronized Map getSubLanguageMap() throws IOException { - Cache cache = Cache.getCache(getName(), CacheType.Persistent); - String cacheKey = getClass().getName() + ".subLanguageMap"; + protected synchronized Map getSubLanguageMap() throws Exception { + Map subLanguageMap = new HashMap(); // try to get language map from cache - Map subLanguageMap = cache.get(cacheKey, Map.class); + Cache cache = Cache.getCache(getName() + "_languages", CacheType.Persistent); + Map m = (Map) cache.computeIf("subLanguageMap", Cache.isAbsent(), it -> { + try { + return xmlrpc.getSubLanguages(); + } catch (Exception e) { + throw new IOException("Failed to retrieve subtitle language map", e); + } + }); - if (subLanguageMap == null) { - subLanguageMap = new HashMap(); + // add additional language aliases for improved compatibility + Map additionalLanguageMappings = MediaDetection.releaseInfo.getLanguageMap(Locale.ENGLISH); + + m.forEach((k, v) -> { + // map id by name + String subLanguageID = k.toString().toLowerCase(); + String subLanguageName = v.toString().toLowerCase(); + + subLanguageMap.put(subLanguageName, subLanguageID); + subLanguageMap.put(subLanguageID, subLanguageID); // add reverse mapping as well for improved compatibility // add additional language aliases for improved compatibility - Map additionalLanguageMappings = MediaDetection.releaseInfo.getLanguageMap(Locale.ENGLISH); - - // fetch language data - try { - for (Entry entry : xmlrpc.getSubLanguages().entrySet()) { - // map id by name - String subLanguageID = entry.getKey().toLowerCase(); - String subLanguageName = entry.getValue().toLowerCase(); - - subLanguageMap.put(subLanguageName, subLanguageID); - subLanguageMap.put(subLanguageID, subLanguageID); // add reverse mapping as well for improved compatibility - - // add additional language aliases for improved compatibility - for (String key : asList(subLanguageID, subLanguageName)) { - Locale locale = additionalLanguageMappings.get(key); - if (locale != null) { - for (String identifier : asList(locale.getLanguage(), locale.getISO3Language(), locale.getDisplayLanguage(Locale.ENGLISH))) { - if (identifier != null && identifier.length() > 0 && !subLanguageMap.containsKey(identifier.toLowerCase())) { - subLanguageMap.put(identifier.toLowerCase(), subLanguageID); - } - } + for (String key : new String[] { subLanguageID, subLanguageName }) { + Locale locale = additionalLanguageMappings.get(key); + if (locale != null) { + for (String identifier : asList(locale.getLanguage(), locale.getISO3Language(), locale.getDisplayLanguage(Locale.ENGLISH))) { + if (identifier != null && identifier.length() > 0 && !subLanguageMap.containsKey(identifier.toLowerCase())) { + subLanguageMap.put(identifier.toLowerCase(), subLanguageID); } } } - } catch (Exception e) { - throw new IOException("Failed to retrieve subtitle language list.", e); } + }); - // some additional special handling - subLanguageMap.put("brazilian", "pob"); - subLanguageMap.put("chinese", "chi,zht,zhe"); // Chinese (Simplified) / Chinese (Traditional) / Chinese (bilingual) - - // cache data - cache.put(cacheKey, subLanguageMap); - } + // some additional special handling + subLanguageMap.put("brazilian", "pob"); + subLanguageMap.put("chinese", "chi,zht,zhe"); // Chinese (Simplified) / Chinese (Traditional) / Chinese (bilingual) return subLanguageMap; } + protected String[] getLanguageFilter(String language) { + return language == null || language.isEmpty() ? new String[0] : new String[] { getSubLanguageID(language, true) }; + } + protected String getSubLanguageID(String languageName, boolean allowMultiLanguageID) { try { String subLanguageID = getSubLanguageMap().get(languageName.toLowerCase()); @@ -663,7 +488,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS subLanguageID = subLanguageID.substring(0, subLanguageID.indexOf(",")); } return subLanguageID; - } catch (IOException e) { + } catch (Exception e) { throw new IllegalStateException(e); } } @@ -677,87 +502,20 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS return null; } - protected static class ResultCache { + public Cache getCache(String section) { + return Cache.getCache(getName() + "_" + section, CacheType.Daily); + } - private final String id; - private final Cache cache; + protected TypedCache> getSearchCache(String method) { + return getCache("search_" + method).castList(SubtitleSearchResult.class); + } - public ResultCache(String id, Cache cache) { - this.id = id; - this.cache = cache; - } + protected TypedCache> getSubtitlesCache() { + return getCache("data").castList(SubtitleDescriptor.class); + } - protected String normalize(String query) { - return query == null ? null : query.trim().toLowerCase(); - } - - public List putSearchResult(String method, String query, List value) { - try { - cache.put(new Key(id, method, normalize(query)), value.toArray(new SubtitleSearchResult[0])); - } catch (Exception e) { - Logger.getLogger(OpenSubtitlesClient.class.getName()).log(Level.WARNING, e.getMessage()); - } - - return value; - } - - @SuppressWarnings("unchecked") - public List getSearchResult(String method, String query) { - try { - SubtitleSearchResult[] array = cache.get(new Key(id, method, normalize(query)), SubtitleSearchResult[].class); - if (array != null) { - return Arrays.asList(array); - } - } catch (Exception e) { - Logger.getLogger(OpenSubtitlesClient.class.getName()).log(Level.WARNING, e.getMessage(), e); - } - - return null; - } - - public List putSubtitleDescriptorList(Query key, List subtitles) { - try { - cache.put(new Key(id, key), subtitles.toArray(new SubtitleDescriptor[0])); - } catch (Exception e) { - Logger.getLogger(OpenSubtitlesClient.class.getName()).log(Level.WARNING, e.getMessage()); - } - - return subtitles; - } - - public List getSubtitleDescriptorList(Query key) { - try { - SubtitleDescriptor[] descriptors = cache.get(new Key(id, key), SubtitleDescriptor[].class); - if (descriptors != null) { - return Arrays.asList(descriptors); - } - } catch (Exception e) { - Logger.getLogger(OpenSubtitlesClient.class.getName()).log(Level.WARNING, e.getMessage(), e); - } - - return null; - } - - public void putData(Object category, Object key, Locale locale, Object object) { - try { - cache.put(new Key(id, category, locale, key), object); - } catch (Exception e) { - Logger.getLogger(OpenSubtitlesClient.class.getName()).log(Level.WARNING, e.getMessage()); - } - } - - public T getData(Object category, Object key, Locale locale, Class type) { - try { - T value = cache.get(new Key(id, category, locale, key), type); - if (value != null) { - return value; - } - } catch (Exception e) { - Logger.getLogger(OpenSubtitlesClient.class.getName()).log(Level.WARNING, e.getMessage(), e); - } - - return null; - } + protected TypedCache getLookupCache(Locale locale) { + return getCache("lookup_" + locale).cast(Movie.class); } protected static class OpenSubtitlesXmlRpcWithRetryAndFloodLimit extends OpenSubtitlesXmlRpc { diff --git a/source/net/filebot/web/OpenSubtitlesXmlRpc.java b/source/net/filebot/web/OpenSubtitlesXmlRpc.java index b939b229..f5ad40de 100644 --- a/source/net/filebot/web/OpenSubtitlesXmlRpc.java +++ b/source/net/filebot/web/OpenSubtitlesXmlRpc.java @@ -90,10 +90,6 @@ public class OpenSubtitlesXmlRpc { return (Map) invoke("ServerInfo", token); } - public List searchSubtitles(int imdbid, int season, int episode, String... sublanguageids) throws XmlRpcFault { - return searchSubtitles(singleton(Query.forImdbId(imdbid, season, episode, sublanguageids))); - } - public List searchSubtitles(Collection queryList) throws XmlRpcFault { List subtitles = new ArrayList(); Map response = invoke("SearchSubtitles", token, queryList); @@ -112,35 +108,41 @@ public class OpenSubtitlesXmlRpc { } public List searchMoviesOnIMDB(String query) throws XmlRpcFault { - Map response = invoke("SearchMoviesOnIMDB", token, query); + try { + // search for movies / series + Map response = invoke("SearchMoviesOnIMDB", token, query); - List> movieData = (List>) response.get("data"); - List movies = new ArrayList(); + List> movieData = (List>) response.get("data"); + List movies = new ArrayList(); - // title pattern - Pattern pattern = Pattern.compile("(.+)[(](\\d{4})([/]I+)?[)]"); + // title pattern + Pattern pattern = Pattern.compile("(.+)[(](\\d{4})([/]I+)?[)]"); - for (Map movie : movieData) { - try { - String imdbid = movie.get("id"); - if (!imdbid.matches("\\d{1,7}")) - throw new IllegalArgumentException("Illegal IMDb movie ID: Must be a 7-digit number"); + for (Map movie : movieData) { + try { + String imdbid = movie.get("id"); + if (!imdbid.matches("\\d{1,7}")) + throw new IllegalArgumentException("Illegal IMDb movie ID: Must be a 7-digit number"); - // match movie name and movie year from search result - Matcher matcher = pattern.matcher(movie.get("title")); - if (!matcher.find()) - throw new IllegalArgumentException("Illegal title: Must be in 'name (year)' format"); + // match movie name and movie year from search result + Matcher matcher = pattern.matcher(movie.get("title")); + if (!matcher.find()) + throw new IllegalArgumentException("Illegal title: Must be in 'name (year)' format"); - String name = matcher.group(1).replaceAll("\"", "").trim(); - int year = Integer.parseInt(matcher.group(2)); + String name = matcher.group(1).replaceAll("\"", "").trim(); + int year = Integer.parseInt(matcher.group(2)); - movies.add(new SubtitleSearchResult(Integer.parseInt(imdbid), name, year, null, -1)); - } catch (Exception e) { - Logger.getLogger(OpenSubtitlesXmlRpc.class.getName()).log(Level.FINE, String.format("Ignore movie [%s]: %s", movie, e.getMessage())); + movies.add(new SubtitleSearchResult(Integer.parseInt(imdbid), name, year, null, -1)); + } catch (Exception e) { + Logger.getLogger(OpenSubtitlesXmlRpc.class.getName()).log(Level.FINE, String.format("Ignore movie [%s]: %s", movie, e.getMessage())); + } } - } - return movies; + return movies; + } catch (ClassCastException e) { + // unexpected xmlrpc responses (e.g. error messages instead of results) will trigger this + throw new XmlRpcException("Illegal XMLRPC response on searchMoviesOnIMDB"); + } } public Movie getIMDBMovieDetails(int imdbid) throws XmlRpcFault { diff --git a/source/net/filebot/web/ShooterSubtitles.java b/source/net/filebot/web/ShooterSubtitles.java index 40534504..d834d27e 100644 --- a/source/net/filebot/web/ShooterSubtitles.java +++ b/source/net/filebot/web/ShooterSubtitles.java @@ -1,7 +1,6 @@ package net.filebot.web; import static java.nio.charset.StandardCharsets.*; -import static java.util.Arrays.*; import static java.util.Collections.*; import static java.util.stream.Collectors.*; import static net.filebot.util.FileUtilities.*; @@ -51,6 +50,10 @@ public class ShooterSubtitles implements VideoHashSubtitleService { return ResourceManager.getIcon("search.shooter"); } + public Cache getCache() { + return Cache.getCache(getName(), CacheType.Daily); + } + @Override public Map> getSubtitleList(File[] videoFiles, String languageName) throws Exception { Map> result = new HashMap>(); @@ -86,24 +89,19 @@ public class ShooterSubtitles implements VideoHashSubtitleService { param.put("format", "json"); param.put("lang", LANGUAGE_CHINESE.equals(languageName) ? "Chn" : "Eng"); - Cache cache = Cache.getCache(getName(), CacheType.Daily); - String key = endpoint.toString() + param.toString(); - SubtitleDescriptor[] value = cache.get(key, SubtitleDescriptor[].class); - if (value != null) { - return asList(value); - } - - ByteBuffer post = WebRequest.post(endpoint, param, null); - Object response = readJson(UTF_8.decode(post)); - - String name = getNameWithoutExtension(file.getName()); - // use the first best option and ignore the rest - return streamJsonObjects(response).flatMap(it -> streamJsonObjects(it, "Files")).map(f -> { - String type = getString(f, "Ext"); - String link = getString(f, "Link"); - return new ShooterSubtitleDescriptor(name, type, link, languageName); - }).limit(1).collect(toList()); + return getCache().castList(SubtitleDescriptor.class).computeIf(param.toString(), Cache.isAbsent(), it -> { + ByteBuffer post = WebRequest.post(endpoint, param, null); + Object response = readJson(UTF_8.decode(post)); + + String name = getNameWithoutExtension(file.getName()); + + return streamJsonObjects(response).flatMap(n -> streamJsonObjects(n, "Files")).map(f -> { + String type = getString(f, "Ext"); + String link = getString(f, "Link"); + return new ShooterSubtitleDescriptor(name, type, link, languageName); + }).limit(1).collect(toList()); + }); } @Override diff --git a/test/net/filebot/web/AcoustIDClientTest.java b/test/net/filebot/web/AcoustIDClientTest.java index fa183243..d76200c8 100644 --- a/test/net/filebot/web/AcoustIDClientTest.java +++ b/test/net/filebot/web/AcoustIDClientTest.java @@ -2,8 +2,6 @@ package net.filebot.web; import static org.junit.Assert.*; -import java.io.IOException; - import org.junit.Test; public class AcoustIDClientTest { @@ -23,7 +21,7 @@ public class AcoustIDClientTest { } @Test - public void lookupChinese() throws IOException, InterruptedException { + public void lookupChinese() throws Exception { int duration = 265; String fingerprint = "AQADtJmWRFJCRkGcHXceND_Oquhz1H_xvjg8D8mYIf5-fOpKVE81NOOF5_hb1PrxJLhhRxfCLkNSOh-61Mvh3DJKOcMnG2eOPsmH_4R_I-SPJB-Df0NTB70-vPiDRtKOS3qK-Duhc8mR9-jyoOvhKhyJH-8FE5eOHHoy3BpC5Tieo_kV9LiZ41McHCF9iJmDPFTQPeiYHD5J_Cfy7DBz_IdxrXBRMTyeP9CSLeJQ8glyC18S5imeSHkSPBeavwgfHrqSD7l09Fl2mGMDVzmekAzS_Gi3HPJbIr0VvD2eJD8u-eAPxytyMccTTQ8u5YmR63iG5jm6UG3wJcmFyzFuNEclvcETfcSb4T-aDz0RWoGs5MQlg9mUBXlyodYjbId_lHke4vPxCFuO5-iNJkw-5FseJM9RckFPHJ-kH3USNL_w4i7xpT5iHvlCVOIR5viFJyFK2Yd59DzqHe8wNUfJF1rwakJTZdB_TJkk5Ntx6YOb7MHj40SZh1ERZv3wD3yaohmzC-2DyM_xND_e48-CWx-6H5FC6ApxpUf-4jpyuEo64VLCZsrwHXcWlBcaDdeWI6Zz5D9qQ0wz4WNPPPCYWWgv6OTw7Ugb_Ghihkd4gdKSqBL0hGyCH1q59GjkHaeQJ0fJLEbz2XiOmBu-RIemG55TDmGPJ3i04zouycIZuMrI4Exz480xqvnxhUS68oHKTD7-I1LGLEX7CteFmNGDD3qO6UvQRNSxKsoVXDnurEHzYWIfPKmFWJqJp3OQP4c5Ukqhx0QeY_-OXj1MLozw6AzqJBmOfNCUKslDhOHB40mGR19wHT0RplRwMsQT5VGG_Kh--D2qKEpU4quFc0Z5NIx4fJIXnHjR73COkNCaJEdF0cifE2SkPHiEJj76Y8qzHO27FE-O79hyS8R59HoQRssV6NKRx6i-o2eKP0ednGiq4Ej1oHeGZgqJnzOeCyEzvmh0XCryaLlRSUJ6YjpxHdd04-qE_kVz_EGNOsR84cuFMJNooWIgNzziKw2anUeZ5cYzBbyI3jnCPB90R0L0hFSBJxfmLLPQHF2T4Ql5nD2eWMFtwnWQL8msQF-MfEezC0x34wue48kRktORUIcbB-fhZw-87ArKI8-E5AmD-mieB7dyXKQYXMvxHDkU5T9K8sTTQ1eLPkeYG992xAweQ-eD5lmDUN_xicaX6PiNM1vxw91InGmOv7ior_AXPDueXbiOhlwkHeUV_DF-5D90Fc1zJCMzK8aT45KNV0XzYvJxJccfIZ-RLEdPKcGzDkdPonmWDMcf4WFy_MGTFVoiGp3WRwOfZMd1PDnxJ4GbCc9O5Eeih2jWo2_AKpPxKMTFHVWOhEdo_AmuD89yNJETdEdSHmGcHEezrjFoCZf0w8Lo7PC54M6DT-vwhEcPP4Hzo9uOH98TJH_TIRJzHNaS4-TBz8nRh8GZFz-eG08f9MzRrDu-iMjWC5eG_wjpoQl_zNHx3mh6BT09o1Zg93iKZj0uhSQmH8nyBHl3VHszUM9RytLwJEqKmT96NC-H41eIHzk0PUeYSx_WCE9y4qaGo7KUomk0C9eJ5L-RfUFzodSLJ3goHX3gHHkJPUMuFdfyJHB8hCeSZxH4BE1vVL6CrkmM6lEePGeK_Ei0v8KTw9GRb3gO_YfjLMgn6agYIh3xfIJ2T8jDodR2OAyso8e3bIrhJgyHHzvyKhCjpxE-MUIezeiD5suW4LzxJEfMlEJy4VFCNNeLUjqeJJ6OP8PNwsfTB9dxHUmeXAgzLuHQ4wljfDqahegj4R2JKzlO5fiDkuERJkfiKVHwxB_OHPyH6soEJk07fB9u6CyF5rmCflFwBdyiRHg4IReSBfWDX8GnHGVGNHOE-NCssEjTHFeNplsPdgmqKBea8eiD5jwuBo-SZ6gkfmhk4U6EpmKOPviJUD-S50WVgE911Id9HX3k4AmHG-9fPAneJ-hBjcWjoPzxHI9JhDSx5awQSlGPWg_8bULPHE2VE30oNNNQb7hyTD4aVUYeQUv2Ivzw1AEd7Wge9Ph-4M_xC89uJEusIVyY4cWTRC_-4-hNNI2WSciP5J3BL_Au4UyPKzgaPUN4yAuP0Dw85jqejE6CUNCRZ8OTo-mD58atGJ0jXjjjIxd09gh7hNnx4UkOnYe_4MQDTWJgaauE8Bc-KmgTDQ_6CleKD6Z8Yufxtwh1QcuCfEmGS4rwE_444TniREmOH-_wCP6MO2mDNUouPNEPTUfzqMPZI1_EB1feHDeFkjzCjMygJznuI2dYouXhS3gfhOXxi9Ap2Uj14DyeJFl6sHrwH37wKRm-8HiUJwnOC-UTNFJ1XMwz4eKDr0GbH54kVJWC78GpVfjRHD2SLcmGb0f44SAj5WgfNGOO5j36K_jUo09mNMWDbrbQOEcsLSeS50fPHL9QUceFKhOP4w_cGKGV489FPD0aJTvKP_hE6EmGpkKZH7ri4FRm44o5oZQ5-Jh-ou_RNImCw1GqTYjMo_aDRsuO__gS-CKefQlyKSf4NEdPGmGOP8eZKbjihzh1nJ_QvEa4Q6VC4UqkIz_-oEeYUH3wRR--C10JD7WOMwquhwbPQ9t6Iw1TXMNPnBciZXkC1YiYRSxq-MI35KikzEoCpcrxLNB2NDlyKcPIGH0OH3eE5wglrdB3hOGH6eKEMw725Oh39DN-NP1RMaGHhznu7Ei_ZIWei7iSCnmOZvbQM1zQ78hTo-aA6ROhJWKi49OxJzdi9fgUlL_RNMm644suXEcsJjua69BsfFpKPDrCV4fPIFe-4IknofKNo9O0Q9L4oFauoBzaiD7eG018oZSj44nW4HlCNPFioa2CPMyFUzye5vjR7mgibTitiRh5Yj7aCQAIMEQoACCQQABhCBNGCMGUEcAYYg1AQCAhDDAAAAagAQAQAAh0BmBCiPAMEHOUAAogASCBBAAklFBEEWaEIkQAAAQjQAgAgHHCIASIA0gQQwQASBggBBFKUCMAIFQSBIQERAnCECRWEACEQJIipYABnIEhACECEUAIs8wg4QRCACBmBCAEKAEIAwYpABSACAAECASCCEKgE04oYBRQChgHhABkAUEAEAIwAwAgQFAgFGMUGcIoA0AIARgAyBhAFKIKCEOIAgQZIARARhgggBGUAYiRAUAIRYQEBABAkBAECOMMIgAIhIQBCiCFCHBMEASAAEoACogoCAFGgGUGWIUAMIgRBIAzhgAFFAJEAEIEgAwZoBgAmCFmhKEMGAAUAAYsQgABgChgNAUGAASIgEAYB4gRQABBBGMGCKEAAIwggShwCChkgGIEGQaocoQBoLRBSACOHALEMQAEAkwAYoAkTDkDICEKIUMQAEQEQRRAgBCJACJCIWSAAKwBQYQABEkCBRHAAEUAoAJIgYBQTAkDAAEIIGEEMIsQx4wAwhgiEQFCGAQQA0oY4gUhCgElgEHEOECEUAYhJAQwxBgJJANIUQKEIYIoARgDhhlAHFBIIAmQQRYhoAhhCBgnLCKEKCEQIQEIR4RTCgkkCAKGCmQQQQAQgAQFgBFBCCGSAwAEIcoIoJQEDCHhEDAKKmCREswQohAgiglkACACKgOhMUAhRgwCBAipEFGMAAGEUABYhAhSAiEFoFEQASGAIAAxJQiESDEHgCEISAEQEAAIJwhAShGoBAUAUCaIUAwIgQgzghgggECAKCIcMQoJxYgSwABlhACAMgMAEkwCpCBzhgADGDACWMIEA0YbIQBiQAAgGCFAKCCEJBAAAYwhAGmiCCOOAIEcMwAIggBzjBhHmHeMSCGIEggiAA0jTCHjCABCAAUQIUQJIowQggFkKBEAGCEBBMQgBIARBkGDCCFGCMMMIIAgQBgSSAI"; diff --git a/test/net/filebot/web/OpenSubtitlesXmlRpcTest.java b/test/net/filebot/web/OpenSubtitlesXmlRpcTest.java index 90279c79..39c3d8c7 100644 --- a/test/net/filebot/web/OpenSubtitlesXmlRpcTest.java +++ b/test/net/filebot/web/OpenSubtitlesXmlRpcTest.java @@ -60,7 +60,7 @@ public class OpenSubtitlesXmlRpcTest { @Test public void getSubtitleListEnglish() throws Exception { - List list = xmlrpc.searchSubtitles(361256, -1, -1, "eng"); + List list = xmlrpc.searchSubtitles(singleton(Query.forImdbId(361256, -1, -1, "eng"))); SubtitleDescriptor sample = list.get(0); @@ -73,7 +73,7 @@ public class OpenSubtitlesXmlRpcTest { @Test public void getSubtitleListAllLanguages() throws Exception { - List list = xmlrpc.searchSubtitles(361256, -1, -1); + List list = xmlrpc.searchSubtitles(singleton(Query.forImdbId(361256, -1, -1))); OpenSubtitlesSubtitleDescriptor sample = list.get(75); @@ -176,7 +176,7 @@ public class OpenSubtitlesXmlRpcTest { @Test public void fetchSubtitle() throws Exception { - List list = xmlrpc.searchSubtitles(361256, -1, -1, "eng"); + List list = xmlrpc.searchSubtitles(singleton(Query.forImdbId(361256, -1, -1, "eng"))); // check format assertEquals("srt", list.get(0).getType()); @@ -190,7 +190,7 @@ public class OpenSubtitlesXmlRpcTest { // @Test(expected = IOException.class) public void fetchSubtitlesExceedLimit() throws Exception { - List list = xmlrpc.searchSubtitles(773262, -1, -1, "eng"); + List list = xmlrpc.searchSubtitles(singleton(Query.forImdbId(773262, -1, -1, "eng"))); for (int i = 0; true; i++) { System.out.format("Fetch #%d: %s%n", i, list.get(i).fetch());