-
+
-
+
{this.state.responseMovieList}
+
+ {this.pageBackwards()}}>Back
+ {this.pageForwards()}}>Forward
+
)
}
-
+
}
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;