X-Git-Url: https://git.kaliko.me/?a=blobdiff_plain;f=musicpd.py;h=10b15cbabec174e42ea22a151ca4ffe4100b4b65;hb=1fb65355de64ef044d0a7b3736a21bed6a6ae290;hp=0fe3b671deff665e3ff73c6394ac7d363e9eb693;hpb=21c2a1843902d21f559af15cdd3eb8a9f35a8b86;p=python-musicpd.git diff --git a/musicpd.py b/musicpd.py index 0fe3b67..10b15cb 100644 --- a/musicpd.py +++ b/musicpd.py @@ -1,6 +1,6 @@ # python-musicpd: Python MPD client library # Copyright (C) 2008-2010 J. Alexander Treuman -# Copyright (C) 2012-2013 Kaliko Jack +# Copyright (C) 2012-2018 Kaliko Jack # # python-musicpd is free software: you can redistribute it and/or modify # it under the terms of the GNU Lesser General Public License as published by @@ -15,16 +15,37 @@ # You should have received a copy of the GNU Lesser General Public License # along with python-musicpd. If not, see . -# pylint: disable=C0111 +# pylint: disable=missing-docstring import socket +import os + +from functools import wraps HELLO_PREFIX = "OK MPD " ERROR_PREFIX = "ACK " SUCCESS = "OK" NEXT = "list_OK" -VERSION = '0.4.2' +VERSION = '0.4.3' + + +def iterator_wrapper(func): + """Decorator handling iterate option""" + @wraps(func) + def decorated_function(instance, *args, **kwargs): + generator = func(instance, *args, **kwargs) + if not instance.iterate: + return list(generator) + instance._iterating = True + def iterator(gen): + try: + for item in gen: + yield item + finally: + instance._iterating = False + return iterator(generator) + return decorated_function class MPDError(Exception): @@ -55,6 +76,8 @@ class Range: self._check() def __str__(self): + if len(self.tpl) == 0: + return ':' if len(self.tpl) == 1: return '{0}:'.format(self.tpl[0]) return '{0[0]}:{0[1]}'.format(self.tpl) @@ -65,15 +88,14 @@ class Range: def _check(self): if not isinstance(self.tpl, tuple): raise CommandError('Wrong type, provide a tuple') - if len(self.tpl) not in [1, 2]: - raise CommandError('length not in [1, 2]') + if len(self.tpl) not in [0, 1, 2]: + raise CommandError('length not in [0, 1, 2]') for index in self.tpl: try: index = int(index) except (TypeError, ValueError): raise CommandError('Not a tuple of int') - class _NotConnected: def __getattr__(self, attr): return self._dummy @@ -130,9 +152,14 @@ class MPDClient: "playlistsearch": self._fetch_songs, "plchanges": self._fetch_songs, "plchangesposid": self._fetch_changes, + "prio": self._fetch_nothing, + "prioid": self._fetch_nothing, + "rangeid": self._fetch_nothing, "shuffle": self._fetch_nothing, "swap": self._fetch_nothing, "swapid": self._fetch_nothing, + "addtagid": self._fetch_nothing, + "cleartagid": self._fetch_nothing, # Stored Playlist Commands "listplaylist": self._fetch_list, "listplaylistinfo": self._fetch_songs, @@ -159,6 +186,11 @@ class MPDClient: "update": self._fetch_item, "rescan": self._fetch_item, "readcomments": self._fetch_object, + # Mounts and neighbors + "mount": self._fetch_nothing, + "unmount": self._fetch_nothing, + "listmounts": self._fetch_mounts, + "listneighbors": self._fetch_neighbors, # Sticker Commands "sticker get": self._fetch_item, "sticker set": self._fetch_nothing, @@ -176,6 +208,7 @@ class MPDClient: "toggleoutput": self._fetch_nothing, "outputs": self._fetch_outputs, # Reflection Commands + "config": self._fetch_object, "commands": self._fetch_list, "notcommands": self._fetch_list, "tagtypes": self._fetch_list, @@ -188,6 +221,32 @@ class MPDClient: "readmessages": self._fetch_messages, "sendmessage": self._fetch_nothing, } + self._get_envvars() + + def _get_envvars(self): + """ + Retrieve MPD env. var. to overrides "localhost:6600" + Use MPD_HOST/MPD_PORT if set + else use MPD_HOST=${XDG_RUNTIME_DIR:-/run/}/mpd/socket if file exists + """ + self.host = 'localhost' + self.password = None + self.port = os.environ.get('MPD_PORT', '6600') + mpd_host_env = os.environ.get('MPD_HOST') + if mpd_host_env: + # If password is set: + # mpd_host_env = ['pass', 'host'] because MPD_HOST=pass@host + mpd_host_env = mpd_host_env.split('@') + mpd_host_env.reverse() + self.host = mpd_host_env[0] + if len(mpd_host_env) > 1 and mpd_host_env[1]: + self.password = mpd_host_env[1] + else: + # Is socket there + xdg_runtime_dir = os.environ.get('XDG_RUNTIME_DIR', '/run') + rundir = os.path.join(xdg_runtime_dir, 'mpd/socket') + if os.path.exists(rundir): + self.host = rundir def __getattr__(self, attr): if attr == 'send_noidle': # have send_noidle to cancel idle as well as noidle @@ -345,19 +404,6 @@ class MPDClient: self._command_list = None self._fetch_nothing() - def _iterator_wrapper(self, iterator): - try: - for item in iterator: - yield item - finally: - self._iterating = False - - def _wrap_iterator(self, iterator): - if not self.iterate: - return list(iterator) - self._iterating = True - return self._iterator_wrapper(iterator) - def _fetch_nothing(self): line = self._read_line() if line is not None: @@ -369,11 +415,13 @@ class MPDClient: return return pairs[0][1] + @iterator_wrapper def _fetch_list(self): - return self._wrap_iterator(self._read_list()) + return self._read_list() + @iterator_wrapper def _fetch_playlist(self): - return self._wrap_iterator(self._read_playlist()) + return self._read_playlist() def _fetch_object(self): objs = list(self._read_objects()) @@ -381,8 +429,9 @@ class MPDClient: return {} return objs[0] + @iterator_wrapper def _fetch_objects(self, delimiters): - return self._wrap_iterator(self._read_objects(delimiters)) + return self._read_objects(delimiters) def _fetch_changes(self): return self._fetch_objects(["cpos"]) @@ -405,8 +454,15 @@ class MPDClient: def _fetch_messages(self): return self._fetch_objects(["channel"]) + def _fetch_mounts(self): + return self._fetch_objects(["mount"]) + + def _fetch_neighbors(self): + return self._fetch_objects(["neighbor"]) + + @iterator_wrapper def _fetch_command_list(self): - return self._wrap_iterator(self._read_command_list()) + return self._read_command_list() def _hello(self): line = self._rfile.readline() @@ -418,7 +474,6 @@ class MPDClient: self.mpd_version = line[len(HELLO_PREFIX):].strip() def _reset(self): - # pylint: disable=w0201 self.mpd_version = None self._iterating = False self._pending = [] @@ -467,7 +522,11 @@ class MPDClient: self._write_command("noidle") return self._fetch_list() - def connect(self, host, port): + def connect(self, host=None, port=None): + if not host: + host = self.host + if not port: + port = self.port if self._sock is not None: raise ConnectionError("Already connected") if host.startswith("/"): @@ -519,5 +578,4 @@ class MPDClient: def escape(text): return text.replace("\\", "\\\\").replace('"', '\\"') - # vim: set expandtab shiftwidth=4 softtabstop=4 textwidth=79: