Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 490 lines (427 sloc) 16.779 kb
0dfcd8a changing license to LGPL
J. Alexander Treuman authored
1 # python-mpd: Python MPD client library
ed08fb6 updating copyright years
J. Alexander Treuman authored
2 # Copyright (C) 2008-2010 J. Alexander Treuman <jat@spatialrift.net>
8fd75f8 @Mic92 Prepare fork and renaming to python-mpd2
authored
3 # Copyright (C) 2012 J. Thalheim <jthalheim@gmail.com>
96c1cf2 adding LICENSE.txt and a copyright notice to mpd.py
J. Alexander Treuman authored
4 #
0dfcd8a changing license to LGPL
J. Alexander Treuman authored
5 # python-mpd is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as published by
96c1cf2 adding LICENSE.txt and a copyright notice to mpd.py
J. Alexander Treuman authored
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
9 #
0dfcd8a changing license to LGPL
J. Alexander Treuman authored
10 # python-mpd is distributed in the hope that it will be useful,
96c1cf2 adding LICENSE.txt and a copyright notice to mpd.py
J. Alexander Treuman authored
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0dfcd8a changing license to LGPL
J. Alexander Treuman authored
13 # GNU Lesser General Public License for more details.
96c1cf2 adding LICENSE.txt and a copyright notice to mpd.py
J. Alexander Treuman authored
14 #
0dfcd8a changing license to LGPL
J. Alexander Treuman authored
15 # You should have received a copy of the GNU Lesser General Public License
16 # along with python-mpd. If not, see <http://www.gnu.org/licenses/>.
96c1cf2 adding LICENSE.txt and a copyright notice to mpd.py
J. Alexander Treuman authored
17
9a76b6e initial commit
J. Alexander Treuman authored
18 import socket
2f11579 @Mic92 add both python3 and python2.7 compatibility
authored
19 from collections import Callable
9a76b6e initial commit
J. Alexander Treuman authored
20
21 HELLO_PREFIX = "OK MPD "
22 ERROR_PREFIX = "ACK "
23 SUCCESS = "OK"
e5e24e0 adding command_list support
J. Alexander Treuman authored
24 NEXT = "list_OK"
9a76b6e initial commit
J. Alexander Treuman authored
25
26
27 class MPDError(Exception):
28 pass
29
ecdbc2e mpd.py: raise ConnectionError on EOF
J. Alexander Treuman authored
30 class ConnectionError(MPDError):
31 pass
32
9a76b6e initial commit
J. Alexander Treuman authored
33 class ProtocolError(MPDError):
34 pass
35
36 class CommandError(MPDError):
37 pass
38
e5e24e0 adding command_list support
J. Alexander Treuman authored
39 class CommandListError(MPDError):
40 pass
41
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
42 class PendingCommandError(MPDError):
43 pass
44
535e659 mpd.py: check if iterating before fetching response
J. Alexander Treuman authored
45 class IteratingError(MPDError):
46 pass
47
9a76b6e initial commit
J. Alexander Treuman authored
48
11ad737 mpd.py: raise ConnectionError when trying to use an unconnected socket
J. Alexander Treuman authored
49 class _NotConnected(object):
50 def __getattr__(self, attr):
51 return self._dummy
52
53 def _dummy(*args):
492dab0 mpd.py: changing exception raising to comply with the Python Style Guide
J. Alexander Treuman authored
54 raise ConnectionError("Not connected")
11ad737 mpd.py: raise ConnectionError when trying to use an unconnected socket
J. Alexander Treuman authored
55
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
56 _commands = {
57 # Status Commands
58 "clearerror": "_fetch_nothing",
59 "currentsong": "_fetch_object",
60 "idle": "_fetch_list",
61 "noidle": None,
62 "status": "_fetch_object",
63 "stats": "_fetch_object",
64 # Playback Option Commands
65 "consume": "_fetch_nothing",
66 "crossfade": "_fetch_nothing",
67 "mixrampdb": "_fetch_nothing",
68 "mixrampdelay": "_fetch_nothing",
69 "random": "_fetch_nothing",
70 "repeat": "_fetch_nothing",
71 "setvol": "_fetch_nothing",
72 "single": "_fetch_nothing",
73 "replay_gain_mode": "_fetch_nothing",
74 "replay_gain_status": "_fetch_item",
75 "volume": "_fetch_nothing",
76 # Playback Control Commands
77 "next": "_fetch_nothing",
78 "pause": "_fetch_nothing",
79 "play": "_fetch_nothing",
80 "playid": "_fetch_nothing",
81 "previous": "_fetch_nothing",
82 "seek": "_fetch_nothing",
83 "seekid": "_fetch_nothing",
0f49d96 @Mic92 adding prior, priorid and seekcur commands
authored
84 "seekcur": "_fetch_nothing",
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
85 "stop": "_fetch_nothing",
86 # Playlist Commands
87 "add": "_fetch_nothing",
88 "addid": "_fetch_item",
89 "clear": "_fetch_nothing",
90 "delete": "_fetch_nothing",
91 "deleteid": "_fetch_nothing",
92 "move": "_fetch_nothing",
93 "moveid": "_fetch_nothing",
94 "playlist": "_fetch_playlist",
95 "playlistfind": "_fetch_songs",
96 "playlistid": "_fetch_songs",
97 "playlistinfo": "_fetch_songs",
98 "playlistsearch": "_fetch_songs",
99 "plchanges": "_fetch_songs",
100 "plchangesposid": "_fetch_changes",
0f49d96 @Mic92 adding prior, priorid and seekcur commands
authored
101 "prior": "_fetch_nothing",
102 "priorid": "_fetch_nothing",
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
103 "shuffle": "_fetch_nothing",
104 "swap": "_fetch_nothing",
105 "swapid": "_fetch_nothing",
106 # Stored Playlist Commands
107 "listplaylist": "_fetch_list",
108 "listplaylistinfo": "_fetch_songs",
109 "listplaylists": "_fetch_playlists",
110 "load": "_fetch_nothing",
111 "playlistadd": "_fetch_nothing",
112 "playlistclear": "_fetch_nothing",
113 "playlistdelete": "_fetch_nothing",
114 "playlistmove": "_fetch_nothing",
115 "rename": "_fetch_nothing",
116 "rm": "_fetch_nothing",
117 "save": "_fetch_nothing",
118 # Database Commands
119 "count": "_fetch_object",
120 "find": "_fetch_songs",
121 "findadd": "_fetch_nothing",
122 "list": "_fetch_list",
123 "listall": "_fetch_database",
124 "listallinfo": "_fetch_database",
125 "lsinfo": "_fetch_database",
126 "search": "_fetch_songs",
127 "update": "_fetch_item",
128 "rescan": "_fetch_item",
129 # Sticker Commands
130 "sticker get": "_fetch_item",
131 "sticker set": "_fetch_nothing",
132 "sticker delete": "_fetch_nothing",
133 "sticker list": "_fetch_list",
134 "sticker find": "_fetch_songs",
135 # Connection Commands
136 "close": None,
137 "kill": None,
138 "password": "_fetch_nothing",
139 "ping": "_fetch_nothing",
140 # Audio Output Commands
141 "disableoutput": "_fetch_nothing",
142 "enableoutput": "_fetch_nothing",
143 "outputs": "_fetch_outputs",
144 # Reflection Commands
145 "commands": "_fetch_list",
146 "notcommands": "_fetch_list",
147 "tagtypes": "_fetch_list",
148 "urlhandlers": "_fetch_list",
149 "decoders": "_fetch_plugins",
1a468a0 @Mic92 Support upcomming client to client commands of mpd
authored
150 # Client To Client
151 "subscribe": "_fetch_nothing",
152 "unsubscribe": "_fetch_nothing",
153 "channels": "_fetch_list",
154 "readmessages": "_fetch_messages",
155 "sendmessage": "_fetch_nothing",
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
156 }
157
158 class MPDClient():
9a76b6e initial commit
J. Alexander Treuman authored
159 def __init__(self):
160 self.iterate = False
161 self._reset()
162
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
163 def _send(self, command, args, retval):
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
164 if self._command_list is not None:
165 raise CommandListError("Cannot use send_%s in a command list" %
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
166 command)
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
167 self._write_command(command, args)
7299c4f mpd.py: if command retval is None, don't require fetching
J. Alexander Treuman authored
168 if retval is not None:
169 self._pending.append(command)
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
170
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
171 def _fetch(self, command, args, retval):
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
172 if self._command_list is not None:
173 raise CommandListError("Cannot use fetch_%s in a command list" %
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
174 command)
535e659 mpd.py: check if iterating before fetching response
J. Alexander Treuman authored
175 if self._iterating:
176 raise IteratingError("Cannot use fetch_%s while iterating" %
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
177 command)
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
178 if not self._pending:
179 raise PendingCommandError("No pending commands to fetch")
180 if self._pending[0] != command:
9eea05a mpd.py: adding support for spaces in command names
J. Alexander Treuman authored
181 raise PendingCommandError("'%s' is not the currently "
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
182 "pending command" % command)
183 del self._pending[0]
2f11579 @Mic92 add both python3 and python2.7 compatibility
authored
184 if isinstance(retval, Callable):
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
185 return retval()
7299c4f mpd.py: if command retval is None, don't require fetching
J. Alexander Treuman authored
186 return retval
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
187
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
188 def _execute(self, command, args, retval):
535e659 mpd.py: check if iterating before fetching response
J. Alexander Treuman authored
189 if self._iterating:
9eea05a mpd.py: adding support for spaces in command names
J. Alexander Treuman authored
190 raise IteratingError("Cannot execute '%s' while iterating" %
191 command)
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
192 if self._pending:
9eea05a mpd.py: adding support for spaces in command names
J. Alexander Treuman authored
193 raise PendingCommandError("Cannot execute '%s' with "
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
194 "pending commands" % command)
461fe7b mpd.py: tidying up _execute()
J. Alexander Treuman authored
195 if self._command_list is not None:
2f11579 @Mic92 add both python3 and python2.7 compatibility
authored
196 if not isinstance(retval, Callable):
9eea05a mpd.py: adding support for spaces in command names
J. Alexander Treuman authored
197 raise CommandListError("'%s' not allowed in command list" %
461fe7b mpd.py: tidying up _execute()
J. Alexander Treuman authored
198 command)
199 self._write_command(command, args)
200 self._command_list.append(retval)
201 else:
202 self._write_command(command, args)
2f11579 @Mic92 add both python3 and python2.7 compatibility
authored
203 if isinstance(retval, Callable):
e5e24e0 adding command_list support
J. Alexander Treuman authored
204 return retval()
205 return retval
9a76b6e initial commit
J. Alexander Treuman authored
206
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
207 def _write_line(self, line):
2f11579 @Mic92 add both python3 and python2.7 compatibility
authored
208 self._wfile.write(("%s\n" % line).encode('utf-8'))
cde055b mpd.py: use a separate file object for reading and writing sockets
J. Alexander Treuman authored
209 self._wfile.flush()
9a76b6e initial commit
J. Alexander Treuman authored
210
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
211 def _write_command(self, command, args=[]):
9a76b6e initial commit
J. Alexander Treuman authored
212 parts = [command]
213 for arg in args:
214 parts.append('"%s"' % escape(str(arg)))
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
215 self._write_line(" ".join(parts))
9a76b6e initial commit
J. Alexander Treuman authored
216
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
217 def _read_line(self):
2f11579 @Mic92 add both python3 and python2.7 compatibility
authored
218 line = self._rfile.readline().decode('utf-8')
ecdbc2e mpd.py: raise ConnectionError on EOF
J. Alexander Treuman authored
219 if not line.endswith("\n"):
492dab0 mpd.py: changing exception raising to comply with the Python Style Guide
J. Alexander Treuman authored
220 raise ConnectionError("Connection lost while reading line")
ecdbc2e mpd.py: raise ConnectionError on EOF
J. Alexander Treuman authored
221 line = line.rstrip("\n")
9a76b6e initial commit
J. Alexander Treuman authored
222 if line.startswith(ERROR_PREFIX):
223 error = line[len(ERROR_PREFIX):].strip()
492dab0 mpd.py: changing exception raising to comply with the Python Style Guide
J. Alexander Treuman authored
224 raise CommandError(error)
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
225 if self._command_list is not None:
e5e24e0 adding command_list support
J. Alexander Treuman authored
226 if line == NEXT:
227 return
228 if line == SUCCESS:
492dab0 mpd.py: changing exception raising to comply with the Python Style Guide
J. Alexander Treuman authored
229 raise ProtocolError("Got unexpected '%s'" % SUCCESS)
e5e24e0 adding command_list support
J. Alexander Treuman authored
230 elif line == SUCCESS:
9a76b6e initial commit
J. Alexander Treuman authored
231 return
232 return line
233
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
234 def _read_pair(self, separator):
235 line = self._read_line()
9a76b6e initial commit
J. Alexander Treuman authored
236 if line is None:
237 return
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
238 pair = line.split(separator, 1)
239 if len(pair) < 2:
240 raise ProtocolError("Could not parse pair: '%s'" % line)
241 return pair
242
243 def _read_pairs(self, separator=": "):
244 pair = self._read_pair(separator)
245 while pair:
246 yield pair
247 pair = self._read_pair(separator)
9a76b6e initial commit
J. Alexander Treuman authored
248
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
249 def _read_list(self):
9a76b6e initial commit
J. Alexander Treuman authored
250 seen = None
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
251 for key, value in self._read_pairs():
9a76b6e initial commit
J. Alexander Treuman authored
252 if key != seen:
253 if seen is not None:
492dab0 mpd.py: changing exception raising to comply with the Python Style Guide
J. Alexander Treuman authored
254 raise ProtocolError("Expected key '%s', got '%s'" %
255 (seen, key))
9a76b6e initial commit
J. Alexander Treuman authored
256 seen = key
257 yield value
258
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
259 def _read_playlist(self):
260 for key, value in self._read_pairs(":"):
9a76b6e initial commit
J. Alexander Treuman authored
261 yield value
262
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
263 def _read_objects(self, delimiters=[]):
9a76b6e initial commit
J. Alexander Treuman authored
264 obj = {}
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
265 for key, value in self._read_pairs():
9a76b6e initial commit
J. Alexander Treuman authored
266 key = key.lower()
267 if obj:
268 if key in delimiters:
269 yield obj
270 obj = {}
c7cae3c mpd.py: don't use has_key()
J. Alexander Treuman authored
271 elif key in obj:
9a76b6e initial commit
J. Alexander Treuman authored
272 if not isinstance(obj[key], list):
273 obj[key] = [obj[key], value]
274 else:
275 obj[key].append(value)
276 continue
277 obj[key] = value
278 if obj:
279 yield obj
280
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
281 def _read_command_list(self):
acefec8 mpd.py: clear command list if an exception is raised
J. Alexander Treuman authored
282 try:
283 for retval in self._command_list:
284 yield retval()
285 finally:
286 self._command_list = None
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
287 self._fetch_nothing()
e5e24e0 adding command_list support
J. Alexander Treuman authored
288
535e659 mpd.py: check if iterating before fetching response
J. Alexander Treuman authored
289 def _iterator_wrapper(self, iterator):
a55e3f1 mpd.py: unset iterating flag if an exception is raised
J. Alexander Treuman authored
290 try:
291 for item in iterator:
292 yield item
293 finally:
294 self._iterating = False
535e659 mpd.py: check if iterating before fetching response
J. Alexander Treuman authored
295
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
296 def _wrap_iterator(self, iterator):
9a76b6e initial commit
J. Alexander Treuman authored
297 if not self.iterate:
298 return list(iterator)
6ab362f mpd.py: set iterating flag before returning iterator
J. Alexander Treuman authored
299 self._iterating = True
535e659 mpd.py: check if iterating before fetching response
J. Alexander Treuman authored
300 return self._iterator_wrapper(iterator)
9a76b6e initial commit
J. Alexander Treuman authored
301
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
302 def _fetch_nothing(self):
303 line = self._read_line()
9a76b6e initial commit
J. Alexander Treuman authored
304 if line is not None:
492dab0 mpd.py: changing exception raising to comply with the Python Style Guide
J. Alexander Treuman authored
305 raise ProtocolError("Got unexpected return value: '%s'" % line)
9a76b6e initial commit
J. Alexander Treuman authored
306
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
307 def _fetch_item(self):
308 pairs = list(self._read_pairs())
309 if len(pairs) != 1:
94fd67b mpd.py: making _getitem return None if no item is returned
J. Alexander Treuman authored
310 return
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
311 return pairs[0][1]
9a76b6e initial commit
J. Alexander Treuman authored
312
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
313 def _fetch_list(self):
314 return self._wrap_iterator(self._read_list())
9a76b6e initial commit
J. Alexander Treuman authored
315
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
316 def _fetch_playlist(self):
317 return self._wrap_iterator(self._read_playlist())
9a76b6e initial commit
J. Alexander Treuman authored
318
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
319 def _fetch_object(self):
320 objs = list(self._read_objects())
9a76b6e initial commit
J. Alexander Treuman authored
321 if not objs:
cdd3dd2 return an empty dict if no object is read
J. Alexander Treuman authored
322 return {}
9a76b6e initial commit
J. Alexander Treuman authored
323 return objs[0]
324
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
325 def _fetch_objects(self, delimiters):
326 return self._wrap_iterator(self._read_objects(delimiters))
9a76b6e initial commit
J. Alexander Treuman authored
327
41739e1 adding decoders command
J. Alexander Treuman authored
328 def _fetch_changes(self):
329 return self._fetch_objects(["cpos"])
330
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
331 def _fetch_songs(self):
332 return self._fetch_objects(["file"])
9a76b6e initial commit
J. Alexander Treuman authored
333
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
334 def _fetch_playlists(self):
335 return self._fetch_objects(["playlist"])
c465a35 adding listplaylists command
J. Alexander Treuman authored
336
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
337 def _fetch_database(self):
338 return self._fetch_objects(["file", "directory", "playlist"])
9a76b6e initial commit
J. Alexander Treuman authored
339
1a468a0 @Mic92 Support upcomming client to client commands of mpd
authored
340 def _fetch_messages(self):
341 return self._fetch_objects(["channel"])
342
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
343 def _fetch_outputs(self):
344 return self._fetch_objects(["outputid"])
9a76b6e initial commit
J. Alexander Treuman authored
345
41739e1 adding decoders command
J. Alexander Treuman authored
346 def _fetch_plugins(self):
347 return self._fetch_objects(["plugin"])
9a76b6e initial commit
J. Alexander Treuman authored
348
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
349 def _fetch_command_list(self):
350 return self._wrap_iterator(self._read_command_list())
e5e24e0 adding command_list support
J. Alexander Treuman authored
351
9a76b6e initial commit
J. Alexander Treuman authored
352 def _hello(self):
2f11579 @Mic92 add both python3 and python2.7 compatibility
authored
353 line = self._rfile.readline().decode('utf-8')
ecdbc2e mpd.py: raise ConnectionError on EOF
J. Alexander Treuman authored
354 if not line.endswith("\n"):
492dab0 mpd.py: changing exception raising to comply with the Python Style Guide
J. Alexander Treuman authored
355 raise ConnectionError("Connection lost while reading MPD hello")
285bcce mpd.py: strip trailing \n from MPD's hello line for a nicer error messag...
J. Alexander Treuman authored
356 line = line.rstrip("\n")
9a76b6e initial commit
J. Alexander Treuman authored
357 if not line.startswith(HELLO_PREFIX):
492dab0 mpd.py: changing exception raising to comply with the Python Style Guide
J. Alexander Treuman authored
358 raise ProtocolError("Got invalid MPD hello: '%s'" % line)
9a76b6e initial commit
J. Alexander Treuman authored
359 self.mpd_version = line[len(HELLO_PREFIX):].strip()
360
361 def _reset(self):
362 self.mpd_version = None
535e659 mpd.py: check if iterating before fetching response
J. Alexander Treuman authored
363 self._iterating = False
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
364 self._pending = []
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
365 self._command_list = None
11ad737 mpd.py: raise ConnectionError when trying to use an unconnected socket
J. Alexander Treuman authored
366 self._sock = None
cde055b mpd.py: use a separate file object for reading and writing sockets
J. Alexander Treuman authored
367 self._rfile = _NotConnected()
368 self._wfile = _NotConnected()
9a76b6e initial commit
J. Alexander Treuman authored
369
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
370 def _connect_unix(self, path):
52157b2 mpd.py: raise ConnectionError if unix sockets aren't supported
J. Alexander Treuman authored
371 if not hasattr(socket, "AF_UNIX"):
372 raise ConnectionError("Unix domain sockets not supported "
373 "on this platform")
8ec145e preliminary unix socket support
J. Alexander Treuman authored
374 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
375 sock.connect(path)
376 return sock
377
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
378 def _connect_tcp(self, host, port):
74eff57 mpd.py: adding a workaround for systems missing socket.AI_ADDRCONFIG
J. Alexander Treuman authored
379 try:
380 flags = socket.AI_ADDRCONFIG
381 except AttributeError:
382 flags = 0
46753bf mpd.py: updating _connect_tcp() with new socket code
J. Alexander Treuman authored
383 err = None
3bbc456 mpd.py: loop over addresses returned by getaddrinfo to connect to
J. Alexander Treuman authored
384 for res in socket.getaddrinfo(host, port, socket.AF_UNSPEC,
385 socket.SOCK_STREAM, socket.IPPROTO_TCP,
74eff57 mpd.py: adding a workaround for systems missing socket.AI_ADDRCONFIG
J. Alexander Treuman authored
386 flags):
3bbc456 mpd.py: loop over addresses returned by getaddrinfo to connect to
J. Alexander Treuman authored
387 af, socktype, proto, canonname, sa = res
46753bf mpd.py: updating _connect_tcp() with new socket code
J. Alexander Treuman authored
388 sock = None
3bbc456 mpd.py: loop over addresses returned by getaddrinfo to connect to
J. Alexander Treuman authored
389 try:
8ec145e preliminary unix socket support
J. Alexander Treuman authored
390 sock = socket.socket(af, socktype, proto)
621664b @Mic92 mpd.py turn on tcp keepalive on tcp sockets
authored
391 sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
8ec145e preliminary unix socket support
J. Alexander Treuman authored
392 sock.connect(sa)
46753bf mpd.py: updating _connect_tcp() with new socket code
J. Alexander Treuman authored
393 return sock
0283e40 @Mic92 mpd.py fix shadowed variable in _connect_tcp()
authored
394 except socket.error as e:
395 err = e
46753bf mpd.py: updating _connect_tcp() with new socket code
J. Alexander Treuman authored
396 if sock is not None:
8ec145e preliminary unix socket support
J. Alexander Treuman authored
397 sock.close()
46753bf mpd.py: updating _connect_tcp() with new socket code
J. Alexander Treuman authored
398 else:
399 raise ConnectionError("getaddrinfo returns an empty list")
8ec145e preliminary unix socket support
J. Alexander Treuman authored
400
da8cb1a @Mic92 more readable exception handling _connect_tcp()
authored
401 raise err
402
8ec145e preliminary unix socket support
J. Alexander Treuman authored
403 def connect(self, host, port):
af6e84c mpd.py: always compare self._sock to None
J. Alexander Treuman authored
404 if self._sock is not None:
8ec145e preliminary unix socket support
J. Alexander Treuman authored
405 raise ConnectionError("Already connected")
406 if host.startswith("/"):
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
407 self._sock = self._connect_unix(host)
8ec145e preliminary unix socket support
J. Alexander Treuman authored
408 else:
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
409 self._sock = self._connect_tcp(host, port)
cde055b mpd.py: use a separate file object for reading and writing sockets
J. Alexander Treuman authored
410 self._rfile = self._sock.makefile("rb")
411 self._wfile = self._sock.makefile("wb")
2027674 mpd.py: reset to disconnected state if _hello() fails in connect()
J. Alexander Treuman authored
412 try:
413 self._hello()
8ab0077 mpd.py: catch all exceptions raised by _hello()
J. Alexander Treuman authored
414 except:
2027674 mpd.py: reset to disconnected state if _hello() fails in connect()
J. Alexander Treuman authored
415 self.disconnect()
416 raise
9a76b6e initial commit
J. Alexander Treuman authored
417
418 def disconnect(self):
cde055b mpd.py: use a separate file object for reading and writing sockets
J. Alexander Treuman authored
419 self._rfile.close()
420 self._wfile.close()
9a76b6e initial commit
J. Alexander Treuman authored
421 self._sock.close()
422 self._reset()
423
ffd41bf mpd.py: adding fileno() to export socket FD
J. Alexander Treuman authored
424 def fileno(self):
af6e84c mpd.py: always compare self._sock to None
J. Alexander Treuman authored
425 if self._sock is None:
ffd41bf mpd.py: adding fileno() to export socket FD
J. Alexander Treuman authored
426 raise ConnectionError("Not connected")
427 return self._sock.fileno()
428
e5e24e0 adding command_list support
J. Alexander Treuman authored
429 def command_list_ok_begin(self):
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
430 if self._command_list is not None:
492dab0 mpd.py: changing exception raising to comply with the Python Style Guide
J. Alexander Treuman authored
431 raise CommandListError("Already in command list")
535e659 mpd.py: check if iterating before fetching response
J. Alexander Treuman authored
432 if self._iterating:
433 raise IteratingError("Cannot begin command list while iterating")
5c84adf mpd.py: adding support for asynchronous commands
J. Alexander Treuman authored
434 if self._pending:
435 raise PendingCommandError("Cannot begin command list "
436 "with pending commands")
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
437 self._write_command("command_list_ok_begin")
438 self._command_list = []
e5e24e0 adding command_list support
J. Alexander Treuman authored
439
440 def command_list_end(self):
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
441 if self._command_list is None:
492dab0 mpd.py: changing exception raising to comply with the Python Style Guide
J. Alexander Treuman authored
442 raise CommandListError("Not in command list")
9c09c83 mpd.py: don't allow command_list_end if already iterating
J. Alexander Treuman authored
443 if self._iterating:
444 raise IteratingError("Already iterating over a command list")
06f8433 mpd.py: internal API cleanup
J. Alexander Treuman authored
445 self._write_command("command_list_end")
446 return self._fetch_command_list()
e5e24e0 adding command_list support
J. Alexander Treuman authored
447
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
448 @classmethod
449 def add_command(cls, name, callback):
450 method = newFunction(cls._execute, key, callback)
451 send_method = newFunction(cls._send, key, callback)
452 fetch_method = newFunction(cls._fetch, key, callback)
453
454 # create new mpd commands as function in the tree flavors:
455 # normal, with "send_"-prefix and with "fetch_"-prefix
456 escaped_name = name.replace(" ", "_")
457 setattr(cls, escaped_name, method)
458 setattr(cls, "send_"+escaped_name, send_method)
459 setattr(cls, "fetch_"+escaped_name, fetch_method)
460
461 @classmethod
462 def remove_command(cls, name):
6264739 @Mic92 raise an error, if removing a non existing command
authored
463 if not hasattr(cls, name):
464 raise ValueError("Can't remove not existent '%s' command" % name)
4d15d68 @Mic92 Use monkey patching to make mpd commands explicit
authored
465 name = name.replace(" ", "_")
466 delattr(cls, str(name))
467 delattr(cls, str("send_" + name))
468 delattr(cls, str("fetch_" + name))
469
470 def bound_decorator(self, function):
471 """ bind decorator to self """
472 def decorator(*args, **kwargs):
473 return function(self, *args, **kwargs)
474 return decorator
475
476 def newFunction(wrapper, name, returnValue):
477 def decorator(self, *args):
478 return wrapper(self, name, args, bound_decorator(self, returnValue))
479 return decorator
480
481 for key, value in _commands.items():
482 returnValue = None if value is None else MPDClient.__dict__[value]
483 MPDClient.add_command(key, returnValue)
9a76b6e initial commit
J. Alexander Treuman authored
484
485 def escape(text):
486 return text.replace("\\", "\\\\").replace('"', '\\"')
487
488
489 # vim: set expandtab shiftwidth=4 softtabstop=4 textwidth=79:
Something went wrong with that request. Please try again.