fondberg / spotcast

Home assistant custom component to start Spotify playback on an idle chromecast device as well as control spotify connect devices
Apache License 2.0
669 stars 95 forks source link

Spotcast stopped working. #347

Closed robkjr closed 2 years ago

robkjr commented 2 years ago

What is this all about? I was able to cast to google speakers and groups last night, but today I get this in the logs. Any ideas? I've tried to update the DC and KEY, but that hasn't worked.

Logger: homeassistant.core Source: custom_components/spotcast/spotify_controller.py:104 Integration: Spotcast (documentation, issues) First occurred: 3:44:55 PM (1 occurrences) Last logged: 3:44:55 PM

Error executing service: <ServiceCall spotcast.start (c:01GBR4HM5R48VM4SZARPTDSMZ4): entity_id=media_player.allspeakers, uri=spotify:playlist:37i9dQZF1DWSSWiBVaJn3j, random_song=False, force_playback=False, start_volume=101, limit=20, repeat=off, ignore_fully_played=False, shuffle=False, offset=0> Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/core.py", line 1731, in catch_exceptions await coro_or_task File "/usr/src/homeassistant/homeassistant/core.py", line 1756, in _execute_service await self._hass.async_add_executor_job( File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) File "/config/custom_components/spotcast/init.py", line 190, in start_casting spotify_device_id = spotcast_controller.get_spotify_device_id( File "/config/custom_components/spotcast/spotcast_controller.py", line 209, in get_spotify_device_id spotify_cast_device.startSpotifyController(access_token, expires) File "/config/custom_components/spotcast/spotcast_controller.py", line 88, in startSpotifyController sp.launch_app() File "/config/custom_components/spotcast/spotify_controller.py", line 104, in launch_app raise LaunchError( pychromecast.error.LaunchError: Timeout when waiting for status response from Spotify app

m4dm4rtig4n commented 2 years ago

Same error here :/

robkjr commented 2 years ago

Same error here :/

Well, that's not good.

DanDixon commented 2 years ago

Also started having this same problem today

I am able to use this Speaker Group if I select it from the Spotify App on Windows.

Source: custom_components/spotcast/spotify_controller.py:58
Integration: Spotcast ([documentation](https://github.com/fondberg/spotcast), [issues](https://github.com/fondberg/spotcast/issues))
First occurred: 2:36:20 PM (2 occurrences)
Last logged: 3:29:01 PM

[Everywhere(192.168.86.250):32052] Exception caught while sending message to controller SpotifyController: Message urn:x-cast:com.spotify.chromecast.secure.v1 from 6ff6f854-e722-4a4d-b0cf-cdb0447a45f0 to sender-0: {'type': 'getInfoResponse', 'payload': {'modelDisplayName': 'Chromecast_Audio', 'brandDisplayName': 'google', 'deviceID': '599253149f22987f1c2c09461c3c3d1b', 'deviceType': 'cast_audio', 'remoteName': 'Living Room Audio', 'clientID': 'd7df0887fb71494ea994202cb473eae7', 'deviceAPI_isGroup': False, 'accountReq': '', 'activeUser': '', 'libraryVersion': '5.15.0_4.24.0-ed6fca3', 'publicKey': 'empty', 'spotifyError': 0, 'scope': 'streaming', 'status': 101, 'statusString': 'OK', 'tokenType': 'accesstoken', 'version': '5.15.0'}}
[(192.168.86.250):32190] Exception caught while sending message to controller SpotifyController: Message urn:x-cast:com.spotify.chromecast.secure.v1 from 6d778836-22a7-4507-b94c-068ea4b9ab39 to sender-0: {'type': 'getInfoResponse', 'payload': {'modelDisplayName': 'Chromecast_Audio', 'brandDisplayName': 'google', 'deviceID': '599253149f22987f1c2c09461c3c3d1b', 'deviceType': 'cast_audio', 'remoteName': 'Living Room Audio', 'clientID': 'd7df0887fb71494ea994202cb473eae7', 'deviceAPI_isGroup': False, 'accountReq': '', 'activeUser': '', 'libraryVersion': '5.15.0_4.24.0-ed6fca3', 'publicKey': 'empty', 'spotifyError': 0, 'scope': 'streaming', 'status': 101, 'statusString': 'OK', 'tokenType': 'accesstoken', 'version': '5.15.0'}}
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 960, in json
    return complexjson.loads(self.content.decode(encoding), **kwargs)
  File "/usr/local/lib/python3.10/site-packages/simplejson/__init__.py", line 525, in loads
    return _default_decoder.decode(s)
  File "/usr/local/lib/python3.10/site-packages/simplejson/decoder.py", line 370, in decode
    obj, end = self.raw_decode(s)
  File "/usr/local/lib/python3.10/site-packages/simplejson/decoder.py", line 400, in raw_decode
    return self.scan_once(s, idx=_w(s, idx).end())
simplejson.errors.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/pychromecast/socket_client.py", line 714, in _route_message
    handled = handler.receive_message(message, data)
  File "/config/custom_components/spotcast/spotify_controller.py", line 58, in receive_message
    json_resp = response.json()
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 968, in json
    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
robkjr commented 2 years ago

@DanDixon well that sucks, but at least I know I'm not the only one.

Dan YES the speaker groups work without issue. Its the fact that SpotCast can't cast to the speakers that is at issue.

mauro967 commented 2 years ago

same mistake this evening!!!!

Logger: homeassistant.core Source: custom_components/spotcast/spotify_controller.py:104 Integration: Spotcast (documentation, issues) First occurred: 00:34:22 (6 occurrences) Last logged: 00:51:57

Error executing service: <ServiceCall spotcast.start (c:01GBRECHWG73ENRCAXEH1CP4WV): force_playback=True, offset=1, random_song=True, start_volume=30, uri=spotify:playlist:37i9dQZF1DWXfoktQogiu0?si=512c5f7d1c984b4d, entity_id=media_player.sala_e_cucina, repeat=off, shuffle=False, limit=20, ignore_fully_played=False> Error executing service: <ServiceCall spotcast.start (c:01GBREFWT61892Z5GXRXYQDJBG): force_playback=True, offset=1, random_song=True, start_volume=30, uri=spotify:playlist:37i9dQZF1DWXfoktQogiu0?si=512c5f7d1c984b4d, entity_id=media_player.sala_e_cucina, repeat=off, shuffle=False, limit=20, ignore_fully_played=False> Error executing service: <ServiceCall spotcast.start (c:01GBREGGKXZDGYCX0TG2EMAHJ1): force_playback=True, offset=1, random_song=True, start_volume=30, uri=spotify:playlist:37i9dQZF1DWXfoktQogiu0?si=512c5f7d1c984b4d, entity_id=media_player.sala_e_cucina, repeat=off, shuffle=False, limit=20, ignore_fully_played=False> Error executing service: <ServiceCall spotcast.start (c:01GBRF3QHDPX803HW5WK3FC2XH): force_playback=True, offset=1, random_song=True, start_volume=30, uri=spotify:playlist:37i9dQZF1DWXfoktQogiu0?si=512c5f7d1c984b4d, entity_id=media_player.sala_e_cucina, repeat=off, shuffle=False, limit=20, ignore_fully_played=False> Error executing service: <ServiceCall spotcast.start (c:01GBRF871VKYC8MEA3J07V617Y): force_playback=True, offset=1, random_song=True, start_volume=30, uri=spotify:playlist:37i9dQZF1DWXfoktQogiu0?si=512c5f7d1c984b4d, entity_id=media_player.sala_e_cucina, repeat=off, shuffle=False, limit=20, ignore_fully_played=False> Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/core.py", line 1731, in catch_exceptions await coro_or_task File "/usr/src/homeassistant/homeassistant/core.py", line 1756, in _execute_service await self._hass.async_add_executor_job( File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) File "/config/custom_components/spotcast/init.py", line 190, in start_casting spotify_device_id = spotcast_controller.get_spotify_device_id( File "/config/custom_components/spotcast/spotcast_controller.py", line 209, in get_spotify_device_id spotify_cast_device.startSpotifyController(access_token, expires) File "/config/custom_components/spotcast/spotcast_controller.py", line 88, in startSpotifyController sp.launch_app() File "/config/custom_components/spotcast/spotify_controller.py", line 104, in launch_app raise LaunchError( pychromecast.error.LaunchError: Timeout when waiting for status response from Spotify app

robkjr commented 2 years ago

So I restarted my HA after clearing the logs and here are the first two errors I get from spotcast

This error originated from a custom integration.

Logger: spotipy.client Source: custom_components/spotcast/init.py:113 Integration: Spotcast (documentation, issues) First occurred: 7:10:32 PM (1 occurrences) Last logged: 7:10:32 PM

HTTP Error for GET to https://api.spotify.com/v1/me/player with Params: {} returned 401 due to Permissions missing

* Error Two *** This error originated from a custom integration.

Logger: homeassistant Source: custom_components/spotcast/init.py:113 Integration: Spotcast (documentation, issues) First occurred: 7:10:32 PM (1 occurrences) Last logged: 7:10:32 PM

Error doing job: Task exception was never retrieved Traceback (most recent call last): File "/usr/local/lib/python3.10/site-packages/spotipy/client.py", line 245, in _internal_call response.raise_for_status() File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 1021, in raise_for_status raise HTTPError(http_error_msg, response=self) requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://api.spotify.com/v1/me/player

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/config/custom_components/spotcast/helpers.py", line 91, in run return await loop.run_in_executor(executor, pfunc) File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) File "/config/custom_components/spotcast/init.py", line 113, in get_player resp = client._get("me/player") File "/usr/local/lib/python3.10/site-packages/spotipy/client.py", line 297, in _get return self._internal_call("GET", url, payload, kwargs) File "/usr/local/lib/python3.10/site-packages/spotipy/client.py", line 267, in _internal_call raise SpotifyException( spotipy.exceptions.SpotifyException: http status: 401, code:-1 - https://api.spotify.com/v1/me/player: Permissions missing, reason: None

mastameista commented 2 years ago

Same errors on my HA after restart, like @robkjr.

In addition, spotify lovelace card keeps on loading playlists: image

Mordaneth commented 2 years ago

Same problem here.

This might be relevant: https://developer.spotify.com/community/news/2022/07/15/mobile-streaming-sdks-update/

1ntroduc3 commented 2 years ago

Just here to tell this also happens here. I also rotated sp_key and such

Ky0sHiR00 commented 2 years ago

Confirmed issue - was wondering about my installation but You cleared out that guys

kreliz commented 2 years ago

Yes also receiving the 401 error as robkjr mentioned above. Tried refreshing the sp_dc and sp_key to be sure but when calling the service i receive the same error in the logs:


2022-08-31 14:16:33.010 ERROR (MainThread) [homeassistant] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/site-packages/spotipy/client.py", line 245, in _internal_call
    response.raise_for_status()
  File "/usr/local/lib/python3.10/site-packages/requests/models.py", line 1021, in raise_for_status
    raise HTTPError(http_error_msg, response=self)
requests.exceptions.HTTPError: 401 Client Error: Unauthorized for url: https://api.spotify.com/v1/me/player

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/config/custom_components/spotcast/helpers.py", line 91, in run
    return await loop.run_in_executor(executor, pfunc)
  File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/config/custom_components/spotcast/__init__.py", line 113, in get_player
    resp = client._get("me/player")
  File "/usr/local/lib/python3.10/site-packages/spotipy/client.py", line 297, in _get
    return self._internal_call("GET", url, payload, kwargs)
  File "/usr/local/lib/python3.10/site-packages/spotipy/client.py", line 267, in _internal_call
    raise SpotifyException(
spotipy.exceptions.SpotifyException: http status: 401, code:-1 - https://api.spotify.com/v1/me/player:
 Permissions missing, reason: None
fcusson commented 2 years ago

All the problem seems to be related to a dependency we use which is spotipy. I will look if Spotipy made any breaking change or if they are aware of a change in the spotify api

PerSterin commented 2 years ago

Same problem here.

robkjr commented 2 years ago

All the problem seems to be related to a dependency we use which is spotipy. I will look if Spotipy made any breaking change or if they are aware of a change in the spotify API

Thanks, Felix. Hope you can get it sorted out.

Qpernicus commented 2 years ago

I have the same error. Probably not related, but I get these for a while, could it be that these led up to a some kind of blacklisting? In that case more of you should have this error as well (with no clear point of origin)

Logger: homeassistant.components.websocket_api.http.connection Source: components/websocket_api/connection.py:102 Integration: Home Assistant WebSocket API (documentation, issues) First occurred: 15:08:16 (1 occurrences) Last logged: 15:08:16

[140263637077488] Error handling message: Unauthorized (unauthorized)

fraintt commented 2 years ago

Same issue here..

prosenba1 commented 2 years ago

same issue here!

same mistake this evening!!!!

Logger: homeassistant.core Source: custom_components/spotcast/spotify_controller.py:104 Integration: Spotcast (documentation, issues) First occurred: 00:34:22 (6 occurrences) Last logged: 00:51:57

Error executing service: <ServiceCall spotcast.start (c:01GBRECHWG73ENRCAXEH1CP4WV): force_playback=True, offset=1, random_song=True, start_volume=30, uri=spotify:playlist:37i9dQZF1DWXfoktQogiu0?si=512c5f7d1c984b4d, entity_id=media_player.sala_e_cucina, repeat=off, shuffle=False, limit=20, ignore_fully_played=False> Error executing service: <ServiceCall spotcast.start (c:01GBREFWT61892Z5GXRXYQDJBG): force_playback=True, offset=1, random_song=True, start_volume=30, uri=spotify:playlist:37i9dQZF1DWXfoktQogiu0?si=512c5f7d1c984b4d, entity_id=media_player.sala_e_cucina, repeat=off, shuffle=False, limit=20, ignore_fully_played=False> Error executing service: <ServiceCall spotcast.start (c:01GBREGGKXZDGYCX0TG2EMAHJ1): force_playback=True, offset=1, random_song=True, start_volume=30, uri=spotify:playlist:37i9dQZF1DWXfoktQogiu0?si=512c5f7d1c984b4d, entity_id=media_player.sala_e_cucina, repeat=off, shuffle=False, limit=20, ignore_fully_played=False> Error executing service: <ServiceCall spotcast.start (c:01GBRF3QHDPX803HW5WK3FC2XH): force_playback=True, offset=1, random_song=True, start_volume=30, uri=spotify:playlist:37i9dQZF1DWXfoktQogiu0?si=512c5f7d1c984b4d, entity_id=media_player.sala_e_cucina, repeat=off, shuffle=False, limit=20, ignore_fully_played=False> Error executing service: <ServiceCall spotcast.start (c:01GBRF871VKYC8MEA3J07V617Y): force_playback=True, offset=1, random_song=True, start_volume=30, uri=spotify:playlist:37i9dQZF1DWXfoktQogiu0?si=512c5f7d1c984b4d, entity_id=media_player.sala_e_cucina, repeat=off, shuffle=False, limit=20, ignore_fully_played=False> Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/core.py", line 1731, in catch_exceptions await coro_or_task File "/usr/src/homeassistant/homeassistant/core.py", line 1756, in _execute_service await self._hass.async_add_executor_job( File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run result = self.fn(*self.args, self.kwargs) File "/config/custom_components/spotcast/init**.py", line 190, in start_casting spotify_device_id = spotcast_controller.get_spotify_device_id( File "/config/custom_components/spotcast/spotcast_controller.py", line 209, in get_spotify_device_id spotify_cast_device.startSpotifyController(access_token, expires) File "/config/custom_components/spotcast/spotcast_controller.py", line 88, in startSpotifyController sp.launch_app() File "/config/custom_components/spotcast/spotify_controller.py", line 104, in launch_app raise LaunchError( pychromecast.error.LaunchError: Timeout when waiting for status response from Spotify app

Gramatus commented 2 years ago

I also have the same issue. I've done a bit of testing and can at least report this for my part:

It seems, at least for me, that anything under https://api.spotify.com/v1/me/player/* fails, while other endpoints works.

Examples:

Works:

https://developer.spotify.com/console/get-recently-played/

{
  "error": {
    "status": 403,
    "message": "Insufficient client scope"
  }
}

https://developer.spotify.com/console/get-user-player/

{
  "error": {
    "status": 401,
    "message": "Permissions missing"
  }
}
seanmccabe commented 2 years ago

Additional log info if it is helpful:

Error executing service: <ServiceCall spotcast.start (c:01GBV23EYV20FCVQ8VWH0P67RW): entity_id=media_player.study_speaker, uri=spotify:playlist:34vmX2Lg32nr1E0TKPEXkC, force_playback=True, random_song=True, repeat=context, shuffle=True, offset=1, start_volume=50, ignore_fully_played=True, limit=20> Traceback (most recent call last): File "/usr/src/homeassistant/homeassistant/core.py", line 1731, in catch_exceptions await coro_or_task File "/usr/src/homeassistant/homeassistant/core.py", line 1756, in _execute_service await self._hass.async_add_executor_job( File "/usr/local/lib/python3.10/concurrent/futures/thread.py", line 58, in run result = self.fn(*self.args, **self.kwargs) File "/config/custom_components/spotcast/init.py", line 190, in start_casting spotify_device_id = spotcast_controller.get_spotify_device_id( File "/config/custom_components/spotcast/spotcast_controller.py", line 209, in get_spotify_device_id spotify_cast_device.startSpotifyController(access_token, expires) File "/config/custom_components/spotcast/spotcast_controller.py", line 88, in startSpotifyController sp.launch_app() File "/config/custom_components/spotcast/spotify_controller.py", line 104, in launch_app raise LaunchError( pychromecast.error.LaunchError: Timeout when waiting for status response from Spotify app

seanmccabe commented 2 years ago

Spotify is having a partial outage on their playlist api. Maybe related? https://status.spotify.dev/

That is resolved, and the issue was happening before this, and continues after

fcusson commented 2 years ago

Please this is an issue ticket not a forum, if you have no additionnal information to provide, A comments that you are affected just create noise while we try to troubleshoot the issue and read relevant logs. Due to the high number of them, comments with no relevant information were deleted.

You can react to the first post to indicate the number of people affected, but clearly at this point every one is affected by the problem, no need to indicate it.

fcusson commented 2 years ago

After exploration our code, the problem seems to be the scope we have with the current tokens that we extract from a connected browser. My guess is that Spotify changed the scope of these tokens making it not possible to get device ids anymore with it. This might mean refactoring the code to use OAuth completely. This is still a guess and mostly to document the current state of my research

jorgeelima commented 2 years ago

Thanks for the feedback on the issue @fcusson. We all appreciate your hard work to find the solution for this amazing integration

Gramatus commented 2 years ago

Another possibly interesting observation that might confirm your suspicions about web player token having a more limited scope @fcusson: I noticed that when I try to cast from https://open.spotify.com/ it seems to open the standard "chrome cast options"-thingy: image

I don't use the web player very often, but as far as I can recall there used to be a list of my chromecast devices on the "choose device" button: image

I also tried using Firefox and in that browser casting is not an option: image

I might simply remember incorrectly, but I am quite sure this worked differently last time I tried.

PerSterin commented 2 years ago

The date does not match the event in Soptcast per se but still.

Sunset of libspotify on May 16, 2022 https://developer.spotify.com/community/news/2022/04/12/libspotify-sunset/

Announcing the new Spotify Web Playback SDK https://developer.spotify.com/community/news/spotify-web-api/

PerSterin commented 2 years ago

Authorization 2.0 In order to make successful Web API requests your app will need a valid access token. One can be obtained through [OAuth 2.0] (https://developer.spotify.com/documentation/general/guides/authorization-guide/).

Guides to authorization 2.0 https://developer.spotify.com/documentation/general/guides/authorization/

Jasperwolsing commented 2 years ago

I got the same issue

ivarw commented 2 years ago

Authorization 2.0 In order to make successful Web API requests your app will need a valid access token. One can be obtained through [OAuth 2.0] (https://developer.spotify.com/documentation/general/guides/authorization-guide/).

Guides to authorization 2.0 https://developer.spotify.com/documentation/general/guides/authorization/

Is this possible with the current version of Spotcast? In that case how?

I see there is a long thread on what seems to be the changes Spotify has implemented.: https://community.spotify.com/t5/Spotify-for-Developers/Please-continue-supporting-iOS-Android-streaming-SDKs/td-p/5416477

Is this the change causing that Spotcast no longer works?

Any other work-around or plans of development on Spotcast to authentificate again?

fcusson commented 2 years ago

Any other work-around or plans of development on Spotcast to authentificate again?

Currently working on drafting a change in the authentication method. That would mean a massive refactoring of the authentification process in the code.

With my currently limited time allocation for spotcast, alone, that will take time to implement, If people are willing and able to help in the refactoring and exploratory changes it will for sure help a lot to makeit work again sooner.

itkama commented 2 years ago

@fcusson Please let us know how we can help. I have a bit of python experience (not much, but better than nothing) and study computer science - so some basic concepts are there too. If there is a way to help, I would gladly try :)

ivarw commented 2 years ago

Any other work-around or plans of development on Spotcast to authentificate again?

Currently working on drafting a change in the authentication method. That would mean a massive refactoring of the authentification process in the code.

With my currently limited time allocation for spotcast, alone, that will take time to implement, If people are willing and able to help in the refactoring and exploratory changes it will for sure help a lot to makeit work again sooner.

I totally understand! Not having much coding experience, and indeed any knowlede on authentification, I have little to contribute with, exept encurraging users to get involved thogh community posts and any channel available. Spotcast is perhaps the most important and usefull integration for my HASS-instance. Thank you for all the effort you have layed down in development!

Is it the case that an updated version would need autthenitification through Oauth 2? Is it doable? Would it involve a complete revision of Spotcast or spesific parts of the code to be re-written. Finally, if that is the case, is it in theory and for the usage in HASS possible to implement changes that would enable the integration's useres to set up an authentification that comolies with Spotify?

Finally an encurragement to all Spotcast users to join the thread on the Spotify Dev. community to make it perfectly clear to our swedish friends that they need to reverse the chabges in authentifications they have implemented. OR ELSE ..... 🤬🤬 ... no more premium-paying customers for you!

Gramatus commented 2 years ago

With my currently limited time allocation for spotcast, alone, that will take time to implement, If people are willing and able to help in the refactoring and exploratory changes it will for sure help a lot to makeit work again sooner.

I'm interested in helping. Not very experienced with Python, but I have tinkered a bit in my own HA instance. And I do development in my day job. I have some limited experience with oauth as well, but not very much. I was playing around with the spotify "Authorization Code Flow" (which I think is the only one that might give us enough permissions?) yesterday and did manage at least to actually get the flow going with some manual fetching in the browser. What I am currently not sure how to handle is the bit where we need to open the page where the user accepts giving the app permissions and then we are redirected to some page. It is easy enough to do if you are setting up a web page in a browser, but I am not sure how to do that from a more "backend" perspective. Have you, or anyone else in this thread, any experience or suggestions on how to do that? However, I think that HA itself uses the same flow so possibly it is quite doable. I might look further into that tomorrow, but it would be interesting to know what challenges have already been solved by others before I try to find new solutions.

Currently working on drafting a change in the authentication method.

So, based on everything I said above, is that draft still in the mental stage or is there a branch or some notes or something that I can take a look at and see if I have any suggestions?

Gramatus commented 2 years ago

However, I think that HA itself uses the same flow so possibly it is quite doable. I might look further into that tomorrow, but it would be interesting to know what challenges have already been solved by others before I try to find new solutions.

Ok, I managed to get the token HA uses for the Spotify integration and that token works for a lot of stuff in Spotify dev console), including /player endpoints. So that probably means there is a solution for the whole oauth without user always opening pages thing.

I also managed to test the token with some of my own code and it works halfway (some missing scopes, that should be ok to fix). I have tried to get my Spotcast to use the token from HA as well, not quite successfull yet. If I get that to work I will also need to extend the scopes, but I think that is doable.

I think I will try to look further into these things tomorrow:

@fcusson Is any this useful help for you? Any tips on where I ought to continue?

snp88 commented 2 years ago

I can help with testing when the change will be more in testing stage ;)

Gramatus commented 2 years ago

I think I will try to look further into these things tomorrow:

  • See if I can use a more or less hardcoded token in Spotcast for test purposes
  • See if I can get enough permissions and scopes with a manually gotten token to make Spotcast work
  • See if I can create a config_flow.py for Spotcast that will setup a similar flow for Spotcast. I tried just copying a few files from Spotify in Core, but that doesn't seem to do the trick. Probably read some docs and stuff.

I actually did the last item first and now think I have a working config_flow.py that gives me the scopes I want (i.e. I can add new scopes as needed). I guess the next step will be to figure out which scopes Spotcast needs to work, and also update Spotcast to actually use the token from the config flow rather than from st.start_session.

ivarw commented 2 years ago

I think I will try to look further into these things tomorrow:

  • See if I can use a more or less hardcoded token in Spotcast for test purposes
  • See if I can get enough permissions and scopes with a manually gotten token to make Spotcast work
  • See if I can create a config_flow.py for Spotcast that will setup a similar flow for Spotcast. I tried just copying a few files from Spotify in Core, but that doesn't seem to do the trick. Probably read some docs and stuff.

Awewaomme work, my friend! You are really helping a great manny people getting the core of numbero uno integration back on track! There is more than a cup of coffee at the end of the rainbow for you.

Gramatus commented 2 years ago

I think I have got the bit with using the token from config flow working, but the actual fix seems harder. I am stuck in SpotifyController.receive_message at the point where we actually use the token by calling https://spclient.wg.spotify.com/device-auth/v1/refresh.

If I use the token based on the web player I get a 401 response. If I use the new oauth token, however, I get 403 which isn't much better. The 403 comes with response data:

{'status': 403, 'message': 'Client not allowed'}

I think this might be some issue with ClientID as it seems the payload in the received message contains a ClientID of d7df0887fb71494ea994202cb473eae7 (which I believe is the web player client id or something, it certainly isn't my person Spotify app). I also tried hardcoding my personal ClientId in the request_body, but that leads to the same 403 error.

The scopes I have requested currently are:

SPOTIFY_SCOPES = [
    # Needed to be able to control playback
    "user-modify-playback-state",
    # Needed in order to read available devices
    "user-read-playback-state",
    # Needed to determine if the user has Spotify Premium
    "user-read-private",
    # Needed for media browsing
    "playlist-read-private",
    "playlist-read-collaborative",
    "user-library-read",
    "user-top-read",
    "user-read-playback-position",
    "user-read-recently-played",
    "user-follow-read",
    # Added for testing
    "playlist-modify-public",
    "playlist-modify-private",
    "streaming"
]

I am planning to put my current work in a fork in not too long, in case someone else wants to have a go and continue from what I am currently not figuring out. Not that I am giving up, but right now I am not sure how to proceed.

Gramatus commented 2 years ago

If anyone is interested in looking and possibly build on what I've done so far my latest version can be found here: https://github.com/Gramatus/spotcast/tree/bug347

Still not working and I don't know why or how to fix it, but hopefully either someone else has good suggestions or I figure something out myself.

Gramatus commented 2 years ago

Looking a bit closer at the error message gave me possibly some more info as it returned a WWW-Authenticate response header with the following information:

Bearer realm="spotify", error="insufficient_scope", error_description="Client not allowed"

Probably needs to look closer at available scopes.

foxymichelle commented 2 years ago

I've been playing around with things here and there, splitting my time between trying to get something temporary working in HA for our morning alarms and just reading up on how the oauth changes, but not actively trying things out.

I was in and out of the Media and Music Assistant interface in HA yesterday, and all of the sudden the Media screen changed to a "Cast" list and added all of my Spotify accounts. I can go into each account and view playlists, etc., but if I hit play, it fails. If I go into the Spotify interface and hit play, then switch to the speaker I was targeting in HA, then the play status will be reflected in HA Media. From there, The HA media play, pause and skip buttons work, but I can't freely start a new song. (I also can't switch speakers - changing speakers shows me what's playing on the new speaker rather than transferring what's playing on the original speaker to the new one.)

When trying to play Spotify, the log error is PLAY command requested but no session is active. An obvious issue.

Once Spotify is started, trying to play a new song throws two log errors. I assume they are the same errors you're logging, so I'll only post if you request them. The first error is the Exception caught while sending message to controller SpotifyController - interestingly, the client ID in my error matches yours: 'clientID': 'd7df0887fb71494ea994202cb473eae7'. The second error is Error executing service: <ServiceCall spotcast.start.... HA will endlessly keep trying, but going into the Spotify app and switching to the song I requested updates and fixes HA's streaming status.

I don't know why the Spotify accounts suddenly showed up in Media - nothing was updated in HA. I'm curious if you see this on your end and know what the deal is. I've included a screenshot of my main Media page. I disable Music Assistant to see if that had anything to do with it, but Media remained the same. MA only lets you log in to one account anyway. These are the 4 accounts added through the official Spotify integration and Spotcast. There's something interesting going on here, though, because the Spotify Card that works with Spotcast still can't pull up playlists, but they are easily accessed through Media. I'm curious if the is an official Spotify thing and Spotcast is overriding their play options... I would need to disable Spotcast and see what's there and working to rule that out.

Maybe I'll have time this evening to load and play with your branch. Thanks for taking this on!

Screen Shot 2022-09-02 at 3 19 45 PM

robkjr commented 2 years ago

So to everyone looking into solving this problem, thanks a million. Right now, all my media projects are on hold as I really don't want to move away from my Google Speakers and Spotify. That said, if anyone is interested in the advice of someone who ran a rather large development organization in another life, I strongly suggest bringing Oauth2 into play here in an easy way for the end users. Following instructions to grab data out of a cookie is fine for those of us with experience doing these things, but for the average end user, not so much. The fix should make integration user friendly as possible. Just my 2c. Take them for what they are.

Gramatus commented 2 years ago

Some more possibly interesting things. I've discovered that I can look for a call to https://spclient.wg.spotify.com/device-auth/v1/refresh in the network tab in chrome, grab the token from the header there and push it into HA, Then I can do the same from there (i.e. post to https://spclient.wg.spotify.com/device-auth/v1/refresh and get an updated device token (?)): image

However, trying either the token created through "sp_dc" and "spkey" or the token from oauth still gives 40x-errors (the sp token gives 401, the oauth token gives 403). So nothing has changed there. The interesting thing is that the web player seems to have a different token scope then the one I get through sp_dc/sp_key. So perhaps something changed there as well.

foxymichelle commented 2 years ago

I actually just made the big switch from Alexa to Google Assistant, not realizing Spotify not working with morning alarms this week was a bigger issue! Still needed to make the switch - Google plays nicer with HA.

I just tried deleting the Spotcast app and the Spotify accounts disappeared from the Media page; added it back in and they came back, so definitely a Spotcast thing. I'll be back at it tonight!

Gramatus commented 2 years ago

Also tried adding every scope listed at https://developer.spotify.com/documentation/general/guides/authorization/scopes/:

playlist-read-private
playlist-read-collaborative
ugc-image-upload
user-follow-read
playlist-modify-private
user-read-email
user-read-private
app-remote-control
streaming
user-modify-playback-state
user-follow-modify
user-library-read
user-library-modify
playlist-modify-public
user-read-playback-state
user-read-currently-playing
user-read-recently-played
user-read-playback-position
user-top-read

Still gives me error="insufficient_scope", error_description="Client not allowed". Seems like this is not just a scoping thing.

Gramatus commented 2 years ago

I think I found the problem. It seems that Spotify gives us a less usable token because of the user-agent string sent when requesting the token. So basically I just had to change that string and things started working again (since the string is in a referenced package, and that package is just about 20 lines of code, I moved the code into this repo).

@fcusson what do you think, is this a feasible solution?

BenHall commented 2 years ago

@Gramatus Nice!! I swapped the file with your PR, restarted and Spotify and spotify-card was working again.

mauro967 commented 2 years ago

@Gramatus WOW!!!!! I modified the file as instructed and everything started working again !!! Big thanks

cdn4lf commented 2 years ago

Loaded the new file from the PR. It works great!

jorgeelima commented 2 years ago

Will it be a new update for the integration to fixe the issue? I don’t know the process to solve

Pollot commented 2 years ago

@Gramatus works like a charm! Big thanks for your work.