mirror of
https://github.com/mitb-archive/filebot
synced 2025-01-11 05:48:01 -05:00
Experiment with new CachedResource framework
This commit is contained in:
parent
bc2b96d09b
commit
7d3b099c07
@ -6,15 +6,12 @@ import static net.filebot.Logging.*;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import net.filebot.CachedResource2.Fetch;
|
import net.filebot.CachedResource2.Fetch;
|
||||||
import net.filebot.CachedResource2.Resource;
|
|
||||||
import net.filebot.CachedResource2.Transform;
|
import net.filebot.CachedResource2.Transform;
|
||||||
import net.filebot.web.FloodLimit;
|
|
||||||
import net.sf.ehcache.Element;
|
import net.sf.ehcache.Element;
|
||||||
|
|
||||||
import org.w3c.dom.Document;
|
import org.w3c.dom.Document;
|
||||||
@ -28,20 +25,20 @@ public class Cache {
|
|||||||
return CacheManager.getInstance().getCache(name.toLowerCase(), type);
|
return CacheManager.getInstance().getCache(name.toLowerCase(), type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <R> CachedResource2<String, R> resource(String key, Resource<String> source, Fetch fetch, Transform<ByteBuffer, ? extends Object> parse, Transform<? super Object, R> cast, Duration expirationTime) {
|
public CachedResource2<String, String> text(String key, Transform<String, URL> resource, Duration expirationTime, Fetch fetch) {
|
||||||
return new CachedResource2<String, R>(key, source, fetch, parse, cast, expirationTime, this);
|
return new CachedResource2<String, String>(key, resource, fetch, getText(UTF_8), String.class::cast, expirationTime, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CachedResource2<String, String> text(String url, Duration expirationTime, FloodLimit limit) {
|
public CachedResource2<String, Document> xml(String key, Transform<String, URL> resource, Duration expirationTime) {
|
||||||
return new CachedResource2<String, String>(url, URL::new, withPermit(fetchIfModified(), r -> limit.acquirePermit() != null), getText(UTF_8), String.class::cast, expirationTime, this);
|
return new CachedResource2<String, Document>(key, resource, fetchIfModified(), validateXml(getText(UTF_8)), getXml(String.class::cast), expirationTime, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CachedResource2<String, Document> xml(String key, Resource<String> source, Duration expirationTime) {
|
public CachedResource2<String, Object> json(String key, Transform<String, URL> resource, Duration expirationTime) {
|
||||||
return new CachedResource2<String, Document>(key, source, fetchIfModified(), validateXml(getText(UTF_8)), getXml(String.class::cast), expirationTime, this);
|
return json(key, resource, expirationTime, fetchIfModified());
|
||||||
}
|
}
|
||||||
|
|
||||||
public CachedResource2<String, Object> json(String key, Resource<String> source, Duration expirationTime) {
|
public CachedResource2<String, Object> json(String key, Transform<String, URL> resource, Duration expirationTime, Fetch fetch) {
|
||||||
return new CachedResource2<String, Object>(key, source, fetchIfModified(), validateJson(getText(UTF_8)), getJson(String.class::cast), expirationTime, this);
|
return new CachedResource2<String, Object>(key, resource, fetch, validateJson(getText(UTF_8)), getJson(String.class::cast), expirationTime, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
private final net.sf.ehcache.Cache cache;
|
private final net.sf.ehcache.Cache cache;
|
||||||
|
@ -8,6 +8,9 @@ import java.net.URL;
|
|||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
import net.filebot.util.JsonUtilities;
|
import net.filebot.util.JsonUtilities;
|
||||||
@ -22,7 +25,7 @@ public class CachedResource2<K, R> {
|
|||||||
|
|
||||||
private K key;
|
private K key;
|
||||||
|
|
||||||
private Resource<K> source;
|
private Transform<K, URL> resource;
|
||||||
private Fetch fetch;
|
private Fetch fetch;
|
||||||
private Transform<ByteBuffer, ? extends Object> parse;
|
private Transform<ByteBuffer, ? extends Object> parse;
|
||||||
private Transform<? super Object, R> cast;
|
private Transform<? super Object, R> cast;
|
||||||
@ -34,13 +37,13 @@ public class CachedResource2<K, R> {
|
|||||||
|
|
||||||
private final Cache cache;
|
private final Cache cache;
|
||||||
|
|
||||||
public CachedResource2(K key, Resource<K> source, Fetch fetch, Transform<ByteBuffer, ? extends Object> parse, Transform<? super Object, R> cast, Duration expirationTime, Cache cache) {
|
public CachedResource2(K key, Transform<K, URL> resource, Fetch fetch, Transform<ByteBuffer, ? extends Object> parse, Transform<? super Object, R> cast, Duration expirationTime, Cache cache) {
|
||||||
this(key, source, fetch, parse, cast, DEFAULT_RETRY_LIMIT, DEFAULT_RETRY_DELAY, expirationTime, cache);
|
this(key, resource, fetch, parse, cast, DEFAULT_RETRY_LIMIT, DEFAULT_RETRY_DELAY, expirationTime, cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CachedResource2(K key, Resource<K> source, Fetch fetch, Transform<ByteBuffer, ? extends Object> parse, Transform<? super Object, R> cast, int retryCountLimit, Duration retryWaitTime, Duration expirationTime, Cache cache) {
|
public CachedResource2(K key, Transform<K, URL> resource, Fetch fetch, Transform<ByteBuffer, ? extends Object> parse, Transform<? super Object, R> cast, int retryCountLimit, Duration retryWaitTime, Duration expirationTime, Cache cache) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
this.source = source;
|
this.resource = resource;
|
||||||
this.fetch = fetch;
|
this.fetch = fetch;
|
||||||
this.parse = parse;
|
this.parse = parse;
|
||||||
this.cast = cast;
|
this.cast = cast;
|
||||||
@ -52,13 +55,11 @@ public class CachedResource2<K, R> {
|
|||||||
|
|
||||||
public synchronized R get() throws Exception {
|
public synchronized R get() throws Exception {
|
||||||
Object value = cache.computeIfStale(key, expirationTime, element -> {
|
Object value = cache.computeIfStale(key, expirationTime, element -> {
|
||||||
URL resource = source.source(key);
|
URL url = resource.transform(key);
|
||||||
long lastModified = element == null ? 0 : element.getLatestOfCreationAndUpdateTime();
|
long lastModified = element == null ? 0 : element.getLatestOfCreationAndUpdateTime();
|
||||||
|
|
||||||
debug.fine(format("Fetch %s (If-Modified-Since: %tc)", resource, lastModified));
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
ByteBuffer data = retry(() -> fetch.fetch(resource, lastModified), retryCountLimit, retryWaitTime);
|
ByteBuffer data = retry(() -> fetch.fetch(url, lastModified), retryCountLimit, retryWaitTime);
|
||||||
|
|
||||||
// 304 Not Modified
|
// 304 Not Modified
|
||||||
if (data == null && element != null && element.getObjectValue() != null) {
|
if (data == null && element != null && element.getObjectValue() != null) {
|
||||||
@ -96,11 +97,6 @@ public class CachedResource2<K, R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@FunctionalInterface
|
|
||||||
public interface Resource<K> {
|
|
||||||
URL source(K key) throws Exception;
|
|
||||||
}
|
|
||||||
|
|
||||||
@FunctionalInterface
|
@FunctionalInterface
|
||||||
public interface Fetch {
|
public interface Fetch {
|
||||||
ByteBuffer fetch(URL url, long lastModified) throws Exception;
|
ByteBuffer fetch(URL url, long lastModified) throws Exception;
|
||||||
@ -151,6 +147,7 @@ public class CachedResource2<K, R> {
|
|||||||
public static Fetch fetchIfModified() {
|
public static Fetch fetchIfModified() {
|
||||||
return (url, lastModified) -> {
|
return (url, lastModified) -> {
|
||||||
try {
|
try {
|
||||||
|
debug.fine(format("Fetch %s (If-Modified-Since: %tc)", url, lastModified));
|
||||||
return WebRequest.fetchIfModified(url, lastModified);
|
return WebRequest.fetchIfModified(url, lastModified);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
debug.warning(format("Resource not found: %s => %s", url, e));
|
debug.warning(format("Resource not found: %s => %s", url, e));
|
||||||
@ -159,6 +156,29 @@ public class CachedResource2<K, R> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Fetch fetchIfNoneMatch(Cache etagStorage) {
|
||||||
|
return (url, lastModified) -> {
|
||||||
|
Map<String, List<String>> responseHeaders = new HashMap<String, List<String>>();
|
||||||
|
|
||||||
|
String etagKey = url.toString();
|
||||||
|
Object etagValue = etagStorage.get(etagKey);
|
||||||
|
|
||||||
|
try {
|
||||||
|
debug.fine(format("Fetch %s (If-None-Match: %s, If-Modified-Since: %tc)", url, etagValue, lastModified));
|
||||||
|
return WebRequest.fetch(url, lastModified, etagValue, null, responseHeaders);
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
debug.warning(format("Resource not found: %s => %s", url, e));
|
||||||
|
return ByteBuffer.allocate(0);
|
||||||
|
} finally {
|
||||||
|
List<String> value = responseHeaders.get("ETag");
|
||||||
|
if (value != null && value.size() > 0 && !value.contains(etagValue)) {
|
||||||
|
debug.finest(format("ETag %s", value));
|
||||||
|
etagStorage.put(etagKey, value.get(0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public static Fetch withPermit(Fetch fetch, Permit<?> permit) {
|
public static Fetch withPermit(Fetch fetch, Permit<?> permit) {
|
||||||
return (url, lastModified) -> {
|
return (url, lastModified) -> {
|
||||||
if (permit.acquirePermit(url)) {
|
if (permit.acquirePermit(url)) {
|
||||||
|
@ -276,11 +276,11 @@ public class ScriptShellMethods {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer get(URL self) throws IOException {
|
public static ByteBuffer get(URL self) throws IOException {
|
||||||
return WebRequest.fetch(self, 0, null, null);
|
return WebRequest.fetch(self, 0, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer get(URL self, Map<String, String> requestParameters) throws IOException {
|
public static ByteBuffer get(URL self, Map<String, String> requestParameters) throws IOException {
|
||||||
return WebRequest.fetch(self, 0, requestParameters, null);
|
return WebRequest.fetch(self, 0, null, requestParameters, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer post(URL self, Map<String, ?> parameters, Map<String, String> requestParameters) throws IOException {
|
public static ByteBuffer post(URL self, Map<String, ?> parameters, Map<String, String> requestParameters) throws IOException {
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
package net.filebot.web;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import net.sf.ehcache.Cache;
|
|
||||||
import net.sf.ehcache.CacheManager;
|
|
||||||
import net.sf.ehcache.Element;
|
|
||||||
|
|
||||||
public abstract class ETagCachedResource<T extends Serializable> extends CachedResource<T> {
|
|
||||||
|
|
||||||
public ETagCachedResource(String resource, Class<T> type) {
|
|
||||||
super(resource, type, ONE_WEEK, 2, 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ETagCachedResource(String resource, Class<T> type, long expirationTime, int retryCountLimit, long retryWaitTime) {
|
|
||||||
super(resource, type, expirationTime, retryCountLimit, retryWaitTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ByteBuffer fetchData(URL url, long lastModified) throws IOException {
|
|
||||||
String etagKey = "ETag" + ":" + url.toString();
|
|
||||||
Element etag = getCache().get(etagKey);
|
|
||||||
|
|
||||||
Map<String, String> requestParameters = new HashMap<String, String>();
|
|
||||||
if (etag != null && etag.getObjectValue() != null) {
|
|
||||||
requestParameters.put("If-None-Match", etag.getObjectValue().toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If-Modified-Since must not be set if If-None-Match is set
|
|
||||||
Map<String, List<String>> responseHeaders = new HashMap<String, List<String>>();
|
|
||||||
ByteBuffer data = WebRequest.fetch(url, requestParameters.size() > 0 ? -1 : lastModified, requestParameters, responseHeaders);
|
|
||||||
|
|
||||||
if (responseHeaders.containsKey("ETag")) {
|
|
||||||
getCache().put(new Element(etagKey, responseHeaders.get("ETag").get(0)));
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Cache getCache() {
|
|
||||||
return CacheManager.getInstance().getCache("web-datasource-lv3");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -2,13 +2,14 @@ package net.filebot.web;
|
|||||||
|
|
||||||
import static java.util.Collections.*;
|
import static java.util.Collections.*;
|
||||||
import static java.util.stream.Collectors.*;
|
import static java.util.stream.Collectors.*;
|
||||||
|
import static net.filebot.CachedResource2.*;
|
||||||
import static net.filebot.Logging.*;
|
import static net.filebot.Logging.*;
|
||||||
import static net.filebot.util.JsonUtilities.*;
|
import static net.filebot.util.JsonUtilities.*;
|
||||||
import static net.filebot.util.StringUtilities.*;
|
import static net.filebot.util.StringUtilities.*;
|
||||||
import static net.filebot.web.WebRequest.*;
|
import static net.filebot.web.WebRequest.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.time.Duration;
|
import java.net.URL;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.time.format.DateTimeParseException;
|
import java.time.format.DateTimeParseException;
|
||||||
import java.time.temporal.ChronoField;
|
import java.time.temporal.ChronoField;
|
||||||
@ -134,12 +135,16 @@ public class OMDbClient implements MovieIdentificationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Map<?, ?> request(Map<String, Object> parameters) throws Exception {
|
public Map<?, ?> request(Map<String, Object> parameters) throws Exception {
|
||||||
String url = "http://www.omdbapi.com/?" + encodeParameters(parameters, true);
|
String key = '?' + encodeParameters(parameters, true);
|
||||||
|
|
||||||
Cache cache = Cache.getCache(getName(), CacheType.Weekly);
|
Cache cache = Cache.getCache(getName(), CacheType.Weekly);
|
||||||
String json = cache.text(url, Duration.ofDays(7), REQUEST_LIMIT).get();
|
Object json = cache.json(key, s -> getResource(s), Cache.ONE_WEEK, withPermit(fetchIfModified(), r -> REQUEST_LIMIT.acquirePermit() != null)).get();
|
||||||
|
|
||||||
return asMap(readJson(json));
|
return asMap(json);
|
||||||
|
}
|
||||||
|
|
||||||
|
public URL getResource(String file) throws Exception {
|
||||||
|
return new URL("http://www.omdbapi.com/" + file);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getMovieInfo(Integer i, String t, String y, boolean tomatoes) throws Exception {
|
public Map<String, String> getMovieInfo(Integer i, String t, String y, boolean tomatoes) throws Exception {
|
||||||
|
@ -2,17 +2,15 @@ package net.filebot.web;
|
|||||||
|
|
||||||
import static java.util.Arrays.*;
|
import static java.util.Arrays.*;
|
||||||
import static java.util.Collections.*;
|
import static java.util.Collections.*;
|
||||||
|
import static net.filebot.CachedResource2.*;
|
||||||
import static net.filebot.util.StringUtilities.*;
|
import static net.filebot.util.StringUtilities.*;
|
||||||
import static net.filebot.web.WebRequest.*;
|
import static net.filebot.web.WebRequest.*;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileNotFoundException;
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.AbstractList;
|
import java.util.AbstractList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -33,6 +31,8 @@ import java.util.regex.Pattern;
|
|||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
|
import net.filebot.Cache;
|
||||||
|
import net.filebot.CacheType;
|
||||||
import net.filebot.Language;
|
import net.filebot.Language;
|
||||||
import net.filebot.ResourceManager;
|
import net.filebot.ResourceManager;
|
||||||
import net.filebot.web.TMDbClient.MovieInfo.MovieProperty;
|
import net.filebot.web.TMDbClient.MovieInfo.MovieProperty;
|
||||||
@ -67,7 +67,7 @@ public class TMDbClient implements MovieIdentificationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Movie> searchMovie(String query, Locale locale) throws IOException {
|
public List<Movie> searchMovie(String query, Locale locale) throws Exception {
|
||||||
// query by name with year filter if possible
|
// query by name with year filter if possible
|
||||||
Matcher nameYear = Pattern.compile("(.+)\\b\\(?(19\\d{2}|20\\d{2})\\)?$").matcher(query.trim());
|
Matcher nameYear = Pattern.compile("(.+)\\b\\(?(19\\d{2}|20\\d{2})\\)?$").matcher(query.trim());
|
||||||
if (nameYear.matches()) {
|
if (nameYear.matches()) {
|
||||||
@ -77,7 +77,7 @@ public class TMDbClient implements MovieIdentificationService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Movie> searchMovie(String movieName, int movieYear, Locale locale, boolean extendedInfo) throws IOException {
|
public List<Movie> searchMovie(String movieName, int movieYear, Locale locale, boolean extendedInfo) throws Exception {
|
||||||
// ignore queries that are too short to yield good results
|
// ignore queries that are too short to yield good results
|
||||||
if (movieName.length() < 3 && !(movieName.length() >= 1 && movieYear > 0)) {
|
if (movieName.length() < 3 && !(movieName.length() >= 1 && movieYear > 0)) {
|
||||||
return emptyList();
|
return emptyList();
|
||||||
@ -155,7 +155,7 @@ public class TMDbClient implements MovieIdentificationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Movie getMovieDescriptor(Movie id, Locale locale) throws IOException {
|
public Movie getMovieDescriptor(Movie id, Locale locale) throws Exception {
|
||||||
if (id.getTmdbId() > 0 || id.getImdbId() > 0) {
|
if (id.getTmdbId() > 0 || id.getImdbId() > 0) {
|
||||||
MovieInfo info = getMovieInfo(id, locale, false);
|
MovieInfo info = getMovieInfo(id, locale, false);
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
@ -175,7 +175,7 @@ public class TMDbClient implements MovieIdentificationService {
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
public MovieInfo getMovieInfo(Movie movie, Locale locale, boolean extendedInfo) throws IOException {
|
public MovieInfo getMovieInfo(Movie movie, Locale locale, boolean extendedInfo) throws Exception {
|
||||||
try {
|
try {
|
||||||
if (movie.getTmdbId() > 0) {
|
if (movie.getTmdbId() > 0) {
|
||||||
return getMovieInfo(String.valueOf(movie.getTmdbId()), locale, extendedInfo);
|
return getMovieInfo(String.valueOf(movie.getTmdbId()), locale, extendedInfo);
|
||||||
@ -188,7 +188,7 @@ public class TMDbClient implements MovieIdentificationService {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public MovieInfo getMovieInfo(String id, Locale locale, boolean extendedInfo) throws IOException {
|
public MovieInfo getMovieInfo(String id, Locale locale, boolean extendedInfo) throws Exception {
|
||||||
JSONObject response = request("movie/" + id, extendedInfo ? singletonMap("append_to_response", "alternative_titles,releases,casts,trailers") : null, locale, REQUEST_LIMIT);
|
JSONObject response = request("movie/" + id, extendedInfo ? singletonMap("append_to_response", "alternative_titles,releases,casts,trailers") : null, locale, REQUEST_LIMIT);
|
||||||
|
|
||||||
Map<MovieProperty, String> fields = new EnumMap<MovieProperty, String>(MovieProperty.class);
|
Map<MovieProperty, String> fields = new EnumMap<MovieProperty, String>(MovieProperty.class);
|
||||||
@ -325,7 +325,7 @@ public class TMDbClient implements MovieIdentificationService {
|
|||||||
return new MovieInfo(fields, alternativeTitles, genres, certifications, spokenLanguages, productionCountries, productionCompanies, cast, trailers);
|
return new MovieInfo(fields, alternativeTitles, genres, certifications, spokenLanguages, productionCountries, productionCompanies, cast, trailers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<Artwork> getArtwork(String id) throws IOException {
|
public List<Artwork> getArtwork(String id) throws Exception {
|
||||||
// http://api.themoviedb.org/3/movie/11/images
|
// http://api.themoviedb.org/3/movie/11/images
|
||||||
JSONObject config = request("configuration", null, null, REQUEST_LIMIT);
|
JSONObject config = request("configuration", null, null, REQUEST_LIMIT);
|
||||||
String baseUrl = (String) ((JSONObject) config.get("images")).get("base_url");
|
String baseUrl = (String) ((JSONObject) config.get("images")).get("base_url");
|
||||||
@ -350,7 +350,7 @@ public class TMDbClient implements MovieIdentificationService {
|
|||||||
return artwork;
|
return artwork;
|
||||||
}
|
}
|
||||||
|
|
||||||
public JSONObject request(String resource, Map<String, Object> parameters, Locale locale, final FloodLimit limit) throws IOException {
|
public JSONObject request(String resource, Map<String, Object> parameters, Locale locale, final FloodLimit limit) throws Exception {
|
||||||
// default parameters
|
// default parameters
|
||||||
LinkedHashMap<String, Object> data = new LinkedHashMap<String, Object>();
|
LinkedHashMap<String, Object> data = new LinkedHashMap<String, Object>();
|
||||||
if (parameters != null) {
|
if (parameters != null) {
|
||||||
@ -371,37 +371,23 @@ public class TMDbClient implements MovieIdentificationService {
|
|||||||
}
|
}
|
||||||
data.put("api_key", apikey);
|
data.put("api_key", apikey);
|
||||||
|
|
||||||
URL url = new URL("http", host, "/" + version + "/" + resource + "?" + encodeParameters(data, true));
|
String key = resource + '?' + encodeParameters(data, true);
|
||||||
|
|
||||||
CachedResource<String> json = new ETagCachedResource<String>(url.toString(), String.class) {
|
Cache etagStorage = Cache.getCache("etag", CacheType.Monthly);
|
||||||
|
Cache cache = Cache.getCache(getName(), CacheType.Monthly);
|
||||||
|
String json = cache.text(key, s -> getResource(s), Cache.ONE_WEEK, withPermit(fetchIfNoneMatch(etagStorage), r -> REQUEST_LIMIT.acquirePermit() != null)).get();
|
||||||
|
|
||||||
@Override
|
JSONObject object = (JSONObject) JSONValue.parse(json);
|
||||||
public String process(ByteBuffer data) throws Exception {
|
|
||||||
return Charset.forName("UTF-8").decode(data).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected ByteBuffer fetchData(URL url, long lastModified) throws IOException {
|
|
||||||
try {
|
|
||||||
if (limit != null) {
|
|
||||||
limit.acquirePermit();
|
|
||||||
}
|
|
||||||
return super.fetchData(url, lastModified);
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
return ByteBuffer.allocate(0);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
JSONObject object = (JSONObject) JSONValue.parse(json.get());
|
|
||||||
if (object == null || object.isEmpty()) {
|
if (object == null || object.isEmpty()) {
|
||||||
throw new FileNotFoundException("Resource not found: " + url);
|
throw new FileNotFoundException("Resource not found: " + getResource(key));
|
||||||
}
|
}
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public URL getResource(String file) throws Exception {
|
||||||
|
return new URL("http", host, "/" + version + "/" + file);
|
||||||
|
}
|
||||||
|
|
||||||
protected List<JSONObject> jsonList(final Object array) {
|
protected List<JSONObject> jsonList(final Object array) {
|
||||||
return new AbstractList<JSONObject>() {
|
return new AbstractList<JSONObject>() {
|
||||||
|
|
||||||
|
@ -97,17 +97,25 @@ public final class WebRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer fetch(URL resource) throws IOException {
|
public static ByteBuffer fetch(URL resource) throws IOException {
|
||||||
return fetch(resource, 0, null, null);
|
return fetch(resource, 0, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer fetchIfModified(URL resource, long ifModifiedSince) throws IOException {
|
public static ByteBuffer fetchIfModified(URL resource, long ifModifiedSince) throws IOException {
|
||||||
return fetch(resource, ifModifiedSince, null, null);
|
return fetch(resource, ifModifiedSince, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static ByteBuffer fetch(URL url, long ifModifiedSince, Map<String, String> requestParameters, Map<String, List<String>> responseParameters) throws IOException {
|
public static ByteBuffer fetchIfNoneMatch(URL resource, Object etag) throws IOException {
|
||||||
|
return fetch(resource, 0, etag, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ByteBuffer fetch(URL url, long ifModifiedSince, Object etag, Map<String, String> requestParameters, Map<String, List<String>> responseParameters) throws IOException {
|
||||||
URLConnection connection = url.openConnection();
|
URLConnection connection = url.openConnection();
|
||||||
|
|
||||||
if (ifModifiedSince > 0) {
|
if (ifModifiedSince > 0) {
|
||||||
connection.setIfModifiedSince(ifModifiedSince);
|
connection.setIfModifiedSince(ifModifiedSince);
|
||||||
|
} else if (etag != null) {
|
||||||
|
// If-Modified-Since must not be set if If-None-Match is set
|
||||||
|
connection.addRequestProperty("If-None-Match", etag.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -14,7 +14,7 @@ import org.junit.Test;
|
|||||||
|
|
||||||
public class TMDbClientTest {
|
public class TMDbClientTest {
|
||||||
|
|
||||||
private final TMDbClient tmdb = new TMDbClient("66308fb6e3fd850dde4c7d21df2e8306");
|
TMDbClient tmdb = new TMDbClient("66308fb6e3fd850dde4c7d21df2e8306");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void searchByName() throws Exception {
|
public void searchByName() throws Exception {
|
||||||
@ -74,9 +74,9 @@ public class TMDbClientTest {
|
|||||||
MovieInfo movie = tmdb.getMovieInfo(new Movie(null, 0, 418279, -1), Locale.ENGLISH, true);
|
MovieInfo movie = tmdb.getMovieInfo(new Movie(null, 0, 418279, -1), Locale.ENGLISH, true);
|
||||||
|
|
||||||
assertEquals("Transformers", movie.getName());
|
assertEquals("Transformers", movie.getName());
|
||||||
assertEquals("2007-07-02", movie.getReleased().toString());
|
assertEquals("2007-06-27", movie.getReleased().toString());
|
||||||
assertEquals("PG-13", movie.getCertification());
|
assertEquals("PG-13", movie.getCertification());
|
||||||
assertEquals("[en, es]", movie.getSpokenLanguages().toString());
|
assertEquals("[es, en]", movie.getSpokenLanguages().toString());
|
||||||
assertEquals("Shia LaBeouf", movie.getActors().get(0));
|
assertEquals("Shia LaBeouf", movie.getActors().get(0));
|
||||||
assertEquals("Michael Bay", movie.getDirector());
|
assertEquals("Michael Bay", movie.getDirector());
|
||||||
}
|
}
|
||||||
@ -85,7 +85,7 @@ public class TMDbClientTest {
|
|||||||
public void getArtwork() throws Exception {
|
public void getArtwork() throws Exception {
|
||||||
List<Artwork> artwork = tmdb.getArtwork("tt0418279");
|
List<Artwork> artwork = tmdb.getArtwork("tt0418279");
|
||||||
assertEquals("backdrops", artwork.get(0).getCategory());
|
assertEquals("backdrops", artwork.get(0).getCategory());
|
||||||
assertEquals("http://image.tmdb.org/t/p/original/dXTeZELpoVMDOTTLnNoCpsCngwW.jpg", artwork.get(0).getUrl().toString());
|
assertEquals("http://image.tmdb.org/t/p/original/ac0HwGJIU3GxjjGujlIjLJmAGPR.jpg", artwork.get(0).getUrl().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
|
Loading…
Reference in New Issue
Block a user