metabrainz / liblistenbrainz

A simple ListenBrainz client library for Python
https://pylistenbrainz.readthedocs.io/en/latest/
GNU General Public License v3.0
27 stars 16 forks source link

Add playlist and recommendation API endpoints #9

Open ssssam opened 2 years ago

ssssam commented 2 years ago

Hello, Listenbrainz has a playlist API, and recently generated 2021 retrospective recommendations for everyone.

These are my initial thoughts on adding support for those to pylistenbrainz. I haven't thought about how the Python API would look.

Stage 1 - read only access

Endpoints to wrap:

* GET `user/<username>/playlists`: fetch <username>'s playlists (metadata only)
* GET `playlist/<id>`: fetch a specific playlist (content included)

Is this something you'd be interested in having in pylistenbrainz API?

Stage 2 - write access

After that's done, write access would involve:

* POST `create`, `edit`, `item/add,move,delete`, `delete`

I noticed this in the docs for create:

If a created_for field is found and the user is not an approved playlist bot, then a 403 forbidden will be raised.

It sounds like write access is not open to everyone right now, so maybe it's not worth adding to pylistenbrainz yet.

paramsingh commented 2 years ago

Is this something you'd be interested in having in pylistenbrainz API?

@ssssam Yes, I'm definitely interested in keeping up with the ListenBrainz API. Is this something you want to write or a feature request for me? I can try to find some time to write this feature this weekend.

It sounds like write access is not open to everyone right now, so maybe it's not worth adding to pylistenbrainz yet.

I think what that means is that you cannot create playlists for other users, I'll dig into it, but if the endpoint can be used in any way by normal users, we should probably support it in pylistenbrainz.

ssssam commented 2 years ago

Is this something you want to write or a feature request for me? I can try to find some time to write this feature this weekend.

Consider it a low priority feature request :) If you could at least come up with an API design then one of us can implement when we get the chance.

I think what that means is that you cannot create playlists for other users

Ah... that makes more sense.

paramsingh commented 2 years ago

Coming up with a design shouldn't be much work. My high-level thoughts (at least for stage 1) are as follows:

get user playlists

def get_user_playlists(self, username, count=None, offset=None) -> PlaylistMetadata:
    pass

PlaylistMetadata is a class wrapping the output of the endpoint.

We can also add a parameter to this method to allow calls to the other 2 playlist retrieval endpoints: https://listenbrainz.readthedocs.io/en/production/dev/api/#get--1-user-(playlist_user_name)-playlists-collaborator and https://listenbrainz.readthedocs.io/en/production/dev/api/#get--1-user-(playlist_user_name)-playlists-createdfor

get playlist data

def get_playlist(self, playlist_id) -> Playlist:
   pass

Playlist is a class wrapping playlists (maybe with to_jspf methods etc)

What do you think?

ssssam commented 2 years ago

We can also add a parameter to this method to allow calls to the other 2 playlist retrieval endpoints

Sounds good, so... created_for and collaborator flags? Would collaborator return the union of playlists/ and playlists/collaborator/ (seems more intuitive) or only playlists/collaborator/ (maps closer to the real API?).

Playlist is a class wrapping playlists (maybe with to_jspf methods etc)

Presumably this would be able to return a PlaylistMetadata object somehow too, since GET /playlist/ includes the metadata?

Being able to output straight to JSPF would be cool, in fact, for my use case that's probably the only thing required.

paramsingh commented 2 years ago

Sounds good, so... created_for and collaborator flags? Would collaborator return the union of playlists/ and playlists/collaborator/ (seems more intuitive) or only playlists/collaborator/ (maps closer to the real API?).

That's what I was thinking, I'll think it over a bit more when I write it.

Presumably this would be able to return a PlaylistMetadata object somehow too, since GET /playlist/ includes the metadata?

Yeah, I think we can just have a metadata prop in the Playlist object which is a PlaylistMetadata.

Being able to output straight to JSPF would be cool, in fact, for my use case that's probably the only thing required.

Makes sense! I'll make sure to include that.

Thanks for your help here!

ssssam commented 2 years ago

I made a start on this - let me know what you think :) https://github.com/paramsingh/pylistenbrainz/pull/10