From 8f6247d82160704a3cfb76262696957b27641e87 Mon Sep 17 00:00:00 2001 From: sct Date: Sat, 19 Sep 2020 22:13:48 +0900 Subject: [PATCH] feat(api): validate plex when settings are saved --- package.json | 4 ++ server/api/plexapi.ts | 39 +++++++++++++++ server/lib/settings.ts | 11 +++++ server/overseerr-api.yml | 5 +- server/routes/settings.ts | 31 ++++++++++-- server/types/plex-api.d.ts | 1 + yarn.lock | 99 ++++++++++++++++++++++++++++++++++++-- 7 files changed, 182 insertions(+), 8 deletions(-) create mode 100644 server/api/plexapi.ts create mode 100644 server/types/plex-api.d.ts diff --git a/package.json b/package.json index 48daab52..4055ad53 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "lodash": "^4.17.20", "next": "9.5.3", "nookies": "^2.4.0", + "plex-api": "^5.3.1", "react": "16.13.1", "react-dom": "16.13.1", "react-intl": "^5.8.1", @@ -37,6 +38,8 @@ "swagger-ui-express": "^4.1.4", "swr": "^0.3.2", "typeorm": "^0.2.26", + "uuid": "^8.3.0", + "xml2js": "^0.4.23", "yamljs": "^0.3.0" }, "devDependencies": { @@ -54,6 +57,7 @@ "@types/react-toast-notifications": "^2.4.0", "@types/react-transition-group": "^4.4.0", "@types/swagger-ui-express": "^4.1.2", + "@types/uuid": "^8.3.0", "@types/yamljs": "^0.2.31", "@typescript-eslint/eslint-plugin": "^4.0.0", "@typescript-eslint/parser": "^3.10.1", diff --git a/server/api/plexapi.ts b/server/api/plexapi.ts new file mode 100644 index 00000000..92d44a03 --- /dev/null +++ b/server/api/plexapi.ts @@ -0,0 +1,39 @@ +import NodePlexAPI from 'plex-api'; +import { getSettings } from '../lib/settings'; + +class PlexAPI { + private plexClient: typeof NodePlexAPI; + + constructor({ plexToken }: { plexToken?: string }) { + const settings = getSettings(); + + this.plexClient = new NodePlexAPI({ + hostname: settings.plex.ip, + post: settings.plex.port, + token: plexToken, + authenticator: { + authenticate: ( + _plexApi: typeof PlexAPI, + cb: (err?: string, token?: string) => void + ) => { + if (!plexToken) { + return cb('Plex Token not found!'); + } + cb(undefined, plexToken); + }, + }, + options: { + identifier: settings.clientId, + product: 'Overseerr', + deviceName: 'Overseerr', + platform: 'Overseerr', + }, + }); + } + + public async getStatus() { + return await this.plexClient.query('/'); + } +} + +export default PlexAPI; diff --git a/server/lib/settings.ts b/server/lib/settings.ts index 7625be2c..67abf17d 100644 --- a/server/lib/settings.ts +++ b/server/lib/settings.ts @@ -1,5 +1,6 @@ import fs from 'fs'; import path from 'path'; +import { v4 as uuidv4 } from 'uuid'; interface Library { id: string; @@ -47,6 +48,7 @@ interface PublicSettings { } interface AllSettings { + clientId?: string; main: MainSettings; plex: PlexSettings; radarr: RadarrSettings[]; @@ -122,6 +124,15 @@ class Settings { this.data.public = data; } + get clientId(): string { + if (!this.data.clientId) { + this.data.clientId = uuidv4(); + this.save(); + } + + return this.data.clientId; + } + /** * Settings Load * diff --git a/server/overseerr-api.yml b/server/overseerr-api.yml index 8dd2b128..49b9af6b 100644 --- a/server/overseerr-api.yml +++ b/server/overseerr-api.yml @@ -68,9 +68,11 @@ components: name: type: string example: 'Main Server' + readOnly: true machineId: type: string - example: '1234-1234-1234-1234' + example: '1234123412341234' + readOnly: true ip: type: string example: '127.0.0.1' @@ -79,6 +81,7 @@ components: example: 32400 libraries: type: array + readOnly: true items: $ref: '#/components/schemas/PlexLibrary' required: diff --git a/server/routes/settings.ts b/server/routes/settings.ts index 6f885dab..79144623 100644 --- a/server/routes/settings.ts +++ b/server/routes/settings.ts @@ -1,5 +1,8 @@ import { Router } from 'express'; import { getSettings, RadarrSettings, SonarrSettings } from '../lib/settings'; +import { getRepository } from 'typeorm'; +import { User } from '../entity/User'; +import PlexAPI from '../api/plexapi'; const settingsRoutes = Router(); @@ -24,11 +27,33 @@ settingsRoutes.get('/plex', (_req, res) => { res.status(200).json(settings.plex); }); -settingsRoutes.post('/plex', (req, res) => { +settingsRoutes.post('/plex', async (req, res, next) => { + const userRepository = getRepository(User); const settings = getSettings(); + try { + const admin = await userRepository.findOneOrFail({ + select: ['id', 'plexToken'], + order: { id: 'ASC' }, + }); - settings.plex = req.body; - settings.save(); + Object.assign(settings.plex, req.body); + + const plexClient = new PlexAPI({ plexToken: admin.plexToken }); + + const result = await plexClient.getStatus(); + + if (result?.MediaContainer?.machineIdentifier) { + settings.plex.machineId = result.MediaContainer.machineIdentifier; + settings.plex.name = result.MediaContainer.friendlyName; + + settings.save(); + } + } catch (e) { + return next({ + status: 500, + message: `Failed to connect to Plex: ${e.message}`, + }); + } return res.status(200).json(settings.plex); }); diff --git a/server/types/plex-api.d.ts b/server/types/plex-api.d.ts new file mode 100644 index 00000000..0940d3b1 --- /dev/null +++ b/server/types/plex-api.d.ts @@ -0,0 +1 @@ +declare module 'plex-api'; diff --git a/yarn.lock b/yarn.lock index 3c0604ec..427ead99 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1840,6 +1840,11 @@ "@types/express" "*" "@types/serve-static" "*" +"@types/uuid@^8.3.0": + version "8.3.0" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.0.tgz#215c231dff736d5ba92410e6d602050cce7e273f" + integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== + "@types/yamljs@^0.2.31": version "0.2.31" resolved "https://registry.yarnpkg.com/@types/yamljs/-/yamljs-0.2.31.tgz#b1a620b115c96db7b3bfdf0cf54aee0c57139245" @@ -2686,7 +2691,7 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@^3.5.5: +bluebird@^3.3.5, bluebird@^3.5.0, bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -6387,7 +6392,7 @@ lodash.zipobject@^4.1.3: resolved "https://registry.yarnpkg.com/lodash.zipobject/-/lodash.zipobject-4.1.3.tgz#b399f5aba8ff62a746f6979bf20b214f964dbef8" integrity sha1-s5n1q6j/YqdG9peb8gshT5ZNvvg= -lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20: +lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -7651,6 +7656,32 @@ please-upgrade-node@^3.2.0: dependencies: semver-compare "^1.0.0" +plex-api-credentials@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/plex-api-credentials/-/plex-api-credentials-3.0.1.tgz#60b6a43c8edb5c13e4d1a390ea5ea20fe5268809" + integrity sha512-E0PdSVSqE5rmdEFNsIvFPDJQZPdBX7UR4sgkm9HF4V8VNbX0N4elASnMuoste8i9eTh4hCIqt761NQfzl45XnQ== + dependencies: + bluebird "^3.3.5" + plex-api-headers "1.1.0" + request-promise "4.2.4" + xml2js "0.4.19" + +plex-api-headers@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/plex-api-headers/-/plex-api-headers-1.1.0.tgz#4ce364715d9648cccf2c064583279ef87c12fbf2" + integrity sha1-TONkcV2WSMzPLAZFgyee+HwS+/I= + +plex-api@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/plex-api/-/plex-api-5.3.1.tgz#1a6b218cc67c3aa617acccbf1d036616099ce0ae" + integrity sha512-WQVNOEqTCRx0/3oW5Orc+0OLAyQiDisCQ36mSVQHZOuuwXVj+l6WY9EksJzDXclp7Az3U8I/BNFDnopP1NxAFw== + dependencies: + plex-api-credentials "3.0.1" + plex-api-headers "1.1.0" + request "^2.87.0" + uuid "2.0.2" + xml2js "0.4.16" + pnp-webpack-plugin@1.6.4: version "1.6.4" resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.6.4.tgz#c9711ac4dc48a685dabafc86f8b6dd9f8df84149" @@ -8554,6 +8585,23 @@ repeat-string@^1.6.1: resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= +request-promise-core@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.2.tgz#339f6aababcafdb31c799ff158700336301d3346" + integrity sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag== + dependencies: + lodash "^4.17.11" + +request-promise@4.2.4: + version "4.2.4" + resolved "https://registry.yarnpkg.com/request-promise/-/request-promise-4.2.4.tgz#1c5ed0d71441e38ad58c7ce4ea4ea5b06d54b310" + integrity sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg== + dependencies: + bluebird "^3.5.0" + request-promise-core "1.1.2" + stealthy-require "^1.1.1" + tough-cookie "^2.3.3" + request@^2.87.0: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" @@ -9231,6 +9279,11 @@ static-extend@^0.1.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +stealthy-require@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= + stream-browserify@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-3.0.0.tgz#22b0a2850cdf6503e73085da1fc7b7d0c2122f2f" @@ -9750,7 +9803,7 @@ touch@^3.1.0: dependencies: nopt "~1.0.10" -tough-cookie@~2.5.0: +tough-cookie@^2.3.3, tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== @@ -10111,11 +10164,21 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= +uuid@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.2.tgz#48bd5698f0677e3c7901a1c46ef15b1643794726" + integrity sha1-SL1WmPBnfjx5AaHEbvFbFkN5RyY= + uuid@^3.3.2: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== +uuid@^8.3.0: + version "8.3.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.0.tgz#ab738085ca22dc9a8c92725e459b1d507df5d6ea" + integrity sha512-fX6Z5o4m6XsXBdli9g7DtWgAx+osMsRRZFKma1mIUsLCz6vRvv+pz5VNbyu9UEDzpMWulZfvpgb/cmDXVulYFQ== + v8-compile-cache@^2.0.3: version "2.1.1" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745" @@ -10337,7 +10400,23 @@ xdg-basedir@^4.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== -xml2js@^0.4.17: +xml2js@0.4.16: + version "0.4.16" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.16.tgz#f82fccd2f9540d7e0a9b5dac163e7471195c9db3" + integrity sha1-+C/M0vlUDX4Km12sFj50cRlcnbM= + dependencies: + sax ">=0.6.0" + xmlbuilder "^4.1.0" + +xml2js@0.4.19: + version "0.4.19" + resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.19.tgz#686c20f213209e94abf0d1bcf1efaa291c7827a7" + integrity sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q== + dependencies: + sax ">=0.6.0" + xmlbuilder "~9.0.1" + +xml2js@^0.4.17, xml2js@^0.4.23: version "0.4.23" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== @@ -10345,11 +10424,23 @@ xml2js@^0.4.17: sax ">=0.6.0" xmlbuilder "~11.0.0" +xmlbuilder@^4.1.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.2.1.tgz#aa58a3041a066f90eaa16c2f5389ff19f3f461a5" + integrity sha1-qlijBBoGb5DqoWwvU4n/GfP0YaU= + dependencies: + lodash "^4.0.0" + xmlbuilder@~11.0.0: version "11.0.1" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== +xmlbuilder@~9.0.1: + version "9.0.7" + resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-9.0.7.tgz#132ee63d2ec5565c557e20f4c22df9aca686b10d" + integrity sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0= + xtend@^4.0.0, xtend@^4.0.2, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"