Compare commits
61 Commits
1.0.6
...
renovate/c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e981b32f6b | ||
| 3a9131a022 | |||
| 77433e8505 | |||
| 3845000b3f | |||
| 071fd54825 | |||
| 537f237e83 | |||
| d3bc854e03 | |||
| 15826a00ba | |||
| 4019d63f3b | |||
| 91dcfaccb9 | |||
| 270a259cee | |||
| 162d20ae52 | |||
| 9f1badc1b1 | |||
| ac027a97d6 | |||
| 127db88ded | |||
| 4b07434615 | |||
| 5d6f2baa34 | |||
| 1a1a7328a3 | |||
| b9dec2344e | |||
| 476a34fb69 | |||
| e3ed08e8dd | |||
| 70f6497404 | |||
| 99bab3fb73 | |||
| e6796aff8b | |||
| 784aa2616a | |||
| 7cb55ce054 | |||
| 87eb6de802 | |||
| 840816c930 | |||
| 91d238de7c | |||
| 0ac17d3d0a | |||
| 87c76e3f1d | |||
| e64c4d5d01 | |||
| 22e57c03de | |||
| d80386da40 | |||
| e7c66af3f6 | |||
| 8ece7b84c4 | |||
| 4250b1bd17 | |||
| 7e46d32e30 | |||
| 5a48158f07 | |||
| 161a466ab7 | |||
| 8f5bd44e4d | |||
| 5d8869e042 | |||
| 90b8ee005e | |||
| 1b0525063f | |||
| 41d6bba743 | |||
| 8977a4b195 | |||
| 7e0da028de | |||
| 2250cf2c4b | |||
| b2bd7b6a1f | |||
| a2ad7f5628 | |||
| f85d31991f | |||
| 08dc2153ae | |||
| bc64e69b3e | |||
| a29bca7361 | |||
| d84aa5f173 | |||
| 48ebd398bc | |||
| 1b95103acd | |||
| 6a1d6687eb | |||
| e849864bc2 | |||
| ecc2a67d48 | |||
| bfe0d55f71 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,5 +1,6 @@
|
||||
.DS_Store
|
||||
|
||||
development.json
|
||||
env
|
||||
shows.db
|
||||
|
||||
|
||||
4
.gitmodules
vendored
4
.gitmodules
vendored
@@ -4,3 +4,7 @@
|
||||
path = torrent_search
|
||||
url = https://github.com/KevinMidboe/torrent_search.git
|
||||
branch = master
|
||||
|
||||
[submodule "delugeClient"]
|
||||
path = delugeClient
|
||||
url = https://github.com/KevinMidboe/delugeClient.git
|
||||
|
||||
@@ -7,6 +7,12 @@ script:
|
||||
- yarn coverage
|
||||
before_install:
|
||||
- cd seasoned_api
|
||||
before_script: yarn
|
||||
before_script:
|
||||
- yarn
|
||||
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
||||
- chmod +x ./cc-test-reporter
|
||||
- ./cc-test-reporter before-build
|
||||
after-script:
|
||||
- ./cc-test-resporter after-build --exit-code $TRAVIS_TEST_RESULT
|
||||
cache: false
|
||||
os: linux
|
||||
|
||||
25
README.md
25
README.md
@@ -13,9 +13,6 @@
|
||||
<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>
|
||||
<a href="https://www.versioneye.com/user/projects/5ac541370fb24f4489396e02">
|
||||
<img src="https://www.versioneye.com/user/projects/5ac541370fb24f4489396e02/badge.svg" 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="">
|
||||
</a>
|
||||
@@ -69,7 +66,7 @@ After you have downloaded a package manager and node.js javascript engine, the f
|
||||
- Open terminal
|
||||
- Install git. This can be done by running `xcode-select --install` in your favorite terminal.
|
||||
- Install a package manager, refer to this [wiki page] for yarn or [wiki page] for npm
|
||||
- Type: `git clone https://github.com/KevinMidboe/seasonedShows.git`
|
||||
- Type: `git clone --recurse-submodules git@github.com:KevinMidboe/seasonedShows.git`
|
||||
- Type: `cd seasonedShows/`
|
||||
- Install required packages
|
||||
* yarn: `yarn install`
|
||||
@@ -85,7 +82,7 @@ After you have downloaded a package manager and node.js javascript engine, the f
|
||||
- Install git
|
||||
* Ubuntu/Debian: `sudo apt-get install git-core`
|
||||
* Fedora: `sudo yum install git`
|
||||
- Type: `git clone https://github.com/KevinMidboe/seasonedShows.git`
|
||||
- Type: `git clone --recurse-submodules git@github.com:KevinMidboe/seasonedShows.git`
|
||||
- Type: `cd seasonedShows/`
|
||||
- Install required packages
|
||||
* yarn: `yarn install`
|
||||
@@ -142,21 +139,3 @@ The flow of the system will first check for new folders in your tv shows directo
|
||||
Then there is a script for looking for replies on twitter by user_admin, if caanges are needed, it handles the changes specified and updates dtabbase.
|
||||
|
||||
After approval by user the files are modified and moved to folders in resptected area. If error occours, pasteee link if log is sent to user.
|
||||
|
||||
#### External
|
||||
+ Seasoned: request, discover and manage.
|
||||
+ Stray: Overview of downloaded episodes before they are organized.
|
||||
+ (+) Admin Panel: Overview of all stray episodes/movies.
|
||||
|
||||
#### Api
|
||||
+ All communication between public website to server.
|
||||
+ Plex: All querying to what is localy available in your plex library.
|
||||
+ Stray (seasoned) -> also calls services (moveStray) through api.
|
||||
+ Tmdb: Requesting information from tmdb.
|
||||
+ (+) Admin Panel: Use secure login and session tokens to handle logged in viewer.
|
||||
|
||||
#### Services
|
||||
+ Parse directories for new content.
|
||||
+ Extract and save in db information about stray item.
|
||||
+ Move a confirmed stray item.
|
||||
+ (+) Search for torrents matching new content.
|
||||
|
||||
@@ -188,9 +188,6 @@ def XOR(list1, list2):
|
||||
return set(list1) ^ set(list2)
|
||||
|
||||
def filterChildItems(parent):
|
||||
if (not os.path.isdir(parent)):
|
||||
strayEpisode(parent[:-4], parent)
|
||||
return
|
||||
try:
|
||||
children = getDirContent('/'.join([env.input_dir, parent]))
|
||||
if children:
|
||||
|
||||
5
renovate.json
Normal file
5
renovate.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"extends": [
|
||||
"config:base"
|
||||
]
|
||||
}
|
||||
@@ -8,16 +8,12 @@
|
||||
"tmdb": {
|
||||
"apiKey": ""
|
||||
},
|
||||
"plex": {
|
||||
"ip": ""
|
||||
},
|
||||
"raven": {
|
||||
"DSN": ""
|
||||
},
|
||||
"mail": {
|
||||
"host": "",
|
||||
"user": "",
|
||||
"password": "",
|
||||
"user_pi": "",
|
||||
"password_pi": ""
|
||||
},
|
||||
"authentication": {
|
||||
"secret": "secret"
|
||||
}
|
||||
@@ -8,6 +8,9 @@
|
||||
"tmdb": {
|
||||
"apiKey": "bogus-api-key"
|
||||
},
|
||||
"plex": {
|
||||
"ip": "0.0.0.0"
|
||||
},
|
||||
"raven": {
|
||||
"DSN": ""
|
||||
},
|
||||
|
||||
@@ -8,24 +8,26 @@
|
||||
"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",
|
||||
"test": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. mocha --recursive test/unit test/system",
|
||||
"coverage": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. nyc mocha --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"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"bcrypt-nodejs": "^0.0.3",
|
||||
"body-parser": "~1.18.2",
|
||||
"cross-env": "~5.1.4",
|
||||
"express": "~4.16.0",
|
||||
"jsonwebtoken": "^8.0.1",
|
||||
"km-moviedb": "^0.2.13",
|
||||
"mongoose": "~5.0.11",
|
||||
"moviedb": "^0.2.10",
|
||||
"km-moviedb": "^0.2.12",
|
||||
"node-cache": "^4.1.1",
|
||||
"python-shell": "^0.5.0",
|
||||
"request": "^2.85.0",
|
||||
"request-promise": "^4.2",
|
||||
"sqlite3": "4.0.0"
|
||||
"sqlite3": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"coveralls": "^3.0.0",
|
||||
|
||||
@@ -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,
|
||||
@@ -56,3 +64,23 @@ CREATE TABLE IF NOT EXISTS shows(
|
||||
date_added DATE,
|
||||
date_modified DATE DEFUALT CURRENT_DATE NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS requested_torrent (
|
||||
magnet TEXT UNIQUE,
|
||||
torrent_name TEXT,
|
||||
tmdb_id TEXT
|
||||
date_added DATE DEFAULT (datetime('now','localtime'))
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS deluge_torrent (
|
||||
key TEXT UNIQUE,
|
||||
name TEXT,
|
||||
progress TEXT,
|
||||
eta NUMBER,
|
||||
save_path TEXT,
|
||||
state TEXT,
|
||||
paused BOOLEAN,
|
||||
finished BOOLEAN,
|
||||
files TEXT,
|
||||
is_folder BOOLEAN
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -3,6 +3,8 @@ const http = require('http');
|
||||
const { URL } = require('url');
|
||||
const PythonShell = require('python-shell');
|
||||
|
||||
const establishedDatabase = require('src/database/database');
|
||||
|
||||
function getMagnetFromURL(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const options = new URL(url);
|
||||
@@ -19,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.6',
|
||||
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
|
||||
}
|
||||
|
||||
@@ -33,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.6',
|
||||
scriptPath: '../delugeClient',
|
||||
args: ['add', magnet]
|
||||
};
|
||||
|
||||
PythonShell.run('../app/magnet.py', options, callback);
|
||||
PythonShell.run('deluge_cli.py', options, callback);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
@@ -61,7 +63,7 @@ async function SearchPiratebay(query) {
|
||||
}));
|
||||
}
|
||||
|
||||
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 */
|
||||
@@ -70,6 +72,14 @@ async function AddMagnet(magnet) {
|
||||
}
|
||||
/* eslint-disable no-console */
|
||||
console.log('result/error:', err, results);
|
||||
|
||||
database = establishedDatabase;
|
||||
insert_query = "INSERT INTO requested_torrent(magnet,torrent_name,tmdb_id) \
|
||||
VALUES (?,?,?)";
|
||||
|
||||
let response = database.run(insert_query, [magnet, name, tmdb_id]);
|
||||
console.log('Response from requsted_torrent insert: ' + response);
|
||||
|
||||
resolve({ success: true });
|
||||
}));
|
||||
}
|
||||
|
||||
20
seasoned_api/src/plex/convertPlexToEpisode.js
Normal file
20
seasoned_api/src/plex/convertPlexToEpisode.js
Normal file
@@ -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
seasoned_api/src/plex/convertPlexToMovie.js
Normal file
15
seasoned_api/src/plex/convertPlexToMovie.js
Normal file
@@ -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
seasoned_api/src/plex/convertPlexToShow.js
Normal file
13
seasoned_api/src/plex/convertPlexToShow.js
Normal file
@@ -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;
|
||||
60
seasoned_api/src/plex/plex.js
Normal file
60
seasoned_api/src/plex/plex.js
Normal file
@@ -0,0 +1,60 @@
|
||||
const axios = require('axios')
|
||||
const convertPlexToMovie = require('src/plex/convertPlexToMovie')
|
||||
const convertPlexToShow = require('src/plex/convertPlexToShow')
|
||||
const convertPlexToEpisode = require('src/plex/convertPlexToEpisode')
|
||||
|
||||
class Plex {
|
||||
constructor(ip) {
|
||||
this.plexIP = ip
|
||||
this.plexPort = 32400
|
||||
}
|
||||
|
||||
existsInPlex(tmdbMovie) {
|
||||
return Promise.resolve()
|
||||
.then(() => this.search(tmdbMovie.title))
|
||||
// TODO handle this when whitelist of local ip is not set in plex
|
||||
.catch((error) => { console.error('Unable to search plex')})
|
||||
.then((plexMovies) => {
|
||||
const matches = plexMovies.some((plexMovie) => {
|
||||
return tmdbMovie.title === plexMovie.title && tmdbMovie.type === plexMovie.type
|
||||
})
|
||||
|
||||
tmdbMovie.existsInPlex = matches
|
||||
return tmdbMovie
|
||||
})
|
||||
}
|
||||
|
||||
search(query) {
|
||||
const options = {
|
||||
baseURL: `http://${this.plexIP}:${this.plexPort}`,
|
||||
url: '/hubs/search',
|
||||
params: { query: query },
|
||||
responseType: 'json',
|
||||
timeout: 3000
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => axios.request(options))
|
||||
.catch((error) => { throw new Error(`Unable to search plex library`, error) })
|
||||
.then(response => this.mapResults(response))
|
||||
}
|
||||
|
||||
|
||||
mapResults(response) {
|
||||
return response.data.MediaContainer.Hub.reduce((result, hub) => {
|
||||
if (hub.type === 'movie' && hub.Metadata !== undefined) {
|
||||
return [...result, ...hub.Metadata.map(convertPlexToMovie)]
|
||||
}
|
||||
else if (hub.type === 'show' && hub.Metadata !== undefined) {
|
||||
return [...result, ...hub.Metadata.map(convertPlexToShow)]
|
||||
}
|
||||
else if (hub.type === 'episode' && hub.Metadata !== undefined) {
|
||||
return [...result, ...hub.Metadata.map(convertPlexToEpisode)]
|
||||
}
|
||||
|
||||
return result
|
||||
}, [])
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Plex;
|
||||
@@ -3,6 +3,10 @@ const convertPlexToStream = require('src/plex/convertPlexToStream');
|
||||
const rp = require('request-promise');
|
||||
|
||||
class PlexRepository {
|
||||
constructor(plexIP) {
|
||||
this.plexIP = plexIP;
|
||||
}
|
||||
|
||||
inPlex(tmdbResult) {
|
||||
return Promise.resolve()
|
||||
.then(() => this.search(tmdbResult.title))
|
||||
@@ -15,9 +19,10 @@ class PlexRepository {
|
||||
}
|
||||
|
||||
search(query) {
|
||||
console.log('searching:', query)
|
||||
const queryUri = encodeURIComponent(query)
|
||||
const uri = encodeURI(`http://${this.plexIP}:32400/search?query=${queryUri}`)
|
||||
const options = {
|
||||
uri: `http://10.0.0.44:32400/search?query=${query}`,
|
||||
uri: uri,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
@@ -26,6 +31,7 @@ class PlexRepository {
|
||||
|
||||
return rp(options)
|
||||
.catch((error) => {
|
||||
console.log(error)
|
||||
throw new Error('Unable to search plex.')
|
||||
})
|
||||
.then(result => this.mapResults(result))
|
||||
@@ -39,6 +45,7 @@ class PlexRepository {
|
||||
tmdb.matchedInPlex = false
|
||||
}
|
||||
else {
|
||||
// console.log('plex and tmdb:', plexResult, '\n', tmdb)
|
||||
plexResult.results.map((plexItem) => {
|
||||
if (tmdb.title === plexItem.title && tmdb.year === plexItem.year)
|
||||
tmdb.matchedInPlex = true;
|
||||
@@ -52,7 +59,6 @@ class PlexRepository {
|
||||
mapResults(response) {
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
console.log('plexResponse:', response)
|
||||
if (!response.MediaContainer.hasOwnProperty('Metadata')) return [[], 0];
|
||||
|
||||
const mappedResults = response.MediaContainer.Metadata.filter((element) => {
|
||||
@@ -65,7 +71,7 @@ class PlexRepository {
|
||||
|
||||
nowPlaying() {
|
||||
const options = {
|
||||
uri: 'http://10.0.0.44:32400/status/sessions',
|
||||
uri: `http://${this.plexIP}:32400/status/sessions`,
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@ const configuration = require('src/config/configuration').getInstance();
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const establishedDatabase = require('src/database/database');
|
||||
|
||||
const plexRepository = new PlexRepository();
|
||||
const plexRepository = new PlexRepository(configuration.get('plex', 'ip'));
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
|
||||
@@ -86,7 +86,11 @@ class RequestRepository {
|
||||
}
|
||||
throw new Error('Unable to fetch your requests');
|
||||
})
|
||||
.then((result) => { return result; });
|
||||
.then((result) => {
|
||||
// TODO do a correct mapping before sending, not just a dump of the database
|
||||
result.map(item => item.poster = item.poster_path)
|
||||
return result
|
||||
});
|
||||
}
|
||||
|
||||
updateRequestedById(id, type, status) {
|
||||
|
||||
16
seasoned_api/src/plex/types/episode.js
Normal file
16
seasoned_api/src/plex/types/episode.js
Normal file
@@ -0,0 +1,16 @@
|
||||
class Episode {
|
||||
constructor(title, show, year) {
|
||||
this.title = title;
|
||||
this.show = show;
|
||||
this.year = year;
|
||||
this.season = null;
|
||||
this.episode = null;
|
||||
this.summary = null;
|
||||
this.rating = null;
|
||||
this.views = null;
|
||||
this.aired = null;
|
||||
this.type = 'episode';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Episode;
|
||||
12
seasoned_api/src/plex/types/movie.js
Normal file
12
seasoned_api/src/plex/types/movie.js
Normal file
@@ -0,0 +1,12 @@
|
||||
class Movie {
|
||||
constructor(title, year) {
|
||||
this.title = title;
|
||||
this.year = year;
|
||||
this.summary = null;
|
||||
this.rating = null;
|
||||
this.tagline = null;
|
||||
this.type = 'movie';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Movie;
|
||||
13
seasoned_api/src/plex/types/show.js
Normal file
13
seasoned_api/src/plex/types/show.js
Normal file
@@ -0,0 +1,13 @@
|
||||
class Show {
|
||||
constructor(title, year) {
|
||||
this.title = title;
|
||||
this.year = year;
|
||||
this.summary = null;
|
||||
this.rating = null;
|
||||
this.seasons = null;
|
||||
this.episodes = null;
|
||||
this.type = 'show';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Show;
|
||||
157
seasoned_api/src/request/request.js
Normal file
157
seasoned_api/src/request/request.js
Normal file
@@ -0,0 +1,157 @@
|
||||
const assert = require('assert')
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
const establishedDatabase = require('src/database/database');
|
||||
const utils = require('./utils');
|
||||
|
||||
class RequestRepository {
|
||||
constructor(database) {
|
||||
this.database = database || establishedDatabase;
|
||||
this.queries = {
|
||||
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',
|
||||
fetchAllFilteredStatus: '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 ? ?`,
|
||||
fetchAllFilter: `select id, type from request where ? is "?"`,
|
||||
fetchAllQuery: `select id, type from request where title like "%?%" or year like "%?%"`,
|
||||
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)',
|
||||
// deluge: '(select status from deluge_torrent where id is request.id and type is request.type limit 1)',
|
||||
// fetchAllFilterStatus: 'select * from request where '
|
||||
read: 'select id, title, year, type, status, requested_by, ip, date, user_agent from requests where id is ? and type is ?'
|
||||
};
|
||||
}
|
||||
|
||||
sortAndFilterToDbQuery(by, direction, filter, query) {
|
||||
let dbQuery = undefined;
|
||||
|
||||
if (query !== undefined) {
|
||||
const dbParams = [query, query];
|
||||
const dbquery = this.queries.fetchAllQuery
|
||||
|
||||
dbQuery = dbquery.split('').map((char) => char === '?' ? dbParams.shift() : char).join('')
|
||||
}
|
||||
else if (by !== undefined && filter !== undefined) {
|
||||
const paramToColumnAndValue = {
|
||||
movie: ['type', 'movie'],
|
||||
show: ['type', 'show']
|
||||
}
|
||||
const dbParams = paramToColumnAndValue[filter].concat([by, direction]);
|
||||
const query = this.queries.fetchAllFilterAndSort;
|
||||
|
||||
dbQuery = query.split('').map((char) => char === '?' ? dbParams.shift() : char).join('')
|
||||
}
|
||||
else if (by !== undefined) {
|
||||
const dbParams = [by, direction];
|
||||
const query = this.queries.fetchAllSort;
|
||||
|
||||
dbQuery = query.split('').map((char) => char === '?' ? dbParams.shift() : char).join('')
|
||||
}
|
||||
else if (filter !== undefined) {
|
||||
const paramToColumnAndValue = {
|
||||
movie: ['type', 'movie'],
|
||||
show: ['type', 'show'],
|
||||
downloaded: [this.queries.downloaded, 'downloaded']
|
||||
// downloading: [this.database.delugeStatus, 'downloading']
|
||||
}
|
||||
const dbParams = paramToColumnAndValue[filter]
|
||||
const query = this.queries.fetchAllFilter;
|
||||
|
||||
dbQuery = query.split('').map((char) => char === '?' ? dbParams.shift() : char).join('')
|
||||
}
|
||||
else {
|
||||
dbQuery = this.queries.fetchAll;
|
||||
}
|
||||
|
||||
return dbQuery
|
||||
}
|
||||
|
||||
mapToTmdbByType(rows) {
|
||||
return rows.map((row) => {
|
||||
if (row.type === 'movie')
|
||||
return tmdb.movieInfo(row.id)
|
||||
else if (row.type === 'show')
|
||||
return tmdb.showInfo(row.id)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Add tmdb movie|show to requests
|
||||
* @param {tmdb} tmdb class of movie|show to add
|
||||
* @returns {Promise}
|
||||
*/
|
||||
requestFromTmdb(tmdb, ip, user_agent, user) {
|
||||
return Promise.resolve()
|
||||
.then(() => this.database.get(this.queries.read, [tmdb.id, tmdb.type]))
|
||||
.then(row => assert.equal(row, undefined, 'Id has already been requested'))
|
||||
.then(() => this.database.run(this.queries.add, [tmdb.id, tmdb.title, tmdb.year, tmdb.poster, tmdb.backdrop, user, 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);
|
||||
throw new Error('Could not add request');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get request item by id
|
||||
* @param {String} id
|
||||
* @param {String} type
|
||||
* @returns {Promise}
|
||||
*/
|
||||
getRequestByIdAndType(id, type) {
|
||||
return Promise.resolve()
|
||||
.then(() => this.database.get(this.queries.read, [id, type]))
|
||||
.then(row => {
|
||||
assert(row, 'Could not find request item with that id and type')
|
||||
return JSON.stringify(row)
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all requests with optional sort and filter params
|
||||
* @param {String} what we are sorting by
|
||||
* @param {String} direction that can be either 'asc' or 'desc', default 'asc'.
|
||||
* @param {String} params to filter by
|
||||
* @param {String} query param to filter result on. Filters on title and year
|
||||
* @returns {Promise}
|
||||
*/
|
||||
fetchAll(page=1, sort_by=undefined, sort_direction='asc', filter=undefined, query=undefined) {
|
||||
// TODO implemented sort and filter
|
||||
let fetchQuery = this.queries.fetchAll
|
||||
let fetchTotalResults = this.queries.totalRequests
|
||||
let fetchParams = [page]
|
||||
|
||||
if (filter && (filter === 'downloading' || filter === 'downloaded' || filter === 'requested')) {
|
||||
console.log('tes')
|
||||
fetchQuery = this.queries.fetchAllFilteredStatus
|
||||
fetchTotalResults = this.queries.totalRequestsFilteredStatus
|
||||
fetchParams = [filter, page]
|
||||
} else {
|
||||
filter = undefined
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
.then((dbQuery) => this.database.all(fetchQuery, fetchParams))
|
||||
.then(async (rows) => {
|
||||
const sqliteResponse = await this.database.get(fetchTotalResults, filter ? filter : undefined)
|
||||
const totalRequests = sqliteResponse['totalRequests']
|
||||
const totalPages = Math.ceil(totalRequests / 26)
|
||||
|
||||
return [ rows.map(item => { item.poster = item.poster_path; return item }), totalPages ]
|
||||
return Promise.all(this.mapToTmdbByType(rows))
|
||||
})
|
||||
.then(([result, totalPages]) => Promise.resolve({
|
||||
results: result, total_results: result.length, page: page, total_pages: totalPages
|
||||
}))
|
||||
.catch(error => { console.log(error);throw error })
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = RequestRepository;
|
||||
34
seasoned_api/src/request/utils.js
Normal file
34
seasoned_api/src/request/utils.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// TODO : test title and date are valid matches to columns in the database
|
||||
const validSortParams = ['title', 'date']
|
||||
const validSortDirs = ['asc', 'desc']
|
||||
const validFilterParams = ['movie', 'show', 'seeding', 'downloading', 'paused', 'finished', 'downloaded']
|
||||
|
||||
function validSort(by, direction) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (by === undefined) {
|
||||
resolve()
|
||||
}
|
||||
|
||||
if (validSortParams.includes(by) && validSortDirs.includes(direction)) {
|
||||
resolve()
|
||||
} else {
|
||||
reject(new Error(`invalid sort parameter, must be of: ${validSortParams} with optional sort directions: ${validSortDirs} appended with ':'`))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function validFilter(filter_param) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (filter_param === undefined) {
|
||||
resolve()
|
||||
}
|
||||
|
||||
if (filter_param && validFilterParams.includes(filter_param)) {
|
||||
resolve()
|
||||
} else {
|
||||
reject(new Error(`filter parameteres must be of type: ${validFilterParams}`))
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { validSort, validFilter }
|
||||
49
seasoned_api/src/tmdb/convertTmdbToMovie.js
Normal file
49
seasoned_api/src/tmdb/convertTmdbToMovie.js
Normal file
@@ -0,0 +1,49 @@
|
||||
const Movie = require('src/tmdb/types/movie');
|
||||
|
||||
const tmdbSwitcher = (tmdbMovie, property) => tmdbMovie[property]
|
||||
|
||||
function convertTmdbToMovie(tmdbMovie, credits=undefined) {
|
||||
const movie = new Movie(tmdbMovie.id, tmdbMovie.title)
|
||||
movie.overview = tmdbMovie.overview;
|
||||
movie.rank = tmdbMovie.vote_average;
|
||||
|
||||
if (credits) {
|
||||
movie.credits = credits;
|
||||
}
|
||||
|
||||
if (tmdbMovie.release_date !== undefined) {
|
||||
movie.release_date = new Date(tmdbMovie.release_date);
|
||||
movie.year = movie.release_date.getFullYear();
|
||||
}
|
||||
|
||||
if (tmdbMovie.poster_path !== undefined) {
|
||||
movie.poster = tmdbMovie.poster_path;
|
||||
}
|
||||
if (tmdbMovie.backdrop_path !== undefined) {
|
||||
movie.backdrop = tmdbMovie.backdrop_path;
|
||||
}
|
||||
|
||||
if (tmdbMovie.status !== undefined) {
|
||||
movie.status = tmdbMovie.status;
|
||||
}
|
||||
|
||||
if (tmdbMovie.genres !== undefined) {
|
||||
movie.genres = tmdbMovie.genres.map(genre => genre.name);
|
||||
}
|
||||
|
||||
if (tmdbMovie.tagline !== undefined) {
|
||||
movie.tagline = tmdbMovie.tagline;
|
||||
}
|
||||
|
||||
if (tmdbMovie.runtime !== undefined) {
|
||||
movie.runtime = tmdbMovie.runtime;
|
||||
}
|
||||
|
||||
if (tmdbMovie.imdb_id !== undefined) {
|
||||
movie.imdb_id = tmdbMovie.imdb_id;
|
||||
}
|
||||
|
||||
return movie;
|
||||
}
|
||||
|
||||
module.exports = convertTmdbToMovie;
|
||||
30
seasoned_api/src/tmdb/convertTmdbToPerson.js
Normal file
30
seasoned_api/src/tmdb/convertTmdbToPerson.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const Person = require('src/tmdb/types/person');
|
||||
const convertTmdbToMovie = require('src/tmdb/convertTmdbToMovie');
|
||||
|
||||
function convertTmdbToPerson(tmdbPerson, cast=undefined) {
|
||||
const person = new Person(tmdbPerson.id, tmdbPerson.name);
|
||||
|
||||
if (tmdbPerson.profile_path !== undefined) {
|
||||
person.poster = tmdbPerson.profile_path;
|
||||
}
|
||||
|
||||
if (tmdbPerson.birthday !== undefined) {
|
||||
person.birthday = new Date(tmdbPerson.birthday);
|
||||
}
|
||||
|
||||
if (tmdbPerson.deathday !== undefined) {
|
||||
person.deathday = tmdbPerson.deathday;
|
||||
}
|
||||
|
||||
if (tmdbPerson.known_for !== undefined) {
|
||||
person.known_for = tmdbPerson.known_for.map(convertTmdbToMovie);
|
||||
}
|
||||
|
||||
if (cast) {
|
||||
person.cast = cast.cast;
|
||||
}
|
||||
|
||||
return person;
|
||||
}
|
||||
|
||||
module.exports = convertTmdbToPerson;
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
const TMDB = require('src/media_classes/tmdb');
|
||||
const Movie = require('src/types/movie');
|
||||
|
||||
function translateYear(tmdbReleaseDate) {
|
||||
return new Date(tmdbReleaseDate).getFullYear();
|
||||
@@ -14,10 +14,28 @@ function convertType(tmdbType) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function convertTmdbToSeasoned(tmdb, manualType = undefined) {
|
||||
function convertTmdbToMovie(tmdb) {
|
||||
const year =
|
||||
const movie = new Movie();
|
||||
let seasoned = undefined;
|
||||
|
||||
if (tmdb.id && tmdb.title && tmdb.release_date) {
|
||||
const year = tmdb.release_date.getFullYear();
|
||||
seasoned = new Movie(tmdb.id, tmdb.title, year);
|
||||
}
|
||||
else if (tmdb.id && tmdb.name && tmdb.first_air_date) {
|
||||
const year = tmdb.first_air_date.getFullYear();
|
||||
seasoned = new Show(tmdb.id, tmdb.name, year);
|
||||
seasoned.seasons = tmdb.number_of_season;
|
||||
seasoned.episodes = tmdb.episodes;
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const title = tmdb.title || tmdb.name;
|
||||
const year = translateYear(tmdb.release_date || tmdb.first_air_date);
|
||||
const type = manualType || convertType(tmdb.media_type) || 'movie';
|
||||
const type = manualType || convertType(tmdb.type) || 'movie';
|
||||
|
||||
const id = tmdb.id;
|
||||
const summary = tmdb.overview;
|
||||
|
||||
41
seasoned_api/src/tmdb/convertTmdbToShow.js
Normal file
41
seasoned_api/src/tmdb/convertTmdbToShow.js
Normal file
@@ -0,0 +1,41 @@
|
||||
const Show = require('src/tmdb/types/show');
|
||||
|
||||
function convertTmdbToShow(tmdbShow, credits=undefined) {
|
||||
const show = new Show(tmdbShow.id, tmdbShow.name)
|
||||
show.seasons = tmdbShow.number_of_seasons;
|
||||
show.episodes = tmdbShow.number_of_episodes;
|
||||
show.overview = tmdbShow.overview;
|
||||
show.rank = tmdbShow.vote_average;
|
||||
|
||||
if (credits) {
|
||||
show.credits = credits
|
||||
}
|
||||
|
||||
if (tmdbShow.genres !== undefined) {
|
||||
show.genres = tmdbShow.genres.map(genre => genre.name);
|
||||
}
|
||||
|
||||
if (tmdbShow.first_air_date !== undefined) {
|
||||
show.first_air_date = new Date(tmdbShow.first_air_date);
|
||||
show.year = show.first_air_date.getFullYear();
|
||||
}
|
||||
|
||||
if (tmdbShow.poster_path !== undefined) {
|
||||
show.poster = tmdbShow.poster_path;
|
||||
}
|
||||
if (tmdbShow.backdrop_path !== undefined) {
|
||||
show.backdrop = tmdbShow.backdrop_path;
|
||||
}
|
||||
|
||||
if (tmdbShow.status !== undefined) {
|
||||
show.status = tmdbShow.status;
|
||||
}
|
||||
|
||||
if (tmdbShow.episode_run_time !== undefined) {
|
||||
show.runtime = tmdbShow.runtime;
|
||||
}
|
||||
|
||||
return show;
|
||||
}
|
||||
|
||||
module.exports = convertTmdbToShow;
|
||||
@@ -1,28 +1,27 @@
|
||||
const moviedb = require('moviedb');
|
||||
const convertTmdbToSeasoned = require('src/tmdb/convertTmdbToSeasoned');
|
||||
|
||||
const TMDB_METHODS = {
|
||||
upcoming: { movie: 'miscUpcomingMovies' },
|
||||
discover: { movie: 'discoverMovie', show: 'discoverTv' },
|
||||
popular: { movie: 'miscPopularMovies', show: 'miscPopularTvs' },
|
||||
nowplaying: { movie: 'miscNowPlayingMovies', show: 'tvOnTheAir' },
|
||||
similar: { movie: 'movieSimilar', show: 'tvSimilar' },
|
||||
search: { movie: 'searchMovie', show: 'searchTv', multi: 'searchMulti' },
|
||||
info: { movie: 'movieInfo', show: 'tvInfo' }
|
||||
};
|
||||
const moviedb = require('km-moviedb');
|
||||
const convertTmdbToMovie = require('src/tmdb/convertTmdbToMovie');
|
||||
const convertTmdbToShow = require('src/tmdb/convertTmdbToShow');
|
||||
const convertTmdbToPerson = require('src/tmdb/convertTmdbToPerson');
|
||||
|
||||
class TMDB {
|
||||
constructor(cache, apiKey, tmdbLibrary) {
|
||||
this.cache = cache;
|
||||
this.tmdbLibrary = tmdbLibrary || moviedb(apiKey);
|
||||
this.cacheTags = {
|
||||
search: 'se',
|
||||
info: 'i',
|
||||
upcoming: 'u',
|
||||
discover: 'd',
|
||||
popular: 'p',
|
||||
nowplaying: 'n',
|
||||
similar: 'si',
|
||||
multiSearch: 'mus',
|
||||
movieSearch: 'mos',
|
||||
showSearch: 'ss',
|
||||
personSearch: 'ps',
|
||||
movieInfo: 'mi',
|
||||
showInfo: 'si',
|
||||
personInfo: 'pi',
|
||||
miscNowPlayingMovies: 'npm',
|
||||
miscPopularMovies: 'pm',
|
||||
miscTopRatedMovies: 'tpm',
|
||||
miscUpcomingMovies: 'um',
|
||||
tvOnTheAir: 'toa',
|
||||
miscPopularTvs: 'pt',
|
||||
miscTopRatedTvs: 'trt',
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,7 +39,7 @@ class TMDB {
|
||||
.catch(() => this.tmdb(TMDB_METHODS['info'][type], query))
|
||||
.catch(() => { throw new Error('Could not find a movie with that id.'); })
|
||||
.then(response => this.cache.set(cacheKey, response))
|
||||
.then((response) => {
|
||||
.then(response => {
|
||||
try {
|
||||
return convertTmdbToSeasoned(response, type);
|
||||
} catch (parseError) {
|
||||
@@ -68,6 +67,174 @@ class TMDB {
|
||||
.then(response => this.mapResults(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a specific movie by id from TMDB.
|
||||
* @param {Number} identifier of the movie you want to retrieve
|
||||
* @param {String} type filter results by type (default movie).
|
||||
* @returns {Promise} succeeds if movie was found
|
||||
*/
|
||||
movieInfo(identifier, credits=false) {
|
||||
const query = { id: identifier };
|
||||
const cacheKey = `${this.cacheTags.movieInfo}:${identifier}:${credits}`;
|
||||
|
||||
const requests = [this.tmdb('movieInfo', query)]
|
||||
|
||||
if (credits) {
|
||||
requests.push(this.tmdb('movieCredits', query))
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => this.cache.get(cacheKey))
|
||||
.catch(() => Promise.all(requests))
|
||||
.catch((error) => { console.log(error); throw new Error('Could not find a movie with that id.'); })
|
||||
.then(([movies, credits]) => this.cache.set(cacheKey, [movies, credits]))
|
||||
.then(([movies, credits]) => convertTmdbToMovie(movies, credits))
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a specific show by id from TMDB.
|
||||
* @param {Number} identifier of the show you want to retrieve
|
||||
* @param {String} type filter results by type (default show).
|
||||
* @returns {Promise} succeeds if show was found
|
||||
*/
|
||||
showInfo(identifier, credits=false) {
|
||||
const query = { id: identifier };
|
||||
const cacheKey = `${this.cacheTags.showInfo}:${identifier}:${credits}`;
|
||||
|
||||
const requests = [this.tmdb('tvInfo', query)]
|
||||
|
||||
if (credits) {
|
||||
requests.push(this.tmdb('tvCredits', query))
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => this.cache.get(cacheKey))
|
||||
.catch(() => Promise.all(requests))
|
||||
.catch(() => { throw new Error('Could not find a show with that id.'); })
|
||||
.then(([shows, credits]) => this.cache.set(cacheKey, [shows, credits]))
|
||||
.then(([shows, credits]) => convertTmdbToShow(shows, credits))
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a specific person id from TMDB.
|
||||
* @param {Number} identifier of the person you want to retrieve
|
||||
* @param {String} type filter results by type (default person).
|
||||
* @returns {Promise} succeeds if person was found
|
||||
*/
|
||||
personInfo(identifier) {
|
||||
const query = { id: identifier };
|
||||
const cacheKey = `${this.cacheTags.personInfo}:${identifier}`;
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => this.cache.get(cacheKey))
|
||||
.catch(() => Promise.all([this.tmdb('personInfo', query), this.tmdb('personCombinedCredits', query)]))
|
||||
.catch(() => { throw new Error('Could not find a person with that id.'); })
|
||||
.then(([person, cast]) => this.cache.set(cacheKey, [person, cast]))
|
||||
.then(([person, cast]) => convertTmdbToPerson(person, cast))
|
||||
.catch(err => new Error('Unable to convert result to person', err))
|
||||
}
|
||||
|
||||
|
||||
|
||||
multiSearch(search_query, page=1) {
|
||||
const query = { query: search_query, page: page };
|
||||
const cacheKey = `${this.cacheTags.multiSearch}:${page}:${search_query}`;
|
||||
return Promise.resolve()
|
||||
.then(() => this.cache.get(cacheKey))
|
||||
.catch(() => this.tmdb('searchMulti', query))
|
||||
.catch(() => { throw new Error('Could not complete search to tmdb'); })
|
||||
.then(response => this.cache.set(cacheKey, response))
|
||||
.then(response => this.mapResults(response));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive movie search results from TMDB.
|
||||
* @param {String} text query you want to search for
|
||||
* @param {Number} page representing pagination of results
|
||||
* @returns {Promise} dict with query results, current page and total_pages
|
||||
*/
|
||||
movieSearch(query, page=1) {
|
||||
const tmdbquery = { query: query, page: page };
|
||||
const cacheKey = `${this.cacheTags.movieSearch}:${page}:${query}`;
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => this.cache.get(cacheKey))
|
||||
.catch(() => this.tmdb('searchMovie', tmdbquery))
|
||||
.catch(() => { throw new Error('Could not complete movie search to tmdb'); })
|
||||
.then(response => this.cache.set(cacheKey, response))
|
||||
.then(response => this.mapAndCreateResponse(response, convertTmdbToMovie))
|
||||
.catch((error) => { console.log(error); throw new Error('Could not parse movie search result') })
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive show search results from TMDB.
|
||||
* @param {String} text query you want to search for
|
||||
* @param {Number} page representing pagination of results
|
||||
* @returns {Promise} dict with query results, current page and total_pages
|
||||
*/
|
||||
showSearch(query, page=1) {
|
||||
const tmdbquery = { query: query, page: page };
|
||||
const cacheKey = `${this.cacheTags.showSearch}:${page}:${query}`;
|
||||
return Promise.resolve()
|
||||
.then(() => this.cache.get(cacheKey))
|
||||
.catch(() => this.tmdb('searchTv', tmdbquery))
|
||||
.catch(() => { throw new Error('Could not complete show search to tmdb'); })
|
||||
.then(response => this.cache.set(cacheKey, response))
|
||||
.then(response => this.mapAndCreateResponse(response, convertTmdbToShow))
|
||||
.catch((error) => { console.log(error); throw new Error('Could not parse show search result') })
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrive person search results from TMDB.
|
||||
* @param {String} text query you want to search for
|
||||
* @param {Number} page representing pagination of results
|
||||
* @returns {Promise} dict with query results, current page and total_pages
|
||||
*/
|
||||
personSearch(query, page=1) {
|
||||
const tmdbquery = { query: query, page: page };
|
||||
const cacheKey = `${this.cacheTags.personSearch}:${page}:${query}`;
|
||||
return Promise.resolve()
|
||||
.then(() => this.cache.get(cacheKey))
|
||||
.catch(() => this.tmdb('searchPerson', tmdbquery))
|
||||
.catch(() => { throw new Error('Could not complete person search to tmdb'); })
|
||||
.then(response => this.cache.set(cacheKey, response))
|
||||
.then(response => this.mapAndCreateResponse(response, convertTmdbToPerson))
|
||||
.catch((error) => { console.log(error); throw new Error('Could not parse person search result') })
|
||||
}
|
||||
|
||||
mapAndCreateResponse(response, resultConvertFunction) {
|
||||
// console.log(response)
|
||||
return {
|
||||
results: response.results.map(resultConvertFunction),
|
||||
page: response.page,
|
||||
total_results: response.total_results,
|
||||
total_pages: response.total_pages
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
movieList(listname, page = 1) {
|
||||
const query = { page: page };
|
||||
const cacheKey = `${this.cacheTags[listname]}:${page}`;
|
||||
return Promise.resolve()
|
||||
.then(() => this.cache.get(cacheKey))
|
||||
.catch(() => this.tmdb(listname, query))
|
||||
.catch(() => { throw new Error('Unable to get movie list from tmdb')})
|
||||
.then(response => this.cache.set(cacheKey, response))
|
||||
.then(response => this.mapAndCreateResponse(response, convertTmdbToMovie));
|
||||
}
|
||||
|
||||
showList(listname, page = 1) {
|
||||
const query = { page: page };
|
||||
const cacheKey = `${this.cacheTags[listname]}:${page}`;
|
||||
return Promise.resolve()
|
||||
.then(() => this.cache.get(cacheKey))
|
||||
.catch(() => this.tmdb(listname, query))
|
||||
.catch(() => { throw new Error('Unable to get show list from tmdb')})
|
||||
.then(response => this.cache.set(cacheKey, response))
|
||||
.then(response => this.mapAndCreateResponse(response, convertTmdbToShow));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches a given list from tmdb.
|
||||
* @param {String} listName Name of list
|
||||
@@ -87,27 +254,40 @@ class TMDB {
|
||||
.then(response => this.mapResults(response, type));
|
||||
}
|
||||
|
||||
popular(type='movie', page=1) {
|
||||
const query = { type: type, page: page };
|
||||
const cacheKey = `${this.cacheTags.popular}:${type}:${page}`;
|
||||
return Promise.resolve()
|
||||
.then(() => this.cache.get(cacheKey))
|
||||
.catch(() => this.tmdb('miscPopularMovies', query))
|
||||
.catch((e) => { throw new Error(`Error fetching popular list of type ${type} : ${e}`) })
|
||||
.then(response => this.cache.set(cacheKey, response))
|
||||
.then(response => this.mapResults(response, type));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps our response from tmdb api to a movie/show object.
|
||||
* @param {String} response from tmdb.
|
||||
* @param {String} The type declared in listSearch.
|
||||
* @returns {Promise} dict with tmdb results, mapped as movie/show objects.
|
||||
*/
|
||||
mapResults(response, type) {
|
||||
console.log(response.page);
|
||||
return Promise.resolve()
|
||||
.then(() => {
|
||||
const mappedResults = response.results.filter((element) => {
|
||||
return (element.media_type === 'movie' || element.media_type === 'tv' || element.media_type === undefined);
|
||||
}).map((element) => convertTmdbToSeasoned(element, type));
|
||||
return {
|
||||
results: mappedResults,
|
||||
page: response.page,
|
||||
total_pages: response.total_pages,
|
||||
total_results: response.total_results
|
||||
mapResults(response, _) {
|
||||
let results = response.results.map((result) => {
|
||||
if (result.media_type === 'movie') {
|
||||
return convertTmdbToMovie(result);
|
||||
} else if (result.media_type === 'tv') {
|
||||
return convertTmdbToShow(result);
|
||||
} else if (result.media_type === 'person') {
|
||||
return convertTmdbToPerson(result);
|
||||
}
|
||||
})
|
||||
.catch((error) => { throw new Error(error); });
|
||||
|
||||
return {
|
||||
results: results,
|
||||
page: response.page,
|
||||
total_results: response.total_results,
|
||||
total_pages: response.total_pages
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,7 +302,7 @@ class TMDB {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
return resolve(reponse);
|
||||
resolve(reponse);
|
||||
};
|
||||
|
||||
if (!argument) {
|
||||
|
||||
20
seasoned_api/src/tmdb/types/movie.js
Normal file
20
seasoned_api/src/tmdb/types/movie.js
Normal file
@@ -0,0 +1,20 @@
|
||||
class Movie {
|
||||
constructor(id, title, year=null, overview=null, poster=null, backdrop=null, rank=null, genres=null, status=null,
|
||||
tagline=null, runtime=null, imdb_id=null) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.year = year;
|
||||
this.overview = overview;
|
||||
this.poster = poster;
|
||||
this.backdrop = backdrop;
|
||||
this.rank = rank;
|
||||
this.genres = genres;
|
||||
this.status = status;
|
||||
this.tagline = tagline;
|
||||
this.runtime = runtime;
|
||||
this.imdb_id = imdb_id;
|
||||
this.type = 'movie';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Movie;
|
||||
13
seasoned_api/src/tmdb/types/person.js
Normal file
13
seasoned_api/src/tmdb/types/person.js
Normal file
@@ -0,0 +1,13 @@
|
||||
class Person {
|
||||
constructor(id, name, poster=null, birthday=null, deathday=null, known_for=null) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
this.poster = poster;
|
||||
this.birthday = birthday;
|
||||
this.deathday = deathday;
|
||||
this.known_for = known_for;
|
||||
this.type = 'person';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Person;
|
||||
20
seasoned_api/src/tmdb/types/show.js
Normal file
20
seasoned_api/src/tmdb/types/show.js
Normal file
@@ -0,0 +1,20 @@
|
||||
class Show {
|
||||
constructor(id, title, year=null, seasons=null, episodes=null, overview=null, rank=null, genres=null,
|
||||
poster=null, backdrop=null, status=null, runtime=null) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
this.year = year;
|
||||
this.seasons = seasons;
|
||||
this.episodes = episodes;
|
||||
this.overview = overview;
|
||||
this.rank = rank;
|
||||
this.genres = genres;
|
||||
this.poster = poster;
|
||||
this.backdrop = backdrop;
|
||||
this.status = status;
|
||||
this.runtime = runtime;
|
||||
this.type = 'show';
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Show;
|
||||
@@ -6,16 +6,14 @@ const mustBeAuthenticated = require('./middleware/mustBeAuthenticated');
|
||||
const mustBeAdmin = require('./middleware/mustBeAdmin');
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
|
||||
const listController = require('./controllers/list/listController');
|
||||
|
||||
// TODO: Have our raven router check if there is a value, if not don't enable raven.
|
||||
Raven.config(configuration.get('raven', 'DSN')).install();
|
||||
|
||||
const app = express(); // define our app using express
|
||||
app.use(Raven.requestHandler());
|
||||
// this will let us get the data from a POST
|
||||
// configure app to use bodyParser()
|
||||
app.use(bodyParser.json());
|
||||
// router.use(bodyParser.urlencoded({ extended: true }));
|
||||
|
||||
|
||||
const router = express.Router();
|
||||
const allowedOrigins = ['https://kevinmidboe.com', 'http://localhost:8080'];
|
||||
@@ -31,9 +29,9 @@ router.use(tokenToUser);
|
||||
router.use((req, res, next) => {
|
||||
// TODO add logging of all incoming
|
||||
console.log('Request: ', req.originalUrl);
|
||||
|
||||
const origin = req.headers.origin;
|
||||
if (allowedOrigins.indexOf(origin) > -1) {
|
||||
console.log('allowed');
|
||||
res.setHeader('Access-Control-Allow-Origin', origin);
|
||||
}
|
||||
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, loggedinuser');
|
||||
@@ -67,19 +65,45 @@ router.get('/v1/seasoned/all', require('./controllers/seasoned/readStrays.js'));
|
||||
router.get('/v1/seasoned/:strayId', require('./controllers/seasoned/strayById.js'));
|
||||
router.post('/v1/seasoned/verify/:strayId', require('./controllers/seasoned/verifyStray.js'));
|
||||
|
||||
router.get('/v2/search/', require('./controllers/search/multiSearch.js'));
|
||||
router.get('/v2/search/movie', require('./controllers/search/movieSearch.js'));
|
||||
router.get('/v2/search/show', require('./controllers/search/showSearch.js'));
|
||||
router.get('/v2/search/person', require('./controllers/search/personSearch.js'));
|
||||
|
||||
router.get('/v2/movie/now_playing', listController.nowPlayingMovies);
|
||||
router.get('/v2/movie/popular', listController.popularMovies);
|
||||
router.get('/v2/movie/top_rated', listController.topRatedMovies);
|
||||
router.get('/v2/movie/upcoming', listController.upcomingMovies);
|
||||
|
||||
router.get('/v2/show/now_playing', listController.nowPlayingShows);
|
||||
router.get('/v2/show/popular', listController.popularShows);
|
||||
router.get('/v2/show/top_rated', listController.topRatedShows);
|
||||
|
||||
router.get('/v2/movie/:id', require('./controllers/info/movieInfo.js'));
|
||||
router.get('/v2/show/:id', require('./controllers/info/showInfo.js'));
|
||||
router.get('/v2/person/:id', require('./controllers/info/personInfo.js'));
|
||||
/**
|
||||
* Plex
|
||||
*/
|
||||
router.get('/v2/plex/search', require('./controllers/plex/search'));
|
||||
|
||||
/**
|
||||
* List
|
||||
*/
|
||||
router.get('/v1/plex/search', require('./controllers/plex/searchMedia.js'));
|
||||
router.get('/v1/plex/playing', require('./controllers/plex/plexPlaying.js'));
|
||||
router.get('/v1/plex/request', require('./controllers/plex/searchRequest.js'));
|
||||
router.get('/v1/plex/request/:mediaId', require('./controllers/plex/readRequest.js'));
|
||||
router.post('/v1/plex/request/:mediaId', require('./controllers/plex/submitRequest.js'));
|
||||
router.get('/v1/plex/hook', require('./controllers/plex/hookDump.js'));
|
||||
router.post('/v1/plex/hook', require('./controllers/plex/hookDump.js'));
|
||||
|
||||
/**
|
||||
* Requests
|
||||
*/
|
||||
|
||||
router.get('/v2/request', require('./controllers/request/fetchAllRequests.js'));
|
||||
router.get('/v2/request/:id', require('./controllers/request/getRequest.js'));
|
||||
router.post('/v2/request', require('./controllers/request/requestTmdbId.js'));
|
||||
router.get('/v1/plex/requests/all', require('./controllers/plex/fetchRequested.js'));
|
||||
router.put('/v1/plex/request/:requestId', mustBeAuthenticated, require('./controllers/plex/updateRequested.js'));
|
||||
|
||||
|
||||
30
seasoned_api/src/webserver/controllers/info/movieInfo.js
Normal file
30
seasoned_api/src/webserver/controllers/info/movieInfo.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const Plex = require('src/plex/plex');
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
const plex = new Plex(configuration.get('plex', 'ip'));
|
||||
|
||||
/**
|
||||
* Controller: Retrieve information for a movie
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
async function movieInfoController(req, res) {
|
||||
const movieId = req.params.id;
|
||||
const { credits } = req.query;
|
||||
const movie = await tmdb.movieInfo(movieId, credits);
|
||||
|
||||
plex.existsInPlex(movie)
|
||||
.catch((error) => { console.log('Error when searching plex'); })
|
||||
.then(() => {
|
||||
console.log('movie', movie)
|
||||
res.send(movie);
|
||||
}).catch((error) => {
|
||||
res.status(404).send({ success: false, error: error.message });
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = movieInfoController;
|
||||
24
seasoned_api/src/webserver/controllers/info/personInfo.js
Normal file
24
seasoned_api/src/webserver/controllers/info/personInfo.js
Normal file
@@ -0,0 +1,24 @@
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
|
||||
/**
|
||||
* Controller: Retrieve information for a person
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
|
||||
function personInfoController(req, res) {
|
||||
const personId = req.params.id;
|
||||
tmdb.personInfo(personId)
|
||||
.then((person) => {
|
||||
res.send(person);
|
||||
}).catch((error) => {
|
||||
res.status(404).send({ success: false, error: error.message });
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = personInfoController;
|
||||
31
seasoned_api/src/webserver/controllers/info/showInfo.js
Normal file
31
seasoned_api/src/webserver/controllers/info/showInfo.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const Plex = require('src/plex/plex');
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
const plex = new Plex(configuration.get('plex', 'ip'));
|
||||
|
||||
/**
|
||||
* Controller: Retrieve information for a show
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
|
||||
async function showInfoController(req, res) {
|
||||
const showId = req.params.id;
|
||||
const { credits } = req.query;
|
||||
const show = await tmdb.showInfo(showId, credits);
|
||||
|
||||
plex.existsInPlex(show)
|
||||
.catch((error) => { console.log('Error when searching plex'); })
|
||||
.then(() => {
|
||||
console.log('show', show)
|
||||
res.send(show);
|
||||
}).catch((error) => {
|
||||
res.status(404).send({ success: false, error: error.message });
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = showInfoController;
|
||||
@@ -0,0 +1,85 @@
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
|
||||
// there should be a translate function from query params to
|
||||
// tmdb list that is valid. Should it be a helper function or does it
|
||||
// belong in tmdb.
|
||||
// + could also have default value that are sent to the client.
|
||||
// * have the same class create a getListNames() and a fetchList()
|
||||
// * dicover list might be overkill_https://tinyurl.com/y7f8ragw
|
||||
// + trending! https://tinyurl.com/ydywrqox
|
||||
// by all, mediatype, or person. Can also define time periode to
|
||||
// get more trending view of what people are checking out.
|
||||
// + newly created (tv/latest).
|
||||
// + movie/latest
|
||||
//
|
||||
|
||||
function getTmdbMovieList(res, listname, page) {
|
||||
Promise.resolve()
|
||||
.then(() => tmdb.movieList(listname, page))
|
||||
.then((response) => res.send(response))
|
||||
.catch((error) => {
|
||||
res.status(500).send({ success: false, error: error.message });
|
||||
})
|
||||
}
|
||||
|
||||
function getTmdbShowList(res, listname, page) {
|
||||
Promise.resolve()
|
||||
.then(() => tmdb.showList(listname, page))
|
||||
.then((response) => res.send(response))
|
||||
.catch((error) => {
|
||||
res.status(500).send({ success: false, error: error.message });
|
||||
})
|
||||
}
|
||||
|
||||
exports.nowPlayingMovies = (req, res) => {
|
||||
const { page } = req.query;
|
||||
const listname = 'miscNowPlayingMovies'
|
||||
|
||||
getTmdbMovieList(res, listname, page);
|
||||
}
|
||||
|
||||
exports.popularMovies = (req, res) => {
|
||||
const { page } = req.query;
|
||||
const listname = 'miscPopularMovies'
|
||||
|
||||
getTmdbMovieList(res, listname, page);
|
||||
}
|
||||
|
||||
exports.topRatedMovies = (req, res) => {
|
||||
const { page } = req.query;
|
||||
const listname = 'miscTopRatedMovies'
|
||||
|
||||
getTmdbMovieList(res, listname, page);
|
||||
}
|
||||
|
||||
exports.upcomingMovies = (req, res) => {
|
||||
const { page } = req.query;
|
||||
const listname = 'miscUpcomingMovies'
|
||||
|
||||
getTmdbMovieList(res, listname, page);
|
||||
}
|
||||
|
||||
exports.nowPlayingShows = (req, res) => {
|
||||
const { page } = req.query;
|
||||
const listname = 'tvOnTheAir'
|
||||
|
||||
getTmdbShowList(res, listname, page);
|
||||
}
|
||||
|
||||
exports.popularShows = (req, res) => {
|
||||
const { page } = req.query;
|
||||
const listname = 'miscPopularTvs'
|
||||
|
||||
getTmdbShowList(res, listname, page);
|
||||
}
|
||||
|
||||
exports.topRatedShows = (req, res) => {
|
||||
const { page } = req.query;
|
||||
const listname = 'miscTopRatedTvs'
|
||||
|
||||
getTmdbShowList(res, listname, page);
|
||||
}
|
||||
@@ -10,8 +10,10 @@ const PirateRepository = require('src/pirate/pirateRepository');
|
||||
|
||||
function addMagnet(req, res) {
|
||||
const magnet = req.body.magnet;
|
||||
const name = req.body.name;
|
||||
const tmdb_id = req.body.tmdb_id;
|
||||
|
||||
PirateRepository.AddMagnet(magnet)
|
||||
PirateRepository.AddMagnet(magnet, name, tmdb_id)
|
||||
.then((result) => {
|
||||
res.send(result);
|
||||
})
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const PlexRepository = require('src/plex/plexRepository');
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
|
||||
const plexRepository = new PlexRepository();
|
||||
const plexRepository = new PlexRepository(configuration.get('plex', 'ip'));
|
||||
|
||||
function playingController(req, res) {
|
||||
plexRepository.nowPlaying()
|
||||
|
||||
25
seasoned_api/src/webserver/controllers/plex/search.js
Normal file
25
seasoned_api/src/webserver/controllers/plex/search.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Plex = require('src/plex/plex');
|
||||
const plex = new Plex(configuration.get('plex', 'ip'));
|
||||
|
||||
/**
|
||||
* Controller: Search plex for movies, shows and episodes by query
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
function searchPlexController(req, res) {
|
||||
const { query, type } = req.query;
|
||||
plex.search(query, type)
|
||||
.then((movies) => {
|
||||
if (movies.length > 0) {
|
||||
res.send(movies);
|
||||
} else {
|
||||
res.status(404).send({ success: false, error: 'Search query did not give any results from plex.'})
|
||||
}
|
||||
}).catch((error) => {
|
||||
res.status(500).send({ success: false, error: error.message });
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = searchPlexController;
|
||||
@@ -1,6 +1,7 @@
|
||||
const PlexRepository = require('src/plex/plexRepository');
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
|
||||
const plexRepository = new PlexRepository();
|
||||
const plexRepository = new PlexRepository(configuration.get('plex', 'ip'));
|
||||
|
||||
/**
|
||||
* Controller: Search for media and check existence
|
||||
|
||||
@@ -1,6 +1,19 @@
|
||||
const RequestRepository = require('src/plex/requestRepository.js');
|
||||
const configuration = require('src/config/configuration').getInstance()
|
||||
const RequestRepository = require('src/request/request');
|
||||
const Cache = require('src/tmdb/cache')
|
||||
const TMDB = require('src/tmdb/tmdb')
|
||||
|
||||
const requestRepository = new RequestRepository();
|
||||
const cache = new Cache()
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'))
|
||||
const request = new RequestRepository()
|
||||
|
||||
const tmdbMovieInfo = (id) => {
|
||||
return tmdb.movieInfo(id)
|
||||
}
|
||||
|
||||
const tmdbShowInfo = (id) => {
|
||||
return tmdb.showInfo(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller: POST a media id to be donwloaded
|
||||
@@ -8,22 +21,31 @@ const requestRepository = new RequestRepository();
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
|
||||
function submitRequestController(req, res) {
|
||||
// This is the id that is the param of the url
|
||||
const id = req.params.mediaId;
|
||||
const type = req.query.type;
|
||||
const type = req.query.type ? req.query.type.toLowerCase() : undefined
|
||||
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||
const user_agent = req.headers['user-agent'];
|
||||
const user = req.loggedInUser;
|
||||
let mediaFunction = undefined
|
||||
|
||||
requestRepository.sendRequest(id, type, ip, user_agent, user)
|
||||
.then(() => {
|
||||
res.send({ success: true, message: 'Media item sucessfully requested!' });
|
||||
})
|
||||
.catch((error) => {
|
||||
res.status(500).send({ success: false, error: error.message });
|
||||
});
|
||||
if (type === 'movie') {
|
||||
console.log('movie')
|
||||
mediaFunction = tmdbMovieInfo
|
||||
} else if (type === 'show') {
|
||||
console.log('show')
|
||||
mediaFunction = tmdbShowInfo
|
||||
} else {
|
||||
res.status(422).send({ success: false, error: 'Incorrect type. Allowed types: "movie" or "show"'})
|
||||
}
|
||||
|
||||
if (mediaFunction === undefined) { res.status(200); return }
|
||||
|
||||
mediaFunction(id)
|
||||
.then(tmdbMedia => request.requestFromTmdb(tmdbMedia, ip, user_agent, user))
|
||||
.then(() => res.send({ success: true, message: 'Media item successfully requested' }))
|
||||
.catch(err => res.status(500).send({ success: false, error: err.message }))
|
||||
}
|
||||
|
||||
module.exports = submitRequestController;
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
const RequestRepository = require('src/request/request');
|
||||
const request = new RequestRepository();
|
||||
|
||||
/**
|
||||
* Controller: Fetch all requested items
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
function fetchAllRequests(req, res) {
|
||||
let { page, filter, sort, query } = req.query;
|
||||
let sort_by = sort;
|
||||
let sort_direction = undefined;
|
||||
|
||||
if (sort !== undefined && sort.includes(':')) {
|
||||
[sort_by, sort_direction] = sort.split(':')
|
||||
}
|
||||
|
||||
Promise.resolve()
|
||||
.then(() => request.fetchAll(page, sort_by, sort_direction, filter, query))
|
||||
.then((result) => res.send(result))
|
||||
.catch((error) => {
|
||||
res.status(404).send({ success: false, error: error.message });
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = fetchAllRequests;
|
||||
22
seasoned_api/src/webserver/controllers/request/getRequest.js
Normal file
22
seasoned_api/src/webserver/controllers/request/getRequest.js
Normal file
@@ -0,0 +1,22 @@
|
||||
const RequestRepository = require('src/request/request');
|
||||
const request = new RequestRepository();
|
||||
|
||||
/**
|
||||
* Controller: Get requested item by tmdb id and type
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
function fetchAllRequests(req, res) {
|
||||
const id = req.params.id;
|
||||
const { type } = req.query;
|
||||
|
||||
Promise.resolve()
|
||||
.then(() => request.getRequestByIdAndType(id, type))
|
||||
.then((result) => res.send(result))
|
||||
.catch((error) => {
|
||||
res.status(404).send({ success: false, error: error.message });
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = fetchAllRequests;
|
||||
@@ -0,0 +1,52 @@
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const RequestRepository = require('src/request/request');
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
const request = new RequestRepository();
|
||||
|
||||
const tmdbMovieInfo = (id) => {
|
||||
return tmdb.movieInfo(id)
|
||||
}
|
||||
|
||||
const tmdbShowInfo = (id) => {
|
||||
return tmdb.showInfo(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Controller: Request by id with type param
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
function requestTmdbIdController(req, res) {
|
||||
const { id, type } = req.body
|
||||
console.log('body', req.body)
|
||||
console.log('id & type', id, type)
|
||||
|
||||
const ip = req.headers['x-forwarded-for'] || req.connection.remoteAddress;
|
||||
const user_agent = req.headers['user-agent'];
|
||||
const user = req.loggedInUser;
|
||||
let mediaFunction = undefined
|
||||
|
||||
if (type === 'movie') {
|
||||
console.log('movie')
|
||||
mediaFunction = tmdbMovieInfo
|
||||
} else if (type === 'show') {
|
||||
console.log('show')
|
||||
mediaFunction = tmdbShowInfo
|
||||
} else {
|
||||
res.status(422).send({ success: false, error: 'Incorrect type. Allowed types: "movie" or "show"'})
|
||||
}
|
||||
|
||||
mediaFunction(id)
|
||||
.catch((error) => { console.error(error); res.status(404).send({ success: false, error: 'Id not found' }) })
|
||||
.then((tmdbMedia) => request.requestFromTmdb(tmdbMedia, ip, user_agent, user))
|
||||
.then(() => res.send({success: true, message: 'Request has been submitted.'}))
|
||||
.catch((error) => {
|
||||
res.status(501).send({ success: false, error: error.message });
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = requestTmdbIdController;
|
||||
35
seasoned_api/src/webserver/controllers/search/movieSearch.js
Normal file
35
seasoned_api/src/webserver/controllers/search/movieSearch.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const SearchHistory = require('src/searchHistory/searchHistory');
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
const searchHistory = new SearchHistory();
|
||||
|
||||
/**
|
||||
* Controller: Search for movies by query and pagey
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
function movieSearchController(req, res) {
|
||||
const user = req.loggedInUser;
|
||||
const { query, page } = req.query;
|
||||
|
||||
Promise.resolve()
|
||||
.then(() => {
|
||||
if (user) {
|
||||
return searchHistory.create(user, query);
|
||||
}
|
||||
return null
|
||||
})
|
||||
.then(() => tmdb.movieSearch(query, page))
|
||||
.then((movies) => {
|
||||
res.send(movies);
|
||||
})
|
||||
.catch((error) => {
|
||||
res.status(500).send({ success: false, error: error.message });
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = movieSearchController;
|
||||
35
seasoned_api/src/webserver/controllers/search/multiSearch.js
Normal file
35
seasoned_api/src/webserver/controllers/search/multiSearch.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const SearchHistory = require('src/searchHistory/searchHistory');
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
const searchHistory = new SearchHistory();
|
||||
|
||||
/**
|
||||
* Controller: Search for multi (movies, shows and people by query and pagey
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
function multiSearchController(req, res) {
|
||||
const user = req.loggedInUser;
|
||||
const { query, page } = req.query;
|
||||
|
||||
Promise.resolve()
|
||||
.then(() => {
|
||||
if (user) {
|
||||
return searchHistory.create(user, query);
|
||||
}
|
||||
return null
|
||||
})
|
||||
.then(() => tmdb.multiSearch(query, page))
|
||||
.then((result) => {
|
||||
res.send(result);
|
||||
})
|
||||
.catch((error) => {
|
||||
res.status(500).send({ success: false, error: error.message });
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = multiSearchController;
|
||||
@@ -0,0 +1,35 @@
|
||||
const SearchHistory = require('src/searchHistory/searchHistory');
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
const searchHistory = new SearchHistory();
|
||||
|
||||
/**
|
||||
* Controller: Search for person by query and pagey
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
function personSearchController(req, res) {
|
||||
const user = req.loggedInUser;
|
||||
const { query, page } = req.query;
|
||||
|
||||
Promise.resolve()
|
||||
.then(() => {
|
||||
if (user) {
|
||||
return searchHistory.create(user, query);
|
||||
}
|
||||
return null
|
||||
})
|
||||
.then(() => tmdb.personSearch(query, page))
|
||||
.then((person) => {
|
||||
res.send(person);
|
||||
})
|
||||
.catch((error) => {
|
||||
res.status(500).send({ success: false, error: error.message });
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = personSearchController;
|
||||
35
seasoned_api/src/webserver/controllers/search/showSearch.js
Normal file
35
seasoned_api/src/webserver/controllers/search/showSearch.js
Normal file
@@ -0,0 +1,35 @@
|
||||
const SearchHistory = require('src/searchHistory/searchHistory');
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const cache = new Cache();
|
||||
const tmdb = new TMDB(cache, configuration.get('tmdb', 'apiKey'));
|
||||
const searchHistory = new SearchHistory();
|
||||
|
||||
/**
|
||||
* Controller: Search for shows by query and pagey
|
||||
* @param {Request} req http request variable
|
||||
* @param {Response} res
|
||||
* @returns {Callback}
|
||||
*/
|
||||
function showSearchController(req, res) {
|
||||
const user = req.loggedInUser;
|
||||
const { query, page } = req.query;
|
||||
|
||||
Promise.resolve()
|
||||
.then(() => {
|
||||
if (user) {
|
||||
return searchHistory.create(user, query);
|
||||
}
|
||||
return null
|
||||
})
|
||||
.then(() => tmdb.showSearch(query, page))
|
||||
.then((shows) => {
|
||||
res.send(shows);
|
||||
})
|
||||
.catch((error) => {
|
||||
res.status(500).send({ success: false, error: error.message });
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = showSearchController;
|
||||
1
seasoned_api/test/fixtures/blade_runner_2049-info-success-response.json
vendored
Normal file
1
seasoned_api/test/fixtures/blade_runner_2049-info-success-response.json
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"adult":false,"backdrop_path":"/mVr0UiqyltcfqxbAUcLl9zWL8ah.jpg","belongs_to_collection":{"id":422837,"name":"Blade Runner Collection","poster_path":"/cWESb1o9lW2i2Z3Xllv9u40aNIk.jpg","backdrop_path":"/bSHZIvLoPBWyGLeiAudN1mXdvQX.jpg"},"budget":150000000,"genres":[{"id":9648,"name":"Mystery"},{"id":878,"name":"Science Fiction"},{"id":53,"name":"Thriller"}],"homepage":"http://bladerunnermovie.com/","id":335984,"imdb_id":"tt1856101","original_language":"en","original_title":"Blade Runner 2049","overview":"Thirty years after the events of the first film, a new blade runner, LAPD Officer K, unearths a long-buried secret that has the potential to plunge what's left of society into chaos. K's discovery leads him on a quest to find Rick Deckard, a former LAPD blade runner who has been missing for 30 years.","popularity":30.03,"poster_path":"/gajva2L0rPYkEWjzgFlBXCAVBE5.jpg","production_companies":[{"id":79529,"logo_path":"/gVN3k8emmKy4iV4KREWcCtxusZK.png","name":"Torridon Films","origin_country":"US"},{"id":101829,"logo_path":"/8IOjCvgjq0zTrtP91cWD3kL2jMK.png","name":"16:14 Entertainment","origin_country":"US"},{"id":1645,"logo_path":"/6Ry6uNBaa0IbbSs1XYIgX5DkA9r.png","name":"Scott Free Productions","origin_country":""},{"id":5,"logo_path":"/71BqEFAF4V3qjjMPCpLuyJFB9A.png","name":"Columbia Pictures","origin_country":"US"},{"id":1088,"logo_path":"/9WOE5AQUXbOtLU6GTwfjS8OMF0v.png","name":"Alcon Entertainment","origin_country":"US"},{"id":78028,"logo_path":"/sTFcDFfJaSVT3sv3DoaZDE4SlGB.png","name":"Thunderbird Entertainment","origin_country":"CA"},{"id":174,"logo_path":"/ky0xOc5OrhzkZ1N6KyUxacfQsCk.png","name":"Warner Bros. Pictures","origin_country":"US"}],"production_countries":[{"iso_3166_1":"CA","name":"Canada"},{"iso_3166_1":"US","name":"United States of America"},{"iso_3166_1":"HU","name":"Hungary"},{"iso_3166_1":"GB","name":"United Kingdom"}],"release_date":"2017-10-04","revenue":259239658,"runtime":163,"spoken_languages":[{"iso_639_1":"en","name":"English"},{"iso_639_1":"fi","name":"suomi"}],"status":"Released","tagline":"There's still a page left.","title":"Blade Runner 2049","video":false,"vote_average":7.3,"vote_count":5478}
|
||||
1
seasoned_api/test/fixtures/interstellar-query-movie-success-response.json
vendored
Normal file
1
seasoned_api/test/fixtures/interstellar-query-movie-success-response.json
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -7,11 +7,11 @@ const popularMoviesSuccess = require('test/fixtures/popular-movies-success-respo
|
||||
|
||||
describe('As a user I want to get popular movies', () => {
|
||||
before(() => resetDatabase());
|
||||
before(() => createCacheEntry('p:movie:1', popularMoviesSuccess));
|
||||
before(() => createCacheEntry('pm:1', popularMoviesSuccess));
|
||||
|
||||
it('should return 200 with the information', () =>
|
||||
request(app)
|
||||
.get('/api/v1/tmdb/list/popular')
|
||||
.get('/api/v2/movie/popular')
|
||||
.expect(200)
|
||||
.then(response => assert.equal(response.body.results.length, 20))
|
||||
);
|
||||
|
||||
@@ -7,11 +7,11 @@ const popularShowsSuccess = require('test/fixtures/popular-show-success-response
|
||||
|
||||
describe('As a user I want to get popular shows', () => {
|
||||
before(() => resetDatabase());
|
||||
before(() => createCacheEntry('p:show:1', popularShowsSuccess));
|
||||
before(() => createCacheEntry('pt:1', popularShowsSuccess));
|
||||
|
||||
it('should return 200 with the information', () =>
|
||||
request(app)
|
||||
.get('/api/v1/tmdb/list/popular?type=show')
|
||||
.get('/api/v2/show/popular')
|
||||
.expect(200)
|
||||
.then(response => assert.equal(response.body.results.length, 20))
|
||||
);
|
||||
|
||||
@@ -4,18 +4,19 @@ const app = require('src/webserver/app');
|
||||
const request = require('supertest-as-promised');
|
||||
const createUser = require('test/helpers/createUser');
|
||||
const createToken = require('test/helpers/createToken');
|
||||
const infoMovieSuccess = require('test/fixtures/arrival-info-success-response.json');
|
||||
const infoMovieSuccess = require('test/fixtures/blade_runner_2049-info-success-response.json');
|
||||
|
||||
describe('As a user I want to request a movie', () => {
|
||||
before(() => {
|
||||
return resetDatabase()
|
||||
.then(() => createUser('test_user', 'test@gmail.com', 'password'));
|
||||
})
|
||||
before(() => createCacheEntry('i:movie:329865', infoMovieSuccess));
|
||||
before(() => createCacheEntry('mi:335984', infoMovieSuccess));
|
||||
|
||||
it('should return 200 when item is requested', () =>
|
||||
request(app)
|
||||
.post('/api/v1/plex/request/329865')
|
||||
.post('/api/v2/request')
|
||||
.send({ id: 335984, type: 'movie' })
|
||||
.set('Authorization', createToken('test_user', 'secret'))
|
||||
.expect(200)
|
||||
);
|
||||
|
||||
@@ -2,15 +2,15 @@ const createCacheEntry = require('test/helpers/createCacheEntry');
|
||||
const resetDatabase = require('test/helpers/resetDatabase');
|
||||
const request = require('supertest-as-promised');
|
||||
const app = require('src/webserver/app');
|
||||
const interstellarQuerySuccess = require('test/fixtures/interstellar-query-success-response.json');
|
||||
const interstellarQuerySuccess = require('test/fixtures/interstellar-query-movie-success-response.json');
|
||||
|
||||
describe('As an anonymous user I want to search for a movie', () => {
|
||||
before(() => resetDatabase());
|
||||
before(() => createCacheEntry('se:1:multi:interstellar', interstellarQuerySuccess));
|
||||
before(() => createCacheEntry('mos:1:interstellar', interstellarQuerySuccess));
|
||||
|
||||
it('should return 200 with the search results even if user is not logged in', () =>
|
||||
request(app)
|
||||
.get('/api/v1/tmdb/search?query=interstellar&page=1')
|
||||
.get('/api/v2/search/movie?query=interstellar&page=1')
|
||||
.expect(200)
|
||||
);
|
||||
});
|
||||
|
||||
30
seasoned_api/test/unit/tmdb/testConvertTmdbToMovie.js
Normal file
30
seasoned_api/test/unit/tmdb/testConvertTmdbToMovie.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const assert = require('assert');
|
||||
const convertTmdbToMovie = require('src/tmdb/convertTmdbToMovie');
|
||||
const bladeRunnerQuerySuccess = require('test/fixtures/blade_runner_2049-info-success-response.json')
|
||||
|
||||
describe('Convert tmdb movieInfo to movie', () => {
|
||||
beforeEach(() => this.bladeRunnerTmdbMovie = bladeRunnerQuerySuccess);
|
||||
|
||||
it('should translate the tmdb release date to movie year', () => {
|
||||
const bladeRunner = convertTmdbToMovie(this.bladeRunnerTmdbMovie);
|
||||
assert.strictEqual(bladeRunner.year, 2017);
|
||||
});
|
||||
|
||||
it('should translate the tmdb release date to instance of Date', () => {
|
||||
const bladeRunner = convertTmdbToMovie(this.bladeRunnerTmdbMovie);
|
||||
assert(bladeRunner.release_date instanceof Date);
|
||||
});
|
||||
|
||||
it('should translate the tmdb title to title', () => {
|
||||
const bladeRunner = convertTmdbToMovie(this.bladeRunnerTmdbMovie);
|
||||
assert.equal(bladeRunner.title, 'Blade Runner 2049');
|
||||
});
|
||||
|
||||
it('should translate the tmdb vote_average to rank', () => {
|
||||
const bladeRunner = convertTmdbToMovie(this.bladeRunnerTmdbMovie);
|
||||
assert.equal(bladeRunner.rank, 7.3);
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
31
seasoned_api/test/unit/tmdb/testTmdb.disabled
Normal file
31
seasoned_api/test/unit/tmdb/testTmdb.disabled
Normal file
@@ -0,0 +1,31 @@
|
||||
const assert = require('assert');
|
||||
// const Movie = require('src/movie/movie');
|
||||
const TMDB = require('src/tmdb/tmdb');
|
||||
const Cache = require('src/tmdb/cache');
|
||||
const SqliteDatabase = require('src/database/sqliteDatabase');
|
||||
const tmdbMock = require('test/helpers/tmdbMock');
|
||||
|
||||
const emptyQuerySuccess = require('test/fixtures/empty-query-success-response.json');
|
||||
const interstellarQuerySuccess = require('test/fixtures/arrival-info-success-response.json');
|
||||
const popularMovieSuccessResponse = require('test/fixtures/popular-movies-success-response.json');
|
||||
|
||||
describe('TMDB', function test() {
|
||||
beforeEach(() => {
|
||||
this.mockMoviedb = tmdbMock();
|
||||
this.database = new SqliteDatabase(':memory:');
|
||||
return Promise.resolve()
|
||||
.then(() => this.database.setUp());
|
||||
});
|
||||
|
||||
describe('popular', () => {
|
||||
it('should return the "Blade Runner 2049" year in the collection of popular movies', () => {
|
||||
this.mockMoviedb.response = popularMovieSuccessResponse;
|
||||
const cache = new Cache(this.database);
|
||||
const tmdb = new TMDB(cache, 'bogus-api-key', this.mockMoviedb);
|
||||
return tmdb.popular()
|
||||
.then(movies =>
|
||||
assert.equal(movies[0].title, "Blade Runner 2049")
|
||||
);
|
||||
});
|
||||
})
|
||||
});
|
||||
@@ -44,6 +44,16 @@ ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0:
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.3.0"
|
||||
|
||||
ajv@^6.5.5:
|
||||
version "6.10.0"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.0.tgz#90d0d54439da587cd7e843bfb7045f50bd22bdf1"
|
||||
integrity sha512-nffhOpkymDECQyR0mnsUtoCE8RlX38G0rYP+wgLWFyZuUyuuojSSvi/+euOiQBIn63whYwYVIIH1TvE3tu4OEg==
|
||||
dependencies:
|
||||
fast-deep-equal "^2.0.1"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
align-text@^0.1.1, align-text@^0.1.3:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
|
||||
@@ -161,7 +171,7 @@ assign-symbols@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
|
||||
|
||||
async@1.x, async@^1.4.0, async@^1.5.2:
|
||||
async@1.x, async@^1.4.0:
|
||||
version "1.5.2"
|
||||
resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
|
||||
|
||||
@@ -187,6 +197,19 @@ aws4@^1.6.0:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e"
|
||||
|
||||
aws4@^1.8.0:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
|
||||
integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
|
||||
|
||||
axios@^0.18.0:
|
||||
version "0.18.1"
|
||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.18.1.tgz#ff3f0de2e7b5d180e757ad98000f1081b87bcea3"
|
||||
integrity sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==
|
||||
dependencies:
|
||||
follow-redirects "1.5.10"
|
||||
is-buffer "^2.0.2"
|
||||
|
||||
babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
|
||||
version "6.26.0"
|
||||
resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b"
|
||||
@@ -528,12 +551,19 @@ color-name@^1.1.1:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
|
||||
|
||||
combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5:
|
||||
combined-stream@1.0.6, combined-stream@~1.0.5:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
commander@2.11.0:
|
||||
version "2.11.0"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563"
|
||||
@@ -587,7 +617,7 @@ cookie@0.3.1:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
|
||||
|
||||
cookiejar@^2.0.6, cookiejar@^2.1.0:
|
||||
cookiejar@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.1.tgz#41ad57b1b555951ec171412a81942b1e8200d34a"
|
||||
|
||||
@@ -655,18 +685,26 @@ debug-log@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f"
|
||||
|
||||
debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
|
||||
debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9:
|
||||
version "2.6.9"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@3.1.0, debug@^3.1.0:
|
||||
debug@3.1.0, debug@=3.1.0, debug@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
|
||||
integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
|
||||
dependencies:
|
||||
ms "2.0.0"
|
||||
|
||||
debug@^3.2.6:
|
||||
version "3.2.6"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
|
||||
integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
|
||||
dependencies:
|
||||
ms "^2.1.1"
|
||||
|
||||
decamelize@^1.0.0, decamelize@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
@@ -675,9 +713,10 @@ decode-uri-component@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
||||
|
||||
deep-extend@~0.4.0:
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
|
||||
deep-extend@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
|
||||
integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
|
||||
|
||||
deep-is@~0.1.3:
|
||||
version "0.1.3"
|
||||
@@ -1037,6 +1076,11 @@ extend@^3.0.0, extend@~3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
|
||||
|
||||
extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
|
||||
external-editor@^2.0.4:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.2.0.tgz#045511cfd8d133f3846673d1047c154e214ad3d5"
|
||||
@@ -1076,6 +1120,11 @@ fast-deep-equal@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
|
||||
|
||||
fast-deep-equal@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
|
||||
|
||||
fast-json-stable-stringify@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
|
||||
@@ -1162,6 +1211,13 @@ flat-cache@^1.2.1:
|
||||
graceful-fs "^4.1.2"
|
||||
write "^0.2.1"
|
||||
|
||||
follow-redirects@1.5.10:
|
||||
version "1.5.10"
|
||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
|
||||
integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
|
||||
dependencies:
|
||||
debug "=3.1.0"
|
||||
|
||||
for-in@^1.0.1, for-in@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
|
||||
@@ -1183,14 +1239,6 @@ forever-agent@~0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||
|
||||
form-data@1.0.0-rc4:
|
||||
version "1.0.0-rc4"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.0-rc4.tgz#05ac6bc22227b43e4461f488161554699d4f8b5e"
|
||||
dependencies:
|
||||
async "^1.5.2"
|
||||
combined-stream "^1.0.5"
|
||||
mime-types "^2.1.10"
|
||||
|
||||
form-data@^2.3.1, form-data@~2.3.1:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
|
||||
@@ -1199,7 +1247,16 @@ form-data@^2.3.1, form-data@~2.3.1:
|
||||
combined-stream "1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formidable@^1.0.17, formidable@^1.1.1:
|
||||
form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formidable@^1.1.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.1.tgz#70fb7ca0290ee6ff961090415f4b3df3d2082659"
|
||||
|
||||
@@ -1348,6 +1405,14 @@ har-validator@~5.0.3:
|
||||
ajv "^5.1.0"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
har-validator@~5.1.0:
|
||||
version "5.1.3"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
|
||||
integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
|
||||
dependencies:
|
||||
ajv "^6.5.5"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
has-ansi@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
|
||||
@@ -1536,6 +1601,11 @@ is-buffer@^1.1.5, is-buffer@~1.1.1:
|
||||
version "1.1.6"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
|
||||
|
||||
is-buffer@^2.0.2:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
|
||||
integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
|
||||
|
||||
is-builtin-module@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe"
|
||||
@@ -1803,6 +1873,11 @@ json-schema-traverse@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
|
||||
|
||||
json-schema-traverse@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
|
||||
|
||||
json-schema@0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
||||
@@ -1880,6 +1955,13 @@ kind-of@^6.0.0, kind-of@^6.0.2:
|
||||
version "6.0.2"
|
||||
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
|
||||
|
||||
km-moviedb@^0.2.12:
|
||||
version "0.2.13"
|
||||
resolved "https://registry.yarnpkg.com/km-moviedb/-/km-moviedb-0.2.13.tgz#1981f1468ed4a52f6ec3a257310719d79a0892ab"
|
||||
integrity sha512-/AsIP3oltR6UVDrf05gRsjjIL6cnCP136U65QLf1TQiyz9ixGGNO9M/dxOrMJVCmIdOHW1EJtXDvzBYv7lMfYg==
|
||||
dependencies:
|
||||
superagent "3.8.2"
|
||||
|
||||
lazy-cache@^1.0.3:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
|
||||
@@ -2072,21 +2154,33 @@ micromatch@^3.1.8:
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.2"
|
||||
|
||||
mime-db@1.40.0:
|
||||
version "1.40.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
|
||||
integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
|
||||
|
||||
mime-db@~1.33.0:
|
||||
version "1.33.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
|
||||
|
||||
mime-types@^2.1.10, mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18:
|
||||
mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18:
|
||||
version "2.1.18"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
|
||||
dependencies:
|
||||
mime-db "~1.33.0"
|
||||
|
||||
mime-types@~2.1.19:
|
||||
version "2.1.24"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
|
||||
integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
|
||||
dependencies:
|
||||
mime-db "1.40.0"
|
||||
|
||||
mime@1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
|
||||
|
||||
mime@^1.3.4, mime@^1.4.1:
|
||||
mime@^1.4.1:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
|
||||
|
||||
@@ -2190,12 +2284,6 @@ mongoose@~5.0.11:
|
||||
regexp-clone "0.0.1"
|
||||
sliced "1.0.1"
|
||||
|
||||
moviedb@^0.2.10:
|
||||
version "0.2.10"
|
||||
resolved "https://registry.yarnpkg.com/moviedb/-/moviedb-0.2.10.tgz#53238d403608478b8ba69e8d8dad19e3f0af78e8"
|
||||
dependencies:
|
||||
superagent "^2.3.0"
|
||||
|
||||
mpath@0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.3.0.tgz#7a58f789e9b5fd3c94520634157960f26bd5ef44"
|
||||
@@ -2221,9 +2309,10 @@ mute-stream@0.0.7:
|
||||
version "0.0.7"
|
||||
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
|
||||
|
||||
nan@~2.9.2:
|
||||
version "2.9.2"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.9.2.tgz#f564d75f5f8f36a6d9456cca7a6c4fe488ab7866"
|
||||
nan@^2.12.1:
|
||||
version "2.14.0"
|
||||
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
|
||||
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.9"
|
||||
@@ -2246,11 +2335,12 @@ natural-compare@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
|
||||
|
||||
needle@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.0.tgz#f14efc69cee1024b72c8b21c7bdf94a731dc12fa"
|
||||
needle@^2.2.1:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
|
||||
integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==
|
||||
dependencies:
|
||||
debug "^2.1.2"
|
||||
debug "^3.2.6"
|
||||
iconv-lite "^0.4.4"
|
||||
sax "^1.2.4"
|
||||
|
||||
@@ -2265,17 +2355,18 @@ node-cache@^4.1.1:
|
||||
clone "2.x"
|
||||
lodash "4.x"
|
||||
|
||||
node-pre-gyp@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.9.0.tgz#bdd4c3afac9b1b1ebff0a9ff3362859eb6781bb8"
|
||||
node-pre-gyp@^0.11.0:
|
||||
version "0.11.0"
|
||||
resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.11.0.tgz#db1f33215272f692cd38f03238e3e9b47c5dd054"
|
||||
integrity sha512-TwWAOZb0j7e9eGaf9esRx3ZcLaE5tQ2lvYy1pb5IAaG1a2e2Kv5Lms1Y4hpj+ciXJRofIxxlt5haeQ/2ANeE0Q==
|
||||
dependencies:
|
||||
detect-libc "^1.0.2"
|
||||
mkdirp "^0.5.1"
|
||||
needle "^2.2.0"
|
||||
needle "^2.2.1"
|
||||
nopt "^4.0.1"
|
||||
npm-packlist "^1.1.6"
|
||||
npmlog "^4.0.2"
|
||||
rc "^1.1.7"
|
||||
rc "^1.2.7"
|
||||
rimraf "^2.6.1"
|
||||
semver "^5.3.0"
|
||||
tar "^4"
|
||||
@@ -2374,6 +2465,11 @@ oauth-sign@~0.8.2:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
|
||||
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||
|
||||
object-assign@^4.0.1, object-assign@^4.1.0:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
@@ -2610,18 +2706,33 @@ pseudomap@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||
|
||||
psl@^1.1.24:
|
||||
version "1.1.32"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.32.tgz#3f132717cf2f9c169724b2b6caf373cf694198db"
|
||||
integrity sha512-MHACAkHpihU/REGGPLj4sEfc/XKW2bheigvHO1dUqjaKigMp1C8+WLQYRGgeKFMsw5PMfegZcaN8IDXK/cD0+g==
|
||||
|
||||
punycode@^1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
|
||||
punycode@^2.1.0:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
|
||||
|
||||
python-shell@^0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/python-shell/-/python-shell-0.5.0.tgz#461983bafd092010bc2760c365b13e7d50aab231"
|
||||
|
||||
qs@6.5.1, qs@^6.1.0, qs@^6.5.1, qs@~6.5.1:
|
||||
qs@6.5.1, qs@^6.5.1, qs@~6.5.1:
|
||||
version "6.5.1"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
|
||||
|
||||
qs@~6.5.2:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
|
||||
|
||||
randomatic@^1.1.3:
|
||||
version "1.1.7"
|
||||
resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c"
|
||||
@@ -2652,11 +2763,12 @@ raw-body@2.3.2:
|
||||
iconv-lite "0.4.19"
|
||||
unpipe "1.0.0"
|
||||
|
||||
rc@^1.1.7:
|
||||
version "1.2.6"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.6.tgz#eb18989c6d4f4f162c399f79ddd29f3835568092"
|
||||
rc@^1.2.7:
|
||||
version "1.2.8"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
|
||||
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
|
||||
dependencies:
|
||||
deep-extend "~0.4.0"
|
||||
deep-extend "^0.6.0"
|
||||
ini "~1.3.0"
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
@@ -2788,6 +2900,32 @@ request@^2.79.0, request@^2.85.0:
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.1.0"
|
||||
|
||||
request@^2.87.0:
|
||||
version "2.88.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
|
||||
integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.8.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.6"
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.0"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.19"
|
||||
oauth-sign "~0.9.0"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.4.3"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
|
||||
@@ -2875,6 +3013,11 @@ safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@~5.1.0, s
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853"
|
||||
|
||||
safe-buffer@^5.1.2:
|
||||
version "5.1.2"
|
||||
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
|
||||
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
|
||||
|
||||
safe-regex@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
|
||||
@@ -3088,12 +3231,14 @@ sprintf-js@~1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
|
||||
sqlite3@4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-4.0.0.tgz#cc0e093ab51873f50d9dfc4126fcbef15d486570"
|
||||
sqlite3@^4.0.0:
|
||||
version "4.0.8"
|
||||
resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-4.0.8.tgz#81ee60d54befaa52f5421fe6337050bd43d4bb95"
|
||||
integrity sha512-kgwHu4j10KhpCHtx//dejd/tVQot7jc3sw+Sn0vMuKOw0X00Ckyg9VceKgzPyGmmz+zEoYue9tOLriWTvYy0ww==
|
||||
dependencies:
|
||||
nan "~2.9.2"
|
||||
node-pre-gyp "~0.9.0"
|
||||
nan "^2.12.1"
|
||||
node-pre-gyp "^0.11.0"
|
||||
request "^2.87.0"
|
||||
|
||||
sshpk@^1.7.0:
|
||||
version "1.14.1"
|
||||
@@ -3187,24 +3332,10 @@ strip-json-comments@~2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
|
||||
|
||||
superagent@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/superagent/-/superagent-2.3.0.tgz#703529a0714e57e123959ddefbce193b2e50d115"
|
||||
dependencies:
|
||||
component-emitter "^1.2.0"
|
||||
cookiejar "^2.0.6"
|
||||
debug "^2.2.0"
|
||||
extend "^3.0.0"
|
||||
form-data "1.0.0-rc4"
|
||||
formidable "^1.0.17"
|
||||
methods "^1.1.1"
|
||||
mime "^1.3.4"
|
||||
qs "^6.1.0"
|
||||
readable-stream "^2.0.5"
|
||||
|
||||
superagent@^3.0.0:
|
||||
superagent@3.8.2, superagent@^3.0.0:
|
||||
version "3.8.2"
|
||||
resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.2.tgz#e4a11b9d047f7d3efeb3bbe536d9ec0021d16403"
|
||||
integrity sha512-gVH4QfYHcY3P0f/BZzavLreHW3T1v7hG9B+hpMQotGQqurOvhv87GcMCd6LWySmBuf+BDR44TQd0aISjVHLeNQ==
|
||||
dependencies:
|
||||
component-emitter "^1.2.0"
|
||||
cookiejar "^2.1.0"
|
||||
@@ -3336,6 +3467,14 @@ tough-cookie@>=2.3.3, tough-cookie@~2.3.3:
|
||||
dependencies:
|
||||
punycode "^1.4.1"
|
||||
|
||||
tough-cookie@~2.4.3:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
|
||||
integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
|
||||
dependencies:
|
||||
psl "^1.1.24"
|
||||
punycode "^1.4.1"
|
||||
|
||||
trim-right@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
|
||||
@@ -3400,6 +3539,13 @@ unset-value@^1.0.0:
|
||||
has-value "^0.3.1"
|
||||
isobject "^3.0.0"
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.2.2"
|
||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
|
||||
integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
urix@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
||||
@@ -3426,6 +3572,11 @@ uuid@^3.1.0:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
|
||||
|
||||
uuid@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
||||
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
|
||||
|
||||
validate-npm-package-license@^3.0.1:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338"
|
||||
|
||||
Reference in New Issue
Block a user