From ea6a839aa828c7a7c539354c651016e413097416 Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Sat, 5 Jul 2008 11:37:03 +0000 Subject: [PATCH] * switched back to using List as return value for EpisodeList- and SubtitleClients (lazy XPath evaluation not needed anymore, because we are fast enough anyway) --- .../filebot/ui/AbstractSearchPanel.java | 25 ++-- .../ui/panel/search/FetchEpisodeListTask.java | 2 +- .../filebot/ui/panel/search/SearchPanel.java | 9 +- .../ui/panel/subtitle/LanguageResolver.java | 6 +- .../ui/panel/subtitle/SubtitlePanel.java | 30 ++-- .../sourceforge/filebot/web/AnidbClient.java | 36 ++--- .../filebot/web/EpisodeListClient.java | 7 +- .../net/sourceforge/filebot/web/HtmlUtil.java | 7 +- .../sourceforge/filebot/web/HyperLink.java | 19 ++- .../filebot/web/OpenSubtitlesClient.java | 28 ++-- .../web/OpenSubtitlesSubtitleClient.java | 21 +-- .../filebot/web/SearchResultCache.java | 18 ++- .../filebot/web/SubsceneSubtitleClient.java | 138 +++++++++++------- .../filebot/web/SubtitleClient.java | 18 +-- .../sourceforge/filebot/web/TVRageClient.java | 6 +- .../filebot/web/TvdotcomClient.java | 45 ++---- .../tuned/DefaultProgressIterator.java | 54 ------- .../tuned/DefaultThreadFactory.java | 5 + .../sourceforge/tuned/FunctionIterator.java | 131 ----------------- .../sourceforge/tuned/ProgressIterator.java | 15 -- .../filebot/web/TVRageClientTest.java | 5 +- .../net/sourceforge/tuned/TunedTestSuite.java | 2 +- 22 files changed, 209 insertions(+), 418 deletions(-) delete mode 100644 source/net/sourceforge/tuned/DefaultProgressIterator.java delete mode 100644 source/net/sourceforge/tuned/FunctionIterator.java delete mode 100644 source/net/sourceforge/tuned/ProgressIterator.java diff --git a/source/net/sourceforge/filebot/ui/AbstractSearchPanel.java b/source/net/sourceforge/filebot/ui/AbstractSearchPanel.java index 14a549b0..0fdc1869 100644 --- a/source/net/sourceforge/filebot/ui/AbstractSearchPanel.java +++ b/source/net/sourceforge/filebot/ui/AbstractSearchPanel.java @@ -8,6 +8,7 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.net.URI; +import java.util.Collection; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -30,7 +31,6 @@ import javax.swing.SwingWorker; import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.filebot.web.SearchResult; import net.sourceforge.tuned.ExceptionUtil; -import net.sourceforge.tuned.ProgressIterator; import net.sourceforge.tuned.ui.SelectButtonTextField; import net.sourceforge.tuned.ui.SwingWorkerPropertyChangeAdapter; import net.sourceforge.tuned.ui.TunedUtil; @@ -137,7 +137,7 @@ public abstract class AbstractSearchPanel extends Fi }; - protected abstract class SearchTask extends SwingWorker, Void> { + protected abstract class SearchTask extends SwingWorker, Void> { private final String searchText; private final S client; @@ -153,7 +153,7 @@ public abstract class AbstractSearchPanel extends Fi @Override - protected abstract List doInBackground() throws Exception; + protected abstract Collection doInBackground() throws Exception; public String getSearchText() { @@ -240,13 +240,13 @@ public abstract class AbstractSearchPanel extends Fi private SearchResult selectSearchResult(SearchTask task) throws Exception { - List searchResults = task.get(); + Collection searchResults = task.get(); switch (searchResults.size()) { case 0: return null; case 1: - return searchResults.get(0); + return searchResults.iterator().next(); } // multiple results have been found, user must selected one @@ -288,17 +288,10 @@ public abstract class AbstractSearchPanel extends Fi protected final Void doInBackground() throws Exception { long start = System.currentTimeMillis(); - ProgressIterator iterator = fetch(); + Collection results = fetch(); - while (!isCancelled() && iterator.hasNext()) { - - try { - publish(iterator.next()); - } catch (Exception e) { - Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, e.getMessage()); - } - - setProgress((iterator.getPosition() * 100) / iterator.getLength()); + for (E result : results) { + publish(result); count++; } @@ -308,7 +301,7 @@ public abstract class AbstractSearchPanel extends Fi } - protected abstract ProgressIterator fetch() throws Exception; + protected abstract Collection fetch() throws Exception; @Override diff --git a/source/net/sourceforge/filebot/ui/panel/search/FetchEpisodeListTask.java b/source/net/sourceforge/filebot/ui/panel/search/FetchEpisodeListTask.java index 549602af..541b083e 100644 --- a/source/net/sourceforge/filebot/ui/panel/search/FetchEpisodeListTask.java +++ b/source/net/sourceforge/filebot/ui/panel/search/FetchEpisodeListTask.java @@ -33,7 +33,7 @@ class FetchEpisodeListTask extends SwingWorker, Void> { protected List doInBackground() throws Exception { long start = System.currentTimeMillis(); - Iterator itr = searchEngine.getEpisodeList(searchResult, numberOfSeason); + Iterator itr = searchEngine.getEpisodeList(searchResult, numberOfSeason).iterator(); ArrayList list = new ArrayList(); diff --git a/source/net/sourceforge/filebot/ui/panel/search/SearchPanel.java b/source/net/sourceforge/filebot/ui/panel/search/SearchPanel.java index 2a808a68..e6a0cd7a 100644 --- a/source/net/sourceforge/filebot/ui/panel/search/SearchPanel.java +++ b/source/net/sourceforge/filebot/ui/panel/search/SearchPanel.java @@ -11,7 +11,6 @@ import java.beans.PropertyChangeListener; import java.net.URI; import java.text.NumberFormat; import java.util.Collection; -import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; @@ -185,7 +184,7 @@ public class SearchPanel extends FileBotPanel { }; - private class SearchTask extends SwingWorker, Void> { + private class SearchTask extends SwingWorker, Void> { private final String query; private final EpisodeListClient client; @@ -200,7 +199,7 @@ public class SearchPanel extends FileBotPanel { @Override - protected List doInBackground() throws Exception { + protected Collection doInBackground() throws Exception { return client.search(query); } @@ -242,7 +241,7 @@ public class SearchPanel extends FileBotPanel { SearchTask task = (SearchTask) evt.getSource(); - List searchResults; + Collection searchResults; try { searchResults = task.get(); @@ -268,7 +267,7 @@ public class SearchPanel extends FileBotPanel { if (searchResults.size() == 1) { // only one show found, select this one - selectedResult = searchResults.get(0); + selectedResult = searchResults.iterator().next(); } else if (searchResults.size() > 1) { // multiple shows found, let user selected one Window window = SwingUtilities.getWindowAncestor(SearchPanel.this); diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/LanguageResolver.java b/source/net/sourceforge/filebot/ui/panel/subtitle/LanguageResolver.java index f7da2813..9af7e0e1 100644 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/LanguageResolver.java +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/LanguageResolver.java @@ -16,7 +16,7 @@ public class LanguageResolver { return defaultInstance; } - private final Map localeMap = new HashMap(); + private final Map cache = new HashMap(); /** @@ -28,11 +28,11 @@ public class LanguageResolver { public synchronized Locale getLocale(String languageName) { languageName = languageName.toLowerCase(); - Locale locale = localeMap.get(languageName); + Locale locale = cache.get(languageName); if (locale == null) { locale = findLocale(languageName); - localeMap.put(languageName, locale); + cache.put(languageName, locale); } return locale; diff --git a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java index 4b2968da..a72d5d9e 100644 --- a/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java +++ b/source/net/sourceforge/filebot/ui/panel/subtitle/SubtitlePanel.java @@ -3,7 +3,10 @@ package net.sourceforge.filebot.ui.panel.subtitle; import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Locale; import net.sourceforge.filebot.ListChangeSynchronizer; import net.sourceforge.filebot.Settings; @@ -13,9 +16,6 @@ import net.sourceforge.filebot.ui.SelectDialog; import net.sourceforge.filebot.web.SearchResult; import net.sourceforge.filebot.web.SubtitleClient; import net.sourceforge.filebot.web.SubtitleDescriptor; -import net.sourceforge.tuned.FunctionIterator; -import net.sourceforge.tuned.ProgressIterator; -import net.sourceforge.tuned.FunctionIterator.Function; import net.sourceforge.tuned.ui.SimpleIconProvider; @@ -72,7 +72,7 @@ public class SubtitlePanel extends AbstractSearchPanel doInBackground() throws Exception { + protected Collection doInBackground() throws Exception { return getClient().search(getSearchText()); } @@ -87,10 +87,16 @@ public class SubtitlePanel extends AbstractSearchPanel fetch() throws Exception { - ProgressIterator descriptors = getClient().getSubtitleList(getSearchResult()); + protected Collection fetch() throws Exception { + //TODO language combobox + Collection descriptors = getClient().getSubtitleList(getSearchResult(), Locale.ENGLISH); + ArrayList packages = new ArrayList(); - return new FunctionIterator(descriptors, new SubtitlePackageFunction()); + for (SubtitleDescriptor descriptor : descriptors) { + packages.add(new SubtitlePackage(descriptor)); + } + + return packages; } @@ -109,14 +115,4 @@ public class SubtitlePanel extends AbstractSearchPanel { - - @Override - public SubtitlePackage evaluate(SubtitleDescriptor sourceValue) { - return new SubtitlePackage(sourceValue); - } - - } - } diff --git a/source/net/sourceforge/filebot/web/AnidbClient.java b/source/net/sourceforge/filebot/web/AnidbClient.java index 4894851d..cceb8716 100644 --- a/source/net/sourceforge/filebot/web/AnidbClient.java +++ b/source/net/sourceforge/filebot/web/AnidbClient.java @@ -17,10 +17,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import net.sourceforge.filebot.resources.ResourceManager; -import net.sourceforge.tuned.FunctionIterator; -import net.sourceforge.tuned.ProgressIterator; import net.sourceforge.tuned.XPathUtil; -import net.sourceforge.tuned.FunctionIterator.Function; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -88,33 +85,19 @@ public class AnidbClient extends EpisodeListClient { @Override - public ProgressIterator getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException { + public List getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException { Document dom = HtmlUtil.getHtmlDocument(getEpisodeListLink(searchResult, season)); List nodes = XPathUtil.selectNodes("id('eplist')//TR/TD/SPAN/ancestor::TR", dom); - return new FunctionIterator(nodes, new EpisodeFunction(searchResult, nodes.size())); - } - - - private static class EpisodeFunction implements Function { + NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH); + numberFormat.setMinimumIntegerDigits(Math.max(Integer.toString(nodes.size()).length(), 2)); + numberFormat.setGroupingUsed(false); - private final SearchResult searchResult; - private final NumberFormat numberFormat; + ArrayList episodes = new ArrayList(nodes.size()); - - public EpisodeFunction(SearchResult searchResult, int nodeCount) { - this.searchResult = searchResult; - - numberFormat = NumberFormat.getInstance(Locale.ENGLISH); - numberFormat.setMinimumIntegerDigits(Math.max(Integer.toString(nodeCount).length(), 2)); - numberFormat.setGroupingUsed(false); - } - - - @Override - public Episode evaluate(Node node) { + for (Node node : nodes) { String number = XPathUtil.selectString("./TD[contains(@class,'id')]/A", node); String title = XPathUtil.selectString("./TD[@class='title']/LABEL/text()", node); @@ -129,15 +112,16 @@ public class AnidbClient extends EpisodeListClient { } // no seasons for anime - return new Episode(searchResult.getName(), null, number, title); + episodes.add(new Episode(searchResult.getName(), null, number, title)); } + return episodes; } - + @Override public URI getEpisodeListLink(SearchResult searchResult, int season) { - return ((HyperLink) searchResult).getUri(); + return ((HyperLink) searchResult).toUri(); } diff --git a/source/net/sourceforge/filebot/web/EpisodeListClient.java b/source/net/sourceforge/filebot/web/EpisodeListClient.java index 68979dd5..2c21244a 100644 --- a/source/net/sourceforge/filebot/web/EpisodeListClient.java +++ b/source/net/sourceforge/filebot/web/EpisodeListClient.java @@ -4,13 +4,12 @@ package net.sourceforge.filebot.web; import java.net.URI; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import javax.swing.ImageIcon; -import net.sourceforge.tuned.ProgressIterator; - public abstract class EpisodeListClient { @@ -41,10 +40,10 @@ public abstract class EpisodeListClient { } - public abstract List search(String searchterm) throws Exception; + public abstract Collection search(String searchterm) throws Exception; - public abstract ProgressIterator getEpisodeList(SearchResult searchResult, int season) throws Exception; + public abstract Collection getEpisodeList(SearchResult searchResult, int season) throws Exception; public abstract URI getEpisodeListLink(SearchResult searchResult, int season); diff --git a/source/net/sourceforge/filebot/web/HtmlUtil.java b/source/net/sourceforge/filebot/web/HtmlUtil.java index 1efb5fc4..42359fc8 100644 --- a/source/net/sourceforge/filebot/web/HtmlUtil.java +++ b/source/net/sourceforge/filebot/web/HtmlUtil.java @@ -52,8 +52,11 @@ public class HtmlUtil { public static Document getHtmlDocument(URL url) throws IOException, SAXException { - URLConnection connection = url.openConnection(); - + return getHtmlDocument(url.openConnection()); + } + + + public static Document getHtmlDocument(URLConnection connection) throws IOException, SAXException { Charset charset = getCharset(connection.getContentType()); String encoding = connection.getContentEncoding(); InputStream inputStream = connection.getInputStream(); diff --git a/source/net/sourceforge/filebot/web/HyperLink.java b/source/net/sourceforge/filebot/web/HyperLink.java index 8b5c8ff3..d145b593 100644 --- a/source/net/sourceforge/filebot/web/HyperLink.java +++ b/source/net/sourceforge/filebot/web/HyperLink.java @@ -8,23 +8,22 @@ import java.net.URL; public class HyperLink extends SearchResult { - private final URI uri; + private final URL url; - public HyperLink(String name, URI uri) { - super(name); - this.uri = uri; - } - - public HyperLink(String name, URL url) { super(name); - this.uri = URI.create(url.toString()); + this.url = url; } - public URI getUri() { - return uri; + public URL getUrl() { + return url; + } + + + public URI toUri() { + return URI.create(url.toString()); } } diff --git a/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java b/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java index 28a8c454..ff480bf2 100644 --- a/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesClient.java @@ -4,8 +4,10 @@ package net.sourceforge.filebot.web; import java.net.MalformedURLException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; @@ -155,20 +157,18 @@ public class OpenSubtitlesClient { @SuppressWarnings("unchecked") - public List searchSubtitles(int... imdbidArray) throws XmlRpcFault { + public List searchSubtitles(int imdbid, Locale language) throws XmlRpcFault { - List> imdbidList = new ArrayList>(imdbidArray.length); + Map searchListEntry = new HashMap(2); - for (int imdbid : imdbidArray) { - Map map = new HashMap(1); - - // pad id with zeros - map.put("imdbid", String.format("%07d", imdbid)); - - imdbidList.add(map); - } + // pad imdbId with zeros + //TODO needed??? + searchListEntry.put("imdbid", String.format("%07d", imdbid)); + searchListEntry.put("sublanguageid", getSubLanguageID(language)); - Map>> response = (Map>>) invoke("SearchSubtitles", token, imdbidList); + List> searchList = Collections.singletonList(searchListEntry); + + Map>> response = (Map>>) invoke("SearchSubtitles", token, searchList); ArrayList subs = new ArrayList(); @@ -184,6 +184,12 @@ public class OpenSubtitlesClient { } + private String getSubLanguageID(Locale locale) { + //TODO test if sublanguageid is really ISO3 language code + return locale.getISO3Language(); + } + + @SuppressWarnings("unchecked") public List searchMoviesOnIMDB(String query) throws XmlRpcFault { diff --git a/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleClient.java b/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleClient.java index 8ae08f77..f823eb4f 100644 --- a/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleClient.java +++ b/source/net/sourceforge/filebot/web/OpenSubtitlesSubtitleClient.java @@ -3,7 +3,9 @@ package net.sourceforge.filebot.web; import java.net.URI; +import java.util.Collection; import java.util.List; +import java.util.Locale; import java.util.Timer; import java.util.TimerTask; import java.util.logging.Level; @@ -11,9 +13,6 @@ import java.util.logging.Logger; import net.sourceforge.filebot.Settings; import net.sourceforge.filebot.resources.ResourceManager; -import net.sourceforge.tuned.FunctionIterator; -import net.sourceforge.tuned.ProgressIterator; -import net.sourceforge.tuned.FunctionIterator.Function; /** @@ -44,15 +43,14 @@ public class OpenSubtitlesSubtitleClient extends SubtitleClient { } + @SuppressWarnings("unchecked") @Override - public ProgressIterator getSubtitleList(SearchResult searchResult) throws Exception { + public Collection getSubtitleList(SearchResult searchResult, Locale language) throws Exception { login(); int imdbId = ((MovieDescriptor) searchResult).getImdbId(); - List subtitles = client.searchSubtitles(imdbId); - - return new FunctionIterator(subtitles, new SubtitleFunction()); + return (Collection) client.searchSubtitles(imdbId, language); } @@ -135,13 +133,4 @@ public class OpenSubtitlesSubtitleClient extends SubtitleClient { }; } - - private static class SubtitleFunction implements Function { - - @Override - public SubtitleDescriptor evaluate(OpenSubtitlesSubtitleDescriptor sourceValue) { - return sourceValue; - } - } - } diff --git a/source/net/sourceforge/filebot/web/SearchResultCache.java b/source/net/sourceforge/filebot/web/SearchResultCache.java index a7db6bbb..8a5c4d4a 100644 --- a/source/net/sourceforge/filebot/web/SearchResultCache.java +++ b/source/net/sourceforge/filebot/web/SearchResultCache.java @@ -2,28 +2,26 @@ package net.sourceforge.filebot.web; -import java.util.Collections; -import java.util.Map; -import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; public class SearchResultCache { - private final Map cache = Collections.synchronizedMap(new TreeMap(String.CASE_INSENSITIVE_ORDER)); + private final ConcurrentHashMap cache = new ConcurrentHashMap(); public boolean containsKey(String name) { - return cache.containsKey(name); + return cache.containsKey(key(name)); } public SearchResult get(String name) { - return cache.get(name); + return cache.get(key(name)); } public void add(SearchResult searchResult) { - cache.put(searchResult.getName(), searchResult); + cache.putIfAbsent(key(searchResult.getName()), searchResult); } @@ -32,4 +30,10 @@ public class SearchResultCache { add(searchResult); } } + + + private String key(String name) { + return name.toLowerCase(); + } + } diff --git a/source/net/sourceforge/filebot/web/SubsceneSubtitleClient.java b/source/net/sourceforge/filebot/web/SubsceneSubtitleClient.java index a671f90a..d726a95e 100644 --- a/source/net/sourceforge/filebot/web/SubsceneSubtitleClient.java +++ b/source/net/sourceforge/filebot/web/SubsceneSubtitleClient.java @@ -7,10 +7,13 @@ import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; +import java.net.URLConnection; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Locale; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; @@ -18,10 +21,7 @@ import java.util.regex.Pattern; import net.sourceforge.filebot.resources.ResourceManager; import net.sourceforge.tuned.FileUtil; -import net.sourceforge.tuned.FunctionIterator; -import net.sourceforge.tuned.ProgressIterator; import net.sourceforge.tuned.XPathUtil; -import net.sourceforge.tuned.FunctionIterator.Function; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -70,69 +70,105 @@ public class SubsceneSubtitleClient extends SubtitleClient { return searchResults; } + HashMap languageIdCache; + + + public String getLanguageID(Locale language) { + return languageIdCache.get(language.getDisplayLanguage(Locale.ENGLISH).toLowerCase()); + } + @Override - public ProgressIterator getSubtitleList(SearchResult searchResult) throws Exception { + public List getSubtitleList(SearchResult searchResult, Locale language) throws Exception { + URL url = getSubtitleListLink(searchResult).toURL(); - Document dom = HtmlUtil.getHtmlDocument(url); + Document dom = null; + + if (languageIdCache != null) { + URLConnection connection = url.openConnection(); + + if (language != null && language != Locale.ROOT) { + System.out.println(getLanguageID(language)); + connection.addRequestProperty("Cookie", "subscene_sLanguageIds=" + getLanguageID(language)); + } + + dom = HtmlUtil.getHtmlDocument(connection); + } else { + URLConnection connection = url.openConnection(); + + dom = HtmlUtil.getHtmlDocument(connection); + + List nodes = XPathUtil.selectNodes("//DIV[@class='languageList']/DIV", dom); + + Pattern onClickPattern = Pattern.compile("selectLanguage\\((\\d+)\\);"); + + languageIdCache = new HashMap(); + + for (Node node : nodes) { + Matcher matcher = onClickPattern.matcher(XPathUtil.selectString("./INPUT/@onclick", node)); + + if (matcher.matches()) { + String name = XPathUtil.selectString("./LABEL/text()", node); + String id = matcher.group(1); + + //TODO sysout + System.out.println(name + " = " + id); + + languageIdCache.put(name.toLowerCase(), id); + } + } + } List nodes = XPathUtil.selectNodes("//TABLE[@class='filmSubtitleList']//A[@id]//ancestor::TR", dom); - return new FunctionIterator(nodes, new SubtitleFunction(url)); + Pattern hrefPattern = Pattern.compile("javascript:Subtitle\\((\\d+), '(\\w+)', '\\d+', '(\\d+)'\\);"); + + ArrayList subtitles = new ArrayList(nodes.size()); + + for (Node node : nodes) { + try { + Node linkNode = XPathUtil.selectFirstNode("./TD[1]/A", node); + + String lang = XPathUtil.selectString("./SPAN[1]", linkNode); + + String href = XPathUtil.selectString("@href", linkNode); + + String name = XPathUtil.selectString("./SPAN[2]", linkNode); + + String author = XPathUtil.selectString("./TD[4]", node); + + Matcher matcher = hrefPattern.matcher(href); + + if (!matcher.matches()) + throw new IllegalArgumentException("Cannot extract download parameters: " + href); + + String subtitleId = matcher.group(1); + String typeId = matcher.group(2); + + URL downloadUrl = getDownloadUrl(url, subtitleId, typeId); + + subtitles.add(new SubsceneSubtitleDescriptor(name, lang, author, typeId, downloadUrl, url)); + } catch (Exception e) { + Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Cannot parse subtitle node", e); + } + } + + return subtitles; } - - private static class SubtitleFunction implements Function { - - private final Pattern hrefPattern = Pattern.compile("javascript:Subtitle\\((\\d+), '(\\w+)', '0', '(\\d+)'\\);"); - - private final URL url; - - - public SubtitleFunction(URL url) { - this.url = url; - } - - @Override - public SubtitleDescriptor evaluate(Node node) throws Exception { - Node linkNode = XPathUtil.selectFirstNode("./TD[1]/A", node); - - String href = XPathUtil.selectString("@href", linkNode); - - String lang = XPathUtil.selectString("./SPAN[1]", linkNode); - String name = XPathUtil.selectString("./SPAN[2]", linkNode); - - String author = XPathUtil.selectString("./TD[4]", node); - - Matcher matcher = hrefPattern.matcher(href); - - if (!matcher.matches()) - throw new IllegalArgumentException("Cannot extract download parameters: " + href); - - String subtitleId = matcher.group(1); - String typeId = matcher.group(2); - - URL downloadUrl = getDownloadUrl(url, subtitleId, typeId); - - return new SubsceneSubtitleDescriptor(name, lang, author, typeId, downloadUrl, url); - } - - - private URL getDownloadUrl(URL referer, String subtitleId, String typeId) throws MalformedURLException { - String basePath = FileUtil.getNameWithoutExtension(referer.getFile()); - String path = String.format("%s-dlpath-%s/%s.zipx", basePath, subtitleId, typeId); - - return new URL(referer.getProtocol(), referer.getHost(), path); - } + private URL getDownloadUrl(URL referer, String subtitleId, String typeId) throws MalformedURLException { + String basePath = FileUtil.getNameWithoutExtension(referer.getFile()); + String path = String.format("%s-dlpath-%s/%s.zipx", basePath, subtitleId, typeId); + return new URL(referer.getProtocol(), referer.getHost(), path); } - + @Override public URI getSubtitleListLink(SearchResult searchResult) { - return ((HyperLink) searchResult).getUri(); + return ((HyperLink) searchResult).toUri(); } diff --git a/source/net/sourceforge/filebot/web/SubtitleClient.java b/source/net/sourceforge/filebot/web/SubtitleClient.java index 6ca780ee..b0a58bbc 100644 --- a/source/net/sourceforge/filebot/web/SubtitleClient.java +++ b/source/net/sourceforge/filebot/web/SubtitleClient.java @@ -4,12 +4,12 @@ package net.sourceforge.filebot.web; import java.net.URI; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Locale; -import javax.swing.ImageIcon; - -import net.sourceforge.tuned.ProgressIterator; +import javax.swing.Icon; public abstract class SubtitleClient { @@ -28,20 +28,20 @@ public abstract class SubtitleClient { return Collections.unmodifiableList(registry); } - private String name; - private ImageIcon icon; + private final String name; + private final Icon icon; - public SubtitleClient(String name, ImageIcon icon) { + public SubtitleClient(String name, Icon icon) { this.name = name; this.icon = icon; } - public abstract List search(String searchterm) throws Exception; + public abstract Collection search(String searchterm) throws Exception; - public abstract ProgressIterator getSubtitleList(SearchResult searchResult) throws Exception; + public abstract Collection getSubtitleList(SearchResult searchResult, Locale language) throws Exception; public abstract URI getSubtitleListLink(SearchResult searchResult); @@ -52,7 +52,7 @@ public abstract class SubtitleClient { } - public ImageIcon getIcon() { + public Icon getIcon() { return icon; } diff --git a/source/net/sourceforge/filebot/web/TVRageClient.java b/source/net/sourceforge/filebot/web/TVRageClient.java index d14df243..d2e8c850 100644 --- a/source/net/sourceforge/filebot/web/TVRageClient.java +++ b/source/net/sourceforge/filebot/web/TVRageClient.java @@ -13,8 +13,6 @@ import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import net.sourceforge.filebot.resources.ResourceManager; -import net.sourceforge.tuned.DefaultProgressIterator; -import net.sourceforge.tuned.ProgressIterator; import net.sourceforge.tuned.XPathUtil; import org.w3c.dom.Document; @@ -63,7 +61,7 @@ public class TVRageClient extends EpisodeListClient { @Override - public ProgressIterator getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException, ParserConfigurationException { + public List getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException, ParserConfigurationException { int showId = ((TVRageSearchResult) searchResult).getShowId(); String episodeListUri = String.format("http://" + host + "/feeds/episode_list.php?sid=" + showId); @@ -95,7 +93,7 @@ public class TVRageClient extends EpisodeListClient { } } - return new DefaultProgressIterator(episodes); + return episodes; } diff --git a/source/net/sourceforge/filebot/web/TvdotcomClient.java b/source/net/sourceforge/filebot/web/TvdotcomClient.java index cf2e3f03..d605d060 100644 --- a/source/net/sourceforge/filebot/web/TvdotcomClient.java +++ b/source/net/sourceforge/filebot/web/TvdotcomClient.java @@ -18,10 +18,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import net.sourceforge.filebot.resources.ResourceManager; -import net.sourceforge.tuned.FunctionIterator; -import net.sourceforge.tuned.ProgressIterator; import net.sourceforge.tuned.XPathUtil; -import net.sourceforge.tuned.FunctionIterator.Function; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -77,39 +74,22 @@ public class TvdotcomClient extends EpisodeListClient { @Override - public ProgressIterator getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException { + public List getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException { Document dom = HtmlUtil.getHtmlDocument(getEpisodeListLink(searchResult, season)); List nodes = XPathUtil.selectNodes("id('episode-listing')/DIV/TABLE/TR/TD/ancestor::TR", dom); - return new FunctionIterator(nodes, new EpisodeFunction(searchResult, season, nodes.size())); - } - - - private static class EpisodeFunction implements Function { + NumberFormat numberFormat = NumberFormat.getInstance(Locale.ENGLISH); + numberFormat.setMinimumIntegerDigits(Math.max(Integer.toString(nodes.size()).length(), 2)); + numberFormat.setGroupingUsed(false); - private final SearchResult searchResult; - private final NumberFormat numberFormat; + Integer episodeOffset = null; + String seasonString = (season >= 1) ? Integer.toString(season) : null; - private Integer episodeOffset = null; - private String seasonString = null; + ArrayList episodes = new ArrayList(nodes.size()); - - public EpisodeFunction(SearchResult searchResult, int season, int nodeCount) { - this.searchResult = searchResult; - - numberFormat = NumberFormat.getInstance(Locale.ENGLISH); - numberFormat.setMinimumIntegerDigits(Math.max(Integer.toString(nodeCount).length(), 2)); - numberFormat.setGroupingUsed(false); - - if (season >= 1) - seasonString = Integer.toString(season); - } - - - @Override - public Episode evaluate(Node node) { + for (Node node : nodes) { String episodeNumber = XPathUtil.selectString("./TD[1]", node); String title = XPathUtil.selectString("./TD[2]/A", node); @@ -125,16 +105,17 @@ public class TvdotcomClient extends EpisodeListClient { // episode number may be "Pilot", "Special", ... } - return new Episode(searchResult.getName(), seasonString, episodeNumber, title); + episodes.add(new Episode(searchResult.getName(), seasonString, episodeNumber, title)); } + + return episodes; } - + @Override public URI getEpisodeListLink(SearchResult searchResult, int season) { - String summaryFile = null; - summaryFile = ((HyperLink) searchResult).getUri().getPath(); + String summaryFile = ((HyperLink) searchResult).getUrl().getPath(); String base = summaryFile.substring(0, summaryFile.indexOf("summary.html")); String file = base + "episode_listings.html"; diff --git a/source/net/sourceforge/tuned/DefaultProgressIterator.java b/source/net/sourceforge/tuned/DefaultProgressIterator.java deleted file mode 100644 index 64d0bb53..00000000 --- a/source/net/sourceforge/tuned/DefaultProgressIterator.java +++ /dev/null @@ -1,54 +0,0 @@ - -package net.sourceforge.tuned; - - -import java.util.Collection; -import java.util.Iterator; - - -public class DefaultProgressIterator implements ProgressIterator { - - private final Iterator sourceIterator; - private final int length; - - private int position = 0; - - - public DefaultProgressIterator(Collection source) { - this.sourceIterator = source.iterator(); - this.length = source.size(); - } - - - @Override - public int getLength() { - return length; - } - - - @Override - public int getPosition() { - return position; - } - - - @Override - public boolean hasNext() { - return sourceIterator.hasNext(); - } - - - @Override - public E next() { - position++; - return sourceIterator.next(); - } - - - @Override - public void remove() { - // TODO Auto-generated method stub - - } - -} diff --git a/source/net/sourceforge/tuned/DefaultThreadFactory.java b/source/net/sourceforge/tuned/DefaultThreadFactory.java index 8a334a6e..b6dd5185 100644 --- a/source/net/sourceforge/tuned/DefaultThreadFactory.java +++ b/source/net/sourceforge/tuned/DefaultThreadFactory.java @@ -15,6 +15,11 @@ public class DefaultThreadFactory implements ThreadFactory { private final boolean daemon; + public DefaultThreadFactory(String name) { + this(name, Thread.NORM_PRIORITY); + } + + public DefaultThreadFactory(String name, int priority) { this(name, priority, false); } diff --git a/source/net/sourceforge/tuned/FunctionIterator.java b/source/net/sourceforge/tuned/FunctionIterator.java deleted file mode 100644 index 223c89b8..00000000 --- a/source/net/sourceforge/tuned/FunctionIterator.java +++ /dev/null @@ -1,131 +0,0 @@ - -package net.sourceforge.tuned; - - -import java.util.Collection; -import java.util.Iterator; -import java.util.NoSuchElementException; - - -public class FunctionIterator implements ProgressIterator { - - /** - * A Function transforms one Object into another. - * - * @param type of source Objects - * @param type Objects are transformed into - */ - public static interface Function { - - /** - * Transform the given sourceValue into any kind of Object. - * - * @param sourceValue - the Object to transform - * @return the transformed version of the object - */ - public T evaluate(S sourceValue) throws Exception; - } - - private final Iterator sourceIterator; - private final Function function; - private final int length; - - private int position = 0; - - - public FunctionIterator(Collection source, Function function) { - this(source.iterator(), source.size(), function); - } - - - //TODO TEST case!!! for piped functions -> correct progress - public FunctionIterator(ProgressIterator iterator, Function function) { - this(iterator, iterator.getLength(), function); - } - - - public FunctionIterator(Iterator iterator, int length, Function function) { - this.sourceIterator = iterator; - this.length = length; - this.function = function; - } - - - @Override - public boolean hasNext() { - try { - return peekNext() != null; - } catch (Exception e) { - return true; - } - } - - - @Override - public T next() { - if (!hasNext()) - throw new NoSuchElementException(); - - try { - return peekNext(); - } finally { - cache = null; - currentException = null; - } - } - - private T cache = null; - private RuntimeException currentException = null; - - - private T peekNext() { - while (cache == null && (sourceIterator.hasNext() || currentException != null)) { - if (currentException != null) - throw currentException; - - try { - cache = transform(sourceIterator.next()); - } catch (Exception e) { - currentException = ExceptionUtil.asRuntimeException(e); - } - - position++; - } - - return cache; - } - - - private T transform(S sourceValue) throws Exception { - return function.evaluate(sourceValue); - } - - - @Override - public int getPosition() { - if (sourceIterator instanceof FunctionIterator) { - return ((ProgressIterator) sourceIterator).getPosition(); - } - - return position; - } - - - @Override - public int getLength() { - return length; - } - - - /** - * The remove operation is not supported by this implementation of Iterator. - * - * @throws UnsupportedOperationException if this method is invoked. - * @see java.util.Iterator - */ - @Override - public void remove() { - throw new UnsupportedOperationException(); - } - -} diff --git a/source/net/sourceforge/tuned/ProgressIterator.java b/source/net/sourceforge/tuned/ProgressIterator.java deleted file mode 100644 index 4abbf254..00000000 --- a/source/net/sourceforge/tuned/ProgressIterator.java +++ /dev/null @@ -1,15 +0,0 @@ - -package net.sourceforge.tuned; - - -import java.util.Iterator; - - -public interface ProgressIterator extends Iterator { - - public int getPosition(); - - - public int getLength(); - -} diff --git a/test/net/sourceforge/filebot/web/TVRageClientTest.java b/test/net/sourceforge/filebot/web/TVRageClientTest.java index 1dfa9355..8ca84026 100644 --- a/test/net/sourceforge/filebot/web/TVRageClientTest.java +++ b/test/net/sourceforge/filebot/web/TVRageClientTest.java @@ -7,7 +7,6 @@ import static org.junit.Assert.assertEquals; import java.util.List; import net.sourceforge.filebot.web.TVRageClient.TVRageSearchResult; -import net.sourceforge.tuned.TestUtil; import org.junit.Test; @@ -32,7 +31,7 @@ public class TVRageClientTest { @Test public void getEpisodeList() throws Exception { - List list = TestUtil.asList(tvrage.getEpisodeList(testResult, 7)); + List list = tvrage.getEpisodeList(testResult, 7); Episode chosen = list.get(21); @@ -45,7 +44,7 @@ public class TVRageClientTest { @Test public void getEpisodeListAll() throws Exception { - List list = TestUtil.asList(tvrage.getEpisodeList(testResult, 0)); + List list = tvrage.getEpisodeList(testResult, 0); assertEquals(145, list.size()); diff --git a/test/net/sourceforge/tuned/TunedTestSuite.java b/test/net/sourceforge/tuned/TunedTestSuite.java index f9596dbe..c32e0d7d 100644 --- a/test/net/sourceforge/tuned/TunedTestSuite.java +++ b/test/net/sourceforge/tuned/TunedTestSuite.java @@ -11,7 +11,7 @@ import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses( { FunctionIteratorTest.class, PreferencesMapTest.class, PreferencesListTest.class }) +@SuiteClasses( { PreferencesMapTest.class, PreferencesListTest.class }) public class TunedTestSuite { public static Test suite() {