mirror of
https://github.com/mitb-archive/filebot
synced 2024-11-16 06:15:02 -05:00
* TVRageClient uses the xml feeds now
* some testcases
This commit is contained in:
parent
adb4d68055
commit
2b4218ffce
@ -3,25 +3,19 @@ package net.sourceforge.filebot.web;
|
|||||||
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.net.MalformedURLException;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
import javax.xml.parsers.DocumentBuilderFactory;
|
||||||
import java.util.regex.Matcher;
|
import javax.xml.parsers.ParserConfigurationException;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import net.sourceforge.filebot.resources.ResourceManager;
|
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.ProgressIterator;
|
||||||
import net.sourceforge.tuned.XPathUtil;
|
import net.sourceforge.tuned.XPathUtil;
|
||||||
import net.sourceforge.tuned.FunctionIterator.Function;
|
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
import org.w3c.dom.Node;
|
import org.w3c.dom.Node;
|
||||||
@ -41,28 +35,25 @@ public class TVRageClient extends EpisodeListClient {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SearchResult> search(String searchterm) throws IOException, SAXException {
|
public List<SearchResult> search(String searchterm) throws SAXException, IOException, ParserConfigurationException {
|
||||||
if (cache.containsKey(searchterm)) {
|
if (cache.containsKey(searchterm)) {
|
||||||
return Collections.singletonList(cache.get(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<Node> nodes = XPathUtil.selectNodes("id('search_begin')/TABLE[1]/*/TR/TD/A[1]", dom);
|
Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(searchUri);
|
||||||
|
|
||||||
|
List<Node> nodes = XPathUtil.selectNodes("Results/show", dom);
|
||||||
|
|
||||||
List<SearchResult> searchResults = new ArrayList<SearchResult>(nodes.size());
|
List<SearchResult> searchResults = new ArrayList<SearchResult>(nodes.size());
|
||||||
|
|
||||||
for (Node node : nodes) {
|
for (Node node : nodes) {
|
||||||
String href = XPathUtil.selectString("@href", node);
|
String showid = XPathUtil.selectString("showid", node);
|
||||||
String title = XPathUtil.selectString(".", node);
|
String name = XPathUtil.selectString("name", node);
|
||||||
|
String link = XPathUtil.selectString("link", node);
|
||||||
|
|
||||||
try {
|
searchResults.add(new TVRageSearchResult(name, showid, link));
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cache.addAll(searchResults);
|
cache.addAll(searchResults);
|
||||||
@ -72,87 +63,73 @@ public class TVRageClient extends EpisodeListClient {
|
|||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProgressIterator<Episode> getEpisodeList(SearchResult searchResult, int season) throws IOException, SAXException {
|
public ProgressIterator<Episode> 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<Node> nodes = XPathUtil.selectNodes("//TABLE[@class='b']//TR[@id='brow']", dom);
|
Document dom = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(episodeListUri);
|
||||||
|
|
||||||
return new FunctionIterator<Node, Episode>(nodes, new EpisodeFunction(searchResult, season));
|
int numberOfSeasons = XPathUtil.selectInteger("Show/totalseasons", dom);
|
||||||
}
|
|
||||||
|
|
||||||
|
if (season > numberOfSeasons)
|
||||||
|
throw new IllegalArgumentException(String.format("%s only has %d seasons", searchResult.getName(), numberOfSeasons));
|
||||||
|
|
||||||
private static class EpisodeFunction implements Function<Node, Episode> {
|
Node episodeListNode = XPathUtil.selectNode("Show/Episodelist", dom);
|
||||||
|
|
||||||
private final SearchResult searchResult;
|
boolean allSeasons = (season == 0);
|
||||||
private final int season;
|
|
||||||
|
|
||||||
|
List<Episode> episodes = new ArrayList<Episode>(24);
|
||||||
|
|
||||||
public EpisodeFunction(SearchResult searchResult, int season) {
|
for (int i = 0; i <= numberOfSeasons; i++) {
|
||||||
this.searchResult = searchResult;
|
if (i == season || allSeasons) {
|
||||||
this.season = season;
|
List<Node> 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);
|
||||||
|
|
||||||
@Override
|
episodes.add(new Episode(searchResult.getName(), seasonNumber, episodeNumber, title));
|
||||||
public Episode evaluate(Node node) {
|
|
||||||
String seasonAndEpisodeNumber = XPathUtil.selectString("./TD[2]/A", node);
|
|
||||||
String title = XPathUtil.selectString("./TD[5]", node);
|
|
||||||
|
|
||||||
List<Node> 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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return new DefaultProgressIterator<Episode>(episodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public URI getEpisodeListLink(SearchResult searchResult, int season) {
|
public URI getEpisodeListLink(SearchResult searchResult, int season) {
|
||||||
URI baseUri = ((HyperLink) searchResult).getUri();
|
String page = ((TVRageSearchResult) searchResult).getLink();
|
||||||
|
String seasonString = (season >= 1) ? Integer.toString(season) : "all";
|
||||||
|
|
||||||
String seasonString = "all";
|
return URI.create(page + "/episode_list/" + seasonString);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private URL getSearchUrl(String searchterm) throws UnsupportedEncodingException, MalformedURLException {
|
public static class TVRageSearchResult extends SearchResult {
|
||||||
String qs = URLEncoder.encode(searchterm, "UTF-8");
|
|
||||||
String file = "/search.php?search=" + qs;
|
private final String showId;
|
||||||
return new URL("http", host, file);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
54
source/net/sourceforge/tuned/DefaultProgressIterator.java
Normal file
54
source/net/sourceforge/tuned/DefaultProgressIterator.java
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
|
||||||
|
package net.sourceforge.tuned;
|
||||||
|
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
|
||||||
|
public class DefaultProgressIterator<E> implements ProgressIterator<E> {
|
||||||
|
|
||||||
|
private final Iterator<E> sourceIterator;
|
||||||
|
private final int length;
|
||||||
|
|
||||||
|
private int position = 0;
|
||||||
|
|
||||||
|
|
||||||
|
public DefaultProgressIterator(Collection<E> 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
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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 {
|
private static XPathExpression getXPath(String xpath) throws XPathExpressionException {
|
||||||
return XPathFactory.newInstance().newXPath().compile(xpath);
|
return XPathFactory.newInstance().newXPath().compile(xpath);
|
||||||
}
|
}
|
||||||
|
73
test/net/sourceforge/filebot/web/TVRageClientTest.java
Normal file
73
test/net/sourceforge/filebot/web/TVRageClientTest.java
Normal file
@ -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<SearchResult> 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<Episode> 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<Episode> 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");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -5,6 +5,7 @@ package net.sourceforge.tuned;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
@ -23,6 +24,17 @@ public class TestUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static <T> List<T> asList(Iterator<T> iterator) {
|
||||||
|
List<T> list = new ArrayList<T>();
|
||||||
|
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
list.add(iterator.next());
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public static List<Object[]> asParameters(Object... parameterSet) {
|
public static List<Object[]> asParameters(Object... parameterSet) {
|
||||||
List<Object[]> list = new ArrayList<Object[]>();
|
List<Object[]> list = new ArrayList<Object[]>();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user