implemented a bunch of commands

--HG--
extra : convert_revision : svn%3A41726ec3-264d-0410-9c23-a9f1637257cc/trunk%40115
This commit is contained in:
adrian.sampson 2009-02-05 06:55:45 +00:00
parent 5ee460bcd5
commit 8fe53fec4c
3 changed files with 87 additions and 15 deletions

View file

@ -1 +1,2 @@
from beets.library import Library
import beets.library
Library = beets.library.Library

View file

@ -105,7 +105,8 @@ class Item(object):
self.dirty[key] = False
def __repr__(self):
return 'Item(' + repr(self.record) + ', library=' + self.library + ')'
return 'Item(' + repr(self.record) + \
', library=' + repr(self.library) + ')'
#### item field accessors ####
@ -358,15 +359,26 @@ class Query(object):
c = library.conn.cursor()
c.execute(*self.statement())
return ResultIterator(c, library)
class SubstringQuery(Query):
"""A query that matches a substring in a specific item field."""
class FieldQuery(Query):
"""An abstract query that searches in a specific field for a
pattern.
"""
def __init__(self, field, pattern):
if field not in item_keys:
raise InvalidFieldError(field + ' is not an item key')
self.field = field
self.pattern = pattern
class MatchQuery(FieldQuery):
"""A query that looks for exact matches in an item field."""
def clause(self):
return self.field + " = ?", [self.pattern]
class SubstringQuery(FieldQuery):
"""A query that matches a substring in a specific item field."""
def clause(self):
search = '%' + (self.pattern.replace('\\','\\\\').replace('%','\\%')
@ -490,12 +502,22 @@ class ResultIterator(object):
def __iter__(self): return self
def count(self):
"""Returns the number of matched rows and invalidates the
iterator."""
# Apparently, there is no good way to get the number of rows
# returned by an sqlite SELECT.
num = 0
for i in self:
num += 1
return num
def next(self):
try:
row = self.cursor.next()
except StopIteration:
self.cursor.close()
raise StopIteration
raise
return Item(row, self.library)

View file

@ -8,7 +8,7 @@ use of the wide range of MPD clients.
import eventlet.api
import re
from string import Template
from beets import Library
import beets
import sys
import traceback
@ -152,8 +152,8 @@ class Server(object):
returns its index in the playlist.
"""
track_id = cast_arg(int, track_id)
for index, track in self.playlist:
if _item_id(track) == track_id:
for index, track in enumerate(self.playlist):
if self._item_id(track) == track_id:
return index
# Loop finished with no track found.
raise ArgumentNotFoundError()
@ -311,10 +311,19 @@ class Server(object):
track = self.playlist[index]
except IndexError:
raise ArgumentIndexError()
return SuccessReponse(self._item_info(track))
return SuccessResponse(self._item_info(track))
def cmd_playlistid(self, track_id=-1):
return self.cmd_playlistinfo(self._id_to_index(track_id))
def cmd_plchanges(self, version):
"""Returns playlist changes since the given version.
This is a "fake" implementation that ignores the version and
just returns the entire playlist (rather like version=0). This
seems to satisfy many clients.
"""
return self.cmd_playlistinfo()
def cmd_currentsong(self):
"""Returns information about the currently-playing song.
"""
@ -354,9 +363,13 @@ class Server(object):
self.current_index = index
self.paused = False
def cmd_playid(self, track_id=0):
index = self._id_to_index(track_id)
track_id = cast_arg(int, track_id)
if track_id == -1:
index = -1
else:
index = self._id_to_index(track_id)
self.cmd_play(index)
def cmd_stop(self):
@ -525,7 +538,6 @@ class CommandList(list):
for i, command in enumerate(self):
resp = command.run(server)
print resp.items
out.extend(resp.items)
# If the command failed, stop executing and send the completion
@ -640,16 +652,53 @@ class BGServer(Server):
return item.id
def cmd_lsinfo(self, path="/"):
"""Return info on all the items in the path."""
if path != "/":
raise BPDError(ERROR_NO_EXIST, 'cannot list paths other than /')
return self._items_info(self.lib.get())
def cmd_listallinfo(self, path="/"):
"""Return info on all the items in the directory, recursively."""
# Because we have a flat directory path, this recursive version
# is equivalent to the non-recursive version.
return self.cmd_lsinfo(path)
def cmd_listall(self, path="/"):
"""Return the paths all items in the directory, recursively."""
if path != "/":
raise BPDError(ERROR_NO_EXIST, 'cannot list paths other than /')
out = ['file: ' + i.path for i in self.lib.get()]
return SuccessResponse(out)
def cmd_search(self, key, value):
"""Perform a substring match in a specific column."""
if key == 'filename':
key = 'path'
query = key + ':' + value + ''
query = beets.library.SubstringQuery(key, value)
return self._items_info(self.lib.get(query))
def cmd_find(self, key, value):
"""Perform an exact match in a specific column."""
if key == 'filename':
key = 'path'
query = beets.library.MatchQuery(key, value)
return self._items_info(self.lib.get(query))
def _get_by_path(self, path):
it = self.lib.get(beets.library.MatchQuery('path', path))
try:
return it.next()
except StopIteration:
raise ArgumentNotFoundError()
def cmd_add(self, path):
"""Adds a track to the playlist, specified by its path."""
self.playlist.append(self._get_by_path(path))
self.playlist_version += 1
def cmd_addid(self, path):
"""Same as cmd_add but returns an id."""
track = self._get_by_path(path)
self.playlist.append(track)
self.playlist_version += 1
return SuccessResponse(['Id: ' + str(track.id)])
if __name__ == '__main__':
BGServer(Library('library.blb')).run()
BGServer(beets.Library('library.blb')).run()