1 Commits

Author SHA1 Message Date
Renovate Bot
e981b32f6b Add renovate.json 2019-07-13 04:53:32 +00:00
77 changed files with 1656 additions and 5255 deletions

View File

@@ -1,5 +1,5 @@
language: node_js language: node_js
node_js: '11.9.0' node_js: '8.7.0'
git: git:
submodules: true submodules: true
script: script:

View File

@@ -10,8 +10,8 @@
<img src="https://travis-ci.org/KevinMidboe/seasonedShows.svg?branch=master" <img src="https://travis-ci.org/KevinMidboe/seasonedShows.svg?branch=master"
alt="Travis CI"> alt="Travis CI">
</a> </a>
<a href="https://coveralls.io/github/KevinMidboe/seasonedShows?branch=api/v2"> <a href="https://coveralls.io/github/KevinMidboe/seasonedShows?branch=coverage">
<img src="https://coveralls.io/repos/github/KevinMidboe/seasonedShows/badge.svg?branch=api/v2" alt=""> <img src="https://coveralls.io/repos/github/KevinMidboe/seasonedShows/badge.svg?branch=coverage" alt="">
</a> </a>
<a href="https://snyk.io/test/github/KevinMidboe/seasonedShows?targetFile=seasoned_api/package.json"> <a href="https://snyk.io/test/github/KevinMidboe/seasonedShows?targetFile=seasoned_api/package.json">
<img src="https://snyk.io/test/github/KevinMidboe/seasonedShows/badge.svg?targetFile=seasoned_api/package.json" alt=""> <img src="https://snyk.io/test/github/KevinMidboe/seasonedShows/badge.svg?targetFile=seasoned_api/package.json" alt="">

View File

@@ -12,7 +12,7 @@
}, },
"dependencies": { "dependencies": {
"clean-webpack-plugin": "^0.1.17", "clean-webpack-plugin": "^0.1.17",
"css-loader": "^1.0.0", "css-loader": "^0.28.4",
"html-webpack-plugin": "^2.28.0", "html-webpack-plugin": "^2.28.0",
"path": "^0.12.7", "path": "^0.12.7",
"react": "^15.6.1", "react": "^15.6.1",
@@ -30,8 +30,8 @@
"redux-thunk": "^2.2.0", "redux-thunk": "^2.2.0",
"urijs": "^1.18.12", "urijs": "^1.18.12",
"webfontloader": "^1.6.28", "webfontloader": "^1.6.28",
"webpack": "^4.0.0", "webpack": "^3.5.5",
"webpack-dev-server": "^3.1.11", "webpack-dev-server": "^2.4.5",
"webpack-merge": "^4.1.0" "webpack-merge": "^4.1.0"
}, },
"devDependencies": { "devDependencies": {

5
renovate.json Normal file
View File

@@ -0,0 +1,5 @@
{
"extends": [
"config:base"
]
}

View File

@@ -7,48 +7,39 @@
}, },
"main": "webserver/server.js", "main": "webserver/server.js",
"scripts": { "scripts": {
"start": "cross-env SEASONED_CONFIG=conf/development.json PROD=true NODE_PATH=. babel-node src/webserver/server.js", "start": "cross-env SEASONED_CONFIG=conf/development.json PROD=true NODE_PATH=. node src/webserver/server.js",
"test": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. mocha --require @babel/register --recursive test/unit test/system", "test": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. mocha --recursive test/unit test/system",
"coverage": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. nyc mocha --require @babel/register --recursive test && nyc report --reporter=text-lcov | coveralls", "coverage": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. nyc mocha --recursive test && nyc report --reporter=text-lcov | coveralls",
"lint": "./node_modules/.bin/eslint src/", "lint": "./node_modules/.bin/eslint src/",
"update": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. node src/plex/updateRequestsInPlex.js", "update": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. node src/plex/updateRequestsInPlex.js"
"docs": "yarn apiDocs; yarn classDocs",
"apiDocs": "",
"classDocs": "./script/generate-class-docs.sh"
}, },
"dependencies": { "dependencies": {
"axios": "^0.18.0", "axios": "^0.18.0",
"bcrypt": "^3.0.6", "bcrypt-nodejs": "^0.0.3",
"body-parser": "~1.18.2", "body-parser": "~1.18.2",
"cross-env": "~5.1.4", "cross-env": "~5.1.4",
"express": "~4.16.0", "express": "~4.16.0",
"jsonwebtoken": "^8.2.0", "jsonwebtoken": "^8.0.1",
"km-moviedb": "^0.2.13",
"mongoose": "~5.0.11",
"km-moviedb": "^0.2.12", "km-moviedb": "^0.2.12",
"node-cache": "^4.1.1", "node-cache": "^4.1.1",
"node-fetch": "^2.6.0",
"python-shell": "^0.5.0", "python-shell": "^0.5.0",
"raven": "^2.4.2", "request": "^2.85.0",
"request": "^2.87.0",
"request-promise": "^4.2", "request-promise": "^4.2",
"sqlite3": "^4.0.0" "sqlite3": "^4.0.0"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.5.5", "coveralls": "^3.0.0",
"@babel/node": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/register": "^7.5.5",
"@types/node": "^12.6.8",
"coveralls": "^3.0.5",
"documentation": "^12.0.3",
"eslint": "^4.9.0", "eslint": "^4.9.0",
"eslint-config-airbnb-base": "^12.1.0", "eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.8.0", "eslint-plugin-import": "^2.8.0",
"istanbul": "^0.4.5", "istanbul": "^0.4.5",
"mocha": "^6.2.0", "mocha": "^5.0.4",
"mocha-lcov-reporter": "^1.3.0", "mocha-lcov-reporter": "^1.3.0",
"nyc": "^11.6.0", "nyc": "^11.6.0",
"raven": "^2.4.2",
"supertest": "^3.0.0", "supertest": "^3.0.0",
"supertest-as-promised": "^4.0.1", "supertest-as-promised": "^4.0.1"
"typescript": "^3.5.3"
} }
} }

View File

@@ -25,7 +25,7 @@ class SqliteDatabase {
* @param {Array} parameters in the SQL query * @param {Array} parameters in the SQL query
* @returns {Promise} * @returns {Promise}
*/ */
run(sql, parameters) { async run(sql, parameters) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.connection.run(sql, parameters, (error, result) => { this.connection.run(sql, parameters, (error, result) => {
if (error) if (error)
@@ -41,7 +41,7 @@ class SqliteDatabase {
* @param {Array} parameters in the SQL query * @param {Array} parameters in the SQL query
* @returns {Promise} * @returns {Promise}
*/ */
all(sql, parameters) { async all(sql, parameters) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.connection.all(sql, parameters, (err, rows) => { this.connection.all(sql, parameters, (err, rows) => {
if (err) { if (err) {
@@ -58,7 +58,7 @@ class SqliteDatabase {
* @param {Array} parameters in the SQL query * @param {Array} parameters in the SQL query
* @returns {Promise} * @returns {Promise}
*/ */
get(sql, parameters) { async get(sql, parameters) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.connection.get(sql, parameters, (err, rows) => { this.connection.get(sql, parameters, (err, rows) => {
if (err) { if (err) {
@@ -75,7 +75,7 @@ class SqliteDatabase {
* @param {Array} parameters in the SQL query * @param {Array} parameters in the SQL query
* @returns {Promise} * @returns {Promise}
*/ */
execute(sql) { async execute(sql) {
return new Promise(resolve => { return new Promise(resolve => {
this.connection.exec(sql, (err, database) => { this.connection.exec(sql, (err, database) => {
if (err) { if (err) {

View File

@@ -12,7 +12,7 @@ function getMagnetFromURL(url) {
resolve(url) resolve(url)
http.get(options, (res) => { http.get(options, (res) => {
if (res.statusCode == 301 || res.statusCode == 302) { if (res.statusCode == 301) {
resolve(res.headers.location) resolve(res.headers.location)
} }
}); });
@@ -21,7 +21,7 @@ function getMagnetFromURL(url) {
async function find(searchterm, callback) { async function find(searchterm, callback) {
const options = { const options = {
pythonPath: '../torrent_search/env/bin/python3', pythonPath: '../torrent_search/env/bin/python3.6',
scriptPath: '../torrent_search', scriptPath: '../torrent_search',
args: [searchterm, '-s', 'jackett', '-f', '--print'] args: [searchterm, '-s', 'jackett', '-f', '--print']
} }
@@ -35,7 +35,7 @@ async function callPythonAddMagnet(url, callback) {
getMagnetFromURL(url) getMagnetFromURL(url)
.then((magnet) => { .then((magnet) => {
const options = { const options = {
pythonPath: '../delugeClient/env/bin/python3', pythonPath: '../delugeClient/env/bin/python3.6',
scriptPath: '../delugeClient', scriptPath: '../delugeClient',
args: ['add', magnet] args: ['add', magnet]
}; };
@@ -51,10 +51,13 @@ async function callPythonAddMagnet(url, callback) {
async function SearchPiratebay(query) { async function SearchPiratebay(query) {
return await new Promise((resolve, reject) => find(query, (err, results) => { return await new Promise((resolve, reject) => find(query, (err, results) => {
if (err) { if (err) {
/* eslint-disable no-console */
console.log('THERE WAS A FUCKING ERROR!\n', err); console.log('THERE WAS A FUCKING ERROR!\n', err);
reject(Error('There was a error when searching for torrents')); reject(Error('There was a error when searching for torrents'));
} }
if (results) { if (results) {
/* eslint-disable no-console */
console.log('result', results);
resolve(JSON.parse(results, null, '\t')); resolve(JSON.parse(results, null, '\t'));
} }
})); }));

View File

@@ -1,89 +1,59 @@
const fetch = require('node-fetch') const axios = require('axios')
const convertPlexToMovie = require('src/plex/convertPlexToMovie') const convertPlexToMovie = require('src/plex/convertPlexToMovie')
const convertPlexToShow = require('src/plex/convertPlexToShow') const convertPlexToShow = require('src/plex/convertPlexToShow')
const convertPlexToEpisode = require('src/plex/convertPlexToEpisode') const convertPlexToEpisode = require('src/plex/convertPlexToEpisode')
const { Movie, Show, Person } = require('src/tmdb/types');
// const { Movie, }
// TODO? import class definitions to compare types ?
// what would typescript do?
class Plex { class Plex {
constructor(ip, port=32400) { constructor(ip) {
this.plexIP = ip this.plexIP = ip
this.plexPort = port this.plexPort = 32400
}
matchTmdbAndPlexMedia(plex, tmdb) {
if (plex === undefined || tmdb === undefined)
return false
const sanitize = (string) => string.toLowerCase()
const matchTitle = sanitize(plex.title) === sanitize(tmdb.title)
const matchYear = plex.year === tmdb.year
return matchTitle && matchYear
} }
existsInPlex(tmdbMovie) { existsInPlex(tmdbMovie) {
return this.search(tmdbMovie.title) return Promise.resolve()
.then(plexMovies => plexMovies.some(plex => this.matchTmdbAndPlexMedia(plex, tmdbMovie))) .then(() => this.search(tmdbMovie.title))
} // TODO handle this when whitelist of local ip is not set in plex
.catch((error) => { console.error('Unable to search plex')})
.then((plexMovies) => {
const matches = plexMovies.some((plexMovie) => {
return tmdbMovie.title === plexMovie.title && tmdbMovie.type === plexMovie.type
})
successfullResponse(response) { tmdbMovie.existsInPlex = matches
const { status, statusText } = response return tmdbMovie
})
if (status === 200) {
return response.json()
} else {
throw { message: statusText, status: status }
}
} }
search(query) { search(query) {
const url = `http://${this.plexIP}:${this.plexPort}/hubs/search?query=${query}`
const options = { const options = {
timeout: 2000, baseURL: `http://${this.plexIP}:${this.plexPort}`,
headers: { 'Accept': 'application/json' } url: '/hubs/search',
params: { query: query },
responseType: 'json',
timeout: 3000
} }
return fetch(url, options) return Promise.resolve()
.then(this.successfullResponse) .then(() => axios.request(options))
.then(this.mapResults) .catch((error) => { throw new Error(`Unable to search plex library`, error) })
.catch(error => { .then(response => this.mapResults(response))
if (error.type === 'request-timeout') {
throw { message: 'Plex did not respond', status: 408, success: false }
}
throw error
})
} }
mapResults(response) {
if (response === undefined || response.MediaContainer === undefined) {
console.log('response was not valid to map', response)
return []
}
return response.MediaContainer.Hub mapResults(response) {
.filter(category => category.size > 0) return response.data.MediaContainer.Hub.reduce((result, hub) => {
.map(category => { if (hub.type === 'movie' && hub.Metadata !== undefined) {
if (category.type === 'movie') { return [...result, ...hub.Metadata.map(convertPlexToMovie)]
return category.Metadata.map(movie => { }
const ovie = Movie.convertFromPlexResponse(movie) else if (hub.type === 'show' && hub.Metadata !== undefined) {
return ovie.createJsonResponse() return [...result, ...hub.Metadata.map(convertPlexToShow)]
}) }
} else if (category.type === 'show') { else if (hub.type === 'episode' && hub.Metadata !== undefined) {
return category.Metadata.map(convertPlexToShow) return [...result, ...hub.Metadata.map(convertPlexToEpisode)]
} else if (category.type === 'episode') { }
return category.Metadata.map(convertPlexToEpisode)
} return result
}) }, [])
.filter(result => result !== undefined)
.flat()
} }
} }

View File

@@ -6,6 +6,7 @@ class Show {
this.rating = null; this.rating = null;
this.seasons = null; this.seasons = null;
this.episodes = null; this.episodes = null;
this.type = 'show';
} }
} }

View File

@@ -1,39 +0,0 @@
const Plex = require('src/plex/plex')
const configuration = require('src/config/configuration').getInstance();
const plex = new Plex(configuration.get('plex', 'ip'))
const establishedDatabase = require('src/database/database');
class UpdateRequestsInPlex {
constructor() {
this.database = establishedDatabase;
this.queries = {
getMovies: `SELECT * FROM requests WHERE status = 'requested' OR status = 'downloading'`,
// getMovies: "select * from requests where status is 'reset'",
saveNewStatus: `UPDATE requests SET status = ? WHERE id IS ? and type IS ?`,
}
}
getByStatus() {
return this.database.all(this.queries.getMovies);
}
scrub() {
return this.getByStatus()
.then((requests) => Promise.all(requests.map(movie => plex.existsInPlex(movie))))
}
commitNewStatus(status, id, type, title) {
console.log(type, title, 'updated to:', status)
this.database.run(this.queries.saveNewStatus, [status, id, type])
}
updateStatus(status) {
this.getByStatus()
.then(requests => Promise.all(requests.map(request => plex.existsInPlex(request))))
.then(matchedRequests => matchedRequests.filter(request => request.existsInPlex))
.then(newMatches => newMatches.map(match => this.commitNewStatus(status, match.id, match.type, match.title)))
}
}
var requestsUpdater = new UpdateRequestsInPlex();
requestsUpdater.updateStatus('downloaded')
module.exports = UpdateRequestsInPlex

View File

@@ -23,7 +23,6 @@ class RequestRepository {
downloaded: '(select status from requests where id is request.id and type is request.type limit 1)', downloaded: '(select status from requests where id is request.id and type is request.type limit 1)',
// deluge: '(select status from deluge_torrent where id is request.id and type is request.type limit 1)', // deluge: '(select status from deluge_torrent where id is request.id and type is request.type limit 1)',
// fetchAllFilterStatus: 'select * from request where ' // fetchAllFilterStatus: 'select * from request where '
readWithoutUserData: 'select id, title, year, type, status, date from requests where id is ? and type is ?',
read: 'select id, title, year, type, status, requested_by, ip, date, user_agent from requests where id is ? and type is ?' read: 'select id, title, year, type, status, requested_by, ip, date, user_agent from requests where id is ? and type is ?'
}; };
} }
@@ -107,17 +106,11 @@ class RequestRepository {
* @returns {Promise} * @returns {Promise}
*/ */
getRequestByIdAndType(id, type) { getRequestByIdAndType(id, type) {
return this.database.get(this.queries.readWithoutUserData, [id, type]) return Promise.resolve()
.then(() => this.database.get(this.queries.read, [id, type]))
.then(row => { .then(row => {
assert(row, 'Could not find request item with that id and type') assert(row, 'Could not find request item with that id and type')
return { return JSON.stringify(row)
id: row.id,
title: row.title,
year: row.year,
type: row.type,
status: row.status,
requested_date: new Date(row.date)
}
}) })
} }
@@ -131,7 +124,6 @@ class RequestRepository {
*/ */
fetchAll(page=1, sort_by=undefined, sort_direction='asc', filter=undefined, query=undefined) { fetchAll(page=1, sort_by=undefined, sort_direction='asc', filter=undefined, query=undefined) {
// TODO implemented sort and filter // TODO implemented sort and filter
page = parseInt(page)
let fetchQuery = this.queries.fetchAll let fetchQuery = this.queries.fetchAll
let fetchTotalResults = this.queries.totalRequests let fetchTotalResults = this.queries.totalRequests
let fetchParams = [page] let fetchParams = [page]
@@ -152,15 +144,11 @@ class RequestRepository {
const totalRequests = sqliteResponse['totalRequests'] const totalRequests = sqliteResponse['totalRequests']
const totalPages = Math.ceil(totalRequests / 26) const totalPages = Math.ceil(totalRequests / 26)
return [ rows.map(item => { return [ rows.map(item => { item.poster = item.poster_path; return item }), totalPages ]
item.poster = item.poster_path; delete item.poster_path;
item.backdrop = item.background_path; delete item.background_path;
return item
}), totalPages, totalRequests ]
return Promise.all(this.mapToTmdbByType(rows)) return Promise.all(this.mapToTmdbByType(rows))
}) })
.then(([result, totalPages, totalRequests]) => Promise.resolve({ .then(([result, totalPages]) => Promise.resolve({
results: result, total_results: totalRequests, page: page, total_pages: totalPages results: result, total_results: result.length, page: page, total_pages: totalPages
})) }))
.catch(error => { console.log(error);throw error }) .catch(error => { console.log(error);throw error })
} }

View File

@@ -1,3 +0,0 @@
{
"presets": ["@babel/preset-env"]
}

View File

@@ -18,12 +18,12 @@ class Cache {
* @returns {Object} * @returns {Object}
*/ */
get(key) { get(key) {
return Promise.resolve() return Promise.resolve()
.then(() => this.database.get(this.queries.read, [key])) .then(() => this.database.get(this.queries.read, [key]))
.then(row => { .then((row) => {
assert(row, 'Could not find cache entry with that key.'); assert(row, 'Could not find cache enrty with that key.');
return JSON.parse(row.value); return JSON.parse(row.value);
}) });
} }
/** /**

View File

@@ -0,0 +1,49 @@
const Movie = require('src/tmdb/types/movie');
const tmdbSwitcher = (tmdbMovie, property) => tmdbMovie[property]
function convertTmdbToMovie(tmdbMovie, credits=undefined) {
const movie = new Movie(tmdbMovie.id, tmdbMovie.title)
movie.overview = tmdbMovie.overview;
movie.rank = tmdbMovie.vote_average;
if (credits) {
movie.credits = credits;
}
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;

View File

@@ -0,0 +1,30 @@
const Person = require('src/tmdb/types/person');
const convertTmdbToMovie = require('src/tmdb/convertTmdbToMovie');
function convertTmdbToPerson(tmdbPerson, cast=undefined) {
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);
}
if (cast) {
person.cast = cast.cast;
}
return person;
}
module.exports = convertTmdbToPerson;

View File

@@ -0,0 +1,62 @@
const TMDB = require('src/media_classes/tmdb');
const Movie = require('src/types/movie');
function translateYear(tmdbReleaseDate) {
return new Date(tmdbReleaseDate).getFullYear();
}
function translateGenre(tmdbGenres) {
return tmdbGenres.map(genre => genre.name);
}
function convertType(tmdbType) {
if (tmdbType === 'tv') return 'show';
return undefined;
}
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.type) || 'movie';
const id = tmdb.id;
const summary = tmdb.overview;
const poster_path = tmdb.poster_path;
const background_path = tmdb.backdrop_path;
const popularity = tmdb.popularity;
const score = tmdb.vote_average;
// const genres = translateGenre(tmdb.genres);
const release_status = tmdb.status;
const tagline = tmdb.tagline;
const seasons = tmdb.number_of_seasons;
const episodes = tmdb.episodes;
const seasoned = new TMDB(
title, year, type, id, summary, poster_path, background_path,
popularity, score, release_status, tagline, seasons, episodes
);
// seasoned.print()
return seasoned;
}
module.exports = convertTmdbToSeasoned;

View File

@@ -0,0 +1,41 @@
const Show = require('src/tmdb/types/show');
function convertTmdbToShow(tmdbShow, credits=undefined) {
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 (credits) {
show.credits = credits
}
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;

View File

@@ -1,7 +1,7 @@
const moviedb = require('km-moviedb'); const moviedb = require('km-moviedb');
const convertTmdbToMovie = require('src/tmdb/convertTmdbToMovie');
const { Movie, Show, Person, Credits, ReleaseDates } = require('src/tmdb/types'); const convertTmdbToShow = require('src/tmdb/convertTmdbToShow');
// const { tmdbInfo } = require('src/tmdb/types') const convertTmdbToPerson = require('src/tmdb/convertTmdbToPerson');
class TMDB { class TMDB {
constructor(cache, apiKey, tmdbLibrary) { constructor(cache, apiKey, tmdbLibrary) {
@@ -13,10 +13,7 @@ class TMDB {
showSearch: 'ss', showSearch: 'ss',
personSearch: 'ps', personSearch: 'ps',
movieInfo: 'mi', movieInfo: 'mi',
movieCredits: 'mc',
movieReleaseDates: 'mrd',
showInfo: 'si', showInfo: 'si',
showCredits: 'sc',
personInfo: 'pi', personInfo: 'pi',
miscNowPlayingMovies: 'npm', miscNowPlayingMovies: 'npm',
miscPopularMovies: 'pm', miscPopularMovies: 'pm',
@@ -28,54 +25,70 @@ class TMDB {
}; };
} }
/**
* 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
*/
lookup(identifier, type = 'movie') {
const query = { id: identifier };
const cacheKey = `${this.cacheTags.info}:${type}:${identifier}`;
return Promise.resolve()
.then(() => this.cache.get(cacheKey))
.catch(() => this.tmdb(TMDB_METHODS['info'][type], query))
.catch(() => { throw new Error('Could not find a movie with that id.'); })
.then(response => this.cache.set(cacheKey, response))
.then(response => {
try {
return convertTmdbToSeasoned(response, type);
} catch (parseError) {
console.error(parseError);
throw new Error('Could not parse movie.');
}
});
}
/**
* Retrive search results from TMDB.
* @param {String} text query you want to search for
* @param {Number} page representing pagination of results
* @param {String} type filter results by type (default multi)
* @returns {Promise} dict with query results, current page and total_pages
*/
search(text, page = 1, type = 'multi') {
const query = { query: text, page: page };
const cacheKey = `${this.cacheTags.search}:${page}:${type}:${text}`;
return Promise.resolve()
.then(() => this.cache.get(cacheKey))
.catch(() => this.tmdb(TMDB_METHODS['search'][type], query))
.catch(() => { throw new Error('Could not search for movies/shows at tmdb.'); })
.then(response => this.cache.set(cacheKey, response))
.then(response => this.mapResults(response));
}
/** /**
* Retrieve a specific movie by id from TMDB. * Retrieve a specific movie by id from TMDB.
* @param {Number} identifier of the movie you want to retrieve * @param {Number} identifier of the movie you want to retrieve
* @param {Boolean} add credits (cast & crew) for movie * @param {String} type filter results by type (default movie).
* @param {Boolean} add release dates for every country
* @returns {Promise} succeeds if movie was found * @returns {Promise} succeeds if movie was found
*/ */
movieInfo(identifier) { movieInfo(identifier, credits=false) {
const query = { id: identifier }; const query = { id: identifier };
const cacheKey = `${this.cacheTags.movieInfo}:${identifier}`; const cacheKey = `${this.cacheTags.movieInfo}:${identifier}:${credits}`;
return this.cache.get(cacheKey) const requests = [this.tmdb('movieInfo', query)]
.catch(() => this.tmdb('movieInfo', query))
.catch(tmdbError => tmdbErrorResponse(tmdbError, 'movie info'))
.then(movie => this.cache.set(cacheKey, movie, 1))
.then(movie => Movie.convertFromTmdbResponse(movie))
}
/** if (credits) {
* Retrieve credits for a movie requests.push(this.tmdb('movieCredits', query))
* @param {Number} identifier of the movie to get credits for }
* @returns {Promise} movie cast object
*/
movieCredits(identifier) {
const query = { id: identifier }
const cacheKey = `${this.cacheTags.movieCredits}:${identifier}`
return this.cache.get(cacheKey) return Promise.resolve()
.catch(() => this.tmdb('movieCredits', query)) .then(() => this.cache.get(cacheKey))
.catch(tmdbError => tmdbErrorResponse(tmdbError, 'movie credits')) .catch(() => Promise.all(requests))
.then(credits => this.cache.set(cacheKey, credits, 1)) .catch((error) => { console.log(error); throw new Error('Could not find a movie with that id.'); })
.then(credits => Credits.convertFromTmdbResponse(credits)) .then(([movies, credits]) => this.cache.set(cacheKey, [movies, credits]))
} .then(([movies, credits]) => convertTmdbToMovie(movies, credits))
/**
* Retrieve release dates for a movie
* @param {Number} identifier of the movie to get release dates for
* @returns {Promise} movie release dates object
*/
movieReleaseDates(identifier) {
const query = { id: identifier }
const cacheKey = `${this.cacheTags.movieReleaseDates}:${identifier}`
return this.cache.get(cacheKey)
.catch(() => this.tmdb('movieReleaseDates', query))
.catch(tmdbError => tmdbErrorResponse(tmdbError, 'movie release dates'))
.then(releaseDates => this.cache.set(cacheKey, releaseDates, 1))
.then(releaseDates => ReleaseDates.convertFromTmdbResponse(releaseDates))
} }
/** /**
@@ -84,26 +97,22 @@ class TMDB {
* @param {String} type filter results by type (default show). * @param {String} type filter results by type (default show).
* @returns {Promise} succeeds if show was found * @returns {Promise} succeeds if show was found
*/ */
showInfo(identifier) { showInfo(identifier, credits=false) {
const query = { id: identifier }; const query = { id: identifier };
const cacheKey = `${this.cacheTags.showInfo}:${identifier}`; const cacheKey = `${this.cacheTags.showInfo}:${identifier}:${credits}`;
return this.cache.get(cacheKey) const requests = [this.tmdb('tvInfo', query)]
.catch(() => this.tmdb('tvInfo', query))
.catch(tmdbError => tmdbErrorResponse(tmdbError, 'tv info'))
.then(show => this.cache.set(cacheKey, show, 1))
.then(show => Show.convertFromTmdbResponse(show))
}
showCredits(identifier) { if (credits) {
const query = { id: identifier } requests.push(this.tmdb('tvCredits', query))
const cacheKey = `${this.cacheTags.showCredits}:${identifier}` }
return this.cache.get(cacheKey) return Promise.resolve()
.catch(() => this.tmdb('tvCredits', query)) .then(() => this.cache.get(cacheKey))
.catch(tmdbError => tmdbErrorResponse(tmdbError, 'show credits')) .catch(() => Promise.all(requests))
.then(credits => this.cache.set(cacheKey, credits, 1)) .catch(() => { throw new Error('Could not find a show with that id.'); })
.then(credits => Credits.convertFromTmdbResponse(credits)) .then(([shows, credits]) => this.cache.set(cacheKey, [shows, credits]))
.then(([shows, credits]) => convertTmdbToShow(shows, credits))
} }
/** /**
@@ -116,20 +125,25 @@ class TMDB {
const query = { id: identifier }; const query = { id: identifier };
const cacheKey = `${this.cacheTags.personInfo}:${identifier}`; const cacheKey = `${this.cacheTags.personInfo}:${identifier}`;
return this.cache.get(cacheKey) return Promise.resolve()
.catch(() => this.tmdb('personInfo', query)) .then(() => this.cache.get(cacheKey))
.catch(tmdbError => tmdbErrorResponse(tmdbError, 'person info')) .catch(() => Promise.all([this.tmdb('personInfo', query), this.tmdb('personCombinedCredits', query)]))
.then(person => this.cache.set(cacheKey, person, 1)) .catch(() => { throw new Error('Could not find a person with that id.'); })
.then(person => Person.convertFromTmdbResponse(person)) .then(([person, cast]) => this.cache.set(cacheKey, [person, cast]))
.then(([person, cast]) => convertTmdbToPerson(person, cast))
.catch(err => new Error('Unable to convert result to person', err))
} }
multiSearch(search_query, page=1) { multiSearch(search_query, page=1) {
const query = { query: search_query, page: page }; const query = { query: search_query, page: page };
const cacheKey = `${this.cacheTags.multiSearch}:${page}:${search_query}`; const cacheKey = `${this.cacheTags.multiSearch}:${page}:${search_query}`;
return this.cache.get(cacheKey) return Promise.resolve()
.then(() => this.cache.get(cacheKey))
.catch(() => this.tmdb('searchMulti', query)) .catch(() => this.tmdb('searchMulti', query))
.catch(tmdbError => tmdbErrorResponse(tmdbError, 'search results')) .catch(() => { throw new Error('Could not complete search to tmdb'); })
.then(response => this.cache.set(cacheKey, response, 1)) .then(response => this.cache.set(cacheKey, response))
.then(response => this.mapResults(response)); .then(response => this.mapResults(response));
} }
@@ -143,11 +157,13 @@ class TMDB {
const tmdbquery = { query: query, page: page }; const tmdbquery = { query: query, page: page };
const cacheKey = `${this.cacheTags.movieSearch}:${page}:${query}`; const cacheKey = `${this.cacheTags.movieSearch}:${page}:${query}`;
return this.cache.get(cacheKey) return Promise.resolve()
.catch(() => this.tmdb('searchMovie', tmdbquery)) .then(() => this.cache.get(cacheKey))
.catch(tmdbError => tmdbErrorResponse(tmdbError, 'movie search results')) .catch(() => this.tmdb('searchMovie', tmdbquery))
.then(response => this.cache.set(cacheKey, response, 1)) .catch(() => { throw new Error('Could not complete movie search to tmdb'); })
.then(response => this.mapResults(response, 'movie')) .then(response => this.cache.set(cacheKey, response))
.then(response => this.mapAndCreateResponse(response, convertTmdbToMovie))
.catch((error) => { console.log(error); throw new Error('Could not parse movie search result') })
} }
/** /**
@@ -159,12 +175,13 @@ class TMDB {
showSearch(query, page=1) { showSearch(query, page=1) {
const tmdbquery = { query: query, page: page }; const tmdbquery = { query: query, page: page };
const cacheKey = `${this.cacheTags.showSearch}:${page}:${query}`; const cacheKey = `${this.cacheTags.showSearch}:${page}:${query}`;
return Promise.resolve()
return this.cache.get(cacheKey) .then(() => this.cache.get(cacheKey))
.catch(() => this.tmdb('searchTv', tmdbquery)) .catch(() => this.tmdb('searchTv', tmdbquery))
.catch(tmdbError => tmdbErrorResponse(tmdbError, 'tv search results')) .catch(() => { throw new Error('Could not complete show search to tmdb'); })
.then(response => this.cache.set(cacheKey, response, 1)) .then(response => this.cache.set(cacheKey, response))
.then(response => this.mapResults(response, 'show')) .then(response => this.mapAndCreateResponse(response, convertTmdbToShow))
.catch((error) => { console.log(error); throw new Error('Could not parse show search result') })
} }
/** /**
@@ -174,36 +191,78 @@ class TMDB {
* @returns {Promise} dict with query results, current page and total_pages * @returns {Promise} dict with query results, current page and total_pages
*/ */
personSearch(query, page=1) { personSearch(query, page=1) {
const tmdbquery = { query: query, page: page };
const tmdbquery = { query: query, page: page, include_adult: true };
const cacheKey = `${this.cacheTags.personSearch}:${page}:${query}`; const cacheKey = `${this.cacheTags.personSearch}:${page}:${query}`;
return Promise.resolve()
return this.cache.get(cacheKey) .then(() => this.cache.get(cacheKey))
.catch(() => this.tmdb('searchPerson', tmdbquery)) .catch(() => this.tmdb('searchPerson', tmdbquery))
.catch(tmdbError => tmdbErrorResponse(tmdbError, 'person search results')) .catch(() => { throw new Error('Could not complete person search to tmdb'); })
.then(response => this.cache.set(cacheKey, response, 1)) .then(response => this.cache.set(cacheKey, response))
.then(response => this.mapResults(response, 'person')) .then(response => this.mapAndCreateResponse(response, convertTmdbToPerson))
.catch((error) => { console.log(error); throw new Error('Could not parse person search result') })
} }
mapAndCreateResponse(response, resultConvertFunction) {
// console.log(response)
return {
results: response.results.map(resultConvertFunction),
page: response.page,
total_results: response.total_results,
total_pages: response.total_pages
}
}
movieList(listname, page = 1) { movieList(listname, page = 1) {
const query = { page: page }; const query = { page: page };
const cacheKey = `${this.cacheTags[listname]}:${page}`; const cacheKey = `${this.cacheTags[listname]}:${page}`;
return this.cache.get(cacheKey) return Promise.resolve()
.then(() => this.cache.get(cacheKey))
.catch(() => this.tmdb(listname, query)) .catch(() => this.tmdb(listname, query))
.catch(tmdbError => this.tmdbErrorResponse(tmdbError, 'movie list ' + listname)) .catch(() => { throw new Error('Unable to get movie list from tmdb')})
.then(response => this.cache.set(cacheKey, response, 1)) .then(response => this.cache.set(cacheKey, response))
.then(response => this.mapResults(response, 'movie')) .then(response => this.mapAndCreateResponse(response, convertTmdbToMovie));
} }
showList(listname, page = 1) { showList(listname, page = 1) {
const query = { page: page }; const query = { page: page };
const cacheKey = `${this.cacheTags[listname]}:${page}`; const cacheKey = `${this.cacheTags[listname]}:${page}`;
return Promise.resolve()
return this.cache.get(cacheKey) .then(() => this.cache.get(cacheKey))
.catch(() => this.tmdb(listname, query)) .catch(() => this.tmdb(listname, query))
.catch(tmdbError => this.tmdbErrorResponse(tmdbError, 'show list ' + listname)) .catch(() => { throw new Error('Unable to get show list from tmdb')})
.then(response => this.cache.set(cacheKey, response, 1)) .then(response => this.cache.set(cacheKey, response))
.then(response => this.mapResults(response, 'show')) .then(response => this.mapAndCreateResponse(response, convertTmdbToShow));
}
/**
* Fetches a given list from tmdb.
* @param {String} listName Name of list
* @param {String} type filter results by type (default movie)
* @param {Number} page representing pagination of results
* @returns {Promise} dict with query results, current page and total_pages
*/
listSearch(listName, type = 'movie', page = '1') {
const query = { page: page };
console.log(query);
const cacheKey = `${this.cacheTags[listName]}:${type}:${page}`;
return Promise.resolve()
.then(() => this.cache.get(cacheKey))
.catch(() => this.tmdb(TMDB_METHODS[listName][type], query))
.catch(() => { throw new Error('Error fetching list from tmdb.'); })
.then(response => this.cache.set(cacheKey, response))
.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));
} }
/** /**
@@ -212,20 +271,14 @@ class TMDB {
* @param {String} The type declared in listSearch. * @param {String} The type declared in listSearch.
* @returns {Promise} dict with tmdb results, mapped as movie/show objects. * @returns {Promise} dict with tmdb results, mapped as movie/show objects.
*/ */
mapResults(response, type=undefined) { mapResults(response, _) {
// console.log(response.results) let results = response.results.map((result) => {
// response.results.map(te => console.table(te)) if (result.media_type === 'movie') {
return convertTmdbToMovie(result);
let results = response.results.map(result => { } else if (result.media_type === 'tv') {
if (type === 'movie' || result.media_type === 'movie') { return convertTmdbToShow(result);
const movie = Movie.convertFromTmdbResponse(result) } else if (result.media_type === 'person') {
return movie.createJsonResponse() return convertTmdbToPerson(result);
} else if (type === 'show' || result.media_type === 'tv') {
const show = Show.convertFromTmdbResponse(result)
return show.createJsonResponse()
} else if (type === 'person' || result.media_type === 'person') {
const person = Person.convertFromTmdbResponse(result)
return person.createJsonResponse()
} }
}) })
@@ -259,28 +312,6 @@ class TMDB {
} }
}); });
} }
}
function tmdbErrorResponse(error, typeString=undefined) {
if (error.status === 404) {
let message = error.response.body.status_message;
throw {
status: 404,
message: message.slice(0, -1) + " in tmdb."
}
} else if (error.status === 401) {
throw {
status: 401,
message: error.response.body.status_message
}
}
throw {
status: 500,
message: `An unexpected error occured while fetching ${typeString} from tmdb`
}
} }
module.exports = TMDB; module.exports = TMDB;

View File

@@ -1,7 +0,0 @@
import { Movie } from './types'
Movie('str', 123)
module.exports = TMDB;

View File

@@ -1,7 +0,0 @@
import Movie from './types/movie.js'
import Show from './types/show.js'
import Person from './types/person.js'
import Credits from './types/credits.js'
import ReleaseDates from './types/releaseDates.js'
module.exports = { Movie, Show, Person, Credits, ReleaseDates }

View File

@@ -1,64 +0,0 @@
interface Movie {
adult: boolean;
backdrop: string;
genres: Genre[];
id: number;
imdb_id: number;
overview: string;
popularity: number;
poster: string;
release_date: Date;
rank: number;
runtime: number;
status: string;
tagline: string;
title: string;
vote_count: number;
}
interface Show {
adult: boolean;
backdrop: string;
episodes: number;
genres: Genre[];
id: number;
imdb_id: number;
overview: string;
popularity: number;
poster: string;
rank: number;
runtime: number;
seasons: number;
status: string;
tagline: string;
title: string;
vote_count: number;
}
interface Person {
birthday: Date;
deathday: Date;
id: number;
known_for: string;
name: string;
poster: string;
}
interface SearchResult {
adult: boolean;
backdrop_path: string;
id: number;
original_title: string;
release_date: Date;
poster_path: string;
popularity: number;
vote_average: number;
vote_counte: number;
}
interface Genre {
id: number;
name: string;
}
export { Movie, Show, Person, Genre }

View File

@@ -1,75 +0,0 @@
class Credits {
constructor(id, cast=[], crew=[]) {
this.id = id;
this.cast = cast;
this.crew = crew;
this.type = 'credits';
}
static convertFromTmdbResponse(response) {
const { id, cast, crew } = response;
const allCast = cast.map(cast =>
new CastMember(cast.character, cast.gender, cast.id, cast.name, cast.profile_path))
const allCrew = crew.map(crew =>
new CrewMember(crew.department, crew.gender, crew.id, crew.job, crew.name, crew.profile_path))
return new Credits(id, allCast, allCrew)
}
createJsonResponse() {
return {
id: this.id,
cast: this.cast.map(cast => cast.createJsonResponse()),
crew: this.crew.map(crew => crew.createJsonResponse())
}
}
}
class CastMember {
constructor(character, gender, id, name, profile_path) {
this.character = character;
this.gender = gender;
this.id = id;
this.name = name;
this.profile_path = profile_path;
this.type = 'cast member';
}
createJsonResponse() {
return {
character: this.character,
gender: this.gender,
id: this.id,
name: this.name,
profile_path: this.profile_path,
type: this.type
}
}
}
class CrewMember {
constructor(department, gender, id, job, name, profile_path) {
this.department = department;
this.gender = gender;
this.id = id;
this.job = job;
this.name = name;
this.profile_path = profile_path;
this.type = 'crew member';
}
createJsonResponse() {
return {
department: this.department,
gender: this.gender,
id: this.id,
job: this.job,
name: this.name,
profile_path: this.profile_path,
type: this.type
}
}
}
module.exports = Credits;

View File

@@ -1,62 +1,20 @@
class Movie { class Movie {
constructor(id, title, year=undefined, overview=undefined, poster=undefined, backdrop=undefined, constructor(id, title, year=null, overview=null, poster=null, backdrop=null, rank=null, genres=null, status=null,
releaseDate=undefined, rating=undefined, genres=undefined, productionStatus=undefined, tagline=null, runtime=null, imdb_id=null) {
tagline=undefined, runtime=undefined, imdb_id=undefined, popularity=undefined) {
this.id = id; this.id = id;
this.title = title; this.title = title;
this.year = year; this.year = year;
this.overview = overview; this.overview = overview;
this.poster = poster; this.poster = poster;
this.backdrop = backdrop; this.backdrop = backdrop;
this.releaseDate = releaseDate; this.rank = rank;
this.rating = rating;
this.genres = genres; this.genres = genres;
this.productionStatus = productionStatus; this.status = status;
this.tagline = tagline; this.tagline = tagline;
this.runtime = runtime; this.runtime = runtime;
this.imdb_id = imdb_id; this.imdb_id = imdb_id;
this.popularity = popularity;
this.type = 'movie'; this.type = 'movie';
} }
static convertFromTmdbResponse(response) {
const { id, title, release_date, overview, poster_path, backdrop_path, vote_average, genres, status,
tagline, runtime, imdb_id, popularity } = response;
const releaseDate = new Date(release_date);
const year = releaseDate.getFullYear();
const genreNames = genres ? genres.map(g => g.name) : undefined
return new Movie(id, title, year, overview, poster_path, backdrop_path, releaseDate, vote_average, genreNames, status,
tagline, runtime, imdb_id, popularity)
}
static convertFromPlexResponse(response) {
// console.log('response', response)
const { title, year, rating, tagline, summary } = response;
const _ = undefined
return new Movie(null, title, year, summary, _, _, _, rating, _, _, tagline)
}
createJsonResponse() {
return {
id: this.id,
title: this.title,
year: this.year,
overview: this.overview,
poster: this.poster,
backdrop: this.backdrop,
release_date: this.releaseDate,
rating: this.rating,
genres: this.genres,
production_status: this.productionStatus,
tagline: this.tagline,
runtime: this.runtime,
imdb_id: this.imdb_id,
type: this.type
}
}
} }
module.exports = Movie; module.exports = Movie;

View File

@@ -1,37 +1,13 @@
class Person { class Person {
constructor(id, name, poster=undefined, birthday=undefined, deathday=undefined, constructor(id, name, poster=null, birthday=null, deathday=null, known_for=null) {
adult=undefined, knownForDepartment=undefined) {
this.id = id; this.id = id;
this.name = name; this.name = name;
this.poster = poster; this.poster = poster;
this.birthday = birthday; this.birthday = birthday;
this.deathday = deathday; this.deathday = deathday;
this.adult = adult; this.known_for = known_for;
this.knownForDepartment = knownForDepartment;
this.type = 'person'; this.type = 'person';
} }
static convertFromTmdbResponse(response) {
const { id, name, poster, birthday, deathday, adult, known_for_department } = response;
const birthDay = new Date(birthday)
const deathDay = deathday ? new Date(deathday) : null
return new Person(id, name, poster, birthDay, deathDay, adult, known_for_department)
}
createJsonResponse() {
return {
id: this.id,
name: this.name,
poster: this.poster,
birthday: this.birthday,
deathday: this.deathday,
known_for_department: this.knownForDepartment,
adult: this.adult,
type: this.type
}
}
} }
module.exports = Person; module.exports = Person;

View File

@@ -1,78 +0,0 @@
class ReleaseDates {
constructor(id, releases) {
this.id = id;
this.releases = releases;
}
static convertFromTmdbResponse(response) {
const { id, results } = response;
const releases = results.map(countryRelease =>
new Release(
countryRelease.iso_3166_1,
countryRelease.release_dates.map(rd => new ReleaseDate(rd.certification, rd.iso_639_1, rd.release_date, rd.type, rd.note))
))
return new ReleaseDates(id, releases)
}
createJsonResponse() {
return {
id: this.id,
results: this.releases.map(release => release.createJsonResponse())
}
}
}
class Release {
constructor(country, releaseDates) {
this.country = country;
this.releaseDates = releaseDates;
}
createJsonResponse() {
return {
country: this.country,
release_dates: this.releaseDates.map(releaseDate => releaseDate.createJsonResponse())
}
}
}
class ReleaseDate {
constructor(certification, language, releaseDate, type, note) {
this.certification = certification;
this.language = language;
this.releaseDate = releaseDate;
this.type = this.releaseTypeLookup(type);
this.note = note;
}
releaseTypeLookup(releaseTypeKey) {
const releaseTypeEnum = {
1: 'Premier',
2: 'Limited theatrical',
3: 'Theatrical',
4: 'Digital',
5: 'Physical',
6: 'TV'
}
if (releaseTypeKey <= Object.keys(releaseTypeEnum).length) {
return releaseTypeEnum[releaseTypeKey]
} else {
// TODO log | Release type not defined, does this need updating?
return null
}
}
createJsonResponse() {
return {
certification: this.certification,
language: this.language,
release_date: this.releaseDate,
type: this.type,
note: this.note
}
}
}
module.exports = ReleaseDates;

View File

@@ -1,50 +1,20 @@
class Show { class Show {
constructor(id, title, year=undefined, overview=undefined, poster=undefined, backdrop=undefined, constructor(id, title, year=null, seasons=null, episodes=null, overview=null, rank=null, genres=null,
seasons=undefined, episodes=undefined, rank=undefined, genres=undefined, status=undefined, poster=null, backdrop=null, status=null, runtime=null) {
runtime=undefined) {
this.id = id; this.id = id;
this.title = title; this.title = title;
this.year = year; this.year = year;
this.overview = overview;
this.poster = poster;
this.backdrop = backdrop;
this.seasons = seasons; this.seasons = seasons;
this.episodes = episodes; this.episodes = episodes;
this.overview = overview;
this.rank = rank; this.rank = rank;
this.genres = genres; this.genres = genres;
this.productionStatus = status; this.poster = poster;
this.backdrop = backdrop;
this.status = status;
this.runtime = runtime; this.runtime = runtime;
this.type = 'show'; this.type = 'show';
} }
static convertFromTmdbResponse(response) {
const { id, name, first_air_date, overview, poster_path, backdrop_path, number_of_seasons, number_of_episodes,
rank, genres, status, episode_run_time, popularity } = response;
const year = new Date(first_air_date).getFullYear()
const genreNames = genres ? genres.map(g => g.name) : undefined
return new Show(id, name, year, overview, poster_path, backdrop_path, number_of_seasons, number_of_episodes,
rank, genreNames, status, episode_run_time, popularity)
}
createJsonResponse() {
return {
id: this.id,
title: this.title,
year: this.year,
overview: this.overview,
poster: this.poster,
backdrop: this.backdrop,
seasons: this.seasons,
episodes: this.episodes,
rank: this.rank,
genres: this.genres,
production_status: this.productionStatus,
runtime: this.runtime,
type: this.type
}
}
} }
module.exports = Show; module.exports = Show;

View File

@@ -2,44 +2,36 @@ const User = require('src/user/user');
const jwt = require('jsonwebtoken'); const jwt = require('jsonwebtoken');
class Token { class Token {
constructor(user, admin=false) { constructor(user) {
this.user = user; this.user = user;
this.admin = admin; }
}
/** /**
* Generate a new token. * Generate a new token.
* @param {String} secret a cipher of the token * @param {String} secret a cipher of the token
* @returns {String} * @returns {String}
*/ */
toString(secret) { toString(secret) {
const username = this.user.username; return jwt.sign({ username: this.user.username }, secret);
const admin = this.admin; }
let data = { username }
if (admin) /**
data = { ...data, admin }
return jwt.sign(data, secret, { expiresIn: '90d' });
}
/**
* Decode a token. * Decode a token.
* @param {Token} jwtToken an encrypted token * @param {Token} jwtToken an encrypted token
* @param {String} secret a cipher of the token * @param {String} secret a cipher of the token
* @returns {Token} * @returns {Token}
*/ */
static fromString(jwtToken, secret) { static fromString(jwtToken, secret) {
let username = null; let username = null;
const token = jwt.verify(jwtToken, secret, { clockTolerance: 10000 }) try {
if (token.username === undefined || token.username === null) username = jwt.verify(jwtToken, secret).username;
throw new Error('Malformed token') } catch (error) {
throw new Error('The token is invalid.');
username = token.username }
const user = new User(username) const user = new User(username);
return new Token(user) return new Token(user);
} }
} }
module.exports = Token; module.exports = Token;

View File

@@ -26,7 +26,6 @@ class UserRepository {
if (error.name === 'AssertionError' || error.message.endsWith('user_name')) { if (error.name === 'AssertionError' || error.message.endsWith('user_name')) {
throw new Error('That username is already registered'); throw new Error('That username is already registered');
} }
throw Error(error)
}); });
} }

View File

@@ -1,72 +1,73 @@
const bcrypt = require('bcrypt'); const bcrypt = require('bcrypt-nodejs');
const UserRepository = require('src/user/userRepository'); const UserRepository = require('src/user/userRepository');
class UserSecurity { class UserSecurity {
constructor(database) { constructor(database) {
this.userRepository = new UserRepository(database); this.userRepository = new UserRepository(database);
} }
/** /**
* Create a new user in PlanFlix. * Create a new user in PlanFlix.
* @param {User} user the new user you want to create * @param {User} user the new user you want to create
* @param {String} clearPassword a password of the user * @param {String} clearPassword a password of the user
* @returns {Promise} * @returns {Promise}
*/ */
createNewUser(user, clearPassword) { createNewUser(user, clearPassword) {
if (user.username.trim() === '') { if (user.username.trim() === '') {
throw new Error('The username is empty.'); throw new Error('The username is empty.');
} else if (clearPassword.trim() === '') { } else if (clearPassword.trim() === '') {
throw new Error('The password is empty.'); throw new Error('The password is empty.');
} else { } else {
return Promise.resolve() return Promise.resolve()
.then(() => this.userRepository.create(user)) .then(() => this.userRepository.create(user))
.then(() => UserSecurity.hashPassword(clearPassword)) .then(() => UserSecurity.hashPassword(clearPassword))
.then(hash => this.userRepository.changePassword(user, hash)) .then(hash => this.userRepository.changePassword(user, hash));
} }
} }
/** /**
* Login into PlanFlix. * Login into PlanFlix.
* @param {User} user the user you want to login * @param {User} user the user you want to login
* @param {String} clearPassword the user's password * @param {String} clearPassword the user's password
* @returns {Promise} * @returns {Promise}
*/ */
login(user, clearPassword) { login(user, clearPassword) {
return Promise.resolve() return Promise.resolve()
.then(() => this.userRepository.retrieveHash(user)) .then(() => this.userRepository.retrieveHash(user))
.then(hash => UserSecurity.compareHashes(hash, clearPassword)) .then(hash => UserSecurity.compareHashes(hash, clearPassword))
.catch(() => { throw new Error('Incorrect username or password.'); }); .catch(() => { throw new Error('Wrong username or password.'); });
} }
/** /**
* Compare between a password and a hash password from database. * Compare between a password and a hash password from database.
* @param {String} hash the hash password from database * @param {String} hash the hash password from database
* @param {String} clearPassword the user's password * @param {String} clearPassword the user's password
* @returns {Promise} * @returns {Promise}
*/ */
static compareHashes(hash, clearPassword) { static compareHashes(hash, clearPassword) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
bcrypt.compare(clearPassword, hash, (error, match) => { bcrypt.compare(clearPassword, hash, (error, matches) => {
if (match) if (matches === true) {
resolve() resolve();
reject() } else {
reject();
}
});
}); });
}); }
}
/** /**
* Hashes a password. * Hashes a password.
* @param {String} clearPassword the user's password * @param {String} clearPassword the user's password
* @returns {Promise} * @returns {Promise}
*/ */
static hashPassword(clearPassword) { static hashPassword(clearPassword) {
return new Promise((resolve) => { return new Promise((resolve) => {
const saltRounds = 10; bcrypt.hash(clearPassword, null, null, (error, hash) => {
bcrypt.hash(clearPassword, saltRounds, (error, hash) => { resolve(hash);
resolve(hash); });
}); });
}); }
}
} }
module.exports = UserSecurity; module.exports = UserSecurity;

View File

@@ -28,6 +28,8 @@ router.use(tokenToUser);
// TODO: Should have a separate middleware/router for handling headers. // TODO: Should have a separate middleware/router for handling headers.
router.use((req, res, next) => { router.use((req, res, next) => {
// TODO add logging of all incoming // TODO add logging of all incoming
console.log('Request: ', req.originalUrl);
const origin = req.headers.origin; const origin = req.headers.origin;
if (allowedOrigins.indexOf(origin) > -1) { if (allowedOrigins.indexOf(origin) > -1) {
res.setHeader('Access-Control-Allow-Origin', origin); res.setHeader('Access-Control-Allow-Origin', origin);
@@ -77,14 +79,9 @@ router.get('/v2/show/now_playing', listController.nowPlayingShows);
router.get('/v2/show/popular', listController.popularShows); router.get('/v2/show/popular', listController.popularShows);
router.get('/v2/show/top_rated', listController.topRatedShows); router.get('/v2/show/top_rated', listController.topRatedShows);
router.get('/v2/movie/:id/credits', require('./controllers/movie/credits.js')); router.get('/v2/movie/:id', require('./controllers/info/movieInfo.js'));
router.get('/v2/movie/:id/release_dates', require('./controllers/movie/releaseDates.js')); router.get('/v2/show/:id', require('./controllers/info/showInfo.js'));
router.get('/v2/show/:id/credits', require('./controllers/show/credits.js')); router.get('/v2/person/:id', require('./controllers/info/personInfo.js'));
router.get('/v2/movie/:id', require('./controllers/movie/info.js'));
router.get('/v2/show/:id', require('./controllers/show/info.js'));
router.get('/v2/person/:id', require('./controllers/person/info.js'));
/** /**
* Plex * Plex
*/ */
@@ -116,6 +113,13 @@ router.put('/v1/plex/request/:requestId', mustBeAuthenticated, require('./contro
router.get('/v1/pirate/search', mustBeAuthenticated, require('./controllers/pirate/searchTheBay.js')); router.get('/v1/pirate/search', mustBeAuthenticated, require('./controllers/pirate/searchTheBay.js'));
router.post('/v1/pirate/add', mustBeAuthenticated, require('./controllers/pirate/addMagnet.js')); router.post('/v1/pirate/add', mustBeAuthenticated, require('./controllers/pirate/addMagnet.js'));
/**
* TMDB
*/
router.get('/v1/tmdb/search', require('./controllers/tmdb/searchMedia.js'));
router.get('/v1/tmdb/list/:listname', require('./controllers/tmdb/listSearch.js'));
router.get('/v1/tmdb/:mediaId', require('./controllers/tmdb/readMedia.js'));
/** /**
* git * git
*/ */

View File

@@ -0,0 +1,30 @@
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
* @param {Request} req http request variable
* @param {Response} res
* @returns {Callback}
*/
async function movieInfoController(req, res) {
const movieId = req.params.id;
const { credits } = req.query;
const movie = await tmdb.movieInfo(movieId, credits);
plex.existsInPlex(movie)
.catch((error) => { console.log('Error when searching plex'); })
.then(() => {
console.log('movie', movie)
res.send(movie);
}).catch((error) => {
res.status(404).send({ success: false, error: error.message });
});
}
module.exports = movieInfoController;

View File

@@ -13,12 +13,11 @@ const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
function personInfoController(req, res) { function personInfoController(req, res) {
const personId = req.params.id; const personId = req.params.id;
tmdb.personInfo(personId) tmdb.personInfo(personId)
.then(person => res.send(person.createJsonResponse())) .then((person) => {
.catch(error => { res.send(person);
res.status(404).send({ success: false, message: error.message }); }).catch((error) => {
res.status(404).send({ success: false, error: error.message });
}); });
} }

View File

@@ -0,0 +1,31 @@
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
* @param {Request} req http request variable
* @param {Response} res
* @returns {Callback}
*/
async function showInfoController(req, res) {
const showId = req.params.id;
const { credits } = req.query;
const show = await tmdb.showInfo(showId, credits);
plex.existsInPlex(show)
.catch((error) => { console.log('Error when searching plex'); })
.then(() => {
console.log('show', show)
res.send(show);
}).catch((error) => {
res.status(404).send({ success: false, error: error.message });
});
}
module.exports = showInfoController;

View File

@@ -16,55 +16,70 @@ const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
// + newly created (tv/latest). // + newly created (tv/latest).
// + movie/latest // + movie/latest
// //
function handleError(error, res) {
const { status, message } = error;
if (status && message) { function getTmdbMovieList(res, listname, page) {
res.status(status).send({ success: false, message }) Promise.resolve()
} else { .then(() => tmdb.movieList(listname, page))
console.log('caught list controller error', error) .then((response) => res.send(response))
res.status(500).send({ message: 'An unexpected error occured while requesting list'}) .catch((error) => {
} res.status(500).send({ success: false, error: error.message });
})
} }
function handleListResponse(response, res) { function getTmdbShowList(res, listname, page) {
return res.send(response) Promise.resolve()
.catch(error => handleError(error, res)) .then(() => tmdb.showList(listname, page))
.then((response) => res.send(response))
.catch((error) => {
res.status(500).send({ success: false, error: error.message });
})
} }
function fetchTmdbList(req, res, listname, type) { exports.nowPlayingMovies = (req, res) => {
const { page } = req.query; const { page } = req.query;
const listname = 'miscNowPlayingMovies'
if (type === 'movie') { getTmdbMovieList(res, listname, page);
return tmdb.movieList(listname, page)
.then(listResponse => res.send(listResponse))
.catch(error => handleError(error, res))
} else if (type === 'show') {
return tmdb.showList(listname, page)
.then(listResponse => res.send(listResponse))
.catch(error => handleError(error, res))
}
handleError({
status: 400,
message: `'${type}' is not a valid list type.`
}, res)
} }
const nowPlayingMovies = (req, res) => fetchTmdbList(req, res, 'miscNowPlayingMovies', 'movie') exports.popularMovies = (req, res) => {
const popularMovies = (req, res) => fetchTmdbList(req, res, 'miscPopularMovies', 'movie') const { page } = req.query;
const topRatedMovies = (req, res) => fetchTmdbList(req, res, 'miscTopRatedMovies', 'movie') const listname = 'miscPopularMovies'
const upcomingMovies = (req, res) => fetchTmdbList(req, res, 'miscUpcomingMovies', 'movie')
const nowPlayingShows = (req, res) => fetchTmdbList(req, res, 'tvOnTheAir', 'show')
const popularShows = (req, res) => fetchTmdbList(req, res, 'miscPopularTvs', 'show')
const topRatedShows = (req, res) => fetchTmdbList(req, res, 'miscTopRatedTvs', 'show')
module.exports = { getTmdbMovieList(res, listname, page);
nowPlayingMovies, }
popularMovies,
topRatedMovies, exports.topRatedMovies = (req, res) => {
upcomingMovies, const { page } = req.query;
nowPlayingShows, const listname = 'miscTopRatedMovies'
popularShows,
topRatedShows getTmdbMovieList(res, listname, page);
}
exports.upcomingMovies = (req, res) => {
const { page } = req.query;
const listname = 'miscUpcomingMovies'
getTmdbMovieList(res, listname, page);
}
exports.nowPlayingShows = (req, res) => {
const { page } = req.query;
const listname = 'tvOnTheAir'
getTmdbShowList(res, listname, page);
}
exports.popularShows = (req, res) => {
const { page } = req.query;
const listname = 'miscPopularTvs'
getTmdbShowList(res, listname, page);
}
exports.topRatedShows = (req, res) => {
const { page } = req.query;
const listname = 'miscTopRatedTvs'
getTmdbShowList(res, listname, page);
} }

View File

@@ -1,26 +0,0 @@
const configuration = require('src/config/configuration').getInstance();
const Cache = require('src/tmdb/cache');
const TMDB = require('src/tmdb/tmdb');
const cache = new Cache();
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
const movieCreditsController = (req, res) => {
const movieId = req.params.id;
tmdb.movieCredits(movieId)
.then(credits => res.send(credits.createJsonResponse()))
.catch(error => {
const { status, message } = error;
if (status && message) {
res.status(status).send({ success: false, message })
} else {
// TODO log unhandled errors
console.log('caugth movie credits controller error', error)
res.status(500).send({ message: 'An unexpected error occured while requesting movie credits' })
}
})
}
module.exports = movieCreditsController;

View File

@@ -1,58 +0,0 @@
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'));
function handleError(error, res) {
const { status, message } = error;
if (status && message) {
res.status(status).send({ success: false, message })
} else {
console.log('caught movieinfo controller error', error)
res.status(500).send({ message: 'An unexpected error occured while requesting movie info'})
}
}
/**
* Controller: Retrieve information for a movie
* @param {Request} req http request variable
* @param {Response} res
* @returns {Callback}
*/
async function movieInfoController(req, res) {
const movieId = req.params.id;
let { credits, release_dates, check_existance } = req.query;
credits && credits.toLowerCase() === 'true' ? credits = true : credits = false
release_dates && release_dates.toLowerCase() === 'true' ? release_dates = true : release_dates = false
check_existance && check_existance.toLowerCase() === 'true' ? check_existance = true : check_existance = false
let tmdbQueue = [tmdb.movieInfo(movieId)]
if (credits)
tmdbQueue.push(tmdb.movieCredits(movieId))
if (release_dates)
tmdbQueue.push(tmdb.movieReleaseDates(movieId))
try {
const [ Movie, Credits, ReleaseDates ] = await Promise.all(tmdbQueue)
const movie = Movie.createJsonResponse()
if (Credits)
movie.credits = Credits.createJsonResponse()
if (ReleaseDates)
movie.release_dates = ReleaseDates.createJsonResponse().results
if (check_existance)
movie.exists_in_plex = await plex.existsInPlex(movie)
res.send(movie)
} catch(error) {
handleError(error, res)
}
}
module.exports = movieInfoController;

View File

@@ -1,26 +0,0 @@
const configuration = require('src/config/configuration').getInstance();
const Cache = require('src/tmdb/cache');
const TMDB = require('src/tmdb/tmdb');
const cache = new Cache();
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
const movieReleaseDatesController = (req, res) => {
const movieId = req.params.id;
tmdb.movieReleaseDates(movieId)
.then(releaseDates => res.send(releaseDates.createJsonResponse()))
.catch(error => {
const { status, message } = error;
if (status && message) {
res.status(status).send({ success: false, message })
} else {
// TODO log unhandled errors : here our at tmdbReleaseError ?
console.log('caugth release dates controller error', error)
res.status(500).send({ message: 'An unexpected error occured while requesting movie credits' })
}
})
}
module.exports = movieReleaseDatesController;

View File

@@ -17,8 +17,8 @@ function addMagnet(req, res) {
.then((result) => { .then((result) => {
res.send(result); res.send(result);
}) })
.catch(error => { .catch((error) => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, error: error.message });
}); });
} }

View File

@@ -21,8 +21,8 @@ function updateRequested(req, res) {
.then((result) => { .then((result) => {
res.send({ success: true, results: result }); res.send({ success: true, results: result });
}) })
.catch(error => { .catch((error) => {
res.status(401).send({ success: false, message: error.message }); res.status(401).send({ success: false, error: error.message });
}); });
} }

View File

@@ -17,7 +17,7 @@ function fetchRequestedController(req, res) {
res.send({ success: true, results: requestedItems, total_results: requestedItems.length }); res.send({ success: true, results: requestedItems, total_results: requestedItems.length });
}) })
.catch((error) => { .catch((error) => {
res.status(401).send({ success: false, message: error.message }); res.status(401).send({ success: false, error: error.message });
}); });
} }

View File

@@ -5,11 +5,11 @@ const plexRepository = new PlexRepository(configuration.get('plex', 'ip'));
function playingController(req, res) { function playingController(req, res) {
plexRepository.nowPlaying() plexRepository.nowPlaying()
.then(movies => { .then((movies) => {
res.send(movies); res.send(movies);
}) })
.catch(error => { .catch((error) => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, error: error.message });
}); });
} }

View File

@@ -12,10 +12,10 @@ function readRequestController(req, res) {
const mediaId = req.params.mediaId; const mediaId = req.params.mediaId;
const { type } = req.query; const { type } = req.query;
requestRepository.lookup(mediaId, type) requestRepository.lookup(mediaId, type)
.then(movies => { .then((movies) => {
res.send(movies); res.send(movies);
}).catch(error => { }).catch((error) => {
res.status(404).send({ success: false, message: error.message }); res.status(404).send({ success: false, error: error.message });
}); });
} }

View File

@@ -11,14 +11,14 @@ const plex = new Plex(configuration.get('plex', 'ip'));
function searchPlexController(req, res) { function searchPlexController(req, res) {
const { query, type } = req.query; const { query, type } = req.query;
plex.search(query, type) plex.search(query, type)
.then(movies => { .then((movies) => {
if (movies.length > 0) { if (movies.length > 0) {
res.send(movies); res.send(movies);
} else { } else {
res.status(404).send({ success: false, message: 'Search query did not give any results from plex.'}) res.status(404).send({ success: false, error: 'Search query did not give any results from plex.'})
} }
}).catch(error => { }).catch((error) => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, error: error.message });
}); });
} }

View File

@@ -14,15 +14,15 @@ function searchMediaController(req, res) {
const { query } = req.query; const { query } = req.query;
plexRepository.search(query) plexRepository.search(query)
.then(media => { .then((media) => {
if (media !== undefined || media.length > 0) { if (media !== undefined || media.length > 0) {
res.send(media); res.send(media);
} else { } else {
res.status(404).send({ success: false, message: 'Search query did not return any results.' }); res.status(404).send({ success: false, error: 'Search query did not return any results.' });
} }
}) })
.catch(error => { .catch((error) => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, error: error.message });
}); });
} }

View File

@@ -18,8 +18,8 @@ function searchRequestController(req, res) {
.then((searchResult) => { .then((searchResult) => {
res.send(searchResult); res.send(searchResult);
}) })
.catch(error => { .catch((error) => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, error: error });
}); });
} }

View File

@@ -37,7 +37,7 @@ function submitRequestController(req, res) {
console.log('show') console.log('show')
mediaFunction = tmdbShowInfo mediaFunction = tmdbShowInfo
} else { } else {
res.status(422).send({ success: false, message: 'Incorrect type. Allowed types: "movie" or "show"'}) res.status(422).send({ success: false, error: 'Incorrect type. Allowed types: "movie" or "show"'})
} }
if (mediaFunction === undefined) { res.status(200); return } if (mediaFunction === undefined) { res.status(200); return }
@@ -45,7 +45,7 @@ function submitRequestController(req, res) {
mediaFunction(id) mediaFunction(id)
.then(tmdbMedia => request.requestFromTmdb(tmdbMedia, ip, user_agent, user)) .then(tmdbMedia => request.requestFromTmdb(tmdbMedia, ip, user_agent, user))
.then(() => res.send({ success: true, message: 'Media item successfully requested' })) .then(() => res.send({ success: true, message: 'Media item successfully requested' }))
.catch(err => res.status(500).send({ success: false, message: err.message })) .catch(err => res.status(500).send({ success: false, error: err.message }))
} }
module.exports = submitRequestController; module.exports = submitRequestController;

View File

@@ -18,7 +18,7 @@ function updateRequested(req, res) {
res.send({ success: true }); res.send({ success: true });
}) })
.catch((error) => { .catch((error) => {
res.status(401).send({ success: false, message: error.message }); res.status(401).send({ success: false, error: error.message });
}); });
} }

View File

@@ -18,9 +18,9 @@ function fetchAllRequests(req, res) {
Promise.resolve() Promise.resolve()
.then(() => request.fetchAll(page, sort_by, sort_direction, filter, query)) .then(() => request.fetchAll(page, sort_by, sort_direction, filter, query))
.then(result => res.send(result)) .then((result) => res.send(result))
.catch(error => { .catch((error) => {
res.status(404).send({ success: false, message: error.message }); res.status(404).send({ success: false, error: error.message });
}); });
} }

View File

@@ -11,10 +11,11 @@ function fetchAllRequests(req, res) {
const id = req.params.id; const id = req.params.id;
const { type } = req.query; const { type } = req.query;
request.getRequestByIdAndType(id, type) Promise.resolve()
.then(result => res.send(result)) .then(() => request.getRequestByIdAndType(id, type))
.catch(error => { .then((result) => res.send(result))
res.status(404).send({ success: false, message: error.message }); .catch((error) => {
res.status(404).send({ success: false, error: error.message });
}); });
} }

View File

@@ -22,31 +22,30 @@ const tmdbShowInfo = (id) => {
*/ */
function requestTmdbIdController(req, res) { function requestTmdbIdController(req, res) {
const { id, type } = req.body const { id, type } = req.body
console.log('body', req.body)
console.log('id & type', id, type)
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress; const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
const user_agent = req.headers['user-agent']; const user_agent = req.headers['user-agent'];
const user = req.loggedInUser; const user = req.loggedInUser;
let mediaFunction = undefined let mediaFunction = undefined
if (id === undefined || type === undefined) {
res.status(422).send({ success: false, message: "'Missing parameteres: 'id' and/or 'type'"})
}
if (type === 'movie') { if (type === 'movie') {
console.log('movie')
mediaFunction = tmdbMovieInfo mediaFunction = tmdbMovieInfo
} else if (type === 'show') { } else if (type === 'show') {
console.log('show')
mediaFunction = tmdbShowInfo mediaFunction = tmdbShowInfo
} else { } else {
res.status(422).send({ success: false, message: 'Incorrect type. Allowed types: "movie" or "show"'}) res.status(422).send({ success: false, error: 'Incorrect type. Allowed types: "movie" or "show"'})
} }
mediaFunction(id) mediaFunction(id)
// .catch((error) => { console.error(error); res.status(404).send({ success: false, error: 'Id not found' }) }) .catch((error) => { console.error(error); res.status(404).send({ success: false, error: 'Id not found' }) })
.then(tmdbMedia => request.requestFromTmdb(tmdbMedia, ip, user_agent, user)) .then((tmdbMedia) => request.requestFromTmdb(tmdbMedia, ip, user_agent, user))
.then(() => res.send({success: true, message: 'Request has been submitted.'})) .then(() => res.send({success: true, message: 'Request has been submitted.'}))
.catch(error => { .catch((error) => {
res.send({ success: false, message: error.message }); res.status(501).send({ success: false, error: error.message });
}) })
} }

View File

@@ -1,7 +1,7 @@
const SearchHistory = require('src/searchHistory/searchHistory');
const configuration = require('src/config/configuration').getInstance(); const configuration = require('src/config/configuration').getInstance();
const Cache = require('src/tmdb/cache'); const Cache = require('src/tmdb/cache');
const TMDB = require('src/tmdb/tmdb'); const TMDB = require('src/tmdb/tmdb');
const SearchHistory = require('src/searchHistory/searchHistory');
const cache = new Cache(); const cache = new Cache();
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey')); const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
const searchHistory = new SearchHistory(); const searchHistory = new SearchHistory();
@@ -16,25 +16,20 @@ function movieSearchController(req, res) {
const user = req.loggedInUser; const user = req.loggedInUser;
const { query, page } = req.query; const { query, page } = req.query;
if (user) { Promise.resolve()
return searchHistory.create(user, query); .then(() => {
} if (user) {
return searchHistory.create(user, query);
tmdb.movieSearch(query, page) }
.then(movieSearchResults => res.send(movieSearchResults)) return null
.catch(error => { })
const { status, message } = error; .then(() => tmdb.movieSearch(query, page))
.then((movies) => {
if (status && message) { res.send(movies);
res.status(status).send({ success: false, message }) })
} else { .catch((error) => {
// TODO log unhandled errors res.status(500).send({ success: false, error: error.message });
console.log('caugth movie search controller error', error) });
res.status(500).send({
message: `An unexpected error occured while searching movies with query: ${query}`
})
}
})
} }
module.exports = movieSearchController; module.exports = movieSearchController;

View File

@@ -1,18 +1,11 @@
const SearchHistory = require('src/searchHistory/searchHistory');
const configuration = require('src/config/configuration').getInstance(); const configuration = require('src/config/configuration').getInstance();
const Cache = require('src/tmdb/cache'); const Cache = require('src/tmdb/cache');
const TMDB = require('src/tmdb/tmdb'); const TMDB = require('src/tmdb/tmdb');
const SearchHistory = require('src/searchHistory/searchHistory');
const cache = new Cache(); const cache = new Cache();
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey')); const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
const searchHistory = new SearchHistory(); const searchHistory = new SearchHistory();
function checkAndCreateJsonResponse(result) {
if (typeof result['createJsonResponse'] === 'function') {
return result.createJsonResponse()
}
return result
}
/** /**
* Controller: Search for multi (movies, shows and people by query and pagey * Controller: Search for multi (movies, shows and people by query and pagey
* @param {Request} req http request variable * @param {Request} req http request variable
@@ -23,23 +16,20 @@ function multiSearchController(req, res) {
const user = req.loggedInUser; const user = req.loggedInUser;
const { query, page } = req.query; const { query, page } = req.query;
if (user) { Promise.resolve()
searchHistory.create(user, query) .then(() => {
} if (user) {
return searchHistory.create(user, query);
return tmdb.multiSearch(query, page)
.then(multiSearchResults => res.send(multiSearchResults))
.catch(error => {
const { status, message } = error;
if (status && message) {
res.status(status).send({ success: false, message })
} else {
// TODO log unhandled errors
console.log('caugth multi search controller error', error)
res.status(500).send({ message: `An unexpected error occured while searching with query: ${query}` })
} }
return null
}) })
.then(() => tmdb.multiSearch(query, page))
.then((result) => {
res.send(result);
})
.catch((error) => {
res.status(500).send({ success: false, error: error.message });
});
} }
module.exports = multiSearchController; module.exports = multiSearchController;

View File

@@ -1,7 +1,7 @@
const SearchHistory = require('src/searchHistory/searchHistory');
const configuration = require('src/config/configuration').getInstance(); const configuration = require('src/config/configuration').getInstance();
const Cache = require('src/tmdb/cache'); const Cache = require('src/tmdb/cache');
const TMDB = require('src/tmdb/tmdb'); const TMDB = require('src/tmdb/tmdb');
const SearchHistory = require('src/searchHistory/searchHistory');
const cache = new Cache(); const cache = new Cache();
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey')); const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
const searchHistory = new SearchHistory(); const searchHistory = new SearchHistory();
@@ -16,27 +16,20 @@ function personSearchController(req, res) {
const user = req.loggedInUser; const user = req.loggedInUser;
const { query, page } = req.query; const { query, page } = req.query;
if (user) { Promise.resolve()
return searchHistory.create(user, query); .then(() => {
} if (user) {
return searchHistory.create(user, query);
tmdb.personSearch(query, page) }
.then((person) => { return null
res.send(person); })
}) .then(() => tmdb.personSearch(query, page))
.catch(error => { .then((person) => {
const { status, message } = error; res.send(person);
})
if (status && message) { .catch((error) => {
res.status(status).send({ success: false, message }) res.status(500).send({ success: false, error: error.message });
} else { });
// TODO log unhandled errors
console.log('caugth person search controller error', error)
res.status(500).send({
message: `An unexpected error occured while searching people with query: ${query}`
})
}
})
} }
module.exports = personSearchController; module.exports = personSearchController;

View File

@@ -27,8 +27,8 @@ function showSearchController(req, res) {
.then((shows) => { .then((shows) => {
res.send(shows); res.send(shows);
}) })
.catch(error => { .catch((error) => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, error: error.message });
}); });
} }

View File

@@ -10,7 +10,7 @@ function readStraysController(req, res) {
res.send(strays); res.send(strays);
}) })
.catch((error) => { .catch((error) => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, error: error.message });
}); });
} }

View File

@@ -10,7 +10,7 @@ function strayByIdController(req, res) {
res.send(stray); res.send(stray);
}) })
.catch((error) => { .catch((error) => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, error: error.message });
}); });
} }

View File

@@ -10,7 +10,7 @@ function verifyStrayController(req, res) {
res.send({ success: true, message: 'Episode verified' }); res.send({ success: true, message: 'Episode verified' });
}) })
.catch((error) => { .catch((error) => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, error: error.message });
}); });
} }

View File

@@ -1,26 +0,0 @@
const configuration = require('src/config/configuration').getInstance();
const Cache = require('src/tmdb/cache');
const TMDB = require('src/tmdb/tmdb');
const cache = new Cache();
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
const showCreditsController = (req, res) => {
const showId = req.params.id;
tmdb.showCredits(showId)
.then(credits => res.send(credits.createJsonResponse()))
.catch(error => {
const { status, message } = error;
if (status && message) {
res.status(status).send({ success: false, message })
} else {
// TODO log unhandled errors
console.log('caugth show credits controller error', error)
res.status(500).send({ message: 'An unexpected error occured while requesting show credits' })
}
})
}
module.exports = showCreditsController;

View File

@@ -1,56 +0,0 @@
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'));
function handleError(error, res) {
const { status, message } = error;
if (status && message) {
res.status(status).send({ success: false, message })
} else {
console.log('caught showinfo controller error', error)
res.status(500).send({
message: 'An unexpected error occured while requesting show info.'
})
}
}
/**
* Controller: Retrieve information for a show
* @param {Request} req http request variable
* @param {Response} res
* @returns {Callback}
*/
async function showInfoController(req, res) {
const showId = req.params.id;
let { credits, check_existance } = req.query;
credits && credits.toLowerCase() === 'true' ? credits = true : credits = false
check_existance && check_existance.toLowerCase() === 'true' ? check_existance = true : check_existance = false
let tmdbQueue = [tmdb.showInfo(showId)]
if (credits)
tmdbQueue.push(tmdb.showCredits(showId))
try {
const [Show, Credits] = await Promise.all(tmdbQueue)
const show = Show.createJsonResponse()
if (credits)
show.credits = Credits.createJsonResponse()
if (check_existance)
show.exists_in_plex = await plex.existsInPlex(show)
res.send(show)
} catch(error) {
handleError(error, res)
}
}
module.exports = showInfoController;

View File

@@ -0,0 +1,25 @@
const configuration = require('src/config/configuration').getInstance();
const Cache = require('src/tmdb/cache');
const TMDB = require('src/tmdb/tmdb');
const cache = new Cache();
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
/**
* Controller: Retrieve nowplaying movies / now airing shows
* @param {Request} req http request variable
* @param {Response} res
* @returns {Callback}
*/
function listSearchController(req, res) {
const listname = req.params.listname;
const { type, page } = req.query;
tmdb.listSearch(listname, type, page)
.then((results) => {
res.send(results);
}).catch((error) => {
res.status(404).send({ success: false, error: error.message });
});
}
module.exports = listSearchController;

View File

@@ -0,0 +1,25 @@
const configuration = require('src/config/configuration').getInstance();
const Cache = require('src/tmdb/cache');
const TMDB = require('src/tmdb/tmdb');
const cache = new Cache();
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
/**
* Controller: Retrieve information for a movie
* @param {Request} req http request variable
* @param {Response} res
* @returns {Callback}
*/
function readMediaController(req, res) {
const mediaId = req.params.mediaId;
const { type } = req.query;
tmdb.lookup(mediaId, type)
.then((movies) => {
res.send(movies);
}).catch((error) => {
res.status(404).send({ success: false, error: error.message });
});
}
module.exports = readMediaController;

View File

@@ -0,0 +1,31 @@
const configuration = require('src/config/configuration').getInstance();
const Cache = require('src/tmdb/cache');
const TMDB = require('src/tmdb/tmdb');
const cache = new Cache();
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
/**
* Controller: Search for movies by query, page and optional type
* @param {Request} req http request variable
* @param {Response} res
* @returns {Callback}
*/
function searchMediaController(req, res) {
const { query, page, type } = req.query;
Promise.resolve()
.then(() => tmdb.search(query, page, type))
.then((movies) => {
if (movies !== undefined || movies.length > 0) {
res.send(movies);
} else {
res.status(404).send({ success: false, error: 'Search query did not return any results.' });
}
})
.catch((error) => {
res.status(500).send({ success: false, error: error.message });
});
}
module.exports = searchMediaController;

View File

@@ -13,11 +13,11 @@ function historyController(req, res) {
const username = user === undefined ? undefined : user.username; const username = user === undefined ? undefined : user.username;
searchHistory.read(username) searchHistory.read(username)
.then(searchQueries => { .then((searchQueries) => {
res.send({ success: true, searchQueries }); res.send({ success: true, searchQueries });
}) })
.catch(error => { .catch((error) => {
res.status(404).send({ success: false, message: error.message }); res.status(404).send({ success: false, error: error });
}); });
} }

View File

@@ -20,13 +20,13 @@ function loginController(req, res) {
userSecurity.login(user, password) userSecurity.login(user, password)
.then(() => userRepository.checkAdmin(user)) .then(() => userRepository.checkAdmin(user))
.then(checkAdmin => { .then((checkAdmin) => {
const isAdmin = checkAdmin === 1 ? true : false; const token = new Token(user).toString(secret);
const token = new Token(user, isAdmin).toString(secret); const admin_state = checkAdmin === 1 ? true : false;
res.send({ success: true, token }); res.send({ success: true, token, admin: admin_state });
}) })
.catch(error => { .catch((error) => {
res.status(401).send({ success: false, message: error.message }); res.status(401).send({ success: false, error: error.message });
}); });
} }

View File

@@ -20,15 +20,15 @@ function registerController(req, res) {
userSecurity.createNewUser(user, password) userSecurity.createNewUser(user, password)
.then(() => userRepository.checkAdmin(user)) .then(() => userRepository.checkAdmin(user))
.then(checkAdmin => { .then((checkAdmin) => {
const isAdmin = checkAdmin === 1 ? true : false; const token = new Token(user).toString(secret);
const token = new Token(user, isAdmin).toString(secret); const admin_state = checkAdmin === 1 ? true : false;
res.send({ res.send({
success: true, message: 'Welcome to Seasoned!', token success: true, message: 'Welcome to Seasoned!', token, admin: admin_state,
}); });
}) })
.catch(error => { .catch((error) => {
res.status(401).send({ success: false, message: error.message }); res.status(401).send({ success: false, error: error.message });
}); });
} }

View File

@@ -12,11 +12,12 @@ function requestsController(req, res) {
const user = req.loggedInUser; const user = req.loggedInUser;
requestRepository.userRequests(user) requestRepository.userRequests(user)
.then(requests => { .then((requests) => {
res.send({ success: true, results: requests, total_results: requests.length }); res.send({ success: true, results: requests, total_results: requests.length });
}) })
.catch(error => { .catch((error) => {
res.status(500).send({ success: false, message: error.message }); console.log(error)
res.status(500).send({ success: false, error: error });
}); });
} }

View File

@@ -8,16 +8,16 @@ const Token = require('src/user/token');
// curl -i -H "Authorization:[token]" localhost:31459/api/v1/user/history // curl -i -H "Authorization:[token]" localhost:31459/api/v1/user/history
const tokenToUser = (req, res, next) => { const tokenToUser = (req, res, next) => {
const rawToken = req.headers.authorization; const rawToken = req.headers.authorization;
if (rawToken) { if (rawToken) {
try { try {
const token = Token.fromString(rawToken, secret); const token = Token.fromString(rawToken, secret);
req.loggedInUser = token.user; req.loggedInUser = token.user;
} catch (error) { } catch (error) {
req.loggedInUser = undefined; req.loggedInUser = undefined;
} }
} }
next(); next();
}; };
module.exports = tokenToUser; module.exports = tokenToUser;

View File

@@ -1 +1 @@
[{"adult":false,"backdrop_path":"/mVr0UiqyltcfqxbAUcLl9zWL8ah.jpg","belongs_to_collection":{"id":422837,"name":"Blade Runner Collection","poster_path":"/cWESb1o9lW2i2Z3Xllv9u40aNIk.jpg","backdrop_path":"/bSHZIvLoPBWyGLeiAudN1mXdvQX.jpg"},"budget":150000000,"genres":[{"id":9648,"name":"Mystery"},{"id":878,"name":"Science Fiction"},{"id":53,"name":"Thriller"}],"homepage":"http://bladerunnermovie.com/","id":335984,"imdb_id":"tt1856101","original_language":"en","original_title":"Blade Runner 2049","overview":"Thirty years after the events of the first film, a new blade runner, LAPD Officer K, unearths a long-buried secret that has the potential to plunge what's left of society into chaos. K's discovery leads him on a quest to find Rick Deckard, a former LAPD blade runner who has been missing for 30 years.","popularity":30.03,"poster_path":"/gajva2L0rPYkEWjzgFlBXCAVBE5.jpg","production_companies":[{"id":79529,"logo_path":"/gVN3k8emmKy4iV4KREWcCtxusZK.png","name":"Torridon Films","origin_country":"US"},{"id":101829,"logo_path":"/8IOjCvgjq0zTrtP91cWD3kL2jMK.png","name":"16:14 Entertainment","origin_country":"US"},{"id":1645,"logo_path":"/6Ry6uNBaa0IbbSs1XYIgX5DkA9r.png","name":"Scott Free Productions","origin_country":""},{"id":5,"logo_path":"/71BqEFAF4V3qjjMPCpLuyJFB9A.png","name":"Columbia Pictures","origin_country":"US"},{"id":1088,"logo_path":"/9WOE5AQUXbOtLU6GTwfjS8OMF0v.png","name":"Alcon Entertainment","origin_country":"US"},{"id":78028,"logo_path":"/sTFcDFfJaSVT3sv3DoaZDE4SlGB.png","name":"Thunderbird Entertainment","origin_country":"CA"},{"id":174,"logo_path":"/ky0xOc5OrhzkZ1N6KyUxacfQsCk.png","name":"Warner Bros. Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"CA","name":"Canada"},{"iso_3166_1":"US","name":"United States of America"},{"iso_3166_1":"HU","name":"Hungary"},{"iso_3166_1":"GB","name":"United Kingdom"}],"release_date":"2017-10-04","revenue":259239658,"runtime":163,"spoken_languages":[{"iso_639_1":"en","name":"English"},{"iso_639_1":"fi","name":"suomi"}],"status":"Released","tagline":"There's still a page left.","title":"Blade Runner 2049","video":false,"vote_average":7.3,"vote_count":5478}] {"adult":false,"backdrop_path":"/mVr0UiqyltcfqxbAUcLl9zWL8ah.jpg","belongs_to_collection":{"id":422837,"name":"Blade Runner Collection","poster_path":"/cWESb1o9lW2i2Z3Xllv9u40aNIk.jpg","backdrop_path":"/bSHZIvLoPBWyGLeiAudN1mXdvQX.jpg"},"budget":150000000,"genres":[{"id":9648,"name":"Mystery"},{"id":878,"name":"Science Fiction"},{"id":53,"name":"Thriller"}],"homepage":"http://bladerunnermovie.com/","id":335984,"imdb_id":"tt1856101","original_language":"en","original_title":"Blade Runner 2049","overview":"Thirty years after the events of the first film, a new blade runner, LAPD Officer K, unearths a long-buried secret that has the potential to plunge what's left of society into chaos. K's discovery leads him on a quest to find Rick Deckard, a former LAPD blade runner who has been missing for 30 years.","popularity":30.03,"poster_path":"/gajva2L0rPYkEWjzgFlBXCAVBE5.jpg","production_companies":[{"id":79529,"logo_path":"/gVN3k8emmKy4iV4KREWcCtxusZK.png","name":"Torridon Films","origin_country":"US"},{"id":101829,"logo_path":"/8IOjCvgjq0zTrtP91cWD3kL2jMK.png","name":"16:14 Entertainment","origin_country":"US"},{"id":1645,"logo_path":"/6Ry6uNBaa0IbbSs1XYIgX5DkA9r.png","name":"Scott Free Productions","origin_country":""},{"id":5,"logo_path":"/71BqEFAF4V3qjjMPCpLuyJFB9A.png","name":"Columbia Pictures","origin_country":"US"},{"id":1088,"logo_path":"/9WOE5AQUXbOtLU6GTwfjS8OMF0v.png","name":"Alcon Entertainment","origin_country":"US"},{"id":78028,"logo_path":"/sTFcDFfJaSVT3sv3DoaZDE4SlGB.png","name":"Thunderbird Entertainment","origin_country":"CA"},{"id":174,"logo_path":"/ky0xOc5OrhzkZ1N6KyUxacfQsCk.png","name":"Warner Bros. Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"CA","name":"Canada"},{"iso_3166_1":"US","name":"United States of America"},{"iso_3166_1":"HU","name":"Hungary"},{"iso_3166_1":"GB","name":"United Kingdom"}],"release_date":"2017-10-04","revenue":259239658,"runtime":163,"spoken_languages":[{"iso_639_1":"en","name":"English"},{"iso_639_1":"fi","name":"suomi"}],"status":"Released","tagline":"There's still a page left.","title":"Blade Runner 2049","video":false,"vote_average":7.3,"vote_count":5478}

View File

@@ -1,6 +0,0 @@
{
"page":1,
"results":[],
"total_results":0,
"total_pages":1
}

File diff suppressed because one or more lines are too long

View File

@@ -1,16 +0,0 @@
const tmdbMock = () => ({
error: null,
response: null,
searchMovie(query, callback) {
callback(this.error, this.response);
},
movieInfo(query, callback) {
callback(this.error, this.response);
},
miscPopularMovies(callback) {
console.log('miscPopMovies callback', callback)
callback(this.error, this.response);
},
});
module.exports = tmdbMock;

View File

@@ -5,8 +5,8 @@ xdescribe('As a developer I want the server to start', () => {
beforeEach(() => beforeEach(() =>
this.server = require('src/webserver/server')); this.server = require('src/webserver/server'));
it('should listen on port 31400', (done) => { it('should listen on port 31459', (done) => {
net.createConnection(31400, done); net.createConnection(31459, done);
}); });
afterEach(() => afterEach(() =>

View File

@@ -15,6 +15,6 @@ describe('As a user I want error when registering existing username', () => {
.post('/api/v1/user') .post('/api/v1/user')
.send({ username: 'test_user', password: 'password' }) .send({ username: 'test_user', password: 'password' })
.expect(401) .expect(401)
.then(response => assert.equal(response.text, '{"success":false,"message":"That username is already registered"}')) .then(response => assert.equal(response.text, '{"success":false,"error":"That username is already registered"}'))
); );
}); });

View File

@@ -7,17 +7,17 @@ const createToken = require('test/helpers/createToken');
const infoMovieSuccess = require('test/fixtures/blade_runner_2049-info-success-response.json'); const infoMovieSuccess = require('test/fixtures/blade_runner_2049-info-success-response.json');
describe('As a user I want to request a movie', () => { describe('As a user I want to request a movie', () => {
before(async () => { before(() => {
await resetDatabase() return resetDatabase()
await createUser('test_user', 'test@gmail.com', 'password') .then(() => createUser('test_user', 'test@gmail.com', 'password'));
}) })
before(() => createCacheEntry('mi:335984:false', infoMovieSuccess)); before(() => createCacheEntry('mi:335984', infoMovieSuccess));
it('should return 200 when item is requested', () => it('should return 200 when item is requested', () =>
request(app) request(app)
.post('/api/v2/request') .post('/api/v2/request')
.set('authorization', createToken('test_user', 'secret'))
.send({ id: 335984, type: 'movie' }) .send({ id: 335984, type: 'movie' })
.set('Authorization', createToken('test_user', 'secret'))
.expect(200) .expect(200)
); );
}); });

View File

@@ -1,29 +1,28 @@
const assert = require('assert'); const assert = require('assert');
// const convertTmdbToMovie = require('src/tmdb/convertTmdbToMovie'); const convertTmdbToMovie = require('src/tmdb/convertTmdbToMovie');
const { Movie } = require('src/tmdb/types');
const bladeRunnerQuerySuccess = require('test/fixtures/blade_runner_2049-info-success-response.json') const bladeRunnerQuerySuccess = require('test/fixtures/blade_runner_2049-info-success-response.json')
describe('Convert tmdb movieInfo to movie', () => { describe('Convert tmdb movieInfo to movie', () => {
beforeEach(() => [this.bladeRunnerTmdbMovie] = bladeRunnerQuerySuccess); beforeEach(() => this.bladeRunnerTmdbMovie = bladeRunnerQuerySuccess);
it('should translate the tmdb release date to movie year', () => { it('should translate the tmdb release date to movie year', () => {
const bladeRunner = Movie.convertFromTmdbResponse(this.bladeRunnerTmdbMovie); const bladeRunner = convertTmdbToMovie(this.bladeRunnerTmdbMovie);
assert.strictEqual(bladeRunner.year, 2017); assert.strictEqual(bladeRunner.year, 2017);
}); });
it('should translate the tmdb release date to instance of Date', () => { it('should translate the tmdb release date to instance of Date', () => {
const bladeRunner = Movie.convertFromTmdbResponse(this.bladeRunnerTmdbMovie); const bladeRunner = convertTmdbToMovie(this.bladeRunnerTmdbMovie);
assert(bladeRunner.releaseDate instanceof Date); assert(bladeRunner.release_date instanceof Date);
}); });
it('should translate the tmdb title to title', () => { it('should translate the tmdb title to title', () => {
const bladeRunner = Movie.convertFromTmdbResponse(this.bladeRunnerTmdbMovie); const bladeRunner = convertTmdbToMovie(this.bladeRunnerTmdbMovie);
assert.equal(bladeRunner.title, 'Blade Runner 2049'); assert.equal(bladeRunner.title, 'Blade Runner 2049');
}); });
it('should translate the tmdb vote_average to rating', () => { it('should translate the tmdb vote_average to rank', () => {
const bladeRunner = Movie.convertFromTmdbResponse(this.bladeRunnerTmdbMovie); const bladeRunner = convertTmdbToMovie(this.bladeRunnerTmdbMovie);
assert.equal(bladeRunner.rating, 7.3); assert.equal(bladeRunner.rank, 7.3);
}); });

View File

@@ -21,7 +21,7 @@ describe('TMDB', function test() {
it('should return the "Blade Runner 2049" year in the collection of popular movies', () => { it('should return the "Blade Runner 2049" year in the collection of popular movies', () => {
this.mockMoviedb.response = popularMovieSuccessResponse; this.mockMoviedb.response = popularMovieSuccessResponse;
const cache = new Cache(this.database); const cache = new Cache(this.database);
const tmdb = new TMDB(cache, 'bogus-pi-key', this.mockMoviedb); const tmdb = new TMDB(cache, 'bogus-api-key', this.mockMoviedb);
return tmdb.popular() return tmdb.popular()
.then(movies => .then(movies =>
assert.equal(movies[0].title, "Blade Runner 2049") assert.equal(movies[0].title, "Blade Runner 2049")

File diff suppressed because it is too large Load Diff