diff --git a/docs/changes.rst b/docs/changes.rst index ef040b9e..e3664013 100644 --- a/docs/changes.rst +++ b/docs/changes.rst @@ -24,6 +24,12 @@ v0.13.0 (in development) the Mopidy process will now always make it log tracebacks for all alive threads. +- :meth:`mopidy.core.TracklistController.add` now accepts an ``uri`` which it + will lookup in the libraries and then add to the tracklist. This is helpful + for e.g. web clients that doesn't want to transfer all track meta data back + to the server just to add it to the tracklist when the server already got all + the needed information easily available. (Fixes: :issue:`325`) + **Audio sub-system** - Make audio error logging handle log messages with non-ASCII chars. (Fixes: diff --git a/mopidy/core/tracklist.py b/mopidy/core/tracklist.py index 402e6c09..1c8f437f 100644 --- a/mopidy/core/tracklist.py +++ b/mopidy/core/tracklist.py @@ -62,10 +62,13 @@ class TracklistController(object): Is not reset before Mopidy is restarted. """ - def add(self, tracks, at_position=None): + def add(self, tracks=None, at_position=None, uri=None): """ Add the track or list of tracks to the tracklist. + If ``uri`` is given instead of ``tracks``, the URI is looked up in the + library and the resulting tracks are added to the tracklist. + If ``at_position`` is given, the tracks placed at the given position in the tracklist. If ``at_position`` is not given, the tracks are appended to the end of the tracklist. @@ -76,9 +79,18 @@ class TracklistController(object): :type tracks: list of :class:`mopidy.models.Track` :param at_position: position in tracklist to add track :type at_position: int or :class:`None` + :param uri: URI for tracks to add + :type uri: string :rtype: list of :class:`mopidy.models.TlTrack` """ + assert tracks is not None or uri is not None, \ + 'tracks or uri must be provided' + + if tracks is None and uri is not None: + tracks = self._core.library.lookup(uri) + tl_tracks = [] + for track in tracks: tl_track = TlTrack(self._next_tlid, track) self._next_tlid += 1 diff --git a/mopidy/frontends/mpd/protocol/current_playlist.py b/mopidy/frontends/mpd/protocol/current_playlist.py index d1b0e59a..055d39e6 100644 --- a/mopidy/frontends/mpd/protocol/current_playlist.py +++ b/mopidy/frontends/mpd/protocol/current_playlist.py @@ -22,11 +22,9 @@ def add(context, uri): """ if not uri: return - tracks = context.core.library.lookup(uri).get() - if tracks: - context.core.tracklist.add(tracks) - return - raise MpdNoExistError('directory or file not found', command='add') + tl_tracks = context.core.tracklist.add(uri=uri).get() + if not tl_tracks: + raise MpdNoExistError('directory or file not found', command='add') @handle_request(r'^addid "(?P[^"]*)"( "(?P\d+)")*$') @@ -52,12 +50,11 @@ def addid(context, uri, songpos=None): raise MpdNoExistError('No such song', command='addid') if songpos is not None: songpos = int(songpos) - tracks = context.core.library.lookup(uri).get() - if not tracks: - raise MpdNoExistError('No such song', command='addid') if songpos and songpos > context.core.tracklist.length.get(): raise MpdArgError('Bad song index', command='addid') - tl_tracks = context.core.tracklist.add(tracks, at_position=songpos).get() + tl_tracks = context.core.tracklist.add(uri=uri, at_position=songpos).get() + if not tl_tracks: + raise MpdNoExistError('No such song', command='addid') return ('Id', tl_tracks[0].tlid) diff --git a/mopidy/frontends/mpris/objects.py b/mopidy/frontends/mpris/objects.py index a9a93b45..04a72676 100644 --- a/mopidy/frontends/mpris/objects.py +++ b/mopidy/frontends/mpris/objects.py @@ -279,9 +279,8 @@ class MprisObject(dbus.service.Object): return # NOTE Check if URI has MIME type known to the backend, if MIME support # is added to the backend. - tracks = self.core.library.lookup(uri).get() - if tracks: - tl_tracks = self.core.tracklist.add(tracks).get() + tl_tracks = self.core.tracklist.add(uri=uri).get() + if tl_tracks: self.core.playback.play(tl_tracks[0]) else: logger.debug('Track with URI "%s" not found in library.', uri) diff --git a/tests/core/tracklist_test.py b/tests/core/tracklist_test.py index 550cfe63..93d914ed 100644 --- a/tests/core/tracklist_test.py +++ b/tests/core/tracklist_test.py @@ -1,5 +1,8 @@ from __future__ import unicode_literals +import mock + +from mopidy.backends import base from mopidy.core import Core from mopidy.models import Track @@ -9,13 +12,31 @@ from tests import unittest class TracklistTest(unittest.TestCase): def setUp(self): self.tracks = [ - Track(uri='a', name='foo'), - Track(uri='b', name='foo'), - Track(uri='c', name='bar') + Track(uri='dummy1:a', name='foo'), + Track(uri='dummy1:b', name='foo'), + Track(uri='dummy1:c', name='bar'), ] - self.core = Core(audio=None, backends=[]) + + self.backend = mock.Mock() + self.backend.uri_schemes.get.return_value = ['dummy1'] + self.library = mock.Mock(spec=base.BaseLibraryProvider) + self.backend.library = self.library + + self.core = Core(audio=None, backends=[self.backend]) self.tl_tracks = self.core.tracklist.add(self.tracks) + def test_add_by_uri_looks_up_uri_in_library(self): + track = Track(uri='dummy1:x', name='x') + self.library.lookup().get.return_value = [track] + self.library.lookup.reset_mock() + + tl_tracks = self.core.tracklist.add(uri='dummy1:x') + + self.library.lookup.assert_called_once_with('dummy1:x') + self.assertEqual(1, len(tl_tracks)) + self.assertEqual(track, tl_tracks[0].track) + self.assertEqual(tl_tracks, self.core.tracklist.tl_tracks[-1:]) + def test_remove_removes_tl_tracks_matching_query(self): tl_tracks = self.core.tracklist.remove(name='foo')