Spotify media player authorization problem

Anybody tried to use Spotify media player from this PR https://github.com/home-assistant/home-assistant/pull/6980
I have problem with authorisation.

1 Like

What’s the problem?

After I click Configure button in HA and authorization on Spotify website, the browser (Firefox and Chrome) downloads a blank file named spotify. In HA I click “I authorized successfully” and a new configure button appears.
Log:

[homeassistant.components.http] Serving /api/spotify to xxx.xxx.xxx.xxx (auth: False) 17-04-10 16:04:07 INFO (Thread-8) [homeassistant.components.media_player.spotify] no token; requesting authorization

Can you check your config directory for a file called .spotify-token-cache? Do you see any other errors in the log?

There isn’t .spotify-token-cache file in my config directory. No other errors in log. I try today with Chrome Mobile and it shows information that it can’t download spotify file.

I’m seeing the same here. If i do view-source:http://<myurl>/api/spotify?code=xxxx It shows:

<html><head><title>500 Internal Server Error</title></head><body><h1>500 Internal Server Error</h1>Server got itself in trouble</body></html>

The HA logs show that there is an error while handling the oAuth callback:

Apr 10 20:34:03 homeassistant hass[794]: 17-04-10 20:34:03 ERROR (MainThread) [aiohttp.server] Error handling request
Apr 10 20:34:03 homeassistant hass[794]: Traceback (most recent call last):
Apr 10 20:34:03 homeassistant hass[794]:   File "/home/hass/.homeassistant/deps/aiohttp/web_protocol.py", line 417, in start
Apr 10 20:34:03 homeassistant hass[794]:     resp = yield from self._request_handler(request)
Apr 10 20:34:03 homeassistant hass[794]:   File "/home/hass/.homeassistant/deps/aiohttp/web.py", line 289, in _handle
Apr 10 20:34:03 homeassistant hass[794]:     resp = yield from handler(request)
Apr 10 20:34:03 homeassistant hass[794]:   File "/usr/lib/python3.5/asyncio/coroutines.py", line 209, in coro
Apr 10 20:34:03 homeassistant hass[794]:     res = yield from res
Apr 10 20:34:03 homeassistant hass[794]:   File "/usr/lib/python3.5/asyncio/coroutines.py", line 209, in coro
Apr 10 20:34:03 homeassistant hass[794]:     res = yield from res
Apr 10 20:34:03 homeassistant hass[794]:   File "/srv/hass/lib/python3.5/site-packages/homeassistant/components/http/ban.py", line 58, in ban_middleware_handler
Apr 10 20:34:03 homeassistant hass[794]:     return (yield from handler(request))
Apr 10 20:34:03 homeassistant hass[794]:   File "/srv/hass/lib/python3.5/site-packages/homeassistant/components/http/__init__.py", line 422, in handle
Apr 10 20:34:03 homeassistant hass[794]:     result = handler(request, **request.match_info)
Apr 10 20:34:03 homeassistant hass[794]:   File "/home/hass/.homeassistant/custom_components/media_player/spotify.py", line 110, in get
Apr 10 20:34:03 homeassistant hass[794]:     self.oauth.get_access_token(request.GET['code'])
Apr 10 20:34:03 homeassistant hass[794]:   File "/srv/hass/lib/python3.5/site-packages/spotipy/oauth2.py", line 218, in get_access_token
Apr 10 20:34:03 homeassistant hass[794]:     raise SpotifyOauthError(response.reason)
Apr 10 20:34:03 homeassistant hass[794]: spotipy.oauth2.SpotifyOauthError: Bad Request

That’s expected if you submit a bad code. I’ll reset my auth tonight and see if I can replicate these issues. Thanks for trying it out, folks.

It’s the code generated by Spotify and sent to the configured Redirect URI.

BTW: awesome feature. I was working on something similar which used the “Spotilocal” functionality since the Spotify Connect API wasn’t there until recently (?). But that required a local daemon and isn’t as flexible as Spotify Connect. Looking forward to trying this out once it’s working! :slight_smile:

I found this in Raspberry log:

Apr 10 16:04:07 raspberry hass[17119]: warning:couldn't write token cache to .spotify-token-cache

Oh, that’s a problem. Try specifying the cache_path attribute in your configuration. Point it at a location writable by Home Assistant.

media_player:
  - platform: spotify
    client_id: ..
    client_secret: ...
    cache_path: /location/hass/can/write/to/.spotify-token-cache

I use cache_path: /home/homeassistant/.homeassistant/.spotify-token-cache and now there is a .spotify-token-cache file in HA config folder but I have in log something about expired token:

17-04-10 21:20:35 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/lib/python3.4/asyncio/tasks.py", line 233, in _step
    result = coro.throw(exc)
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 359, in async_process_entity
    new_entity, self, update_before_add=update_before_add
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 189, in async_add_entity
    yield from self.hass.loop.run_in_executor(None, entity.update)
  File "/usr/lib/python3.4/asyncio/futures.py", line 388, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.4/asyncio/tasks.py", line 286, in _wakeup
    value = future.result()
  File "/usr/lib/python3.4/asyncio/futures.py", line 277, in result
    raise self._exception
  File "/usr/lib/python3.4/concurrent/futures/thread.py", line 54, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/components/media_player/spotify.py", line 152, in update
    self.refresh_spotify_instance()
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/components/media_player/spotify.py", line 139, in refresh_spotify_instance
    spotipy.oauth2.is_token_expired(self._token_info))
AttributeError: 'module' object has no attribute 'is_token_expired'

I’m not sure why that would be, it works in my tests. But try this!

Change line 139 from

spotipy.oauth2.is_token_expired(self._token_info))
to
self._oauth.is_token_expired(self._token_info))

Unfortunately still the same error.

Did you install spotipy from my fork?

It can’t be exactly the same error, if that line was changed.

If I add the cache path and make the required change the modal box for authorization becomes empty after linking and then disappears. A .spotify-token-cache file (with JSON content) is then written to my HA directory.

No media_player shows up though, but the logs do indicate something went wrong with it:

Apr 10 22:40:38 homeassistant hass[2072]: 17-04-10 22:40:38 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Apr 10 22:40:38 homeassistant hass[2072]: Traceback (most recent call last):
Apr 10 22:40:38 homeassistant hass[2072]:   File "/usr/lib/python3.5/asyncio/tasks.py", line 241, in _step
Apr 10 22:40:38 homeassistant hass[2072]:     result = coro.throw(exc)
Apr 10 22:40:38 homeassistant hass[2072]:   File "/srv/hass/lib/python3.5/site-packages/homeassistant/helpers/entity_component.py", line 359, in async_process_entity
Apr 10 22:40:38 homeassistant hass[2072]:     new_entity, self, update_before_add=update_before_add
Apr 10 22:40:38 homeassistant hass[2072]:   File "/srv/hass/lib/python3.5/site-packages/homeassistant/helpers/entity_component.py", line 189, in async_add_entity
Apr 10 22:40:38 homeassistant hass[2072]:     yield from self.hass.loop.run_in_executor(None, entity.update)
Apr 10 22:40:38 homeassistant hass[2072]:   File "/usr/lib/python3.5/asyncio/futures.py", line 361, in __iter__
Apr 10 22:40:38 homeassistant hass[2072]:     yield self  # This tells Task to wait for completion.
Apr 10 22:40:38 homeassistant hass[2072]:   File "/usr/lib/python3.5/asyncio/tasks.py", line 296, in _wakeup
Apr 10 22:40:38 homeassistant hass[2072]:     future.result()
Apr 10 22:40:38 homeassistant hass[2072]:   File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result
Apr 10 22:40:38 homeassistant hass[2072]:     raise self._exception
Apr 10 22:40:38 homeassistant hass[2072]:   File "/usr/lib/python3.5/concurrent/futures/thread.py", line 55, in run
Apr 10 22:40:38 homeassistant hass[2072]:     result = self.fn(*self.args, **self.kwargs)
Apr 10 22:40:38 homeassistant hass[2072]:   File "/home/hass/.homeassistant/custom_components/media_player/spotify.py", line 154, in update
Apr 10 22:40:38 homeassistant hass[2072]:     item = current.get('item')
Apr 10 22:40:38 homeassistant hass[2072]: AttributeError: 'NoneType' object has no attribute 'get'

I am using your forked spotipy.

This particular exception seems to occur if no media is playing at Spotify.

I then pressed Play on my desktop client and restarted HA.
The media_player then showed up with proper artist/title and fanart. Next seems to work fine as well!

So a few minor things to tweak I guess are:

  1. Deal with caching (e.g. cache = hass.config.path(DEFAULT_CACHE_PATH) like the Ring component is using seems to work better)
  2. Dealing with the token refresh, your change for L139 seems to work
  3. Dealing with a non-playing player where no result is being given

I use this component https://github.com/home-assistant/home-assistant/pull/6980/files#diff-b4e0de3960c941b2052c28b3eabda74b and install spotipy by pip install spotipy==2.4.4 --target ~/.homeassistant/deps. Error isn’t exactly the same. My bad.

17-04-10 23:09:55 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/lib/python3.4/asyncio/tasks.py", line 233, in _step
    result = coro.throw(exc)
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 359, in async_process_entity
    new_entity, self, update_before_add=update_before_add
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 189, in async_add_entity
    yield from self.hass.loop.run_in_executor(None, entity.update)
  File "/usr/lib/python3.4/asyncio/futures.py", line 388, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.4/asyncio/tasks.py", line 286, in _wakeup
    value = future.result()
  File "/usr/lib/python3.4/asyncio/futures.py", line 277, in result
    raise self._exception
  File "/usr/lib/python3.4/concurrent/futures/thread.py", line 54, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/components/media_player/spotify.py", line 152, in update
    self.refresh_spotify_instance()
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/components/media_player/spotify.py", line 139, in refresh_spotify_instance
    self._oauth.is_token_expired(self._token_info))
AttributeError: 'SpotifyOAuth' object has no attribute 'is_token_expired'

That’s the original library. Until the open PR for it has been merged you’ll have to install his fork:

pip3 install https://github.com/happyleavesaoc/spotipy/archive/544614f4b1d508201d363e84e871f86c90aa26b2.zip#spotipy==2.4.4

The original doesn’t yet have support for Spotify Connect.

1 Like

@syphernl Thanks for the notes. I pushed a commit that should address all of those things: https://github.com/home-assistant/home-assistant/pull/6980/commits/e6fedf36dce12942c2b2072e58abdffba910ca76

I was never able to get a “non-playing” state that was empty, only “paused” or “playing”.

@Bieniu Yes, install spotipy the way syphernl specified. Your version is old and doesn’t support the new web connect API, or apparently token refresh in the way the component does it.

1 Like

I installed spotipy like @syphernl shows and player is working! Greate job @happyleaves. Thank you guys for help.
But I have small isuue. When I turn to standby my Spotify player (Denon AVR) in HA log appears this error few times:

17-04-11 07:16:19 ERROR (MainThread) [homeassistant.helpers.entity] Update for media_player.spotify fails
Traceback (most recent call last):
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/helpers/entity.py", line 225, in async_update_ha_state
    None, self.update)
  File "/usr/lib/python3.4/asyncio/futures.py", line 388, in __iter__
    yield self  # This tells Task to wait for completion.
  File "/usr/lib/python3.4/asyncio/tasks.py", line 286, in _wakeup
    value = future.result()
  File "/usr/lib/python3.4/asyncio/futures.py", line 277, in result
    raise self._exception
  File "/usr/lib/python3.4/concurrent/futures/thread.py", line 54, in run
    result = self.fn(*self.args, **self.kwargs)
  File "/srv/homeassistant/homeassistant_venv/lib/python3.4/site-packages/homeassistant/components/media_player/spotify.py", line 167, in update
    self._volume = current.get('device').get('volume_percent') / 100
TypeError: unsupported operand type(s) for /: 'NoneType' and 'int'

Tested it this morning and seems to work a lot better. Awesome stuff, works like a charm!

I wonder whether it would be possible for the player to return to an idle state, because now it always stays at paused indefinite if you pause it at one point?