From e7b96afa418db444345995201ae91a339bd22908 Mon Sep 17 00:00:00 2001 From: Felix Cusson Date: Fri, 1 Mar 2024 07:54:48 -0500 Subject: [PATCH 1/3] moved to direct call to websocket_api --- custom_components/spotcast/__init__.py | 98 +++++++++++++++++++------- 1 file changed, 72 insertions(+), 26 deletions(-) diff --git a/custom_components/spotcast/__init__.py b/custom_components/spotcast/__init__.py index 5c6d8f33..9d33b7a8 100644 --- a/custom_components/spotcast/__init__.py +++ b/custom_components/spotcast/__init__.py @@ -101,7 +101,11 @@ def setup(hass: ha_core.HomeAssistant, config: collections.OrderedDict) -> bool: hass.data[DOMAIN]["controller"] = spotcast_controller @callback - def websocket_handle_playlists(hass: ha_core.HomeAssistant, connection, msg): + def websocket_handle_playlists( + hass: ha_core.HomeAssistant, + connection, + msg: str + ): @async_wrap def get_playlist(): """Handle to get playlist""" @@ -115,26 +119,37 @@ def get_playlist(): resp = spotcast_controller.get_playlists( account, playlist_type, country_code, locale, limit ) - connection.send_message(websocket_api.result_message(msg["id"], resp)) + connection.send_message( + websocket_api.result_message(msg["id"], resp)) hass.async_add_job(get_playlist()) @callback - def websocket_handle_devices(hass: ha_core.HomeAssistant, connection, msg): + def websocket_handle_devices( + hass: ha_core.HomeAssistant, + connection, + msg: str, + ): @async_wrap def get_devices(): """Handle to get devices. Only for default account""" account = msg.get("account", None) client = spotcast_controller.get_spotify_client(account) me_resp = client._get("me") # pylint: disable=W0212 - spotify_media_player = get_spotify_media_player(hass, me_resp["id"]) + spotify_media_player = get_spotify_media_player( + hass, me_resp["id"]) resp = get_spotify_devices(spotify_media_player) - connection.send_message(websocket_api.result_message(msg["id"], resp)) + connection.send_message( + websocket_api.result_message(msg["id"], resp)) hass.async_add_job(get_devices()) @callback - def websocket_handle_player(hass: ha_core.HomeAssistant, connection, msg): + def websocket_handle_player( + hass: ha_core.HomeAssistant, + connection, + msg: str, + ): @async_wrap def get_player(): """Handle to get player""" @@ -142,12 +157,17 @@ def get_player(): _LOGGER.debug("websocket_handle_player msg: %s", msg) client = spotcast_controller.get_spotify_client(account) resp = client._get("me/player") # pylint: disable=W0212 - connection.send_message(websocket_api.result_message(msg["id"], resp)) + connection.send_message( + websocket_api.result_message(msg["id"], resp)) hass.async_add_job(get_player()) @callback - def websocket_handle_accounts(hass: ha_core.HomeAssistant, connection, msg): # pylint: disable=W0613 + def websocket_handle_accounts( + hass: ha_core.HomeAssistant, + connection, + msg: str, + ): """Handle to get accounts""" _LOGGER.debug("websocket_handle_accounts msg: %s", msg) resp = list(accounts.keys()) if accounts is not None else [] @@ -155,7 +175,10 @@ def websocket_handle_accounts(hass: ha_core.HomeAssistant, connection, msg): # connection.send_message(websocket_api.result_message(msg["id"], resp)) @callback - def websocket_handle_castdevices(hass: ha_core.HomeAssistant, connection, msg): + def websocket_handle_castdevices( + hass: ha_core.HomeAssistant, + connection, msg: str + ): """Handle to get cast devices for debug purposes""" _LOGGER.debug("websocket_handle_castdevices msg: %s", msg) @@ -222,18 +245,24 @@ def start_casting(call: ha_core.ServiceCall): account, spotify_device_id, device_name, entity_id ) - if is_empty_str(uri) and is_empty_str(search) and is_empty_str(category): + if ( + is_empty_str(uri) + and is_empty_str(search) + and is_empty_str(category) + ): _LOGGER.debug("Transfering playback") current_playback = client.current_playback() if current_playback is not None: - _LOGGER.debug("Current_playback from spotify: %s", current_playback) + _LOGGER.debug("Current_playback from spotify: %s", + current_playback) force_playback = True _LOGGER.debug("Force playback: %s", force_playback) client.transfer_playback( device_id=spotify_device_id, force_play=force_playback ) elif category: - uri = get_random_playlist_from_category(client, category, country, limit) + uri = get_random_playlist_from_category( + client, category, country, limit) if uri is None: _LOGGER.error("No playlist returned. Stop service call") @@ -265,7 +294,8 @@ def start_casting(call: ha_core.ServiceCall): if start_volume <= 100: _LOGGER.debug("Setting volume to %d", start_volume) time.sleep(2) - client.volume(volume_percent=start_volume, device_id=spotify_device_id) + client.volume(volume_percent=start_volume, + device_id=spotify_device_id) if shuffle: _LOGGER.debug("Turning shuffle on") time.sleep(3) @@ -276,28 +306,44 @@ def start_casting(call: ha_core.ServiceCall): client.repeat(state=repeat, device_id=spotify_device_id) # Register websocket and service - hass.components.websocket_api.async_register_command( - WS_TYPE_SPOTCAST_PLAYLISTS, websocket_handle_playlists, SCHEMA_PLAYLISTS + websocket_api.async_register_command( + hass=hass, + command_or_handler=WS_TYPE_SPOTCAST_PLAYLISTS, + handler=websocket_handle_playlists, + schema=SCHEMA_PLAYLISTS, ) - hass.components.websocket_api.async_register_command( - WS_TYPE_SPOTCAST_DEVICES, websocket_handle_devices, SCHEMA_WS_DEVICES + websocket_api.async_register_command( + hass=hass, + command_or_handler=WS_TYPE_SPOTCAST_DEVICES, + handler=websocket_handle_devices, + schema=SCHEMA_WS_DEVICES, ) - hass.components.websocket_api.async_register_command( - WS_TYPE_SPOTCAST_PLAYER, websocket_handle_player, SCHEMA_WS_PLAYER + websocket_api.async_register_command( + hass=hass, + command_or_handler=WS_TYPE_SPOTCAST_PLAYER, + handler=websocket_handle_player, + schema=SCHEMA_WS_PLAYER, ) - hass.components.websocket_api.async_register_command( - WS_TYPE_SPOTCAST_ACCOUNTS, websocket_handle_accounts, SCHEMA_WS_ACCOUNTS + websocket_api.async_register_command( + hass=hass, + command_or_handler=WS_TYPE_SPOTCAST_ACCOUNTS, + handler=websocket_handle_accounts, + schema=SCHEMA_WS_ACCOUNTS, ) - hass.components.websocket_api.async_register_command( - WS_TYPE_SPOTCAST_CASTDEVICES, - websocket_handle_castdevices, - SCHEMA_WS_CASTDEVICES, + websocket_api.async_register_command( + hass=hass, + command_or_handler=WS_TYPE_SPOTCAST_CASTDEVICES, + handler=websocket_handle_castdevices, + schema=SCHEMA_WS_CASTDEVICES, ) hass.services.register( - DOMAIN, "start", start_casting, schema=SERVICE_START_COMMAND_SCHEMA + domain=DOMAIN, + service="start", + service_func=start_casting, + schema=SERVICE_START_COMMAND_SCHEMA, ) return True From a3ce3efe5130efa09d433a47aae353b305e5705b Mon Sep 17 00:00:00 2001 From: Felix Cusson Date: Fri, 1 Mar 2024 07:56:16 -0500 Subject: [PATCH 2/3] ignored positional argmunents from callback --- custom_components/spotcast/spotify_controller.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/custom_components/spotcast/spotify_controller.py b/custom_components/spotcast/spotify_controller.py index 4e3e3013..5b6c1411 100644 --- a/custom_components/spotcast/spotify_controller.py +++ b/custom_components/spotcast/spotify_controller.py @@ -54,9 +54,15 @@ def receive_message(self, _message, data: dict): 'content-type': 'text/plain;charset=UTF-8' } - request_body = json.dumps({'clientId': self.client, 'deviceId': self.device}) + request_body = json.dumps( + {'clientId': self.client, 'deviceId': self.device}) + + response = requests.post( + 'https://spclient.wg.spotify.com/device-auth/v1/refresh', + headers=headers, + data=request_body + ) - response = requests.post('https://spclient.wg.spotify.com/device-auth/v1/refresh', headers=headers, data=request_body) json_resp = response.json() self.send_message({ "type": TYPE_ADD_USER, @@ -86,13 +92,13 @@ def launch_app(self, timeout=10): if self.access_token is None or self.expires is None: raise ValueError("access_token and expires cannot be empty") - def callback(): + def callback(*_): """Callback function""" self.send_message({"type": TYPE_GET_INFO, "payload": { "remoteName": self.castDevice.cast_info.friendly_name, "deviceID": self.getSpotifyDeviceID(), "deviceAPI_isGroup": False, - },}) + }, }) self.device = None self.credential_error = False @@ -126,4 +132,4 @@ def getSpotifyDeviceID(self) -> str: """ Retrieve the Spotify deviceID from provided chromecast info """ - return hashlib.md5(self.castDevice.cast_info.friendly_name.encode()).hexdigest() \ No newline at end of file + return hashlib.md5(self.castDevice.cast_info.friendly_name.encode()).hexdigest() From 02480d14600590e1e83d3c443a0ce3bb46cef033 Mon Sep 17 00:00:00 2001 From: Felix Cusson Date: Fri, 1 Mar 2024 07:57:51 -0500 Subject: [PATCH 3/3] code cleanup --- custom_components/spotcast/spotify_controller.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/custom_components/spotcast/spotify_controller.py b/custom_components/spotcast/spotify_controller.py index 5b6c1411..93292d2a 100644 --- a/custom_components/spotcast/spotify_controller.py +++ b/custom_components/spotcast/spotify_controller.py @@ -121,7 +121,8 @@ def callback(*_): def quick_play(self, **kwargs): """ Launches the spotify controller and returns when it's ready. - To actually play media, another application using spotify connect is required. + To actually play media, another application using spotify + connect is required. """ self.access_token = kwargs["access_token"] self.expires = kwargs["expires"] @@ -132,4 +133,6 @@ def getSpotifyDeviceID(self) -> str: """ Retrieve the Spotify deviceID from provided chromecast info """ - return hashlib.md5(self.castDevice.cast_info.friendly_name.encode()).hexdigest() + return hashlib.md5( + self.castDevice.cast_info.friendly_name.encode() + ).hexdigest()