* internal support for fetching complete movie info including artwork

This commit is contained in:
Reinhard Pointner 2011-12-25 11:18:55 +00:00
parent cb1aa12201
commit 05a7fbb1af
2 changed files with 279 additions and 19 deletions

View File

@ -2,17 +2,21 @@
package net.sourceforge.filebot.web; package net.sourceforge.filebot.web;
import static java.util.Arrays.*;
import static java.util.Collections.*;
import static net.sourceforge.filebot.web.WebRequest.*; import static net.sourceforge.filebot.web.WebRequest.*;
import static net.sourceforge.tuned.XPathUtilities.*; import static net.sourceforge.tuned.XPathUtilities.*;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Scanner; import java.util.Scanner;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
@ -23,6 +27,8 @@ import org.w3c.dom.Node;
import org.xml.sax.SAXException; import org.xml.sax.SAXException;
import net.sourceforge.filebot.ResourceManager; import net.sourceforge.filebot.ResourceManager;
import net.sourceforge.filebot.web.TMDbClient.Artwork.ArtworkProperty;
import net.sourceforge.filebot.web.TMDbClient.MovieInfo.MovieProperty;
public class TMDbClient implements MovieIdentificationService { public class TMDbClient implements MovieIdentificationService {
@ -32,24 +38,24 @@ public class TMDbClient implements MovieIdentificationService {
private final String apikey; private final String apikey;
public TMDbClient(String apikey) { public TMDbClient(String apikey) {
this.apikey = apikey; this.apikey = apikey;
} }
@Override @Override
public String getName() { public String getName() {
return "TheMovieDB"; return "TheMovieDB";
} }
@Override @Override
public Icon getIcon() { public Icon getIcon() {
return ResourceManager.getIcon("search.themoviedb"); return ResourceManager.getIcon("search.themoviedb");
} }
@Override @Override
public List<Movie> searchMovie(String query, Locale locale) throws IOException { public List<Movie> searchMovie(String query, Locale locale) throws IOException {
try { try {
@ -57,21 +63,24 @@ public class TMDbClient implements MovieIdentificationService {
} catch (SAXException e) { } catch (SAXException e) {
// TMDb output is sometimes malformed xml // TMDb output is sometimes malformed xml
Logger.getLogger(getClass().getName()).log(Level.WARNING, e.getMessage()); Logger.getLogger(getClass().getName()).log(Level.WARNING, e.getMessage());
return Collections.emptyList(); return emptyList();
} }
} }
public List<Movie> searchMovie(File file, Locale locale) throws IOException, SAXException { public List<Movie> searchMovie(File file, Locale locale) throws IOException, SAXException {
if (file.length() < OpenSubtitlesHasher.HASH_CHUNK_SIZE)
return emptyList();
return searchMovie(OpenSubtitlesHasher.computeHash(file), file.length(), locale); return searchMovie(OpenSubtitlesHasher.computeHash(file), file.length(), locale);
} }
public List<Movie> searchMovie(String hash, long bytesize, Locale locale) throws IOException, SAXException { public List<Movie> searchMovie(String hash, long bytesize, Locale locale) throws IOException, SAXException {
return getMovies("Media.getInfo", hash + "/" + bytesize, locale); return getMovies("Media.getInfo", hash + "/" + bytesize, locale);
} }
@Override @Override
public Movie getMovieDescriptor(int imdbid, Locale locale) throws Exception { public Movie getMovieDescriptor(int imdbid, Locale locale) throws Exception {
URL resource = getResource("Movie.imdbLookup", String.format("tt%07d", imdbid), locale); URL resource = getResource("Movie.imdbLookup", String.format("tt%07d", imdbid), locale);
@ -86,7 +95,7 @@ public class TMDbClient implements MovieIdentificationService {
return new Movie(name, year, imdbid); return new Movie(name, year, imdbid);
} }
@Override @Override
public Movie[] getMovieDescriptors(File[] movieFiles, Locale locale) throws Exception { public Movie[] getMovieDescriptors(File[] movieFiles, Locale locale) throws Exception {
Movie[] movies = new Movie[movieFiles.length]; Movie[] movies = new Movie[movieFiles.length];
@ -101,7 +110,7 @@ public class TMDbClient implements MovieIdentificationService {
return movies; return movies;
} }
protected List<Movie> getMovies(String method, String parameter, Locale locale) throws IOException, SAXException { protected List<Movie> getMovies(String method, String parameter, Locale locale) throws IOException, SAXException {
List<Movie> result = new ArrayList<Movie>(); List<Movie> result = new ArrayList<Movie>();
@ -124,10 +133,248 @@ public class TMDbClient implements MovieIdentificationService {
return result; return result;
} }
protected URL getResource(String method, String parameter, Locale locale) throws MalformedURLException { protected URL getResource(String method, String parameter, Locale locale) throws MalformedURLException {
// e.g. http://api.themoviedb.org/2.1/Movie.search/en/xml/{apikey}/serenity // e.g. http://api.themoviedb.org/2.1/Movie.search/en/xml/{apikey}/serenity
return new URL("http", host, "/" + version + "/" + method + "/" + locale.getLanguage() + "/xml/" + apikey + "/" + parameter); return new URL("http", host, "/" + version + "/" + method + "/" + locale.getLanguage() + "/xml/" + apikey + "/" + parameter);
} }
public MovieInfo getMovieInfo(Movie movie, Locale locale) throws Exception {
URL resource = getResource("Movie.imdbLookup", String.format("tt%07d", movie.getImdbId()), locale);
Node node = selectNode("//movie", getDocument(resource));
Map<MovieProperty, String> movieProperties = new EnumMap<MovieProperty, String>(MovieProperty.class);
for (MovieProperty property : MovieProperty.values()) {
movieProperties.put(property, getTextContent(property.name(), node));
}
List<String> genres = new ArrayList<String>();
for (Node category : selectNodes("//category[@type='genre']", node)) {
genres.add(getAttribute("name", category));
}
List<Artwork> artwork = new ArrayList<Artwork>();
for (Node image : selectNodes("//image", node)) {
Map<ArtworkProperty, String> artworkProperties = new EnumMap<ArtworkProperty, String>(ArtworkProperty.class);
for (ArtworkProperty property : ArtworkProperty.values()) {
artworkProperties.put(property, getAttribute(property.name(), image));
}
artwork.add(new Artwork(artworkProperties));
}
return new MovieInfo(movieProperties, genres, artwork);
}
public static class MovieInfo implements Serializable {
public static enum MovieProperty {
translated,
adult,
language,
name,
type,
id,
imdb_id,
url,
overview,
votes,
rating,
certification,
released,
runtime
}
protected Map<MovieProperty, String> fields;
protected String[] genres;
protected Artwork[] images;
protected MovieInfo() {
// used by serializer
}
protected MovieInfo(Map<MovieProperty, String> fields, List<String> genres, List<Artwork> images) {
this.fields = new EnumMap<MovieProperty, String>(fields);
this.genres = genres.toArray(new String[0]);
this.images = images.toArray(new Artwork[0]);
}
public String get(Object key) {
return fields.get(MovieProperty.valueOf(key.toString()));
}
public String get(MovieProperty key) {
return fields.get(key);
}
public boolean isTranslated() {
return Boolean.valueOf(get(MovieProperty.translated));
}
public boolean isAdult() {
return Boolean.valueOf(get(MovieProperty.adult));
}
public Locale getLanguage() {
return new Locale(get(MovieProperty.language));
}
public String getName() {
return get(MovieProperty.name);
}
public String getType() {
return get(MovieProperty.type);
}
public int getId() {
return Integer.parseInt(get(MovieProperty.id));
}
public int getImdbId() {
// e.g. tt0379786
return Integer.parseInt(get(MovieProperty.imdb_id).substring(2));
}
public URL getUrl() {
try {
return new URL(get(MovieProperty.url));
} catch (Exception e) {
return null;
}
}
public String getOverview() {
return get(MovieProperty.overview);
}
public int getVotes() {
return Integer.parseInt(get(MovieProperty.votes));
}
public double getRating() {
return Double.parseDouble(get(MovieProperty.rating));
}
public String getCertification() {
// e.g. PG-13
return get(MovieProperty.certification);
}
public Date getReleased() {
// e.g. 2005-09-30
return Date.parse(get(MovieProperty.released), "yyyy-MM-dd");
}
public int getRuntime() {
return Integer.parseInt(get(MovieProperty.runtime));
}
public List<String> getGenres() {
return unmodifiableList(asList(genres));
}
public List<Artwork> getImages() {
return unmodifiableList(asList(images));
}
@Override
public String toString() {
return fields.toString();
}
}
public static class Artwork implements Serializable {
public static enum ArtworkProperty {
type,
url,
size,
width,
height
}
protected Map<ArtworkProperty, String> fields;
protected Artwork() {
// used by serializer
}
protected Artwork(Map<ArtworkProperty, String> fields) {
this.fields = new EnumMap<ArtworkProperty, String>(fields);
}
public String get(Object key) {
return fields.get(ArtworkProperty.valueOf(key.toString()));
}
public String get(ArtworkProperty key) {
return fields.get(key);
}
public String getType() {
return get(ArtworkProperty.type);
}
public URL getUrl() {
try {
return new URL(get(ArtworkProperty.url));
} catch (MalformedURLException e) {
return null;
}
}
public String getSize() {
return get(ArtworkProperty.size);
}
public int getWidth() {
return Integer.parseInt(get(ArtworkProperty.width));
}
public int getHeight() {
return Integer.parseInt(get(ArtworkProperty.height));
}
@Override
public String toString() {
return fields.toString();
}
}
} }

View File

@ -10,12 +10,14 @@ import java.util.Locale;
import org.junit.Test; import org.junit.Test;
import net.sourceforge.filebot.web.TMDbClient.MovieInfo;
public class TMDbClientTest { public class TMDbClientTest {
private final TMDbClient tmdb = new TMDbClient(getApplicationProperty("themoviedb.apikey")); private final TMDbClient tmdb = new TMDbClient(getApplicationProperty("themoviedb.apikey"));
@Test @Test
public void searchByName() throws Exception { public void searchByName() throws Exception {
List<Movie> result = tmdb.searchMovie("Serenity", Locale.CHINESE); List<Movie> result = tmdb.searchMovie("Serenity", Locale.CHINESE);
@ -26,25 +28,36 @@ public class TMDbClientTest {
assertEquals(379786, movie.getImdbId()); assertEquals(379786, movie.getImdbId());
} }
@Test @Test
public void searchByHash() throws Exception { public void searchByHash() throws Exception {
List<Movie> results = tmdb.searchMovie("907172e7fe51ba57", 742086656, Locale.ENGLISH); List<Movie> results = tmdb.searchMovie("907172e7fe51ba57", 742086656, Locale.ENGLISH);
Movie movie = results.get(0); Movie movie = results.get(0);
assertEquals("Sin City", movie.getName()); assertEquals("Sin City", movie.getName());
assertEquals(2005, movie.getYear()); assertEquals(2005, movie.getYear(), 0);
assertEquals(401792, movie.getImdbId()); assertEquals(401792, movie.getImdbId(), 0);
} }
@Test @Test
public void searchByIMDB() throws Exception { public void searchByIMDB() throws Exception {
Movie movie = tmdb.getMovieDescriptor(418279, Locale.ENGLISH); Movie movie = tmdb.getMovieDescriptor(418279, Locale.ENGLISH);
assertEquals("Transformers", movie.getName()); assertEquals("Transformers", movie.getName());
assertEquals(2007, movie.getYear()); assertEquals(2007, movie.getYear(), 0);
assertEquals(418279, movie.getImdbId()); assertEquals(418279, movie.getImdbId(), 0);
} }
@Test
public void getMovieInfo() throws Exception {
MovieInfo movie = tmdb.getMovieInfo(new Movie(null, 0, 418279), Locale.ENGLISH);
assertEquals("Transformers", movie.getName());
assertEquals("2007-07-03", movie.getReleased().toString());
assertEquals("Adventure", movie.getGenres().get(0));
assertEquals("thumb", movie.getImages().get(0).getSize());
assertEquals("http://cf2.imgobject.com/t/p/w92/bgSHbGEA1OM6qDs3Qba4VlSZsNG.jpg", movie.getImages().get(0).getUrl().toString());
}
} }