diff --git a/src/client.py b/src/client.py index cc043d8..5cc0b11 100644 --- a/src/client.py +++ b/src/client.py @@ -650,57 +650,25 @@ class Client(Base): def _get_albumart(self, album): - data = None if album in self._albums: album = self._albums[album] - if not album.get_tracks(): - return (album, None) self._logger.debug("get albumart for album \"%s\"", album.get_title()) - size = 1 - offset = 0 - index = 0 - # Read data until size is reached - try: - while offset < size: - self._write('albumart', args=[album.get_tracks()[0].get_file(), offset]) + # Use "albumart" command + if album.get_tracks(): + try: + return (album, self._read_binary('albumart', album.get_tracks()[0].get_file(), False)) + except CommandException as e: + # The "albumart" command throws an exception if not found + if e.get_error_number() != Client.PROTOCOL_ERROR_NOEXISTS: + raise e + # If no albumart can be found, use "readpicture" command + for track in album.get_tracks(): + data = self._read_binary('readpicture', track.get_file(), True) + if data: + return (album, data) - # Read first line which tells us whether there is an albumart - line = self._read_line() - if line.startswith(Client.PROTOCOL_ERROR): - error = line[len(Client.PROTOCOL_ERROR):].strip() - self._logger.debug("command failed: %r", error) - raise CommandException(error) - # First line is the file size - size = int(self._parse_dict([line])['size']) - self._logger.debug("size: %d", size) - # Second line is the count of bytes read - binary = int(self._parse_dict([self._read_line()])['binary']) - self._logger.debug("binary: %d", binary) - - # Create new data array on the first iteration - if not data: - data = bytearray(size) - # Create a view for the current chunk of data - data_view = memoryview(data)[offset:offset+binary] - # Read actual bytes - self._read_bytes(data_view, binary) - offset += binary - # Read line break to complete previous repsonse - self._read_line() - # Read command completion - end = self._read_line() - if not end.startswith(Client.PROTOCOL_COMPLETION): - self._logger.debug("albumart not completed") - data = None - break - except CommandException as e: - # If no albumart can be found, do not throw an exception - if e.get_error_number() == Client.PROTOCOL_ERROR_NOEXISTS: - data = None - else: - raise e - return (album, data) + return (album, None) def _get_custom(self, name): @@ -844,6 +812,55 @@ class Client(Base): return None + def _read_binary(self, command, filename, has_mimetype): + data = None + size = 1 + offset = 0 + index = 0 + + # Read data until size is reached + while offset < size: + self._write(command, args=[filename, offset]) + + # Read first line + line = self._read_line() + # Check first line for error + if line.startswith(Client.PROTOCOL_ERROR): + error = line[len(Client.PROTOCOL_ERROR):].strip() + self._logger.debug("command failed: %r", error) + raise CommandException(error) + # Check first line for completion + if line.startswith(Client.PROTOCOL_COMPLETION): + break + # First line is the file size + size = int(self._parse_dict([line])['size']) + self._logger.debug("size: %d", size) + # For some commands the second line is the mimetype + if has_mimetype: + mimetype = self._parse_dict([self._read_line()])['type'] + # Next line is the count of bytes read + binary = int(self._parse_dict([self._read_line()])['binary']) + self._logger.debug("binary: %d", binary) + + # Create new data array on the first iteration + if not data: + data = bytearray(size) + # Create a view for the current chunk of data + data_view = memoryview(data)[offset:offset+binary] + # Read actual bytes + self._read_bytes(data_view, binary) + offset += binary + # Read line break to complete previous repsonse + self._read_line() + # Read command completion + end = self._read_line() + if not end.startswith(Client.PROTOCOL_COMPLETION): + self._logger.debug("albumart not completed") + data = None + break + return data + + def _read_bytes(self, buf, nbytes): self._logger.debug("reading bytes") # Use already buffered data