+ major rewrite of episode metadata / SeriesInfo

This commit is contained in:
Reinhard Pointner 2014-12-10 18:53:58 +00:00
parent b912baccac
commit 4022251746
23 changed files with 735 additions and 653 deletions

View File

@ -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<SearchResult> results = getLocalIndex().search(name);
if (results.size() > 0) {
return getSeriesInfo((TheTVDBSearchResult) results.get(0), locale);
}
return null;
}
@Override
public List<SearchResult> fetchSearchResult(final String query, final Locale locale) throws Exception {
Callable<List<SearchResult>> 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) {

View File

@ -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;
}

View File

@ -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<SearchResult> getProbableMatches(String query, Collection<SearchResult> options) {

View File

@ -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<String> keywords = new LinkedHashSet<String>(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<String> 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<String, SeriesInfo> seriesInfoCache = new HashMap<String, SeriesInfo>();
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;

View File

@ -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<TableModel> {
@ -59,20 +59,17 @@ class AttributeTool extends Tool<TableModel> {
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) {

View File

@ -124,7 +124,7 @@ public class EpisodeListPanel extends AbstractSearchPanel<EpisodeListProvider, E
EpisodeListProvider provider = searchTextField.getSelectButton().getSelectedValue();
// lock season spinner on "All Seasons" if provider doesn't support fetching of single seasons
if (!provider.hasSingleSeasonSupport()) {
if (!provider.hasSeasonSupport()) {
seasonSpinnerModel.lock(ALL_SEASONS);
} else {
seasonSpinnerModel.unlock();

View File

@ -60,8 +60,8 @@ import net.filebot.util.ui.EmptySelectionModel;
import net.filebot.web.Movie;
import net.filebot.web.OpenSubtitlesClient;
import net.filebot.web.SearchResult;
import net.filebot.web.TheTVDBClient.SeriesInfo;
import net.filebot.web.TheTVDBSearchResult;
import net.filebot.web.TheTVDBSeriesInfo;
import net.filebot.web.VideoHashSubtitleService.CheckResult;
import net.miginfocom.swing.MigLayout;
@ -689,10 +689,10 @@ public class SubtitleUploadDialog extends JDialog {
for (String name : seriesNames) {
List<SearchResult> 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;
}
}

View File

@ -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<Node> 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<String> selectStrings(String xpath, Object node) {
List<String> values = new ArrayList<String>();
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<Node> getChildren(String nodeName, Node parentNode) {
List<Node> children = new ArrayList<Node>();
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<String> getListContent(String childName, String delimiter, Node parentNode) {
List<String> list = new ArrayList<String>();
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<Node> {
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();
}
}
}

View File

@ -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<SearchResult> fetchSearchResult(String query, Locale locale) throws Exception;
protected abstract List<Episode> fetchEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception;
protected abstract SeriesData fetchSeriesData(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception;
public List<SearchResult> 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<SearchResult> search(String query, Locale locale) throws Exception {
ResultCache cache = getCache();
List<SearchResult> results = (cache != null) ? cache.getSearchResult(query, locale) : null;
public List<SearchResult> search(String query, Locale language) throws Exception {
List<SearchResult> 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<Episode> getEpisodeList(SearchResult searchResult, String sortOrder, String locale) throws Exception {
return getEpisodeList(searchResult, sortOrder == null ? SortOrder.Airdate : SortOrder.forName(sortOrder), new Locale(locale));
}
public List<Episode> getEpisodeList(SearchResult searchResult) throws Exception {
return getEpisodeList(searchResult, SortOrder.Airdate, getDefaultLocale());
return getCache().putSearchResult(query, language, results);
}
@Override
public List<Episode> getEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception {
ResultCache cache = getCache();
List<Episode> episodes = (cache != null) ? cache.getEpisodeList(searchResult, sortOrder, locale) : null;
if (episodes != null) {
return episodes;
public List<Episode> getEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale language) throws Exception {
return getSeriesData(searchResult, sortOrder, language).getEpisodeList();
}
@Override
public List<Episode> 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<Episode> episodeList) {
this.seriesInfo = seriesInfo;
this.episodeList = episodeList.toArray(new Episode[episodeList.size()]);
}
public SeriesInfo getSeriesInfo() {
return seriesInfo.clone();
}
public List<Episode> 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 <T extends SearchResult> List<T> putSearchResult(String query, Locale locale, List<T> 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<SearchResult> 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<Episode> putEpisodeList(SearchResult key, SortOrder sortOrder, Locale locale, List<Episode> 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<Episode> 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> 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> T getData(Object category, Object key, Locale locale, Class<T> 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;
}

View File

@ -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<SearchResult>(index.search(query));
}
@Override
public List<Episode> 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<Episode>();
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<Episode> episodes = new ArrayList<Episode>(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

View File

@ -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<Integer> getNumbers() {

View File

@ -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

View File

@ -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<SearchResult> search(String query, Locale locale) throws Exception;
public List<Episode> getEpisodeList(SearchResult searchResult, SortOrder order, Locale locale) throws Exception;
public List<Episode> 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);
}

View File

@ -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

View File

@ -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<String> 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<String>() {
@Override

View File

@ -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<String> getAliasNames() {
return aliasNames == null ? asList() : asList(aliasNames.clone());
}
public void setAliasNames(List<String> aliasNames) {
this.aliasNames = aliasNames.toArray(new String[aliasNames.size()]);
}
public List<String> getActors() {
return actors == null ? asList() : asList(actors.clone());
}
public void setActors(List<String> 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<String> getGenres() {
return genres == null ? asList() : asList(genres.clone());
}
public void setGenres(List<String> 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;
}
}

View File

@ -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<Episode> 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<Episode> episodes = new ArrayList<Episode>(25);
List<Episode> specials = new ArrayList<Episode>(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<String, Object> 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");

View File

@ -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<SearchResult> fetchSearchResult(String query, Locale locale) throws Exception {
// perform online search
@ -120,14 +124,36 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
}
@Override
public List<Episode> 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<Node> nodes = selectNodes("Data/Episode", dom);
List<Episode> episodes = new ArrayList<Episode>(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<SeriesProperty, String> fields = new EnumMap<SeriesProperty, String>(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<SeriesProperty, String> fields;
protected SeriesInfo() {
// used by serializer
}
protected SeriesInfo(Map<SeriesProperty, String> fields) {
this.fields = new EnumMap<SeriesProperty, String>(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<String> getActors() {
// e.g. |Zachary Levi|Adam Baldwin|Yvonne Strzechowski|
return split(get(SeriesProperty.Actors));
}
public List<String> getGenres() {
// e.g. |Comedy|
return split(get(SeriesProperty.Genre));
}
protected List<String> split(String values) {
List<String> items = new ArrayList<String>();
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());
}
/**

View File

@ -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);
}
}

View File

@ -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<Match<File, Episode>> m = new Matcher<File, Episode>(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());
}
}

View File

@ -45,7 +45,7 @@ public class AnidbClientTest {
@Test
public void search() throws Exception {
List<SearchResult> results = anidb.search("one piece");
List<SearchResult> 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<SearchResult> results = anidb.search("i will not find anything for this query string");
List<SearchResult> 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<Episode> list = anidb.getEpisodeList(monsterSearchResult);
List<Episode> 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<Episode> list = anidb.getEpisodeList(twelvekingdomsSearchResult);
List<Episode> 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

View File

@ -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<SearchResult> results = tvrage.search("Buffy");
List<SearchResult> 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<Episode> list = EpisodeUtilities.filterBySeason(tvrage.getEpisodeList(buffySearchResult), 7);
List<Episode> 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<Episode> list = tvrage.getEpisodeList(buffySearchResult);
List<Episode> list = tvrage.getEpisodeList(buffySearchResult, SortOrder.Airdate, Locale.ENGLISH);
assertEquals(143, list.size());

View File

@ -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<SearchResult> results = thetvdb.search("babylon 5");
List<SearchResult> 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<SearchResult> 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<Episode> list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Buffy the Vampire Slayer", 70327));
List<Episode> 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<Episode> list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Wonderfalls", 78845));
List<Episode> 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<Episode> 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<String, String> filter = new HashMap<String, String>();
@ -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<BannerDescriptor> 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();
}
}