Add a semi-playlist of the liked songs

This commit is contained in:
Valentijn 2018-03-11 01:20:03 +01:00
parent 8e622266b3
commit 0fc0d0ae79
2 changed files with 57 additions and 4 deletions

View file

@ -69,6 +69,8 @@ Documentation is ![available here](http://clay.readthedocs.io/en/latest/).
# What works # What works
- Playback - Playback
- Configurable keybinds and colours
- Liked songs playlist (cur. static)
- Music library browsing & management - Music library browsing & management
- Playlists - Playlists
- Radio stations - Radio stations
@ -87,7 +89,7 @@ Documentation is ![available here](http://clay.readthedocs.io/en/latest/).
# What is being developed # What is being developed
- Like/dislike tracks - Like/dislike tracks (mostly done but currently is a one time only action)
- Playlist editing - Playlist editing
- Artist/album search - Artist/album search
- Other functionality that is supported by [gmusicapi] - Other functionality that is supported by [gmusicapi]
@ -188,6 +190,8 @@ You *should* get the sound working. Also docker will reuse the Clay config file
- `<CTRL> u` - remove highlighted song from the queue - `<CTRL> u` - remove highlighted song from the queue
- `<CTRL> p` - start station from highlighted song - `<CTRL> p` - start station from highlighted song
- `<ALT> m` - show context menu for this song - `<ALT> m` - show context menu for this song
- `<ALT> u` - thumb up the highlighted song
- `<ALT> d` - thumb down the highlighted song
## Playback ## Playback

View file

@ -101,10 +101,13 @@ class Track(object):
self.title = data['title'] self.title = data['title']
self.artist = data['artist'] self.artist = data['artist']
self.duration = int(data['durationMillis']) self.duration = int(data['durationMillis'])
self.rating = (data['rating'] if 'rating' in data else 0) self.rating = (int(data['rating']) if 'rating' in data else 0)
self.source = source self.source = source
self.cached_url = None self.cached_url = None
if self.rating == 5:
gp.cached_liked_songs.add_liked_song(self)
# User uploaded songs miss a store_id # User uploaded songs miss a store_id
self.album_name = data['album'] self.album_name = data['album']
self.album_url = (data['albumArtRef'][0]['url'] if 'albumArtRef' in data else "") self.album_url = (data['albumArtRef'][0]['url'] if 'albumArtRef' in data else "")
@ -233,6 +236,9 @@ class Track(object):
self.original_data['rating'] = rating self.original_data['rating'] = rating
self.rating = rating self.rating = rating
if rating == 5:
gp.cached_liked_songs.add_liked_song(self)
# print(gp.mobile_client.rate_songs(self.original_data, rating)) # print(gp.mobile_client.rate_songs(self.original_data, rating))
def __str__(self): def __str__(self):
@ -375,6 +381,46 @@ class Playlist(object):
) )
class LikedSongs(object):
"""
A local model that represents the songs that a user liked and displays them as a faux playlist.
This mirrors the "liked songs" generated playlist feature of the Google Play Music apps.
"""
def __init__(self):
self._id = None # pylint: disable=invalid-name
self.name = "Liked Songs"
self._tracks = []
self._sorted = False
@property
def tracks(self):
"""
Get a sorted list of liked tracks.
"""
if self._sorted:
tracks = self._tracks
else:
self._tracks.sort(key=lambda k: k.original_data['lastRatingChangeTimestamp'],
reverse=True)
self._sorted = True
tracks = self._tracks
return tracks
def add_liked_song(self, song):
"""
Add a liked song to the list.
"""
self._tracks.append(song)
def remove_liked_song(self, song):
"""
Remove a liked song from the list
"""
self._tracks.remove(song)
class _GP(object): class _GP(object):
""" """
Interface to :class:`gmusicapi.Mobileclient`. Implements Interface to :class:`gmusicapi.Mobileclient`. Implements
@ -395,6 +441,7 @@ class _GP(object):
# self.debug_file = open('/tmp/clay-api-log.json', 'w') # self.debug_file = open('/tmp/clay-api-log.json', 'w')
# self._last_call_index = 0 # self._last_call_index = 0
self.cached_tracks = None self.cached_tracks = None
self.cached_liked_songs = LikedSongs()
self.cached_playlists = None self.cached_playlists = None
self.invalidate_caches() self.invalidate_caches()
@ -488,6 +535,7 @@ class _GP(object):
return self.cached_tracks return self.cached_tracks
data = self.mobile_client.get_all_songs() data = self.mobile_client.get_all_songs()
self.cached_tracks = Track.from_data(data, Track.SOURCE_LIBRARY, True) self.cached_tracks = Track.from_data(data, Track.SOURCE_LIBRARY, True)
return self.cached_tracks return self.cached_tracks
get_all_tracks_async = asynchronous(get_all_tracks) get_all_tracks_async = asynchronous(get_all_tracks)
@ -506,14 +554,15 @@ class _GP(object):
Return list of :class:`.Playlist` instances. Return list of :class:`.Playlist` instances.
""" """
if self.cached_playlists: if self.cached_playlists:
return self.cached_playlists return [self.cached_liked_songs] + self.cached_playlists
self.get_all_tracks() self.get_all_tracks()
self.cached_playlists = Playlist.from_data( self.cached_playlists = Playlist.from_data(
self.mobile_client.get_all_user_playlist_contents(), self.mobile_client.get_all_user_playlist_contents(),
True True
) )
return self.cached_playlists return [self.cached_liked_songs] + self.cached_playlists
get_all_user_playlist_contents_async = ( # pylint: disable=invalid-name get_all_user_playlist_contents_async = ( # pylint: disable=invalid-name
asynchronous(get_all_user_playlist_contents) asynchronous(get_all_user_playlist_contents)