Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spotify: Play owned/starred playlists by name/by frontend #11887

Closed
wants to merge 18 commits into from
Closed

Spotify: Play owned/starred playlists by name/by frontend #11887

wants to merge 18 commits into from

Conversation

tringler
Copy link
Contributor

@tringler tringler commented Jan 24, 2018

Description:

This PR allows you to play owned/starred playlists by name (or uid/uri) or by frontend without the playlist uid.

Pull request in home-assistant.github.io with documentation (if applicable): home-assistant/home-assistant.github.io# home-assistant/home-assistant.io#4447

Example entry for configuration.yaml (if applicable):

# Play a owned/starred playlist by the name
script:
  script_play_music_starred_playlist:
    sequence:
      - service: media_player.select_source
        data_template:
          source: "{{ source }}"
      - service: media_player.play_media
        data:
          media_content_type: playlist
          media_content_id: 'Top 50 Charts' #or 37i9dQZEVXbJiZcmkrIHGU #or spotify:user:spotifycharts
          entity_id: media_player.spotify

Checklist:

  • The code change is tested and works locally.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • Local tests with tox run successfully. Your PR cannot be merged unless tests pass
  • New dependencies have been added to the REQUIREMENTS variable (example).
  • New dependencies are only imported inside functions that use them (example).
  • New dependencies have been added to requirements_all.txt by running script/gen_requirements_all.py.
  • New files were added to .coveragerc.

If the code does not interact with devices:

  • Local tests with tox run successfully. Your PR cannot be merged unless tests pass
  • Tests have been added to verify that the new code works.

@tschmidty69
Copy link
Contributor

To fix the requirements problem in the build you need to checkout your branch in a virtualenv, pip -e install it and rerun the gen_requirements script. You can't just edit the txt file directly since that isn't what tox does.

@tringler
Copy link
Contributor Author

@andrey-git Could you review my PR please?

Copy link
Contributor

@dgomes dgomes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work!

I'm no oficial reviewer, but here is some feedback.

REQUIREMENTS = ['https://github.com/happyleavesaoc/spotipy/'
'archive/%s.zip#spotipy==2.4.4' % COMMIT]
REQUIREMENTS = ['https://github.com/plamere/spotipy/'
'archive/master.zip#spotipy==2.4.4']
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checked and spotipy is available in pypi in version 2.4.4

No need for tor this hack...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is needed, because the current PyPi 2.4.4 package does not include this PR: spotipy-dev/spotipy#182

The pypi package is from January 2017.
At least I wanted to upgrade from @happyleavesaoc repo to the original master repo.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just download the code from pypi and GitHub

This package is 💩... same version and different content :(

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, definitely track the spotipy release instead of my fork. w.r.t. pypi version, issue has been open for awhile: spotipy-dev/spotipy#211

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe contacting @plamere directly through email ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have the power to merge :)

But the guidelines are well defined: only pypi packages in requirements

Copy link
Contributor Author

@tringler tringler Feb 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That means I cannot improve a component which is using a GitHub repo since years? Don't touch that component otherwise you are forced to persuade the pypi owner to update the package or maintain your own package for us.

Copy link
Contributor

@dgomes dgomes Feb 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reasoning is that the master.zip can change and break stuff, while pypi packages will perdure in time.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great - Then I will revert to @happyleavesaoc commit .zip 👍

Copy link
Contributor Author

@tringler tringler Feb 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will leave it as it is for now - If someone wants to merge it, he can just revert the 618e751 and a667e4b


def save(self):
"""Save playlists."""
with open(self.hass.config.path(PERSISTENCE), 'wt') as file:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Over complicated and "file" is a dangerous variable name, I suggest:

with open(self.hass.config.path(PERSISTENCE), 'wt') as p_file:
    json.dump(self.playlist,p_file)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you suggest how you would simplify it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

look at the code in my comment ...

path = self.hass.config.path(PERSISTENCE)
if not os.path.isfile(path):
return {}
with open(path) as file:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Over complicated and "file" is a dangerous variable name, I suggest:

with open(path) as p_file:
     return json.load(p_file)

if playlist is not None:
self.playlists[playlist['id']] = playlist
self.save()
self.playlists = self.load()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this need to reload a playlist that was just saved ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be removed, but I just wanted to avoid any differences between json and class data. Which approach would you choose? Just load once at init?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't save() enough ?

from your code there is no difference...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then I need to call load() on init, because the idea was to save it locally to avoid all playlists will be discovered at each restart of HASS.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might be a semantic issue... are you updating the persistent file or the playlist variable ? maybe splitting update into two different methods ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to indent lines 20:21 and 25:26, but that looks good

def save(self):
"""Save playlists."""
with open(self.hass.config.path(PERSISTENCE), 'wt') as p_file:
json.dump(self.playlist, yp_file)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

undefined name 'yp_file'


def save(self):
"""Save playlists."""
with open(self.hass.config.path(PERSISTENCE), 'wt') as p_file:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

local variable 'p_file' is assigned to but never used

Copy link
Member

@balloob balloob left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that the approach is wrong. We should not fetch playlists on every update. That's too intense. I also don't think that we should store the playlists on disk.

They should be fetched on demand when the user passes a playlist to play_media

Also please get rid of the view. I think that if we want such a view, we should make it part of the media player component (but in a separate PR)

@tringler
Copy link
Contributor Author

tringler commented Feb 23, 2018

@balloob
The main idea behind the PR is to provide a list of playlists in the media player component frontend, which is updated dynamically if I add/remove/follow/unfollow a playlist. That I can pass a playlistname to play_media is just a side-benefit.

If I fetch the playlists at init of the component I need to restart HASS everytime I update the playlists in Spotify. If I fetch it on demand at play_media action I cannot show it on the frontend as a list.

If I not store it on disk, I need to use the state machine which is also not wanted. Where I should store the data else?

Which approach should I choose?

I agree that the view should be moved to the media_player component.

@balloob
Copy link
Member

balloob commented Feb 26, 2018

We should not store playlists at all.

The HTTP view that the media player will register can just get the live data upon request and then pass it on to the client. That way it is only queried when the user needs it (because they opened the media player more info dialog).

When the user passes a playlist to play_media we will query the playlists and find the right one to use.

Neither use case requires us to store playlists.

@tringler
Copy link
Contributor Author

tringler commented Feb 26, 2018

@balloob Allright. I think it's the best if I close that PR.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants