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()); + } }