Experiment with TheTVDB API v2
This commit is contained in:
parent
4c85678975
commit
a17423dd95
|
@ -7,13 +7,16 @@ import java.io.IOException;
|
|||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.time.Duration;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
|
@ -173,10 +176,14 @@ public class CachedResource<K, R> implements Resource<R> {
|
|||
}
|
||||
|
||||
public static Fetch fetchIfModified() {
|
||||
return fetchIfModified(Collections::emptyMap);
|
||||
}
|
||||
|
||||
public static Fetch fetchIfModified(Supplier<Map<String, String>> requestParameters) {
|
||||
return (url, lastModified) -> {
|
||||
debug.fine(WebRequest.log(url, lastModified, null));
|
||||
try {
|
||||
debug.fine(WebRequest.log(url, lastModified, null));
|
||||
return WebRequest.fetchIfModified(url, lastModified);
|
||||
return WebRequest.fetch(url, lastModified, null, requestParameters.get(), null);
|
||||
} catch (FileNotFoundException e) {
|
||||
return fileNotFound(url, e);
|
||||
}
|
||||
|
@ -185,28 +192,25 @@ public class CachedResource<K, R> implements Resource<R> {
|
|||
|
||||
public static Fetch fetchIfNoneMatch(Function<URL, Object> etagRetrieve, BiConsumer<URL, String> etagStore) {
|
||||
return (url, lastModified) -> {
|
||||
// record ETag response header
|
||||
Map<String, List<String>> responseHeaders = new HashMap<String, List<String>>();
|
||||
Object etagValue = etagRetrieve.apply(url);
|
||||
|
||||
debug.fine(WebRequest.log(url, lastModified, etagValue));
|
||||
try {
|
||||
debug.fine(WebRequest.log(url, lastModified, etagValue));
|
||||
if (etagValue != null) {
|
||||
return WebRequest.fetch(url, 0, etagValue, null, responseHeaders);
|
||||
} else {
|
||||
return WebRequest.fetch(url, lastModified, null, null, responseHeaders);
|
||||
}
|
||||
return WebRequest.fetch(url, etagValue == null ? lastModified : 0, etagValue, null, storeETag(url, etagStore));
|
||||
} catch (FileNotFoundException e) {
|
||||
return fileNotFound(url, e);
|
||||
} finally {
|
||||
WebRequest.getETag(responseHeaders).ifPresent(etag -> {
|
||||
debug.finest(format("Store ETag: %s", etag));
|
||||
etagStore.accept(url, etag);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static Consumer<Map<String, List<String>>> storeETag(URL url, BiConsumer<URL, String> etagStore) {
|
||||
return (responseHeaders) -> {
|
||||
WebRequest.getETag(responseHeaders).ifPresent(etag -> {
|
||||
debug.finest(format("Store ETag: %s", etag));
|
||||
etagStore.accept(url, etag);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
private static ByteBuffer fileNotFound(URL url, FileNotFoundException e) {
|
||||
debug.warning(format("Resource not found: %s", url));
|
||||
return ByteBuffer.allocate(0);
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.stream.Stream;
|
|||
|
||||
import com.cedarsoftware.util.io.JsonObject;
|
||||
import com.cedarsoftware.util.io.JsonReader;
|
||||
import com.cedarsoftware.util.io.JsonWriter;
|
||||
|
||||
public class JsonUtilities {
|
||||
|
||||
|
@ -23,6 +24,10 @@ public class JsonUtilities {
|
|||
return JsonReader.jsonToJava(json.toString(), singletonMap(JsonReader.USE_MAPS, true));
|
||||
}
|
||||
|
||||
public static String asJsonString(Object object) {
|
||||
return JsonWriter.objectToJson(object);
|
||||
}
|
||||
|
||||
public static Map<?, ?> asMap(Object node) {
|
||||
if (node instanceof Map) {
|
||||
return (Map<?, ?>) node;
|
||||
|
|
|
@ -50,6 +50,12 @@ public class SeriesInfo implements Serializable {
|
|||
this.status = other.status;
|
||||
}
|
||||
|
||||
public SeriesInfo(Datasource database, Locale language, Integer id) {
|
||||
this.database = database.getIdentifier();
|
||||
this.language = language.getLanguage();
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public SeriesInfo(Datasource database, SortOrder order, Locale language, Integer id) {
|
||||
this.database = database.getIdentifier();
|
||||
this.order = order.name();
|
||||
|
|
|
@ -0,0 +1,294 @@
|
|||
package net.filebot.web;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.*;
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.Collections.*;
|
||||
import static java.util.stream.Collectors.*;
|
||||
import static net.filebot.CachedResource.fetchIfModified;
|
||||
import static net.filebot.Logging.*;
|
||||
import static net.filebot.util.JsonUtilities.*;
|
||||
import static net.filebot.util.StringUtilities.*;
|
||||
import static net.filebot.web.EpisodeUtilities.*;
|
||||
import static net.filebot.web.WebRequest.*;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import net.filebot.Cache;
|
||||
import net.filebot.CacheType;
|
||||
import net.filebot.ResourceManager;
|
||||
|
||||
public class TheTVDBClient2 extends AbstractEpisodeListProvider {
|
||||
|
||||
private String apikey;
|
||||
|
||||
public TheTVDBClient2(String apikey) {
|
||||
this.apikey = apikey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "TheTVDB";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Icon getIcon() {
|
||||
return ResourceManager.getIcon("search.thetvdb");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSeasonSupport() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected Object requestJson(String path, Object post) throws Exception {
|
||||
// curl -X POST --header 'Content-Type: application/json' --header 'Accept: application/json' 'https://api.thetvdb.com/login' --data '{"apikey":"XXXXX"}'
|
||||
ByteBuffer response = post(getEndpoint(path), asJsonString(post).getBytes(UTF_8), "application/json", null);
|
||||
return readJson(UTF_8.decode(response));
|
||||
}
|
||||
|
||||
protected Object requestJson(String path, Locale locale, Duration expirationTime) throws Exception {
|
||||
Cache cache = Cache.getCache(locale == null ? getName() : getName() + "_" + locale.getLanguage(), CacheType.Monthly);
|
||||
return cache.json(path, this::getEndpoint).fetch(fetchIfModified(() -> getRequestHeader(locale))).expire(expirationTime).get();
|
||||
}
|
||||
|
||||
protected URL getEndpoint(String path) throws Exception {
|
||||
return new URL("https://api.thetvdb.com/" + path);
|
||||
}
|
||||
|
||||
private Map<String, String> getRequestHeader(Locale locale) {
|
||||
Map<String, String> header = new LinkedHashMap<String, String>(3);
|
||||
if (locale != null) {
|
||||
header.put("Accept-Language", locale.getLanguage());
|
||||
}
|
||||
header.put("Accept", "application/json");
|
||||
header.put("Authorization", "Bearer " + getAuthorizationToken());
|
||||
return header;
|
||||
}
|
||||
|
||||
private String token = null;
|
||||
|
||||
private synchronized String getAuthorizationToken() {
|
||||
// curl -v -X GET --header 'Accept: application/json' --header 'Authorization: Bearer TOKEN' 'https://api.thetvdb.com/languages'
|
||||
if (token == null) {
|
||||
try {
|
||||
Object json = requestJson("login", singletonMap("apikey", apikey));
|
||||
token = getString(json, "token");
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("Failed to retrieve authorization token: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
protected String[] languages() throws Exception {
|
||||
Object response = requestJson("languages", Cache.ONE_MONTH);
|
||||
return streamJsonObjects(response, "data").map(it -> getString(it, "abbreviation")).toArray(String[]::new);
|
||||
}
|
||||
|
||||
protected List<SearchResult> search(String path, Map<String, Object> query, Locale locale, Duration expirationTime) throws Exception {
|
||||
Object json = requestJson(path + "?" + encodeParameters(query, true), locale, expirationTime);
|
||||
|
||||
return streamJsonObjects(json, "data").map(it -> {
|
||||
// e.g. aliases, banner, firstAired, id, network, overview, seriesName, status
|
||||
int id = getInteger(it, "id");
|
||||
String seriesName = getString(it, "seriesName");
|
||||
String[] aliasNames = stream(getArray(it, "aliases")).toArray(String[]::new);
|
||||
|
||||
if (seriesName.startsWith("**") && seriesName.endsWith("**")) {
|
||||
debug.fine(format("Invalid series: %s [%d]", seriesName, id));
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SearchResult(id, seriesName, aliasNames);
|
||||
}).filter(Objects::nonNull).collect(toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SearchResult> fetchSearchResult(String query, Locale locale) throws Exception {
|
||||
return search("search/series", singletonMap("name", query), locale, Cache.ONE_DAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SeriesInfo getSeriesInfo(SearchResult series, Locale locale) throws Exception {
|
||||
Object json = requestJson("series/" + series.getId(), locale, Cache.ONE_WEEK);
|
||||
Object data = getMap(json, "data");
|
||||
|
||||
SeriesInfo info = new SeriesInfo(this, locale, series.getId());
|
||||
info.setAliasNames(Stream.of(series.getAliasNames(), getArray(data, "aliases")).flatMap(it -> stream(it)).map(Object::toString).distinct().toArray(String[]::new));
|
||||
|
||||
info.setName(getString(data, "seriesName"));
|
||||
info.setCertification(getString(data, "rating"));
|
||||
info.setNetwork(getString(data, "network"));
|
||||
info.setStatus(getString(data, "status"));
|
||||
|
||||
info.setRating(getDecimal(data, "siteRating"));
|
||||
info.setRatingCount(getInteger(data, "siteRatingCount")); // TODO rating count not implemented in the new API yet
|
||||
|
||||
info.setRuntime(matchInteger(getString(data, "runtime")));
|
||||
info.setGenres(stream(getArray(data, "genre")).map(Object::toString).collect(toList()));
|
||||
info.setStartDate(getStringValue(data, "firstAired", SimpleDate::parse));
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SeriesData fetchSeriesData(SearchResult series, SortOrder sortOrder, Locale locale) throws Exception {
|
||||
// fetch series info
|
||||
SeriesInfo info = getSeriesInfo(series, locale);
|
||||
info.setOrder(sortOrder.name());
|
||||
|
||||
// fetch episode data
|
||||
List<Episode> episodes = new ArrayList<Episode>();
|
||||
List<Episode> specials = new ArrayList<Episode>();
|
||||
|
||||
for (int page = 1, lastPage = 1; page <= lastPage; page++) {
|
||||
Object json = requestJson("series/" + series.getId() + "/episodes?page=" + page, locale, Cache.ONE_DAY);
|
||||
lastPage = getInteger(getMap(json, "links"), "last");
|
||||
|
||||
streamJsonObjects(json, "data").forEach(it -> {
|
||||
String episodeName = getString(it, "episodeName");
|
||||
Integer absoluteNumber = getInteger(it, "absoluteNumber");
|
||||
SimpleDate airdate = getStringValue(it, "firstAired", SimpleDate::parse);
|
||||
|
||||
// default numbering
|
||||
Integer episodeNumber = getInteger(it, "airedEpisodeNumber");
|
||||
Integer seasonNumber = getInteger(it, "airedSeason");
|
||||
|
||||
// use preferred numbering if possible
|
||||
if (sortOrder == SortOrder.DVD) {
|
||||
Integer dvdSeasonNumber = getInteger(it, "dvdSeason");
|
||||
Integer dvdEpisodeNumber = getInteger(it, "dvdEpisodeNumber");
|
||||
|
||||
// require both values to be valid integer numbers
|
||||
if (dvdSeasonNumber != null && dvdEpisodeNumber != null) {
|
||||
seasonNumber = dvdSeasonNumber;
|
||||
episodeNumber = dvdEpisodeNumber;
|
||||
}
|
||||
} else if (sortOrder == SortOrder.Absolute && absoluteNumber != null && absoluteNumber > 0) {
|
||||
episodeNumber = absoluteNumber;
|
||||
seasonNumber = null;
|
||||
}
|
||||
|
||||
if (seasonNumber == null || seasonNumber > 0) {
|
||||
// handle as normal episode
|
||||
episodes.add(new Episode(info.getName(), seasonNumber, episodeNumber, episodeName, absoluteNumber, null, airdate, new SeriesInfo(info)));
|
||||
} else {
|
||||
// handle as special episode
|
||||
specials.add(new Episode(info.getName(), null, null, episodeName, null, episodeNumber, airdate, new SeriesInfo(info)));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// episodes my not be ordered by DVD episode number
|
||||
episodes.sort(episodeComparator());
|
||||
|
||||
// add specials at the end
|
||||
episodes.addAll(specials);
|
||||
|
||||
return new SeriesData(info, episodes);
|
||||
}
|
||||
|
||||
public SearchResult lookupByID(int id, Locale locale) throws Exception {
|
||||
if (id <= 0) {
|
||||
throw new IllegalArgumentException("Illegal TheTVDB ID: " + id);
|
||||
}
|
||||
|
||||
SeriesInfo info = getSeriesInfo(new SearchResult(id, null), locale);
|
||||
return new SearchResult(id, info.getName(), info.getAliasNames());
|
||||
}
|
||||
|
||||
public SearchResult lookupByIMDbID(int imdbid, Locale locale) throws Exception {
|
||||
if (imdbid <= 0) {
|
||||
throw new IllegalArgumentException("Illegal IMDbID ID: " + imdbid);
|
||||
}
|
||||
|
||||
List<SearchResult> result = search("search/series", singletonMap("imdbId", imdbid), locale, Cache.ONE_MONTH);
|
||||
return result.size() > 0 ? result.get(0) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getEpisodeListLink(SearchResult searchResult) {
|
||||
return URI.create("http://www.thetvdb.com/?tab=seasonall&id=" + searchResult.getId());
|
||||
}
|
||||
|
||||
public List<Image> getImages(SearchResult series, String keyType) throws Exception {
|
||||
Object json = requestJson("series/" + series.getId() + "/images/query?keyType=" + keyType, null, Cache.ONE_WEEK);
|
||||
|
||||
return streamJsonObjects(json, "data").map(it -> {
|
||||
Integer id = getInteger(it, "id");
|
||||
String subKey = getString(it, "subKey");
|
||||
String fileName = getString(it, "fileName");
|
||||
String resolution = getString(it, "resolution");
|
||||
Double rating = getDecimal(getString(it, "ratingsInfo"), "average");
|
||||
|
||||
return new Image(id, keyType, subKey, fileName, resolution, rating);
|
||||
}).collect(toList());
|
||||
}
|
||||
|
||||
public static class Image implements Serializable {
|
||||
|
||||
private Integer id;
|
||||
private String keyType;
|
||||
private String subKey;
|
||||
private String fileName;
|
||||
private String resolution;
|
||||
private Double rating;
|
||||
|
||||
protected Image() {
|
||||
// used by serializer
|
||||
}
|
||||
|
||||
public Image(Integer id, String keyType, String subKey, String fileName, String resolution, Double rating) {
|
||||
this.id = id;
|
||||
this.keyType = keyType;
|
||||
this.subKey = subKey;
|
||||
this.fileName = fileName;
|
||||
this.resolution = resolution;
|
||||
this.rating = rating;
|
||||
}
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getKeyType() {
|
||||
return keyType;
|
||||
}
|
||||
|
||||
public String getSubKey() {
|
||||
return subKey;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public String getResolution() {
|
||||
return resolution;
|
||||
}
|
||||
|
||||
public Double getRating() {
|
||||
return rating;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "[id=" + id + ", keyType=" + keyType + ", subKey=" + subKey + ", fileName=" + fileName + ", resolution=" + resolution + ", rating=" + rating + "]";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -28,13 +28,13 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.logging.Level;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import java.util.zip.Inflater;
|
||||
import java.util.zip.InflaterInputStream;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
@ -56,12 +56,15 @@ import net.filebot.util.ByteBufferOutputStream;
|
|||
|
||||
public final class WebRequest {
|
||||
|
||||
private static final String ENCODING_GZIP = "gzip";
|
||||
private static final String CHARSET_UTF8 = "UTF-8";
|
||||
|
||||
public static Reader getReader(URLConnection connection) throws IOException {
|
||||
try {
|
||||
connection.addRequestProperty("Accept-Encoding", "gzip,deflate");
|
||||
connection.addRequestProperty("Accept-Charset", "UTF-8,ISO-8859-1");
|
||||
connection.addRequestProperty("Accept-Encoding", ENCODING_GZIP);
|
||||
connection.addRequestProperty("Accept-Charset", CHARSET_UTF8);
|
||||
} catch (IllegalStateException e) {
|
||||
// too bad, can't request gzipped document anymore
|
||||
debug.log(Level.WARNING, e, e::toString);
|
||||
}
|
||||
|
||||
Charset charset = getCharset(connection.getContentType());
|
||||
|
@ -69,10 +72,8 @@ public final class WebRequest {
|
|||
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
|
||||
if ("gzip".equalsIgnoreCase(encoding))
|
||||
if (ENCODING_GZIP.equalsIgnoreCase(encoding)) {
|
||||
inputStream = new GZIPInputStream(inputStream);
|
||||
else if ("deflate".equalsIgnoreCase(encoding)) {
|
||||
inputStream = new InflaterInputStream(inputStream, new Inflater(true));
|
||||
}
|
||||
|
||||
return new InputStreamReader(inputStream, charset);
|
||||
|
@ -110,7 +111,7 @@ public final class WebRequest {
|
|||
return fetch(resource, ifModifiedSince, null, null, null);
|
||||
}
|
||||
|
||||
public static ByteBuffer fetch(URL url, long ifModifiedSince, Object etag, Map<String, String> requestParameters, Map<String, List<String>> responseParameters) throws IOException {
|
||||
public static ByteBuffer fetch(URL url, long ifModifiedSince, Object etag, Map<String, String> requestParameters, Consumer<Map<String, List<String>>> responseParameters) throws IOException {
|
||||
URLConnection connection = url.openConnection();
|
||||
|
||||
if (ifModifiedSince > 0) {
|
||||
|
@ -121,38 +122,33 @@ public final class WebRequest {
|
|||
}
|
||||
|
||||
try {
|
||||
connection.addRequestProperty("Accept-Encoding", "gzip,deflate");
|
||||
connection.addRequestProperty("Accept-Charset", "UTF-8");
|
||||
connection.addRequestProperty("Accept-Encoding", ENCODING_GZIP);
|
||||
connection.addRequestProperty("Accept-Charset", CHARSET_UTF8);
|
||||
} catch (IllegalStateException e) {
|
||||
// too bad, can't request gzipped data
|
||||
debug.log(Level.WARNING, e, e::toString);
|
||||
}
|
||||
|
||||
if (requestParameters != null) {
|
||||
for (Entry<String, String> parameter : requestParameters.entrySet()) {
|
||||
connection.addRequestProperty(parameter.getKey(), parameter.getValue());
|
||||
}
|
||||
requestParameters.forEach(connection::addRequestProperty);
|
||||
}
|
||||
|
||||
int contentLength = connection.getContentLength();
|
||||
String encoding = connection.getContentEncoding();
|
||||
|
||||
InputStream in = connection.getInputStream();
|
||||
if ("gzip".equalsIgnoreCase(encoding))
|
||||
in = new GZIPInputStream(in);
|
||||
else if ("deflate".equalsIgnoreCase(encoding)) {
|
||||
in = new InflaterInputStream(in, new Inflater(true));
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
if (ENCODING_GZIP.equalsIgnoreCase(encoding)) {
|
||||
inputStream = new GZIPInputStream(inputStream);
|
||||
}
|
||||
|
||||
// store response headers
|
||||
if (responseParameters != null) {
|
||||
responseParameters.putAll(connection.getHeaderFields());
|
||||
responseParameters.accept(connection.getHeaderFields());
|
||||
}
|
||||
|
||||
ByteBufferOutputStream buffer = new ByteBufferOutputStream(contentLength >= 0 ? contentLength : 4 * 1024);
|
||||
|
||||
ByteBufferOutputStream buffer = new ByteBufferOutputStream(contentLength >= 0 ? contentLength : BUFFER_SIZE);
|
||||
try {
|
||||
// read all
|
||||
buffer.transferFully(in);
|
||||
buffer.transferFully(inputStream);
|
||||
} catch (IOException e) {
|
||||
// if the content length is not known in advance an IOException (Premature EOF)
|
||||
// is always thrown after all the data has been read
|
||||
|
@ -160,7 +156,7 @@ public final class WebRequest {
|
|||
throw e;
|
||||
}
|
||||
} finally {
|
||||
in.close();
|
||||
inputStream.close();
|
||||
}
|
||||
|
||||
// no data, e.g. If-Modified-Since requests
|
||||
|
@ -173,7 +169,7 @@ public final class WebRequest {
|
|||
|
||||
public static ByteBuffer post(URL url, Map<String, ?> parameters, Map<String, String> requestParameters) throws IOException {
|
||||
byte[] postData = encodeParameters(parameters, true).getBytes("UTF-8");
|
||||
if (requestParameters != null && "gzip".equals(requestParameters.get("Content-Encoding"))) {
|
||||
if (requestParameters != null && ENCODING_GZIP.equals(requestParameters.get("Content-Encoding"))) {
|
||||
postData = gzip(postData);
|
||||
}
|
||||
return post(url, postData, "application/x-www-form-urlencoded", requestParameters);
|
||||
|
@ -184,6 +180,7 @@ public final class WebRequest {
|
|||
|
||||
connection.addRequestProperty("Content-Length", String.valueOf(postData.length));
|
||||
connection.addRequestProperty("Content-Type", contentType);
|
||||
|
||||
connection.setRequestMethod("POST");
|
||||
connection.setDoOutput(true);
|
||||
|
||||
|
@ -202,17 +199,15 @@ public final class WebRequest {
|
|||
int contentLength = connection.getContentLength();
|
||||
String encoding = connection.getContentEncoding();
|
||||
|
||||
InputStream in = connection.getInputStream();
|
||||
if ("gzip".equalsIgnoreCase(encoding))
|
||||
in = new GZIPInputStream(in);
|
||||
else if ("deflate".equalsIgnoreCase(encoding)) {
|
||||
in = new InflaterInputStream(in, new Inflater(true));
|
||||
InputStream inputStream = connection.getInputStream();
|
||||
if (ENCODING_GZIP.equalsIgnoreCase(encoding)) {
|
||||
inputStream = new GZIPInputStream(inputStream);
|
||||
}
|
||||
|
||||
ByteBufferOutputStream buffer = new ByteBufferOutputStream(contentLength >= 0 ? contentLength : BUFFER_SIZE);
|
||||
try {
|
||||
// read all
|
||||
buffer.transferFully(in);
|
||||
buffer.transferFully(inputStream);
|
||||
} catch (IOException e) {
|
||||
// if the content length is not known in advance an IOException (Premature EOF)
|
||||
// is always thrown after all the data has been read
|
||||
|
@ -220,7 +215,7 @@ public final class WebRequest {
|
|||
throw e;
|
||||
}
|
||||
} finally {
|
||||
in.close();
|
||||
inputStream.close();
|
||||
}
|
||||
|
||||
return buffer.getByteBuffer();
|
||||
|
@ -252,9 +247,9 @@ public final class WebRequest {
|
|||
|
||||
private static byte[] gzip(byte[] data) throws IOException {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(data.length);
|
||||
GZIPOutputStream gzip = new GZIPOutputStream(out);
|
||||
gzip.write(data);
|
||||
gzip.close();
|
||||
try (GZIPOutputStream gzip = new GZIPOutputStream(out)) {
|
||||
gzip.write(data);
|
||||
}
|
||||
return out.toByteArray();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,151 @@
|
|||
package net.filebot.web;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import net.filebot.web.TheTVDBClient2.Image;
|
||||
|
||||
public class TheTVDBClient2Test {
|
||||
|
||||
TheTVDBClient2 thetvdb = new TheTVDBClient2("BA864DEE427E384A");
|
||||
|
||||
SearchResult buffy = new SearchResult(70327, "Buffy the Vampire Slayer");
|
||||
SearchResult wonderfalls = new SearchResult(78845, "Wonderfalls");
|
||||
SearchResult firefly = new SearchResult(78874, "Firefly");
|
||||
|
||||
@Test
|
||||
public void languages() throws Exception {
|
||||
String[] languages = thetvdb.languages();
|
||||
assertEquals("[zh, en, sv, no, da, fi, nl, de, it, es, fr, pl, hu, el, tr, ru, he, ja, pt, cs, sl, hr, ko]", asList(languages).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void search() throws Exception {
|
||||
// test default language and query escaping (blanks)
|
||||
List<SearchResult> results = thetvdb.search("babylon 5", Locale.ENGLISH);
|
||||
|
||||
assertEquals(2, results.size());
|
||||
|
||||
SearchResult first = results.get(0);
|
||||
|
||||
assertEquals("Babylon 5", first.getName());
|
||||
assertEquals(70726, first.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void searchGerman() throws Exception {
|
||||
List<SearchResult> results = thetvdb.search("Buffy the Vampire Slayer", Locale.GERMAN);
|
||||
|
||||
assertEquals(2, results.size());
|
||||
|
||||
SearchResult first = results.get(0);
|
||||
|
||||
assertEquals("Buffy the Vampire Slayer", first.getName());
|
||||
assertEquals(70327, first.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEpisodeListAll() throws Exception {
|
||||
List<Episode> list = thetvdb.getEpisodeList(buffy, SortOrder.Airdate, Locale.ENGLISH);
|
||||
|
||||
assertEquals(145, list.size());
|
||||
|
||||
// check ordinary episode
|
||||
Episode first = list.get(0);
|
||||
assertEquals("Buffy the Vampire Slayer", first.getSeriesName());
|
||||
assertEquals("1997-03-10", first.getSeriesInfo().getStartDate().toString());
|
||||
assertEquals("Welcome to the Hellmouth (1)", first.getTitle());
|
||||
assertEquals("1", first.getEpisode().toString());
|
||||
assertEquals("1", first.getSeason().toString());
|
||||
assertEquals("1", first.getAbsolute().toString());
|
||||
assertEquals("1997-03-10", first.getAirdate().toString());
|
||||
|
||||
// check special episode
|
||||
Episode last = list.get(list.size() - 1);
|
||||
assertEquals("Buffy the Vampire Slayer", last.getSeriesName());
|
||||
assertEquals("Unaired Pilot", last.getTitle());
|
||||
assertEquals(null, last.getSeason());
|
||||
assertEquals(null, last.getEpisode());
|
||||
assertEquals(null, last.getAbsolute());
|
||||
assertEquals("1", last.getSpecial().toString());
|
||||
assertEquals(null, last.getAirdate());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEpisodeListSingleSeason() throws Exception {
|
||||
List<Episode> list = thetvdb.getEpisodeList(wonderfalls, SortOrder.Airdate, Locale.ENGLISH);
|
||||
|
||||
Episode first = list.get(0);
|
||||
|
||||
assertEquals("Wonderfalls", first.getSeriesName());
|
||||
assertEquals("2004-03-12", first.getSeriesInfo().getStartDate().toString());
|
||||
assertEquals("Wax Lion", first.getTitle());
|
||||
assertEquals("1", first.getEpisode().toString());
|
||||
assertEquals("1", first.getSeason().toString());
|
||||
assertEquals(null, first.getAbsolute()); // should be "1" but data has not yet been entered
|
||||
assertEquals("2004-03-12", first.getAirdate().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getEpisodeListNumbering() throws Exception {
|
||||
List<Episode> list = thetvdb.getEpisodeList(firefly, SortOrder.DVD, Locale.ENGLISH);
|
||||
|
||||
Episode first = list.get(0);
|
||||
assertEquals("Firefly", first.getSeriesName());
|
||||
assertEquals("2002-09-20", first.getSeriesInfo().getStartDate().toString());
|
||||
assertEquals("Serenity", first.getTitle());
|
||||
assertEquals("1", first.getEpisode().toString());
|
||||
assertEquals("1", first.getSeason().toString());
|
||||
assertEquals("1", first.getAbsolute().toString());
|
||||
assertEquals("2002-12-20", first.getAirdate().toString());
|
||||
}
|
||||
|
||||
public void getEpisodeListLink() {
|
||||
assertEquals("http://www.thetvdb.com/?tab=seasonall&id=78874", thetvdb.getEpisodeListLink(firefly).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lookupByID() throws Exception {
|
||||
SearchResult series = thetvdb.lookupByID(78874, Locale.ENGLISH);
|
||||
assertEquals("Firefly", series.getName());
|
||||
assertEquals(78874, series.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void lookupByIMDbID() throws Exception {
|
||||
SearchResult series = thetvdb.lookupByIMDbID(303461, Locale.ENGLISH);
|
||||
assertEquals("Firefly", series.getName());
|
||||
assertEquals(78874, series.getId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSeriesInfo() throws Exception {
|
||||
TheTVDBSeriesInfo it = (TheTVDBSeriesInfo) thetvdb.getSeriesInfo(80348, Locale.ENGLISH);
|
||||
|
||||
assertEquals(80348, it.getId(), 0);
|
||||
assertEquals("TV-PG", it.getContentRating());
|
||||
assertEquals("2007-09-24", it.getFirstAired().toString());
|
||||
assertEquals("Action", it.getGenres().get(0));
|
||||
assertEquals("tt0934814", it.getImdbId());
|
||||
assertEquals("en", it.getLanguage());
|
||||
assertEquals(987, it.getOverview().length());
|
||||
assertEquals("45", it.getRuntime().toString());
|
||||
assertEquals("Chuck", it.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getImages() throws Exception {
|
||||
Image i = thetvdb.getImages(buffy, "fanart").get(0);
|
||||
|
||||
assertEquals("fanart", i.getKeyType());
|
||||
assertEquals(null, i.getSubKey());
|
||||
assertEquals("1280x720", i.getResolution());
|
||||
assertEquals("fanart/original/70327-1.jpg", i.getFileName());
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue