/*
* Copyright (c) 2004-2016 Matthew Altman & Stuart Boston
*
* This file is part of TheTVDB API.
*
* TheTVDB 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, either version 3 of the License, or
* any later version.
*
* TheTVDB API is distributed in the hope that it will be useful,
* 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 TheTVDB API. If not, see <http://www.gnu.org/licenses/>.
*
*/
package com.omertron.thetvdbapi;
import com.omertron.thetvdbapi.model.Actor;
import com.omertron.thetvdbapi.model.Banners;
import com.omertron.thetvdbapi.model.Episode;
import com.omertron.thetvdbapi.model.Language;
import com.omertron.thetvdbapi.model.Series;
import com.omertron.thetvdbapi.model.TVDBUpdates;
import com.omertron.thetvdbapi.tools.DOMHelper;
import com.omertron.thetvdbapi.tools.TvdbParser;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.http.client.HttpClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.yamj.api.common.http.SimpleHttpClientBuilder;
/**
* @author altman.matthew
* @author stuart.boston
*/
public class TheTVDBApi {
private static final Logger LOG = LoggerFactory.getLogger(TheTVDBApi.class);
private String apiKey = null;
private HttpClient httpClient;
private static final String BASE_URL = "http://thetvdb.com/api/";
private static final String XML_EXTENSION = ".xml";
private static final String SERIES_URL = "/series/";
private static final String ALL_URL = "/all/";
private static final String WEEKLY_UPDATES_URL = "/updates/updates_week.xml";
private static final String URL = "URL: {}";
/**
* Create an API object with the passed API Key
*
* @param apiKey Must be valid
*/
public TheTVDBApi(String apiKey) {
// No HttpClient passed, so use a default
this(apiKey, new SimpleHttpClientBuilder().build());
}
/**
* Create an API object with the passed API key and using the supplied
* HttpClient
*
* @param apiKey Must not be null or empty
* @param httpClient
*/
public TheTVDBApi(String apiKey, HttpClient httpClient) {
if (StringUtils.isBlank(apiKey)) {
return;
}
this.apiKey = apiKey;
this.httpClient = httpClient;
DOMHelper.setHttpClient(this.httpClient);
}
/**
* Get the series information
*
* @param id
* @param language
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public Series getSeries(String id, String language) throws TvDbException {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(BASE_URL)
.append(apiKey)
.append(SERIES_URL)
.append(id)
.append("/");
if (StringUtils.isNotBlank(language)) {
urlBuilder.append(language).append(XML_EXTENSION);
}
LOG.trace(URL, urlBuilder.toString());
List<Series> seriesList = TvdbParser.getSeriesList(urlBuilder.toString());
if (seriesList.isEmpty()) {
return null;
} else {
return seriesList.get(0);
}
}
/**
* Get all the episodes for a series. Note: This could be a lot of records
*
* @param id
* @param language
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public List<Episode> getAllEpisodes(String id, String language) throws TvDbException {
List<Episode> episodeList = Collections.emptyList();
if (isValidNumber(id)) {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(BASE_URL)
.append(apiKey)
.append(SERIES_URL)
.append(id)
.append(ALL_URL);
if (StringUtils.isNotBlank(language)) {
urlBuilder.append(language).append(XML_EXTENSION);
}
LOG.trace(URL, urlBuilder.toString());
episodeList = TvdbParser.getAllEpisodes(urlBuilder.toString(), -1);
}
return episodeList;
}
/**
* Get all the episodes from a specific season for a series. Note: This
* could be a lot of records
*
* @param id
* @param season
* @param language
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public List<Episode> getSeasonEpisodes(String id, int season, String language) throws TvDbException {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(BASE_URL)
.append(apiKey)
.append(SERIES_URL)
.append(id)
.append(ALL_URL);
if (StringUtils.isNotBlank(language)) {
urlBuilder.append(language).append(XML_EXTENSION);
}
LOG.trace(URL, urlBuilder.toString());
return TvdbParser.getAllEpisodes(urlBuilder.toString(), season);
}
/**
* Get a specific episode's information
*
* @param seriesId
* @param seasonNbr
* @param episodeNbr
* @param language
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public Episode getEpisode(String seriesId, int seasonNbr, int episodeNbr, String language) throws TvDbException {
return getTVEpisode(seriesId, seasonNbr, episodeNbr, language, "/default/");
}
/**
* Get a specific DVD episode's information
*
* @param seriesId
* @param seasonNbr
* @param episodeNbr
* @param language
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public Episode getDVDEpisode(String seriesId, int seasonNbr, int episodeNbr, String language) throws TvDbException {
return getTVEpisode(seriesId, seasonNbr, episodeNbr, language, "/dvd/");
}
/**
* Generic function to get either the standard TV episode list or the DVD
* list
*
* @param seriesId
* @param seasonNbr
* @param episodeNbr
* @param language
* @param episodeType
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
private Episode getTVEpisode(String seriesId, int seasonNbr, int episodeNbr, String language, String episodeType) throws TvDbException {
if (!isValidNumber(seriesId) || !isValidNumber(seasonNbr) || !isValidNumber(episodeNbr)) {
// Invalid number passed
return new Episode();
}
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(BASE_URL)
.append(apiKey)
.append(SERIES_URL)
.append(seriesId)
.append(episodeType)
.append(seasonNbr)
.append("/")
.append(episodeNbr)
.append("/");
if (StringUtils.isNotBlank(language)) {
urlBuilder.append(language).append(XML_EXTENSION);
}
LOG.trace(URL, urlBuilder.toString());
return TvdbParser.getEpisode(urlBuilder.toString());
}
/**
* Get a specific absolute episode's information
*
* @param seriesId
* @param episodeNbr
* @param language
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public Episode getAbsoluteEpisode(String seriesId, int episodeNbr, String language) throws TvDbException {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(BASE_URL)
.append(apiKey)
.append(SERIES_URL)
.append(seriesId)
.append("/absolute/")
.append(episodeNbr)
.append("/");
if (StringUtils.isNotBlank(language)) {
urlBuilder.append(language).append(XML_EXTENSION);
}
LOG.trace(URL, urlBuilder.toString());
return TvdbParser.getEpisode(urlBuilder.toString());
}
/**
* Get a list of banners for the series id
*
* @param id
* @param seasonNbr
* @param language
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public String getSeasonYear(String id, int seasonNbr, String language) throws TvDbException {
String year = null;
Episode episode = getEpisode(id, seasonNbr, 1, language);
if (episode != null && StringUtils.isNotBlank(episode.getFirstAired())) {
Date date;
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
date = dateFormat.parse(episode.getFirstAired());
} catch (ParseException ex) {
LOG.trace("Failed to transform date: {}", episode.getFirstAired(), ex);
date = null;
}
if (date != null) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
year = String.valueOf(cal.get(Calendar.YEAR));
}
}
return year;
}
/**
* Get a list of banners for the series id
*
* @param seriesId
* @return
* @throws TvDbException
*/
public Banners getBanners(String seriesId) throws TvDbException {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(BASE_URL)
.append(apiKey)
.append(SERIES_URL)
.append(seriesId)
.append("/banners.xml");
LOG.trace(URL, urlBuilder.toString());
Banners b = TvdbParser.getBanners(urlBuilder.toString());
if (b != null) {
b.setSeriesId(NumberUtils.toInt(seriesId));
}
return b;
}
/**
* Get a list of actors from the series id
*
* @param seriesId
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public List<Actor> getActors(String seriesId) throws TvDbException {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(BASE_URL)
.append(apiKey)
.append(SERIES_URL)
.append(seriesId)
.append("/actors.xml");
LOG.trace(URL, urlBuilder.toString());
return TvdbParser.getActors(urlBuilder.toString());
}
/**
* Get a list of series using a title and language
*
* @param title
* @param language
* @return
* @throws TvDbException
*/
public List<Series> searchSeries(String title, String language) throws TvDbException {
StringBuilder urlBuilder = new StringBuilder();
try {
urlBuilder.append(BASE_URL)
.append("GetSeries.php?seriesname=")
.append(URLEncoder.encode(title, "UTF-8"));
if (StringUtils.isNotBlank(language)) {
urlBuilder.append("&language=").append(language);
}
} catch (UnsupportedEncodingException ex) {
LOG.trace("Failed to encode title: {}", title, ex);
// Try and use the raw title
urlBuilder.append(title);
}
LOG.trace(URL, urlBuilder.toString());
return TvdbParser.getSeriesList(urlBuilder.toString());
}
/**
* Get information for a specific episode
*
* @param episodeId
* @param language
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public Episode getEpisodeById(String episodeId, String language) throws TvDbException {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(BASE_URL)
.append(apiKey)
.append("/episodes/")
.append(episodeId)
.append("/");
if (StringUtils.isNotBlank(language)) {
urlBuilder.append(language);
urlBuilder.append(XML_EXTENSION);
}
LOG.trace(URL, urlBuilder.toString());
return TvdbParser.getEpisode(urlBuilder.toString());
}
/**
* Get the weekly updates
*
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public TVDBUpdates getWeeklyUpdates() throws TvDbException {
return getWeeklyUpdates(0);
}
/**
* Get the weekly updates limited by Series ID
*
* @param seriesId 0 (zero) gets all series
* @return
* @throws com.omertron.thetvdbapi.TvDbException
*/
public TVDBUpdates getWeeklyUpdates(int seriesId) throws TvDbException {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(BASE_URL)
.append(apiKey)
.append(WEEKLY_UPDATES_URL);
LOG.trace(URL, urlBuilder.toString());
return TvdbParser.getUpdates(urlBuilder.toString(), seriesId);
}
/**
* Gets the languages.
*
* @return the languages
* @throws com.omertron.thetvdbapi.TvDbException
*/
public List<Language> getLanguages() throws TvDbException {
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(BASE_URL)
.append(apiKey)
.append("/languages")
.append(XML_EXTENSION);
LOG.trace(URL, urlBuilder.toString());
return TvdbParser.getLanguages(urlBuilder.toString());
}
/**
* Convert a string to a number and then validate it
*
* @param number
* @return
*/
private boolean isValidNumber(String number) {
return isValidNumber(NumberUtils.toInt(number, 0));
}
/**
* Validate the number, i.e. ensure it is greater than zero
*
* @param number
* @return
*/
private boolean isValidNumber(int number) {
return number >= 0;
}
}