diff --git a/clay/gp.py b/clay/gp.py index b4b7564..e67268b 100644 --- a/clay/gp.py +++ b/clay/gp.py @@ -4,6 +4,16 @@ Google Play Music integration via gmusicapi. # pylint: disable=broad-except # pylint: disable=protected-access from __future__ import print_function +try: # Python 3.x + from urllib.request import urlopen +except ImportError: # Python 2.x + from urllib import urlopen +try: + from PIL import Image +except ImportError: + Image = None +from io import BytesIO +from hashlib import sha1 from threading import Thread, Lock from uuid import UUID @@ -11,6 +21,7 @@ from gmusicapi.clients import Mobileclient from clay.eventhook import EventHook from clay.log import logger +from clay.settings import settings STATION_FETCH_LEN = 50 @@ -96,12 +107,27 @@ class Track(object): data = data['track'] self.store_id = data['storeId'] + artist_art_ref = next(iter(sorted( + [ + ref + for ref + in data.get('artistArtRef', []) + ], + key=lambda x: x['aspectRatio'] + )), None) self.title = data['title'] self.artist = data['artist'] self.duration = int(data['durationMillis']) self.rating = (int(data['rating']) if 'rating' in data else 0) self.source = source self.cached_url = None + self.artist_art_url = None + self.artist_art_filename = None + if artist_art_ref is not None: + self.artist_art_url = artist_art_ref['url'] + self.artist_art_filename = sha1( + self.artist_art_url.encode('utf-8') + ).hexdigest() + u'.jpg' self.explicit_rating = (int(data['explicitType'])) if self.rating == 5: @@ -194,6 +220,30 @@ class Track(object): track_id = self.library_id gp.get_stream_url_async(track_id, callback=on_get_url) + @synchronized + def get_artist_art_filename(self): + """ + Return artist art filename, None if this track doesn't have any. + Downloads if necessary. + """ + if self.artist_art_url is None: + return None + + if not settings.get_is_file_cached(self.artist_art_filename): + response = urlopen(self.artist_art_url) + data = response.read() + if Image: + image = Image.open(BytesIO(data)) + image.thumbnail((128, 128)) + out = BytesIO() + image.save(out, format='JPEG') + data = out.getvalue() + settings.save_file_to_cache(self.artist_art_filename, data) + + return settings.get_cached_file_path(self.artist_art_filename) + + # get_artist_arg_filename_async = asynchronous(get_artist_art_filename) + @synchronized def create_station(self): """ diff --git a/clay/osd.py b/clay/osd.py index 79a9d44..ebc8901 100644 --- a/clay/osd.py +++ b/clay/osd.py @@ -1,6 +1,8 @@ """ On-screen display stuff. """ +from threading import Thread + from clay.notifications import notification_area from clay import meta @@ -33,21 +35,27 @@ class _OSDManager(object): ) self.notify_interface = Interface(self.notifcations, "org.freedesktop.Notifications") - def notify(self, title, message): + def notify(self, track): """ Create new or update existing notification. """ if IS_INIT: - self._last_id = self.notify_interface.Notify( - meta.APP_NAME, - self._last_id, - 'audio-headphones', - title, - message, - [], - dict(), - 5000 - ) + thread = Thread(target=self._notify, args=(track,)) + thread.daemon = True + thread.start() + + def _notify(self, track): + artist_art_filename = track.get_artist_art_filename() + self._last_id = self.notify_interface.Notify( + meta.APP_NAME, + self._last_id, + artist_art_filename if artist_art_filename is not None else 'audio-headphones', + track.title, + u'by {}\nfrom {}'.format(track.artist, track.album_name), + [], + dict(), + 5000 + ) osd_manager = _OSDManager() # pylint: disable=invalid-name diff --git a/clay/player.py b/clay/player.py index 44d0989..92c7193 100644 --- a/clay/player.py +++ b/clay/player.py @@ -418,10 +418,7 @@ class _Player(object): self.media_player.play() - osd_manager.notify('Now playing', '{} - {}'.format( - track.artist, - track.title - )) + osd_manager.notify(track) @property def is_loading(self): diff --git a/clay/songlist.py b/clay/songlist.py index bcb30b7..ffb318c 100644 --- a/clay/songlist.py +++ b/clay/songlist.py @@ -64,7 +64,9 @@ class SongListItem(urwid.Pile): RATING_ICONS = { 0: ' ', 1: u'\U0001F593' if _unicode else '-', - 4: u'\U0001F593' if _unicode else '-', + 2: u'\U0001F593' if _unicode else '2', + 3: u'\U0001F593' if _unicode else '3', + 4: u'\U0001F593' if _unicode else '4', 5: u'\U0001F592' if _unicode else '+' }