Added track caching option & more debugging.

This commit is contained in:
Andrew Dunai 2018-02-01 17:25:52 +02:00
parent 75e62e5fe3
commit c4cb66a759
7 changed files with 108 additions and 3 deletions

View file

@ -63,6 +63,7 @@ Documentation is ![available here](http://clay.readthedocs.io/en/latest/).
- Notifications
- Audio equalizer
- Global hotkeys
- Song file caching
- Configuration UI
- Token caching for faster authorizations
- Song operations (add to library, start station etc.)

View file

@ -615,3 +615,10 @@ class GP(object):
Return True if user is authenticated on Google Play Music, false otherwise.
"""
return self.mobile_client.is_authenticated()
@property
def is_subscribed(self):
"""
Return True if user is subscribed on Google Play Music, false otherwise.
"""
return self.mobile_client.is_subscribed

View file

@ -7,7 +7,7 @@ except ImportError:
codename = None
APP_NAME = 'Clay Player'
VERSION = '0.5.6'
VERSION = '0.6.0'
if codename is not None:
VERSION_WITH_CODENAME = VERSION + '-' + codename(separator='-', id=VERSION)
else:

View file

@ -6,6 +6,7 @@ import urwid
from clay.pages.page import AbstractPage
from clay.log import Logger
from clay.clipboard import copy
from clay.gp import GP
class DebugItem(urwid.AttrMap):
@ -52,12 +53,38 @@ class DebugPage(urwid.Pile, AbstractPage):
self._append_log(log_record)
Logger.get().on_log_event += self._append_log
self.listbox = urwid.ListBox(self.walker)
self.debug_data = urwid.Text('')
super(DebugPage, self).__init__([
('pack', self.debug_data),
('pack', urwid.Text('')),
('pack', urwid.Text('Hit "Enter" to copy selected message to clipboard.')),
('pack', urwid.Divider(u'\u2550')),
self.listbox
])
GP.get().auth_state_changed += self.update
self.update()
def update(self, *_):
"""
Update this widget.
"""
gpclient = GP.get()
self.debug_data.set_text(
'- Is authenticated: {}\n'
'- Is subscribed: {}'.format(
gpclient.is_authenticated,
gpclient.is_subscribed if gpclient.is_authenticated else None
)
)
def _append_log(self, log_record):
"""
Add log record to list.
"""
self.walker.insert(0, urwid.Divider(u'\u2500'))
self.walker.insert(0, DebugItem(log_record))

View file

@ -138,6 +138,10 @@ class SettingsPage(urwid.Columns, AbstractPage):
self.device_id = urwid.Edit(
edit_text=config.get('device_id', '')
)
self.download_tracks = urwid.CheckBox(
'Download tracks before playback',
state=config.get('download_tracks', False)
)
self.equalizer = Equalizer()
super(SettingsPage, self).__init__([urwid.ListBox(urwid.SimpleListWalker([
urwid.Text('Settings'),
@ -151,6 +155,8 @@ class SettingsPage(urwid.Columns, AbstractPage):
urwid.Text('Device ID'),
urwid.AttrWrap(self.device_id, 'input', 'input_focus'),
urwid.Divider(' '),
self.download_tracks,
urwid.Divider(' '),
urwid.AttrWrap(urwid.Button(
'Save', on_press=self.on_save
), 'input', 'input_focus'),
@ -165,7 +171,8 @@ class SettingsPage(urwid.Columns, AbstractPage):
Settings.set_config(dict(
username=self.username.edit_text,
password=self.password.edit_text,
device_id=self.device_id.edit_text
device_id=self.device_id.edit_text,
download_tracks=self.download_tracks.state
))
self.app.set_page('MyLibraryPage')
self.app.log_in()

View file

@ -5,12 +5,18 @@ Media player built using libVLC.
# pylint: disable=too-many-public-methods
from random import randint
import json
try: # Python 3.x
from urllib.request import urlopen
except ImportError: # Python 2.x
from urllib2 import urlopen
from clay import vlc
from clay.eventhook import EventHook
from clay.notifications import NotificationArea
from clay.hotkeys import HotkeyManager
from clay.settings import Settings
from clay import meta
from clay.log import Logger
class Queue(object):
@ -329,10 +335,34 @@ class Player(object):
if track is None:
return
self._is_loading = True
track.get_url(callback=self._play_ready)
self.broadcast_state()
self.track_changed.fire(track)
if Settings.get_config().get('download_tracks', False):
path = Settings.get_cached_file_path(track.store_id + '.mp3')
if path is None:
Logger.get().debug('Track %s not in cache, downloading...', track.store_id)
track.get_url(callback=self._download_track)
else:
Logger.get().debug('Track %s in cache, playing', track.store_id)
self._play_ready(path, None, track)
else:
Logger.get().debug('Starting to stream %s', track.store_id)
track.get_url(callback=self._play_ready)
def _download_track(self, url, error, track):
if error:
NotificationArea.notify('Failed to request media URL: {}'.format(str(error)))
Logger.get().error(
'Failed to request media URL for track %s: %s',
track.store_id,
str(error)
)
return
response = urlopen(url)
path = Settings.save_file_to_cache(track.store_id + '.mp3', response.read())
self._play_ready(path, None, track)
def _play_ready(self, url, error, track):
"""
Called once track's media stream URL request completes.
@ -341,6 +371,11 @@ class Player(object):
self._is_loading = False
if error:
NotificationArea.notify('Failed to request media URL: {}'.format(str(error)))
Logger.get().error(
'Failed to request media URL for track %s: %s',
track.store_id,
str(error)
)
return
assert track
media = vlc.Media(url)

View file

@ -25,6 +25,12 @@ class Settings(object):
if error.errno != errno.EEXIST:
raise
try:
os.makedirs(appdirs.user_cache_dir('clay', 'Clay'))
except OSError as error:
if error.errno != errno.EEXIST:
raise
path = os.path.join(filedir, 'config.yaml')
if not os.path.exists(path):
with open(path, 'w') as settings:
@ -48,3 +54,25 @@ class Settings(object):
config.update(new_config)
with open(Settings.get_config_filename(), 'w') as settings:
settings.write(yaml.dump(config, default_flow_style=False))
@classmethod
def get_cached_file_path(cls, filename):
"""
Get full path to cached file.
"""
cache_dir = appdirs.user_cache_dir('clay', 'Clay')
path = os.path.join(cache_dir, filename)
if os.path.exists(path):
return path
return None
@classmethod
def save_file_to_cache(cls, filename, content):
"""
Save content into file in cache.
"""
cache_dir = appdirs.user_cache_dir('clay', 'Clay')
path = os.path.join(cache_dir, filename)
with open(path, 'wb') as cachefile:
cachefile.write(content)
return path