X-Git-Url: http://git.kaliko.me/?a=blobdiff_plain;f=musicpd.py;h=d4d1974e146d5b5da5bc79c353492e7c8817d1ac;hb=50d138362c3ae54ff4d995e4479f8ce5182a3d0e;hp=8c5bfc32c155e7cd1b8179ecdca217185239f591;hpb=79fd7d84fe8acbc03b857c4ff483db9c16a0c5b1;p=python-musicpd.git diff --git a/musicpd.py b/musicpd.py index 8c5bfc3..d4d1974 100644 --- a/musicpd.py +++ b/musicpd.py @@ -1,5 +1,5 @@ # python-musicpd: Python MPD client library -# Copyright (C) 2012-2019 kaliko +# Copyright (C) 2012-2020 kaliko # Copyright (C) 2019 Naglis Jonaitis # Copyright (C) 2019 Bart Van Loon # Copyright (C) 2008-2010 J. Alexander Treuman @@ -24,12 +24,11 @@ import os from functools import wraps - HELLO_PREFIX = "OK MPD " ERROR_PREFIX = "ACK " SUCCESS = "OK" NEXT = "list_OK" -VERSION = '0.4.5' +VERSION = '0.6.0' #: seconds before a tcp connection attempt times out CONNECTION_TIMEOUT = 5 @@ -226,6 +225,7 @@ class MPDClient: # Database Commands "albumart": self._fetch_composite, "count": self._fetch_object, + "getfingerprint": self._fetch_object, "find": self._fetch_songs, "findadd": self._fetch_nothing, "list": self._fetch_list, @@ -234,6 +234,7 @@ class MPDClient: "listfiles": self._fetch_database, "lsinfo": self._fetch_database, "readcomments": self._fetch_object, + "readpicture": self._fetch_composite, "search": self._fetch_songs, "searchadd": self._fetch_nothing, "searchaddpl": self._fetch_nothing, @@ -264,6 +265,8 @@ class MPDClient: "partition": self._fetch_nothing, "listpartitions": self._fetch_list, "newpartition": self._fetch_nothing, + "delpartition": self._fetch_nothing, + "moveoutput": self._fetch_nothing, # Audio Output Commands "disableoutput": self._fetch_nothing, "enableoutput": self._fetch_nothing, @@ -391,8 +394,22 @@ class MPDClient: parts.append('"%s"' % escape(str(arg))) self._write_line(" ".join(parts)) - def _read_line(self): - line = self._rfile.readline() + def _read_binary(self, amount): + chunk = bytearray() + while amount > 0: + result = self._rbfile.read(amount) + if len(result) == 0: + self.disconnect() + raise ConnectionError("Connection lost while reading binary content") + chunk.extend(result) + amount -= len(result) + return bytes(chunk) + + def _read_line(self, binary=False): + if binary: + line = self._rbfile.readline().decode('utf-8') + else: + line = self._rfile.readline() if not line.endswith("\n"): self.disconnect() raise ConnectionError("Connection lost while reading line") @@ -409,8 +426,8 @@ class MPDClient: return return line - def _read_pair(self, separator): - line = self._read_line() + def _read_pair(self, separator, binary=False): + line = self._read_line(binary=binary) if line is None: return pair = line.split(separator, 1) @@ -418,11 +435,11 @@ class MPDClient: raise ProtocolError("Could not parse pair: '%s'" % line) return pair - def _read_pairs(self, separator=": "): - pair = self._read_pair(separator) + def _read_pairs(self, separator=": ", binary=False): + pair = self._read_pair(separator, binary=binary) while pair: yield pair - pair = self._read_pair(separator) + pair = self._read_pair(separator, binary=binary) def _read_list(self): seen = None @@ -524,13 +541,27 @@ class MPDClient: def _fetch_composite(self): obj = {} - for key, value in self._read_pairs(): + for key, value in self._read_pairs(binary=True): key = key.lower() obj[key] = value if key == 'binary': break - by = self._read_line() - obj['data'] = by.encode(errors='surrogateescape') + if not obj: + # If the song file was recognized, but there is no picture, the + # response is successful, but is otherwise empty. + return obj + amount = int(obj['binary']) + try: + obj['data'] = self._read_binary(amount) + except IOError as err: + raise ConnectionError('Error reading binary content: %s' % err) + if len(obj['data']) != amount: + raise ConnectionError('Error reading binary content: ' + 'Expects %sB, got %s' % (amount, len(obj['data']))) + # Fetches trailing new line + self._read_line(binary=True) + # Fetches SUCCESS code + self._read_line(binary=True) return obj @iterator_wrapper @@ -553,6 +584,7 @@ class MPDClient: self._command_list = None self._sock = None self._rfile = _NotConnected() + self._rbfile = _NotConnected() self._wfile = _NotConnected() def _connect_unix(self, path): @@ -633,6 +665,7 @@ class MPDClient: else: self._sock = self._connect_tcp(host, port) self._rfile = self._sock.makefile("r", encoding='utf-8', errors='surrogateescape') + self._rbfile = self._sock.makefile("rb") self._wfile = self._sock.makefile("w", encoding='utf-8') try: self._hello() @@ -647,6 +680,8 @@ class MPDClient: """ if hasattr(self._rfile, 'close'): self._rfile.close() + if hasattr(self._rbfile, 'close'): + self._rbfile.close() if hasattr(self._wfile, 'close'): self._wfile.close() if hasattr(self._sock, 'close'):