|
@@ -22,11 +22,12 @@ class MusicObject:
|
|
|
|
|
|
|
|
|
class Song(MusicObject):
|
|
|
- def __init__(self, title, album, albumId, artist, id_):
|
|
|
+ def __init__(self, title, album, albumId, artist, artistId, id_):
|
|
|
self.title = title
|
|
|
self.album = album
|
|
|
self.albumId = albumId
|
|
|
self.artist = artist
|
|
|
+ self.artistId = artistId
|
|
|
self.id = id_
|
|
|
|
|
|
def __repr__(self):
|
|
@@ -48,17 +49,19 @@ class Song(MusicObject):
|
|
|
album = d['album']
|
|
|
albumId = d['albumId']
|
|
|
artist = d['artist']
|
|
|
+ artistId = d['artistId'][0]
|
|
|
try:
|
|
|
id_ = d['id']
|
|
|
except KeyError:
|
|
|
id_ = d['storeId']
|
|
|
- return Song(title, album, albumId, artist, id_)
|
|
|
+ return Song(title, album, albumId, artist, artistId, id_)
|
|
|
|
|
|
|
|
|
class Album(MusicObject):
|
|
|
- def __init__(self, title, artist, year, id_):
|
|
|
+ def __init__(self, title, artist, artistId, year, id_):
|
|
|
self.title = title
|
|
|
self.artist = artist
|
|
|
+ self.artistId = artistId
|
|
|
self.year = year
|
|
|
self.id = id_
|
|
|
|
|
@@ -76,9 +79,10 @@ class Album(MusicObject):
|
|
|
def from_dict(d):
|
|
|
title = d['name']
|
|
|
artist = d['albumArtist']
|
|
|
+ artistId = d['artistId'][0]
|
|
|
year = d['year']
|
|
|
id_ = d['albumId']
|
|
|
- return Album(title, artist, year, id_)
|
|
|
+ return Album(title, artist, artistId, year, id_)
|
|
|
|
|
|
|
|
|
class Artist(MusicObject):
|
|
@@ -129,8 +133,11 @@ class SearchPanel(urwid.ListBox):
|
|
|
def keypress(self, size, key):
|
|
|
if key == 'q':
|
|
|
selected = self.selected_search_obj()
|
|
|
- if selected and type(selected) in (Song, Album):
|
|
|
- self.app.queue_panel.add_to_queue(selected)
|
|
|
+ if selected:
|
|
|
+ if type(selected) == Song:
|
|
|
+ self.app.queue_panel.add_song_to_queue(selected)
|
|
|
+ elif type(selected) == Album:
|
|
|
+ self.app.queue_panel.add_album_to_queue(selected)
|
|
|
elif key == 'e':
|
|
|
self.app.expand(self.selected_search_obj())
|
|
|
elif key == 'j':
|
|
@@ -140,26 +147,25 @@ class SearchPanel(urwid.ListBox):
|
|
|
else:
|
|
|
super().keypress(size, key)
|
|
|
|
|
|
- def set_search_results(self, search_results):
|
|
|
- self.search_results = search_results
|
|
|
- songs, albums, artists = search_results
|
|
|
+ def set_search_results(self, songs, albums, artists):
|
|
|
+ self.search_results = (songs, albums, artists)
|
|
|
|
|
|
self.walker.clear()
|
|
|
|
|
|
- if songs:
|
|
|
- self.walker.append(Song.header())
|
|
|
- for song in songs:
|
|
|
- self.walker.append(song.ui())
|
|
|
+ if artists:
|
|
|
+ self.walker.append(Artist.header())
|
|
|
+ for artist in artists:
|
|
|
+ self.walker.append(artist.ui())
|
|
|
|
|
|
if albums:
|
|
|
self.walker.append(Album.header())
|
|
|
for album in albums:
|
|
|
self.walker.append(album.ui())
|
|
|
|
|
|
- if artists:
|
|
|
- self.walker.append(Artist.header())
|
|
|
- for artist in artists:
|
|
|
- self.walker.append(artist.ui())
|
|
|
+ if songs:
|
|
|
+ self.walker.append(Song.header())
|
|
|
+ for song in songs:
|
|
|
+ self.walker.append(song.ui())
|
|
|
|
|
|
if self.walker:
|
|
|
self.walker.set_focus(1)
|
|
@@ -170,13 +176,13 @@ class SearchPanel(urwid.ListBox):
|
|
|
|
|
|
try:
|
|
|
focus_id -= 1
|
|
|
- if focus_id < len(songs):
|
|
|
- return songs[focus_id]
|
|
|
- focus_id -= (1 + len(songs))
|
|
|
+ if focus_id < len(artists):
|
|
|
+ return artists[focus_id]
|
|
|
+ focus_id -= (1 + len(artists))
|
|
|
if focus_id < len(albums):
|
|
|
return albums[focus_id]
|
|
|
focus_id -= (1 + len(albums))
|
|
|
- return artists[focus_id]
|
|
|
+ return songs[focus_id]
|
|
|
except IndexError:
|
|
|
return None
|
|
|
|
|
@@ -188,10 +194,17 @@ class QueuePanel(urwid.ListBox):
|
|
|
self.queue = []
|
|
|
super().__init__(self.walker)
|
|
|
|
|
|
- def add_to_queue(self, music_obj):
|
|
|
- # assume Song for now
|
|
|
- self.queue.append(music_obj)
|
|
|
- self.walker.append(music_obj.ui())
|
|
|
+ def add_song_to_queue(self, song):
|
|
|
+ self.queue.append(song)
|
|
|
+ self.walker.append(song.ui())
|
|
|
+
|
|
|
+ def add_album_to_queue(self, album):
|
|
|
+ album_info = self.app.g_api.get_album_info(album.id)
|
|
|
+
|
|
|
+ for track in album_info['tracks']:
|
|
|
+ song = Song.from_dict(track)
|
|
|
+ self.queue.append(song)
|
|
|
+ self.walker.append(song.ui())
|
|
|
|
|
|
def drop(self, idx):
|
|
|
if 0 <= idx < len(self.queue):
|
|
@@ -324,15 +337,13 @@ class App(urwid.Pile):
|
|
|
self.progress.set_text(f'{curr_time[0]}:{curr_time[1]:02d}/{total_time[0]}:{total_time[1]:02d}')
|
|
|
|
|
|
def update_now_playing(self):
|
|
|
- msg = str(self.player.playlist)
|
|
|
- msg = ''
|
|
|
if self.play_state == 'play':
|
|
|
self.update_progress()
|
|
|
- self.now_playing.set_text(f'Now Playing: {str(self.current_song)}, {msg}')
|
|
|
+ self.now_playing.set_text(f'Now Playing: {str(self.current_song)}')
|
|
|
self.schedule_refresh()
|
|
|
elif self.play_state == 'pause':
|
|
|
self.update_progress()
|
|
|
- self.now_playing.set_text(f'Paused: {str(self.current_song)}, {msg}')
|
|
|
+ self.now_playing.set_text(f'Paused: {str(self.current_song)}')
|
|
|
else:
|
|
|
self.now_playing.set_text('')
|
|
|
|
|
@@ -407,40 +418,34 @@ class App(urwid.Pile):
|
|
|
|
|
|
def expand(self, obj):
|
|
|
if type(obj) == Song:
|
|
|
- # TODO: Expand Song (probably just album?)
|
|
|
- pass
|
|
|
+ album_info = self.g_api.get_album_info(obj.albumId)
|
|
|
+
|
|
|
+ songs = [Song.from_dict(track) for track in album_info['tracks']]
|
|
|
+ albums = [obj]
|
|
|
+ artists = [Artist(obj.artist, obj.artistId)]
|
|
|
elif type(obj) == Album:
|
|
|
album_info = self.g_api.get_album_info(obj.id)
|
|
|
|
|
|
- songs = []
|
|
|
- for track in album_info['tracks']:
|
|
|
- song = Song.from_dict(track)
|
|
|
- songs.append(song)
|
|
|
- self.search_panel.set_search_results((songs, [], []))
|
|
|
+ songs = [Song.from_dict(track) for track in album_info['tracks']]
|
|
|
+ albums = [obj]
|
|
|
+ artists = [Artist(obj.artist, obj.artistId)]
|
|
|
else: # Artist
|
|
|
- # TODO: Expand Artist (top songs/albums etc)
|
|
|
- pass
|
|
|
+ artist_info = self.g_api.get_artist_info(obj.id)
|
|
|
|
|
|
- def search(self, query):
|
|
|
+ songs = [Song.from_dict(track) for track in artist_info['topTracks']]
|
|
|
+ albums = [Album.from_dict(album) for album in artist_info['albums']]
|
|
|
+ artists = [Artist.from_dict(artist) for artist in artist_info['related_artists']]
|
|
|
+ artists.insert(0, obj)
|
|
|
+ self.search_panel.set_search_results(songs, albums, artists)
|
|
|
|
|
|
+ def search(self, query):
|
|
|
results = self.g_api.search(query)
|
|
|
|
|
|
- songs = []
|
|
|
- for hit in results['song_hits']:
|
|
|
- song = Song.from_dict(hit['track'])
|
|
|
- songs.append(song)
|
|
|
-
|
|
|
- albums = []
|
|
|
- for hit in results['album_hits']:
|
|
|
- album = Album.from_dict(hit['album'])
|
|
|
- albums.append(album)
|
|
|
-
|
|
|
- artists = []
|
|
|
- for hit in results['artist_hits']:
|
|
|
- artist = Artist.from_dict(hit['artist'])
|
|
|
- albums.append(artist)
|
|
|
+ songs = [Song.from_dict(hit['track']) for hit in results['song_hits']]
|
|
|
+ albums = [Album.from_dict(hit['album']) for hit in results['album_hits']]
|
|
|
+ artists = [Artist.from_dict(hit['artist']) for hit in results['artist_hits']]
|
|
|
|
|
|
- self.search_panel.set_search_results((songs, albums, artists))
|
|
|
+ self.search_panel.set_search_results(songs, albums, artists)
|
|
|
self.set_focus(self.search_panel_wrapped)
|
|
|
|
|
|
def cleanup(self):
|
|
@@ -458,7 +463,7 @@ if __name__ == '__main__':
|
|
|
raise urwid.ExitMainLoop()
|
|
|
signal.signal(signal.SIGINT, handle_sigint)
|
|
|
|
|
|
- loop = urwid.MainLoop(app, app.palette, pop_ups=True)
|
|
|
+ loop = urwid.MainLoop(app, app.palette)
|
|
|
app.loop = loop
|
|
|
loop.run()
|
|
|
app.cleanup()
|