From f6a66604b8841254069f0b86c0474e2e7a943102 Mon Sep 17 00:00:00 2001 From: Antoine Pierlot-Garcin Date: Tue, 7 Jun 2011 23:46:28 -0400 Subject: [PATCH 01/11] pyspotify now returns unicode objects --- mopidy/backends/spotify/translator.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/mopidy/backends/spotify/translator.py b/mopidy/backends/spotify/translator.py index 21abdf78..0ab4def9 100644 --- a/mopidy/backends/spotify/translator.py +++ b/mopidy/backends/spotify/translator.py @@ -4,7 +4,6 @@ import logging from spotify import Link, SpotifyError from mopidy import settings -from mopidy.backends.spotify import ENCODING from mopidy.models import Artist, Album, Track, Playlist logger = logging.getLogger('mopidy.backends.spotify.translator') @@ -16,7 +15,7 @@ class SpotifyTranslator(object): return Artist(name=u'[loading...]') return Artist( uri=str(Link.from_artist(spotify_artist)), - name=spotify_artist.name().decode(ENCODING, 'replace'), + name=spotify_artist.name() ) @classmethod @@ -24,7 +23,7 @@ class SpotifyTranslator(object): if spotify_album is None or not spotify_album.is_loaded(): return Album(name=u'[loading...]') # TODO pyspotify got much more data on albums than this - return Album(name=spotify_album.name().decode(ENCODING, 'replace')) + return Album(name=spotify_album.name()) @classmethod def to_mopidy_track(cls, spotify_track): @@ -38,7 +37,7 @@ class SpotifyTranslator(object): date = None return Track( uri=uri, - name=spotify_track.name().decode(ENCODING, 'replace'), + name=spotify_track.name(), artists=[cls.to_mopidy_artist(a) for a in spotify_track.artists()], album=cls.to_mopidy_album(spotify_track.album()), track_no=spotify_track.index(), @@ -57,7 +56,7 @@ class SpotifyTranslator(object): try: return Playlist( uri=str(Link.from_playlist(spotify_playlist)), - name=spotify_playlist.name().decode(ENCODING, 'replace'), + name=spotify_playlist.name(), # FIXME if check on link is a hackish workaround for is_local tracks=[cls.to_mopidy_track(t) for t in spotify_playlist if str(Link.from_track(t, 0))], From d46c22dca380f301115d053e9ba8506f54e522f2 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 10 Jun 2011 13:46:50 +0200 Subject: [PATCH 02/11] Make Spotify backend fail early if settings is incomplete --- mopidy/backends/spotify/__init__.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/mopidy/backends/spotify/__init__.py b/mopidy/backends/spotify/__init__.py index 87997059..774273e3 100644 --- a/mopidy/backends/spotify/__init__.py +++ b/mopidy/backends/spotify/__init__.py @@ -72,19 +72,22 @@ class SpotifyBackend(ThreadingActor, Backend): self.gstreamer = None self.spotify = None + # Fail early if settings are not present + self.username = settings.SPOTIFY_USERNAME + self.password = settings.SPOTIFY_PASSWORD + def on_start(self): gstreamer_refs = ActorRegistry.get_by_class(GStreamer) assert len(gstreamer_refs) == 1, 'Expected exactly one running gstreamer.' self.gstreamer = gstreamer_refs[0].proxy() + logger.info(u'Mopidy uses SPOTIFY(R) CORE') self.spotify = self._connect() def _connect(self): from .session_manager import SpotifySessionManager - logger.info(u'Mopidy uses SPOTIFY(R) CORE') logger.debug(u'Connecting to Spotify') - spotify = SpotifySessionManager( - settings.SPOTIFY_USERNAME, settings.SPOTIFY_PASSWORD) + spotify = SpotifySessionManager(self.username, self.password) spotify.start() return spotify From ce8cc55f7932092b0153359d5effd0ab0e8c57f3 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 10 Jun 2011 13:48:50 +0200 Subject: [PATCH 03/11] Log GStreamer output addition at debug level --- mopidy/gstreamer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy/gstreamer.py b/mopidy/gstreamer.py index f52292d2..166c487e 100644 --- a/mopidy/gstreamer.py +++ b/mopidy/gstreamer.py @@ -298,7 +298,7 @@ class GStreamer(ThreadingActor): output.sync_state_with_parent() # Required to add to running pipe gst.element_link_many(self._tee, output) self._outputs.append(output) - logger.info('Added %s', output.get_name()) + logger.debug('GStreamer added %s', output.get_name()) def list_outputs(self): """ From fbc47a041a75d10cebd35576abe98a10005e3054 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 10 Jun 2011 14:15:17 +0200 Subject: [PATCH 04/11] Add more debug logging to stop_all_actors --- mopidy/utils/process.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mopidy/utils/process.py b/mopidy/utils/process.py index 5b09148d..2e18280e 100644 --- a/mopidy/utils/process.py +++ b/mopidy/utils/process.py @@ -22,9 +22,13 @@ def exit_handler(signum, frame): def stop_all_actors(): num_actors = len(ActorRegistry.get_all()) while num_actors: + logger.debug(u'Seeing %d actor and %d non-actor thread(s): %s', + num_actors, threading.active_count() - num_actors, + ', '.join([t.name for t in threading.enumerate()])) logger.debug(u'Stopping %d actor(s)...', num_actors) ActorRegistry.stop_all() num_actors = len(ActorRegistry.get_all()) + logger.debug(u'All actors stopped.') class BaseThread(threading.Thread): def __init__(self): From 2453e6826f93301a0003b869e46d4cb41aeb81b7 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 10 Jun 2011 14:17:29 +0200 Subject: [PATCH 05/11] Add exit_process() function for shutting down Mopidy instead of ActorRegistry.stop_all() --- mopidy/core.py | 5 ++--- mopidy/utils/process.py | 10 ++++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/mopidy/core.py b/mopidy/core.py index b89a5456..8138f198 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -40,11 +40,10 @@ def main(): setup_mixer() setup_backend() setup_frontends() - while ActorRegistry.get_all(): + while True: time.sleep(1) - logger.info(u'No actors left. Exiting...') except KeyboardInterrupt: - logger.info(u'User interrupt. Exiting...') + logger.info(u'Interrupted. Exiting...') stop_all_actors() def parse_options(): diff --git a/mopidy/utils/process.py b/mopidy/utils/process.py index 2e18280e..c1d1c9f5 100644 --- a/mopidy/utils/process.py +++ b/mopidy/utils/process.py @@ -1,5 +1,6 @@ import logging import signal +import thread import threading import gobject @@ -12,12 +13,17 @@ from mopidy import SettingsError logger = logging.getLogger('mopidy.utils.process') +def exit_process(): + logger.debug(u'Interrupting main...') + thread.interrupt_main() + logger.debug(u'Interrupted main') + def exit_handler(signum, frame): """A :mod:`signal` handler which will exit the program on signal.""" signals = dict((k, v) for v, k in signal.__dict__.iteritems() if v.startswith('SIG') and not v.startswith('SIG_')) - logger.info(u'Got %s. Exiting...', signals[signum]) - stop_all_actors() + logger.info(u'Got %s signal', signals[signum]) + exit_process() def stop_all_actors(): num_actors = len(ActorRegistry.get_all()) From 51e43487c37faafe236ac67234d99cc0591d0862 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 10 Jun 2011 14:18:09 +0200 Subject: [PATCH 06/11] Log traceback for exceptions popping up to main() --- mopidy/core.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mopidy/core.py b/mopidy/core.py index 8138f198..8c6e9833 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -44,6 +44,9 @@ def main(): time.sleep(1) except KeyboardInterrupt: logger.info(u'Interrupted. Exiting...') + except Exception as e: + logger.exception(e) + finally: stop_all_actors() def parse_options(): From 8e983c337f4569547c70da9cb7a5f82554d693d9 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Fri, 10 Jun 2011 14:18:38 +0200 Subject: [PATCH 07/11] Only log the error message for SettingsError --- mopidy/core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mopidy/core.py b/mopidy/core.py index 8c6e9833..65472a29 100644 --- a/mopidy/core.py +++ b/mopidy/core.py @@ -42,6 +42,8 @@ def main(): setup_frontends() while True: time.sleep(1) + except SettingsError as e: + logger.error(e.message) except KeyboardInterrupt: logger.info(u'Interrupted. Exiting...') except Exception as e: From 98d410545fd6d7ffff40f88198afde57b6729c6e Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 12 Jun 2011 01:39:57 +0200 Subject: [PATCH 08/11] Add MANIFEST.in to MANIFEST.in --- MANIFEST.in | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MANIFEST.in b/MANIFEST.in index 033c51f2..f3723ecd 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,10 @@ -include LICENSE pylintrc *.rst *.ini data/mopidy.desktop +include *.ini +include *.rst +include LICENSE +include MANIFEST.in +include data/mopidy.desktop include mopidy/backends/spotify/spotify_appkey.key +include pylintrc recursive-include docs * prune docs/_build recursive-include requirements * From 8107c77bcf805ff3ec7e3a64068d13d5bea6287b Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 12 Jun 2011 02:25:51 +0200 Subject: [PATCH 09/11] Require pyspotify 1.3 --- docs/changes.rst | 2 +- mopidy/backends/spotify/__init__.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/changes.rst b/docs/changes.rst index 2c240bfa..2a36fbbc 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -18,7 +18,7 @@ Please note that 0.5.0 requires some updated dependencies, as listed under **Important changes** - If you use the Spotify backend, you *must* upgrade to libspotify 0.0.8 and - pyspotify 1.2. If you install from APT, libspotify and pyspotify will + pyspotify 1.3. If you install from APT, libspotify and pyspotify will automatically be upgraded. If you are not installing from APT, follow the instructions at :doc:`/installation/libspotify/`. diff --git a/mopidy/backends/spotify/__init__.py b/mopidy/backends/spotify/__init__.py index 774273e3..66bcffd4 100644 --- a/mopidy/backends/spotify/__init__.py +++ b/mopidy/backends/spotify/__init__.py @@ -33,7 +33,7 @@ class SpotifyBackend(ThreadingActor, Backend): **Dependencies:** - libspotify == 0.0.8 (libspotify8 package from apt.mopidy.com) - - pyspotify == 1.2 (python-spotify package from apt.mopidy.com) + - pyspotify == 1.3 (python-spotify package from apt.mopidy.com) **Settings:** From 4090c14ae18246d2b14fcd80a31ffd67c563c503 Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 12 Jun 2011 11:37:15 +0200 Subject: [PATCH 10/11] pyspotify 1.3 adds autolinking of tracks. Fixes #34. --- docs/changes.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/changes.rst b/docs/changes.rst index 2a36fbbc..c93e0ee8 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -45,8 +45,9 @@ Please note that 0.5.0 requires some updated dependencies, as listed under workaround of searching and reconnecting to make the playlists appear are no longer necessary. (Fixes: :issue:`59`) - - Replace not decodable characters returned from Spotify instead of throwing - an exception, as we won't try to figure out the encoding of non-UTF-8-data. + - Track's that are no longer available in Spotify's archives are now + "autolinked" to corresponding tracks in other albums, just like the + official Spotify clients do. (Fixes: :issue:`34`) - MPD frontend: From a6c85710050556dd6f3a2893d0a9a42230c0e81c Mon Sep 17 00:00:00 2001 From: Stein Magnus Jodal Date: Sun, 12 Jun 2011 14:19:42 +0200 Subject: [PATCH 11/11] Fix error/reconnect during retrieval of command list. MpdDispatcher returns [] instead of None after the filter refactoring --- mopidy/frontends/mpd/session.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mopidy/frontends/mpd/session.py b/mopidy/frontends/mpd/session.py index 53f4cab7..ce5d3be7 100644 --- a/mopidy/frontends/mpd/session.py +++ b/mopidy/frontends/mpd/session.py @@ -49,7 +49,7 @@ class MpdSession(asynchat.async_chat): Format a response from the MPD command handlers and send it to the client. """ - if response is not None: + if response: response = LINE_TERMINATOR.join(response) logger.debug(u'Response to [%s]:%s: %s', self.client_address, self.client_port, indent(response))