diff --git a/Readme.md b/Readme.md index 8135f24..2dabd21 100644 --- a/Readme.md +++ b/Readme.md @@ -8,20 +8,27 @@ Small module which helps you query the Plex Media Server HTTP API. Instantiate a PlexAPI client. +The parameter can be a string representing the server's hostname, or an object with the following properties: + Options: - **hostname**: hostname where Plex Server runs - **port**: port number Plex Server is listening on (optional, default: 32400) - **username**: plex.tv username (optional / required for PlexHome) - **password**: plex.tv password (optional / required for PlexHome) -- **options**: override additional PlexHome options (optional for PlexHome) - - **identifier**: client identifier, default `generated uuid v4` - - **product**: default `App` - - **version**: default `1.0` - - **device**: default `App` +- **options**: override additional PlexHome options (optional, but recommended for PlexHome) + - **identifier**: A unique client identifier. Default is a `generated uuid v4`. *Note: you should really provide this rather than let it get generated. Every time your app runs, a new "device" will get registered on your Plex account, which can lead to poor performance once hundreds or thousands of them get created. Trust me!* + - **product**: The name of your application. Official Plex examples: `Plex Web`, `Plex Home Theater`, `Plex for Xbox One`. Default `Node.js App` + - **version**: The version of your app. Default `1.0` + - **deviceName**: The "name" of the device your app is running on. For apps like Plex Home Theater and mobile apps, it's the computer or phone's name chosen by the user. Default `Node.js App` + - **platform**: The platform your app is running on. The use of this is inconsistent in the official Plex apps. It is not displayed on the web interface. Official Plex examples: `Chrome`, `Plex Home Theater`, `Windows`. Default is `Node.js`. + - **platformVersion**: The platform version. Default is the version of Node running. + - **device**: The name of the type of computer your app is running on, usually the OS name. Official Plex examples: `Windows`, `iPhone`, `Xbox One`. Default is whatever `os.platform()` returns. + +Here's an example of what an app shows up as on the Plex web interface -If argument is a `string` it is used as the hostname. +![Plex Device Example](docs/plex-device-example.png?raw) -For those who has PlexHome enabled on their server, will have to specify their username and password used at plex.tv. +The rows in that example from top to bottom are `deviceName`, `version`, `product`, and `device`. **query(uri) : Retrieve content from URI** diff --git a/docs/plex-device-example.png b/docs/plex-device-example.png new file mode 100644 index 0000000..c75176a Binary files /dev/null and b/docs/plex-device-example.png differ diff --git a/lib/api.js b/lib/api.js index bd474c3..dfa3592 100644 --- a/lib/api.js +++ b/lib/api.js @@ -1,3 +1,4 @@ +var os = require('os'); var uuid = require('uuid'); var url = require('url'); var request = require('request'); @@ -19,6 +20,12 @@ function PlexAPI(options, deprecatedPort) { this.password = opts.password; this.options = opts.options || {}; this.options.identifier = this.options.identifier || uuid.v4(); + this.options.product = this.options.product || 'Node.js App'; + this.options.version = this.options.version || '1.0'; + this.options.device = this.options.device || os.platform(); + this.options.deviceName = this.options.deviceName || 'Node.js App'; + this.options.platform = this.options.platform || 'Node.js'; + this.options.platformVersion = this.options.platformVersion || process.version; if (typeof this.hostname !== 'string') { throw new TypeError('Invalid Plex Server hostname'); @@ -86,7 +93,14 @@ PlexAPI.prototype._request = function _request(relativeUrl, method, parseRespons method: method || 'GET', headers: { 'Accept': 'application/json', - 'X-Plex-Client-Identifier': self.getIdentifier() + 'X-Plex-Client-Identifier': self.getIdentifier(), + 'X-Plex-Product': self.options.product, + 'X-Plex-Version': self.options.version, + 'X-Plex-Device': self.options.device, + 'X-Plex-Device-Name': self.options.deviceName, + 'X-Plex-Platform': self.options.platform, + 'X-Plex-Platform-Version': self.options.platformVersion, + 'X-Plex-Provides': 'controller' } }; diff --git a/lib/auth.js b/lib/auth.js index c5f2790..d357423 100644 --- a/lib/auth.js +++ b/lib/auth.js @@ -1,11 +1,6 @@ -var os = require('os'); -var uuid = require('uuid'); var request = require('request'); var Q = require('q'); -var platform = os.platform(); -var release = os.release(); - var rxAuthToken = /authenticationToken="([^"]+)"/; function authHeaderVal(username, password) { @@ -20,12 +15,13 @@ function requestSignIn(username, password, headers) { url: 'https://plex.tv/users/sign_in.xml', headers: { 'Authorization': authHeaderVal(username, password), - 'X-Plex-Client-Identifier': headers.identifier || uuid.v4(), - 'X-Plex-Product': headers.product || 'App', - 'X-Plex-Version': headers.version || '1.0', - 'X-Plex-Device': headers.device || 'App', - 'X-Plex-Platform': platform, - 'X-Plex-Platform-Version': release, + 'X-Plex-Client-Identifier': headers.identifier, + 'X-Plex-Product': headers.product, + 'X-Plex-Version': headers.version, + 'X-Plex-Device': headers.device, + 'X-Plex-Device-Name': headers.deviceName, + 'X-Plex-Platform': headers.platform, + 'X-Plex-Platform-Version': headers.platformVersion, 'X-Plex-Provides': 'controller' } }; diff --git a/test/api-test.js b/test/api-test.js index c2ba90b..13f02b2 100644 --- a/test/api-test.js +++ b/test/api-test.js @@ -47,4 +47,37 @@ describe('Module API', function() { done(); }); }); + + it('should have configurable options that get sent in every request', function() { + api = new PlexAPI({ + hostname : 'localhost', + options: { + identifier : 'mock-identifier', + product : 'mock-product', + version : 'mock-version', + device : 'mock-device', + deviceName : 'mock-deviceName', + platform : 'mock-platform', + platformVersion: 'mock-platformVersion' + } + }); + + server.stop(); + var nockServer = server.start({ + reqheaders: { + 'X-Plex-Client-Identifier': 'mock-identifier', + 'X-Plex-Product' : 'mock-product', + 'X-Plex-Version' : 'mock-version', + 'X-Plex-Device' : 'mock-device', + 'X-Plex-Device-Name' : 'mock-deviceName', + 'X-Plex-Platform' : 'mock-platform', + 'X-Plex-Platform-Version' : 'mock-platformVersion' + } + }); + + api.query(ROOT_URL).done(function(result) { + expect(result).to.be.an('object'); + nockServer.done(); + }); + }); }); \ No newline at end of file diff --git a/test/auth-test.js b/test/auth-test.js index 1f527ad..58bc584 100644 --- a/test/auth-test.js +++ b/test/auth-test.js @@ -131,10 +131,13 @@ describe('Auth Tests', function() { it('should override default options when specified', function () { api = new PlexAPI({ hostname: 'localhost', username: 'foo', password: 'bar', options: { - identifier: 'mock-identifier', - product : 'mock-product', - version : 'mock-version', - device : 'mock-device' + identifier : 'mock-identifier', + product : 'mock-product', + version : 'mock-version', + device : 'mock-device', + deviceName : 'mock-deviceName', + platform : 'mock-platform', + platformVersion: 'mock-platformVersion' } }); @@ -143,7 +146,10 @@ describe('Auth Tests', function() { 'X-Plex-Client-Identifier': 'mock-identifier', 'X-Plex-Product' : 'mock-product', 'X-Plex-Version' : 'mock-version', - 'X-Plex-Device' : 'mock-device' + 'X-Plex-Device' : 'mock-device', + 'X-Plex-Device-Name' : 'mock-deviceName', + 'X-Plex-Platform' : 'mock-platform', + 'X-Plex-Platform-Version' : 'mock-platformVersion' } });