From a4d363bb97d06e09451413fbb33ff2d402f89ae9 Mon Sep 17 00:00:00 2001 From: Reinhard Pointner Date: Mon, 7 Mar 2016 19:46:47 +0000 Subject: [PATCH] Remove json-simple.jar --- .classpath | 1 - build.xml | 4 - ivy.xml | 1 - source/net/filebot/util/JsonUtilities.java | 42 ++- source/net/filebot/web/AcoustIDClient.java | 5 +- source/net/filebot/web/FanartTVClient.java | 13 +- source/net/filebot/web/ShooterSubtitles.java | 52 +--- source/net/filebot/web/TMDbClient.java | 257 +++++++------------ 8 files changed, 144 insertions(+), 231 deletions(-) diff --git a/.classpath b/.classpath index ced21f30..8336886e 100644 --- a/.classpath +++ b/.classpath @@ -4,7 +4,6 @@ - diff --git a/build.xml b/build.xml index ee237b4f..b114cfc6 100644 --- a/build.xml +++ b/build.xml @@ -82,10 +82,6 @@ - - - - diff --git a/ivy.xml b/ivy.xml index eb5737d5..e85af73f 100644 --- a/ivy.xml +++ b/ivy.xml @@ -12,7 +12,6 @@ - diff --git a/source/net/filebot/util/JsonUtilities.java b/source/net/filebot/util/JsonUtilities.java index 6df70599..c43d8312 100644 --- a/source/net/filebot/util/JsonUtilities.java +++ b/source/net/filebot/util/JsonUtilities.java @@ -4,6 +4,7 @@ import static java.util.Arrays.*; import static java.util.Collections.*; import static net.filebot.Logging.*; +import java.util.EnumMap; import java.util.Map; import java.util.function.Function; import java.util.stream.Stream; @@ -72,20 +73,20 @@ public class JsonUtilities { } public static String getString(Object node, String key) { - Object value = asMap(node).get(key); - if (value != null) { - return value.toString(); - } - return null; + return nonEmptyOrNull(asMap(node).get(key)); } public static Integer getInteger(Object node, String key) { return getStringValue(node, key, Integer::parseInt); } + public static Double getDecimal(Object node, String key) { + return getStringValue(node, key, Double::parseDouble); + } + public static V getStringValue(Object node, String key, Function converter) { String value = getString(node, key); - if (value != null && value.length() > 0) { + if (value != null) { try { return converter.apply(getString(node, key)); } catch (Exception e) { @@ -95,4 +96,33 @@ public class JsonUtilities { return null; } + public static > EnumMap mapStringValues(Object node, Class cls) { + return mapValues(node, cls, JsonUtilities::nonEmptyOrNull); + } + + public static , V> EnumMap mapValues(Object node, Class cls, Function converter) { + Map values = asMap(node); + EnumMap map = new EnumMap(cls); + for (K key : cls.getEnumConstants()) { + Object object = values.get(key.name()); + if (object != null) { + V value = converter.apply(object); + if (value != null) { + map.put(key, value); + } + } + } + return map; + } + + public static String nonEmptyOrNull(Object object) { + if (object != null) { + String string = object.toString(); + if (string.length() > 0) { + return string; + } + } + return null; + } + } diff --git a/source/net/filebot/web/AcoustIDClient.java b/source/net/filebot/web/AcoustIDClient.java index c832f44c..9077655c 100644 --- a/source/net/filebot/web/AcoustIDClient.java +++ b/source/net/filebot/web/AcoustIDClient.java @@ -109,8 +109,9 @@ public class AcoustIDClient implements MusicIdentificationService { public AudioTrack parseResult(String json, final int targetDuration) throws IOException { Object data = readJson(json); - if (!"ok".equals(getString(data, "status"))) { - throw new IOException("acoustid responded with error: " + getString(data, "status")); + String status = getString(data, "status"); + if (!"ok".equals(status)) { + throw new IOException(String.format("%s responded with error: %s", getName(), status)); } for (Object result : getArray(data, "results")) { diff --git a/source/net/filebot/web/FanartTVClient.java b/source/net/filebot/web/FanartTVClient.java index b56340f9..d1d8a345 100644 --- a/source/net/filebot/web/FanartTVClient.java +++ b/source/net/filebot/web/FanartTVClient.java @@ -45,17 +45,10 @@ public class FanartTVClient { return asMap(json).entrySet().stream().flatMap(it -> { return streamJsonObjects(it.getValue()).map(item -> { - Map fields = new EnumMap(FanartProperty.class); - fields.put(FanartProperty.type, it.getKey().toString()); + Map map = mapStringValues(item, FanartProperty.class); + map.put(FanartProperty.type, it.getKey().toString()); - for (FanartProperty prop : FanartProperty.values()) { - Object value = item.get(prop.name()); - if (value != null) { - fields.put(prop, value.toString()); - } - } - - return new FanartDescriptor(fields); + return new FanartDescriptor(map); }).filter(art -> art.getProperties().size() > 1); }).toArray(FanartDescriptor[]::new); } diff --git a/source/net/filebot/web/ShooterSubtitles.java b/source/net/filebot/web/ShooterSubtitles.java index 7d81a606..40534504 100644 --- a/source/net/filebot/web/ShooterSubtitles.java +++ b/source/net/filebot/web/ShooterSubtitles.java @@ -1,8 +1,11 @@ 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.util.FileUtilities.*; +import static net.filebot.util.JsonUtilities.*; import java.io.File; import java.io.IOException; @@ -13,10 +16,8 @@ import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.nio.ByteBuffer; -import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; -import java.util.AbstractList; import java.util.ArrayList; import java.util.HashMap; import java.util.LinkedHashMap; @@ -30,10 +31,6 @@ import net.filebot.Cache; import net.filebot.CacheType; import net.filebot.ResourceManager; -import org.json.simple.JSONArray; -import org.json.simple.JSONObject; -import org.json.simple.JSONValue; - public class ShooterSubtitles implements VideoHashSubtitleService { private static final String LANGUAGE_CHINESE = "Chinese"; @@ -97,30 +94,16 @@ public class ShooterSubtitles implements VideoHashSubtitleService { } ByteBuffer post = WebRequest.post(endpoint, param, null); - Object response = JSONValue.parse(StandardCharsets.UTF_8.decode(post).toString()); + Object response = readJson(UTF_8.decode(post)); - List results = new ArrayList(); String name = getNameWithoutExtension(file.getName()); - JSON: for (JSONObject result : jsonList(response)) { - if (result == null) - continue; - - List files = jsonList(result.get("Files")); - if (files.size() == 1) { - for (JSONObject fd : jsonList(result.get("Files"))) { - String type = (String) fd.get("Ext"); - String link = (String) fd.get("Link"); - results.add(new ShooterSubtitleDescriptor(name, type, link, languageName)); - - // use the first best option and ignore the rest - break JSON; - } - } - } - - cache.put(key, results.toArray(new SubtitleDescriptor[0])); - return results; + // use the first best option and ignore the rest + return streamJsonObjects(response).flatMap(it -> streamJsonObjects(it, "Files")).map(f -> { + String type = getString(f, "Ext"); + String link = getString(f, "Link"); + return new ShooterSubtitleDescriptor(name, type, link, languageName); + }).limit(1).collect(toList()); } @Override @@ -133,21 +116,6 @@ public class ShooterSubtitles implements VideoHashSubtitleService { throw new UnsupportedOperationException(); } - protected static List jsonList(final Object array) { - return new AbstractList() { - - @Override - public JSONObject get(int index) { - return (JSONObject) ((JSONArray) array).get(index); - } - - @Override - public int size() { - return array == null ? 0 : ((JSONArray) array).size(); - } - }; - } - /** * * @see https://docs.google.com/document/d/1w5MCBO61rKQ6hI5m9laJLWse__yTYdRugpVyz4RzrmM/preview diff --git a/source/net/filebot/web/TMDbClient.java b/source/net/filebot/web/TMDbClient.java index 58bb178e..210fd333 100644 --- a/source/net/filebot/web/TMDbClient.java +++ b/source/net/filebot/web/TMDbClient.java @@ -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 result = new ArrayList(); + 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 alternativeTitles = new LinkedHashSet(); if (originalTitle != null) { @@ -122,32 +110,24 @@ public class TMDbClient implements MovieIdentificationService { if (extendedInfo) { try { - Set internationalTitles = new TreeSet(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 fields = new EnumMap(MovieProperty.class); - for (MovieProperty key : MovieProperty.values()) { - Object value = response.get(key.name()); - if (value != null) { - fields.put(key, value.toString()); - } - } + Map 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 genres = new ArrayList(); 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 spokenLanguages = new ArrayList(); 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 productionCountries = new ArrayList(); 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 productionCompanies = new ArrayList(); 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 alternativeTitles = new ArrayList(); 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 certifications = new HashMap(); + Map certifications = new LinkedHashMap(); 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 cast = new ArrayList(); 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 person = new EnumMap(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 trailers = new ArrayList(); 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 sources = new LinkedHashMap(); - 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 sources = new LinkedHashMap(); + 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 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 = new ArrayList(); + 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 = 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 parameters, Locale locale, final FloodLimit limit) throws Exception { + public Map request(String resource, Map parameters, Locale locale, final FloodLimit limit) throws Exception { // default parameters LinkedHashMap data = new LinkedHashMap(); 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 jsonList(final Object array) { - return new AbstractList() { - - @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(fields); this.alternativeTitles = alternativeTitles.toArray(new String[0]); this.genres = genres.toArray(new String[0]); - this.certifications = new HashMap(certifications); + this.certifications = new LinkedHashMap(certifications); this.spokenLanguages = spokenLanguages.toArray(new String[0]); this.productionCountries = productionCountries.toArray(new String[0]); this.productionCompanies = productionCompanies.toArray(new String[0]);