|
|
|
@ -2,7 +2,10 @@ package net.filebot.web;
|
|
|
|
|
|
|
|
|
|
import static java.util.Arrays.*;
|
|
|
|
|
import static java.util.Collections.*;
|
|
|
|
|
import static java.util.stream.Collectors.*;
|
|
|
|
|
import static net.filebot.CachedResource2.*;
|
|
|
|
|
import static net.filebot.Logging.*;
|
|
|
|
|
import static net.filebot.util.JsonUtilities.*;
|
|
|
|
|
import static net.filebot.util.StringUtilities.*;
|
|
|
|
|
import static net.filebot.web.WebRequest.*;
|
|
|
|
|
|
|
|
|
@ -11,23 +14,22 @@ import java.io.FileNotFoundException;
|
|
|
|
|
import java.io.Serializable;
|
|
|
|
|
import java.net.URI;
|
|
|
|
|
import java.net.URL;
|
|
|
|
|
import java.util.AbstractList;
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.EnumMap;
|
|
|
|
|
import java.util.HashMap;
|
|
|
|
|
import java.util.LinkedHashMap;
|
|
|
|
|
import java.util.LinkedHashSet;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.Locale;
|
|
|
|
|
import java.util.Map;
|
|
|
|
|
import java.util.Objects;
|
|
|
|
|
import java.util.Set;
|
|
|
|
|
import java.util.TreeSet;
|
|
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
import java.util.logging.Level;
|
|
|
|
|
import java.util.logging.Logger;
|
|
|
|
|
import java.util.regex.Matcher;
|
|
|
|
|
import java.util.regex.Pattern;
|
|
|
|
|
import java.util.stream.Stream;
|
|
|
|
|
|
|
|
|
|
import javax.swing.Icon;
|
|
|
|
|
|
|
|
|
@ -38,10 +40,6 @@ import net.filebot.ResourceManager;
|
|
|
|
|
import net.filebot.web.TMDbClient.MovieInfo.MovieProperty;
|
|
|
|
|
import net.filebot.web.TMDbClient.Person.PersonProperty;
|
|
|
|
|
|
|
|
|
|
import org.json.simple.JSONArray;
|
|
|
|
|
import org.json.simple.JSONObject;
|
|
|
|
|
import org.json.simple.JSONValue;
|
|
|
|
|
|
|
|
|
|
public class TMDbClient implements MovieIdentificationService {
|
|
|
|
|
|
|
|
|
|
private static final String host = "api.themoviedb.org";
|
|
|
|
@ -89,31 +87,21 @@ public class TMDbClient implements MovieIdentificationService {
|
|
|
|
|
param.put("year", movieYear);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSONObject response = request("search/movie", param, locale, SEARCH_LIMIT);
|
|
|
|
|
List<Movie> result = new ArrayList<Movie>();
|
|
|
|
|
Map<?, ?> response = request("search/movie", param, locale, SEARCH_LIMIT);
|
|
|
|
|
|
|
|
|
|
for (JSONObject it : jsonList(response.get("results"))) {
|
|
|
|
|
if (it == null) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// e.g.
|
|
|
|
|
// {"id":16320,"title":"冲出宁静号","release_date":"2005-09-30","original_title":"Serenity"}
|
|
|
|
|
// e.g. {"id":16320,"title":"冲出宁静号","release_date":"2005-09-30","original_title":"Serenity"}
|
|
|
|
|
return streamJsonObjects(response, "results").map(it -> {
|
|
|
|
|
int id = -1, year = -1;
|
|
|
|
|
String title = (String) it.get("title");
|
|
|
|
|
String originalTitle = (String) it.get("original_title");
|
|
|
|
|
if (title == null || title.isEmpty()) {
|
|
|
|
|
|
|
|
|
|
String title = getString(it, "title");
|
|
|
|
|
String originalTitle = getString(it, "original_title");
|
|
|
|
|
if (title == null) {
|
|
|
|
|
title = originalTitle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
id = Float.valueOf(it.get("id").toString()).intValue();
|
|
|
|
|
try {
|
|
|
|
|
String release = (String) it.get("release_date");
|
|
|
|
|
year = matchInteger(release);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
throw new IllegalArgumentException("Missing data: release date");
|
|
|
|
|
}
|
|
|
|
|
id = getDecimal(it, "id").intValue();
|
|
|
|
|
year = matchInteger(getString(it, "release_date")); // release date is often missing
|
|
|
|
|
|
|
|
|
|
Set<String> alternativeTitles = new LinkedHashSet<String>();
|
|
|
|
|
if (originalTitle != null) {
|
|
|
|
@ -122,32 +110,24 @@ public class TMDbClient implements MovieIdentificationService {
|
|
|
|
|
|
|
|
|
|
if (extendedInfo) {
|
|
|
|
|
try {
|
|
|
|
|
Set<String> internationalTitles = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
|
|
|
|
|
JSONObject titles = request("movie/" + id + "/alternative_titles", null, null, REQUEST_LIMIT);
|
|
|
|
|
for (JSONObject node : jsonList(titles.get("titles"))) {
|
|
|
|
|
String t = (String) node.get("title");
|
|
|
|
|
if (t != null && t.length() >= 3) {
|
|
|
|
|
internationalTitles.add(t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
alternativeTitles.addAll(internationalTitles);
|
|
|
|
|
Map<?, ?> titles = request("movie/" + id + "/alternative_titles", null, null, REQUEST_LIMIT);
|
|
|
|
|
streamJsonObjects(titles, "titles").map(n -> {
|
|
|
|
|
return getString(n, "title");
|
|
|
|
|
}).filter(t -> t != null && t.length() >= 3).forEach(alternativeTitles::add);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Logger.getLogger(TMDbClient.class.getName()).log(Level.WARNING, String.format("Unable to retrieve alternative titles [%s]: %s", title, e.getMessage()));
|
|
|
|
|
debug.warning(format("Failed to fetch alternative titles for %s [%d] => %s", title, id, e));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// make sure main title is not in the set of alternative titles
|
|
|
|
|
alternativeTitles.remove(title);
|
|
|
|
|
|
|
|
|
|
result.add(new Movie(title, alternativeTitles.toArray(new String[0]), year, -1, id, locale));
|
|
|
|
|
return new Movie(title, alternativeTitles.toArray(new String[0]), year, -1, id, locale);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// only print 'missing release date' warnings for matching movie titles
|
|
|
|
|
if (movieName.equalsIgnoreCase(title) || movieName.equalsIgnoreCase(originalTitle)) {
|
|
|
|
|
Logger.getLogger(TMDbClient.class.getName()).log(Level.WARNING, String.format("Ignore movie metadata: %s [%d]: %s", title, id, e.getMessage()));
|
|
|
|
|
}
|
|
|
|
|
debug.warning(format("Bad data: %s", it));
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}).filter(Objects::nonNull).collect(toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public URI getMoviePageLink(int tmdbid) {
|
|
|
|
@ -189,137 +169,100 @@ public class TMDbClient implements MovieIdentificationService {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
Map<?, ?> 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);
|
|
|
|
|
for (MovieProperty key : MovieProperty.values()) {
|
|
|
|
|
Object value = response.get(key.name());
|
|
|
|
|
if (value != null) {
|
|
|
|
|
fields.put(key, value.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Map<MovieProperty, String> fields = mapStringValues(response, MovieProperty.class);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
JSONObject collection = (JSONObject) response.get("belongs_to_collection");
|
|
|
|
|
fields.put(MovieProperty.collection, (String) collection.get("name"));
|
|
|
|
|
Map<?, ?> collection = getMap(response, "belongs_to_collection");
|
|
|
|
|
fields.put(MovieProperty.collection, getString(collection, "name"));
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
// movie doesn't belong to any collection
|
|
|
|
|
// movie does not belong to any collection
|
|
|
|
|
debug.warning(format("Bad data: belongs_to_collection => %s", response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<String> genres = new ArrayList<String>();
|
|
|
|
|
try {
|
|
|
|
|
for (JSONObject it : jsonList(response.get("genres"))) {
|
|
|
|
|
String name = (String) it.get("name");
|
|
|
|
|
if (name != null && name.length() > 0) {
|
|
|
|
|
genres.add(name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
streamJsonObjects(response, "genres").map(it -> getString(it, "name")).filter(Objects::nonNull).forEach(genres::add);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Illegal genres data: " + response);
|
|
|
|
|
debug.warning(format("Bad data: genres => %s", response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<String> spokenLanguages = new ArrayList<String>();
|
|
|
|
|
try {
|
|
|
|
|
for (JSONObject it : jsonList(response.get("spoken_languages"))) {
|
|
|
|
|
spokenLanguages.add((String) it.get("iso_639_1"));
|
|
|
|
|
}
|
|
|
|
|
streamJsonObjects(response, "spoken_languages").map(it -> getString(it, "iso_639_1")).filter(Objects::nonNull).forEach(spokenLanguages::add);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Illegal spoken_languages data: " + response);
|
|
|
|
|
debug.warning(format("Bad data: spoken_languages => %s", response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<String> productionCountries = new ArrayList<String>();
|
|
|
|
|
try {
|
|
|
|
|
for (JSONObject it : jsonList(response.get("production_countries"))) {
|
|
|
|
|
productionCountries.add((String) it.get("iso_3166_1"));
|
|
|
|
|
}
|
|
|
|
|
streamJsonObjects(response, "production_countries").map(it -> getString(it, "iso_3166_1")).filter(Objects::nonNull).forEach(productionCountries::add);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Illegal production_countries data: " + response);
|
|
|
|
|
debug.warning(format("Bad data: production_countries => %s", response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<String> productionCompanies = new ArrayList<String>();
|
|
|
|
|
try {
|
|
|
|
|
for (JSONObject it : jsonList(response.get("production_companies"))) {
|
|
|
|
|
productionCompanies.add((String) it.get("name"));
|
|
|
|
|
}
|
|
|
|
|
streamJsonObjects(response, "production_companies").map(it -> getString(it, "name")).filter(Objects::nonNull).forEach(productionCompanies::add);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Illegal production_companies data: " + response);
|
|
|
|
|
debug.warning(format("Bad data: production_companies => %s", response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<String> alternativeTitles = new ArrayList<String>();
|
|
|
|
|
try {
|
|
|
|
|
JSONObject titles = (JSONObject) response.get("alternative_titles");
|
|
|
|
|
if (titles != null) {
|
|
|
|
|
for (JSONObject it : jsonList(titles.get("titles"))) {
|
|
|
|
|
alternativeTitles.add((String) it.get("title"));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
streamJsonObjects(getMap(response, "alternative_titles"), "titles").map(it -> getString(it, "title")).filter(Objects::nonNull).forEach(alternativeTitles::add);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Illegal alternative_titles data: " + response);
|
|
|
|
|
debug.warning(format("Bad data: alternative_titles => %s", response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Map<String, String> certifications = new HashMap<String, String>();
|
|
|
|
|
Map<String, String> certifications = new LinkedHashMap<String, String>();
|
|
|
|
|
try {
|
|
|
|
|
String countryCode = locale.getCountry().isEmpty() ? "US" : locale.getCountry();
|
|
|
|
|
JSONObject releases = (JSONObject) response.get("releases");
|
|
|
|
|
if (releases != null) {
|
|
|
|
|
for (JSONObject it : jsonList(releases.get("countries"))) {
|
|
|
|
|
String certificationCountry = (String) it.get("iso_3166_1");
|
|
|
|
|
String certification = (String) it.get("certification");
|
|
|
|
|
if (certification != null && certificationCountry != null && certification.length() > 0 && certificationCountry.length() > 0) {
|
|
|
|
|
// add country specific certification code
|
|
|
|
|
if (countryCode.equals(certificationCountry)) {
|
|
|
|
|
fields.put(MovieProperty.certification, certification);
|
|
|
|
|
}
|
|
|
|
|
// collect all certification codes just in case
|
|
|
|
|
certifications.put(certificationCountry, certification);
|
|
|
|
|
|
|
|
|
|
streamJsonObjects(getMap(response, "releases"), "countries").forEach(it -> {
|
|
|
|
|
String certificationCountry = getString(it, "iso_3166_1");
|
|
|
|
|
String certification = getString(it, "certification");
|
|
|
|
|
|
|
|
|
|
if (certification != null && certificationCountry != null) {
|
|
|
|
|
// add country specific certification code
|
|
|
|
|
if (countryCode.equals(certificationCountry)) {
|
|
|
|
|
fields.put(MovieProperty.certification, certification);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// collect all certification codes just in case
|
|
|
|
|
certifications.put(certificationCountry, certification);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Illegal releases data: " + response);
|
|
|
|
|
debug.warning(format("Bad data: certification => %s", response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<Person> cast = new ArrayList<Person>();
|
|
|
|
|
try {
|
|
|
|
|
JSONObject castResponse = (JSONObject) response.get("casts");
|
|
|
|
|
if (castResponse != null) {
|
|
|
|
|
for (String section : new String[] { "cast", "crew" }) {
|
|
|
|
|
for (JSONObject it : jsonList(castResponse.get(section))) {
|
|
|
|
|
Map<PersonProperty, String> person = new EnumMap<PersonProperty, String>(PersonProperty.class);
|
|
|
|
|
for (PersonProperty key : PersonProperty.values()) {
|
|
|
|
|
Object value = it.get(key.name());
|
|
|
|
|
if (value != null) {
|
|
|
|
|
person.put(key, value.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
cast.add(new Person(person));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Stream.of("cast", "crew").flatMap(section -> streamJsonObjects(getMap(response, "casts"), section)).map(it -> {
|
|
|
|
|
return mapStringValues(it, PersonProperty.class);
|
|
|
|
|
}).map(Person::new).forEach(cast::add);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Illegal casts data: " + response);
|
|
|
|
|
debug.warning(format("Bad data: casts => %s", response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
List<Trailer> trailers = new ArrayList<Trailer>();
|
|
|
|
|
try {
|
|
|
|
|
JSONObject trailerResponse = (JSONObject) response.get("trailers");
|
|
|
|
|
if (trailerResponse != null) {
|
|
|
|
|
for (String section : new String[] { "quicktime", "youtube" }) {
|
|
|
|
|
for (JSONObject it : jsonList(trailerResponse.get(section))) {
|
|
|
|
|
Map<String, String> sources = new LinkedHashMap<String, String>();
|
|
|
|
|
if (it.containsKey("sources")) {
|
|
|
|
|
for (JSONObject s : jsonList(it.get("sources"))) {
|
|
|
|
|
sources.put(s.get("size").toString(), s.get("source").toString());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
sources.put(it.get("size").toString(), it.get("source").toString());
|
|
|
|
|
Stream.of("quicktime", "youtube").forEach(section -> {
|
|
|
|
|
streamJsonObjects(getMap(response, "trailers"), section).map(it -> {
|
|
|
|
|
Map<String, String> sources = new LinkedHashMap<String, String>();
|
|
|
|
|
Stream.concat(Stream.of(it), streamJsonObjects(it, "sources")).forEach(source -> {
|
|
|
|
|
String size = getString(source, "size");
|
|
|
|
|
if (size != null) {
|
|
|
|
|
sources.put(size, getString(source, "source"));
|
|
|
|
|
}
|
|
|
|
|
trailers.add(new Trailer(section, it.get("name").toString(), sources));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
return new Trailer(section, getString(it, "name"), sources);
|
|
|
|
|
}).forEach(trailers::add);
|
|
|
|
|
});
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Illegal trailers data: " + response);
|
|
|
|
|
debug.warning(format("Bad data: trailers => %s", response));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return new MovieInfo(fields, alternativeTitles, genres, certifications, spokenLanguages, productionCountries, productionCompanies, cast, trailers);
|
|
|
|
@ -327,30 +270,29 @@ public class TMDbClient implements MovieIdentificationService {
|
|
|
|
|
|
|
|
|
|
public List<Artwork> getArtwork(String id) throws Exception {
|
|
|
|
|
// http://api.themoviedb.org/3/movie/11/images
|
|
|
|
|
JSONObject config = request("configuration", null, null, REQUEST_LIMIT);
|
|
|
|
|
String baseUrl = (String) ((JSONObject) config.get("images")).get("base_url");
|
|
|
|
|
Map<?, ?> config = request("configuration", null, null, REQUEST_LIMIT);
|
|
|
|
|
String baseUrl = getString(getMap(config, "images"), "base_url");
|
|
|
|
|
|
|
|
|
|
JSONObject images = request("movie/" + id + "/images", null, null, REQUEST_LIMIT);
|
|
|
|
|
List<Artwork> artwork = new ArrayList<Artwork>();
|
|
|
|
|
Map<?, ?> images = request("movie/" + id + "/images", null, null, REQUEST_LIMIT);
|
|
|
|
|
|
|
|
|
|
for (String section : new String[] { "backdrops", "posters" }) {
|
|
|
|
|
for (JSONObject it : jsonList(images.get(section))) {
|
|
|
|
|
return Stream.of("backdrops", "posters").flatMap(section -> {
|
|
|
|
|
Stream<Artwork> artwork = streamJsonObjects(images, section).map(it -> {
|
|
|
|
|
try {
|
|
|
|
|
String url = baseUrl + "original" + (String) it.get("file_path");
|
|
|
|
|
int width = Float.valueOf(it.get("width").toString()).intValue();
|
|
|
|
|
int height = Float.valueOf(it.get("height").toString()).intValue();
|
|
|
|
|
String lang = (String) it.get("iso_639_1");
|
|
|
|
|
artwork.add(new Artwork(section, new URL(url), width, height, lang));
|
|
|
|
|
String url = baseUrl + "original" + getString(it, "file_path");
|
|
|
|
|
int width = getDecimal(it, "width").intValue();
|
|
|
|
|
int height = getDecimal(it, "height").intValue();
|
|
|
|
|
String lang = getString(it, "iso_639_1");
|
|
|
|
|
return new Artwork(section, new URL(url), width, height, lang);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
Logger.getLogger(getClass().getName()).log(Level.WARNING, "Invalid artwork: " + it, e);
|
|
|
|
|
debug.warning(format("Bad artwork: %s => %s", it, e));
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return artwork;
|
|
|
|
|
});
|
|
|
|
|
return artwork;
|
|
|
|
|
}).collect(toList());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public JSONObject request(String resource, Map<String, Object> parameters, Locale locale, final FloodLimit limit) throws Exception {
|
|
|
|
|
public Map<?, ?> request(String resource, Map<String, Object> parameters, Locale locale, final FloodLimit limit) throws Exception {
|
|
|
|
|
// default parameters
|
|
|
|
|
LinkedHashMap<String, Object> data = new LinkedHashMap<String, Object>();
|
|
|
|
|
if (parameters != null) {
|
|
|
|
@ -375,34 +317,19 @@ public class TMDbClient implements MovieIdentificationService {
|
|
|
|
|
|
|
|
|
|
Cache etagStorage = Cache.getCache("etag", CacheType.Monthly);
|
|
|
|
|
Cache cache = Cache.getCache(getName(), CacheType.Monthly);
|
|
|
|
|
String json = cache.text(key, s -> getResource(s)).fetch(withPermit(fetchIfNoneMatch(etagStorage), r -> REQUEST_LIMIT.acquirePermit() != null)).expire(Cache.ONE_WEEK).get();
|
|
|
|
|
Object json = cache.json(key, s -> getResource(s)).fetch(withPermit(fetchIfNoneMatch(etagStorage), r -> limit.acquirePermit() != null)).expire(Cache.ONE_WEEK).get();
|
|
|
|
|
|
|
|
|
|
JSONObject object = (JSONObject) JSONValue.parse(json);
|
|
|
|
|
if (object == null || object.isEmpty()) {
|
|
|
|
|
throw new FileNotFoundException("Resource not found: " + getResource(key));
|
|
|
|
|
Map<?, ?> root = asMap(json);
|
|
|
|
|
if (root.isEmpty()) {
|
|
|
|
|
throw new FileNotFoundException(String.format("Resource is empty: %s => %s", json, getResource(key)));
|
|
|
|
|
}
|
|
|
|
|
return object;
|
|
|
|
|
return root;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public URL getResource(String file) throws Exception {
|
|
|
|
|
return new URL("http", host, "/" + version + "/" + file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected List<JSONObject> jsonList(final Object array) {
|
|
|
|
|
return new AbstractList<JSONObject>() {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public JSONObject get(int index) {
|
|
|
|
|
return (JSONObject) ((JSONArray) array).get(index);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int size() {
|
|
|
|
|
return ((JSONArray) array).size();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static class MovieInfo implements Serializable {
|
|
|
|
|
|
|
|
|
|
public static enum MovieProperty {
|
|
|
|
@ -429,7 +356,7 @@ public class TMDbClient implements MovieIdentificationService {
|
|
|
|
|
this.fields = new EnumMap<MovieProperty, String>(fields);
|
|
|
|
|
this.alternativeTitles = alternativeTitles.toArray(new String[0]);
|
|
|
|
|
this.genres = genres.toArray(new String[0]);
|
|
|
|
|
this.certifications = new HashMap<String, String>(certifications);
|
|
|
|
|
this.certifications = new LinkedHashMap<String, String>(certifications);
|
|
|
|
|
this.spokenLanguages = spokenLanguages.toArray(new String[0]);
|
|
|
|
|
this.productionCountries = productionCountries.toArray(new String[0]);
|
|
|
|
|
this.productionCompanies = productionCompanies.toArray(new String[0]);
|
|
|
|
|