From 2a32fd445dcd34d0ef84bf536b764cc334e70d64 Mon Sep 17 00:00:00 2001 From: "mike.rode" Date: Tue, 19 Feb 2019 18:51:56 -0600 Subject: [PATCH] Refactor plexApi to remove class dependency. --- package-lock.json | 56 ++++++++++-- package.json | 3 + server/controllers/apis/plex/index.js | 2 + server/services/plexApi/auth.js | 10 +-- server/services/plexApi/index.js | 19 +++-- server/services/plexApi/plexApi.js | 82 +++++++++--------- .../services/plexApi/mocks/plexResponses.js | 85 +++++++++++++++++++ test/server/services/plexApi/plexApi.test.js | 36 ++++---- 8 files changed, 211 insertions(+), 82 deletions(-) diff --git a/package-lock.json b/package-lock.json index ef0297b..0c26bec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1314,6 +1314,11 @@ "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", "dev": true }, + "btoa": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz", + "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==" + }, "buffer-shims": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", @@ -9984,6 +9989,13 @@ "request": "^2.87.0", "uuid": "2.0.2", "xml2js": "0.4.16" + }, + "dependencies": { + "uuid": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.2.tgz", + "integrity": "sha1-SL1WmPBnfjx5AaHEbvFbFkN5RyY=" + } } }, "plex-api-credentials": { @@ -9995,6 +10007,18 @@ "plex-api-headers": "1.1.0", "request-promise": "^3.0.0", "xml2js": "^0.4.16" + }, + "dependencies": { + "request-promise": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-3.0.0.tgz", + "integrity": "sha1-vh7bJvQcSc0dVlbGdT1oQqEkn0Y=", + "requires": { + "bluebird": "^3.3", + "lodash": "^4.6.1", + "request": "^2.34" + } + } } }, "plex-api-headers": { @@ -10352,13 +10376,22 @@ } }, "request-promise": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-3.0.0.tgz", - "integrity": "sha1-vh7bJvQcSc0dVlbGdT1oQqEkn0Y=", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.4.tgz", + "integrity": "sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==", "requires": { - "bluebird": "^3.3", - "lodash": "^4.6.1", - "request": "^2.34" + "bluebird": "^3.5.0", + "request-promise-core": "1.1.2", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "request-promise-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", + "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", + "requires": { + "lodash": "^4.17.11" } }, "require-main-filename": { @@ -10890,6 +10923,11 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" + }, "strict-uri-encode": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", @@ -11617,9 +11655,9 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, "uuid": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.2.tgz", - "integrity": "sha1-SL1WmPBnfjx5AaHEbvFbFkN5RyY=" + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", + "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" }, "v8flags": { "version": "2.1.1", diff --git a/package.json b/package.json index f48dc27..7830ef9 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "dependencies": { "axios": "^0.18.0", "body-parser": "^1.18.3", + "btoa": "^1.2.1", "build-url": "^1.3.2", "cors": "^2.8.5", "custom-env": "^1.0.0", @@ -24,8 +25,10 @@ "onchange": "^5.2.0", "pg": "^7.8.0", "plex-api": "^5.2.1", + "request-promise": "^4.2.4", "sequelize": "^4.42.0", "tdaw": "^1.3.0", + "uuid": "^3.3.2", "xml2json": "^0.11.2" }, "devDependencies": { diff --git a/server/controllers/apis/plex/index.js b/server/controllers/apis/plex/index.js index 3dc12fb..734f648 100644 --- a/server/controllers/apis/plex/index.js +++ b/server/controllers/apis/plex/index.js @@ -3,6 +3,8 @@ import plexService from '../../../services/plexApi'; const router = Router(); +router.get('/auth', plexService.getAuthToken); + // users router.get('/users', plexService.getUsers); diff --git a/server/services/plexApi/auth.js b/server/services/plexApi/auth.js index 2ad1a00..2bac11b 100644 --- a/server/services/plexApi/auth.js +++ b/server/services/plexApi/auth.js @@ -17,11 +17,11 @@ const encryptUserCreds = (username, password) => { return btoa(creds); }; -const fetchToken = (username, password) => { - request.post(options(username, password)).then(res => { - const token = res.match(rxAuthToken)[1]; - return token; - }); +const fetchToken = async (username, password) => { + const res = await request.post(options(username, password)); + console.log(res); + const token = res.match(rxAuthToken)[1]; + return token; }; export default fetchToken; diff --git a/server/services/plexApi/index.js b/server/services/plexApi/index.js index 5c83f4d..d307b0e 100644 --- a/server/services/plexApi/index.js +++ b/server/services/plexApi/index.js @@ -1,27 +1,35 @@ -import plexApiClient from './plexApi'; +import plexApi from './plexApi'; import importData from './importData'; +import auth from './auth'; +import helpers from './helpers'; + +const getAuthToken = async (req, res) => { + const {username} = req.query; + const {password} = req.query; + + auth(username, password).then(data => { + console.log(data); + return res.json(data); + }); +}; const getUsers = async (req, res) => { - const plexApi = plexApiClient(); const users = await plexApi.getUsers(); res.json(users); }; const getMostWatched = async (req, res) => { - const plexApi = plexApiClient(); const mostWatched = await plexApi.getMostWatched(req); res.json(mostWatched); }; const getSections = async (req, res) => { - const plexApi = plexApiClient(); const sections = await plexApi.getSections(); res.json(sections); }; const getLibraryDataBySection = async (req, res) => { try { - const plexApi = plexApiClient(); const sections = await plexApi.getLibraryDataBySection(req); res.json(sections); } catch (error) { @@ -53,4 +61,5 @@ export default { importSections, importLibraries, importMostWatched, + getAuthToken, }; diff --git a/server/services/plexApi/plexApi.js b/server/services/plexApi/plexApi.js index 14ab725..b7cbdf6 100644 --- a/server/services/plexApi/plexApi.js +++ b/server/services/plexApi/plexApi.js @@ -1,37 +1,29 @@ import axios from 'axios'; -import buildUrl from 'build-url'; +import buildUrlPack from 'build-url'; import config from '../../../config'; import formatResponse from './helpers'; -function PlexApiClient(options) { - this.setOptions(options); -} - -PlexApiClient.prototype.setOptions = function(options) { - this.options = options || {}; -}; - -PlexApiClient.prototype.getUsersUrlParams = function() { +const getUsersUrlParams = function() { return { host: config.plex.plexApiUrl, path: '/users', queryParams: { - 'X-Plex-Token': this.options.token || config.plex.token, + 'X-Plex-Token': config.plex.token, }, }; }; -PlexApiClient.prototype.getSectionsUrlParams = function() { +const getSectionsUrlParams = function() { return { host: config.plex.plexServerUrl, path: '/library/sections', queryParams: { - 'X-Plex-Token': this.options.token || config.plex.token, + 'X-Plex-Token': config.plex.token, }, }; }; -PlexApiClient.prototype.mostWatchedUrlParams = function(req) { +const mostWatchedUrlParams = function(req) { return { host: config.plex.plexServerUrl, path: '/library/all/top', @@ -41,40 +33,40 @@ PlexApiClient.prototype.mostWatchedUrlParams = function(req) { ...((req && (req.query.limit && {limit: req.query.limit})) || { limit: 10, }), - 'X-Plex-Token': this.options.token || config.plex.token, + 'X-Plex-Token': config.plex.token, }, }; }; -PlexApiClient.prototype.getLibraryDataBySectionUrlParams = function(req) { +const getLibraryDataBySectionUrlParams = function(req) { const sectionId = req.sectionId || req.params.id; return { host: config.plex.plexServerUrl, path: `/library/sections/${sectionId}/all`, queryParams: { - 'X-Plex-Token': this.options.token || config.plex.token, + 'X-Plex-Token': config.plex.token, }, }; }; -PlexApiClient.prototype.buildUrl = function(urlParams) { +const buildUrl = function(urlParams) { try { const params = urlParams; const {host} = params; delete params.host; const urlHash = params; - return buildUrl(host, urlHash); + return buildUrlPack(host, urlHash); } catch (error) { console.log(error); return error; } }; -PlexApiClient.prototype.request = async function(url) { +const request = async function(url) { console.log('Request URL', url); return new Promise((resolve, reject) => { - const httpClient = this.options.httpClient || axios; + const httpClient = axios; httpClient .get(url) .then(response => { @@ -97,43 +89,47 @@ PlexApiClient.prototype.request = async function(url) { }); }; -PlexApiClient.prototype.getUsers = async function() { - const urlParams = this.getUsersUrlParams(); - const getUsersUrl = this.buildUrl(urlParams); - const response = await this.request(getUsersUrl); +const getUsers = async function() { + const urlParams = getUsersUrlParams(); + const getUsersUrl = buildUrl(urlParams); + const response = await request(getUsersUrl); return response.MediaContainer.User; }; -PlexApiClient.prototype.getMostWatched = async function(req) { - const urlParams = this.mostWatchedUrlParams(req); - const mostWatchedUrl = this.buildUrl(urlParams); - const response = await this.request(mostWatchedUrl); +const getMostWatched = async function(req) { + const urlParams = mostWatchedUrlParams(req); + const mostWatchedUrl = buildUrl(urlParams); + const response = await request(mostWatchedUrl); console.log(response.MediaContainer.Metadata); return response.MediaContainer.Metadata; }; -PlexApiClient.prototype.getSections = async function() { - const urlParams = this.getSectionsUrlParams(); - const getSectionsUrl = this.buildUrl(urlParams); - const response = await this.request(getSectionsUrl); +const getSections = async function() { + const urlParams = getSectionsUrlParams(); + const getSectionsUrl = buildUrl(urlParams); + const response = await request(getSectionsUrl); return response.MediaContainer.Directory; }; -PlexApiClient.prototype.getLibraryDataBySection = async function(req) { +const getLibraryDataBySection = async function(req) { try { - console.log('Query', req.query); - const urlParams = this.getLibraryDataBySectionUrlParams(req); - const getLibraryDataBySectionUrl = this.buildUrl(urlParams); - const response = await this.request(getLibraryDataBySectionUrl); + const urlParams = getLibraryDataBySectionUrlParams(req); + const getLibraryDataBySectionUrl = buildUrl(urlParams); + const response = await request(getLibraryDataBySectionUrl); return response.MediaContainer.Metadata; } catch (error) { - console.log(error); return error; } }; -const plexApiClient = (options = []) => { - return new PlexApiClient(options); +export default { + getUsers, + getMostWatched, + getSections, + getLibraryDataBySection, + getUsersUrlParams, + getLibraryDataBySectionUrlParams, + getSectionsUrlParams, + buildUrl, + request, }; - -export default plexApiClient; diff --git a/test/server/services/plexApi/mocks/plexResponses.js b/test/server/services/plexApi/mocks/plexResponses.js index e881ae6..a0605f7 100644 --- a/test/server/services/plexApi/mocks/plexResponses.js +++ b/test/server/services/plexApi/mocks/plexResponses.js @@ -3794,4 +3794,89 @@ export default { ], }, }, + authResponse: ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mjrode + michaelrode44@gmail.com + 2014-01-03 03:05:51 UTC + testPlexApiToken + `, }; diff --git a/test/server/services/plexApi/plexApi.test.js b/test/server/services/plexApi/plexApi.test.js index 28702ea..34ac409 100644 --- a/test/server/services/plexApi/plexApi.test.js +++ b/test/server/services/plexApi/plexApi.test.js @@ -4,47 +4,44 @@ import chai from 'chai'; import chaiHttp from 'chai-http'; import nock from 'nock'; import plexResponses from './mocks/plexResponses'; -import plexApiClient from '../../../../server/services/plexApi/plexApi'; +import plexApi from '../../../../server/services/plexApi/plexApi'; const should = chai.should(); describe('plexApi', () => { - it('sets options when passed valid options object', () => { - const options = { token: 'plexToken' }; - const result = plexApiClient(options).options; - result.should.deep.equal({ - token: 'plexToken', - }); - }); + // it('sets options when passed valid options object', () => { + // const options = { token: 'testPlexApiToken' }; + // const result = plexApi.options; + // result.should.deep.equal({ + // token: 'testPlexApiToken', + // }); + // }); it('return url params object', () => { - const options = { token: 'plexToken' }; - const result = plexApiClient(options).getUsersUrlParams(); + const result = plexApi.getUsersUrlParams(); result.should.deep.equal({ host: 'https://plex.tv/api', path: '/users', queryParams: { - 'X-Plex-Token': 'plexToken', + 'X-Plex-Token': 'testPlexApiToken', }, }); }); it('returns url', () => { - const options = { token: 'plexToken' }; - const PlexApi = plexApiClient(options); + const PlexApi = plexApi; const urlParams = PlexApi.getUsersUrlParams(); const url = PlexApi.buildUrl(urlParams); - url.should.equal('https://plex.tv/api/users?X-Plex-Token=plexToken'); + url.should.equal('https://plex.tv/api/users?X-Plex-Token=testPlexApiToken'); }); it('returns users', async () => { const usersResponse = `${__dirname}/mocks/getUsersResponse.xml`; nock('https://plex.tv') - .get('/api/users?X-Plex-Token=plexToken') + .get('/api/users?X-Plex-Token=testPlexApiToken') .replyWithFile(200, usersResponse, { 'Content-Type': 'text/xml' }); - const options = { token: 'plexToken' }; - const PlexApi = plexApiClient(options); + const PlexApi = plexApi; const urlParams = PlexApi.getUsersUrlParams(); const url = PlexApi.buildUrl(urlParams); const result = await PlexApi.request(url); @@ -54,11 +51,10 @@ describe('plexApi', () => { it('returns users using getUsers', async () => { const usersResponse = `${__dirname}/mocks/getUsersResponse.xml`; nock('https://plex.tv') - .get('/api/users?X-Plex-Token=plexToken') + .get('/api/users?X-Plex-Token=testPlexApiToken') .replyWithFile(200, usersResponse, { 'Content-Type': 'text/xml' }); - const options = { token: 'plexToken' }; - const PlexApi = plexApiClient(options); + const PlexApi = plexApi; const result = await PlexApi.getUsers(); result.should.deep.equal(plexResponses.getUsersParsed); });