Spotify media player (pr 6980)

So the media-player-authorization-problem thread got me hooked on this plugin and I decided to give it a try, but I ran into some troubles. I don’t want to derail that thread, at least before that problem is solved, so I am asking in a new thread instead, hope that’s ok.

Installation looks ok I think. On the first run I got the configuration box and connected to the spotify site to confirm my identity, and .spotify-token-cacheis created in the config dir (/home/homeassistant/.homeassistant), but no new media player shows up in https://<mydomain>:8123/dev-state and I get the following messages in the log:

Apr 12 19:03:50 razberry hass[20731]: 17-04-12 19:03:50 INFO (MainThread) [homeassistant.components.media_player] Setting up media_player.spotify
Apr 12 19:03:50 razberry hass[20731]: 17-04-12 19:03:50 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Apr 12 19:03:50 razberry hass[20731]: Traceback (most recent call last):
Apr 12 19:03:50 razberry hass[20731]: File "/usr/lib/python3.4/asyncio/tasks.py", line 233, in _step
Apr 12 19:03:50 razberry hass[20731]: result = coro.throw(exc)
Apr 12 19:03:50 razberry hass[20731]: File "/srv/homeassistant/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 359, in async_process_entity
Apr 12 19:03:50 razberry hass[20731]: new_entity, self, update_before_add=update_before_add
Apr 12 19:03:50 razberry hass[20731]: File "/srv/homeassistant/lib/python3.4/site-packages/homeassistant/helpers/entity_component.py", line 189, in async_add_entity
Apr 12 19:03:50 razberry hass[20731]: yield from self.hass.loop.run_in_executor(None, entity.update)
Apr 12 19:03:50 razberry hass[20731]: File "/usr/lib/python3.4/asyncio/futures.py", line 388, in __iter__
Apr 12 19:03:50 razberry hass[20731]: yield self  # This tells Task to wait for completion.
Apr 12 19:03:50 razberry hass[20731]: File "/usr/lib/python3.4/asyncio/tasks.py", line 286, in _wakeup
Apr 12 19:03:50 razberry hass[20731]: value = future.result()
Apr 12 19:03:50 razberry hass[20731]: File "/usr/lib/python3.4/asyncio/futures.py", line 277, in result
Apr 12 19:03:50 razberry hass[20731]: raise self._exception
Apr 12 19:03:50 razberry hass[20731]: File "/usr/lib/python3.4/concurrent/futures/thread.py", line 54, in run
Apr 12 19:03:50 razberry hass[20731]: result = self.fn(*self.args, **self.kwargs)
Apr 12 19:03:50 razberry hass[20731]: File "/srv/homeassistant/lib/python3.4/site-packages/homeassistant/components/media_player/spotify.py", line 153, in update
Apr 12 19:03:50 razberry hass[20731]: current = self._player.current_playback()
Apr 12 19:03:50 razberry hass[20731]: AttributeError: 'Spotify' object has no attribute 'current_playback'

###my installation steps
####spotify.py
As for the installation I hope I got it right, I cloned home-assistant and checked out the pr#6980
The hash that I’m using for home-assistant/pr#6980: ff8c226e6271d33f7a2d542ee50b0cfe3e964fad

I made a soft link to the spotify.py in the git repo:
ln -s /srv/homeassistant/src/home-assistant/homeassistant/components/media_player/spotify.py /srv/homeassistant/lib/python3.4/site-packages/homeassistant/components/media_player/

####spotipy.py
After that I activated my virtual environment and installed spotipy from @happyleaves fork
(happyleavesaoc/spotipy: 7499d8e511ce3f5588a16702c9533233ec716cab)

git clone https://github.com/happyleavesaoc/spotipy.git
source /srv/homeassistant/bin/activate
cd spotipy/
python setup.py install

####api
As for the spotify API I created a new app and set the redirect uri to https://<mydomain>:8123/api/spotify
Not sure if this is the way to go, but https://:8123 is the way I connect to home-assistant both outside and inside my network.

####config
for the media player config, all I am using is this (with keys in my secrets files)

- platform: spotify
  client_id: !secret spotify_client_id
  client_secret: !secret spotify_client_secret

Not sure where to go from here. Suggestions?

Something went wrong with your spotipy install. current_playback is a method that my fork added.

From your hass virtual environment, try pip install https://github.com/happyleavesaoc/spotipy/archive/544614f4b1d508201d363e84e871f86c90aa26b2.zip#spotipy==2.4.4

1 Like

Ah, great! Running that command with --force-reinstall --upgrade removed the errors.

I see what I did wrong, I thought I was using your branch,when in fact I was on the master branch by Paul Lamere. Thanks @happyleaves!

I must say that you have done a good job on this. Most operations run fine and I can see myself using this regulary once it’s complete.

That being said, I did run into a couple of problems that I don’t know if they are related to spotify or spotipy:
I can’t seem to start/switch to a playlist using play_media. Starting single tracks works fine.

So URI:s like these work:

spotify:track:644es5aYPJghtZLjM1rmSP
spotify:track:21vNMGKtXBA2a8PaVdIgrM

…but this one doesn’t:

spotify:user:spotify:playlist:4BKT5olNFqLB1FAa8OtC8k

And neither does URI:s to playlists created by my own account.

Also, I noticed that “media_content_type” seems to be ignored, and works the same no matter if it’s set to MUSIC, PLAYLIST or FOO. As long as the URI points to a single track it works, the value will show up in the log though.


This is the error logs when I try starting a playlist:

Apr 12 22:45:18 razberry hass[23773]: 17-04-12 22:45:18 INFO (MainThread) [homeassistant.core] Bus:Handling <Event call_service[L]: service=play_media, service_data=entity_id=media_player.spotify, media_content_type=PLAYLIST, media_content_id=spotify:user:spotify:playlist:4BKT5olNFqLB1FAa8OtC8k, domain=media_player, service_call_id=1977756592-50>
Apr 12 22:45:18 razberry hass[23773]: 17-04-12 22:45:18 ERROR (MainThread) [homeassistant.core] Error doing job: Task exception was never retrieved
Apr 12 22:45:18 razberry hass[23773]: Traceback (most recent call last):
Apr 12 22:45:18 razberry hass[23773]: File "/srv/homeassistant/lib/python3.4/site-packages/spotipy/client.py", line 121, in _internal_call
Apr 12 22:45:18 razberry hass[23773]: r.raise_for_status()
Apr 12 22:45:18 razberry hass[23773]: File "/srv/homeassistant/lib/python3.4/site-packages/requests/models.py", line 909, in raise_for_status
Apr 12 22:45:18 razberry hass[23773]: raise HTTPError(http_error_msg, response=self)
Apr 12 22:45:18 razberry hass[23773]: requests.exceptions.HTTPError: 400 Client Error: Bad Request for url: https://api.spotify.com/v1/me/player/play
Apr 12 22:45:18 razberry hass[23773]: During handling of the above exception, another exception occurred:
Apr 12 22:45:18 razberry hass[23773]: Traceback (most recent call last):
Apr 12 22:45:18 razberry hass[23773]: File "/usr/lib/python3.4/asyncio/tasks.py", line 233, in _step
Apr 12 22:45:18 razberry hass[23773]: result = coro.throw(exc)
Apr 12 22:45:18 razberry hass[23773]: File "/srv/homeassistant/lib/python3.4/site-packages/homeassistant/core.py", line 1010, in _event_to_service_call
Apr 12 22:45:18 razberry hass[23773]: yield from service_handler.func(service_call)
Apr 12 22:45:18 razberry hass[23773]: File "/srv/homeassistant/lib/python3.4/site-packages/homeassistant/components/media_player/__init__.py", line 365, in async_service_handler
Apr 12 22:45:18 razberry hass[23773]: yield from getattr(player, method['method'])(**params)
Apr 12 22:45:18 razberry hass[23773]: File "/usr/lib/python3.4/asyncio/futures.py", line 388, in __iter__
Apr 12 22:45:18 razberry hass[23773]: yield self  # This tells Task to wait for completion.
Apr 12 22:45:18 razberry hass[23773]: File "/usr/lib/python3.4/asyncio/tasks.py", line 286, in _wakeup
Apr 12 22:45:18 razberry hass[23773]: value = future.result()
Apr 12 22:45:18 razberry hass[23773]: File "/usr/lib/python3.4/asyncio/futures.py", line 277, in result
Apr 12 22:45:18 razberry hass[23773]: raise self._exception
Apr 12 22:45:18 razberry hass[23773]: File "/usr/lib/python3.4/concurrent/futures/thread.py", line 54, in run
Apr 12 22:45:18 razberry hass[23773]: result = self.fn(*self.args, **self.kwargs)
Apr 12 22:45:18 razberry hass[23773]: File "/srv/homeassistant/lib/python3.4/site-packages/homeassistant/components/media_player/spotify.py", line 217, in play_media
Apr 12 22:45:18 razberry hass[23773]: self._player.start_playback(uris=[media_id])
Apr 12 22:45:18 razberry hass[23773]: File "/srv/homeassistant/lib/python3.4/site-packages/spotipy/client.py", line 913, in start_playback
Apr 12 22:45:18 razberry hass[23773]: return self._put(self._append_device_id("me/player/play", device_id), payload=data)
Apr 12 22:45:18 razberry hass[23773]: File "/srv/homeassistant/lib/python3.4/site-packages/spotipy/client.py", line 190, in _put
Apr 12 22:45:18 razberry hass[23773]: return self._internal_call('PUT', url, payload, kwargs)
Apr 12 22:45:18 razberry hass[23773]: File "/srv/homeassistant/lib/python3.4/site-packages/spotipy/client.py", line 126, in _internal_call
Apr 12 22:45:18 razberry hass[23773]: headers=r.headers)
Apr 12 22:45:18 razberry hass[23773]: spotipy.client.SpotifyException: http status: 400, code:-1 - https://api.spotify.com/v1/me/player/play:
Apr 12 22:45:18 razberry hass[23773]: Invalid track uri in payload

This is the service data for media_player.play_media that I tried from the dev-service page:

{
"entity_id":"media_player.spotify",
"media_content_id":"spotify:user:spotify:playlist:4BKT5olNFqLB1FAa8OtC8k",
"media_content_type":"PLAYLIST"
}

and I tried other combinations of id/type aswell with the same result.

I added support for media content types “playlist” and “music” (note lower case).

Album is a type of playlist (context_uri in Spotify terminology: https://developer.spotify.com/web-api/start-a-users-playback/).

Thanks for the help, I tested with lowercase, but it makes no difference. I don’t know if it’s of any help to you, but I played around with the spotify web api console, and the following is a valid url that starts the given playlist (tokens edited out):

curl -X PUT "https://api.spotify.com/v1/me/player/play" -H "Accept: application/json" -H "Authorization: Bearer xxxxxxxxxx" -H "Content-Type: application/json" --data "{\"context_uri\":\"spotify:user:spotify:playlist:4BKT5olNFqLB1FAa8OtC8k\"}"

Nothing in the curl command mentions that it’s a playlist, except the uri itself, so I think it’s safe to ignore the value of media_content_type.

The reason I used caps for media_content_type is that’s what the home-assistant documentation mention:
media_content_type: The type of the content to play. Must be one of MUSIC, TVSHOW, VIDEO, EPISODE, CHANNEL or PLAYLIST

Did you update your spotify.py to the latest? I just added the support last night. Maybe I didn’t make that clear.

Your command is right. But its the context_uri that indicates “playlist”. If it was a track, it would be uris. So the distinction is important - and that is what the media_content_type controls.

I know the docs say the content types are in caps, but that’s not accurate: https://github.com/home-assistant/home-assistant/blob/dev/homeassistant/components/media_player/init.py#L85-L90

Heh, well, I thought I did, but I must have messed up the git command. Not sure how to update it the correct way, so I re-cloned it and fetched the PR once more.

So far it has worked great with all playlists I have thrown at it. Good job on the update! :+1:


Btw, these are the steps I took to get the PR the first time (placing it in a local branch spotify):

git clone https://github.com/home-assistant/home-assistant.git
cd home-assistant
git fetch origin pull/6980/head:spotify
git checkout spotify

I am not used working with pull requests and forks (surprising, I know ;)). What’s the best way to get the latest update from a pull request?