Skip to content

Commit 80da13d

Browse files
committed
Proof of concept - can get list of shows On Deck!
1 parent 298f1c8 commit 80da13d

7 files changed

+164
-17
lines changed

.npmignore

+3
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@ Gruntfile.js
22
dist
33
*.bat
44
docs
5+
.idea
6+
coverage
7+
test

deploy.bat

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,6 @@ rmdir dist\install /S /Q
33
mkdir dist\install
44
call npm install --prefix dist\install .
55
del dist\dist.zip
6-
7z a dist\dist.zip .\dist\install\node_modules\alexa-20q\*
6+
7z a dist\dist.zip .\dist\install\node_modules\alexa-plex\*
77
echo Function zipped. Updating...
88
aws lambda update-function-code --zip-file fileb://dist\dist.zip --function-name alexa-plex

index.js

+61
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,73 @@
1+
require('dotenv').load();
12
var alexa = require('alexa-app');
23
var app = new alexa.app('plex');
4+
var plexAPI = require('plex-api');
5+
var plex = new plexAPI({
6+
hostname: process.env.PMS_HOSTNAME,
7+
username: process.env.PMS_USERNAME,
8+
port: process.env.PMS_PORT,
9+
password: process.env.PMS_PASSWORD
10+
});
311

412
// Connect the alexa-app to AWS Lambda
513
exports.handler = app.lambda();
614

15+
// TODO remove for production - this is only exported for tests at the moment
16+
exports.plex = plex;
17+
718
// TODO there is no way to do any pre-logic in alexa-app to validate the appID.
819
// Need to hack something in or wait for next release.
920

1021
app.launch(function(request,response) {
1122
response.say("Plex is ready");
1223
});
24+
25+
app.intent('OnDeckIntent', function(request,response) {
26+
plex.query('/library/onDeck').then(function(result) {
27+
var shows = [];
28+
29+
for(i = 0; i < result._children.length && i < 6; i++) {
30+
shows.push(result._children[i].grandparentTitle);
31+
}
32+
33+
var showsPhrase = buildNaturalLangList(shows, 'and');
34+
35+
//console.log(result);
36+
37+
response.say("On deck you've got " + showsPhrase + '.');
38+
response.card('Plex', showsPhrase + '.', 'On Deck');
39+
response.send();
40+
});
41+
42+
return false; // This is how you tell alexa-app that this intent is async.
43+
});
44+
45+
//app.intent('StartShowIntent', function(request,response) {
46+
// plex.query('/library/metadata/4899').then(function(result) {
47+
// console.log(result);
48+
//
49+
// response.say("Placeholder");
50+
// response.card('Plex', showsPhrase + '.', 'StartShowIntent');
51+
// response.send();
52+
// });
53+
//
54+
// return false; // This is how you tell alexa-app that this intent is async.
55+
//});
56+
57+
function buildNaturalLangList(items, finalWord) {
58+
var output = '';
59+
for(var i = 0; i<items.length; i++) {
60+
if(i === 0) {
61+
output += items[i];
62+
} else if (i < items.length-1) {
63+
output += ', ' + items[i];
64+
} else {
65+
if(items.length > 2) {
66+
output += ',';
67+
}
68+
output += ' ' + finalWord + ' ' + items[i];
69+
}
70+
}
71+
72+
return output;
73+
}

intent-schema.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"intents": [
3+
{
4+
"intent": "OnDeckIntent",
5+
"slots": []
6+
}
7+
]
8+
}

package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@
2828
"mocha": "^2.2.5",
2929
"npm": "^2.12.0",
3030
"sinon": "^1.15.4",
31+
"sinon-as-promised": "^4.0.0",
3132
"sinon-chai": "^2.8.0"
3233
},
3334
"dependencies": {
3435
"alexa-app": "^2.0.0",
35-
"dotenv": "^1.2.0"
36+
"dotenv": "^1.2.0",
37+
"plex-api": "OverloadUT/node-plex-api",
38+
"plex-control": "^1.0.1"
3639
}
3740
}

test/LaunchRequest.json test/RequestTemplate.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,11 @@
1212
}
1313
},
1414
"request": {
15-
"type": "LaunchRequest",
16-
"requestId": "request5678"
15+
"type": "TemplateRequest",
16+
"requestId": "request5678",
17+
"intent": {
18+
"name": "TemplateIntent",
19+
"slots": {}
20+
}
1721
}
1822
}

test/main.js

+81-13
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,108 @@
11
/* jshint node: true */
22
process.env.NODE_ENV = 'test';
3+
//require('dotenv').config({path: './test/.env'});
4+
35
var sinon = require('sinon');
46
var chai = require('chai');
7+
var expect = require('chai').expect;
58
var sinonChai = require("sinon-chai");
69
chai.use(sinonChai);
7-
var expect = require('chai').expect;
8-
//require('dotenv').config({path: './test/.env'});
10+
require('sinon-as-promised')
911

10-
describe('Main handler basic functionality', function () {
11-
var lambda = require('../index.js');
12+
var plexAPI = require('plex-api');
1213

13-
beforeEach(function(){
14-
});
14+
var requestTemplate = require('./RequestTemplate.json');
1515

16-
afterEach(function(){
17-
});
16+
describe('Main handler basic functionality', function () {
17+
var lambda = require('../index.js');
1818

1919
//it('should reject invalid AppID', function () {
2020
// var request = require('./LaunchRequestInvalidApp.json');
2121
// // TODO reject invalid AppID
2222
//});
2323

2424
it('should handle LaunchRequest', function (done) {
25-
var request = require('./LaunchRequest.json');
25+
var request = JSON.parse(JSON.stringify(requestTemplate)); // Yes this is slow but hey it's just tests?
26+
request.request.type = 'LaunchRequest';
2627

2728
lambda.handler(request, {
2829
succeed: function(res) {
29-
console.log(res);
30+
//console.log(res);
3031
expect(res.response.shouldEndSession).to.be.true;
31-
expect(res.response.card).to.not.exist;
32-
expect(res.response.outputSpeech.text).to.contain('Plex is ready');
32+
expect(res).to.not.have.deep.property('response.card');
33+
expect(res).to.have.deep.property('response.outputSpeech.text')
34+
.that.matches(/plex is ready/i);
35+
3336
done();
3437
}, fail: function(res) {
38+
console.log(res);
3539
expect.fail();
3640
done();
3741
}
3842
});
3943
});
40-
});
44+
});
45+
46+
describe('Intents', function () {
47+
var lambda = require('../index.js');
48+
//var plex;
49+
//var plexQueryStub;
50+
var plexQuerySpy;
51+
52+
beforeEach(function() {
53+
//plex = new plexAPI('localhost');
54+
//plexQueryStub = sinon.stub(plex, 'query')
55+
// .resolves('a');
56+
plexQuerySpy = sinon.spy(lambda.plex, 'query');
57+
});
58+
59+
afterEach(function() {
60+
plexQuerySpy.restore();
61+
});
62+
63+
it('should handle OnDeck Intent', function (done) {
64+
var request = JSON.parse(JSON.stringify(requestTemplate)); // Yes this is slow but hey it's just tests?
65+
request.request.type = 'IntentRequest';
66+
request.request.intent.name = 'OnDeckIntent';
67+
68+
lambda.handler(request, {
69+
succeed: function(res) {
70+
console.log(res);
71+
expect(res.response.shouldEndSession).to.be.true;
72+
expect(res).to.have.deep.property('response.card.subtitle')
73+
.that.matches(/on deck/i);
74+
expect(res).to.have.deep.property('response.outputSpeech.text')
75+
.that.matches(/on deck/i);
76+
expect(plexQuerySpy).to.have.been.calledOnce;
77+
done();
78+
}, fail: function(res) {
79+
console.log(res);
80+
done(Error('Lambda returned fail()'));
81+
}
82+
});
83+
});
84+
85+
//it('should handle OnDeck Intent', function (done) {
86+
// var request = JSON.parse(JSON.stringify(requestTemplate)); // Yes this is slow but hey it's just tests?
87+
// request.request.type = 'IntentRequest';
88+
// request.request.intent.name = 'StartShowIntent';
89+
//
90+
// lambda.handler(request, {
91+
// succeed: function(res) {
92+
// console.log(res);
93+
// expect(res.response.shouldEndSession).to.be.true;
94+
// expect(res).to.have.deep.property('response.card.subtitle')
95+
// .that.matches(/on deck/i);
96+
// expect(res).to.have.deep.property('response.outputSpeech.text')
97+
// .that.matches(/on deck/i);
98+
// expect(plexQuerySpy).to.have.been.calledOnce;
99+
// done();
100+
// }, fail: function(res) {
101+
// console.log(res);
102+
// done(Error('Lambda returned fail()'));
103+
// }
104+
// });
105+
//});
106+
});
107+
108+

0 commit comments

Comments
 (0)