diff --git a/mopidy/models.py b/mopidy/models.py index 951ada6d..6d0b0dee 100644 --- a/mopidy/models.py +++ b/mopidy/models.py @@ -196,15 +196,24 @@ class Playlist(ImmutableObject): Optionally limit output to the slice ``[start:end]`` of the playlist. :param start: position of first track to include in output - :type start: int + :type start: int (positive or negative) :param end: position after last track to include in output - :type end: int or :class:`None` for end of list + :type end: int (positive or negative) or :class:`None` for end of list :rtype: list of lists of two-tuples """ - if end is None: - end = self.length + if start < 0: + range_start = self.length + start + else: + range_start = start + if end is not None and end < 0: + range_end = self.length - end + elif end is not None and end >= 0: + range_end = end + else: + range_end = self.length tracks = [] - for track, position in zip(self.tracks[start:end], range(start, end)): + for track, position in zip(self.tracks[start:end], + range(range_start, range_end)): tracks.append(track.mpd_format(position, search_result)) return tracks diff --git a/mopidy/mpd/handler.py b/mopidy/mpd/handler.py index d60e16e7..fdd9a5b9 100644 --- a/mopidy/mpd/handler.py +++ b/mopidy/mpd/handler.py @@ -394,7 +394,7 @@ class MpdHandler(object): return self.backend.current_playlist.playlist.mpd_format() @handle_pattern(r'^playlistinfo$') - @handle_pattern(r'^playlistinfo "(?P\d+)"$') + @handle_pattern(r'^playlistinfo "(?P-?\d+)"$') @handle_pattern(r'^playlistinfo "(?P\d+):(?P\d+)*"$') def _current_playlist_playlistinfo(self, songpos=None, start=None, end=None): @@ -406,11 +406,20 @@ class MpdHandler(object): Displays a list of all songs in the playlist, or if the optional argument is given, displays information only for the song ``SONGPOS`` or the range of songs ``START:END``. + + *ncmpc:* + + - uses negative indexes, like ``playlistinfo "-1"``, to request + information on the last track in the playlist. """ if songpos is not None: songpos = int(songpos) + start = songpos + end = songpos + 1 + if start == -1: + end = None return self.backend.current_playlist.playlist.mpd_format( - songpos, songpos + 1) + start, end) else: if start is None: start = 0 diff --git a/tests/modelstest.py b/tests/modelstest.py index 6e4717bf..43d6ca53 100644 --- a/tests/modelstest.py +++ b/tests/modelstest.py @@ -182,6 +182,20 @@ class PlaylistTest(unittest.TestCase): self.assertEqual(len(result), 1) self.assertEqual(dict(result[0])['Track'], 2) + def test_mpd_format_with_negative_start_and_no_end(self): + playlist = Playlist(tracks=[ + Track(track_no=1), Track(track_no=2), Track(track_no=3)]) + result = playlist.mpd_format(-1, None) + self.assertEqual(len(result), 1) + self.assertEqual(dict(result[0])['Track'], 3) + + def test_mpd_format_with_negative_start_and_end(self): + playlist = Playlist(tracks=[ + Track(track_no=1), Track(track_no=2), Track(track_no=3)]) + result = playlist.mpd_format(-2, -1) + self.assertEqual(len(result), 1) + self.assertEqual(dict(result[0])['Track'], 2) + def test_with_new_uri(self): tracks = [Track()] last_modified = dt.datetime.now() diff --git a/tests/mpd/handlertest.py b/tests/mpd/handlertest.py index c030ae94..58187d1e 100644 --- a/tests/mpd/handlertest.py +++ b/tests/mpd/handlertest.py @@ -701,6 +701,10 @@ class CurrentPlaylistHandlerTest(unittest.TestCase): result = self.h.handle_request(u'playlistinfo "5"') self.assert_(u'OK' in result) + def test_playlistinfo_with_negative_songpos(self): + result = self.h.handle_request(u'playlistinfo "-1"') + self.assert_(u'OK' in result) + def test_playlistinfo_with_open_range(self): result = self.h.handle_request(u'playlistinfo "10:"') self.assert_(u'OK' in result)