From 81a76bfd92992ebc8a9d6f102c9f7f0e8d107055 Mon Sep 17 00:00:00 2001 From: Trygve Aaberge Date: Wed, 19 Dec 2012 21:56:02 +0100 Subject: [PATCH 1/5] audio: Define mixer_scale in _setup_mixer --- mopidy/audio/actor.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mopidy/audio/actor.py b/mopidy/audio/actor.py index 3910ee80..78fbd056 100644 --- a/mopidy/audio/actor.py +++ b/mopidy/audio/actor.py @@ -41,6 +41,7 @@ class Audio(pykka.ThreadingActor): self._playbin = None self._mixer = None self._mixer_track = None + self._mixer_scale = None self._software_mixing = False self._appsrc = None self._volume_set = None @@ -150,6 +151,8 @@ class Audio(pykka.ThreadingActor): self._mixer = mixer self._mixer_track = track + self._mixer_scale = ( + self._mixer_track.min_volume, self._mixer_track.max_volume) logger.info( 'Audio mixer set to "%s" using track "%s"', mixer.get_factory().get_name(), track.label) @@ -390,15 +393,13 @@ class Audio(pykka.ThreadingActor): avg_volume = float(sum(volumes)) / len(volumes) internal_scale = (0, 100) - mixer_scale = ( - self._mixer_track.min_volume, self._mixer_track.max_volume) if self._volume_set is not None and self._rescale(self._volume_set, - old=internal_scale, new=mixer_scale) == avg_volume: + old=internal_scale, new=self._mixer_scale) == avg_volume: return self._volume_set else: return self._rescale( - avg_volume, old=mixer_scale, new=internal_scale) + avg_volume, old=self._mixer_scale, new=internal_scale) def set_volume(self, volume): """ @@ -418,10 +419,9 @@ class Audio(pykka.ThreadingActor): self._volume_set = volume internal_scale = (0, 100) - mixer_scale = ( - self._mixer_track.min_volume, self._mixer_track.max_volume) - volume = self._rescale(volume, old=internal_scale, new=mixer_scale) + volume = self._rescale( + volume, old=internal_scale, new=self._mixer_scale) volumes = (volume,) * self._mixer_track.num_channels self._mixer.set_volume(self._mixer_track, volumes) From 8be84a1ea409a38f4898bb40ee4d6654a786d5a4 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 19 Dec 2012 22:40:32 +0100 Subject: [PATCH 2/5] audio: Fix flake8 warning --- mopidy/audio/actor.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mopidy/audio/actor.py b/mopidy/audio/actor.py index 78fbd056..1b6c79b3 100644 --- a/mopidy/audio/actor.py +++ b/mopidy/audio/actor.py @@ -394,8 +394,13 @@ class Audio(pykka.ThreadingActor): internal_scale = (0, 100) - if self._volume_set is not None and self._rescale(self._volume_set, - old=internal_scale, new=self._mixer_scale) == avg_volume: + if self._volume_set is not None: + volume_set_on_mixer_scale = self._rescale( + self._volume_set, old=internal_scale, new=self._mixer_scale) + else: + volume_set_on_mixer_scale = None + + if volume_set_on_mixer_scale == avg_volume: return self._volume_set else: return self._rescale( From d1b2641b863ccee4877eb068df93848d03313a55 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 19 Dec 2012 23:16:45 +0100 Subject: [PATCH 3/5] spotify: Gather the search functionality in one place --- mopidy/backends/spotify/library.py | 56 ++++++++++++++++------ mopidy/backends/spotify/session_manager.py | 13 ----- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/mopidy/backends/spotify/library.py b/mopidy/backends/spotify/library.py index df04058b..f451a93a 100644 --- a/mopidy/backends/spotify/library.py +++ b/mopidy/backends/spotify/library.py @@ -1,8 +1,8 @@ from __future__ import unicode_literals import logging -import Queue +import pykka from spotify import Link, SpotifyError from mopidy.backends import base @@ -67,14 +67,46 @@ class SpotifyLibraryProvider(base.BaseLibraryProvider): def search(self, **query): if not query: - # Since we can't search for the entire Spotify library, we return - # all tracks in the playlists when the query is empty. - tracks = [] - for playlist in self.backend.playlists.playlists: - tracks += playlist.tracks - return tracks + return self._get_all_tracks() + + spotify_query = self._translate_search_query(query) + logger.debug('Spotify search query: %s' % spotify_query) + + future = pykka.ThreadingFuture() + + def callback(results, userdata=None): + # TODO Include results from results.albums(), etc. too + # TODO Consider launching a second search if results.total_tracks() + # is larger than len(results.tracks()) + tracks = [ + translator.to_mopidy_track(t) for t in results.tracks()] + future.set(tracks) + + self.backend.spotify.connected.wait() + + self.backend.spotify.session.search( + spotify_query, callback, + track_count=100, album_count=0, artist_count=0) + + timeout = 10 # TODO Make this a setting + try: + return future.get(timeout=timeout) + except pykka.Timeout: + logger.debug( + 'Timeout: Spotify search did not return in %ds', timeout) + return [] + + def _get_all_tracks(self): + # Since we can't search for the entire Spotify library, we return + # all tracks in the playlists when the query is empty. + tracks = [] + for playlist in self.backend.playlists.playlists: + tracks += playlist.tracks + return tracks + + def _translate_search_query(self, mopidy_query): spotify_query = [] - for (field, values) in query.iteritems(): + for (field, values) in mopidy_query.iteritems(): if field == 'uri': tracks = [] for value in values: @@ -97,10 +129,4 @@ class SpotifyLibraryProvider(base.BaseLibraryProvider): else: spotify_query.append('%s:"%s"' % (field, value)) spotify_query = ' '.join(spotify_query) - logger.debug('Spotify search query: %s' % spotify_query) - queue = Queue.Queue() - self.backend.spotify.search(spotify_query, queue) - try: - return queue.get(timeout=3) # XXX What is an reasonable timeout? - except Queue.Empty: - return [] + return spotify_query diff --git a/mopidy/backends/spotify/session_manager.py b/mopidy/backends/spotify/session_manager.py index 288c61f2..f2631406 100644 --- a/mopidy/backends/spotify/session_manager.py +++ b/mopidy/backends/spotify/session_manager.py @@ -165,19 +165,6 @@ class SpotifySessionManager(process.BaseThread, PyspotifySessionManager): logger.info('Loaded %d Spotify playlist(s)', len(playlists)) BackendListener.send('playlists_loaded') - def search(self, query, queue): - """Search method used by Mopidy backend""" - def callback(results, userdata=None): - # TODO Include results from results.albums(), etc. too - # TODO Consider launching a second search if results.total_tracks() - # is larger than len(results.tracks()) - tracks = [ - translator.to_mopidy_track(t) for t in results.tracks()] - queue.put(tracks) - self.connected.wait() - self.session.search( - query, callback, track_count=100, album_count=0, artist_count=0) - def logout(self): """Log out from spotify""" logger.debug('Logging out from Spotify') From 3cdc9e4e99c3284cc72ccce8a472610237790e95 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 19 Dec 2012 23:25:20 +0100 Subject: [PATCH 4/5] spotify: Add SPOTIFY_TIMEOUT setting --- docs/changes.rst | 5 +++++ mopidy/settings.py | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/docs/changes.rst b/docs/changes.rst index 8d614f1d..b5217200 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -8,6 +8,11 @@ This change log is used to track all major changes to Mopidy. v0.11.0 (in development) ======================== +**Spotify backend** + +- Add :attr:`mopidy.settings.SPOTIFY_TIMEOUT` setting which allows you to + control how long we should wait before giving up on Spotify searches, etc. + **MPD frontend** - Add support for the ``findadd`` command. diff --git a/mopidy/settings.py b/mopidy/settings.py index 0a71ccfa..0a272035 100644 --- a/mopidy/settings.py +++ b/mopidy/settings.py @@ -282,3 +282,12 @@ SPOTIFY_PROXY_USERNAME = None #: #: SPOTIFY_PROXY_PASSWORD = None SPOTIFY_PROXY_PASSWORD = None + +#: Max number of seconds to wait for Spotify operations to complete. +#: +#: Used by :mod:`mopidy.backends.spotify` +#: +#: Default:: +#: +#: SPOTIFY_TIMEOUT = 10 +SPOTIFY_TIMEOUT = 10 From 8baf813fb6dd8858d85a20c016dffb184686cea1 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Wed, 19 Dec 2012 23:31:33 +0100 Subject: [PATCH 5/5] spotify: Use SPOTIFY_TIMEOUT in search --- mopidy/backends/spotify/library.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/mopidy/backends/spotify/library.py b/mopidy/backends/spotify/library.py index f451a93a..ca6ee92a 100644 --- a/mopidy/backends/spotify/library.py +++ b/mopidy/backends/spotify/library.py @@ -5,6 +5,7 @@ import logging import pykka from spotify import Link, SpotifyError +from mopidy import settings from mopidy.backends import base from mopidy.models import Track @@ -82,18 +83,20 @@ class SpotifyLibraryProvider(base.BaseLibraryProvider): translator.to_mopidy_track(t) for t in results.tracks()] future.set(tracks) - self.backend.spotify.connected.wait() + if not self.backend.spotify.connected.wait(settings.SPOTIFY_TIMEOUT): + logger.debug('Not connected: Spotify search cancelled') + return [] self.backend.spotify.session.search( spotify_query, callback, track_count=100, album_count=0, artist_count=0) - timeout = 10 # TODO Make this a setting try: - return future.get(timeout=timeout) + return future.get(timeout=settings.SPOTIFY_TIMEOUT) except pykka.Timeout: logger.debug( - 'Timeout: Spotify search did not return in %ds', timeout) + 'Timeout: Spotify search did not return in %ds', + settings.SPOTIFY_TIMEOUT) return [] def _get_all_tracks(self):