1
0
mirror of https://github.com/mitb-archive/filebot synced 2024-11-15 22:05:00 -05:00

+ 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.AcoustIDClient;
import net.filebot.web.AnidbClient; import net.filebot.web.AnidbClient;
import net.filebot.web.AnidbSearchResult; import net.filebot.web.AnidbSearchResult;
import net.filebot.web.AudioTrack;
import net.filebot.web.EpisodeListProvider; import net.filebot.web.EpisodeListProvider;
import net.filebot.web.FanartTVClient; import net.filebot.web.FanartTVClient;
import net.filebot.web.ID3Lookup; import net.filebot.web.ID3Lookup;
@ -40,10 +39,9 @@ import net.filebot.web.SubtitleDescriptor;
import net.filebot.web.SubtitleProvider; import net.filebot.web.SubtitleProvider;
import net.filebot.web.TMDbClient; import net.filebot.web.TMDbClient;
import net.filebot.web.TVRageClient; import net.filebot.web.TVRageClient;
import net.filebot.web.TVRageSearchResult;
import net.filebot.web.TheTVDBClient; import net.filebot.web.TheTVDBClient;
import net.filebot.web.TheTVDBClient.SeriesInfo;
import net.filebot.web.TheTVDBSearchResult; import net.filebot.web.TheTVDBSearchResult;
import net.filebot.web.TheTVDBSeriesInfo;
import net.filebot.web.VideoHashSubtitleService; import net.filebot.web.VideoHashSubtitleService;
/** /**
@ -114,21 +112,6 @@ public final class WebServices {
return null; // default 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 final ExecutorService requestThreadPool = Executors.newCachedThreadPool();
public static class TheTVDBClientWithLocalSearch extends TheTVDBClient { public static class TheTVDBClientWithLocalSearch extends TheTVDBClient {
@ -161,14 +144,6 @@ public final class WebServices {
return localIndex; 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 @Override
public List<SearchResult> fetchSearchResult(final String query, final Locale locale) throws Exception { public List<SearchResult> fetchSearchResult(final String query, final Locale locale) throws Exception {
Callable<List<SearchResult>> apiSearch = () -> TheTVDBClientWithLocalSearch.super.fetchSearchResult(query, locale); Callable<List<SearchResult>> apiSearch = () -> TheTVDBClientWithLocalSearch.super.fetchSearchResult(query, locale);
@ -258,10 +233,11 @@ public final class WebServices {
public Movie getIMDbID(SearchResult result) throws Exception { public Movie getIMDbID(SearchResult result) throws Exception {
if (result instanceof TheTVDBSearchResult) { if (result instanceof TheTVDBSearchResult) {
TheTVDBSearchResult s = (TheTVDBSearchResult) result; TheTVDBSearchResult searchResult = (TheTVDBSearchResult) result;
SeriesInfo seriesInfo = ((TheTVDBClient) seriesIndex).getSeriesInfo(s, Locale.ENGLISH); TheTVDBSeriesInfo seriesInfo = (TheTVDBSeriesInfo) ((TheTVDBClient) seriesIndex).getSeriesInfo(searchResult, Locale.ENGLISH);
if (seriesInfo.getImdbId() != null) { 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) { if (result instanceof Movie) {

View File

@ -44,16 +44,15 @@ import net.filebot.mediainfo.MediaInfo.StreamKind;
import net.filebot.similarity.SimilarityComparator; import net.filebot.similarity.SimilarityComparator;
import net.filebot.util.FileUtilities; import net.filebot.util.FileUtilities;
import net.filebot.util.FileUtilities.ExtensionFileFilter; import net.filebot.util.FileUtilities.ExtensionFileFilter;
import net.filebot.web.AnidbSearchResult;
import net.filebot.web.AudioTrack; import net.filebot.web.AudioTrack;
import net.filebot.web.Episode; import net.filebot.web.Episode;
import net.filebot.web.EpisodeListProvider; import net.filebot.web.EpisodeListProvider;
import net.filebot.web.Movie; import net.filebot.web.Movie;
import net.filebot.web.MoviePart; import net.filebot.web.MoviePart;
import net.filebot.web.MultiEpisode; import net.filebot.web.MultiEpisode;
import net.filebot.web.SearchResult; import net.filebot.web.SeriesInfo;
import net.filebot.web.SimpleDate; import net.filebot.web.SimpleDate;
import net.filebot.web.TheTVDBSearchResult; import net.filebot.web.SortOrder;
import com.cedarsoftware.util.io.JsonWriter; import com.cedarsoftware.util.io.JsonWriter;
@ -99,7 +98,7 @@ public class MediaBindingBean {
@Define("y") @Define("y")
public Integer getYear() { public Integer getYear() {
if (infoObject instanceof Episode) if (infoObject instanceof Episode)
return getEpisode().getSeriesStartDate().getYear(); return getEpisode().getSeriesInfo().getStartDate().getYear();
if (infoObject instanceof Movie) if (infoObject instanceof Movie)
return getMovie().getYear(); return getMovie().getYear();
if (infoObject instanceof AudioTrack) if (infoObject instanceof AudioTrack)
@ -191,7 +190,7 @@ public class MediaBindingBean {
@Define("startdate") @Define("startdate")
public SimpleDate startdate() { public SimpleDate startdate() {
return getEpisode().getSeriesStartDate(); return getEpisode().getSeriesInfo().getStartDate();
} }
@Define("absolute") @Define("absolute")
@ -205,8 +204,8 @@ public class MediaBindingBean {
} }
@Define("series") @Define("series")
public SearchResult getSeriesObject() { public SeriesInfo getSeriesInfo() {
return getEpisode().getSeries(); return getEpisode().getSeriesInfo();
} }
@Define("alias") @Define("alias")
@ -214,11 +213,9 @@ public class MediaBindingBean {
if (infoObject instanceof Movie) { if (infoObject instanceof Movie) {
return asList(getMovie().getAliasNames()); return asList(getMovie().getAliasNames());
} }
if (infoObject instanceof Episode) { if (infoObject instanceof Episode) {
return asList(getSeriesObject().getAliasNames()); return getSeriesInfo().getAliasNames();
} }
return emptyList(); return emptyList();
} }
@ -229,13 +226,13 @@ public class MediaBindingBean {
} }
if (infoObject instanceof Episode) { if (infoObject instanceof Episode) {
if (getSeriesObject() instanceof TheTVDBSearchResult) { // force English series name for TheTVDB data
return WebServices.TheTVDB.getSeriesInfo((TheTVDBSearchResult) getSeriesObject(), Locale.ENGLISH).getName(); if (WebServices.TheTVDB.getName().equals(getSeriesInfo().getDatabase())) {
return WebServices.TheTVDB.getSeriesInfo(getSeriesInfo().getId(), Locale.ENGLISH).getName();
} }
if (getSeriesObject() instanceof AnidbSearchResult) {
return ((AnidbSearchResult) getSeriesObject()).getPrimaryTitle(); // default to series info name (for anime this would be the primary title)
} return getSeriesInfo().getName();
return getSeriesObject().getName(); // default to original search result
} }
return null; return null;
@ -558,10 +555,7 @@ public class MediaBindingBean {
if (metaInfo == null) { if (metaInfo == null) {
try { try {
if (infoObject instanceof Episode) { if (infoObject instanceof Episode) {
Episode episode = (Episode) infoObject; metaInfo = getSeriesInfo();
if (episode.getSeries() instanceof TheTVDBSearchResult) {
metaInfo = WebServices.TheTVDB.getSeriesInfo((TheTVDBSearchResult) episode.getSeries(), episode.getLanguage() == null ? Locale.ENGLISH : episode.getLanguage());
}
} else if (infoObject instanceof Movie) { } else if (infoObject instanceof Movie) {
if (getMovie().getTmdbId() > 0) { if (getMovie().getTmdbId() > 0) {
metaInfo = WebServices.TheMovieDB.getMovieInfo(getMovie(), getMovie().getLanguage() == null ? Locale.ENGLISH : getMovie().getLanguage(), true); 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"); throw new UnsupportedOperationException("Extended metadata not available");
} }
return createMapBindings(new PropertyBindings(metaInfo, null)); return createMapBindings(new PropertyBindings(metaInfo, null));
} }
@Define("imdb") @Define("omdb")
public synchronized AssociativeScriptObject getImdbApiInfo() { public synchronized AssociativeScriptObject getOmdbApiInfo() {
Object metaInfo = null; Object metaInfo = null;
try { try {
if (infoObject instanceof Episode) { 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) { if (infoObject instanceof Movie) {
metaInfo = WebServices.OMDb.getMovieInfo(getMovie()); metaInfo = WebServices.OMDb.getMovieInfo(getMovie());
@ -605,19 +599,10 @@ public class MediaBindingBean {
@Define("episodelist") @Define("episodelist")
public Object getEpisodeList() throws Exception { public Object getEpisodeList() throws Exception {
return ((EpisodeListProvider) getDatabase()).getEpisodeList(getSeriesObject(), getEpisode().getOrder(), getEpisode().getLanguage()); for (EpisodeListProvider service : WebServices.getEpisodeListProviders()) {
if (getSeriesInfo().getDatabase().equals(service.getName())) {
return service.getEpisodeList(getSeriesInfo().getId(), SortOrder.forName(getSeriesInfo().getOrder()), new Locale(getSeriesInfo().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());
} }
return null; return null;
} }

View File

@ -65,8 +65,8 @@ import net.filebot.web.Episode;
import net.filebot.web.Movie; import net.filebot.web.Movie;
import net.filebot.web.MovieIdentificationService; import net.filebot.web.MovieIdentificationService;
import net.filebot.web.SearchResult; import net.filebot.web.SearchResult;
import net.filebot.web.SeriesInfo;
import net.filebot.web.SimpleDate; import net.filebot.web.SimpleDate;
import net.filebot.web.TheTVDBClient.SeriesInfo;
import net.filebot.web.TheTVDBSearchResult; import net.filebot.web.TheTVDBSearchResult;
public class MediaDetection { public class MediaDetection {
@ -1259,7 +1259,9 @@ public class MediaDetection {
} }
public static SeriesInfo grepSeries(File nfo, Locale locale) throws Exception { 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) { 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.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import net.filebot.WebServices;
import net.filebot.media.MediaDetection; import net.filebot.media.MediaDetection;
import net.filebot.media.SmartSeasonEpisodeMatcher; import net.filebot.media.SmartSeasonEpisodeMatcher;
import net.filebot.similarity.SeasonEpisodeMatcher.SxE; import net.filebot.similarity.SeasonEpisodeMatcher.SxE;
@ -34,9 +33,8 @@ import net.filebot.vfs.FileInfo;
import net.filebot.web.Episode; import net.filebot.web.Episode;
import net.filebot.web.EpisodeFormat; import net.filebot.web.EpisodeFormat;
import net.filebot.web.Movie; import net.filebot.web.Movie;
import net.filebot.web.SeriesInfo;
import net.filebot.web.SimpleDate; import net.filebot.web.SimpleDate;
import net.filebot.web.TheTVDBClient.SeriesInfo;
import net.filebot.web.TheTVDBSearchResult;
import com.ibm.icu.text.Transliterator; import com.ibm.icu.text.Transliterator;
@ -212,7 +210,7 @@ public enum EpisodeMetrics implements SimilarityMetric {
LinkedHashSet<String> keywords = new LinkedHashSet<String>(4); LinkedHashSet<String> keywords = new LinkedHashSet<String>(4);
keywords.add(removeTrailingBrackets(episode.getSeriesName())); keywords.add(removeTrailingBrackets(episode.getSeriesName()));
keywords.add(removeTrailingBrackets(episode.getTitle())); keywords.add(removeTrailingBrackets(episode.getTitle()));
for (String it : episode.getSeries().getEffectiveNames()) { for (String it : episode.getSeriesInfo().getAliasNames()) {
keywords.add(removeTrailingBrackets(it)); keywords.add(removeTrailingBrackets(it));
} }
@ -277,7 +275,7 @@ public enum EpisodeMetrics implements SimilarityMetric {
protected List<?> getEffectiveIdentifiers(Object object) { protected List<?> getEffectiveIdentifiers(Object object) {
if (object instanceof Episode) { if (object instanceof Episode) {
return ((Episode) object).getSeries().getEffectiveNames(); return ((Episode) object).getSeriesInfo().getAliasNames();
} else if (object instanceof Movie) { } else if (object instanceof Movie) {
return ((Movie) object).getEffectiveNames(); return ((Movie) object).getEffectiveNames();
} else if (object instanceof File) { } else if (object instanceof File) {
@ -346,7 +344,7 @@ public enum EpisodeMetrics implements SimilarityMetric {
List<String> names = null; List<String> names = null;
if (object instanceof Episode) { if (object instanceof Episode) {
names = ((Episode) object).getSeries().getEffectiveNames(); names = ((Episode) object).getSeriesInfo().getAliasNames();
} else if (object instanceof File) { } else if (object instanceof File) {
File file = (File) object; File file = (File) object;
@ -558,25 +556,10 @@ public enum EpisodeMetrics implements SimilarityMetric {
return max(r1, r2); return max(r1, r2);
} }
private final Map<String, SeriesInfo> seriesInfoCache = new HashMap<String, SeriesInfo>(); public float getRating(Object object) {
if (object instanceof Episode) {
public float getRating(Object o) { SeriesInfo seriesInfo = ((Episode) object).getSeriesInfo();
if (o instanceof Episode) { if (seriesInfo != null && seriesInfo.getRating() != null && seriesInfo.getRatingCount() != null) {
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) { if (seriesInfo.getRatingCount() >= 100) {
return (float) floor(seriesInfo.getRating() / 3) + 1; // BOOST POPULAR SHOWS return (float) floor(seriesInfo.getRating() / 3) + 1; // BOOST POPULAR SHOWS
} }
@ -589,10 +572,6 @@ public enum EpisodeMetrics implements SimilarityMetric {
return -1; // BIG PENALTY FOR SHOWS WITH 0 RATINGS return -1; // BIG PENALTY FOR SHOWS WITH 0 RATINGS
} }
} }
} catch (Exception e) {
Logger.getLogger(EpisodeMetrics.class.getName()).log(Level.WARNING, e.getMessage());
}
}
return 0; return 0;
} }
}), }),

View File

@ -20,7 +20,7 @@ import net.filebot.util.FileUtilities;
import net.filebot.util.ui.LoadingOverlayPane; import net.filebot.util.ui.LoadingOverlayPane;
import net.filebot.web.Episode; import net.filebot.web.Episode;
import net.filebot.web.Movie; import net.filebot.web.Movie;
import net.filebot.web.SearchResult; import net.filebot.web.SeriesInfo;
import net.miginfocom.swing.MigLayout; import net.miginfocom.swing.MigLayout;
class AttributeTool extends Tool<TableModel> { class AttributeTool extends Tool<TableModel> {
@ -59,20 +59,17 @@ class AttributeTool extends Tool<TableModel> {
originalName = attributes.getOriginalName(); originalName = attributes.getOriginalName();
metaObject = attributes.getObject(); metaObject = attributes.getObject();
String format = "%s::%d";
if (metaObject instanceof Episode) { if (metaObject instanceof Episode) {
Object seriesObject = ((Episode) metaObject).getSeries(); SeriesInfo seriesInfo = ((Episode) metaObject).getSeriesInfo();
if (seriesObject != null) { if (seriesInfo != null) {
String type = seriesObject.getClass().getSimpleName().replace(SearchResult.class.getSimpleName(), ""); metaId = String.format("%s::%d", seriesInfo.getDatabase(), seriesInfo.getId());
Integer code = (Integer) seriesObject.getClass().getMethod("getId").invoke(seriesObject);
metaId = String.format(format, type, code);
} }
} else if (metaObject instanceof Movie) { } else if (metaObject instanceof Movie) {
Movie movie = (Movie) metaObject; Movie movie = (Movie) metaObject;
if (movie.getTmdbId() > 0) { if (movie.getTmdbId() > 0) {
metaId = String.format(format, "TheMovieDB", movie.getTmdbId()); metaId = String.format("%s::%d", "TheMovieDB", movie.getTmdbId());
} else if (movie.getImdbId() > 0) { } else if (movie.getImdbId() > 0) {
metaId = String.format(format, "IMDB", movie.getImdbId()); metaId = String.format("%s::%d", "OMDb", movie.getImdbId());
} }
} }
} catch (Exception e) { } catch (Exception e) {

View File

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

View File

@ -60,8 +60,8 @@ import net.filebot.util.ui.EmptySelectionModel;
import net.filebot.web.Movie; import net.filebot.web.Movie;
import net.filebot.web.OpenSubtitlesClient; import net.filebot.web.OpenSubtitlesClient;
import net.filebot.web.SearchResult; import net.filebot.web.SearchResult;
import net.filebot.web.TheTVDBClient.SeriesInfo;
import net.filebot.web.TheTVDBSearchResult; import net.filebot.web.TheTVDBSearchResult;
import net.filebot.web.TheTVDBSeriesInfo;
import net.filebot.web.VideoHashSubtitleService.CheckResult; import net.filebot.web.VideoHashSubtitleService.CheckResult;
import net.miginfocom.swing.MigLayout; import net.miginfocom.swing.MigLayout;
@ -689,10 +689,10 @@ public class SubtitleUploadDialog extends JDialog {
for (String name : seriesNames) { for (String name : seriesNames) {
List<SearchResult> options = WebServices.TheTVDB.search(name, Locale.ENGLISH); List<SearchResult> options = WebServices.TheTVDB.search(name, Locale.ENGLISH);
for (SearchResult entry : options) { for (SearchResult entry : options) {
SeriesInfo seriesInfo = WebServices.TheTVDB.getSeriesInfo((TheTVDBSearchResult) entry, Locale.ENGLISH); TheTVDBSeriesInfo seriesInfo = (TheTVDBSeriesInfo) WebServices.TheTVDB.getSeriesInfo((TheTVDBSearchResult) entry, Locale.ENGLISH);
Integer imdbid = seriesInfo.getImdbId(); if (seriesInfo.getImdbId() != null) {
if (imdbid != null && imdbid > 0) { int imdbId = grepImdbId(seriesInfo.getImdbId()).iterator().next();
mapping.setIdentity(WebServices.OpenSubtitles.getMovieDescriptor(new Movie(null, 0, imdbid, -1), Locale.ENGLISH)); mapping.setIdentity(WebServices.OpenSubtitles.getMovieDescriptor(new Movie(null, 0, imdbId, -1), Locale.ENGLISH));
break; break;
} }
} }

View File

@ -1,10 +1,9 @@
package net.filebot.util; package net.filebot.util;
import java.util.AbstractList; import java.util.AbstractList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Scanner;
import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpression;
@ -14,7 +13,6 @@ import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Node; import org.w3c.dom.Node;
import org.w3c.dom.NodeList; import org.w3c.dom.NodeList;
public final class XPathUtilities { public final class XPathUtilities {
public static Node selectNode(String xpath, Object node) { public static Node selectNode(String xpath, Object node) {
@ -25,7 +23,6 @@ public final class XPathUtilities {
} }
} }
public static List<Node> selectNodes(String xpath, Object node) { public static List<Node> selectNodes(String xpath, Object node) {
try { try {
return new NodeListDecorator((NodeList) getXPath(xpath).evaluate(node, XPathConstants.NODESET)); return new NodeListDecorator((NodeList) getXPath(xpath).evaluate(node, XPathConstants.NODESET));
@ -34,7 +31,6 @@ public final class XPathUtilities {
} }
} }
public static String selectString(String xpath, Object node) { public static String selectString(String xpath, Object node) {
try { try {
return ((String) getXPath(xpath).evaluate(node, XPathConstants.STRING)).trim(); return ((String) getXPath(xpath).evaluate(node, XPathConstants.STRING)).trim();
@ -43,10 +39,26 @@ public final class XPathUtilities {
} }
} }
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 nodeName
* @param parentNode search in the child nodes of this nodes * 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 * @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) { public static Node getChild(String nodeName, Node parentNode) {
@ -58,7 +70,6 @@ public final class XPathUtilities {
return null; return null;
} }
public static List<Node> getChildren(String nodeName, Node parentNode) { public static List<Node> getChildren(String nodeName, Node parentNode) {
List<Node> children = new ArrayList<Node>(); List<Node> children = new ArrayList<Node>();
@ -70,7 +81,6 @@ public final class XPathUtilities {
return children; return children;
} }
public static String getAttribute(String attribute, Node node) { public static String getAttribute(String attribute, Node node) {
Node attributeNode = node.getAttributes().getNamedItem(attribute); Node attributeNode = node.getAttributes().getNamedItem(attribute);
@ -80,14 +90,13 @@ public final class XPathUtilities {
return null; return null;
} }
/** /**
* Get text content of the first child node matching the given node name. Use this method * 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.
* 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 childName
* @param parentNode search in the child nodes of this nodes * 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 * @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) { public static String getTextContent(String childName, Node parentNode) {
@ -100,7 +109,6 @@ public final class XPathUtilities {
return getTextContent(child); return getTextContent(child);
} }
public static String getTextContent(Node node) { public static String getTextContent(Node node) {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -111,21 +119,46 @@ public final class XPathUtilities {
return sb.toString().trim(); return sb.toString().trim();
} }
public static Integer getIntegerContent(String childName, Node parentNode) { public static Integer getIntegerContent(String childName, Node parentNode) {
try { try {
return new Integer(getTextContent(childName, parentNode)); return new Scanner(getTextContent(childName, parentNode)).useDelimiter("\\D+").nextInt();
} catch (NumberFormatException e) { } catch (Exception e) {
return null; 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 { private static XPathExpression getXPath(String xpath) throws XPathExpressionException {
return XPathFactory.newInstance().newXPath().compile(xpath); return XPathFactory.newInstance().newXPath().compile(xpath);
} }
/** /**
* Dummy constructor to prevent instantiation. * Dummy constructor to prevent instantiation.
*/ */
@ -133,23 +166,19 @@ public final class XPathUtilities {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
protected static class NodeListDecorator extends AbstractList<Node> { protected static class NodeListDecorator extends AbstractList<Node> {
private final NodeList nodes; private final NodeList nodes;
public NodeListDecorator(NodeList nodes) { public NodeListDecorator(NodeList nodes) {
this.nodes = nodes; this.nodes = nodes;
} }
@Override @Override
public Node get(int index) { public Node get(int index) {
return nodes.item(index); return nodes.item(index);
} }
@Override @Override
public int size() { public int size() {
return nodes.getLength(); return nodes.getLength();

View File

@ -1,6 +1,8 @@
package net.filebot.web; package net.filebot.web;
import java.util.Arrays; import static java.util.Arrays.*;
import java.io.Serializable;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.logging.Level; import java.util.logging.Level;
@ -11,69 +13,86 @@ import net.filebot.Cache.Key;
public abstract class AbstractEpisodeListProvider implements EpisodeListProvider { 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<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 { protected abstract SearchResult createSearchResult(int id);
return search(query, getDefaultLocale());
} protected abstract ResultCache getCache();
protected abstract SortOrder vetoRequestParameter(SortOrder order);
protected abstract Locale vetoRequestParameter(Locale language);
@Override @Override
public List<SearchResult> search(String query, Locale locale) throws Exception { public List<SearchResult> search(String query, Locale language) throws Exception {
ResultCache cache = getCache(); List<SearchResult> results = getCache().getSearchResult(query, language);
List<SearchResult> results = (cache != null) ? cache.getSearchResult(query, locale) : null;
if (results != null) { if (results != null) {
return results; return results;
} }
// perform actual search // perform actual search
results = fetchSearchResult(query, locale); results = fetchSearchResult(query, language);
// cache results and return // cache results and return
return (cache != null) ? cache.putSearchResult(query, locale, results) : results; return getCache().putSearchResult(query, language, 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());
} }
@Override @Override
public List<Episode> getEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception { public List<Episode> getEpisodeList(SearchResult searchResult, SortOrder sortOrder, Locale language) throws Exception {
ResultCache cache = getCache(); return getSeriesData(searchResult, sortOrder, language).getEpisodeList();
List<Episode> episodes = (cache != null) ? cache.getEpisodeList(searchResult, sortOrder, locale) : null;
if (episodes != null) {
return episodes;
} }
// perform actual search @Override
episodes = fetchEpisodeList(searchResult, sortOrder, locale); 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 lookup
data = fetchSeriesData(searchResult, order, language);
// cache results and return // cache results and return
return (cache != null) ? cache.putEpisodeList(searchResult, sortOrder, locale, episodes) : episodes; return getCache().putSeriesData(searchResult, order, language, data);
} }
public Locale getDefaultLocale() { protected static class SeriesData implements Serializable {
return Locale.ENGLISH;
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 { 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) { public <T extends SearchResult> List<T> putSearchResult(String query, Locale locale, List<T> value) {
try { putData("SearchResult", normalize(query), locale, value.toArray(new SearchResult[value.size()]));
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());
}
return value; return value;
} }
public List<SearchResult> getSearchResult(String query, Locale locale) { public List<SearchResult> getSearchResult(String query, Locale locale) {
try { SearchResult[] data = getData("SearchResult", normalize(query), locale, SearchResult[].class);
SearchResult[] results = cache.get(new Key(id, normalize(query), locale), SearchResult[].class); return data == null ? null : asList(data);
if (results != null) {
return Arrays.asList(results);
}
} catch (Exception e) {
Logger.getLogger(AbstractEpisodeListProvider.class.getName()).log(Level.WARNING, e.getMessage(), e);
} }
return null; public SeriesData putSeriesData(SearchResult key, SortOrder sortOrder, Locale locale, SeriesData seriesData) {
putData("SeriesData." + sortOrder.name(), key, locale, seriesData);
return seriesData;
} }
public List<Episode> putEpisodeList(SearchResult key, SortOrder sortOrder, Locale locale, List<Episode> episodes) { public SeriesData getSeriesData(SearchResult key, SortOrder sortOrder, Locale locale) {
try { return getData("SeriesData." + sortOrder.name(), key, locale, SeriesData.class);
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 <T> T putData(Object category, Object key, Locale locale, T object) {
}
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 void putData(Object category, Object key, Locale locale, Object object) {
try { try {
cache.put(new Key(id, category, locale, key), object); cache.put(new Key(id, category, locale, key), object);
} catch (Exception e) { } catch (Exception e) {
Logger.getLogger(AbstractEpisodeListProvider.class.getName()).log(Level.WARNING, e.getMessage()); 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) { public <T> T getData(Object category, Object key, Locale locale, Class<T> type) {
try { try {
T value = cache.get(new Key(id, category, locale, key), type); return cache.get(new Key(id, category, locale, key), type);
if (value != null) {
return value;
}
} catch (Exception e) { } catch (Exception e) {
Logger.getLogger(AbstractEpisodeListProvider.class.getName()).log(Level.WARNING, e.getMessage(), e); Logger.getLogger(AbstractEpisodeListProvider.class.getName()).log(Level.WARNING, e.getMessage(), e);
} }
return null; return null;
} }

View File

@ -1,5 +1,6 @@
package net.filebot.web; package net.filebot.web;
import static java.util.Collections.*;
import static net.filebot.util.XPathUtilities.*; import static net.filebot.util.XPathUtilities.*;
import static net.filebot.web.EpisodeUtilities.*; import static net.filebot.web.EpisodeUtilities.*;
import static net.filebot.web.WebRequest.*; import static net.filebot.web.WebRequest.*;
@ -58,18 +59,23 @@ public class AnidbClient extends AbstractEpisodeListProvider {
} }
@Override @Override
public boolean hasSingleSeasonSupport() { public boolean hasSeasonSupport() {
return false; return false;
} }
@Override @Override
public boolean hasLocaleSupport() { protected SortOrder vetoRequestParameter(SortOrder order) {
return true; return SortOrder.Absolute;
}
@Override
protected Locale vetoRequestParameter(Locale language) {
return language != null ? language : Locale.ENGLISH;
} }
@Override @Override
public ResultCache getCache() { public ResultCache getCache() {
return new ResultCache(host, Cache.getCache("web-datasource-lv2")); return new ResultCache(getName(), Cache.getCache("web-datasource-lv2"));
} }
@Override @Override
@ -87,12 +93,11 @@ public class AnidbClient extends AbstractEpisodeListProvider {
return set(it.getEffectiveNames()); return set(it.getEffectiveNames());
} }
}; };
return new ArrayList<SearchResult>(index.search(query)); return new ArrayList<SearchResult>(index.search(query));
} }
@Override @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; AnidbSearchResult anime = (AnidbSearchResult) searchResult;
// e.g. http://api.anidb.net:9001/httpapi?request=anime&client=filebot&clientver=1&protover=1&aid=4521 // 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 // get anime page as xml
Document dom = getDocument(url); 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 // AniDB types: Movie, Music Video, Other, OVA, TV Series, TV Special, Web, unknown
String animeType = selectString("//type", dom); String animeType = selectString("//type", dom);
if (animeType != null && animeType.matches("(?i:music.video|unkown|other)")) { 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 seriesInfo.setName(selectString("anime/titles/title[@type='main']", dom));
SimpleDate seriesStartDate = SimpleDate.parse(selectString("//startdate", dom), "yyyy-MM-dd"); seriesInfo.setRating(new Double(selectString("anime/ratings/permanent", dom)));
String animeTitle = selectString("//titles/title[@type='official' and @lang='" + locale.getLanguage() + "']", dom); seriesInfo.setRatingCount(new Integer(selectString("anime/ratings/permanent/@count", dom)));
if (animeTitle.isEmpty()) { seriesInfo.setStartDate(SimpleDate.parse(selectString("anime/startdate", dom), "yyyy-MM-dd"));
animeTitle = selectString("//titles/title[@type='main']", dom);
// 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); 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); Node epno = getChild("epno", node);
int number = Integer.parseInt(getTextContent(epno).replaceAll("\\D", "")); int number = Integer.parseInt(getTextContent(epno).replaceAll("\\D", ""));
int type = Integer.parseInt(getAttribute("type", epno)); int type = Integer.parseInt(getAttribute("type", epno));
@ -132,9 +145,9 @@ public class AnidbClient extends AbstractEpisodeListProvider {
} }
if (type == 1) { 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 { } 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))); 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 @Override

View File

@ -3,13 +3,10 @@ package net.filebot.web;
import java.io.Serializable; import java.io.Serializable;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.Locale;
public class Episode implements Serializable { public class Episode implements Serializable {
protected String seriesName; protected String seriesName;
protected SimpleDate seriesStartDate;
protected Integer season; protected Integer season;
protected Integer episode; protected Integer episode;
protected String title; protected String title;
@ -20,50 +17,39 @@ public class Episode implements Serializable {
// special number // special number
protected Integer special; protected Integer special;
// optional episode number order hint & episode name / title language hint
protected String order;
protected String language;
// episode airdate // episode airdate
protected SimpleDate airdate; protected SimpleDate airdate;
// original series descriptor // extended series metadata
protected SearchResult series; protected SeriesInfo seriesInfo;
protected Episode() { protected Episode() {
// used by serializer
} }
public Episode(Episode obj) { 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) { public Episode(String seriesName, Integer season, Integer episode, String title) {
this(seriesName, seriesStartDate, season, episode, title, null, null, null, null, null, series); 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.seriesName = seriesName;
this.seriesStartDate = (seriesStartDate == null ? null : seriesStartDate.clone());
this.season = season; this.season = season;
this.episode = episode; this.episode = episode;
this.title = title; this.title = title;
this.absolute = absolute; this.absolute = absolute;
this.special = special; 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.airdate = (airdate == null ? null : airdate.clone());
this.series = (series == null ? null : series.clone()); this.seriesInfo = (seriesInfo == null ? null : seriesInfo.clone());
} }
public String getSeriesName() { public String getSeriesName() {
return seriesName; return seriesName;
} }
public SimpleDate getSeriesStartDate() {
return seriesStartDate;
}
public Integer getEpisode() { public Integer getEpisode() {
return episode; return episode;
} }
@ -84,20 +70,12 @@ public class Episode implements Serializable {
return special; 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() { public SimpleDate getAirdate() {
return airdate; return airdate;
} }
public SearchResult getSeries() { public SeriesInfo getSeriesInfo() {
return series; return seriesInfo;
} }
public List<Integer> getNumbers() { public List<Integer> getNumbers() {

View File

@ -187,7 +187,7 @@ public class EpisodeFormat extends Format {
// did parse input // did parse input
pos.setIndex(source.length()); 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 // failed to parse input

View File

@ -1,33 +1,28 @@
package net.filebot.web; package net.filebot.web;
import java.net.URI; import java.net.URI;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import javax.swing.Icon; import javax.swing.Icon;
public interface EpisodeListProvider { public interface EpisodeListProvider {
public String getName(); public String getName();
public Icon getIcon(); public Icon getIcon();
public boolean hasSeasonSupport();
public boolean hasSingleSeasonSupport();
public boolean hasLocaleSupport();
public List<SearchResult> search(String query, Locale locale) throws Exception; 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(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); public URI getEpisodeListLink(SearchResult searchResult);

View File

@ -87,7 +87,7 @@ public class OpenSubtitlesClient implements SubtitleProvider, VideoHashSubtitleS
} }
public ResultCache getCache() { public ResultCache getCache() {
return new ResultCache("opensubtitles.org", Cache.getCache("web-datasource")); return new ResultCache(getName(), Cache.getCache("web-datasource"));
} }
@Override @Override

View File

@ -1,8 +1,9 @@
package net.filebot.web; package net.filebot.web;
import static java.util.Collections.*;
import java.io.Serializable; import java.io.Serializable;
import java.util.AbstractList; import java.util.AbstractList;
import java.util.Collections;
import java.util.List; import java.util.List;
public abstract class SearchResult implements Serializable { public abstract class SearchResult implements Serializable {
@ -28,10 +29,12 @@ public abstract class SearchResult implements Serializable {
} }
public List<String> getEffectiveNames() { public List<String> getEffectiveNames() {
if (aliasNames == null || aliasNames.length == 0) { if (name == null || name.length() == 0) {
return Collections.singletonList(name); return emptyList();
}
if (aliasNames == null || aliasNames.length == 0) {
return singletonList(name);
} }
return new AbstractList<String>() { return new AbstractList<String>() {
@Override @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"); 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 @Override
public ResultCache getCache() { public ResultCache getCache() {
return new ResultCache(host, Cache.getCache("web-datasource")); return new ResultCache(getName(), Cache.getCache("web-datasource"));
} }
@Override @Override
@ -67,14 +82,24 @@ public class TVRageClient extends AbstractEpisodeListProvider {
} }
@Override @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; 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); // parse series data
SimpleDate seriesStartDate = SimpleDate.parse(selectString("Show/started", dom), "MMM/dd/yyyy"); Node seriesNode = selectNode("Show", dom);
Locale language = Locale.ENGLISH; 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> episodes = new ArrayList<Episode>(25);
List<Episode> specials = new ArrayList<Episode>(5); List<Episode> specials = new ArrayList<Episode>(5);
@ -86,30 +111,26 @@ public class TVRageClient extends AbstractEpisodeListProvider {
Integer seasonNumber = seasonIdentifier == null ? null : new Integer(seasonIdentifier); Integer seasonNumber = seasonIdentifier == null ? null : new Integer(seasonIdentifier);
SimpleDate airdate = SimpleDate.parse(getTextContent("airdate", node), "yyyy-MM-dd"); 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 // check if we have season and episode number, if not it must be a special episode
if (episodeNumber == null || seasonNumber == null) { if (episodeNumber == null || seasonNumber == null) {
// handle as special episode // handle as special episode
seasonNumber = getIntegerContent("season", node); seasonNumber = getIntegerContent("season", node);
int specialNumber = filterBySeason(specials, seasonNumber).size() + 1; 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 { } else {
// handle as normal episode // handle as normal episode
if (sortOrder == SortOrder.Absolute) { if (sortOrder == SortOrder.Absolute) {
episodeNumber = getIntegerContent("epnum", node); episodeNumber = getIntegerContent("epnum", node);
seasonNumber = null; seasonNumber = null;
order = SortOrder.Absolute;
} }
episodes.add(new Episode(seriesInfo.getName(), seasonNumber, episodeNumber, title, null, null, airdate, new SeriesInfo(seriesInfo)));
episodes.add(new Episode(seriesName, seriesStartDate, seasonNumber, episodeNumber, title, null, null, order, language, airdate, searchResult));
} }
} }
// add specials at the end // add specials at the end
episodes.addAll(specials); episodes.addAll(specials);
return episodes; return new SeriesData(seriesInfo, episodes);
} }
public Document request(String resource, Map<String, Object> parameters) throws IOException, SAXException { public Document request(String resource, Map<String, Object> parameters) throws IOException, SAXException {
@ -121,6 +142,11 @@ public class TVRageClient extends AbstractEpisodeListProvider {
return getDocument(url); return getDocument(url);
} }
@Override
protected SearchResult createSearchResult(int id) {
return new TVRageSearchResult(null, id, null);
}
@Override @Override
public URI getEpisodeListLink(SearchResult searchResult) { public URI getEpisodeListLink(SearchResult searchResult) {
return URI.create(((TVRageSearchResult) searchResult).getLink() + "/episode_list/all"); 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.ResourceManager;
import net.filebot.util.FileUtilities; import net.filebot.util.FileUtilities;
import net.filebot.web.TheTVDBClient.BannerDescriptor.BannerProperty; import net.filebot.web.TheTVDBClient.BannerDescriptor.BannerProperty;
import net.filebot.web.TheTVDBClient.SeriesInfo.SeriesProperty;
import org.w3c.dom.Document; import org.w3c.dom.Document;
import org.w3c.dom.Node; import org.w3c.dom.Node;
@ -60,13 +59,23 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
} }
@Override @Override
public boolean hasSingleSeasonSupport() { public boolean hasSeasonSupport() {
return true; return true;
} }
@Override @Override
public boolean hasLocaleSupport() { protected SortOrder vetoRequestParameter(SortOrder order) {
return true; 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) { public String getLanguageCode(Locale locale) {
@ -85,11 +94,6 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
return code; return code;
} }
@Override
public ResultCache getCache() {
return new ResultCache(host, Cache.getCache("web-datasource"));
}
@Override @Override
public List<SearchResult> fetchSearchResult(String query, Locale locale) throws Exception { public List<SearchResult> fetchSearchResult(String query, Locale locale) throws Exception {
// perform online search // perform online search
@ -120,14 +124,36 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
} }
@Override @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; TheTVDBSearchResult series = (TheTVDBSearchResult) searchResult;
Document dom = getXmlResource(MirrorType.XML, "/api/" + apikey + "/series/" + series.getSeriesId() + "/all/" + getLanguageCode(locale) + ".xml"); 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 // parse series info
String seriesName = selectString("Data/Series/SeriesName", dom); Node seriesNode = selectNode("Data/Series", dom);
SimpleDate seriesStartDate = SimpleDate.parse(selectString("Data/Series/FirstAired", dom), "yyyy-MM-dd"); 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<Node> nodes = selectNodes("Data/Episode", dom);
List<Episode> episodes = new ArrayList<Episode>(nodes.size()); List<Episode> episodes = new ArrayList<Episode>(nodes.size());
@ -143,7 +169,6 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
// default numbering // default numbering
Integer episodeNumber = getIntegerContent("EpisodeNumber", node); Integer episodeNumber = getIntegerContent("EpisodeNumber", node);
Integer seasonNumber = getIntegerContent("SeasonNumber", node); Integer seasonNumber = getIntegerContent("SeasonNumber", node);
SortOrder order = SortOrder.Airdate;
if (seasonNumber == null || seasonNumber == 0) { if (seasonNumber == null || seasonNumber == 0) {
// handle as special episode // 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 // use given episode number as special number or count specials by ourselves
Integer specialNumber = (episodeNumber != null) ? episodeNumber : filterBySeason(specials, seasonNumber).size() + 1; 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 { } else {
// handle as normal episode // handle as normal episode
if (sortOrder == SortOrder.Absolute) { if (sortOrder == SortOrder.Absolute) {
if (absoluteNumber != null) { if (absoluteNumber != null) {
episodeNumber = absoluteNumber; episodeNumber = absoluteNumber;
seasonNumber = null; seasonNumber = null;
order = SortOrder.Absolute;
} }
} else if (sortOrder == SortOrder.DVD) { } else if (sortOrder == SortOrder.DVD) {
try { try {
@ -171,13 +195,12 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
// require both values to be successfully read // require both values to be successfully read
episodeNumber = eno; episodeNumber = eno;
seasonNumber = sno; seasonNumber = sno;
order = SortOrder.DVD;
} catch (Exception e) { } catch (Exception e) {
// ignore, fallback to default numbering // 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 // add specials at the end
episodes.addAll(specials); episodes.addAll(specials);
return episodes; return new SeriesData(seriesInfo, episodes);
} }
public TheTVDBSearchResult lookupByID(int id, Locale locale) throws Exception { public TheTVDBSearchResult lookupByID(int id, Locale locale) throws Exception {
@ -227,11 +250,6 @@ public class TheTVDBClient extends AbstractEpisodeListProvider {
return series; 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 { protected String getMirror(MirrorType mirrorType) throws IOException {
synchronized (mirrors) { synchronized (mirrors) {
if (mirrors.isEmpty()) { 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 { public SeriesInfo getSeriesInfoByIMDbID(int imdbid, Locale locale) throws Exception {
return getSeriesInfo(lookupByIMDbID(imdbid, locale), locale); return getSeriesInfo(lookupByIMDbID(imdbid, locale), locale);
} }
public SeriesInfo getSeriesInfoByName(String name, Locale locale) throws Exception { @Override
for (SearchResult it : search(name, locale)) { protected SearchResult createSearchResult(int id) {
if (name.equalsIgnoreCase(it.getName())) { return new TheTVDBSearchResult(null, id);
return getSeriesInfo((TheTVDBSearchResult) it, locale);
}
}
return null;
}
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 @Override
public String toString() { public URI getEpisodeListLink(SearchResult searchResult) {
return fields.toString(); 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 java.util.List;
import net.filebot.web.Episode; import net.filebot.web.Episode;
import net.filebot.web.SimpleDate;
import net.filebot.web.TheTVDBSearchResult;
import org.junit.Test; import org.junit.Test;
@ -17,7 +15,7 @@ public class EpisodeMetricsTest {
@Test @Test
public void substringMetrics() { 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"); // 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 fY1T1 = new File("Doctor Who (2005)/Doctor Who - 1x01 - Rose");
File fY2T2 = new File("Doctor Who (1963)/Doctor Who - 1x01 - An Unearthly Child"); 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("Greek/Greek - S01E19 - No Campus for Old Rules"));
files.add(new File("Veronica Mars - Season 1/Veronica Mars [1x19] Hot Dogs")); 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("Veronica Mars", 1, 19, "Hot Dogs"));
episodes.add(new Episode("Greek", null, 1, 19, "No Campus for Old Rules", new TheTVDBSearchResult("Greek", -1))); episodes.add(new Episode("Greek", 1, 19, "No Campus for Old Rules"));
SimilarityMetric[] metrics = new SimilarityMetric[] { EpisodeIdentifier, SubstringFields }; SimilarityMetric[] metrics = new SimilarityMetric[] { EpisodeIdentifier, SubstringFields };
List<Match<File, Episode>> m = new Matcher<File, Episode>(files, episodes, true, metrics).match(); 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).getValue().getName());
assertEquals("Veronica Mars - 1x19 - Hot Dogs", m.get(1).getCandidate().toString()); assertEquals("Veronica Mars - 1x19 - Hot Dogs", m.get(1).getCandidate().toString());
} }
} }

View File

@ -45,7 +45,7 @@ public class AnidbClientTest {
@Test @Test
public void search() throws Exception { 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); AnidbSearchResult result = (AnidbSearchResult) results.get(0);
assertEquals("One Piece", result.getName()); assertEquals("One Piece", result.getName());
@ -54,7 +54,7 @@ public class AnidbClientTest {
@Test @Test
public void searchNoMatch() throws Exception { 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()); assertTrue(results.isEmpty());
} }
@ -62,23 +62,23 @@ public class AnidbClientTest {
@Test @Test
public void searchTitleAlias() throws Exception { public void searchTitleAlias() throws Exception {
// Seikai no Senki (main title), Banner of the Stars (official English title) // 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("banner of the stars", Locale.ENGLISH).get(0).getName());
assertEquals("Seikai no Senki", anidb.search("seikai no senki").get(0).getName()); assertEquals("Seikai no Senki", anidb.search("seikai no senki", Locale.ENGLISH).get(0).getName());
// no matching title // no matching title
assertEquals("Naruto", anidb.search("naruto").get(0).getName()); assertEquals("Naruto", anidb.search("naruto", Locale.ENGLISH).get(0).getName());
} }
@Test @Test
public void getEpisodeListAll() throws Exception { 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()); assertEquals(77, list.size());
Episode first = list.get(0); Episode first = list.get(0);
assertEquals("Monster", first.getSeriesName()); 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("Herr Dr. Tenma", first.getTitle());
assertEquals("1", first.getEpisode().toString()); assertEquals("1", first.getEpisode().toString());
assertEquals("1", first.getAbsolute().toString()); assertEquals("1", first.getAbsolute().toString());
@ -88,14 +88,14 @@ public class AnidbClientTest {
@Test @Test
public void getEpisodeListAllShortLink() throws Exception { 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()); assertEquals(46, list.size());
Episode first = list.get(0); Episode first = list.get(0);
assertEquals("The Twelve Kingdoms", first.getSeriesName()); 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("Shadow of the Moon, The Sea of Shadow - Chapter 1", first.getTitle());
assertEquals("1", first.getEpisode().toString()); assertEquals("1", first.getEpisode().toString());
assertEquals("1", first.getAbsolute().toString()); assertEquals("1", first.getAbsolute().toString());
@ -105,7 +105,7 @@ public class AnidbClientTest {
@Test @Test
public void getEpisodeListEncoding() throws Exception { 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 @Test
@ -114,7 +114,7 @@ public class AnidbClientTest {
Episode last = list.get(73); Episode last = list.get(73);
assertEquals("モンスター", last.getSeriesName()); assertEquals("モンスター", last.getSeriesName());
assertEquals("2004-04-07", last.getSeriesStartDate().toString()); assertEquals("2004-04-07", last.getSeriesInfo().getStartDate().toString());
assertEquals("本当の怪物", last.getTitle()); assertEquals("本当の怪物", last.getTitle());
assertEquals("74", last.getEpisode().toString()); assertEquals("74", last.getEpisode().toString());
assertEquals("74", last.getAbsolute().toString()); assertEquals("74", last.getAbsolute().toString());
@ -124,7 +124,7 @@ public class AnidbClientTest {
@Test @Test
public void getEpisodeListTrimRecap() throws Exception { 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 @Test

View File

@ -3,6 +3,7 @@ package net.filebot.web;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.util.List; import java.util.List;
import java.util.Locale;
import org.junit.Test; import org.junit.Test;
@ -15,7 +16,7 @@ public class TVRageClientTest {
@Test @Test
public void search() throws Exception { 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); TVRageSearchResult result = (TVRageSearchResult) results.get(0);
@ -28,14 +29,14 @@ public class TVRageClientTest {
@Test @Test
public void getEpisodeList() throws Exception { 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()); assertEquals(22, list.size());
Episode chosen = list.get(21); Episode chosen = list.get(21);
assertEquals("Buffy the Vampire Slayer", chosen.getSeriesName()); 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("Chosen", chosen.getTitle());
assertEquals("22", chosen.getEpisode().toString()); assertEquals("22", chosen.getEpisode().toString());
assertEquals("7", chosen.getSeason().toString()); assertEquals("7", chosen.getSeason().toString());
@ -45,7 +46,7 @@ public class TVRageClientTest {
@Test @Test
public void getEpisodeListAll() throws Exception { 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()); assertEquals(143, list.size());

View File

@ -1,7 +1,5 @@
package net.filebot.web; package net.filebot.web;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.util.EnumSet; import java.util.EnumSet;
@ -12,23 +10,20 @@ import java.util.Map;
import net.filebot.web.TheTVDBClient.BannerDescriptor; import net.filebot.web.TheTVDBClient.BannerDescriptor;
import net.filebot.web.TheTVDBClient.MirrorType; import net.filebot.web.TheTVDBClient.MirrorType;
import net.filebot.web.TheTVDBClient.SeriesInfo;
import net.sf.ehcache.CacheManager; import net.sf.ehcache.CacheManager;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
public class TheTVDBClientTest { public class TheTVDBClientTest {
private TheTVDBClient thetvdb = new TheTVDBClient("BA864DEE427E384A"); private TheTVDBClient thetvdb = new TheTVDBClient("BA864DEE427E384A");
@Test @Test
public void search() throws Exception { public void search() throws Exception {
// test default language and query escaping (blanks) // 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()); assertEquals(2, results.size());
@ -38,7 +33,6 @@ public class TheTVDBClientTest {
assertEquals(70726, first.getSeriesId()); assertEquals(70726, first.getSeriesId());
} }
@Test @Test
public void searchGerman() throws Exception { public void searchGerman() throws Exception {
List<SearchResult> results = thetvdb.search("Buffy the Vampire Slayer", Locale.GERMAN); List<SearchResult> results = thetvdb.search("Buffy the Vampire Slayer", Locale.GERMAN);
@ -51,17 +45,16 @@ public class TheTVDBClientTest {
assertEquals(70327, first.getSeriesId()); assertEquals(70327, first.getSeriesId());
} }
@Test @Test
public void getEpisodeListAll() throws Exception { 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); assertTrue(list.size() >= 144);
// check ordinary episode // check ordinary episode
Episode first = list.get(0); Episode first = list.get(0);
assertEquals("Buffy the Vampire Slayer", first.getSeriesName()); 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("Welcome to the Hellmouth (1)", first.getTitle());
assertEquals("1", first.getEpisode().toString()); assertEquals("1", first.getEpisode().toString());
assertEquals("1", first.getSeason().toString()); assertEquals("1", first.getSeason().toString());
@ -79,15 +72,14 @@ public class TheTVDBClientTest {
assertEquals(null, last.getAirdate()); assertEquals(null, last.getAirdate());
} }
@Test @Test
public void getEpisodeListSingleSeason() throws Exception { 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); Episode first = list.get(0);
assertEquals("Wonderfalls", first.getSeriesName()); 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("Wax Lion", first.getTitle());
assertEquals("1", first.getEpisode().toString()); assertEquals("1", first.getEpisode().toString());
assertEquals("1", first.getSeason().toString()); assertEquals("1", first.getSeason().toString());
@ -95,14 +87,13 @@ public class TheTVDBClientTest {
assertEquals("2004-03-12", first.getAirdate().toString()); assertEquals("2004-03-12", first.getAirdate().toString());
} }
@Test @Test
public void getEpisodeListNumbering() throws Exception { public void getEpisodeListNumbering() throws Exception {
List<Episode> list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Firefly", 78874), SortOrder.DVD, Locale.ENGLISH); List<Episode> list = thetvdb.getEpisodeList(new TheTVDBSearchResult("Firefly", 78874), SortOrder.DVD, Locale.ENGLISH);
Episode first = list.get(0); Episode first = list.get(0);
assertEquals("Firefly", first.getSeriesName()); assertEquals("Firefly", first.getSeriesName());
assertEquals("2002-09-20", first.getSeriesStartDate().toString()); assertEquals("2002-09-20", first.getSeriesInfo().getStartDate().toString());
assertEquals("Serenity", first.getTitle()); assertEquals("Serenity", first.getTitle());
assertEquals("1", first.getEpisode().toString()); assertEquals("1", first.getEpisode().toString());
assertEquals("1", first.getSeason().toString()); assertEquals("1", first.getSeason().toString());
@ -110,13 +101,11 @@ public class TheTVDBClientTest {
assertEquals("2002-12-20", first.getAirdate().toString()); assertEquals("2002-12-20", first.getAirdate().toString());
} }
@Test @Test
public void getEpisodeListLink() { public void getEpisodeListLink() {
assertEquals("http://www.thetvdb.com/?tab=seasonall&id=78874", thetvdb.getEpisodeListLink(new TheTVDBSearchResult("Firefly", 78874)).toString()); assertEquals("http://www.thetvdb.com/?tab=seasonall&id=78874", thetvdb.getEpisodeListLink(new TheTVDBSearchResult("Firefly", 78874)).toString());
} }
@Test @Test
public void getMirror() throws Exception { public void getMirror() throws Exception {
assertNotNull(thetvdb.getMirror(MirrorType.XML)); assertNotNull(thetvdb.getMirror(MirrorType.XML));
@ -124,7 +113,6 @@ public class TheTVDBClientTest {
assertNotNull(thetvdb.getMirror(MirrorType.ZIP)); assertNotNull(thetvdb.getMirror(MirrorType.ZIP));
} }
@Test @Test
public void resolveTypeMask() { public void resolveTypeMask() {
// no flags set // no flags set
@ -137,7 +125,6 @@ public class TheTVDBClientTest {
assertEquals(EnumSet.allOf(MirrorType.class), MirrorType.fromTypeMask(7)); assertEquals(EnumSet.allOf(MirrorType.class), MirrorType.fromTypeMask(7));
} }
@Test @Test
public void lookupByID() throws Exception { public void lookupByID() throws Exception {
TheTVDBSearchResult series = thetvdb.lookupByID(78874, Locale.ENGLISH); TheTVDBSearchResult series = thetvdb.lookupByID(78874, Locale.ENGLISH);
@ -145,7 +132,6 @@ public class TheTVDBClientTest {
assertEquals(78874, series.getSeriesId()); assertEquals(78874, series.getSeriesId());
} }
@Test @Test
public void lookupByIMDbID() throws Exception { public void lookupByIMDbID() throws Exception {
TheTVDBSearchResult series = thetvdb.lookupByIMDbID(303461, Locale.ENGLISH); TheTVDBSearchResult series = thetvdb.lookupByIMDbID(303461, Locale.ENGLISH);
@ -153,23 +139,21 @@ public class TheTVDBClientTest {
assertEquals(78874, series.getSeriesId()); assertEquals(78874, series.getSeriesId());
} }
@Test @Test
public void getSeriesInfo() throws Exception { 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(80348, it.getId(), 0);
assertEquals("TV-PG", it.getContentRating()); assertEquals("TV-PG", it.getContentRating());
assertEquals("2007-09-24", it.getFirstAired().toString()); assertEquals("2007-09-24", it.getFirstAired().toString());
assertEquals("Action", it.getGenres().get(0)); assertEquals("Action", it.getGenres().get(0));
assertEquals(934814, it.getImdbId(), 0); assertEquals("tt0934814", it.getImdbId());
assertEquals("English", it.getLanguage().getDisplayLanguage(Locale.ENGLISH)); assertEquals("English", it.getLanguage());
assertEquals(310, it.getOverview().length()); assertEquals(310, it.getOverview().length());
assertEquals("60", it.getRuntime()); assertEquals("60", it.getRuntime());
assertEquals("Chuck", it.getName()); assertEquals("Chuck", it.getName());
} }
@Test @Test
public void getBanner() throws Exception { public void getBanner() throws Exception {
Map<String, String> filter = new HashMap<String, String>(); Map<String, String> filter = new HashMap<String, String>();
@ -187,7 +171,6 @@ public class TheTVDBClientTest {
assertEquals(99712, WebRequest.fetch(banner.getUrl()).remaining(), 0); assertEquals(99712, WebRequest.fetch(banner.getUrl()).remaining(), 0);
} }
@Test @Test
public void getBannerList() throws Exception { public void getBannerList() throws Exception {
List<BannerDescriptor> banners = thetvdb.getBannerList(new TheTVDBSearchResult("Buffy the Vampire Slayer", 70327)); List<BannerDescriptor> banners = thetvdb.getBannerList(new TheTVDBSearchResult("Buffy the Vampire Slayer", 70327));
@ -197,7 +180,6 @@ public class TheTVDBClientTest {
assertEquals(486993, WebRequest.fetch(banners.get(0).getUrl()).remaining(), 0); assertEquals(486993, WebRequest.fetch(banners.get(0).getUrl()).remaining(), 0);
} }
@BeforeClass @BeforeClass
@AfterClass @AfterClass
public static void clearCache() { public static void clearCache() {