From 96e2b25670b663346cc8ad897d3c2705f37fa488 Mon Sep 17 00:00:00 2001 From: kaliko Date: Wed, 22 Apr 2015 15:31:08 +0200 Subject: [PATCH 1/1] Initial import --- musicpdasio.py | 122 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 musicpdasio.py diff --git a/musicpdasio.py b/musicpdasio.py new file mode 100644 index 0000000..3848ecd --- /dev/null +++ b/musicpdasio.py @@ -0,0 +1,122 @@ +# -*- coding: utf-8 -*- +# +# python-musicpd: Python MPD client library +# Copyright (C) 2014-2015 Kaliko Jack +# +# python-musicpdasio is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# python-musicpd is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with python-musicpd. If not, see . + +try: + import asyncio +except ImportError: + print('Failed to import asyncio, need python >= 3.4') + +import sys + +HELLO_PREFIX = "OK MPD " +ERROR_PREFIX = "ACK " +SUCCESS = "OK" +NEXT = "list_OK" + + +class MPDError(Exception): + pass + +class ConnectionError(MPDError): + pass + +class ProtocolError(MPDError): + pass + +class CommandError(MPDError): + pass + +class CommandListError(MPDError): + pass + +class PendingCommandError(MPDError): + pass + +class IteratingError(MPDError): + pass + +loop = asyncio.get_event_loop() + +class Response: + def __init__(self): + self.version = None + self.resp = '' + self.err = None + + def __repr__(self): + return '{0}, {1}… ({2})'.format(self.err, self.resp[:15], self.version) + +class MPDProto(asyncio.Protocol): + def __init__(self, future, payload): + self.future = future + self.payload = payload + self.sess = Response() + + def connection_made(self, transport): + self.transport = transport + self.transport.write(bytes('{}\n'.format(self.payload), 'utf-8')) + + def data_received(self, data): + rcv = data.decode('utf-8') + if '\n' not in rcv: + self.sess.err = 'Connection lost while reading line' + self.future.set_result(self.sess) + raise ConnectionError("Connection lost while reading line") + + rcv = rcv.strip('\n') + + if rcv.startswith(HELLO_PREFIX): + self.sess.version = rcv[len(HELLO_PREFIX):] + return + self.transport.close() + + # set the result on the Future so that the main() coroutine can + # resume + if rcv.startswith(ERROR_PREFIX): + self.sess.err = rcv[len(ERROR_PREFIX):].strip() + self.future.set_result(self.sess) + return + else: + self.sess.resp = rcv + self.future.set_result(self.sess) + +def command(payload): + future = asyncio.Future() + if payload: + cli = MPDProto(future, payload) + # kick off a task to create the connection to MPD. + asyncio.async(loop.create_connection(lambda: cli, host='192.168.0.20', port=6600)) + else: + future.set_result((None, None, None)) + + # return the future for the main() coroutine to wait on. + return future + + +def main(): + """main""" + import logging + logging.basicConfig(level=logging.DEBUG) + res = yield from command('currentsongt') + if res.err: + raise CommandError(res.err) + print(res) + print(res.resp) + +if __name__ == '__main__': + loop.run_until_complete(main()) -- 2.39.5