Fix json-io parse issues
This commit is contained in:
parent
ed455635bd
commit
335c857688
|
@ -1,13 +1,19 @@
|
||||||
package net.filebot.util;
|
package net.filebot.util;
|
||||||
|
|
||||||
|
import static java.util.Arrays.*;
|
||||||
import static java.util.Collections.*;
|
import static java.util.Collections.*;
|
||||||
|
import static net.filebot.Logging.*;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import com.cedarsoftware.util.io.JsonObject;
|
||||||
import com.cedarsoftware.util.io.JsonReader;
|
import com.cedarsoftware.util.io.JsonReader;
|
||||||
|
|
||||||
public class JsonUtilities {
|
public class JsonUtilities {
|
||||||
|
|
||||||
|
public static final Object[] EMPTY_ARRAY = new Object[0];
|
||||||
|
|
||||||
public static Map<?, ?> readJson(CharSequence json) {
|
public static Map<?, ?> readJson(CharSequence json) {
|
||||||
return (Map<?, ?>) JsonReader.jsonToJava(json.toString(), singletonMap(JsonReader.USE_MAPS, true));
|
return (Map<?, ?>) JsonReader.jsonToJava(json.toString(), singletonMap(JsonReader.USE_MAPS, true));
|
||||||
}
|
}
|
||||||
|
@ -16,30 +22,48 @@ public class JsonUtilities {
|
||||||
if (node instanceof Map) {
|
if (node instanceof Map) {
|
||||||
return (Map<?, ?>) node;
|
return (Map<?, ?>) node;
|
||||||
}
|
}
|
||||||
return null;
|
return EMPTY_MAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] asArray(Object node) {
|
public static Object[] asArray(Object node) {
|
||||||
if (node instanceof Object[]) {
|
if (node instanceof Object[]) {
|
||||||
return (Object[]) node;
|
return (Object[]) node;
|
||||||
}
|
}
|
||||||
return null;
|
if (node instanceof JsonObject) {
|
||||||
|
JsonObject<?, ?> jsonObject = (JsonObject<?, ?>) node;
|
||||||
|
if (jsonObject.isArray()) {
|
||||||
|
return jsonObject.getArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return EMPTY_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<?, ?>[] asMapArray(Object node) {
|
||||||
|
return stream(asArray(node)).map(JsonUtilities::asMap).filter(m -> m.size() > 0).toArray(Map[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Object[] getArray(Object node, String key) {
|
public static Object[] getArray(Object node, String key) {
|
||||||
return asArray(((Map<?, ?>) node).get(key));
|
return asArray(asMap(node).get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<?, ?> getMap(Object node, String key) {
|
||||||
|
return asMap(asMap(node).get(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Map<?, ?>[] getMapArray(Object node, String key) {
|
||||||
|
return asMapArray(asMap(node).get(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Map<?, ?> getFirstMap(Object node, String key) {
|
public static Map<?, ?> getFirstMap(Object node, String key) {
|
||||||
Object[] values = getArray(node, key);
|
Object[] values = getArray(node, key);
|
||||||
if (values != null && values.length > 0) {
|
if (values.length > 0) {
|
||||||
return (Map<?, ?>) values[0];
|
return asMap(values[0]);
|
||||||
}
|
}
|
||||||
return null;
|
return EMPTY_MAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getString(Object node, String key) {
|
public static String getString(Object node, String key) {
|
||||||
Object value = ((Map<?, ?>) node).get(key);
|
Object value = asMap(node).get(key);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
return value.toString();
|
return value.toString();
|
||||||
}
|
}
|
||||||
|
@ -47,9 +71,17 @@ public class JsonUtilities {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Integer getInteger(Object node, String key) {
|
public static Integer getInteger(Object node, String key) {
|
||||||
|
return getStringValue(node, key, Integer::parseInt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <V> V getStringValue(Object node, String key, Function<String, V> converter) {
|
||||||
String value = getString(node, key);
|
String value = getString(node, key);
|
||||||
if (value != null && value.length() > 0) {
|
if (value != null && value.length() > 0) {
|
||||||
return new Integer(value.toString());
|
try {
|
||||||
|
return converter.apply(getString(node, key));
|
||||||
|
} catch (Exception e) {
|
||||||
|
debug.warning(format("Bad %s value: %s => %s", key, value, e));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package net.filebot.web;
|
package net.filebot.web;
|
||||||
|
|
||||||
|
import static java.nio.charset.StandardCharsets.*;
|
||||||
|
import static java.util.Arrays.*;
|
||||||
import static net.filebot.util.JsonUtilities.*;
|
import static net.filebot.util.JsonUtilities.*;
|
||||||
import static net.filebot.web.WebRequest.*;
|
import static net.filebot.web.WebRequest.*;
|
||||||
|
|
||||||
|
@ -9,7 +11,6 @@ import java.io.InputStreamReader;
|
||||||
import java.lang.ProcessBuilder.Redirect;
|
import java.lang.ProcessBuilder.Redirect;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
@ -18,11 +19,11 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.Logger;
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
|
@ -99,7 +100,7 @@ public class AcoustIDClient implements MusicIdentificationService {
|
||||||
requestParam.put("Accept-Encoding", "gzip");
|
requestParam.put("Accept-Encoding", "gzip");
|
||||||
|
|
||||||
// submit
|
// submit
|
||||||
response = Charset.forName("UTF-8").decode(post(url, postParam, requestParam)).toString();
|
response = UTF_8.decode(post(url, postParam, requestParam)).toString();
|
||||||
|
|
||||||
cache.put(cacheKey, response);
|
cache.put(cacheKey, response);
|
||||||
return response;
|
return response;
|
||||||
|
@ -114,20 +115,18 @@ public class AcoustIDClient implements MusicIdentificationService {
|
||||||
|
|
||||||
for (Object result : getArray(data, "results")) {
|
for (Object result : getArray(data, "results")) {
|
||||||
// pick most likely matching recording
|
// pick most likely matching recording
|
||||||
return Stream.of(getArray(result, "recordings")).sorted((Object o1, Object o2) -> {
|
return stream(getMapArray(result, "recordings")).sorted((Map<?, ?> r1, Map<?, ?> r2) -> {
|
||||||
Integer i1 = getInteger(o1, "duration");
|
Integer i1 = getInteger(r1, "duration");
|
||||||
Integer i2 = getInteger(o2, "duration");
|
Integer i2 = getInteger(r2, "duration");
|
||||||
return Double.compare(i1 == null ? Double.NaN : Math.abs(i1 - targetDuration), i2 == null ? Double.NaN : Math.abs(i2 - targetDuration));
|
return Double.compare(i1 == null ? Double.NaN : Math.abs(i1 - targetDuration), i2 == null ? Double.NaN : Math.abs(i2 - targetDuration));
|
||||||
}).map((Object o) -> {
|
}).map((Map<?, ?> recording) -> {
|
||||||
Map<?, ?> recording = (Map<?, ?>) o;
|
|
||||||
try {
|
try {
|
||||||
Map<?, ?> releaseGroup = getFirstMap(recording, "releasegroups");
|
Map<?, ?> releaseGroup = getFirstMap(recording, "releasegroups");
|
||||||
if (releaseGroup == null) {
|
String artist = getString(getFirstMap(recording, "artists"), "name");
|
||||||
return null;
|
String title = getString(recording, "title");
|
||||||
}
|
|
||||||
|
|
||||||
String artist = (String) getFirstMap(recording, "artists").get("name");
|
if (artist == null || title == null || releaseGroup.isEmpty())
|
||||||
String title = (String) recording.get("title");
|
return null;
|
||||||
|
|
||||||
AudioTrack audioTrack = new AudioTrack(artist, title, null);
|
AudioTrack audioTrack = new AudioTrack(artist, title, null);
|
||||||
audioTrack.mbid = getString(result, "id");
|
audioTrack.mbid = getString(result, "id");
|
||||||
|
@ -136,15 +135,15 @@ public class AcoustIDClient implements MusicIdentificationService {
|
||||||
Object[] secondaryTypes = getArray(releaseGroup, "secondarytypes");
|
Object[] secondaryTypes = getArray(releaseGroup, "secondarytypes");
|
||||||
Object[] releases = getArray(releaseGroup, "releases");
|
Object[] releases = getArray(releaseGroup, "releases");
|
||||||
|
|
||||||
if (releases == null || secondaryTypes != null || (!"Album".equals(type))) {
|
if (releases.length == 0 || secondaryTypes.length > 0 || (!"Album".equals(type))) {
|
||||||
return audioTrack; // default to simple music info if album data is undesirable
|
return audioTrack; // default to simple music info if album data is undesirable
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Object it : releases) {
|
for (Map<?, ?> release : asMapArray(releases)) {
|
||||||
AudioTrack thisRelease = audioTrack.clone();
|
AudioTrack thisRelease = audioTrack.clone();
|
||||||
Map<?, ?> release = (Map<?, ?>) it;
|
|
||||||
Map<?, ?> date = (Map<?, ?>) release.get("date");
|
|
||||||
try {
|
try {
|
||||||
|
Map<?, ?> date = getMap(release, "date");
|
||||||
thisRelease.albumReleaseDate = new SimpleDate(getInteger(date, "year"), getInteger(date, "month"), getInteger(date, "day"));
|
thisRelease.albumReleaseDate = new SimpleDate(getInteger(date, "year"), getInteger(date, "month"), getInteger(date, "day"));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
thisRelease.albumReleaseDate = null;
|
thisRelease.albumReleaseDate = null;
|
||||||
|
@ -163,16 +162,16 @@ public class AcoustIDClient implements MusicIdentificationService {
|
||||||
thisRelease.trackCount = getInteger(medium, "track_count");
|
thisRelease.trackCount = getInteger(medium, "track_count");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
thisRelease.album = release.get("title").toString();
|
thisRelease.album = getString(release, "title");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
thisRelease.album = (String) releaseGroup.get("title");
|
thisRelease.album = getString(releaseGroup, "title");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
thisRelease.albumArtist = (String) getFirstMap(releaseGroup, "artists").get("name");
|
thisRelease.albumArtist = getString(getFirstMap(releaseGroup, "artists"), "name");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
thisRelease.albumArtist = null;
|
thisRelease.albumArtist = null;
|
||||||
}
|
}
|
||||||
thisRelease.trackTitle = (String) track.get("title");
|
thisRelease.trackTitle = getString(track, "title");
|
||||||
|
|
||||||
if (!"Various Artists".equalsIgnoreCase(thisRelease.albumArtist) && (thisRelease.album == null || !thisRelease.album.contains("Greatest Hits"))) {
|
if (!"Various Artists".equalsIgnoreCase(thisRelease.albumArtist) && (thisRelease.album == null || !thisRelease.album.contains("Greatest Hits"))) {
|
||||||
// full info audio track
|
// full info audio track
|
||||||
|
@ -183,10 +182,10 @@ public class AcoustIDClient implements MusicIdentificationService {
|
||||||
// default to simple music info if extended info is not available
|
// default to simple music info if extended info is not available
|
||||||
return audioTrack;
|
return audioTrack;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Logger.getLogger(AcoustIDClient.class.getName()).log(Level.WARNING, e.toString(), e);
|
Logger.getLogger(AcoustIDClient.class.getName()).log(Level.WARNING, e.getMessage(), e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).filter(o -> o != null).sorted(new MostFieldsNotNull()).findFirst().get();
|
}).filter(Objects::nonNull).sorted(new MostFieldsNotNull()).findFirst().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -211,7 +210,7 @@ public class AcoustIDClient implements MusicIdentificationService {
|
||||||
throw new IOException("Failed to exec fpcalc: " + e.getMessage());
|
throw new IOException("Failed to exec fpcalc: " + e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
Scanner scanner = new Scanner(new InputStreamReader(process.getInputStream(), "UTF-8"));
|
Scanner scanner = new Scanner(new InputStreamReader(process.getInputStream(), UTF_8));
|
||||||
LinkedList<Map<String, String>> results = new LinkedList<Map<String, String>>();
|
LinkedList<Map<String, String>> results = new LinkedList<Map<String, String>>();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package net.filebot.web;
|
package net.filebot.web;
|
||||||
|
|
||||||
import static java.nio.charset.StandardCharsets.*;
|
import static java.nio.charset.StandardCharsets.*;
|
||||||
|
import static java.util.Arrays.*;
|
||||||
|
import static java.util.Collections.*;
|
||||||
import static net.filebot.util.JsonUtilities.*;
|
import static net.filebot.util.JsonUtilities.*;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -41,33 +42,21 @@ public class FanartTVClient {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public FanartDescriptor[] process(ByteBuffer data) throws Exception {
|
public FanartDescriptor[] process(ByteBuffer data) throws Exception {
|
||||||
List<FanartDescriptor> fanart = new ArrayList<FanartDescriptor>();
|
return readJson(UTF_8.decode(data)).entrySet().stream().flatMap(it -> {
|
||||||
|
return stream(asMapArray(it.getValue())).map(item -> {
|
||||||
readJson(UTF_8.decode(data)).forEach((k, v) -> {
|
|
||||||
Object[] array = asArray(v);
|
|
||||||
if (array == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (Object it : array) {
|
|
||||||
Map<?, ?> item = asMap(it);
|
|
||||||
if (item == null)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Map<FanartProperty, String> fields = new EnumMap<FanartProperty, String>(FanartProperty.class);
|
Map<FanartProperty, String> fields = new EnumMap<FanartProperty, String>(FanartProperty.class);
|
||||||
fields.put(FanartProperty.type, k.toString());
|
fields.put(FanartProperty.type, it.getKey().toString());
|
||||||
|
|
||||||
for (FanartProperty prop : FanartProperty.values()) {
|
for (FanartProperty prop : FanartProperty.values()) {
|
||||||
Object value = item.get(prop.name());
|
Object value = item.get(prop.name());
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
fields.put(prop, value.toString());
|
fields.put(prop, value.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (fields.size() > 1) {
|
|
||||||
fanart.add(new FanartDescriptor(fields));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return fanart.toArray(new FanartDescriptor[0]);
|
return new FanartDescriptor(fields);
|
||||||
|
}).filter(art -> art.getProperties().size() > 1);
|
||||||
|
}).toArray(FanartDescriptor[]::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -90,31 +79,35 @@ public class FanartTVClient {
|
||||||
type, id, url, lang, likes, season, disc, disc_type
|
type, id, url, lang, likes, season, disc, disc_type
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<FanartProperty, String> fields;
|
protected Map<FanartProperty, String> properties;
|
||||||
|
|
||||||
protected FanartDescriptor() {
|
protected FanartDescriptor() {
|
||||||
// used by serializer
|
// used by serializer
|
||||||
}
|
}
|
||||||
|
|
||||||
protected FanartDescriptor(Map<FanartProperty, String> fields) {
|
protected FanartDescriptor(Map<FanartProperty, String> fields) {
|
||||||
this.fields = new EnumMap<FanartProperty, String>(fields);
|
this.properties = new EnumMap<FanartProperty, String>(fields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<FanartProperty, String> getProperties() {
|
||||||
|
return unmodifiableMap(properties);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String get(Object key) {
|
public String get(Object key) {
|
||||||
return fields.get(FanartProperty.valueOf(key.toString()));
|
return properties.get(FanartProperty.valueOf(key.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public String get(FanartProperty key) {
|
public String get(FanartProperty key) {
|
||||||
return fields.get(key);
|
return properties.get(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return fields.get(FanartProperty.type);
|
return properties.get(FanartProperty.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
try {
|
try {
|
||||||
return new Integer(fields.get(FanartProperty.id));
|
return new Integer(properties.get(FanartProperty.id));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -122,7 +115,7 @@ public class FanartTVClient {
|
||||||
|
|
||||||
public URL getUrl() {
|
public URL getUrl() {
|
||||||
try {
|
try {
|
||||||
return new URL(fields.get(FanartProperty.url));
|
return new URL(properties.get(FanartProperty.url));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -130,7 +123,7 @@ public class FanartTVClient {
|
||||||
|
|
||||||
public Integer getLikes() {
|
public Integer getLikes() {
|
||||||
try {
|
try {
|
||||||
return new Integer(fields.get(FanartProperty.likes));
|
return new Integer(properties.get(FanartProperty.likes));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -138,7 +131,7 @@ public class FanartTVClient {
|
||||||
|
|
||||||
public Locale getLanguage() {
|
public Locale getLanguage() {
|
||||||
try {
|
try {
|
||||||
return new Locale(fields.get(FanartProperty.lang));
|
return new Locale(properties.get(FanartProperty.lang));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -146,7 +139,7 @@ public class FanartTVClient {
|
||||||
|
|
||||||
public Integer getSeason() {
|
public Integer getSeason() {
|
||||||
try {
|
try {
|
||||||
return new Integer(fields.get(FanartProperty.season));
|
return new Integer(properties.get(FanartProperty.season));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -154,19 +147,19 @@ public class FanartTVClient {
|
||||||
|
|
||||||
public Integer getDiskNumber() {
|
public Integer getDiskNumber() {
|
||||||
try {
|
try {
|
||||||
return new Integer(fields.get(FanartProperty.disc));
|
return new Integer(properties.get(FanartProperty.disc));
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDiskType() {
|
public String getDiskType() {
|
||||||
return fields.get(FanartProperty.disc_type);
|
return properties.get(FanartProperty.disc_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return fields.toString();
|
return properties.toString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ 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.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.*;
|
||||||
|
|
||||||
|
@ -40,9 +41,6 @@ import net.filebot.web.TMDbClient.Person;
|
||||||
import net.sf.ehcache.Cache;
|
import net.sf.ehcache.Cache;
|
||||||
import net.sf.ehcache.CacheManager;
|
import net.sf.ehcache.CacheManager;
|
||||||
|
|
||||||
import com.cedarsoftware.util.io.JsonObject;
|
|
||||||
import com.cedarsoftware.util.io.JsonReader;
|
|
||||||
|
|
||||||
public class OMDbClient implements MovieIdentificationService {
|
public class OMDbClient implements MovieIdentificationService {
|
||||||
|
|
||||||
private static final FloodLimit REQUEST_LIMIT = new FloodLimit(20, 10, TimeUnit.SECONDS);
|
private static final FloodLimit REQUEST_LIMIT = new FloodLimit(20, 10, TimeUnit.SECONDS);
|
||||||
|
@ -71,11 +69,6 @@ public class OMDbClient implements MovieIdentificationService {
|
||||||
throw new IllegalArgumentException(String.format("Cannot find imdb id: %s", link));
|
throw new IllegalArgumentException(String.format("Cannot find imdb id: %s", link));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Object[] array(Object node, String key) {
|
|
||||||
Object value = ((Map<?, ?>) node).get(key);
|
|
||||||
return value == null ? new Object[0] : ((JsonObject<?, ?>) value).getArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Movie> searchMovie(String query, Locale locale) throws IOException {
|
public List<Movie> searchMovie(String query, Locale locale) throws IOException {
|
||||||
// query by name with year filter if possible
|
// query by name with year filter if possible
|
||||||
|
@ -97,7 +90,7 @@ public class OMDbClient implements MovieIdentificationService {
|
||||||
Map<?, ?> response = request(param, REQUEST_LIMIT);
|
Map<?, ?> response = request(param, REQUEST_LIMIT);
|
||||||
|
|
||||||
List<Movie> result = new ArrayList<Movie>();
|
List<Movie> result = new ArrayList<Movie>();
|
||||||
for (Object it : array(response, "Search")) {
|
for (Object it : getArray(response, "Search")) {
|
||||||
Map<String, String> info = getInfoMap(it);
|
Map<String, String> info = getInfoMap(it);
|
||||||
if ("movie".equals(info.get("Type"))) {
|
if ("movie".equals(info.get("Type"))) {
|
||||||
result.add(getMovie(info));
|
result.add(getMovie(info));
|
||||||
|
@ -178,7 +171,7 @@ public class OMDbClient implements MovieIdentificationService {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
return JsonReader.jsonToMaps(json.get());
|
return readJson(json.get());
|
||||||
}
|
}
|
||||||
|
|
||||||
public Map<String, String> getMovieInfo(Integer i, String t, String y, boolean tomatoes) throws IOException {
|
public Map<String, String> getMovieInfo(Integer i, String t, String y, boolean tomatoes) throws IOException {
|
||||||
|
|
|
@ -1,27 +1,23 @@
|
||||||
package net.filebot.web;
|
package net.filebot.web;
|
||||||
|
|
||||||
|
import static java.util.Arrays.*;
|
||||||
|
import static java.util.stream.Collectors.*;
|
||||||
|
import static net.filebot.util.JsonUtilities.*;
|
||||||
import static net.filebot.web.WebRequest.*;
|
import static net.filebot.web.WebRequest.*;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.util.logging.Logger;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
|
|
||||||
import net.filebot.Cache;
|
import net.filebot.Cache;
|
||||||
import net.filebot.ResourceManager;
|
import net.filebot.ResourceManager;
|
||||||
|
|
||||||
import com.cedarsoftware.util.io.JsonObject;
|
|
||||||
|
|
||||||
public class TVMazeClient extends AbstractEpisodeListProvider {
|
public class TVMazeClient extends AbstractEpisodeListProvider {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -62,33 +58,27 @@ public class TVMazeClient extends AbstractEpisodeListProvider {
|
||||||
@Override
|
@Override
|
||||||
public List<SearchResult> fetchSearchResult(String query, Locale locale) throws IOException {
|
public List<SearchResult> fetchSearchResult(String query, Locale locale) throws IOException {
|
||||||
// e.g. http://api.tvmaze.com/search/shows?q=girls
|
// e.g. http://api.tvmaze.com/search/shows?q=girls
|
||||||
JsonObject<?, ?> response = request("search/shows?q=" + encode(query, true));
|
Object response = request("search/shows?q=" + encode(query, true));
|
||||||
|
|
||||||
List<SearchResult> results = new ArrayList<SearchResult>();
|
// TODO: FUTURE WORK: consider adding TVmaze aka titles for each result, e.g. http://api.tvmaze.com/shows/1/akas
|
||||||
if (response.isArray()) {
|
return stream(asMapArray(response)).map(it -> {
|
||||||
for (Object result : response.getArray()) {
|
Object show = it.get("show");
|
||||||
Map<?, ?> show = (Map<?, ?>) ((Map<?, ?>) result).get("show");
|
Integer id = getInteger(show, "id");
|
||||||
|
String name = getString(show, "name");
|
||||||
|
|
||||||
Integer id = getValue(show, "id", Integer::new);
|
return new TVMazeSearchResult(id, name);
|
||||||
String name = getValue(show, "name", String::new);
|
}).collect(toList());
|
||||||
|
|
||||||
// FUTURE WORK: consider adding TVmaze aka titles for each result, e.g. http://api.tvmaze.com/shows/1/akas
|
|
||||||
results.add(new TVMazeSearchResult(id, name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return results;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SeriesInfo fetchSeriesInfo(TVMazeSearchResult show, SortOrder sortOrder, Locale locale) throws IOException {
|
protected SeriesInfo fetchSeriesInfo(TVMazeSearchResult show, SortOrder sortOrder, Locale locale) throws IOException {
|
||||||
// e.g. http://api.tvmaze.com/shows/1
|
// e.g. http://api.tvmaze.com/shows/1
|
||||||
JsonObject<?, ?> response = request("shows/" + show.getId());
|
Object response = request("shows/" + show.getId());
|
||||||
|
|
||||||
String status = getValue(response, "status", String::new);
|
String status = getStringValue(response, "status", String::new);
|
||||||
SimpleDate premiered = getValue(response, "premiered", SimpleDate::parse);
|
SimpleDate premiered = getStringValue(response, "premiered", SimpleDate::parse);
|
||||||
Integer runtime = getValue(response, "runtime", Integer::new);
|
Integer runtime = getStringValue(response, "runtime", Integer::new);
|
||||||
JsonObject<?, ?> genres = (JsonObject<?, ?>) response.get("genres");
|
Object[] genres = getArray(response, "genres");
|
||||||
JsonObject<?, ?> rating = (JsonObject<?, ?>) response.get("rating");
|
Double rating = getStringValue(getMap(response, "rating"), "average", Double::new);
|
||||||
|
|
||||||
SeriesInfo seriesInfo = new SeriesInfo(getName(), sortOrder, locale, show.getId());
|
SeriesInfo seriesInfo = new SeriesInfo(getName(), sortOrder, locale, show.getId());
|
||||||
seriesInfo.setName(show.getName());
|
seriesInfo.setName(show.getName());
|
||||||
|
@ -96,13 +86,8 @@ public class TVMazeClient extends AbstractEpisodeListProvider {
|
||||||
seriesInfo.setStatus(status);
|
seriesInfo.setStatus(status);
|
||||||
seriesInfo.setRuntime(runtime);
|
seriesInfo.setRuntime(runtime);
|
||||||
seriesInfo.setStartDate(premiered);
|
seriesInfo.setStartDate(premiered);
|
||||||
|
seriesInfo.setRating(rating);
|
||||||
if (genres != null && genres.isArray()) {
|
seriesInfo.setGenres(stream(genres).map(Objects::toString).collect(toList()));
|
||||||
seriesInfo.setGenres(Arrays.stream(genres.getArray()).map(Objects::toString).collect(Collectors.toList()));
|
|
||||||
}
|
|
||||||
if (rating != null && !rating.isEmpty()) {
|
|
||||||
seriesInfo.setRating(getValue(rating, "average", Double::new));
|
|
||||||
}
|
|
||||||
|
|
||||||
return seriesInfo;
|
return seriesInfo;
|
||||||
}
|
}
|
||||||
|
@ -112,21 +97,18 @@ public class TVMazeClient extends AbstractEpisodeListProvider {
|
||||||
TVMazeSearchResult show = (TVMazeSearchResult) searchResult;
|
TVMazeSearchResult show = (TVMazeSearchResult) searchResult;
|
||||||
|
|
||||||
SeriesInfo seriesInfo = fetchSeriesInfo(show, sortOrder, locale);
|
SeriesInfo seriesInfo = fetchSeriesInfo(show, sortOrder, locale);
|
||||||
|
|
||||||
// e.g. http://api.tvmaze.com/shows/1/episodes
|
|
||||||
JsonObject<?, ?> response = request("shows/" + show.getId() + "/episodes");
|
|
||||||
|
|
||||||
List<Episode> episodes = new ArrayList<Episode>(25);
|
List<Episode> episodes = new ArrayList<Episode>(25);
|
||||||
|
|
||||||
if (response.isArray()) {
|
// e.g. http://api.tvmaze.com/shows/1/episodes
|
||||||
for (Object element : response.getArray()) {
|
Object response = request("shows/" + show.getId() + "/episodes");
|
||||||
JsonObject<?, ?> episode = (JsonObject<?, ?>) element;
|
|
||||||
|
|
||||||
String episodeTitle = getValue(episode, "name", String::new);
|
for (Map<?, ?> episode : asMapArray(response)) {
|
||||||
Integer seasonNumber = getValue(episode, "season", Integer::new);
|
String episodeTitle = getString(episode, "name");
|
||||||
Integer episodeNumber = getValue(episode, "number", Integer::new);
|
Integer seasonNumber = getInteger(episode, "season");
|
||||||
SimpleDate airdate = getValue(episode, "airdate", SimpleDate::parse);
|
Integer episodeNumber = getInteger(episode, "number");
|
||||||
|
SimpleDate airdate = getStringValue(episode, "airdate", SimpleDate::parse);
|
||||||
|
|
||||||
|
if (episodeNumber != null && episodeTitle != null) {
|
||||||
episodes.add(new Episode(seriesInfo.getName(), seasonNumber, episodeNumber, episodeTitle, null, null, airdate, new SeriesInfo(seriesInfo)));
|
episodes.add(new Episode(seriesInfo.getName(), seasonNumber, episodeNumber, episodeTitle, null, null, airdate, new SeriesInfo(seriesInfo)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -134,19 +116,7 @@ public class TVMazeClient extends AbstractEpisodeListProvider {
|
||||||
return new SeriesData(seriesInfo, episodes);
|
return new SeriesData(seriesInfo, episodes);
|
||||||
}
|
}
|
||||||
|
|
||||||
private <V> V getValue(Map<?, ?> json, String key, Function<String, V> converter) {
|
public Object request(String resource) throws IOException {
|
||||||
try {
|
|
||||||
Object value = json.get(key);
|
|
||||||
if (value != null) {
|
|
||||||
return converter.apply(value.toString());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
Logger.getLogger(TVMazeClient.class.getName()).log(Level.WARNING, "Illegal " + key + " value: " + json);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public JsonObject<?, ?> request(String resource) throws IOException {
|
|
||||||
return new CachedJsonResource("http://api.tvmaze.com/" + resource).getJSON();
|
return new CachedJsonResource("http://api.tvmaze.com/" + resource).getJSON();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,10 @@ import static org.junit.Assert.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import net.sf.ehcache.CacheManager;
|
||||||
|
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class TVMazeClientTest {
|
public class TVMazeClientTest {
|
||||||
|
@ -64,4 +68,10 @@ public class TVMazeClientTest {
|
||||||
assertEquals("http://www.tvmaze.com/shows/427", client.getEpisodeListLink(buffySearchResult).toString());
|
assertEquals("http://www.tvmaze.com/shows/427", client.getEpisodeListLink(buffySearchResult).toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
@AfterClass
|
||||||
|
public static void clearCache() {
|
||||||
|
CacheManager.getInstance().clearAll();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue