Merge pull request #3 from rosskouk/update-documentation
Update documentation
3
.github/workflows/build_sphinx_docs.yml
vendored
@@ -1,6 +1,9 @@
|
||||
name: build_sphinx_docs
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build-documentation:
|
||||
|
||||
3
.gitignore
vendored
@@ -5,5 +5,4 @@ sphinx/resources/*.bkp
|
||||
sphinx/resources/*.dtmp
|
||||
asknavidrome.log
|
||||
test.py
|
||||
NOTES.md
|
||||
sphinx
|
||||
NOTES.md
|
||||
17
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"cSpell.words": [
|
||||
"asknavidrome",
|
||||
"autoclass",
|
||||
"automodule",
|
||||
"Brainz",
|
||||
"maxdepth",
|
||||
"Navi",
|
||||
"Navidrome",
|
||||
"Navisonic",
|
||||
"quickstart",
|
||||
"ssword",
|
||||
"toctree",
|
||||
"undoc",
|
||||
"Unstar"
|
||||
]
|
||||
}
|
||||
205
alexa.json
Normal file
@@ -0,0 +1,205 @@
|
||||
{
|
||||
"interactionModel": {
|
||||
"languageModel": {
|
||||
"invocationName": "navisonic",
|
||||
"intents": [
|
||||
{
|
||||
"name": "AMAZON.CancelIntent",
|
||||
"samples": []
|
||||
},
|
||||
{
|
||||
"name": "AMAZON.HelpIntent",
|
||||
"samples": []
|
||||
},
|
||||
{
|
||||
"name": "AMAZON.StopIntent",
|
||||
"samples": []
|
||||
},
|
||||
{
|
||||
"name": "AMAZON.NavigateHomeIntent",
|
||||
"samples": []
|
||||
},
|
||||
{
|
||||
"name": "AMAZON.FallbackIntent",
|
||||
"samples": []
|
||||
},
|
||||
{
|
||||
"name": "AMAZON.PauseIntent",
|
||||
"samples": []
|
||||
},
|
||||
{
|
||||
"name": "AMAZON.ResumeIntent",
|
||||
"samples": []
|
||||
},
|
||||
{
|
||||
"name": "NaviSonicPlayMusicByArtist",
|
||||
"slots": [
|
||||
{
|
||||
"name": "artist",
|
||||
"type": "AMAZON.Artist"
|
||||
}
|
||||
],
|
||||
"samples": [
|
||||
"play songs by {artist}",
|
||||
"play music by {artist}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "AMAZON.NextIntent",
|
||||
"samples": []
|
||||
},
|
||||
{
|
||||
"name": "AMAZON.PreviousIntent",
|
||||
"samples": []
|
||||
},
|
||||
{
|
||||
"name": "NaviSonicPlayAlbumByArtist",
|
||||
"slots": [
|
||||
{
|
||||
"name": "album",
|
||||
"type": "AMAZON.MusicAlbum"
|
||||
},
|
||||
{
|
||||
"name": "artist",
|
||||
"type": "AMAZON.Artist"
|
||||
}
|
||||
],
|
||||
"samples": [
|
||||
"Play the album {album}",
|
||||
"Play the album {album} by {artist}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NaviSonicPlayPlaylist",
|
||||
"slots": [
|
||||
{
|
||||
"name": "playlist",
|
||||
"type": "playlist_names"
|
||||
}
|
||||
],
|
||||
"samples": [
|
||||
"Play the {playlist} playlist",
|
||||
"Start the {playlist} playlist"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NaviSonicSongDetails",
|
||||
"slots": [],
|
||||
"samples": [
|
||||
"What is playing",
|
||||
"Who is singing",
|
||||
"Who's singing",
|
||||
"What album is this song on",
|
||||
"What album is this on",
|
||||
"Which album",
|
||||
"Which album is this song from",
|
||||
"Which artist is this",
|
||||
"What band is this",
|
||||
"Who sings this song",
|
||||
"Who sings this",
|
||||
"What song is this",
|
||||
"What's playing"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NaviSonicStarSong",
|
||||
"slots": [],
|
||||
"samples": [
|
||||
"Add this song to my favourites",
|
||||
"Favourite this song",
|
||||
"Like this song",
|
||||
"Add this song to my liked songs",
|
||||
"Star this song"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NaviSonicUnstarSong",
|
||||
"slots": [],
|
||||
"samples": [
|
||||
"Remove this song from favourites",
|
||||
"I don't like this song",
|
||||
"Remove the star from this song",
|
||||
"Delete this song from my favourites",
|
||||
"Unstar this song"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NaviSonicPlaySongByArtist",
|
||||
"slots": [
|
||||
{
|
||||
"name": "song",
|
||||
"type": "AMAZON.MusicRecording"
|
||||
},
|
||||
{
|
||||
"name": "artist",
|
||||
"type": "AMAZON.Artist"
|
||||
}
|
||||
],
|
||||
"samples": [
|
||||
"Play the song {song} by the band {artist}",
|
||||
"Play {song} by the band {artist}",
|
||||
"Play {song} by {artist}",
|
||||
"Play the song {song} by the artist {artist}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NaviSonicPlayFavouriteSongs",
|
||||
"slots": [],
|
||||
"samples": [
|
||||
"Play my starred tracks",
|
||||
"Play starred tracks",
|
||||
"Play starred songs",
|
||||
"Play my starred songs",
|
||||
"Play my favourite songs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NaviSonicPlayMusicByGenre",
|
||||
"slots": [
|
||||
{
|
||||
"name": "genre",
|
||||
"type": "AMAZON.Genre"
|
||||
}
|
||||
],
|
||||
"samples": [
|
||||
"Play {genre} songs",
|
||||
"Play {genre} music"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "NaviSonicPlayMusicRandom",
|
||||
"slots": [],
|
||||
"samples": [
|
||||
"Play a selection of music",
|
||||
"Play a mix of tracks",
|
||||
"Play a mix of songs",
|
||||
"Play random music",
|
||||
"Play random songs"
|
||||
]
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"name": "playlist_names",
|
||||
"values": [
|
||||
{
|
||||
"name": {
|
||||
"value": "Background Music"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"value": "Rock Songs"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": {
|
||||
"value": "Work Music"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
20
sphinx/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
# Minimal makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line, and also
|
||||
# from the environment for the first two.
|
||||
SPHINXOPTS ?=
|
||||
SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = .
|
||||
BUILDDIR = _build
|
||||
|
||||
# Put it first so that "make" without argument is like "make help".
|
||||
help:
|
||||
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
|
||||
.PHONY: help Makefile
|
||||
|
||||
# Catch-all target: route all unknown targets to Sphinx using the new
|
||||
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
|
||||
%: Makefile
|
||||
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
|
||||
29
sphinx/_static/css/custom.css
Normal file
@@ -0,0 +1,29 @@
|
||||
.class {
|
||||
padding-bottom: 15px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.function {
|
||||
padding-bottom: 15px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.method {
|
||||
/* border-bottom: 3px solid #d0d0d0; */
|
||||
padding-bottom: 15px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.attribute {
|
||||
padding-bottom: 15px;
|
||||
padding-top: 15px;
|
||||
}
|
||||
|
||||
.admonition-todo {
|
||||
color: orangered;
|
||||
border: 3px dashed orangered;
|
||||
}
|
||||
|
||||
section {
|
||||
padding-top: 20px;
|
||||
}
|
||||
2
sphinx/_templates/layout.html
Normal file
@@ -0,0 +1,2 @@
|
||||
{% extends "!layout.html" %}
|
||||
{% set css_files = css_files + [ "../_static/css/functions.css" ] %}
|
||||
74
sphinx/conf.py
Normal file
@@ -0,0 +1,74 @@
|
||||
# Configuration file for the Sphinx documentation builder.
|
||||
#
|
||||
# This file only contains a selection of the most common options. For a full
|
||||
# list see the documentation:
|
||||
# https://www.sphinx-doc.org/en/master/usage/configuration.html
|
||||
|
||||
# -- Path setup --------------------------------------------------------------
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
sys.path.insert(0, os.path.abspath('../skill'))
|
||||
|
||||
|
||||
# -- Project information -----------------------------------------------------
|
||||
|
||||
project = 'AskNavidrome'
|
||||
copyright = '2022, Ross Stewart'
|
||||
author = 'Ross Stewart'
|
||||
|
||||
# The full version, including alpha/beta/rc tags
|
||||
release = '0.1'
|
||||
|
||||
|
||||
# -- General configuration ---------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'rinoh.frontend.sphinx',
|
||||
'sphinx.ext.autodoc',
|
||||
'autodocsumm',
|
||||
'sphinx.ext.todo'
|
||||
]
|
||||
|
||||
autodoc_default_options = {"autosummary": True}
|
||||
autoclass_content = 'both'
|
||||
autodoc_member_order = 'groupwise'
|
||||
|
||||
todo_include_todos = True
|
||||
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
|
||||
|
||||
|
||||
# -- Options for HTML output -------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
html_theme = 'groundwork'
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
html_css_files = [
|
||||
'css/custom.css',
|
||||
]
|
||||
|
||||
latex_elements = {
|
||||
'extraclassoptions': 'openany,oneside'
|
||||
}
|
||||
442
sphinx/index.rst
Normal file
@@ -0,0 +1,442 @@
|
||||
.. AskNavidrome documentation master file, created by
|
||||
sphinx-quickstart on Sat Jul 2 13:52:30 2022.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
|
||||
**AskNavidrome Alexa Skill Documentation**
|
||||
==========================================
|
||||
|
||||
**AskNavidrome** is an Alexa skill which allows you to play music hosted on a SubSonic API compatible media server, like Navidrome.
|
||||
|
||||
This allows to you stream your own music collection to your Echo devices without the restrictions you would normally face with regular
|
||||
streaming services like Amazon Music or Spotify. AskNavidrome allows you to:
|
||||
|
||||
- Skip backwards and forwards in your current queue or playlist without limitation.
|
||||
- Avoid paying subscription costs.
|
||||
- Avoid being forced to listen to adverts at regular intervals.
|
||||
- Actually use the music collection you have already paid for!
|
||||
- Run the service on a PC directly or inside a Docker container.
|
||||
|
||||
This skill was inspired by `AskSonic <https://github.com/srichter/asksonic>`_, however AskSonic was missing two features I required,
|
||||
the ability to play playlists and the ability to play an individual song. Instead of contributing to that project I have opted to
|
||||
create a new skill based on the **Alexa Skills Kit SDK for Python** as this has been updated more recently than *flask-ask* which is used
|
||||
by AskSonic, AskNavidrome is not a replacement for AskSonic and it does not implement all of AskSonic's features, it is however a viable
|
||||
alternative for those that would like a simple skill to let you stream your own music collection.
|
||||
|
||||
.. warning::
|
||||
The skill requires a username and password for your Navidrome installation which is stored in clear text. As the web service needs to be
|
||||
publicly accessible there is a chance that this password could be compromised. Please do not use an administrative account for your
|
||||
Navidrome installation or a password that you use on any other service. This software is distributed under the MIT license and no warranty
|
||||
is provided.
|
||||
|
||||
|
||||
Requirements
|
||||
************
|
||||
|
||||
In order to use AskNavidrome you will need:
|
||||
|
||||
**Your Music Collection**
|
||||
|
||||
Your collection needs to have been converted to a digital format like MP3. There are many tutorials available on the web to help you do this, but do
|
||||
be aware that there are limitations on the types of files that Echo devices can stream. You should review these before converting your collection as if
|
||||
you do not meet the requirements they will need to be transcoded before your Echo device can stream them. This article explains `Amazon's
|
||||
Audio Stream Requirements <https://developer.amazon.com/en-US/docs/alexa/custom-skills/audioplayer-interface-reference.html#audio-stream-requirements>`_
|
||||
|
||||
**A SubSonic API Compatible Media Server**
|
||||
|
||||
I use Navidrome, but you can use any flavour of SubSonic that you like. For information on getting and setting up Navidrome
|
||||
check out their website `Navidrome <https://www.navidrome.org/>`_. Your media server must be available on port 443 and serve requests using
|
||||
https with a valid TLS certificate, these are requirements dictated by Amazon and you must meet them or you will be unable to stream your collection.
|
||||
The media server needs to be publicly accessible from the Internet, in addition to allowing you to use this skill you will then be able to use any
|
||||
SubSonic API compatible mobile app to listen to your collection too.
|
||||
|
||||
You can get free TLS certificates from `Let's Encrypt <https://letsencrypt.org/>`_
|
||||
|
||||
You can set up dynamic DNS to make your media server accessible for free with `afraid.org <https://freedns.afraid.org/>`_
|
||||
|
||||
**Tags**
|
||||
|
||||
This may seem obvious but you need to make sure that your collection is accurately tagged with information like the artist, title, track number etc.
|
||||
as this is the only way that your media server can identify the music in your collection. If you need a tool to help with this have a look at
|
||||
`MusicBrainz Picard <https://picard.musicbrainz.org/>`_.
|
||||
|
||||
**An Amazon Echo Device**
|
||||
|
||||
You need something to listen to your music on!
|
||||
|
||||
|
||||
About the AskNavidrome Skill
|
||||
****************************
|
||||
|
||||
.. image:: resources/AskNavidrome_Diagram.png
|
||||
:width: 800
|
||||
:align: center
|
||||
:alt: AskNavidrome Overview Diagram
|
||||
|
||||
The skill consists of two parts, the actual Alexa skill and the web service service which allows the skill to connect to your SubSonic API
|
||||
compatible media server. The web service needs to have a valid TLS certificate, the easiest way to enable this is to run the web service
|
||||
behind a reverse proxy, the web service also needs to be publicly accessible on the Internet to allow the Alexa skill to access the service.
|
||||
|
||||
|
||||
Supported Intents
|
||||
*****************
|
||||
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
| Intent Name | Description | Example |
|
||||
+===========================================+============================================+=====================================+
|
||||
| :class:`~app.NaviSonicPlayMusicByArtist` | Play music by a specific artist | Play Where is my Mind by The Pixies |
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
| :class:`~app.NaviSonicPlayAlbumByArtist` | Play a specific album by a specific artist | Play The Blue Album by The Beatles |
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
| :class:`~app.NaviSonicPlaySongByArtist` | Play a specific song by a specific artist | Play the song Help by The Beatles |
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
| :class:`~app.NaviSonicPlayPlaylist` | Play a playlist | Play the playlist work music |
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
| :class:`~app.NaviSonicPlayMusicByGenre` | Play music with a specific genre | Play jazz music |
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
| :class:`~app.NaviSonicPlayMusicRandom` | Play a random mix of songs | Play random songs |
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
| :class:`~app.NaviSonicPlayFavouriteSongs` | Play your starred / favourite songs | Play my favourite songs |
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
| :class:`~app.NaviSonicSongDetails` | Give details on the playing track | What is playing |
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
| :class:`~app.NaviSonicStarSong` | Star / favourite a song | Star this song |
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
| :class:`~app.NaviSonicUnstarSong` | Unstar / unfavourite a song | Unstar this song |
|
||||
+-------------------------------------------+--------------------------------------------+-------------------------------------+
|
||||
|
||||
The following control intents are also supported:
|
||||
|
||||
- :class:`Next / Skip <app.NextPlaybackHandler>`
|
||||
- :class:`Previous / Back <app.PreviousPlaybackHandler>`
|
||||
- :class:`Pause <app.PausePlaybackHandler>`
|
||||
- :class:`Resume <app.ResumePlaybackHandler>`
|
||||
|
||||
Due to the way that Alexa skills operate there are some limitations. Full music Alexa skills require a catalog of content to be provided and this defeats
|
||||
the purpose of being able to search and stream from your own server directly. Because of this a custom skill type is used along with the AudioPlayer interface,
|
||||
but this has some limitations:
|
||||
|
||||
1. You need to open the skill to use it, say *Alexa, open Navisonic*.
|
||||
2. Some intents that you would expect to be able to use when a track is playing need a full skill invocation. For example if you want to get
|
||||
information on the track that is playing you will need to invoke the skill and call the intent by saying the following while the track is playing:
|
||||
|
||||
- Alexa, open Navisonic
|
||||
- What is playing?
|
||||
|
||||
You will then be given information about the current track and it will automatically resume. This is also required for the *star* and *unstar* intents.
|
||||
|
||||
|
||||
Installation and Setup
|
||||
**********************
|
||||
|
||||
Creating the AskNavidrome Alexa Skill
|
||||
-------------------------------------
|
||||
|
||||
#. Login to the Amazon Alexa Skills Kit Builder at https://developer.amazon.com.
|
||||
- You must use the same account that is set on your Echo devices.
|
||||
#. Click *Create Skill*
|
||||
#. Configure the skill:
|
||||
|
||||
.. image:: resources/create_skill_1.png
|
||||
:width: 800
|
||||
:align: center
|
||||
:alt: Skill Creation Step 1
|
||||
|
||||
|
||||
- Set *Skill name* to the name you wish to use to invoke the skill. This should be two words or a warning will be raised, I have found that a single word
|
||||
still works when testing. It can be hard to find a good skill name so feel free to experiment!
|
||||
- Set *Primary locale* to your locale, this **must** also be the locale set on your Echo device.
|
||||
|
||||
.. note:: The locale setting is extremely important, if the skill locale and the locale set on your Echo device do not match the skill will not work. In
|
||||
addition there are no error messages generated making the issue quite difficult to troubleshoot. The locale on your Echo device can be set via the Alexa Android
|
||||
app. Please do check the locale setting if you have trouble setting up the skill as the Alexa Skill Builder will default to your local locale, but Echo devices
|
||||
are set to the US locale by default. Checking this first will save you a few hours of troubleshooting!
|
||||
|
||||
- Set sync locales to *No*
|
||||
- Choose *Custom* as the model.
|
||||
- Choose *Provision your own* as the hosting method for backend resources.
|
||||
- Click *Create skill* again
|
||||
|
||||
#. Choose the template
|
||||
|
||||
.. image:: resources/create_skill_2.png
|
||||
:width: 800
|
||||
:align: center
|
||||
:alt: Skill Creation Step 2
|
||||
|
||||
- Choose *Start from Scratch*
|
||||
- Click *Continue with template* and wait while the skill is created.
|
||||
|
||||
#. Upload the intents
|
||||
|
||||
.. image:: resources/create_skill_3.png
|
||||
:width: 800
|
||||
:align: center
|
||||
:alt: Skill Creation Step 3
|
||||
|
||||
- Click *Interaction Model*, then *JSON Editor*
|
||||
- Delete everything that is currently in the editor and paste in the contents of **alexa.json**
|
||||
- Click *Save Model*
|
||||
|
||||
#. Configure playlists
|
||||
|
||||
To be able to play your playlists you must add the name of each playlist to the *playlist_names* slot type.
|
||||
You will need to maintain the list and add additional playlist names as you create them to allow them to
|
||||
be played via the AskNavisonic skill.
|
||||
|
||||
.. image:: resources/create_skill_4.png
|
||||
:width: 800
|
||||
:align: center
|
||||
:alt: Skill Creation Step 4
|
||||
|
||||
- Click *Slot Types*.
|
||||
- Click *playlist_names*.
|
||||
- Add and remove names as required.
|
||||
- Click the *Save Model* button when you are done.
|
||||
|
||||
#. Enable the Audio Player interface
|
||||
|
||||
.. image:: resources/create_skill_5.png
|
||||
:width: 800
|
||||
:align: center
|
||||
:alt: Skill Creation Step 5
|
||||
|
||||
- Click *Interfaces*, enable *Audio Player*, then click *Save Interfaces*
|
||||
|
||||
#. Set the endpoint
|
||||
|
||||
The skill's endpoint is the location of the AskNavidrome web service.
|
||||
|
||||
.. image:: resources/create_skill_6.png
|
||||
:width: 800
|
||||
:align: center
|
||||
:alt: Skill Creation Step 6
|
||||
|
||||
- Click *Endpoint*
|
||||
- Select *HTTPS*
|
||||
- Enter the the URL to the web service in the *Default Region* box.
|
||||
- Select the SSL certificate type. This will depend on your setup, if you are using Let's Encrypt
|
||||
choose *My development endpoints has a certificate from a trusted certificate authority*
|
||||
- Click *Save Endpoints*
|
||||
|
||||
#. Build the skill
|
||||
|
||||
.. image:: resources/create_skill_7.png
|
||||
:width: 800
|
||||
:align: center
|
||||
:alt: Skill Creation Step 7
|
||||
|
||||
- Click *Invocations*, *Skill Invocation Name*.
|
||||
- Click *Save Model*.
|
||||
- Click *Build Model*, the process will take a few minutes.
|
||||
|
||||
#. Add the skill to your Echo devices.
|
||||
|
||||
The skill you just created should now be available as a development skill in your Alexa app, you can add the development skill to your
|
||||
Echo devices.
|
||||
|
||||
.. warning:: It is important that you **do not** publish the skill. If you do anyone that uses the skill will be able to stream your music
|
||||
collection, it may also be possible for credentials to be retrieved.
|
||||
|
||||
|
||||
Deploying the AskNavidrome Web Service
|
||||
--------------------------------------
|
||||
|
||||
The AskNavidrome Web Service is written in Python and can be run directly on a PC with a Python installation, or as a Docker container (recommended).
|
||||
Whichever method you use, the service and your Navidrome installation must be available via HTTPS with a well known certificate. One of the easiest
|
||||
ways to implement this is with a reverse proxy. There are several
|
||||
available for free:
|
||||
|
||||
* `Caddy <https://caddyserver.com/>`_.
|
||||
* `Apache <https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html/>`_.
|
||||
* `Nginx <https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/>`_.
|
||||
|
||||
|
||||
Run on your PC
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Please remember that the web service needs to be publicly accessible, if you are running it directly on your PC this means your PC is publicly
|
||||
accessible.
|
||||
|
||||
#. Install Python 3
|
||||
* `python3.org <https://www.python.org/downloads/>`_
|
||||
#. Install git tools
|
||||
* `git-scm.com <https://git-scm.com/book/en/v2/Getting-Started-Installing-Git>`_
|
||||
#. Create a directory for the web service
|
||||
#. Change to the directory and clone the repository from GitHub
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd directory
|
||||
git clone https://github.com/rosskouk/asknavidrome.git
|
||||
|
||||
|
||||
#. Change directory to the skill folder
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd asknavidrome/skill
|
||||
|
||||
#. Start the skill by setting the required environment variables and executing the application
|
||||
you can find details of what each option does in the *configuration* section.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
NAVI_SKILL_ID=<your-skill-id> \
|
||||
NAVI_SONG_COUNT=50 \
|
||||
NAVI_URL=https://your-navidrome-server.test \
|
||||
NAVI_USER=<username> \
|
||||
NAVI_PASS=<password> \
|
||||
NAVI_PORT=443 \
|
||||
NAVI_API_PATH=/rest \
|
||||
NAVI_API_VER=1.16.1 \
|
||||
NAVI_DEBUG=0 \
|
||||
python3 app.py
|
||||
|
||||
|
||||
Run inside a Docker container
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A Dockerfile has been provided and a prebuilt container is hosted on github.com. You can configure the service by passing environment variables to
|
||||
the *docker run* command.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
docker run -p 5000:5000 \
|
||||
-e NAVI_SKILL_ID=<your-skill-id> \
|
||||
-e NAVI_SONG_COUNT=50 \
|
||||
-e NAVI_URL=https://your-navidrome-server.test \
|
||||
-e NAVI_USER=<username> \
|
||||
-e NAVI_PASS=<password> \
|
||||
-e NAVI_PORT=443 \
|
||||
-e NAVI_API_PATH=/rest \
|
||||
-e NAVI_API_VER=1.16.1 \
|
||||
-e NAVI_DEBUG=0 \
|
||||
ghcr.io/rosskouk/asknavidrome:<tag>
|
||||
|
||||
If you intent to use the container to build a Kubernetes pod, I have created a side car container which can automatically configure and renew
|
||||
TLS certificates with the Kubernetes Nginx Ingress. `More information <https://github.com/rosskouk/docker-image-k8s-letsencrypt>`_.
|
||||
|
||||
|
||||
Configuration
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
The AskNavidrome Web Service reads it's configuration from environment variables and needs the following configuration
|
||||
information to run:
|
||||
|
||||
+----------------------+----------------------------------------------------------------+------------------------------------------------------+
|
||||
| Environment Variable | Description | Example |
|
||||
+======================+================================================================+======================================================+
|
||||
| NAVI_SKILL_ID | The ID of your Alexa skill, this prevents other skills from | amzn1.ask.skill.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
|
||||
| | connecting to the web service. | |
|
||||
+----------------------+----------------------------------------------------------------+------------------------------------------------------+
|
||||
| NAVI_SONG_COUNT | The minimum number of songs to add to a playlist. If playing | 50 |
|
||||
| | random music, music by genre or music by an artist the web | |
|
||||
| | service will ensure the minimum number of tracks added to the | |
|
||||
| | queue is at least this value | |
|
||||
+----------------------+----------------------------------------------------------------+------------------------------------------------------+
|
||||
| NAVI_URL | The URL to the Subsonic API server | ``https://navidrome.example.test`` |
|
||||
+----------------------+----------------------------------------------------------------+------------------------------------------------------+
|
||||
| NAVI_USER | The user name used to connect to the Subsonic API server | bob |
|
||||
+----------------------+----------------------------------------------------------------+------------------------------------------------------+
|
||||
| NAVI_PASS | The password used to connect to the Subsonic API server | ``Sup3rStrongP@ssword`` |
|
||||
+----------------------+----------------------------------------------------------------+------------------------------------------------------+
|
||||
| NAVI_PORT | The port the Subsonic API server is listening on | 443 |
|
||||
+----------------------+----------------------------------------------------------------+------------------------------------------------------+
|
||||
| NAVI_API_PATH | The path to the Subsonic API, this should be /rest if you are | /rest |
|
||||
| | using Navidrome and haven't changed anything | |
|
||||
+----------------------+----------------------------------------------------------------+------------------------------------------------------+
|
||||
| NAVI_API_VER | The version of the Subsonic API in use | 1.16.1 |
|
||||
+----------------------+----------------------------------------------------------------+------------------------------------------------------+
|
||||
| NAVI_DEBUG | Enable debugging, to disable to not set this variable | 1 |
|
||||
+----------------------+----------------------------------------------------------------+------------------------------------------------------+
|
||||
|
||||
|
||||
Troubleshooting
|
||||
***************
|
||||
|
||||
Troubleshooting and debugging Alexa skills can be a little frustrating, here are the best ways I have found to do it.
|
||||
|
||||
#. Understand that the Alexa skill is effectively just a set of buttons.
|
||||
All the skill does is call functions in the web service, it does nothing other than translate what you say to the function name that will perform the task.
|
||||
Very little can go wrong with this, but here is a list of things to check:
|
||||
|
||||
* Does the locale of the skill match the locale on your Echo device? If this is mismatched it looks like nothing happens when you try to invoke the skill.
|
||||
* Is the endpoint set correctly? The endpoint is the URL to the web service, if the skill cannot communicate with the web service check this first.
|
||||
you must ensure that the URL is https and the certificate is compatible with Amazon services.
|
||||
* If an intent does not work, you might need to add an additional phrase to the intent in the developer console. The included phrases work for me, you might
|
||||
want to make some changes though.
|
||||
|
||||
#. Enable debugging and look at the logs generated by the web service.
|
||||
|
||||
#. When debugging is enabled the following web pages are available from the web service
|
||||
|
||||
* url-to-web-service/queue
|
||||
|
||||
* Shows the tracks in the current queue
|
||||
|
||||
* url-to-web-service/history
|
||||
|
||||
* Shows the tracks that have already been played
|
||||
|
||||
* url-to-web-service/buffer
|
||||
|
||||
* Shows the tracks in the buffer. Note that the buffer and queue differ as Amazon will request the next track to be queued before the track playing is
|
||||
finished. The buffer can be thought of as the list of tracks still to be sent to Amazon, where as the queue is the list of tracks still to be played.
|
||||
|
||||
#. Use the test page in the developer console
|
||||
The test page will show you the responses between Amazon and an simulated Echo device, this can help you uncover error messages that are normally hidden.
|
||||
|
||||
.. image:: resources/debugging_1.png
|
||||
:width: 800
|
||||
:align: center
|
||||
:alt: debugging Step 1
|
||||
|
||||
* Click test and make sure you tick **Device Log**
|
||||
* You can type instructions in the box or use the microphone on your device
|
||||
|
||||
.. image:: resources/debugging_2.png
|
||||
:width: 800
|
||||
:align: center
|
||||
:alt: debugging Step 2
|
||||
|
||||
* After you have entered a command you will get the Alexa response back, scroll down to the **Device Log** section and click through the entries
|
||||
the entries will contain any errors that were thrown.
|
||||
|
||||
|
||||
Code Documentation
|
||||
******************
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Contents:
|
||||
|
||||
AskNavidrome main
|
||||
-----------------
|
||||
.. automodule:: app
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
AskNavidrome controller
|
||||
-----------------------
|
||||
.. automodule:: asknavidrome.controller
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
AskNavidrome media queue
|
||||
------------------------
|
||||
.. autoclass:: asknavidrome.media_queue.MediaQueue
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
AskNavidrome subsonic API
|
||||
-------------------------
|
||||
.. autoclass:: asknavidrome.subsonic_api.SubsonicConnection
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
||||
AskNavidrome track
|
||||
------------------
|
||||
.. autoclass:: asknavidrome.track.Track
|
||||
:members:
|
||||
:undoc-members:
|
||||
35
sphinx/make.bat
Normal file
@@ -0,0 +1,35 @@
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.https://www.sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
|
||||
|
||||
:end
|
||||
popd
|
||||
1
sphinx/resources/AskNavidrome_Diagram.drawio
Normal file
@@ -0,0 +1 @@
|
||||
<mxfile host="Electron" modified="2022-08-27T11:41:46.773Z" agent="5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/20.2.3 Chrome/102.0.5005.167 Electron/19.0.11 Safari/537.36" etag="W0nzd7d5WTMNxKT7Yrkn" version="20.2.3" type="device"><diagram id="91f34WGdwANRlc_FxEr9" name="Page-1">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</diagram></mxfile>
|
||||
BIN
sphinx/resources/AskNavidrome_Diagram.png
Normal file
|
After Width: | Height: | Size: 114 KiB |
BIN
sphinx/resources/create_skill_1.png
Normal file
|
After Width: | Height: | Size: 76 KiB |
BIN
sphinx/resources/create_skill_2.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
sphinx/resources/create_skill_3.png
Normal file
|
After Width: | Height: | Size: 85 KiB |
BIN
sphinx/resources/create_skill_4.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
sphinx/resources/create_skill_5.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
sphinx/resources/create_skill_6.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
sphinx/resources/create_skill_7.png
Normal file
|
After Width: | Height: | Size: 49 KiB |
BIN
sphinx/resources/debugging_1.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
sphinx/resources/debugging_2.png
Normal file
|
After Width: | Height: | Size: 115 KiB |