From 4022251746d210766bbccf1fff36f10b518ff05b Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Wed, 10 Dec 2014 18:53:58 +0000 Subject: [PATCH] + major rewrite of episode metadata / SeriesInfo --- source/net/filebot/WebServices.java | 34 +-- .../net/filebot/format/MediaBindingBean.java | 59 ++-- source/net/filebot/media/MediaDetection.java | 6 +- .../filebot/similarity/EpisodeMetrics.java | 55 ++-- .../net/filebot/ui/analyze/AttributeTool.java | 15 +- .../ui/episodelist/EpisodeListPanel.java | 2 +- .../ui/subtitle/SubtitleUploadDialog.java | 10 +- source/net/filebot/util/XPathUtilities.java | 107 ++++--- .../web/AbstractEpisodeListProvider.java | 155 +++++----- source/net/filebot/web/AnidbClient.java | 50 ++- source/net/filebot/web/Episode.java | 42 +-- source/net/filebot/web/EpisodeFormat.java | 2 +- .../net/filebot/web/EpisodeListProvider.java | 33 +- .../net/filebot/web/OpenSubtitlesClient.java | 2 +- source/net/filebot/web/SearchResult.java | 11 +- source/net/filebot/web/SeriesInfo.java | 203 ++++++++++++ source/net/filebot/web/TVRageClient.java | 52 +++- source/net/filebot/web/TheTVDBClient.java | 289 +++--------------- source/net/filebot/web/TheTVDBSeriesInfo.java | 115 +++++++ .../similarity/EpisodeMetricsTest.java | 9 +- test/net/filebot/web/AnidbClientTest.java | 24 +- test/net/filebot/web/TVRageClientTest.java | 9 +- test/net/filebot/web/TheTVDBClientTest.java | 104 +++---- 23 files changed, 735 insertions(+), 653 deletions(-) create mode 100644 source/net/filebot/web/SeriesInfo.java create mode 100644 source/net/filebot/web/TheTVDBSeriesInfo.java diff --git a/source/net/filebot/WebServices.java b/source/net/filebot/WebServices.java index c989fccb..6051cbf0 100644 --- a/source/net/filebot/WebServices.java +++ b/source/net/filebot/WebServices.java @@ -25,7 +25,6 @@ import net.filebot.similarity.MetricAvg; import net.filebot.web.AcoustIDClient; import net.filebot.web.AnidbClient; import net.filebot.web.AnidbSearchResult; -import net.filebot.web.AudioTrack; import net.filebot.web.EpisodeListProvider; import net.filebot.web.FanartTVClient; import net.filebot.web.ID3Lookup; @@ -40,10 +39,9 @@ import net.filebot.web.SubtitleDescriptor; import net.filebot.web.SubtitleProvider; import net.filebot.web.TMDbClient; import net.filebot.web.TVRageClient; -import net.filebot.web.TVRageSearchResult; import net.filebot.web.TheTVDBClient; -import net.filebot.web.TheTVDBClient.SeriesInfo; import net.filebot.web.TheTVDBSearchResult; +import net.filebot.web.TheTVDBSeriesInfo; import net.filebot.web.VideoHashSubtitleService; /** @@ -114,21 +112,6 @@ public final class WebServices { return null; // default } - public static Object getServiceBySearchResult(Object r) { - if (r instanceof TheTVDBSearchResult) - return WebServices.TheTVDB; - if (r instanceof AnidbSearchResult) - return WebServices.AniDB; - if (r instanceof TVRageSearchResult) - return WebServices.TVRage; - if (r instanceof Movie) - return WebServices.TheMovieDB; - if (r instanceof AudioTrack) - return WebServices.AcoustID; - - return null; - } - public static final ExecutorService requestThreadPool = Executors.newCachedThreadPool(); public static class TheTVDBClientWithLocalSearch extends TheTVDBClient { @@ -161,14 +144,6 @@ public final class WebServices { return localIndex; } - public SeriesInfo getSeriesInfoByLocalIndex(String name, Locale locale) throws Exception { - List results = getLocalIndex().search(name); - if (results.size() > 0) { - return getSeriesInfo((TheTVDBSearchResult) results.get(0), locale); - } - return null; - } - @Override public List fetchSearchResult(final String query, final Locale locale) throws Exception { Callable> apiSearch = () -> TheTVDBClientWithLocalSearch.super.fetchSearchResult(query, locale); @@ -258,10 +233,11 @@ public final class WebServices { public Movie getIMDbID(SearchResult result) throws Exception { if (result instanceof TheTVDBSearchResult) { - TheTVDBSearchResult s = (TheTVDBSearchResult) result; - SeriesInfo seriesInfo = ((TheTVDBClient) seriesIndex).getSeriesInfo(s, Locale.ENGLISH); + TheTVDBSearchResult searchResult = (TheTVDBSearchResult) result; + TheTVDBSeriesInfo seriesInfo = (TheTVDBSeriesInfo) ((TheTVDBClient) seriesIndex).getSeriesInfo(searchResult, Locale.ENGLISH); if (seriesInfo.getImdbId() != null) { - return new Movie(seriesInfo.getName(), seriesInfo.getFirstAired().getYear(), seriesInfo.getImdbId(), -1); + int imdbId = grepImdbId(seriesInfo.getImdbId()).iterator().next(); + return new Movie(seriesInfo.getName(), seriesInfo.getStartDate().getYear(), imdbId, -1); } } if (result instanceof Movie) { diff --git a/source/net/filebot/format/MediaBindingBean.java b/source/net/filebot/format/MediaBindingBean.java index 2f19fd36..e794b9a9 100644 --- a/source/net/filebot/format/MediaBindingBean.java +++ b/source/net/filebot/format/MediaBindingBean.java @@ -44,16 +44,15 @@ import net.filebot.mediainfo.MediaInfo.StreamKind; import net.filebot.similarity.SimilarityComparator; import net.filebot.util.FileUtilities; import net.filebot.util.FileUtilities.ExtensionFileFilter; -import net.filebot.web.AnidbSearchResult; import net.filebot.web.AudioTrack; import net.filebot.web.Episode; import net.filebot.web.EpisodeListProvider; import net.filebot.web.Movie; import net.filebot.web.MoviePart; import net.filebot.web.MultiEpisode; -import net.filebot.web.SearchResult; +import net.filebot.web.SeriesInfo; import net.filebot.web.SimpleDate; -import net.filebot.web.TheTVDBSearchResult; +import net.filebot.web.SortOrder; import com.cedarsoftware.util.io.JsonWriter; @@ -99,7 +98,7 @@ public class MediaBindingBean { @Define("y") public Integer getYear() { if (infoObject instanceof Episode) - return getEpisode().getSeriesStartDate().getYear(); + return getEpisode().getSeriesInfo().getStartDate().getYear(); if (infoObject instanceof Movie) return getMovie().getYear(); if (infoObject instanceof AudioTrack) @@ -191,7 +190,7 @@ public class MediaBindingBean { @Define("startdate") public SimpleDate startdate() { - return getEpisode().getSeriesStartDate(); + return getEpisode().getSeriesInfo().getStartDate(); } @Define("absolute") @@ -205,8 +204,8 @@ public class MediaBindingBean { } @Define("series") - public SearchResult getSeriesObject() { - return getEpisode().getSeries(); + public SeriesInfo getSeriesInfo() { + return getEpisode().getSeriesInfo(); } @Define("alias") @@ -214,11 +213,9 @@ public class MediaBindingBean { if (infoObject instanceof Movie) { return asList(getMovie().getAliasNames()); } - if (infoObject instanceof Episode) { - return asList(getSeriesObject().getAliasNames()); + return getSeriesInfo().getAliasNames(); } - return emptyList(); } @@ -229,13 +226,13 @@ public class MediaBindingBean { } if (infoObject instanceof Episode) { - if (getSeriesObject() instanceof TheTVDBSearchResult) { - return WebServices.TheTVDB.getSeriesInfo((TheTVDBSearchResult) getSeriesObject(), Locale.ENGLISH).getName(); + // force English series name for TheTVDB data + if (WebServices.TheTVDB.getName().equals(getSeriesInfo().getDatabase())) { + return WebServices.TheTVDB.getSeriesInfo(getSeriesInfo().getId(), Locale.ENGLISH).getName(); } - if (getSeriesObject() instanceof AnidbSearchResult) { - return ((AnidbSearchResult) getSeriesObject()).getPrimaryTitle(); - } - return getSeriesObject().getName(); // default to original search result + + // default to series info name (for anime this would be the primary title) + return getSeriesInfo().getName(); } return null; @@ -558,10 +555,7 @@ public class MediaBindingBean { if (metaInfo == null) { try { if (infoObject instanceof Episode) { - Episode episode = (Episode) infoObject; - if (episode.getSeries() instanceof TheTVDBSearchResult) { - metaInfo = WebServices.TheTVDB.getSeriesInfo((TheTVDBSearchResult) episode.getSeries(), episode.getLanguage() == null ? Locale.ENGLISH : episode.getLanguage()); - } + metaInfo = getSeriesInfo(); } else if (infoObject instanceof Movie) { if (getMovie().getTmdbId() > 0) { metaInfo = WebServices.TheMovieDB.getMovieInfo(getMovie(), getMovie().getLanguage() == null ? Locale.ENGLISH : getMovie().getLanguage(), true); @@ -574,20 +568,20 @@ public class MediaBindingBean { } } - if (mediaInfo == null) { + if (metaInfo == null) { throw new UnsupportedOperationException("Extended metadata not available"); } return createMapBindings(new PropertyBindings(metaInfo, null)); } - @Define("imdb") - public synchronized AssociativeScriptObject getImdbApiInfo() { + @Define("omdb") + public synchronized AssociativeScriptObject getOmdbApiInfo() { Object metaInfo = null; try { if (infoObject instanceof Episode) { - metaInfo = WebServices.OMDb.getMovieInfo(new Movie(getEpisode().getSeriesName(), getEpisode().getSeriesStartDate().getYear(), -1, -1)); + metaInfo = WebServices.OMDb.getMovieInfo(new Movie(getEpisode().getSeriesName(), getEpisode().getSeriesInfo().getStartDate().getYear(), -1, -1)); } if (infoObject instanceof Movie) { metaInfo = WebServices.OMDb.getMovieInfo(getMovie()); @@ -605,19 +599,10 @@ public class MediaBindingBean { @Define("episodelist") public Object getEpisodeList() throws Exception { - return ((EpisodeListProvider) getDatabase()).getEpisodeList(getSeriesObject(), getEpisode().getOrder(), getEpisode().getLanguage()); - } - - @Define("database") - public Object getDatabase() { - if (infoObject instanceof Episode) { - return WebServices.getServiceBySearchResult(getSeriesObject()); - } - if (infoObject instanceof Movie) { - return WebServices.getServiceBySearchResult(getMovie()); - } - if (infoObject instanceof AudioTrack) { - return WebServices.getServiceBySearchResult(getMusic()); + for (EpisodeListProvider service : WebServices.getEpisodeListProviders()) { + if (getSeriesInfo().getDatabase().equals(service.getName())) { + return service.getEpisodeList(getSeriesInfo().getId(), SortOrder.forName(getSeriesInfo().getOrder()), new Locale(getSeriesInfo().getLanguage())); + } } return null; } diff --git a/source/net/filebot/media/MediaDetection.java b/source/net/filebot/media/MediaDetection.java index 5885aa62..ee47c85b 100644 --- a/source/net/filebot/media/MediaDetection.java +++ b/source/net/filebot/media/MediaDetection.java @@ -65,8 +65,8 @@ import net.filebot.web.Episode; import net.filebot.web.Movie; import net.filebot.web.MovieIdentificationService; import net.filebot.web.SearchResult; +import net.filebot.web.SeriesInfo; import net.filebot.web.SimpleDate; -import net.filebot.web.TheTVDBClient.SeriesInfo; import net.filebot.web.TheTVDBSearchResult; public class MediaDetection { @@ -1259,7 +1259,9 @@ public class MediaDetection { } public static SeriesInfo grepSeries(File nfo, Locale locale) throws Exception { - return WebServices.TheTVDB.getSeriesInfoByID(grepTheTvdbId(new String(readFile(nfo), "UTF-8")).iterator().next(), locale); + String contents = new String(readFile(nfo), "UTF-8"); + int thetvdbid = grepTheTvdbId(contents).iterator().next(); + return WebServices.TheTVDB.getSeriesInfo(thetvdbid, locale); } public static List getProbableMatches(String query, Collection options) { diff --git a/source/net/filebot/similarity/EpisodeMetrics.java b/source/net/filebot/similarity/EpisodeMetrics.java index f246b473..31a4db6f 100644 --- a/source/net/filebot/similarity/EpisodeMetrics.java +++ b/source/net/filebot/similarity/EpisodeMetrics.java @@ -26,7 +26,6 @@ import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; -import net.filebot.WebServices; import net.filebot.media.MediaDetection; import net.filebot.media.SmartSeasonEpisodeMatcher; import net.filebot.similarity.SeasonEpisodeMatcher.SxE; @@ -34,9 +33,8 @@ import net.filebot.vfs.FileInfo; import net.filebot.web.Episode; import net.filebot.web.EpisodeFormat; import net.filebot.web.Movie; +import net.filebot.web.SeriesInfo; import net.filebot.web.SimpleDate; -import net.filebot.web.TheTVDBClient.SeriesInfo; -import net.filebot.web.TheTVDBSearchResult; import com.ibm.icu.text.Transliterator; @@ -212,7 +210,7 @@ public enum EpisodeMetrics implements SimilarityMetric { LinkedHashSet keywords = new LinkedHashSet(4); keywords.add(removeTrailingBrackets(episode.getSeriesName())); keywords.add(removeTrailingBrackets(episode.getTitle())); - for (String it : episode.getSeries().getEffectiveNames()) { + for (String it : episode.getSeriesInfo().getAliasNames()) { keywords.add(removeTrailingBrackets(it)); } @@ -277,7 +275,7 @@ public enum EpisodeMetrics implements SimilarityMetric { protected List getEffectiveIdentifiers(Object object) { if (object instanceof Episode) { - return ((Episode) object).getSeries().getEffectiveNames(); + return ((Episode) object).getSeriesInfo().getAliasNames(); } else if (object instanceof Movie) { return ((Movie) object).getEffectiveNames(); } else if (object instanceof File) { @@ -346,7 +344,7 @@ public enum EpisodeMetrics implements SimilarityMetric { List names = null; if (object instanceof Episode) { - names = ((Episode) object).getSeries().getEffectiveNames(); + names = ((Episode) object).getSeriesInfo().getAliasNames(); } else if (object instanceof File) { File file = (File) object; @@ -558,39 +556,20 @@ public enum EpisodeMetrics implements SimilarityMetric { return max(r1, r2); } - private final Map seriesInfoCache = new HashMap(); - - public float getRating(Object o) { - if (o instanceof Episode) { - try { - synchronized (seriesInfoCache) { - String n = ((Episode) o).getSeriesName(); - - SeriesInfo seriesInfo = seriesInfoCache.get(n); - if (seriesInfo == null && !seriesInfoCache.containsKey(n)) { - try { - seriesInfo = WebServices.TheTVDB.getSeriesInfo((TheTVDBSearchResult) ((Episode) o).getSeries(), Locale.ENGLISH); - } catch (Exception e) { - seriesInfo = WebServices.TheTVDB.getSeriesInfoByLocalIndex(((Episode) o).getSeriesName(), Locale.ENGLISH); - } - seriesInfoCache.put(n, seriesInfo); - } - - if (seriesInfo != null) { - if (seriesInfo.getRatingCount() >= 100) { - return (float) floor(seriesInfo.getRating() / 3) + 1; // BOOST POPULAR SHOWS - } - if (seriesInfo.getRatingCount() >= 10) { - return (float) floor(seriesInfo.getRating() / 3); // PUT INTO 3 GROUPS - } - if (seriesInfo.getRatingCount() >= 1) { - return 0; // PENALIZE SHOWS WITH FEW RATINGS - } - return -1; // BIG PENALTY FOR SHOWS WITH 0 RATINGS - } + public float getRating(Object object) { + if (object instanceof Episode) { + SeriesInfo seriesInfo = ((Episode) object).getSeriesInfo(); + if (seriesInfo != null && seriesInfo.getRating() != null && seriesInfo.getRatingCount() != null) { + if (seriesInfo.getRatingCount() >= 100) { + return (float) floor(seriesInfo.getRating() / 3) + 1; // BOOST POPULAR SHOWS } - } catch (Exception e) { - Logger.getLogger(EpisodeMetrics.class.getName()).log(Level.WARNING, e.getMessage()); + if (seriesInfo.getRatingCount() >= 10) { + return (float) floor(seriesInfo.getRating() / 3); // PUT INTO 3 GROUPS + } + if (seriesInfo.getRatingCount() >= 1) { + return 0; // PENALIZE SHOWS WITH FEW RATINGS + } + return -1; // BIG PENALTY FOR SHOWS WITH 0 RATINGS } } return 0; diff --git a/source/net/filebot/ui/analyze/AttributeTool.java b/source/net/filebot/ui/analyze/AttributeTool.java index d110fc22..bb8545a4 100644 --- a/source/net/filebot/ui/analyze/AttributeTool.java +++ b/source/net/filebot/ui/analyze/AttributeTool.java @@ -20,7 +20,7 @@ import net.filebot.util.FileUtilities; import net.filebot.util.ui.LoadingOverlayPane; import net.filebot.web.Episode; import net.filebot.web.Movie; -import net.filebot.web.SearchResult; +import net.filebot.web.SeriesInfo; import net.miginfocom.swing.MigLayout; class AttributeTool extends Tool { @@ -59,20 +59,17 @@ class AttributeTool extends Tool { originalName = attributes.getOriginalName(); metaObject = attributes.getObject(); - String format = "%s::%d"; if (metaObject instanceof Episode) { - Object seriesObject = ((Episode) metaObject).getSeries(); - if (seriesObject != null) { - String type = seriesObject.getClass().getSimpleName().replace(SearchResult.class.getSimpleName(), ""); - Integer code = (Integer) seriesObject.getClass().getMethod("getId").invoke(seriesObject); - metaId = String.format(format, type, code); + SeriesInfo seriesInfo = ((Episode) metaObject).getSeriesInfo(); + if (seriesInfo != null) { + metaId = String.format("%s::%d", seriesInfo.getDatabase(), seriesInfo.getId()); } } else if (metaObject instanceof Movie) { Movie movie = (Movie) metaObject; if (movie.getTmdbId() > 0) { - metaId = String.format(format, "TheMovieDB", movie.getTmdbId()); + metaId = String.format("%s::%d", "TheMovieDB", movie.getTmdbId()); } else if (movie.getImdbId() > 0) { - metaId = String.format(format, "IMDB", movie.getImdbId()); + metaId = String.format("%s::%d", "OMDb", movie.getImdbId()); } } } catch (Exception e) { diff --git a/source/net/filebot/ui/episodelist/EpisodeListPanel.java b/source/net/filebot/ui/episodelist/EpisodeListPanel.java index 2dcbab9b..155a6201 100644 --- a/source/net/filebot/ui/episodelist/EpisodeListPanel.java +++ b/source/net/filebot/ui/episodelist/EpisodeListPanel.java @@ -124,7 +124,7 @@ public class EpisodeListPanel extends AbstractSearchPanel options = WebServices.TheTVDB.search(name, Locale.ENGLISH); for (SearchResult entry : options) { - SeriesInfo seriesInfo = WebServices.TheTVDB.getSeriesInfo((TheTVDBSearchResult) entry, Locale.ENGLISH); - Integer imdbid = seriesInfo.getImdbId(); - if (imdbid != null && imdbid > 0) { - mapping.setIdentity(WebServices.OpenSubtitles.getMovieDescriptor(new Movie(null, 0, imdbid, -1), Locale.ENGLISH)); + TheTVDBSeriesInfo seriesInfo = (TheTVDBSeriesInfo) WebServices.TheTVDB.getSeriesInfo((TheTVDBSearchResult) entry, Locale.ENGLISH); + if (seriesInfo.getImdbId() != null) { + int imdbId = grepImdbId(seriesInfo.getImdbId()).iterator().next(); + mapping.setIdentity(WebServices.OpenSubtitles.getMovieDescriptor(new Movie(null, 0, imdbId, -1), Locale.ENGLISH)); break; } } diff --git a/source/net/filebot/util/XPathUtilities.java b/source/net/filebot/util/XPathUtilities.java index d53f0814..8d10a4ec 100644 --- a/source/net/filebot/util/XPathUtilities.java +++ b/source/net/filebot/util/XPathUtilities.java @@ -1,10 +1,9 @@ - package net.filebot.util; - import java.util.AbstractList; import java.util.ArrayList; import java.util.List; +import java.util.Scanner; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; @@ -14,9 +13,8 @@ import javax.xml.xpath.XPathFactory; import org.w3c.dom.Node; import org.w3c.dom.NodeList; - public final class XPathUtilities { - + public static Node selectNode(String xpath, Object node) { try { return (Node) getXPath(xpath).evaluate(node, XPathConstants.NODE); @@ -24,7 +22,6 @@ public final class XPathUtilities { throw new RuntimeException(e); } } - public static List selectNodes(String xpath, Object node) { try { @@ -33,7 +30,6 @@ public final class XPathUtilities { throw new RuntimeException(e); } } - public static String selectString(String xpath, Object node) { try { @@ -42,11 +38,27 @@ public final class XPathUtilities { throw new RuntimeException(e); } } - + + public static List selectStrings(String xpath, Object node) { + List values = new ArrayList(); + try { + for (Node it : selectNodes(xpath, node)) { + String textContent = getTextContent(it); + if (textContent.length() > 0) { + values.add(textContent); + } + } + } catch (Exception e) { + throw new RuntimeException(e); + } + return values; + } /** - * @param nodeName search for nodes with this name - * @param parentNode search in the child nodes of this nodes + * @param nodeName + * search for nodes with this name + * @param parentNode + * search in the child nodes of this nodes * @return text content of the child node or null if no child with the given name was found */ public static Node getChild(String nodeName, Node parentNode) { @@ -54,77 +66,98 @@ public final class XPathUtilities { if (nodeName.equals(child.getNodeName())) return child; } - + return null; } - public static List getChildren(String nodeName, Node parentNode) { List children = new ArrayList(); - + for (Node child : new NodeListDecorator(parentNode.getChildNodes())) { if (nodeName.equals(child.getNodeName())) children.add(child); } - + return children; } - public static String getAttribute(String attribute, Node node) { Node attributeNode = node.getAttributes().getNamedItem(attribute); - + if (attributeNode != null) return attributeNode.getNodeValue().trim(); - + return null; } - /** - * Get text content of the first child node matching the given node name. Use this method - * instead of {@link #selectString(String, Object)} whenever xpath support is not required, - * because it is much faster, especially for large documents. + * Get text content of the first child node matching the given node name. Use this method instead of {@link #selectString(String, Object)} whenever xpath support is not required, because it is much faster, especially for large documents. * - * @param childName search for nodes with this name - * @param parentNode search in the child nodes of this nodes + * @param childName + * search for nodes with this name + * @param parentNode + * search in the child nodes of this nodes * @return text content of the child node or null if no child with the given name was found */ public static String getTextContent(String childName, Node parentNode) { Node child = getChild(childName, parentNode); - + if (child == null) { return null; } - + return getTextContent(child); } - public static String getTextContent(Node node) { StringBuilder sb = new StringBuilder(); - + for (Node textNode : getChildren("#text", node)) { sb.append(textNode.getNodeValue()); } - + return sb.toString().trim(); } - public static Integer getIntegerContent(String childName, Node parentNode) { try { - return new Integer(getTextContent(childName, parentNode)); - } catch (NumberFormatException e) { + return new Scanner(getTextContent(childName, parentNode)).useDelimiter("\\D+").nextInt(); + } catch (Exception e) { return null; } } - + + public static Double getDecimalContent(String childName, Node parentNode) { + try { + return new Double(getTextContent(childName, parentNode)); + } catch (Exception e) { + return null; + } + } + + public static List getListContent(String childName, String delimiter, Node parentNode) { + List list = new ArrayList(); + for (Node node : getChildren(childName, parentNode)) { + String textContent = getTextContent(node); + if (textContent != null && textContent.length() > 0) { + if (delimiter == null) { + list.add(textContent); + } else { + for (String it : textContent.split(delimiter)) { + it = it.trim(); + if (it.length() > 0) { + list.add(it); + } + } + } + } + } + return list; + } private static XPathExpression getXPath(String xpath) throws XPathExpressionException { return XPathFactory.newInstance().newXPath().compile(xpath); } - /** * Dummy constructor to prevent instantiation. @@ -132,29 +165,25 @@ public final class XPathUtilities { private XPathUtilities() { throw new UnsupportedOperationException(); } - protected static class NodeListDecorator extends AbstractList { - + private final NodeList nodes; - public NodeListDecorator(NodeList nodes) { this.nodes = nodes; } - @Override public Node get(int index) { return nodes.item(index); } - @Override public int size() { return nodes.getLength(); } - + } - + } diff --git a/source/net/filebot/web/AbstractEpisodeListProvider.java b/source/net/filebot/web/AbstractEpisodeListProvider.java index 94e28bd3..31fb3f1d 100644 --- a/source/net/filebot/web/AbstractEpisodeListProvider.java +++ b/source/net/filebot/web/AbstractEpisodeListProvider.java @@ -1,6 +1,8 @@ package net.filebot.web; -import java.util.Arrays; +import static java.util.Arrays.*; + +import java.io.Serializable; import java.util.List; import java.util.Locale; import java.util.logging.Level; @@ -11,69 +13,86 @@ import net.filebot.Cache.Key; public abstract class AbstractEpisodeListProvider implements EpisodeListProvider { - @Override - public boolean hasSingleSeasonSupport() { - return true; - } - - @Override - public boolean hasLocaleSupport() { - return false; - } - protected abstract List fetchSearchResult(String query, Locale locale) throws Exception; - protected abstract List fetchEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception; + protected abstract SeriesData fetchSeriesData(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception; - public List search(String query) throws Exception { - return search(query, getDefaultLocale()); - } + protected abstract SearchResult createSearchResult(int id); + + protected abstract ResultCache getCache(); + + protected abstract SortOrder vetoRequestParameter(SortOrder order); + + protected abstract Locale vetoRequestParameter(Locale language); @Override - public List search(String query, Locale locale) throws Exception { - ResultCache cache = getCache(); - List results = (cache != null) ? cache.getSearchResult(query, locale) : null; + public List search(String query, Locale language) throws Exception { + List results = getCache().getSearchResult(query, language); if (results != null) { return results; } // perform actual search - results = fetchSearchResult(query, locale); + results = fetchSearchResult(query, language); // cache results and return - return (cache != null) ? cache.putSearchResult(query, locale, results) : results; - } - - // helper for scripting - public List getEpisodeList(SearchResult searchResult, String sortOrder, String locale) throws Exception { - return getEpisodeList(searchResult, sortOrder == null ? SortOrder.Airdate : SortOrder.forName(sortOrder), new Locale(locale)); - } - - public List getEpisodeList(SearchResult searchResult) throws Exception { - return getEpisodeList(searchResult, SortOrder.Airdate, getDefaultLocale()); + return getCache().putSearchResult(query, language, results); } @Override - public List getEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception { - ResultCache cache = getCache(); - List episodes = (cache != null) ? cache.getEpisodeList(searchResult, sortOrder, locale) : null; - if (episodes != null) { - return episodes; + public List getEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale language) throws Exception { + return getSeriesData(searchResult, sortOrder, language).getEpisodeList(); + } + + @Override + public List getEpisodeList(int id, SortOrder order, Locale language) throws Exception { + return getEpisodeList(createSearchResult(id), order, language); + } + + @Override + public SeriesInfo getSeriesInfo(SearchResult searchResult, Locale language) throws Exception { + return getSeriesData(searchResult, null, language).getSeriesInfo(); + } + + public SeriesInfo getSeriesInfo(int id, Locale language) throws Exception { + return getSeriesInfo(createSearchResult(id), language); + } + + protected SeriesData getSeriesData(SearchResult searchResult, SortOrder order, Locale language) throws Exception { + // override preferences if requested parameters are not supported + order = vetoRequestParameter(order); + language = vetoRequestParameter(language); + + SeriesData data = getCache().getSeriesData(searchResult, order, language); + if (data != null) { + return data; } - // perform actual search - episodes = fetchEpisodeList(searchResult, sortOrder, locale); + // perform actual lookup + data = fetchSeriesData(searchResult, order, language); // cache results and return - return (cache != null) ? cache.putEpisodeList(searchResult, sortOrder, locale, episodes) : episodes; + return getCache().putSeriesData(searchResult, order, language, data); } - public Locale getDefaultLocale() { - return Locale.ENGLISH; - } + protected static class SeriesData implements Serializable { + + public SeriesInfo seriesInfo; + public Episode[] episodeList; + + public SeriesData(SeriesInfo seriesInfo, List episodeList) { + this.seriesInfo = seriesInfo; + this.episodeList = episodeList.toArray(new Episode[episodeList.size()]); + } + + public SeriesInfo getSeriesInfo() { + return seriesInfo.clone(); + } + + public List getEpisodeList() { + return asList(episodeList.clone()); + } - public ResultCache getCache() { - return null; } protected static class ResultCache { @@ -91,69 +110,39 @@ public abstract class AbstractEpisodeListProvider implements EpisodeListProvider } public List putSearchResult(String query, Locale locale, List value) { - try { - cache.put(new Key(id, normalize(query), locale), value.toArray(new SearchResult[0])); - } catch (Exception e) { - Logger.getLogger(AbstractEpisodeListProvider.class.getName()).log(Level.WARNING, e.getMessage()); - } - + putData("SearchResult", normalize(query), locale, value.toArray(new SearchResult[value.size()])); return value; } public List getSearchResult(String query, Locale locale) { - try { - SearchResult[] results = cache.get(new Key(id, normalize(query), locale), SearchResult[].class); - if (results != null) { - return Arrays.asList(results); - } - } catch (Exception e) { - Logger.getLogger(AbstractEpisodeListProvider.class.getName()).log(Level.WARNING, e.getMessage(), e); - } - - return null; + SearchResult[] data = getData("SearchResult", normalize(query), locale, SearchResult[].class); + return data == null ? null : asList(data); } - public List putEpisodeList(SearchResult key, SortOrder sortOrder, Locale locale, List episodes) { - try { - cache.put(new Key(id, key, sortOrder, locale), episodes.toArray(new Episode[0])); - } catch (Exception e) { - Logger.getLogger(AbstractEpisodeListProvider.class.getName()).log(Level.WARNING, e.getMessage()); - } - - return episodes; + public SeriesData putSeriesData(SearchResult key, SortOrder sortOrder, Locale locale, SeriesData seriesData) { + putData("SeriesData." + sortOrder.name(), key, locale, seriesData); + return seriesData; } - public List getEpisodeList(SearchResult key, SortOrder sortOrder, Locale locale) { - try { - Episode[] episodes = cache.get(new Key(id, key, sortOrder, locale), Episode[].class); - if (episodes != null) { - return Arrays.asList(episodes); - } - } catch (Exception e) { - Logger.getLogger(AbstractEpisodeListProvider.class.getName()).log(Level.WARNING, e.getMessage(), e); - } - - return null; + public SeriesData getSeriesData(SearchResult key, SortOrder sortOrder, Locale locale) { + return getData("SeriesData." + sortOrder.name(), key, locale, SeriesData.class); } - public void putData(Object category, Object key, Locale locale, Object object) { + public T putData(Object category, Object key, Locale locale, T object) { try { cache.put(new Key(id, category, locale, key), object); } catch (Exception e) { Logger.getLogger(AbstractEpisodeListProvider.class.getName()).log(Level.WARNING, e.getMessage()); } + return object; } 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; - } + return cache.get(new Key(id, category, locale, key), type); } catch (Exception e) { Logger.getLogger(AbstractEpisodeListProvider.class.getName()).log(Level.WARNING, e.getMessage(), e); } - return null; } diff --git a/source/net/filebot/web/AnidbClient.java b/source/net/filebot/web/AnidbClient.java index ca53bd0b..1d32d2a8 100644 --- a/source/net/filebot/web/AnidbClient.java +++ b/source/net/filebot/web/AnidbClient.java @@ -1,5 +1,6 @@ package net.filebot.web; +import static java.util.Collections.*; import static net.filebot.util.XPathUtilities.*; import static net.filebot.web.EpisodeUtilities.*; import static net.filebot.web.WebRequest.*; @@ -58,18 +59,23 @@ public class AnidbClient extends AbstractEpisodeListProvider { } @Override - public boolean hasSingleSeasonSupport() { + public boolean hasSeasonSupport() { return false; } @Override - public boolean hasLocaleSupport() { - return true; + protected SortOrder vetoRequestParameter(SortOrder order) { + return SortOrder.Absolute; + } + + @Override + protected Locale vetoRequestParameter(Locale language) { + return language != null ? language : Locale.ENGLISH; } @Override public ResultCache getCache() { - return new ResultCache(host, Cache.getCache("web-datasource-lv2")); + return new ResultCache(getName(), Cache.getCache("web-datasource-lv2")); } @Override @@ -87,12 +93,11 @@ public class AnidbClient extends AbstractEpisodeListProvider { return set(it.getEffectiveNames()); } }; - return new ArrayList(index.search(query)); } @Override - public List fetchEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception { + protected SeriesData fetchSeriesData(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception { AnidbSearchResult anime = (AnidbSearchResult) searchResult; // e.g. http://api.anidb.net:9001/httpapi?request=anime&client=filebot&clientver=1&protover=1&aid=4521 @@ -104,22 +109,30 @@ public class AnidbClient extends AbstractEpisodeListProvider { // get anime page as xml Document dom = getDocument(url); + // parse series info + SeriesInfo seriesInfo = new SeriesInfo(getName(), sortOrder, locale, anime.getId()); + seriesInfo.setAliasNames(searchResult.getEffectiveNames()); + // AniDB types: Movie, Music Video, Other, OVA, TV Series, TV Special, Web, unknown String animeType = selectString("//type", dom); if (animeType != null && animeType.matches("(?i:music.video|unkown|other)")) { - return new ArrayList(); + return new SeriesData(seriesInfo, emptyList()); } - // select main title and anime start date - SimpleDate seriesStartDate = SimpleDate.parse(selectString("//startdate", dom), "yyyy-MM-dd"); - String animeTitle = selectString("//titles/title[@type='official' and @lang='" + locale.getLanguage() + "']", dom); - if (animeTitle.isEmpty()) { - animeTitle = selectString("//titles/title[@type='main']", dom); + seriesInfo.setName(selectString("anime/titles/title[@type='main']", dom)); + seriesInfo.setRating(new Double(selectString("anime/ratings/permanent", dom))); + seriesInfo.setRatingCount(new Integer(selectString("anime/ratings/permanent/@count", dom))); + seriesInfo.setStartDate(SimpleDate.parse(selectString("anime/startdate", dom), "yyyy-MM-dd")); + + // parse episode data + String animeTitle = selectString("anime/titles/title[@type='official' and @lang='" + locale.getLanguage() + "']", dom); + if (animeTitle == null || animeTitle.length() == 0) { + animeTitle = seriesInfo.getName(); } List episodes = new ArrayList(25); - for (Node node : selectNodes("//episode", dom)) { + for (Node node : selectNodes("anime/episodes/episode", dom)) { Node epno = getChild("epno", node); int number = Integer.parseInt(getTextContent(epno).replaceAll("\\D", "")); int type = Integer.parseInt(getAttribute("type", epno)); @@ -132,9 +145,9 @@ public class AnidbClient extends AbstractEpisodeListProvider { } if (type == 1) { - episodes.add(new Episode(animeTitle, seriesStartDate, null, number, title, number, null, SortOrder.Absolute, locale, airdate, searchResult)); // normal episode, no seasons for anime + episodes.add(new Episode(animeTitle, null, number, title, number, null, airdate, new SeriesInfo(seriesInfo))); // normal episode, no seasons for anime } else { - episodes.add(new Episode(animeTitle, seriesStartDate, null, null, title, null, number, SortOrder.Absolute, locale, airdate, searchResult)); // special episode + episodes.add(new Episode(animeTitle, null, null, title, null, number, airdate, new SeriesInfo(seriesInfo))); // special episode } } } @@ -148,7 +161,12 @@ public class AnidbClient extends AbstractEpisodeListProvider { Logger.getLogger(AnidbClient.class.getName()).log(Level.WARNING, String.format("Unable to parse episode data: %s (%d) => %s", anime, anime.getAnimeId(), getXmlString(dom, false))); } - return episodes; + return new SeriesData(seriesInfo, episodes); + } + + @Override + protected SearchResult createSearchResult(int id) { + return new AnidbSearchResult(id, null, new String[0]); } @Override diff --git a/source/net/filebot/web/Episode.java b/source/net/filebot/web/Episode.java index d6bb4f6f..5debe927 100644 --- a/source/net/filebot/web/Episode.java +++ b/source/net/filebot/web/Episode.java @@ -3,13 +3,10 @@ package net.filebot.web; import java.io.Serializable; import java.util.Arrays; import java.util.List; -import java.util.Locale; public class Episode implements Serializable { protected String seriesName; - protected SimpleDate seriesStartDate; - protected Integer season; protected Integer episode; protected String title; @@ -20,50 +17,39 @@ public class Episode implements Serializable { // special number protected Integer special; - // optional episode number order hint & episode name / title language hint - protected String order; - protected String language; - // episode airdate protected SimpleDate airdate; - // original series descriptor - protected SearchResult series; + // extended series metadata + protected SeriesInfo seriesInfo; protected Episode() { - // used by serializer + } public Episode(Episode obj) { - this(obj.seriesName, obj.seriesStartDate, obj.season, obj.episode, obj.title, obj.absolute, obj.special, obj.getOrder(), obj.getLanguage(), obj.airdate, obj.series); + this(obj.seriesName, obj.season, obj.episode, obj.title, obj.absolute, obj.special, obj.airdate, obj.seriesInfo); } - public Episode(String seriesName, SimpleDate seriesStartDate, Integer season, Integer episode, String title, SearchResult series) { - this(seriesName, seriesStartDate, season, episode, title, null, null, null, null, null, series); + public Episode(String seriesName, Integer season, Integer episode, String title) { + this(seriesName, season, episode, title, null, null, null, null); } - public Episode(String seriesName, SimpleDate seriesStartDate, Integer season, Integer episode, String title, Integer absolute, Integer special, SortOrder order, Locale locale, SimpleDate airdate, SearchResult series) { + public Episode(String seriesName, Integer season, Integer episode, String title, Integer absolute, Integer special, SimpleDate airdate, SeriesInfo seriesInfo) { this.seriesName = seriesName; - this.seriesStartDate = (seriesStartDate == null ? null : seriesStartDate.clone()); this.season = season; this.episode = episode; this.title = title; this.absolute = absolute; this.special = special; - this.order = (order == null ? null : order.name()); - this.language = (locale == null ? null : locale.getLanguage()); this.airdate = (airdate == null ? null : airdate.clone()); - this.series = (series == null ? null : series.clone()); + this.seriesInfo = (seriesInfo == null ? null : seriesInfo.clone()); } public String getSeriesName() { return seriesName; } - public SimpleDate getSeriesStartDate() { - return seriesStartDate; - } - public Integer getEpisode() { return episode; } @@ -84,20 +70,12 @@ public class Episode implements Serializable { return special; } - public SortOrder getOrder() { - return order == null ? null : SortOrder.forName(order); - } - - public Locale getLanguage() { - return language == null ? null : new Locale(language); - } - public SimpleDate getAirdate() { return airdate; } - public SearchResult getSeries() { - return series; + public SeriesInfo getSeriesInfo() { + return seriesInfo; } public List getNumbers() { diff --git a/source/net/filebot/web/EpisodeFormat.java b/source/net/filebot/web/EpisodeFormat.java index 9b7cd746..917a592d 100644 --- a/source/net/filebot/web/EpisodeFormat.java +++ b/source/net/filebot/web/EpisodeFormat.java @@ -187,7 +187,7 @@ public class EpisodeFormat extends Format { // did parse input pos.setIndex(source.length()); - return new Episode(name, null, season, episode, title, season == null ? episode : null, special, null, null, airdate, null); + return new Episode(name, season, episode, title, season == null ? episode : null, special, airdate, null); } // failed to parse input diff --git a/source/net/filebot/web/EpisodeListProvider.java b/source/net/filebot/web/EpisodeListProvider.java index 865e059b..8ed82683 100644 --- a/source/net/filebot/web/EpisodeListProvider.java +++ b/source/net/filebot/web/EpisodeListProvider.java @@ -1,34 +1,29 @@ - package net.filebot.web; - import java.net.URI; import java.util.List; import java.util.Locale; import javax.swing.Icon; - public interface EpisodeListProvider { - + public String getName(); - - + public Icon getIcon(); - - - public boolean hasSingleSeasonSupport(); - - - public boolean hasLocaleSupport(); - - + + public boolean hasSeasonSupport(); + public List search(String query, Locale locale) throws Exception; - - + public List getEpisodeList(SearchResult searchResult, SortOrder order, Locale locale) throws Exception; - - + + public List getEpisodeList(int id, SortOrder order, Locale locale) throws Exception; + + public SeriesInfo getSeriesInfo(SearchResult searchResult, Locale locale) throws Exception; + + public SeriesInfo getSeriesInfo(int id, Locale locale) throws Exception; + public URI getEpisodeListLink(SearchResult searchResult); - + } diff --git a/source/net/filebot/web/OpenSubtitlesClient.java b/source/net/filebot/web/OpenSubtitlesClient.java index 8564aae9..117d5bba 100644 --- a/source/net/filebot/web/OpenSubtitlesClient.java +++ b/source/net/filebot/web/OpenSubtitlesClient.java @@ -87,7 +87,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS } public ResultCache getCache() { - return new ResultCache("opensubtitles.org", Cache.getCache("web-datasource")); + return new ResultCache(getName(), Cache.getCache("web-datasource")); } @Override diff --git a/source/net/filebot/web/SearchResult.java b/source/net/filebot/web/SearchResult.java index 4d35414a..35b0fdfc 100644 --- a/source/net/filebot/web/SearchResult.java +++ b/source/net/filebot/web/SearchResult.java @@ -1,8 +1,9 @@ package net.filebot.web; +import static java.util.Collections.*; + import java.io.Serializable; import java.util.AbstractList; -import java.util.Collections; import java.util.List; public abstract class SearchResult implements Serializable { @@ -28,10 +29,12 @@ public abstract class SearchResult implements Serializable { } public List getEffectiveNames() { - if (aliasNames == null || aliasNames.length == 0) { - return Collections.singletonList(name); + if (name == null || name.length() == 0) { + return emptyList(); + } + if (aliasNames == null || aliasNames.length == 0) { + return singletonList(name); } - return new AbstractList() { @Override diff --git a/source/net/filebot/web/SeriesInfo.java b/source/net/filebot/web/SeriesInfo.java new file mode 100644 index 00000000..79d730ef --- /dev/null +++ b/source/net/filebot/web/SeriesInfo.java @@ -0,0 +1,203 @@ +package net.filebot.web; + +import static java.util.Arrays.*; + +import java.io.Serializable; +import java.util.List; +import java.util.Locale; + +public class SeriesInfo implements Serializable { + + // request parameters + protected String database; + protected String order; + protected String language; + + // series parameters + protected Integer id; + protected String name; + protected String[] aliasNames; + protected String[] actors; + protected String certification; + protected SimpleDate startDate; + protected String[] genres; + protected String network; + protected Double rating; + protected Integer ratingCount; + protected Integer runtime; + protected String status; + + protected SeriesInfo() { + + } + + public SeriesInfo(SeriesInfo other) { + this.database = other.database; + this.order = other.order; + this.language = other.language; + this.id = other.id; + this.name = other.name; + this.aliasNames = other.aliasNames == null ? null : other.aliasNames.clone(); + this.actors = other.actors == null ? null : other.actors.clone(); + this.certification = other.certification; + this.startDate = other.startDate == null ? null : other.startDate.clone(); + this.genres = other.genres == null ? null : other.genres.clone(); + this.network = other.network; + this.rating = other.rating; + this.ratingCount = other.ratingCount; + this.runtime = other.runtime; + this.status = other.status; + } + + public SeriesInfo(String database, SortOrder order, Locale language, Integer id) { + this.database = database; + this.order = order.name(); + this.language = language.getLanguage(); + this.id = id; + } + + public void setDatabase(String database) { + this.database = database; + } + + public String getDatabase() { + return database; + } + + public void setOrder(String order) { + this.order = order; + } + + public String getOrder() { + return order; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getLanguage() { + return language; + } + + public void setLanguage(String language) { + this.language = language; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getAliasNames() { + return aliasNames == null ? asList() : asList(aliasNames.clone()); + } + + public void setAliasNames(List aliasNames) { + this.aliasNames = aliasNames.toArray(new String[aliasNames.size()]); + } + + public List getActors() { + return actors == null ? asList() : asList(actors.clone()); + } + + public void setActors(List actors) { + this.actors = actors.toArray(new String[actors.size()]); + } + + public String getCertification() { + return certification; + } + + public void setCertification(String certification) { + this.certification = certification; + } + + public SimpleDate getStartDate() { + return startDate; + } + + public void setStartDate(SimpleDate startDate) { + this.startDate = startDate; + } + + public List getGenres() { + return genres == null ? asList() : asList(genres.clone()); + } + + public void setGenres(List genres) { + this.genres = genres.toArray(new String[genres.size()]); + } + + public String getNetwork() { + return network; + } + + public void setNetwork(String network) { + this.network = network; + } + + public Double getRating() { + return rating; + } + + public void setRating(Double rating) { + this.rating = rating; + } + + public Integer getRatingCount() { + return ratingCount; + } + + public void setRatingCount(Integer ratingCount) { + this.ratingCount = ratingCount; + } + + public Integer getRuntime() { + return runtime; + } + + public void setRuntime(Integer runtime) { + this.runtime = runtime; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + @Override + public int hashCode() { + return id; + } + + @Override + public boolean equals(Object object) { + if (object instanceof SeriesInfo) { + SeriesInfo other = (SeriesInfo) object; + return id.equals(other.id) && database.equals(other.database); + } + return false; + } + + @Override + public SeriesInfo clone() { + return new SeriesInfo(this); + } + + @Override + public String toString() { + return database + "::" + id; + } + +} diff --git a/source/net/filebot/web/TVRageClient.java b/source/net/filebot/web/TVRageClient.java index 7de05131..9e5a3dcc 100644 --- a/source/net/filebot/web/TVRageClient.java +++ b/source/net/filebot/web/TVRageClient.java @@ -43,9 +43,24 @@ public class TVRageClient extends AbstractEpisodeListProvider { return ResourceManager.getIcon("search.tvrage"); } + @Override + public boolean hasSeasonSupport() { + return true; + } + + @Override + protected SortOrder vetoRequestParameter(SortOrder order) { + return SortOrder.Airdate; + } + + @Override + protected Locale vetoRequestParameter(Locale language) { + return Locale.ENGLISH; + } + @Override public ResultCache getCache() { - return new ResultCache(host, Cache.getCache("web-datasource")); + return new ResultCache(getName(), Cache.getCache("web-datasource")); } @Override @@ -67,14 +82,24 @@ public class TVRageClient extends AbstractEpisodeListProvider { } @Override - public List fetchEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws IOException, SAXException { + protected SeriesData fetchSeriesData(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception { TVRageSearchResult series = (TVRageSearchResult) searchResult; - Document dom = request("/feeds/full_show_info.php", singletonMap("sid", series.getSeriesId())); + Document dom = request("/feeds/full_show_info.php", singletonMap("sid", series.getId())); - String seriesName = selectString("Show/name", dom); - SimpleDate seriesStartDate = SimpleDate.parse(selectString("Show/started", dom), "MMM/dd/yyyy"); - Locale language = Locale.ENGLISH; + // parse series data + Node seriesNode = selectNode("Show", dom); + SeriesInfo seriesInfo = new SeriesInfo(getName(), sortOrder, locale, series.getId()); + seriesInfo.setAliasNames(searchResult.getEffectiveNames()); + seriesInfo.setName(getTextContent("name", seriesNode)); + seriesInfo.setNetwork(getTextContent("network", seriesNode)); + seriesInfo.setRuntime(getIntegerContent("runtime", seriesNode)); + seriesInfo.setStatus(getTextContent("status", seriesNode)); + + seriesInfo.setGenres(getListContent("genre", null, getChild("genres", seriesNode))); + seriesInfo.setStartDate(SimpleDate.parse(selectString("started", seriesNode), "MMM/dd/yyyy")); + + // parse episode data List episodes = new ArrayList(25); List specials = new ArrayList(5); @@ -86,30 +111,26 @@ public class TVRageClient extends AbstractEpisodeListProvider { Integer seasonNumber = seasonIdentifier == null ? null : new Integer(seasonIdentifier); SimpleDate airdate = SimpleDate.parse(getTextContent("airdate", node), "yyyy-MM-dd"); - SortOrder order = SortOrder.Airdate; // default order - // check if we have season and episode number, if not it must be a special episode if (episodeNumber == null || seasonNumber == null) { // handle as special episode seasonNumber = getIntegerContent("season", node); int specialNumber = filterBySeason(specials, seasonNumber).size() + 1; - specials.add(new Episode(seriesName, seriesStartDate, seasonNumber, null, title, null, specialNumber, order, language, airdate, searchResult)); + specials.add(new Episode(seriesInfo.getName(), seasonNumber, null, title, null, specialNumber, airdate, new SeriesInfo(seriesInfo))); } else { // handle as normal episode if (sortOrder == SortOrder.Absolute) { episodeNumber = getIntegerContent("epnum", node); seasonNumber = null; - order = SortOrder.Absolute; } - - episodes.add(new Episode(seriesName, seriesStartDate, seasonNumber, episodeNumber, title, null, null, order, language, airdate, searchResult)); + episodes.add(new Episode(seriesInfo.getName(), seasonNumber, episodeNumber, title, null, null, airdate, new SeriesInfo(seriesInfo))); } } // add specials at the end episodes.addAll(specials); - return episodes; + return new SeriesData(seriesInfo, episodes); } public Document request(String resource, Map parameters) throws IOException, SAXException { @@ -121,6 +142,11 @@ public class TVRageClient extends AbstractEpisodeListProvider { return getDocument(url); } + @Override + protected SearchResult createSearchResult(int id) { + return new TVRageSearchResult(null, id, null); + } + @Override public URI getEpisodeListLink(SearchResult searchResult) { return URI.create(((TVRageSearchResult) searchResult).getLink() + "/episode_list/all"); diff --git a/source/net/filebot/web/TheTVDBClient.java b/source/net/filebot/web/TheTVDBClient.java index 561f0981..1acd01aa 100644 --- a/source/net/filebot/web/TheTVDBClient.java +++ b/source/net/filebot/web/TheTVDBClient.java @@ -29,7 +29,6 @@ import net.filebot.Cache; import net.filebot.ResourceManager; import net.filebot.util.FileUtilities; import net.filebot.web.TheTVDBClient.BannerDescriptor.BannerProperty; -import net.filebot.web.TheTVDBClient.SeriesInfo.SeriesProperty; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -60,13 +59,23 @@ public class TheTVDBClient extends AbstractEpisodeListProvider { } @Override - public boolean hasSingleSeasonSupport() { + public boolean hasSeasonSupport() { return true; } @Override - public boolean hasLocaleSupport() { - return true; + protected SortOrder vetoRequestParameter(SortOrder order) { + return order != null ? order : SortOrder.Airdate; + } + + @Override + protected Locale vetoRequestParameter(Locale language) { + return language != null ? language : Locale.ENGLISH; + } + + @Override + public ResultCache getCache() { + return new ResultCache(getName(), Cache.getCache("web-datasource")); } public String getLanguageCode(Locale locale) { @@ -85,11 +94,6 @@ public class TheTVDBClient extends AbstractEpisodeListProvider { return code; } - @Override - public ResultCache getCache() { - return new ResultCache(host, Cache.getCache("web-datasource")); - } - @Override public List fetchSearchResult(String query, Locale locale) throws Exception { // perform online search @@ -120,14 +124,36 @@ public class TheTVDBClient extends AbstractEpisodeListProvider { } @Override - public List fetchEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception { + protected SeriesData fetchSeriesData(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception { TheTVDBSearchResult series = (TheTVDBSearchResult) searchResult; Document dom = getXmlResource(MirrorType.XML, "/api/" + apikey + "/series/" + series.getSeriesId() + "/all/" + getLanguageCode(locale) + ".xml"); - // we could get the series name from the search result, but the language may not match the given parameter - String seriesName = selectString("Data/Series/SeriesName", dom); - SimpleDate seriesStartDate = SimpleDate.parse(selectString("Data/Series/FirstAired", dom), "yyyy-MM-dd"); + // parse series info + Node seriesNode = selectNode("Data/Series", dom); + TheTVDBSeriesInfo seriesInfo = new TheTVDBSeriesInfo(getName(), sortOrder, locale, series.getId()); + seriesInfo.setAliasNames(searchResult.getEffectiveNames()); + seriesInfo.setName(getTextContent("SeriesName", seriesNode)); + seriesInfo.setAirsDayOfWeek(getTextContent("Airs_DayOfWeek", seriesNode)); + seriesInfo.setAirTime(getTextContent("Airs_Time", seriesNode)); + seriesInfo.setCertification(getTextContent("ContentRating", seriesNode)); + seriesInfo.setImdbId(getTextContent("IMDB_ID", seriesNode)); + seriesInfo.setNetwork(getTextContent("Network", seriesNode)); + seriesInfo.setOverview(getTextContent("Overview", seriesNode)); + seriesInfo.setStatus(getTextContent("Status", seriesNode)); + + seriesInfo.setRating(getDecimalContent("Rating", seriesNode)); + seriesInfo.setRatingCount(getIntegerContent("RatingCount", seriesNode)); + seriesInfo.setRuntime(getIntegerContent("Runtime", seriesNode)); + seriesInfo.setActors(getListContent("Actors", "\\|", seriesNode)); + seriesInfo.setGenres(getListContent("Genre", "\\|", seriesNode)); + seriesInfo.setStartDate(SimpleDate.parse(getTextContent("FirstAired", seriesNode), "yyyy-MM-dd")); + + seriesInfo.setBannerUrl(getResourceURL(MirrorType.BANNER, "/banners/" + getTextContent("banner", seriesNode))); + seriesInfo.setFanartUrl(getResourceURL(MirrorType.BANNER, "/banners/" + getTextContent("fanart", seriesNode))); + seriesInfo.setPosterUrl(getResourceURL(MirrorType.BANNER, "/banners/" + getTextContent("poster", seriesNode))); + + // parse episode data List nodes = selectNodes("Data/Episode", dom); List episodes = new ArrayList(nodes.size()); @@ -143,7 +169,6 @@ public class TheTVDBClient extends AbstractEpisodeListProvider { // default numbering Integer episodeNumber = getIntegerContent("EpisodeNumber", node); Integer seasonNumber = getIntegerContent("SeasonNumber", node); - SortOrder order = SortOrder.Airdate; if (seasonNumber == null || seasonNumber == 0) { // handle as special episode @@ -154,14 +179,13 @@ public class TheTVDBClient extends AbstractEpisodeListProvider { // use given episode number as special number or count specials by ourselves Integer specialNumber = (episodeNumber != null) ? episodeNumber : filterBySeason(specials, seasonNumber).size() + 1; - specials.add(new Episode(seriesName, seriesStartDate, seasonNumber, null, episodeName, null, specialNumber, order, locale, airdate, searchResult)); + specials.add(new Episode(seriesInfo.getName(), seasonNumber, null, episodeName, null, specialNumber, airdate, new SeriesInfo(seriesInfo))); } else { // handle as normal episode if (sortOrder == SortOrder.Absolute) { if (absoluteNumber != null) { episodeNumber = absoluteNumber; seasonNumber = null; - order = SortOrder.Absolute; } } else if (sortOrder == SortOrder.DVD) { try { @@ -171,13 +195,12 @@ public class TheTVDBClient extends AbstractEpisodeListProvider { // require both values to be successfully read episodeNumber = eno; seasonNumber = sno; - order = SortOrder.DVD; } catch (Exception e) { // ignore, fallback to default numbering } } - episodes.add(new Episode(seriesName, seriesStartDate, seasonNumber, episodeNumber, episodeName, absoluteNumber, null, order, locale, airdate, searchResult)); + episodes.add(new Episode(seriesInfo.getName(), seasonNumber, episodeNumber, episodeName, absoluteNumber, null, airdate, new SeriesInfo(seriesInfo))); } } @@ -187,7 +210,7 @@ public class TheTVDBClient extends AbstractEpisodeListProvider { // add specials at the end episodes.addAll(specials); - return episodes; + return new SeriesData(seriesInfo, episodes); } public TheTVDBSearchResult lookupByID(int id, Locale locale) throws Exception { @@ -227,11 +250,6 @@ public class TheTVDBClient extends AbstractEpisodeListProvider { return series; } - @Override - public URI getEpisodeListLink(SearchResult searchResult) { - return URI.create("http://" + host + "/?tab=seasonall&id=" + ((TheTVDBSearchResult) searchResult).getSeriesId()); - } - protected String getMirror(MirrorType mirrorType) throws IOException { synchronized (mirrors) { if (mirrors.isEmpty()) { @@ -340,229 +358,18 @@ public class TheTVDBClient extends AbstractEpisodeListProvider { } - public SeriesInfo getSeriesInfoByID(int thetvdbid, Locale locale) throws Exception { - return getSeriesInfo(new TheTVDBSearchResult(null, thetvdbid), locale); - } - public SeriesInfo getSeriesInfoByIMDbID(int imdbid, Locale locale) throws Exception { return getSeriesInfo(lookupByIMDbID(imdbid, locale), locale); } - public SeriesInfo getSeriesInfoByName(String name, Locale locale) throws Exception { - for (SearchResult it : search(name, locale)) { - if (name.equalsIgnoreCase(it.getName())) { - return getSeriesInfo((TheTVDBSearchResult) it, locale); - } - } - - return null; + @Override + protected SearchResult createSearchResult(int id) { + return new TheTVDBSearchResult(null, id); } - public SeriesInfo getSeriesInfo(TheTVDBSearchResult searchResult, Locale locale) throws Exception { - // check cache first - SeriesInfo cachedItem = getCache().getData("seriesInfo", searchResult.seriesId, locale, SeriesInfo.class); - if (cachedItem != null) { - return cachedItem; - } - - Document dom = getXmlResource(MirrorType.XML, "/api/" + apikey + "/series/" + searchResult.seriesId + "/" + getLanguageCode(locale) + ".xml"); - - Node node = selectNode("//Series", dom); - Map fields = new EnumMap(SeriesProperty.class); - - // remember banner mirror - fields.put(SeriesProperty.BannerMirror, getResourceURL(MirrorType.BANNER, "/banners/").toString()); - - // copy values from xml - for (SeriesProperty key : SeriesProperty.values()) { - String value = getTextContent(key.name(), node); - if (value != null && value.length() > 0) { - fields.put(key, value); - } - } - - SeriesInfo seriesInfo = new SeriesInfo(fields); - getCache().putData("seriesInfo", searchResult.seriesId, locale, seriesInfo); - return seriesInfo; - } - - public static class SeriesInfo implements Serializable { - - public static enum SeriesProperty { - id, Actors, Airs_DayOfWeek, Airs_Time, ContentRating, FirstAired, Genre, IMDB_ID, Language, Network, Overview, Rating, RatingCount, Runtime, SeriesName, Status, BannerMirror, banner, fanart, poster - } - - protected Map fields; - - protected SeriesInfo() { - // used by serializer - } - - protected SeriesInfo(Map fields) { - this.fields = new EnumMap(fields); - } - - public String get(Object key) { - return fields.get(SeriesProperty.valueOf(key.toString())); - } - - public String get(SeriesProperty key) { - return fields.get(key); - } - - public Integer getId() { - // e.g. 80348 - try { - return Integer.parseInt(get(SeriesProperty.id)); - } catch (Exception e) { - return null; - } - } - - public List getActors() { - // e.g. |Zachary Levi|Adam Baldwin|Yvonne Strzechowski| - return split(get(SeriesProperty.Actors)); - } - - public List getGenres() { - // e.g. |Comedy| - return split(get(SeriesProperty.Genre)); - } - - protected List split(String values) { - List items = new ArrayList(); - if (values != null && values.length() > 0) { - for (String it : values.split("[|]")) { - it = it.trim(); - if (it.length() > 0) { - items.add(it); - } - } - } - return items; - } - - public String getAirDayOfWeek() { - // e.g. Monday - return get(SeriesProperty.Airs_DayOfWeek); - } - - public String getAirTime() { - // e.g. 8:00 PM - return get(SeriesProperty.Airs_Time); - } - - public SimpleDate getFirstAired() { - // e.g. 2007-09-24 - return SimpleDate.parse(get(SeriesProperty.FirstAired), "yyyy-MM-dd"); - } - - public String getContentRating() { - // e.g. TV-PG - return get(SeriesProperty.ContentRating); - } - - public String getCertification() { - return getContentRating(); // another getter for compability reasons - } - - public Integer getImdbId() { - // e.g. tt0934814 - try { - return Integer.parseInt(get(SeriesProperty.IMDB_ID).substring(2)); - } catch (Exception e) { - return null; - } - } - - public Locale getLanguage() { - // e.g. en - try { - return new Locale(get(SeriesProperty.Language)); - } catch (Exception e) { - return null; - } - } - - public String getOverview() { - // e.g. Zachary Levi (Less Than Perfect) plays Chuck... - return get(SeriesProperty.Overview); - } - - public Double getRating() { - // e.g. 9.0 - try { - return Double.parseDouble(get(SeriesProperty.Rating)); - } catch (Exception e) { - return null; - } - } - - public Integer getRatingCount() { - // e.g. 696 - try { - return Integer.parseInt(get(SeriesProperty.RatingCount)); - } catch (Exception e) { - return null; - } - } - - public String getRuntime() { - // e.g. 30 - return get(SeriesProperty.Runtime); - } - - public String getName() { - // e.g. Chuck - return get(SeriesProperty.SeriesName); - } - - public String getNetwork() { - // e.g. CBS - return get(SeriesProperty.Network); - } - - public String getStatus() { - // e.g. Continuing - return get(SeriesProperty.Status); - } - - public URL getBannerMirrorUrl() { - try { - return new URL(get(BannerProperty.BannerMirror)); - } catch (Exception e) { - return null; - } - } - - public URL getBannerUrl() throws MalformedURLException { - try { - return new URL(getBannerMirrorUrl(), get(SeriesProperty.banner)); - } catch (Exception e) { - return null; - } - } - - public URL getFanartUrl() { - try { - return new URL(getBannerMirrorUrl(), get(SeriesProperty.fanart)); - } catch (Exception e) { - return null; - } - } - - public URL getPosterUrl() { - try { - return new URL(getBannerMirrorUrl(), get(SeriesProperty.poster)); - } catch (Exception e) { - return null; - } - } - - @Override - public String toString() { - return fields.toString(); - } + @Override + public URI getEpisodeListLink(SearchResult searchResult) { + return URI.create("http://" + host + "/?tab=seasonall&id=" + ((TheTVDBSearchResult) searchResult).getSeriesId()); } /** diff --git a/source/net/filebot/web/TheTVDBSeriesInfo.java b/source/net/filebot/web/TheTVDBSeriesInfo.java new file mode 100644 index 00000000..a9bd689f --- /dev/null +++ b/source/net/filebot/web/TheTVDBSeriesInfo.java @@ -0,0 +1,115 @@ +package net.filebot.web; + +import java.io.Serializable; +import java.net.URL; +import java.util.Locale; + +public class TheTVDBSeriesInfo extends SeriesInfo implements Serializable { + + protected String imdbId; + protected String overview; + + protected String airsDayOfWeek; + protected String airTime; + + protected String bannerUrl; + protected String fanartUrl; + protected String posterUrl; + + protected TheTVDBSeriesInfo() { + super(); + } + + public TheTVDBSeriesInfo(TheTVDBSeriesInfo other) { + super(other); + this.imdbId = other.imdbId; + this.overview = other.overview; + this.airsDayOfWeek = other.airsDayOfWeek; + this.airTime = other.airTime; + this.bannerUrl = other.bannerUrl; + this.fanartUrl = other.fanartUrl; + this.posterUrl = other.posterUrl; + } + + public TheTVDBSeriesInfo(String database, SortOrder order, Locale language, Integer id) { + super(database, order, language, id); + } + + public SimpleDate getFirstAired() { + return getStartDate(); + } + + public String getContentRating() { + return getCertification(); + } + + public String getImdbId() { + return imdbId; + } + + public void setImdbId(String imdbId) { + this.imdbId = imdbId; + } + + public String getOverview() { + return overview; + } + + public void setOverview(String overview) { + this.overview = overview; + } + + public String getAirsDayOfWeek() { + return airsDayOfWeek; + } + + public void setAirsDayOfWeek(String airsDayOfWeek) { + this.airsDayOfWeek = airsDayOfWeek; + } + + public String getAirTime() { + return airTime; + } + + public void setAirTime(String airTime) { + this.airTime = airTime; + } + + public String getBannerUrl() { + return bannerUrl; + } + + public void setBannerUrl(URL bannerUrl) { + this.bannerUrl = bannerUrl.toString(); + } + + public URL getFanartUrl() { + try { + return new URL(fanartUrl); + } catch (Exception e) { + return null; + } + } + + public void setFanartUrl(URL fanartUrl) { + this.fanartUrl = fanartUrl.toString(); + } + + public URL getPosterUrl() { + try { + return new URL(posterUrl); + } catch (Exception e) { + return null; + } + } + + public void setPosterUrl(URL posterUrl) { + this.posterUrl = posterUrl.toString(); + } + + @Override + public TheTVDBSeriesInfo clone() { + return new TheTVDBSeriesInfo(this); + } + +} diff --git a/test/net/filebot/similarity/EpisodeMetricsTest.java b/test/net/filebot/similarity/EpisodeMetricsTest.java index a51b0734..835034df 100644 --- a/test/net/filebot/similarity/EpisodeMetricsTest.java +++ b/test/net/filebot/similarity/EpisodeMetricsTest.java @@ -8,8 +8,6 @@ import java.util.ArrayList; import java.util.List; import net.filebot.web.Episode; -import net.filebot.web.SimpleDate; -import net.filebot.web.TheTVDBSearchResult; import org.junit.Test; @@ -17,7 +15,7 @@ public class EpisodeMetricsTest { @Test public void substringMetrics() { - Episode eY1T1 = new Episode("Doctor Who", new SimpleDate(2005, 0, 0), 1, 1, "Rose", new TheTVDBSearchResult("Doctor Who", -1)); + Episode eY1T1 = new Episode("Doctor Who", 1, 1, "Rose"); // Episode eY2T2 = new Episode("Doctor Who", new Date(1963, 0, 0), 1, 1, "An Unearthly Child"); File fY1T1 = new File("Doctor Who (2005)/Doctor Who - 1x01 - Rose"); File fY2T2 = new File("Doctor Who (1963)/Doctor Who - 1x01 - An Unearthly Child"); @@ -48,8 +46,8 @@ public class EpisodeMetricsTest { files.add(new File("Greek/Greek - S01E19 - No Campus for Old Rules")); files.add(new File("Veronica Mars - Season 1/Veronica Mars [1x19] Hot Dogs")); - episodes.add(new Episode("Veronica Mars", null, 1, 19, "Hot Dogs", new TheTVDBSearchResult("Veronica Mars", -1))); - episodes.add(new Episode("Greek", null, 1, 19, "No Campus for Old Rules", new TheTVDBSearchResult("Greek", -1))); + episodes.add(new Episode("Veronica Mars", 1, 19, "Hot Dogs")); + episodes.add(new Episode("Greek", 1, 19, "No Campus for Old Rules")); SimilarityMetric[] metrics = new SimilarityMetric[] { EpisodeIdentifier, SubstringFields }; List> m = new Matcher(files, episodes, true, metrics).match(); @@ -59,5 +57,4 @@ public class EpisodeMetricsTest { assertEquals("Veronica Mars [1x19] Hot Dogs", m.get(1).getValue().getName()); assertEquals("Veronica Mars - 1x19 - Hot Dogs", m.get(1).getCandidate().toString()); } - } diff --git a/test/net/filebot/web/AnidbClientTest.java b/test/net/filebot/web/AnidbClientTest.java index d9d9cab1..27ac5ce6 100644 --- a/test/net/filebot/web/AnidbClientTest.java +++ b/test/net/filebot/web/AnidbClientTest.java @@ -45,7 +45,7 @@ public class AnidbClientTest { @Test public void search() throws Exception { - List results = anidb.search("one piece"); + List results = anidb.search("one piece", Locale.ENGLISH); AnidbSearchResult result = (AnidbSearchResult) results.get(0); assertEquals("One Piece", result.getName()); @@ -54,7 +54,7 @@ public class AnidbClientTest { @Test public void searchNoMatch() throws Exception { - List results = anidb.search("i will not find anything for this query string"); + List results = anidb.search("i will not find anything for this query string", Locale.ENGLISH); assertTrue(results.isEmpty()); } @@ -62,23 +62,23 @@ public class AnidbClientTest { @Test public void searchTitleAlias() throws Exception { // Seikai no Senki (main title), Banner of the Stars (official English title) - assertEquals("Seikai no Senki", anidb.search("banner of the stars").get(0).getName()); - assertEquals("Seikai no Senki", anidb.search("seikai no senki").get(0).getName()); + assertEquals("Seikai no Senki", anidb.search("banner of the stars", Locale.ENGLISH).get(0).getName()); + assertEquals("Seikai no Senki", anidb.search("seikai no senki", Locale.ENGLISH).get(0).getName()); // no matching title - assertEquals("Naruto", anidb.search("naruto").get(0).getName()); + assertEquals("Naruto", anidb.search("naruto", Locale.ENGLISH).get(0).getName()); } @Test public void getEpisodeListAll() throws Exception { - List list = anidb.getEpisodeList(monsterSearchResult); + List list = anidb.getEpisodeList(monsterSearchResult, SortOrder.Airdate, Locale.ENGLISH); assertEquals(77, list.size()); Episode first = list.get(0); assertEquals("Monster", first.getSeriesName()); - assertEquals("2004-04-07", first.getSeriesStartDate().toString()); + assertEquals("2004-04-07", first.getSeriesInfo().getStartDate().toString()); assertEquals("Herr Dr. Tenma", first.getTitle()); assertEquals("1", first.getEpisode().toString()); assertEquals("1", first.getAbsolute().toString()); @@ -88,14 +88,14 @@ public class AnidbClientTest { @Test public void getEpisodeListAllShortLink() throws Exception { - List list = anidb.getEpisodeList(twelvekingdomsSearchResult); + List list = anidb.getEpisodeList(twelvekingdomsSearchResult, SortOrder.Airdate, Locale.ENGLISH); assertEquals(46, list.size()); Episode first = list.get(0); assertEquals("The Twelve Kingdoms", first.getSeriesName()); - assertEquals("2002-04-09", first.getSeriesStartDate().toString()); + assertEquals("2002-04-09", first.getSeriesInfo().getStartDate().toString()); assertEquals("Shadow of the Moon, The Sea of Shadow - Chapter 1", first.getTitle()); assertEquals("1", first.getEpisode().toString()); assertEquals("1", first.getAbsolute().toString()); @@ -105,7 +105,7 @@ public class AnidbClientTest { @Test public void getEpisodeListEncoding() throws Exception { - assertEquals("Raven Princess - An der schönen blauen Donau", anidb.getEpisodeList(princessTutuSearchResult).get(6).getTitle()); + assertEquals("Raven Princess - An der schönen blauen Donau", anidb.getEpisodeList(princessTutuSearchResult, SortOrder.Airdate, Locale.ENGLISH).get(6).getTitle()); } @Test @@ -114,7 +114,7 @@ public class AnidbClientTest { Episode last = list.get(73); assertEquals("モンスター", last.getSeriesName()); - assertEquals("2004-04-07", last.getSeriesStartDate().toString()); + assertEquals("2004-04-07", last.getSeriesInfo().getStartDate().toString()); assertEquals("本当の怪物", last.getTitle()); assertEquals("74", last.getEpisode().toString()); assertEquals("74", last.getAbsolute().toString()); @@ -124,7 +124,7 @@ public class AnidbClientTest { @Test public void getEpisodeListTrimRecap() throws Exception { - assertEquals("Sea God of the East, Azure Sea of the West - Transition Chapter", anidb.getEpisodeList(twelvekingdomsSearchResult).get(44).getTitle()); + assertEquals("Sea God of the East, Azure Sea of the West - Transition Chapter", anidb.getEpisodeList(twelvekingdomsSearchResult, SortOrder.Airdate, Locale.ENGLISH).get(44).getTitle()); } @Test diff --git a/test/net/filebot/web/TVRageClientTest.java b/test/net/filebot/web/TVRageClientTest.java index 8a3547f1..fcab3089 100644 --- a/test/net/filebot/web/TVRageClientTest.java +++ b/test/net/filebot/web/TVRageClientTest.java @@ -3,6 +3,7 @@ package net.filebot.web; import static org.junit.Assert.*; import java.util.List; +import java.util.Locale; import org.junit.Test; @@ -15,7 +16,7 @@ public class TVRageClientTest { @Test public void search() throws Exception { - List results = tvrage.search("Buffy"); + List results = tvrage.search("Buffy", Locale.ENGLISH); TVRageSearchResult result = (TVRageSearchResult) results.get(0); @@ -28,14 +29,14 @@ public class TVRageClientTest { @Test public void getEpisodeList() throws Exception { - List list = EpisodeUtilities.filterBySeason(tvrage.getEpisodeList(buffySearchResult), 7); + List list = EpisodeUtilities.filterBySeason(tvrage.getEpisodeList(buffySearchResult, SortOrder.Airdate, Locale.ENGLISH), 7); assertEquals(22, list.size()); Episode chosen = list.get(21); assertEquals("Buffy the Vampire Slayer", chosen.getSeriesName()); - assertEquals("1997-03-10", chosen.getSeriesStartDate().toString()); + assertEquals("1997-03-10", chosen.getSeriesInfo().getStartDate().toString()); assertEquals("Chosen", chosen.getTitle()); assertEquals("22", chosen.getEpisode().toString()); assertEquals("7", chosen.getSeason().toString()); @@ -45,7 +46,7 @@ public class TVRageClientTest { @Test public void getEpisodeListAll() throws Exception { - List list = tvrage.getEpisodeList(buffySearchResult); + List list = tvrage.getEpisodeList(buffySearchResult, SortOrder.Airdate, Locale.ENGLISH); assertEquals(143, list.size()); diff --git a/test/net/filebot/web/TheTVDBClientTest.java b/test/net/filebot/web/TheTVDBClientTest.java index 5de33330..8a238d67 100644 --- a/test/net/filebot/web/TheTVDBClientTest.java +++ b/test/net/filebot/web/TheTVDBClientTest.java @@ -1,7 +1,5 @@ - package net.filebot.web; - import static org.junit.Assert.*; import java.util.EnumSet; @@ -12,62 +10,57 @@ import java.util.Map; import net.filebot.web.TheTVDBClient.BannerDescriptor; import net.filebot.web.TheTVDBClient.MirrorType; -import net.filebot.web.TheTVDBClient.SeriesInfo; import net.sf.ehcache.CacheManager; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; - public class TheTVDBClientTest { - + private TheTVDBClient thetvdb = new TheTVDBClient("BA864DEE427E384A"); - - + @Test public void search() throws Exception { // test default language and query escaping (blanks) - List results = thetvdb.search("babylon 5"); - + List results = thetvdb.search("babylon 5", Locale.ENGLISH); + assertEquals(2, results.size()); - + TheTVDBSearchResult first = (TheTVDBSearchResult) results.get(0); - + assertEquals("Babylon 5", first.getName()); assertEquals(70726, first.getSeriesId()); } - - + @Test public void searchGerman() throws Exception { List results = thetvdb.search("Buffy the Vampire Slayer", Locale.GERMAN); - + assertEquals(2, results.size()); - + TheTVDBSearchResult first = (TheTVDBSearchResult) results.get(0); - + assertEquals("Buffy the Vampire Slayer", first.getName()); assertEquals(70327, first.getSeriesId()); } - - + @Test public void getEpisodeListAll() throws Exception { - List list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Buffy the Vampire Slayer", 70327)); - + List list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Buffy the Vampire Slayer", 70327), SortOrder.Airdate, Locale.ENGLISH); + assertTrue(list.size() >= 144); - + // check ordinary episode Episode first = list.get(0); assertEquals("Buffy the Vampire Slayer", first.getSeriesName()); - assertEquals("1997-03-10", first.getSeriesStartDate().toString()); + assertEquals("1997-03-10", first.getSeriesInfo().getStartDate().toString()); assertEquals("Welcome to the Hellmouth (1)", first.getTitle()); assertEquals("1", first.getEpisode().toString()); assertEquals("1", first.getSeason().toString()); assertEquals("1", first.getAbsolute().toString()); assertEquals("1997-03-10", first.getAirdate().toString()); - + // check special episode Episode last = list.get(list.size() - 1); assertEquals("Buffy the Vampire Slayer", last.getSeriesName()); @@ -78,98 +71,89 @@ public class TheTVDBClientTest { assertEquals("1", last.getSpecial().toString()); assertEquals(null, last.getAirdate()); } - - + @Test public void getEpisodeListSingleSeason() throws Exception { - List list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Wonderfalls", 78845)); - + List list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Wonderfalls", 78845), SortOrder.Airdate, Locale.ENGLISH); + Episode first = list.get(0); - + assertEquals("Wonderfalls", first.getSeriesName()); - assertEquals("2004-03-12", first.getSeriesStartDate().toString()); + assertEquals("2004-03-12", first.getSeriesInfo().getStartDate().toString()); assertEquals("Wax Lion", first.getTitle()); assertEquals("1", first.getEpisode().toString()); assertEquals("1", first.getSeason().toString()); assertEquals(null, first.getAbsolute()); // should be "1" but data has not yet been entered assertEquals("2004-03-12", first.getAirdate().toString()); } - - + @Test public void getEpisodeListNumbering() throws Exception { List list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Firefly", 78874), SortOrder.DVD, Locale.ENGLISH); - + Episode first = list.get(0); assertEquals("Firefly", first.getSeriesName()); - assertEquals("2002-09-20", first.getSeriesStartDate().toString()); + assertEquals("2002-09-20", first.getSeriesInfo().getStartDate().toString()); assertEquals("Serenity", first.getTitle()); assertEquals("1", first.getEpisode().toString()); assertEquals("1", first.getSeason().toString()); assertEquals("1", first.getAbsolute().toString()); assertEquals("2002-12-20", first.getAirdate().toString()); } - - + @Test public void getEpisodeListLink() { assertEquals("http://www.thetvdb.com/?tab=seasonall&id=78874", thetvdb.getEpisodeListLink(new TheTVDBSearchResult("Firefly", 78874)).toString()); } - - + @Test public void getMirror() throws Exception { assertNotNull(thetvdb.getMirror(MirrorType.XML)); assertNotNull(thetvdb.getMirror(MirrorType.BANNER)); assertNotNull(thetvdb.getMirror(MirrorType.ZIP)); } - - + @Test public void resolveTypeMask() { // no flags set assertEquals(EnumSet.noneOf(MirrorType.class), MirrorType.fromTypeMask(0)); - + // xml and zip flags set assertEquals(EnumSet.of(MirrorType.ZIP, MirrorType.XML, MirrorType.SEARCH), MirrorType.fromTypeMask(5)); - + // all flags set assertEquals(EnumSet.allOf(MirrorType.class), MirrorType.fromTypeMask(7)); } - - + @Test public void lookupByID() throws Exception { TheTVDBSearchResult series = thetvdb.lookupByID(78874, Locale.ENGLISH); assertEquals("Firefly", series.getName()); assertEquals(78874, series.getSeriesId()); } - - + @Test public void lookupByIMDbID() throws Exception { TheTVDBSearchResult series = thetvdb.lookupByIMDbID(303461, Locale.ENGLISH); assertEquals("Firefly", series.getName()); assertEquals(78874, series.getSeriesId()); } - - + @Test public void getSeriesInfo() throws Exception { - SeriesInfo it = thetvdb.getSeriesInfo(new TheTVDBSearchResult(null, 80348), Locale.ENGLISH); - + TheTVDBSeriesInfo it = (TheTVDBSeriesInfo) thetvdb.getSeriesInfo(new TheTVDBSearchResult(null, 80348), Locale.ENGLISH); + assertEquals(80348, it.getId(), 0); assertEquals("TV-PG", it.getContentRating()); assertEquals("2007-09-24", it.getFirstAired().toString()); assertEquals("Action", it.getGenres().get(0)); - assertEquals(934814, it.getImdbId(), 0); - assertEquals("English", it.getLanguage().getDisplayLanguage(Locale.ENGLISH)); + assertEquals("tt0934814", it.getImdbId()); + assertEquals("English", it.getLanguage()); assertEquals(310, it.getOverview().length()); assertEquals("60", it.getRuntime()); assertEquals("Chuck", it.getName()); } - - + @Test public void getBanner() throws Exception { Map filter = new HashMap(); @@ -177,31 +161,29 @@ public class TheTVDBClientTest { filter.put("BannerType2", "seasonwide"); filter.put("Season", "7"); filter.put("Language", "en"); - + BannerDescriptor banner = thetvdb.getBanner(new TheTVDBSearchResult("Buffy the Vampire Slayer", 70327), filter); - + assertEquals(857660, banner.getId(), 0); assertEquals("season", banner.getBannerType()); assertEquals("seasonwide", banner.getBannerType2()); assertEquals("http://thetvdb.com/banners/seasonswide/70327-7.jpg", banner.getUrl().toString()); assertEquals(99712, WebRequest.fetch(banner.getUrl()).remaining(), 0); } - - + @Test public void getBannerList() throws Exception { List banners = thetvdb.getBannerList(new TheTVDBSearchResult("Buffy the Vampire Slayer", 70327)); - + assertEquals("fanart", banners.get(0).getBannerType()); assertEquals("1280x720", banners.get(0).getBannerType2()); assertEquals(486993, WebRequest.fetch(banners.get(0).getUrl()).remaining(), 0); } - - + @BeforeClass @AfterClass public static void clearCache() { CacheManager.getInstance().clearAll(); } - + }