Skip to content
This repository was archived by the owner on Sep 1, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,14 @@ kodi.config
MUSICALBUMS
MUSICARTISTS
MUSICSONGS
MUSICGENRES
MUSICPLAYLISTS
VIDEOPLAYLISTS
MOVIES
MOVIEGENRES
MUSICVIDEOGENRES
SHOWS
SHOWGENRES
ADDONS

kodi-alexa/
Expand Down
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ Here are some of the features supported by this skill:
- Play/Shuffle audio and video playlists
- "Party mode" for music (shuffle all)
- Shuffle all episodes of a TV show
- Play random unwatched episode of TV show
- Play random unwatched TV show
- Play random unwatched episode of a specific TV show
- Play specific episode of a TV show ('Play season 4 episode 10 of The Office')
- Play random unwatched movie
- Play random movie from a specific genre
- Play specific movie
- Play trailer for a movie in your library (*requires plugin.video.youtube addon*)
- Play specific episode of a TV show ('Play season 4 episode 10 of The Office')
- Play random music video
- Play random music video from a specific genre
- Continue watching next episode of last show that was watched
- Play next episode of a show
- Play newest episode of a show
Expand Down Expand Up @@ -157,6 +160,8 @@ You need to create the following slots:
- MOVIES
- MOVIEGENRES
- SHOWS
- SHOWGENRES
- MUSICVIDEOGENRES
- MUSICARTISTS
- MUSICALBUMS
- MUSICSONGS
Expand Down
137 changes: 114 additions & 23 deletions alexa.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,7 @@ def alexa_shuffle_media(Show=None):

return statement(response_text).simple_card(card_title, response_text)


# Handle the PlayMedia intent.
#
# Generic play function. Tries to find media to play when the user didn't
Expand Down Expand Up @@ -1540,33 +1541,64 @@ def alexa_back():

# Handle the ViewMovies intent.
@ask.intent('ViewMovies')
def alexa_show_movies():
def alexa_show_movies(MovieGenre):
print 'Navigate: Movies'

kodi = Kodi(config, context)
kodi.ShowMovies()
genre = None
if MovieGenre:
g = kodi.FindVideoGenre(MovieGenre)
if len(g) > 0:
genre = g[0][0]
kodi.ShowMovies(genre)
response_text = render_template('short_confirm').encode("utf-8")
return question(response_text)


# Handle the ViewShows intent.
@ask.intent('ViewShows')
def alexa_show_shows():
def alexa_show_shows(ShowGenre):
print 'Navigate: Shows'

kodi = Kodi(config, context)
kodi.ShowTvShows()
genre = None
if ShowGenre:
g = kodi.FindVideoGenre(ShowGenre, 'tvshow')
if len(g) > 0:
genre = g[0][0]
kodi.ShowTvShows(genre)
response_text = render_template('short_confirm').encode("utf-8")
return question(response_text)


# Handle the ViewMusicVideos intent.
@ask.intent('ViewMusicVideos')
def alexa_show_music_videos(MusicVideoGenre):
print 'Navigate: MusicVideos'

kodi = Kodi(config, context)
genre = None
if MusicVideoGenre:
g = kodi.FindVideoGenre(MusicVideoGenre, 'musicvideo')
if len(g) > 0:
genre = g[0][0]
kodi.ShowMusicVideos(genre)
response_text = render_template('short_confirm').encode("utf-8")
return question(response_text)


# Handle the ViewMusic intent.
@ask.intent('ViewMusic')
def alexa_show_music():
def alexa_show_music(MusicGenre):
print 'Navigate: Music'

kodi = Kodi(config, context)
kodi.ShowMusic()
genre = None
if MusicGenre:
g = kodi.FindMusicGenre(MusicGenre)
if len(g) > 0:
genre = g[0][0]
kodi.ShowMusic(genre)
response_text = render_template('short_confirm').encode("utf-8")
return question(response_text)

Expand All @@ -1593,17 +1625,6 @@ def alexa_show_albums():
return question(response_text)


# Handle the ViewMusicVideos intent.
@ask.intent('ViewMusicVideos')
def alexa_show_music_videos():
print 'Navigate: MusicVideos'

kodi = Kodi(config, context)
kodi.ShowMusicVideos()
response_text = render_template('short_confirm').encode("utf-8")
return question(response_text)


# Handle the ViewVideoPlaylist intent.
@ask.intent('ViewVideoPlaylist')
def alexa_show_video_playlist(VideoPlaylist):
Expand Down Expand Up @@ -1864,6 +1885,7 @@ def alexa_watch_random_movie(MovieGenre):
print card_title

# Select from specified genre if one was matched
movies_array = []
if len(genre) > 0:
movies_array = kodi.GetUnwatchedMoviesByGenre(genre[0][1])
else:
Expand Down Expand Up @@ -1978,14 +2000,9 @@ def alexa_watch_random_episode(Show):
kodi = Kodi(config, context)
show = kodi.FindTvShow(Show)
if len(show) > 0:
episodes_result = kodi.GetUnwatchedEpisodesFromShow(show[0][0])

if not 'episodes' in episodes_result['result']:
# Fall back to all episodes if no unwatched available
episodes_result = kodi.GetEpisodesFromShow(show[0][0])
episodes_result = kodi.GetEpisodesFromShow(show[0][0])

episodes_array = []

for episode in episodes_result['result']['episodes']:
episodes_array.append(episode['episodeid'])

Expand All @@ -2001,6 +2018,43 @@ def alexa_watch_random_episode(Show):
return statement(response_text).simple_card(card_title, response_text)


# Handle the WatchRandomShow intent.
@ask.intent('WatchRandomShow')
def alexa_watch_random_show(ShowGenre):
kodi = Kodi(config, context)
genre = []
# If a genre has been specified, match the genre for use in selecting a random show
if ShowGenre:
card_title = render_template('playing_random_show_genre', genre=ShowGenre).encode("utf-8")
genre = kodi.FindVideoGenre(ShowGenre, 'tvshow')
else:
card_title = render_template('playing_random_show').encode("utf-8")
print card_title

# Select from specified genre if one was matched
if len(genre) > 0:
shows_array = kodi.GetUnwatchedShowsByGenre(genre[0][1])
else:
shows_array = kodi.GetUnwatchedShows()
if len(shows_array) > 0:
random_show = random.choice(shows_array)
return alexa_watch_next_episode(random_show['label'])
else:
# Fall back to all shows if no unwatched available
if len(genre) > 0:
shows = kodi.GetShowsByGenre(genre[0][1])
else:
shows = kodi.GetShows()
if 'result' in shows and 'tvshows' in shows['result']:
shows_array = shows['result']['tvshows']
random_show = random.choice(shows_array)
return alexa_watch_random_episode(random_show['label'])

response_text = render_template('error_parsing_results').encode("utf-8")
return statement(response_text).simple_card(card_title, response_text)



# Handle the WatchEpisode intent.
@ask.intent('WatchEpisode')
def alexa_watch_episode(Show, Season, Episode):
Expand Down Expand Up @@ -2119,6 +2173,43 @@ def alexa_watch_last_show():
return statement(response_text).simple_card(card_title, response_text)


# Handle the WatchRandomMusicVideo intent.
@ask.intent('WatchRandomMusicVideo')
def alexa_watch_random_music_video(MusicVideoGenre):
kodi = Kodi(config, context)
genre = []
# If a genre has been specified, match the genre for use in selecting a random music video
if MusicVideoGenre:
card_title = render_template('playing_random_musicvideo_genre', genre=MusicVideoGenre).encode("utf-8")
genre = kodi.FindVideoGenre(MusicVideoGenre, 'musicvideo')
else:
card_title = render_template('playing_random_musicvideo').encode("utf-8")
print card_title

# Select from specified genre if one was matched
if len(genre) > 0:
musicvideos = kodi.GetMusicVideosByGenre(genre[0][1])
else:
musicvideos = kodi.GetMusicVideos()
musicvideos_array = []
if 'result' in musicvideos and 'musicvideos' in musicvideos['result']:
musicvideos_array = musicvideos['result']['musicvideos']

if len(musicvideos_array) > 0:
random_musicvideo = random.choice(musicvideos_array)
musicvideo_details = kodi.GetMusicVideoDetails(random_musicvideo['musicvideoid'])

kodi.PlayMusicVideo(random_musicvideo['musicvideoid'])
if len(genre) > 0:
response_text = render_template('playing_genre_musicvideo', genre_name=genre[0][1], musicvideo_name=random_musicvideo['label'], artist_name=musicvideo_details['artist'][0]).encode("utf-8")
else:
response_text = render_template('playing_musicvideo', musicvideo_name=random_musicvideo['label'], artist_name=musicvideo_details['artist'][0]).encode("utf-8")
else:
response_text = render_template('error_parsing_results').encode("utf-8")

return statement(response_text).simple_card(card_title, response_text)


# Handle the WatchVideoPlaylist intent.
@ask.intent('WatchVideoPlaylist')
def alexa_watch_video_playlist(VideoPlaylist, shuffle=False):
Expand Down
5 changes: 5 additions & 0 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@
"value": "100",
"required": false
},
"MAX_UNWATCHED_SHOWS": {
"description": "Maximum number of items to fetch when looking for new shows.",
"value": "100",
"required": false
},
"MAX_UNWATCHED_EPISODES": {
"description": "Maximum number of items to fetch when looking for new episodes.",
"value": "100",
Expand Down
12 changes: 12 additions & 0 deletions generate_custom_slots.py
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,18 @@ def write_file(filename, items=[]):
write_file('MOVIEGENRES', cl)


# Generate SHOWGENRES Slot
retrieved = kodi.GetVideoGenres('tvshow')
cl = clean_results(retrieved, 'genres', 'label')
write_file('SHOWGENRES', cl)


# Generate MUSICVIDEOGENRES Slot
retrieved = kodi.GetVideoGenres('musicvideo')
cl = clean_results(retrieved, 'genres', 'label')
write_file('MUSICVIDEOGENRES', cl)


# Generate MOVIES Slot
retrieved = kodi.GetMovies()
cl = clean_results(retrieved, 'movies', 'label')
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
gunicorn
pytz
flask-ask>=0.8.9
kodi-voice>=0.9.5
kodi-voice>=0.9.6
54 changes: 48 additions & 6 deletions speech_assets/IntentSchema.json
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,15 @@
}
]
},
{
"intent": "WatchRandomShow",
"slots": [
{
"name": "ShowGenre",
"type": "SHOWGENRES"
}
]
},
{
"intent": "WatchLatestEpisode",
"slots": [
Expand Down Expand Up @@ -374,6 +383,15 @@
}
]
},
{
"intent": "WatchRandomMusicVideo",
"slots": [
{
"name": "MusicVideoGenre",
"type": "MUSICVIDEOGENRES"
}
]
},
{
"intent": "WatchVideoPlaylist",
"slots": [
Expand Down Expand Up @@ -445,23 +463,47 @@
"intent": "PageDown"
},
{
"intent": "ViewMovies"
"intent": "ViewMovies",
"slots": [
{
"name": "MovieGenre",
"type": "MOVIEGENRES"
}
]
},
{
"intent": "ViewShows",
"slots": [
{
"name": "ShowGenre",
"type": "SHOWGENRES"
}
]
},
{
"intent": "ViewShows"
"intent": "ViewMusicVideos",
"slots": [
{
"name": "MusicVideoGenre",
"type": "MUSICVIDEOGENRES"
}
]
},
{
"intent": "ViewMusic"
"intent": "ViewMusic",
"slots": [
{
"name": "MusicGenre",
"type": "MUSICGENRES"
}
]
},
{
"intent": "ViewArtists"
},
{
"intent": "ViewAlbums"
},
{
"intent": "ViewMusicVideos"
},
{
"intent": "ViewVideoPlaylist",
"slots": [
Expand Down
Loading