From 2b4218ffce5a1e2becb7afdc839128acdf9887a4 Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Sat, 21 Jun 2008 23:31:19 +0000 Subject: [PATCH] * TVRageClient uses the xml feeds now * some testcases --- .../sourceforge/filebot/web/TVRageClient.java | 153 ++++++++---------- .../tuned/DefaultProgressIterator.java | 54 +++++++ source/net/sourceforge/tuned/XPathUtil.java | 5 + .../filebot/web/TVRageClientTest.java | 73 +++++++++ test/net/sourceforge/tuned/TestUtil.java | 12 ++ 5 files changed, 209 insertions(+), 88 deletions(-) create mode 100644 source/net/sourceforge/tuned/DefaultProgressIterator.java create mode 100644 test/net/sourceforge/filebot/web/TVRageClientTest.java diff --git a/source/net/sourceforge/filebot/web/TVRageClient.java b/source/net/sourceforge/filebot/web/TVRageClient.java index 4f3513eb..ba6bdea0 100644 --- a/source/net/sourceforge/filebot/web/TVRageClient.java +++ b/source/net/sourceforge/filebot/web/TVRageClient.java @@ -3,25 +3,19 @@ package net.sourceforge.filebot.web; import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.MalformedURLException; import java.net.URI; -import java.net.URISyntaxException; -import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.regex.Matcher; -import java.util.regex.Pattern; + +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; import net.sourceforge.filebot.resources.ResourceManager; -import net.sourceforge.tuned.FunctionIterator; +import net.sourceforge.tuned.DefaultProgressIterator; 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; @@ -41,28 +35,25 @@ public class TVRageClient extends EpisodeListClient { @Override - public List search(String searchterm) throws IOException, SAXException { + public List search(String searchterm) throws SAXException, IOException, ParserConfigurationException { if (cache.containsKey(searchterm)) { return Collections.singletonList(cache.get(searchterm)); } - Document dom = HtmlUtil.getHtmlDocument(getSearchUrl(searchterm)); + String searchUri = String.format("http://" + host + "/feeds/search.php?show=" + URLEncoder.encode(searchterm, "UTF-8")); - List nodes = XPathUtil.selectNodes("id('search_begin')/TABLE[1]/*/TR/TD/A[1]", dom); + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(searchUri); + + List nodes = XPathUtil.selectNodes("Results/show", dom); List searchResults = new ArrayList(nodes.size()); for (Node node : nodes) { - String href = XPathUtil.selectString("@href", node); - String title = XPathUtil.selectString(".", node); + String showid = XPathUtil.selectString("showid", node); + String name = XPathUtil.selectString("name", node); + String link = XPathUtil.selectString("link", node); - try { - URL url = new URL(href); - - searchResults.add(new HyperLink(title, url)); - } catch (MalformedURLException e) { - Logger.getLogger(Logger.GLOBAL_LOGGER_NAME).log(Level.WARNING, "Invalid href: " + href, e); - } + searchResults.add(new TVRageSearchResult(name, showid, link)); } cache.addAll(searchResults); @@ -72,87 +63,73 @@ public class TVRageClient extends EpisodeListClient { @Override - public ProgressIterator getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException { + public ProgressIterator getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException, ParserConfigurationException { - Document dom = HtmlUtil.getHtmlDocument(getEpisodeListLink(searchResult, season)); + String showId = ((TVRageSearchResult) searchResult).getShowId(); + String episodeListUri = String.format("http://" + host + "/feeds/episode_list.php?sid=" + showId); - List nodes = XPathUtil.selectNodes("//TABLE[@class='b']//TR[@id='brow']", dom); + Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(episodeListUri); - return new FunctionIterator(nodes, new EpisodeFunction(searchResult, season)); - } - - - private static class EpisodeFunction implements Function { + int numberOfSeasons = XPathUtil.selectInteger("Show/totalseasons", dom); - private final SearchResult searchResult; - private final int season; + if (season > numberOfSeasons) + throw new IllegalArgumentException(String.format("%s only has %d seasons", searchResult.getName(), numberOfSeasons)); + Node episodeListNode = XPathUtil.selectNode("Show/Episodelist", dom); - public EpisodeFunction(SearchResult searchResult, int season) { - this.searchResult = searchResult; - this.season = season; - } + boolean allSeasons = (season == 0); - - @Override - public Episode evaluate(Node node) { - String seasonAndEpisodeNumber = XPathUtil.selectString("./TD[2]/A", node); - String title = XPathUtil.selectString("./TD[5]", node); - - List precedings = XPathUtil.selectNodes("../preceding-sibling::TABLE", node); - Node previousTable = precedings.get(precedings.size() - 1); - - String seasonHeader = XPathUtil.selectString("./TR/TD/FONT", previousTable); - - Matcher seasonMatcher = Pattern.compile("Season (\\d+)").matcher(seasonHeader); - - if (seasonMatcher.matches()) { - if ((season == 0) || (season == Integer.parseInt(seasonMatcher.group(1)))) { - Matcher saeMatcher = Pattern.compile("(\\d+)x(\\d+)").matcher(seasonAndEpisodeNumber); + List episodes = new ArrayList(24); + + for (int i = 0; i <= numberOfSeasons; i++) { + if (i == season || allSeasons) { + List nodes = XPathUtil.selectNodes("Season" + i + "/episode", episodeListNode); + + for (Node node : nodes) { + String title = XPathUtil.selectString("title", node); + String episodeNumber = XPathUtil.selectString("seasonnum", node); + String seasonNumber = Integer.toString(i); - String seasonNumber = null; - String episodeNumber = null; - - if (saeMatcher.matches()) { - seasonNumber = saeMatcher.group(1); - episodeNumber = saeMatcher.group(2); - } else { - episodeNumber = seasonAndEpisodeNumber; - } - - return new Episode(searchResult.getName(), seasonNumber, episodeNumber, title); + episodes.add(new Episode(searchResult.getName(), seasonNumber, episodeNumber, title)); } } - - return null; - } - } - - - @Override - public URI getEpisodeListLink(SearchResult searchResult, int season) { - URI baseUri = ((HyperLink) searchResult).getUri(); - - String seasonString = "all"; - - if (season >= 1) { - seasonString = Integer.toString(season); } - String path = baseUri.getPath() + "/episode_list/" + seasonString; - - try { - return new URI("http", host, path, null); - } catch (URISyntaxException e) { - throw new RuntimeException(e); - } + return new DefaultProgressIterator(episodes); } - private URL getSearchUrl(String searchterm) throws UnsupportedEncodingException, MalformedURLException { - String qs = URLEncoder.encode(searchterm, "UTF-8"); - String file = "/search.php?search=" + qs; - return new URL("http", host, file); + @Override + public URI getEpisodeListLink(SearchResult searchResult, int season) { + String page = ((TVRageSearchResult) searchResult).getLink(); + String seasonString = (season >= 1) ? Integer.toString(season) : "all"; + + return URI.create(page + "/episode_list/" + seasonString); + } + + + public static class TVRageSearchResult extends SearchResult { + + private final String showId; + private final String link; + + + public TVRageSearchResult(String name, String showId, String link) { + super(name); + this.showId = showId; + this.link = link; + } + + + public String getShowId() { + return showId; + } + + + public String getLink() { + return link; + } + } } diff --git a/source/net/sourceforge/tuned/DefaultProgressIterator.java b/source/net/sourceforge/tuned/DefaultProgressIterator.java new file mode 100644 index 00000000..64d0bb53 --- /dev/null +++ b/source/net/sourceforge/tuned/DefaultProgressIterator.java @@ -0,0 +1,54 @@ + +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/XPathUtil.java b/source/net/sourceforge/tuned/XPathUtil.java index 1db48a4c..6c2e17aa 100644 --- a/source/net/sourceforge/tuned/XPathUtil.java +++ b/source/net/sourceforge/tuned/XPathUtil.java @@ -65,6 +65,11 @@ public class XPathUtil { } + public static int selectInteger(String xpath, Object node) { + return Integer.parseInt(selectString(xpath, node)); + } + + private static XPathExpression getXPath(String xpath) throws XPathExpressionException { return XPathFactory.newInstance().newXPath().compile(xpath); } diff --git a/test/net/sourceforge/filebot/web/TVRageClientTest.java b/test/net/sourceforge/filebot/web/TVRageClientTest.java new file mode 100644 index 00000000..941cf9fe --- /dev/null +++ b/test/net/sourceforge/filebot/web/TVRageClientTest.java @@ -0,0 +1,73 @@ + +package net.sourceforge.filebot.web; + + +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; + + +public class TVRageClientTest { + + private TVRageClient tvrage = new TVRageClient(); + private TVRageSearchResult testResult = new TVRageSearchResult("Buffy the Vampire Slayer", "2930", "http://www.tvrage.com/Buffy_The_Vampire_Slayer"); + + + @Test + public void search() throws Exception { + List results = tvrage.search("Buffy"); + + TVRageSearchResult result = (TVRageSearchResult) results.get(0); + + assertEquals(testResult.getName(), result.getName()); + assertEquals(testResult.getShowId(), result.getShowId()); + assertEquals(testResult.getLink(), result.getLink()); + } + + + @Test + public void getEpisodeList() throws Exception { + List list = TestUtil.asList(tvrage.getEpisodeList(testResult, 7)); + + Episode chosen = list.get(21); + + assertEquals("Buffy the Vampire Slayer", chosen.getShowName()); + assertEquals("Chosen", chosen.getTitle()); + assertEquals("22", chosen.getNumberOfEpisode()); + assertEquals("7", chosen.getNumberOfSeason()); + } + + + @Test + public void getEpisodeListAll() throws Exception { + List list = TestUtil.asList(tvrage.getEpisodeList(testResult, 0)); + + assertEquals(145, list.size()); + + Episode first = list.get(0); + + assertEquals("Buffy the Vampire Slayer", first.getShowName()); + assertEquals("Unaired Pilot", first.getTitle()); + assertEquals("00", first.getNumberOfEpisode()); + assertEquals("0", first.getNumberOfSeason()); + } + + + @Test(expected = IllegalArgumentException.class) + public void getEpisodeListIllegalSeason() throws Exception { + tvrage.getEpisodeList(testResult, 42); + } + + + @Test + public void getEpisodeListLink() throws Exception { + assertEquals(tvrage.getEpisodeListLink(testResult, 0).toString(), "http://www.tvrage.com/Buffy_The_Vampire_Slayer/episode_list/all"); + assertEquals(tvrage.getEpisodeListLink(testResult, 1).toString(), "http://www.tvrage.com/Buffy_The_Vampire_Slayer/episode_list/1"); + } + +} diff --git a/test/net/sourceforge/tuned/TestUtil.java b/test/net/sourceforge/tuned/TestUtil.java index 089faed3..5efc070e 100644 --- a/test/net/sourceforge/tuned/TestUtil.java +++ b/test/net/sourceforge/tuned/TestUtil.java @@ -5,6 +5,7 @@ package net.sourceforge.tuned; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Iterator; import java.util.List; @@ -23,6 +24,17 @@ public class TestUtil { } + public static List asList(Iterator iterator) { + List list = new ArrayList(); + + while (iterator.hasNext()) { + list.add(iterator.next()); + } + + return list; + } + + public static List asParameters(Object... parameterSet) { List list = new ArrayList();