Feat Drone CI & dockerize 🐳 #132

Merged
KevinMidboe merged 15 commits from feat/drone-ci into master 2022-08-18 18:44:36 +00:00
81 changed files with 9189 additions and 8705 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
**/node_modules
**/yarn.lock

111
.drone.yml Normal file
View File

@@ -0,0 +1,111 @@
---
kind: pipeline
type: docker
name: seasoned api build
platform:
os: linux
arch: amd64
volumes:
- name: cache
host:
path: /tmp/cache
steps:
- name: Load cached packages
image: sinlead/drone-cache:1.0.0
settings:
action: load
key: yarn.lock
mount: node_modules
prefix: yarn-modules-seasoned_api
volumes:
- name: cache
path: /cache
- name: Install dependencies
image: node:18.2.0
commands:
- node -v
- yarn --version
- yarn
- name: Cache packages
image: sinlead/drone-cache:1.0.0
settings:
action: save
key: yarn.lock
mount: node_modules
prefix: yarn-modules-seasoned_api
volumes:
- name: cache
path: /cache
# - name: Compile typescript
# image: node:18.2.0
# commands:
# - yarn build:ts
- name: Run test suite
image: node:18.2.0
commands:
- yarn test
failure: ignore
- name: Lint project using eslint
image: node:18.2.0
commands:
- yarn lint
failure: ignore
- name: Build and publish docker image
image: plugins/docker
settings:
registry: ghcr.io
repo: ghcr.io/kevinmidboe/seasoned_shows
dockerfile: Dockerfile
username:
from_secret: GITHUB_USERNAME
password:
from_secret: GITHUB_PASSWORD
tags: latest
environment:
TMDB_APIKEY:
from_secret: TMDB_APIKEY
PLEX_IP:
from_secret: PLEX_IP
PLEX_TOKEN:
from_secret: PLEX_TOKEN
# when:
# event:
# - push
# branch:
# - master
# - name: deploy
# image: appleboy/drone-ssh
# pull: true
# secrets:
# - ssh_key
# when:
# event:
# - push
# branch:
# - master
# - drone-test
# status: success
# settings:
# host: 10.0.0.54
# username: root
# key:
# from_secret: ssh_key
# command_timeout: 600s
# script:
# - /home/kevin/deploy/seasoned.sh
trigger:
event:
include:
- push
# - pull_request

View File

3
.gitignore vendored
View File

@@ -1,7 +1,8 @@
.DS_Store .DS_Store
development.json development.json
env .env
shows.db shows.db
node_modules
*/package-lock.json */package-lock.json

19
Dockerfile Normal file
View File

@@ -0,0 +1,19 @@
FROM node:18
RUN mkdir -p /opt/seasonedShows/seasoned_api
WORKDIR /opt/seasonedShows
COPY seasoned_api/ seasoned_api
COPY package.json .
RUN apt update
RUN apt install node-pre-gyp -y
RUN yarn
RUN cp seasoned_api/conf/development.json.example seasoned_api/conf/development.json
EXPOSE 31459
CMD ["yarn", "start"]
LABEL org.opencontainers.image.source https://github.com/kevinmidboe/seasoned

View File

@@ -7,14 +7,14 @@
}, },
"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": "yarn cross-env SEASONED_CONFIG=conf/development.json NODE_ENV=production babel-node seasoned_api/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 --require @babel/register --recursive seasoned_api/test/unit seasoned_api/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 --require @babel/register --recursive test && nyc report --reporter=text-lcov | coveralls",
"lint": "./node_modules/.bin/eslint src/", "lint": "eslint seasoned_api/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 seasoned_api/scripts/updateRequestsInPlex.js",
"docs": "yarn apiDocs; yarn classDocs", "docs": "yarn apiDocs; yarn classDocs",
"apiDocs": "", "apiDocs": "",
"classDocs": "./script/generate-class-docs.sh" "classDocs": "seasoned_api/script/generate-class-docs.sh"
}, },
"dependencies": { "dependencies": {
"axios": "^0.18.0", "axios": "^0.18.0",

View File

@@ -2,6 +2,10 @@
"database": { "database": {
"host": "../shows.db" "host": "../shows.db"
}, },
"redis": {
"host": "localhost",
"port": 6379
},
"webserver": { "webserver": {
"port": 31459, "port": 31459,
"origins": [] "origins": []
@@ -10,7 +14,8 @@
"apiKey": "" "apiKey": ""
}, },
"plex": { "plex": {
"ip": "" "ip": "localhost",
"token": ""
}, },
"tautulli": { "tautulli": {
"apiKey": "", "apiKey": "",

View File

@@ -1,52 +1,73 @@
const redis = require("redis") const { promisify } = require("util");
const client = redis.createClient() const configuration = require("../config/configuration").getInstance();
class Cache { let client;
/**
* 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)); try {
}); const redis = require("redis");
}); console.log("Trying to connect with redis..");
} const host = configuration.get("redis", "host");
const port = configuration.get("redis", "port");
/** console.log(`redis://${host}:${port}`);
* Insert cache entry with key and value. client = redis.createClient({
* @param {String} key of the cache entry url: `redis://${host}:${port}`
* @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.on("connect", () => console.log("Redis connection established!"));
client.set(key, json, (error, reply) => {
if (reply == "OK") { client.on("error", function (err) {
// successfully set value with key, now set TTL for key client.quit();
client.expire(key, timeToLive, e => { console.error("Unable to connect to redis, setting up redis-mock.");
if (e)
console.error( client = {
"Unexpected error while setting expiration for key:", get: function () {
key, console.log("redis-dummy get", arguments[0]);
". Error:", return Promise.resolve();
error },
); set: function () {
}); console.log("redis-dummy set", arguments[0]);
return Promise.resolve();
} }
}); };
});
} catch (e) {}
return value; function set(key, value, TTL = 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, TTL, e => {
if (e)
console.error(
"Unexpected error while setting expiration for key:",
key,
". Error:",
error
);
});
}
});
return value;
} }
module.exports = Cache; function get() {
return new Promise((resolve, reject) => {
client.get(key, (error, reply) => {
if (reply == null) {
return reject();
}
resolve(JSON.parse(reply));
});
});
}
module.exports = {
get,
set
};

View File

@@ -1,43 +1,47 @@
const path = require('path'); const path = require("path");
const Field = require('./field.js'); const Field = require("./field.js");
let instance = null; let instance = null;
class Config { class Config {
constructor() { constructor() {
this.location = Config.determineLocation(); this.location = Config.determineLocation();
this.fields = require(`${this.location}`); this.fields = require(`${this.location}`);
} }
static getInstance() { static getInstance() {
if (instance == null) { if (instance == null) {
instance = new Config(); instance = new Config();
} }
return instance; return instance;
} }
static determineLocation() { static determineLocation() {
return path.join(__dirname, '..', '..', process.env.SEASONED_CONFIG); return path.join(__dirname, "..", "..", process.env.SEASONED_CONFIG);
} }
get(section, option) { get(section, option) {
if (this.fields[section] === undefined || this.fields[section][option] === undefined) { if (
throw new Error(`Field "${section} => ${option}" does not exist.`); this.fields[section] === undefined ||
} this.fields[section][option] === undefined
) {
throw new Error(`Field "${section} => ${option}" does not exist.`);
}
const field = new Field(this.fields[section][option]); const field = new Field(this.fields[section][option]);
if (field.value === '') { const envField =
const envField = process.env[[section.toUpperCase(), option.toUpperCase()].join('_')]; process.env[[section.toUpperCase(), option.toUpperCase()].join("_")];
if (envField !== undefined && envField.length !== 0) { return envField; } if (envField !== undefined && envField.length !== 0) {
} return envField;
}
if (field.value === undefined) { if (field.value === undefined) {
throw new Error(`${section} => ${option} is empty.`); throw new Error(`${section} => ${option} is empty.`);
} }
return field.value; return field.value;
} }
} }
module.exports = Config; module.exports = Config;

View File

@@ -1,14 +1,13 @@
const configuration = require('src/config/configuration').getInstance(); const configuration = require("../config/configuration").getInstance();
const SqliteDatabase = require('src/database/sqliteDatabase'); const SqliteDatabase = require("./sqliteDatabase");
const database = new SqliteDatabase(configuration.get('database', 'host')); const database = new SqliteDatabase(configuration.get("database", "host"));
/** /**
* This module establishes a connection to the database * This module establishes a connection to the database
* specified in the confgiuration file. It tries to setup * specified in the confgiuration file. It tries to setup
* the required tables after successfully connecting. * the required tables after successfully connecting.
* If the tables already exists, it simply proceeds. * If the tables already exists, it simply proceeds.
*/ */
Promise.resolve() Promise.resolve().then(() => database.setUp());
.then(() => database.setUp());
module.exports = database; module.exports = database;

View File

@@ -30,7 +30,7 @@ CREATE TABLE IF NOT EXISTS search_history (
foreign key(user_name) REFERENCES user(user_name) ON DELETE CASCADE foreign key(user_name) REFERENCES user(user_name) ON DELETE CASCADE
); );
CREATE TABLE IF NOT EXISTS requests( CREATE TABLE IF NOT EXISTS requests (
id NUMBER, id NUMBER,
title TEXT, title TEXT,
year NUMBER, year NUMBER,
@@ -41,8 +41,8 @@ CREATE TABLE IF NOT EXISTS requests(
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 -- foreign key(requested_by) REFERENCES user(user_name) ON DELETE SET NULL
); );
CREATE TABLE IF NOT EXISTS request( CREATE TABLE IF NOT EXISTS request(

View File

@@ -1,120 +1,119 @@
const fs = require('fs'); const fs = require("fs");
const path = require('path'); const path = require("path");
const sqlite3 = require('sqlite3').verbose(); const sqlite3 = require("sqlite3").verbose();
class SqliteDatabase { 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.execute("pragma foreign_keys = on;");
this.schemaDirectory = path.join(__dirname, 'schemas'); this.schemaDirectory = path.join(__dirname, "schemas");
} }
/** /**
* Connect to the database. * Connect to the database.
* @returns {Promise} succeeds if connection was established * @returns {Promise} succeeds if connection was established
*/ */
// connect() { // connect() {
// let database = ; // let database = ;
// this.connection = database; // this.connection = database;
// return database; // return database;
// } // }
/** /**
* Run a SQL query against the database. * Run a SQL query against the database.
* @param {String} sql SQL query * @param {String} sql SQL query
* @param {Array} parameters in the SQL query * @param {Array} parameters in the SQL query
* @returns {Promise} * @returns {Promise}
*/ */
run(sql, parameters) { 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) reject(error);
reject(error); resolve(result);
resolve(result)
});
}); });
} });
}
/** /**
* Run a SQL query against the database and retrieve all the rows. * Run a SQL query against the database and retrieve all the rows.
* @param {String} sql SQL query * @param {String} sql SQL query
* @param {Array} parameters in the SQL query * @param {Array} parameters in the SQL query
* @returns {Promise} * @returns {Promise}
*/ */
all(sql, parameters) { 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) {
reject(err); reject(err);
} }
resolve(rows); resolve(rows);
}) });
}) });
} }
/** /**
* Run a SQL query against the database and retrieve one row. * Run a SQL query against the database and retrieve one row.
* @param {String} sql SQL query * @param {String} sql SQL query
* @param {Array} parameters in the SQL query * @param {Array} parameters in the SQL query
* @returns {Promise} * @returns {Promise}
*/ */
get(sql, parameters) { 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) {
reject(err); reject(err);
} }
resolve(rows); resolve(rows);
}) });
}) });
} }
/** /**
* Run a SQL query against the database and retrieve the status. * Run a SQL query against the database and retrieve the status.
* @param {String} sql SQL query * @param {String} sql SQL query
* @param {Array} parameters in the SQL query * @param {Array} parameters in the SQL query
* @returns {Promise} * @returns {Promise}
*/ */
execute(sql) { 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) {
console.log('ERROR: ', err); console.log("ERROR: ", err);
reject(err); reject(err);
} }
resolve(); resolve();
}) });
}) });
} }
/** /**
* Setup the database by running setup.sql file in schemas/. * Setup the database by running setup.sql file in schemas/.
* @returns {Promise} * @returns {Promise}
*/ */
setUp() { setUp() {
const setupSchema = this.readSqlFile('setup.sql'); const setupSchema = this.readSqlFile("setup.sql");
return Promise.resolve(this.execute(setupSchema)); return Promise.resolve(this.execute(setupSchema));
} }
/** /**
* Tears down the database by running tearDown.sql file in schemas/. * Tears down the database by running tearDown.sql file in schemas/.
* @returns {Promise} * @returns {Promise}
*/ */
tearDown() { tearDown() {
const tearDownSchema = this.readSqlFile('teardown.sql'); const tearDownSchema = this.readSqlFile("teardown.sql");
return Promise.resolve(this.execute(tearDownSchema)); return Promise.resolve(this.execute(tearDownSchema));
} }
/** /**
* Returns the file contents of a SQL file in schemas/. * Returns the file contents of a SQL file in schemas/.
* @returns {String} * @returns {String}
*/ */
readSqlFile(filename) { readSqlFile(filename) {
const schemaPath = path.join(this.schemaDirectory, filename); const schemaPath = path.join(this.schemaDirectory, filename);
const schema = fs.readFileSync(schemaPath).toString('utf-8'); const schema = fs.readFileSync(schemaPath).toString("utf-8");
return schema; return schema;
} }
} }
module.exports = SqliteDatabase; module.exports = SqliteDatabase;

View File

@@ -1,22 +1,31 @@
const Media = require("./media");
const Media = require('src/media_classes/media');
class Plex extends Media { class Plex extends Media {
constructor(title, year, type, summary, poster_path, background_path, added, seasons, episodes) { constructor(
super(title, year, type); title,
year,
type,
summary,
poster_path,
background_path,
added,
seasons,
episodes
) {
super(title, year, type);
this.summary = summary; this.summary = summary;
this.poster_path = poster_path; this.poster_path = poster_path;
this.background_path = background_path; this.background_path = background_path;
this.added = added; this.added = added;
this.seasons = seasons; this.seasons = seasons;
this.episodes = episodes; this.episodes = episodes;
} }
print() { print() {
super.print(); super.print();
} }
} }
module.exports = Plex; module.exports = Plex;

View File

@@ -1,33 +1,46 @@
const Media = require("./media");
const Media = require('src/media_classes/media');
class TMDB extends Media { class TMDB extends Media {
// constructor(...args) { // constructor(...args) {
constructor(title, year, type, id, summary, poster_path, background_path, popularity, score, release_status, tagline, seasons, episodes) { constructor(
super(title, year, type); title,
year,
type,
id,
summary,
poster_path,
background_path,
popularity,
score,
release_status,
tagline,
seasons,
episodes
) {
super(title, year, type);
this.id = id; this.id = id;
this.summary = summary; this.summary = summary;
this.poster_path = poster_path; this.poster_path = poster_path;
this.background_path = background_path; this.background_path = background_path;
this.popularity = popularity; this.popularity = popularity;
this.score = score; this.score = score;
this.release_status = release_status; this.release_status = release_status;
this.tagline = tagline; this.tagline = tagline;
this.seasons = seasons; this.seasons = seasons;
this.episodes = episodes; this.episodes = episodes;
} }
toString() { toString() {
return `${super.toString()} | ID: ${this.id}`; return `${super.toString()} | ID: ${this.id}`;
} }
print() { print() {
/* eslint-disable no-console */ /* eslint-disable no-console */
console.log(this.toString()); console.log(this.toString());
} }
} }
module.exports = TMDB; module.exports = TMDB;

View File

@@ -1,35 +1,35 @@
const request = require("request"); const request = require("request");
const configuration = require('src/config/configuration').getInstance(); const configuration = require("../config/configuration").getInstance();
const sendSMS = (message) => { const sendSMS = message => {
const apiKey = configuration.get('sms', 'apikey') const apiKey = configuration.get("sms", "apikey");
if (!apiKey) { if (!apiKey) {
console.warning("api key for sms not set, cannot send sms.") console.warning("api key for sms not set, cannot send sms.");
return null return null;
} }
const sender = configuration.get('sms', 'sender') const sender = configuration.get("sms", "sender");
const recipient = configuration.get('sms', 'recipient') const recipient = configuration.get("sms", "recipient");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
request.post( request.post(
{ {
url: `https://gatewayapi.com/rest/mtsms?token=${apiKey}`, url: `https://gatewayapi.com/rest/mtsms?token=${apiKey}`,
json: true, json: true,
body: { body: {
sender, sender,
message, message,
recipients: [{ msisdn: `47${recipient}` }] recipients: [{ msisdn: `47${recipient}` }]
}
},
function (err, r, body) {
console.log(err ? err : body);
console.log("sms provider response:", body);
resolve();
} }
}, );
function(err, r, body) { });
console.log(err ? err : body); };
console.log("sms provider response:", body)
resolve()
}
);
})
}
module.exports = { sendSMS } module.exports = { sendSMS };

View File

@@ -3,10 +3,9 @@ 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("../database/database");
const RedisCache = require("src/cache/redis"); const cache = require("../cache/redis");
const cache = new RedisCache();
function getMagnetFromURL(url) { function getMagnetFromURL(url) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {

View File

@@ -1,7 +1,11 @@
const Episode = require('src/plex/types/episode'); const Episode = require("./types/episode");
function convertPlexToEpisode(plexEpisode) { function convertPlexToEpisode(plexEpisode) {
const episode = new Episode(plexEpisode.title, plexEpisode.grandparentTitle, plexEpisode.year); const episode = new Episode(
plexEpisode.title,
plexEpisode.grandparentTitle,
plexEpisode.year
);
episode.season = plexEpisode.parentIndex; episode.season = plexEpisode.parentIndex;
episode.episode = plexEpisode.index; episode.episode = plexEpisode.index;
episode.summary = plexEpisode.summary; episode.summary = plexEpisode.summary;
@@ -12,7 +16,7 @@ function convertPlexToEpisode(plexEpisode) {
} }
if (plexEpisode.originallyAvailableAt !== undefined) { if (plexEpisode.originallyAvailableAt !== undefined) {
episode.airdate = new Date(plexEpisode.originallyAvailableAt) episode.airdate = new Date(plexEpisode.originallyAvailableAt);
} }
return episode; return episode;

View File

@@ -1,10 +1,10 @@
const Movie = require('src/plex/types/movie'); const Movie = require("./types/movie");
function convertPlexToMovie(plexMovie) { function convertPlexToMovie(plexMovie) {
const movie = new Movie(plexMovie.title, plexMovie.year); const movie = new Movie(plexMovie.title, plexMovie.year);
movie.rating = plexMovie.rating; movie.rating = plexMovie.rating;
movie.tagline = plexMovie.tagline; movie.tagline = plexMovie.tagline;
if (plexMovie.summary !== undefined) { if (plexMovie.summary !== undefined) {
movie.summary = plexMovie.summary; movie.summary = plexMovie.summary;
} }

View File

@@ -1,24 +1,34 @@
const Plex = require('src/media_classes/plex'); const Plex = require("../media_classes/plex");
function translateAdded(date_string) { function translateAdded(date_string) {
return new Date(date_string * 1000); return new Date(date_string * 1000);
} }
function convertPlexToSeasoned(plex) { function convertPlexToSeasoned(plex) {
const title = plex.title; const title = plex.title;
const year = plex.year; const year = plex.year;
const type = plex.type; const type = plex.type;
const summary = plex.summary; const summary = plex.summary;
const poster_path = plex.thumb; const poster_path = plex.thumb;
const background_path = plex.art; const background_path = plex.art;
const added = translateAdded(plex.addedAt); const added = translateAdded(plex.addedAt);
// const genre = plex.genre; // const genre = plex.genre;
const seasons = plex.childCount; const seasons = plex.childCount;
const episodes = plex.leafCount; const episodes = plex.leafCount;
const seasoned = new Plex(title, year, type, summary, poster_path, background_path, added, seasons, episodes); const seasoned = new Plex(
// seasoned.print(); title,
return seasoned; year,
type,
summary,
poster_path,
background_path,
added,
seasons,
episodes
);
// seasoned.print();
return seasoned;
} }
module.exports = convertPlexToSeasoned; module.exports = convertPlexToSeasoned;

View File

@@ -1,4 +1,4 @@
const Show = require('src/plex/types/show'); const Show = require("./types/show");
function convertPlexToShow(plexShow) { function convertPlexToShow(plexShow) {
const show = new Show(plexShow.title, plexShow.year); const show = new Show(plexShow.title, plexShow.year);

View File

@@ -1,19 +1,19 @@
const convertPlexToSeasoned = require('src/plex/convertPlexToSeasoned'); const convertPlexToSeasoned = require("./convertPlexToSeasoned");
const convertStreamToMediaInfo = require('src/plex/convertStreamToMediaInfo'); const convertStreamToMediaInfo = require("./convertStreamToMediaInfo");
const convertStreamToPlayer = require('src/plex/stream/convertStreamToPlayer'); const convertStreamToPlayer = require("./stream/convertStreamToPlayer");
const convertStreamToUser = require('src/plex/stream/convertStreamToUser'); const convertStreamToUser = require("./stream/convertStreamToUser");
const ConvertStreamToPlayback = require('src/plex/stream/convertStreamToPlayback'); const ConvertStreamToPlayback = require("./stream/convertStreamToPlayback");
function convertPlexToStream(plexStream) { function convertPlexToStream(plexStream) {
const stream = convertPlexToSeasoned(plexStream); const stream = convertPlexToSeasoned(plexStream);
const plexStreamMedia = plexStream.Media[0]; const plexStreamMedia = plexStream.Media[0];
stream.mediaInfo = convertStreamToMediaInfo(plexStreamMedia); stream.mediaInfo = convertStreamToMediaInfo(plexStreamMedia);
stream.player = convertStreamToPlayer(plexStream.Player); stream.player = convertStreamToPlayer(plexStream.Player);
stream.user = convertStreamToUser(plexStream.User); stream.user = convertStreamToUser(plexStream.User);
stream.playback = new ConvertStreamToPlayback(plexStreamMedia.Part[0]); stream.playback = new ConvertStreamToPlayback(plexStreamMedia.Part[0]);
return stream; return stream;
} }
module.exports = convertPlexToStream; module.exports = convertPlexToStream;

View File

@@ -1,22 +1,22 @@
const MediaInfo = require('src/media_classes/mediaInfo'); const MediaInfo = require("../media_classes/mediaInfo");
function convertStreamToMediaInfo(plexStream) { function convertStreamToMediaInfo(plexStream) {
const mediaInfo = new MediaInfo(); const mediaInfo = new MediaInfo();
mediaInfo.duration = plexStream.duration; mediaInfo.duration = plexStream.duration;
mediaInfo.height = plexStream.height; mediaInfo.height = plexStream.height;
mediaInfo.width = plexStream.width; mediaInfo.width = plexStream.width;
if (plexStream.bitrate) { if (plexStream.bitrate) {
mediaInfo.bitrate = plexStream.bitrate; mediaInfo.bitrate = plexStream.bitrate;
} }
mediaInfo.resolution = plexStream.videoResolution; mediaInfo.resolution = plexStream.videoResolution;
mediaInfo.framerate = plexStream.videoFrameRate; mediaInfo.framerate = plexStream.videoFrameRate;
mediaInfo.protocol = plexStream.protocol; mediaInfo.protocol = plexStream.protocol;
mediaInfo.container = plexStream.container; mediaInfo.container = plexStream.container;
mediaInfo.audioCodec = plexStream.audioCodec; mediaInfo.audioCodec = plexStream.audioCodec;
return mediaInfo; return mediaInfo;
} }
module.exports = convertStreamToMediaInfo; module.exports = convertStreamToMediaInfo;

View File

@@ -1,7 +1,7 @@
const configuration = require('src/config/configuration').getInstance(); const configuration = require("../config/configuration").getInstance();
function hookDumpController(req, res) { function hookDumpController(req, res) {
console.log(req); console.log(req);
} }
module.exports = hookDumpController; module.exports = hookDumpController;

View File

@@ -1,12 +1,11 @@
const fetch = require("node-fetch"); const fetch = require("node-fetch");
const convertPlexToMovie = require("src/plex/convertPlexToMovie"); const convertPlexToMovie = require("./convertPlexToMovie");
const convertPlexToShow = require("src/plex/convertPlexToShow"); const convertPlexToShow = require("./convertPlexToShow");
const convertPlexToEpisode = require("src/plex/convertPlexToEpisode"); const convertPlexToEpisode = require("./convertPlexToEpisode");
const { Movie, Show, Person } = require("src/tmdb/types"); const { Movie, Show, Person } = require("../tmdb/types");
const RedisCache = require("src/cache/redis"); const redisCache = require("../cache/redis");
const redisCache = new RedisCache();
const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, ""); const sanitize = string => string.toLowerCase().replace(/[^\w]/gi, "");

View File

@@ -1,102 +1,110 @@
const convertPlexToSeasoned = require('src/plex/convertPlexToSeasoned'); const convertPlexToSeasoned = require("./convertPlexToSeasoned");
const convertPlexToStream = require('src/plex/convertPlexToStream'); const convertPlexToStream = require("./convertPlexToStream");
const rp = require('request-promise'); const rp = require("request-promise");
class PlexRepository { class PlexRepository {
constructor(plexIP) { constructor(plexIP) {
this.plexIP = plexIP; this.plexIP = plexIP;
} }
inPlex(tmdbResult) { inPlex(tmdbResult) {
return Promise.resolve() return Promise.resolve()
.then(() => this.search(tmdbResult.title)) .then(() => this.search(tmdbResult.title))
.then(plexResult => this.compareTmdbToPlex(tmdbResult, plexResult)) .then(plexResult => this.compareTmdbToPlex(tmdbResult, plexResult))
.catch((error) => { .catch(error => {
console.log(error) console.log(error);
tmdbResult.matchedInPlex = false; tmdbResult.matchedInPlex = false;
return tmdbResult; return tmdbResult;
}); });
} }
search(query) { search(query) {
const queryUri = encodeURIComponent(query) const queryUri = encodeURIComponent(query);
const uri = encodeURI(`http://${this.plexIP}:32400/search?query=${queryUri}`) const uri = encodeURI(
const options = { `http://${this.plexIP}:32400/search?query=${queryUri}`
uri: uri, );
headers: { const options = {
Accept: 'application/json', uri: uri,
}, headers: {
json: true, Accept: "application/json"
}; },
json: true
};
return rp(options) return rp(options)
.catch((error) => { .catch(error => {
console.log(error) console.log(error);
throw new Error('Unable to search plex.') throw new Error("Unable to search plex.");
}) })
.then(result => this.mapResults(result)) .then(result => this.mapResults(result))
.then(([mappedResults, resultCount]) => ({ results: mappedResults, total_results: resultCount })); .then(([mappedResults, resultCount]) => ({
} results: mappedResults,
total_results: resultCount
}));
}
compareTmdbToPlex(tmdb, plexResult) { compareTmdbToPlex(tmdb, plexResult) {
return Promise.resolve() return Promise.resolve().then(() => {
.then(() => { if (plexResult.results.length === 0) {
if (plexResult.results.length === 0) { tmdb.matchedInPlex = false;
tmdb.matchedInPlex = false } else {
} // console.log('plex and tmdb:', plexResult, '\n', tmdb)
else { plexResult.results.map(plexItem => {
// console.log('plex and tmdb:', plexResult, '\n', tmdb) if (tmdb.title === plexItem.title && tmdb.year === plexItem.year)
plexResult.results.map((plexItem) => { tmdb.matchedInPlex = true;
if (tmdb.title === plexItem.title && tmdb.year === plexItem.year) return tmdb;
tmdb.matchedInPlex = true; });
return tmdb; }
}); return tmdb;
} });
return tmdb; }
});
}
mapResults(response) { mapResults(response) {
return Promise.resolve() return Promise.resolve()
.then(() => { .then(() => {
if (!response.MediaContainer.hasOwnProperty('Metadata')) return [[], 0]; if (!response.MediaContainer.hasOwnProperty("Metadata")) return [[], 0];
const mappedResults = response.MediaContainer.Metadata.filter((element) => { const mappedResults = response.MediaContainer.Metadata.filter(
return (element.type === 'movie' || element.type === 'show'); element => {
}).map((element) => convertPlexToSeasoned(element)); return element.type === "movie" || element.type === "show";
return [mappedResults, mappedResults.length]; }
}) ).map(element => convertPlexToSeasoned(element));
.catch((error) => { throw new Error(error); }); return [mappedResults, mappedResults.length];
} })
.catch(error => {
throw new Error(error);
});
}
nowPlaying() { nowPlaying() {
const options = { const options = {
uri: `http://${this.plexIP}:32400/status/sessions`, uri: `http://${this.plexIP}:32400/status/sessions`,
headers: { headers: {
Accept: 'application/json', Accept: "application/json"
}, },
json: true, json: true
}; };
return rp(options) return rp(options)
.then((result) => { .then(result => {
if (result.MediaContainer.size > 0) { if (result.MediaContainer.size > 0) {
const playing = result.MediaContainer.Metadata.map(convertPlexToStream); const playing =
return { size: Object.keys(playing).length, video: playing }; result.MediaContainer.Metadata.map(convertPlexToStream);
} return { size: Object.keys(playing).length, video: playing };
return { size: 0, video: [] }; }
}) return { size: 0, video: [] };
.catch((err) => { })
throw new Error(`Error handling plex playing. Error: ${err}`); .catch(err => {
}); throw new Error(`Error handling plex playing. Error: ${err}`);
} });
}
// multipleInPlex(tmdbResults) { // multipleInPlex(tmdbResults) {
// const results = tmdbResults.results.map(async (tmdb) => { // const results = tmdbResults.results.map(async (tmdb) => {
// return this.inPlex(tmdb) // return this.inPlex(tmdb)
// }) // })
// return Promise.all(results) // return Promise.all(results)
// } // }
} }
module.exports = PlexRepository; module.exports = PlexRepository;

View File

@@ -1,7 +1,7 @@
const PlexRepository = require("src/plex/plexRepository"); const PlexRepository = require("./plexRepository");
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../config/configuration").getInstance();
const TMDB = require("src/tmdb/tmdb"); const TMDB = require("../tmdb/tmdb");
const establishedDatabase = require("src/database/database"); const establishedDatabase = require("../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 tmdb = new TMDB(configuration.get("tmdb", "apiKey"));

View File

@@ -1,13 +1,13 @@
const Player = require('src/media_classes/player'); const Player = require("../../media_classes/player");
function convertStreamToPlayer(plexStream) { function convertStreamToPlayer(plexStream) {
const player = new Player(plexStream.device, plexStream.address); const player = new Player(plexStream.device, plexStream.address);
player.platform = plexStream.platform; player.platform = plexStream.platform;
player.product = plexStream.product; player.product = plexStream.product;
player.title = plexStream.title; player.title = plexStream.title;
player.state = plexStream.state; player.state = plexStream.state;
return player; return player;
} }
module.exports = convertStreamToPlayer; module.exports = convertStreamToPlayer;

View File

@@ -1,7 +1,7 @@
const User = require('src/media_classes/user'); const User = require("../../media_classes/user");
function convertStreamToUser(plexStream) { function convertStreamToUser(plexStream) {
return new User(plexStream.id, plexStream.title); return new User(plexStream.id, plexStream.title);
} }
module.exports = convertStreamToUser; module.exports = convertStreamToUser;

View File

@@ -1,28 +1,34 @@
const assert = require('assert') const assert = require("assert");
const configuration = require('src/config/configuration').getInstance(); const configuration = require("../config/configuration").getInstance();
const TMDB = require('src/tmdb/tmdb'); const TMDB = require("../tmdb/tmdb");
const tmdb = new TMDB(configuration.get('tmdb', 'apiKey')); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const establishedDatabase = require('src/database/database'); const establishedDatabase = require("../database/database");
const utils = require('./utils'); const utils = require("./utils");
class RequestRepository { class RequestRepository {
constructor(database) { constructor(database) {
this.database = database || establishedDatabase; this.database = database || establishedDatabase;
this.queries = { this.queries = {
add: 'insert into requests (id,title,year,poster_path,background_path,requested_by,ip,user_agent,type) values(?,?,?,?,?,?,?,?,?)', add: "insert into requests (id,title,year,poster_path,background_path,requested_by,ip,user_agent,type) values(?,?,?,?,?,?,?,?,?)",
fetchAll: 'select * from requests where status != "downloaded" order by date desc LIMIT 25 OFFSET ?*25-25', fetchAll:
fetchAllFilteredStatus: 'select * from requests where status = ? order by date desc LIMIT 25 offset ?*25-25', 'select * from requests where status != "downloaded" order by date desc LIMIT 25 OFFSET ?*25-25',
totalRequests: 'select count(*) as totalRequests from requests where status != "downloaded"', fetchAllFilteredStatus:
totalRequestsFilteredStatus: 'select count(*) as totalRequests from requests where status = ?', "select * from requests where status = ? order by date desc LIMIT 25 offset ?*25-25",
totalRequests:
'select count(*) as totalRequests from requests where status != "downloaded"',
totalRequestsFilteredStatus:
"select count(*) as totalRequests from requests where status = ?",
fetchAllSort: `select id, type from request order by ? ?`, fetchAllSort: `select id, type from request order by ? ?`,
fetchAllFilter: `select id, type from request where ? is "?"`, fetchAllFilter: `select id, type from request where ? is "?"`,
fetchAllQuery: `select id, type from request where title like "%?%" or year like "%?%"`, fetchAllQuery: `select id, type from request where title like "%?%" or year like "%?%"`,
fetchAllFilterAndSort: `select id, type from request where ? is "?" order by ? ?`, fetchAllFilterAndSort: `select id, type from request where ? is "?" order by ? ?`,
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 ?', readWithoutUserData:
read: 'select id, title, year, type, status, requested_by, ip, date, user_agent from requests where id is ? and type is ?' "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 ?"
}; };
} }
@@ -31,52 +37,58 @@ class RequestRepository {
if (query !== undefined) { if (query !== undefined) {
const dbParams = [query, query]; const dbParams = [query, query];
const dbquery = this.queries.fetchAllQuery const dbquery = this.queries.fetchAllQuery;
dbQuery = dbquery.split('').map((char) => char === '?' ? dbParams.shift() : char).join('') dbQuery = dbquery
} .split("")
else if (by !== undefined && filter !== undefined) { .map(char => (char === "?" ? dbParams.shift() : char))
.join("");
} else if (by !== undefined && filter !== undefined) {
const paramToColumnAndValue = { const paramToColumnAndValue = {
movie: ['type', 'movie'], movie: ["type", "movie"],
show: ['type', 'show'] show: ["type", "show"]
} };
const dbParams = paramToColumnAndValue[filter].concat([by, direction]); const dbParams = paramToColumnAndValue[filter].concat([by, direction]);
const query = this.queries.fetchAllFilterAndSort; const query = this.queries.fetchAllFilterAndSort;
dbQuery = query.split('').map((char) => char === '?' ? dbParams.shift() : char).join('') dbQuery = query
} .split("")
else if (by !== undefined) { .map(char => (char === "?" ? dbParams.shift() : char))
.join("");
} else if (by !== undefined) {
const dbParams = [by, direction]; const dbParams = [by, direction];
const query = this.queries.fetchAllSort; const query = this.queries.fetchAllSort;
dbQuery = query.split('').map((char) => char === '?' ? dbParams.shift() : char).join('') dbQuery = query
} .split("")
else if (filter !== undefined) { .map(char => (char === "?" ? dbParams.shift() : char))
.join("");
} else if (filter !== undefined) {
const paramToColumnAndValue = { const paramToColumnAndValue = {
movie: ['type', 'movie'], movie: ["type", "movie"],
show: ['type', 'show'], show: ["type", "show"],
downloaded: [this.queries.downloaded, 'downloaded'] downloaded: [this.queries.downloaded, "downloaded"]
// downloading: [this.database.delugeStatus, 'downloading'] // downloading: [this.database.delugeStatus, 'downloading']
} };
const dbParams = paramToColumnAndValue[filter] const dbParams = paramToColumnAndValue[filter];
const query = this.queries.fetchAllFilter; const query = this.queries.fetchAllFilter;
dbQuery = query.split('').map((char) => char === '?' ? dbParams.shift() : char).join('') dbQuery = query
} .split("")
else { .map(char => (char === "?" ? dbParams.shift() : char))
.join("");
} else {
dbQuery = this.queries.fetchAll; dbQuery = this.queries.fetchAll;
} }
return dbQuery return dbQuery;
} }
mapToTmdbByType(rows) { mapToTmdbByType(rows) {
return rows.map((row) => { return rows.map(row => {
if (row.type === 'movie') if (row.type === "movie") return tmdb.movieInfo(row.id);
return tmdb.movieInfo(row.id) else if (row.type === "show") return tmdb.showInfo(row.id);
else if (row.type === 'show') });
return tmdb.showInfo(row.id)
})
} }
/** /**
@@ -87,14 +99,31 @@ class RequestRepository {
requestFromTmdb(tmdb, ip, user_agent, username) { requestFromTmdb(tmdb, ip, user_agent, username) {
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 =>
.then(() => this.database.run(this.queries.add, [tmdb.id, tmdb.title, tmdb.year, tmdb.poster, tmdb.backdrop, username, ip, user_agent, tmdb.type])) assert.equal(row, undefined, "Id has already been requested")
.catch((error) => { )
if (error.name === 'AssertionError' || error.message.endsWith('been requested')) { .then(() =>
throw new Error('This id is already requested', error.message); this.database.run(this.queries.add, [
tmdb.id,
tmdb.title,
tmdb.year,
tmdb.poster,
tmdb.backdrop,
username,
ip,
user_agent,
tmdb.type
])
)
.catch(error => {
if (
error.name === "AssertionError" ||
error.message.endsWith("been requested")
) {
throw new Error("This id is already requested", error.message);
} }
console.log('Error @ request.addTmdb:', error); console.log("Error @ request.addTmdb:", error);
throw new Error('Could not add request'); throw new Error("Could not add request");
}); });
} }
@@ -105,9 +134,10 @@ class RequestRepository {
* @returns {Promise} * @returns {Promise}
*/ */
getRequestByIdAndType(id, type) { getRequestByIdAndType(id, type) {
return this.database.get(this.queries.readWithoutUserData, [id, type]) return this.database
.get(this.queries.readWithoutUserData, [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 {
id: row.id, id: row.id,
title: row.title, title: row.title,
@@ -115,8 +145,8 @@ class RequestRepository {
type: row.type, type: row.type,
status: row.status, status: row.status,
requested_date: new Date(row.date) requested_date: new Date(row.date)
} };
}) });
} }
/** /**
@@ -127,40 +157,68 @@ class RequestRepository {
* @param {String} query param to filter result on. Filters on title and year * @param {String} query param to filter result on. Filters on title and year
* @returns {Promise} * @returns {Promise}
*/ */
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) 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];
if (filter && (filter === 'downloading' || filter === 'downloaded' || filter === 'requested')) { if (
console.log('tes') filter &&
fetchQuery = this.queries.fetchAllFilteredStatus (filter === "downloading" ||
fetchTotalResults = this.queries.totalRequestsFilteredStatus filter === "downloaded" ||
fetchParams = [filter, page] filter === "requested")
) {
console.log("tes");
fetchQuery = this.queries.fetchAllFilteredStatus;
fetchTotalResults = this.queries.totalRequestsFilteredStatus;
fetchParams = [filter, page];
} else { } else {
filter = undefined filter = undefined;
} }
return Promise.resolve() return Promise.resolve()
.then((dbQuery) => this.database.all(fetchQuery, fetchParams)) .then(dbQuery => this.database.all(fetchQuery, fetchParams))
.then(async (rows) => { .then(async rows => {
const sqliteResponse = await this.database.get(fetchTotalResults, filter ? filter : undefined) const sqliteResponse = await this.database.get(
const totalRequests = sqliteResponse['totalRequests'] fetchTotalResults,
const totalPages = Math.ceil(totalRequests / 26) filter ? filter : undefined
);
const totalRequests = sqliteResponse["totalRequests"];
const totalPages = Math.ceil(totalRequests / 26);
return [ rows.map(item => { return [
item.poster = item.poster_path; delete item.poster_path; rows.map(item => {
item.backdrop = item.background_path; delete item.background_path; item.poster = item.poster_path;
return item delete item.poster_path;
}), totalPages, totalRequests ] item.backdrop = item.background_path;
return Promise.all(this.mapToTmdbByType(rows)) delete item.background_path;
}) return item;
.then(([result, totalPages, totalRequests]) => Promise.resolve({ }),
results: result, total_results: totalRequests, page: page, total_pages: totalPages totalPages,
})) totalRequests
.catch(error => { console.log(error);throw error }) ];
return Promise.all(this.mapToTmdbByType(rows));
})
.then(([result, totalPages, totalRequests]) =>
Promise.resolve({
results: result,
total_results: totalRequests,
page: page,
total_pages: totalPages
})
)
.catch(error => {
console.log(error);
throw error;
});
} }
} }

View File

@@ -1,52 +1,57 @@
const establishedDatabase = require('src/database/database'); const establishedDatabase = require("../database/database");
class SearchHistory { class SearchHistory {
constructor(database) { constructor(database) {
this.database = database || establishedDatabase; this.database = database || establishedDatabase;
this.queries = { this.queries = {
'create': 'insert into search_history (search_query, user_name) values (?, ?)', create:
'read': 'select search_query from search_history where user_name = ? order by id desc', "insert into search_history (search_query, user_name) values (?, ?)",
}; read: "select search_query from search_history where user_name = ? order by id desc"
} };
}
/** /**
* Retrive a search queries for a user from the database. * Retrive a search queries for a user from the database.
* @param {User} user existing user * @param {User} user existing user
* @returns {Promise} * @returns {Promise}
*/ */
read(user) { read(user) {
return new Promise((resolve, reject) => this.database.all(this.queries.read, user) return new Promise((resolve, reject) =>
.then((result, error) => { this.database
if (error) throw new Error(error); .all(this.queries.read, user)
resolve(result.map(row => row.search_query)); .then((result, error) => {
}) if (error) throw new Error(error);
.catch((error) => { resolve(result.map(row => row.search_query));
console.log('Error when fetching history from database:', error) })
reject('Unable to get history.'); .catch(error => {
})); console.log("Error when fetching history from database:", error);
} reject("Unable to get history.");
})
);
}
/** /**
* 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 {String} username logged in user doing the search
* @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(username, searchQuery) {
return this.database.run(this.queries.create, [searchQuery, username]) return this.database
.catch(error => { .run(this.queries.create, [searchQuery, username])
if (error.message.includes('FOREIGN')) { .catch(error => {
throw new Error('Could not create search history.'); if (error.message.includes("FOREIGN")) {
} throw new Error("Could not create search history.");
}
throw { throw {
success: false, success: false,
status: 500, status: 500,
message: 'An unexpected error occured', message: "An unexpected error occured",
source: 'database' source: "database"
} };
}); });
} }
} }
module.exports = SearchHistory; module.exports = SearchHistory;

View File

@@ -1,62 +1,68 @@
const assert = require('assert'); const assert = require("assert");
const Stray = require('src/seasoned/stray'); const Stray = require("./stray");
const establishedDatabase = require('src/database/database'); const establishedDatabase = require("../database/database");
const pythonShell = require('python-shell'); const pythonShell = require("python-shell");
class StrayRepository { class StrayRepository {
constructor(database) { constructor(database) {
this.database = database || establishedDatabase; this.database = database || establishedDatabase;
this.queries = { this.queries = {
read: 'SELECT * FROM stray_eps WHERE id = ?', read: "SELECT * FROM stray_eps WHERE id = ?",
readAll: 'SELECT id, name, season, episode, verified FROM stray_eps', readAll: "SELECT id, name, season, episode, verified FROM stray_eps",
readAllFiltered: 'SELECT id, name, season, episode, verified FROM stray_eps WHERE verified = ', readAllFiltered:
checkVerified: 'SELECT id FROM stray_eps WHERE verified = 0 AND id = ?', "SELECT id, name, season, episode, verified FROM stray_eps WHERE verified = ",
verify: 'UPDATE stray_eps SET verified = 1 WHERE id = ?', checkVerified: "SELECT id FROM stray_eps WHERE verified = 0 AND id = ?",
verify: "UPDATE stray_eps SET verified = 1 WHERE id = ?"
};
}
read(strayId) {
return this.database.get(this.queries.read, strayId).then(row => {
assert.notEqual(
row,
undefined,
`Could not find list with id ${strayId}.`
);
return row;
});
}
readAll(verified = null) {
let dbSearchQuery = this.queries.readAll;
if (verified != null) {
dbSearchQuery = this.queries.readAllFiltered + verified.toString();
}
return this.database.all(dbSearchQuery).then(rows =>
rows.map(row => {
const stray = new Stray(row.id);
stray.name = row.name;
stray.season = row.season;
stray.episode = row.episode;
stray.verified = row.verified;
return stray;
})
);
}
verifyStray(strayId) {
return this.database.get(this.queries.checkVerified, strayId).then(row => {
assert.notEqual(row, undefined, `Stray '${strayId}' already verified.`);
const options = {
pythonPath: "../app/env/bin/python3",
args: [strayId]
}; };
}
read(strayId) { pythonShell.run("../app/moveSeasoned.py", options, (err, results) => {
return this.database.get(this.queries.read, strayId).then((row) => { if (err) throw err;
assert.notEqual(row, undefined, `Could not find list with id ${strayId}.`); // TODO Add error handling!! StrayRepository.ERROR
return row; // results is an array consisting of messages collected during execution
console.log("results: %j", results);
}); });
}
readAll(verified = null) { return this.database.run(this.queries.verify, strayId);
let dbSearchQuery = this.queries.readAll; });
if (verified != null) { }
dbSearchQuery = this.queries.readAllFiltered + verified.toString();
}
return this.database.all(dbSearchQuery).then(rows =>
rows.map((row) => {
const stray = new Stray(row.id);
stray.name = row.name;
stray.season = row.season;
stray.episode = row.episode;
stray.verified = row.verified;
return stray;
}));
}
verifyStray(strayId) {
return this.database.get(this.queries.checkVerified, strayId).then((row) => {
assert.notEqual(row, undefined, `Stray '${strayId}' already verified.`);
const options = {
pythonPath: '../app/env/bin/python3',
args: [strayId],
};
pythonShell.run('../app/moveSeasoned.py', options, (err, results) => {
if (err) throw err;
// TODO Add error handling!! StrayRepository.ERROR
// results is an array consisting of messages collected during execution
console.log('results: %j', results);
});
return this.database.run(this.queries.verify, strayId);
});
}
} }
module.exports = StrayRepository; module.exports = StrayRepository;

View File

@@ -1,44 +1,48 @@
const assert = require('assert'); const assert = require("assert");
const establishedDatabase = require('src/database/database'); const establishedDatabase = require("../database/database");
class Cache { class Cache {
constructor(database) { constructor(database) {
this.database = database || establishedDatabase; this.database = database || establishedDatabase;
this.queries = { this.queries = {
read: 'SELECT value, time_to_live, created_at, DATETIME("now", "localtime") as now, ' + read:
'DATETIME(created_at, "+" || time_to_live || " seconds") as expires ' + 'SELECT value, time_to_live, created_at, DATETIME("now", "localtime") as now, ' +
'FROM cache WHERE key = ? AND now < expires', 'DATETIME(created_at, "+" || time_to_live || " seconds") as expires ' +
create: 'INSERT OR REPLACE INTO cache (key, value, time_to_live) VALUES (?, ?, ?)', "FROM cache WHERE key = ? AND now < expires",
}; create:
} "INSERT OR REPLACE INTO cache (key, value, time_to_live) VALUES (?, ?, ?)"
};
}
/** /**
* Retrieve an unexpired cache entry by key. * Retrieve an unexpired cache entry by key.
* @param {String} key of the cache entry * @param {String} key of the cache entry
* @returns {Object} * @returns {Object}
*/ */
get(key) { get(key) {
return Promise.resolve() return Promise.resolve()
.then(() => this.database.get(this.queries.read, [key])) .then(() => this.database.get(this.queries.read, [key]))
.then(row => { .then(row => {
assert(row, 'Could not find cache entry with that key.'); assert(row, "Could not find cache entry with that key.");
return JSON.parse(row.value); return JSON.parse(row.value);
}) });
} }
/** /**
* Insert cache entry with key and value. * Insert cache entry with key and value.
* @param {String} key of the cache entry * @param {String} key of the cache entry
* @param {String} value of the cache entry * @param {String} value of the cache entry
* @param {Number} timeToLive the number of seconds before entry expires * @param {Number} timeToLive the number of seconds before entry expires
* @returns {Object} * @returns {Object}
*/ */
set(key, value, timeToLive = 10800) { set(key, value, timeToLive = 10800) {
const json = JSON.stringify(value); const json = JSON.stringify(value);
return Promise.resolve() return Promise.resolve()
.then(() => this.database.run(this.queries.create, [key, json, timeToLive])) .then(() =>
.then(() => value); this.database.run(this.queries.create, [key, json, timeToLive])
} )
.then(() => value);
}
} }
module.exports = Cache; module.exports = Cache;

View File

@@ -1,14 +1,7 @@
const moviedb = require("km-moviedb"); const moviedb = require("km-moviedb");
const RedisCache = require("src/cache/redis"); const redisCache = require("../cache/redis");
const redisCache = new RedisCache();
const { const { Movie, Show, Person, Credits, ReleaseDates } = require("./types");
Movie,
Show,
Person,
Credits,
ReleaseDates
} = require("src/tmdb/types");
const tmdbErrorResponse = (error, typeString = undefined) => { const tmdbErrorResponse = (error, typeString = undefined) => {
if (error.status === 404) { if (error.status === 404) {
@@ -107,14 +100,20 @@ class TMDB {
* @returns {Promise} movie release dates object * @returns {Promise} movie release dates object
*/ */
movieReleaseDates(identifier) { movieReleaseDates(identifier) {
const query = { id: identifier } const query = { id: identifier };
const cacheKey = `tmdb/${this.cacheTags.movieReleaseDates}:${identifier}` const cacheKey = `tmdb/${this.cacheTags.movieReleaseDates}:${identifier}`;
return this.getFromCacheOrFetchFromTmdb(cacheKey, 'movieReleaseDates', query) return this.getFromCacheOrFetchFromTmdb(
.then(releaseDates => this.cache.set(cacheKey, releaseDates, this.defaultTTL)) cacheKey,
.then(releaseDates => ReleaseDates.convertFromTmdbResponse(releaseDates)) "movieReleaseDates",
query
)
.then(releaseDates =>
this.cache.set(cacheKey, releaseDates, this.defaultTTL)
)
.then(releaseDates => ReleaseDates.convertFromTmdbResponse(releaseDates));
} }
/** /**
* Retrieve a specific show by id from TMDB. * Retrieve a specific show by id from TMDB.
* @param {Number} identifier of the show you want to retrieve * @param {Number} identifier of the show you want to retrieve

View File

@@ -1,4 +1,4 @@
const User = require("src/user/user"); const User = require("./user");
const jwt = require("jsonwebtoken"); const jwt = require("jsonwebtoken");
class Token { class Token {

View File

@@ -1,5 +1,5 @@
const assert = require("assert"); const assert = require("assert");
const establishedDatabase = require("src/database/database"); const establishedDatabase = require("../database/database");
class UserRepository { class UserRepository {
constructor(database) { constructor(database) {

View File

@@ -1,5 +1,5 @@
const bcrypt = require("bcrypt"); const bcrypt = require("bcrypt");
const UserRepository = require("src/user/userRepository"); const UserRepository = require("./userRepository");
class UserSecurity { class UserSecurity {
constructor(database) { constructor(database) {

View File

@@ -3,7 +3,7 @@ const Raven = require("raven");
const cookieParser = require("cookie-parser"); const cookieParser = require("cookie-parser");
const bodyParser = require("body-parser"); const bodyParser = require("body-parser");
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../config/configuration").getInstance();
const reqTokenToUser = require("./middleware/reqTokenToUser"); const reqTokenToUser = require("./middleware/reqTokenToUser");
const mustBeAuthenticated = require("./middleware/mustBeAuthenticated"); const mustBeAuthenticated = require("./middleware/mustBeAuthenticated");

View File

@@ -1,15 +1,16 @@
const GitRepository = require('src/git/gitRepository'); const GitRepository = require("../../../git/gitRepository");
const gitRepository = new GitRepository(); const gitRepository = new GitRepository();
function dumpHookController(req, res) { function dumpHookController(req, res) {
gitRepository.dumpHook(req.body) gitRepository
.then(() => { .dumpHook(req.body)
res.status(200); .then(() => {
}) res.status(200);
.catch((error) => { })
res.status(500); .catch(error => {
}); res.status(500);
});
} }
module.exports = dumpHookController; module.exports = dumpHookController;

View File

@@ -1,15 +1,15 @@
const configuration = require('src/config/configuration').getInstance(); const configuration = require("../../../config/configuration").getInstance();
const TMDB = require('src/tmdb/tmdb'); const TMDB = require("../../../tmdb/tmdb");
const tmdb = new TMDB(configuration.get('tmdb', 'apiKey')); const tmdb = new TMDB(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
// belong in tmdb. // belong in tmdb.
// + could also have default value that are sent to the client. // + could also have default value that are sent to the client.
// * have the same class create a getListNames() and a fetchList() // * have the same class create a getListNames() and a fetchList()
// * dicover list might be overkill_https://tinyurl.com/y7f8ragw // * dicover list might be overkill_https://tinyurl.com/y7f8ragw
// + trending! https://tinyurl.com/ydywrqox // + trending! https://tinyurl.com/ydywrqox
// by all, mediatype, or person. Can also define time periode to // by all, mediatype, or person. Can also define time periode to
// get more trending view of what people are checking out. // get more trending view of what people are checking out.
// + newly created (tv/latest). // + newly created (tv/latest).
// + movie/latest // + movie/latest
@@ -18,44 +18,57 @@ function handleError(error, res) {
const { status, message } = error; const { status, message } = error;
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }) res.status(status).send({ success: false, message });
} else { } else {
console.log('caught list controller error', error) console.log("caught list controller error", error);
res.status(500).send({ message: 'An unexpected error occured while requesting list'}) res
.status(500)
.send({ message: "An unexpected error occured while requesting list" });
} }
} }
function handleListResponse(response, res) { function handleListResponse(response, res) {
return res.send(response) return res.send(response).catch(error => handleError(error, res));
.catch(error => handleError(error, res))
} }
function fetchTmdbList(req, res, listname, type) { function fetchTmdbList(req, res, listname, type) {
const { page } = req.query; const { page } = req.query;
if (type === 'movie') { if (type === "movie") {
return tmdb.movieList(listname, page) return tmdb
.movieList(listname, page)
.then(listResponse => res.send(listResponse)) .then(listResponse => res.send(listResponse))
.catch(error => handleError(error, res)) .catch(error => handleError(error, res));
} else if (type === 'show') { } else if (type === "show") {
return tmdb.showList(listname, page) return tmdb
.showList(listname, page)
.then(listResponse => res.send(listResponse)) .then(listResponse => res.send(listResponse))
.catch(error => handleError(error, res)) .catch(error => handleError(error, res));
} }
handleError({ handleError(
status: 400, {
message: `'${type}' is not a valid list type.` status: 400,
}, res) message: `'${type}' is not a valid list type.`
},
res
);
} }
const nowPlayingMovies = (req, res) => fetchTmdbList(req, res, 'miscNowPlayingMovies', 'movie') const nowPlayingMovies = (req, res) =>
const popularMovies = (req, res) => fetchTmdbList(req, res, 'miscPopularMovies', 'movie') fetchTmdbList(req, res, "miscNowPlayingMovies", "movie");
const topRatedMovies = (req, res) => fetchTmdbList(req, res, 'miscTopRatedMovies', 'movie') const popularMovies = (req, res) =>
const upcomingMovies = (req, res) => fetchTmdbList(req, res, 'miscUpcomingMovies', 'movie') fetchTmdbList(req, res, "miscPopularMovies", "movie");
const nowPlayingShows = (req, res) => fetchTmdbList(req, res, 'tvOnTheAir', 'show') const topRatedMovies = (req, res) =>
const popularShows = (req, res) => fetchTmdbList(req, res, 'miscPopularTvs', 'show') fetchTmdbList(req, res, "miscTopRatedMovies", "movie");
const topRatedShows = (req, res) => fetchTmdbList(req, res, 'miscTopRatedTvs', 'show') 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 = { module.exports = {
nowPlayingMovies, nowPlayingMovies,
@@ -65,4 +78,4 @@ module.exports = {
nowPlayingShows, nowPlayingShows,
popularShows, popularShows,
topRatedShows topRatedShows
} };

View File

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

View File

@@ -1,6 +1,6 @@
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const TMDB = require("src/tmdb/tmdb"); const TMDB = require("../../../tmdb/tmdb");
const Plex = require("src/plex/plex"); const Plex = require("../../../plex/plex");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const plex = new Plex(configuration.get("plex", "ip")); const plex = new Plex(configuration.get("plex", "ip"));
@@ -58,7 +58,7 @@ async function movieInfoController(req, res) {
} else { } else {
console.log("Unkown error from plex!"); console.log("Unkown error from plex!");
} }
console.log(error); console.log(error?.message);
} }
} }

View File

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

View File

@@ -1,5 +1,5 @@
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const TMDB = require("src/tmdb/tmdb"); const TMDB = require("../../../tmdb/tmdb");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const personCreditsController = (req, res) => { const personCreditsController = (req, res) => {

View File

@@ -1,5 +1,5 @@
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const TMDB = require("src/tmdb/tmdb"); const TMDB = require("../../../tmdb/tmdb");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
function handleError(error, res) { function handleError(error, res) {

View File

@@ -1,25 +1,24 @@
/* /*
* @Author: KevinMidboe * @Author: KevinMidboe
* @Date: 2017-10-21 09:54:31 * @Date: 2017-10-21 09:54:31
* @Last Modified by: KevinMidboe * @Last Modified by: KevinMidboe
* @Last Modified time: 2017-10-21 15:32:43 * @Last Modified time: 2017-10-21 15:32:43
*/ */
const PirateRepository = require('src/pirate/pirateRepository'); const PirateRepository = require("../../../pirate/pirateRepository");
function addMagnet(req, res) { function addMagnet(req, res) {
const magnet = req.body.magnet; const magnet = req.body.magnet;
const name = req.body.name; const name = req.body.name;
const tmdb_id = req.body.tmdb_id; const tmdb_id = req.body.tmdb_id;
PirateRepository.AddMagnet(magnet, name, tmdb_id) PirateRepository.AddMagnet(magnet, name, tmdb_id)
.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, message: error.message });
}); });
} }
module.exports = addMagnet; module.exports = addMagnet;

View File

@@ -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("../../../pirate/pirateRepository");
// const pirateRepository = new PirateRepository(); // const pirateRepository = new PirateRepository();
/** /**

View File

@@ -1,4 +1,4 @@
const RequestRepository = require('src/plex/requestRepository.js'); const RequestRepository = require("../../../plex/requestRepository.js");
const requestRepository = new RequestRepository(); const requestRepository = new RequestRepository();
@@ -9,16 +9,21 @@ const requestRepository = new RequestRepository();
* @returns {Callback} * @returns {Callback}
*/ */
function fetchRequestedController(req, res) { function fetchRequestedController(req, res) {
// const user = req.loggedInUser; // const user = req.loggedInUser;
const { status, page } = req.query; const { status, page } = req.query;
requestRepository.fetchRequested(status, page) requestRepository
.then((requestedItems) => { .fetchRequested(status, page)
res.send({ success: true, results: requestedItems, total_results: requestedItems.length }); .then(requestedItems => {
}) res.send({
.catch((error) => { success: true,
res.status(401).send({ success: false, message: error.message }); results: requestedItems,
total_results: requestedItems.length
}); });
})
.catch(error => {
res.status(401).send({ success: false, message: error.message });
});
} }
module.exports = fetchRequestedController; module.exports = fetchRequestedController;

View File

@@ -1,16 +1,17 @@
const PlexRepository = require('src/plex/plexRepository'); const PlexRepository = require("../../../plex/plexRepository");
const configuration = require('src/config/configuration').getInstance(); const configuration = require("../../../config/configuration").getInstance();
const plexRepository = new PlexRepository(configuration.get('plex', 'ip')); const plexRepository = new PlexRepository(configuration.get("plex", "ip"));
function playingController(req, res) { function playingController(req, res) {
plexRepository.nowPlaying() plexRepository
.then(movies => { .nowPlaying()
res.send(movies); .then(movies => {
}) res.send(movies);
.catch(error => { })
res.status(500).send({ success: false, message: error.message }); .catch(error => {
}); res.status(500).send({ success: false, message: error.message });
});
} }
module.exports = playingController; module.exports = playingController;

View File

@@ -1,4 +1,4 @@
const RequestRepository = require('src/plex/requestRepository'); const RequestRepository = require("../../../plex/requestRepository");
const requestRepository = new RequestRepository(); const requestRepository = new RequestRepository();
@@ -9,14 +9,16 @@ const requestRepository = new RequestRepository();
* @returns {Callback} * @returns {Callback}
*/ */
function readRequestController(req, res) { 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
.then(movies => { .lookup(mediaId, type)
res.send(movies); .then(movies => {
}).catch(error => { res.send(movies);
res.status(404).send({ success: false, message: error.message }); })
}); .catch(error => {
res.status(404).send({ success: false, message: error.message });
});
} }
module.exports = readRequestController; module.exports = readRequestController;

View File

@@ -1,6 +1,6 @@
const configuration = require('src/config/configuration').getInstance(); const configuration = require("../../../config/configuration").getInstance();
const Plex = require('src/plex/plex'); const Plex = require("../../../plex/plex");
const plex = new Plex(configuration.get('plex', 'ip')); const plex = new Plex(configuration.get("plex", "ip"));
/** /**
* Controller: Search plex for movies, shows and episodes by query * Controller: Search plex for movies, shows and episodes by query
@@ -9,17 +9,24 @@ const plex = new Plex(configuration.get('plex', 'ip'));
* @returns {Callback} * @returns {Callback}
*/ */
function searchPlexController(req, res) { function searchPlexController(req, res) {
const { query, type } = req.query; const { query, type } = req.query;
plex.search(query, type) plex
.then(movies => { .search(query, type)
if (movies.length > 0) { .then(movies => {
res.send(movies); if (movies.length > 0) {
} else { res.send(movies);
res.status(404).send({ success: false, message: 'Search query did not give any results from plex.'}) } else {
} res
}).catch(error => { .status(404)
res.status(500).send({ success: false, message: error.message }); .send({
}); success: false,
message: "Search query did not give any results from plex."
});
}
})
.catch(error => {
res.status(500).send({ success: false, message: error.message });
});
} }
module.exports = searchPlexController; module.exports = searchPlexController;

View File

@@ -1,7 +1,7 @@
const PlexRepository = require('src/plex/plexRepository'); const PlexRepository = require("../../../plex/plexRepository");
const configuration = require('src/config/configuration').getInstance(); const configuration = require("../../../config/configuration").getInstance();
const plexRepository = new PlexRepository(configuration.get('plex', 'ip')); const plexRepository = new PlexRepository(configuration.get("plex", "ip"));
/** /**
* Controller: Search for media and check existence * Controller: Search for media and check existence
@@ -11,19 +11,25 @@ const plexRepository = new PlexRepository(configuration.get('plex', 'ip'));
* @returns {Callback} * @returns {Callback}
*/ */
function searchMediaController(req, res) { function searchMediaController(req, res) {
const { query } = req.query; const { query } = req.query;
plexRepository.search(query) plexRepository
.then(media => { .search(query)
if (media !== undefined || media.length > 0) { .then(media => {
res.send(media); if (media !== undefined || media.length > 0) {
} else { res.send(media);
res.status(404).send({ success: false, message: 'Search query did not return any results.' }); } else {
} res
}) .status(404)
.catch(error => { .send({
res.status(500).send({ success: false, message: error.message }); success: false,
}); message: "Search query did not return any results."
});
}
})
.catch(error => {
res.status(500).send({ success: false, message: error.message });
});
} }
module.exports = searchMediaController; module.exports = searchMediaController;

View File

@@ -1,6 +1,6 @@
const SearchHistory = require("src/searchHistory/searchHistory"); const SearchHistory = require("../../../searchHistory/searchHistory");
const Cache = require("src/tmdb/cache"); const Cache = require("../../../tmdb/cache");
const RequestRepository = require("src/plex/requestRepository.js"); const RequestRepository = require("../../../plex/requestRepository.js");
const cache = new Cache(); const cache = new Cache();
const requestRepository = new RequestRepository(cache); const requestRepository = new RequestRepository(cache);

View File

@@ -1,6 +1,6 @@
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const RequestRepository = require("src/request/request"); const RequestRepository = require("../../../request/request");
const TMDB = require("src/tmdb/tmdb"); const TMDB = require("../../../tmdb/tmdb");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const request = new RequestRepository(); const request = new RequestRepository();
@@ -35,12 +35,10 @@ function submitRequestController(req, res) {
console.log("show"); console.log("show");
mediaFunction = tmdbShowInfo; mediaFunction = tmdbShowInfo;
} else { } else {
res res.status(422).send({
.status(422) success: false,
.send({ message: 'Incorrect type. Allowed types: "movie" or "show"'
success: false, });
message: 'Incorrect type. Allowed types: "movie" or "show"'
});
} }
if (mediaFunction === undefined) { if (mediaFunction === undefined) {

View File

@@ -1,4 +1,4 @@
const RequestRepository = require('src/plex/requestRepository'); const RequestRepository = require("../../../plex/requestRepository");
const requestRepository = new RequestRepository(); const requestRepository = new RequestRepository();
@@ -9,17 +9,18 @@ const requestRepository = new RequestRepository();
* @returns {Callback} * @returns {Callback}
*/ */
function updateRequested(req, res) { function updateRequested(req, res) {
const id = req.params.requestId; const id = req.params.requestId;
const type = req.body.type; const type = req.body.type;
const status = req.body.status; const status = req.body.status;
requestRepository.updateRequestedById(id, type, status) requestRepository
.then(() => { .updateRequestedById(id, type, status)
res.send({ success: true }); .then(() => {
}) res.send({ success: true });
.catch((error) => { })
res.status(401).send({ success: false, message: error.message }); .catch(error => {
}); res.status(401).send({ success: false, message: error.message });
});
} }
module.exports = updateRequested; module.exports = updateRequested;

View File

@@ -1,6 +1,6 @@
const configuration = require('src/config/configuration').getInstance(); const configuration = require("../../../config/configuration").getInstance();
const Plex = require('src/plex/plex'); const Plex = require("../../../plex/plex");
const plex = new Plex(configuration.get('plex', 'ip')); const plex = new Plex(configuration.get("plex", "ip"));
/** /**
* Controller: Search plex for movies, shows and episodes by query * Controller: Search plex for movies, shows and episodes by query
@@ -9,18 +9,18 @@ const plex = new Plex(configuration.get('plex', 'ip'));
* @returns {Callback} * @returns {Callback}
*/ */
function watchDirectLink (req, res) { function watchDirectLink(req, res) {
const { title, year } = req.query; const { title, year } = req.query;
plex.getDirectLinkByTitleAndYear(title, year) plex
.getDirectLinkByTitleAndYear(title, year)
.then(plexDirectLink => { .then(plexDirectLink => {
if (plexDirectLink == false) if (plexDirectLink == false)
res.status(404).send({ success: true, link: null }) res.status(404).send({ success: true, link: null });
else else res.status(200).send({ success: true, link: plexDirectLink });
res.status(200).send({ success: true, link: plexDirectLink })
}) })
.catch(error => { .catch(error => {
res.status(500).send({ success: false, message: error.message }); res.status(500).send({ success: false, message: error.message });
}); });
} }

View File

@@ -1,4 +1,4 @@
const RequestRepository = require('src/request/request'); const RequestRepository = require("../../../request/request");
const request = new RequestRepository(); const request = new RequestRepository();
/** /**
@@ -12,16 +12,16 @@ function fetchAllRequests(req, res) {
let sort_by = sort; let sort_by = sort;
let sort_direction = undefined; let sort_direction = undefined;
if (sort !== undefined && sort.includes(':')) { if (sort !== undefined && sort.includes(":")) {
[sort_by, sort_direction] = sort.split(':') [sort_by, sort_direction] = sort.split(":");
} }
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, message: error.message });
}); });
} }
module.exports = fetchAllRequests; module.exports = fetchAllRequests;

View File

@@ -1,4 +1,4 @@
const RequestRepository = require('src/request/request'); const RequestRepository = require("../../../request/request");
const request = new RequestRepository(); const request = new RequestRepository();
/** /**
@@ -11,7 +11,8 @@ 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) request
.getRequestByIdAndType(id, type)
.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, message: error.message });

View File

@@ -1,6 +1,6 @@
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const TMDB = require("src/tmdb/tmdb"); const TMDB = require("../../../tmdb/tmdb");
const RequestRepository = require("src/request/request"); const RequestRepository = require("../../../request/request");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const request = new RequestRepository(); const request = new RequestRepository();
// const { sendSMS } = require("src/notifications/sms"); // const { sendSMS } = require("src/notifications/sms");

View File

@@ -1,6 +1,6 @@
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const TMDB = require("src/tmdb/tmdb"); const TMDB = require("../../../tmdb/tmdb");
const SearchHistory = require("src/searchHistory/searchHistory"); const SearchHistory = require("../../../searchHistory/searchHistory");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const searchHistory = new SearchHistory(); const searchHistory = new SearchHistory();

View File

@@ -1,6 +1,6 @@
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../..//config/configuration").getInstance();
const TMDB = require("src/tmdb/tmdb"); const TMDB = require("../../../tmdb/tmdb");
const SearchHistory = require("src/searchHistory/searchHistory"); const SearchHistory = require("../../../searchHistory/searchHistory");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const searchHistory = new SearchHistory(); const searchHistory = new SearchHistory();
@@ -36,11 +36,9 @@ function multiSearchController(req, res) {
} else { } else {
// TODO log unhandled errors // TODO log unhandled errors
console.log("caugth multi search controller error", error); console.log("caugth multi search controller error", error);
res res.status(500).send({
.status(500) message: `An unexpected error occured while searching with query: ${query}`
.send({ });
message: `An unexpected error occured while searching with query: ${query}`
});
} }
}); });
} }

View File

@@ -1,6 +1,6 @@
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const TMDB = require("src/tmdb/tmdb"); const TMDB = require("../../../tmdb/tmdb");
const SearchHistory = require("src/searchHistory/searchHistory"); const SearchHistory = require("../../../searchHistory/searchHistory");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const searchHistory = new SearchHistory(); const searchHistory = new SearchHistory();

View File

@@ -1,6 +1,6 @@
const SearchHistory = require("src/searchHistory/searchHistory"); const SearchHistory = require("../../../searchHistory/searchHistory");
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const TMDB = require("src/tmdb/tmdb"); const TMDB = require("../../../tmdb/tmdb");
const tmdb = new TMDB(configuration.get("tmdb", "apiKey")); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const searchHistory = new SearchHistory(); const searchHistory = new SearchHistory();

View File

@@ -1,17 +1,17 @@
const StrayRepository = require('src/seasoned/strayRepository'); const StrayRepository = require("../../../seasoned/strayRepository");
const strayRepository = new StrayRepository(); const strayRepository = new StrayRepository();
function readStraysController(req, res) { function readStraysController(req, res) {
const { verified, page } = req.query; const { verified, page } = req.query;
strayRepository.readAll(verified, page) strayRepository
.then((strays) => { .readAll(verified, page)
res.send(strays); .then(strays => {
}) res.send(strays);
.catch((error) => { })
res.status(500).send({ success: false, message: error.message }); .catch(error => {
}); res.status(500).send({ success: false, message: error.message });
});
} }
module.exports = readStraysController; module.exports = readStraysController;

View File

@@ -1,17 +1,18 @@
const StrayRepository = require('src/seasoned/strayRepository'); const StrayRepository = require("../../../seasoned/strayRepository");
const strayRepository = new StrayRepository(); const strayRepository = new StrayRepository();
function strayByIdController(req, res) { function strayByIdController(req, res) {
const id = req.params.strayId; const id = req.params.strayId;
strayRepository.read(id) strayRepository
.then((stray) => { .read(id)
res.send(stray); .then(stray => {
}) res.send(stray);
.catch((error) => { })
res.status(500).send({ success: false, message: error.message }); .catch(error => {
}); res.status(500).send({ success: false, message: error.message });
});
} }
module.exports = strayByIdController; module.exports = strayByIdController;

View File

@@ -1,17 +1,18 @@
const StrayRepository = require('src/seasoned/strayRepository'); const StrayRepository = require("../../../seasoned/strayRepository");
const strayRepository = new StrayRepository(); const strayRepository = new StrayRepository();
function verifyStrayController(req, res) { function verifyStrayController(req, res) {
const id = req.params.strayId; const id = req.params.strayId;
strayRepository.verifyStray(id) strayRepository
.then(() => { .verifyStray(id)
res.send({ success: true, message: 'Episode verified' }); .then(() => {
}) res.send({ success: true, message: "Episode verified" });
.catch((error) => { })
res.status(500).send({ success: false, message: error.message }); .catch(error => {
}); res.status(500).send({ success: false, message: error.message });
});
} }
module.exports = verifyStrayController; module.exports = verifyStrayController;

View File

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

View File

@@ -1,24 +1,24 @@
const configuration = require('src/config/configuration').getInstance(); const configuration = require("../../../config/configuration").getInstance();
const TMDB = require('src/tmdb/tmdb'); const TMDB = require("../../../tmdb/tmdb");
const Plex = require('src/plex/plex'); const Plex = require("../../../plex/plex");
const tmdb = new TMDB(configuration.get('tmdb', 'apiKey')); const tmdb = new TMDB(configuration.get("tmdb", "apiKey"));
const plex = new Plex(configuration.get('plex', 'ip')); const plex = new Plex(configuration.get("plex", "ip"));
function handleError(error, res) { function handleError(error, res) {
const { status, message } = error; const { status, message } = error;
if (status && message) { if (status && message) {
res.status(status).send({ success: false, message }) res.status(status).send({ success: false, message });
} else { } else {
console.log('caught showinfo controller error', error) console.log("caught showinfo controller error", error);
res.status(500).send({ res.status(500).send({
message: 'An unexpected error occured while requesting show info.' message: "An unexpected error occured while requesting show info."
}) });
} }
} }
/** /**
* Controller: Retrieve information for a show * Controller: Retrieve information for a show
* @param {Request} req http request variable * @param {Request} req http request variable
* @param {Response} res * @param {Response} res
* @returns {Callback} * @returns {Callback}
@@ -28,26 +28,27 @@ async function showInfoController(req, res) {
const showId = req.params.id; const showId = req.params.id;
let { credits, check_existance } = req.query; let { credits, check_existance } = req.query;
credits && credits.toLowerCase() === 'true' ? credits = true : credits = false credits && credits.toLowerCase() === "true"
check_existance && check_existance.toLowerCase() === 'true' ? check_existance = true : check_existance = false ? (credits = true)
: (credits = false);
check_existance && check_existance.toLowerCase() === "true"
? (check_existance = true)
: (check_existance = false);
let tmdbQueue = [tmdb.showInfo(showId)] let tmdbQueue = [tmdb.showInfo(showId)];
if (credits) if (credits) tmdbQueue.push(tmdb.showCredits(showId));
tmdbQueue.push(tmdb.showCredits(showId))
try { try {
const [Show, Credits] = await Promise.all(tmdbQueue) const [Show, Credits] = await Promise.all(tmdbQueue);
const show = Show.createJsonResponse() const show = Show.createJsonResponse();
if (credits) if (credits) show.credits = Credits.createJsonResponse();
show.credits = Credits.createJsonResponse()
if (check_existance) if (check_existance) show.exists_in_plex = await plex.existsInPlex(show);
show.exists_in_plex = await plex.existsInPlex(show)
res.send(show) res.send(show);
} catch(error) { } catch (error) {
handleError(error, res) handleError(error, res);
} }
} }

View File

@@ -1,4 +1,4 @@
const UserRepository = require("src/user/userRepository"); const UserRepository = require("../../../user/userRepository");
const userRepository = new UserRepository(); const userRepository = new UserRepository();
const fetch = require("node-fetch"); const fetch = require("node-fetch");
const FormData = require("form-data"); const FormData = require("form-data");

View File

@@ -1,8 +1,8 @@
const User = require("src/user/user"); const User = require("../../../user/user");
const Token = require("src/user/token"); const Token = require("../../../user/token");
const UserSecurity = require("src/user/userSecurity"); const UserSecurity = require("../../../user/userSecurity");
const UserRepository = require("src/user/userRepository"); const UserRepository = require("../../../user/userRepository");
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const secret = configuration.get("authentication", "secret"); const secret = configuration.get("authentication", "secret");
const userSecurity = new UserSecurity(); const userSecurity = new UserSecurity();

View File

@@ -1,8 +1,8 @@
const User = require("src/user/user"); const User = require("../../../user/user");
const Token = require("src/user/token"); const Token = require("../../../user/token");
const UserSecurity = require("src/user/userSecurity"); const UserSecurity = require("../../../user/userSecurity");
const UserRepository = require("src/user/userRepository"); const UserRepository = require("../../../user/userRepository");
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const secret = configuration.get("authentication", "secret"); const secret = configuration.get("authentication", "secret");
const userSecurity = new UserSecurity(); const userSecurity = new UserSecurity();

View File

@@ -1,4 +1,4 @@
const RequestRepository = require("src/plex/requestRepository.js"); const RequestRepository = require("../../../plex/requestRepository.js");
const requestRepository = new RequestRepository(); const requestRepository = new RequestRepository();

View File

@@ -1,4 +1,4 @@
const SearchHistory = require("src/searchHistory/searchHistory"); const SearchHistory = require("../../../searchHistory/searchHistory");
const searchHistory = new SearchHistory(); const searchHistory = new SearchHistory();

View File

@@ -1,4 +1,4 @@
const UserRepository = require("src/user/userRepository"); const UserRepository = require("../../../user/userRepository");
const userRepository = new UserRepository(); const userRepository = new UserRepository();
/** /**
* Controller: Retrieves settings of a logged in user * Controller: Retrieves settings of a logged in user

View File

@@ -1,5 +1,5 @@
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../../config/configuration").getInstance();
const Tautulli = require("src/tautulli/tautulli"); const Tautulli = require("../../../tautulli/tautulli");
const apiKey = configuration.get("tautulli", "apiKey"); const apiKey = configuration.get("tautulli", "apiKey");
const ip = configuration.get("tautulli", "ip"); const ip = configuration.get("tautulli", "ip");
const port = configuration.get("tautulli", "port"); const port = configuration.get("tautulli", "port");

View File

@@ -1,27 +1,31 @@
const establishedDatabase = require('src/database/database'); const establishedDatabase = require("../../database/database");
const mustBeAdmin = (req, res, next) => { const mustBeAdmin = (req, res, next) => {
let database = establishedDatabase; let database = establishedDatabase;
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.', message: "You must be logged in."
});
} else {
database
.get(
`SELECT admin FROM user WHERE user_name IS ?`,
req.loggedInUser.username
)
.then(isAdmin => {
console.log(isAdmin, req.loggedInUser);
if (isAdmin.admin == 0) {
return res.status(401).send({
success: false,
message: "You must be logged in as a admin."
});
}
}); });
} else { }
database.get(`SELECT admin FROM user WHERE user_name IS ?`, req.loggedInUser.username)
.then((isAdmin) => {
console.log(isAdmin, req.loggedInUser)
if (isAdmin.admin == 0) {
return res.status(401).send({
success: false,
message: 'You must be logged in as a admin.'
})
}
})
}
return next(); return next();
}; };
module.exports = mustBeAdmin; module.exports = mustBeAdmin;

View File

@@ -1,31 +1,35 @@
const establishedDatabase = require('src/database/database'); const establishedDatabase = require("../../database/database");
const mustHaveAccountLinkedToPlex = (req, res, next) => { const mustHaveAccountLinkedToPlex = (req, res, next) => {
let database = establishedDatabase; let database = establishedDatabase;
const loggedInUser = req.loggedInUser; const loggedInUser = req.loggedInUser;
if (loggedInUser === undefined) { if (loggedInUser === undefined) {
return res.status(401).send({ return res.status(401).send({
success: false, success: false,
message: 'You must have your account linked to a plex account.', message: "You must have your account linked to a plex account."
}); });
} else { } else {
database.get(`SELECT plex_userid FROM settings WHERE user_name IS ?`, loggedInUser.username) database
.get(
`SELECT plex_userid FROM settings WHERE user_name IS ?`,
loggedInUser.username
)
.then(row => { .then(row => {
const plex_userid = row.plex_userid; 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();
}
})
}
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; module.exports = mustHaveAccountLinkedToPlex;

View File

@@ -1,6 +1,6 @@
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
const configuration = require("src/config/configuration").getInstance(); const configuration = require("../../config/configuration").getInstance();
const Token = require("src/user/token"); const Token = require("../../user/token");
const secret = configuration.get("authentication", "secret"); const secret = configuration.get("authentication", "secret");

View File

@@ -1,11 +1,11 @@
const config = require('src/config/configuration').getInstance(); const config = require("../config/configuration").getInstance();
const app = require('./app'); const app = require("./app");
module.exports = app.listen(config.get('webserver', 'port'), () => { module.exports = app.listen(config.get("webserver", "port"), () => {
/* eslint-disable no-console */ /* eslint-disable no-console */
console.log('seasonedAPI'); console.log("seasonedAPI");
/* eslint-disable no-console */ /* eslint-disable no-console */
console.log(`Database is located at ${config.get('database', 'host')}`); console.log(`Database is located at ${config.get("database", "host")}`);
/* eslint-disable no-console */ /* eslint-disable no-console */
console.log(`Webserver is listening on ${config.get('webserver', 'port')}`); console.log(`Webserver is listening on ${config.get("webserver", "port")}`);
}); });

File diff suppressed because it is too large Load Diff

7915
yarn.lock

File diff suppressed because it is too large Load Diff