Skip to main content
`Ctrl`+`K`

# 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, 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

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. 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

You can set up dynamic DNS to make your media server accessible for free with 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.

An Amazon Echo Device

You need something to listen to your music on!

## About the AskNavidrome Skill

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
--- | --- | ---
`NaviSonicPlayMusicByArtist` | Play music by a specific artist | Play Where is my Mind by The Pixies
`NaviSonicPlayAlbumByArtist` | Play a specific album by a specific artist | Play The Blue Album by The Beatles
`NaviSonicPlaySongByArtist` | Play a specific song by a specific artist | Play the song Help by The Beatles
`NaviSonicPlayPlaylist` | Play a playlist | Play the playlist work music
`NaviSonicPlayMusicByGenre` | Play music with a specific genre | Play jazz music
`NaviSonicPlayMusicRandom` | Play a random mix of songs | Play random songs
`NaviSonicPlayFavouriteSongs` | Play your starred / favourite songs | Play my favourite songs
`NaviSonicRandomiseQueue` | Shuffle / randomise the current play queue | Shuffle the queue
`NaviSonicSongDetails` | Give details on the playing track | What is playing
`NaviSonicStarSong` | Star / favourite a song | Star this song
`NaviSonicUnstarSong` | Unstar / unfavourite a song | Unstar this song

The following control intents are also supported:

- `Next / Skip`

- `Previous / Back`

- `Pause`

- `Resume`

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 in how the skill is invoked.

The following voice commands should be successful (thanks to Raul824)

- Alexa ask Navisonic What is Playing?

- Alexa ask Navisonic to star this song.

- Alexa ask Navisonic to unstar this song.

- Alexa ask Navisonic to play rock music

- Alexa ask Navisonic to play playlist “Playlist Name”

If you have any problems with these, you can open the skill manually with Alexa, open Navisonic. Similarly this can be done when a track is playing, 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?

## Installation and Setup

### Creating the AskNavidrome Alexa Skill

1. 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.

2. Click Create Skill

3. Configure the skill:

   - 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

4. Choose the template

   - Choose Start from Scratch

   - Click Continue with template and wait while the skill is created.

5. Upload the intents

   - 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

6. 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.

   - Click Slot Types.

   - Click playlist_names.

   - Add and remove names as required.

   - Click the Save Model button when you are done.

7. Enable the Audio Player interface

   - Click Interfaces, enable Audio Player, then click Save Interfaces

8. Set the endpoint

   The skill’s endpoint is the location of the AskNavidrome web service.

   - 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

   Tip

   There are three options to pick from when setting the SSL certificate type in the Amazon Developer portal. To confirm that you are using the correct option browse to the URL of your AskNavidrome skill, you will see a message similar to 405 Method Not Allowed, this is normal. View the certificate in use by the skill in your browser and look at the Common Name (CN) field. If this contains a * for example *.ngrok-free.app then you are using a wildcard certificate. If the common name does not contain a * then you have a regular certificate.

   - My development endpoint is a sub-domain of a domain that has a wildcard certificate from a certificate authority

       - Use this if your skill uses a wildcard certificate with a *

   - My development endpoint has a certificate from a trusted certificate authority

       - Use this if you have a regular certificate

   - I will upload a self-signed certificate in X509 format

       - Do not select this option unless you know what you are doing.

9. Build the skill

   - Click Invocations, Skill Invocation Name.

   - Click Save Model.

   - Click Build Model, the process will take a few minutes.

10. 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.

- Apache.

- Nginx.

#### 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.

1. Install Python 3

     - python3.org

2. Install git tools

     - git-scm.com

3. Create a directory for the web service

4. Change to the directory and clone the repository from GitHub

       cd directory
       git clone https://github.com/rosskouk/asknavidrome.git

5. Change directory to the skill folder

       cd asknavidrome/skill

6. 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.

       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. Please note that the prebuilt container was created on an amd64 platform. If you require a different architecture such as arm for a Raspberry Pi, you will need to build a new image using the Dockerfile provided with the repository.

You can configure the service by passing environment variables to the docker run command.

    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.

#### 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 connecting to the web service. | amzn1.ask.skill.xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
NAVI_SONG_COUNT | The minimum number of songs to add to a playlist. If playing 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 | 50
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 using Navidrome and haven’t changed anything | /rest
NAVI_API_VER | The version of the Subsonic API in use | 1.16.1
NAVI_DEBUG | Enable debugging, by setting this variable to 1, or 3. | 1

## Tips & Tricks

Here are a list of tips and ideas for using the skill

### Playing Music on Multiple Devices

Note

Thanks to @Rusty77

You can play music on multiple devices, by following these steps:

1. Add all devices you wish to play music on simultaneously to a group in your Alexa app

2. Start playback by asking Alexa to play something on the group

3. Then ask AskNavidrome to play something. It should be played on all devices in the group.

## Troubleshooting

### General

Troubleshooting and debugging Alexa skills can be a little frustrating, here are the best ways I have found to do it.

1. 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.

2. Enable debugging and look at the logs generated by the web service.

3. When level 3 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.

4. 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.

   - Click test and make sure you tick Device Log

   - You can type instructions in the box or use the microphone on your device

   - 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.

### Debug Options

You can enable the following debug options by setting the NAVI_DEBUG environment variable.

- 0 = Logging set to WARNING and higher.

- 1 = Logging set to INFO and higher.

- 2 = Logging set to DEBUG and higher and request / response interceptors are enabled.

- 3 = All features of level 2 and the web ui. Note the UI will be publicly available while this is enabled.

## Known Issues

### The skill appears to work but no music is played. Errors similar to below appear in the web service log

>     2022-11-19 13:16:45,478 - root - DEBUG - In PlaybackFailedHandler
>     2022-11-19 13:16:45,479 - root - ERROR - Playback Failed: {'message': 'Device playback error', 'object_type': 'MEDIA_ERROR_UNKNOWN'}
>     2022-11-19 13:16:45,480 - werkzeug - INFO - 10.44.17.62 - - [19/Nov/2022 13:16:45] "POST / HTTP/1.1" 200 -
>     2022-11-19 13:16:48,599 - root - DEBUG - In PlaybackFailedHandler
>     2022-11-19 13:16:48,600 - root - ERROR - Playback Failed: {'message': 'Device playback error','object_type': 'MEDIA_ERROR_INTERNAL_DEVICE_ERROR'}

> - I have not found a reason as to why this happens from time to time, however it can be resolved by doing a hard reboot of your Echo device. Disconnect the power for a minute and plug it back in then try again and music should play

### The following error is displayed when you try to run the Docker container

>     exec /opt/env/bin/python3: exec format error

> - You are using the prebuilt container on a non amd64 based system. You will need to build your own Docker image using the Dockerfile included with the repository.

### You are having trouble connecting to the skill and use CloudFlare

> Note

> Thanks to @dwebb8272 and @jame25

> Several users have had difficulty connecting to the skill when hosted in or when using CloudFlare for DNS. A user has reported that CloudFlare have a default Web Application Firewall (WAF) which block requests made by Python URLLib, this results in you not being able to connect and is quite difficult to debug.

> The following screenshots show an example of how the user was able to overcome the issue.

> Once you have the rule in place disable proxying for your AskNavidrome web service domain in CloudFlare by navigating to DNS -> Records and setting it to DNS Only.

## Code Documentation

### AskNavidrome main

Classes:

`CheckAudioInterfaceHandler`() | Check if device supports audio play.
`GeneralExceptionHandler`() | Handle general exceptions
`HelpHandler`() | Handle HelpIntent
`LaunchRequestHandler`() | Handle LaunchRequest and NavigateHomeIntent
`LoggingRequestInterceptor`() | Intercept all requests
`LoggingResponseInterceptor`() | Intercept all responses
`NaviSonicPlayAlbumByArtist`() | Handle NaviSonicPlayAlbumByArtist
`NaviSonicPlayFavouriteSongs`() | Handle the NaviSonicPlayFavouriteSongs intent
`NaviSonicPlayMusicByArtist`() | Handle NaviSonicPlayMusicByArtist
`NaviSonicPlayMusicByGenre`() | Play songs from the given genre
`NaviSonicPlayMusicRandom`() | Handle the NaviSonicPlayMusicRandom intent
`NaviSonicPlayPlaylist`() | Handle NaviSonicPlayPlaylist
`NaviSonicPlaySongByArtist`() | Handle the NaviSonicPlaySongByArtist intent
`NaviSonicRandomiseQueue`() | Handle NaviSonicRandomiseQueue Intent
`NaviSonicSongDetails`() | Handle NaviSonicSongDetails Intent
`NaviSonicStarSong`() | Handle NaviSonicStarSong Intent
`NaviSonicUnstarSong`() | Handle NaviSonicUnstarSong Intent
`NextPlaybackHandler`() | Handle NextIntent
`PausePlaybackHandler`() | Handler for stopping audio.
`PlaybackFailedEventHandler`() | AudioPlayer.PlaybackFailed Directive received.
`PlaybackFinishedHandler`() | AudioPlayer.PlaybackFinished Directive received.
`PlaybackNearlyFinishedHandler`() | AudioPlayer.PlaybackNearlyFinished Directive received.
`PlaybackStartedHandler`() | AudioPlayer.PlaybackStarted Directive received.
`PlaybackStoppedHandler`() | AudioPlayer.PlaybackStopped Directive received.
`PreviousPlaybackHandler`() | Handle PreviousIntent
`ResumePlaybackHandler`() | Handler for resuming audio on different events.
`SkillEventHandler`() | Close session for skill events or when session ends.
`SystemExceptionHandler`() | Handle System.ExceptionEncountered

Functions:

`queue_worker_thread`(connection, play_queue, ...) | Media queue worker
`sanitise_speech_output`(speech_string) | Sanitise speech output inline with the SSML standard

class app.CheckAudioInterfaceHandler

  Check if device supports audio play.

  This can be used as the first handler to be checked, before invoking other handlers, thus making the skill respond to unsupported devices without doing much processing.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.GeneralExceptionHandler

  Handle general exceptions

  Handles exceptions and prints error information in the log

  Methods:

  `can_handle`(handler_input, exception) | Checks if the handler can support the exception raised during dispatch.
  `handle`(handler_input, exception) | Process the handler input and exception.

  can_handle(handler_input: HandlerInput, exception: Exception) → bool

    Checks if the handler can support the exception raised during dispatch.

    Parameters:

      - handler_input (HandlerInput) – Handler Input instance.

      - exception (Exception) – Exception raised during dispatch.

    Returns:

      Boolean whether handler can handle exception or not.

    Return type:

      bool

  handle(handler_input: HandlerInput, exception: Exception) → Response

    Process the handler input and exception.

    Parameters:

      - handler_input (HandlerInput) – Handler Input instance.

      - exception (Exception) – Exception raised during dispatch.

    Returns:

      Optional response object to serve as dispatch return.

    Return type:

      Union[None, Response]

class app.HelpHandler

  Handle HelpIntent

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.LaunchRequestHandler

  Handle LaunchRequest and NavigateHomeIntent

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.LoggingRequestInterceptor

  Intercept all requests

  Intercepts all requests sent to the skill and prints them in the log

  Methods:

  `process`(handler_input) | Process the input before the Handler is run.

  process(handler_input: HandlerInput)

    Process the input before the Handler is run.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance.

    Return type:

      None

class app.LoggingResponseInterceptor

  Intercept all responses

  Intercepts all responses sent from the skill and prints them in the log

  Methods:

  `process`(handler_input, response) | Process the input and the response after the Handler is run.

  process(handler_input: HandlerInput, response: Response)

    Process the input and the response after the Handler is run.

    Parameters:

      - handler_input (HandlerInput) – Handler Input instance.

      - response (Union[None, `ask_sdk_model.response.Response`]) – Execution result of the Handler on handler input.

    Return type:

      None

class app.NaviSonicPlayAlbumByArtist

  Handle NaviSonicPlayAlbumByArtist

  Play a given album by a given artist

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NaviSonicPlayFavouriteSongs

  Handle the NaviSonicPlayFavouriteSongs intent

  Play all starred / liked songs, songs are automatically shuffled.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NaviSonicPlayMusicByArtist

  Handle NaviSonicPlayMusicByArtist

  Play a selection of songs for the given artist

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NaviSonicPlayMusicByGenre

  Play songs from the given genre

  50 tracks from the given genre are shuffled and played

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NaviSonicPlayMusicRandom

  Handle the NaviSonicPlayMusicRandom intent

  Play a random selection of music.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NaviSonicPlayPlaylist

  Handle NaviSonicPlayPlaylist

  Play the given playlist

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NaviSonicPlaySongByArtist

  Handle the NaviSonicPlaySongByArtist intent

  Play the given song by the given artist if it exists in the collection.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NaviSonicRandomiseQueue

  Handle NaviSonicRandomiseQueue Intent

  Shuffle the current play queue

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NaviSonicSongDetails

  Handle NaviSonicSongDetails Intent

  Returns information on the track that is currently playing

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NaviSonicStarSong

  Handle NaviSonicStarSong Intent

  Star / favourite the current song

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NaviSonicUnstarSong

  Handle NaviSonicUnstarSong Intent

  Star / favourite the current song

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.NextPlaybackHandler

  Handle NextIntent

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.PausePlaybackHandler

  Handler for stopping audio.

  Handles Stop, Cancel and Pause Intents and PauseCommandIssued event.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.PlaybackFailedEventHandler

  AudioPlayer.PlaybackFailed Directive received.

  Logging the error and restarting playing with no output speech.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.PlaybackFinishedHandler

  AudioPlayer.PlaybackFinished Directive received.

  Confirming that the requested audio file completed playing. Do not send any specific response.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.PlaybackNearlyFinishedHandler

  AudioPlayer.PlaybackNearlyFinished Directive received.

  Replacing queue with the URL again. This should not happen on live streams.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.PlaybackStartedHandler

  AudioPlayer.PlaybackStarted Directive received.

  Confirming that the requested audio file began playing. Do not send any specific response.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.PlaybackStoppedHandler

  AudioPlayer.PlaybackStopped Directive received.

  Confirming that the requested audio file stopped playing. Do not send any specific response.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.PreviousPlaybackHandler

  Handle PreviousIntent

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.ResumePlaybackHandler

  Handler for resuming audio on different events.

  Handles PlayAudio Intent, Resume Intent.

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.SkillEventHandler

  Close session for skill events or when session ends.

  Handler to handle session end or skill events (SkillEnabled, SkillDisabled etc.)

  Methods:

  `can_handle`(handler_input) | Returns true if Request Handler can handle the Request inside Handler Input.
  `handle`(handler_input) | Handles the Request inside handler input and provides a Response for dispatcher to return.

  can_handle(handler_input: HandlerInput) → bool

    Returns true if Request Handler can handle the Request inside Handler Input.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Boolean value that tells the dispatcher if the current request can be handled by this handler.

    Return type:

      bool

  handle(handler_input: HandlerInput) → Response

    Handles the Request inside handler input and provides a Response for dispatcher to return.

    Parameters:

      handler_input (HandlerInput) – Handler Input instance with Request Envelope containing Request.

    Returns:

      Response for the dispatcher to return or None

    Return type:

      Union[Response, None]

class app.SystemExceptionHandler

  Handle System.ExceptionEncountered

  Handles exceptions and prints error information in the log

  Methods:

  `can_handle`(handler_input, exception) | Checks if the handler can support the exception raised during dispatch.
  `handle`(handler_input, exception) | Process the handler input and exception.

  can_handle(handler_input: HandlerInput, exception: Exception) → bool

    Checks if the handler can support the exception raised during dispatch.

    Parameters:

      - handler_input (HandlerInput) – Handler Input instance.

      - exception (Exception) – Exception raised during dispatch.

    Returns:

      Boolean whether handler can handle exception or not.

    Return type:

      bool

  handle(handler_input: HandlerInput, exception: Exception) → Response

    Process the handler input and exception.

    Parameters:

      - handler_input (HandlerInput) – Handler Input instance.

      - exception (Exception) – Exception raised during dispatch.

    Returns:

      Optional response object to serve as dispatch return.

    Return type:

      Union[None, Response]

app.queue_worker_thread(connection: object, play_queue: object, song_id_list: list) → None

  Media queue worker

  This function allows media queues to be populated in the background enabling multithreading and increasing skill response times.

  Parameters:

    - connection (object) – A SubSonic API connection object

    - play_queue (object) – A MediaQueue object

    - song_id_list (list) – A list containing Navidrome song IDs

app.sanitise_speech_output(speech_string: str) → str

  Sanitise speech output inline with the SSML standard

  Speech Synthesis Markup Language (SSML) has certain ASCII characters that are reserved. This function replaces them with alternatives.

  Parameters:

    speech_string (str) – The string to process

  Returns:

    The processed SSML compliant string

  Return type:

    str

### AskNavidrome controller

Functions:

`add_screen_background`(card_data) | Add background to card.
`enqueue_songs`(api, queue, song_id_list) | Enqueue songs
`start_playback`(mode, text, card_data, ...) | Function to play audio.
`stop`(handler_input) | Stop playback

asknavidrome.controller.add_screen_background(card_data: dict) → AudioItemMetadata | None

  Add background to card.

  Cards are viewable on devices with screens and in the Alexa app.

  Parameters:

    card_data (dict) – Dictionary containing card data

  Returns:

    An Amazon AudioItemMetadata object or None if card data is not present

  Return type:

    AudioItemMetadata | None

asknavidrome.controller.enqueue_songs(api: SubsonicConnection, queue: MediaQueue, song_id_list: list) → None

  Enqueue songs

  Add Track objects to the queue deque

  Parameters:

    - api (SubsonicConnection) – A SubsonicConnection object to allow access to the Navidrome API

    - queue (MediaQueue) – A MediaQueue object

    - song_id_list (list) – A list of song IDs to enqueue

  Returns:

    None

asknavidrome.controller.start_playback(mode: str, text: str, card_data: dict, track_details: Track, handler_input: HandlerInput) → Response

  Function to play audio.

  Begin playing audio when:

  > - Play Audio Intent is invoked.

  > - Resuming audio when stopped / paused.

  > - Next / Previous commands issues.

  Note

  - https://developer.amazon.com/docs/custom-skills/audioplayer-interface-reference.html#play

      - REPLACE_ALL: Immediately begin playback of the specified stream, and replace current and enqueued streams.

  Parameters:

    - mode (str) – play | continue - Play immediately or enqueue a track

    - text (str) – Text which should be spoken before playback starts

    - card_data (dict) – Data to display on a card

    - track_details (Track) – A Track object containing details of the track to use

    - handler_input (HandlerInput) – The Amazon Alexa HandlerInput object

  Returns:

    Amazon Alexa Response class

  Return type:

    Response

asknavidrome.controller.stop(handler_input: HandlerInput) → Response

  Stop playback

  Parameters:

    handler_input (HandlerInput) – The Amazon Alexa HandlerInput object

  Returns:

    Amazon Alexa Response class

  Return type:

    Response

### AskNavidrome media queue

class asknavidrome.media_queue.MediaQueue

  The MediaQueue class

  This class provides a queue based on a Python deque. This is used to store the tracks in the current play queue

  Returns:

    None

  Methods:

  `add_track`(track) | Add tracks to the queue
  `clear`() | Clear queue, history and buffer deques
  `enqueue_next_track`() | Get the next buffered track
  `get_buffer`() | Get the buffer
  `get_current_queue`() | Get the current queue
  `get_current_track`() | Method to return current_track attribute
  `get_history`() | Get history
  `get_history_count`() | Get the number of tracks in the history deque
  `get_next_track`() | Get the next track
  `get_previous_track`() | Get the previous track
  `get_queue_count`() | Get the number of tracks in the queue
  `set_current_track_offset`(offset) | Method to set the offset of the current track in milliseconds
  `shuffle`() | Shuffle the queue
  `sync`() | Synchronise the buffer with the queue

  Attributes:

  `buffer` | Deque to contain the list of tracks to be enqueued
  `current_track` | Property to hold the current track object
  `history` | Deque to hold tracks that have already been played
  `logger` | Logger
  `queue` | Deque containing tracks still to be played

  add_track(track: Track ) → None

    Add tracks to the queue

    Parameters:

      track (Track) – A Track object containing details of the track to be played

    Returns:

      None

  clear() → None

    Clear queue, history and buffer deques

    Returns:

      None

  enqueue_next_track() → Track

    Get the next buffered track

    Get the next track from the buffer without updating the current track attribute. This allows Amazon to send the PlaybackNearlyFinished request early to queue the next track while maintaining the playlist

    Returns:

      The next track to be played

    Return type:

      Track

  get_buffer() → deque

    Get the buffer

    Returns a deque containing the current buffer

    Returns:

      The current buffer

    Return type:

      deque

  get_current_queue() → deque

    Get the current queue

    Returns a deque containing the current queue of music to be played

    Returns:

      The current queue

    Return type:

      deque

  get_current_track() → Track

    Method to return current_track attribute

    Added to allow access to the current_track object while using BaseManager for multi threading, as BaseManager does not allow access to class attributes / properties

    Returns:

      A Track object representing the current playing audio track

    Return type:

      Track

  get_history() → deque

    Get history

    Returns a deque of tracks that have already been played

    Returns:

      A deque container tracks that have already been played

    Return type:

      deque

  get_history_count() → int

    Get the number of tracks in the history deque

    Returns:

      The number of tracks in the history deque

    Return type:

      int

  get_next_track() → Track

    Get the next track

    Get the next track from self.queue and add it to the history deque

    Returns:

      The next track object

    Return type:

      Track

  get_previous_track() → Track

    Get the previous track

    Get the last track added to the history deque and add it to the front of the play queue

    Returns:

      The previous track object

    Return type:

      Track

  get_queue_count() → int

    Get the number of tracks in the queue

    Returns:

      The number of tracks in the queue deque

    Return type:

      int

  set_current_track_offset(offset: int) → None

    Method to set the offset of the current track in milliseconds

    Set the offset for the current track in milliseconds. This is used when resuming a paused track to ensure the track isn’t played from the beginning again.

    Parameters:

      offset (int) – The track offset in milliseconds

  shuffle() → None

    Shuffle the queue

    Shuffles the queue and resets the previous track IDs required for the ENQUEUE PlayBehaviour

    Returns:

      None

  sync() → None

    Synchronise the buffer with the queue

    Overwrite the buffer with the current queue. This is useful when pausing or stopping to ensure the resulting PlaybackNearlyFinished request gets the correct. In practice this will have already queued and there for missing from the current buffer

    Returns:

      None

  buffer: deque

    Deque to contain the list of tracks to be enqueued

    This deque is created from self.queue when actions such as next or previous are performed. This is because Amazon can send the PlaybackNearlyFinished request early. Without self.buffer, this would change self.current_track causing us to lose the real position of the queue.

  current_track: Track

    Property to hold the current track object

  history: deque

    Deque to hold tracks that have already been played

  logger

    Logger

  queue: deque

    Deque containing tracks still to be played

### AskNavidrome subsonic API

class asknavidrome.subsonic_api.SubsonicConnection(server_url: str, user: str, passwd: str, port: int, api_location: str, api_version: str)

  Class with methods to interact with Subsonic API compatible media servers

  Parameters:

    - server_url (str) – The URL of the Subsonic API compatible media server

    - user (str) – Username to authenticate against the API

    - passwd (str) – Password to authenticate against the API

    - port (int) – Port the Subsonic compatible server is listening on

    - api_location (str) – Path to the API, this is appended to server_url

    - api_version (str) – The version of the Subsonic API that is in use

  Returns:

    None

  Methods:

  `albums_by_artist`(id) | Get the albums for a given artist
  `build_random_song_list`(count) | Build a shuffled list of random songs
  `build_song_list_from_albums`(albums, length) | Get a list of songs from given albums
  `build_song_list_from_favourites`() | Build a shuffled list favourite songs
  `build_song_list_from_genre`(genre, count) | Build a shuffled list songs of songs from the given genre.
  `build_song_list_from_playlist`(id) | Build a list of songs from a given playlist
  `get_song_details`(id) | Get details about a given song ID
  `get_song_uri`(id) | Create a URI for a given song
  `ping`() | Ping a Subsonic API server
  `scrobble`(track_id, time) | Scrobble the given track
  `search_album`(term) | Search the media server for the given album
  `search_artist`(term) | Search the media server for the given artist
  `search_playlist`(term) | Search the media server for the given playlist
  `search_song`(term) | Search the media server for the given song
  `star_entry`(id, mode) | Add a star to the given entity
  `unstar_entry`(id, mode) | Remove a star from the given entity

  albums_by_artist(id: str) → list[dict]

    Get the albums for a given artist

    Parameters:

      id (str) – The artist ID

    Returns:

      A list of albums

    Return type:

      list of dict

  build_random_song_list(count: int) → list | None

    Build a shuffled list of random songs

    Parameters:

      count (int) – The number of songs to return

    Returns:

      A list of song IDs or None if no tracks are found.

    Return type:

      list | None

  build_song_list_from_albums(albums: list[dict], length: int) → list

    Get a list of songs from given albums

    Build a list of songs from the given albums, keep adding tracks until song_count is greater than of equal to length

    Parameters:

      - albums (list[dict]) – A list of dictionaries containing album information

      - length (int) – The minimum number of songs that should be returned, if -1 there is no limit

    Returns:

      A list of song IDs

    Return type:

      list

  build_song_list_from_favourites() → list | None

    Build a shuffled list favourite songs

    Returns:

      A list of song IDs or None if no favourite tracks are found.

    Return type:

      list | None

  build_song_list_from_genre(genre: str, count: int) → list | None

    Build a shuffled list songs of songs from the given genre.

    Parameters:

      - genre (str) – The genre, acceptable values are with the getGenres Subsonic API call.

      - count (int) – The number of songs to return

    Returns:

      A list of song IDs or None if no tracks are found.

    Return type:

      list | None

  build_song_list_from_playlist(id: str) → list

    Build a list of songs from a given playlist

    Parameters:

      id (str) – The playlist ID

    Returns:

      A list of song IDs

    Return type:

      list

  get_song_details(id: str) → dict

    Get details about a given song ID

    Parameters:

      id (str) – A song ID

    Returns:

      A dictionary of details about the given song.

    Return type:

      dict

  get_song_uri(id: str) → str

    Create a URI for a given song

    Creates a URI for the song represented by the given ID. Authentication details are embedded in the URI

    Parameters:

      id (str) – A song ID

    Returns:

      A properly formatted URI

    Return type:

      str

  ping() → bool

    Ping a Subsonic API server

    Verify the connection to a Subsonic compatible API server is working. Enhanced logging has been added to examine the HTTP response returned from the server to assist with troubleshooting connection issues.

    Returns:

      True if the connection works, False if it does not

    Return type:

      bool

  scrobble(track_id: str, time: int) → None

    Scrobble the given track

    Parameters:

      - track_id (str) – The ID of the track to scrobble

      - time (int) – UNIX timestamp of track play time

    Returns:

      None

  search_album(term: str) → dict | None

    Search the media server for the given album

    Parameters:

      term (str) – The name of the album

    Returns:

      A dictionary of albums or None if no results are found

    Return type:

      dict | None

  search_artist(term: str) → dict | None

    Search the media server for the given artist

    Parameters:

      term (str) – The name of the artist

    Returns:

      A dictionary of artists or None if no results are found

    Return type:

      dict | None

  search_playlist(term: str) → str | None

    Search the media server for the given playlist

    Parameters:

      term (str) – The name of the playlist

    Returns:

      The ID of the playlist or None if the playlist is not found

    Return type:

      str | None

  search_song(term: str) → dict | None

    Search the media server for the given song

    Parameters:

      term (str) – The name of the song

    Returns:

      A dictionary of songs or None if no results are found

    Return type:

      dict | None

  star_entry(id: str, mode: str) → None

    Add a star to the given entity

    Parameters:

      - id (str) – The Navidrome ID of the entity.

      - mode (str) – The type of entity, must be song, artist or album

    Returns:

      None.

  unstar_entry(id: str, mode: str) → None

    Remove a star from the given entity

    Parameters:

      - id (str) – The Navidrome ID of the entity.

      - mode (str) – The type of entity, must be song, artist or album

    Returns:

      None.

### AskNavidrome track

class asknavidrome.track.Track(id: str = '', title: str = '', artist: str = '', artist_id: str = '', album: str = '', album_id: str = '', track_no: int = 0, year: int = 0, genre: str = '', duration: int = 0, bitrate: int = 0, uri: str = '', offset: int = 0, previous_id: str = '')

  An object that represents an audio track

  Parameters:

    - id (str) – The song ID. Defaults to ‘’

    - title (str) – The song title. Defaults to ‘’

    - artist (str) – The artist name. Defaults to ‘’

    - artist_id (str) – The artist ID. Defaults to ‘’

    - album (str) – The album name. Defaults to ‘’

    - album_id (str) – The album ID. Defaults to ‘’

    - track_no (int) – The track number. Defaults to 0

    - year (int) – The release year. Defaults to 0

    - genre (str) – The music genre. Defaults to ‘’

    - duration (int) – The length of the track in seconds. Defaults to 0

    - bitrate (int) – The bit rate in kbps. Defaults to 0

    - uri (str) – The song’s URI for streaming. Defaults to ‘’

    - offset (int) – The position in the track to start playback in milliseconds. Defaults to 0

    - previous_id (str) – The ID of the previous song in the playlist. Defaults to ‘’

  Returns:

    None