Compare commits

..

7 Commits

Author SHA1 Message Date
Ross Stewart e0b6be24c1 Bump version number
Documentation Generator / Build Sphinx documentation (push) Has been cancelled
2026-03-06 15:49:51 +00:00
Ross Stewart cd3575d514 Documentation update 2026-03-06 15:15:09 +00:00
rosskouk 77e8546baa Merge pull request #73 from rosskouk/feature-enhanced-debugging
Added enhanced debugging to ping() method
2026-03-06 15:14:33 +00:00
rosskouk 122d328de4 Merge pull request #66 from f-longobardi/main
Enable display of song metadata
Thanks to @f-longobardi
2026-03-06 15:13:01 +00:00
Ross Stewart f3846a2311 Added enhanced debugging to ping() method 2026-03-06 14:27:29 +00:00
Francesco 0cf1c52743 also for continued play 2025-10-25 16:31:15 +02:00
Francesco fcce6a8d11 add song metadata, respond to button requests in media player 2025-10-25 14:56:38 +02:00
7 changed files with 137 additions and 211 deletions
+20 -9
View File
@@ -1,23 +1,34 @@
FROM alpine:3.22.1 AS build
LABEL maintainer="Ross Stewart <rosskouk@gmail.com>"
LABEL org.opencontainers.image.source=https://github.com/rosskouk/asknavidrome
RUN apk add python3 py3-pip git build-base python3-dev libffi-dev openssl-dev
WORKDIR /opt
RUN pwd
RUN python3 -m venv env
RUN ls -la
RUN git clone https://g.nunks.org/nunks/asknavidrome-cafofo.git
RUN ls -la asknavidrome-cafofo
WORKDIR /opt/asknavidrome-cafofo
RUN pwd
RUN ls -la
RUN git clone https://github.com/rosskouk/asknavidrome.git
WORKDIR /opt/asknavidrome
RUN source ../env/bin/activate && pip --no-cache-dir install wheel && pip --no-cache-dir install -r skill/requirements-docker.txt
FROM alpine:3.22.1
LABEL maintainer="Ross Stewart <rosskouk@gmail.com>"
LABEL org.opencontainers.image.source=https://github.com/rosskouk/asknavidrome
RUN apk add python3
COPY --from=build /opt/env /opt/env
COPY --from=build /opt/asknavidrome-cafofo/skill /opt/asknavidrome/
COPY --from=build /opt/asknavidrome/skill /opt/asknavidrome/
WORKDIR /opt/asknavidrome
# Activate Python Virtual Environment
ENV PATH="/opt/env/bin:$PATH"
EXPOSE 5000
ENTRYPOINT ["python3", "app.py"]
ENTRYPOINT ["python3", "app.py"]
+50 -58
View File
@@ -1,7 +1,7 @@
{
"interactionModel": {
"languageModel": {
"invocationName": "cafofo music",
"invocationName": "navisonic",
"intents": [
{
"name": "AMAZON.CancelIntent",
@@ -40,8 +40,8 @@
}
],
"samples": [
"tocar músicas da {artist}",
"tocar músicas do {artist}"
"play songs by {artist}",
"play music by {artist}"
]
},
{
@@ -65,20 +65,8 @@
}
],
"samples": [
"Tocar o album {album}",
"Tocar o album {album} do {artist}",
"Tocar o album {album} da {artist}",
"Tocar o disco {album}",
"Tocar o disco {album} do {artist}",
"Tocar o disco {album} da {artist}"
]
},
{
"name": "NaviSonicPlayMusicByCurrentAlbum",
"slots": [],
"samples": [
"Tocar mais músicas desse album",
"Tocar mais músicas desse disco"
"Play the album {album}",
"Play the album {album} by {artist}"
]
},
{
@@ -90,42 +78,49 @@
}
],
"samples": [
"Tocar a playlist {playlist}"
"Play the {playlist} playlist",
"Start the {playlist} playlist"
]
},
{
"name": "NaviSonicSongDetails",
"slots": [],
"samples": [
"O que está tocando",
"Quem está tocando",
"Quem está cantando",
"Qual o album dessa música",
"Que banda é essa",
"Que musica é essa",
"Que banda é essa"
"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": [
"Adicionar música aos favoritos",
"Adicionar aos favoritos",
"Favoritar essa musica",
"Lembrar dessa música",
"Eu gosto dessa música"
"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": [
"Tirar a música dos favoritos",
"Tirar dos favoritos",
"Desfavoritar a música",
"Esquecer essa música",
"Eu não gosto dessa música"
"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"
]
},
{
@@ -141,27 +136,21 @@
}
],
"samples": [
"Tocar a música {song} da banda {artist}",
"Tocar {song} da banda {artist}",
"Tocar {song} da {artist}"
]
},
{
"name": "NaviSonicPlayMusicByCurrentArtist",
"slots": [],
"samples": [
"Tocar mais músicas desse artista",
"Tocar mais músicas desse grupo",
"Tocar mais músicas dessa banda"
"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": [
"Tocar favoritos",
"Tocar meus favoritos",
"Tocar minhas músicas favoritas"
"Play my starred tracks",
"Play starred tracks",
"Play starred songs",
"Play my starred songs",
"Play my favourite songs"
]
},
{
@@ -173,26 +162,29 @@
}
],
"samples": [
"Tocar {genre}"
"Play {genre} songs",
"Play {genre} music"
]
},
{
"name": "NaviSonicPlayMusicRandom",
"slots": [],
"samples": [
"Tocar seleção aleatória",
"Tocar qualquer coisa",
"Tocar mix",
"Tocar músicas aleatórias"
"Play a selection of music",
"Play a mix of tracks",
"Play a mix of songs",
"Play random music",
"Play random songs"
]
},
{
"name": "NaviSonicRandomiseQueue",
"slots": [],
"samples": [
"randomise the queue",
"randomise",
"shuffle",
"shuffle na lista",
"mistura tudo"
"shuffle the queue"
]
}
],
@@ -220,4 +212,4 @@
]
}
}
}
}
+3 -1
View File
@@ -3491,7 +3491,9 @@ embedded in the URI</p>
<span class="sig-name descname"><span class="pre">ping</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">&#x2192;</span> <span class="sig-return-typehint"><span class="pre">bool</span></span></span><a class="headerlink" href="#asknavidrome.subsonic_api.SubsonicConnection.ping" title="Link to this definition">#</a></dt>
<dd><p>Ping a Subsonic API server</p>
<p>Verify the connection to a Subsonic compatible API server
is working</p>
is working. Enhanced logging has been added to examine the
HTTP response returned from the server to assist with troubleshooting
connection issues.</p>
<dl class="field-list simple">
<dt class="field-odd">Returns<span class="colon">:</span></dt>
<dd class="field-odd"><p>True if the connection works, False if it does not</p>
+1 -1
View File
File diff suppressed because one or more lines are too long
+27 -130
View File
@@ -42,7 +42,7 @@ logger.addHandler(handler)
# Get service configuration
#
logger.info('AskNavidrome 0.9!')
logger.info('AskNavidrome 0.10!')
logger.debug('Getting configuration from the environment...')
try:
@@ -222,7 +222,7 @@ class LaunchRequestHandler(AbstractRequestHandler):
logger.debug('In LaunchRequestHandler')
connection.ping()
speech = sanitise_speech_output('Simbora!')
speech = sanitise_speech_output('Ready!')
handler_input.response_builder.speak(speech).ask(speech)
return handler_input.response_builder.response
@@ -311,8 +311,7 @@ class NaviSonicPlayMusicByArtist(AbstractRequestHandler):
artist_lookup = connection.search_artist(artist.value)
if artist_lookup is None:
#text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
text = sanitise_speech_output(f"Não achei o artista {artist.value} na nossa coleção.")
text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -329,8 +328,7 @@ class NaviSonicPlayMusicByArtist(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
#speech = sanitise_speech_output(f'Playing music by: {artist.value}')
speech = sanitise_speech_output(f'Tocando músicas de: {artist.value}')
speech = sanitise_speech_output(f'Playing music by: {artist.value}')
logger.info(speech)
card = {'title': 'AskNavidrome',
@@ -341,97 +339,6 @@ class NaviSonicPlayMusicByArtist(AbstractRequestHandler):
track_details = play_queue.get_next_track()
return controller.start_playback('play', speech, card, track_details, handler_input)
def get_current_song_details():
current_track = play_queue.get_current_track()
logger.debug(current_track)
return {
"title": current_track.title,
"artist": current_track.artist,
"album": current_track.album,
"_sanitized": {
"title": sanitise_speech_output(current_track.title),
"artist": sanitise_speech_output(current_track.artist),
"album": sanitise_speech_output(current_track.album)
}
}
class NaviSonicPlayMusicByCurrentArtist(AbstractRequestHandler):
"""Handle NaviSonicPlayMusicByCurrentArtist Intent
Plays more music of the current playing Artist
"""
def can_handle(self, handler_input: HandlerInput) -> bool:
return is_intent_name('NaviSonicPlayMusicByCurrentArtist')(handler_input)
def handle(self, handler_input: HandlerInput) -> Response:
global backgroundProcess
logger.debug('In NaviSonicPlayMusicByCurrentArtist Handler (custom)')
if backgroundProcess is not None:
backgroundProcess.terminate()
backgroundProcess.join()
t = get_current_song_details() #current "T"rack
artist_lookup = connection.search_artist(t["artist"])
artist_album_lookup = connection.albums_by_artist(artist_lookup[0].get('id'))
song_id_list = connection.build_song_list_from_albums(artist_album_lookup, min_song_count)
play_queue.clear()
controller.enqueue_songs(connection, play_queue, [song_id_list[0], song_id_list[1]]) # When generating the playlist return the first two tracks.
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output(f'Tocando mais músicas de {t["artist"]}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
}
play_queue.shuffle()
track_details = play_queue.get_next_track()
return controller.start_playback('play', speech, card, track_details, handler_input)
class NaviSonicPlayMusicByCurrentAlbum(AbstractRequestHandler):
"""Handle NaviSonicPlayMusicByCurrentAlbum Intent
Plays more music of the current playing Album
"""
def can_handle(self, handler_input: HandlerInput) -> bool:
return is_intent_name('NaviSonicPlayMusicByCurrentAlbum')(handler_input)
def handle(self, handler_input: HandlerInput) -> Response:
global backgroundProcess
logger.debug('In NaviSonicPlayMusicByCurrentAlbum Handler (custom)')
if backgroundProcess is not None:
backgroundProcess.terminate()
backgroundProcess.join()
t = get_current_song_details() #current "T"rack
artist_lookup = connection.search_artist(t["artist"])
artist_album_lookup = connection.albums_by_artist(artist_lookup[0].get('id'))
result = [album_result for album_result in artist_album_lookup if album_result.get('name').lower() == t["album"].lower()]
song_id_list = connection.build_song_list_from_albums(result, -1)
play_queue.clear()
controller.enqueue_songs(connection, play_queue, [song_id_list[0], song_id_list[1]]) # When generating the playlist return the first two tracks.
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output(f'Tocando mais músicas do album {t["album"]}, de {t["artist"]}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
}
play_queue.shuffle()
track_details = play_queue.get_next_track()
return controller.start_playback('play', speech, card, track_details, handler_input)
class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
"""Handle NaviSonicPlayAlbumByArtist
@@ -464,8 +371,7 @@ class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
artist_lookup = connection.search_artist(artist.value)
if artist_lookup is None:
#text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
text = sanitise_speech_output(f"Não achei o artista {artist.value} na nossa coleção.")
text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -478,8 +384,7 @@ class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
result = [album_result for album_result in artist_album_lookup if album_result.get('name').lower() == album.value.lower()]
if not result:
#text = sanitise_speech_output(f"I couldn't find an album called {album.value} by {artist.value} in the collection.")
text = sanitise_speech_output(f"Não achei na nossa coleção um disco chamado {album.value} de {artist.value}.")
text = sanitise_speech_output(f"I couldn't find an album called {album.value} by {artist.value} in the collection.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -493,8 +398,7 @@ class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
#speech = sanitise_speech_output(f'Playing {album.value} by: {artist.value}')
speech = sanitise_speech_output(f'Tocando o álbum {album.value} de: {artist.value}')
speech = sanitise_speech_output(f'Playing {album.value} by: {artist.value}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -510,8 +414,7 @@ class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
result = connection.search_album(album.value)
if result is None:
#text = sanitise_speech_output(f"I couldn't find the album {album.value} in the collection.")
text = sanitise_speech_output(f"Não achei o disco {album.value} na nossa coleção.")
text = sanitise_speech_output(f"I couldn't find the album {album.value} in the collection.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -525,7 +428,7 @@ class NaviSonicPlayAlbumByArtist(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output(f'Tocando o disco {album.value}')
speech = sanitise_speech_output(f'Playing {album.value}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -558,8 +461,7 @@ class NaviSonicPlaySongByArtist(AbstractRequestHandler):
artist_lookup = connection.search_artist(artist.value)
if artist_lookup is None:
#text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
text = sanitise_speech_output(f"Não achei o artista {artist.value} na nossa coleção.")
text = sanitise_speech_output(f"I couldn't find the artist {artist.value} in the collection.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -574,8 +476,7 @@ class NaviSonicPlaySongByArtist(AbstractRequestHandler):
song_dets = [item.get('id') for item in song_list if item.get('artistId') == artist_id]
if not song_dets:
#text = sanitise_speech_output(f"I couldn't find a song called {song.value} by {artist.value} in the collection.")
text = sanitise_speech_output(f"Não achei uma música chamada {song.value} de {artist.value} na nossa coleção.")
text = sanitise_speech_output(f"I couldn't find a song called {song.value} by {artist.value} in the collection.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -583,7 +484,7 @@ class NaviSonicPlaySongByArtist(AbstractRequestHandler):
play_queue.clear()
controller.enqueue_songs(connection, play_queue, song_dets)
speech = sanitise_speech_output(f'Tocando {song.value} de {artist.value}')
speech = sanitise_speech_output(f'Playing {song.value} by {artist.value}')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -619,7 +520,7 @@ class NaviSonicPlayPlaylist(AbstractRequestHandler):
playlist_id = connection.search_playlist(playlist.value)
if playlist_id is None:
text = sanitise_speech_output("Não achei a playlist " + str(playlist.value) + ' na nossa coleção.')
text = sanitise_speech_output("I couldn't find the playlist " + str(playlist.value) + ' in the collection.')
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -633,7 +534,7 @@ class NaviSonicPlayPlaylist(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output('Tocando a playlist ' + str(playlist.value))
speech = sanitise_speech_output('Playing playlist ' + str(playlist.value))
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -668,7 +569,7 @@ class NaviSonicPlayMusicByGenre(AbstractRequestHandler):
song_id_list = connection.build_song_list_from_genre(genre.value, min_song_count)
if song_id_list is None:
text = sanitise_speech_output(f"Não achei nada do estilo {genre.value} na nossa coleção.")
text = sanitise_speech_output(f"I couldn't find any {genre.value} songs in the collection.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -682,7 +583,7 @@ class NaviSonicPlayMusicByGenre(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output(f'Tocando músicas do estilo {genre.value}')
speech = sanitise_speech_output(f'Playing {genre.value} music')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -714,8 +615,7 @@ class NaviSonicPlayMusicRandom(AbstractRequestHandler):
song_id_list = connection.build_random_song_list(min_song_count)
if song_id_list is None:
#text = sanitise_speech_output("I couldn't find any songs in the collection.")
text = sanitise_speech_output("Não achei nenhuma música na nossa coleção. Estranho.")
text = sanitise_speech_output("I couldn't find any songs in the collection.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -729,7 +629,7 @@ class NaviSonicPlayMusicRandom(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output('Tocando qualquer coisa aleatória')
speech = sanitise_speech_output('Playing random music')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -761,7 +661,7 @@ class NaviSonicPlayFavouriteSongs(AbstractRequestHandler):
song_id_list = connection.build_song_list_from_favourites()
if song_id_list is None:
text = sanitise_speech_output("Não tenho nada nos favoritos.")
text = sanitise_speech_output("You don't have any favourite songs in the collection.")
handler_input.response_builder.speak(text).ask(text)
return handler_input.response_builder.response
@@ -775,7 +675,7 @@ class NaviSonicPlayFavouriteSongs(AbstractRequestHandler):
backgroundProcess = Process(target=queue_worker_thread, args=(connection, play_queue, song_id_list[2:])) # Create a thread to enqueue the remaining tracks
backgroundProcess.start() # Start the additional thread
speech = sanitise_speech_output('Tocando suas músicas favoritas.')
speech = sanitise_speech_output('Playing your favourite tracks.')
logger.info(speech)
card = {'title': 'AskNavidrome',
'text': speech
@@ -821,8 +721,7 @@ class NaviSonicSongDetails(AbstractRequestHandler):
artist = sanitise_speech_output(current_track.artist)
album = sanitise_speech_output(current_track.album)
# text = f'This is {title} by {artist}, from the album {album}'
text = f'Essa é {title} de {artist}, do album {album}'
text = f'This is {title} by {artist}, from the album {album}'
handler_input.response_builder.speak(text)
return handler_input.response_builder.response
@@ -1004,7 +903,8 @@ class NextPlaybackHandler(AbstractRequestHandler):
"""Handle NextIntent"""
def can_handle(self, handler_input: HandlerInput) -> bool:
return is_intent_name('AMAZON.NextIntent')(handler_input)
return (is_intent_name('AMAZON.NextIntent')(handler_input) or
is_request_type('PlaybackController.NextCommandIssued')(handler_input))
def handle(self, handler_input: HandlerInput) -> Response:
logger.debug('In NextPlaybackHandler')
@@ -1021,7 +921,8 @@ class PreviousPlaybackHandler(AbstractRequestHandler):
"""Handle PreviousIntent"""
def can_handle(self, handler_input: HandlerInput) -> bool:
return is_intent_name('AMAZON.PreviousIntent')(handler_input)
return (is_intent_name('AMAZON.PreviousIntent')(handler_input) or
is_request_type('PlaybackController.PreviousCommandIssued')(handler_input))
def handle(self, handler_input: HandlerInput) -> Response:
logger.debug('In PreviousPlaybackHandler')
@@ -1088,8 +989,7 @@ class SystemExceptionHandler(AbstractExceptionHandler):
if get_request_type(handler_input) == 'IntentRequest':
logger.error(f'Intent Name Was: {get_intent_name(handler_input)}')
#speech = sanitise_speech_output("Sorry, I didn't get that. Can you please say it again!!")
speech = sanitise_speech_output("Foi mal, não entendi.")
speech = sanitise_speech_output("Sorry, I didn't get that. Can you please say it again!!")
handler_input.response_builder.speak(speech).ask(speech)
return handler_input.response_builder.response
@@ -1115,8 +1015,7 @@ class GeneralExceptionHandler(AbstractExceptionHandler):
if get_request_type(handler_input) == 'IntentRequest':
logger.error(f'Intent Name Was: {get_intent_name(handler_input)}')
#speech = sanitise_speech_output("Sorry, I didn't get that. Can you please say it again!!")
speech = sanitise_speech_output("Foi mal, não entendi. Pode repetir!!")
speech = sanitise_speech_output("Sorry, I didn't get that. Can you please say it again!!")
handler_input.response_builder.speak(speech).ask(speech)
return handler_input.response_builder.response
@@ -1215,8 +1114,6 @@ sb.add_request_handler(NaviSonicPlayPlaylist())
sb.add_request_handler(NaviSonicPlayFavouriteSongs())
sb.add_request_handler(NaviSonicPlayMusicByGenre())
sb.add_request_handler(NaviSonicPlayMusicRandom())
sb.add_request_handler(NaviSonicPlayMusicByCurrentArtist())
sb.add_request_handler(NaviSonicPlayMusicByCurrentAlbum())
sb.add_request_handler(NaviSonicRandomiseQueue())
sb.add_request_handler(NaviSonicSongDetails())
sb.add_request_handler(NaviSonicStarSong())
Regular → Executable
+15 -3
View File
@@ -42,7 +42,19 @@ def start_playback(mode: str, text: str, card_data: dict, track_details: Track,
:return: Amazon Alexa Response class
:rtype: Response
"""
metadata = AudioItemMetadata(
title=track_details.title,
subtitle=track_details.artist,
art=display.Image(
content_description=track_details.title,
sources=[
display.ImageInstance(
url='https://github.com/navidrome/navidrome/raw/master/resources/logo-192x192.png'
)
]
)
)
if mode == 'play':
# Starting playback
logger.debug('In start_playback() - play mode')
@@ -67,7 +79,7 @@ def start_playback(mode: str, text: str, card_data: dict, track_details: Track,
url=track_details.uri,
offset_in_milliseconds=track_details.offset,
expected_previous_token=None),
metadata=add_screen_background(card_data) if card_data else None
metadata=metadata
)
)
).set_should_end_session(True)
@@ -95,7 +107,7 @@ def start_playback(mode: str, text: str, card_data: dict, track_details: Track,
# if the Previous intent is used
offset_in_milliseconds=0,
expected_previous_token=track_details.previous_id),
metadata=None
metadata=metadata
)
)
).set_should_end_session(True)
+21 -9
View File
@@ -40,29 +40,41 @@ class SubsonicConnection:
self.api_version,
False)
self.logger.debug('Connected to Navidrome')
self.logger.debug('Connecting to Navidrome.....')
def ping(self) -> bool:
"""Ping a Subsonic API server
Verify the connection to a Subsonic compatible API server
is working
is working. Enhanced logging has been added to examine the
HTTP response returned from the server to assist with troubleshooting
connection issues.
:return: True if the connection works, False if it does not
:rtype: bool
"""
self.logger.debug('In function ping()')
status = self.conn.ping()
http_request = self.conn._getRequest('ping.view')
try:
http_request_result = self.conn._doInfoReq(http_request)
except Exception as e:
self.logger.error('Failed to connect to Navidrome: %s', e, exc_info=True)
return False
if status:
# Success
self.logger.debug('ping() response from server: %s', http_request_result)
status = http_request_result.get('status')
if status == 'ok':
self.logger.info('Successfully connected to Navidrome')
return True
elif status == 'failed':
err = http_request_result.get('error', {})
self.logger.error('Failed to connect to Navidrome: code=%s msg=%s',
err.get('code'), err.get('message'))
return False
else:
# Fail
self.logger.error('Failed to connect to Navidrome')
return self.conn.ping()
self.logger.error('Unexpected error when connecting to Navidrome: %r', status)
return False
def scrobble(self, track_id: str, time: int) -> None:
"""Scrobble the given track