Compare commits
119 Commits
1.1.0
...
feat/types
| Author | SHA1 | Date | |
|---|---|---|---|
| 379e025ab6 | |||
| 628ed52012 | |||
| 1815a429b0 | |||
| cfbd4965db | |||
| 31c4b8b7df | |||
| a4b2e8f51c | |||
| 11fb803838 | |||
| b2d2b0025c | |||
| ae9f3044bc | |||
| 0eab680527 | |||
| 4204515e91 | |||
| 19e99e8c43 | |||
| 007d34f994 | |||
| 5a1e18b839 | |||
| 56262a45c8 | |||
| 0efc109992 | |||
| 851af204ab | |||
| ccebf0d7b0 | |||
| 76fe986f39 | |||
| fbf1ae8dec | |||
| 9164b592bd | |||
| d77b427c3c | |||
| b56b1f6c0c | |||
| c8477fabaa | |||
| 014cac8b06 | |||
| 20d74cafb9 | |||
| 1690bbcdd0 | |||
| 7094aa2bb5 | |||
| 3660e88acf | |||
| d8f7f82127 | |||
| 0a4248bf30 | |||
| 92d139a156 | |||
| 5578bf854a | |||
| 5648b8fffa | |||
| 1b7a754224 | |||
| 5d91f1bae7 | |||
| cdcfae56e7 | |||
| f2c77e092d | |||
| d6ac7e55e9 | |||
| a3543090f2 | |||
| 041e944783 | |||
| bfd31ebd23 | |||
| 5036f4ca36 | |||
| 61b59ae3ea | |||
| 92c49ac523 | |||
| f680642f25 | |||
| f89486ae9e | |||
| 4d853565d1 | |||
| 91c81e5cf6 | |||
| 0ecbde9675 | |||
| d8e951c2ef | |||
| 90f3d86511 | |||
| c6791a7027 | |||
| 5b6a2c2651 | |||
| 4f7a22fff1 | |||
| 31b0c998a8 | |||
| 9ce5b476ef | |||
| 554f292e4c | |||
| d8985aaff7 | |||
| be889b8100 | |||
| b5bd672f44 | |||
| 4501bc5302 | |||
| b384e748af | |||
| c676f182b4 | |||
| 95d2b0095b | |||
| 8165cf8e85 | |||
| 14775744b0 | |||
| 559e32c059 | |||
| f4dbaf4c58 | |||
| 1d25914ae0 | |||
| 4d3d8c874c | |||
| 08433523b7 | |||
| fce8879994 | |||
| 505b126043 | |||
| 589bd7b08d | |||
| f0049ffb4e | |||
| 2b25397253 | |||
| 776f83553a | |||
| 815aaedffb | |||
| 578eff30fb | |||
| 943cbe5cb8 | |||
| f89db46bf2 | |||
| 085fb76e11 | |||
| aa4a1c2a57 | |||
| 74340afd16 | |||
| 2672266908 | |||
| f37786aa76 | |||
| 91f64e5cfb | |||
| a4d3123910 | |||
| bc6fe3ed48 | |||
| b23566509f | |||
| 341a07621d | |||
| 259ed9b06f | |||
| cddf06cbcc | |||
| 318d1e331b | |||
| 5923cbf051 | |||
| 291bdf089c | |||
| 8eacde9ccc | |||
| f8847c62f2 | |||
| ddb7e7379d | |||
| 720fb69648 | |||
| fedacf498e | |||
| 9022853502 | |||
| c1b96e17ca | |||
| a5248f0631 | |||
| e2d85c6242 | |||
| 510c014549 | |||
| 2650497986 | |||
| 639f0ec17a | |||
| 977d05c6f2 | |||
| 601fc1d0de | |||
| acc26a2f09 | |||
| 5d3a5dc8a4 | |||
| 3bb9bd84d9 | |||
| 002e663be1 | |||
| 495a3b4838 | |||
| 9e2a0101c9 | |||
| 05b001de2e | |||
| 1f9dc067e6 |
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
1
.dockerignore
Normal file
1
.dockerignore
Normal file
@@ -0,0 +1 @@
|
||||
**/node_modules
|
||||
111
.drone.yml
Normal file
111
.drone.yml
Normal file
@@ -0,0 +1,111 @@
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: seasoned api build
|
||||
|
||||
platform:
|
||||
os: linux
|
||||
arch: amd64
|
||||
|
||||
volumes:
|
||||
- name: cache
|
||||
host:
|
||||
path: /tmp/cache
|
||||
|
||||
steps:
|
||||
- name: Load cached packages
|
||||
image: sinlead/drone-cache:1.0.0
|
||||
settings:
|
||||
action: load
|
||||
key: yarn.lock
|
||||
mount: node_modules
|
||||
prefix: yarn-modules-seasoned_api
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /cache
|
||||
|
||||
- name: Install dependencies
|
||||
image: node:18.2.0
|
||||
commands:
|
||||
- node -v
|
||||
- yarn --version
|
||||
- yarn
|
||||
|
||||
- name: Cache packages
|
||||
image: sinlead/drone-cache:1.0.0
|
||||
settings:
|
||||
action: save
|
||||
key: yarn.lock
|
||||
mount: node_modules
|
||||
prefix: yarn-modules-seasoned_api
|
||||
volumes:
|
||||
- name: cache
|
||||
path: /cache
|
||||
|
||||
# - name: Compile typescript
|
||||
# image: node:18.2.0
|
||||
# commands:
|
||||
# - yarn build:ts
|
||||
|
||||
- name: Run test suite
|
||||
image: node:18.2.0
|
||||
commands:
|
||||
- yarn test
|
||||
failure: ignore
|
||||
|
||||
- name: Lint project using eslint
|
||||
image: node:18.2.0
|
||||
commands:
|
||||
- yarn lint
|
||||
failure: ignore
|
||||
|
||||
- name: Build and publish docker image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
registry: ghcr.io
|
||||
repo: ghcr.io/kevinmidboe/seasoned_shows
|
||||
dockerfile: Dockerfile
|
||||
username:
|
||||
from_secret: GITHUB_USERNAME
|
||||
password:
|
||||
from_secret: GITHUB_PASSWORD
|
||||
tags: latest
|
||||
environment:
|
||||
TMDB_APIKEY:
|
||||
from_secret: TMDB_APIKEY
|
||||
PLEX_IP:
|
||||
from_secret: PLEX_IP
|
||||
PLEX_TOKEN:
|
||||
from_secret: PLEX_TOKEN
|
||||
when:
|
||||
event:
|
||||
- push
|
||||
branch:
|
||||
- master
|
||||
|
||||
# - name: deploy
|
||||
# image: appleboy/drone-ssh
|
||||
# pull: true
|
||||
# secrets:
|
||||
# - ssh_key
|
||||
# when:
|
||||
# event:
|
||||
# - push
|
||||
# branch:
|
||||
# - master
|
||||
# - drone-test
|
||||
# status: success
|
||||
# settings:
|
||||
# host: 10.0.0.54
|
||||
# username: root
|
||||
# key:
|
||||
# from_secret: ssh_key
|
||||
# command_timeout: 600s
|
||||
# script:
|
||||
# - /home/kevin/deploy/seasoned.sh
|
||||
|
||||
trigger:
|
||||
event:
|
||||
include:
|
||||
- push
|
||||
# - pull_request
|
||||
35
.eslintrc.json
Normal file
35
.eslintrc.json
Normal file
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"root": true,
|
||||
"parserOptions": {
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"ecmaVersion": 2020,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"extends": [
|
||||
"eslint-config-airbnb-base",
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:prettier/recommended"
|
||||
],
|
||||
"plugins": ["mocha", "@typescript-eslint"],
|
||||
"rules": {
|
||||
"lines-between-class-members": [
|
||||
"error",
|
||||
"always",
|
||||
{ "exceptAfterSingleLine": true }
|
||||
],
|
||||
"max-classes-per-file": 1,
|
||||
"no-empty": [
|
||||
2,
|
||||
{
|
||||
"allowEmptyCatch": true
|
||||
}
|
||||
],
|
||||
"no-promise-executor-return": 1,
|
||||
"no-shadow": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"@typescript-eslint/no-var-requires": "off"
|
||||
},
|
||||
"env": {
|
||||
"mocha": true
|
||||
}
|
||||
}
|
||||
0
_config.yml → .github/_config.yml
vendored
0
_config.yml → .github/_config.yml
vendored
9
.gitignore
vendored
9
.gitignore
vendored
@@ -1,7 +1,12 @@
|
||||
.DS_Store
|
||||
|
||||
development.json
|
||||
env
|
||||
configurations/development.json
|
||||
configurations/production.json
|
||||
.env
|
||||
shows.db
|
||||
lib/
|
||||
|
||||
node_modules
|
||||
*/package-lock.json
|
||||
.nyc_output
|
||||
yarn-error.log
|
||||
|
||||
10
.gitmodules
vendored
10
.gitmodules
vendored
@@ -1,10 +0,0 @@
|
||||
# Docs : https://git-scm.com/book/en/v2/Git-Tools-Submodules
|
||||
|
||||
[submodule "torrent_search"]
|
||||
path = torrent_search
|
||||
url = https://github.com/KevinMidboe/torrent_search.git
|
||||
branch = master
|
||||
|
||||
[submodule "delugeClient"]
|
||||
path = delugeClient
|
||||
url = https://github.com/KevinMidboe/delugeClient.git
|
||||
9
.prettierrc
Normal file
9
.prettierrc
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"semi": true,
|
||||
"singleQuote": false,
|
||||
"bracketSpacing": true,
|
||||
"arrowParens": "avoid",
|
||||
"trailingComma": "none"
|
||||
}
|
||||
@@ -7,6 +7,7 @@ script:
|
||||
- yarn coverage
|
||||
before_install:
|
||||
- cd seasoned_api
|
||||
- cp conf/development.json.example conf/development.json
|
||||
before_script:
|
||||
- yarn
|
||||
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
||||
|
||||
21
Dockerfile
Normal file
21
Dockerfile
Normal file
@@ -0,0 +1,21 @@
|
||||
FROM node:18
|
||||
|
||||
RUN mkdir -p /opt/seasonedShows/src
|
||||
|
||||
WORKDIR /opt/seasonedShows
|
||||
|
||||
COPY src/ src
|
||||
COPY configurations/ configurations
|
||||
COPY package.json .
|
||||
COPY yarn.lock .
|
||||
|
||||
RUN apt update
|
||||
RUN apt install node-pre-gyp -y
|
||||
RUN yarn
|
||||
RUN cp configurations/development.json.example configurations/production.json
|
||||
|
||||
EXPOSE 31459
|
||||
|
||||
CMD ["yarn", "start"]
|
||||
|
||||
LABEL org.opencontainers.image.source https://github.com/kevinmidboe/seasoned
|
||||
13
README.md
13
README.md
@@ -6,16 +6,19 @@
|
||||
<h4 align="center"> Season your media library with the shows and movies that you and your friends want.</h4>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://travis-ci.org/KevinMidboe/seasonedShows">
|
||||
<img src="https://travis-ci.org/KevinMidboe/seasonedShows.svg?branch=master"
|
||||
alt="Travis CI">
|
||||
<a href="https://drone.schleppe.cloud/KevinMidboe/seasonedShows">
|
||||
<img src="https://drone.schleppe.cloud/api/badges/KevinMidboe/seasonedShows/status.svg"
|
||||
alt="Drone CI">
|
||||
</a>
|
||||
|
||||
<a href="https://coveralls.io/github/KevinMidboe/seasonedShows?branch=api/v2">
|
||||
<img src="https://coveralls.io/repos/github/KevinMidboe/seasonedShows/badge.svg?branch=api/v2" alt="">
|
||||
</a>
|
||||
<a href="https://snyk.io/test/github/KevinMidboe/seasonedShows?targetFile=seasoned_api/package.json">
|
||||
<img src="https://snyk.io/test/github/KevinMidboe/seasonedShows/badge.svg?targetFile=seasoned_api/package.json" alt="">
|
||||
|
||||
<a href="https://snyk.io/test/github/KevinMidboe/seasonedShows?targetFile=package.json">
|
||||
<img src="https://snyk.io/test/github/KevinMidboe/seasonedShows/badge.svg?targetFile=package.json" alt="">
|
||||
</a>
|
||||
|
||||
<a href="https://opensource.org/licenses/MIT">
|
||||
<img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="">
|
||||
</a>
|
||||
|
||||
31
configurations/development.json.example
Normal file
31
configurations/development.json.example
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"database": {
|
||||
"host": "../shows.db"
|
||||
},
|
||||
"redis": {
|
||||
"host": "localhost",
|
||||
"port": 6379
|
||||
},
|
||||
"webserver": {
|
||||
"port": 31459,
|
||||
"origins": []
|
||||
},
|
||||
"tmdb": {
|
||||
"apiKey": ""
|
||||
},
|
||||
"plex": {
|
||||
"ip": "localhost",
|
||||
"token": ""
|
||||
},
|
||||
"tautulli": {
|
||||
"apiKey": "",
|
||||
"ip": "",
|
||||
"port": ""
|
||||
},
|
||||
"raven": {
|
||||
"DSN": ""
|
||||
},
|
||||
"authentication": {
|
||||
"secret": "secret"
|
||||
}
|
||||
}
|
||||
31
configurations/test.json
Normal file
31
configurations/test.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"database": {
|
||||
"host": ":memory:"
|
||||
},
|
||||
"redis": {
|
||||
"host": "localhost",
|
||||
"port": 6379
|
||||
},
|
||||
"webserver": {
|
||||
"port": 31400,
|
||||
"origins": []
|
||||
},
|
||||
"tmdb": {
|
||||
"apiKey": "bogus-api-key"
|
||||
},
|
||||
"plex": {
|
||||
"ip": "localhost",
|
||||
"token": ""
|
||||
},
|
||||
"tautulli": {
|
||||
"apiKey": "",
|
||||
"ip": "",
|
||||
"port": ""
|
||||
},
|
||||
"raven": {
|
||||
"DSN": ""
|
||||
},
|
||||
"authentication": {
|
||||
"secret": "secret"
|
||||
}
|
||||
}
|
||||
60
package.json
Normal file
60
package.json
Normal file
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"name": "seasoned-api",
|
||||
"description": "Packages needed to build and commands to run seasoned api node server.",
|
||||
"license": {
|
||||
"type": "MIT",
|
||||
"url": "https://www.opensource.org/licenses/mit-license.php"
|
||||
},
|
||||
"main": "webserver/server.js",
|
||||
"scripts": {
|
||||
"start": "SEASONED_CONFIG=configurations/production.json NODE_ENV=production node lib/webserver/server.js",
|
||||
"dev": "SEASONED_CONFIG=configurations/development.json NODE_ENV=development node src/webserver/server.js",
|
||||
"test": "SEASONED_CONFIG=configurations/test.json mocha --recursive tests/unit tests/system",
|
||||
"build": "yarn tsc",
|
||||
"coverage:upload": "SEASONED_CONFIG=configurations/test.json mocha --recursive tests/unit && nyc report --reporter=text-lcov | coveralls",
|
||||
"coverage": "SEASONED_CONFIG=configurations/test.json mocha --recursive tests/unit && nyc report",
|
||||
"lint": "eslint src tests",
|
||||
"update": "SEASONED_CONFIG=configurations/production.json node scripts/updateRequestsInPlex.js",
|
||||
"docs": "yarn apiDocs; yarn classDocs",
|
||||
"apiDocs": "",
|
||||
"classDocs": "scripts/generate-class-docs.sh",
|
||||
"postbuild": "cp -r src/database/schemas lib/database"
|
||||
},
|
||||
"dependencies": {
|
||||
"bcrypt": "^5.0.1",
|
||||
"body-parser": "~1.18.2",
|
||||
"cookie-parser": "^1.4.6",
|
||||
"express": "~4.16.0",
|
||||
"form-data": "^2.5.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"km-moviedb": "^0.2.12",
|
||||
"python-shell": "^0.5.0",
|
||||
"raven": "^2.4.2",
|
||||
"redis": "^3.0.2",
|
||||
"sqlite3": "^5.0.1",
|
||||
"typescript": "^4.7.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/register": "^7.5.5",
|
||||
"@types/node": "^18.7.8",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"chai": "^4.3.6",
|
||||
"chai-http": "^4.3.0",
|
||||
"coveralls": "^3.0.5",
|
||||
"documentation": "^12.0.3",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-config-airbnb-base": "^15.0.0",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"eslint-plugin-mocha": "10.1.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"istanbul": "^0.4.5",
|
||||
"mocha": "8.4.0",
|
||||
"mocha-lcov-reporter": "^1.3.0",
|
||||
"nyc": "15.1.0",
|
||||
"prettier": "^2.7.1"
|
||||
}
|
||||
}
|
||||
44
scripts/updateRequestsInPlex.js
Normal file
44
scripts/updateRequestsInPlex.js
Normal file
@@ -0,0 +1,44 @@
|
||||
const Plex = require("src/plex/plex");
|
||||
const configuration = require("src/config/configuration").getInstance();
|
||||
const plex = new Plex(configuration.get("plex", "ip"));
|
||||
const establishedDatabase = require("src/database/database");
|
||||
|
||||
const queries = {
|
||||
getRequestsNotYetInPlex: `SELECT * FROM requests WHERE status = 'requested' OR status = 'downloading'`,
|
||||
saveNewStatus: `UPDATE requests SET status = ? WHERE id IS ? and type IS ?`
|
||||
};
|
||||
|
||||
const getByStatus = () =>
|
||||
establishedDatabase.all(queries.getRequestsNotYetInPlex);
|
||||
|
||||
const checkIfRequestExistInPlex = async request => {
|
||||
request.existsInPlex = await plex.existsInPlex(request);
|
||||
return request;
|
||||
};
|
||||
|
||||
const commitNewStatus = (status, id, type, title) => {
|
||||
console.log(type, title, "updated to:", status);
|
||||
return establishedDatabase.run(queries.saveNewStatus, [status, id, type]);
|
||||
};
|
||||
|
||||
const getNewRequestMatchesInPlex = async () => {
|
||||
const requests = await getByStatus();
|
||||
|
||||
return Promise.all(requests.map(checkIfRequestExistInPlex))
|
||||
.catch(error =>
|
||||
console.log("error from checking plex for existance:", error)
|
||||
)
|
||||
.then(matchedRequests =>
|
||||
matchedRequests.filter(request => request.existsInPlex)
|
||||
);
|
||||
};
|
||||
|
||||
const updateMatchInDb = (match, status) => {
|
||||
return commitNewStatus(status, match.id, match.type, match.title);
|
||||
};
|
||||
|
||||
getNewRequestMatchesInPlex()
|
||||
.then(newMatches =>
|
||||
Promise.all(newMatches.map(match => updateMatchInDb(match, "downloaded")))
|
||||
)
|
||||
.then(() => process.exit(0));
|
||||
@@ -1,14 +0,0 @@
|
||||
{
|
||||
"extends": [
|
||||
"airbnb-base"
|
||||
],
|
||||
"rules": {
|
||||
"indent": ["error", 3],
|
||||
"prefer-destructuring": 0,
|
||||
"camelcase": 0,
|
||||
"import/no-unresolved": 0,
|
||||
"import/no-extraneous-dependencies": 0,
|
||||
"object-shorthand": 0,
|
||||
"comma-dangle": 0
|
||||
}
|
||||
}
|
||||
66
seasoned_api/.gitignore
vendored
66
seasoned_api/.gitignore
vendored
@@ -1,66 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (https://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
|
||||
# - - - - -
|
||||
# My own gitignore files and folders
|
||||
shows.db
|
||||
conf/development.json
|
||||
|
||||
# conf/development-prod.json
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"database": {
|
||||
"host": "../shows.db"
|
||||
},
|
||||
"webserver": {
|
||||
"port": 31459
|
||||
},
|
||||
"tmdb": {
|
||||
"apiKey": ""
|
||||
},
|
||||
"plex": {
|
||||
"ip": ""
|
||||
},
|
||||
"raven": {
|
||||
"DSN": ""
|
||||
},
|
||||
"authentication": {
|
||||
"secret": "secret"
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"database": {
|
||||
"host": ":memory:"
|
||||
},
|
||||
"webserver": {
|
||||
"port": 31400
|
||||
},
|
||||
"tmdb": {
|
||||
"apiKey": "bogus-api-key"
|
||||
},
|
||||
"plex": {
|
||||
"ip": "0.0.0.0"
|
||||
},
|
||||
"raven": {
|
||||
"DSN": ""
|
||||
},
|
||||
"authentication": {
|
||||
"secret": "secret"
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
{
|
||||
"name": "seasoned-api",
|
||||
"description": "Packages needed to build and commands to run seasoned api node server.",
|
||||
"license": {
|
||||
"type": "MIT",
|
||||
"url": "https://www.opensource.org/licenses/mit-license.php"
|
||||
},
|
||||
"main": "webserver/server.js",
|
||||
"scripts": {
|
||||
"start": "cross-env SEASONED_CONFIG=conf/development.json PROD=true NODE_PATH=. babel-node src/webserver/server.js",
|
||||
"test": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. mocha --require @babel/register --recursive test/unit test/system",
|
||||
"coverage": "cross-env SEASONED_CONFIG=conf/test.json NODE_PATH=. nyc mocha --require @babel/register --recursive test && nyc report --reporter=text-lcov | coveralls",
|
||||
"lint": "./node_modules/.bin/eslint src/",
|
||||
"update": "cross-env SEASONED_CONFIG=conf/development.json NODE_PATH=. node src/plex/updateRequestsInPlex.js",
|
||||
"docs": "yarn apiDocs; yarn classDocs",
|
||||
"apiDocs": "",
|
||||
"classDocs": "./script/generate-class-docs.sh"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^0.18.0",
|
||||
"bcrypt": "^3.0.6",
|
||||
"body-parser": "~1.18.2",
|
||||
"cross-env": "~5.1.4",
|
||||
"express": "~4.16.0",
|
||||
"jsonwebtoken": "^8.2.0",
|
||||
"km-moviedb": "^0.2.12",
|
||||
"node-cache": "^4.1.1",
|
||||
"node-fetch": "^2.6.0",
|
||||
"python-shell": "^0.5.0",
|
||||
"raven": "^2.4.2",
|
||||
"request": "^2.87.0",
|
||||
"request-promise": "^4.2",
|
||||
"sqlite3": "^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.5.5",
|
||||
"@babel/node": "^7.5.5",
|
||||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/register": "^7.5.5",
|
||||
"@types/node": "^12.6.8",
|
||||
"coveralls": "^3.0.5",
|
||||
"documentation": "^12.0.3",
|
||||
"eslint": "^4.9.0",
|
||||
"eslint-config-airbnb-base": "^12.1.0",
|
||||
"eslint-plugin-import": "^2.8.0",
|
||||
"istanbul": "^0.4.5",
|
||||
"mocha": "^6.2.0",
|
||||
"mocha-lcov-reporter": "^1.3.0",
|
||||
"nyc": "^11.6.0",
|
||||
"supertest": "^3.0.0",
|
||||
"supertest-as-promised": "^4.0.1",
|
||||
"typescript": "^3.5.3"
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
const path = require('path');
|
||||
const Field = require('./field.js');
|
||||
|
||||
let instance = null;
|
||||
|
||||
class Config {
|
||||
constructor() {
|
||||
this.location = Config.determineLocation();
|
||||
this.fields = require(`${this.location}`);
|
||||
}
|
||||
|
||||
static getInstance() {
|
||||
if (instance == null) {
|
||||
instance = new Config();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
static determineLocation() {
|
||||
return path.join(__dirname, '..', '..', process.env.SEASONED_CONFIG);
|
||||
}
|
||||
|
||||
get(section, option) {
|
||||
if (this.fields[section] === undefined || this.fields[section][option] === undefined) {
|
||||
throw new Error(`Filed "${section} => ${option}" does not exist.`);
|
||||
}
|
||||
|
||||
const field = new Field(this.fields[section][option]);
|
||||
|
||||
if (field.value === '') {
|
||||
const envField = process.env[['SEASONED', section.toUpperCase(), option.toUpperCase()].join('_')];
|
||||
if (envField !== undefined && envField.length !== 0) { return envField; }
|
||||
}
|
||||
|
||||
if (field.value === undefined) {
|
||||
throw new Error(`${section} => ${option} is empty.`);
|
||||
}
|
||||
|
||||
return field.value;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Config;
|
||||
@@ -1,15 +0,0 @@
|
||||
class EnvironmentVariables {
|
||||
constructor(variables) {
|
||||
this.variables = variables || process.env;
|
||||
}
|
||||
|
||||
get(variable) {
|
||||
return this.variables[variable];
|
||||
}
|
||||
|
||||
has(variable) {
|
||||
return this.get(variable) !== undefined;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = EnvironmentVariables;
|
||||
@@ -1,49 +0,0 @@
|
||||
const Filters = require('./filters.js');
|
||||
const EnvironmentVariables = require('./environmentVariables.js');
|
||||
|
||||
class Field {
|
||||
constructor(rawValue, environmentVariables) {
|
||||
this.rawValue = rawValue;
|
||||
this.filters = new Filters(rawValue);
|
||||
this.valueWithoutFilters = this.filters.removeFiltersFromValue();
|
||||
this.environmentVariables = new EnvironmentVariables(environmentVariables);
|
||||
}
|
||||
|
||||
get value() {
|
||||
if (this.filters.isEmpty()) {
|
||||
return this.valueWithoutFilters;
|
||||
}
|
||||
|
||||
if (this.filters.has('base64') && !this.filters.has('env')) {
|
||||
return Field.base64Decode(this.valueWithoutFilters);
|
||||
}
|
||||
|
||||
if (this.environmentVariables.has(this.valueWithoutFilters) &&
|
||||
this.environmentVariables.get(this.valueWithoutFilters) === '') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (!this.filters.has('base64') && this.filters.has('env')) {
|
||||
if (this.environmentVariables.has(this.valueWithoutFilters)) {
|
||||
return this.environmentVariables.get(this.valueWithoutFilters);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (this.filters.has('env') && this.filters.has('base64')) {
|
||||
if (this.environmentVariables.has(this.valueWithoutFilters)) {
|
||||
const encodedEnvironmentVariable = this.environmentVariables.get(this.valueWithoutFilters);
|
||||
return Field.base64Decode(encodedEnvironmentVariable);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.valueWithoutFilters;
|
||||
}
|
||||
|
||||
static base64Decode(string) {
|
||||
return new Buffer(string, 'base64').toString('utf-8');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Field;
|
||||
@@ -1,34 +0,0 @@
|
||||
class Filters {
|
||||
constructor(value) {
|
||||
this.value = value;
|
||||
this.delimiter = '|';
|
||||
}
|
||||
|
||||
get filters() {
|
||||
return this.value.split(this.delimiter).slice(0, -1);
|
||||
}
|
||||
|
||||
isEmpty() {
|
||||
return !this.hasValidType() || this.value.length === 0;
|
||||
}
|
||||
|
||||
has(filter) {
|
||||
return this.filters.includes(filter);
|
||||
}
|
||||
|
||||
hasValidType() {
|
||||
return (typeof this.value === 'string');
|
||||
}
|
||||
|
||||
removeFiltersFromValue() {
|
||||
if (this.hasValidType() === false) {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
let filtersCombined = this.filters.join(this.delimiter);
|
||||
filtersCombined += this.filters.length >= 1 ? this.delimiter : '';
|
||||
return this.value.replace(filtersCombined, '');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Filters;
|
||||
@@ -1,14 +0,0 @@
|
||||
const configuration = require('src/config/configuration').getInstance();
|
||||
const SqliteDatabase = require('src/database/sqliteDatabase');
|
||||
|
||||
const database = new SqliteDatabase(configuration.get('database', 'host'));
|
||||
/**
|
||||
* This module establishes a connection to the database
|
||||
* specified in the confgiuration file. It tries to setup
|
||||
* the required tables after successfully connecting.
|
||||
* If the tables already exists, it simply proceeds.
|
||||
*/
|
||||
Promise.resolve()
|
||||
.then(() => database.setUp());
|
||||
|
||||
module.exports = database;
|
||||
@@ -1,119 +0,0 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const sqlite3 = require('sqlite3').verbose();
|
||||
|
||||
class SqliteDatabase {
|
||||
constructor(host) {
|
||||
this.host = host;
|
||||
this.connection = new sqlite3.Database(this.host);
|
||||
this.schemaDirectory = path.join(__dirname, 'schemas');
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the database.
|
||||
* @returns {Promise} succeeds if connection was established
|
||||
*/
|
||||
// connect() {
|
||||
// let database = ;
|
||||
// this.connection = database;
|
||||
// return database;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Run a SQL query against the database.
|
||||
* @param {String} sql SQL query
|
||||
* @param {Array} parameters in the SQL query
|
||||
* @returns {Promise}
|
||||
*/
|
||||
run(sql, parameters) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.connection.run(sql, parameters, (error, result) => {
|
||||
if (error)
|
||||
reject(error);
|
||||
resolve(result)
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a SQL query against the database and retrieve all the rows.
|
||||
* @param {String} sql SQL query
|
||||
* @param {Array} parameters in the SQL query
|
||||
* @returns {Promise}
|
||||
*/
|
||||
all(sql, parameters) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.connection.all(sql, parameters, (err, rows) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(rows);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a SQL query against the database and retrieve one row.
|
||||
* @param {String} sql SQL query
|
||||
* @param {Array} parameters in the SQL query
|
||||
* @returns {Promise}
|
||||
*/
|
||||
get(sql, parameters) {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.connection.get(sql, parameters, (err, rows) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
}
|
||||
resolve(rows);
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a SQL query against the database and retrieve the status.
|
||||
* @param {String} sql SQL query
|
||||
* @param {Array} parameters in the SQL query
|
||||
* @returns {Promise}
|
||||
*/
|
||||
execute(sql) {
|
||||
return new Promise(resolve => {
|
||||
this.connection.exec(sql, (err, database) => {
|
||||
if (err) {
|
||||
console.log('ERROR: ', err);
|
||||
reject(err);
|
||||
}
|
||||
resolve();
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup the database by running setup.sql file in schemas/.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
setUp() {
|
||||
const setupSchema = this.readSqlFile('setup.sql');
|
||||
return Promise.resolve(this.execute(setupSchema));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tears down the database by running tearDown.sql file in schemas/.
|
||||
* @returns {Promise}
|
||||
*/
|
||||
tearDown() {
|
||||
const tearDownSchema = this.readSqlFile('teardown.sql');
|
||||
return Promise.resolve(this.execute(tearDownSchema));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file contents of a SQL file in schemas/.
|
||||
* @returns {String}
|
||||
*/
|
||||
readSqlFile(filename) {
|
||||
const schemaPath = path.join(this.schemaDirectory, filename);
|
||||
const schema = fs.readFileSync(schemaPath).toString('utf-8');
|
||||
return schema;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SqliteDatabase;
|
||||
@@ -1,9 +0,0 @@
|
||||
|
||||
class GitRepository {
|
||||
static dumpHook(body) {
|
||||
/* eslint-disable no-console */
|
||||
console.log(body);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GitRepository;
|
||||
@@ -1,19 +0,0 @@
|
||||
|
||||
class Media {
|
||||
constructor(title, year, type) {
|
||||
this.title = title;
|
||||
this.year = year;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `N: ${this.title} | Y: ${this.year} | T: ${this.type}`;
|
||||
}
|
||||
|
||||
print() {
|
||||
/* eslint-disable no-console */
|
||||
console.log(this.toString());
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Media;
|
||||
@@ -1,15 +0,0 @@
|
||||
class MediaInfo {
|
||||
constructor() {
|
||||
this.duration = undefined;
|
||||
this.height = undefined;
|
||||
this.width = undefined;
|
||||
this.bitrate = undefined;
|
||||
this.resolution = undefined;
|
||||
this.framerate = undefined;
|
||||
this.protocol = undefined;
|
||||
this.container = undefined;
|
||||
this.audioCodec = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = MediaInfo;
|
||||
@@ -1,12 +0,0 @@
|
||||
class Player {
|
||||
constructor(device, address) {
|
||||
this.device = device;
|
||||
this.ip = address;
|
||||
this.platform = undefined;
|
||||
this.product = undefined;
|
||||
this.title = undefined;
|
||||
this.state = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Player;
|
||||
@@ -1,22 +0,0 @@
|
||||
|
||||
const Media = require('src/media_classes/media');
|
||||
|
||||
class Plex extends Media {
|
||||
constructor(title, year, type, summary, poster_path, background_path, added, seasons, episodes) {
|
||||
super(title, year, type);
|
||||
|
||||
this.summary = summary;
|
||||
this.poster_path = poster_path;
|
||||
this.background_path = background_path;
|
||||
this.added = added;
|
||||
|
||||
this.seasons = seasons;
|
||||
this.episodes = episodes;
|
||||
}
|
||||
|
||||
print() {
|
||||
super.print();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Plex;
|
||||
@@ -1,33 +0,0 @@
|
||||
|
||||
const Media = require('src/media_classes/media');
|
||||
|
||||
class TMDB extends Media {
|
||||
// constructor(...args) {
|
||||
constructor(title, year, type, id, summary, poster_path, background_path, popularity, score, release_status, tagline, seasons, episodes) {
|
||||
super(title, year, type);
|
||||
|
||||
this.id = id;
|
||||
this.summary = summary;
|
||||
this.poster_path = poster_path;
|
||||
this.background_path = background_path;
|
||||
this.popularity = popularity;
|
||||
this.score = score;
|
||||
|
||||
this.release_status = release_status;
|
||||
this.tagline = tagline;
|
||||
|
||||
this.seasons = seasons;
|
||||
this.episodes = episodes;
|
||||
}
|
||||
|
||||
toString() {
|
||||
return `${super.toString()} | ID: ${this.id}`;
|
||||
}
|
||||
|
||||
print() {
|
||||
/* eslint-disable no-console */
|
||||
console.log(this.toString());
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TMDB;
|
||||
@@ -1,8 +0,0 @@
|
||||
class User {
|
||||
constructor(id, title) {
|
||||
this.id = id;
|
||||
this.title = title;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = User;
|
||||
@@ -1,84 +0,0 @@
|
||||
const assert = require('assert');
|
||||
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);
|
||||
if (options.protocol.includes('magnet'))
|
||||
resolve(url)
|
||||
|
||||
http.get(options, (res) => {
|
||||
if (res.statusCode == 301 || res.statusCode == 302) {
|
||||
resolve(res.headers.location)
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async function find(searchterm, callback) {
|
||||
const options = {
|
||||
pythonPath: '../torrent_search/env/bin/python3',
|
||||
scriptPath: '../torrent_search',
|
||||
args: [searchterm, '-s', 'jackett', '-f', '--print']
|
||||
}
|
||||
|
||||
PythonShell.run('torrentSearch/search.py', options, callback);
|
||||
// PythonShell does not support return
|
||||
}
|
||||
|
||||
|
||||
async function callPythonAddMagnet(url, callback) {
|
||||
getMagnetFromURL(url)
|
||||
.then((magnet) => {
|
||||
const options = {
|
||||
pythonPath: '../delugeClient/env/bin/python3',
|
||||
scriptPath: '../delugeClient',
|
||||
args: ['add', magnet]
|
||||
};
|
||||
|
||||
PythonShell.run('deluge_cli.py', options, callback);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
throw new Error(err);
|
||||
})
|
||||
}
|
||||
|
||||
async function SearchPiratebay(query) {
|
||||
return await new Promise((resolve, reject) => find(query, (err, results) => {
|
||||
if (err) {
|
||||
console.log('THERE WAS A FUCKING ERROR!\n', err);
|
||||
reject(Error('There was a error when searching for torrents'));
|
||||
}
|
||||
if (results) {
|
||||
resolve(JSON.parse(results, null, '\t'));
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
async function AddMagnet(magnet, name, tmdb_id) {
|
||||
return await new Promise((resolve, reject) => callPythonAddMagnet(magnet, (err, results) => {
|
||||
if (err) {
|
||||
/* eslint-disable no-console */
|
||||
console.log(err);
|
||||
reject(Error('Enable to add torrent', err))
|
||||
}
|
||||
/* 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 });
|
||||
}));
|
||||
}
|
||||
|
||||
module.exports = { SearchPiratebay, AddMagnet };
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user