diff --git a/src/main/java/com/omertron/themoviedbapi/TheMovieDbApi.java b/src/main/java/com/omertron/themoviedbapi/TheMovieDbApi.java
index 5b5f375f3..7afdb918b 100644
--- a/src/main/java/com/omertron/themoviedbapi/TheMovieDbApi.java
+++ b/src/main/java/com/omertron/themoviedbapi/TheMovieDbApi.java
@@ -57,6 +57,7 @@ public class TheMovieDbApi {
private static final String BASE_LIST = "list/";
private static final String BASE_KEYWORD = "keyword/";
private static final String BASE_JOB = "job/";
+ private static final String BASE_DISCOVER = "discover/";
// Jackson JSON configuration
private static ObjectMapper mapper = new ObjectMapper();
@@ -1585,4 +1586,81 @@ public class TheMovieDbApi {
}
}
//
+
+ //
+ /**
+ * Discover movies by different types of data like average rating, number of votes, genres and certifications.
+ *
+ * You can alternatively create a "discover" object and pass it to this method to cut out the requirement for all of these
+ * parameters
+ *
+ * @param page Minimum value is 1
+ * @param language ISO 639-1 code.
+ * @param sortBy Available options are vote_average.desc, vote_average.asc, release_date.desc, release_date.asc,
+ * popularity.desc, popularity.asc
+ * @param includeAdult Toggle the inclusion of adult titles
+ * @param year Filter the results release dates to matches that include this value
+ * @param primaryReleaseYear Filter the results so that only the primary release date year has this value
+ * @param voteCountGte Only include movies that are equal to, or have a vote count higher than this value
+ * @param voteAverageGte Only include movies that are equal to, or have a higher average rating than this value
+ * @param withGenres Only include movies with the specified genres. Expected value is an integer (the id of a genre). Multiple
+ * values can be specified. Comma separated indicates an 'AND' query, while a pipe (|) separated value indicates an 'OR'.
+ * @param releaseDateGte The minimum release to include. Expected format is YYYY-MM-DD
+ * @param releaseDateLte The maximum release to include. Expected format is YYYY-MM-DD
+ * @param certificationCountry Only include movies with certifications for a specific country. When this value is specified,
+ * 'certificationLte' is required. A ISO 3166-1 is expected.
+ * @param certificationLte Only include movies with this certification and lower. Expected value is a valid certification for
+ * the specified 'certificationCountry'.
+ * @param withCompanies Filter movies to include a specific company. Expected value is an integer (the id of a company). They
+ * can be comma separated to indicate an 'AND' query.
+ * @return
+ * @throws MovieDbException
+ */
+ public List getDiscover(int page, String language, String sortBy, boolean includeAdult, int year,
+ int primaryReleaseYear, int voteCountGte, float voteAverageGte, String withGenres, String releaseDateGte,
+ String releaseDateLte, String certificationCountry, String certificationLte, String withCompanies) throws MovieDbException {
+
+ Discover d = new Discover();
+ d.page(page)
+ .language(language)
+ .sortBy(sortBy)
+ .includeAdult(includeAdult)
+ .year(year)
+ .primaryReleaseYear(primaryReleaseYear)
+ .voteCountGte(voteCountGte)
+ .voteAverageGte(voteAverageGte)
+ .withGenres(withGenres)
+ .releaseDateGte(releaseDateGte)
+ .releaseDateLte(releaseDateLte)
+ .certificationCountry(certificationCountry)
+ .certificationLte(certificationLte)
+ .withCompanies(withCompanies);
+
+ return getDiscover(d);
+ }
+
+ /**
+ * Discover movies by different types of data like average rating, number of votes, genres and certifications.
+ *
+ * @param discover A discover object containing the search criteria required
+ * @return
+ * @throws MovieDbException
+ */
+ public List getDiscover(Discover discover) throws MovieDbException {
+ ApiUrl apiUrl = new ApiUrl(apiKey, BASE_DISCOVER, "/movie");
+
+ apiUrl.setArguments(discover.getParams());
+
+ URL url = apiUrl.buildUrl();
+ String webpage = WebBrowser.request(url);
+
+ try {
+ WrapperMovie wrapper = mapper.readValue(webpage, WrapperMovie.class);
+ return wrapper.getMovies();
+ } catch (IOException ex) {
+ LOG.warn("Failed to get job list: {}", ex.getMessage());
+ throw new MovieDbException(MovieDbExceptionType.MAPPING_FAILED, webpage, ex);
+ }
+ }
+ //
}
diff --git a/src/main/java/com/omertron/themoviedbapi/model/Discover.java b/src/main/java/com/omertron/themoviedbapi/model/Discover.java
new file mode 100644
index 000000000..f803afb51
--- /dev/null
+++ b/src/main/java/com/omertron/themoviedbapi/model/Discover.java
@@ -0,0 +1,262 @@
+/*
+ * Copyright (c) 2004-2013 Stuart Boston
+ *
+ * This file is part of TheMovieDB API.
+ *
+ * TheMovieDB API is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation;private either version 3 of the License;private or
+ * any later version.
+ *
+ * TheMovieDB API is distributed in the hope that it will be useful;private
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with TheMovieDB API. If not;private see .
+ *
+ */
+package com.omertron.themoviedbapi.model;
+
+import java.util.HashMap;
+import java.util.Map;
+import static com.omertron.themoviedbapi.tools.ApiUrl.*;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Generate a discover object for use in the MovieDbApi
+ *
+ * This allows you to just add the search components you are concerned with
+ *
+ * @author stuart.boston
+ */
+public class Discover {
+
+ private Map params = new HashMap();
+ private static final String PARAM_PRIMARY_RELEASE_YEAR = "primary_release_year=";
+ private static final String PARAM_VOTE_COUNT_GTE = "vote_count.gte=";
+ private static final String PARAM_VOTE_AVERAGE_GTE = "vote_average.gte=";
+ private static final String PARAM_WITH_GENRES = "with_genres=";
+ private static final String PARAM_RELEASE_DATE_GTE = "release_date.gte=";
+ private static final String PARAM_RELEASE_DATE_LTE = "release_date.lte=";
+ private static final String PARAM_CERTIFICATION_COUNTRY = "certification_country=";
+ private static final String PARAM_CERTIFICATION_LTE = "certification.lte=";
+ private static final String PARAM_WITH_COMPANIES = "with_companies=";
+ private static final String PARAM_SORT_BY = "sort_by=";
+ private static final int YEAR_MIN = 1900;
+ private static final int YEAR_MAX = 2100;
+
+ /**
+ * Get the parameters
+ *
+ * This will be used to construct the URL in the API
+ *
+ * @return
+ */
+ public Map getParams() {
+ return params;
+ }
+
+ /**
+ * Minimum value is 1 if included.
+ *
+ * @param page
+ */
+ public Discover page(int page) {
+ if (page > 0) {
+ params.put(PARAM_PAGE, String.valueOf(page));
+ }
+ return this;
+ }
+
+ /**
+ * ISO 639-1 code
+ *
+ * @param language
+ */
+ public Discover language(String language) {
+ if (StringUtils.isNotBlank(language)) {
+ params.put(PARAM_LANGUAGE, language);
+ }
+ return this;
+ }
+
+ /**
+ * Available options are
+ * vote_average.desc
+ * vote_average.asc
+ * release_date.desc
+ * release_date.asc
+ * popularity.desc
+ * popularity.asc
+ *
+ * @param sortBy
+ */
+ public Discover sortBy(String sortBy) {
+ if (StringUtils.isNotBlank(sortBy)) {
+ params.put(PARAM_SORT_BY, sortBy);
+ }
+ return this;
+ }
+
+ /**
+ * Toggle the inclusion of adult titles
+ *
+ * @param includeAdult
+ */
+ public Discover includeAdult(boolean includeAdult) {
+ params.put(PARAM_ADULT, String.valueOf(includeAdult));
+ return this;
+ }
+
+ /**
+ * Filter the results release dates to matches that include this value.
+ *
+ * @param year
+ */
+ public Discover year(int year) {
+ if (checkYear(year)) {
+ params.put(PARAM_YEAR, String.valueOf(year));
+ }
+ return this;
+ }
+
+ /**
+ * Filter the results so that only the primary release date year has this value
+ *
+ * @param primaryReleaseYear
+ */
+ public Discover primaryReleaseYear(int primaryReleaseYear) {
+ if (checkYear(primaryReleaseYear)) {
+ params.put(PARAM_PRIMARY_RELEASE_YEAR, String.valueOf(primaryReleaseYear));
+ }
+ return this;
+ }
+
+ /**
+ * Only include movies that are equal to, or have a vote count higher than this value
+ *
+ * @param voteCountGte
+ */
+ public Discover voteCountGte(int voteCountGte) {
+ if (voteCountGte > 0) {
+ params.put(PARAM_VOTE_COUNT_GTE, String.valueOf(voteCountGte));
+ }
+ return this;
+ }
+
+ /**
+ * Only include movies that are equal to, or have a higher average rating than this value
+ *
+ * @param voteAverageGte
+ */
+ public Discover voteAverageGte(float voteAverageGte) {
+ if (voteAverageGte > 0) {
+ params.put(PARAM_VOTE_AVERAGE_GTE, String.valueOf(voteAverageGte));
+ }
+ return this;
+ }
+
+ /**
+ * Only include movies with the specified genres.
+ *
+ * Expected value is an integer (the id of a genre).
+ *
+ * Multiple values can be specified.
+ *
+ * Comma separated indicates an 'AND' query, while a pipe (|) separated value indicates an 'OR'
+ *
+ * @param withGenres
+ */
+ public Discover withGenres(String withGenres) {
+ if (StringUtils.isNotBlank(withGenres)) {
+ params.put(PARAM_WITH_GENRES, withGenres);
+ }
+ return this;
+ }
+
+ /**
+ * The minimum release to include.
+ *
+ * Expected format is YYYY-MM-DD.
+ *
+ * @param releaseDateGte
+ */
+ public Discover releaseDateGte(String releaseDateGte) {
+ if (StringUtils.isNotBlank(releaseDateGte)) {
+ params.put(PARAM_RELEASE_DATE_GTE, releaseDateGte);
+ }
+ return this;
+ }
+
+ /**
+ * The maximum release to include.
+ *
+ * Expected format is YYYY-MM-DD.
+ *
+ * @param releaseDateLte
+ */
+ public Discover releaseDateLte(String releaseDateLte) {
+ if (StringUtils.isNotBlank(releaseDateLte)) {
+ params.put(PARAM_RELEASE_DATE_LTE, releaseDateLte);
+ }
+ return this;
+ }
+
+ /**
+ * Only include movies with certifications for a specific country.
+ *
+ * When this value is specified, 'certificationLte' is required.
+ *
+ * A ISO 3166-1 is expected
+ *
+ * @param certificationCountry
+ */
+ public Discover certificationCountry(String certificationCountry) {
+ if (StringUtils.isNotBlank(certificationCountry)) {
+ params.put(PARAM_CERTIFICATION_COUNTRY, certificationCountry);
+ }
+ return this;
+ }
+
+ /**
+ * Only include movies with this certification and lower.
+ *
+ * Expected value is a valid certification for the specified 'certificationCountry'.
+ *
+ * @param certificationLte
+ */
+ public Discover certificationLte(String certificationLte) {
+ if (StringUtils.isNotBlank(certificationLte)) {
+ params.put(PARAM_CERTIFICATION_LTE, certificationLte);
+ }
+ return this;
+ }
+
+ /**
+ * Filter movies to include a specific company.
+ *
+ * Expected value is an integer (the id of a company).
+ *
+ * They can be comma separated to indicate an 'AND' query
+ *
+ * @param withCompanies
+ */
+ public Discover withCompanies(String withCompanies) {
+ if (StringUtils.isNotBlank(withCompanies)) {
+ params.put(PARAM_WITH_COMPANIES, withCompanies);
+ }
+ return this;
+ }
+
+ /**
+ * check the year is between the min and max
+ *
+ * @param year
+ * @return
+ */
+ private boolean checkYear(int year) {
+ return (year >= YEAR_MIN && year <= YEAR_MAX);
+ }
+}
diff --git a/src/main/java/com/omertron/themoviedbapi/tools/ApiUrl.java b/src/main/java/com/omertron/themoviedbapi/tools/ApiUrl.java
index 5977eb352..10ac63cde 100644
--- a/src/main/java/com/omertron/themoviedbapi/tools/ApiUrl.java
+++ b/src/main/java/com/omertron/themoviedbapi/tools/ApiUrl.java
@@ -25,6 +25,7 @@ import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
+import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -66,7 +67,6 @@ public class ApiUrl {
public static final String PARAM_ID = "id=";
public static final String PARAM_LANGUAGE = "language=";
public static final String PARAM_INCLUDE_ALL_MOVIES = "include_all_movies=";
-// public static final String PARAM_MOVIE_ID = "movie_id=";
public static final String PARAM_MOVIE_WATCHLIST = "movie_watchlist=";
public static final String PARAM_PAGE = "page=";
public static final String PARAM_QUERY = "query=";
@@ -113,6 +113,9 @@ public class ApiUrl {
// We have either a queury, or a direct request
if (arguments.containsKey(PARAM_QUERY)) {
// Append the suffix of the API URL
+ if(StringUtils.endsWith(urlString, "/") && submethod.startsWith("/")) {
+ urlString.deleteCharAt(urlString.length()-1);
+ }
urlString.append(submethod);
// Append the key information
@@ -133,6 +136,7 @@ public class ApiUrl {
urlString.append(query);
}
+ // Remove the query from the arguments so it is not added later
arguments.remove(PARAM_QUERY);
} else {
// Append the ID if provided
@@ -142,6 +146,9 @@ public class ApiUrl {
}
// Append the suffix of the API URL
+ if(StringUtils.endsWith(urlString, "/") && submethod.startsWith("/")) {
+ urlString.deleteCharAt(urlString.length()-1);
+ }
urlString.append(submethod);
// Append the key information
@@ -195,6 +202,16 @@ public class ApiUrl {
arguments.put(key, Boolean.toString(value));
}
+ /**
+ * Add arguments individually
+ *
+ * @param key
+ * @param value
+ */
+ public void addArgument(String key, float value) {
+ arguments.put(key, Float.toString(value));
+ }
+
/**
* Clear the arguments
*/
diff --git a/src/test/java/com/omertron/themoviedbapi/TheMovieDbApiTest.java b/src/test/java/com/omertron/themoviedbapi/TheMovieDbApiTest.java
index 7a46df29b..dde2c093b 100644
--- a/src/test/java/com/omertron/themoviedbapi/TheMovieDbApiTest.java
+++ b/src/test/java/com/omertron/themoviedbapi/TheMovieDbApiTest.java
@@ -24,6 +24,7 @@ import com.omertron.themoviedbapi.model.Artwork;
import com.omertron.themoviedbapi.model.Collection;
import com.omertron.themoviedbapi.model.CollectionInfo;
import com.omertron.themoviedbapi.model.Company;
+import com.omertron.themoviedbapi.model.Discover;
import com.omertron.themoviedbapi.model.Genre;
import com.omertron.themoviedbapi.model.JobDepartment;
import com.omertron.themoviedbapi.model.Keyword;
@@ -703,7 +704,7 @@ public class TheMovieDbApiTest {
/**
* Test of getPersonPopular method, of class TheMovieDbApi.
*/
- @Ignore
+ @Test
public void testGetPersonPopular_int() throws Exception {
LOG.info("getPersonPopular");
int page = 0;
@@ -762,4 +763,29 @@ public class TheMovieDbApiTest {
List result = tmdb.getJobs();
assertFalse("No jobs found", result.isEmpty());
}
+
+ /**
+ * Test of getDiscover method, of class TheMovieDbApi.
+ */
+ @Ignore("Not required")
+ public void testGetDiscover_14args() throws Exception {
+ }
+
+ /**
+ * Test of getDiscover method, of class TheMovieDbApi.
+ */
+ @Test
+ public void testGetDiscover_Discover() throws Exception {
+ LOG.info("getDiscover");
+ Discover discover = new Discover();
+ discover.year(2013).language(LANGUAGE_ENGLISH);
+
+ List result = tmdb.getDiscover(discover);
+
+ for(MovieDb m : result) {
+ LOG.info(" {} : {}",m.getTitle(),m.toString());
+ }
+
+ assertFalse("No movies discovered", result.isEmpty());
+ }
}