diff --git a/client/app/components/MovieObject.jsx b/client/app/components/MovieObject.jsx index e2c87aa..1349f68 100644 --- a/client/app/components/MovieObject.jsx +++ b/client/app/components/MovieObject.jsx @@ -1,102 +1,32 @@ import React from 'react'; -import glamorous from 'glamorous'; // StyleComponents -import mediaResultItem from './styledComponents/mediaResultItem.jsx'; +import movieStyle from './styles/movieObjectStyle.jsx'; class MovieObject { constructor(object) { this.id = object.id; this.title = object.title; this.year = object.year; + this.type = object.type; // Check if object.poster != undefined this.poster = object.poster; this.matchedInPlex = object.matchedInPlex; - this.overview = object.overview; + this.summary = object.summary; } requestExisting(movie) { console.log('Exists', movie); } - requestMovie(id) { - fetch('https://apollo.kevinmidboe.com/api/v1/plex/request/' + id, { + requestMovie() { + // fetch('https://apollo.kevinmidboe.com/api/v1/plex/request/' + id, { + fetch('http://localhost:31459/api/v1/plex/request/' + this.id + '?type='+this.type, { method: 'POST' }); } getElement() { - // TODO move this to separate files. - var resultItem = { - maxWidth: '95%', - margin: '0 auto', - minHeight: '230px' - } - var movie_content = { - marginLeft: '15px' - } - var resultTitle = { - color: 'black', - fontSize: '2em', - } - - var resultPoster = { - float: 'left', - zIndex: '3', - position: 'relative', - marginRight: '30px' - } - - var resultPosterImg = { - border: '2px none', - borderRadius: '2px', - width: '150px' - } - - var buttons = { - paddingTop: '20px' - } - - var requestButton = { - color: '#e9a131', - marginRight: '10px', - background: 'white', - border: '#e9a131 2px solid', - borderRadius: '4px', - textAlign: 'center', - padding: '10px', - minWidth: '100px', - float: 'left', - fontSize: '13px', - fontWeight: '800', - cursor: 'pointer' - } - - var tmdbButton = { - color: '#00d17c', - marginRight: '10px', - background: 'white', - border: '#00d17c 2px solid', - borderRadius: '4px', - textAlign: 'center', - padding: '10px', - minWidth: '100px', - float: 'left', - fontSize: '13px', - fontWeight: '800', - cursor: 'pointer' - } - - var row = { - width: '100%' - } - - var itemDivider = { - width: '90%', - borderBottom: '1px solid grey', - margin: '2rem auto' - } - // TODO set the poster image async by updating the dom after this is returned if (this.poster == null || this.poster == undefined) { var posterPath = 'https://openclipart.org/image/2400px/svg_to_png/211479/Simple-Image-Not-Found-Icon.png' @@ -106,10 +36,10 @@ class MovieObject { var foundInPlex; if (this.matchedInPlex) { foundInPlex = ; + style={movieStyle.requestButton}>Request Anyway; } else { - foundInPlex = ; + foundInPlex = ; } var themoviedbLink = 'https://www.themoviedb.org/movie/' + this.id @@ -117,27 +47,29 @@ class MovieObject { return (
-
-
- +
+
+
- {this.title} ({this.year}) + {this.title} ({this.year})

- {this.overview} + {this.summary}

-
+
{foundInPlex} - + + +
-
-
+
+
) diff --git a/client/app/components/SearchRequest.jsx b/client/app/components/SearchRequest.jsx index 32c3be9..e32d4da 100644 --- a/client/app/components/SearchRequest.jsx +++ b/client/app/components/SearchRequest.jsx @@ -2,37 +2,67 @@ import React from 'react'; import MovieObject from './MovieObject.jsx'; -// TODO add option for searching multi, movies or tv shows +// StyleComponents +import searchStyle from './styles/searchRequestStyle.jsx'; +// TODO add option for searching multi, movies or tv shows class SearchRequest extends React.Component { - constructor(props){ + constructor(props){ super(props) // Constructor with states holding the search query and the element of reponse. this.state = { searchQuery: '', responseMovieList: null, movieFilter: true, - tvshowFilter: false + tvshowFilter: false, + page: 1 } this.URLs = { - request: 'https://apollo.kevinmidboe.com/api/v1/plex/request?query=', - sendRequest: 'https://apollo.kevinmidboe.com/api/v1/plex/request?query=' + // request: 'https://apollo.kevinmidboe.com/api/v1/plex/request?page='+this.state.page+'&query=', + request: 'http://localhost:31459/api/v1/plex/request?page='+this.state.page+'&query=', + // upcoming: 'https://apollo.kevinmidboe.com/api/v1/tmdb/upcoming', + upcoming: 'http://localhost:31459/api/v1/tmdb/upcoming', + // sendRequest: 'https://apollo.kevinmidboe.com/api/v1/plex/request?query=' + sendRequest: 'http://localhost:31459/api/v1/plex/request?query=' } } componentDidMount(){ - var that = this; - this.setState({responseMovieList: null}) + var that = this; + // this.setState({responseMovieList: null}) + this.getUpcoming(); } // Handles all errors of the response of a fetch call handleErrors(response) { - if (!response.ok) { - throw Error(response.status); - } - return response; + if (!response.ok) { + throw Error(response.status); + } + return response; + } + + getUpcoming() { + let url = this.URLs.upcoming + '?page=' + this.state.page; + + fetch(url) + .then(response => this.handleErrors(response)) + .then(response => response.json()) + .then(data => { + console.log(data.total_pages) + if (data.results.length > 0) { + this.setState({ + responseMovieList: data.results.map(item => this.createMovieObjects(item)) + }) + } + }) + .catch(error => { + console.log(error); + this.setState({ + reposemovieList:

Not found (upcoming)

+ }) + }) } fetchQuery() { @@ -42,27 +72,27 @@ class SearchRequest extends React.Component { } fetch(url) - // Check if the response is ok - .then(response => this.handleErrors(response)) - .then(response => response.json()) // Convert to json object and pass to next then - .then(data => { // Parse the data of the JSON response - // If it is something here it updates the state variable with the HTML list of all - // movie objects that where returned by the search request - if (data.length > 0) { - this.setState({ - responseMovieList: data.map(item => this.createMovieObjects(item)) - }) - } - }) - // If the -------- - .catch(error => { - console.log(error) - this.setState({ - responseMovieList:

Not Found

- }) + // Check if the response is ok + .then(response => this.handleErrors(response)) + .then(response => response.json()) // Convert to json object and pass to next then + .then(data => { // Parse the data of the JSON response + // If it is something here it updates the state variable with the HTML list of all + // movie objects that where returned by the search request + if (data.length > 0) { + this.setState({ + responseMovieList: data.map(item => this.createMovieObjects(item)) + }) + } + }) + // If the -------- + .catch(error => { + console.log(error) + this.setState({ + responseMovieList:

Not Found

+ }) - console.log('Error submit: ', error.toString()); - }); + console.log('Error submit: ', error.toString()); + }); } // Updates the internal state of the query search field. @@ -101,163 +131,45 @@ class SearchRequest extends React.Component { } } + pageBackwards() { + if (this.state.page > 1) { + console.log('backwards'); + this.state.page--; + this.getUpcoming(); + } + console.log(this.state.page) + } + + pageForwards() { + this.state.page++; + this.getUpcoming(); + console.log('forwards'); + console.log(this.state.page) + } + render(){ - - var body = { - fontFamily: "'Open Sans', sans-serif", - backgroundColor: '#f7f7f7', - margin: 0, - padding: 0, - minHeight: '100%', - position: 'relative' - } - - var backgroundHeader = { - width: '100%', - minHeight: '400px', - backgroundColor: '#011c23', - zIndex: 1, - position: 'absolute' - } - - - var requestWrapper = { - top: '300px', - width: '90%', - maxWidth: '1200px', - margin: 'auto', - paddingTop: '20px', - backgroundColor: 'white', - position: 'relative', - zIndex: '10', - boxShadow: '0 2px 10px grey' - } - - var pageTitle = { - display: 'flex', - alignItems: 'center', - justifyContent: 'center' - } - - var pageTitleSpan = { - color: 'white', - fontSize: '3em', - marginTop: '4vh', - marginBottom: '6vh' - } - - var box = { - width: '90%', - height: '50px', - maxWidth: '1200px', - margin: '0 auto' - } - - var container = { - verticalAlign: 'middle', - whiteSpace: 'nowrap', - position: 'relative', - display: 'flex', - justifyContent: 'center' - } - - var searchIcon = { - position: 'absolute', - marginLeft: '17px', - marginTop: '17px', - zIndex: '1', - color: '#4f5b66' - } - - var searchBar = { - width: '60%', - minWidth: '120px', - height: '50px', - background: '#ffffff', - border: 'none', - fontSize: '10pt', - float: 'left', - color: '#63717f', - paddingLeft: '45px', - borderRadius: '5px', - marginRight: '15px' - } - - var searchFilter = { - color: 'white', - fontSize: '1em', - paddingTop: '12px', - marginBottom: '12px', - marginLeft: '10px', - cursor: 'pointer' - } - - var hvrUnderlineFromCenter = { - color: 'white', - fontSize: '1em', - paddingTop: '12px', - marginBottom: '12px', - marginLeft: '10px', - cursor: 'pointer', - display: 'inline-block', - verticalAlign: 'middle', - WebkitTransform: 'perspective(1px) translateZ(0)', - transform: 'perspective(1px) translateZ(0)', - boxShadow: '0 0 1px transparent', - position: 'relative', - overflow: 'hidden', - ':before': { - content: "", - position: 'absolute', - zIndex: '-1', - left: '50%', - right: '50%', - bottom: '0', - background: '#00d17c', - height: '2px', - WebkitTransitionProperty: 'left, right', - transitionProperty: 'left, right', - WebkitTransitionDuration: '0.3s', - transitionDuration: '0.3s', - WebkitTransitionTimingFunction: 'ease-out', - transitionTimingFunction: 'ease-out' - }, - ':hover:before': { - left: 0, - right: 0 - }, - 'focus:before': { - left: 0, - right: 0 - }, - 'active:before': { - left: 0, - right: 0 - } - } - return( -
-
-
- Request new movies or tv shows +
+
+
+ Request new movies or tv shows
-
-
- +
+
+ - this._handleQueryKeyPress(event)} onChange={event => this.updateQueryState(event)} value={this.state.searchQuery}/> - {this.toggleFilter('movies')}} id="category_active">Movies - {this.toggleFilter('tvshows')}} id="category_inactive">TV Shows @@ -265,14 +177,18 @@ class SearchRequest extends React.Component {
-
+
{this.state.responseMovieList}
+
+ + +
) } - + } export default SearchRequest; \ No newline at end of file diff --git a/client/app/components/styles/movieObjectStyle.jsx b/client/app/components/styles/movieObjectStyle.jsx new file mode 100644 index 0000000..a87c726 --- /dev/null +++ b/client/app/components/styles/movieObjectStyle.jsx @@ -0,0 +1,80 @@ + +export default { + resultItem: { + maxWidth: '95%', + margin: '0 auto', + minHeight: '230px' + }, + + resultItem: { + maxWidth: '95%', + margin: '0 auto', + minHeight: '230px' + }, + + movie_content: { + marginLeft: '15px' + }, + + resultTitle: { + color: 'black', + fontSize: '2em', + }, + + resultPoster: { + float: 'left', + zIndex: '3', + position: 'relative', + marginRight: '30px' + }, + + resultPosterImg: { + border: '2px none', + borderRadius: '2px', + width: '150px' + }, + + buttons: { + paddingTop: '20px' + }, + + requestButton: { + color: '#e9a131', + marginRight: '10px', + background: 'white', + border: '#e9a131 2px solid', + borderRadius: '4px', + textAlign: 'center', + padding: '10px', + minWidth: '100px', + float: 'left', + fontSize: '13px', + fontWeight: '800', + cursor: 'pointer' + }, + + tmdbButton: { + color: '#00d17c', + marginRight: '10px', + background: 'white', + border: '#00d17c 2px solid', + borderRadius: '4px', + textAlign: 'center', + padding: '10px', + minWidth: '100px', + float: 'left', + fontSize: '13px', + fontWeight: '800', + cursor: 'pointer' + }, + + row: { + width: '100%' + }, + + itemDivider: { + width: '90%', + borderBottom: '1px solid grey', + margin: '2rem auto' + } +} \ No newline at end of file diff --git a/client/app/components/styles/searchRequestStyle.jsx b/client/app/components/styles/searchRequestStyle.jsx new file mode 100644 index 0000000..d02eb5e --- /dev/null +++ b/client/app/components/styles/searchRequestStyle.jsx @@ -0,0 +1,134 @@ + +export default { + body: { + fontFamily: "'Open Sans', sans-serif", + backgroundColor: '#f7f7f7', + margin: 0, + padding: 0, + minHeight: '100%', + position: 'relative' + }, + + backgroundHeader: { + width: '100%', + minHeight: '400px', + backgroundColor: '#011c23', + zIndex: 1, + position: 'absolute' + }, + + requestWrapper: { + top: '300px', + width: '90%', + maxWidth: '1200px', + margin: 'auto', + paddingTop: '20px', + backgroundColor: 'white', + position: 'relative', + zIndex: '10', + boxShadow: '0 2px 10px grey' + }, + + pageTitle: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center' + }, + + pageTitleSpan: { + color: 'white', + fontSize: '3em', + marginTop: '4vh', + marginBottom: '6vh' + }, + + box: { + width: '90%', + height: '50px', + maxWidth: '1200px', + margin: '0 auto' + }, + + container: { + verticalAlign: 'middle', + whiteSpace: 'nowrap', + position: 'relative', + display: 'flex', + justifyContent: 'center' + }, + + searchIcon: { + position: 'absolute', + marginLeft: '17px', + marginTop: '17px', + zIndex: '1', + color: '#4f5b66' + }, + + searchBar: { + width: '60%', + minWidth: '120px', + height: '50px', + background: '#ffffff', + border: 'none', + fontSize: '10pt', + float: 'left', + color: '#63717f', + paddingLeft: '45px', + borderRadius: '5px', + marginRight: '15px' + }, + + searchFilter: { + color: 'white', + fontSize: '1em', + paddingTop: '12px', + marginBottom: '12px', + marginLeft: '10px', + cursor: 'pointer' + }, + + hvrUnderlineFromCenter: { + color: 'white', + fontSize: '1em', + paddingTop: '12px', + marginBottom: '12px', + marginLeft: '10px', + cursor: 'pointer', + display: 'inline-block', + verticalAlign: 'middle', + WebkitTransform: 'perspective(1px) translateZ(0)', + transform: 'perspective(1px) translateZ(0)', + boxShadow: '0 0 1px transparent', + position: 'relative', + overflow: 'hidden', + ':before': { + content: "", + position: 'absolute', + zIndex: '-1', + left: '50%', + right: '50%', + bottom: '0', + background: '#00d17c', + height: '2px', + WebkitTransitionProperty: 'left, right', + transitionProperty: 'left, right', + WebkitTransitionDuration: '0.3s', + transitionDuration: '0.3s', + WebkitTransitionTimingFunction: 'ease-out', + transitionTimingFunction: 'ease-out' + }, + ':hover:before': { + left: 0, + right: 0 + }, + 'focus:before': { + left: 0, + right: 0 + }, + 'active:before': { + left: 0, + right: 0 + } + } +} \ No newline at end of file diff --git a/seasoned_api/package.json b/seasoned_api/package.json index 52fe956..94cd8bd 100644 --- a/seasoned_api/package.json +++ b/seasoned_api/package.json @@ -9,7 +9,7 @@ "cross-env": "^3.1.3", "express": "~4.0.0", "mongoose": "^3.6.13", - "moviedb": "^0.2.7", + "moviedb": "^0.2.10", "node-cache": "^4.1.1", "nodemailer": "^4.0.1", "python-shell": "^0.4.0", diff --git a/seasoned_api/src/plex/requestRepository.js b/seasoned_api/src/plex/requestRepository.js index 8aef0ca..e72dc72 100644 --- a/seasoned_api/src/plex/requestRepository.js +++ b/seasoned_api/src/plex/requestRepository.js @@ -67,13 +67,16 @@ class RequestRepository { }); } - sendRequest(identifier) { + /** + * Send request for given media id. + * @param {identifier, type} the id of the media object and type of media must be defined + * @returns {Promise} If nothing has gone wrong. + */ + sendRequest(identifier, type) { // TODO add to DB so can have a admin page // TODO try a cache hit on the movie item - tmdb.lookup(identifier).then(movie => { - console.log(movie.title) - + tmdb.lookup(identifier, type).then(movie => { // create reusable transporter object using the default SMTP transport let transporter = nodemailer.createTransport({ @@ -110,6 +113,7 @@ class RequestRepository { }) + // TODO add better response when done. return Promise.resolve(); } diff --git a/seasoned_api/src/tmdb/convertTmdbToSeasoned.js b/seasoned_api/src/tmdb/convertTmdbToSeasoned.js index 642b7ea..7379610 100644 --- a/seasoned_api/src/tmdb/convertTmdbToSeasoned.js +++ b/seasoned_api/src/tmdb/convertTmdbToSeasoned.js @@ -1,8 +1,8 @@ const Movie = require('src/media_classes/movie'); const Show = require('src/media_classes/show'); -function convertTmdbToSeasoned(tmdbObject) { - const mediaType = tmdbObject.media_type; +function convertTmdbToSeasoned(tmdbObject, strictType=undefined) { + const mediaType = strictType || tmdbObject.media_type; // There are many diff types of content, we only want to look at movies and tv shows if (mediaType === 'movie') { @@ -16,6 +16,7 @@ function convertTmdbToSeasoned(tmdbObject) { const movie = new Movie(title, year, mediaType); + movie.id = tmdbObject.id; movie.summary = tmdbObject.overview; movie.rating = tmdbObject.vote_average; movie.poster = tmdbObject.poster_path; @@ -27,11 +28,12 @@ function convertTmdbToSeasoned(tmdbObject) { return movie; } - else if (mediaType === 'tv') { + else if (mediaType === 'tv' || mediaType === 'show') { const year = new Date(tmdbObject.first_air_date).getFullYear(); - const show = new Show(tmdbObject.title, year, mediaType); + const show = new Show(tmdbObject.name, year, 'show'); + show.id = tmdbObject.id; show.summary = tmdbObject.overview; show.rating = tmdbObject.vote_average; show.poster = tmdbObject.poster_path; diff --git a/seasoned_api/src/tmdb/tmdb.js b/seasoned_api/src/tmdb/tmdb.js index a536381..c9481b7 100644 --- a/seasoned_api/src/tmdb/tmdb.js +++ b/seasoned_api/src/tmdb/tmdb.js @@ -1,7 +1,10 @@ const moviedb = require('moviedb'); const convertTmdbToSeasoned = require('src/tmdb/convertTmdbToSeasoned'); -var methodTypes = { 'movie': 'searchMovie', 'tv': 'searchTv', 'multi': 'searchMulti', 'movieInfo': 'movieInfo', - 'tvInfo': 'tvInfo' }; +var methodTypes = { 'movie': 'searchMovie', 'show': 'searchTv', 'multi': 'searchMulti', 'movieInfo': 'movieInfo', + 'tvInfo': 'tvInfo', 'upcomingMovies': 'miscUpcomingMovies', 'discoverMovie': 'discoverMovie', + 'discoverShow': 'discoverTv', 'popularMovies': 'miscPopularMovies', 'popularShows': 'miscPopularTvs', + 'nowPlayingMovies': 'miscNowPlayingMovies', 'nowAiringShows': 'tvOnTheAir', 'movieSimilar': 'movieSimilar', + 'showSimilar': 'tvSimilar' }; class TMDB { constructor(apiKey, tmdbLibrary) { @@ -9,7 +12,7 @@ class TMDB { } search(text, page = 1, type = 'multi') { - const query = { query: text, page }; + const query = { 'query': text, 'page': page }; return Promise.resolve() .then(() => this.tmdb(type, query)) .catch(() => { throw new Error('Could not search for movies.'); }) @@ -26,27 +29,235 @@ class TMDB { } + /** + * Retrive list of discover section of movies from TMDB. + * @param {Page, type} the page number to specify in the request for discover, + * and type for movie or show + * @returns {Promise} dict with query results, current page and total_pages + */ + discover(page, type='movie') { + // Sets the tmdb function type to the corresponding type from query + var tmdbType; + if (type === 'movie') { + tmdbType = 'discoverMovie'; + } else if (type === 'show') { + tmdbType = 'discoverShow'; + } else { + // Throw error if invalid type from query + return Promise.resolve() + .then(() => { + throw new Error('Invalid type declaration.') + }) + } + + // Build a query for tmdb with pagenumber + const query = { 'page': page } + return Promise.resolve() + .then(() => this.tmdb(tmdbType, query)) + .catch(() => { throw new Error('Could not fetch discover.'); }) + .then((response) => { + try { + // Return a object that has the results and a variable for page, total_pages + // and seasonedResponse + var seasonedResponse = response.results.map((result) => { + return convertTmdbToSeasoned(result, type); } + ); + return { 'results': seasonedResponse, + 'page': response.page, 'total_pages': response.total_pages }; + } catch (error) { + console.log(error) + throw new Error('Error while parsing discover list.') + } + }); + } + + + /** + * Retrive list of popular section of movies or shows from TMDB. + * @param {Page, type} the page number to specify in the request for popular, + * and type for movie or show + * @returns {Promise} dict with query results, current page and total_pages + */ + // TODO add filter for language + popular(page, type='movie') { + // Sets the tmdb function type to the corresponding type from query + var tmdbType; + if (type === 'movie') { + tmdbType = 'popularMovies'; + } else if (type === 'show') { + tmdbType = 'popularShows'; + } else { + // Throw error if invalid type from query + return Promise.resolve() + .then(() => { + throw new Error('Invalid type declaration.') + }) + } + + // Build a query for tmdb with pagenumber + const query = { 'page': page } + return Promise.resolve() + .then(() => this.tmdb(tmdbType, query)) + .catch(() => { throw new Error('Could not fetch popular.'); }) + .then((response) => { + try { + var seasonedResponse = response.results.map((result) => { + return convertTmdbToSeasoned(result, type); } + ); + // Return a object that has the results and a variable for page, total_pages + // and seasonedResponse + return { 'results': seasonedResponse, + 'page': response.page, 'total_pages': response.total_pages }; + } catch (error) { + console.log(error) + throw new Error('Error while parsing discover list.') + } + }); + } + + + + /** + * Retrive list of now playing/airing section of movies or shows from TMDB. + * @param {Page, type} the page number to specify in the request for now playing/airing, + * and type for movie or show + * @returns {Promise} dict with query results, current page and total_pages + */ + // TODO add filter for language + nowplaying(page, type='movie') { + // Sets the tmdb function type to the corresponding type from query + var tmdbType; + if (type === 'movie') { + tmdbType = 'nowPlayingMovies'; + } else if (type === 'show') { + tmdbType = 'nowAiringShows'; + } else { + // Throw error if invalid type from query + return Promise.resolve() + .then(() => { + throw new Error('Invalid type declaration.') + }) + } + + // Build a query for tmdb with pagenumber + const query = { 'page': page } + return Promise.resolve() + .then(() => this.tmdb(tmdbType, query)) + .catch(() => { throw new Error('Could not fetch popular.'); }) + .then((response) => { + try { + var seasonedResponse = response.results.map((result) => { + return convertTmdbToSeasoned(result, type); } + ); + // Return a object that has the results and a variable for page, total_pages + // and seasonedResponse + return { 'results': seasonedResponse, + 'page': response.page, 'total_pages': response.total_pages }; + } catch (error) { + console.log(error) + throw new Error('Error while parsing discover list.') + } + }); + } + + /** + * Retrive list of upcmoing movies from TMDB. + * @param {Page} the page number to specify in the request for upcoming movies + * @returns {Promise} dict with query results, current page and total_pages + */ + // TODO add filter for language + upcoming(page) { + const query = { 'page': page } + return Promise.resolve() + .then(() => this.tmdb('upcomingMovies', query)) + .catch(() => { throw new Error('Could not fetch upcoming movies.'); }) + .then((response) => { + try { + var seasonedResponse = response.results.map((result) => { + return convertTmdbToSeasoned(result, 'movie'); } + ); + // Return a object that has the results and a variable for page, total_pages + // and seasonedResponse + return { 'results': seasonedResponse, + 'page': response.page, 'total_pages': response.total_pages }; + } catch (parseError) { + throw new Error('Error while parsing upcoming movies list.') + } + }); + } + + + /** + * Retrive list of upcmoing movies from TMDB. + * @param {Page} the page number to specify in the request for upcoming movies + * @returns {Promise} dict with query results, current page and total_pages + */ + // TODO add filter for language + similar(identifier, type) { + var tmdbType; + if (type === 'movie') { + tmdbType = 'movieSimilar'; + } else if (type === 'show') { + tmdbType = 'showSimilar'; + } else { + // Throw error if invalid type from query + return Promise.resolve() + .then(() => { + throw new Error('Invalid type declaration.') + }) + } + + const query = { id: identifier } + return Promise.resolve() + .then(() => this.tmdb(tmdbType, query)) + .catch(() => { throw new Error('Could not fetch upcoming movies.'); }) + .then((response) => { + try { + var seasonedResponse = response.results.map((result) => { + return convertTmdbToSeasoned(result, type); } + ); + // Return a object that has the results and a variable for page, total_pages + // and seasonedResponse + return { 'results': seasonedResponse, + 'page': response.page, 'total_pages': response.total_pages }; + } catch (parseError) { + throw new Error('Error while parsing silimar media list.') + } + }); + } + + /** * Retrieve a specific movie by id from TMDB. * @param {Number} identifier of the movie you want to retrieve * @returns {Promise} succeeds if movie was found */ - lookup(identifier, type = 'movie') { - if (type === 'movie') { type = 'movieInfo'} - else if (type === 'tv') { type = 'tvInfo'} + lookup(identifier, queryType = 'movie') { + var type; + if (queryType === 'movie') { type = 'movieInfo'} + else if (queryType === 'show') { type = 'tvInfo'} + else { + return Promise.resolve() + .then(() => { + throw new Error('Invalid type declaration.') + }) + } const query = { id: identifier }; return Promise.resolve() - .then(() => this.tmdb(type, query)) - .catch(() => { throw new Error('Could not find a movie with that id.'); }) - .then((response) => { - try { - return convertTmdbToSeasoned(response); - } catch (parseError) { - throw new Error('Could not parse movie.'); - } - }); + .then(() => this.tmdb(type, query)) + .catch(() => { throw new Error('Could not find a movie with that id.'); }) + .then((response) => { + try { + var car = convertTmdbToSeasoned(response, queryType); + console.log(car); + return car; + } catch (parseError) { + throw new Error('Could not parse movie.'); + } + }); } + // TODO ADD CACHE LOOKUP tmdb(method, argument) { return new Promise((resolve, reject) => { const callback = (error, reponse) => { @@ -58,6 +269,7 @@ class TMDB { if (!argument) { this.tmdbLibrary[methodTypes[method]](callback); + // this.tmdbLibrary['miscUpcomingMovies'] } else { this.tmdbLibrary[methodTypes[method]](argument, callback); } diff --git a/seasoned_api/src/webserver/app.js b/seasoned_api/src/webserver/app.js index 63dde87..9bd47fe 100644 --- a/seasoned_api/src/webserver/app.js +++ b/seasoned_api/src/webserver/app.js @@ -15,7 +15,8 @@ var allowedOrigins = ['https://kevinmidboe.com', 'http://localhost:8080'] router.use(function(req, res, next) { - console.log('Something is happening.'); + // TODO add logging of all incoming + console.log('Request: ', req.originalUrl); var origin = req.headers.origin; if (allowedOrigins.indexOf(origin) > -1) { res.setHeader('Access-Control-Allow-Origin', origin); @@ -40,6 +41,12 @@ router.post('/v1/plex/request/:mediaId', require('./controllers/plex/submitReque router.get('/v1/plex/hook', require('./controllers/plex/hookDump.js')); router.get('/v1/tmdb/search', require('./controllers/tmdb/searchMedia.js')); +router.get('/v1/tmdb/discover', require('./controllers/tmdb/discoverMedia.js')); +router.get('/v1/tmdb/popular', require('./controllers/tmdb/popularMedia.js')); +router.get('/v1/tmdb/nowplaying', require('./controllers/tmdb/nowPlayingMedia.js')); +router.get('/v1/tmdb/upcoming', require('./controllers/tmdb/getUpcoming.js')); + +router.get('/v1/tmdb/similar/:mediaId', require('./controllers/tmdb/searchSimilar.js')); router.get('/v1/tmdb/:mediaId', require('./controllers/tmdb/readMedia.js')); router.post('/v1/git/dump', require('./controllers/git/dumpHook.js')); diff --git a/seasoned_api/src/webserver/controllers/plex/submitRequest.js b/seasoned_api/src/webserver/controllers/plex/submitRequest.js index 80e1355..fd6345f 100644 --- a/seasoned_api/src/webserver/controllers/plex/submitRequest.js +++ b/seasoned_api/src/webserver/controllers/plex/submitRequest.js @@ -11,8 +11,9 @@ const requestRepository = new RequestRepository(); function submitRequestController(req, res) { // This is the id that is the param of the url const id = req.params.mediaId; + const type = req.query.type; - requestRepository.sendRequest(id) + requestRepository.sendRequest(id, type) .then(() => { res.send({ success: true, message: 'Media item sucessfully requested!' }); }) diff --git a/seasoned_api/src/webserver/controllers/tmdb/discoverMedia.js b/seasoned_api/src/webserver/controllers/tmdb/discoverMedia.js new file mode 100644 index 0000000..3669035 --- /dev/null +++ b/seasoned_api/src/webserver/controllers/tmdb/discoverMedia.js @@ -0,0 +1,21 @@ +const configuration = require('src/config/configuration').getInstance(); +const TMDB = require('src/tmdb/tmdb'); +const tmdb = new TMDB(configuration.get('tmdb', 'apiKey')); + +/** + * Controller: Retrieve a list of movies or shows in discover section in TMDB + * @param {Request} req http request variable + * @param {Response} res + * @returns {Callback} + */ +function discoverMediaController(req, res) { + const { page, type } = req.query; + tmdb.discover(page, type) + .then((results) => { + res.send(results); + }).catch((error) => { + res.status(404).send({ success: false, error: error.message }); + }); +} + +module.exports = discoverMediaController; diff --git a/seasoned_api/src/webserver/controllers/tmdb/getUpcoming.js b/seasoned_api/src/webserver/controllers/tmdb/getUpcoming.js new file mode 100644 index 0000000..9c9e049 --- /dev/null +++ b/seasoned_api/src/webserver/controllers/tmdb/getUpcoming.js @@ -0,0 +1,21 @@ +const configuration = require('src/config/configuration').getInstance(); +const TMDB = require('src/tmdb/tmdb'); +const tmdb = new TMDB(configuration.get('tmdb', 'apiKey')); + +/** + * Controller: Retrieve upcoming movies + * @param {Request} req http request variable + * @param {Response} res + * @returns {Callback} + */ +function getUpcomingController(req, res) { + const { page } = req.query; + tmdb.upcoming(page) + .then((results) => { + res.send(results); + }).catch((error) => { + res.status(404).send({ success: false, error: error.message }); + }); +} + +module.exports = getUpcomingController; diff --git a/seasoned_api/src/webserver/controllers/tmdb/nowPlayingMedia.js b/seasoned_api/src/webserver/controllers/tmdb/nowPlayingMedia.js new file mode 100644 index 0000000..5e67db8 --- /dev/null +++ b/seasoned_api/src/webserver/controllers/tmdb/nowPlayingMedia.js @@ -0,0 +1,21 @@ +const configuration = require('src/config/configuration').getInstance(); +const TMDB = require('src/tmdb/tmdb'); +const tmdb = new TMDB(configuration.get('tmdb', 'apiKey')); + +/** + * Controller: Retrieve nowplaying movies / now airing shows + * @param {Request} req http request variable + * @param {Response} res + * @returns {Callback} + */ +function nowPlayingMediaController(req, res) { + const { page, type } = req.query; + tmdb.nowplaying(page, type) + .then((results) => { + res.send(results); + }).catch((error) => { + res.status(404).send({ success: false, error: error.message }); + }); +} + +module.exports = nowPlayingMediaController; diff --git a/seasoned_api/src/webserver/controllers/tmdb/popularMedia.js b/seasoned_api/src/webserver/controllers/tmdb/popularMedia.js new file mode 100644 index 0000000..963d553 --- /dev/null +++ b/seasoned_api/src/webserver/controllers/tmdb/popularMedia.js @@ -0,0 +1,21 @@ +const configuration = require('src/config/configuration').getInstance(); +const TMDB = require('src/tmdb/tmdb'); +const tmdb = new TMDB(configuration.get('tmdb', 'apiKey')); + +/** + * Controller: Retrieve information for a movie + * @param {Request} req http request variable + * @param {Response} res + * @returns {Callback} + */ +function popularMediaController(req, res) { + const { page, type } = req.query; + tmdb.popular(page, type) + .then((results) => { + res.send(results); + }).catch((error) => { + res.status(404).send({ success: false, error: error.message }); + }); +} + +module.exports = popularMediaController; diff --git a/seasoned_api/src/webserver/controllers/tmdb/searchMedia.js b/seasoned_api/src/webserver/controllers/tmdb/searchMedia.js index f09b859..90f5cda 100644 --- a/seasoned_api/src/webserver/controllers/tmdb/searchMedia.js +++ b/seasoned_api/src/webserver/controllers/tmdb/searchMedia.js @@ -14,7 +14,7 @@ function searchMoviesController(req, res) { Promise.resolve() .then(() => tmdb.search(query, page, type)) .then((movies) => { - if (movies.length > 0) { + if (movies !== undefined || movies.length > 0) { res.send(movies); } else { res.status(404).send({ success: false, error: 'Search query did not return any results.'}) diff --git a/seasoned_api/src/webserver/controllers/tmdb/searchSimilar.js b/seasoned_api/src/webserver/controllers/tmdb/searchSimilar.js new file mode 100644 index 0000000..bc2383f --- /dev/null +++ b/seasoned_api/src/webserver/controllers/tmdb/searchSimilar.js @@ -0,0 +1,22 @@ +const configuration = require('src/config/configuration').getInstance(); +const TMDB = require('src/tmdb/tmdb'); +const tmdb = new TMDB(configuration.get('tmdb', 'apiKey')); + +/** + * Controller: Retrieve similar movies or shows + * @param {Request} req http request variable + * @param {Response} res + * @returns {Callback} + */ +function similarMediaController(req, res) { + const mediaId = req.params.mediaId; + const { type } = req.query; + tmdb.similar(mediaId, type) + .then((results) => { + res.send(results); + }).catch((error) => { + res.status(404).send({ success: false, error: error.message }); + }); +} + +module.exports = similarMediaController;