Skip to content

Commit f814d9f

Browse files
committed
Query for recently added media
Adds support for asking Alexa for recently added shows or movies. The intent supports querying for just shows, just movies, or for both.
1 parent ef996a9 commit f814d9f

7 files changed

Lines changed: 117 additions & 5 deletions

File tree

ask_configuration/LIBRARYTYPE.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
TV Shows
2+
Shows
3+
Movies
4+
Films

ask_configuration/intent-schema.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,15 @@
2828
"intent": "OnDeckIntent",
2929
"slots": []
3030
},
31+
{
32+
"intent": "RecentlyAddedIntent",
33+
"slots": [
34+
{
35+
"name": "libraryType",
36+
"type": "LIBRARYTYPE"
37+
}
38+
]
39+
},
3140
{
3241
"intent": "AMAZON.YesIntent"
3342
},

ask_configuration/sample-utterances.txt

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,18 @@ AuthorizeMeIntent Authorize me
66
AuthorizeMeIntent Sign in to Plex
77
AuthorizeMeIntent Link my account
88
WhatsNewIntent Release notes
9-
OnDeckIntent What's new
10-
OnDeckIntent What is new
9+
RecentlyAddedIntent What's new
10+
RecentlyAddedIntent What is new
11+
RecentlyAddedIntent What's new in {libraryType}
12+
RecentlyAddedIntent What is new in {libraryType}
13+
RecentlyAddedIntent What are my new {libraryType}
14+
RecentlyAddedIntent What are my recently added {libraryType}
15+
RecentlyAddedIntent What are the new {libraryType}
16+
RecentlyAddedIntent Latest {libraryType}
17+
RecentlyAddedIntent About the latest {libraryType}
18+
RecentlyAddedIntent Recently added {libraryType}
19+
RecentlyAddedIntent About the recently added {libraryType}
20+
RecentlyAddedIntent About recently added {libraryType}
1121
OnDeckIntent What is on deck
1222
OnDeckIntent What's on deck
1323
StartShowIntent Put on {showName}

lib/plexutils.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,20 @@ var getOnDeck = function(app, library) {
7575
}
7676
};
7777

78+
/**
79+
* Gets a list of items that have been recently added, either for all library types or a specific one.
80+
* @param {module:App~App} app
81+
* @param {?Object} library - Optional library object to ask for only items in that library
82+
* @returns {Object} JSON object of shows/movies/etc recently added
83+
*/
84+
var getRecentlyAdded = function(app, library) {
85+
if (library) {
86+
return query(app.plex.pms, library.uri + '/recentlyAdded');
87+
} else {
88+
return query(app.plex.pms, '/library/recentlyAdded');
89+
}
90+
};
91+
7892
/**
7993
* @typedef {Object} PlexAPI.Directory
8094
*/
@@ -340,7 +354,9 @@ var getShowNamesFromList = function(apiResult) {
340354
for(i = 0; i < apiResult._children.length && i < 6; i++) {
341355
if(apiResult._children[i].type == 'episode') {
342356
shows.push(apiResult._children[i].grandparentTitle);
343-
} else if (apiResult._children[i].type == 'movie') {
357+
} else if (apiResult._children[i].type == 'season') {
358+
shows.push(apiResult._children[i].parentTitle);
359+
}else if (apiResult._children[i].type == 'movie') {
344360
shows.push(apiResult._children[i].title);
345361
}
346362
}
@@ -359,6 +375,7 @@ module.exports = {
359375
getPlayers: getPlayers,
360376
startShow: startShow,
361377
getOnDeck: getOnDeck,
378+
getRecentlyAdded: getRecentlyAdded,
362379
getListOfTVShows: getListOfTVShows,
363380
getAllEpisodesOfShow: getAllEpisodesOfShow,
364381
playMedia: playMedia,

lib/states/authed.js

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,41 @@ var onDeckIntent = function(request, response) {
5454
.card("TV Shows Ready to Watch", "On Deck in your TV library: \n\n" + showListCard)
5555
.send();
5656
}).catch(function(err) {
57-
app.skill.error(err, request, response);
58-
});
57+
app.skill.error(err, request, response);
58+
});
59+
60+
return false;
61+
};
62+
63+
var recentlyAddedIntent = function (request, response) {
64+
var app = request.data._plex_app;
65+
var libraryType = request.slot('libraryType', null);
66+
var library;
67+
68+
if (libraryType === 'tv shows' || libraryType === 'shows') {
69+
library = app.user.TVLibrary;
70+
} else if (libraryType === 'movies' || libraryType === 'films') {
71+
library = app.user.MovieLibrary;
72+
}
73+
74+
plexutils.getRecentlyAdded(app, library)
75+
.then(plexutils.getShowNamesFromList)
76+
.then(function (mediaList) {
77+
if(mediaList.length === 0) {
78+
return response.say("You have not added any media recently!").send();
79+
}
80+
81+
var showListCard = mediaList.join('\n');
82+
var showSpokenListHyphenated = utils.buildNaturalLangList(mediaList, 'and', true);
83+
var libraryTypeTitle = ("Recently Added " + (utils.toTitleCase(libraryType) || '')).trim();
84+
85+
return response.say(libraryTypeTitle + ": " + showSpokenListHyphenated + '.')
86+
.card(libraryTypeTitle, showListCard)
87+
.send();
88+
})
89+
.catch(function(err) {
90+
app.skill.error(err, request, response);
91+
});
5992

6093
return false;
6194
};
@@ -220,6 +253,7 @@ var noIntent = function(request,response) {
220253
module.exports = {
221254
intents: {
222255
'OnDeckIntent': onDeckIntent,
256+
'RecentlyAddedIntent': recentlyAddedIntent,
223257
'StartShowIntent': startShowIntent,
224258
'StartRandomShowIntent': startRandomShowIntent,
225259
'StartSpecificEpisodeIntent': startSpecificEpisodeIntent,

lib/user.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,25 @@ var User = function(app, dbobject) {
3737
}
3838
});
3939

40+
Object.defineProperty(this, 'MovieLibrary', {
41+
get: function() {
42+
if (!context.dbobject.libraries) {
43+
throw new Error("Trying to get MovieLibrary with no libraries on the user record");
44+
}
45+
46+
var libraries = context.dbobject.libraries.filter(function(library) {
47+
return library.type == "movie";
48+
});
49+
50+
// For now we're going to sort by key, which more or less gives us a sort by creation date.
51+
libraries.sort(function(a, b) {
52+
return Number(a.key) - Number(b.key);
53+
});
54+
55+
return libraries[0];
56+
}
57+
});
58+
4059
Object.defineProperty(this, 'TVLibrary', {
4160
get: function() {
4261
if (!context.dbobject.libraries) {

lib/utils.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,23 @@ module.exports.buildNaturalLangList = function(items, finalWord, hyphenize) {
5555

5656
module.exports.randomInt = function(low, high) {
5757
return Math.floor(Math.random() * (high - low) + low);
58+
};
59+
60+
/**
61+
* Super simple title-casing, does not handle lots of things well. Best to just use with simple
62+
* complete words, no acronyms or anything complicated;
63+
* @param {String} string -- String to change to title case
64+
* @return {String} Title-cased string
65+
*/
66+
module.exports.toTitleCase = function(string) {
67+
var exceptions = ['a', 'an', 'the', 'at', 'by', 'for', 'in', 'of', 'on', 'to', 'up', 'and', 'as', 'but', 'or', 'nor'];
68+
if (string) {
69+
string = string.split(' ').map(function(word) {
70+
return exceptions.find(function(compare) {
71+
return compare === word.toLowerCase();
72+
}) ? word : word.charAt(0).toUpperCase() + word.slice(1);
73+
}).join(' ');
74+
}
75+
76+
return string;
5877
};

0 commit comments

Comments
 (0)