From e2d7cc99b2db087919dbc1dd94b2c6b42916374c Mon Sep 17 00:00:00 2001 From: Waldemar Schlackow Date: Mon, 18 Mar 2019 22:23:56 +0000 Subject: [PATCH 1/7] * Fix/Adjust some utterances and intents --- metadata/intents/v1/locale/en_GB/intents.json | 34 ++++++++++++++----- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/metadata/intents/v1/locale/en_GB/intents.json b/metadata/intents/v1/locale/en_GB/intents.json index 3254ebf..4c4ffd0 100644 --- a/metadata/intents/v1/locale/en_GB/intents.json +++ b/metadata/intents/v1/locale/en_GB/intents.json @@ -143,6 +143,18 @@ "what we are listening to in the {Player}" ] }, + { + "name": "PlayIntent", + "slots": [ + { + "name": "Player", + "type": "PLAYER" + } + ], + "samples": [ + "Play on {Player}" + ] + }, { "name": "SelectPlayerIntent", "slots": [ @@ -174,7 +186,10 @@ "turn {Player} player on", "switch {Player} on", "switch on {Player}", - "switch {Player} player on" + "switch {Player} player on", + "power {Player} on", + "power on {Player}", + "power {Player} player on" ] }, { @@ -191,7 +206,10 @@ "turn {Player} player off", "switch {Player} off", "switch off {Player}", - "switch {Player} player off" + "switch {Player} player off", + "power {Player} off", + "power off {Player}", + "power {Player} player off" ] }, { @@ -215,12 +233,12 @@ } ], "samples": [ - "play some {Genre}", - "play some {Genre} and {SecondaryGenre}", - "play some {Genre} and some {SecondaryGenre}", - "play some {Genre} some {SecondaryGenre} and some {TertiaryGenre}", - "play a mix of {Genre} and {SecondaryGenre}", - "play a mix of {Genre} {SecondaryGenre} and {TertiaryGenre}" + "play some {Genre} on {Player}", + "play some {Genre} and {SecondaryGenre} on {Player}", + "play some {Genre} and some {SecondaryGenre} on {Player}", + "play some {Genre} some {SecondaryGenre} and some {TertiaryGenre} on {Player}", + "play a mix of {Genre} and {SecondaryGenre} on {Player}", + "play a mix of {Genre} {SecondaryGenre} and {TertiaryGenre} on {Player}" ] }, { From 3ec17566c907163100fc947afa3aed478d29e9db Mon Sep 17 00:00:00 2001 From: Waldemar Schlackow Date: Mon, 18 Mar 2019 22:25:28 +0000 Subject: [PATCH 2/7] * Add feature to allow the default player to be dependent on the Alexa device that is being used --- handler.py | 14 ++++-- metadata/intents/v1/locale/en_GB/intents.json | 17 +++++++ squeezealexa/alexa/intents.py | 1 + squeezealexa/main.py | 8 +++ squeezealexa/squeezebox/server.py | 50 ++++++++++++++++++- 5 files changed, 86 insertions(+), 4 deletions(-) diff --git a/handler.py b/handler.py index b05c77a..bfc01b9 100644 --- a/handler.py +++ b/handler.py @@ -30,10 +30,11 @@ def _(s): factory = ServerFactory(TransportFactory()) -def get_server(): +def get_server(player, deviceId): return factory.create(user=LMS_SETTINGS.username, password=LMS_SETTINGS.password, - cur_player_id=LMS_SETTINGS.default_player, + cur_player_id=player or LMS_SETTINGS.default_player, + deviceId=deviceId, debug=LMS_SETTINGS.debug) @@ -41,8 +42,15 @@ def lambda_handler(event, context, server=None): """ Route the incoming request based on type (LaunchRequest, IntentRequest, etc.) The JSON body of the request is provided in the event parameter. """ + deviceId = event['context']['System']['device']['deviceId'] + server = server or get_server(LMS_SETTINGS.default_player, deviceId) + echomaps = server.get_echomaps() + inverted_echomaps = {v['url']: k for k, v in echomaps.items()} + if deviceId in inverted_echomaps: + player = inverted_echomaps[deviceId] + server.cur_player_id = player try: - sqa = SqueezeAlexa(server=server or get_server(), + sqa = SqueezeAlexa(server=server, app_id=SKILL_SETTINGS.application_id) return sqa.handle(event, context) except Exception as e: diff --git a/metadata/intents/v1/locale/en_GB/intents.json b/metadata/intents/v1/locale/en_GB/intents.json index 4c4ffd0..9099a95 100644 --- a/metadata/intents/v1/locale/en_GB/intents.json +++ b/metadata/intents/v1/locale/en_GB/intents.json @@ -259,6 +259,23 @@ "play my {Playlist} playlist in {Player}" ] }, + { + "name": "SetEchoMapIntent", + "slots": [ + { + "name": "Player", + "type": "PLAYER" + } + ], + "samples": [ + "Set the default player to {Player}", + "I'm using {Player}", + "I'm in {Player}", + "Set the player in this room to {Player}", + "I am using {Player}", + "I am in {Player}" + ] + }, { "name": "AllOnIntent", "samples": [ diff --git a/squeezealexa/alexa/intents.py b/squeezealexa/alexa/intents.py index 81b50bd..32c0c92 100644 --- a/squeezealexa/alexa/intents.py +++ b/squeezealexa/alexa/intents.py @@ -54,3 +54,4 @@ class Custom(object): for s in ["SetVolume", "SetVolumePercent"]) NOW_PLAYING, SELECT_PLAYER = ("%sIntent" % s for s in ["NowPlaying", "SelectPlayer"]) + SET_ECHOMAP = "SetEchoMapIntent" \ No newline at end of file diff --git a/squeezealexa/main.py b/squeezealexa/main.py index 59e2fef..f557ee2 100644 --- a/squeezealexa/main.py +++ b/squeezealexa/main.py @@ -212,6 +212,14 @@ def on_select_player(self, intent, session, pid=None): return speech_response(title, speech, reprompt_text=reprompt, end=False) + @handler.handle(Custom.SET_ECHOMAP) + def on_set_echomap(self, intent, session, pid=None): + srv = self._server + srv.set_echomap(pid, srv.deviceId) + player = srv.players[pid] + return self.smart_response(text=_("Set the default player for current Echo to {player}").format(player=player.name), + speech=_("I have set the default player for current Echo to {player}").format(player=player.name)) + @handler.handle(Audio.SHUFFLE_ON) @handler.handle(CustomAudio.SHUFFLE_ON) def on_shuffle_on(self, intent, session, pid=None): diff --git a/squeezealexa/squeezebox/server.py b/squeezealexa/squeezebox/server.py index 2c1b20d..76df982 100644 --- a/squeezealexa/squeezebox/server.py +++ b/squeezealexa/squeezebox/server.py @@ -86,12 +86,13 @@ class Server(object): _MAX_FAILURES = 3 def __init__(self, transport, user=None, password=None, - cur_player_id=None, debug=False): + cur_player_id=None, deviceId=None, debug=False): self.transport = transport self._debug = debug self.user = user self.password = password + self.deviceId = deviceId if user and password: self.log_in() print_d("Authenticated with %s!" % self) @@ -114,6 +115,7 @@ def __init__(self, transport, user=None, password=None, self.__genres = [] self.__playlists = [] self.__favorites = [] + self.__echomaps = {} @property def connected(self): @@ -382,6 +384,52 @@ def __str__(self): def __del__(self): self.disconnect() + def get_squeezealexa_favorite_id(self): + resp = self.__a_request("favorites items 0 255", + raw=True) + favorites = {d['name']: d + for d in self._groups(resp, 'id') + if d['hasitems']} + if not 'squeeze-alexa' in favorites: + print_d("Creating squeeze-alexa container in Favorites...") + resp = self.__a_request("favorites addlevel title:squeeze-alexa", + raw=True) + resp = self.__a_request("favorites items 0 255", + raw=True) + favorites = {d['name']: d + for d in self._groups(resp, 'id') + if d['hasitems']} + id = favorites['squeeze-alexa']['id'] + print_d("Found squeeze-alexa favorite id={id}", id=id) + return id + + def get_echomaps(self): + """ Updates the list of the Squeezebox players available and other + server metadata.""" + id = self.get_squeezealexa_favorite_id() + resp = self.__a_request("favorites items 0 255 item_id:%s want_url:1" % id, + raw=True) + self.__echomaps = {d['name']: d for d in self._groups(resp, 'id') + if d['isaudio']} + print_d(with_example("Loaded {num} Echo Maps", self.__echomaps)) + return self.__echomaps + + def set_echomap(self, player, deviceId): + self.__echomaps = self.get_echomaps() + inverted_echomaps = {v['url']: { 'player': k, 'id': v['id'] } for k, v in self.__echomaps.items()} + id = self.get_squeezealexa_favorite_id() + if deviceId not in inverted_echomaps: + print_d("Setting new Echo Map from {player} to {deviceId}", player=player, deviceId=deviceId) + resp = self.__a_request("favorites add item_id:%s.0 title:%s url:%s" % (id, player, deviceId), + raw=True) + elif inverted_echomaps[deviceId]['player'] != player: + print_d("Deleting outdated Echo Map with {id}", id=inverted_echomaps[deviceId]['id']) + resp = self.__a_request("favorites delete item_id:%s" % inverted_echomaps[deviceId]['id'], + raw=True) + print_d("Setting new Echo Map from {player} to {deviceId}", player=player, deviceId=deviceId) + resp = self.__a_request("favorites add item_id:%s.0 title:%s url:%s" % (id, player, deviceId), + raw=True) + return True def people_from(details: Dict) -> Union[str, None]: genres = {g.lower() for g in details.get('genre', [])} From 8153bbd952cb80dd322c8113b5817856ed1a6945 Mon Sep 17 00:00:00 2001 From: Waldemar Schlackow Date: Tue, 19 Mar 2019 11:34:40 +0000 Subject: [PATCH 3/7] * Some bugs fixed * Allow voice deletions of default echo/player maps * Code simplification --- handler.py | 12 ++++---- metadata/intents/v1/locale/en_GB/intents.json | 28 ++++++++++++++++++ squeezealexa/alexa/intents.py | 3 +- squeezealexa/main.py | 17 ++++++++++- squeezealexa/squeezebox/server.py | 29 ++++++++++++++----- 5 files changed, 73 insertions(+), 16 deletions(-) diff --git a/handler.py b/handler.py index bfc01b9..ceaf775 100644 --- a/handler.py +++ b/handler.py @@ -30,10 +30,10 @@ def _(s): factory = ServerFactory(TransportFactory()) -def get_server(player, deviceId): +def get_server(deviceId): return factory.create(user=LMS_SETTINGS.username, password=LMS_SETTINGS.password, - cur_player_id=player or LMS_SETTINGS.default_player, + cur_player_id=LMS_SETTINGS.default_player, deviceId=deviceId, debug=LMS_SETTINGS.debug) @@ -43,12 +43,10 @@ def lambda_handler(event, context, server=None): etc.) The JSON body of the request is provided in the event parameter. """ deviceId = event['context']['System']['device']['deviceId'] - server = server or get_server(LMS_SETTINGS.default_player, deviceId) + server = server or get_server(deviceId) echomaps = server.get_echomaps() - inverted_echomaps = {v['url']: k for k, v in echomaps.items()} - if deviceId in inverted_echomaps: - player = inverted_echomaps[deviceId] - server.cur_player_id = player + if deviceId in echomaps: + server.cur_player_id = echomaps[deviceId]['name'] try: sqa = SqueezeAlexa(server=server, app_id=SKILL_SETTINGS.application_id) diff --git a/metadata/intents/v1/locale/en_GB/intents.json b/metadata/intents/v1/locale/en_GB/intents.json index 9099a95..1fd7a1e 100644 --- a/metadata/intents/v1/locale/en_GB/intents.json +++ b/metadata/intents/v1/locale/en_GB/intents.json @@ -276,6 +276,34 @@ "I am in {Player}" ] }, + { + "name": "DelEchoMapPlayerIntent", + "slots": [ + { + "name": "Player", + "type": "PLAYER" + } + ], + "samples": [ + "Delete the default echo device for player {Player}", + "Delete the default echo device for {Player}", + "Delete the default echo for player {Player}", + "Delete the default echo for {Player}", + "Delete the default association for player {Player}", + "Delete the default association for {Player}" + ] + }, + { + "name": "DelEchoMapDeviceIntent", + "slots": [], + "samples": [ + "Delete the default player here", + "Delete the default player for this room", + "Delete the default player for this echo device", + "Delete the default player for this echo", + "Delete the default player" + ] + }, { "name": "AllOnIntent", "samples": [ diff --git a/squeezealexa/alexa/intents.py b/squeezealexa/alexa/intents.py index 32c0c92..138e7d6 100644 --- a/squeezealexa/alexa/intents.py +++ b/squeezealexa/alexa/intents.py @@ -54,4 +54,5 @@ class Custom(object): for s in ["SetVolume", "SetVolumePercent"]) NOW_PLAYING, SELECT_PLAYER = ("%sIntent" % s for s in ["NowPlaying", "SelectPlayer"]) - SET_ECHOMAP = "SetEchoMapIntent" \ No newline at end of file + SET_ECHOMAP, DEL_ECHOMAP_PLAYER, DEL_ECHOMAP_DEVICE = ("%sIntent" % s + for s in ["SetEchoMap", "DelEchoMapPlayer", "DelEchoMapDevice"]) diff --git a/squeezealexa/main.py b/squeezealexa/main.py index d903f01..bc9d58b 100644 --- a/squeezealexa/main.py +++ b/squeezealexa/main.py @@ -216,10 +216,25 @@ def on_select_player(self, intent, session, pid=None): def on_set_echomap(self, intent, session, pid=None): srv = self._server srv.set_echomap(pid, srv.deviceId) - player = srv.players[pid] + player = srv.players[pid] return self.smart_response(text=_("Set the default player for current Echo to {player}").format(player=player.name), speech=_("I have set the default player for current Echo to {player}").format(player=player.name)) + @handler.handle(Custom.DEL_ECHOMAP_PLAYER) + def on_del_echomap_player(self, intent, session, pid=None): + srv = self._server + srv.del_echomap(pid) + player = srv.players[pid] + return self.smart_response(text=_("Removed the default associations for player {player}").format(player=player.name), + speech=_("I have removed the default associations for player {player}").format(player=player.name)) + + @handler.handle(Custom.DEL_ECHOMAP_DEVICE) + def on_del_echomap_device(self, intent, session, pid=None): + srv = self._server + srv.del_echomap(False, srv.deviceId) + return self.smart_response(text=_("Removed the default player for the current Echo device"), + speech=_("I have removed the default player for the current Echo device")) + @handler.handle(Audio.SHUFFLE_ON) @handler.handle(CustomAudio.SHUFFLE_ON) def on_shuffle_on(self, intent, session, pid=None): diff --git a/squeezealexa/squeezebox/server.py b/squeezealexa/squeezebox/server.py index 34fb8e4..48e4bc0 100644 --- a/squeezealexa/squeezebox/server.py +++ b/squeezealexa/squeezebox/server.py @@ -415,27 +415,42 @@ def get_echomaps(self): id = self.get_squeezealexa_favorite_id() resp = self.__a_request("favorites items 0 255 item_id:%s want_url:1" % id, raw=True) - self.__echomaps = {d['name']: d for d in self._groups(resp, 'id') + self.__echomaps = {d['url']: d for d in self._groups(resp, 'id') if d['isaudio']} print_d(with_example("Loaded {num} Echo Maps", self.__echomaps)) return self.__echomaps def set_echomap(self, player, deviceId): self.__echomaps = self.get_echomaps() - inverted_echomaps = {v['url']: { 'player': k, 'id': v['id'] } for k, v in self.__echomaps.items()} id = self.get_squeezealexa_favorite_id() - if deviceId not in inverted_echomaps: + if deviceId not in self.__echomaps: print_d("Setting new Echo Map from {player} to {deviceId}", player=player, deviceId=deviceId) resp = self.__a_request("favorites add item_id:%s.0 title:%s url:%s" % (id, player, deviceId), raw=True) - elif inverted_echomaps[deviceId]['player'] != player: - print_d("Deleting outdated Echo Map with {id}", id=inverted_echomaps[deviceId]['id']) - resp = self.__a_request("favorites delete item_id:%s" % inverted_echomaps[deviceId]['id'], + elif self.__echomaps[deviceId]['name'] != player: + print_d("Deleting outdated Echo Map with {id}", id=self.__echomaps[deviceId]['id']) + resp = self.__a_request("favorites delete item_id:%s" % self.__echomaps[deviceId]['id'], raw=True) print_d("Setting new Echo Map from {player} to {deviceId}", player=player, deviceId=deviceId) resp = self.__a_request("favorites add item_id:%s.0 title:%s url:%s" % (id, player, deviceId), raw=True) - return True + + def del_echomap(self, player=False, deviceId=False): + self.__echomaps = self.get_echomaps() + if deviceId: + print_d("Trying to remove default player for {deviceId}", deviceId=deviceId) + while deviceId in self.__echomaps: + print_d("Deleting Echo Map with ID {id}", id=self.__echomaps[deviceId]['id']) + resp = self.__a_request("favorites delete item_id:%s" % self.__echomaps[deviceId]['id'], + raw=True) + self.__echomaps = self.get_echomaps() + if player: + inverted_echomaps = {v['name']: { 'deviceId': k, 'id': v['id'] } for k, v in self.__echomaps.items()} + while player in inverted_echomaps: + print_d("Deleting Echo Map with ID {id}", id=inverted_echomaps[player]['id']) + resp = self.__a_request("favorites delete item_id:%s" % inverted_echomaps[player]['id'], + raw=True) + self.__echomaps = self.get_echomaps() def people_from(details: Dict, default=None) -> Union[str, None]: genres = {g.lower() for g in details.get('genre', [])} From 9c4ed4df1b1fec28e8644cc4ae897a066183618a Mon Sep 17 00:00:00 2001 From: Waldemar Schlackow Date: Tue, 19 Mar 2019 11:43:06 +0000 Subject: [PATCH 4/7] * Fix KeyError in tests --- squeezealexa/squeezebox/server.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/squeezealexa/squeezebox/server.py b/squeezealexa/squeezebox/server.py index 48e4bc0..30e9f7e 100644 --- a/squeezealexa/squeezebox/server.py +++ b/squeezealexa/squeezebox/server.py @@ -405,9 +405,12 @@ def get_squeezealexa_favorite_id(self): favorites = {d['name']: d for d in self._groups(resp, 'id') if d['hasitems']} - id = favorites['squeeze-alexa']['id'] - print_d("Found squeeze-alexa favorite id={id}", id=id) - return id + if 'squeeze-alexa' in favorites: + id = favorites['squeeze-alexa']['id'] + print_d("Found squeeze-alexa favorite id={id}", id=id) + return id + else: + return False def get_echomaps(self): """ Updates the list of the Squeezebox players available and other From fc80e6c1244543131dd12d1bd3274b1741984509 Mon Sep 17 00:00:00 2001 From: Waldemar Schlackow Date: Tue, 19 Mar 2019 12:04:54 +0000 Subject: [PATCH 5/7] * Further error handling improvements --- squeezealexa/main.py | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/squeezealexa/main.py b/squeezealexa/main.py index bc9d58b..eb93a13 100644 --- a/squeezealexa/main.py +++ b/squeezealexa/main.py @@ -216,17 +216,45 @@ def on_select_player(self, intent, session, pid=None): def on_set_echomap(self, intent, session, pid=None): srv = self._server srv.set_echomap(pid, srv.deviceId) - player = srv.players[pid] - return self.smart_response(text=_("Set the default player for current Echo to {player}").format(player=player.name), + if pid: + player = srv.players[pid] + return self.smart_response(text=_("Set the default player for current Echo to {player}").format(player=player.name), speech=_("I have set the default player for current Echo to {player}").format(player=player.name)) + speech = (_("I only found these players: {players}. " + "Could you try again?") + .format(players=human_join(srv.player_names))) + reprompt = (_("You can select a player by saying \"{utterance}\" " + "and then the player name.") + .format(utterance=Utterances.SELECT_PLAYER)) + try: + player = intent['slots']['Player']['value'] + title = (_("No player called \"{name}\"").format(name=player)) + except KeyError: + title = "Didn't recognise a player name" + return speech_response(title, speech, reprompt_text=reprompt, + end=False) @handler.handle(Custom.DEL_ECHOMAP_PLAYER) def on_del_echomap_player(self, intent, session, pid=None): srv = self._server srv.del_echomap(pid) - player = srv.players[pid] - return self.smart_response(text=_("Removed the default associations for player {player}").format(player=player.name), + if pid: + player = srv.players[pid] + return self.smart_response(text=_("Removed the default associations for player {player}").format(player=player.name), speech=_("I have removed the default associations for player {player}").format(player=player.name)) + speech = (_("I only found these players: {players}. " + "Could you try again?") + .format(players=human_join(srv.player_names))) + reprompt = (_("You can select a player by saying \"{utterance}\" " + "and then the player name.") + .format(utterance=Utterances.SELECT_PLAYER)) + try: + player = intent['slots']['Player']['value'] + title = (_("No player called \"{name}\"").format(name=player)) + except KeyError: + title = "Didn't recognise a player name" + return speech_response(title, speech, reprompt_text=reprompt, + end=False) @handler.handle(Custom.DEL_ECHOMAP_DEVICE) def on_del_echomap_device(self, intent, session, pid=None): From c11ceedbfb13829006ee3a9c2b70677a68696f16 Mon Sep 17 00:00:00 2001 From: Waldemar Schlackow Date: Tue, 19 Mar 2019 12:17:54 +0000 Subject: [PATCH 6/7] * Further error handling --- handler.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/handler.py b/handler.py index ceaf775..967171c 100644 --- a/handler.py +++ b/handler.py @@ -42,9 +42,16 @@ def lambda_handler(event, context, server=None): """ Route the incoming request based on type (LaunchRequest, IntentRequest, etc.) The JSON body of the request is provided in the event parameter. """ - deviceId = event['context']['System']['device']['deviceId'] - server = server or get_server(deviceId) - echomaps = server.get_echomaps() + deviceId = '' + echomaps = {} + try: + if event: + deviceId = event['context']['System']['device']['deviceId'] + server = server or get_server(deviceId) + echomaps = server.get_echomaps() + except KeyError or NoneType: + if not SKILL_SETTINGS.use_spoken_errors: + raise e if deviceId in echomaps: server.cur_player_id = echomaps[deviceId]['name'] try: From f118990715dab357f116f809b34ea20abb80c7dd Mon Sep 17 00:00:00 2001 From: Waldemar Schlackow Date: Tue, 19 Mar 2019 13:30:46 +0000 Subject: [PATCH 7/7] * Stylistic fixes --- handler.py | 2 +- squeezealexa/alexa/intents.py | 5 ++- squeezealexa/main.py | 23 ++++++++--- squeezealexa/squeezebox/server.py | 69 +++++++++++++++++++------------ 4 files changed, 63 insertions(+), 36 deletions(-) diff --git a/handler.py b/handler.py index 967171c..5e10d7f 100644 --- a/handler.py +++ b/handler.py @@ -49,7 +49,7 @@ def lambda_handler(event, context, server=None): deviceId = event['context']['System']['device']['deviceId'] server = server or get_server(deviceId) echomaps = server.get_echomaps() - except KeyError or NoneType: + except KeyError as e: if not SKILL_SETTINGS.use_spoken_errors: raise e if deviceId in echomaps: diff --git a/squeezealexa/alexa/intents.py b/squeezealexa/alexa/intents.py index 138e7d6..ffbd699 100644 --- a/squeezealexa/alexa/intents.py +++ b/squeezealexa/alexa/intents.py @@ -54,5 +54,6 @@ class Custom(object): for s in ["SetVolume", "SetVolumePercent"]) NOW_PLAYING, SELECT_PLAYER = ("%sIntent" % s for s in ["NowPlaying", "SelectPlayer"]) - SET_ECHOMAP, DEL_ECHOMAP_PLAYER, DEL_ECHOMAP_DEVICE = ("%sIntent" % s - for s in ["SetEchoMap", "DelEchoMapPlayer", "DelEchoMapDevice"]) + (SET_ECHOMAP, DEL_ECHOMAP_PLAYER, + DEL_ECHOMAP_DEVICE) = ("%sIntent" % s for s in ["SetEchoMap", + "DelEchoMapPlayer", "DelEchoMapDevice"]) diff --git a/squeezealexa/main.py b/squeezealexa/main.py index eb93a13..17b1889 100644 --- a/squeezealexa/main.py +++ b/squeezealexa/main.py @@ -218,8 +218,12 @@ def on_set_echomap(self, intent, session, pid=None): srv.set_echomap(pid, srv.deviceId) if pid: player = srv.players[pid] - return self.smart_response(text=_("Set the default player for current Echo to {player}").format(player=player.name), - speech=_("I have set the default player for current Echo to {player}").format(player=player.name)) + return self.smart_response( + text=(_("Set the default player for current Echo " + "to {player}").format(player=player.name)), + speech=(_("I have set the default player for " + "current Echo to {player}") + .format(player=player.name))) speech = (_("I only found these players: {players}. " "Could you try again?") .format(players=human_join(srv.player_names))) @@ -240,8 +244,12 @@ def on_del_echomap_player(self, intent, session, pid=None): srv.del_echomap(pid) if pid: player = srv.players[pid] - return self.smart_response(text=_("Removed the default associations for player {player}").format(player=player.name), - speech=_("I have removed the default associations for player {player}").format(player=player.name)) + text = (_("Removed the default associations for player {player}") + .format(player=player.name)) + speech = (_("I have removed the default associations " + "for player {player}") + .format(player=player.name)) + return self.smart_response(text, speech) speech = (_("I only found these players: {players}. " "Could you try again?") .format(players=human_join(srv.player_names))) @@ -260,8 +268,11 @@ def on_del_echomap_player(self, intent, session, pid=None): def on_del_echomap_device(self, intent, session, pid=None): srv = self._server srv.del_echomap(False, srv.deviceId) - return self.smart_response(text=_("Removed the default player for the current Echo device"), - speech=_("I have removed the default player for the current Echo device")) + return self.smart_response( + text=_("Removed the default player for " + "the current Echo device"), + speech=_("I have removed the default player for " + "the current Echo device")) @handler.handle(Audio.SHUFFLE_ON) @handler.handle(CustomAudio.SHUFFLE_ON) diff --git a/squeezealexa/squeezebox/server.py b/squeezealexa/squeezebox/server.py index 30e9f7e..00c2693 100644 --- a/squeezealexa/squeezebox/server.py +++ b/squeezealexa/squeezebox/server.py @@ -394,17 +394,17 @@ def get_squeezealexa_favorite_id(self): resp = self.__a_request("favorites items 0 255", raw=True) favorites = {d['name']: d - for d in self._groups(resp, 'id') - if d['hasitems']} - if not 'squeeze-alexa' in favorites: + for d in self._groups(resp, 'id') + if d['hasitems']} + if 'squeeze-alexa' not in favorites: print_d("Creating squeeze-alexa container in Favorites...") resp = self.__a_request("favorites addlevel title:squeeze-alexa", - raw=True) + raw=True) resp = self.__a_request("favorites items 0 255", - raw=True) + raw=True) favorites = {d['name']: d - for d in self._groups(resp, 'id') - if d['hasitems']} + for d in self._groups(resp, 'id') + if d['hasitems']} if 'squeeze-alexa' in favorites: id = favorites['squeeze-alexa']['id'] print_d("Found squeeze-alexa favorite id={id}", id=id) @@ -416,10 +416,10 @@ def get_echomaps(self): """ Updates the list of the Squeezebox players available and other server metadata.""" id = self.get_squeezealexa_favorite_id() - resp = self.__a_request("favorites items 0 255 item_id:%s want_url:1" % id, - raw=True) + resp = self.__a_request("favorites items 0 255 item_id:%s want_url:1" % + id, raw=True) self.__echomaps = {d['url']: d for d in self._groups(resp, 'id') - if d['isaudio']} + if d['isaudio']} print_d(with_example("Loaded {num} Echo Maps", self.__echomaps)) return self.__echomaps @@ -427,33 +427,48 @@ def set_echomap(self, player, deviceId): self.__echomaps = self.get_echomaps() id = self.get_squeezealexa_favorite_id() if deviceId not in self.__echomaps: - print_d("Setting new Echo Map from {player} to {deviceId}", player=player, deviceId=deviceId) - resp = self.__a_request("favorites add item_id:%s.0 title:%s url:%s" % (id, player, deviceId), - raw=True) + print_d("Setting new Echo Map from {player} to {deviceId}", + player=player, deviceId=deviceId) + self.__a_request("favorites add item_id:%s.0 title:%s" + "url:%s" % (id, player, deviceId), + raw=True) elif self.__echomaps[deviceId]['name'] != player: - print_d("Deleting outdated Echo Map with {id}", id=self.__echomaps[deviceId]['id']) - resp = self.__a_request("favorites delete item_id:%s" % self.__echomaps[deviceId]['id'], - raw=True) - print_d("Setting new Echo Map from {player} to {deviceId}", player=player, deviceId=deviceId) - resp = self.__a_request("favorites add item_id:%s.0 title:%s url:%s" % (id, player, deviceId), - raw=True) + print_d("Deleting outdated Echo Map with {id}", + id=self.__echomaps[deviceId]['id']) + self.__a_request("favorites delete item_id:%s" % + self.__echomaps[deviceId]['id'], + raw=True) + print_d("Setting new Echo Map from {player} to {deviceId}", + player=player, deviceId=deviceId) + self.__a_request("favorites add item_id:%s.0 title:%s " + "url:%s" % (id, player, deviceId), + raw=True) def del_echomap(self, player=False, deviceId=False): self.__echomaps = self.get_echomaps() if deviceId: - print_d("Trying to remove default player for {deviceId}", deviceId=deviceId) + print_d("Trying to remove default player for {deviceId}", + deviceId=deviceId) while deviceId in self.__echomaps: - print_d("Deleting Echo Map with ID {id}", id=self.__echomaps[deviceId]['id']) - resp = self.__a_request("favorites delete item_id:%s" % self.__echomaps[deviceId]['id'], - raw=True) + print_d("Deleting Echo Map with ID {id}", + id=self.__echomaps[deviceId]['id']) + self.__a_request("favorites delete item_id:%s" % + self.__echomaps[deviceId]['id'], + raw=True) self.__echomaps = self.get_echomaps() if player: - inverted_echomaps = {v['name']: { 'deviceId': k, 'id': v['id'] } for k, v in self.__echomaps.items()} + inverted_echomaps = {v['name']: {'deviceId': k, 'id': v['id']} + for k, v in self.__echomaps.items()} while player in inverted_echomaps: - print_d("Deleting Echo Map with ID {id}", id=inverted_echomaps[player]['id']) - resp = self.__a_request("favorites delete item_id:%s" % inverted_echomaps[player]['id'], - raw=True) + print_d("Deleting Echo Map with ID {id}", + id=inverted_echomaps[player]['id']) + self.__a_request("favorites delete item_id:%s" % + inverted_echomaps[player]['id'], + raw=True) self.__echomaps = self.get_echomaps() + inverted_echomaps = {v['name']: {'deviceId': k, 'id': v['id']} + for k, v in self.__echomaps.items()} + def people_from(details: Dict, default=None) -> Union[str, None]: genres = {g.lower() for g in details.get('genre', [])}