diff --git a/beetsplug/bpd/__init__.py b/beetsplug/bpd/__init__.py index 8d90b5cf6..ab515b388 100644 --- a/beetsplug/bpd/__init__.py +++ b/beetsplug/bpd/__init__.py @@ -583,23 +583,25 @@ class BaseServer(object): """Indicates supported URL schemes. None by default.""" pass - def cmd_playlistinfo(self, conn, index=-1): + def cmd_playlistinfo(self, conn, index=None): """Gives metadata information about the entire playlist or a single track, given by its index. """ - index = cast_arg(int, index) - if index == -1: + if index is None: for track in self.playlist: yield self._item_info(track) else: + indices = self._parse_range(index, accept_single_number=True) try: - track = self.playlist[index] + tracks = [self.playlist[i] for i in indices] except IndexError: raise ArgumentIndexError() - yield self._item_info(track) + for track in tracks: + yield self._item_info(track) - def cmd_playlistid(self, conn, track_id=-1): - if track_id != -1: + def cmd_playlistid(self, conn, track_id=None): + if track_id is not None: + track_id = cast_arg(int, track_id) track_id = self._id_to_index(track_id) return self.cmd_playlistinfo(conn, track_id) @@ -1139,6 +1141,21 @@ class Server(BaseServer): return info_lines + def _parse_range(self, items, accept_single_number=False): + """Convert a range of positions to a list of item info. + MPD specifies ranges as START:STOP (endpoint excluded) for some + commands. Sometimes a single number can be provided instead. + """ + try: + start, stop = str(items).split(':', 1) + except ValueError: + if accept_single_number: + return [cast_arg(int, items)] + raise BPDError(ERROR_ARG, u'bad range syntax') + start = cast_arg(int, start) + stop = cast_arg(int, stop) + return range(start, stop) + def _item_id(self, item): return item.id diff --git a/test/test_player.py b/test/test_player.py index 9bd75519f..735f9c62c 100644 --- a/test/test_player.py +++ b/test/test_player.py @@ -339,8 +339,9 @@ class BPDTestHelper(unittest.TestCase, TestHelper): previous_commands = response[0:pos] self._assert_ok(*previous_commands) response = response[pos] - self.assertEqual(pos, response.err_data[1]) self.assertFalse(response.ok) + if pos is not None: + self.assertEqual(pos, response.err_data[1]) if code is not None: self.assertEqual(code, response.err_data[0]) @@ -781,12 +782,15 @@ class BPDQueueTest(BPDTestHelper): def test_cmd_playlistinfo(self): with self.run_bpd() as client: - self._bpd_add(client, self.item1) + self._bpd_add(client, self.item1, self.item2) responses = client.send_commands( ('playlistinfo',), ('playlistinfo', '0'), + ('playlistinfo', '0:2'), ('playlistinfo', '200')) - self._assert_failed(responses, bpd.ERROR_ARG, pos=2) + self._assert_failed(responses, bpd.ERROR_ARG, pos=3) + self.assertEqual('1', responses[1].data['Id']) + self.assertEqual(['1', '2'], responses[2].data['Id']) def test_cmd_playlistinfo_tagtypes(self): with self.run_bpd() as client: