Full Code of m0ngr31/kanzi for AI

master a624ed57178e
35 files
823.6 KB
202.8k tokens
Showing preview only (849K chars total). The displayed content is truncated. Use the JSON API for full output.
Repository: m0ngr31/kanzi
Branch: master
Commit: a624ed57178e
Files: 35
Total size: 823.6 KB

Directory structure:
gitextract_dv16a75p/

├── .gitignore
├── .travis.yml
├── CHANGELOG.txt
├── CONTRIBUTING.md
├── LICENSE
├── Procfile
├── README.md
├── UPGRADING.md
├── alexa.py
├── alexa.wsgi
├── app.json
├── generate_custom_slots.py
├── requirements.txt
├── runtime.txt
├── sample_slotvals.de.txt
├── sample_slotvals.en.txt
├── sample_slotvals.es.txt
├── sample_slotvals.fr.txt
├── sample_slotvals.it.txt
├── speech_assets/
│   ├── IntentSchema.json
│   ├── SampleUtterances.de.txt
│   ├── SampleUtterances.en.txt
│   ├── SampleUtterances.es.txt
│   ├── SampleUtterances.fr.txt
│   └── SampleUtterances.it.txt
├── templates.de.yaml
├── templates.en.yaml
├── templates.es.yaml
├── templates.fr.yaml
├── templates.it.yaml
├── utterances.de.txt
├── utterances.en.txt
├── utterances.es.txt
├── utterances.fr.txt
└── utterances.it.txt

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================

# Created by https://www.gitignore.io/api/python

### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
venv/

# PyInstaller
#  Usually these files are written by a python script from a template
#  before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Django stuff:
*.log

# Sphinx documentation
docs/_build/

# PyBuilder
target/

test.py

.vscode

.env
*.ini
kodi.config
MUSICALBUMS
MUSICARTISTS
MUSICSONGS
MUSICGENRES
MUSICPLAYLISTS
VIDEOPLAYLISTS
MOVIES
MOVIEGENRES
SHOWS
SHOWGENRES
MUSICVIDEOS
MUSICVIDEOGENRES
ADDONS

kodi-alexa/
run.sh

zappa_settings.json
templates.yaml


================================================
FILE: .travis.yml
================================================
language: python
python:
- '2.7'
script:
- sudo apt-get install python-dev -y
- cd $TRAVIS_BUILD_DIR
- git clean -fXd
- pip install -r requirements.txt -t .
- pip install python-Levenshtein
- rm -rf numpy boto*
- ls | grep dist-info | xargs rm -rf
- sed -i 's/StringIO/BytesIO/g' flask_ask/core.py
- rm flask_ask/core.pyc
- zip -r9 ~/Release.zip . -x \*.git\*
- mkdir dist
- mv ~/Release.zip dist/
before_deploy:
  - git config --local user.name "m0ngr31"
  - git config --local user.email "joe@ipson.me"
  - git tag "$(date +'%m.%d.%Y')-$(git log --format=%h -1)"
deploy:
  skip_cleanup: true
  provider: releases
  api_key:
    secure: eoxDYqEtdRTIb2ZWqH68FuWDB6v2UFtTNJ5OcYGNByeMws7djkK20NtRaNljMmDwfkhYK4biCwSul3A9KAdWntTRe1JKmxwlNdHUVQaDfuoZ/HCNeTe59RLN5JITQk/ppgLoJ+3BwcXymWkWb8xI1M5dv5cuQE67WV9jcaW28dcMsoPQyDGdTabtYU+47TNSKuYGTM7QxZMhCactfmNUrsBZceQ6qjjHlV/xbM+ZR2IeIT49Pua5xRcj4CNr0Ggt/KD+Cg/nV9XIC9IUHjn9lPD3Tb7kmRTvikOM+R04nIbTAFNap0yHHxA2zzxoQdiXyfscZilXtfVmrel6uJNp62adLQFGAd6af3zfHbzcwQu06Aml4jV+15sQVvXTL7NKN9rTkem+/rs1pO5H5Wnq6D4WTajVZz1kGDz88q35q0uRn4ghf1ZDcedX0AImqSGiOCX6DgJOOt8PDIeLgy+ajXnSXxAIrJLzAEgwBgaUElx5b3yeWQWCwWW8/PMkwJBCTZxI+Z1DFnNH8BU1KueftBw08k/1Owz0CsN8XnmQ3Ls8K2+6yMHl49Ci8kU+T8PnbNeT7FW4Kime9aJUfKlcrdg5TgapuYgEhP2ArYXUOs4HV2NahIRnOGoEoMrZ5+t8mSIJmY7Z9qLnym7EbK1EJx5cI4tTGgkGs1oeDc0Frl4=
  file: $TRAVIS_BUILD_DIR/dist/Release.zip
  on:
    repo: m0ngr31/kanzi


================================================
FILE: CHANGELOG.txt
================================================
v2.9.6 (07/30/2018)
* Add French language support.

v2.9.5 (10/19/2017)
* Add ability to cache responses via Amazon S3 bucket or ownCloud/nextCloud.
* Update documentation.
* Add 'loglevel' and 'logsensitive' config options.

v2.9.0 (09/03/2017)
* Add support for specifying genre in recommendations.
* Optimize media recommendations.
* Add ability to toggle stereoscopic mode.
* Add ability to toggle audio passthrough.
* Expand help to include example utterances.
* Add read_timeout and read_timeout_async config variables.

v2.8.5 (08/20/2017)
* Add support for playing music videos.

v2.8.0 (08/09/2017)
* Add ability to play a random TV show.
* Add ability to play a random music video.
* Add ability to specify genre when opening library views.
* Add ability to open (show on-screen) recently added items.
* Add ability to open (show on-screen) library views.
* Fix play of recommended music video.

v2.7.5 (07/25/2017)
* Add ability to download subtitles.
* Add support for music genres.
* Add ability to request movie trailers.
* Add ability to open library views.
* Make maximum slot items configurable.
* Update slot generator.
* Improve confirmation question for destructive commands.
* Fix error response on session timeout.
* Fix response when setting volume.

v2.7.0 (06/26/2017)
* Better matching for songs and albums in certain cases.
* Return newest instead of most recently-added album when asking for newest
  album by an artist.

v2.6.6 (06/20/2017)
* Speed up speech responses for certain requests.
* Add ability to specify an album when playing a song.
* Add playlist_max_items option.

v2.6.5 (06/12/2017)
* Speed up matching for titles that do not contain numbers.
* Support for recommended songs.
* Add 'recommend something to watch' and 'recommend something to listen to'.
* Shorten welcome message.
* Allow (play/listen to/shuffle) (latest/newest) recently added songs.

v2.6.4 (06/06/2017)
* Assume UTF-8 encoding in JSON responses (speed up)
* New intents to recommend media
- Requires script.skin.helper.widgets
* New options in kodi.config to limit unwatched results
* Queries now leave session open if it was already open
* Remove OpenRemote Intent
- All nav commands now leave session open
- Or start a session with just "open kodi"

v2.6.3 (06/01/2017)
* Significantly improve matching for titles with numbers
* Fix German utterances for AddonGlobalSearch
* Minor matching tweak for German
* Remove more invalid characters from slot items

v2.6.2 (05/28/2017)
* Add ListenToLatestAlbum (by artist) Intent
* Include song artists in results
* Fix WatchNextEpisode and ContinueLastShow Intents
* Fix AudioStreamNext/Previous
* Update documentation
* Update translations

v2.6.1 (05/22/2017)
* Update German translation
* Better handling of non-ASCII strings
* Fix errors retrieving certain config variables

v2.6.0 (05/12/2017)
* Fixed shuffling of really large playlists
* Added Shuffle On/Off Intents
* Added Loop On/Off Intents
* Better matching for titles with roman numerals
* Clean up Cards and Responses
* Added generic play/shuffle commands ("deep searches")
- "play <media>"
- "shuffle <media>"
- "listen to <music>"
- "watch <video>"
* Fixed an issue with Flask-Ask 0.9.2
* Update German translation
* Added basic support for multiple Kodi installations

v2.5.0 (04/13/2017)
* Migrated to Flask-Ask
* Added session support
* Added OpenRemote intent
* Added support for German language
* Updated Python slot generator to trim illegal characters
* Added Help intent
* Fixed BigForward/Backward and StartOver intents
* Replaced pycontry dependency with light-weight alternative
* Added option to make Shutdown equal Quit
* Added 'Deploy to heroku' functionality
* Added confirmation for destructive power commands
* Reduced number of slot items the generator produces
* Allow step/jump by arbitrary durations
* Utilized Amazon Standard Built-ins for playback control
* Various minor bug fixes

v2.1.0 (01/05/2017)
* Misc bug fixes
* Added ability to execute addons
* Added ability to specify genre in WhatNewMovies intent
* No longer assumes music if no media type specified
* Added ability to request a specific song from library
* Added songs to DoSearch intent
* Allow (play/listen to) ({Album}/{Song}) by {Artist}
* Allow 'visualizer' as alias for 'fullscreen'
* Added support for video playlists
* Fix shuffling of recently added songs
* Verbs "watch" and "listen" assume corresponding media type now
* Defer to fuzzy matching earlier to get better matches
* Added ability to shuffle playlists
* Fixed Clean Library functionality

v2.0.6 (11/30/2016)
* Fixes for Lambda deployments
* Support playing random movie by genre
* Added ability to query Kodi library for recently-added albums
* Support searching for albums
* Added volume commands
* Allow user to specify timezone for responses that include an absolute time
* Fix update/clean library commands

v2.0.5 (11/09/2016)
* Added ability to play a specific album
* Added intent to query available albums by a specific artist
* Added intent to query new (unwatched) movies
* Better content matching
* Added ability to request time remaining on currently playing item

v2.0.4 (10/27/2016)
* Wrote python script to handle deploying to lambda
* Added power intents
* Added EjectMedia intents
* Added Fullscreen (Toggle) intent
* Added Mute (Toggle) intent
* Added support for selecting/toggling subtitles
* Added support for cycling audio streams
* Added basic step forward and step backwards commands
* Added check for verifying requests come from Alexa for WSGI servers
* Added the capability to resume movies and TV-Shows

v2.0.0 (10/02/2016)
* Merged in a bunch of good PRs dealing with playing playlists
* Added ability to query information about currently playing item
* Added in 'Search' and 'Party mode' intents
* Reversed order of Update/Clean functions and threaded them so now the skill won't timeout
* Updated documentation

v1.5.0 (04/13/2016)
* Updated utterances to use custom slots instead of AMAZON.LITERALs
* Re-wrote how the phrases get parsed to be as good as possible
* Added Intents to clean/update audio and video libraries
* Added Intent to watch the newest episode of a show

v1.0.2 (04/07/2016)
* Updated documentation and source for using Heroku by default instead of Openshift

v1.0.1 (01/12/2016)
* Changed random on movies and tv shows to only search for unwatched episodes. If there are none, pick a watched one
* Added Intent to be able to watch next episode of whatever was watched last
* Added Intent to be able to watch next episode of specific tv show

v.1.0.0 (01/01/2016)
* Initial release


================================================
FILE: CONTRIBUTING.md
================================================
# Contributing Guide

## Please Read
If you would like to contribute, please keep the following in mind:
 - If you make a change that affects the setup (ex. Adding a new custom slot type), make sure you're updating the [docs site](https://github.com/m0ngr31/lexigr.am).
 - If you make a new intent, make sure that you follow the same syntax as the rest of the templates. DO NOT just put English text in `alexa.py` file.
   - Make sure you look at the translating guide below to get your intent ready for translation.

## Needs
 - Translation help! If you are a native German speaker, please help with staying on top of new intents and responses. Look at the translating guide below to get setup.
 - New features and refactoring. Please test all code extensively before you commit.

## Translating
There are two main areas translation needs to happen. The sampleUtterances and templates files. Translation should be pretty straight forward.


================================================
FILE: LICENSE
================================================
The MIT License (MIT)

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

================================================
FILE: Procfile
================================================
web: gunicorn alexa:app

================================================
FILE: README.md
================================================
# Kanzi: Alexa Integration With Kodi

[![Build Status](https://travis-ci.org/m0ngr31/kanzi.svg?branch=master)](https://travis-ci.org/m0ngr31/kanzi)

<p align="center">
  <img src="https://i.imgur.com/k0MOv2r.png" width="200"/>
</p>

## Documentation
Visit the [documentation here](https://lexigr.am) to learn how to setup this skill.

## About
This is a skill for Amazon Alexa that allows you to control one or more instances of [Kodi](https://kodi.tv) with your voice.

The process of setting up the skill may seem daunting at first, but the reward -- we feel -- is well worth the effort.  If you carefully follow the directions to the tee, you might find it is not as complicated as it seems.

Unfortunately, as of this moment, we cannot simply ship this skill normally as other skills on Amazon's skill marketplace.  The main technical hurdle is that some features we would need are currently only supported in the US region.  Beyond that, there is the consideration of cost for hosting the skill and the associated database backend.  Do try to keep in mind that this is a hobby project for the developers -- we do not get paid in any way.

However, we have made every effort to here to provide clear and concise documentation to allow you to make use of this skill now.

### Supported Commands
Most everything you can do with a remote or keyboard is supported in the skill, and more:

- Basic navigation (Up/Down, Left/Right, Page Up/Down, Select, Back, Menu, Zoom, Rotate, Move)
- Open library views (Movies, Shows, Music, Artists, Albums, Music Videos, Playlists)
- Open library views by genre (Movies, Shows, Music, Music Videos)
- Open recently added playlists (Movies, Episodes, Albums, Music Videos)
- Playback control (Play/Pause, Skip, Previous, Stop, Step/Jump)
- Adjust volume
- Shuffle all music by an artist
- Play/Shuffle specific album
- Play/Shuffle the latest album by an artist
- Play a specific song
- Play/Shuffle audio and video playlists
- "Party mode" for music (shuffle all)
- Play/Shuffle music videos
- Play/Shuffle music videos from a specific genre
- Play/Shuffle music videos by a specific artist
- Shuffle all episodes of a TV show
- Play random TV show
- Play random TV show from a specific genre
- Play random episode of a specific TV show
- Play specific episode of a TV show ('Play season 4 episode 10 of The Office')
- Play random 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 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
- Recommend media to watch/listen to
- List/Play recently added media
- List available albums by an artist
- Clean/Update video and audio sources
- "What's playing?" functionality for music, movies, and shows
- Report time remaining on current media and when it will end
- Cycle through audio and subtitle streams
- Search for something in your library (**requires script.globalsearch addon**)
- Execute addons
- Shutdown/reboot/sleep/hibernate system
- Toggle fullscreen
- Eject media
- Send text

Instead of providing the exact verbiage here for each command, we strive to make the experience as natural as we can.  Simply try asking for what you want in a way that feels _right_ to you.  If a particular phrase doesn't work and you think it should, see [Getting Help](#getting-help) to notify us and we will see what we can do to accommodate the phrase you prefer.

### Kanzi in Action
<p>
  <a href="https://www.youtube.com/watch?v=Xar4byrlEvo">
    <img src="https://i.imgur.com/BrXDYm6.png" style="max-width: 500px">
  </a>
</p>

<p>
  <a href="https://www.youtube.com/watch?v=vAYUWaP3EXA">
    <img src="https://i.imgur.com/gOCYnmE.png" style="max-width: 500px">
  </a>
</p>

## Getting Help
If you need help getting a server going or configuring the Skill, please visit the [support thread on the Kodi forum](http://forum.kodi.tv/showthread.php?tid=254502).

If you run into an actual issue with the code, please open an Issue here on Github; however, most issues you might run into will be a result of the complexity of the installation, so we urge you to first search the [support thread](http://forum.kodi.tv/showthread.php?tid=254502) for your issue.  If you cannot find a resolution for your issue with a search, post there and someone will help you determine if your problem lies within the skill code or your particular configuration.

## Contributors
I would like to thank and name all the contributors who have donated their precious time and talents to improving this skill:
 - [ausweider](https://github.com/ausweider)
 - [digiltd](https://github.com/digiltd)
 - [ghlynch](https://github.com/ghlynch)
 - [jagsta](https://github.com/jagsta)
 - [jingai](https://github.com/jingai)
 - [kuruoujou](https://github.com/kuruoujou)
 - [m0ngr31](https://github.com/m0ngr31)
 - [mcl22](https://github.com/mcl22)
 - [nemik](https://github.com/nemik)
 - [ruben0909](https://github.com/ruben0909)
 - [YantCaccia](https://github.com/YantCaccia)

## Donate
[![Buy Me A Coffee](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/lexigram)

## Developer Discussion
If you're interested in chatting with us about the development of the skill, we are on [Slack](https://lexigram-slack.herokuapp.com/).

================================================
FILE: UPGRADING.md
================================================
# Upgrading

For each new update, please run the Slot generator again and repopulate all of your slots with the output. If you don't do this, the skill might seem to successfully build and save, but those with large libraries may encounter issues at runtime. There might be new slots needed for new functionality as well.

Remember to always update the Intents and Utterances in the skill. If new slots were added, you will need to add those as well.

Please also check the current [kodi.config.example template](https://raw.githubusercontent.com/m0ngr31/kodi-voice/master/kodi_voice/kodi.config.example) for new configuration variables that you may need to set.

Almost anything else can change, too.  Please be sure to check the CHANGELOG and README again when updating.

## Heroku

Just delete the existing app from your Heroku Dashboard, and create another with the button below with the same name you gave earlier.
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://www.heroku.com/deploy/?template=https://github.com/m0ngr31/kanzi)

## AWS Lambda

If you are not using Zappa yet, please go back to the README file there and start from scratch.

If you are already using Zappa, browse to the application directory in your terminal.  Then activate the virtualenv with:

`virtualenv venv` and `source venv/bin/activate` (if you are on Windows, that's `venv\Scripts\activate.bat` or `venv\Scripts\activate.ps1` for Powershell).

Finally, execute all of the following:

```
git pull origin master
pip install zappa --upgrade
pip install -r requirements.txt
zappa update dev
```


================================================
FILE: alexa.py
================================================
#!/usr/bin/python

# For a complete discussion, see http://forum.kodi.tv/showthread.php?tid=254502

import datetime
import pytz
import random
import string
import sys
import time
import os
import re
import codecs
import logging
from flask import Flask, json, render_template
from functools import wraps
from flask_ask import Ask, session, question, statement, audio, request, context
from shutil import copyfile
from kodi_voice import KodiConfigParser, Kodi


app = Flask(__name__)

config_file = os.path.join(os.path.dirname(__file__), "kodi.config")
config = KodiConfigParser(config_file)

LOGLEVEL = config.get('global', 'loglevel')
LOGSENSITIVE = config.getboolean('global', 'logsensitive')
logging.basicConfig(level=logging.INFO)
log = logging.getLogger('kodi_alexa.' + __name__)
log.setLevel(LOGLEVEL)
kodi_voice_log = logging.getLogger('kodi_voice')
kodi_voice_log.setLevel(LOGLEVEL)
kodi_voice_log.propagate = True
if LOGSENSITIVE:
  requests_log = logging.getLogger('requests.packages.urllib3')
  requests_log.setLevel(LOGLEVEL)
  requests_log.propagate = True

SKILL_ID = config.get('alexa', 'skill_id')
if SKILL_ID and SKILL_ID != 'None' and not os.getenv('MEDIA_CENTER_SKILL_ID'):
  app.config['ASK_APPLICATION_ID'] = SKILL_ID
elif os.getenv('MEDIA_CENTER_SKILL_ID'):
  app.config['ASK_APPLICATION_ID'] = os.getenv('MEDIA_CENTER_SKILL_ID')

LANGUAGE = config.get('global', 'language')
if LANGUAGE == 'de':
  TEMPLATE_FILE = "templates.de.yaml"
elif LANGUAGE == 'fr':
  TEMPLATE_FILE = "templates.fr.yaml"  
elif LANGUAGE == 'es':
  TEMPLATE_FILE = "templates.es.yaml"
elif LANGUAGE == 'it':
  TEMPLATE_FILE = "templates.it.yaml"
else:
  LANGUAGE = 'en'
  TEMPLATE_FILE = "templates.en.yaml"

# According to this: https://alexatutorial.com/flask-ask/configuration.html
# Timestamp based verification shouldn't be used in production. Use at own risk
# app.config['ASK_VERIFY_TIMESTAMP_DEBUG'] = True

# Needs to be instanced after app is configured
ask = Ask(app, "/", None, path=TEMPLATE_FILE)


# Direct lambda handler
def lambda_handler(event, _context):
  return ask.run_aws_lambda(event)


# Decorator to check your config for basic info and if your account is linked (when using the hosted skill)
def preflight_check(f):
  @wraps(f)
  def decorated_function(*args, **kwargs):
    if os.getenv('MEDIA_CENTER_URL') and not session.get('user', {}).get('accessToken'):
      response_text = render_template('not_logged_in').encode('utf-8')
      return statement(response_text).link_account_card()

    kodi = Kodi(config, context)

    if kodi.config_error:
      if os.getenv('MEDIA_CENTER_URL'):
        response_text = render_template('hosted_config_missing').encode('utf-8')
      else:
        response_text = render_template('config_missing').encode('utf-8')

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

    # Since we're not getting any of the actual args passed in, we have to create them here
    slots = request.get('intent', {}).get('slots', {})
    for key, value in slots.iteritems():
      kwargs.update({key: value.get('value')})
    kwargs.update({'kodi': kodi})

    return f(*args, **kwargs)
  return decorated_function

# Start of intent methods

# Handle the CurrentPlayItemInquiry intent.
@ask.intent('CurrentPlayItemInquiry')
@preflight_check
def alexa_current_playitem_inquiry(kodi):
  card_title = render_template('current_playing_item').encode('utf-8')
  log.info(card_title)

  response_text = render_template('nothing_playing')

  curitem = kodi.GetActivePlayItem()
  if curitem:
    response_text = render_template('unknown_playing')

    if curitem['type'] == 'episode':
      # is a tv show
      if curitem['showtitle']:
        response_text = render_template('current_show_is')
        response_text += u' '
        response_text += curitem['showtitle']
        if curitem['season']:
          response_text += u', %s %s' % (render_template('season'), curitem['season'])
        if curitem['episode']:
          response_text += u', %s %s' % (render_template('episode'), curitem['episode'])
        if curitem['title']:
          response_text += u', '
          response_text += curitem['title']
    elif curitem['type'] == 'song' or curitem['type'] == 'musicvideo':
      # is a song (music video or audio)
      if curitem['title']:
        response_text = render_template('current_song_is')
        response_text += u' '
        response_text += curitem['title']
        if curitem['artist']:
          response_text += u' ' + render_template('by') + u' '
          response_text += curitem['artist'][0]
        if curitem['album']:
          response_text += u', '
          response_text += render_template('on_the_album')
          response_text += u' '
          response_text += curitem['album']
    elif curitem['type'] == 'movie':
      # is a video
      if curitem['title']:
        response_text = render_template('current_movie_is')
        response_text += u' '
        response_text += curitem['title']

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


# Handle the CurrentPlayItemTimeRemaining intent.
@ask.intent('CurrentPlayItemTimeRemaining')
@preflight_check
def alexa_current_playitem_time_remaining(kodi):
  card_title = render_template('time_left_playing').encode('utf-8')
  log.info(card_title)

  response_text = render_template('nothing_playing').encode('utf-8')

  status = kodi.GetPlayerStatus()
  if status['state'] is not 'stop':
    minsleft = status['total_mins'] - status['time_mins']
    if minsleft == 0:
      response_text = render_template('remaining_close').encode('utf-8')
    elif minsleft == 1:
      response_text = render_template('remaining_min').encode('utf-8')
    elif minsleft > 1:
      response_text = render_template('remaining_mins', minutes=minsleft).encode('utf-8')
      tz = config.get(kodi.dev_cfg_section, 'timezone')
      if minsleft > 9 and tz and tz != 'None':
        utctime = datetime.datetime.now(pytz.utc)
        loctime = utctime.astimezone(pytz.timezone(tz))
        endtime = loctime + datetime.timedelta(minutes=minsleft)
        response_text += render_template('remaining_time', end_time=endtime.strftime('%I:%M')).encode('utf-8')

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


def alexa_play_pause(kodi):
  card_title = render_template('play_pause').encode('utf-8')
  log.info(card_title)

  kodi.PlayerPlayPause()
  return statement('').simple_card(card_title, '')


# Handle the AMAZON.PauseIntent intent.
@ask.intent('AMAZON.PauseIntent')
@preflight_check
def alexa_pause(kodi):
  return alexa_play_pause(kodi)


# Handle the AMAZON.ResumeIntent intent.
@ask.intent('AMAZON.ResumeIntent')
@preflight_check
def alexa_resume(kodi):
  return alexa_play_pause(kodi)


def alexa_stop_cancel(kodi):
  if session.new:
    card_title = render_template('stopping').encode('utf-8')
    log.info(card_title)

    kodi.PlayerStop()
    response_text = render_template('playback_stopped').encode('utf-8')
    return statement(response_text).simple_card(card_title, response_text)
  else:
    return statement('')


# Handle the AMAZON.StopIntent intent.
@ask.intent('AMAZON.StopIntent')
@preflight_check
def alexa_stop(kodi):
  return alexa_stop_cancel(kodi)


# Handle the AMAZON.CancelIntent intent.
@ask.intent('AMAZON.CancelIntent')
@preflight_check
def alexa_cancel(kodi):
  return alexa_stop_cancel(kodi)


# Handle the AMAZON.NoIntent intent.
@ask.intent('AMAZON.NoIntent')
@preflight_check
def alexa_no(kodi):
  if 'play_media_generic_type' in session.attributes:
    generic_type = session.attributes['play_media_generic_type']
    if generic_type == 'video':
      item = kodi.GetRecommendedVideoItem()
    else:
      item = kodi.GetRecommendedAudioItem()
    return alexa_recommend_item(kodi, item, generic_type)
  elif 'play_media_type' in session.attributes:
    genre = None
    if 'play_media_genre' in session.attributes:
      genre = session.attributes['play_media_genre']
    item = kodi.GetRecommendedItem(session.attributes['play_media_type'] + 's', genre)
    return alexa_recommend_item(kodi, item)

  return alexa_stop_cancel(kodi)


# Handle the AMAZON.YesIntent intent.
@ask.intent('AMAZON.YesIntent')
@preflight_check
def alexa_yes(kodi):
  card_title = None

  if 'shutting_down' in session.attributes:
    quit = config.get(kodi.dev_cfg_section, 'shutdown')
    if quit and quit == 'quit':
      card_title = render_template('quitting').encode('utf-8')
      kodi.ApplicationQuit()
    else:
      card_title = render_template('shutting_down').encode('utf-8')
      kodi.SystemShutdown()
  elif 'rebooting' in session.attributes:
    card_title = render_template('rebooting').encode('utf-8')
    kodi.SystemReboot()
  elif 'hibernating' in session.attributes:
    card_title = render_template('hibernating').encode('utf-8')
    kodi.SystemHibernate()
  elif 'suspending' in session.attributes:
    card_title = render_template('suspending_system').encode('utf-8')
    kodi.SystemSuspend()

  if 'play_media_type' in session.attributes:
    media_type = session.attributes['play_media_type']
    media_id = session.attributes['play_media_id']
    if media_type == 'movie':
      kodi.PlayMovie(media_id)
    elif media_type == 'tvshow':
      # Try the next unwatched episode first
      episode_id = kodi.GetNextUnwatchedEpisode(media_id)
      if not episode_id:
        # All episodes already watched, so just play a random episode
        episodes_result = kodi.GetEpisodesFromShow(media_id)
        for episode in episodes_result['result']['episodes']:
          episodes_array.append(episode['episodeid'])
        episode_id = random.choice(episodes_array)
      kodi.PlayEpisode(episode_id)
    elif media_type == 'episode':
      kodi.PlayEpisode(media_id)
    elif media_type == 'musicvideo':
      kodi.PlayMusicVideo(media_id)
    elif media_type == 'artist':
      songs_result = kodi.GetArtistSongs(media_id)
      songs = songs_result['result']['songs']
      songs_array = []
      for song in songs:
        songs_array.append(song['songid'])

      kodi.PlayerStop()
      kodi.ClearAudioPlaylist()
      kodi.AddSongsToPlaylist(songs_array, True)
      kodi.StartAudioPlaylist()
    elif media_type == 'album':
      kodi.PlayerStop()
      kodi.ClearAudioPlaylist()
      kodi.AddAlbumToPlaylist(media_id)
      kodi.StartAudioPlaylist()
    elif media_type == 'song':
      kodi.PlayerStop()
      kodi.ClearAudioPlaylist()
      kodi.AddSongToPlaylist(media_id)
      kodi.StartAudioPlaylist()
    return statement(render_template('okay').encode('utf-8'))

  if card_title:
    log.info(card_title)
    return statement(card_title).simple_card(card_title, "")
  else:
    return statement('')


def duration_in_seconds(duration_str):
  if duration_str[0] != 'P':
    raise ValueError('Not an ISO 8601 Duration string')

  seconds = 0
  # split by the 'T'
  for i, item in enumerate(duration_str.split('T')):
    for number, unit in re.findall('(?P<number>\d+)(?P<period>S|M|H|D|W|Y)', item):
      number = int(number)
      this = 0
      if unit == 'Y':
        this = number * 31557600 # 365.25
      elif unit == 'W':
        this = number * 604800
      elif unit == 'D':
        this = number * 86400
      elif unit == 'H':
        this = number * 3600
      elif unit == 'M':
        # ambiguity alleviated with index i
        if i == 0:
          this = number * 2678400 # assume 30 days
        else:
          this = number * 60
      elif unit == 'S':
        this = number
      seconds = seconds + this
  return seconds


# Handle the PlayerSeekForward intent.
@ask.intent('PlayerSeekForward')
@preflight_check
def alexa_player_seek_forward(kodi, ForwardDur):
  card_title = render_template('step_forward').encode('utf-8')
  log.info(card_title)

  seek_sec = duration_in_seconds(ForwardDur)

  card_body = 'Stepping forward by %d seconds' % (seek_sec)
  log.info(card_body)

  kodi.PlayerSeek(seek_sec)
  return statement('').simple_card(card_title, card_body)


# Handle the PlayerSeekBackward intent.
@ask.intent('PlayerSeekBackward')
@preflight_check
def alexa_player_seek_backward(kodi, BackwardDur):
  card_title = render_template('step_backward').encode('utf-8')
  log.info(card_title)

  seek_sec = duration_in_seconds(BackwardDur)

  card_body = 'Stepping backward by %d seconds' % (seek_sec)
  log.info(card_body)

  kodi.PlayerSeek(-seek_sec)
  return statement('').simple_card(card_title, card_body)


# Handle the PlayerSeekSmallForward intent.
@ask.intent('PlayerSeekSmallForward')
@preflight_check
def alexa_player_seek_smallforward(kodi):
  card_title = render_template('step_forward').encode('utf-8')
  log.info(card_title)

  kodi.PlayerSeekSmallForward()
  return statement('').simple_card(card_title, '')


# Handle the PlayerSeekSmallBackward intent.
@ask.intent('PlayerSeekSmallBackward')
@preflight_check
def alexa_player_seek_smallbackward(kodi):
  card_title = render_template('step_backward').encode('utf-8')
  log.info(card_title)

  kodi.PlayerSeekSmallBackward()
  return statement('').simple_card(card_title, '')


# Handle the PlayerSeekBigForward intent.
@ask.intent('PlayerSeekBigForward')
@preflight_check
def alexa_player_seek_bigforward(kodi):
  card_title = render_template('big_step_forward').encode('utf-8')
  log.info(card_title)

  kodi.PlayerSeekBigForward()
  return statement('').simple_card(card_title, '')


# Handle the PlayerSeekBigBackward intent.
@ask.intent('PlayerSeekBigBackward')
@preflight_check
def alexa_player_seek_bigbackward(kodi):
  card_title = render_template('big_step_backward').encode('utf-8')
  log.info(card_title)

  kodi.PlayerSeekBigBackward()
  return statement('').simple_card(card_title, '')


def find_and_play(kodi, needle, content=['video','audio'], shuffle=False, slot_hint='unknown', slot_ignore=[]):
  log.info('Find and Play: "%s"', needle.encode('utf-8'))
  if slot_hint != 'unknown':
    log.info('Pre-match with slot: ' + slot_hint)
  log.info('Searching content types: ')
  log.info(content)

  # The order of the searches here is not random, please don't reorganize
  # without giving some thought to overall performance based on most
  # frequently requested types and user expectations.

  # Video playlist?
  if 'video' in content and 'VideoPlaylist' not in slot_ignore and (slot_hint == 'unknown' or slot_hint == 'VideoPlaylist'):
    playlist = kodi.FindVideoPlaylist(needle)
    if playlist:
      if shuffle:
        videos = kodi.GetPlaylistItems(playlist[0][0])['result']['files']
        videos_array = []
        for video in videos:
          videos_array.append(video['file'])

        kodi.PlayerStop()
        kodi.ClearVideoPlaylist()
        kodi.AddVideosToPlaylist(videos_array, True)
        kodi.StartVideoPlaylist()
        op = render_template('shuffling_empty').encode('utf-8')
      else:
        kodi.PlayerStop()
        kodi.StartVideoPlaylist(playlist[0][0])
        op = render_template('playing_empty').encode('utf-8')
      return render_template('playing_playlist_video', action=op, playlist_name=playlist[0][1]).encode('utf-8')

  # Audio playlist?
  if 'audio' in content and 'AudioPlaylist' not in slot_ignore and (slot_hint == 'unknown' or slot_hint == 'AudioPlaylist'):
    playlist = kodi.FindAudioPlaylist(needle)
    if playlist:
      if shuffle:
        songs = kodi.GetPlaylistItems(playlist[0][0])['result']['files']
        songs_array = []
        for song in songs:
          songs_array.append(song['id'])

        kodi.PlayerStop()
        kodi.ClearAudioPlaylist()
        kodi.AddSongsToPlaylist(songs_array, True)
        kodi.StartAudioPlaylist()
        op = render_template('shuffling_empty').encode('utf-8')
      else:
        kodi.PlayerStop()
        kodi.StartAudioPlaylist(playlist[0][0])
        op = render_template('playing_empty').encode('utf-8')
      return render_template('playing_playlist_audio', action=op, playlist_name=playlist[0][1]).encode('utf-8')

  # Movie?
  if 'video' in content and 'Movie' not in slot_ignore and (slot_hint == 'unknown' or slot_hint == 'Movie'):
    movie = kodi.FindMovie(needle)
    if movie:
      if kodi.GetMovieDetails(movie[0][0])['resume']['position'] > 0:
        action = render_template('resuming_empty').encode('utf-8')
      else:
        action = render_template('playing_empty').encode('utf-8')
      kodi.PlayMovie(movie[0][0])
      return render_template('playing_action', action=action, movie_name=movie[0][1]).encode('utf-8')

  # Show?
  if 'video' in content and 'Show' not in slot_ignore and (slot_hint == 'unknown' or slot_hint == 'Show'):
    show = kodi.FindTvShow(needle)
    if show:
      episode_id = None
      episodes_array = []

      if shuffle:
        # Shuffle all episodes of the specified show
        episodes_result = kodi.GetEpisodesFromShow(show[0][0])
        for episode in episodes_result['result']['episodes']:
          episodes_array.append(episode['episodeid'])

        kodi.PlayerStop()
        kodi.ClearVideoPlaylist()
        kodi.AddEpisodesToPlaylist(episodes_array, shuffle)
        kodi.StartVideoPlaylist()
        return render_template('shuffling', heard_name=show[0][1]).encode('utf-8')
      else:
        # Try the next unwatched episode first
        episode_id = kodi.GetNextUnwatchedEpisode(show[0][0])
        if not episode_id:
          # All episodes already watched, so just play a random episode
          episodes_result = kodi.GetEpisodesFromShow(show[0][0])
          for episode in episodes_result['result']['episodes']:
            episodes_array.append(episode['episodeid'])
          episode_id = random.choice(episodes_array)

        if episode_id:
          episode_details = kodi.GetEpisodeDetails(episode_id)
          kodi.PlayEpisode(episode_id)
          return render_template('playing_episode_number', season=episode_details['season'], episode=episode_details['episode'], show_name=show[0][1]).encode('utf-8')

  # Music Video?
  if 'video' in content and 'MusicVideo' not in slot_ignore and (slot_hint == 'unknown' or slot_hint == 'MusicVideo'):
    musicvideo = kodi.FindMusicVideo(needle)
    if musicvideo:
      musicvideo_details = kodi.GetMusicVideoDetails(musicvideo[0][0])
      kodi.PlayMusicVideo(musicvideo[0][0])
      return render_template('playing_musicvideo', musicvideo_name=musicvideo[0][1], artist_name=musicvideo_details['artist'][0]).encode('utf-8')

  # Artist?
  if 'audio' in content and 'Artist' not in slot_ignore and (slot_hint == 'unknown' or slot_hint == 'Artist'):
    artist = kodi.FindArtist(needle)
    if artist:
      songs_result = kodi.GetArtistSongs(artist[0][0])
      songs = songs_result['result']['songs']
      songs_array = []
      for song in songs:
        songs_array.append(song['songid'])

      kodi.PlayerStop()
      kodi.ClearAudioPlaylist()
      # Always shuffle when generically requesting an Artist
      kodi.AddSongsToPlaylist(songs_array, True)
      kodi.StartAudioPlaylist()
      if shuffle:
        op = render_template('shuffling_empty').encode('utf-8')
      else:
        op = render_template('playing_empty').encode('utf-8')
      return render_template('playing_action', action=op, movie_name=artist[0][1]).encode('utf-8')

  # Song?
  if 'audio' in content and 'Song' not in slot_ignore and (slot_hint == 'unknown' or slot_hint == 'Song'):
    song = kodi.FindSong(needle)
    if song:
      kodi.PlayerStop()
      kodi.ClearAudioPlaylist()
      kodi.AddSongToPlaylist(song[0][0])
      kodi.StartAudioPlaylist()
      return render_template('playing_song', song_name=song[0][1]).encode('utf-8')

  # Album?
  if 'audio' in content and 'Album' not in slot_ignore and (slot_hint == 'unknown' or slot_hint == 'Album'):
    album = kodi.FindAlbum(needle)
    if album:
      kodi.PlayerStop()
      kodi.ClearAudioPlaylist()
      kodi.AddAlbumToPlaylist(album[0][0], shuffle)
      kodi.StartAudioPlaylist()
      if shuffle:
        return render_template('shuffling_album', album_name=album[0][1]).encode('utf-8')
      else:
        return render_template('playing_album', album_name=album[0][1]).encode('utf-8')

  return ''


# Handle the ShuffleMedia intent.
#
# Generic shuffle function.  Tries to find media to play when the user didn't
# specify the media type.
#
# Matches directly to Show slot only, but will fuzzy match across the whole
# library if nothing found.
#
# See find_and_play() for the order of the searches.
@ask.intent('ShuffleMedia')
@preflight_check
def alexa_shuffle_media(kodi, Show=None):
  # Some media types don't make sense when shuffling
  ignore_slots = ['Movie', 'Song']

  card_title = render_template('shuffling', heard_name=Show).encode('utf-8')
  log.info(card_title)

  if not config.getboolean('global', 'deep_search'):
    response_text = render_template('help_play').encode('utf-8')
  else:
    response_text = find_and_play(kodi, Show, shuffle=True, slot_hint='Show', slot_ignore=ignore_slots)
    if not response_text:
      ignore_slots.append('Show')
      response_text = find_and_play(kodi, Show, shuffle=True, slot_ignore=ignore_slots)
    if not response_text:
      response_text = render_template('could_not_find', heard_name=Show).encode('utf-8')

  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
# specify the media type.  Can be restricted to video or audio by passing
# in the array argument content, which is most useful when the user's verb
# is "listen to" or "watch".
#
# Matches directly to slots Movie and Artist only, but will fuzzy match
# across the whole library if neither are found.
#
# See find_and_play() for the order of the searches.
def _alexa_play_media(kodi, Movie=None, Artist=None, content=None, shuffle=False):
  if not content:
    content=['video','audio']

  heard_search = ''
  heard_slot = 'unknown'
  if 'video' in content and Movie:
    heard_search = Movie
    heard_slot = 'Movie'
  elif 'audio' in content and Artist:
    heard_search = Artist
    heard_slot = 'Artist'

  card_title = render_template('playing', heard_name=heard_search).encode('utf-8')
  log.info(card_title)

  if not config.getboolean('global', 'deep_search'):
    response_text = render_template('help_play').encode('utf-8')
  else:
    response_text = find_and_play(kodi, heard_search, content, shuffle, slot_hint=heard_slot)
    if not response_text and heard_slot != 'unknown':
      response_text = find_and_play(kodi, heard_search, content, shuffle, slot_ignore=[heard_slot])
    if not response_text:
      response_text = render_template('could_not_find', heard_name=heard_search).encode('utf-8')

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


@ask.intent('PlayMedia')
@preflight_check
def alexa_play_media(kodi, Movie=None, Artist=None):
  return _alexa_play_media(kodi, Movie, Artist)


# Handle the ListenToAudio intent.
#
# Defaults to Artists, but will fuzzy match across the library if none found.
@ask.intent('ListenToAudio')
@preflight_check
def alexa_listen_audio(kodi, Artist):
  log.info('Listen to audio')
  return _alexa_play_media(kodi, Artist=Artist, content=['audio'])


# Handle the ListenToGenre intent (Shuffles all music of a specific genre).
@ask.intent('ListenToGenre')
@preflight_check
def alexa_listen_genre(kodi, MusicGenre):
  card_title = render_template('playing_genre', genre_name=MusicGenre).encode('utf-8')
  log.info(card_title)

  genre = kodi.FindMusicGenre(MusicGenre)
  if genre:
    songs_result = kodi.GetSongsByGenre(genre[0][1])
    if 'songs' in songs_result['result']:
      songs = songs_result['result']['songs']

      songs_array = []
      for song in songs:
        songs_array.append(song['songid'])

      kodi.PlayerStop()
      kodi.ClearAudioPlaylist()
      kodi.AddSongsToPlaylist(songs_array, True)
      kodi.StartAudioPlaylist()
      response_text = render_template('playing_genre', genre_name=genre[0][1]).encode('utf-8')
    else:
      response_text = render_template('could_not_find_genre', genre_name=genre[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find', heard_name=MusicGenre).encode('utf-8')

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


# Handle the ListenToArtist intent (Shuffles all music by an artist, optionally of a specific genre).
@ask.intent('ListenToArtist')
@preflight_check
def alexa_listen_artist(kodi, Artist, MusicGenre):
  genre = []
  if MusicGenre:
    card_title = render_template('listen_artist_genre', heard_genre=MusicGenre, heard_artist=Artist).encode('utf-8')
    genre = kodi.FindMusicGenre(MusicGenre)
  else:
    card_title = render_template('listen_artist', heard_artist=Artist).encode('utf-8')
  log.info(card_title)

  artist = kodi.FindArtist(Artist)
  if artist:
    if genre:
      songs_result = kodi.GetArtistSongsByGenre(artist[0][1], genre[0][1])
      response_text = render_template('playing_genre_artist', genre_name=genre[0][1], artist_name=artist[0][1]).encode('utf-8')
    else:
      songs_result = kodi.GetArtistSongs(artist[0][0])
      response_text = render_template('playing', heard_name=artist[0][1]).encode('utf-8')
    if 'songs' in songs_result['result']:
      songs = songs_result['result']['songs']

      songs_array = []
      for song in songs:
        songs_array.append(song['songid'])

      kodi.PlayerStop()
      kodi.ClearAudioPlaylist()
      kodi.AddSongsToPlaylist(songs_array, True)
      kodi.StartAudioPlaylist()
    elif genre:
      response_text = render_template('could_not_find_genre_artist', genre_name=genre[0][1], artist_name=artist[0][1]).encode('utf-8')
    else:
      response_text = render_template('could_not_find_artist', artist_name=artist[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find', heard_name=Artist).encode('utf-8')

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


def _alexa_listen_album(kodi, Album, Artist, shuffle=False):
  if shuffle:
    card_title = render_template('shuffling_album_card').encode('utf-8')
  else:
    card_title = render_template('playing_album_card').encode('utf-8')
  log.info(card_title)

  album = None
  response_text = ''
  if Artist:
    artist = kodi.FindArtist(Artist)
    if artist:
      for a in artist:
        log.info('Searching albums by "%s"', a[1].encode('utf-8'))
        album = kodi.FindAlbum(Album, a[0])
        if album:
          if shuffle:
            response_text = render_template('shuffling_album_artist', album_name=album[0][1], artist=a[1]).encode('utf-8')
          else:
            response_text = render_template('playing_album_artist', album_name=album[0][1], artist=a[1]).encode('utf-8')
          break
        elif not response_text:
          response_text = render_template('could_not_find_album_artist', album_name=Album, artist=a[1]).encode('utf-8')
    else:
      response_text = render_template('could_not_find_album_artist', album_name=Album, artist=Artist).encode('utf-8')
  else:
    album = kodi.FindAlbum(Album)
    if album:
      if shuffle:
        response_text = render_template('shuffling_album', album_name=album[0][1]).encode('utf-8')
      else:
        response_text = render_template('playing_album', album_name=album[0][1]).encode('utf-8')
    else:
      response_text = render_template('could_not_find_album', album_name=Album).encode('utf-8')

  if album:
    kodi.PlayerStop()
    kodi.ClearAudioPlaylist()
    kodi.AddAlbumToPlaylist(album[0][0], shuffle)
    kodi.StartAudioPlaylist()

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


# Handle the ListenToAlbum intent (Play whole album, or whole album by a specific artist).
@ask.intent('ListenToAlbum')
@preflight_check
def alexa_listen_album(kodi, Album, Artist):
  return _alexa_listen_album(kodi, Album, Artist)


# Handle the ShuffleAlbum intent (Shuffle whole album, or whole album by a specific artist).
@ask.intent('ShuffleAlbum')
@preflight_check
def alexa_shuffle_album(kodi, Album, Artist):
  return _alexa_listen_album(kodi, Album, Artist, True)


def _alexa_listen_latest_album(kodi, Artist, shuffle=False):
  if shuffle:
    card_title = render_template('shuffling_latest_album_card', heard_artist=Artist).encode('utf-8')
  else:
    card_title = render_template('playing_latest_album_card', heard_artist=Artist).encode('utf-8')
  log.info(card_title)

  artist = kodi.FindArtist(Artist)
  if artist:
    album_id = kodi.GetNewestAlbumFromArtist(artist[0][0])
    if album_id:
      album_label = kodi.GetAlbumDetails(album_id)['label']
      kodi.PlayerStop()
      kodi.ClearAudioPlaylist()
      kodi.AddAlbumToPlaylist(album_id, shuffle)
      kodi.StartAudioPlaylist()
      if shuffle:
        response_text = render_template('shuffling_album_artist', album_name=album_label, artist=artist[0][1]).encode('utf-8')
      else:
        response_text = render_template('playing_album_artist', album_name=album_label, artist=artist[0][1]).encode('utf-8')
    else:
      response_text = render_template('could_not_find_artist', artist_name=artist[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find', heard_name=Artist).encode('utf-8')

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


# Handle the ListenToLatestAlbum intent (Play latest album by a specific artist).
@ask.intent('ListenToLatestAlbum')
@preflight_check
def alexa_listen_latest_album(kodi, Artist):
  return _alexa_listen_latest_album(kodi, Artist)


# Handle the ShuffleLatestAlbum intent (Shuffle latest album by a specific artist).
@ask.intent('ShuffleLatestAlbum')
@preflight_check
def alexa_shuffle_latest_album(kodi, Artist):
  return _alexa_listen_latest_album(kodi, Artist, True)


# Handle the ListenToSong intent (Play a song, song by a specific artist,
# or song on a specific album).
@ask.intent('ListenToSong')
@preflight_check
def alexa_listen_song(kodi, Song, Album, Artist):
  card_title = render_template('playing_song_card').encode('utf-8')
  log.info(card_title)

  response_text = ''
  song = None
  if Artist:
    artist = kodi.FindArtist(Artist)
    if artist:
      for a in artist:
        log.info('Searching songs by "%s"', a[1].encode('utf-8'))
        song = kodi.FindSong(Song, a[0])
        if song:
          response_text = render_template('playing_song_artist', song_name=song[0][1], artist=a[1]).encode('utf-8')
          break
        elif not response_text:
          response_text = render_template('could_not_find_song_artist', song_name=Song, artist=a[1]).encode('utf-8')
    else:
      response_text = render_template('could_not_find_song_artist', song_name=Song, artist=Artist).encode('utf-8')
  elif Album:
    album = kodi.FindAlbum(Album)
    if album:
      for a in album:
        log.info('Searching on album "%s"', a[1].encode('utf-8'))
        song = kodi.FindSong(Song, album_id=a[0])
        if song:
          response_text = render_template('playing_song_album', song_name=song[0][1], album_name=a[1]).encode('utf-8')
          break
        elif not response_text:
          response_text = render_template('could_not_find_song_album', song_name=Song, album_name=a[1]).encode('utf-8')
    else:
      response_text = render_template('could_not_find_song_album', song_name=Song, album_name=Album).encode('utf-8')
  else:
    song = kodi.FindSong(Song)
    if song:
      response_text = render_template('playing_song', song_name=song[0][1]).encode('utf-8')
    else:
      response_text = render_template('could_not_find_song', song_name=Song).encode('utf-8')

  if song:
    kodi.PlayerStop()
    kodi.ClearAudioPlaylist()
    kodi.AddSongToPlaylist(song[0][0])
    kodi.StartAudioPlaylist()

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


# Handle the ListenToAlbumOrSong intent (Play whole album or song by a specific artist).
@ask.intent('ListenToAlbumOrSong')
@preflight_check
def alexa_listen_album_or_song(kodi, Song, Artist):
  card_title = render_template('playing_album_or_song').encode('utf-8')
  log.info(card_title)

  response_text = ''

  artist = kodi.FindArtist(Artist)
  if artist:
    for a in artist:
      log.info('Searching songs and albums by "%s"', a[1].encode('utf-8'))
      song = kodi.FindSong(Song, a[0])
      if song:
        kodi.PlayerStop()
        kodi.ClearAudioPlaylist()
        kodi.AddSongToPlaylist(song[0][0])
        kodi.StartAudioPlaylist()
        response_text = render_template('playing_song_artist', song_name=song[0][1], artist=a[1]).encode('utf-8')
        break
      else:
        album = kodi.FindAlbum(Song, a[0])
        if album:
          kodi.PlayerStop()
          kodi.ClearAudioPlaylist()
          kodi.AddAlbumToPlaylist(album[0][0])
          kodi.StartAudioPlaylist()
          response_text = render_template('playing_album_artist', album_name=album[0][1], artist=a[1]).encode('utf-8')
          break
        elif not response_text:
          response_text = render_template('could_not_find_multi', heard_name=Song, artist=a[1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find', heard_name=Artist).encode('utf-8')

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


# Handle the ListenToAudioPlaylistRecent intent (Shuffle all recently added songs).
@ask.intent('ListenToAudioPlaylistRecent')
@preflight_check
def alexa_listen_recently_added_songs(kodi):
  card_title = render_template('playing_recent_songs').encode('utf-8')
  log.info(card_title)

  response_text = render_template('no_recent_songs').encode('utf-8')

  songs_result = kodi.GetRecentlyAddedSongs()
  if songs_result:
    songs = songs_result['result']['songs']

    songs_array = []
    for song in songs:
      songs_array.append(song['songid'])

    kodi.PlayerStop()
    kodi.ClearAudioPlaylist()
    kodi.AddSongsToPlaylist(songs_array, True)
    kodi.StartAudioPlaylist()
    response_text = render_template('playing_recent_songs').encode('utf-8')

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


def _alexa_listen_audio_playlist(kodi, AudioPlaylist, shuffle=False):
  if shuffle:
    op = render_template('shuffling_empty').encode('utf-8')
  else:
    op = render_template('playing_empty').encode('utf-8')

  card_title = render_template('action_audio_playlist', action=op).encode('utf-8')
  log.info(card_title)

  playlist = kodi.FindAudioPlaylist(AudioPlaylist)
  if playlist:
    if shuffle:
      songs = kodi.GetPlaylistItems(playlist[0][0])['result']['files']
      songs_array = []
      for song in songs:
        songs_array.append(song['id'])

      kodi.PlayerStop()
      kodi.ClearAudioPlaylist()
      kodi.AddSongsToPlaylist(songs_array, True)
      kodi.StartAudioPlaylist()
    else:
      kodi.PlayerStop()
      kodi.StartAudioPlaylist(playlist[0][0])
    response_text = render_template('playing_playlist_audio', action=op, playlist_name=playlist[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find_playlist', heard_name=AudioPlaylist).encode('utf-8')

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


# Handle the ListenToAudioPlaylist intent.
@ask.intent('ListenToAudioPlaylist')
@preflight_check
def alexa_listen_audio_playlist(kodi, AudioPlaylist):
  return _alexa_listen_audio_playlist(kodi, AudioPlaylist)


# Handle the ShuffleAudioPlaylist intent.
@ask.intent('ShuffleAudioPlaylist')
@preflight_check
def alexa_shuffle_audio_playlist(kodi, AudioPlaylist):
  return _alexa_listen_audio_playlist(kodi, AudioPlaylist, True)


# Handle the PartyMode intent.
@ask.intent('PartyMode')
@preflight_check
def alexa_party_play(kodi):
  card_title = render_template('party_mode').encode('utf-8')
  log.info(card_title)

  kodi.PlayerStop()
  kodi.ClearAudioPlaylist()
  kodi.PartyPlayMusic()
  response_text = render_template('playing_party').encode('utf-8')
  return statement(response_text).simple_card(card_title, response_text)


# Handle the AMAZON.StartOverIntent intent.
@ask.intent('AMAZON.StartOverIntent')
@preflight_check
def alexa_start_over(kodi):
  card_title = render_template('playing_same').encode('utf-8')
  log.info(card_title)

  kodi.PlayerStartOver()
  return statement('').simple_card(card_title, '')


# Handle the AMAZON.NextIntent intent.
@ask.intent('AMAZON.NextIntent')
@preflight_check
def alexa_next(kodi):
  card_title = render_template('playing_next').encode('utf-8')
  log.info(card_title)

  kodi.PlayerSkip()
  return statement('').simple_card(card_title, '')


# Handle the AMAZON.PreviousIntent intent.
@ask.intent('AMAZON.PreviousIntent')
@preflight_check
def alexa_prev(kodi):
  card_title = render_template('playing_previous').encode('utf-8')
  log.info(card_title)

  kodi.PlayerPrev()
  return statement('').simple_card(card_title, '')


# Handle the AMAZON.ShuffleOnIntent intent.
@ask.intent('AMAZON.ShuffleOnIntent')
@preflight_check
def alexa_shuffle_on(kodi):
  card_title = render_template('shuffle_enable').encode('utf-8')
  log.info(card_title)

  kodi.PlayerShuffleOn()
  response_text = render_template('shuffle_on').encode('utf-8')
  return statement(response_text).simple_card(card_title, response_text)


# Handle the AMAZON.ShuffleOffIntent intent.
@ask.intent('AMAZON.ShuffleOffIntent')
@preflight_check
def alexa_shuffle_off(kodi):
  card_title = render_template('shuffle_disable').encode('utf-8')
  log.info(card_title)

  kodi.PlayerShuffleOff()
  response_text = render_template('shuffle_off').encode('utf-8')
  return statement(response_text).simple_card(card_title, response_text)


# Handle the AMAZON.LoopOnIntent intent.
@ask.intent('AMAZON.LoopOnIntent')
@preflight_check
def alexa_loop_on(kodi):
  card_title = render_template('loop_enable').encode('utf-8')
  log.info(card_title)

  kodi.PlayerLoopOn()

  response_text = ''

  curprops = kodi.GetActivePlayProperties()
  if curprops is not None:
    if curprops['repeat'] == 'one':
      response_text = render_template('loop_one').encode('utf-8')
    elif curprops['repeat'] == 'all':
      response_text = render_template('loop_all').encode('utf-8')
    elif curprops['repeat'] == 'off':
      response_text = render_template('loop_off').encode('utf-8')

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


# Handle the AMAZON.LoopOffIntent intent.
@ask.intent('AMAZON.LoopOffIntent')
@preflight_check
def alexa_loop_off(kodi):
  card_title = render_template('loop_disable').encode('utf-8')
  log.info(card_title)

  kodi.PlayerLoopOff()
  response_text = render_template('loop_off').encode('utf-8')
  return statement(response_text).simple_card(card_title, response_text)


# Handle the Fullscreen intent.
@ask.intent('Fullscreen')
@preflight_check
def alexa_fullscreen(kodi):
  card_title = render_template('toggle_fullscreen').encode('utf-8')
  log.info(card_title)

  kodi.ToggleFullscreen()
  return statement('').simple_card(card_title, '')


# Handle the StereoscopicMode intent.
@ask.intent('StereoscopicMode')
@preflight_check
def alexa_stereoscopic_mode(kodi):
  card_title = render_template('toggle_stereoscopic_mode').encode('utf-8')
  log.info(card_title)

  kodi.ToggleStereoscopicMode()
  return statement('').simple_card(card_title, '')


# Handle the AudioPassthrough intent.
@ask.intent('AudioPassthrough')
@preflight_check
def alexa_audio_passthrough(kodi):
  card_title = render_template('toggle_audio_passthrough').encode('utf-8')
  log.info(card_title)

  kodi.ToggleAudioPassthrough()
  return statement('').simple_card(card_title, '')


# Handle the Mute intent.
@ask.intent('Mute')
@preflight_check
def alexa_mute(kodi):
  card_title = render_template('mute_unmute').encode('utf-8')
  log.info(card_title)

  kodi.ToggleMute()
  return statement('').simple_card(card_title, '')


# Handle the VolumeUp intent.
@ask.intent('VolumeUp')
@preflight_check
def alexa_volume_up(kodi):
  card_title = render_template('volume_up').encode('utf-8')
  log.info(card_title)

  vol = kodi.VolumeUp()['result']
  response_text = render_template('volume_set', num=vol).encode('utf-8')
  return statement(response_text).simple_card(card_title, response_text)


# Handle the VolumeDown intent.
@ask.intent('VolumeDown')
@preflight_check
def alexa_volume_down(kodi):
  card_title = render_template('volume_down').encode('utf-8')
  log.info(card_title)

  vol = kodi.VolumeDown()['result']
  response_text = render_template('volume_set', num=vol).encode('utf-8')
  return statement(response_text).simple_card(card_title, response_text)


# Handle the VolumeSet intent.
@ask.intent('VolumeSet')
@preflight_check
def alexa_volume_set(kodi, Volume):
  card_title = render_template('adjusting_volume').encode('utf-8')
  log.info(card_title)

  vol = kodi.VolumeSet(int(Volume), False)['result']
  response_text = render_template('volume_set', num=vol).encode('utf-8')
  return statement(response_text).simple_card(card_title, response_text)


# Handle the VolumeSetPct intent.
@ask.intent('VolumeSetPct')
@preflight_check
def alexa_volume_set_pct(kodi, Volume):
  card_title = render_template('adjusting_volume').encode('utf-8')
  log.info(card_title)

  vol = kodi.VolumeSet(int(Volume))['result']
  response_text = render_template('volume_set', num=vol).encode('utf-8')
  return statement(response_text).simple_card(card_title, response_text)


# Handle the SubtitlesOn intent.
@ask.intent('SubtitlesOn')
@preflight_check
def alexa_subtitles_on(kodi):
  card_title = render_template('subtitles_enable').encode('utf-8')
  log.info(card_title)

  kodi.PlayerSubtitlesOn()
  response_text = kodi.GetCurrentSubtitles()
  return statement(response_text).simple_card(card_title, response_text)


# Handle the SubtitlesOff intent.
@ask.intent('SubtitlesOff')
@preflight_check
def alexa_subtitles_off(kodi):
  card_title = render_template('subtitles_disable').encode('utf-8')
  log.info(card_title)

  kodi.PlayerSubtitlesOff()
  response_text = render_template('subtitles_disable').encode('utf-8')
  return statement(response_text).simple_card(card_title, response_text)


# Handle the SubtitlesNext intent.
@ask.intent('SubtitlesNext')
@preflight_check
def alexa_subtitles_next(kodi):
  card_title = render_template('subtitles_next').encode('utf-8')
  log.info(card_title)

  kodi.PlayerSubtitlesNext()
  response_text = kodi.GetCurrentSubtitles()
  return statement(response_text).simple_card(card_title, response_text)


# Handle the SubtitlesPrevious intent.
@ask.intent('SubtitlesPrevious')
@preflight_check
def alexa_subtitles_previous(kodi):
  card_title = render_template('subtitles_previous').encode('utf-8')
  log.info(card_title)

  kodi.PlayerSubtitlesPrevious()
  response_text = kodi.GetCurrentSubtitles()
  return statement(response_text).simple_card(card_title, response_text)


# Handle the SubtitlesDownload intent.
@ask.intent('SubtitlesDownload')
@preflight_check
def alexa_subtitles_download(kodi):
  card_title = render_template('subtitles_download').encode('utf-8')
  log.info(card_title)

  item = kodi.DownloadSubtitles()
  return statement(card_title).simple_card(card_title, '')


# Handle the AudioStreamNext intent.
@ask.intent('AudioStreamNext')
@preflight_check
def alexa_audiostream_next(kodi):
  card_title = render_template('audio_stream_next').encode('utf-8')
  log.info(card_title)

  kodi.PlayerAudioStreamNext()
  response_text = kodi.GetCurrentAudioStream()
  return statement(response_text).simple_card(card_title, response_text)


# Handle the AudioStreamPrevious intent.
@ask.intent('AudioStreamPrevious')
@preflight_check
def alexa_audiostream_previous(kodi):
  card_title = render_template('audio_stream_previous').encode('utf-8')
  log.info(card_title)

  kodi.PlayerAudioStreamPrevious()
  response_text = kodi.GetCurrentAudioStream()
  return statement(response_text).simple_card(card_title, response_text)


# Handle the PlayerMoveUp intent.
@ask.intent('PlayerMoveUp')
@preflight_check
def alexa_player_move_up(kodi):
  card_title = render_template('player_move_up').encode('utf-8')
  log.info(card_title)

  kodi.PlayerMoveUp()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerMoveDown intent.
@ask.intent('PlayerMoveDown')
@preflight_check
def alexa_player_move_down(kodi):
  card_title = render_template('player_move_down').encode('utf-8')
  log.info(card_title)

  kodi.PlayerMoveDown()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerMoveLeft intent.
@ask.intent('PlayerMoveLeft')
@preflight_check
def alexa_player_move_left(kodi):
  card_title = render_template('player_move_left').encode('utf-8')
  log.info(card_title)

  kodi.PlayerMoveLeft()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerMoveRight intent.
@ask.intent('PlayerMoveRight')
@preflight_check
def alexa_player_move_right(kodi):
  card_title = render_template('player_move_right').encode('utf-8')
  log.info(card_title)

  kodi.PlayerMoveRight()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerRotateClockwise intent.
@ask.intent('PlayerRotateClockwise')
@preflight_check
def alexa_player_rotate_clockwise(kodi):
  card_title = render_template('player_rotate').encode('utf-8')
  log.info(card_title)

  kodi.PlayerRotateClockwise()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerRotateCounterClockwise intent.
@ask.intent('PlayerRotateCounterClockwise')
@preflight_check
def alexa_player_rotate_counterclockwise(kodi):
  card_title = render_template('player_rotate_cc').encode('utf-8')
  log.info(card_title)

  kodi.PlayerRotateCounterClockwise()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomHold intent.
@ask.intent('PlayerZoomHold')
@preflight_check
def alexa_player_zoom_hold(kodi):
  card_title = render_template('player_zoom_hold').encode('utf-8')
  log.info(card_title)

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


# Handle the PlayerZoomIn intent.
@ask.intent('PlayerZoomIn')
@preflight_check
def alexa_player_zoom_in(kodi):
  card_title = render_template('player_zoom_in').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoomIn()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomInMoveUp intent.
@ask.intent('PlayerZoomInMoveUp')
@preflight_check
def alexa_player_zoom_in_move_up(kodi):
  card_title = render_template('player_zoom_in_up').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoomIn()
  kodi.PlayerMoveUp()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomInMoveDown intent.
@ask.intent('PlayerZoomInMoveDown')
@preflight_check
def alexa_player_zoom_in_move_down(kodi):
  card_title = render_template('player_zoom_in_down').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoomIn()
  kodi.PlayerMoveDown()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomInMoveLeft intent.
@ask.intent('PlayerZoomInMoveLeft')
@preflight_check
def alexa_player_zoom_in_move_left(kodi):
  card_title = render_template('player_zoom_in_left').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoomIn()
  kodi.PlayerMoveLeft()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomInMoveRight intent.
@ask.intent('PlayerZoomInMoveRight')
@preflight_check
def alexa_player_zoom_in_move_right(kodi):
  card_title = render_template('player_zoom_in_right').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoomIn()
  kodi.PlayerMoveRight()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomOut intent.
@ask.intent('PlayerZoomOut')
@preflight_check
def alexa_player_zoom_out(kodi):
  card_title = render_template('player_zoom_out').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoomOut()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomOutMoveUp intent.
@ask.intent('PlayerZoomOutMoveUp')
@preflight_check
def alexa_player_zoom_out_move_up(kodi):
  card_title = render_template('player_zoom_out_up').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoomOut()
  kodi.PlayerMoveUp()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomOutMoveDown intent.
@ask.intent('PlayerZoomOutMoveDown')
@preflight_check
def alexa_player_zoom_out_move_down(kodi):
  card_title = render_template('player_zoom_out_down').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoomOut()
  kodi.PlayerMoveDown()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomOutMoveLeft intent.
@ask.intent('PlayerZoomOutMoveLeft')
@preflight_check
def alexa_player_zoom_out_move_left(kodi):
  card_title = render_template('player_zoom_out_left').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoomOut()
  kodi.PlayerMoveLeft()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomOutMoveRight intent.
@ask.intent('PlayerZoomOutMoveRight')
@preflight_check
def alexa_player_zoom_out_move_right(kodi):
  card_title = render_template('player_zoom_out_right').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoomOut()
  kodi.PlayerMoveRight()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PlayerZoomReset intent.
@ask.intent('PlayerZoomReset')
@preflight_check
def alexa_player_zoom_reset(kodi):
  card_title = render_template('player_zoom_normal').encode('utf-8')
  log.info(card_title)

  kodi.PlayerZoom(1)
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the Menu intent.
@ask.intent('Menu')
@preflight_check
def alexa_context_menu(kodi):
  log.info('Navigate: Context Menu')

  kodi.Menu()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the Home intent.
@ask.intent('Home')
@preflight_check
def alexa_go_home(kodi):
  log.info('Navigate: Home')

  kodi.Home()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the Select intent.
@ask.intent('Select')
@preflight_check
def alexa_select(kodi):
  log.info('Navigate: Select')

  kodi.Select()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PageUp intent.
@ask.intent('PageUp')
@preflight_check
def alexa_pageup(kodi):
  log.info('Navigate: Page up')

  kodi.PageUp()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the PageDown intent.
@ask.intent('PageDown')
@preflight_check
def alexa_pagedown(kodi):
  log.info('Navigate: Page down')

  kodi.PageDown()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the Left intent.
@ask.intent('Left')
@preflight_check
def alexa_left(kodi):
  log.info('Navigate: Left')

  kodi.Left()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the Right intent.
@ask.intent('Right')
@preflight_check
def alexa_right(kodi):
  log.info('Navigate: Right')

  kodi.Right()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the Up intent.
@ask.intent('Up')
@preflight_check
def alexa_up(kodi):
  log.info('Navigate: Up')

  kodi.Up()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the Down intent.
@ask.intent('Down')
@preflight_check
def alexa_down(kodi):
  log.info('Navigate: Down')

  kodi.Down()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the Back intent.
@ask.intent('Back')
@preflight_check
def alexa_back(kodi):
  log.info('Navigate: Back')

  kodi.Back()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the Info intent.
@ask.intent('Info')
@preflight_check
def alexa_info(kodi):
  log.info('Navigate: Info')

  kodi.Info()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the ViewMovies intent.
@ask.intent('ViewMovies')
@preflight_check
def alexa_show_movies(kodi, MovieGenre):
  log.info('Navigate: Movies')

  genre = None
  if MovieGenre:
    g = kodi.FindVideoGenre(MovieGenre)
    if g:
      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')
@preflight_check
def alexa_show_shows(kodi, ShowGenre):
  log.info('Navigate: Shows')

  genre = None
  if ShowGenre:
    g = kodi.FindVideoGenre(ShowGenre, 'tvshow')
    if g:
      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')
@preflight_check
def alexa_show_music_videos(kodi, MusicVideoGenre):
  log.info('Navigate: MusicVideos')

  genre = None
  if MusicVideoGenre:
    g = kodi.FindVideoGenre(MusicVideoGenre, 'musicvideo')
    if g:
      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')
@preflight_check
def alexa_show_music(kodi, MusicGenre):
  log.info('Navigate: Music')

  genre = None
  if MusicGenre:
    g = kodi.FindMusicGenre(MusicGenre)
    if g:
      genre = g[0][0]
  kodi.ShowMusic(genre)
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the ViewArtists intent.
@ask.intent('ViewArtists')
@preflight_check
def alexa_show_artists(kodi):
  log.info('Navigate: Artists')

  kodi.ShowMusicArtists()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the ViewAlbums intent.
@ask.intent('ViewAlbums')
@preflight_check
def alexa_show_albums(kodi):
  log.info('Navigate: Albums')

  kodi.ShowMusicAlbums()
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the ViewVideoPlaylist intent.
@ask.intent('ViewVideoPlaylist')
@preflight_check
def alexa_show_video_playlist(kodi, VideoPlaylist):
  log.info('Navigate: Video Playlist')

  playlist = kodi.FindVideoPlaylist(VideoPlaylist)
  if playlist:
    kodi.ShowVideoPlaylist(playlist[0][0])
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the ViewMoviePlaylistRecent intent.
@ask.intent('ViewMoviePlaylistRecent')
@preflight_check
def alexa_show_recent_movies_playlist(kodi):
  log.info('Navigate: Recently Added Movies')

  kodi.ShowVideoPlaylist('videodb://recentlyaddedmovies/')
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the ViewEpisodePlaylistRecent intent.
@ask.intent('ViewEpisodePlaylistRecent')
@preflight_check
def alexa_show_recent_episodes_playlist(kodi):
  log.info('Navigate: Recently Added Episodes')

  kodi.ShowVideoPlaylist('videodb://recentlyaddedepisodes/')
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the ViewMusicVideoPlaylistRecent intent.
@ask.intent('ViewMusicVideoPlaylistRecent')
@preflight_check
def alexa_show_recent_musicvideos_playlist(kodi):
  log.info('Navigate: Recently Added Music Videos')

  kodi.ShowVideoPlaylist('videodb://recentlyaddedmusicvideos/')
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the ViewAudioPlaylist intent.
@ask.intent('ViewAudioPlaylist')
@preflight_check
def alexa_show_audio_playlist(kodi, AudioPlaylist):
  log.info('Navigate: Audio Playlist')

  playlist = kodi.FindAudioPlaylist(AudioPlaylist)
  if playlist:
    kodi.ShowMusicPlaylist(playlist[0][0])
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the ViewAudioPlaylistRecent intent.
@ask.intent('ViewAudioPlaylistRecent')
@preflight_check
def alexa_show_recent_audio_playlist(kodi):
  log.info('Navigate: Recently Added Albums')

  kodi.ShowMusicPlaylist('musicdb://recentlyaddedalbums/')
  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the ViewPlaylist intent.
@ask.intent('ViewPlaylist')
@preflight_check
def alexa_show_playlist(kodi, VideoPlaylist, AudioPlaylist):
  log.info('Navigate: Playlist')

  heard_search = ''
  if VideoPlaylist:
    heard_search = VideoPlaylist
  elif AudioPlaylist:
    heard_search = AudioPlaylist

  if heard_search:
    playlist = kodi.FindVideoPlaylist(heard_search)
    if playlist:
      kodi.ShowVideoPlaylist(playlist[0][0])
    else:
      playlist = kodi.FindAudioPlaylist(heard_search)
      if playlist:
        kodi.ShowMusicPlaylist(playlist[0][0])

  response_text = render_template('short_confirm').encode('utf-8')
  return question(response_text)


# Handle the Shutdown intent.
@ask.intent('Shutdown')
@preflight_check
def alexa_shutdown(kodi):
  response_text = render_template('are_you_sure_shutdown').encode('utf-8')
  session.attributes['shutting_down'] = True
  return question(response_text).reprompt(response_text)


# Handle the Reboot intent.
@ask.intent('Reboot')
@preflight_check
def alexa_reboot(kodi):
  response_text = render_template('are_you_sure_reboot').encode('utf-8')
  session.attributes['rebooting'] = True
  return question(response_text).reprompt(response_text)


# Handle the Hibernate intent.
@ask.intent('Hibernate')
@preflight_check
def alexa_hibernate(kodi):
  response_text = render_template('are_you_sure_hibernate').encode('utf-8')
  session.attributes['hibernating'] = True
  return question(response_text).reprompt(response_text)


# Handle the Suspend intent.
@ask.intent('Suspend')
@preflight_check
def alexa_suspend(kodi):
  response_text = render_template('are_you_sure_suspend').encode('utf-8')
  session.attributes['suspending'] = True
  return question(response_text).reprompt(response_text)


# Handle the EjectMedia intent.
@ask.intent('EjectMedia')
@preflight_check
def alexa_ejectmedia(kodi):
  card_title = render_template('ejecting_media').encode('utf-8')
  log.info(card_title)

  kodi.SystemEjectMedia()

  if not 'queries_keep_open' in session.attributes:
    return statement(card_title).simple_card(card_title, '')

  return question(card_title)


# Handle the CleanVideo intent.
@ask.intent('CleanVideo')
@preflight_check
def alexa_clean_video(kodi):
  card_title = render_template('clean_video').encode('utf-8')
  log.info(card_title)

  kodi.CleanVideo()
  return statement(card_title).simple_card(card_title, '')


# Handle the UpdateVideo intent.
@ask.intent('UpdateVideo')
@preflight_check
def alexa_update_video(kodi):
  card_title = render_template('update_video').encode('utf-8')
  log.info(card_title)

  kodi.UpdateVideo()
  return statement(card_title).simple_card(card_title, '')


# Handle the CleanAudio intent.
@ask.intent('CleanAudio')
@preflight_check
def alexa_clean_audio(kodi):
  card_title = render_template('clean_audio').encode('utf-8')
  log.info(card_title)

  kodi.CleanMusic()
  return statement(card_title).simple_card(card_title, '')


# Handle the UpdateAudio intent.
@ask.intent('UpdateAudio')
@preflight_check
def alexa_update_audio(kodi):
  card_title = render_template('update_audio').encode('utf-8')
  log.info(card_title)

  kodi.UpdateMusic()
  return statement(card_title).simple_card(card_title, '')


# Handle the AddonExecute intent.
@ask.intent('AddonExecute')
@preflight_check
def alexa_addon_execute(kodi, Addon):
  card_title = render_template('open_addon').encode('utf-8')
  log.info(card_title)

  addon = kodi.FindAddon(Addon)
  if addon:
    kodi.Home()
    kodi.AddonExecute(addon[0][0])
    response_text = render_template('opening', heard_name=addon[0][1]).encode('utf-8')
    return statement(response_text).simple_card(card_title, response_text)
  else:
    response_text = render_template('could_not_find_addon', heard_addon=Addon).encode('utf-8')

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

# Handle the AddonGlobalSearch intent.
@ask.intent('AddonGlobalSearch')
@preflight_check
def alexa_addon_globalsearch(kodi, Movie, Show, Artist, Album, Song):
  card_title = render_template('search').encode('utf-8')
  log.info(card_title)
  heard_search = ''

  if Movie:
    heard_search = Movie
  elif Show:
    heard_search = Show
  elif Artist:
    heard_search = Artist
  elif Album:
    heard_search = Album
  elif Song:
    heard_search = Song

  if heard_search:
    kodi.Home()
    kodi.AddonGlobalSearch(heard_search)
    response_text = render_template('searching', heard_name=heard_search).encode('utf-8')
  else:
    response_text = render_template('could_not_find_generic').encode('utf-8')

  if not 'queries_keep_open' in session.attributes:
    return statement(response_text).simple_card(card_title, response_text)

  return question(response_text).reprompt(response_text)


# Handle the WatchVideo intent.
#
# Defaults to Movies, but will fuzzy match across the library if none found.
@ask.intent('WatchVideo')
@preflight_check
def alexa_watch_video(kodi, Movie):
  log.info('Watch a video...')
  return _alexa_play_media(kodi, Movie=Movie, content=['video'])


# Handle the WatchRandomMovie intent.
@ask.intent('WatchRandomMovie')
@preflight_check
def alexa_watch_random_movie(kodi, MovieGenre):
  genre = []
  # If a genre has been specified, match the genre for use in selecting a random film
  if MovieGenre:
    card_title = render_template('playing_random_movie_genre', genre=MovieGenre).encode('utf-8')
    genre = kodi.FindVideoGenre(MovieGenre)
  else:
    card_title = render_template('playing_random_movie').encode('utf-8')
  log.info(card_title)

  # Select from specified genre if one was matched
  movies_array = []
  if genre:
    movies_array = kodi.GetUnwatchedMoviesByGenre(genre[0][1])
  else:
    movies_array = kodi.GetUnwatchedMovies()
  if not movies_array:
    # Fall back to all movies if no unwatched available
    if genre:
      movies = kodi.GetMoviesByGenre(genre[0][1])
    else:
      movies = kodi.GetMovies()
    if 'result' in movies and 'movies' in movies['result']:
      movies_array = movies['result']['movies']

  if movies_array:
    random_movie = random.choice(movies_array)
    kodi.PlayMovie(random_movie['movieid'], False)
    if genre:
      response_text = render_template('playing_genre_movie', genre=genre[0][1], movie_name=random_movie['label']).encode('utf-8')
    else:
      response_text = render_template('playing', heard_name=random_movie['label']).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 WatchMovie intent.
@ask.intent('WatchMovie')
@preflight_check
def alexa_watch_movie(kodi, Movie):
  card_title = render_template('playing_movie').encode('utf-8')
  log.info(card_title)

  movie = kodi.FindMovie(Movie)
  if movie:
    kodi.PlayMovie(movie[0][0])
    if kodi.GetMovieDetails(movie[0][0])['resume']['position'] > 0:
      action = render_template('resuming_empty').encode('utf-8')
    else:
      action = render_template('playing_empty').encode('utf-8')
    response_text = render_template('playing_action', action=action, movie_name=movie[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find_movie', heard_movie=Movie).encode('utf-8')

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


# Handle the WatchMovieTrailer intent.
@ask.intent('WatchMovieTrailer')
@preflight_check
def alexa_watch_movie_trailer(kodi, Movie):
  card_title = render_template('playing_movie_trailer').encode('utf-8')
  log.info(card_title)

  movie_id = None
  # If we're currently recommending a movie to the user, let's assume that
  # they're wanting to watch the trailer for that.
  if 'play_media_type' in session.attributes and session.attributes['play_media_type'] == 'movie':
    movie_id = session.attributes['play_media_id']
  elif Movie:
    movie = kodi.FindMovie(Movie)
    if movie:
      movie_id = movie[0][0]

  if movie_id:
    movie_details = kodi.GetMovieDetails(movie_id)
    if 'trailer' in movie_details and movie_details['trailer']:
      kodi.PlayFile(movie_details['trailer'])
      response_text = render_template('playing_trailer', heard_name=movie_details['label']).encode('utf-8')
    else:
      response_text = render_template('could_not_find_trailer', heard_name=Movie).encode('utf-8')
  elif Movie:
    response_text = render_template('could_not_find_movie', heard_movie=Movie).encode('utf-8')
  else:
    response_text = render_template('could_not_find_generic').encode('utf-8')

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


# Handle the ShuffleShow intent.
@ask.intent('ShuffleShow')
@preflight_check
def alexa_shuffle_show(kodi, Show):
  card_title = render_template('shuffling_episodes', heard_show=Show).encode('utf-8')
  log.info(card_title)

  show = kodi.FindTvShow(Show)
  if show:
    episodes_array = []
    episodes_result = kodi.GetEpisodesFromShow(show[0][0])
    for episode in episodes_result['result']['episodes']:
      episodes_array.append(episode['episodeid'])

    kodi.PlayerStop()
    kodi.ClearVideoPlaylist()
    kodi.AddEpisodesToPlaylist(episodes_array, True)
    kodi.StartVideoPlaylist()
    response_text = render_template('shuffling', heard_name=show[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find_show', heard_show=Show).encode('utf-8')

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


def _alexa_watch_random_episode(kodi, Show):
  card_title = render_template('playing_random_episode', heard_show=Show).encode('utf-8')
  log.info(card_title)

  show = kodi.FindTvShow(Show)
  if show:
    episodes_result = kodi.GetEpisodesFromShow(show[0][0])

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

    episode_id = random.choice(episodes_array)
    episode_details = kodi.GetEpisodeDetails(episode_id)

    kodi.PlayEpisode(episode_id, False)
    response_text = render_template('playing_episode_number', season=episode_details['season'], episode=episode_details['episode'], show_name=show[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find_show', heard_show=Show).encode('utf-8')

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


# Handle the WatchRandomEpisode intent.
@ask.intent('WatchRandomEpisode')
@preflight_check
def alexa_watch_random_episode(kodi, Show):
  return _alexa_watch_random_episode(kodi, Show)


# Handle the WatchRandomShow intent.
@ask.intent('WatchRandomShow')
@preflight_check
def alexa_watch_random_show(kodi, ShowGenre):
  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')
  log.info(card_title)

  # Select from specified genre if one was matched
  if genre:
    shows_array = kodi.GetUnwatchedShowsByGenre(genre[0][1])
  else:
    shows_array = kodi.GetUnwatchedShows()
  if shows_array:
    random_show = random.choice(shows_array)
    return _alexa_watch_next_episode(kodi, random_show['label'])
  else:
    # Fall back to all shows if no unwatched available
    if genre:
      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(kodi, 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')
@preflight_check
def alexa_watch_episode(kodi, Show, Season, Episode):
  card_title = render_template('playing_an_episode', heard_show=Show).encode('utf-8')
  log.info(card_title)

  show = kodi.FindTvShow(Show)
  if show:
    episode_id = kodi.GetSpecificEpisode(show[0][0], Season, Episode)
    if episode_id:
      kodi.PlayEpisode(episode_id)

      if kodi.GetEpisodeDetails(episode_id)['resume']['position'] > 0:
        action = render_template('resuming_empty').encode('utf-8')
      else:
        action = render_template('playing_empty').encode('utf-8')
      response_text = render_template('playing_action_episode_number', action=action, season=Season, episode=Episode, show_name=show[0][1]).encode('utf-8')

    else:
      response_text = render_template('could_not_find_episode_show', season=Season, episode=Episode, show_name=show[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find_show', heard_show=Show).encode('utf-8')

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


def _alexa_watch_next_episode(kodi, Show):
  card_title = render_template('playing_next_unwatched_episode', heard_show=Show).encode('utf-8')
  log.info(card_title)

  show = kodi.FindTvShow(Show)
  if show:
    next_episode_id = kodi.GetNextUnwatchedEpisode(show[0][0])
    if next_episode_id:
      kodi.PlayEpisode(next_episode_id)

      episode_details = kodi.GetEpisodeDetails(next_episode_id)
      if episode_details['resume']['position'] > 0:
        action = render_template('resuming_empty').encode('utf-8')
      else:
        action = render_template('playing_empty').encode('utf-8')
      response_text = render_template('playing_action_episode_number', action=action, season=episode_details['season'], episode=episode_details['episode'], show_name=show[0][1]).encode('utf-8')
    else:
      response_text = render_template('no_new_episodes_show', show_name=show[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find_show', heard_show=Show).encode('utf-8')

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


# Handle the WatchNextEpisode intent.
@ask.intent('WatchNextEpisode')
@preflight_check
def alexa_watch_next_episode(kodi, Show):
  return _alexa_watch_next_episode(kodi, Show)


# Handle the WatchLatestEpisode intent.
@ask.intent('WatchLatestEpisode')
@preflight_check
def alexa_watch_newest_episode(kodi, Show):
  card_title = render_template('playing_newest_episode', heard_show=Show).encode('utf-8')
  log.info(card_title)

  show = kodi.FindTvShow(Show)
  if show:
    episode_id = kodi.GetNewestEpisodeFromShow(show[0][0])
    if episode_id:
      kodi.PlayEpisode(episode_id)

      episode_details = kodi.GetEpisodeDetails(episode_id)
      if episode_details['resume']['position'] > 0:
        action = render_template('resuming_empty').encode('utf-8')
      else:
        action = render_template('playing_empty').encode('utf-8')
      response_text = render_template('playing_action_episode_number', action=action, season=episode_details['season'], episode=episode_details['episode'], show_name=show[0][1]).encode('utf-8')
    else:
      response_text = render_template('no_new_episodes_show', show_name=show[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find_show', heard_show=Show).encode('utf-8')

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


# Handle the WatchLastShow intent.
@ask.intent('WatchLastShow')
@preflight_check
def alexa_watch_last_show(kodi):
  card_title = render_template('last_unwatched').encode('utf-8')
  log.info(card_title)

  last_show_obj = kodi.GetLastWatchedShow()

  try:
    last_show_id = last_show_obj['result']['episodes'][0]['tvshowid']
    next_episode_id = kodi.GetNextUnwatchedEpisode(last_show_id)

    if next_episode_id:
      kodi.PlayEpisode(next_episode_id)

      episode_details = kodi.GetEpisodeDetails(next_episode_id)
      if episode_details['resume']['position'] > 0:
        action = render_template('resuming_empty').encode('utf-8')
      else:
        action = render_template('playing_empty').encode('utf-8')
      response_text = render_template('playing_action_episode_number', action=action, season=episode_details['season'], episode=episode_details['episode'], show_name=last_show_obj['result']['episodes'][0]['showtitle']).encode('utf-8')
    else:
      response_text = render_template('no_new_episodes_show', show_name=last_show_obj['result']['episodes'][0]['showtitle']).encode('utf-8')
  except:
    response_text = render_template('error_parsing_results').encode('utf-8')

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


# Handle the WatchRandomMusicVideo intent.
@ask.intent('WatchRandomMusicVideo')
@preflight_check
def alexa_watch_random_music_video(kodi, MusicVideoGenre, Artist):
  if MusicVideoGenre and Artist:
    card_title = render_template('playing_random_musicvideo_genre_artist', genre=MusicVideoGenre, artist=Artist).encode('utf-8')
  if MusicVideoGenre:
    card_title = render_template('playing_random_musicvideo_genre', genre=MusicVideoGenre).encode('utf-8')
  elif Artist:
    card_title = render_template('playing_random_musicvideo_artist', artist=Artist).encode('utf-8')
  else:
    card_title = render_template('playing_random_musicvideo').encode('utf-8')
  log.info(card_title)

  # Select from specified genre if specified
  genre = []
  if MusicVideoGenre:
    genre = kodi.FindVideoGenre(MusicVideoGenre, 'musicvideo')
  if genre:
    mvs = kodi.GetMusicVideosByGenre(genre[0][1])
  else:
    mvs = kodi.GetMusicVideos()

  if 'result' in mvs and 'musicvideos' in mvs['result']:
    # Narrow down by artist if specified
    if Artist:
      musicvideos_result = kodi.FilterMusicVideosByArtist(mvs['result']['musicvideos'], Artist)
    else:
      musicvideos_result = mvs['result']['musicvideos']

    if musicvideos_result:
      random_musicvideo = random.choice(musicvideos_result)
      kodi.PlayMusicVideo(random_musicvideo['musicvideoid'])

      musicvideo_details = kodi.GetMusicVideoDetails(random_musicvideo['musicvideoid'])
      response_text = render_template('playing_musicvideo', musicvideo_name=random_musicvideo['label'], artist_name=musicvideo_details['artist'][0]).encode('utf-8')
    elif genre and Artist:
      response_text = render_template('could_not_find_musicvideos_genre_artist', genre_name=genre[0][1], artist_name=Artist).encode('utf-8')
    elif MusicVideoGenre and Artist:
      response_text = render_template('could_not_find_musicvideos_genre_artist', genre_name=MusicVideoGenre, artist_name=Artist).encode('utf-8')
    elif genre:
      response_text = render_template('could_not_find_musicvideos_genre', genre_name=genre[0][1]).encode('utf-8')
    elif MusicVideoGenre:
      response_text = render_template('could_not_find_musicvideos_genre', genre_name=MusicVideoGenre).encode('utf-8')
    elif Artist:
      response_text = render_template('could_not_find_musicvideos_artist', artist_name=Artist).encode('utf-8')
    else:
      response_text = render_template('error_parsing_results').encode('utf-8')
  elif genre:
    response_text = render_template('could_not_find_musicvideos_genre', genre_name=genre[0][1]).encode('utf-8')
  elif MusicVideoGenre:
    response_text = render_template('could_not_find_musicvideos_genre', genre_name=MusicVideoGenre).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 WatchMusicVideo intent.
@ask.intent('WatchMusicVideo')
@preflight_check
def alexa_watch_music_video(kodi, MusicVideo, Artist):
  card_title = render_template('playing_musicvideo_card').encode('utf-8')
  log.info(card_title)

  musicvideo = kodi.FindMusicVideo(MusicVideo, Artist)
  if musicvideo:
    kodi.PlayMusicVideo(musicvideo[0][0])

    musicvideo_details = kodi.GetMusicVideoDetails(musicvideo[0][0])
    response_text = render_template('playing_musicvideo', musicvideo_name=musicvideo[0][1], artist_name=musicvideo_details['artist'][0]).encode('utf-8')
  elif Artist:
    response_text = render_template('could_not_find_musicvideo_artist', heard_musicvideo=MusicVideo, heard_artist=Artist).encode('utf-8')
  else:
    response_text = render_template('could_not_find_musicvideo', heard_musicvideo=MusicVideo).encode('utf-8')

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


# Handle the ShuffleMusicVideos intent.
@ask.intent('ShuffleMusicVideos')
@preflight_check
def alexa_shuffle_music_videos(kodi, MusicVideoGenre, Artist):
  if MusicVideoGenre and Artist:
    card_title = render_template('shuffling_musicvideos_genre_artist', genre=MusicVideoGenre, artist=Artist).encode('utf-8')
  elif MusicVideoGenre:
    card_title = render_template('shuffling_musicvideos_genre', genre=MusicVideoGenre).encode('utf-8')
  elif Artist:
    card_title = render_template('shuffling_musicvideos_artist', artist=Artist).encode('utf-8')
  else:
    card_title = render_template('shuffling_musicvideos').encode('utf-8')
  log.info(card_title)

  # Select from specified genre if specified
  genre = []
  if MusicVideoGenre:
    genre = kodi.FindVideoGenre(MusicVideoGenre, 'musicvideo')
  if genre:
    mvs = kodi.GetMusicVideosByGenre(genre[0][1])
  else:
    mvs = kodi.GetMusicVideos()

  if 'result' in mvs and 'musicvideos' in mvs['result']:
    # Narrow down by artist if specified
    if Artist:
      musicvideos_result = kodi.FilterMusicVideosByArtist(mvs['result']['musicvideos'], Artist)
    else:
      musicvideos_result = mvs['result']['musicvideos']

    if musicvideos_result:
      musicvideos_array = []
      for musicvideo in musicvideos_result:
        musicvideos_array.append(musicvideo['musicvideoid'])

      kodi.PlayerStop()
      kodi.ClearVideoPlaylist()
      kodi.AddMusicVideosToPlaylist(musicvideos_array, True)
      kodi.StartVideoPlaylist()

      if genre and Artist:
        response_text = render_template('shuffling_musicvideos_genre_artist', genre=genre[0][1], artist=musicvideos_result[0]['artist']).encode('utf-8')
      elif genre:
        response_text = render_template('shuffling_musicvideos_genre', genre=genre[0][1]).encode('utf-8')
      elif Artist:
        response_text = render_template('shuffling_musicvideos_artist', artist=musicvideos_result[0]['artist']).encode('utf-8')
      else:
        response_text = render_template('shuffling_musicvideos').encode('utf-8')
    elif genre and Artist:
      response_text = render_template('could_not_find_musicvideos_genre_artist', genre_name=genre[0][1], artist_name=Artist).encode('utf-8')
    elif MusicVideoGenre and Artist:
      response_text = render_template('could_not_find_musicvideos_genre_artist', genre_name=MusicVideoGenre, artist_name=Artist).encode('utf-8')
    elif genre:
      response_text = render_template('could_not_find_musicvideos_genre', genre_name=genre[0][1]).encode('utf-8')
    elif MusicVideoGenre:
      response_text = render_template('could_not_find_musicvideos_genre', genre_name=MusicVideoGenre).encode('utf-8')
    elif Artist:
      response_text = render_template('could_not_find_musicvideos_artist', artist_name=Artist).encode('utf-8')
    else:
      response_text = render_template('error_parsing_results').encode('utf-8')
  elif genre:
    response_text = render_template('could_not_find_musicvideos_genre', genre_name=genre[0][1]).encode('utf-8')
  elif MusicVideoGenre:
    response_text = render_template('could_not_find_musicvideos_genre', genre_name=MusicVideoGenre).encode('utf-8')
  else:
    response_text = render_template('error_parsing_results').encode('utf-8')

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


def _alexa_watch_video_playlist(kodi, VideoPlaylist, shuffle=False):
  if shuffle:
    op = render_template('shuffling_empty').encode('utf-8')
  else:
    op = render_template('playing_empty').encode('utf-8')

  card_title = render_template('action_video_playlist', action=op).encode('utf-8')
  log.info(card_title)

  playlist = kodi.FindVideoPlaylist(VideoPlaylist)
  if playlist:
    if shuffle:
      videos = kodi.GetPlaylistItems(playlist[0][0])['result']['files']
      videos_array = []
      for video in videos:
        videos_array.append(video['file'])

      kodi.PlayerStop()
      kodi.ClearVideoPlaylist()
      kodi.AddVideosToPlaylist(videos_array, True)
      kodi.StartVideoPlaylist()
    else:
      kodi.PlayerStop()
      kodi.StartVideoPlaylist(playlist[0][0])
    response_text = render_template('playing_playlist_video', action=op, playlist_name=playlist[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find_playlist', heard_name=VideoPlaylist).encode('utf-8')

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


# Handle the WatchVideoPlaylist intent.
@ask.intent('WatchVideoPlaylist')
@preflight_check
def alexa_watch_video_playlist(kodi, VideoPlaylist):
  return _alexa_watch_video_playlist(kodi, VideoPlaylist, False)


# Handle the ShuffleVideoPlaylist intent.
@ask.intent('ShuffleVideoPlaylist')
@preflight_check
def alexa_shuffle_video_playlist(kodi, VideoPlaylist):
  return _alexa_watch_video_playlist(kodi, VideoPlaylist, True)


# Handle the ShufflePlaylist intent.
@ask.intent('ShufflePlaylist')
@preflight_check
def alexa_shuffle_playlist(kodi, VideoPlaylist, AudioPlaylist):
  heard_search = ''
  if VideoPlaylist:
    heard_search = VideoPlaylist
  elif AudioPlaylist:
    heard_search = AudioPlaylist

  card_title = render_template('shuffling_playlist', playlist_name=heard_search).encode('utf-8')
  log.info(card_title)

  if heard_search:
    playlist = kodi.FindVideoPlaylist(heard_search)
    if playlist:
      videos = kodi.GetPlaylistItems(playlist[0][0])['result']['files']
      videos_array = []
      for video in videos:
        videos_array.append(video['file'])

      kodi.PlayerStop()
      kodi.ClearVideoPlaylist()
      kodi.AddVideosToPlaylist(videos_array, True)
      kodi.StartVideoPlaylist()
      response_text = render_template('shuffling_playlist_video', playlist_name=playlist[0][1]).encode('utf-8')
    else:
      playlist = kodi.FindAudioPlaylist(heard_search)
      if playlist:
        songs = kodi.GetPlaylistItems(playlist[0][0])['result']['files']
        songs_array = []
        for song in songs:
          songs_array.append(song['id'])

        kodi.PlayerStop()
        kodi.ClearAudioPlaylist()
        kodi.AddSongsToPlaylist(songs_array, True)
        kodi.StartAudioPlaylist()
        response_text = render_template('shuffling_playlist_audio', playlist_name=playlist[0][1]).encode('utf-8')

    if not playlist:
      response_text = render_template('could_not_find_playlist', heard_name=heard_search).encode('utf-8')
  else:
    response_text = render_template('error_parsing_results').encode('utf-8')

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


def alexa_recommend_item(kodi, item, generic_type=None):
  response_text = render_template('no_recommendations').encode('utf-8')

  if item[0] == 'movie':
    response_text = render_template('recommend_movie', movie_name=item[1]).encode('utf-8')
  elif item[0] == 'tvshow':
    response_text = render_template('recommend_show', show_name=item[1]).encode('utf-8')
  elif item[0] == 'episode':
    episode_details = kodi.GetEpisodeDetails(item[2])
    response_text = render_template('recommend_episode', season=episode_details['season'], episode=episode_details['episode'], show_name=episode_details['showtitle']).encode('utf-8')
  elif item[0] == 'musicvideo':
    musicvideo_details = kodi.GetMusicVideoDetails(item[2])
    response_text = render_template('recommend_musicvideo', musicvideo_name=item[1], artist_name=musicvideo_details['artist'][0]).encode('utf-8')
  elif item[0] == 'artist':
    response_text = render_template('recommend_artist', artist_name=item[1]).encode('utf-8')
  elif item[0] == 'album':
    album_details = kodi.GetAlbumDetails(item[2])
    response_text = render_template('recommend_album', album_name=item[1], artist_name=album_details['artist'][0]).encode('utf-8')
  elif item[0] == 'song':
    song_details = kodi.GetSongDetails(item[2])
    response_text = render_template('recommend_song', song_name=item[1], artist_name=song_details['artist'][0]).encode('utf-8')
  else:
    return statement(response_text)

  if generic_type:
    session.attributes['play_media_generic_type'] = generic_type
  session.attributes['play_media_type'] = item[0]
  session.attributes['play_media_id'] = item[2]
  session.attributes['play_media_genre'] = item[3]
  return question(response_text)


# Handle the RecommendVideo intent.
@ask.intent('RecommendVideo')
@preflight_check
def alexa_recommend_video(kodi):
  log.info('Recommending video')

  item = kodi.GetRecommendedVideoItem()
  return alexa_recommend_item(kodi, item, 'video')


# Handle the RecommendAudio intent.
@ask.intent('RecommendAudio')
@preflight_check
def alexa_recommend_audio(kodi):
  log.info('Recommending audio')

  item = kodi.GetRecommendedAudioItem()
  return alexa_recommend_item(kodi, item, 'audio')


# Handle the RecommendMovie intent.
@ask.intent('RecommendMovie')
@preflight_check
def alexa_recommend_movie(kodi, MovieGenre):
  log.info('Recommending movie')

  genre = None
  if MovieGenre:
    g = kodi.FindVideoGenre(MovieGenre)
    if g:
      genre = g[0][1]
  item = kodi.GetRecommendedItem('movies', genre)
  return alexa_recommend_item(kodi, item)


# Handle the RecommendShow intent.
@ask.intent('RecommendShow')
@preflight_check
def alexa_recommend_show(kodi, ShowGenre):
  log.info('Recommending show')

  genre = None
  if ShowGenre:
    g = kodi.FindVideoGenre(ShowGenre, 'tvshow')
    if g:
      genre = g[0][1]
  item = kodi.GetRecommendedItem('tvshows', genre)
  return alexa_recommend_item(kodi, item)


# Handle the RecommendEpisode intent.
@ask.intent('RecommendEpisode')
@preflight_check
def alexa_recommend_episode(kodi, ShowGenre):
  log.info('Recommending episode')

  genre = None
  if ShowGenre:
    g = kodi.FindVideoGenre(ShowGenre, 'tvshow')
    if g:
      genre = g[0][1]
  item = kodi.GetRecommendedItem('episodes', genre)
  return alexa_recommend_item(kodi, item)


# Handle the RecommendMusicVideo intent.
@ask.intent('RecommendMusicVideo')
@preflight_check
def alexa_recommend_music_video(kodi, MusicVideoGenre):
  log.info('Recommending music video')

  genre = None
  if MusicVideoGenre:
    g = kodi.FindVideoGenre(MusicVideoGenre, 'musicvideo')
    if g:
      genre = g[0][1]
  item = kodi.GetRecommendedItem('musicvideos', genre)
  return alexa_recommend_item(kodi, item)


# Handle the RecommendArtist intent.
@ask.intent('RecommendArtist')
@preflight_check
def alexa_recommend_artist(kodi, MusicGenre):
  log.info('Recommending artist')

  genre = None
  if MusicGenre:
    g = kodi.FindMusicGenre(MusicGenre)
    if g:
      genre = g[0][1]
  item = kodi.GetRecommendedItem('artists', genre)
  return alexa_recommend_item(kodi, item)


# Handle the RecommendAlbum intent.
@ask.intent('RecommendAlbum')
@preflight_check
def alexa_recommend_album(kodi, MusicGenre):
  log.info('Recommending album')

  genre = None
  if MusicGenre:
    g = kodi.FindMusicGenre(MusicGenre)
    if g:
      genre = g[0][1]
  item = kodi.GetRecommendedItem('albums', genre)
  return alexa_recommend_item(kodi, item)


# Handle the RecommendSong intent.
@ask.intent('RecommendSong')
@preflight_check
def alexa_recommend_song(kodi, MusicGenre):
  log.info('Recommending song')

  genre = None
  if MusicGenre:
    g = kodi.FindMusicGenre(MusicGenre)
    if g:
      genre = g[0][1]
  item = kodi.GetRecommendedItem('songs', genre)
  return alexa_recommend_item(kodi, item)


# Handle the WhatNewAlbums intent.
@ask.intent('WhatNewAlbums')
@preflight_check
def alexa_what_new_albums(kodi):
  card_title = render_template('newly_added_albums').encode('utf-8')
  log.info(card_title)

  new_albums = kodi.GetRecentlyAddedAlbums()['result']['albums']

  by_word = render_template('by')
  new_album_names = list(set([u'%s %s %s' % (x['label'], by_word, x['artist'][0]) for x in new_albums]))
  num_albums = len(new_album_names)

  if num_albums == 0:
    # There's been nothing added to Kodi recently
    response_text = render_template('no_new_albums').encode('utf-8')
  else:
    random.shuffle(new_album_names)
    limited_new_album_names = new_album_names[0:5]
    album_list = limited_new_album_names[0]
    for one_album in limited_new_album_names[1:-1]:
      album_list += u', ' + one_album
    if num_albums > 5:
      album_list += u', ' + limited_new_album_names[-1] + render_template('and_more_similar')
    elif num_albums > 1:
      album_list += render_template('and') + limited_new_album_names[-1]
    response_text = render_template('you_have_list', items=album_list).encode('utf-8')

  if not 'queries_keep_open' in session.attributes:
    return statement(response_text).simple_card(card_title, response_text)

  return question(response_text)


# Handle the WhatNewMovies intent.
@ask.intent('WhatNewMovies')
@preflight_check
def alexa_what_new_movies(kodi, MovieGenre):
  new_movies = None

  # If a genre has been specified, match the genre for use in selecting random films
  if MovieGenre:
    card_title = render_template('newly_added_movies_genre', genre=MovieGenre).encode('utf-8')
    genre = kodi.FindVideoGenre(MovieGenre)
    if genre:
      new_movies = kodi.GetUnwatchedMoviesByGenre(genre[0][1])
  else:
    card_title = render_template('newly_added_movies').encode('utf-8')
    new_movies = kodi.GetUnwatchedMovies()
  log.info(card_title)

  if new_movies:
    new_movie_names = list(set([u'%s' % (x['title']) for x in new_movies]))
    num_movies = len(new_movie_names)
  else:
    num_movies = 0

  if num_movies == 0:
    # There's been nothing added to Kodi recently
    response_text = render_template('no_new_movies').encode('utf-8')
  else:
    random.shuffle(new_movie_names)
    limited_new_movie_names = new_movie_names[0:5]
    movie_list = limited_new_movie_names[0]
    for one_movie in limited_new_movie_names[1:-1]:
      movie_list += u', ' + one_movie
    if num_movies > 5:
      movie_list += u', ' + limited_new_movie_names[-1] + render_template('and_more_similar')
    elif num_movies > 1:
      movie_list += render_template('and') + limited_new_movie_names[-1]
    response_text = render_template('you_have_list', items=movie_list).encode('utf-8')

  if not 'queries_keep_open' in session.attributes:
    return statement(response_text).simple_card(card_title, response_text)

  return question(response_text)


# Handle the WhatNewShows intent.
#
# Lists the shows that have had new episodes added to Kodi in the last 5 days
@ask.intent('WhatNewShows')
@preflight_check
def alexa_what_new_shows(kodi):
  card_title = render_template('newly_added_shows').encode('utf-8')
  log.info(card_title)

  new_episodes = kodi.GetUnwatchedEpisodes()

  # Find out how many EPISODES were recently added and get the names of the SHOWS
  new_show_names = list(set([u'%s' % (x['show']) for x in new_episodes]))
  num_shows = len(new_show_names)

  if num_shows == 0:
    # There's been nothing added to Kodi recently
    response_text = render_template('no_new_shows').encode('utf-8')
  elif len(new_show_names) == 1:
    # There's only one new show, so provide information about the number of episodes, too.
    count = len(new_episodes)
    if count == 1:
      response_text = render_template('one_new_episode', show_name=new_show_names[0]).encode('utf-8')
    elif count == 2:
      response_text = render_template('two_new_episodes', show_name=new_show_names[0]).encode('utf-8')
    else:
      response_text = render_template('multiple_new_episodes', show_name=new_show_names[0], count=count).encode('utf-8')
  else:
    # More than one new show has new episodes ready
    random.shuffle(new_show_names)
    limited_new_show_names = new_show_names[0:5]
    show_list = limited_new_show_names[0]
    for one_show in limited_new_show_names[1:-1]:
      show_list += u', ' + one_show
    if num_shows > 5:
      show_list += u', ' + limited_new_show_names[-1] + render_template('and_more_similar')
    elif num_shows > 1:
      show_list += render_template('and') + limited_new_show_names[-1]
    response_text = render_template('you_have_episode_list', items=show_list).encode('utf-8')

  if not 'queries_keep_open' in session.attributes:
    return statement(response_text).simple_card(card_title, response_text)

  return question(response_text)


# Handle the WhatNewEpisodes intent.
@ask.intent('WhatNewEpisodes')
@preflight_check
def alexa_what_new_episodes(kodi, Show):
  card_title = render_template('looking_for_show', heard_show=Show).encode('utf-8')
  log.info(card_title)

  show = kodi.FindTvShow(Show)
  if show:
    num_unwatched = len(kodi.GetUnwatchedEpisodesFromShow(show[0][0]))

    if num_unwatched > 0:
      if num_unwatched == 1:
        response_text = render_template('one_unseen_show', show_name=show[0][1]).encode('utf-8')
      else:
        response_text = render_template('multiple_unseen_show', show_name=show[0][1], num=num_unwatched).encode('utf-8')
    else:
      response_text = render_template('no_unseen_show', show_name=show[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find', heard_name=Show).encode('utf-8')

  if not 'queries_keep_open' in session.attributes:
    return statement(response_text).simple_card(card_title, response_text)

  return question(response_text)


# Handle the WhatAlbums intent.
@ask.intent('WhatAlbums')
@preflight_check
def alexa_what_albums(kodi, Artist):
  card_title = render_template('albums_by', heard_artist=Artist).encode('utf-8')
  log.info(card_title)

  artist = kodi.FindArtist(Artist)
  if artist:
    albums_result = kodi.GetArtistAlbums(artist[0][0])
    albums = albums_result['result']['albums']
    num_albums = len(albums)
    if num_albums > 0:
      really_albums = list(set([u'%s' % (x['label']) for x in albums]))
      album_list = really_albums[0]
      if num_albums > 1:
        for one_album in really_albums[1:-1]:
          album_list += u', ' + one_album
        album_list += render_template('and') + really_albums[-1]
      response_text = render_template('you_have_list', items=album_list).encode('utf-8')
    else:
      response_text = render_template('no_albums_artist', artist=artist[0][1]).encode('utf-8')
  else:
    response_text = render_template('could_not_find', heard_name=Artist).encode('utf-8')

  if not 'queries_keep_open' in session.attributes:
    return statement(response_text).simple_card(card_title, response_text)

  return question(response_text)


def get_help_samples(limit=7):
  # read example slot values from language-specific file.
  sample_slotvals = {}
  fn = os.path.join(os.path.dirname(__file__), 'sample_slotvals.%s.txt' % (LANGUAGE))
  f = codecs.open(fn, 'rb', 'utf-8')
  for line in f:
    media_type, media_title = line.encode('utf-8').strip().split(' ', 1)
    sample_slotvals[media_type] = media_title.strip()
  f.close()

  # don't suggest utterances for the following intents, because they depend on
  # context to make any sense:
  ignore_intents = [
    'PlayerMoveUp',
    'PlayerMoveDown',
    'PlayerMoveLeft',
    'PlayerMoveRight',
    'PlayerRotateClockwise',
    'PlayerRotateCounterClockwise',
    'PlayerZoomHold',
    'PlayerZoomIn',
    'PlayerZoomInMoveUp',
    'PlayerZoomInMoveDown',
    'PlayerZoomInMoveLeft',
    'PlayerZoomInMoveRight',
    'PlayerZoomOut',
    'PlayerZoomOutMoveUp',
    'PlayerZoomOutMoveDown',
    'PlayerZoomOutMoveLeft',
    'PlayerZoomOutMoveRight',
    'PlayerZoomReset'
  ]

  # build complete list of possible utterances from file.
  utterances = {}
  fn = os.path.join(os.path.dirname(__file__), 'speech_assets/SampleUtterances.%s.txt' % (LANGUAGE))
  f = codecs.open(fn, 'rb', 'utf-8')
  for line in f:
    intent, utterance = line.encode('utf-8').strip().split(' ', 1)
    if intent in ignore_intents: continue
    if intent not in utterances:
      utterances[intent] = []
    utterances[intent].append(utterance)
  f.close()

  # pick random utterances to return, up to the specified limit.
  sample_utterances = {}
  for k in random.sample(utterances.keys(), limit):
    # substitute slot references for sample media titles.
    sample_utterances[k] = re.sub(r'{(\w+)?}', lambda m: sample_slotvals.get(m.group(1), m.group(1)), random.choice(utterances[k])).decode('utf-8')

  return sample_utterances


@ask.intent('AMAZON.HelpIntent')
@preflight_check
def prepare_help_message(kodi):
  sample_utterances = get_help_samples()

  response_text = render_template('help', example=sample_utterances.popitem()[1]).encode('utf-8')
  reprompt_text = render_template('help_short', example=sample_utterances.popitem()[1]).encode('utf-8')
  card_title = render_template('help_card').encode('utf-8')
  samples = ''
  for sample in sample_utterances.values():
    samples += '"%s"\n' % (sample)
  card_text = render_template('help_text', examples=samples).encode('utf-8')
  log.info(card_title)

  if not 'queries_keep_open' in session.attributes:
    return statement(response_text).simple_card(card_title, card_text)

  return question(response_text).reprompt(reprompt_text).simple_card(card_title, card_text)


# No intents invoked
@ask.launch
def alexa_launch():
  sample_utterances = get_help_samples()

  response_text = render_template('welcome').encode('utf-8')
  reprompt_text = render_template('help_short', example=sample_utterances.popitem()[1]).encode('utf-8')
  card_title = response_text
  log.info(card_title)

  # All non-playback requests should keep the session open
  session.attributes['queries_keep_open'] = True

  return question(response_text).reprompt(reprompt_text)


@ask.session_ended
def session_ended():
  return "{}", 200

@ask.intent('InsertText')
@preflight_check
def alexa_insert_text(kodi, someText):
  card_title = render_template('sending_text', textToBeSent=someText).encode('utf-8')
  log.info(card_title)
  kodi.SendText(someText)
  return statement('').simple_card(card_title, '')


# End of intent methods


================================================
FILE: alexa.wsgi
================================================
#!/usr/bin/python
import os, sys
sys.path += [os.path.dirname(__file__)]
from alexa import app as application


================================================
FILE: app.json
================================================
{
  "name": "Kanzi Skill",
  "description": "An Alexa still that let's you control (almost) anything on a Kodi box.",
  "repository": "https://github.com/m0ngr31/kanzi",
  "logo": "https://i.imgur.com/k0MOv2r.png",
  "keywords": ["kodi", "alexa", "python", "flask-ask"],
  "website": "https://github.com/m0ngr31/kanzi",
  "env": {
    "KODI_ADDRESS": {
      "description": "IP address or fully-qualified domain name to talk to Kodi.",
      "value": ""
    },
    "KODI_PORT": {
      "description": "Open port on your router that forwards to Kodi.",
      "value": ""
    },
    "KODI_USERNAME": {
      "description": "Your Kodi user name.",
      "value": ""
    },
    "KODI_PASSWORD": {
      "description": "Your Kodi password.",
      "value": ""
    },
    "KODI_SCHEME": {
      "description": "The Kodi webserver only supports HTTP, however if you have a reverse proxy running and have SSL enabled, enter 'https' here. Otherwise, leave blank.",
      "value": "",
      "required": false
    },
    "KODI_SUBPATH": {
      "description": "If using a reverse proxy you might need to add an extra bit to the url before 'jsonrpc'.",
      "value": "",
      "required": false
    },
    "READ_TIMEOUT": {
      "description": "How long to wait for responses from Kodi.  Don't change unless you know what you're doing.",
      "value": "120",
      "required": false
    },
    "READ_TIMEOUT_ASYNC": {
      "description": "Read timeout for 'fire-and-forget' commands.  Increase gradually only if Kodi is sometimes not executing commands.",
      "value": "0.01",
      "required": false
    },
    "SKILL_APPID": {
      "description": "Add your skill's Application ID here to verify incomming requests are from your copy of the skill.",
      "value": "",
      "required": false
    },
    "SKILL_TZ": {
      "description": "Your local time zone for responses that include absolute times. See https://en.wikipedia.org/wiki/List_of_tz_database_time_zones. Leave empty or undefined (commented out) if you don't need or want absolute time responses.",
      "value": "",
      "required": false
    },
    "LANGUAGE": {
      "description": "If you are German speaker, put 'de' here. If not, leave blank.",
      "value": "",
      "required": false
    },
    "SHUTDOWN_MEANS_QUIT": {
      "description": "If you'd like 'Alexa, tell Kodi to shut down' to quit Kodi instead of shutting down the system, type 'quit'.",
      "value": "",
      "required": false
    },
    "DEEP_SEARCH": {
      "description": "If you'd like to enable searching the entire library with generic play commands.",
      "value": "yes",
      "required": false
    },
    "MAX_PLAYLIST_ITEMS": {
      "description": "Maximum number of items to add to playlists.  Empty means unlimited.",
      "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",
      "required": false
    },
    "MAX_UNWATCHED_MOVIES": {
      "description": "Maximum number of items to fetch when looking for new movies.",
      "value": "100",
      "required": false
    },
    "SKILL_LOGLEVEL": {
      "description": "Set to CRITICAL, ERROR, WARNING, INFO, or DEBUG.",
      "value": "INFO",
      "required": false
    },
    "CACHE_BUCKET": {
      "description": "Amazon S3 bucket or directory name in which to cache responses, if you wish to do so.  Leave empty to disable.",
      "value": "",
      "required": false
    },
    "S3_CACHE_AWS_ACCESS_KEY_ID": {
      "description": "AWS Access Key ID for the Amazon S3 cache bucket.",
      "value": "",
      "required": false
    },
    "S3_CACHE_AWS_SECRET_ACCESS_KEY": {
      "description": "AWS Secret Access Key for the Amazon S3 cache bucket.",
      "value": "",
      "required": false
    },
    "OWNCLOUD_CACHE_URL": {
      "description": "Base URL for ownCloud server where the cache will be located.",
      "value": "",
      "required": false
    },
    "OWNCLOUD_CACHE_USER": {
      "description": "ownCloud user name.",
      "value": "",
      "required": false
    },
    "OWNCLOUD_CACHE_PASSWORD": {
      "description": "ownCloud password.",
      "value": "",
      "required": false
    }
  },
  "image": "heroku/python",
  "stack": "heroku-18"
}


================================================
FILE: generate_custom_slots.py
================================================
import re
import string
import random
import os
from kodi_voice import KodiConfigParser, Kodi

config_file = os.path.join(os.path.dirname(__file__), "kodi.config")
config = KodiConfigParser(config_file)

kodi = Kodi(config)


def most_words(l=[]):
  longest = 0
  for s in l:
    if len(s.split()) > longest:
      longest = len(s.split())
  return longest


def sort_by_words(l, longest):
  distributed = []
  for i in range(1, longest + 1):
    dl = [s for s in l if len(s.split()) == i]
    if dl:
      distributed.append(dl)
  return distributed


def clean_results(resp, cat, key, limit=None):
  if not limit:
    try:
      limit = kodi.config.get('alexa', 'slot_items_max')
      if limit and limit != 'None':
        limit = int(limit)
      else:
        limit = None
    except:
      limit = None
  if not limit:
    limit = 100

  cleaned = []
  if 'result' in resp and cat in resp['result']:
    for v in retrieved['result'][cat]:
      name = kodi.sanitize_name(v[key], normalize=False)
      # omit titles with digits, as Amazon never passes numbers as digits
      if not re.search(r'\d', name):
        cleaned.append(name)

  cleaned = {v.lower(): v for v in cleaned}.values()
  cleaned = filter(None, cleaned)
  random.shuffle(cleaned)

  # distribute strings evenly by number of words
  if len(cleaned) > limit:
    longest = most_words(cleaned)
    distributed = sort_by_words(cleaned, longest)
    if distributed:
      total = 0
      cleaned = []
      while total < limit:
        for l in distributed:
          if l:
            total += 1
            cleaned.append(l.pop())

  # sort by number of words just for visibility
  if cleaned:
    longest = most_words(cleaned)
    distributed = sort_by_words(cleaned, longest)
    if distributed:
      cleaned = []
      for dl in distributed:
        cleaned += [l for l in dl]

  return cleaned[:limit]


def write_file(filename, items=[]):
  print 'Writing: %s' % (filename)
  f = open(filename, 'w')
  for a in items:
    f.write("%s\n" % a.encode("utf-8"))
  f.close()


# Generate MUSICPLAYLISTS Slot
retrieved = kodi.GetMusicPlaylists()
cl = clean_results(retrieved, 'files', 'label')
write_file('MUSICPLAYLISTS', cl)


# Generate MUSICGENRES Slot
retrieved = kodi.GetMusicGenres()
cl = clean_results(retrieved, 'genres', 'label')
write_file('MUSICGENRES', cl)


# Generate MUSICARTISTS Slot
retrieved = kodi.GetMusicArtists()
cl = clean_results(retrieved, 'artists', 'artist')
write_file('MUSICARTISTS', cl)


# Generate MUSICALBUMS Slot
retrieved = kodi.GetAlbums()
cl = clean_results(retrieved, 'albums', 'label')
write_file('MUSICALBUMS', cl)


# Generate MUSICSONGS Slot
retrieved = kodi.GetSongs()
cl = clean_results(retrieved, 'songs', 'label')
write_file('MUSICSONGS', cl)


# Generate VIDEOPLAYLISTS Slot
retrieved = kodi.GetVideoPlaylists()
cl = clean_results(retrieved, 'files', 'label')
write_file('VIDEOPLAYLISTS', cl)


# Generate MOVIEGENRES Slot
retrieved = kodi.GetVideoGenres()
cl = clean_results(retrieved, 'genres', 'label')
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')
write_file('MOVIES', cl)


# Generate SHOWS Slot
retrieved = kodi.GetShows()
cl = clean_results(retrieved, 'tvshows', 'label')
write_file('SHOWS', cl)


# Generate MUSICVIDEOS Slot
retrieved = kodi.GetMusicVideos()
cl = clean_results(retrieved, 'musicvideos', 'label')
write_file('MUSICVIDEOS', cl)


# Generate ADDONS Slot
retrieved = {'result': {'addons': []}}
for content in ['video', 'audio', 'image', 'executable']:
  r = kodi.GetAddons(content)
  if 'result' in r and 'addons' in r['result']:
    retrieved['result']['addons'] += r['result']['addons']
cl = clean_results(retrieved, 'addons', 'name')
write_file('ADDONS', cl)


================================================
FILE: requirements.txt
================================================
gunicorn
pytz
git+https://github.com/johnwheeler/flask-ask@master#egg=flask-ask
git+https://github.com/m0ngr31/kodi-voice@master#egg=kodi-voice
cryptography==2.1.4


================================================
FILE: runtime.txt
================================================
python-2.7.18


================================================
FILE: sample_slotvals.de.txt
================================================
Addon YouTube
MovieGenre Komödie
Movie Männertag
Artist Helene Fischer
Album Farbenspiel
MusicGenre Schlager
AudioPlaylist Partymusik
Song Atemlos
Show Farscape
VideoPlaylist HD videos
ShowGenre Science Fiction
MusicVideoGenre Pop
MusicVideo Die Hölle morgen früh
Volume Fünfundsiebzig
Season zwei
Episode acht
ForwardDur eine Minute
BackwardDur 30 Sekunden


================================================
FILE: sample_slotvals.en.txt
================================================
Addon YouTube
MovieGenre Comedy
Movie Tropic Thunder
Artist Sia
Album One Thousand Forms of Fear
MusicGenre Pop
AudioPlaylist Holiday
Song Elastic Heart
Show Farscape
VideoPlaylist HD videos
ShowGenre Science Fiction
MusicVideoGenre Pop
MusicVideo Chandelier
Volume seventy five
Season two
Episode eight
ForwardDur one minute
BackwardDur thirty seconds


================================================
FILE: sample_slotvals.es.txt
================================================
Addon YouTube
MovieGenre Comedia
Movie Tropic Thunder una guerra muy perra
Artist Camilo Sexto
Album 19 días y 500 noches
MusicGenre Pop
AudioPlaylist Vacaciones
Song El perro verde
Show Farscape
VideoPlaylist HD videos
ShowGenre Ciencia ficción
MusicVideoGenre Pop
MusicVideo La Macarena
Volume stenta y cinco
Season dos
Episode ocho
ForwardDur un minuto
BackwardDur 30 segundos


================================================
FILE: sample_slotvals.fr.txt
================================================
Addon YouTube
MovieGenre Comédie
Movie Tropic Thunder
Artist Sia
Album One Thousand Forms of Fear
MusicGenre Pop
AudioPlaylist Vacances
Song Elastic Heart
Show Farscape
VideoPlaylist vidéos HD
ShowGenre Science Fiction
MusicVideoGenre Pop
MusicVideo Chandelier
Volume soixante-quinze
Season deux
Episode huit
ForwardDur une minute
BackwardDur trente secondes


================================================
FILE: sample_slotvals.it.txt
================================================
Addon YouTube
MovieGenre Commedia
Movie Tropic Thunder
Artist Daniele Silvestri
Album Monetine
MusicGenre Pop
AudioPlaylist Vacanza
Song Sogno-B
Show Titans
VideoPlaylist Video HD
ShowGenre Fantascienza
MusicVideoGenre Pop
MusicVideo a-ha MTV Unplugged
Volume settantacinque
Season due
Episode otto
ForwardDur due minuti
BackwardDur trenta secondi


================================================
FILE: speech_assets/IntentSchema.json
================================================
{
  "intents": [
    {
      "intent": "RecommendVideo"
    },
    {
      "intent": "RecommendAudio"
    },
    {
      "intent": "RecommendMovie",
      "slots": [
        {
          "name": "MovieGenre",
          "type": "MOVIEGENRES"
        }
      ]
    },
    {
      "intent": "RecommendShow",
      "slots": [
        {
          "name": "ShowGenre",
          "type": "SHOWGENRES"
        }
      ]
    },
    {
      "intent": "RecommendEpisode",
      "slots": [
        {
          "name": "ShowGenre",
          "type": "SHOWGENRES"
        }
      ]
    },
    {
      "intent": "RecommendMusicVideo",
      "slots": [
        {
          "name": "MusicVideoGenre",
          "type": "MUSICVIDEOGENRES"
        }
      ]
    },
    {
      "intent": "RecommendArtist",
      "slots": [
        {
          "name": "MusicGenre",
          "type": "MUSICGENRES"
        }
      ]
    },
    {
      "intent": "RecommendAlbum",
      "slots": [
        {
          "name": "MusicGenre",
          "type": "MUSICGENRES"
        }
      ]
    },
    {
      "intent": "RecommendSong",
      "slots": [
        {
          "name": "MusicGenre",
          "type": "MUSICGENRES"
        }
      ]
    },
    {
      "intent": "WhatNewAlbums"
    },
    {
      "intent": "WhatNewMovies",
      "slots": [
        {
          "name": "MovieGenre",
          "type": "MOVIEGENRES"
        }
      ]
    },
    {
      "intent": "WhatNewShows"
    },
    {
      "intent": "WhatNewEpisodes",
      "slots": [
        {
          "name": "Show",
          "type": "SHOWS"
        }
      ]
    },
    {
      "intent": "CleanVideo"
    },
    {
      "intent": "UpdateVideo"
    },
    {
      "intent": "CleanAudio"
    },
    {
      "intent": "UpdateAudio"
    },
    {
      "intent": "PlayerSeekForward",
      "slots": [
        {
          "name": "ForwardDur",
          "type": "AMAZON.DURATION"
        }
      ]
    },
    {
      "intent": "PlayerSeekBackward",
      "slots": [
        {
          "name": "BackwardDur",
          "type": "AMAZON.DURATION"
        }
      ]
    },
    {
      "intent": "PlayerSeekSmallForward"
    },
    {
      "intent": "PlayerSeekSmallBackward"
    },
    {
      "intent": "PlayerSeekBigForward"
    },
    {
      "intent": "PlayerSeekBigBackward"
    },
    {
      "intent": "AMAZON.CancelIntent"
    },
    {
      "intent": "AMAZON.StopIntent"
    },
    {
      "intent": "AMAZON.NoIntent"
    },
    {
      "intent": "AMAZON.YesIntent"
    },
    {
      "intent": "AMAZON.NextIntent"
    },
    {
      "intent": "AMAZON.PauseIntent"
    },
    {
      "intent": "AMAZON.PreviousIntent"
    },
    {
      "intent": "AMAZON.ResumeIntent"
    },
    {
      "intent": "AMAZON.StartOverIntent"
    },
    {
      "intent": "AMAZON.ShuffleOnIntent"
    },
    {
      "intent": "AMAZON.ShuffleOffIntent"
    },
    {
      "intent": "AMAZON.LoopOnIntent"
    },
    {
      "intent": "AMAZON.LoopOffIntent"
    },
    {
      "intent": "AMAZON.HelpIntent"
    },
    {
      "intent": "PlayMedia",
      "slots": [
        {
          "name": "Movie",
          "type": "MOVIES"
        }
      ]
    },
    {
      "intent": "ShuffleMedia",
      "slots": [
        {
          "name": "Show",
          "type": "SHOWS"
        }
      ]
    },
    {
      "intent": "WhatAlbums",
      "slots": [
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        }
      ]
    },
    {
      "intent": "ListenToAudio",
      "slots": [
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        }
      ]
    },
    {
      "intent": "ListenToGenre",
      "slots": [
        {
          "name": "MusicGenre",
          "type": "MUSICGENRES"
        }
      ]
    },
    {
      "intent": "ListenToArtist",
      "slots": [
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        },
        {
          "name": "MusicGenre",
          "type": "MUSICGENRES"
        }
      ]
    },
    {
      "intent": "ListenToLatestAlbum",
      "slots": [
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        }
      ]
    },
    {
      "intent": "ListenToAlbum",
      "slots": [
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        },
        {
          "name": "Album",
          "type": "MUSICALBUMS"
        }
      ]
    },
    {
      "intent": "ListenToSong",
      "slots": [
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        },
        {
          "name": "Song",
          "type": "MUSICSONGS"
        },
        {
          "name": "Album",
          "type": "MUSICALBUMS"
        }
      ]
    },
    {
      "intent": "ListenToAlbumOrSong",
      "slots": [
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        },
        {
          "name": "Song",
          "type": "MUSICSONGS"
        }
      ]
    },
    {
      "intent": "ListenToAudioPlaylist",
      "slots": [
        {
          "name": "AudioPlaylist",
          "type": "MUSICPLAYLISTS"
        }
      ]
    },
    {
      "intent": "ShuffleLatestAlbum",
      "slots": [
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        }
      ]
    },
    {
      "intent": "ShuffleAlbum",
      "slots": [
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        },
        {
          "name": "Album",
          "type": "MUSICALBUMS"
        }
      ]
    },
    {
      "intent": "ShuffleAudioPlaylist",
      "slots": [
        {
          "name": "AudioPlaylist",
          "type": "MUSICPLAYLISTS"
        }
      ]
    },
    {
      "intent": "ListenToAudioPlaylistRecent"
    },
    {
      "intent": "WatchVideo",
      "slots": [
        {
          "name": "Movie",
          "type": "MOVIES"
        }
      ]
    },
    {
      "intent": "WatchEpisode",
      "slots": [
        {
          "name": "Show",
          "type": "SHOWS"
        },
        {
          "name": "Episode",
          "type": "AMAZON.NUMBER"
        },
        {
          "name": "Season",
          "type": "AMAZON.NUMBER"
        }
      ]
    },
    {
      "intent": "WatchRandomEpisode",
      "slots": [
        {
          "name": "Show",
          "type": "SHOWS"
        }
      ]
    },
    {
      "intent": "WatchRandomShow",
      "slots": [
        {
          "name": "ShowGenre",
          "type": "SHOWGENRES"
        }
      ]
    },
    {
      "intent": "WatchLatestEpisode",
      "slots": [
        {
          "name": "Show",
          "type": "SHOWS"
        }
      ]
    },
    {
      "intent": "WatchNextEpisode",
      "slots": [
        {
          "name": "Show",
          "type": "SHOWS"
        }
      ]
    },
    {
      "intent": "WatchLastShow"
    },
    {
      "intent": "WatchMovie",
      "slots": [
        {
          "name": "Movie",
          "type": "MOVIES"
        }
      ]
    },
    {
      "intent": "WatchRandomMovie",
      "slots": [
        {
          "name": "MovieGenre",
          "type": "MOVIEGENRES"
        }
      ]
    },
    {
      "intent": "WatchMovieTrailer",
      "slots": [
        {
          "name": "Movie",
          "type": "MOVIES"
        }
      ]
    },
    {
      "intent": "WatchMusicVideo",
      "slots": [
        {
          "name": "MusicVideo",
          "type": "MUSICVIDEOS"
        },
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        }
      ]
    },
    {
      "intent": "WatchRandomMusicVideo",
      "slots": [
        {
          "name": "MusicVideoGenre",
          "type": "MUSICVIDEOGENRES"
        },
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        }
      ]
    },
    {
      "intent": "WatchVideoPlaylist",
      "slots": [
        {
          "name": "VideoPlaylist",
          "type": "VIDEOPLAYLISTS"
        }
      ]
    },
    {
      "intent": "ShuffleMusicVideos",
      "slots": [
        {
          "name": "MusicVideoGenre",
          "type": "MUSICVIDEOGENRES"
        },
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        }
      ]
    },
    {
      "intent": "ShuffleShow",
      "slots": [
        {
          "name": "Show",
          "type": "SHOWS"
        }
      ]
    },
    {
      "intent": "ShuffleVideoPlaylist",
      "slots": [
        {
          "name": "VideoPlaylist",
          "type": "VIDEOPLAYLISTS"
        }
      ]
    },
    {
      "intent": "ShufflePlaylist",
      "slots": [
        {
          "name": "AudioPlaylist",
          "type": "MUSICPLAYLISTS"
        },
        {
          "name": "VideoPlaylist",
          "type": "VIDEOPLAYLISTS"
        }
      ]
    },
    {
      "intent": "Home"
    },
    {
      "intent": "Back"
    },
    {
      "intent": "Info"
    },
    {
      "intent": "Up"
    },
    {
      "intent": "Down"
    },
    {
      "intent": "Right"
    },
    {
      "intent": "Left"
    },
    {
      "intent": "Select"
    },
    {
      "intent": "Menu"
    },
    {
      "intent": "PageUp"
    },
    {
      "intent": "PageDown"
    },
    {
      "intent": "ViewMovies",
      "slots": [
        {
          "name": "MovieGenre",
          "type": "MOVIEGENRES"
        }
      ]
    },
    {
      "intent": "ViewShows",
      "slots": [
        {
          "name": "ShowGenre",
          "type": "SHOWGENRES"
        }
      ]
    },
    {
      "intent": "ViewMusicVideos",
      "slots": [
        {
          "name": "MusicVideoGenre",
          "type": "MUSICVIDEOGENRES"
        }
      ]
    },
    {
      "intent": "ViewMusic",
      "slots": [
        {
          "name": "MusicGenre",
          "type": "MUSICGENRES"
        }
      ]
    },
    {
      "intent": "ViewArtists"
    },
    {
      "intent": "ViewAlbums"
    },
    {
      "intent": "ViewVideoPlaylist",
      "slots": [
        {
          "name": "VideoPlaylist",
          "type": "VIDEOPLAYLISTS"
        }
      ]
    },
    {
      "intent": "ViewMoviePlaylistRecent"
    },
    {
      "intent": "ViewEpisodePlaylistRecent"
    },
    {
      "intent": "ViewMusicVideoPlaylistRecent"
    },
    {
      "intent": "ViewAudioPlaylist",
      "slots": [
        {
          "name": "AudioPlaylist",
          "type": "MUSICPLAYLISTS"
        }
      ]
    },
    {
      "intent": "ViewAudioPlaylistRecent"
    },
    {
      "intent": "ViewPlaylist",
      "slots": [
        {
          "name": "AudioPlaylist",
          "type": "MUSICPLAYLISTS"
        },
        {
          "name": "VideoPlaylist",
          "type": "VIDEOPLAYLISTS"
        }
      ]
    },
    {
      "intent": "Fullscreen"
    },
    {
      "intent": "StereoscopicMode"
    },
    {
      "intent": "AudioPassthrough"
    },
    {
      "intent": "Mute"
    },
    {
      "intent": "VolumeUp"
    },
    {
      "intent": "VolumeDown"
    },
    {
      "intent": "VolumeSet",
      "slots": [
        {
          "name": "Volume",
          "type": "AMAZON.NUMBER"
        }
      ]
    },
    {
      "intent": "VolumeSetPct",
      "slots": [
        {
          "name": "Volume",
          "type": "AMAZON.NUMBER"
        }
      ]
    },
    {
      "intent": "SubtitlesOn"
    },
    {
      "intent": "SubtitlesOff"
    },
    {
      "intent": "SubtitlesNext"
    },
    {
      "intent": "SubtitlesPrevious"
    },
    {
      "intent": "SubtitlesDownload"
    },
    {
      "intent": "AudioStreamNext"
    },
    {
      "intent": "AudioStreamPrevious"
    },
    {
      "intent": "PlayerMoveUp"
    },
    {
      "intent": "PlayerMoveDown"
    },
    {
      "intent": "PlayerMoveLeft"
    },
    {
      "intent": "PlayerMoveRight"
    },
    {
      "intent": "PlayerRotateClockwise"
    },
    {
      "intent": "PlayerRotateCounterClockwise"
    },
    {
      "intent": "PlayerZoomHold"
    },
    {
      "intent": "PlayerZoomIn"
    },
    {
      "intent": "PlayerZoomInMoveUp"
    },
    {
      "intent": "PlayerZoomInMoveDown"
    },
    {
      "intent": "PlayerZoomInMoveLeft"
    },
    {
      "intent": "PlayerZoomInMoveRight"
    },
    {
      "intent": "PlayerZoomOut"
    },
    {
      "intent": "PlayerZoomOutMoveUp"
    },
    {
      "intent": "PlayerZoomOutMoveDown"
    },
    {
      "intent": "PlayerZoomOutMoveLeft"
    },
    {
      "intent": "PlayerZoomOutMoveRight"
    },
    {
      "intent": "PlayerZoomReset"
    },
    {
      "intent": "Hibernate"
    },
    {
      "intent": "Reboot"
    },
    {
      "intent": "Shutdown"
    },
    {
      "intent": "Suspend"
    },
    {
      "intent": "EjectMedia"
    },
    {
      "intent": "PartyMode"
    },
    {
      "intent": "CurrentPlayItemInquiry"
    },
    {
      "intent": "CurrentPlayItemTimeRemaining"
    },
    {
      "intent": "AddonExecute",
      "slots": [
        {
          "name": "Addon",
          "type": "ADDONS"
        }
      ]
    },
    {
      "intent": "AddonGlobalSearch",
      "slots": [
        {
          "name": "Artist",
          "type": "MUSICARTISTS"
        },
        {
          "name": "Album",
          "type": "MUSICALBUMS"
        },
        {
          "name": "Song",
          "type": "MUSICSONGS"
        },
        {
          "name": "Movie",
          "type": "MOVIES"
        },
        {
          "name": "Show",
          "type": "SHOWS"
        }
      ]
    },
    {
      "intent": "InsertText",
      "slots": [
        {
          "name": "someText",
          "type": "AMAZON.SearchQuery"
        }
      ]
    }
  ]
}


================================================
FILE: speech_assets/SampleUtterances.de.txt
================================================
AMAZON.HelpIntent nach was ich es fragen kann
AMAZON.HelpIntent was es alles kann
AMAZON.HelpIntent was es kann
AMAZON.HelpIntent was ich es fragen kann
AddonExecute führe add on {Addon} aus
AddonExecute führe addon {Addon} aus
AddonExecute führe erweiterung {Addon} aus
AddonExecute führe plug in {Addon} aus
AddonExecute führe plugin {Addon} aus
AddonExecute führe script {Addon} aus
AddonExecute führe {Addon} aus
AddonExecute öffne {Addon}
AddonGlobalSearch finde {Album}
AddonGlobalSearch finde {Artist}
AddonGlobalSearch finde {Movie}
AddonGlobalSearch finde {Show}
AddonGlobalSearch suche nach {Album}
AddonGlobalSearch suche nach {Artist}
AddonGlobalSearch suche nach {Movie}
AddonGlobalSearch suche nach {Show}
AddonGlobalSearch suche {Album}
AddonGlobalSearch suche {Artist}
AddonGlobalSearch suche {Movie}
AddonGlobalSearch suche {Show}
AudioPassthrough aktiviere digital
AudioPassthrough aktiviere passthrough
AudioPassthrough schalte Audioausgabe auf digital
AudioPassthrough schalte Audioausgabe auf digital um
AudioPassthrough schalte Audioausgabe auf passthrough
AudioPassthrough schalte Audioausgabe auf passthrough um
AudioPassthrough schalte Audioausgabe um
AudioPassthrough schalte auf digital
AudioPassthrough schalte auf digital um
AudioPassthrough schalte auf passthrough
AudioPassthrough schalte auf passthrough um
AudioPassthrough schalte digital
AudioPassthrough schalte digital um
AudioPassthrough schalte passthrough
AudioPassthrough schalte passthrough um
AudioStreamNext Sprache umschalten
AudioStreamNext audio Stream umschalten
AudioStreamNext nächste Sprache
AudioStreamNext nächster audio Stream
AudioStreamPrevious vorige Sprache
AudioStreamPrevious voriger audio Stream
Back zurück
CleanAudio Audio Bibliothek säubern
CleanAudio Musik Bibliothek säubern
CleanAudio säuber Audio Bibliothek
CleanAudio säuber Musik Bibliothek
CleanAudio säubere Audio Bibliothek
CleanAudio säubere Musik Bibliothek
CleanVideo Video Bibliothek säubern
CleanVideo säuber Video Bibliothek
CleanVideo säubere Video Bibliothek
CurrentPlayItemInquiry was das ist
CurrentPlayItemInquiry was gerade läuft
CurrentPlayItemInquiry was gerade spielt
CurrentPlayItemInquiry was jetzt gerade läuft
CurrentPlayItemInquiry was jetzt gerade spielt
CurrentPlayItemInquiry was jetzt läuft
CurrentPlayItemInquiry was jetzt spielt
CurrentPlayItemInquiry was läuft
CurrentPlayItemInquiry was spielt
CurrentPlayItemInquiry welche Episode das ist
CurrentPlayItemInquiry welche Episode gerade läuft
CurrentPlayItemInquiry welche Episode gerade spielt
CurrentPlayItemInquiry welche Episode jetzt gerade läuft
CurrentPlayItemInquiry welche Episode jetzt gerade spielt
CurrentPlayItemInquiry welche Episode jetzt läuft
CurrentPlayItemInquiry welche Episode jetzt spielt
CurrentPlayItemInquiry welche Episode läuft
CurrentPlayItemInquiry welche Episode spielt
CurrentPlayItemInquiry welche Folge das ist
CurrentPlayItemInquiry welche Folge gerade läuft
CurrentPlayItemInquiry welche Folge gerade spielt
CurrentPlayItemInquiry welche Folge jetzt gerade läuft
CurrentPlayItemInquiry welche Folge jetzt gerade spielt
CurrentPlayItemInquiry welche Folge jetzt läuft
CurrentPlayItemInquiry welche Folge jetzt spielt
CurrentPlayItemInquiry welche Folge läuft
CurrentPlayItemInquiry welche Folge spielt
CurrentPlayItemInquiry welche Serie das ist
CurrentPlayItemInquiry welche Serie gerade läuft
CurrentPlayItemInquiry welche Serie gerade spielt
CurrentPlayItemInquiry welche Serie jetzt gerade läuft
CurrentPlayItemInquiry welche Serie jetzt gerade spielt
CurrentPlayItemInquiry welche Serie jetzt läuft
CurrentPlayItemInquiry welche Serie jetzt spielt
CurrentPlayItemInquiry welche Serie läuft
CurrentPlayItemInquiry welche Serie spielt
CurrentPlayItemInquiry welche Staffel das ist
CurrentPlayItemInquiry welche Staffel gerade läuft
CurrentPlayItemInquiry welche Staffel gerade spielt
CurrentPlayItemInquiry welche Staffel jetzt gerade läuft
CurrentPlayItemInquiry welche Staffel jetzt gerade spielt
CurrentPlayItemInquiry welche Staffel jetzt läuft
CurrentPlayItemInquiry welche Staffel jetzt spielt
CurrentPlayItemInquiry welche Staffel läuft
CurrentPlayItemInquiry welche Staffel spielt
CurrentPlayItemInquiry welche das ist
CurrentPlayItemInquiry welche gerade läuft
CurrentPlayItemInquiry welche gerade spielt
CurrentPlayItemInquiry welche jetzt gerade läuft
CurrentPlayItemInquiry welche jetzt gerade spielt
CurrentPlayItemInquiry welche jetzt läuft
CurrentPlayItemInquiry welche jetzt spielt
CurrentPlayItemInquiry welche läuft
CurrentPlayItemInquiry welche spielt
CurrentPlayItemInquiry welcher Song das ist
CurrentPlayItemInquiry welcher Song gerade läuft
CurrentPlayItemInquiry welcher Song gerade spielt
CurrentPlayItemInquiry welcher Song jetzt gerade läuft
CurrentPlayItemInquiry welcher Song jetzt gerade spielt
CurrentPlayItemInquiry welcher Song jetzt läuft
CurrentPlayItemInquiry welcher Song jetzt spielt
CurrentPlayItemInquiry welcher Song läuft
CurrentPlayItemInquiry welcher Song spielt
CurrentPlayItemInquiry welcher das ist
CurrentPlayItemInquiry welcher gerade läuft
CurrentPlayItemInquiry welcher gerade spielt
CurrentPlayItemInquiry welcher jetzt gerade läuft
CurrentPlayItemInquiry welcher jetzt gerade spielt
CurrentPlayItemInquiry welcher jetzt läuft
CurrentPlayItemInquiry welcher jetzt spielt
CurrentPlayItemInquiry welcher läuft
CurrentPlayItemInquiry welcher spielt
CurrentPlayItemInquiry welches Lied das ist
CurrentPlayItemInquiry welches Lied gerade läuft
CurrentPlayItemInquiry welches Lied gerade spielt
CurrentPlayItemInquiry welches Lied jetzt gerade läuft
CurrentPlayItemInquiry welches Lied jetzt gerade spielt
CurrentPlayItemInquiry welches Lied jetzt läuft
CurrentPlayItemInquiry welches Lied jetzt spielt
CurrentPlayItemInquiry welches Lied läuft
CurrentPlayItemInquiry welches Lied spielt
CurrentPlayItemInquiry welches Video das ist
CurrentPlayItemInquiry welches Video gerade läuft
CurrentPlayItemInquiry welches Video gerade spielt
CurrentPlayItemInquiry welches Video jetzt gerade läuft
CurrentPlayItemInquiry welches Video jetzt gerade spielt
CurrentPlayItemInquiry welches Video jetzt läuft
CurrentPlayItemInquiry welches Video jetzt spielt
CurrentPlayItemInquiry welches Video läuft
CurrentPlayItemInquiry welches Video spielt
CurrentPlayItemInquiry welches das ist
CurrentPlayItemInquiry welches gerade läuft
CurrentPlayItemInquiry welches gerade spielt
CurrentPlayItemInquiry welches jetzt gerade läuft
CurrentPlayItemInquiry welches jetzt gerade spielt
CurrentPlayItemInquiry welches jetzt läuft
CurrentPlayItemInquiry welches jetzt spielt
CurrentPlayItemInquiry welches läuft
CurrentPlayItemInquiry welches spielt
CurrentPlayItemInquiry wer das ist
CurrentPlayItemTimeRemaining um wieviel Uhr das Lied aus ist
CurrentPlayItemTimeRemaining um wieviel Uhr das Lied aus sein wird
CurrentPlayItemTimeRemaining um wieviel Uhr das Lied enden wird
CurrentPlayItemTimeRemaining um wieviel Uhr das Lied endet
CurrentPlayItemTimeRemaining um wieviel Uhr das Lied zuende ist
CurrentPlayItemTimeRemaining um wieviel Uhr das Video aus ist
CurrentPlayItemTimeRemaining um wieviel Uhr das Video aus sein wird
CurrentPlayItemTimeRemaining um wieviel Uhr das Video enden wird
CurrentPlayItemTimeRemaining um wieviel Uhr das Video endet
CurrentPlayItemTimeRemaining um wieviel Uhr das Video zuende ist
CurrentPlayItemTimeRemaining um wieviel Uhr der Film aus ist
CurrentPlayItemTimeRemaining um wieviel Uhr der Film aus sein wird
CurrentPlayItemTimeRemaining um wieviel Uhr der Film enden wird
CurrentPlayItemTimeRemaining um wieviel Uhr der Film endet
CurrentPlayItemTimeRemaining um wieviel Uhr der Film zuende ist
CurrentPlayItemTimeRemaining um wieviel Uhr die Episode aus ist
CurrentPlayItemTimeRemaining um wieviel Uhr die Episode aus sein wird
CurrentPlayItemTimeRemaining um wieviel Uhr die Episode enden wird
CurrentPlayItemTimeRemaining um wieviel Uhr die Episode endet
CurrentPlayItemTimeRemaining um wieviel Uhr die Episode zuende ist
CurrentPlayItemTimeRemaining um wieviel Uhr die Folge aus ist
CurrentPlayItemTimeRemaining um wieviel Uhr die Folge aus sein wird
CurrentPlayItemTimeRemaining um wieviel Uhr die Folge enden wird
CurrentPlayItemTimeRemaining um wieviel Uhr die Folge endet
CurrentPlayItemTimeRemaining um wieviel Uhr die Folge zuende ist
CurrentPlayItemTimeRemaining um wieviel Uhr die Serie aus ist
CurrentPlayItemTimeRemaining um wieviel Uhr die Serie aus sein wird
CurrentPlayItemTimeRemaining um wieviel Uhr die Serie enden wird
CurrentPlayItemTimeRemaining um wieviel Uhr die Serie endet
CurrentPlayItemTimeRemaining um wieviel Uhr die Serie zuende ist
CurrentPlayItemTimeRemaining wann das Lied aus ist
CurrentPlayItemTimeRemaining wann das Lied aus sein wird
CurrentPlayItemTimeRemaining wann das Lied enden wird
CurrentPlayItemTimeRemaining wann das Lied endet
CurrentPlayItemTimeRemaining wann das Lied zuende ist
CurrentPlayItemTimeRemaining wann das Video aus ist
CurrentPlayItemTimeRemaining wann das Video aus sein wird
CurrentPlayItemTimeRemaining wann das Video enden wird
CurrentPlayItemTimeRemaining wann das Video endet
CurrentPlayItemTimeRemaining wann das Video zuende ist
CurrentPlayItemTimeRemaining wann der Film aus ist
CurrentPlayItemTimeRemaining wann der Film aus sein wird
CurrentPlayItemTimeRemaining wann der Film enden wird
CurrentPlayItemTimeRemaining wann der Film endet
CurrentPlayItemTimeRemaining wann der Film zuende ist
CurrentPlayItemTimeRemaining wann die Episode aus ist
CurrentPlayItemTimeRemaining wann die Episode aus sein wird
CurrentPlayItemTimeRemaining wann die Episode enden wird
CurrentPlayItemTimeRemaining wann die Episode endet
CurrentPlayItemTimeRemaining wann die Episode zuende ist
CurrentPlayItemTimeRemaining wann die Folge aus ist
CurrentPlayItemTimeRemaining wann die Folge aus sein wird
CurrentPlayItemTimeRemaining wann die Folge enden wird
CurrentPlayItemTimeRemaining wann die Folge endet
CurrentPlayItemTimeRemaining wann die Folge zuende ist
CurrentPlayItemTimeRemaining wann die Serie aus ist
CurrentPlayItemTimeRemaining wann die Serie aus sein wird
CurrentPlayItemTimeRemaining wann die Serie enden wird
CurrentPlayItemTimeRemaining wann die Serie endet
CurrentPlayItemTimeRemaining wann die Serie zuende ist
CurrentPlayItemTimeRemaining wie lang das Lied geht
CurrentPlayItemTimeRemaining wie lang das Lied ist
CurrentPlayItemTimeRemaining wie lang das Lied läuft
CurrentPlayItemTimeRemaining wie lang das Lied noch geht
CurrentPlayItemTimeRemaining wie lang das Lied noch ist
CurrentPlayItemTimeRemaining wie lang das Lied noch läuft
CurrentPlayItemTimeRemaining wie lang das Video geht
CurrentPlayItemTimeRemaining wie lang das Video ist
CurrentPlayItemTimeRemaining wie lang das Video läuft
CurrentPlayItemTimeRemaining wie lang das Video noch geht
CurrentPlayItemTimeRemaining wie lang das Video noch ist
CurrentPlayItemTimeRemaining wie lang das Video noch läuft
CurrentPlayItemTimeRemaining wie lang der Film geht
CurrentPlayItemTimeRemaining wie lang der Film ist
CurrentPlayItemTimeRemaining wie lang der Film läuft
CurrentPlayItemTimeRemaining wie lang der Film noch geht
CurrentPlayItemTimeRemaining wie lang der Film noch ist
CurrentPlayItemTimeRemaining wie lang der Film noch läuft
CurrentPlayItemTimeRemaining wie lang die Episode geht
CurrentPlayItemTimeRemaining wie lang die Episode ist
CurrentPlayItemTimeRemaining wie lang die Episode läuft
CurrentPlayItemTimeRemaining wie lang die Episode noch geht
CurrentPlayItemTimeRemaining wie lang die Episode noch ist
CurrentPlayItemTimeRemaining wie lang die Episode noch läuft
CurrentPlayItemTimeRemaining wie lang die Folge geht
CurrentPlayItemTimeRemaining wie lang die Folge ist
CurrentPlayItemTimeRemaining wie lang die Folge läuft
CurrentPlayItemTimeRemaining wie lang die Folge noch geht
CurrentPlayItemTimeRemaining wie lang die Folge noch ist
CurrentPlayItemTimeRemaining wie lang die Folge noch läuft
CurrentPlayItemTimeRemaining wie lang die Serie geht
CurrentPlayItemTimeRemaining wie lang die Serie ist
CurrentPlayItemTimeRemaining wie lang die Serie läuft
CurrentPlayItemTimeRemaining wie lang die Serie noch geht
CurrentPlayItemTimeRemaining wie lang die Serie noch ist
CurrentPlayItemTimeRemaining wie lang die Serie noch läuft
CurrentPlayItemTimeRemaining wie lange das Lied geht
CurrentPlayItemTimeRemaining wie lange das Lied ist
CurrentPlayItemTimeRemaining wie lange das Lied läuft
CurrentPlayItemTimeRemaining wie lange das Lied noch geht
CurrentPlayItemTimeRemaining wie lange das Lied noch ist
CurrentPlayItemTimeRemaining wie lange das Lied noch läuft
CurrentPlayItemTimeRemaining wie lange das Video geht
CurrentPlayItemTimeRemaining wie lange das Video ist
CurrentPlayItemTimeRemaining wie lange das Video läuft
CurrentPlayItemTimeRemaining wie lange das Video noch geht
CurrentPlayItemTimeRemaining wie lange das Video noch ist
CurrentPlayItemTimeRemaining wie lange das Video noch läuft
CurrentPlayItemTimeRemaining wie lange das noch geht
CurrentPlayItemTimeRemaining wie lange das noch ist
CurrentPlayItemTimeRemaining wie lange das noch läuft
CurrentPlayItemTimeRemaining wie lange der Film geht
CurrentPlayItemTimeRemaining wie lange der Film ist
CurrentPlayItemTimeRemaining wie lange der Film läuft
CurrentPlayItemTimeRemaining wie lange der Film noch geht
CurrentPlayItemTimeRemaining wie lange der Film noch ist
CurrentPlayItemTimeRemaining wie lange der Film noch läuft
CurrentPlayItemTimeRemaining wie lange die Episode geht
CurrentPlayItemTimeRemaining wie lange die Episode ist
CurrentPlayItemTimeRemaining wie lange die Episode läuft
CurrentPlayItemTimeRemaining wie lange die Episode noch geht
CurrentPlayItemTimeRemaining wie lange die Episode noch ist
CurrentPlayItemTimeRemaining wie lange die Episode noch läuft
CurrentPlayItemTimeRemaining wie lange die Folge geht
CurrentPlayItemTimeRemaining wie lange die Folge ist
CurrentPlayItemTimeRemaining wie lange die Folge läuft
CurrentPlayItemTimeRemaining wie lange die Folge noch geht
CurrentPlayItemTimeRemaining wie lange die Folge noch ist
CurrentPlayItemTimeRemaining wie lange die Folge noch läuft
CurrentPlayItemTimeRemaining wie lange die Serie geht
CurrentPlayItemTimeRemaining wie lange die Serie ist
CurrentPlayItemTimeRemaining wie lange die Serie läuft
CurrentPlayItemTimeRemaining wie lange die Serie noch geht
CurrentPlayItemTimeRemaining wie lange die Serie noch ist
CurrentPlayItemTimeRemaining wie lange die Serie noch läuft
Down nach unten
Down navigier nach unten
Down navigier runter
Down navigiere nach unten
Down navigiere runter
Down runter
EjectMedia Scheibe auswerfen
EjectMedia audio cd auswerfen
EjectMedia audio disc auswerfen
EjectMedia auswerfen
EjectMedia bluray auswerfen
EjectMedia bluray disc auswerfen
EjectMedia cd auswerfen
EjectMedia disc auswerfen
EjectMedia dvd auswerfen
EjectMedia medium auswerfen
Fullscreen vollbild
Fullscreen vollbild umschalten
Hibernate hibernate
Hibernate ruhezustand
Hibernate system hibernate
Hibernate system ruhezustand
Hibernate system tiefschlaf
Hibernate tiefschlaf
Home startseite
InsertText schreibst {someText}
InsertText eingeben {someText}
Info info
Info info dialog
Info info fenster
Info information
Info informations dialog
Info informations fenster
Info öffne info
Info öffne info dialog
Info öffne info fenster
Info öffne information
Info öffne informations dialog
Info öffne informations fenster
Info zeige info
Info zeige info dialog
Info zeige info fenster
Info zeige information
Info zeige informations dialog
Info zeige informations fenster
Left links
Left nach links
Left navigier links
Left navigier nach links
Left navigiere links
Left navigiere nach links
ListenToAlbum spiel das Album {Album}
ListenToAlbum spiel das Album {Album} von {Artist}
ListenToAlbum spiel die CD {Album}
ListenToAlbum spiel die CD {Album} von {Artist}
ListenToAlbum spiel die Platte {Album}
ListenToAlbum spiel die Platte {Album} von {Artist}
ListenToAlbum spiele das Album {Album}
ListenToAlbum spiele das Album {Album} von {Artist}
ListenToAlbum spiele die CD {Album}
ListenToAlbum spiele die CD {Album} von {Artist}
ListenToAlbum spiele die Platte {Album}
ListenToAlbum spiele die Platte {Album} von {Artist}
ListenToAlbumOrSong spiel {Song} von {Artist}
ListenToAlbumOrSong spiele {Song} von {Artist}
ListenToArtist spiel Musik von dem Artist {Artist}
ListenToArtist spiel Musik von dem Interpreten {Artist}
ListenToArtist spiel Musik von dem Komponisten {Artist}
ListenToArtist spiel Musik von dem Künstler {Artist}
ListenToArtist spiel Musik von der Band {Artist}
ListenToArtist spiel Musik von der Gruppe {Artist}
ListenToArtist spiel Musik von der Komponistin {Artist}
ListenToArtist spiel Musik von der Künstlerin {Artist}
ListenToArtist spiel Musik von {Artist}
ListenToArtist spiel Songs von dem Artist {Artist}
ListenToArtist spiel Songs von dem Interpreten {Artist}
ListenToArtist spiel Songs von dem Komponisten {Artist}
ListenToArtist spiel Songs von dem Künstler {Artist}
ListenToArtist spiel Songs von der Band {Artist}
ListenToArtist spiel Songs von der Gruppe {Artist}
ListenToArtist spiel Songs von der Komponistin {Artist}
ListenToArtist spiel Songs von der Künstlerin {Artist}
ListenToArtist spiel Songs von {Artist}
ListenToArtist spiel {MusicGenre} Musik von dem Artist {Artist}
ListenToArtist spiel {MusicGenre} Musik von dem Interpreten {Artist}
ListenToArtist spiel {MusicGenre} Musik von dem Komponisten {Artist}
ListenToArtist spiel {MusicGenre} Musik von dem Künstler {Artist}
ListenToArtist spiel {MusicGenre} Musik von der Band {Artist}
ListenToArtist spiel {MusicGenre} Musik von der Gruppe {Artist}
ListenToArtist spiel {MusicGenre} Musik von der Komponistin {Artist}
ListenToArtist spiel {MusicGenre} Musik von der Künstlerin {Artist}
ListenToArtist spiel {MusicGenre} Musik von {Artist}
ListenToArtist spiel {MusicGenre} Songs von dem Artist {Artist}
ListenToArtist spiel {MusicGenre} Songs von dem Interpreten {Artist}
ListenToArtist spiel {MusicGenre} Songs von dem Komponisten {Artist}
ListenToArtist spiel {MusicGenre} Songs von dem Künstler {Artist}
ListenToArtist spiel {MusicGenre} Songs von der Band {Artist}
ListenToArtist spiel {MusicGenre} Songs von der Gruppe {Artist}
ListenToArtist spiel {MusicGenre} Songs von der Komponistin {Artist}
ListenToArtist spiel {MusicGenre} Songs von der Künstlerin {Artist}
ListenToArtist spiel {MusicGenre} Songs von {Artist}
ListenToArtist spiele Musik von dem Artist {Artist}
ListenToArtist spiele Musik von dem Interpreten {Artist}
ListenToArtist spiele Musik von dem Komponisten {Artist}
ListenToArtist spiele Musik von dem Künstler {Artist}
ListenToArtist spiele Musik von der Band {Artist}
ListenToArtist spiele Musik von der Gruppe {Artist}
ListenToArtist spiele Musik von der Komponistin {Artist}
ListenToArtist spiele Musik von der Künstlerin {Artist}
ListenToArtist spiele Musik von {Artist}
ListenToArtist spiele Songs von dem Artist {Artist}
ListenToArtist spiele Songs von dem Interpreten {Artist}
ListenToArtist spiele Songs von dem Komponisten {Artist}
ListenToArtist spiele Songs von dem Künstler {Artist}
ListenToArtist spiele Songs von der Band {Artist}
ListenToArtist spiele Songs von der Gruppe {Artist}
ListenToArtist spiele Songs von der Komponistin {Artist}
ListenToArtist spiele Songs von der Künstlerin {Artist}
ListenToArtist spiele Songs von {Artist}
ListenToArtist spiele {MusicGenre} Musik von dem Artist {Artist}
ListenToArtist spiele {MusicGenre} Musik von dem Interpreten {Artist}
ListenToArtist spiele {MusicGenre} Musik von dem Komponisten {Artist}
ListenToArtist spiele {MusicGenre} Musik von dem Künstler {Artist}
ListenToArtist spiele {MusicGenre} Musik von der Band {Artist}
ListenToArtist spiele {MusicGenre} Musik von der Gruppe {Artist}
ListenToArtist spiele {MusicGenre} Musik von der Komponistin {Artist}
ListenToArtist spiele {MusicGenre} Musik von der Künstlerin {Artist}
ListenToArtist spiele {MusicGenre} Musik von {Artist}
ListenToArtist spiele {MusicGenre} Songs von dem Artist {Artist}
ListenToArtist spiele {MusicGenre} Songs von dem Interpreten {Artist}
ListenToArtist spiele {MusicGenre} Songs von dem Komponisten {Artist}
ListenToArtist spiele {MusicGenre} Songs von dem Künstler {Artist}
ListenToArtist spiele {MusicGenre} Songs von der Band {Artist}
ListenToArtist spiele {MusicGenre} Songs von der Gruppe {Artist}
ListenToArtist spiele {MusicGenre} Songs von der Komponistin {Artist}
ListenToArtist spiele {MusicGenre} Songs von der Künstlerin {Artist}
ListenToArtist spiele {MusicGenre} Songs von {Artist}
ListenToAudio {Artist} anhören
ListenToAudioPlaylist spiel Lieder playlist {AudioPlaylist}
ListenToAudioPlaylist spiel Musik playlist {AudioPlaylist}
ListenToAudioPlaylist spiel Song playlist {AudioPlaylist}
ListenToAudioPlaylist spiel {AudioPlaylist} Lieder playlist
ListenToAudioPlaylist spiel {AudioPlaylist} Musik playlist
ListenToAudioPlaylist spiel {AudioPlaylist} Song playlist
ListenToAudioPlaylist spiele Lieder playlist {AudioPlaylist}
ListenToAudioPlaylist spiele Musik playlist {AudioPlaylist}
ListenToAudioPlaylist spiele Song playlist {AudioPlaylist}
ListenToAudioPlaylist spiele {AudioPlaylist} Lieder playlist
ListenToAudioPlaylist spiele {AudioPlaylist} Musik playlist
ListenToAudioPlaylist spiele {AudioPlaylist} Song playlist
ListenToAudioPlaylistRecent spiel kürzlich hinzugefügte Lieder
ListenToAudioPlaylistRecent spiel kürzlich hinzugefügte Musik
ListenToAudioPlaylistRecent spiel kürzlich hinzugefügte Songs
ListenToAudioPlaylistRecent spiel neue Lieder
ListenToAudioPlaylistRecent spiel neue Musik
ListenToAudioPlaylistRecent spiel neue Songs
ListenToAudioPlaylistRecent spiel zuletzt hinzugefügte Lieder
ListenToAudioPlaylistRecent spiel zuletzt hinzugefügte Musik
ListenToAudioPlaylistRecent spiel zuletzt hinzugefügte Songs
ListenToAudioPlaylistRecent spiele kürzlich hinzugefügte Lieder
ListenToAudioPlaylistRecent spiele kürzlich hinzugefügte Musik
ListenToAudioPlaylistRecent spiele kürzlich hinzugefügte Songs
ListenToAudioPlaylistRecent spiele neue Lieder
ListenToAudioPlaylistRecent spiele neue Musik
ListenToAudioPlaylistRecent spiele neue Songs
ListenToAudioPlaylistRecent spiele zuletzt hinzugefügte Lieder
ListenToAudioPlaylistRecent spiele zuletzt hinzugefügte Musik
ListenToAudioPlaylistRecent spiele zuletzt hinzugefügte Songs
ListenToGenre spiel {MusicGenre} Genre
ListenToGenre spiel {MusicGenre} Musik
ListenToGenre spiel {MusicGenre} Songs
ListenToGenre spiele {MusicGenre} Genre
ListenToGenre spiele {MusicGenre} Musik
ListenToGenre spiele {MusicGenre} Songs
ListenToLatestAlbum spiele aktuelles Album von {Artist}
ListenToLatestAlbum spiele aktuellstes Album von {Artist}
ListenToLatestAlbum spiele das aktuelle Album von {Artist}
ListenToLatestAlbum spiele das aktuellste Album von {Artist}
ListenToLatestAlbum spiele das neue Album von {Artist}
ListenToLatestAlbum spiele das neueste Album von {Artist}
ListenToLatestAlbum spiele neues Album von {Artist}
ListenToLatestAlbum spiele neuestes Album von {Artist}
ListenToLatestAlbum spiele zuletzt das hinzugefügte Album von {Artist}
ListenToLatestAlbum spiele zuletzt hinzugefügtes Album von {Artist}
ListenToSong spiel das Lied {Song}
ListenToSong spiel das Lied {Song} auf dem Album {Album}
ListenToSong spiel das Lied {Song} aus dem Album {Album}
ListenToSong spiel das Lied {Song} vom Album {Album}
ListenToSong spiel das Lied {Song} von dem Album {Album}
ListenToSong spiel das Lied {Song} von {Artist}
ListenToSong spiel den Song {Song}
ListenToSong spiel den Song {Song} auf dem Album {Album}
ListenToSong spiel den Song {Song} aus dem Album {Album}
ListenToSong spiel den Song {Song} vom Album {Album}
ListenToSong spiel den Song {Song} von dem Album {Album}
ListenToSong spiel den Song {Song} von {Artist}
ListenToSong spiele das Lied {Song}
ListenToSong spiele das Lied {Song} auf dem Album {Album}
ListenToSong spiele das Lied {Song} aus dem Album {Album}
ListenToSong spiele das Lied {Song} vom Album {Album}
ListenToSong spiele das Lied {Song} von dem Album {Album}
ListenToSong spiele das Lied {Song} von {Artist}
ListenToSong spiele den Song {Song}
ListenToSong spiele den Song {Song} auf dem Album {Album}
ListenToSong spiele den Song {Song} aus dem Album {Album}
ListenToSong spiele den Song {Song} vom Album {Album}
ListenToSong spiele den Song {Song} von dem Album {Album}
ListenToSong spiele den Song {Song} von {Artist}
Menu öffne Menü
Mute ton an
Mute ton anschalten
Mute ton aus
Mute ton ausschalten
PageDown Seite nach unten
PageDown Seite runter
PageDown navigier Seite nach unten
PageDown navigier Seite runter
PageDown navigiere Seite nach unten
PageDown navigiere Seite runter
PageUp Seite hoch
PageUp Seite nach oben
PageUp navigier Seite hoch
PageUp navigier Seite nach oben
PageUp navigiere Seite hoch
PageUp navigiere Seite nach oben
PartyMode Party
PartyMode Party Modus
PartyMode leg Lieder auf
PartyMode leg Mucke auf
PartyMode leg Musik auf
PartyMode leg Songs auf
PartyMode leg irgendetwas auf
PartyMode leg irgendwas auf
PartyMode leg irgendwelche Lieder auf
PartyMode leg irgendwelche Mucke auf
PartyMode leg irgendwelche Musik auf
PartyMode leg irgendwelche Songs auf
PartyMode leg was auf
PartyMode leg zufällige Lieder auf
PartyMode leg zufällige Mucke auf
PartyMode leg zufällige Musik auf
PartyMode leg zufällige Songs auf
PartyMode lege Lieder auf
PartyMode lege Mucke auf
PartyMode lege Musik auf
PartyMode lege Songs auf
PartyMode lege irgendetwas auf
PartyMode lege irgendwas auf
PartyMode lege irgendwelche Lieder auf
PartyMode lege irgendwelche Mucke auf
PartyMode lege irgendwelche Musik auf
PartyMode lege irgendwelche Songs auf
PartyMode lege was auf
PartyMode lege zufällige Lieder auf
PartyMode lege zufällige Mucke auf
PartyMode lege zufällige Musik auf
PartyMode lege zufällige Songs auf
PartyMode spiel Lieder
PartyMode spiel Mucke
PartyMode spiel Musik
PartyMode spiel Songs
PartyMode spiel irgendwelche Lieder
PartyMode spiel irgendwelche Mucke
PartyMode spiel irgendwelche Musik
PartyMode spiel irgendwelche Songs
PartyMode spiel zufällige Lieder
PartyMode spiel zufällige Mucke
PartyMode spiel zufällige Musik
PartyMode spiel zufällige Songs
PartyMode spiele Lieder
PartyMode spiele Mucke
PartyMode spiele Musik
PartyMode spiele Songs
PartyMode spiele irgendetwas
PartyMode spiele irgendwas
PartyMode spiele irgendwelche Lieder
PartyMode spiele irgendwelche Mucke
PartyMode spiele irgendwelche Musik
PartyMode spiele irgendwelche Songs
PartyMode spiele zufällige Lieder
PartyMode spiele zufällige Mucke
PartyMode spiele zufällige Musik
PartyMode spiele zufällige Songs
PartyMode zufallswiedergabe Lieder
PartyMode zufallswiedergabe Mucke
PartyMode zufallswiedergabe Musik
PartyMode zufallswiedergabe Songs
PlayMedia spiel {Movie}
PlayMedia spiele {Movie}
PlayerMoveDown geh nach unten
PlayerMoveDown geh runter
PlayerMoveDown gehe nach unten
PlayerMoveDown gehe runter
PlayerMoveDown nach unten
PlayerMoveDown runter
PlayerMoveLeft geh links
PlayerMoveLeft geh nach links
PlayerMoveLeft gehe links
PlayerMoveLeft gehe nach links
PlayerMoveLeft links
PlayerMoveLeft nach links
PlayerMoveRight geh nach rechts
PlayerMoveRight geh rechts
PlayerMoveRight gehe nach rechts
PlayerMoveRight gehe rechts
PlayerMoveRight nach rechts
PlayerMoveRight rechts
PlayerMoveUp geh hoch
PlayerMoveUp geh nach oben
PlayerMoveUp gehe hoch
PlayerMoveUp gehe nach oben
PlayerMoveUp hoch
PlayerMoveUp nach oben
PlayerRotateClockwise drehe
PlayerRotateClockwise drehe im Uhrzeigersinn
PlayerRotateClockwise drehe neunzig grad
PlayerRotateClockwise rotiere
PlayerRotateClockwise rotiere im Uhrzeigersinn
PlayerRotateClockwise rotiere neunzig grad
PlayerRotateCounterClockwise drehe gegen den Uhrzeigersinn
PlayerRotateCounterClockwise rotiere gegen den Uhrzeigersinn
PlayerSeekBackward Schritt rückwärts um {BackwardDur}
PlayerSeekBackward Schritt rückwärts {BackwardDur}
PlayerSeekBackward Schritt zurück um {BackwardDur}
PlayerSeekBackward Schritt zurück {BackwardDur}
PlayerSeekBackward Sprung rückwärts um {BackwardDur}
PlayerSeekBackward Sprung rückwärts {BackwardDur}
PlayerSeekBackward Sprung zurück um {BackwardDur}
PlayerSeekBackward Sprung zurück {BackwardDur}
PlayerSeekBackward rückwärts Schritt um {BackwardDur}
PlayerSeekBackward rückwärts Sprung um {BackwardDur}
PlayerSeekBackward zurück Schritt um {BackwardDur}
PlayerSeekBackward zurück Sprung um {BackwardDur}
PlayerSeekBigBackward weiter zurück
PlayerSeekBigBackward weiter zurückspringen
PlayerSeekBigBackward weiter zurückspulen
PlayerSeekBigForward großer Schritt rückwärts
PlayerSeekBigForward großer Schritt vor
PlayerSeekBigForward großer Schritt vorwärts
PlayerSeekBigForward großer Schritt zurück
PlayerSeekBigForward großer Sprung rückwärts
PlayerSeekBigForward großer Sprung vor
PlayerSeekBigForward großer Sprung vorwärts
PlayerSeekBigForward großer Sprung zurück
PlayerSeekBigForward großer rückwärts Schritt
PlayerSeekBigForward großer rückwärts Sprung
PlayerSeekBigForward großer vorwärts Schritt
PlayerSeekBigForward großer vorwärts Sprung
PlayerSeekBigForward langer Schritt rückwärts
PlayerSeekBigForward langer Schritt vor
PlayerSeekBigForward langer Schritt vorwärts
PlayerSeekBigForward langer Schritt zurück
PlayerSeekBigForward langer Sprung rückwärts
PlayerSeekBigForward langer Sprung vor
PlayerSeekBigForward langer Sprung vorwärts
PlayerSeekBigForward langer Sprung zurück
PlayerSeekBigForward langer rückwärts Schritt
PlayerSeekBigForward langer rückwärts Sprung
PlayerSeekBigForward langer vorwärts Schritt
PlayerSeekBigForward langer vorwärts Sprung
PlayerSeekBigForward weiter Schritt rückwärts
PlayerSeekBigForward weiter Schritt vor
PlayerSeekBigForward weiter Schritt vorwärts
PlayerSeekBigForward weiter Schritt zurück
PlayerSeekBigForward weiter Sprung rückwärts
PlayerSeekBigForward weiter Sprung vor
PlayerSeekBigForward weiter Sprung vorwärts
PlayerSeekBigForward weiter Sprung zurück
PlayerSeekBigForward weiter rückwärts Schritt
PlayerSeekBigForward weiter rückwärts Sprung
PlayerSeekBigForward weiter vor
PlayerSeekBigForward weiter vorspringen
PlayerSeekBigForward weiter vorspulen
PlayerSeekBigForward weiter vorwärts Schritt
PlayerSeekBigForward weiter vorwärts Sprung
PlayerSeekForward Schritt um {ForwardDur}
PlayerSeekForward Schritt vor um {ForwardDur}
PlayerSeekForward Schritt vor {ForwardDur}
PlayerSeekForward Schritt vorwärts um {ForwardDur}
PlayerSeekForward Schritt vorwärts {ForwardDur}
PlayerSeekForward Schritt {ForwardDur}
PlayerSeekForward Sprung um {ForwardDur}
PlayerSeekForward Sprung vor um {ForwardDur}
PlayerSeekForward Sprung vor {ForwardDur}
PlayerSeekForward Sprung vorwärts um {ForwardDur}
PlayerSeekForward Sprung vorwärts {ForwardDur}
PlayerSeekForward Sprung {ForwardDur}
PlayerSeekForward vorwärts Schritt um {ForwardDur}
PlayerSeekForward vorwärts Sprung um {ForwardDur}
PlayerSeekSmallBackward Schritt rückwärts
PlayerSeekSmallBackward Schritt zurück
PlayerSeekSmallBackward Sprung rückwärts
PlayerSeekSmallBackward Sprung zurück
PlayerSeekSmallBackward kleiner Schritt rückwärts
PlayerSeekSmallBackward kleiner Schritt zurück
PlayerSeekSmallBackward kleiner Sprung rückwärts
PlayerSeekSmallBackward kleiner Sprung zurück
PlayerSeekSmallBackward rückwärts
PlayerSeekSmallBackward zurück
PlayerSeekSmallBackward zurückspulen
PlayerSeekSmallForward Schritt vor
PlayerSeekSmallForward Schritt vorwärts
PlayerSeekSmallForward Sprung vor
PlayerSeekSmallForward Sprung vorwärts
PlayerSeekSmallForward kleiner Schritt vor
PlayerSeekSmallForward kleiner Schritt vorwärts
PlayerSeekSmallForward kleiner Sprung vor
PlayerSeekSmallForward kleiner Sprung vorwärts
PlayerSeekSmallForward kleiner vorwärts Schritt
PlayerSeekSmallForward kleiner vorwärts Sprung
PlayerSeekSmallForward vor
PlayerSeekSmallForward vorspulen
PlayerSeekSmallForward vorwärts
PlayerSeekSmallForward vorwärts Schritt
PlayerSeekSmallForward vorwärts Sprung
PlayerZoomHold halte
PlayerZoomHold halte Zoom
PlayerZoomHold halte Zoom da
PlayerZoomHold halte Zoom genau da
PlayerZoomHold halte da
PlayerZoomHold halte den Zoom
PlayerZoomHold halte den Zoom da
PlayerZoomHold halte den Zoom genau da
PlayerZoomHold halte es
PlayerZoomHold halte es da
PlayerZoomHold halte es genau da
PlayerZoomHold halte genau da
PlayerZoomIn rein zoomen
PlayerZoomIn vergrößern
PlayerZoomIn zoom rein
PlayerZoomInMoveDown rein zoomen und geh runter
PlayerZoomInMoveDown rein zoomen und gehe runter
PlayerZoomInMoveDown rein zoomen und runter
PlayerZoomInMoveDown vergrößern und geh runter
PlayerZoomInMoveDown vergrößern und gehe runter
PlayerZoomInMoveDown vergrößern und runter
PlayerZoomInMoveDown zoom rein und geh runter
PlayerZoomInMoveDown zoom rein und gehe runter
PlayerZoomInMoveDown zoom rein und runter
PlayerZoomInMoveLeft rein zoomen und geh links
PlayerZoomInMoveLeft rein zoomen und geh nach links
PlayerZoomInMoveLeft rein zoomen und gehe links
PlayerZoomInMoveLeft rein zoomen und gehe nach links
PlayerZoomInMoveLeft rein zoomen und links
PlayerZoomInMoveLeft rein zoomen und nach links
PlayerZoomInMoveLeft vergrößern und geh links
PlayerZoomInMoveLeft vergrößern und geh nach links
PlayerZoomInMoveLeft vergrößern und gehe links
PlayerZoomInMoveLeft vergrößern und gehe nach links
PlayerZoomInMoveLeft vergrößern und links
PlayerZoomInMoveLeft vergrößern und nach links
PlayerZoomInMoveLeft zoom rein und geh links
PlayerZoomInMoveLeft zoom rein und geh nach links
PlayerZoomInMoveLeft zoom rein und gehe links
PlayerZoomInMoveLeft zoom rein und gehe nach links
PlayerZoomInMoveLeft zoom rein und links
PlayerZoomInMoveLeft zoom rein und nach links
PlayerZoomInMoveRight rein zoomen und geh nach rechts
PlayerZoomInMoveRight rein zoomen und geh rechts
PlayerZoomInMoveRight rein zoomen und gehe nach rechts
PlayerZoomInMoveRight rein zoomen und gehe rechts
PlayerZoomInMoveRight rein zoomen und nach rechts
PlayerZoomInMoveRight rein zoomen und rechts
PlayerZoomInMoveRight vergrößern und geh nach rechts
PlayerZoomInMoveRight vergrößern und geh rechts
PlayerZoomInMoveRight vergrößern und gehe nach rechts
PlayerZoomInMoveRight vergrößern und gehe rechts
PlayerZoomInMoveRight vergrößern und nach rechts
PlayerZoomInMoveRight vergrößern und rechts
PlayerZoomInMoveRight zoom rein und geh nach rechts
PlayerZoomInMoveRight zoom rein und geh rechts
PlayerZoomInMoveRight zoom rein und gehe nach rechts
PlayerZoomInMoveRight zoom rein und gehe rechts
PlayerZoomInMoveRight zoom rein und nach rechts
PlayerZoomInMoveRight zoom rein und rechts
PlayerZoomInMoveUp rein zoomen und geh hoch
PlayerZoomInMoveUp rein zoomen und gehe hoch
PlayerZoomInMoveUp rein zoomen und hoch
PlayerZoomInMoveUp vergrößern und geh hoch
PlayerZoomInMoveUp vergrößern und gehe hoch
PlayerZoomInMoveUp vergrößern und hoch
PlayerZoomInMoveUp zoom rein und geh hoch
PlayerZoomInMoveUp zoom rein und gehe hoch
PlayerZoomInMoveUp zoom rein und hoch
PlayerZoomOut raus zoomen
PlayerZoomOut verkleinern
PlayerZoomOut zoom raus
PlayerZoomOutMoveDown raus zoomen und geh nach unten
PlayerZoomOutMoveDown raus zoomen und geh runter
PlayerZoomOutMoveDown raus zoomen und gehe nach unten
PlayerZoomOutMoveDown raus zoomen und gehe runter
PlayerZoomOutMoveDown raus zoomen und nach unten
PlayerZoomOutMoveDown raus zoomen und runter
PlayerZoomOutMoveDown verkleinern und geh nach unten
PlayerZoomOutMoveDown verkleinern und geh runter
PlayerZoomOutMoveDown verkleinern und gehe nach unten
PlayerZoomOutMoveDown verkleinern und gehe runter
PlayerZoomOutMoveDown verkleinern und nach unten
PlayerZoomOutMoveDown verkleinern und runter
PlayerZoomOutMoveDown zoom raus und geh nach unten
PlayerZoomOutMoveDown zoom raus und geh runter
PlayerZoomOutMoveDown zoom raus und gehe nach unten
PlayerZoomOutMoveDown zoom raus und gehe runter
PlayerZoomOutMoveDown zoom raus und nach unten
PlayerZoomOutMoveDown zoom raus und runter
PlayerZoomOutMoveLeft raus zoomen und geh links
PlayerZoomOutMoveLeft raus zoomen und geh nach links
PlayerZoomOutMoveLeft raus zoomen und gehe links
PlayerZoomOutMoveLeft raus zoomen und gehe nach links
PlayerZoomOutMoveLeft raus zoomen und links
PlayerZoomOutMoveLeft raus zoomen und nach links
PlayerZoomOutMoveLeft verkleinern und geh links
PlayerZoomOutMoveLeft verkleinern und geh nach links
PlayerZoomOutMoveLeft verkleinern und gehe links
PlayerZoomOutMoveLeft verkleinern und gehe nach links
PlayerZoomOutMoveLeft verkleinern und links
PlayerZoomOutMoveLeft verkleinern und nach links
PlayerZoomOutMoveLeft zoom raus und geh links
PlayerZoomOutMoveLeft zoom raus und geh nach links
PlayerZoomOutMoveLeft zoom raus und gehe links
PlayerZoomOutMoveLeft zoom raus und gehe nach links
PlayerZoomOutMoveLeft zoom raus und links
PlayerZoomOutMoveLeft zoom raus und nach links
PlayerZoomOutMoveRight raus zoomen und geh nach rechts
PlayerZoomOutMoveRight raus zoomen und geh rechts
PlayerZoomOutMoveRight raus zoomen und gehe nach rechts
PlayerZoomOutMoveRight raus zoomen und gehe rechts
PlayerZoomOutMoveRight raus zoomen und nach rechts
PlayerZoomOutMoveRight raus zoomen und rechts
PlayerZoomOutMoveRight verkleinern und geh nach rechts
PlayerZoomOutMoveRight verkleinern und geh rechts
PlayerZoomOutMoveRight verkleinern und gehe nach rechts
PlayerZoomOutMoveRight verkleinern und gehe rechts
PlayerZoomOutMoveRight verkleinern und nach rechts
PlayerZoomOutMoveRight verkleinern und rechts
PlayerZoomOutMoveRight zoom raus und geh nach rechts
PlayerZoomOutMoveRight zoom raus und geh rechts
PlayerZoomOutMoveRight zoom raus und gehe nach rechts
PlayerZoomOutMoveRight zoom raus und gehe rechts
PlayerZoomOutMoveRight zoom raus und nach rechts
PlayerZoomOutMoveRight zoom raus und rechts
PlayerZoomOutMoveUp raus zoomen und geh hoch
PlayerZoomOutMoveUp raus zoomen und geh nach oben
PlayerZoomOutMoveUp raus zoomen und geh rauf
PlayerZoomOutMoveUp raus zoomen und gehe hoch
PlayerZoomOutMoveUp raus zoomen und gehe nach oben
PlayerZoomOutMoveUp raus zoomen und gehe rauf
PlayerZoomOutMoveUp raus zoomen und hoch
PlayerZoomOutMoveUp raus zoomen und nach oben
PlayerZoomOutMoveUp raus zoomen und rauf
PlayerZoomOutMoveUp verkleinern und geh hoch
PlayerZoomOutMoveUp verkleinern und geh nach oben
PlayerZoomOutMoveUp verkleinern und geh rauf
PlayerZoomOutMoveUp verkleinern und gehe hoch
PlayerZoomOutMoveUp verkleinern und gehe nach oben
PlayerZoomOutMoveUp verkleinern und gehe rauf
PlayerZoomOutMoveUp verkleinern und hoch
PlayerZoomOutMoveUp verkleinern und nach oben
PlayerZoomOutMoveUp verkleinern und rauf
PlayerZoomOutMoveUp zoom raus und geh hoch
PlayerZoomOutMoveUp zoom raus und geh nach oben
PlayerZoomOutMoveUp zoom raus und geh rauf
PlayerZoomOutMoveUp zoom raus und gehe hoch
PlayerZoomOutMoveUp zoom raus und gehe nach oben
PlayerZoomOutMoveUp zoom raus und gehe rauf
PlayerZoomOutMoveUp zoom raus und hoch
PlayerZoomOutMoveUp zoom raus und nach oben
PlayerZoomOutMoveUp zoom raus und rauf
PlayerZoomReset kein zoom
PlayerZoomReset normal zoom
PlayerZoomReset reset zoom
Reboot neustarten
Reboot reboot
Reboot system neustarten
Reboot system reboot
RecommendAlbum welches Album es empfiehlt
RecommendAlbum welches Album es mir empfiehlt
RecommendAlbum welches Album es mir vorschlägt
RecommendAlbum welches Album es vorschlägt
RecommendAlbum welches {MusicGenre} Album es empfiehlt
RecommendAlbum welches {MusicGenre} Album es mir empfiehlt
RecommendAlbum welches {MusicGenre} Album es mir vorschlägt
RecommendAlbum welches {MusicGenre} Album es vorschlägt
RecommendArtist welchen Interpreten es empfiehlt
RecommendArtist welchen Interpreten es mir empfiehlt
RecommendArtist welchen Interpreten es mir vorschlägt
RecommendArtist welchen Interpreten es vorschlägt
RecommendArtist welchen {MusicGenre} Interpreten es empfiehlt
RecommendArtist welchen {MusicGenre} Interpreten es mir empfiehlt
RecommendArtist welchen {MusicGenre} Interpreten es mir vorschlägt
RecommendArtist welchen {MusicGenre} Interpreten es vorschlägt
RecommendAudio welche Musik es empfiehlt
RecommendAudio welche Musik es mir empfiehlt
RecommendAudio welche Musik es mir vorschlägt
RecommendAudio welche Musik es vorschlägt
RecommendEpisode welche Episode es empfiehlt
RecommendEpisode welche Episode es mir empfiehlt
RecommendEpisode welche Episode es mir vorschlägt
RecommendEpisode welche Episode es vorschlägt
RecommendEpisode welche Folge es empfiehlt
RecommendEpisode welche Folge es mir empfiehlt
RecommendEpisode welche Folge es mir vorschlägt
RecommendEpisode welche Folge es vorschlägt
RecommendEpisode welche {ShowGenre} Episode es empfiehlt
RecommendEpisode welche {ShowGenre} Episode es mir empfiehlt
RecommendEpisode welche {ShowGenre} Episode es mir vorschlägt
RecommendEpisode welche {ShowGenre} Episode es vorschlägt
RecommendEpisode welche {ShowGenre} Folge es empfiehlt
RecommendEpisode welche {ShowGenre} Folge es mir empfiehlt
RecommendEpisode welche {ShowGenre} Folge es mir vorschlägt
RecommendEpisode welche {ShowGenre} Folge es vorschlägt
RecommendMovie welchen Film es empfiehlt
RecommendMovie welchen Film es mir empfiehlt
RecommendMovie welchen Film es mir vorschlägt
RecommendMovie welchen Film es vorschlägt
RecommendMovie welchen {MovieGenre} Film es empfiehlt
RecommendMovie welchen {MovieGenre} Film es mir empfiehlt
RecommendMovie welchen {MovieGenre} Film es mir vorschlägt
RecommendMovie welchen {MovieGenre} Film es vorschlägt
RecommendMusicVideo welches Musikvideo es empfiehlt
RecommendMusicVideo welches Musikvideo es mir empfiehlt
RecommendMusicVideo welches Musikvideo es mir vorschlägt
RecommendMusicVideo welches Musikvideo es vorschlägt
RecommendMusicVideo welches {MusicVideoGenre} Musikvideo es empfiehlt
RecommendMusicVideo welches {MusicVideoGenre} Musikvideo es mir empfiehlt
RecommendMusicVideo welches {MusicVideoGenre} Musikvideo es mir vorschlägt
RecommendMusicVideo welches {MusicVideoGenre} Musikvideo es vorschlägt
RecommendShow welche Serie es empfiehlt
RecommendShow welche Serie es mir empfiehlt
RecommendShow welche Serie es mir vorschlägt
RecommendShow welche Serie es vorschlägt
RecommendShow welche {ShowGenre} Serie es empfiehlt
RecommendShow welche {ShowGenre} Serie es mir empfiehlt
RecommendShow welche {ShowGenre} Serie es mir vorschlägt
RecommendShow welche {ShowGenre} Serie es vorschlägt
RecommendSong welchen Song es empfiehlt
RecommendSong welchen Song es mir empfiehlt
RecommendSong welchen Song es mir vorschlägt
RecommendSong welchen Song es vorschlägt
RecommendSong welchen {MusicGenre} Song es empfiehlt
RecommendSong welchen {MusicGenre} Song es mir empfiehlt
RecommendSong welchen {MusicGenre} Song es mir vorschlägt
RecommendSong welchen {MusicGenre} Song es vorschlägt
RecommendSong welches Lied es empfiehlt
RecommendSong welches Lied es mir empfiehlt
RecommendSong welches Lied es mir vorschlägt
RecommendSong welches Lied es vorschlägt
RecommendSong welches {MusicGenre} Lied es empfiehlt
RecommendSong welches {MusicGenre} Lied es mir empfiehlt
RecommendSong welches {MusicGenre} Lied es mir vorschlägt
RecommendSong welches {MusicGenre} Lied es vorschlägt
RecommendVideo welches Video es empfiehlt
RecommendVideo welches Video es mir empfiehlt
RecommendVideo welches Video es mir vorschlägt
RecommendVideo welches Video es vorschlägt
Right nach rechts
Right navigier nach rechts
Right navigier rechts
Right navigiere nach rechts
Right navigiere rechts
Right rechts
Select auswählen
ShuffleAlbum zufallswiedergabe album {Album}
ShuffleAlbum zufallswiedergabe album {Album} von {Artist}
ShuffleAlbum zufallswiedergabe das albums {Album} von {Artist}
ShuffleAlbum zufallswiedergabe des albums {Album}
ShuffleAlbum zufallswiedergabe vom album {Album}
ShuffleAlbum zufallswiedergabe vom album {Album} von {Artist}
ShuffleAlbum zufallswiedergabe {Album} von {Artist}
ShuffleAudioPlaylist zufallswiedergabe Audio playlist {AudioPlaylist}
ShuffleAudioPlaylist zufallswiedergabe Musik playlist {AudioPlaylist}
ShuffleAudioPlaylist zufallswiedergabe {AudioPlaylist} Audio playlist
ShuffleAudioPlaylist zufallswiedergabe {AudioPlaylist} Musik playlist
ShuffleLatestAlbum Zufallswiedergabe des aktuellen Albums von {Artist}
ShuffleLatestAlbum Zufallswiedergabe des aktuellsten Albums von {Artist}
ShuffleLatestAlbum Zufallswiedergabe des neuen Albums von {Artist}
ShuffleLatestAlbum Zufallswiedergabe des neuesten Albums von {Artist}
ShuffleLatestAlbum Zufallswiedergabe des zuletzt hinzugefügten Albums von {Artist}
ShuffleLatestAlbum shuffle des aktuellen Albums von {Artist}
ShuffleLatestAlbum shuffle des aktuellsten Albums von {Artist}
ShuffleLatestAlbum shuffle des neuen Albums von {Artist}
ShuffleLatestAlbum shuffle des neuesten Albums von {Artist}
ShuffleLatestAlbum shuffle des zuletzt hinzugefügten Albums von {Artist}
ShuffleLatestAlbum starte Zufallswiedergabe des aktuellen Albums von {Artist}
ShuffleLatestAlbum starte Zufallswiedergabe des aktuellsten Albums von {Artist}
ShuffleLatestAlbum starte Zufallswiedergabe des neuen Albums von {Artist}
ShuffleLatestAlbum starte Zufallswiedergabe des neuesten Albums von {Artist}
ShuffleLatestAlbum starte Zufallswiedergabe des zuletzt hinzugefügten Albums von {Artist}
ShuffleMedia zufallswiedergabe {Show}
ShuffleMusicVideos spiele alle Musikvideos
ShuffleMusicVideos spiele alle Musikvideos von {Artist}
ShuffleMusicVideos spiele alle {MusicVideoGenre} Musikvideos
ShuffleMusicVideos spiele alle {MusicVideoGenre} Musikvideos von {Artist}
ShuffleMusicVideos spiele zufällige Musikvideos
ShuffleMusicVideos spiele zufällige Musikvideos von {Artist}
ShuffleMusicVideos spiele zufällige {MusicVideoGenre} Musikvideos
ShuffleMusicVideos spiele zufällige {MusicVideoGenre} Musikvideos von {Artist}
ShuffleMusicVideos zeige alle Musikvideos
ShuffleMusicVideos zeige alle Musikvideos von {Artist}
ShuffleMusicVideos zeige alle {MusicVideoGenre} Musikvideos
ShuffleMusicVideos zeige alle {MusicVideoGenre} Musikvideos von {Artist}
ShuffleMusicVideos zeige zufällige Musikvideos
ShuffleMusicVideos zeige zufällige Musikvideos von {Artist}
ShuffleMusicVideos zeige zufällige {MusicVideoGenre} Musikvideos
ShuffleMusicVideos zeige zufällige {MusicVideoGenre} Musikvideos von {Artist}
ShufflePlaylist zufallswiedergabe playlist {AudioPlaylist}
ShufflePlaylist zufallswiedergabe playlist {VideoPlaylist}
ShufflePlaylist zufallswiedergabe {AudioPlaylist} playlist
ShufflePlaylist zufallswiedergabe {VideoPlaylist} playlist
ShuffleShow zufallswiedergabe aller episoden von {Show}
ShuffleShow zufallswiedergabe episoden von {Show}
ShuffleVideoPlaylist zufallswiedergabe Film playlist {VideoPlaylist}
ShuffleVideoPlaylist zufallswiedergabe Serie playlist {VideoPlaylist}
ShuffleVideoPlaylist zufallswiedergabe Video playlist {VideoPlaylist}
ShuffleVideoPlaylist zufallswiedergabe {VideoPlaylist} Film playlist
ShuffleVideoPlaylist zufallswiedergabe {VideoPlaylist} Serie playlist
ShuffleVideoPlaylist zufallswiedergabe {VideoPlaylist} Video playlist
Shutdown herunterfahren
Shutdown shutdown
Shutdown system herunterfahren
Shutdown system shutdown
StereoscopicMode aktiviere three d.
StereoscopicMode aktiviere three d. Modus
StereoscopicMode schalte auf three d.
StereoscopicMode schalte auf three d. Modus
StereoscopicMode schalte auf three d. Modus um
StereoscopicMode schalte auf three d. um
SubtitlesDownload download Untertitel
SubtitlesNext Untertitel umschalten
SubtitlesNext nächster Untertitel
SubtitlesOff Untertitel aus
SubtitlesOff Untertitel ausschalten
SubtitlesOn Untertitel an
SubtitlesOn Untertitel anschalten
SubtitlesPrevious voriger Untertitel
Suspend bereitschaft
Suspend geh schlafen
Suspend gehe schlafen
Suspend schlafen
Suspend standby
Suspend suspend
Suspend system bereitschaft
Suspend system geh schlafen
Suspend system gehe schlafen
Suspend system schlafen
Suspend system standby
Suspend system suspend
Up hoch
Up nach oben
Up navigier hoch
Up navigier nach oben
Up navigiere hoch
Up navigiere nach oben
UpdateAudio Audio Bibliothek erneuern
UpdateAudio Audio Bibliothek refreshen
UpdateAudio Audio Bibliothek updaten
UpdateAudio Musik Bibliothek erneuern
UpdateAudio Musik Bibliothek refreshen
UpdateAudio Musik Bibliothek updaten
UpdateAudio erneuer Audio Bibliothek
UpdateAudio erneuer Musik Bibliothek
UpdateAudio erneuere Audio Bibliothek
UpdateAudio erneuere Musik Bibliothek
UpdateAudio refresh Audio Bibliothek
UpdateAudio refresh Musik Bibliothek
UpdateAudio refreshe Audio Bibliothek
UpdateAudio refreshe Musik Bibliothek
UpdateAudio update Audio Bibliothek
UpdateAudio update Musik Bibliothek
UpdateVideo Video Bibliothek erneuern
UpdateVideo Video Bibliothek refreshen
UpdateVideo Video Bibliothek updaten
UpdateVideo erneuer Video Bibliothek
UpdateVideo erneuere Video Bibliothek
UpdateVideo refresh Video Bibliothek
UpdateVideo refreshe Video Bibliothek
UpdateVideo update Video Bibliothek
ViewAlbums gehe zu Alben
ViewAlbums öffne Alben
ViewArtists gehe zu Interpreten
ViewArtists gehe zu Künstler
ViewArtists gehe zu Musiker
ViewArtists öffne Interpreten
ViewArtists öffne Künstler
ViewArtists öffne Musiker
ViewAudioPlaylist gehe zu Lieder playlist {AudioPlaylist}
ViewAudioPlaylist gehe zu Musik playlist {AudioPlaylist}
ViewAudioPlaylist gehe zu Song playlist {AudioPlaylist}
ViewAudioPlaylist gehe zu {AudioPlaylist} Lieder playlist
ViewAudioPlaylist gehe zu {AudioPlaylist} Musik playlist
ViewAudioPlaylist gehe zu {AudioPlaylist} Song playlist
ViewAudioPlaylist öffne Lieder playlist {AudioPlaylist}
ViewAudioPlaylist öffne Musik playlist {AudioPlaylist}
ViewAudioPlaylist öffne Song playlist {AudioPlaylist}
ViewAudioPlaylist öffne {AudioPlaylist} Lieder playlist
ViewAudioPlaylist öffne {AudioPlaylist} Musik playlist
ViewAudioPlaylist öffne {AudioPlaylist} Song playlist
ViewAudioPlaylistRecent gehe zu kürzlich hinzugefügte Lieder
ViewAudioPlaylistRecent gehe zu kürzlich hinzugefügte Musik
ViewAudioPlaylistRecent gehe zu kürzlich hinzugefügte Songs
ViewAudioPlaylistRecent gehe zu neue Lieder
ViewAudioPlaylistRecent gehe zu neue Musik
ViewAudioPlaylistRecent gehe zu neue Songs
ViewAudioPlaylistRecent gehe zu zuletzt hinzugefügte Lieder
ViewAudioPlaylistRecent gehe zu zuletzt hinzugefügte Musik
ViewAudioPlaylistRecent gehe zu zuletzt hinzugefügte Songs
ViewAudioPlaylistRecent öffne kürzlich hinzugefügte Lieder
ViewAudioPlaylistRecent öffne kürzlich hinzugefügte Musik
ViewAudioPlaylistRecent öffne kürzlich hinzugefügte Songs
ViewAudioPlaylistRecent öffne neue Lieder
ViewAudioPlaylistRecent öffne neue Musik
ViewAudioPlaylistRecent öffne neue Songs
ViewAudioPlaylistRecent öffne zuletzt hinzugefügte Lieder
ViewAudioPlaylistRecent öffne zuletzt hinzugefügte Musik
ViewAudioPlaylistRecent öffne zuletzt hinzugefügte Songs
ViewEpisodePlaylistRecent gehe zu kürzlich hinzugefügte Serien
ViewEpisodePlaylistRecent gehe zu neue Serien
ViewEpisodePlaylistRecent gehe zu zuletzt hinzugefügte Serien
ViewEpisodePlaylistRecent öffne kürzlich hinzugefügte Serien
ViewEpisodePlaylistRecent öffne neue Serien
ViewEpisodePlaylistRecent öffne zuletzt hinzugefügte Serien
ViewMusicVideoPlaylistRecent gehe zu kürzlich hinzugefügte Musikvideos
ViewMusicVideoPlaylistRecent gehe zu neue Musikvideos
ViewMusicVideoPlaylistRecent gehe zu zuletzt hinzugefügte Musikvideos
ViewMusicVideoPlaylistRecent öffne kürzlich hinzugefügte Musikvideos
ViewMusicVideoPlaylistRecent öffne neue Musikvideos
ViewMusicVideoPlaylistRecent öffne zuletzt hinzugefügte Musikvideos
ViewMoviePlaylistRecent gehe zu kürzlich hinzugefügte Filme
ViewMoviePlaylistRecent gehe zu kürzlich hinzugefügte Videos
ViewMoviePlaylistRecent gehe zu neue Filme
ViewMoviePlaylistRecent gehe zu neue Videos
ViewMoviePlaylistRecent gehe zu zuletzt hinzugefügte Filme
ViewMoviePlaylistRecent gehe zu zuletzt hinzugefügte Videos
ViewMoviePlaylistRecent öffne kürzlich hinzugefügte Filme
ViewMoviePlaylistRecent öffne kürzlich hinzugefügte Videos
ViewMoviePlaylistRecent öffne neue Filme
ViewMoviePlaylistRecent öffne neue Videos
ViewMoviePlaylistRecent öffne zuletzt hinzugefügte Filme
ViewMoviePlaylistRecent öffne zuletzt hinzugefügte Videos
ViewMovies finde {MovieGenre} Filme
ViewMovies gehe zu Filme
ViewMovies suche nach {MovieGenre} Filmen
ViewMovies suche {MovieGenre} Filme
ViewMovies öffne Filme
ViewMusic finde {MusicGenre} Musik
ViewMusic gehe zu Musik
ViewMusic suche nach {MusicGenre} Musik
ViewMusic suche {MusicGenre} Musik
ViewMusic öffne Musik
ViewMusicVideos finde {MusicVideoGenre} Musikvideos
ViewMusicVideos gehe zu Musikvideos
ViewMusicVideos suche nach {MusicVideoGenre} Musikvideos
ViewMusicVideos suche {MusicVideoGenre} Musikvideos
ViewMusicVideos öffne Musikvideos
ViewPlaylist gehe zu playlist {AudioPlaylist}
ViewPlaylist gehe zu playlist {VideoPlaylist}
ViewPlaylist gehe zu {AudioPlaylist} playlist
ViewPlaylist gehe zu {VideoPlaylist} playlist
ViewPlaylist öffne playlist {AudioPlaylist}
ViewPlaylist öffne playlist {VideoPlaylist}
ViewPlaylist öffne {AudioPlaylist} playlist
ViewPlaylist öffne {VideoPlaylist} playlist
ViewShows finde {ShowGenre} Serien
ViewShows gehe zu Serien
ViewShows suche nach {ShowGenre} Serien
ViewShows suche {ShowGenre} Serien
ViewShows öffne Serien
ViewVideoPlaylist gehe zu Film playlist {VideoPlaylist}
ViewVideoPlaylist gehe zu Serie playlist {VideoPlaylist}
ViewVideoPlaylist gehe zu Video playlist {VideoPlaylist}
ViewVideoPlaylist gehe zu {VideoPlaylist} Film playlist
ViewVideoPlaylist gehe zu {VideoPlaylist} Serie playlist
ViewVideoPlaylist gehe zu {VideoPlaylist} Video playlist
ViewVideoPlaylist öffne Film playlist {VideoPlaylist}
ViewVideoPlaylist öffne Serie playlist {VideoPlaylist}
ViewVideoPlaylist öffne Video playlist {VideoPlaylist}
ViewVideoPlaylist öffne {VideoPlaylist} Film playlist
ViewVideoPlaylist öffne {VideoPlaylist} Serie playlist
ViewVideoPlaylist öffne {VideoPlaylist} Video playlist
VolumeDown leiser
VolumeSet Lautstärke auf {Volume}
VolumeSet Lautstärke {Volume}
VolumeSet stelle Lautstärke auf {Volume}
VolumeSet stelle Lautstärke {Volume}
VolumeSetPct Lautstärke auf {Volume} Prozent
VolumeSetPct Lautstärke {Volume} Prozent
VolumeSetPct stelle Lautstärke auf {Volume} Prozent
VolumeSetPct stelle Lautstärke {Volume} Prozent
VolumeUp lauter
WatchEpisode zeige Staffel {Season} Episode {Episode} von {Show}
WatchEpisode zeige Staffel {Season} Folge {Episode} von {Show}
WatchLastShow weiter mit Serie
WatchLastShow weiter mit letzter Serie
WatchLatestEpisode zeige letzte Episode von {Show}
WatchLatestEpisode zeige letzte Folge von {Show}
WatchLatestEpisode zeige neueste Episode von {Show}
WatchLatestEpisode zeige neueste Folge von {Show}
WatchMovie zeige Film {Movie}
WatchMovieTrailer spiele Trailer
WatchMovieTrailer spiele Trailer für {Movie}
WatchMovieTrailer spiele Trailer von {Movie}
WatchMovieTra
gitextract_dv16a75p/

├── .gitignore
├── .travis.yml
├── CHANGELOG.txt
├── CONTRIBUTING.md
├── LICENSE
├── Procfile
├── README.md
├── UPGRADING.md
├── alexa.py
├── alexa.wsgi
├── app.json
├── generate_custom_slots.py
├── requirements.txt
├── runtime.txt
├── sample_slotvals.de.txt
├── sample_slotvals.en.txt
├── sample_slotvals.es.txt
├── sample_slotvals.fr.txt
├── sample_slotvals.it.txt
├── speech_assets/
│   ├── IntentSchema.json
│   ├── SampleUtterances.de.txt
│   ├── SampleUtterances.en.txt
│   ├── SampleUtterances.es.txt
│   ├── SampleUtterances.fr.txt
│   └── SampleUtterances.it.txt
├── templates.de.yaml
├── templates.en.yaml
├── templates.es.yaml
├── templates.fr.yaml
├── templates.it.yaml
├── utterances.de.txt
├── utterances.en.txt
├── utterances.es.txt
├── utterances.fr.txt
└── utterances.it.txt
Condensed preview — 35 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (868K chars).
[
  {
    "path": ".gitignore",
    "chars": 1019,
    "preview": "\n# Created by https://www.gitignore.io/api/python\n\n### Python ###\n# Byte-compiled / optimized / DLL files\n__pycache__/\n*..."
  },
  {
    "path": ".travis.yml",
    "chars": 1396,
    "preview": "language: python\npython:\n- '2.7'\nscript:\n- sudo apt-get install python-dev -y\n- cd $TRAVIS_BUILD_DIR\n- git clean -fXd\n-..."
  },
  {
    "path": "CHANGELOG.txt",
    "chars": 6620,
    "preview": "v2.9.6 (07/30/2018)\n* Add French language support.\n\nv2.9.5 (10/19/2017)\n* Add ability to cache responses via Amazon S3 b..."
  },
  {
    "path": "CONTRIBUTING.md",
    "chars": 940,
    "preview": "# Contributing Guide\n\n## Please Read\nIf you would like to contribute, please keep the following in mind:\n - If you make..."
  },
  {
    "path": "LICENSE",
    "chars": 1045,
    "preview": "The MIT License (MIT)\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and..."
  },
  {
    "path": "Procfile",
    "chars": 23,
    "preview": "web: gunicorn alexa:app"
  },
  {
    "path": "README.md",
    "chars": 5473,
    "preview": "# Kanzi: Alexa Integration With Kodi\n\n[![Build Status](https://travis-ci.org/m0ngr31/kanzi.svg?branch=master)](https://t..."
  },
  {
    "path": "UPGRADING.md",
    "chars": 1592,
    "preview": "# Upgrading\n\nFor each new update, please run the Slot generator again and repopulate all of your slots with the output...."
  },
  {
    "path": "alexa.py",
    "chars": 99582,
    "preview": "#!/usr/bin/python\n\n# For a complete discussion, see http://forum.kodi.tv/showthread.php?tid=254502\n\nimport datetime\nimpo..."
  },
  {
    "path": "alexa.wsgi",
    "chars": 110,
    "preview": "#!/usr/bin/python\nimport os, sys\nsys.path += [os.path.dirname(__file__)]\nfrom alexa import app as application\n"
  },
  {
    "path": "app.json",
    "chars": 4495,
    "preview": "{\n  \"name\": \"Kanzi Skill\",\n  \"description\": \"An Alexa still that let's you control (almost) anything on a Kodi box.\",..."
  },
  {
    "path": "generate_custom_slots.py",
    "chars": 4105,
    "preview": "import re\nimport string\nimport random\nimport os\nfrom kodi_voice import KodiConfigParser, Kodi\n\nconfig_file = os.path.joi..."
  },
  {
    "path": "requirements.txt",
    "chars": 164,
    "preview": "gunicorn\npytz\ngit+https://github.com/johnwheeler/flask-ask@master#egg=flask-ask\ngit+https://github.com/m0ngr31/kodi-voic..."
  },
  {
    "path": "runtime.txt",
    "chars": 14,
    "preview": "python-2.7.18\n"
  },
  {
    "path": "sample_slotvals.de.txt",
    "chars": 358,
    "preview": "Addon YouTube\nMovieGenre Komödie\nMovie Männertag\nArtist Helene Fischer\nAlbum Farbenspiel\nMusicGenre Schlager\nAudioPlayli..."
  },
  {
    "path": "sample_slotvals.en.txt",
    "chars": 353,
    "preview": "Addon YouTube\nMovieGenre Comedy\nMovie Tropic Thunder\nArtist Sia\nAlbum One Thousand Forms of Fear\nMusicGenre Pop\nAudioPla..."
  },
  {
    "path": "sample_slotvals.es.txt",
    "chars": 380,
    "preview": "Addon YouTube\nMovieGenre Comedia\nMovie Tropic Thunder una guerra muy perra\nArtist Camilo Sexto\nAlbum 19 días y 500 noche..."
  },
  {
    "path": "sample_slotvals.fr.txt",
    "chars": 359,
    "preview": "Addon YouTube\nMovieGenre Comédie\nMovie Tropic Thunder\nArtist Sia\nAlbum One Thousand Forms of Fear\nMusicGenre Pop\nAudioPl..."
  },
  {
    "path": "sample_slotvals.it.txt",
    "chars": 348,
    "preview": "Addon YouTube\nMovieGenre Commedia\nMovie Tropic Thunder\nArtist Daniele Silvestri\nAlbum Monetine\nMusicGenre Pop\nAudioPlayl..."
  },
  {
    "path": "speech_assets/IntentSchema.json",
    "chars": 13559,
    "preview": "{\n  \"intents\": [\n    {\n      \"intent\": \"RecommendVideo\"\n    },\n    {\n      \"intent\": \"RecommendAudio\"\n    },\n    {..."
  },
  {
    "path": "speech_assets/SampleUtterances.de.txt",
    "chars": 62546,
    "preview": "AMAZON.HelpIntent nach was ich es fragen kann\nAMAZON.HelpIntent was es alles kann\nAMAZON.HelpIntent was es kann\nAMAZON.H..."
  },
  {
    "path": "speech_assets/SampleUtterances.en.txt",
    "chars": 74535,
    "preview": "AMAZON.HelpIntent things to try\nAMAZON.HelpIntent what can i ask you\nAMAZON.HelpIntent what can you do\nAddonExecute exec..."
  },
  {
    "path": "speech_assets/SampleUtterances.es.txt",
    "chars": 77206,
    "preview": "# A list of utterance variations written in a shorthand syntax\n# Syntax and information\n# Tool to expand the single line..."
  },
  {
    "path": "speech_assets/SampleUtterances.fr.txt",
    "chars": 156704,
    "preview": "# A list of utterance variations written in a shorthand syntax\n# Syntax and information\n# Tool to expand the single line..."
  },
  {
    "path": "speech_assets/SampleUtterances.it.txt",
    "chars": 192278,
    "preview": "AMAZON.HelpIntent cosa posso chiederti\nAMAZON.HelpIntent cosa puoi fare\nAMAZON.HelpIntent cose da provare\nAMAZON.StopInt..."
  },
  {
    "path": "templates.de.yaml",
    "chars": 13652,
    "preview": "############################\n##   Response Templates   ##\n############################\n\nconfig_missing: \"Verbindungsinfo..."
  },
  {
    "path": "templates.en.yaml",
    "chars": 12620,
    "preview": "############################\n##   Response Templates   ##\n############################\n\nconfig_missing: \"Could not find..."
  },
  {
    "path": "templates.es.yaml",
    "chars": 13324,
    "preview": "############################\n##   Response Templates   ##\n############################\n\nconfig_missing: \"No se pudo enco..."
  },
  {
    "path": "templates.fr.yaml",
    "chars": 13938,
    "preview": "############################\n##   Response Templates   ##\n############################\n\nconfig_missing: \"Je n'ai pas tro..."
  },
  {
    "path": "templates.it.yaml",
    "chars": 13780,
    "preview": "############################\n##   Response Templates   ##\n############################\n\nconfig_missing: \"Non sono riusci..."
  },
  {
    "path": "utterances.de.txt",
    "chars": 13009,
    "preview": "# A list of utterance variations written in a shorthand syntax\n\n# Syntax and information\n# http://www.makermusings.com/2..."
  },
  {
    "path": "utterances.en.txt",
    "chars": 13331,
    "preview": "# A list of utterance variations written in a shorthand syntax\n\n# Syntax and information\n# http://www.makermusings.com/2..."
  },
  {
    "path": "utterances.es.txt",
    "chars": 14113,
    "preview": "# A list of utterance variations written in a shorthand syntax\n\n# Syntax and information\n# http://www.makermusings.com/2..."
  },
  {
    "path": "utterances.fr.txt",
    "chars": 13800,
    "preview": "# A list of utterance variations written in a shorthand syntax\n\n# Syntax and information\n# http://www.makermusings.com/2..."
  },
  {
    "path": "utterances.it.txt",
    "chars": 16615,
    "preview": "# A list of utterance variations written in a shorthand syntax\n\n# Syntax and information\n# http://www.makermusings.com/2..."
  }
]

About this extraction

This page contains the full source code of the m0ngr31/kanzi GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 35 files (823.6 KB), approximately 202.8k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!