Compare commits
1 Commits
feat/cooki
...
renovate/c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e981b32f6b |
10
.prettierrc
10
.prettierrc
@@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"tabWidth": 2,
|
|
||||||
"useTabs": false,
|
|
||||||
"semi": true,
|
|
||||||
"singleQuote": false,
|
|
||||||
"bracketSpacing": true,
|
|
||||||
"arrowParens": "avoid",
|
|
||||||
"vueIndentScriptAndStyle": false,
|
|
||||||
"trailingComma": "none"
|
|
||||||
}
|
|
||||||
@@ -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:
|
||||||
@@ -7,7 +7,6 @@ script:
|
|||||||
- yarn coverage
|
- yarn coverage
|
||||||
before_install:
|
before_install:
|
||||||
- cd seasoned_api
|
- cd seasoned_api
|
||||||
- cp conf/development.json.example conf/development.json
|
|
||||||
before_script:
|
before_script:
|
||||||
- yarn
|
- yarn
|
||||||
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
||||||
|
|||||||
@@ -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="">
|
||||||
|
|||||||
@@ -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
5
renovate.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"extends": [
|
||||||
|
"config:base"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -3,8 +3,7 @@
|
|||||||
"host": "../shows.db"
|
"host": "../shows.db"
|
||||||
},
|
},
|
||||||
"webserver": {
|
"webserver": {
|
||||||
"port": 31459,
|
"port": 31459
|
||||||
"origins": []
|
|
||||||
},
|
},
|
||||||
"tmdb": {
|
"tmdb": {
|
||||||
"apiKey": ""
|
"apiKey": ""
|
||||||
@@ -12,11 +11,6 @@
|
|||||||
"plex": {
|
"plex": {
|
||||||
"ip": ""
|
"ip": ""
|
||||||
},
|
},
|
||||||
"tautulli": {
|
|
||||||
"apiKey": "",
|
|
||||||
"ip": "",
|
|
||||||
"port": ""
|
|
||||||
},
|
|
||||||
"raven": {
|
"raven": {
|
||||||
"DSN": ""
|
"DSN": ""
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,51 +7,39 @@
|
|||||||
},
|
},
|
||||||
"main": "webserver/server.js",
|
"main": "webserver/server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "cross-env SEASONED_CONFIG=conf/development.json NODE_ENV=production 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 scripts/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": "^5.0.1",
|
"bcrypt-nodejs": "^0.0.3",
|
||||||
"body-parser": "~1.18.2",
|
"body-parser": "~1.18.2",
|
||||||
"cookie-parser": "^1.4.6",
|
|
||||||
"cross-env": "~5.1.4",
|
"cross-env": "~5.1.4",
|
||||||
"express": "~4.16.0",
|
"express": "~4.16.0",
|
||||||
"form-data": "^2.5.1",
|
"jsonwebtoken": "^8.0.1",
|
||||||
"jsonwebtoken": "^8.5.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",
|
||||||
"redis": "^3.0.2",
|
|
||||||
"request": "^2.87.0",
|
|
||||||
"request-promise": "^4.2",
|
"request-promise": "^4.2",
|
||||||
"sqlite3": "^5.0.1"
|
"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"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,44 +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");
|
|
||||||
|
|
||||||
const queries = {
|
|
||||||
getRequestsNotYetInPlex: `SELECT * FROM requests WHERE status = 'requested' OR status = 'downloading'`,
|
|
||||||
saveNewStatus: `UPDATE requests SET status = ? WHERE id IS ? and type IS ?`
|
|
||||||
};
|
|
||||||
|
|
||||||
const getByStatus = () =>
|
|
||||||
establishedDatabase.all(queries.getRequestsNotYetInPlex);
|
|
||||||
|
|
||||||
const checkIfRequestExistInPlex = async request => {
|
|
||||||
request.existsInPlex = await plex.existsInPlex(request);
|
|
||||||
return request;
|
|
||||||
};
|
|
||||||
|
|
||||||
const commitNewStatus = (status, id, type, title) => {
|
|
||||||
console.log(type, title, "updated to:", status);
|
|
||||||
return establishedDatabase.run(queries.saveNewStatus, [status, id, type]);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getNewRequestMatchesInPlex = async () => {
|
|
||||||
const requests = await getByStatus();
|
|
||||||
|
|
||||||
return Promise.all(requests.map(checkIfRequestExistInPlex))
|
|
||||||
.catch(error =>
|
|
||||||
console.log("error from checking plex for existance:", error)
|
|
||||||
)
|
|
||||||
.then(matchedRequests =>
|
|
||||||
matchedRequests.filter(request => request.existsInPlex)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateMatchInDb = (match, status) => {
|
|
||||||
return commitNewStatus(status, match.id, match.type, match.title);
|
|
||||||
};
|
|
||||||
|
|
||||||
getNewRequestMatchesInPlex()
|
|
||||||
.then(newMatches =>
|
|
||||||
Promise.all(newMatches.map(match => updateMatchInDb(match, "downloaded")))
|
|
||||||
)
|
|
||||||
.then(() => process.exit(0));
|
|
||||||
52
seasoned_api/src/cache/redis.js
vendored
52
seasoned_api/src/cache/redis.js
vendored
@@ -1,52 +0,0 @@
|
|||||||
const redis = require("redis")
|
|
||||||
const client = redis.createClient()
|
|
||||||
|
|
||||||
class Cache {
|
|
||||||
/**
|
|
||||||
* Retrieve an unexpired cache entry by key.
|
|
||||||
* @param {String} key of the cache entry
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
get(key) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
client.get(key, (error, reply) => {
|
|
||||||
if (reply == null) {
|
|
||||||
return reject();
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(JSON.parse(reply));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Insert cache entry with key and value.
|
|
||||||
* @param {String} key of the cache entry
|
|
||||||
* @param {String} value of the cache entry
|
|
||||||
* @param {Number} timeToLive the number of seconds before entry expires
|
|
||||||
* @returns {Object}
|
|
||||||
*/
|
|
||||||
set(key, value, timeToLive = 10800) {
|
|
||||||
if (value == null || key == null) return null;
|
|
||||||
|
|
||||||
const json = JSON.stringify(value);
|
|
||||||
client.set(key, json, (error, reply) => {
|
|
||||||
if (reply == "OK") {
|
|
||||||
// successfully set value with key, now set TTL for key
|
|
||||||
client.expire(key, timeToLive, e => {
|
|
||||||
if (e)
|
|
||||||
console.error(
|
|
||||||
"Unexpected error while setting expiration for key:",
|
|
||||||
key,
|
|
||||||
". Error:",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Cache;
|
|
||||||
@@ -22,13 +22,13 @@ class Config {
|
|||||||
|
|
||||||
get(section, option) {
|
get(section, option) {
|
||||||
if (this.fields[section] === undefined || this.fields[section][option] === undefined) {
|
if (this.fields[section] === undefined || this.fields[section][option] === undefined) {
|
||||||
throw new Error(`Field "${section} => ${option}" does not exist.`);
|
throw new Error(`Filed "${section} => ${option}" does not exist.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const field = new Field(this.fields[section][option]);
|
const field = new Field(this.fields[section][option]);
|
||||||
|
|
||||||
if (field.value === '') {
|
if (field.value === '') {
|
||||||
const envField = process.env[[section.toUpperCase(), option.toUpperCase()].join('_')];
|
const envField = process.env[['SEASONED', section.toUpperCase(), option.toUpperCase()].join('_')];
|
||||||
if (envField !== undefined && envField.length !== 0) { return envField; }
|
if (envField !== undefined && envField.length !== 0) { return envField; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,11 @@
|
|||||||
CREATE TABLE IF NOT EXISTS user (
|
CREATE TABLE IF NOT EXISTS user (
|
||||||
user_name varchar(127) UNIQUE,
|
user_name varchar(127) UNIQUE,
|
||||||
password varchar(127),
|
password varchar(127),
|
||||||
admin boolean DEFAULT 0,
|
|
||||||
email varchar(127) UNIQUE,
|
email varchar(127) UNIQUE,
|
||||||
|
admin boolean DEFAULT 0,
|
||||||
primary key (user_name)
|
primary key (user_name)
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS settings (
|
|
||||||
user_name varchar(127) UNIQUE,
|
|
||||||
dark_mode boolean DEFAULT 0,
|
|
||||||
plex_userid varchar(127) DEFAULT NULL,
|
|
||||||
emoji varchar(16) DEFAULT NULL,
|
|
||||||
foreign key(user_name) REFERENCES user(user_name) ON DELETE CASCADE
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS cache (
|
CREATE TABLE IF NOT EXISTS cache (
|
||||||
key varchar(255),
|
key varchar(255),
|
||||||
value blob,
|
value blob,
|
||||||
@@ -31,18 +23,17 @@ CREATE TABLE IF NOT EXISTS search_history (
|
|||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS requests(
|
CREATE TABLE IF NOT EXISTS requests(
|
||||||
id NUMBER,
|
id TEXT,
|
||||||
title TEXT,
|
title TEXT,
|
||||||
year NUMBER,
|
year NUMBER,
|
||||||
poster_path TEXT DEFAULT NULL,
|
poster_path TEXT DEFAULT NULL,
|
||||||
background_path TEXT DEFAULT NULL,
|
background_path TEXT DEFAULT NULL,
|
||||||
requested_by varchar(127) DEFAULT NULL,
|
requested_by TEXT,
|
||||||
ip TEXT,
|
ip TEXT,
|
||||||
date DATE DEFAULT CURRENT_TIMESTAMP,
|
date DATE DEFAULT CURRENT_TIMESTAMP,
|
||||||
status CHAR(25) DEFAULT 'requested' NOT NULL,
|
status CHAR(25) DEFAULT 'requested' NOT NULL,
|
||||||
user_agent CHAR(255) DEFAULT NULL,
|
user_agent CHAR(255) DEFAULT NULL,
|
||||||
type CHAR(50) DEFAULT 'movie',
|
type CHAR(50) DEFAULT 'movie'
|
||||||
foreign key(requested_by) REFERENCES user(user_name) ON DELETE SET NULL
|
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS request(
|
CREATE TABLE IF NOT EXISTS request(
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
DROP TABLE IF EXISTS user;
|
DROP TABLE IF EXISTS user;
|
||||||
DROP TABLE IF EXISTS settings;
|
|
||||||
DROP TABLE IF EXISTS search_history;
|
DROP TABLE IF EXISTS search_history;
|
||||||
DROP TABLE IF EXISTS requests;
|
DROP TABLE IF EXISTS requests;
|
||||||
DROP TABLE IF EXISTS request;
|
DROP TABLE IF EXISTS request;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ class SqliteDatabase {
|
|||||||
constructor(host) {
|
constructor(host) {
|
||||||
this.host = host;
|
this.host = host;
|
||||||
this.connection = new sqlite3.Database(this.host);
|
this.connection = new sqlite3.Database(this.host);
|
||||||
this.execute('pragma foreign_keys = on;');
|
|
||||||
this.schemaDirectory = path.join(__dirname, 'schemas');
|
this.schemaDirectory = path.join(__dirname, 'schemas');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,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)
|
||||||
@@ -42,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) {
|
||||||
@@ -59,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) {
|
||||||
@@ -76,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) {
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
const request = require("request");
|
|
||||||
const configuration = require('src/config/configuration').getInstance();
|
|
||||||
|
|
||||||
const sendSMS = (message) => {
|
|
||||||
const apiKey = configuration.get('sms', 'apikey')
|
|
||||||
|
|
||||||
if (!apiKey) {
|
|
||||||
console.warning("api key for sms not set, cannot send sms.")
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const sender = configuration.get('sms', 'sender')
|
|
||||||
const recipient = configuration.get('sms', 'recipient')
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
request.post(
|
|
||||||
{
|
|
||||||
url: `https://gatewayapi.com/rest/mtsms?token=${apiKey}`,
|
|
||||||
json: true,
|
|
||||||
body: {
|
|
||||||
sender,
|
|
||||||
message,
|
|
||||||
recipients: [{ msisdn: `47${recipient}` }]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
function(err, r, body) {
|
|
||||||
console.log(err ? err : body);
|
|
||||||
console.log("sms provider response:", body)
|
|
||||||
resolve()
|
|
||||||
}
|
|
||||||
);
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = { sendSMS }
|
|
||||||
@@ -1,21 +1,19 @@
|
|||||||
const assert = require("assert");
|
const assert = require('assert');
|
||||||
const http = require("http");
|
const http = require('http');
|
||||||
const { URL } = require("url");
|
const { URL } = require('url');
|
||||||
const PythonShell = require("python-shell");
|
const PythonShell = require('python-shell');
|
||||||
|
|
||||||
const establishedDatabase = require("src/database/database");
|
const establishedDatabase = require('src/database/database');
|
||||||
|
|
||||||
const RedisCache = require("src/cache/redis");
|
|
||||||
const cache = new RedisCache();
|
|
||||||
|
|
||||||
function getMagnetFromURL(url) {
|
function getMagnetFromURL(url) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const options = new URL(url);
|
const options = new URL(url);
|
||||||
if (options.protocol.includes("magnet")) resolve(url);
|
if (options.protocol.includes('magnet'))
|
||||||
|
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)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -23,82 +21,67 @@ 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", "--print"]
|
args: [searchterm, '-s', 'jackett', '-f', '--print']
|
||||||
};
|
}
|
||||||
|
|
||||||
PythonShell.run("torrentSearch/search.py", options, callback);
|
PythonShell.run('torrentSearch/search.py', options, callback);
|
||||||
// PythonShell does not support return
|
// PythonShell does not support return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function callPythonAddMagnet(url, callback) {
|
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]
|
||||||
};
|
};
|
||||||
|
|
||||||
PythonShell.run("deluge_cli.py", options, callback);
|
PythonShell.run('deluge_cli.py', options, callback);
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
throw new Error(err);
|
throw new Error(err);
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function SearchPiratebay(query) {
|
async function SearchPiratebay(query) {
|
||||||
if (query && query.includes("+")) {
|
return await new Promise((resolve, reject) => find(query, (err, results) => {
|
||||||
query = query.replace("+", "%20");
|
|
||||||
}
|
|
||||||
|
|
||||||
const cacheKey = `pirate/${query}`;
|
|
||||||
|
|
||||||
return new Promise((resolve, reject) =>
|
|
||||||
cache
|
|
||||||
.get(cacheKey)
|
|
||||||
.then(resolve)
|
|
||||||
.catch(() =>
|
|
||||||
find(query, (err, results) => {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log("THERE WAS A FUCKING ERROR!\n", err);
|
/* eslint-disable no-console */
|
||||||
reject(Error("There was a error when searching for torrents"));
|
console.log('THERE WAS A FUCKING ERROR!\n', err);
|
||||||
|
reject(Error('There was a error when searching for torrents'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (results) {
|
if (results) {
|
||||||
const jsonData = JSON.parse(results[1], null, "\t");
|
/* eslint-disable no-console */
|
||||||
cache.set(cacheKey, jsonData);
|
console.log('result', results);
|
||||||
resolve(jsonData);
|
resolve(JSON.parse(results, null, '\t'));
|
||||||
}
|
}
|
||||||
})
|
}));
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function AddMagnet(magnet, name, tmdb_id) {
|
async function AddMagnet(magnet, name, tmdb_id) {
|
||||||
return await new Promise((resolve, reject) =>
|
return await new Promise((resolve, reject) => callPythonAddMagnet(magnet, (err, results) => {
|
||||||
callPythonAddMagnet(magnet, (err, results) => {
|
|
||||||
if (err) {
|
if (err) {
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
console.log(err);
|
console.log(err);
|
||||||
reject(Error("Enable to add torrent", err));
|
reject(Error('Enable to add torrent', err))
|
||||||
}
|
}
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
console.log("result/error:", err, results);
|
console.log('result/error:', err, results);
|
||||||
|
|
||||||
database = establishedDatabase;
|
database = establishedDatabase;
|
||||||
insert_query =
|
insert_query = "INSERT INTO requested_torrent(magnet,torrent_name,tmdb_id) \
|
||||||
"INSERT INTO requested_torrent(magnet,torrent_name,tmdb_id) \
|
|
||||||
VALUES (?,?,?)";
|
VALUES (?,?,?)";
|
||||||
|
|
||||||
let response = database.run(insert_query, [magnet, name, tmdb_id]);
|
let response = database.run(insert_query, [magnet, name, tmdb_id]);
|
||||||
console.log("Response from requsted_torrent insert: " + response);
|
console.log('Response from requsted_torrent insert: ' + response);
|
||||||
|
|
||||||
resolve({ success: true });
|
resolve({ success: true });
|
||||||
})
|
}));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { SearchPiratebay, AddMagnet };
|
module.exports = { SearchPiratebay, AddMagnet };
|
||||||
|
|||||||
@@ -1,240 +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 RedisCache = require("src/cache/redis");
|
|
||||||
const redisCache = new RedisCache();
|
|
||||||
|
|
||||||
const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, "");
|
|
||||||
|
|
||||||
function fixedEncodeURIComponent(str) {
|
|
||||||
return encodeURIComponent(str).replace(/[!'()*]/g, function (c) {
|
|
||||||
return "%" + c.charCodeAt(0).toString(16).toUpperCase();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const matchingTitleAndYear = (plex, tmdb) => {
|
|
||||||
let matchingTitle, matchingYear;
|
|
||||||
|
|
||||||
if (plex["title"] != null && tmdb["title"] != null) {
|
|
||||||
const plexTitle = sanitize(plex.title);
|
|
||||||
const tmdbTitle = sanitize(tmdb.title);
|
|
||||||
matchingTitle = plexTitle == tmdbTitle;
|
|
||||||
matchingTitle = matchingTitle
|
|
||||||
? matchingTitle
|
|
||||||
: plexTitle.startsWith(tmdbTitle);
|
|
||||||
} else matchingTitle = false;
|
|
||||||
|
|
||||||
if (plex["year"] != null && tmdb["year"] != null)
|
|
||||||
matchingYear = plex.year == tmdb.year;
|
|
||||||
else matchingYear = false;
|
|
||||||
|
|
||||||
return matchingTitle && matchingYear;
|
|
||||||
};
|
|
||||||
|
|
||||||
const successfullResponse = response => {
|
|
||||||
if (response && response["MediaContainer"]) return response;
|
|
||||||
|
|
||||||
if (
|
|
||||||
response == null ||
|
|
||||||
response["status"] == null ||
|
|
||||||
response["statusText"] == null
|
|
||||||
) {
|
|
||||||
throw Error("Unable to decode response");
|
|
||||||
}
|
|
||||||
|
|
||||||
const { status, statusText } = response;
|
|
||||||
|
|
||||||
if (status === 200) {
|
|
||||||
return response.json();
|
|
||||||
} else {
|
|
||||||
throw { message: statusText, status: status };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Plex {
|
class Plex {
|
||||||
constructor(ip, port = 32400, cache = null) {
|
constructor(ip) {
|
||||||
this.plexIP = ip;
|
this.plexIP = ip
|
||||||
this.plexPort = port;
|
this.plexPort = 32400
|
||||||
|
|
||||||
this.cache = cache || redisCache;
|
|
||||||
this.cacheTags = {
|
|
||||||
machineInfo: "plex/mi",
|
|
||||||
search: "plex/s"
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchMachineIdentifier() {
|
existsInPlex(tmdbMovie) {
|
||||||
const cacheKey = `${this.cacheTags.machineInfo}`;
|
return Promise.resolve()
|
||||||
const url = `http://${this.plexIP}:${this.plexPort}/`;
|
.then(() => this.search(tmdbMovie.title))
|
||||||
const options = {
|
// TODO handle this when whitelist of local ip is not set in plex
|
||||||
timeout: 20000,
|
.catch((error) => { console.error('Unable to search plex')})
|
||||||
headers: { Accept: "application/json" }
|
.then((plexMovies) => {
|
||||||
};
|
const matches = plexMovies.some((plexMovie) => {
|
||||||
|
return tmdbMovie.title === plexMovie.title && tmdbMovie.type === plexMovie.type
|
||||||
return new Promise((resolve, reject) =>
|
|
||||||
this.cache
|
|
||||||
.get(cacheKey)
|
|
||||||
.then(machineInfo => resolve(machineInfo["machineIdentifier"]))
|
|
||||||
.catch(() => fetch(url, options))
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(machineInfo =>
|
|
||||||
this.cache.set(cacheKey, machineInfo["MediaContainer"], 2628000)
|
|
||||||
)
|
|
||||||
.then(machineInfo => resolve(machineInfo["machineIdentifier"]))
|
|
||||||
.catch(error => {
|
|
||||||
if (error != undefined && error.type === "request-timeout") {
|
|
||||||
reject({
|
|
||||||
message: "Plex did not respond",
|
|
||||||
status: 408,
|
|
||||||
success: false
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
reject(error);
|
|
||||||
})
|
})
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
matchTmdbAndPlexMedia(plex, tmdb) {
|
tmdbMovie.existsInPlex = matches
|
||||||
let match;
|
return tmdbMovie
|
||||||
|
})
|
||||||
if (plex == null || tmdb == null) return false;
|
|
||||||
|
|
||||||
if (plex instanceof Array) {
|
|
||||||
let possibleMatches = plex.map(plexItem =>
|
|
||||||
matchingTitleAndYear(plexItem, tmdb)
|
|
||||||
);
|
|
||||||
match = possibleMatches.includes(true);
|
|
||||||
} else {
|
|
||||||
match = matchingTitleAndYear(plex, tmdb);
|
|
||||||
}
|
|
||||||
|
|
||||||
return match;
|
|
||||||
}
|
|
||||||
|
|
||||||
async existsInPlex(tmdb) {
|
|
||||||
const plexMatch = await this.findPlexItemByTitleAndYear(
|
|
||||||
tmdb.title,
|
|
||||||
tmdb.year
|
|
||||||
);
|
|
||||||
return plexMatch ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
findPlexItemByTitleAndYear(title, year) {
|
|
||||||
const query = { title, year };
|
|
||||||
|
|
||||||
return this.search(title).then(plexResults => {
|
|
||||||
const matchesInPlex = plexResults.map(plex =>
|
|
||||||
this.matchTmdbAndPlexMedia(plex, query)
|
|
||||||
);
|
|
||||||
const matchesIndex = matchesInPlex.findIndex(el => el === true);
|
|
||||||
return matchesInPlex != -1 ? plexResults[matchesIndex] : null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getDirectLinkByTitleAndYear(title, year) {
|
|
||||||
const machineIdentifierPromise = this.fetchMachineIdentifier();
|
|
||||||
const matchingObjectInPlexPromise = this.findPlexItemByTitleAndYear(
|
|
||||||
title,
|
|
||||||
year
|
|
||||||
);
|
|
||||||
|
|
||||||
return Promise.all([
|
|
||||||
machineIdentifierPromise,
|
|
||||||
matchingObjectInPlexPromise
|
|
||||||
]).then(([machineIdentifier, matchingObjectInPlex]) => {
|
|
||||||
if (
|
|
||||||
matchingObjectInPlex == false ||
|
|
||||||
matchingObjectInPlex == null ||
|
|
||||||
matchingObjectInPlex["key"] == null ||
|
|
||||||
machineIdentifier == null
|
|
||||||
)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const keyUriComponent = fixedEncodeURIComponent(matchingObjectInPlex.key);
|
|
||||||
return `https://app.plex.tv/desktop#!/server/${machineIdentifier}/details?key=${keyUriComponent}`;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
search(query) {
|
search(query) {
|
||||||
const cacheKey = `${this.cacheTags.search}:${query}`;
|
|
||||||
|
|
||||||
const url = `http://${this.plexIP}:${
|
|
||||||
this.plexPort
|
|
||||||
}/hubs/search?query=${fixedEncodeURIComponent(query)}`;
|
|
||||||
const options = {
|
const options = {
|
||||||
timeout: 20000,
|
baseURL: `http://${this.plexIP}:${this.plexPort}`,
|
||||||
headers: { Accept: "application/json" }
|
url: '/hubs/search',
|
||||||
};
|
params: { query: query },
|
||||||
|
responseType: 'json',
|
||||||
return new Promise((resolve, reject) =>
|
timeout: 3000
|
||||||
this.cache
|
|
||||||
.get(cacheKey)
|
|
||||||
.catch(() => fetch(url, options)) // else fetch fresh data
|
|
||||||
.then(successfullResponse)
|
|
||||||
.then(results => this.cache.set(cacheKey, results, 21600)) // 6 hours
|
|
||||||
.then(this.mapResults)
|
|
||||||
.then(resolve)
|
|
||||||
.catch(error => {
|
|
||||||
if (error != undefined && error.type === "request-timeout") {
|
|
||||||
reject({
|
|
||||||
message: "Plex did not respond",
|
|
||||||
status: 408,
|
|
||||||
success: false
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
reject(error);
|
return Promise.resolve()
|
||||||
})
|
.then(() => axios.request(options))
|
||||||
);
|
.catch((error) => { throw new Error(`Unable to search plex library`, error) })
|
||||||
|
.then(response => this.mapResults(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
// this is not guarenteed to work, but if we see a movie or
|
|
||||||
// show has been imported, this function can be helpfull to call
|
|
||||||
// in order to try bust the cache preventing movieInfo and
|
|
||||||
// showInfo from seeing updates through existsInPlex.
|
|
||||||
bustSearchCacheWithTitle(title) {
|
|
||||||
const query = title;
|
|
||||||
const cacheKey = `${this.cacheTags.search}/${query}*`;
|
|
||||||
|
|
||||||
this.cache.del(
|
|
||||||
cacheKey,
|
|
||||||
(error,
|
|
||||||
response => {
|
|
||||||
if (response == 1) return true;
|
|
||||||
|
|
||||||
// TODO improve cache key matching by lowercasing it on the backend.
|
|
||||||
// what do we actually need to check for if the key was deleted or not
|
|
||||||
// it might be an error or another response code.
|
|
||||||
console.log("Unable to delete, key might not exists");
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
mapResults(response) {
|
mapResults(response) {
|
||||||
if (
|
return response.data.MediaContainer.Hub.reduce((result, hub) => {
|
||||||
response == null ||
|
if (hub.type === 'movie' && hub.Metadata !== undefined) {
|
||||||
response.MediaContainer == null ||
|
return [...result, ...hub.Metadata.map(convertPlexToMovie)]
|
||||||
response.MediaContainer.Hub == null
|
}
|
||||||
) {
|
else if (hub.type === 'show' && hub.Metadata !== undefined) {
|
||||||
return [];
|
return [...result, ...hub.Metadata.map(convertPlexToShow)]
|
||||||
|
}
|
||||||
|
else if (hub.type === 'episode' && hub.Metadata !== undefined) {
|
||||||
|
return [...result, ...hub.Metadata.map(convertPlexToEpisode)]
|
||||||
}
|
}
|
||||||
|
|
||||||
return response.MediaContainer.Hub.filter(category => category.size > 0)
|
return result
|
||||||
.map(category => {
|
}, [])
|
||||||
if (category.type === "movie") {
|
|
||||||
return category.Metadata;
|
|
||||||
} else if (category.type === "show") {
|
|
||||||
return category.Metadata.map(convertPlexToShow);
|
|
||||||
} else if (category.type === "episode") {
|
|
||||||
return category.Metadata.map(convertPlexToEpisode);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter(result => result !== undefined);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
const PlexRepository = require("src/plex/plexRepository");
|
const PlexRepository = require('src/plex/plexRepository');
|
||||||
const configuration = require("src/config/configuration").getInstance();
|
const Cache = require('src/tmdb/cache');
|
||||||
const TMDB = require("src/tmdb/tmdb");
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
const establishedDatabase = require("src/database/database");
|
const TMDB = require('src/tmdb/tmdb');
|
||||||
|
const establishedDatabase = require('src/database/database');
|
||||||
|
|
||||||
const plexRepository = new PlexRepository(configuration.get("plex", "ip"));
|
const plexRepository = new PlexRepository(configuration.get('plex', 'ip'));
|
||||||
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
const cache = new Cache();
|
||||||
|
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||||
|
|
||||||
class RequestRepository {
|
class RequestRepository {
|
||||||
constructor(database) {
|
constructor(database) {
|
||||||
@@ -12,19 +14,15 @@ class RequestRepository {
|
|||||||
this.queries = {
|
this.queries = {
|
||||||
insertRequest: `INSERT INTO requests(id,title,year,poster_path,background_path,requested_by,ip,user_agent,type)
|
insertRequest: `INSERT INTO requests(id,title,year,poster_path,background_path,requested_by,ip,user_agent,type)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||||
fetchRequestedItems:
|
fetchRequestedItems: 'SELECT * FROM requests ORDER BY date DESC LIMIT 25 OFFSET ?*25-25',
|
||||||
"SELECT * FROM requests ORDER BY date DESC LIMIT 25 OFFSET ?*25-25",
|
fetchRequestedItemsByStatus: 'SELECT * FROM requests WHERE status IS ? AND type LIKE ? ORDER BY date DESC LIMIT 25 OFFSET ?*25-25',
|
||||||
fetchRequestedItemsByStatus:
|
updateRequestedById: 'UPDATE requests SET status = ? WHERE id is ? AND type is ?',
|
||||||
"SELECT * FROM requests WHERE status IS ? AND type LIKE ? ORDER BY date DESC LIMIT 25 OFFSET ?*25-25",
|
checkIfIdRequested: 'SELECT * FROM requests WHERE id IS ? AND type IS ?',
|
||||||
updateRequestedById:
|
userRequests: 'SELECT * FROM requests WHERE requested_by IS ? ORDER BY date DESC',
|
||||||
"UPDATE requests SET status = ? WHERE id is ? AND type is ?",
|
|
||||||
checkIfIdRequested: "SELECT * FROM requests WHERE id IS ? AND type IS ?",
|
|
||||||
userRequests:
|
|
||||||
"SELECT * FROM requests WHERE requested_by IS ? ORDER BY date DESC"
|
|
||||||
};
|
};
|
||||||
this.cacheTags = {
|
this.cacheTags = {
|
||||||
search: "se",
|
search: 'se',
|
||||||
lookup: "i"
|
lookup: 'i',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,28 +32,21 @@ class RequestRepository {
|
|||||||
.catch(error => Error(`error in the house${error}`));
|
.catch(error => Error(`error in the house${error}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
lookup(identifier, type = "movie") {
|
lookup(identifier, type = 'movie') {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => tmdb.lookup(identifier, type))
|
.then(() => tmdb.lookup(identifier, type))
|
||||||
.then(tmdbMovie => this.checkID(tmdbMovie))
|
.then(tmdbMovie => this.checkID(tmdbMovie))
|
||||||
.then(tmdbMovie => plexRepository.inPlex(tmdbMovie))
|
.then(tmdbMovie => plexRepository.inPlex(tmdbMovie))
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
throw new Error(error);
|
throw new Error(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
checkID(tmdbMovie) {
|
checkID(tmdbMovie) {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() =>
|
.then(() => this.database.get(this.queries.checkIfIdRequested, [tmdbMovie.id, tmdbMovie.type]))
|
||||||
this.database.get(this.queries.checkIfIdRequested, [
|
|
||||||
tmdbMovie.id,
|
|
||||||
tmdbMovie.type
|
|
||||||
])
|
|
||||||
)
|
|
||||||
.then((result, error) => {
|
.then((result, error) => {
|
||||||
if (error) {
|
if (error) { throw new Error(error); }
|
||||||
throw new Error(error);
|
|
||||||
}
|
|
||||||
tmdbMovie.requested = result ? true : false;
|
tmdbMovie.requested = result ? true : false;
|
||||||
return tmdbMovie;
|
return tmdbMovie;
|
||||||
});
|
});
|
||||||
@@ -69,61 +60,41 @@ class RequestRepository {
|
|||||||
sendRequest(identifier, type, ip, user_agent, user) {
|
sendRequest(identifier, type, ip, user_agent, user) {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => tmdb.lookup(identifier, type))
|
.then(() => tmdb.lookup(identifier, type))
|
||||||
.then(movie => {
|
.then((movie) => {
|
||||||
const username = user === undefined ? undefined : user.username;
|
const username = user === undefined ? undefined : user.username;
|
||||||
// Add request to database
|
// Add request to database
|
||||||
return this.database.run(this.queries.insertRequest, [
|
return this.database.run(this.queries.insertRequest, [movie.id, movie.title, movie.year, movie.poster_path, movie.background_path, username, ip, user_agent, movie.type]);
|
||||||
movie.id,
|
|
||||||
movie.title,
|
|
||||||
movie.year,
|
|
||||||
movie.poster_path,
|
|
||||||
movie.background_path,
|
|
||||||
username,
|
|
||||||
ip,
|
|
||||||
user_agent,
|
|
||||||
movie.type
|
|
||||||
]);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchRequested(status, page = "1", type = "%") {
|
fetchRequested(status, page = '1', type = '%') {
|
||||||
return Promise.resolve().then(() => {
|
|
||||||
if (
|
|
||||||
status === "requested" ||
|
|
||||||
status === "downloading" ||
|
|
||||||
status === "downloaded"
|
|
||||||
)
|
|
||||||
return this.database.all(this.queries.fetchRequestedItemsByStatus, [
|
|
||||||
status,
|
|
||||||
type,
|
|
||||||
page
|
|
||||||
]);
|
|
||||||
else return this.database.all(this.queries.fetchRequestedItems, page);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
userRequests(username) {
|
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => this.database.all(this.queries.userRequests, username))
|
.then(() => {
|
||||||
.catch(error => {
|
if (status === 'requested' || status === 'downloading' || status === 'downloaded')
|
||||||
if (String(error).includes("no such column")) {
|
return this.database.all(this.queries.fetchRequestedItemsByStatus, [status, type, page]);
|
||||||
throw new Error("Username not found");
|
else
|
||||||
}
|
return this.database.all(this.queries.fetchRequestedItems, page);
|
||||||
throw new Error("Unable to fetch your requests");
|
|
||||||
})
|
})
|
||||||
.then(result => {
|
}
|
||||||
|
|
||||||
|
userRequests(user) {
|
||||||
|
return Promise.resolve()
|
||||||
|
.then(() => this.database.all(this.queries.userRequests, user.username))
|
||||||
|
.catch((error) => {
|
||||||
|
if (String(error).includes('no such column')) {
|
||||||
|
throw new Error('Username not found');
|
||||||
|
}
|
||||||
|
throw new Error('Unable to fetch your requests');
|
||||||
|
})
|
||||||
|
.then((result) => {
|
||||||
// TODO do a correct mapping before sending, not just a dump of the database
|
// TODO do a correct mapping before sending, not just a dump of the database
|
||||||
result.map(item => (item.poster = item.poster_path));
|
result.map(item => item.poster = item.poster_path)
|
||||||
return result;
|
return result
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRequestedById(id, type, status) {
|
updateRequestedById(id, type, status) {
|
||||||
return this.database.run(this.queries.updateRequestedById, [
|
return this.database.run(this.queries.updateRequestedById, [status, id, type]);
|
||||||
status,
|
|
||||||
id,
|
|
||||||
type
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
const assert = require('assert')
|
const assert = require('assert')
|
||||||
const configuration = require('src/config/configuration').getInstance();
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
|
const Cache = require('src/tmdb/cache');
|
||||||
const TMDB = require('src/tmdb/tmdb');
|
const TMDB = require('src/tmdb/tmdb');
|
||||||
const tmdb = new TMDB(configuration.get('tmdb', 'apiKey'));
|
const cache = new Cache();
|
||||||
|
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||||
const establishedDatabase = require('src/database/database');
|
const establishedDatabase = require('src/database/database');
|
||||||
const utils = require('./utils');
|
const utils = require('./utils');
|
||||||
|
|
||||||
@@ -21,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 ?'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -84,11 +85,11 @@ class RequestRepository {
|
|||||||
* @param {tmdb} tmdb class of movie|show to add
|
* @param {tmdb} tmdb class of movie|show to add
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
requestFromTmdb(tmdb, ip, user_agent, username) {
|
requestFromTmdb(tmdb, ip, user_agent, user) {
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
.then(() => this.database.get(this.queries.read, [tmdb.id, tmdb.type]))
|
.then(() => this.database.get(this.queries.read, [tmdb.id, tmdb.type]))
|
||||||
.then(row => assert.equal(row, undefined, 'Id has already been requested'))
|
.then(row => assert.equal(row, undefined, 'Id has already been requested'))
|
||||||
.then(() => this.database.run(this.queries.add, [tmdb.id, tmdb.title, tmdb.year, tmdb.poster, tmdb.backdrop, username, ip, user_agent, tmdb.type]))
|
.then(() => this.database.run(this.queries.add, [tmdb.id, tmdb.title, tmdb.year, tmdb.poster, tmdb.backdrop, user, ip, user_agent, tmdb.type]))
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (error.name === 'AssertionError' || error.message.endsWith('been requested')) {
|
if (error.name === 'AssertionError' || error.message.endsWith('been requested')) {
|
||||||
throw new Error('This id is already requested', error.message);
|
throw new Error('This id is already requested', error.message);
|
||||||
@@ -105,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)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,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]
|
||||||
@@ -150,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 })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,23 +28,17 @@ class SearchHistory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new search entry in the database.
|
* Creates a new search entry in the database.
|
||||||
* @param {String} username logged in user doing the search
|
* @param {User} user a new user
|
||||||
* @param {String} searchQuery the query the user searched for
|
* @param {String} searchQuery the query the user searched for
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
create(username, searchQuery) {
|
create(user, searchQuery) {
|
||||||
return this.database.run(this.queries.create, [searchQuery, username])
|
return Promise.resolve()
|
||||||
.catch(error => {
|
.then(() => this.database.run(this.queries.create, [searchQuery, user]))
|
||||||
|
.catch((error) => {
|
||||||
if (error.message.includes('FOREIGN')) {
|
if (error.message.includes('FOREIGN')) {
|
||||||
throw new Error('Could not create search history.');
|
throw new Error('Could not create search history.');
|
||||||
}
|
}
|
||||||
|
|
||||||
throw {
|
|
||||||
success: false,
|
|
||||||
status: 500,
|
|
||||||
message: 'An unexpected error occured',
|
|
||||||
source: 'database'
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,74 +0,0 @@
|
|||||||
const fetch = require("node-fetch");
|
|
||||||
|
|
||||||
class Tautulli {
|
|
||||||
constructor(apiKey, ip, port) {
|
|
||||||
this.apiKey = apiKey;
|
|
||||||
this.ip = ip;
|
|
||||||
this.port = port;
|
|
||||||
}
|
|
||||||
|
|
||||||
buildUrlWithCmdAndUserid(cmd, user_id) {
|
|
||||||
const url = new URL("api/v2", `http://${this.ip}:${this.port}`);
|
|
||||||
url.searchParams.append("apikey", this.apiKey);
|
|
||||||
url.searchParams.append("cmd", cmd);
|
|
||||||
url.searchParams.append("user_id", user_id);
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
logTautulliError(error) {
|
|
||||||
console.error("error fetching from tautulli");
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlaysByDayOfWeek(plex_userid, days, y_axis) {
|
|
||||||
const url = this.buildUrlWithCmdAndUserid(
|
|
||||||
"get_plays_by_dayofweek",
|
|
||||||
plex_userid
|
|
||||||
);
|
|
||||||
url.searchParams.append("time_range", days);
|
|
||||||
url.searchParams.append("y_axis", y_axis);
|
|
||||||
|
|
||||||
return fetch(url.href)
|
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(error => this.logTautulliError(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
getPlaysByDays(plex_userid, days, y_axis) {
|
|
||||||
const url = this.buildUrlWithCmdAndUserid("get_plays_by_date", plex_userid);
|
|
||||||
url.searchParams.append("time_range", days);
|
|
||||||
url.searchParams.append("y_axis", y_axis);
|
|
||||||
|
|
||||||
return fetch(url.href)
|
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(error => this.logTautulliError(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
watchTimeStats(plex_userid) {
|
|
||||||
const url = this.buildUrlWithCmdAndUserid(
|
|
||||||
"get_user_watch_time_stats",
|
|
||||||
plex_userid
|
|
||||||
);
|
|
||||||
url.searchParams.append("grouping", 0);
|
|
||||||
|
|
||||||
return fetch(url.href)
|
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(error => this.logTautulliError(error));
|
|
||||||
}
|
|
||||||
|
|
||||||
viewHistory(plex_userid) {
|
|
||||||
const url = this.buildUrlWithCmdAndUserid("get_history", plex_userid);
|
|
||||||
|
|
||||||
url.searchParams.append("start", 0);
|
|
||||||
url.searchParams.append("length", 50);
|
|
||||||
|
|
||||||
console.log("fetching url", url.href);
|
|
||||||
|
|
||||||
return fetch(url.href)
|
|
||||||
.then(resp => resp.json())
|
|
||||||
.catch(error => this.logTautulliError(error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = Tautulli;
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": ["@babel/preset-env"]
|
|
||||||
}
|
|
||||||
@@ -20,10 +20,10 @@ class Cache {
|
|||||||
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);
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
49
seasoned_api/src/tmdb/convertTmdbToMovie.js
Normal file
49
seasoned_api/src/tmdb/convertTmdbToMovie.js
Normal 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;
|
||||||
30
seasoned_api/src/tmdb/convertTmdbToPerson.js
Normal file
30
seasoned_api/src/tmdb/convertTmdbToPerson.js
Normal 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;
|
||||||
62
seasoned_api/src/tmdb/convertTmdbToSeasoned.js
Normal file
62
seasoned_api/src/tmdb/convertTmdbToSeasoned.js
Normal 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;
|
||||||
41
seasoned_api/src/tmdb/convertTmdbToShow.js
Normal file
41
seasoned_api/src/tmdb/convertTmdbToShow.js
Normal 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;
|
||||||
@@ -1,118 +1,94 @@
|
|||||||
const moviedb = require("km-moviedb");
|
const moviedb = require('km-moviedb');
|
||||||
const RedisCache = require("src/cache/redis");
|
const convertTmdbToMovie = require('src/tmdb/convertTmdbToMovie');
|
||||||
const redisCache = new RedisCache();
|
const convertTmdbToShow = require('src/tmdb/convertTmdbToShow');
|
||||||
|
const convertTmdbToPerson = require('src/tmdb/convertTmdbToPerson');
|
||||||
const {
|
|
||||||
Movie,
|
|
||||||
Show,
|
|
||||||
Person,
|
|
||||||
Credits,
|
|
||||||
ReleaseDates
|
|
||||||
} = require("src/tmdb/types");
|
|
||||||
|
|
||||||
const 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`
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
class TMDB {
|
class TMDB {
|
||||||
constructor(apiKey, cache, tmdbLibrary) {
|
constructor(cache, apiKey, tmdbLibrary) {
|
||||||
|
this.cache = cache;
|
||||||
this.tmdbLibrary = tmdbLibrary || moviedb(apiKey);
|
this.tmdbLibrary = tmdbLibrary || moviedb(apiKey);
|
||||||
|
|
||||||
this.cache = cache || redisCache;
|
|
||||||
this.cacheTags = {
|
this.cacheTags = {
|
||||||
multiSearch: "mus",
|
multiSearch: 'mus',
|
||||||
movieSearch: "mos",
|
movieSearch: 'mos',
|
||||||
showSearch: "ss",
|
showSearch: 'ss',
|
||||||
personSearch: "ps",
|
personSearch: 'ps',
|
||||||
movieInfo: "mi",
|
movieInfo: 'mi',
|
||||||
movieCredits: "mc",
|
showInfo: 'si',
|
||||||
movieReleaseDates: "mrd",
|
personInfo: 'pi',
|
||||||
movieImages: "mimg",
|
miscNowPlayingMovies: 'npm',
|
||||||
showInfo: "si",
|
miscPopularMovies: 'pm',
|
||||||
showCredits: "sc",
|
miscTopRatedMovies: 'tpm',
|
||||||
personInfo: "pi",
|
miscUpcomingMovies: 'um',
|
||||||
personCredits: "pc",
|
tvOnTheAir: 'toa',
|
||||||
miscNowPlayingMovies: "npm",
|
miscPopularTvs: 'pt',
|
||||||
miscPopularMovies: "pm",
|
miscTopRatedTvs: 'trt',
|
||||||
miscTopRatedMovies: "tpm",
|
|
||||||
miscUpcomingMovies: "um",
|
|
||||||
tvOnTheAir: "toa",
|
|
||||||
miscPopularTvs: "pt",
|
|
||||||
miscTopRatedTvs: "trt"
|
|
||||||
};
|
};
|
||||||
this.defaultTTL = 86400;
|
|
||||||
}
|
|
||||||
|
|
||||||
getFromCacheOrFetchFromTmdb(cacheKey, tmdbMethod, query) {
|
|
||||||
return new Promise((resolve, reject) =>
|
|
||||||
this.cache
|
|
||||||
.get(cacheKey)
|
|
||||||
.then(resolve)
|
|
||||||
.catch(() => this.tmdb(tmdbMethod, query))
|
|
||||||
.then(resolve)
|
|
||||||
.catch(error => reject(tmdbErrorResponse(error, tmdbMethod)))
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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) {
|
lookup(identifier, type = 'movie') {
|
||||||
const query = { id: identifier };
|
const query = { id: identifier };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.movieInfo}:${identifier}`;
|
const cacheKey = `${this.cacheTags.info}:${type}:${identifier}`;
|
||||||
|
return Promise.resolve()
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, "movieInfo", query)
|
.then(() => this.cache.get(cacheKey))
|
||||||
.then(movie => this.cache.set(cacheKey, movie, this.defaultTTL))
|
.catch(() => this.tmdb(TMDB_METHODS['info'][type], query))
|
||||||
.then(movie => Movie.convertFromTmdbResponse(movie));
|
.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.');
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve credits for a movie
|
* Retrive search results from TMDB.
|
||||||
* @param {Number} identifier of the movie to get credits for
|
* @param {String} text query you want to search for
|
||||||
* @returns {Promise} movie cast object
|
* @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
|
||||||
*/
|
*/
|
||||||
movieCredits(identifier) {
|
search(text, page = 1, type = 'multi') {
|
||||||
const query = { id: identifier };
|
const query = { query: text, page: page };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.movieCredits}:${identifier}`;
|
const cacheKey = `${this.cacheTags.search}:${page}:${type}:${text}`;
|
||||||
|
return Promise.resolve()
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, "movieCredits", query)
|
.then(() => this.cache.get(cacheKey))
|
||||||
.then(credits => this.cache.set(cacheKey, credits, this.defaultTTL))
|
.catch(() => this.tmdb(TMDB_METHODS['search'][type], query))
|
||||||
.then(credits => Credits.convertFromTmdbResponse(credits));
|
.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 release dates for a movie
|
* Retrieve a specific movie by id from TMDB.
|
||||||
* @param {Number} identifier of the movie to get release dates for
|
* @param {Number} identifier of the movie you want to retrieve
|
||||||
* @returns {Promise} movie release dates object
|
* @param {String} type filter results by type (default movie).
|
||||||
|
* @returns {Promise} succeeds if movie was found
|
||||||
*/
|
*/
|
||||||
movieReleaseDates(identifier) {
|
movieInfo(identifier, credits=false) {
|
||||||
const query = { id: identifier }
|
const query = { id: identifier };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.movieReleaseDates}:${identifier}`
|
const cacheKey = `${this.cacheTags.movieInfo}:${identifier}:${credits}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'movieReleaseDates', query)
|
const requests = [this.tmdb('movieInfo', query)]
|
||||||
.then(releaseDates => this.cache.set(cacheKey, releaseDates, this.defaultTTL))
|
|
||||||
.then(releaseDates => ReleaseDates.convertFromTmdbResponse(releaseDates))
|
if (credits) {
|
||||||
|
requests.push(this.tmdb('movieCredits', query))
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.resolve()
|
||||||
|
.then(() => this.cache.get(cacheKey))
|
||||||
|
.catch(() => Promise.all(requests))
|
||||||
|
.catch((error) => { console.log(error); throw new Error('Could not find a movie with that id.'); })
|
||||||
|
.then(([movies, credits]) => this.cache.set(cacheKey, [movies, credits]))
|
||||||
|
.then(([movies, credits]) => convertTmdbToMovie(movies, credits))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -121,22 +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 = `tmdb/${this.cacheTags.showInfo}:${identifier}`;
|
const cacheKey = `${this.cacheTags.showInfo}:${identifier}:${credits}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, "tvInfo", query)
|
const requests = [this.tmdb('tvInfo', query)]
|
||||||
.then(show => this.cache.set(cacheKey, show, this.defaultTTL))
|
|
||||||
.then(show => Show.convertFromTmdbResponse(show));
|
if (credits) {
|
||||||
|
requests.push(this.tmdb('tvCredits', query))
|
||||||
}
|
}
|
||||||
|
|
||||||
showCredits(identifier) {
|
return Promise.resolve()
|
||||||
const query = { id: identifier };
|
.then(() => this.cache.get(cacheKey))
|
||||||
const cacheKey = `tmdb/${this.cacheTags.showCredits}:${identifier}`;
|
.catch(() => Promise.all(requests))
|
||||||
|
.catch(() => { throw new Error('Could not find a show with that id.'); })
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, "tvCredits", query)
|
.then(([shows, credits]) => this.cache.set(cacheKey, [shows, credits]))
|
||||||
.then(credits => this.cache.set(cacheKey, credits, this.defaultTTL))
|
.then(([shows, credits]) => convertTmdbToShow(shows, credits))
|
||||||
.then(credits => Credits.convertFromTmdbResponse(credits));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,32 +123,27 @@ class TMDB {
|
|||||||
*/
|
*/
|
||||||
personInfo(identifier) {
|
personInfo(identifier) {
|
||||||
const query = { id: identifier };
|
const query = { id: identifier };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.personInfo}:${identifier}`;
|
const cacheKey = `${this.cacheTags.personInfo}:${identifier}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, "personInfo", query)
|
return Promise.resolve()
|
||||||
.then(person => this.cache.set(cacheKey, person, this.defaultTTL))
|
.then(() => this.cache.get(cacheKey))
|
||||||
.then(person => Person.convertFromTmdbResponse(person));
|
.catch(() => Promise.all([this.tmdb('personInfo', query), this.tmdb('personCombinedCredits', query)]))
|
||||||
|
.catch(() => { throw new Error('Could not find a person with that id.'); })
|
||||||
|
.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))
|
||||||
}
|
}
|
||||||
|
|
||||||
personCredits(identifier) {
|
|
||||||
const query = { id: identifier };
|
|
||||||
const cacheKey = `tmdb/${this.cacheTags.personCredits}:${identifier}`;
|
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(
|
|
||||||
cacheKey,
|
|
||||||
"personCombinedCredits",
|
|
||||||
query
|
|
||||||
)
|
|
||||||
.then(credits => this.cache.set(cacheKey, credits, this.defaultTTL))
|
|
||||||
.then(credits => Credits.convertFromTmdbResponse(credits));
|
|
||||||
}
|
|
||||||
|
|
||||||
multiSearch(search_query, page = 1, include_adult = true) {
|
multiSearch(search_query, page=1) {
|
||||||
const query = { query: search_query, page, include_adult };
|
const query = { query: search_query, page: page };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.multiSearch}:${page}:${search_query}:${include_adult}`;
|
const cacheKey = `${this.cacheTags.multiSearch}:${page}:${search_query}`;
|
||||||
|
return Promise.resolve()
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMulti", query)
|
.then(() => this.cache.get(cacheKey))
|
||||||
.then(response => this.cache.set(cacheKey, response, this.defaultTTL))
|
.catch(() => this.tmdb('searchMulti', query))
|
||||||
|
.catch(() => { throw new Error('Could not complete search to tmdb'); })
|
||||||
|
.then(response => this.cache.set(cacheKey, response))
|
||||||
.then(response => this.mapResults(response));
|
.then(response => this.mapResults(response));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,13 +153,17 @@ class TMDB {
|
|||||||
* @param {Number} page representing pagination of results
|
* @param {Number} page representing pagination of results
|
||||||
* @returns {Promise} dict with query results, current page and total_pages
|
* @returns {Promise} dict with query results, current page and total_pages
|
||||||
*/
|
*/
|
||||||
movieSearch(search_query, page = 1, include_adult = true) {
|
movieSearch(query, page=1) {
|
||||||
const tmdbquery = { query: search_query, page, include_adult };
|
const tmdbquery = { query: query, page: page };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.movieSearch}:${page}:${search_query}:${include_adult}`;
|
const cacheKey = `${this.cacheTags.movieSearch}:${page}:${query}`;
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchMovie", tmdbquery)
|
return Promise.resolve()
|
||||||
.then(response => this.cache.set(cacheKey, response, this.defaultTTL))
|
.then(() => this.cache.get(cacheKey))
|
||||||
.then(response => this.mapResults(response, "movie"));
|
.catch(() => this.tmdb('searchMovie', tmdbquery))
|
||||||
|
.catch(() => { throw new Error('Could not complete movie search to tmdb'); })
|
||||||
|
.then(response => this.cache.set(cacheKey, response))
|
||||||
|
.then(response => this.mapAndCreateResponse(response, convertTmdbToMovie))
|
||||||
|
.catch((error) => { console.log(error); throw new Error('Could not parse movie search result') })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -197,13 +172,16 @@ class TMDB {
|
|||||||
* @param {Number} page representing pagination of results
|
* @param {Number} page representing pagination of results
|
||||||
* @returns {Promise} dict with query results, current page and total_pages
|
* @returns {Promise} dict with query results, current page and total_pages
|
||||||
*/
|
*/
|
||||||
showSearch(search_query, page = 1, include_adult = true) {
|
showSearch(query, page=1) {
|
||||||
const tmdbquery = { query: search_query, page, include_adult };
|
const tmdbquery = { query: query, page: page };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.showSearch}:${page}:${search_query}:${include_adult}`;
|
const cacheKey = `${this.cacheTags.showSearch}:${page}:${query}`;
|
||||||
|
return Promise.resolve()
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchTv", tmdbquery)
|
.then(() => this.cache.get(cacheKey))
|
||||||
.then(response => this.cache.set(cacheKey, response, this.defaultTTL))
|
.catch(() => this.tmdb('searchTv', tmdbquery))
|
||||||
.then(response => this.mapResults(response, "show"));
|
.catch(() => { throw new Error('Could not complete show search to tmdb'); })
|
||||||
|
.then(response => this.cache.set(cacheKey, response))
|
||||||
|
.then(response => this.mapAndCreateResponse(response, convertTmdbToShow))
|
||||||
|
.catch((error) => { console.log(error); throw new Error('Could not parse show search result') })
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -212,31 +190,79 @@ class TMDB {
|
|||||||
* @param {Number} page representing pagination of results
|
* @param {Number} page representing pagination of results
|
||||||
* @returns {Promise} dict with query results, current page and total_pages
|
* @returns {Promise} dict with query results, current page and total_pages
|
||||||
*/
|
*/
|
||||||
personSearch(search_query, page = 1, include_adult = true) {
|
personSearch(query, page=1) {
|
||||||
const tmdbquery = { query: search_query, page, include_adult };
|
const tmdbquery = { query: query, page: page };
|
||||||
const cacheKey = `tmdb/${this.cacheTags.personSearch}:${page}:${search_query}:${include_adult}`;
|
const cacheKey = `${this.cacheTags.personSearch}:${page}:${query}`;
|
||||||
|
return Promise.resolve()
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, "searchPerson", tmdbquery)
|
.then(() => this.cache.get(cacheKey))
|
||||||
.then(response => this.cache.set(cacheKey, response, this.defaultTTL))
|
.catch(() => this.tmdb('searchPerson', tmdbquery))
|
||||||
.then(response => this.mapResults(response, "person"));
|
.catch(() => { throw new Error('Could not complete person search to tmdb'); })
|
||||||
|
.then(response => this.cache.set(cacheKey, response))
|
||||||
|
.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 = `tmdb/${this.cacheTags[listname]}:${page}`;
|
const cacheKey = `${this.cacheTags[listname]}:${page}`;
|
||||||
|
return Promise.resolve()
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, listname, query)
|
.then(() => this.cache.get(cacheKey))
|
||||||
.then(response => this.cache.set(cacheKey, response, this.defaultTTL))
|
.catch(() => this.tmdb(listname, query))
|
||||||
.then(response => this.mapResults(response, "movie"));
|
.catch(() => { throw new Error('Unable to get movie list from tmdb')})
|
||||||
|
.then(response => this.cache.set(cacheKey, response))
|
||||||
|
.then(response => this.mapAndCreateResponse(response, convertTmdbToMovie));
|
||||||
}
|
}
|
||||||
|
|
||||||
showList(listname, page = 1) {
|
showList(listname, page = 1) {
|
||||||
const query = { page: page };
|
const query = { page: page };
|
||||||
const cacheKey = `tmdb/${this.cacheTags[listname]}:${page}`;
|
const cacheKey = `${this.cacheTags[listname]}:${page}`;
|
||||||
|
return Promise.resolve()
|
||||||
|
.then(() => this.cache.get(cacheKey))
|
||||||
|
.catch(() => this.tmdb(listname, query))
|
||||||
|
.catch(() => { throw new Error('Unable to get show list from tmdb')})
|
||||||
|
.then(response => this.cache.set(cacheKey, response))
|
||||||
|
.then(response => this.mapAndCreateResponse(response, convertTmdbToShow));
|
||||||
|
}
|
||||||
|
|
||||||
return this.getFromCacheOrFetchFromTmdb(cacheKey, listName, query)
|
/**
|
||||||
.then(response => this.cache.set(cacheKey, response, this.defaultTTL))
|
* Fetches a given list from tmdb.
|
||||||
.then(response => this.mapResults(response, "show"));
|
* @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));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -245,26 +271,23 @@ 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, _) {
|
||||||
let results = response.results.map(result => {
|
let results = response.results.map((result) => {
|
||||||
if (type === "movie" || result.media_type === "movie") {
|
if (result.media_type === 'movie') {
|
||||||
const movie = Movie.convertFromTmdbResponse(result);
|
return convertTmdbToMovie(result);
|
||||||
return movie.createJsonResponse();
|
} else if (result.media_type === 'tv') {
|
||||||
} else if (type === "show" || result.media_type === "tv") {
|
return convertTmdbToShow(result);
|
||||||
const show = Show.convertFromTmdbResponse(result);
|
} else if (result.media_type === 'person') {
|
||||||
return show.createJsonResponse();
|
return convertTmdbToPerson(result);
|
||||||
} else if (type === "person" || result.media_type === "person") {
|
|
||||||
const person = Person.convertFromTmdbResponse(result);
|
|
||||||
return person.createJsonResponse();
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
return {
|
return {
|
||||||
results: results,
|
results: results,
|
||||||
page: response.page,
|
page: response.page,
|
||||||
total_results: response.total_results,
|
total_results: response.total_results,
|
||||||
total_pages: response.total_pages
|
total_pages: response.total_pages
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
import { Movie } from './types'
|
|
||||||
|
|
||||||
Movie('str', 123)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
module.exports = TMDB;
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
const Movie = require('./types/movie.js')
|
|
||||||
const Show = require('./types/show.js')
|
|
||||||
const Person = require('./types/person.js')
|
|
||||||
const Credits = require('./types/credits.js')
|
|
||||||
const ReleaseDates = require('./types/releaseDates.js')
|
|
||||||
|
|
||||||
module.exports = { Movie, Show, Person, Credits, ReleaseDates }
|
|
||||||
@@ -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 }
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
import Movie from "./movie";
|
|
||||||
import Show from "./show";
|
|
||||||
|
|
||||||
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 => {
|
|
||||||
if (cast["media_type"]) {
|
|
||||||
if (cast.media_type === "movie") {
|
|
||||||
return CreditedMovie.convertFromTmdbResponse(cast);
|
|
||||||
} else if (cast.media_type === "tv") {
|
|
||||||
return CreditedShow.convertFromTmdbResponse(cast);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return new CastMember(
|
|
||||||
cast.character,
|
|
||||||
cast.gender,
|
|
||||||
cast.id,
|
|
||||||
cast.name,
|
|
||||||
cast.profile_path
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
const allCrew = crew.map(crew => {
|
|
||||||
if (cast["media_type"]) {
|
|
||||||
if (cast.media_type === "movie") {
|
|
||||||
return CreditedMovie.convertFromTmdbResponse(cast);
|
|
||||||
} else if (cast.media_type === "tv") {
|
|
||||||
return CreditedShow.convertFromTmdbResponse(cast);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 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 = "person";
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = "person";
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class CreditedMovie extends Movie {}
|
|
||||||
class CreditedShow extends Show {}
|
|
||||||
|
|
||||||
module.exports = Credits;
|
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -1,69 +1,12 @@
|
|||||||
class Person {
|
class Person {
|
||||||
constructor(
|
constructor(id, name, poster=null, birthday=null, deathday=null, known_for=null) {
|
||||||
id,
|
|
||||||
name,
|
|
||||||
poster = undefined,
|
|
||||||
birthday = undefined,
|
|
||||||
deathday = undefined,
|
|
||||||
adult = undefined,
|
|
||||||
placeOfBirth = undefined,
|
|
||||||
biography = 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.placeOfBirth = placeOfBirth;
|
this.type = 'person';
|
||||||
this.biography = biography;
|
|
||||||
this.knownForDepartment = knownForDepartment;
|
|
||||||
this.type = "person";
|
|
||||||
}
|
|
||||||
|
|
||||||
static convertFromTmdbResponse(response) {
|
|
||||||
const {
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
profile_path,
|
|
||||||
birthday,
|
|
||||||
deathday,
|
|
||||||
adult,
|
|
||||||
place_of_birth,
|
|
||||||
biography,
|
|
||||||
known_for_department
|
|
||||||
} = response;
|
|
||||||
|
|
||||||
const birthDay = new Date(birthday);
|
|
||||||
const deathDay = deathday ? new Date(deathday) : null;
|
|
||||||
|
|
||||||
return new Person(
|
|
||||||
id,
|
|
||||||
name,
|
|
||||||
profile_path,
|
|
||||||
birthDay,
|
|
||||||
deathDay,
|
|
||||||
adult,
|
|
||||||
place_of_birth,
|
|
||||||
biography,
|
|
||||||
known_for_department
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
createJsonResponse() {
|
|
||||||
return {
|
|
||||||
id: this.id,
|
|
||||||
name: this.name,
|
|
||||||
poster: this.poster,
|
|
||||||
birthday: this.birthday,
|
|
||||||
deathday: this.deathday,
|
|
||||||
place_of_birth: this.placeOfBirth,
|
|
||||||
biography: this.biography,
|
|
||||||
known_for_department: this.knownForDepartment,
|
|
||||||
adult: this.adult,
|
|
||||||
type: this.type
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
@@ -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;
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
const User = require("src/user/user");
|
const User = require('src/user/user');
|
||||||
const jwt = require("jsonwebtoken");
|
const jwt = require('jsonwebtoken');
|
||||||
|
|
||||||
class Token {
|
class Token {
|
||||||
constructor(user, admin = false, settings = null) {
|
constructor(user) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.admin = admin;
|
|
||||||
this.settings = settings;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -14,12 +12,7 @@ class Token {
|
|||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
toString(secret) {
|
toString(secret) {
|
||||||
const { user, admin, settings } = this;
|
return jwt.sign({ username: this.user.username }, secret);
|
||||||
|
|
||||||
let data = { username: user.username, settings };
|
|
||||||
if (admin) data["admin"] = admin;
|
|
||||||
|
|
||||||
return jwt.sign(data, secret, { expiresIn: "90d" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,12 +22,15 @@ class Token {
|
|||||||
* @returns {Token}
|
* @returns {Token}
|
||||||
*/
|
*/
|
||||||
static fromString(jwtToken, secret) {
|
static fromString(jwtToken, secret) {
|
||||||
const token = jwt.verify(jwtToken, secret, { clockTolerance: 10000 });
|
let username = null;
|
||||||
if (token.username == null) throw new Error("Malformed token");
|
|
||||||
|
|
||||||
const { username, admin, settings } = token;
|
try {
|
||||||
|
username = jwt.verify(jwtToken, secret).username;
|
||||||
|
} catch (error) {
|
||||||
|
throw new Error('The token is invalid.');
|
||||||
|
}
|
||||||
const user = new User(username);
|
const user = new User(username);
|
||||||
return new Token(user, admin, settings);
|
return new Token(user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,21 +1,15 @@
|
|||||||
const assert = require("assert");
|
const assert = require('assert');
|
||||||
const establishedDatabase = require("src/database/database");
|
const establishedDatabase = require('src/database/database');
|
||||||
|
|
||||||
class UserRepository {
|
class UserRepository {
|
||||||
constructor(database) {
|
constructor(database) {
|
||||||
this.database = database || establishedDatabase;
|
this.database = database || establishedDatabase;
|
||||||
this.queries = {
|
this.queries = {
|
||||||
read: "select * from user where lower(user_name) = lower(?)",
|
read: 'select * from user where lower(user_name) = lower(?)',
|
||||||
create: "insert into user (user_name) values (?)",
|
create: 'insert into user (user_name) values (?)',
|
||||||
change: "update user set password = ? where user_name = ?",
|
change: 'update user set password = ? where user_name = ?',
|
||||||
retrieveHash: "select * from user where user_name = ?",
|
retrieveHash: 'select * from user where user_name = ?',
|
||||||
getAdminStateByUser: "select admin from user where user_name = ?",
|
getAdminStateByUser: 'select admin from user where user_name = ?'
|
||||||
link: "update settings set plex_userid = ? where user_name = ?",
|
|
||||||
unlink: "update settings set plex_userid = null where user_name = ?",
|
|
||||||
createSettings: "insert into settings (user_name) values (?)",
|
|
||||||
updateSettings:
|
|
||||||
"update settings set user_name = ?, dark_mode = ?, emoji = ?",
|
|
||||||
getSettings: "select * from settings where user_name = ?"
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,17 +19,13 @@ class UserRepository {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
create(user) {
|
create(user) {
|
||||||
return this.database
|
return Promise.resolve()
|
||||||
.get(this.queries.read, user.username)
|
.then(() => this.database.get(this.queries.read, user.username))
|
||||||
.then(() => this.database.run(this.queries.create, user.username))
|
.then(() => this.database.run(this.queries.create, user.username))
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
if (
|
if (error.name === 'AssertionError' || error.message.endsWith('user_name')) {
|
||||||
error.name === "AssertionError" ||
|
throw new Error('That username is already registered');
|
||||||
error.message.endsWith("user_name")
|
|
||||||
) {
|
|
||||||
throw new Error("That username is already registered");
|
|
||||||
}
|
}
|
||||||
throw Error(error);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,16 +35,13 @@ class UserRepository {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
retrieveHash(user) {
|
retrieveHash(user) {
|
||||||
return this.database
|
return Promise.resolve()
|
||||||
.get(this.queries.retrieveHash, user.username)
|
.then(() => this.database.get(this.queries.retrieveHash, user.username))
|
||||||
.then(row => {
|
.then((row) => {
|
||||||
assert(row, "The user does not exist.");
|
assert(row, 'The user does not exist.');
|
||||||
return row.password;
|
return row.password;
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch((err) => { console.log(error); throw new Error('Unable to find your user.'); });
|
||||||
console.log(error);
|
|
||||||
throw new Error("Unable to find your user.");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -64,193 +51,14 @@ class UserRepository {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
changePassword(user, password) {
|
changePassword(user, password) {
|
||||||
return this.database.run(this.queries.change, [password, user.username]);
|
return Promise.resolve(this.database.run(this.queries.change, [password, user.username]));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Link plex userid with seasoned user
|
|
||||||
* @param {String} username the user you want to lunk plex userid with
|
|
||||||
* @param {Number} plexUserID plex unique id
|
|
||||||
* @returns {Promsie}
|
|
||||||
*/
|
|
||||||
linkPlexUserId(username, plexUserID) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.database
|
|
||||||
.run(this.queries.link, [plexUserID, username])
|
|
||||||
.then(row => resolve(row))
|
|
||||||
.catch(error => {
|
|
||||||
// TODO log this unknown db error
|
|
||||||
console.error("db error", error);
|
|
||||||
|
|
||||||
reject({
|
|
||||||
status: 500,
|
|
||||||
message:
|
|
||||||
"An unexpected error occured while linking plex and seasoned accounts",
|
|
||||||
source: "seasoned database"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Unlink plex userid with seasoned user
|
|
||||||
* @param {User} user the user you want to lunk plex userid with
|
|
||||||
* @returns {Promsie}
|
|
||||||
*/
|
|
||||||
unlinkPlexUserId(username) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.database
|
|
||||||
.run(this.queries.unlink, username)
|
|
||||||
.then(row => resolve(row))
|
|
||||||
.catch(error => {
|
|
||||||
// TODO log this unknown db error
|
|
||||||
console.log("db error", error);
|
|
||||||
|
|
||||||
reject({
|
|
||||||
status: 500,
|
|
||||||
message:
|
|
||||||
"An unexpected error occured while unlinking plex and seasoned accounts",
|
|
||||||
source: "seasoned database"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if the user has boolean flag set for admin in database
|
|
||||||
* @param {User} user object
|
|
||||||
* @returns {Promsie}
|
|
||||||
*/
|
|
||||||
checkAdmin(user) {
|
checkAdmin(user) {
|
||||||
return this.database
|
return this.database.get(this.queries.getAdminStateByUser, user.username).then((row) => {
|
||||||
.get(this.queries.getAdminStateByUser, user.username)
|
return row.admin;
|
||||||
.then(row => row.admin);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get settings for user matching string username
|
|
||||||
* @param {String} username
|
|
||||||
* @returns {Promsie}
|
|
||||||
*/
|
|
||||||
getSettings(username) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
this.database
|
|
||||||
.get(this.queries.getSettings, username)
|
|
||||||
.then(async row => {
|
|
||||||
if (row == null) {
|
|
||||||
console.debug(
|
|
||||||
`settings do not exist for user: ${username}. Creating settings entry.`
|
|
||||||
);
|
|
||||||
|
|
||||||
const userExistsWithUsername = await this.database.get(
|
|
||||||
"select * from user where user_name is ?",
|
|
||||||
username
|
|
||||||
);
|
|
||||||
if (userExistsWithUsername !== undefined) {
|
|
||||||
try {
|
|
||||||
resolve(this.dbCreateSettings(username));
|
|
||||||
} catch (error) {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reject({
|
|
||||||
status: 404,
|
|
||||||
message: "User not found, no settings to get"
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(row);
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error(
|
|
||||||
"Unexpected error occured while fetching settings for your account. Error:",
|
|
||||||
error
|
|
||||||
);
|
|
||||||
reject({
|
|
||||||
status: 500,
|
|
||||||
message:
|
|
||||||
"An unexpected error occured while fetching settings for your account",
|
|
||||||
source: "seasoned database"
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update settings values for user matching string username
|
|
||||||
* @param {String} username
|
|
||||||
* @param {String} dark_mode
|
|
||||||
* @param {String} emoji
|
|
||||||
* @returns {Promsie}
|
|
||||||
*/
|
|
||||||
updateSettings(username, dark_mode = undefined, emoji = undefined) {
|
|
||||||
const settings = this.getSettings(username);
|
|
||||||
dark_mode = dark_mode !== undefined ? dark_mode : settings.dark_mode;
|
|
||||||
emoji = emoji !== undefined ? emoji : settings.emoji;
|
|
||||||
|
|
||||||
return this.dbUpdateSettings(username, dark_mode, emoji).catch(error => {
|
|
||||||
if (error.status && error.message) {
|
|
||||||
return error;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
status: 500,
|
|
||||||
message:
|
|
||||||
"An unexpected error occured while updating settings for your account"
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function for creating settings in the database
|
|
||||||
* @param {String} username
|
|
||||||
* @returns {Promsie}
|
|
||||||
*/
|
|
||||||
dbCreateSettings(username) {
|
|
||||||
return this.database
|
|
||||||
.run(this.queries.createSettings, username)
|
|
||||||
.then(() => this.database.get(this.queries.getSettings, username))
|
|
||||||
.catch(error =>
|
|
||||||
rejectUnexpectedDatabaseError(
|
|
||||||
"Unexpected error occured while creating settings",
|
|
||||||
503,
|
|
||||||
error
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper function for updating settings in the database
|
|
||||||
* @param {String} username
|
|
||||||
* @returns {Promsie}
|
|
||||||
*/
|
|
||||||
dbUpdateSettings(username, dark_mode, emoji) {
|
|
||||||
return new Promise((resolve, reject) =>
|
|
||||||
this.database
|
|
||||||
.run(this.queries.updateSettings, [username, dark_mode, emoji])
|
|
||||||
.then(row => resolve(row))
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const rejectUnexpectedDatabaseError = (
|
|
||||||
message,
|
|
||||||
status,
|
|
||||||
error,
|
|
||||||
reject = null
|
|
||||||
) => {
|
|
||||||
console.error(error);
|
|
||||||
const body = {
|
|
||||||
status,
|
|
||||||
message,
|
|
||||||
source: "seasoned database"
|
|
||||||
};
|
|
||||||
|
|
||||||
if (reject == null) {
|
|
||||||
return new Promise((resolve, reject) => reject(body));
|
|
||||||
}
|
|
||||||
reject(body);
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = UserRepository;
|
module.exports = UserRepository;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
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) {
|
||||||
@@ -13,13 +13,13 @@ class UserSecurity {
|
|||||||
* @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 this.userRepository
|
return Promise.resolve()
|
||||||
.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));
|
||||||
}
|
}
|
||||||
@@ -32,12 +32,10 @@ class UserSecurity {
|
|||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
login(user, clearPassword) {
|
login(user, clearPassword) {
|
||||||
return this.userRepository
|
return Promise.resolve()
|
||||||
.retrieveHash(user)
|
.then(() => this.userRepository.retrieveHash(user))
|
||||||
.then(hash => UserSecurity.compareHashes(hash, clearPassword))
|
.then(hash => UserSecurity.compareHashes(hash, clearPassword))
|
||||||
.catch(() => {
|
.catch(() => { throw new Error('Wrong username or password.'); });
|
||||||
throw new Error("Incorrect username or password.");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,9 +46,12 @@ class UserSecurity {
|
|||||||
*/
|
*/
|
||||||
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) resolve(true);
|
if (matches === true) {
|
||||||
reject(false);
|
resolve();
|
||||||
|
} else {
|
||||||
|
reject();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -61,11 +62,8 @@ class UserSecurity {
|
|||||||
* @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) => {
|
|
||||||
if (error) reject(error);
|
|
||||||
|
|
||||||
resolve(hash);
|
resolve(hash);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,239 +1,137 @@
|
|||||||
const express = require("express");
|
const express = require('express');
|
||||||
const Raven = require("raven");
|
const Raven = require('raven');
|
||||||
const cookieParser = require("cookie-parser");
|
const bodyParser = require('body-parser');
|
||||||
const bodyParser = require("body-parser");
|
const tokenToUser = require('./middleware/tokenToUser');
|
||||||
|
const mustBeAuthenticated = require('./middleware/mustBeAuthenticated');
|
||||||
|
const mustBeAdmin = require('./middleware/mustBeAdmin');
|
||||||
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
|
|
||||||
const configuration = require("src/config/configuration").getInstance();
|
const listController = require('./controllers/list/listController');
|
||||||
|
|
||||||
const reqTokenToUser = require("./middleware/reqTokenToUser");
|
|
||||||
const mustBeAuthenticated = require("./middleware/mustBeAuthenticated");
|
|
||||||
const mustBeAdmin = require("./middleware/mustBeAdmin");
|
|
||||||
const mustHaveAccountLinkedToPlex = require("./middleware/mustHaveAccountLinkedToPlex");
|
|
||||||
|
|
||||||
const listController = require("./controllers/list/listController");
|
|
||||||
const tautulli = require("./controllers/user/viewHistory.js");
|
|
||||||
const SettingsController = require("./controllers/user/settings");
|
|
||||||
const AuthenticatePlexAccountController = require("./controllers/user/authenticatePlexAccount");
|
|
||||||
|
|
||||||
// TODO: Have our raven router check if there is a value, if not don't enable raven.
|
// TODO: Have our raven router check if there is a value, if not don't enable raven.
|
||||||
Raven.config(configuration.get("raven", "DSN")).install();
|
Raven.config(configuration.get('raven', 'DSN')).install();
|
||||||
|
|
||||||
const app = express(); // define our app using express
|
const app = express(); // define our app using express
|
||||||
app.use(Raven.requestHandler());
|
app.use(Raven.requestHandler());
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
app.use(cookieParser());
|
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const allowedOrigins = configuration.get("webserver", "origins");
|
const allowedOrigins = ['https://kevinmidboe.com', 'http://localhost:8080'];
|
||||||
|
|
||||||
// TODO: All JSON handling in a single router
|
// TODO: All JSON handling in a single router
|
||||||
// router.use(bodyParser.json());
|
// router.use(bodyParser.json());
|
||||||
app.use(bodyParser.urlencoded({ extended: true }));
|
app.use(bodyParser.urlencoded({ extended: true }));
|
||||||
|
|
||||||
/* Check header and cookie for authentication and set req.loggedInUser */
|
/* Decode the Authorization header if provided */
|
||||||
router.use(reqTokenToUser);
|
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
|
||||||
// const origin = req.headers.origin;
|
console.log('Request: ', req.originalUrl);
|
||||||
// if (allowedOrigins.indexOf(origin) > -1) {
|
|
||||||
// res.setHeader("Access-Control-Allow-Origin", origin);
|
|
||||||
// }
|
|
||||||
|
|
||||||
res.header(
|
const origin = req.headers.origin;
|
||||||
"Access-Control-Allow-Headers",
|
if (allowedOrigins.indexOf(origin) > -1) {
|
||||||
"Content-Type, Authorization, loggedinuser, set-cookie"
|
res.setHeader('Access-Control-Allow-Origin', origin);
|
||||||
);
|
}
|
||||||
|
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, loggedinuser');
|
||||||
res.header("Access-Control-Allow-Credentials", "true");
|
res.header('Access-Control-Allow-Methods', 'POST, GET, PUT');
|
||||||
res.header("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS");
|
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/", (req, res) => {
|
router.get('/', function mainHandler(req, res) {
|
||||||
res.send("welcome to seasoned api");
|
throw new Error('Broke!');
|
||||||
});
|
});
|
||||||
|
|
||||||
app.use(Raven.errorHandler());
|
app.use(Raven.errorHandler());
|
||||||
app.use((err, req, res, next) => {
|
app.use(function onError(err, req, res, next) {
|
||||||
res.statusCode = 500;
|
res.statusCode = 500;
|
||||||
res.end(res.sentry + "\n");
|
res.end(res.sentry + '\n');
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User
|
* User
|
||||||
*/
|
*/
|
||||||
router.post("/v1/user", require("./controllers/user/register.js"));
|
router.post('/v1/user', require('./controllers/user/register.js'));
|
||||||
router.post("/v1/user/login", require("./controllers/user/login.js"));
|
router.post('/v1/user/login', require('./controllers/user/login.js'));
|
||||||
router.post("/v1/user/logout", require("./controllers/user/logout.js"));
|
router.get('/v1/user/history', mustBeAuthenticated, require('./controllers/user/history.js'));
|
||||||
router.get(
|
router.get('/v1/user/requests', mustBeAuthenticated, require('./controllers/user/requests.js'));
|
||||||
"/v1/user/settings",
|
|
||||||
mustBeAuthenticated,
|
|
||||||
SettingsController.getSettingsController
|
|
||||||
);
|
|
||||||
router.put(
|
|
||||||
"/v1/user/settings",
|
|
||||||
mustBeAuthenticated,
|
|
||||||
SettingsController.updateSettingsController
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
"/v1/user/search_history",
|
|
||||||
mustBeAuthenticated,
|
|
||||||
require("./controllers/user/searchHistory.js")
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
"/v1/user/requests",
|
|
||||||
mustBeAuthenticated,
|
|
||||||
require("./controllers/user/requests.js")
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
"/v1/user/link_plex",
|
|
||||||
mustBeAuthenticated,
|
|
||||||
AuthenticatePlexAccountController.link
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
"/v1/user/unlink_plex",
|
|
||||||
mustBeAuthenticated,
|
|
||||||
AuthenticatePlexAccountController.unlink
|
|
||||||
);
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
"/v1/user/view_history",
|
|
||||||
mustHaveAccountLinkedToPlex,
|
|
||||||
tautulli.userViewHistoryController
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
"/v1/user/watch_time",
|
|
||||||
mustHaveAccountLinkedToPlex,
|
|
||||||
tautulli.watchTimeStatsController
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
"/v1/user/plays_by_day",
|
|
||||||
mustHaveAccountLinkedToPlex,
|
|
||||||
tautulli.getPlaysByDaysController
|
|
||||||
);
|
|
||||||
router.get(
|
|
||||||
"/v1/user/plays_by_dayofweek",
|
|
||||||
mustHaveAccountLinkedToPlex,
|
|
||||||
tautulli.getPlaysByDayOfWeekController
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Seasoned
|
* Seasoned
|
||||||
*/
|
*/
|
||||||
router.get("/v1/seasoned/all", require("./controllers/seasoned/readStrays.js"));
|
router.get('/v1/seasoned/all', require('./controllers/seasoned/readStrays.js'));
|
||||||
router.get(
|
router.get('/v1/seasoned/:strayId', require('./controllers/seasoned/strayById.js'));
|
||||||
"/v1/seasoned/:strayId",
|
router.post('/v1/seasoned/verify/:strayId', require('./controllers/seasoned/verifyStray.js'));
|
||||||
require("./controllers/seasoned/strayById.js")
|
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
"/v1/seasoned/verify/:strayId",
|
|
||||||
require("./controllers/seasoned/verifyStray.js")
|
|
||||||
);
|
|
||||||
|
|
||||||
router.get("/v2/search/", require("./controllers/search/multiSearch.js"));
|
router.get('/v2/search/', require('./controllers/search/multiSearch.js'));
|
||||||
router.get("/v2/search/movie", require("./controllers/search/movieSearch.js"));
|
router.get('/v2/search/movie', require('./controllers/search/movieSearch.js'));
|
||||||
router.get("/v2/search/show", require("./controllers/search/showSearch.js"));
|
router.get('/v2/search/show', require('./controllers/search/showSearch.js'));
|
||||||
router.get(
|
router.get('/v2/search/person', require('./controllers/search/personSearch.js'));
|
||||||
"/v2/search/person",
|
|
||||||
require("./controllers/search/personSearch.js")
|
|
||||||
);
|
|
||||||
|
|
||||||
router.get("/v2/movie/now_playing", listController.nowPlayingMovies);
|
router.get('/v2/movie/now_playing', listController.nowPlayingMovies);
|
||||||
router.get("/v2/movie/popular", listController.popularMovies);
|
router.get('/v2/movie/popular', listController.popularMovies);
|
||||||
router.get("/v2/movie/top_rated", listController.topRatedMovies);
|
router.get('/v2/movie/top_rated', listController.topRatedMovies);
|
||||||
router.get("/v2/movie/upcoming", listController.upcomingMovies);
|
router.get('/v2/movie/upcoming', listController.upcomingMovies);
|
||||||
router.get("/v2/movie/:id/credits", require("./controllers/movie/credits.js"));
|
|
||||||
router.get(
|
|
||||||
"/v2/movie/:id/release_dates",
|
|
||||||
require("./controllers/movie/releaseDates.js")
|
|
||||||
);
|
|
||||||
router.get("/v2/movie/:id", require("./controllers/movie/info.js"));
|
|
||||||
|
|
||||||
router.get("/v2/show/now_playing", listController.nowPlayingShows);
|
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/show/:id/credits", require("./controllers/show/credits.js"));
|
|
||||||
router.get("/v2/show/:id", require("./controllers/show/info.js"));
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
"/v2/person/:id/credits",
|
|
||||||
require("./controllers/person/credits.js")
|
|
||||||
);
|
|
||||||
router.get("/v2/person/:id", require("./controllers/person/info.js"));
|
|
||||||
|
|
||||||
|
router.get('/v2/movie/:id', require('./controllers/info/movieInfo.js'));
|
||||||
|
router.get('/v2/show/:id', require('./controllers/info/showInfo.js'));
|
||||||
|
router.get('/v2/person/:id', require('./controllers/info/personInfo.js'));
|
||||||
/**
|
/**
|
||||||
* Plex
|
* Plex
|
||||||
*/
|
*/
|
||||||
router.get("/v2/plex/search", require("./controllers/plex/search"));
|
router.get('/v2/plex/search', require('./controllers/plex/search'));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List
|
* List
|
||||||
*/
|
*/
|
||||||
router.get("/v1/plex/search", require("./controllers/plex/searchMedia.js"));
|
router.get('/v1/plex/search', require('./controllers/plex/searchMedia.js'));
|
||||||
router.get("/v1/plex/playing", require("./controllers/plex/plexPlaying.js"));
|
router.get('/v1/plex/playing', require('./controllers/plex/plexPlaying.js'));
|
||||||
router.get("/v1/plex/request", require("./controllers/plex/searchRequest.js"));
|
router.get('/v1/plex/request', require('./controllers/plex/searchRequest.js'));
|
||||||
router.get(
|
router.get('/v1/plex/request/:mediaId', require('./controllers/plex/readRequest.js'));
|
||||||
"/v1/plex/request/:mediaId",
|
router.post('/v1/plex/request/:mediaId', require('./controllers/plex/submitRequest.js'));
|
||||||
require("./controllers/plex/readRequest.js")
|
router.post('/v1/plex/hook', require('./controllers/plex/hookDump.js'));
|
||||||
);
|
|
||||||
router.post(
|
|
||||||
"/v1/plex/request/:mediaId",
|
|
||||||
require("./controllers/plex/submitRequest.js")
|
|
||||||
);
|
|
||||||
router.post("/v1/plex/hook", require("./controllers/plex/hookDump.js"));
|
|
||||||
|
|
||||||
router.get(
|
|
||||||
"/v1/plex/watch-link",
|
|
||||||
mustBeAuthenticated,
|
|
||||||
require("./controllers/plex/watchDirectLink.js")
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Requests
|
* Requests
|
||||||
*/
|
*/
|
||||||
|
|
||||||
router.get("/v2/request", require("./controllers/request/fetchAllRequests.js"));
|
router.get('/v2/request', require('./controllers/request/fetchAllRequests.js'));
|
||||||
router.get("/v2/request/:id", require("./controllers/request/getRequest.js"));
|
router.get('/v2/request/:id', require('./controllers/request/getRequest.js'));
|
||||||
router.post("/v2/request", require("./controllers/request/requestTmdbId.js"));
|
router.post('/v2/request', require('./controllers/request/requestTmdbId.js'));
|
||||||
router.get(
|
router.get('/v1/plex/requests/all', require('./controllers/plex/fetchRequested.js'));
|
||||||
"/v1/plex/requests/all",
|
router.put('/v1/plex/request/:requestId', mustBeAuthenticated, require('./controllers/plex/updateRequested.js'));
|
||||||
require("./controllers/plex/fetchRequested.js")
|
|
||||||
);
|
|
||||||
router.put(
|
|
||||||
"/v1/plex/request/:requestId",
|
|
||||||
mustBeAuthenticated,
|
|
||||||
require("./controllers/plex/updateRequested.js")
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pirate
|
* Pirate
|
||||||
*/
|
*/
|
||||||
router.get(
|
router.get('/v1/pirate/search', mustBeAuthenticated, require('./controllers/pirate/searchTheBay.js'));
|
||||||
"/v1/pirate/search",
|
router.post('/v1/pirate/add', mustBeAuthenticated, require('./controllers/pirate/addMagnet.js'));
|
||||||
mustBeAuthenticated,
|
|
||||||
require("./controllers/pirate/searchTheBay.js")
|
/**
|
||||||
);
|
* TMDB
|
||||||
router.post(
|
*/
|
||||||
"/v1/pirate/add",
|
router.get('/v1/tmdb/search', require('./controllers/tmdb/searchMedia.js'));
|
||||||
mustBeAuthenticated,
|
router.get('/v1/tmdb/list/:listname', require('./controllers/tmdb/listSearch.js'));
|
||||||
require("./controllers/pirate/addMagnet.js")
|
router.get('/v1/tmdb/:mediaId', require('./controllers/tmdb/readMedia.js'));
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* git
|
* git
|
||||||
*/
|
*/
|
||||||
router.post("/v1/git/dump", require("./controllers/git/dumpHook.js"));
|
router.post('/v1/git/dump', require('./controllers/git/dumpHook.js'));
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* misc
|
* misc
|
||||||
*/
|
*/
|
||||||
router.get("/v1/emoji", require("./controllers/misc/emoji.js"));
|
router.get('/v1/emoji', require('./controllers/misc/emoji.js'));
|
||||||
|
|
||||||
// REGISTER OUR ROUTES -------------------------------
|
// REGISTER OUR ROUTES -------------------------------
|
||||||
// all of our routes will be prefixed with /api
|
// all of our routes will be prefixed with /api
|
||||||
app.use("/api", router);
|
app.use('/api', router);
|
||||||
|
|
||||||
module.exports = app;
|
module.exports = app;
|
||||||
|
|||||||
30
seasoned_api/src/webserver/controllers/info/movieInfo.js
Normal file
30
seasoned_api/src/webserver/controllers/info/movieInfo.js
Normal 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;
|
||||||
24
seasoned_api/src/webserver/controllers/info/personInfo.js
Normal file
24
seasoned_api/src/webserver/controllers/info/personInfo.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
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 person
|
||||||
|
* @param {Request} req http request variable
|
||||||
|
* @param {Response} res
|
||||||
|
* @returns {Callback}
|
||||||
|
*/
|
||||||
|
|
||||||
|
function personInfoController(req, res) {
|
||||||
|
const personId = req.params.id;
|
||||||
|
tmdb.personInfo(personId)
|
||||||
|
.then((person) => {
|
||||||
|
res.send(person);
|
||||||
|
}).catch((error) => {
|
||||||
|
res.status(404).send({ success: false, error: error.message });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = personInfoController;
|
||||||
31
seasoned_api/src/webserver/controllers/info/showInfo.js
Normal file
31
seasoned_api/src/webserver/controllers/info/showInfo.js
Normal 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;
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
const configuration = require('src/config/configuration').getInstance();
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
|
const Cache = require('src/tmdb/cache');
|
||||||
const TMDB = require('src/tmdb/tmdb');
|
const TMDB = require('src/tmdb/tmdb');
|
||||||
const tmdb = new TMDB(configuration.get('tmdb', 'apiKey'));
|
const cache = new Cache();
|
||||||
|
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||||
|
|
||||||
// there should be a translate function from query params to
|
// there should be a translate function from query params to
|
||||||
// tmdb list that is valid. Should it be a helper function or does it
|
// tmdb list that is valid. Should it be a helper function or does it
|
||||||
@@ -14,55 +16,70 @@ const tmdb = new TMDB(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({
|
exports.popularMovies = (req, res) => {
|
||||||
status: 400,
|
const { page } = req.query;
|
||||||
message: `'${type}' is not a valid list type.`
|
const listname = 'miscPopularMovies'
|
||||||
}, res)
|
|
||||||
|
getTmdbMovieList(res, listname, page);
|
||||||
}
|
}
|
||||||
|
|
||||||
const nowPlayingMovies = (req, res) => fetchTmdbList(req, res, 'miscNowPlayingMovies', 'movie')
|
exports.topRatedMovies = (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 = 'miscTopRatedMovies'
|
||||||
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.upcomingMovies = (req, res) => {
|
||||||
upcomingMovies,
|
const { page } = req.query;
|
||||||
nowPlayingShows,
|
const listname = 'miscUpcomingMovies'
|
||||||
popularShows,
|
|
||||||
topRatedShows
|
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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
const configuration = require('src/config/configuration').getInstance();
|
|
||||||
const TMDB = require('src/tmdb/tmdb');
|
|
||||||
|
|
||||||
const tmdb = new TMDB(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;
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
const configuration = require("src/config/configuration").getInstance();
|
|
||||||
const TMDB = require("src/tmdb/tmdb");
|
|
||||||
const Plex = require("src/plex/plex");
|
|
||||||
const tmdb = new TMDB(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) {
|
|
||||||
try {
|
|
||||||
movie.exists_in_plex = await plex.existsInPlex(movie);
|
|
||||||
} catch (error) {
|
|
||||||
if (error.status === 401) {
|
|
||||||
console.log("Unathorized request, check plex server LAN settings");
|
|
||||||
} else {
|
|
||||||
console.log("Unkown error from plex!");
|
|
||||||
}
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res.send(movie);
|
|
||||||
} catch (error) {
|
|
||||||
handleError(error, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = movieInfoController;
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
const configuration = require('src/config/configuration').getInstance();
|
|
||||||
const TMDB = require('src/tmdb/tmdb');
|
|
||||||
|
|
||||||
const tmdb = new TMDB(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;
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
const configuration = require("src/config/configuration").getInstance();
|
|
||||||
const TMDB = require("src/tmdb/tmdb");
|
|
||||||
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
|
||||||
|
|
||||||
const personCreditsController = (req, res) => {
|
|
||||||
const personId = req.params.id;
|
|
||||||
|
|
||||||
return tmdb
|
|
||||||
.personCredits(personId)
|
|
||||||
.then(credits => res.send(credits))
|
|
||||||
.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 person credits"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = personCreditsController;
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
const configuration = require("src/config/configuration").getInstance();
|
|
||||||
const TMDB = require("src/tmdb/tmdb");
|
|
||||||
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
|
||||||
|
|
||||||
function handleError(error, res) {
|
|
||||||
const { status, message } = error;
|
|
||||||
|
|
||||||
if (status && message) {
|
|
||||||
res.status(status).send({ success: false, message });
|
|
||||||
} else {
|
|
||||||
console.log("caught personinfo controller error", error);
|
|
||||||
res.status(500).send({
|
|
||||||
message: "An unexpected error occured while requesting person info."
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller: Retrieve information for a person
|
|
||||||
* @param {Request} req http request variable
|
|
||||||
* @param {Response} res
|
|
||||||
* @returns {Callback}
|
|
||||||
*/
|
|
||||||
|
|
||||||
async function personInfoController(req, res) {
|
|
||||||
const personId = req.params.id;
|
|
||||||
let { credits } = req.query;
|
|
||||||
arguments;
|
|
||||||
|
|
||||||
credits && credits.toLowerCase() === "true"
|
|
||||||
? (credits = true)
|
|
||||||
: (credits = false);
|
|
||||||
|
|
||||||
let tmdbQueue = [tmdb.personInfo(personId)];
|
|
||||||
if (credits) tmdbQueue.push(tmdb.personCredits(personId));
|
|
||||||
|
|
||||||
try {
|
|
||||||
const [Person, Credits] = await Promise.all(tmdbQueue);
|
|
||||||
|
|
||||||
const person = Person.createJsonResponse();
|
|
||||||
if (credits) person.credits = Credits.createJsonResponse();
|
|
||||||
|
|
||||||
return res.send(person);
|
|
||||||
} catch (error) {
|
|
||||||
handleError(error, res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = personInfoController;
|
|
||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
* @Last Modified time: 2018-02-26 19:56:32
|
* @Last Modified time: 2018-02-26 19:56:32
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const PirateRepository = require("src/pirate/pirateRepository");
|
const PirateRepository = require('src/pirate/pirateRepository');
|
||||||
// const pirateRepository = new PirateRepository();
|
// const pirateRepository = new PirateRepository();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -18,11 +18,11 @@ function updateRequested(req, res) {
|
|||||||
const { query, page, type } = req.query;
|
const { query, page, type } = req.query;
|
||||||
|
|
||||||
PirateRepository.SearchPiratebay(query, page, type)
|
PirateRepository.SearchPiratebay(query, page, type)
|
||||||
.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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
const SearchHistory = require("src/searchHistory/searchHistory");
|
const SearchHistory = require('src/searchHistory/searchHistory');
|
||||||
const Cache = require("src/tmdb/cache");
|
const Cache = require('src/tmdb/cache');
|
||||||
const RequestRepository = require("src/plex/requestRepository.js");
|
const RequestRepository = require('src/plex/requestRepository.js');
|
||||||
|
|
||||||
const cache = new Cache();
|
const cache = new Cache();
|
||||||
const requestRepository = new RequestRepository(cache);
|
const requestRepository = new RequestRepository(cache);
|
||||||
const searchHistory = new SearchHistory();
|
const searchHistory = new SearchHistory();
|
||||||
|
|
||||||
|
|
||||||
function searchRequestController(req, res) {
|
function searchRequestController(req, res) {
|
||||||
|
const user = req.loggedInUser;
|
||||||
const { query, page, type } = req.query;
|
const { query, page, type } = req.query;
|
||||||
const username = req.loggedInUser ? req.loggedInUser.username : null;
|
const username = user === undefined ? undefined : user.username;
|
||||||
|
|
||||||
Promise.resolve()
|
Promise.resolve()
|
||||||
.then(() => searchHistory.create(username, query))
|
.then(() => searchHistory.create(username, query))
|
||||||
.then(() => requestRepository.search(query, page, type))
|
.then(() => requestRepository.search(query, page, type))
|
||||||
.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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
const configuration = require("src/config/configuration").getInstance();
|
const configuration = require('src/config/configuration').getInstance()
|
||||||
const RequestRepository = require("src/request/request");
|
const RequestRepository = require('src/request/request');
|
||||||
const TMDB = require("src/tmdb/tmdb");
|
const Cache = require('src/tmdb/cache')
|
||||||
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
const TMDB = require('src/tmdb/tmdb')
|
||||||
const request = new RequestRepository();
|
|
||||||
|
|
||||||
const tmdbMovieInfo = id => {
|
const cache = new Cache()
|
||||||
return tmdb.movieInfo(id);
|
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'))
|
||||||
};
|
const request = new RequestRepository()
|
||||||
|
|
||||||
const tmdbShowInfo = id => {
|
const tmdbMovieInfo = (id) => {
|
||||||
return tmdb.showInfo(id);
|
return tmdb.movieInfo(id)
|
||||||
};
|
}
|
||||||
|
|
||||||
|
const tmdbShowInfo = (id) => {
|
||||||
|
return tmdb.showInfo(id)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller: POST a media id to be donwloaded
|
* Controller: POST a media id to be donwloaded
|
||||||
@@ -21,43 +24,28 @@ const tmdbShowInfo = id => {
|
|||||||
function submitRequestController(req, res) {
|
function submitRequestController(req, res) {
|
||||||
// This is the id that is the param of the url
|
// This is the id that is the param of the url
|
||||||
const id = req.params.mediaId;
|
const id = req.params.mediaId;
|
||||||
const type = req.query.type ? req.query.type.toLowerCase() : undefined;
|
const type = req.query.type ? req.query.type.toLowerCase() : undefined
|
||||||
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 username = req.loggedInUser ? req.loggedInUser.username : null;
|
const user = req.loggedInUser;
|
||||||
|
let mediaFunction = undefined
|
||||||
|
|
||||||
let mediaFunction = undefined;
|
if (type === 'movie') {
|
||||||
|
console.log('movie')
|
||||||
if (type === "movie") {
|
mediaFunction = tmdbMovieInfo
|
||||||
console.log("movie");
|
} else if (type === 'show') {
|
||||||
mediaFunction = tmdbMovieInfo;
|
console.log('show')
|
||||||
} else if (type === "show") {
|
mediaFunction = tmdbShowInfo
|
||||||
console.log("show");
|
|
||||||
mediaFunction = tmdbShowInfo;
|
|
||||||
} else {
|
} else {
|
||||||
res
|
res.status(422).send({ success: false, error: 'Incorrect type. Allowed types: "movie" or "show"'})
|
||||||
.status(422)
|
|
||||||
.send({
|
|
||||||
success: false,
|
|
||||||
message: 'Incorrect type. Allowed types: "movie" or "show"'
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mediaFunction === undefined) {
|
if (mediaFunction === undefined) { res.status(200); return }
|
||||||
res.status(200);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaFunction(id)
|
mediaFunction(id)
|
||||||
.then(tmdbMedia =>
|
.then(tmdbMedia => request.requestFromTmdb(tmdbMedia, ip, user_agent, user))
|
||||||
request.requestFromTmdb(tmdbMedia, ip, user_agent, username)
|
.then(() => res.send({ success: true, message: 'Media item successfully requested' }))
|
||||||
)
|
.catch(err => res.status(500).send({ success: false, error: err.message }))
|
||||||
.then(() =>
|
|
||||||
res.send({ success: true, message: "Media item successfully requested" })
|
|
||||||
)
|
|
||||||
.catch(err =>
|
|
||||||
res.status(500).send({ success: false, message: err.message })
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = submitRequestController;
|
module.exports = submitRequestController;
|
||||||
|
|||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
const configuration = require('src/config/configuration').getInstance();
|
|
||||||
const Plex = require('src/plex/plex');
|
|
||||||
const plex = new Plex(configuration.get('plex', 'ip'));
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller: Search plex for movies, shows and episodes by query
|
|
||||||
* @param {Request} req http request variable
|
|
||||||
* @param {Response} res
|
|
||||||
* @returns {Callback}
|
|
||||||
*/
|
|
||||||
|
|
||||||
function watchDirectLink (req, res) {
|
|
||||||
const { title, year } = req.query;
|
|
||||||
|
|
||||||
plex.getDirectLinkByTitleAndYear(title, year)
|
|
||||||
.then(plexDirectLink => {
|
|
||||||
if (plexDirectLink == false)
|
|
||||||
res.status(404).send({ success: true, link: null })
|
|
||||||
else
|
|
||||||
res.status(200).send({ success: true, link: plexDirectLink })
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
res.status(500).send({ success: false, message: error.message });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = watchDirectLink;
|
|
||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
const configuration = require("src/config/configuration").getInstance();
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
const TMDB = require("src/tmdb/tmdb");
|
const Cache = require('src/tmdb/cache');
|
||||||
const RequestRepository = require("src/request/request");
|
const TMDB = require('src/tmdb/tmdb');
|
||||||
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
const RequestRepository = require('src/request/request');
|
||||||
|
const cache = new Cache();
|
||||||
|
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||||
const request = new RequestRepository();
|
const request = new RequestRepository();
|
||||||
// const { sendSMS } = require("src/notifications/sms");
|
|
||||||
|
|
||||||
const tmdbMovieInfo = id => {
|
const tmdbMovieInfo = (id) => {
|
||||||
return tmdb.movieInfo(id);
|
return tmdb.movieInfo(id)
|
||||||
};
|
}
|
||||||
|
|
||||||
const tmdbShowInfo = id => {
|
const tmdbShowInfo = (id) => {
|
||||||
return tmdb.showInfo(id);
|
return tmdb.showInfo(id)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller: Request by id with type param
|
* Controller: Request by id with type param
|
||||||
@@ -20,48 +21,32 @@ const tmdbShowInfo = id => {
|
|||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
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 username = req.loggedInUser ? req.loggedInUser.username : null;
|
const user = req.loggedInUser;
|
||||||
|
let mediaFunction = undefined
|
||||||
|
|
||||||
let mediaFunction = undefined;
|
if (type === 'movie') {
|
||||||
|
console.log('movie')
|
||||||
if (id === undefined || type === undefined) {
|
mediaFunction = tmdbMovieInfo
|
||||||
res.status(422).send({
|
} else if (type === 'show') {
|
||||||
success: false,
|
console.log('show')
|
||||||
message: "'Missing parameteres: 'id' and/or 'type'"
|
mediaFunction = tmdbShowInfo
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type === "movie") {
|
|
||||||
mediaFunction = tmdbMovieInfo;
|
|
||||||
} else if (type === "show") {
|
|
||||||
mediaFunction = tmdbShowInfo;
|
|
||||||
} else {
|
} else {
|
||||||
res.status(422).send({
|
res.status(422).send({ success: false, error: 'Incorrect type. Allowed types: "movie" or "show"'})
|
||||||
success: false,
|
|
||||||
message: '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 => {
|
.then((tmdbMedia) => request.requestFromTmdb(tmdbMedia, ip, user_agent, user))
|
||||||
request.requestFromTmdb(tmdbMedia, ip, user_agent, username);
|
.then(() => res.send({success: true, message: 'Request has been submitted.'}))
|
||||||
|
.catch((error) => {
|
||||||
// TODO enable SMS
|
res.status(501).send({ success: false, error: error.message });
|
||||||
// const url = `https://request.movie?${tmdbMedia.type}=${tmdbMedia.id}`;
|
|
||||||
// const message = `${tmdbMedia.title} (${tmdbMedia.year}) requested!\n${url}`;
|
|
||||||
// sendSMS(message);
|
|
||||||
})
|
})
|
||||||
.then(() =>
|
|
||||||
res.send({ success: true, message: "Request has been submitted." })
|
|
||||||
)
|
|
||||||
.catch(error => {
|
|
||||||
res.send({ success: false, message: error.message });
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = requestTmdbIdController;
|
module.exports = requestTmdbIdController;
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
const configuration = require("src/config/configuration").getInstance();
|
const SearchHistory = require('src/searchHistory/searchHistory');
|
||||||
const TMDB = require("src/tmdb/tmdb");
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
const SearchHistory = require("src/searchHistory/searchHistory");
|
const Cache = require('src/tmdb/cache');
|
||||||
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
const TMDB = require('src/tmdb/tmdb');
|
||||||
|
const cache = new Cache();
|
||||||
|
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||||
const searchHistory = new SearchHistory();
|
const searchHistory = new SearchHistory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,29 +13,22 @@ const searchHistory = new SearchHistory();
|
|||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function movieSearchController(req, res) {
|
function movieSearchController(req, res) {
|
||||||
const { query, page, adult } = req.query;
|
const user = req.loggedInUser;
|
||||||
const username = req.loggedInUser ? req.loggedInUser.username : null;
|
const { query, page } = req.query;
|
||||||
const includeAdult = adult == "true" ? true : false;
|
|
||||||
|
|
||||||
if (username) {
|
Promise.resolve()
|
||||||
searchHistory.create(username, query);
|
.then(() => {
|
||||||
}
|
if (user) {
|
||||||
|
return searchHistory.create(user, query);
|
||||||
return tmdb
|
|
||||||
.movieSearch(query, page, includeAdult)
|
|
||||||
.then(movieSearchResults => res.send(movieSearchResults))
|
|
||||||
.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 search controller error", error);
|
|
||||||
res.status(500).send({
|
|
||||||
message: `An unexpected error occured while searching movies with query: ${query}`
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
.then(() => tmdb.movieSearch(query, page))
|
||||||
|
.then((movies) => {
|
||||||
|
res.send(movies);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
res.status(500).send({ success: false, error: error.message });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,11 @@
|
|||||||
const configuration = require("src/config/configuration").getInstance();
|
const SearchHistory = require('src/searchHistory/searchHistory');
|
||||||
const TMDB = require("src/tmdb/tmdb");
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
const SearchHistory = require("src/searchHistory/searchHistory");
|
const Cache = require('src/tmdb/cache');
|
||||||
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
const TMDB = require('src/tmdb/tmdb');
|
||||||
|
const cache = new Cache();
|
||||||
|
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
|
||||||
@@ -18,30 +13,22 @@ function checkAndCreateJsonResponse(result) {
|
|||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function multiSearchController(req, res) {
|
function multiSearchController(req, res) {
|
||||||
const { query, page, adult } = req.query;
|
const user = req.loggedInUser;
|
||||||
const username = req.loggedInUser ? req.loggedInUser.username : null;
|
const { query, page } = req.query;
|
||||||
|
|
||||||
if (username) {
|
Promise.resolve()
|
||||||
searchHistory.create(username, query);
|
.then(() => {
|
||||||
}
|
if (user) {
|
||||||
|
return searchHistory.create(user, query);
|
||||||
return tmdb
|
|
||||||
.multiSearch(query, page, adult)
|
|
||||||
.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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
const configuration = require("src/config/configuration").getInstance();
|
const SearchHistory = require('src/searchHistory/searchHistory');
|
||||||
const TMDB = require("src/tmdb/tmdb");
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
const SearchHistory = require("src/searchHistory/searchHistory");
|
const Cache = require('src/tmdb/cache');
|
||||||
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
const TMDB = require('src/tmdb/tmdb');
|
||||||
|
const cache = new Cache();
|
||||||
|
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||||
const searchHistory = new SearchHistory();
|
const searchHistory = new SearchHistory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,29 +13,22 @@ const searchHistory = new SearchHistory();
|
|||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function personSearchController(req, res) {
|
function personSearchController(req, res) {
|
||||||
const { query, page, adult } = req.query;
|
const user = req.loggedInUser;
|
||||||
const username = req.loggedInUser ? req.loggedInUser.username : null;
|
const { query, page } = req.query;
|
||||||
const includeAdult = adult == "true" ? true : false;
|
|
||||||
|
|
||||||
if (username) {
|
Promise.resolve()
|
||||||
searchHistory.create(username, query);
|
.then(() => {
|
||||||
}
|
if (user) {
|
||||||
|
return searchHistory.create(user, query);
|
||||||
return tmdb
|
|
||||||
.personSearch(query, page, includeAdult)
|
|
||||||
.then(persons => res.send(persons))
|
|
||||||
.catch(error => {
|
|
||||||
const { status, message } = error;
|
|
||||||
|
|
||||||
if (status && message) {
|
|
||||||
res.status(status).send({ success: false, 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}`
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
.then(() => tmdb.personSearch(query, page))
|
||||||
|
.then((person) => {
|
||||||
|
res.send(person);
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
res.status(500).send({ success: false, error: error.message });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
const SearchHistory = require("src/searchHistory/searchHistory");
|
const SearchHistory = require('src/searchHistory/searchHistory');
|
||||||
const configuration = require("src/config/configuration").getInstance();
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
const TMDB = require("src/tmdb/tmdb");
|
const Cache = require('src/tmdb/cache');
|
||||||
const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
|
const TMDB = require('src/tmdb/tmdb');
|
||||||
|
const cache = new Cache();
|
||||||
|
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||||
const searchHistory = new SearchHistory();
|
const searchHistory = new SearchHistory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -11,21 +13,22 @@ const searchHistory = new SearchHistory();
|
|||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function showSearchController(req, res) {
|
function showSearchController(req, res) {
|
||||||
const { query, page, adult } = req.query;
|
const user = req.loggedInUser;
|
||||||
const username = req.loggedInUser ? req.loggedInUser.username : null;
|
const { query, page } = req.query;
|
||||||
const includeAdult = adult == "true" ? true : false;
|
|
||||||
|
|
||||||
if (username) {
|
Promise.resolve()
|
||||||
searchHistory.create(username, query);
|
.then(() => {
|
||||||
|
if (user) {
|
||||||
|
return searchHistory.create(user, query);
|
||||||
}
|
}
|
||||||
|
return null
|
||||||
return tmdb
|
})
|
||||||
.showSearch(query, page, includeAdult)
|
.then(() => tmdb.showSearch(query, page))
|
||||||
.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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
const configuration = require('src/config/configuration').getInstance();
|
|
||||||
const TMDB = require('src/tmdb/tmdb');
|
|
||||||
const tmdb = new TMDB(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;
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
const configuration = require('src/config/configuration').getInstance();
|
|
||||||
const TMDB = require('src/tmdb/tmdb');
|
|
||||||
const Plex = require('src/plex/plex');
|
|
||||||
const tmdb = new TMDB(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;
|
|
||||||
25
seasoned_api/src/webserver/controllers/tmdb/listSearch.js
Normal file
25
seasoned_api/src/webserver/controllers/tmdb/listSearch.js
Normal 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;
|
||||||
25
seasoned_api/src/webserver/controllers/tmdb/readMedia.js
Normal file
25
seasoned_api/src/webserver/controllers/tmdb/readMedia.js
Normal 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;
|
||||||
31
seasoned_api/src/webserver/controllers/tmdb/searchMedia.js
Normal file
31
seasoned_api/src/webserver/controllers/tmdb/searchMedia.js
Normal 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;
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
const UserRepository = require("src/user/userRepository");
|
|
||||||
const userRepository = new UserRepository();
|
|
||||||
const fetch = require("node-fetch");
|
|
||||||
const FormData = require("form-data");
|
|
||||||
|
|
||||||
function handleError(error, res) {
|
|
||||||
let { status, message, source } = error;
|
|
||||||
|
|
||||||
if (status && message) {
|
|
||||||
if (status === 401) {
|
|
||||||
(message = "Unauthorized. Please check plex credentials."),
|
|
||||||
(source = "plex");
|
|
||||||
}
|
|
||||||
|
|
||||||
res.status(status).send({ success: false, message, source });
|
|
||||||
} else {
|
|
||||||
console.log("caught authenticate plex account controller error", error);
|
|
||||||
res.status(500).send({
|
|
||||||
message:
|
|
||||||
"An unexpected error occured while authenticating your account with plex",
|
|
||||||
source
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleResponse(response) {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw {
|
|
||||||
success: false,
|
|
||||||
status: response.status,
|
|
||||||
message: response.statusText
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.json();
|
|
||||||
}
|
|
||||||
|
|
||||||
function plexAuthenticate(username, password) {
|
|
||||||
const url = "https://plex.tv/api/v2/users/signin";
|
|
||||||
|
|
||||||
const form = new FormData();
|
|
||||||
form.append("login", username);
|
|
||||||
form.append("password", password);
|
|
||||||
form.append("rememberMe", "false");
|
|
||||||
|
|
||||||
const headers = {
|
|
||||||
Accept: "application/json, text/plain, */*",
|
|
||||||
"Content-Type": form.getHeaders()["content-type"],
|
|
||||||
"X-Plex-Client-Identifier": "seasonedRequest"
|
|
||||||
};
|
|
||||||
const options = {
|
|
||||||
method: "POST",
|
|
||||||
headers,
|
|
||||||
body: form
|
|
||||||
};
|
|
||||||
|
|
||||||
return fetch(url, options).then(resp => handleResponse(resp));
|
|
||||||
}
|
|
||||||
|
|
||||||
function link(req, res) {
|
|
||||||
const user = req.loggedInUser;
|
|
||||||
const { username, password } = req.body;
|
|
||||||
|
|
||||||
return plexAuthenticate(username, password)
|
|
||||||
.then(plexUser => userRepository.linkPlexUserId(user.username, plexUser.id))
|
|
||||||
.then(response =>
|
|
||||||
res.send({
|
|
||||||
success: true,
|
|
||||||
message:
|
|
||||||
"Successfully authenticated and linked plex account with seasoned request."
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.catch(error => handleError(error, res));
|
|
||||||
}
|
|
||||||
|
|
||||||
function unlink(req, res) {
|
|
||||||
const username = req.loggedInUser ? req.loggedInUser.username : null;
|
|
||||||
|
|
||||||
return userRepository
|
|
||||||
.unlinkPlexUserId(username)
|
|
||||||
.then(response =>
|
|
||||||
res.send({
|
|
||||||
success: true,
|
|
||||||
message: "Successfully unlinked plex account from seasoned request."
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.catch(error => handleError(error, res));
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
link,
|
|
||||||
unlink
|
|
||||||
};
|
|
||||||
24
seasoned_api/src/webserver/controllers/user/history.js
Normal file
24
seasoned_api/src/webserver/controllers/user/history.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
const SearchHistory = require('src/searchHistory/searchHistory');
|
||||||
|
|
||||||
|
const searchHistory = new SearchHistory();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Controller: Retrieves search history of a logged in user
|
||||||
|
* @param {Request} req http request variable
|
||||||
|
* @param {Response} res
|
||||||
|
* @returns {Callback}
|
||||||
|
*/
|
||||||
|
function historyController(req, res) {
|
||||||
|
const user = req.loggedInUser;
|
||||||
|
const username = user === undefined ? undefined : user.username;
|
||||||
|
|
||||||
|
searchHistory.read(username)
|
||||||
|
.then((searchQueries) => {
|
||||||
|
res.send({ success: true, searchQueries });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
res.status(404).send({ success: false, error: error });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = historyController;
|
||||||
@@ -1,61 +1,33 @@
|
|||||||
const User = require("src/user/user");
|
const User = require('src/user/user');
|
||||||
const Token = require("src/user/token");
|
const Token = require('src/user/token');
|
||||||
const UserSecurity = require("src/user/userSecurity");
|
const UserSecurity = require('src/user/userSecurity');
|
||||||
const UserRepository = require("src/user/userRepository");
|
const UserRepository = require('src/user/userRepository');
|
||||||
const configuration = require("src/config/configuration").getInstance();
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
|
|
||||||
const secret = configuration.get("authentication", "secret");
|
const secret = configuration.get('authentication', 'secret');
|
||||||
const userSecurity = new UserSecurity();
|
const userSecurity = new UserSecurity();
|
||||||
const userRepository = new UserRepository();
|
const userRepository = new UserRepository();
|
||||||
|
|
||||||
// TODO look to move some of the token generation out of the reach of the final "catch-all"
|
|
||||||
// catch including the, maybe sensitive, error message.
|
|
||||||
|
|
||||||
const isProduction = process.env.NODE_ENV === "production";
|
|
||||||
const cookieOptions = {
|
|
||||||
httpOnly: false,
|
|
||||||
secure: isProduction,
|
|
||||||
maxAge: 90 * 24 * 3600000, // 90 days
|
|
||||||
sameSite: isProduction ? "Strict" : "Lax"
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller: Log in a user provided correct credentials.
|
* Controller: Log in a user provided correct credentials.
|
||||||
* @param {Request} req http request variable
|
* @param {Request} req http request variable
|
||||||
* @param {Response} res
|
* @param {Response} res
|
||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
async function loginController(req, res) {
|
function loginController(req, res) {
|
||||||
const user = new User(req.body.username);
|
const user = new User(req.body.username);
|
||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
|
|
||||||
try {
|
userSecurity.login(user, password)
|
||||||
const [loggedIn, isAdmin, settings] = await Promise.all([
|
.then(() => userRepository.checkAdmin(user))
|
||||||
userSecurity.login(user, password),
|
.then((checkAdmin) => {
|
||||||
userRepository.checkAdmin(user),
|
const token = new Token(user).toString(secret);
|
||||||
userRepository.getSettings(user.username)
|
const admin_state = checkAdmin === 1 ? true : false;
|
||||||
]);
|
res.send({ success: true, token, admin: admin_state });
|
||||||
|
})
|
||||||
if (!loggedIn) {
|
.catch((error) => {
|
||||||
return res.status(503).send({
|
res.status(401).send({ success: false, error: error.message });
|
||||||
success: false,
|
|
||||||
message: "Unexpected error! Unable to create user."
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const token = new Token(
|
|
||||||
user,
|
|
||||||
isAdmin === 1 ? true : false,
|
|
||||||
settings
|
|
||||||
).toString(secret);
|
|
||||||
|
|
||||||
return res.cookie("authorization", token, cookieOptions).status(200).send({
|
|
||||||
success: true,
|
|
||||||
message: "Welcome to request.movie!"
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
return res.status(401).send({ success: false, message: error.message });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = loginController;
|
module.exports = loginController;
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
/**
|
|
||||||
* Controller: Log out a user (destroy authorization token)
|
|
||||||
* @param {Request} req http request variable
|
|
||||||
* @param {Response} res
|
|
||||||
* @returns {Callback}
|
|
||||||
*/
|
|
||||||
async function logoutController(req, res) {
|
|
||||||
res.clearCookie("authorization");
|
|
||||||
|
|
||||||
return res.status(200).send({
|
|
||||||
success: true,
|
|
||||||
message: "Logged out, see you later!"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = logoutController;
|
|
||||||
@@ -1,21 +1,13 @@
|
|||||||
const User = require("src/user/user");
|
const User = require('src/user/user');
|
||||||
const Token = require("src/user/token");
|
const Token = require('src/user/token');
|
||||||
const UserSecurity = require("src/user/userSecurity");
|
const UserSecurity = require('src/user/userSecurity');
|
||||||
const UserRepository = require("src/user/userRepository");
|
const UserRepository = require('src/user/userRepository');
|
||||||
const configuration = require("src/config/configuration").getInstance();
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
|
|
||||||
const secret = configuration.get("authentication", "secret");
|
const secret = configuration.get('authentication', 'secret');
|
||||||
const userSecurity = new UserSecurity();
|
const userSecurity = new UserSecurity();
|
||||||
const userRepository = new UserRepository();
|
const userRepository = new UserRepository();
|
||||||
|
|
||||||
const isProduction = process.env.NODE_ENV === "production";
|
|
||||||
const cookieOptions = {
|
|
||||||
httpOnly: false,
|
|
||||||
secure: isProduction,
|
|
||||||
maxAge: 90 * 24 * 3600000, // 90 days
|
|
||||||
sameSite: isProduction ? "Strict" : "Lax"
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Controller: Register a new user
|
* Controller: Register a new user
|
||||||
* @param {Request} req http request variable
|
* @param {Request} req http request variable
|
||||||
@@ -26,21 +18,17 @@ function registerController(req, res) {
|
|||||||
const user = new User(req.body.username, req.body.email);
|
const user = new User(req.body.username, req.body.email);
|
||||||
const password = req.body.password;
|
const password = req.body.password;
|
||||||
|
|
||||||
userSecurity
|
userSecurity.createNewUser(user, password)
|
||||||
.createNewUser(user, password)
|
.then(() => userRepository.checkAdmin(user))
|
||||||
.then(() => {
|
.then((checkAdmin) => {
|
||||||
const token = new Token(user, false).toString(secret);
|
const token = new Token(user).toString(secret);
|
||||||
|
const admin_state = checkAdmin === 1 ? true : false;
|
||||||
return res
|
res.send({
|
||||||
.cookie("authorization", token, cookieOptions)
|
success: true, message: 'Welcome to Seasoned!', token, admin: admin_state,
|
||||||
.status(200)
|
|
||||||
.send({
|
|
||||||
success: true,
|
|
||||||
message: "Welcome to Seasoned!"
|
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch((error) => {
|
||||||
res.status(401).send({ success: false, message: error.message });
|
res.status(401).send({ success: false, error: error.message });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const RequestRepository = require("src/plex/requestRepository.js");
|
const RequestRepository = require('src/plex/requestRepository.js');
|
||||||
|
|
||||||
const requestRepository = new RequestRepository();
|
const requestRepository = new RequestRepository();
|
||||||
|
|
||||||
@@ -9,19 +9,15 @@ const requestRepository = new RequestRepository();
|
|||||||
* @returns {Callback}
|
* @returns {Callback}
|
||||||
*/
|
*/
|
||||||
function requestsController(req, res) {
|
function requestsController(req, res) {
|
||||||
const username = req.loggedInUser ? req.loggedInUser.username : null;
|
const user = req.loggedInUser;
|
||||||
|
|
||||||
requestRepository
|
requestRepository.userRequests(user)
|
||||||
.userRequests(username)
|
.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 });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +0,0 @@
|
|||||||
const SearchHistory = require("src/searchHistory/searchHistory");
|
|
||||||
|
|
||||||
const searchHistory = new SearchHistory();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller: Retrieves search history of a logged in user
|
|
||||||
* @param {Request} req http request variable
|
|
||||||
* @param {Response} res
|
|
||||||
* @returns {Callback}
|
|
||||||
*/
|
|
||||||
function historyController(req, res) {
|
|
||||||
const username = req.loggedInUser ? req.loggedInUser.username : null;
|
|
||||||
|
|
||||||
searchHistory
|
|
||||||
.read(username)
|
|
||||||
.then(searchQueries => {
|
|
||||||
res.send({ success: true, searchQueries });
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
res.status(404).send({ success: false, message: error.message });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = historyController;
|
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
const UserRepository = require("src/user/userRepository");
|
|
||||||
const userRepository = new UserRepository();
|
|
||||||
/**
|
|
||||||
* Controller: Retrieves settings of a logged in user
|
|
||||||
* @param {Request} req http request variable
|
|
||||||
* @param {Response} res
|
|
||||||
* @returns {Callback}
|
|
||||||
*/
|
|
||||||
const getSettingsController = (req, res) => {
|
|
||||||
const username = req.loggedInUser ? req.loggedInUser.username : null;
|
|
||||||
|
|
||||||
userRepository
|
|
||||||
.getSettings(username)
|
|
||||||
.then(settings => {
|
|
||||||
res.send({ success: true, settings });
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
res.status(404).send({ success: false, message: error.message });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const updateSettingsController = (req, res) => {
|
|
||||||
const username = req.loggedInUser ? req.loggedInUser.username : null;
|
|
||||||
|
|
||||||
const idempotencyKey = req.headers("Idempotency-Key"); // TODO implement better transactions
|
|
||||||
const { dark_mode, emoji } = req.body;
|
|
||||||
|
|
||||||
userRepository
|
|
||||||
.updateSettings(username, dark_mode, emoji)
|
|
||||||
.then(settings => {
|
|
||||||
res.send({ success: true, settings });
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
res.status(404).send({ success: false, message: error.message });
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
getSettingsController,
|
|
||||||
updateSettingsController
|
|
||||||
};
|
|
||||||
@@ -1,107 +0,0 @@
|
|||||||
const configuration = require("src/config/configuration").getInstance();
|
|
||||||
const Tautulli = require("src/tautulli/tautulli");
|
|
||||||
const apiKey = configuration.get("tautulli", "apiKey");
|
|
||||||
const ip = configuration.get("tautulli", "ip");
|
|
||||||
const port = configuration.get("tautulli", "port");
|
|
||||||
const tautulli = new Tautulli(apiKey, ip, port);
|
|
||||||
|
|
||||||
function handleError(error, res) {
|
|
||||||
const { status, message } = error;
|
|
||||||
|
|
||||||
if (status && message) {
|
|
||||||
return res.status(status).send({ success: false, message });
|
|
||||||
} else {
|
|
||||||
console.log("caught view history controller error", error);
|
|
||||||
return res.status(500).send({
|
|
||||||
message: "An unexpected error occured while fetching view history"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function watchTimeStatsController(req, res) {
|
|
||||||
const user = req.loggedInUser;
|
|
||||||
|
|
||||||
return tautulli
|
|
||||||
.watchTimeStats(user.plex_userid)
|
|
||||||
.then(data => {
|
|
||||||
return res.send({
|
|
||||||
success: true,
|
|
||||||
data: data.response.data,
|
|
||||||
message: "watch time successfully fetched from tautulli"
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => handleError(error, res));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPlaysByDayOfWeekController(req, res) {
|
|
||||||
const user = req.loggedInUser;
|
|
||||||
const { days, y_axis } = req.query;
|
|
||||||
|
|
||||||
return tautulli
|
|
||||||
.getPlaysByDayOfWeek(user.plex_userid, days, y_axis)
|
|
||||||
.then(data =>
|
|
||||||
res.send({
|
|
||||||
success: true,
|
|
||||||
data: data.response.data,
|
|
||||||
message: "play by day of week successfully fetched from tautulli"
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.catch(error => handleError(error, res));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getPlaysByDaysController(req, res) {
|
|
||||||
const user = req.loggedInUser;
|
|
||||||
const { days, y_axis } = req.query;
|
|
||||||
|
|
||||||
if (days === undefined) {
|
|
||||||
return res.status(422).send({
|
|
||||||
success: false,
|
|
||||||
message: "Missing parameter: days (number)"
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const allowedYAxisDataType = ["plays", "duration"];
|
|
||||||
if (!allowedYAxisDataType.includes(y_axis)) {
|
|
||||||
return res.status(422).send({
|
|
||||||
success: false,
|
|
||||||
message: `Y axis parameter must be one of values: [${allowedYAxisDataType}]`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return tautulli
|
|
||||||
.getPlaysByDays(user.plex_userid, days, y_axis)
|
|
||||||
.then(data =>
|
|
||||||
res.send({
|
|
||||||
success: true,
|
|
||||||
data: data.response.data
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.catch(error => handleError(error, res));
|
|
||||||
}
|
|
||||||
|
|
||||||
function userViewHistoryController(req, res) {
|
|
||||||
const user = req.loggedInUser;
|
|
||||||
|
|
||||||
// TODO here we should check if we can init tau
|
|
||||||
// and then return 501 Not implemented
|
|
||||||
|
|
||||||
return tautulli
|
|
||||||
.viewHistory(user.plex_userid)
|
|
||||||
.then(data => {
|
|
||||||
return res.send({
|
|
||||||
success: true,
|
|
||||||
data: data.response.data.data,
|
|
||||||
message: "view history successfully fetched from tautulli"
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => handleError(error, res));
|
|
||||||
|
|
||||||
// const username = user.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
watchTimeStatsController,
|
|
||||||
getPlaysByDaysController,
|
|
||||||
getPlaysByDayOfWeekController,
|
|
||||||
userViewHistoryController
|
|
||||||
};
|
|
||||||
@@ -6,7 +6,7 @@ const mustBeAdmin = (req, res, next) => {
|
|||||||
if (req.loggedInUser === undefined) {
|
if (req.loggedInUser === undefined) {
|
||||||
return res.status(401).send({
|
return res.status(401).send({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'You must be logged in.',
|
error: 'You must be logged in.',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
database.get(`SELECT admin FROM user WHERE user_name IS ?`, req.loggedInUser.username)
|
database.get(`SELECT admin FROM user WHERE user_name IS ?`, req.loggedInUser.username)
|
||||||
@@ -15,7 +15,7 @@ const mustBeAdmin = (req, res, next) => {
|
|||||||
if (isAdmin.admin == 0) {
|
if (isAdmin.admin == 0) {
|
||||||
return res.status(401).send({
|
return res.status(401).send({
|
||||||
success: false,
|
success: false,
|
||||||
message: 'You must be logged in as a admin.'
|
error: 'You must be logged in as a admin.'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ const mustBeAuthenticated = (req, res, next) => {
|
|||||||
if (req.loggedInUser === undefined) {
|
if (req.loggedInUser === undefined) {
|
||||||
return res.status(401).send({
|
return res.status(401).send({
|
||||||
success: false,
|
success: false,
|
||||||
message: "You must be logged in."
|
error: 'You must be logged in.',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return next();
|
return next();
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
const establishedDatabase = require('src/database/database');
|
|
||||||
|
|
||||||
const mustHaveAccountLinkedToPlex = (req, res, next) => {
|
|
||||||
let database = establishedDatabase;
|
|
||||||
const loggedInUser = req.loggedInUser;
|
|
||||||
|
|
||||||
if (loggedInUser === undefined) {
|
|
||||||
return res.status(401).send({
|
|
||||||
success: false,
|
|
||||||
message: 'You must have your account linked to a plex account.',
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
database.get(`SELECT plex_userid FROM settings WHERE user_name IS ?`, loggedInUser.username)
|
|
||||||
.then(row => {
|
|
||||||
const plex_userid = row.plex_userid;
|
|
||||||
|
|
||||||
if (plex_userid === null || plex_userid === undefined) {
|
|
||||||
return res.status(403).send({
|
|
||||||
success: false,
|
|
||||||
message: 'No plex account user id found for your user. Please authenticate your plex account at /user/authenticate.'
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
req.loggedInUser.plex_userid = plex_userid;
|
|
||||||
return next();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = mustHaveAccountLinkedToPlex;
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
/* eslint-disable no-param-reassign */
|
|
||||||
const configuration = require("src/config/configuration").getInstance();
|
|
||||||
const Token = require("src/user/token");
|
|
||||||
|
|
||||||
const secret = configuration.get("authentication", "secret");
|
|
||||||
|
|
||||||
// Token example:
|
|
||||||
// curl -i -H "Authorization:[token]" localhost:31459/api/v1/user/history
|
|
||||||
|
|
||||||
const reqTokenToUser = (req, res, next) => {
|
|
||||||
const cookieAuthToken = req.cookies.authorization;
|
|
||||||
const headerAuthToken = req.headers.authorization;
|
|
||||||
|
|
||||||
if (cookieAuthToken || headerAuthToken) {
|
|
||||||
try {
|
|
||||||
const token = Token.fromString(
|
|
||||||
cookieAuthToken || headerAuthToken,
|
|
||||||
secret
|
|
||||||
);
|
|
||||||
req.loggedInUser = token.user;
|
|
||||||
} catch (error) {
|
|
||||||
req.loggedInUser = undefined;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// guest session
|
|
||||||
console.debug("No auth token in header or cookie.");
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = reqTokenToUser;
|
|
||||||
23
seasoned_api/src/webserver/middleware/tokenToUser.js
Normal file
23
seasoned_api/src/webserver/middleware/tokenToUser.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/* eslint-disable no-param-reassign */
|
||||||
|
const configuration = require('src/config/configuration').getInstance();
|
||||||
|
|
||||||
|
const secret = configuration.get('authentication', 'secret');
|
||||||
|
const Token = require('src/user/token');
|
||||||
|
|
||||||
|
// Token example:
|
||||||
|
// curl -i -H "Authorization:[token]" localhost:31459/api/v1/user/history
|
||||||
|
|
||||||
|
const tokenToUser = (req, res, next) => {
|
||||||
|
const rawToken = req.headers.authorization;
|
||||||
|
if (rawToken) {
|
||||||
|
try {
|
||||||
|
const token = Token.fromString(rawToken, secret);
|
||||||
|
req.loggedInUser = token.user;
|
||||||
|
} catch (error) {
|
||||||
|
req.loggedInUser = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = tokenToUser;
|
||||||
@@ -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}
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"page":1,
|
|
||||||
"results":[],
|
|
||||||
"total_results":0,
|
|
||||||
"total_pages":1
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -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;
|
|
||||||
@@ -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(() =>
|
||||||
|
|||||||
@@ -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"}'))
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
Reference in New Issue
Block a user