2014-04-19 02:30:29 -04:00
|
|
|
package net.filebot.web;
|
2009-01-04 13:28:28 -05:00
|
|
|
|
2015-01-18 03:57:37 -05:00
|
|
|
import static java.util.Collections.*;
|
2016-03-07 05:55:45 -05:00
|
|
|
import static java.util.stream.Collectors.*;
|
2016-03-09 05:32:52 -05:00
|
|
|
import static net.filebot.Logging.*;
|
2016-01-09 23:54:35 -05:00
|
|
|
import static net.filebot.util.StringUtilities.*;
|
2014-04-19 02:30:29 -04:00
|
|
|
import static net.filebot.util.XPathUtilities.*;
|
|
|
|
import static net.filebot.web.EpisodeUtilities.*;
|
|
|
|
import static net.filebot.web.WebRequest.*;
|
2009-01-04 13:28:28 -05:00
|
|
|
|
2011-12-20 09:09:18 -05:00
|
|
|
import java.io.Serializable;
|
2009-01-04 13:28:28 -05:00
|
|
|
import java.net.URI;
|
|
|
|
import java.net.URL;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.EnumMap;
|
|
|
|
import java.util.EnumSet;
|
2011-11-04 05:11:11 -04:00
|
|
|
import java.util.LinkedHashMap;
|
2009-01-04 13:28:28 -05:00
|
|
|
import java.util.List;
|
|
|
|
import java.util.Locale;
|
|
|
|
import java.util.Map;
|
2011-12-30 05:35:26 -05:00
|
|
|
import java.util.Map.Entry;
|
2009-01-04 13:28:28 -05:00
|
|
|
import java.util.Random;
|
|
|
|
import java.util.logging.Level;
|
|
|
|
|
|
|
|
import javax.swing.Icon;
|
2009-07-13 08:41:19 -04:00
|
|
|
|
2014-04-19 02:30:29 -04:00
|
|
|
import net.filebot.Cache;
|
2016-03-09 05:32:52 -05:00
|
|
|
import net.filebot.Cache.TypedCache;
|
2016-03-06 13:11:30 -05:00
|
|
|
import net.filebot.CacheType;
|
2014-04-19 02:30:29 -04:00
|
|
|
import net.filebot.ResourceManager;
|
|
|
|
import net.filebot.util.FileUtilities;
|
|
|
|
import net.filebot.web.TheTVDBClient.BannerDescriptor.BannerProperty;
|
2009-01-04 13:28:28 -05:00
|
|
|
|
2012-07-25 00:34:20 -04:00
|
|
|
import org.w3c.dom.Document;
|
|
|
|
import org.w3c.dom.Node;
|
|
|
|
|
2011-08-08 13:37:45 -04:00
|
|
|
public class TheTVDBClient extends AbstractEpisodeListProvider {
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
private final Map<MirrorType, String> mirrors = MirrorType.newMap();
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-11-13 13:22:50 -05:00
|
|
|
private final String apikey;
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
public TheTVDBClient(String apikey) {
|
2009-01-24 19:08:57 -05:00
|
|
|
if (apikey == null)
|
|
|
|
throw new NullPointerException("apikey must not be null");
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
this.apikey = apikey;
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
@Override
|
|
|
|
public String getName() {
|
|
|
|
return "TheTVDB";
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
@Override
|
|
|
|
public Icon getIcon() {
|
|
|
|
return ResourceManager.getIcon("search.thetvdb");
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
@Override
|
2014-12-10 13:53:58 -05:00
|
|
|
public boolean hasSeasonSupport() {
|
2009-01-04 13:28:28 -05:00
|
|
|
return true;
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
@Override
|
2014-12-10 13:53:58 -05:00
|
|
|
protected SortOrder vetoRequestParameter(SortOrder order) {
|
|
|
|
return order != null ? order : SortOrder.Airdate;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected Locale vetoRequestParameter(Locale language) {
|
|
|
|
return language != null ? language : Locale.ENGLISH;
|
|
|
|
}
|
|
|
|
|
2012-07-14 10:54:07 -04:00
|
|
|
public String getLanguageCode(Locale locale) {
|
|
|
|
String code = locale.getLanguage();
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-02-08 12:27:17 -05:00
|
|
|
// sanity check
|
|
|
|
if (code.length() != 2) {
|
|
|
|
// see http://thetvdb.com/api/BA864DEE427E384A/languages.xml
|
|
|
|
throw new IllegalArgumentException("Expecting 2-letter language code: " + code);
|
|
|
|
}
|
|
|
|
|
2012-07-14 10:54:07 -04:00
|
|
|
// Java language code => TheTVDB language code
|
|
|
|
if (code.equals("iw")) // Hebrew
|
|
|
|
return "he";
|
|
|
|
if (code.equals("hi")) // Hungarian
|
|
|
|
return "hu";
|
|
|
|
if (code.equals("in")) // Indonesian
|
|
|
|
return "id";
|
|
|
|
if (code.equals("ro")) // Russian
|
|
|
|
return "ru";
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2012-07-14 10:54:07 -04:00
|
|
|
return code;
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-11-26 04:44:49 -05:00
|
|
|
@Override
|
2012-07-14 10:54:07 -04:00
|
|
|
public List<SearchResult> fetchSearchResult(String query, Locale locale) throws Exception {
|
2010-11-09 03:04:12 -05:00
|
|
|
// perform online search
|
2016-03-07 05:55:45 -05:00
|
|
|
Document dom = getXmlResource(MirrorType.SEARCH, "GetSeries.php?seriesname=" + encode(query, true) + "&language=" + getLanguageCode(locale));
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-11-04 05:11:11 -04:00
|
|
|
Map<Integer, TheTVDBSearchResult> resultSet = new LinkedHashMap<Integer, TheTVDBSearchResult>();
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 00:58:36 -05:00
|
|
|
for (Node node : selectNodes("Data/Series", dom)) {
|
2016-01-09 23:54:35 -05:00
|
|
|
int sid = matchInteger(getTextContent("seriesid", node));
|
2009-02-21 07:48:52 -05:00
|
|
|
String seriesName = getTextContent("SeriesName", node);
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-01 00:19:27 -05:00
|
|
|
if (seriesName.startsWith("**") && seriesName.endsWith("**")) {
|
2016-03-09 15:36:28 -05:00
|
|
|
debug.log(Level.WARNING, String.format("Invalid series: %s [%d]", seriesName, sid));
|
2016-03-01 00:19:27 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2014-08-15 04:16:30 -04:00
|
|
|
List<String> aliasNames = new ArrayList<String>();
|
2013-09-06 03:55:13 -04:00
|
|
|
for (Node aliasNode : selectNodes("AliasNames", node)) {
|
2014-08-15 04:16:30 -04:00
|
|
|
for (String aliasName : getTextContent(aliasNode).split("\\|")) {
|
|
|
|
if (aliasName.trim().length() > 0) {
|
|
|
|
aliasNames.add(aliasName.trim());
|
|
|
|
}
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
}
|
|
|
|
|
2011-11-04 05:11:11 -04:00
|
|
|
if (!resultSet.containsKey(sid)) {
|
2013-09-06 03:55:13 -04:00
|
|
|
resultSet.put(sid, new TheTVDBSearchResult(seriesName, aliasNames.toArray(new String[0]), sid));
|
2011-11-04 05:11:11 -04:00
|
|
|
}
|
2009-01-04 13:28:28 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-11-04 05:11:11 -04:00
|
|
|
return new ArrayList<SearchResult>(resultSet.values());
|
2009-01-04 13:28:28 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
@Override
|
2014-12-10 13:53:58 -05:00
|
|
|
protected SeriesData fetchSeriesData(SearchResult searchResult, SortOrder sortOrder, Locale locale) throws Exception {
|
2011-08-08 13:37:45 -04:00
|
|
|
TheTVDBSearchResult series = (TheTVDBSearchResult) searchResult;
|
2016-03-07 05:55:45 -05:00
|
|
|
Document dom = getXmlResource(MirrorType.XML, "series/" + series.getSeriesId() + "/all/" + getLanguageCode(locale) + ".xml");
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2014-12-10 13:53:58 -05:00
|
|
|
// parse series info
|
|
|
|
Node seriesNode = selectNode("Data/Series", dom);
|
|
|
|
TheTVDBSeriesInfo seriesInfo = new TheTVDBSeriesInfo(getName(), sortOrder, locale, series.getId());
|
|
|
|
seriesInfo.setAliasNames(searchResult.getEffectiveNames());
|
|
|
|
|
|
|
|
seriesInfo.setName(getTextContent("SeriesName", seriesNode));
|
|
|
|
seriesInfo.setAirsDayOfWeek(getTextContent("Airs_DayOfWeek", seriesNode));
|
|
|
|
seriesInfo.setAirTime(getTextContent("Airs_Time", seriesNode));
|
|
|
|
seriesInfo.setCertification(getTextContent("ContentRating", seriesNode));
|
|
|
|
seriesInfo.setImdbId(getTextContent("IMDB_ID", seriesNode));
|
|
|
|
seriesInfo.setNetwork(getTextContent("Network", seriesNode));
|
|
|
|
seriesInfo.setOverview(getTextContent("Overview", seriesNode));
|
|
|
|
seriesInfo.setStatus(getTextContent("Status", seriesNode));
|
|
|
|
|
2014-12-23 01:38:29 -05:00
|
|
|
seriesInfo.setRating(getDecimal(getTextContent("Rating", seriesNode)));
|
2016-01-09 23:54:35 -05:00
|
|
|
seriesInfo.setRatingCount(matchInteger(getTextContent("RatingCount", seriesNode)));
|
|
|
|
seriesInfo.setRuntime(matchInteger(getTextContent("Runtime", seriesNode)));
|
2014-12-10 13:53:58 -05:00
|
|
|
seriesInfo.setActors(getListContent("Actors", "\\|", seriesNode));
|
|
|
|
seriesInfo.setGenres(getListContent("Genre", "\\|", seriesNode));
|
2016-02-10 06:47:13 -05:00
|
|
|
seriesInfo.setStartDate(SimpleDate.parse(getTextContent("FirstAired", seriesNode)));
|
2014-12-10 13:53:58 -05:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
seriesInfo.setBannerUrl(getResource(MirrorType.BANNER, getTextContent("banner", seriesNode)));
|
|
|
|
seriesInfo.setFanartUrl(getResource(MirrorType.BANNER, getTextContent("fanart", seriesNode)));
|
|
|
|
seriesInfo.setPosterUrl(getResource(MirrorType.BANNER, getTextContent("poster", seriesNode)));
|
2014-12-10 13:53:58 -05:00
|
|
|
|
|
|
|
// parse episode data
|
2016-03-09 00:58:36 -05:00
|
|
|
List<Episode> episodes = new ArrayList<Episode>(50);
|
2010-02-03 16:36:04 -05:00
|
|
|
List<Episode> specials = new ArrayList<Episode>(5);
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 00:58:36 -05:00
|
|
|
for (Node node : selectNodes("Data/Episode", dom)) {
|
2009-01-04 13:28:28 -05:00
|
|
|
String episodeName = getTextContent("EpisodeName", node);
|
2016-01-09 23:54:35 -05:00
|
|
|
Integer absoluteNumber = matchInteger(getTextContent("absolute_number", node));
|
2016-02-10 06:47:13 -05:00
|
|
|
SimpleDate airdate = SimpleDate.parse(getTextContent("FirstAired", node));
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2012-02-13 04:54:57 -05:00
|
|
|
// default numbering
|
2016-01-09 23:54:35 -05:00
|
|
|
Integer episodeNumber = matchInteger(getTextContent("EpisodeNumber", node));
|
|
|
|
Integer seasonNumber = matchInteger(getTextContent("SeasonNumber", node));
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2015-01-10 06:27:38 -05:00
|
|
|
// adjust for DVD numbering if possible
|
|
|
|
if (sortOrder == SortOrder.DVD) {
|
2016-01-09 23:54:35 -05:00
|
|
|
Integer dvdSeasonNumber = matchInteger(getTextContent("DVD_season", node));
|
|
|
|
Integer dvdEpisodeNumber = matchInteger(getTextContent("DVD_episodenumber", node));
|
2015-01-10 06:27:38 -05:00
|
|
|
|
|
|
|
// require both values to be valid integer numbers
|
|
|
|
if (dvdSeasonNumber != null && dvdEpisodeNumber != null) {
|
|
|
|
seasonNumber = dvdSeasonNumber;
|
|
|
|
episodeNumber = dvdEpisodeNumber;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// adjust for special numbering if necessary
|
2010-11-15 05:06:24 -05:00
|
|
|
if (seasonNumber == null || seasonNumber == 0) {
|
2010-02-03 16:36:04 -05:00
|
|
|
// handle as special episode
|
2015-01-08 14:23:56 -05:00
|
|
|
for (String specialSeasonTag : new String[] { "airsafter_season", "airsbefore_season" }) {
|
2016-01-09 23:54:35 -05:00
|
|
|
Integer specialSeason = matchInteger(getTextContent(specialSeasonTag, node));
|
2015-01-08 14:23:56 -05:00
|
|
|
if (specialSeason != null && specialSeason != 0) {
|
|
|
|
seasonNumber = specialSeason;
|
|
|
|
break;
|
|
|
|
}
|
2010-02-03 16:36:04 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-10-23 10:09:41 -04:00
|
|
|
// use given episode number as special number or count specials by ourselves
|
|
|
|
Integer specialNumber = (episodeNumber != null) ? episodeNumber : filterBySeason(specials, seasonNumber).size() + 1;
|
2014-12-10 13:53:58 -05:00
|
|
|
specials.add(new Episode(seriesInfo.getName(), seasonNumber, null, episodeName, null, specialNumber, airdate, new SeriesInfo(seriesInfo)));
|
2010-02-03 16:36:04 -05:00
|
|
|
} else {
|
2015-01-10 06:27:38 -05:00
|
|
|
// adjust for absolute numbering if possible
|
2012-02-13 04:54:57 -05:00
|
|
|
if (sortOrder == SortOrder.Absolute) {
|
2015-01-10 06:27:38 -05:00
|
|
|
if (absoluteNumber != null && absoluteNumber > 0) {
|
2012-02-13 04:54:57 -05:00
|
|
|
episodeNumber = absoluteNumber;
|
|
|
|
seasonNumber = null;
|
|
|
|
}
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2015-01-10 06:27:38 -05:00
|
|
|
// handle as normal episode
|
2014-12-10 13:53:58 -05:00
|
|
|
episodes.add(new Episode(seriesInfo.getName(), seasonNumber, episodeNumber, episodeName, absoluteNumber, null, airdate, new SeriesInfo(seriesInfo)));
|
2010-02-03 16:36:04 -05:00
|
|
|
}
|
2009-01-04 13:28:28 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2010-11-15 05:06:24 -05:00
|
|
|
// episodes my not be ordered by DVD episode number
|
2015-01-18 03:57:37 -05:00
|
|
|
sort(episodes, episodeComparator());
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2010-02-03 16:36:04 -05:00
|
|
|
// add specials at the end
|
|
|
|
episodes.addAll(specials);
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2014-12-10 13:53:58 -05:00
|
|
|
return new SeriesData(seriesInfo, episodes);
|
2009-01-04 13:28:28 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
public TheTVDBSearchResult lookupByID(int id, Locale language) throws Exception {
|
|
|
|
if (id <= 0) {
|
|
|
|
throw new IllegalArgumentException("Illegal TheTVDB ID: " + id);
|
2012-01-01 22:07:09 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 14:51:41 -05:00
|
|
|
return getLookupCache("id", language).computeIfAbsent(id, it -> {
|
2016-03-09 05:32:52 -05:00
|
|
|
Document dom = getXmlResource(MirrorType.XML, "series/" + id + "/all/" + getLanguageCode(language) + ".xml");
|
|
|
|
String name = selectString("//SeriesName", dom);
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
return new TheTVDBSearchResult(name, id);
|
|
|
|
});
|
2011-12-12 09:06:26 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2012-07-14 10:54:07 -04:00
|
|
|
public TheTVDBSearchResult lookupByIMDbID(int imdbid, Locale locale) throws Exception {
|
2014-05-26 12:47:04 -04:00
|
|
|
if (imdbid <= 0) {
|
2016-03-09 05:32:52 -05:00
|
|
|
throw new IllegalArgumentException("Illegal IMDbID ID: " + imdbid);
|
2012-01-01 22:07:09 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 14:51:41 -05:00
|
|
|
return getLookupCache("imdbid", locale).computeIfAbsent(imdbid, it -> {
|
2016-03-09 05:32:52 -05:00
|
|
|
Document dom = getXmlResource(MirrorType.SEARCH, "GetSeriesByRemoteID.php?imdbid=" + imdbid + "&language=" + getLanguageCode(locale));
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
String id = selectString("//seriesid", dom);
|
|
|
|
String name = selectString("//SeriesName", dom);
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
if (id.isEmpty() || name.isEmpty())
|
|
|
|
return null;
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
return new TheTVDBSearchResult(name, Integer.parseInt(id));
|
|
|
|
});
|
2011-12-13 20:19:36 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
protected String getMirror(MirrorType mirrorType) throws Exception {
|
|
|
|
// use default server
|
|
|
|
if (mirrorType == MirrorType.NULL) {
|
|
|
|
return "http://thetvdb.com";
|
|
|
|
}
|
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
synchronized (mirrors) {
|
2016-03-07 05:55:45 -05:00
|
|
|
// initialize mirrors
|
2009-01-04 13:28:28 -05:00
|
|
|
if (mirrors.isEmpty()) {
|
2016-03-07 05:55:45 -05:00
|
|
|
Document dom = getXmlResource(MirrorType.NULL, "mirrors.xml");
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
// collect all mirror data
|
2016-03-09 00:58:36 -05:00
|
|
|
Map<MirrorType, List<String>> mirrorLists = streamNodes("Mirrors/Mirror", dom).flatMap(node -> {
|
2009-02-21 07:48:52 -05:00
|
|
|
String mirror = getTextContent("mirrorpath", node);
|
|
|
|
int typeMask = Integer.parseInt(getTextContent("typemask", node));
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
return MirrorType.fromTypeMask(typeMask).stream().collect(toMap(m -> m, m -> mirror)).entrySet().stream();
|
|
|
|
}).collect(groupingBy(Entry::getKey, MirrorType::newMap, mapping(Entry::getValue, toList())));
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
// select random mirror for each type
|
2009-01-04 13:28:28 -05:00
|
|
|
Random random = new Random();
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
mirrorLists.forEach((type, options) -> {
|
|
|
|
String selection = options.get(random.nextInt(options.size()));
|
|
|
|
mirrors.put(type, selection);
|
|
|
|
});
|
2009-01-04 13:28:28 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
// return selected mirror
|
2009-01-04 13:28:28 -05:00
|
|
|
return mirrors.get(mirrorType);
|
|
|
|
}
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 06:32:00 -05:00
|
|
|
protected Document getXmlResource(MirrorType mirror, String resource) throws Exception {
|
2016-03-07 05:55:45 -05:00
|
|
|
Cache cache = Cache.getCache(getName(), CacheType.Monthly);
|
2016-03-07 11:01:10 -05:00
|
|
|
return cache.xml(resource, s -> getResource(mirror, s)).get();
|
2013-10-15 03:12:42 -04:00
|
|
|
}
|
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
protected URL getResource(MirrorType mirror, String path) throws Exception {
|
|
|
|
StringBuilder url = new StringBuilder(getMirror(mirror)).append('/').append(mirror.prefix()).append('/');
|
|
|
|
if (mirror.keyRequired()) {
|
|
|
|
url.append(apikey).append('/');
|
2013-03-25 05:35:17 -04:00
|
|
|
}
|
2016-03-07 05:55:45 -05:00
|
|
|
return new URL(url.append(path).toString());
|
2009-07-13 08:41:19 -04:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
protected static enum MirrorType {
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
NULL(0), SEARCH(1), XML(1), BANNER(2);
|
|
|
|
|
|
|
|
final int bitMask;
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
private MirrorType(int bitMask) {
|
|
|
|
this.bitMask = bitMask;
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
public String prefix() {
|
|
|
|
return this != BANNER ? "api" : "banners";
|
|
|
|
}
|
|
|
|
|
|
|
|
public boolean keyRequired() {
|
|
|
|
return this != BANNER && this != SEARCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
public static EnumSet<MirrorType> fromTypeMask(int mask) {
|
|
|
|
// convert bit mask to enumset
|
|
|
|
return EnumSet.of(SEARCH, XML, BANNER).stream().filter(m -> {
|
|
|
|
return (mask & m.bitMask) != 0;
|
|
|
|
}).collect(toCollection(MirrorType::newSet));
|
2009-01-04 13:28:28 -05:00
|
|
|
};
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-07 05:55:45 -05:00
|
|
|
public static EnumSet<MirrorType> newSet() {
|
|
|
|
return EnumSet.noneOf(MirrorType.class);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static <T> EnumMap<MirrorType, T> newMap() {
|
|
|
|
return new EnumMap<MirrorType, T>(MirrorType.class);
|
|
|
|
}
|
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2012-01-02 10:27:20 -05:00
|
|
|
public SeriesInfo getSeriesInfoByIMDbID(int imdbid, Locale locale) throws Exception {
|
|
|
|
return getSeriesInfo(lookupByIMDbID(imdbid, locale), locale);
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2014-12-10 13:53:58 -05:00
|
|
|
@Override
|
|
|
|
protected SearchResult createSearchResult(int id) {
|
|
|
|
return new TheTVDBSearchResult(null, id);
|
2011-12-21 00:54:30 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2014-12-10 13:53:58 -05:00
|
|
|
@Override
|
|
|
|
public URI getEpisodeListLink(SearchResult searchResult) {
|
2016-03-07 06:32:00 -05:00
|
|
|
return URI.create("http://www.thetvdb.com/?tab=seasonall&id=" + ((TheTVDBSearchResult) searchResult).getSeriesId());
|
2011-12-21 00:54:30 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-19 21:37:36 -05:00
|
|
|
/**
|
|
|
|
* Search for a series banner matching the given parameters
|
2015-07-25 18:47:19 -04:00
|
|
|
*
|
2011-12-19 21:37:36 -05:00
|
|
|
* @see http://thetvdb.com/wiki/index.php/API:banners.xml
|
|
|
|
*/
|
2011-12-30 05:35:26 -05:00
|
|
|
public BannerDescriptor getBanner(TheTVDBSearchResult series, Map<?, ?> filterDescriptor) throws Exception {
|
|
|
|
EnumMap<BannerProperty, String> filter = new EnumMap<BannerProperty, String>(BannerProperty.class);
|
|
|
|
for (Entry<?, ?> it : filterDescriptor.entrySet()) {
|
|
|
|
if (it.getValue() != null) {
|
|
|
|
filter.put(BannerProperty.valueOf(it.getKey().toString()), it.getValue().toString());
|
|
|
|
}
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-19 21:37:36 -05:00
|
|
|
// search for a banner matching the selector
|
2011-12-28 20:31:11 -05:00
|
|
|
for (BannerDescriptor it : getBannerList(series)) {
|
2011-12-30 05:35:26 -05:00
|
|
|
if (it.fields.entrySet().containsAll(filter.entrySet())) {
|
|
|
|
return it;
|
2011-12-19 21:37:36 -05:00
|
|
|
}
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-19 21:37:36 -05:00
|
|
|
return null;
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-28 20:31:11 -05:00
|
|
|
public List<BannerDescriptor> getBannerList(TheTVDBSearchResult series) throws Exception {
|
2016-03-09 14:51:41 -05:00
|
|
|
return getBannerCache().computeIfAbsent(series.getId(), it -> {
|
2016-03-09 05:32:52 -05:00
|
|
|
Document dom = getXmlResource(MirrorType.XML, "series/" + series.getId() + "/banners.xml");
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
String bannerMirror = getResource(MirrorType.BANNER, "").toString();
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
return streamNodes("//Banner", dom).map(n -> {
|
|
|
|
Map<BannerProperty, String> map = getEnumMap(n, BannerProperty.class);
|
|
|
|
map.put(BannerProperty.BannerMirror, bannerMirror);
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
return new BannerDescriptor(map);
|
|
|
|
}).filter(m -> m.getUrl() != null).collect(toList());
|
|
|
|
});
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
protected TypedCache<TheTVDBSearchResult> getLookupCache(String type, Locale language) {
|
|
|
|
// lookup should always yield the same results so we can cache it for longer
|
|
|
|
return Cache.getCache(getName() + "_" + "lookup" + "_" + type + "_" + language, CacheType.Monthly).cast(TheTVDBSearchResult.class);
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
protected TypedCache<List<BannerDescriptor>> getBannerCache() {
|
|
|
|
// banners do not change that often so we can cache them for longer
|
|
|
|
return Cache.getCache(getName() + "_" + "banner", CacheType.Weekly).castList(BannerDescriptor.class);
|
2011-12-19 21:37:36 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 09:09:18 -05:00
|
|
|
public static class BannerDescriptor implements Serializable {
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 08:00:38 -05:00
|
|
|
public static enum BannerProperty {
|
2013-07-13 06:01:33 -04:00
|
|
|
id, BannerMirror, BannerPath, BannerType, BannerType2, Season, Colors, Language, Rating, RatingCount, SeriesName, ThumbnailPath, VignettePath
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-21 00:54:30 -05:00
|
|
|
protected Map<BannerProperty, String> fields;
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 09:09:18 -05:00
|
|
|
protected BannerDescriptor() {
|
|
|
|
// used by serializer
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 08:00:38 -05:00
|
|
|
protected BannerDescriptor(Map<BannerProperty, String> fields) {
|
|
|
|
this.fields = new EnumMap<BannerProperty, String>(fields);
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-21 00:54:30 -05:00
|
|
|
public String get(Object key) {
|
|
|
|
return fields.get(BannerProperty.valueOf(key.toString()));
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-21 00:54:30 -05:00
|
|
|
public String get(BannerProperty key) {
|
|
|
|
return fields.get(key);
|
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
public URL getBannerMirrorUrl(String path) {
|
2011-12-30 05:35:26 -05:00
|
|
|
try {
|
2016-03-09 05:32:52 -05:00
|
|
|
return new URL(new URL(get(BannerProperty.BannerMirror)), path);
|
2011-12-30 05:35:26 -05:00
|
|
|
} catch (Exception e) {
|
2016-03-09 05:32:52 -05:00
|
|
|
debug.finest(format("Bad banner url: %s", e));
|
2011-12-30 05:35:26 -05:00
|
|
|
return null;
|
|
|
|
}
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
public URL getUrl() {
|
|
|
|
return getBannerMirrorUrl(get(BannerProperty.BannerPath));
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 08:00:38 -05:00
|
|
|
public String getExtension() {
|
2011-12-21 00:54:30 -05:00
|
|
|
return FileUtilities.getExtension(get(BannerProperty.BannerPath));
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-30 05:35:26 -05:00
|
|
|
public Integer getId() {
|
|
|
|
try {
|
|
|
|
return new Integer(get(BannerProperty.id));
|
|
|
|
} catch (Exception e) {
|
|
|
|
return null;
|
|
|
|
}
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 08:00:38 -05:00
|
|
|
public String getBannerType() {
|
2011-12-21 00:54:30 -05:00
|
|
|
return get(BannerProperty.BannerType);
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 08:00:38 -05:00
|
|
|
public String getBannerType2() {
|
2011-12-21 00:54:30 -05:00
|
|
|
return get(BannerProperty.BannerType2);
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 08:00:38 -05:00
|
|
|
public Integer getSeason() {
|
|
|
|
try {
|
2011-12-21 00:54:30 -05:00
|
|
|
return new Integer(get(BannerProperty.Season));
|
2016-03-09 05:32:52 -05:00
|
|
|
} catch (Exception e) {
|
2011-12-20 08:00:38 -05:00
|
|
|
return null;
|
|
|
|
}
|
2011-12-19 21:37:36 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 08:00:38 -05:00
|
|
|
public String getColors() {
|
2011-12-21 00:54:30 -05:00
|
|
|
return get(BannerProperty.Colors);
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 08:00:38 -05:00
|
|
|
public Locale getLocale() {
|
2011-12-30 05:35:26 -05:00
|
|
|
try {
|
|
|
|
return new Locale(get(BannerProperty.Language));
|
|
|
|
} catch (Exception e) {
|
|
|
|
return null;
|
|
|
|
}
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-30 05:35:26 -05:00
|
|
|
public Double getRating() {
|
|
|
|
try {
|
|
|
|
return new Double(get(BannerProperty.Rating));
|
|
|
|
} catch (Exception e) {
|
|
|
|
return null;
|
|
|
|
}
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-30 05:35:26 -05:00
|
|
|
public Integer getRatingCount() {
|
|
|
|
try {
|
|
|
|
return new Integer(get(BannerProperty.RatingCount));
|
|
|
|
} catch (Exception e) {
|
|
|
|
return null;
|
|
|
|
}
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 08:00:38 -05:00
|
|
|
public boolean hasSeriesName() {
|
2011-12-21 00:54:30 -05:00
|
|
|
return Boolean.parseBoolean(get(BannerProperty.SeriesName));
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
public URL getThumbnailUrl() {
|
|
|
|
return getBannerMirrorUrl(get(BannerProperty.ThumbnailPath));
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2016-03-09 05:32:52 -05:00
|
|
|
public URL getVignetteUrl() {
|
|
|
|
return getBannerMirrorUrl(get(BannerProperty.VignettePath));
|
2011-12-20 08:00:38 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2011-12-20 08:00:38 -05:00
|
|
|
@Override
|
|
|
|
public String toString() {
|
|
|
|
return fields.toString();
|
2011-12-19 21:37:36 -05:00
|
|
|
}
|
2016-03-09 05:32:52 -05:00
|
|
|
|
2011-12-19 21:37:36 -05:00
|
|
|
}
|
2013-09-06 03:55:13 -04:00
|
|
|
|
2009-01-04 13:28:28 -05:00
|
|
|
}
|