package com.miz.apis.tmdb;
import android.content.Context;
import android.text.TextUtils;
import com.miz.abstractclasses.TvShowApiService;
import com.miz.apis.thetvdb.Episode;
import com.miz.apis.thetvdb.Season;
import com.miz.apis.thetvdb.TvShow;
import com.miz.functions.Actor;
import com.miz.functions.MizLib;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class TMDbTvShowService extends TvShowApiService {
private static TMDbTvShowService mService;
private final String mTmdbApiKey;
private final Context mContext;
public static TMDbTvShowService getInstance(Context context) {
if (mService == null)
mService = new TMDbTvShowService(context);
return mService;
}
private TMDbTvShowService(Context context) {
mContext = context;
mTmdbApiKey = MizLib.getTmdbApiKey(mContext);
}
@Override
public List<TvShow> search(String query, String language) {
language = getLanguage(language);
String serviceUrl = "";
try {
serviceUrl = "https://api.themoviedb.org/3/search/tv?query=" + URLEncoder.encode(query, "utf-8") + "&language=" + language + "&api_key=" + mTmdbApiKey;
} catch (UnsupportedEncodingException e) {}
return getListFromUrl(serviceUrl);
}
@Override
public List<TvShow> search(String query, String year, String language) {
language = getLanguage(language);
String serviceUrl = "";
try {
serviceUrl = "https://api.themoviedb.org/3/search/tv?query=" + URLEncoder.encode(query, "utf-8") + "&language=" + language + "&first_air_date_year=" + year + "&api_key=" + mTmdbApiKey;
} catch (UnsupportedEncodingException e) {}
return getListFromUrl(serviceUrl);
}
@Override
public List<TvShow> searchByImdbId(String imdbId, String language) {
language = getLanguage(language);
ArrayList<TvShow> results = new ArrayList<TvShow>();
try {
JSONObject jObject = MizLib.getJSONObject(mContext, "https://api.themoviedb.org/3/find/" + imdbId + "?language=" + language + "&external_source=imdb_id&api_key=" + mTmdbApiKey);
JSONArray array = jObject.getJSONArray("tv_results");
String baseUrl = MizLib.getTmdbImageBaseUrl(mContext);
String imageSizeUrl = MizLib.getImageUrlSize(mContext);
for (int i = 0; i < array.length(); i++) {
TvShow show = new TvShow();
show.setTitle(array.getJSONObject(i).getString("name"));
show.setOriginalTitle(array.getJSONObject(i).getString("original_name"));
show.setFirstAired(array.getJSONObject(i).getString("first_air_date"));
show.setDescription(""); // TMDb doesn't support descriptions in search results
show.setRating(String.valueOf(array.getJSONObject(i).getDouble("vote_average")));
show.setId(String.valueOf(array.getJSONObject(i).getInt("id")));
show.setCoverUrl(baseUrl + imageSizeUrl + array.getJSONObject(i).getString("poster_path"));
results.add(show);
}
} catch (JSONException e) {}
return results;
}
@Override
public TvShow get(String id, String language) {
language = getLanguage(language);
TvShow show = new TvShow();
show.setId(id);
String baseUrl = MizLib.getTmdbImageBaseUrl(mContext);
JSONObject jObject = MizLib.getJSONObject(mContext, "https://api.themoviedb.org/3/tv/" + id + "?api_key=" + mTmdbApiKey + "&language=" + language + "&append_to_response=credits,images,external_ids");
// Set title
show.setTitle(MizLib.getStringFromJSONObject(jObject, "name", ""));
// Set description
show.setDescription(MizLib.getStringFromJSONObject(jObject, "overview", ""));
if (!language.equals("en")) { // This is a localized search - let's fill in the blanks
JSONObject englishResults = MizLib.getJSONObject(mContext, "https://api.themoviedb.org/3/tv/" + id + "?api_key=" + mTmdbApiKey + "&language=en");
if (TextUtils.isEmpty(show.getTitle()))
show.setTitle(MizLib.getStringFromJSONObject(englishResults, "name", ""));
if (TextUtils.isEmpty(show.getDescription()))
show.setDescription(MizLib.getStringFromJSONObject(englishResults, "overview", ""));
}
// Set actors
try {
StringBuilder actors = new StringBuilder();
JSONArray array = jObject.getJSONObject("credits").getJSONArray("cast");
for (int i = 0; i < array.length(); i++) {
actors.append(array.getJSONObject(i).getString("name"));
actors.append("|");
}
show.setActors(actors.toString());
} catch (Exception e) {}
// Set genres
try {
String genres = "";
for (int i = 0; i < jObject.getJSONArray("genres").length(); i++)
genres = genres + jObject.getJSONArray("genres").getJSONObject(i).getString("name") + ", ";
show.setGenres(genres.substring(0, genres.length() - 2));
} catch (Exception e) {}
// Set rating
show.setRating(MizLib.getStringFromJSONObject(jObject, "vote_average", "0.0"));
// Set cover path
show.setCoverUrl(baseUrl + MizLib.getImageUrlSize(mContext) + MizLib.getStringFromJSONObject(jObject, "poster_path", ""));
// Set backdrop path
show.setBackdropUrl(baseUrl + MizLib.getBackdropUrlSize(mContext) + MizLib.getStringFromJSONObject(jObject, "backdrop_path", ""));
// Set certification - not available with TMDb
show.setCertification("");
try {
// Set runtime
show.setRuntime(String.valueOf(jObject.getJSONArray("episode_run_time").getInt(0)));
} catch (JSONException e) {}
// Set first aired date
show.setFirstAired(MizLib.getStringFromJSONObject(jObject, "first_air_date", ""));
try {
// Set IMDb ID
show.setIMDbId(jObject.getJSONObject("external_ids").getString("imdb_id"));
} catch (JSONException e) {}
// Seasons
try {
JSONArray seasons = jObject.getJSONArray("seasons");
for (int i = 0; i < seasons.length(); i++) {
Season s = new Season();
s.setSeason(seasons.getJSONObject(i).getInt("season_number"));
s.setCoverPath(baseUrl + MizLib.getImageUrlSize(mContext) + MizLib.getStringFromJSONObject(seasons.getJSONObject(i), "poster_path", ""));
show.addSeason(s);
}
} catch (JSONException e) {}
// Episode details
for (Season s : show.getSeasons()) {
jObject = MizLib.getJSONObject(mContext, "https://api.themoviedb.org/3/tv/" + id + "/season/" + s.getSeason() + "?api_key=" + mTmdbApiKey);
try {
JSONArray episodes = jObject.getJSONArray("episodes");
for (int i = 0; i < episodes.length(); i++) {
Episode ep = new Episode();
ep.setSeason(s.getSeason());
ep.setEpisode(episodes.getJSONObject(i).getInt("episode_number"));
ep.setTitle(episodes.getJSONObject(i).getString("name"));
ep.setAirdate(episodes.getJSONObject(i).getString("air_date"));
ep.setDescription(episodes.getJSONObject(i).getString("overview"));
ep.setRating(MizLib.getStringFromJSONObject(episodes.getJSONObject(i), "vote_average", "0.0"));
try {
// This is quite nasty... An HTTP call for each episode, yuck!
// Sadly, this is needed in order to get proper screenshot URLS
// and info about director, writer and guest stars
JSONObject episodeCall = MizLib.getJSONObject(mContext, "https://api.themoviedb.org/3/tv/" + id + "/season/" + s.getSeason() + "/episode/" + ep.getEpisode() + "?api_key=" + mTmdbApiKey + "&append_to_response=credits,images");
// Screenshot URL in the correct size
JSONArray images = episodeCall.getJSONObject("images").getJSONArray("stills");
if (images.length() > 0) {
JSONObject firstImage = images.getJSONObject(0);
int width = firstImage.getInt("width");
if (width < 500) {
ep.setScreenshotUrl(baseUrl + "original" + MizLib.getStringFromJSONObject(firstImage, "file_path", ""));
} else {
ep.setScreenshotUrl(baseUrl + MizLib.getBackdropThumbUrlSize(mContext) + MizLib.getStringFromJSONObject(firstImage, "file_path", ""));
}
}
try {
// Guest stars
StringBuilder actors = new StringBuilder();
JSONArray guest_stars = episodeCall.getJSONObject("credits").getJSONArray("guest_stars");
for (int j = 0; j < guest_stars.length(); j++) {
actors.append(guest_stars.getJSONObject(j).getString("name"));
actors.append("|");
}
ep.setGueststars(actors.toString());
} catch (Exception e) {}
try {
// Crew information
StringBuilder director = new StringBuilder(), writer = new StringBuilder();
JSONArray crew = episodeCall.getJSONObject("credits").getJSONArray("crew");
for (int j = 0; j < crew.length(); j++) {
if (crew.getJSONObject(j).getString("job").equals("Director")) {
director.append(crew.getJSONObject(j).getString("name"));
director.append("|");
} else if (crew.getJSONObject(j).getString("job").equals("Writer")) {
writer.append(crew.getJSONObject(j).getString("name"));
writer.append("|");
}
}
ep.setDirector(director.toString());
ep.setWriter(writer.toString());
} catch (Exception e) {}
} catch (Exception e) {}
show.addEpisode(ep);
}
} catch (JSONException e) {}
}
return show;
}
private ArrayList<TvShow> getListFromUrl(String serviceUrl) {
ArrayList<TvShow> results = new ArrayList<TvShow>();
try {
JSONObject jObject = MizLib.getJSONObject(mContext, serviceUrl);
JSONArray array = jObject.getJSONArray("results");
String baseUrl = MizLib.getTmdbImageBaseUrl(mContext);
String imageSizeUrl = MizLib.getImageUrlSize(mContext);
for (int i = 0; i < array.length(); i++) {
TvShow show = new TvShow();
show.setTitle(array.getJSONObject(i).getString("name"));
show.setOriginalTitle(array.getJSONObject(i).getString("original_name"));
show.setFirstAired(array.getJSONObject(i).getString("first_air_date"));
show.setDescription(""); // TMDb doesn't support descriptions in search results
show.setRating(String.valueOf(array.getJSONObject(i).getDouble("vote_average")));
show.setId(String.valueOf(array.getJSONObject(i).getInt("id")));
show.setCoverUrl(baseUrl + imageSizeUrl + array.getJSONObject(i).getString("poster_path"));
results.add(show);
}
} catch (JSONException e) {}
return results;
}
@Override
public List<String> getCovers(String id) {
ArrayList<String> covers = new ArrayList<String>();
String baseUrl = MizLib.getTmdbImageBaseUrl(mContext);
try {
JSONObject jObject = MizLib.getJSONObject(mContext, "https://api.themoviedb.org/3/tv/" + id + "/images" + "?api_key=" + mTmdbApiKey);
JSONArray jArray = jObject.getJSONArray("posters");
for (int i = 0; i < jArray.length(); i++) {
covers.add(baseUrl + MizLib.getImageUrlSize(mContext) + MizLib.getStringFromJSONObject(jArray.getJSONObject(i), "file_path", ""));
}
} catch (JSONException e) {}
return covers;
}
@Override
public List<String> getBackdrops(String id) {
ArrayList<String> covers = new ArrayList<String>();
String baseUrl = MizLib.getTmdbImageBaseUrl(mContext);
try {
JSONObject jObject = MizLib.getJSONObject(mContext, "https://api.themoviedb.org/3/tv/" + id + "/images" + "?api_key=" + mTmdbApiKey);
JSONArray jArray = jObject.getJSONArray("backdrops");
for (int i = 0; i < jArray.length(); i++) {
covers.add(baseUrl + MizLib.getBackdropThumbUrlSize(mContext) + MizLib.getStringFromJSONObject(jArray.getJSONObject(i), "file_path", ""));
}
} catch (JSONException e) {}
return covers;
}
/**
* Get the language code or a default one if
* the supplied one is empty or {@link null}.
* @param language
* @return Language code
*/
@Override
public String getLanguage(String language) {
if (TextUtils.isEmpty(language))
language = "en";
return language;
}
@Override
public List<TvShow> searchNgram(String query, String language) {
language = getLanguage(language);
String serviceUrl = "";
try {
serviceUrl = "https://api.themoviedb.org/3/search/tv?query=" + URLEncoder.encode(query, "utf-8") + "&language=" + language + "&search_type=ngram&api_key=" + mTmdbApiKey;
} catch (UnsupportedEncodingException e) {}
return getListFromUrl(serviceUrl);
}
@Override
public List<Actor> getActors(String id) {
ArrayList<Actor> results = new ArrayList<Actor>();
String baseUrl = MizLib.getTmdbImageBaseUrl(mContext);
try {
JSONObject jObject = MizLib.getJSONObject(mContext, "https://api.themoviedb.org/3/tv/" + id + "/credits?api_key=" + mTmdbApiKey);
JSONArray jArray = jObject.getJSONArray("cast");
Set<String> actorIds = new HashSet<String>();
for (int i = 0; i < jArray.length(); i++) {
if (!actorIds.contains(jArray.getJSONObject(i).getString("id"))) {
actorIds.add(jArray.getJSONObject(i).getString("id"));
results.add(new Actor(
jArray.getJSONObject(i).getString("name"),
jArray.getJSONObject(i).getString("character"),
jArray.getJSONObject(i).getString("id"),
baseUrl + MizLib.getActorUrlSize(mContext) + jArray.getJSONObject(i).getString("profile_path")));
}
}
} catch (Exception ignored) {}
return results;
}
}