Skip to content

Commit

Permalink
Merge pull request #111 from KevinMidboe/api/v2
Browse files Browse the repository at this point in the history
Api/v2
  • Loading branch information
KevinMidboe authored Nov 4, 2019
2 parents c3d87e2 + fd47526 commit ea5bc36
Show file tree
Hide file tree
Showing 89 changed files with 6,270 additions and 1,687 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
.DS_Store

development.json
env
shows.db

Expand Down
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
language: node_js
node_js: '8.7.0'
node_js: '11.9.0'
git:
submodules: true
script:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
<img src="https://travis-ci.org/KevinMidboe/seasonedShows.svg?branch=master"
alt="Travis CI">
</a>
<a href="https://coveralls.io/github/KevinMidboe/seasonedShows?branch=coverage">
<img src="https://coveralls.io/repos/github/KevinMidboe/seasonedShows/badge.svg?branch=coverage" alt="">
<a href="https://coveralls.io/github/KevinMidboe/seasonedShows?branch=api/v2">
<img src="https://coveralls.io/repos/github/KevinMidboe/seasonedShows/badge.svg?branch=api/v2" alt="">
</a>
<a href="https://snyk.io/test/github/KevinMidboe/seasonedShows?targetFile=seasoned_api/package.json">
<img src="https://snyk.io/test/github/KevinMidboe/seasonedShows/badge.svg?targetFile=seasoned_api/package.json" alt="">
Expand Down
4 changes: 2 additions & 2 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
"redux-thunk": "^2.2.0",
"urijs": "^1.18.12",
"webfontloader": "^1.6.28",
"webpack": "^3.5.5",
"webpack-dev-server": "^2.4.5",
"webpack": "^4.0.0",
"webpack-dev-server": "^3.1.11",
"webpack-merge": "^4.1.0"
},
"devDependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,13 @@
"tmdb": {
"apiKey": ""
},
"plex": {
"ip": ""
},
"raven": {
"DSN": ""
},
"mail": {
"host": "",
"user": "",
"password": "",
"user_pi": "",
"password_pi": ""
},
"authentication": {
"secret": "secret"
}
"secret": "secret"
}
}
3 changes: 3 additions & 0 deletions seasoned_api/conf/test.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
"tmdb": {
"apiKey": "bogus-api-key"
},
"plex": {
"ip": "0.0.0.0"
},
"raven": {
"DSN": ""
},
Expand Down
31 changes: 21 additions & 10 deletions seasoned_api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,48 @@
},
"main": "webserver/server.js",
"scripts": {
"start": "cross-env SEASONED_CONFIG=conf/development.json PROD=true NODE_PATH=. node src/webserver/server.js",
"test": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. mocha --recursive test",
"coverage": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. nyc mocha --recursive test && nyc report --reporter=text-lcov | coveralls",
"start": "cross-env SEASONED_CONFIG=conf/development.json PROD=true NODE_PATH=. babel-node src/webserver/server.js",
"test": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. mocha --require @babel/register --recursive test/unit test/system",
"coverage": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. nyc mocha --require @babel/register --recursive test && nyc report --reporter=text-lcov | coveralls",
"lint": "./node_modules/.bin/eslint src/",
"update": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. node src/plex/updateRequestsInPlex.js"
"update": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. node src/plex/updateRequestsInPlex.js",
"docs": "yarn apiDocs; yarn classDocs",
"apiDocs": "",
"classDocs": "./script/generate-class-docs.sh"
},
"dependencies": {
"bcrypt-nodejs": "^0.0.3",
"axios": "^0.18.0",
"bcrypt": "^3.0.6",
"body-parser": "~1.18.2",
"cross-env": "~5.1.4",
"express": "~4.16.0",
"jsonwebtoken": "^8.2.0",
"mongoose": "~5.2.12",
"km-moviedb": "^0.2.12",
"node-cache": "^4.1.1",
"node-fetch": "^2.6.0",
"python-shell": "^0.5.0",
"raven": "^2.4.2",
"request": "^2.87.0",
"request-promise": "^4.2",
"sqlite3": "^4.0.0"
},
"devDependencies": {
"coveralls": "^3.0.0",
"@babel/core": "^7.5.5",
"@babel/node": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"@babel/register": "^7.5.5",
"@types/node": "^12.6.8",
"coveralls": "^3.0.5",
"documentation": "^12.0.3",
"eslint": "^4.9.0",
"eslint-config-airbnb-base": "^12.1.0",
"eslint-plugin-import": "^2.8.0",
"istanbul": "^0.4.5",
"mocha": "^5.0.4",
"mocha": "^6.2.0",
"mocha-lcov-reporter": "^1.3.0",
"nyc": "^11.6.0",
"raven": "^2.4.2",
"supertest": "^3.0.0",
"supertest-as-promised": "^4.0.1"
"supertest-as-promised": "^4.0.1",
"typescript": "^3.5.3"
}
}
8 changes: 8 additions & 0 deletions seasoned_api/src/database/schemas/setup.sql
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ CREATE TABLE IF NOT EXISTS requests(
type CHAR(50) DEFAULT 'movie'
);

CREATE TABLE IF NOT EXISTS request(
id int not null,
title text not null,
year int not null,
type char(10) not null,
date timestamp default (strftime('%s', 'now'))
);


CREATE TABLE IF NOT EXISTS stray_eps(
id TEXT UNIQUE,
Expand Down
1 change: 1 addition & 0 deletions seasoned_api/src/database/schemas/teardown.sql
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
DROP TABLE IF EXISTS user;
DROP TABLE IF EXISTS search_history;
DROP TABLE IF EXISTS requests;
DROP TABLE IF EXISTS request;
8 changes: 4 additions & 4 deletions seasoned_api/src/database/sqliteDatabase.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class SqliteDatabase {
* @param {Array} parameters in the SQL query
* @returns {Promise}
*/
async run(sql, parameters) {
run(sql, parameters) {
return new Promise((resolve, reject) => {
this.connection.run(sql, parameters, (error, result) => {
if (error)
Expand All @@ -41,7 +41,7 @@ class SqliteDatabase {
* @param {Array} parameters in the SQL query
* @returns {Promise}
*/
async all(sql, parameters) {
all(sql, parameters) {
return new Promise((resolve, reject) => {
this.connection.all(sql, parameters, (err, rows) => {
if (err) {
Expand All @@ -58,7 +58,7 @@ class SqliteDatabase {
* @param {Array} parameters in the SQL query
* @returns {Promise}
*/
async get(sql, parameters) {
get(sql, parameters) {
return new Promise((resolve, reject) => {
this.connection.get(sql, parameters, (err, rows) => {
if (err) {
Expand All @@ -75,7 +75,7 @@ class SqliteDatabase {
* @param {Array} parameters in the SQL query
* @returns {Promise}
*/
async execute(sql) {
execute(sql) {
return new Promise(resolve => {
this.connection.exec(sql, (err, database) => {
if (err) {
Expand Down
25 changes: 11 additions & 14 deletions seasoned_api/src/pirate/pirateRepository.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ function getMagnetFromURL(url) {
resolve(url)

http.get(options, (res) => {
if (res.statusCode == 301) {
if (res.statusCode == 301 || res.statusCode == 302) {
resolve(res.headers.location)
}
});
Expand All @@ -21,12 +21,12 @@ function getMagnetFromURL(url) {

async function find(searchterm, callback) {
const options = {
pythonPath: '/usr/bin/python3',
// pythonPath: '/Library/Frameworks/Python.framework/Versions/3.6/bin/python3',
args: [searchterm, '-s', 'jackett', '-f', '--print'],
};
pythonPath: '../torrent_search/env/bin/python3',
scriptPath: '../torrent_search',
args: [searchterm, '-s', 'jackett', '-f', '--print']
}

PythonShell.run('../torrent_search/torrentSearch/search.py', options, callback);
PythonShell.run('torrentSearch/search.py', options, callback);
// PythonShell does not support return
}

Expand All @@ -35,12 +35,12 @@ async function callPythonAddMagnet(url, callback) {
getMagnetFromURL(url)
.then((magnet) => {
const options = {
pythonPath: '/usr/bin/python',
// pythonPath: '/Library/Frameworks/Python.framework/Versions/3.6/bin/python3',
args: [magnet],
pythonPath: '../delugeClient/env/bin/python3',
scriptPath: '../delugeClient',
args: ['add', magnet]
};

PythonShell.run('../app/magnet.py', options, callback);
PythonShell.run('deluge_cli.py', options, callback);
})
.catch((err) => {
console.log(err);
Expand All @@ -51,19 +51,16 @@ async function callPythonAddMagnet(url, callback) {
async function SearchPiratebay(query) {
return await new Promise((resolve, reject) => find(query, (err, results) => {
if (err) {
/* eslint-disable no-console */
console.log('THERE WAS A FUCKING ERROR!\n', err);
reject(Error('There was a error when searching for torrents'));
}
if (results) {
/* eslint-disable no-console */
console.log('result', results);
resolve(JSON.parse(results, null, '\t'));
}
}));
}

async function AddMagnet(magnet) {
async function AddMagnet(magnet, name, tmdb_id) {
return await new Promise((resolve, reject) => callPythonAddMagnet(magnet, (err, results) => {
if (err) {
/* eslint-disable no-console */
Expand Down
20 changes: 20 additions & 0 deletions seasoned_api/src/plex/convertPlexToEpisode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
const Episode = require('src/plex/types/episode');

function convertPlexToEpisode(plexEpisode) {
const episode = new Episode(plexEpisode.title, plexEpisode.grandparentTitle, plexEpisode.year);
episode.season = plexEpisode.parentIndex;
episode.episode = plexEpisode.index;
episode.summary = plexEpisode.summary;
episode.rating = plexEpisode.rating;

if (plexEpisode.viewCount !== undefined) {
episode.views = plexEpisode.viewCount;
}

if (plexEpisode.originallyAvailableAt !== undefined) {
episode.airdate = new Date(plexEpisode.originallyAvailableAt)
}

return episode;
}
module.exports = convertPlexToEpisode;
15 changes: 15 additions & 0 deletions seasoned_api/src/plex/convertPlexToMovie.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const Movie = require('src/plex/types/movie');

function convertPlexToMovie(plexMovie) {
const movie = new Movie(plexMovie.title, plexMovie.year);
movie.rating = plexMovie.rating;
movie.tagline = plexMovie.tagline;

if (plexMovie.summary !== undefined) {
movie.summary = plexMovie.summary;
}

return movie;
}

module.exports = convertPlexToMovie;
13 changes: 13 additions & 0 deletions seasoned_api/src/plex/convertPlexToShow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const Show = require('src/plex/types/show');

function convertPlexToShow(plexShow) {
const show = new Show(plexShow.title, plexShow.year);
show.summary = plexShow.summary;
show.rating = plexShow.rating;
show.seasons = plexShow.childCount;
show.episodes = plexShow.leafCount;

return show;
}

module.exports = convertPlexToShow;
90 changes: 90 additions & 0 deletions seasoned_api/src/plex/plex.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const fetch = require('node-fetch')
const convertPlexToMovie = require('src/plex/convertPlexToMovie')
const convertPlexToShow = require('src/plex/convertPlexToShow')
const convertPlexToEpisode = require('src/plex/convertPlexToEpisode')


const { Movie, Show, Person } = require('src/tmdb/types');

// const { Movie, }
// TODO? import class definitions to compare types ?
// what would typescript do?

class Plex {
constructor(ip, port=32400) {
this.plexIP = ip
this.plexPort = port
}

matchTmdbAndPlexMedia(plex, tmdb) {
if (plex === undefined || tmdb === undefined)
return false

const sanitize = (string) => string.toLowerCase()

const matchTitle = sanitize(plex.title) === sanitize(tmdb.title)
const matchYear = plex.year === tmdb.year

return matchTitle && matchYear
}

existsInPlex(tmdbMovie) {
return this.search(tmdbMovie.title)
.then(plexMovies => plexMovies.some(plex => this.matchTmdbAndPlexMedia(plex, tmdbMovie)))
}

successfullResponse(response) {
const { status, statusText } = response

if (status === 200) {
return response.json()
} else {
throw { message: statusText, status: status }
}
}

search(query) {
const url = `http://${this.plexIP}:${this.plexPort}/hubs/search?query=${query}`
const options = {
timeout: 2000,
headers: { 'Accept': 'application/json' }
}

return fetch(url, options)
.then(this.successfullResponse)
.then(this.mapResults)
.catch(error => {
if (error.type === 'request-timeout') {
throw { message: 'Plex did not respond', status: 408, success: false }
}

throw error
})
}

mapResults(response) {
if (response === undefined || response.MediaContainer === undefined) {
console.log('response was not valid to map', response)
return []
}

return response.MediaContainer.Hub
.filter(category => category.size > 0)
.map(category => {
if (category.type === 'movie') {
return category.Metadata.map(movie => {
const ovie = Movie.convertFromPlexResponse(movie)
return ovie.createJsonResponse()
})
} else if (category.type === 'show') {
return category.Metadata.map(convertPlexToShow)
} else if (category.type === 'episode') {
return category.Metadata.map(convertPlexToEpisode)
}
})
.filter(result => result !== undefined)
.flat()
}
}

module.exports = Plex;
Loading

0 comments on commit ea5bc36

Please sign in to comment.