2007-12-23 14:28:04 -05:00
|
|
|
|
|
|
|
package net.sourceforge.filebot.web;
|
|
|
|
|
|
|
|
|
2009-05-17 13:22:44 -04:00
|
|
|
import static net.sourceforge.filebot.web.WebRequest.*;
|
|
|
|
import static net.sourceforge.tuned.XPathUtilities.*;
|
2009-01-04 13:28:28 -05:00
|
|
|
|
2007-12-23 14:28:04 -05:00
|
|
|
import java.io.IOException;
|
|
|
|
import java.net.MalformedURLException;
|
2008-06-21 15:24:18 -04:00
|
|
|
import java.net.URI;
|
2007-12-23 14:28:04 -05:00
|
|
|
import java.net.URL;
|
|
|
|
import java.net.URLEncoder;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
2009-05-25 16:13:30 -04:00
|
|
|
import java.util.Locale;
|
2008-02-09 12:53:08 -05:00
|
|
|
import java.util.logging.Level;
|
|
|
|
import java.util.logging.Logger;
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2008-07-13 13:59:05 -04:00
|
|
|
import javax.swing.Icon;
|
|
|
|
|
2008-10-10 14:59:01 -04:00
|
|
|
import net.sourceforge.filebot.ResourceManager;
|
2007-12-23 14:28:04 -05:00
|
|
|
|
|
|
|
import org.w3c.dom.Document;
|
|
|
|
import org.w3c.dom.Node;
|
|
|
|
import org.xml.sax.SAXException;
|
|
|
|
|
|
|
|
|
2009-03-18 16:09:45 -04:00
|
|
|
public class AnidbClient implements EpisodeListProvider {
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2008-07-30 18:37:01 -04:00
|
|
|
private static final String host = "anidb.net";
|
2007-12-23 14:28:04 -05:00
|
|
|
|
|
|
|
|
2008-07-13 13:59:05 -04:00
|
|
|
@Override
|
|
|
|
public String getName() {
|
|
|
|
return "AniDB";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public Icon getIcon() {
|
|
|
|
return ResourceManager.getIcon("search.anidb");
|
|
|
|
}
|
2007-12-23 14:28:04 -05:00
|
|
|
|
|
|
|
|
|
|
|
@Override
|
2009-01-04 13:28:28 -05:00
|
|
|
public List<SearchResult> search(String query) throws IOException, SAXException {
|
2009-05-25 16:13:30 -04:00
|
|
|
// Air Status: ignore
|
|
|
|
// Anime Type: TV Series, TV Special, OVA
|
|
|
|
// Hide Synonyms: true
|
2009-05-24 09:25:49 -04:00
|
|
|
URL searchUrl = new URL("http", host, "/perl-bin/animedb.pl?type.tvspecial=1&type.tvseries=1&type.ova=1&show=animelist&orderby.name=0.1&noalias=1&do.update=update&adb.search=" + URLEncoder.encode(query, "UTF-8"));
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
Document dom = getHtmlDocument(searchUrl);
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
List<Node> nodes = selectNodes("//TABLE[@class='animelist']//TR/TD/ancestor::TR", dom);
|
2008-03-29 08:20:01 -04:00
|
|
|
|
2009-05-25 16:13:30 -04:00
|
|
|
List<SearchResult> results = new ArrayList<SearchResult>(nodes.size());
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2008-07-07 19:38:17 -04:00
|
|
|
for (Node node : nodes) {
|
2009-05-25 16:13:30 -04:00
|
|
|
Node link = selectNode("./TD[@class='name']/A", node);
|
|
|
|
|
|
|
|
// prefer title that is similar to the search query
|
|
|
|
String title = selectString("./following-sibling::*[@class='match']", link);
|
|
|
|
|
|
|
|
// remove leading and trailing parenthesis
|
|
|
|
title = title.replaceAll("(^\\()|(\\)$)", "");
|
2008-07-07 19:38:17 -04:00
|
|
|
|
2009-05-25 16:13:30 -04:00
|
|
|
if (title.isEmpty()) {
|
|
|
|
// fallback: use main title
|
|
|
|
title = getTextContent(link);
|
|
|
|
}
|
|
|
|
|
|
|
|
// anime page
|
|
|
|
String href = getAttribute("href", link);
|
2008-07-07 19:38:17 -04:00
|
|
|
|
|
|
|
try {
|
2009-05-25 16:13:30 -04:00
|
|
|
results.add(new HyperLink(title, new URL("http", host, "/perl-bin/" + href)));
|
2008-07-07 19:38:17 -04:00
|
|
|
} catch (MalformedURLException e) {
|
2009-03-14 06:20:59 -04:00
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Invalid href: " + href);
|
2008-07-07 19:38:17 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// we might have been redirected to the episode list page
|
2009-05-25 16:13:30 -04:00
|
|
|
if (results.isEmpty()) {
|
|
|
|
// get anime information from document
|
|
|
|
String title = selectTitle(dom);
|
|
|
|
String link = selectString("//*[@class='data']//A[@class='short_link']/@href", dom);
|
|
|
|
|
|
|
|
try {
|
|
|
|
// insert single entry
|
|
|
|
results.add(new HyperLink(title, new URL(link)));
|
|
|
|
} catch (MalformedURLException e) {
|
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Invalid location: " + link);
|
2007-12-23 14:28:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-25 16:13:30 -04:00
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected String selectTitle(Document animePage) {
|
|
|
|
// prefer official english title
|
|
|
|
String title = selectOfficialTitle(animePage, Locale.ENGLISH);
|
|
|
|
|
|
|
|
if (title.isEmpty()) {
|
|
|
|
// fallback: extract name from header (e.g. "Anime: Naruto")
|
|
|
|
title = selectString("//H1", animePage).replaceFirst("Anime:\\s*", "");;
|
|
|
|
}
|
|
|
|
|
|
|
|
return title;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected String selectOfficialTitle(Document animePage, Locale language) {
|
|
|
|
// create xpath query for official title of the given language
|
|
|
|
// e.g. //*[@class='data']//*[contains(@class, 'official') and .//*[contains(@title, 'english')]]//LABEL
|
|
|
|
|
|
|
|
String condition = String.format(".//*[contains(@title, '%s')]", language.getDisplayLanguage(Locale.ENGLISH).toLowerCase());
|
|
|
|
String xpath = String.format("//*[@class='data']//*[contains(@class, 'official') and %s]//LABEL", condition);
|
|
|
|
|
|
|
|
return selectString(xpath, animePage);
|
2007-12-23 14:28:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
2008-07-05 23:17:23 -04:00
|
|
|
public List<Episode> getEpisodeList(SearchResult searchResult) throws IOException, SAXException {
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
Document dom = getHtmlDocument(getEpisodeListLink(searchResult).toURL());
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2009-05-25 16:13:30 -04:00
|
|
|
// use title from anime page
|
|
|
|
String animeTitle = selectTitle(dom);
|
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
List<Node> nodes = selectNodes("id('eplist')//TR/TD/SPAN/ancestor::TR", dom);
|
2008-06-21 15:24:18 -04:00
|
|
|
|
2008-07-05 07:37:03 -04:00
|
|
|
ArrayList<Episode> episodes = new ArrayList<Episode>(nodes.size());
|
2008-06-21 15:24:18 -04:00
|
|
|
|
2008-07-05 07:37:03 -04:00
|
|
|
for (Node node : nodes) {
|
2009-05-25 16:13:30 -04:00
|
|
|
List<Node> columns = getChildren("TD", node);
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2009-05-25 16:13:30 -04:00
|
|
|
String number = columns.get(0).getTextContent().trim();
|
|
|
|
String title = columns.get(1).getTextContent().trim();
|
2007-12-23 14:28:04 -05:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
// if number does not match, episode is probably some kind of special (S1, S2, ...)
|
|
|
|
if (number.matches("\\d+")) {
|
2008-07-07 19:38:17 -04:00
|
|
|
// no seasons for anime
|
2009-05-25 16:13:30 -04:00
|
|
|
episodes.add(new Episode(animeTitle, null, number, title));
|
2007-12-23 14:28:04 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-07-05 07:37:03 -04:00
|
|
|
return episodes;
|
2007-12-23 14:28:04 -05:00
|
|
|
}
|
|
|
|
|
2008-07-05 07:37:03 -04:00
|
|
|
|
2008-07-05 23:17:23 -04:00
|
|
|
@Override
|
|
|
|
public URI getEpisodeListLink(SearchResult searchResult) {
|
2008-07-06 14:31:04 -04:00
|
|
|
return ((HyperLink) searchResult).toURI();
|
2008-07-05 23:17:23 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean hasSingleSeasonSupport() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@Override
|
2009-02-09 15:56:20 -05:00
|
|
|
public List<Episode> getEpisodeList(SearchResult searchResult, int season) throws Exception {
|
2008-07-05 23:17:23 -04:00
|
|
|
throw new UnsupportedOperationException();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-29 08:20:01 -04:00
|
|
|
@Override
|
2008-06-21 15:24:18 -04:00
|
|
|
public URI getEpisodeListLink(SearchResult searchResult, int season) {
|
2009-03-17 17:59:19 -04:00
|
|
|
return null;
|
2007-12-23 14:28:04 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|