diff --git a/seasoned_api/src/tmdb/convertTmdbToMovie.js b/seasoned_api/src/tmdb/convertTmdbToMovie.js new file mode 100644 index 0000000..3e702a0 --- /dev/null +++ b/seasoned_api/src/tmdb/convertTmdbToMovie.js @@ -0,0 +1,45 @@ +const Movie = require('src/tmdb/types/movie'); + +const tmdbSwitcher = (tmdbMovie, property) => tmdbMovie[property] + +function convertTmdbToMovie(tmdbMovie) { + const movie = new Movie(tmdbMovie.id, tmdbMovie.title) + movie.overview = tmdbMovie.overview; + movie.rank = tmdbMovie.vote_average; + + if (tmdbMovie.release_date !== undefined) { + movie.release_date = new Date(tmdbMovie.release_date); + movie.year = movie.release_date.getFullYear(); + } + + if (tmdbMovie.poster_path !== undefined) { + movie.poster = tmdbMovie.poster_path; + } + if (tmdbMovie.backdrop_path !== undefined) { + movie.backdrop = tmdbMovie.backdrop_path; + } + + if (tmdbMovie.status !== undefined) { + movie.status = tmdbMovie.status; + } + + if (tmdbMovie.genres !== undefined) { + movie.genres = tmdbMovie.genres.map(genre => genre.name); + } + + if (tmdbMovie.tagline !== undefined) { + movie.tagline = tmdbMovie.tagline; + } + + if (tmdbMovie.runtime !== undefined) { + movie.runtime = tmdbMovie.runtime; + } + + if (tmdbMovie.imdb_id !== undefined) { + movie.imdb_id = tmdbMovie.imdb_id; + } + + return movie; +} + +module.exports = convertTmdbToMovie; diff --git a/seasoned_api/src/tmdb/convertTmdbToPerson.js b/seasoned_api/src/tmdb/convertTmdbToPerson.js new file mode 100644 index 0000000..5821c84 --- /dev/null +++ b/seasoned_api/src/tmdb/convertTmdbToPerson.js @@ -0,0 +1,26 @@ +const Person = require('src/tmdb/types/person'); +const convertTmdbToMovie = require('src/tmdb/convertTmdbToMovie'); + +function convertTmdbToPerson(tmdbPerson) { + const person = new Person(tmdbPerson.id, tmdbPerson.name); + + if (tmdbPerson.profile_path !== undefined) { + person.poster = tmdbPerson.profile_path; + } + + if (tmdbPerson.birthday !== undefined) { + person.birthday = new Date(tmdbPerson.birthday); + } + + if (tmdbPerson.deathday !== undefined) { + person.deathday = tmdbPerson.deathday; + } + + if (tmdbPerson.known_for !== undefined) { + person.known_for = tmdbPerson.known_for.map(convertTmdbToMovie); + } + + return person; +} + +module.exports = convertTmdbToPerson; diff --git a/seasoned_api/src/tmdb/convertTmdbToSeasoned.js b/seasoned_api/src/tmdb/convertTmdbToSeasoned.js index 05502b9..b89fd44 100644 --- a/seasoned_api/src/tmdb/convertTmdbToSeasoned.js +++ b/seasoned_api/src/tmdb/convertTmdbToSeasoned.js @@ -1,5 +1,5 @@ - const TMDB = require('src/media_classes/tmdb'); +const Movie = require('src/types/movie'); function translateYear(tmdbReleaseDate) { return new Date(tmdbReleaseDate).getFullYear(); @@ -14,10 +14,28 @@ function convertType(tmdbType) { return undefined; } -function convertTmdbToSeasoned(tmdb, manualType = undefined) { - const title = tmdb.title || tmdb.name; +function convertTmdbToMovie(tmdb) { + const year = + const movie = new Movie(); + let seasoned = undefined; + + if (tmdb.id && tmdb.title && tmdb.release_date) { + const year = tmdb.release_date.getFullYear(); + seasoned = new Movie(tmdb.id, tmdb.title, year); + } + else if (tmdb.id && tmdb.name && tmdb.first_air_date) { + const year = tmdb.first_air_date.getFullYear(); + seasoned = new Show(tmdb.id, tmdb.name, year); + seasoned.seasons = tmdb.number_of_season; + seasoned.episodes = tmdb.episodes; + return + } +} + + + const title = tmdb.title || tmdb.name; const year = translateYear(tmdb.release_date || tmdb.first_air_date); - const type = manualType || convertType(tmdb.media_type) || 'movie'; + const type = manualType || convertType(tmdb.type) || 'movie'; const id = tmdb.id; const summary = tmdb.overview; diff --git a/seasoned_api/src/tmdb/convertTmdbToShow.js b/seasoned_api/src/tmdb/convertTmdbToShow.js new file mode 100644 index 0000000..594f160 --- /dev/null +++ b/seasoned_api/src/tmdb/convertTmdbToShow.js @@ -0,0 +1,37 @@ +const Show = require('src/tmdb/types/show'); + +function convertTmdbToShow(tmdbShow) { + const show = new Show(tmdbShow.id, tmdbShow.name) + show.seasons = tmdbShow.number_of_seasons; + show.episodes = tmdbShow.number_of_episodes; + show.overview = tmdbShow.overview; + show.rank = tmdbShow.vote_average; + + if (tmdbShow.genres !== undefined) { + show.genres = tmdbShow.genres.map(genre => genre.name); + } + + if (tmdbShow.first_air_date !== undefined) { + show.first_air_date = new Date(tmdbShow.first_air_date); + show.year = show.first_air_date.getFullYear(); + } + + if (tmdbShow.poster_path !== undefined) { + show.poster = tmdbShow.poster_path; + } + if (tmdbShow.backdrop_path !== undefined) { + show.backdrop = tmdbShow.backdrop_path; + } + + if (tmdbShow.status !== undefined) { + show.status = tmdbShow.status; + } + + if (tmdbShow.episode_run_time !== undefined) { + show.runtime = tmdbShow.runtime; + } + + return show; +} + +module.exports = convertTmdbToShow; diff --git a/seasoned_api/src/tmdb/tmdb.js b/seasoned_api/src/tmdb/tmdb.js index 5efe0ed..bfe895c 100644 --- a/seasoned_api/src/tmdb/tmdb.js +++ b/seasoned_api/src/tmdb/tmdb.js @@ -1,5 +1,8 @@ -const moviedb = require('moviedb'); -const convertTmdbToSeasoned = require('src/tmdb/convertTmdbToSeasoned'); +const moviedb = require('km-moviedb'); +const convertTmdbToMovie = require('src/tmdb/convertTmdbToMovie'); +const convertTmdbToShow = require('src/tmdb/convertTmdbToShow'); +const convertTmdbToPerson = require('src/tmdb/convertTmdbToPerson'); + const TMDB_METHODS = { upcoming: { movie: 'miscUpcomingMovies' }, @@ -12,19 +15,24 @@ const TMDB_METHODS = { }; class TMDB { - constructor(cache, apiKey, tmdbLibrary) { - this.cache = cache; - this.tmdbLibrary = tmdbLibrary || moviedb(apiKey); - this.cacheTags = { - search: 'se', - info: 'i', - upcoming: 'u', - discover: 'd', - popular: 'p', - nowplaying: 'n', - similar: 'si', - }; - } + constructor(cache, apiKey, tmdbLibrary) { + this.cache = cache; + this.tmdbLibrary = tmdbLibrary || moviedb(apiKey); + this.cacheTags = { + multiSearch: 'muse', + movieSearch: 'mose', + showSearch: 'sse', + personSearch: 'pse', + movieInfo: 'mi', + showInfo: 'si', + personInfo: 'pi', + upcoming: 'u', + discover: 'd', + popular: 'p', + nowplaying: 'n', + similar: 'sim', + }; + } /** * Retrieve a specific movie by id from TMDB. @@ -68,9 +76,84 @@ class TMDB { .then(response => this.mapResults(response)); } + /** + * Retrieve a specific movie by id from TMDB. + * @param {Number} identifier of the movie you want to retrieve + * @param {String} type filter results by type (default movie). + * @returns {Promise} succeeds if movie was found + */ + movieInfo(identifier) { + const query = { id: identifier }; + const cacheKey = `${this.cacheTags.movieInfo}:${identifier}`; + return Promise.resolve() + .then(() => this.cache.get(cacheKey)) + .catch(() => this.tmdb('movieInfo', query)) + .catch(() => { throw new Error('Could not find a movie with that id.'); }) + .then(response => this.cache.set(cacheKey, response)) + .then((response) => { + try { + return convertTmdbToMovie(response); + } catch (parseError) { + console.error(parseError); + throw new Error('Could not parse movie.'); + } + }); + } + + /** + * Retrieve a specific show by id from TMDB. + * @param {Number} identifier of the show you want to retrieve + * @param {String} type filter results by type (default show). + * @returns {Promise} succeeds if show was found + */ + showInfo(identifier) { + const query = { id: identifier }; + const cacheKey = `${this.cacheTags.showInfo}:${identifier}`; + return Promise.resolve() + .then(() => this.cache.get(cacheKey)) + .catch(() => this.tmdb('tvInfo', query)) + .catch(() => { throw new Error('Could not find a show with that id.'); }) + .then(response => this.cache.set(cacheKey, response)) + .then((response) => { + try { + return convertTmdbToShow(response); + } catch (parseError) { + console.error(parseError); + throw new Error('Could not parse show.'); + } + }); + } + + /** + * Retrieve a specific person id from TMDB. + * @param {Number} identifier of the person you want to retrieve + * @param {String} type filter results by type (default person). + * @returns {Promise} succeeds if person was found + */ + personInfo(identifier) { + const query = { id: identifier }; + const cacheKey = `${this.cacheTags.personInfo}:${identifier}`; + return Promise.resolve() + .then(() => this.cache.get(cacheKey)) + .catch(() => this.tmdb('personInfo', query)) + .catch(() => { throw new Error('Could not find a person with that id.'); }) + .then(response => this.cache.set(cacheKey, response)) + .then((response) => { + try { + return convertTmdbToPerson(response); + } catch (parseError) { + console.error(parseError); + throw new Error('Could not parse person.'); + } + }); + } + + + + multiSearch(search_query, page=1) { const query = { query: search_query, page: page }; - const cacheKey = `${this.cacheTags.multiSeach}:${page}:${search_query}`; + const cacheKey = `${this.cacheTags.multiSearch}:${page}:${search_query}`; return Promise.resolve() .then(() => this.cache.get(cacheKey)) .catch(() => this.tmdb('searchMulti', query)) @@ -79,6 +162,96 @@ class TMDB { .then(response => this.mapResults(response)); } + /** + * Retrive movie search results from TMDB. + * @param {String} text query you want to search for + * @param {Number} page representing pagination of results + * @returns {Promise} dict with query results, current page and total_pages + */ + movieSearch(query, page=1) { + const tmdbquery = { query: query, page: page }; + const cacheKey = `${this.cacheTags.movieSearch}:${page}:${query}`; + return Promise.resolve() + .then(() => this.cache.get(cacheKey)) + .catch(() => this.tmdb('searchMovie', tmdbquery)) + .catch(() => { throw new Error('Could not complete movie search to tmdb'); }) + .then(response => this.cache.set(cacheKey, response)) + .then((response) => { + try { + return { + results: response.results.map(convertTmdbToMovie), + page: page, + total_results: response.total_results, + total_pages: response.total_pages + } + } catch (parseError) { + console.error(`ParseError: ${parseError}`); + throw new Error('Could not parse movie search results.') + } + }); + } + + /** + * Retrive show search results from TMDB. + * @param {String} text query you want to search for + * @param {Number} page representing pagination of results + * @returns {Promise} dict with query results, current page and total_pages + */ + showSearch(query, page=1) { + const tmdbquery = { query: query, page: page }; + const cacheKey = `${this.cacheTags.showSearch}:${page}:${query}`; + return Promise.resolve() + .then(() => this.cache.get(cacheKey)) + .catch(() => this.tmdb('searchTv', tmdbquery)) + .catch(() => { throw new Error('Could not complete show search to tmdb'); }) + .then(response => this.cache.set(cacheKey, response)) + .then((response) => { + try { + return { + results: response.results.map(convertTmdbToShow), + page: page, + total_results: response.total_results, + total_pages: response.total_pages + } + } catch (parseError) { + console.error(`ParseError: ${parseError}`); + throw new Error('Could not parse show search results.') + } + }); + } + + /** + * Retrive person search results from TMDB. + * @param {String} text query you want to search for + * @param {Number} page representing pagination of results + * @returns {Promise} dict with query results, current page and total_pages + */ + personSearch(query, page=1) { + const tmdbquery = { query: query, page: page }; + const cacheKey = `${this.cacheTags.personSearch}:${page}:${query}`; + return Promise.resolve() + .then(() => this.cache.get(cacheKey)) + .catch(() => this.tmdb('searchPerson', tmdbquery)) + .catch(() => { throw new Error('Could not complete person search to tmdb'); }) + .then(response => this.cache.set(cacheKey, response)) + .then((response) => { + try { + return { + results: response.results.map(convertTmdbToPerson), + page: page, + total_results: response.total_results, + total_pages: response.total_pages + } + } catch (parseError) { + console.error(`ParseError: ${parseError}`); + throw new Error('Could not parse show search results.') + } + }); + } + + + + /** * Fetches a given list from tmdb. * @param {String} listName Name of list @@ -98,28 +271,41 @@ class TMDB { .then(response => this.mapResults(response, type)); } - /** + popular(type='movie', page=1) { + const query = { type: type, page: page }; + const cacheKey = `${this.cacheTags.popular}:${type}:${page}`; + return Promise.resolve() + .then(() => this.cache.get(cacheKey)) + .catch(() => this.tmdb('miscPopularMovies', query)) + .catch((e) => { throw new Error(`Error fetching popular list of type ${type} : ${e}`) }) + .then(response => this.cache.set(cacheKey, response)) + .then(response => this.mapResults(response, type)); + } + + /** * Maps our response from tmdb api to a movie/show object. * @param {String} response from tmdb. * @param {String} The type declared in listSearch. * @returns {Promise} dict with tmdb results, mapped as movie/show objects. */ - mapResults(response, type) { - console.log(response.page); - return Promise.resolve() - .then(() => { - const mappedResults = response.results.filter((element) => { - return (element.media_type === 'movie' || element.media_type === 'tv' || element.media_type === undefined); - }).map((element) => convertTmdbToSeasoned(element, type)); - return { - results: mappedResults, - page: response.page, - total_pages: response.total_pages, - total_results: response.total_results - } - }) - .catch((error) => { throw new Error(error); }); - } + mapResults(response, type) { + let results = response.results.map((result) => { + if (result.media_type === 'movie') { + return convertTmdbToMovie(result); + } else if (result.media_type === 'tv') { + return convertTmdbToShow(result); + } else if (result.media_type === 'person') { + return convertTmdbToPerson(result); + } + }) + + return { + results: results, + page: response.page, + total_results: response.total_results, + total_pages: response.total_pages + } + } /** * Wraps moviedb library to support Promises. diff --git a/seasoned_api/src/tmdb/types/movie.js b/seasoned_api/src/tmdb/types/movie.js new file mode 100644 index 0000000..1d443d2 --- /dev/null +++ b/seasoned_api/src/tmdb/types/movie.js @@ -0,0 +1,20 @@ +class Movie { + constructor(id, title, year=null, overview=null, poster=null, backdrop=null, rank=null, genres=null, status=null, + tagline=null, runtime=null, imdb_id=null) { + this.id = id; + this.title = title; + this.year = year; + this.overview = overview; + this.poster = poster; + this.backdrop = backdrop; + this.rank = rank; + this.genres = genres; + this.status = status; + this.tagline = tagline; + this.runtime = runtime; + this.imdb_id = imdb_id; + this.type = 'movie'; + } +} + +module.exports = Movie; diff --git a/seasoned_api/src/tmdb/types/person.js b/seasoned_api/src/tmdb/types/person.js new file mode 100644 index 0000000..4c469fb --- /dev/null +++ b/seasoned_api/src/tmdb/types/person.js @@ -0,0 +1,13 @@ +class Person { + constructor(id, name, poster=null, birthday=null, deathday=null, known_for=null) { + this.id = id; + this.name = name; + this.poster = poster; + this.birthday = birthday; + this.deathday = deathday; + this.known_for = known_for; + this.type = 'person'; + } +} + +module.exports = Person; diff --git a/seasoned_api/src/tmdb/types/show.js b/seasoned_api/src/tmdb/types/show.js new file mode 100644 index 0000000..5aaf8d1 --- /dev/null +++ b/seasoned_api/src/tmdb/types/show.js @@ -0,0 +1,20 @@ +class Show { + constructor(id, title, year=null, seasons=null, episodes=null, overview=null, rank=null, genres=null, + poster=null, backdrop=null, status=null, runtime=null) { + this.id = id; + this.title = title; + this.year = year; + this.seasons = seasons; + this.episodes = episodes; + this.overview = overview; + this.rank = rank; + this.genres = genres; + this.poster = poster; + this.backdrop = backdrop; + this.status = status; + this.runtime = runtime; + this.type = 'show'; + } +} + +module.exports = Show; diff --git a/seasoned_api/src/webserver/controllers/info/movieInfo.js b/seasoned_api/src/webserver/controllers/info/movieInfo.js index 5afa547..3607285 100644 --- a/seasoned_api/src/webserver/controllers/info/movieInfo.js +++ b/seasoned_api/src/webserver/controllers/info/movieInfo.js @@ -1,8 +1,10 @@ const configuration = require('src/config/configuration').getInstance(); const Cache = require('src/tmdb/cache'); const TMDB = require('src/tmdb/tmdb'); +const Plex = require('src/plex/plex'); const cache = new Cache(); const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey')); +const plex = new Plex(configuration.get('plex', 'ip')); /** * Controller: Retrieve information for a movie @@ -10,10 +12,10 @@ const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey')); * @param {Response} res * @returns {Callback} */ - function movieInfoController(req, res) { const movieId = req.params.id; tmdb.movieInfo(movieId) + .then((movie) => plex.existsInPlex(movie)) .then((movie) => { res.send(movie); }).catch((error) => { diff --git a/seasoned_api/src/webserver/controllers/info/showInfo.js b/seasoned_api/src/webserver/controllers/info/showInfo.js index 5e1e33d..f345855 100644 --- a/seasoned_api/src/webserver/controllers/info/showInfo.js +++ b/seasoned_api/src/webserver/controllers/info/showInfo.js @@ -1,8 +1,10 @@ const configuration = require('src/config/configuration').getInstance(); const Cache = require('src/tmdb/cache'); const TMDB = require('src/tmdb/tmdb'); +const Plex = require('src/plex/plex'); const cache = new Cache(); const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey')); +const plex = new Plex(configuration.get('plex', 'ip')); /** * Controller: Retrieve information for a show @@ -14,6 +16,7 @@ const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey')); function showInfoController(req, res) { const showId = req.params.id; tmdb.showInfo(showId) + .then((show) => plex.existsInPlex(show)) .then((show) => { res.send(show); }).catch((error) => {