1
2
3
4
5
6
7
8 import socket
9
10
11
12
13
14
15
17
19 self.host = host
20 self.port = port
21 self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
22 self.sock.connect((host, port))
23 self.file = self.sock.makefile("rb+")
24 self.current_line = ''
25 self.ack = ''
26 self.done = True
27
28
29
31 if not self.current_line:
32 self.current_line = self.file.readline().rstrip("\n")
33 if not self.current_line:
34 raise EOFError
35 if self.current_line == "OK" or self.current_line.startswith("ACK"):
36 self.done = True
37 return self.current_line
38
40 self.file.write("%s\n" % line)
41 self.file.flush()
42 self.done = False
43
45 line = self.get_line()
46 self.ack = ''
47
48 if self.done:
49 if line.startswith("ACK"):
50 self.ack = line.split(None, 1)[1]
51 return ()
52
53 pair = line.split(": ", 1)
54 if len(pair) != 2:
55 raise RuntimeError("bogus response: ``%s''" % line)
56
57 return pair
58
59 ZERO = 0
60 ONE = 1
61 MANY = 2
62
63 plitem_delim = ["file", "directory", "playlist"]
64
65 commands = {
66
67
68
69
70
71
72
73
74
75 ("kill", 0): ('%s', ZERO, '', []),
76 ("outputs", 0): ('%s', MANY, 'outputs', ['outputid']),
77 ("clear", 0): ('%s', ZERO, '', []),
78 ("currentsong", 0): ('%s', ONE, '', []),
79 ("shuffle", 0): ('%s', ZERO, '', []),
80 ("next", 0): ('%s', ZERO, '', []),
81 ("previous", 0): ('%s', ZERO, '', []),
82 ("stop", 0): ('%s', ZERO, '', []),
83 ("clearerror", 0): ('%s', ZERO, '', []),
84 ("close", 0): ('%s', ZERO, '', []),
85 ("commands", 0): ('%s', MANY, 'commands', ['command']),
86 ("notcommands", 0): ('%s', MANY, 'notcommands', ['command']),
87 ("ping", 0): ('%s', ZERO, '', []),
88 ("stats", 0): ('%s', ONE, 'stats', []),
89 ("status", 0): ('%s', ONE, 'status', []),
90 ("play", 0): ('%s', ZERO, '', []),
91 ("playlistinfo", 0): ('%s', MANY, '', plitem_delim),
92 ("playlistid", 0): ('%s', MANY, '', plitem_delim),
93 ("lsinfo", 0): ('%s', MANY, '', plitem_delim),
94 ("update", 0): ('%s', ZERO, '', []),
95 ("listall", 0): ('%s', MANY, '', plitem_delim),
96 ("listallinfo", 0): ('%s', MANY, '', plitem_delim),
97
98 ("disableoutput", 1): ("%s %d", ZERO, '', []),
99 ("enableoutput", 1): ("%s %d", ZERO, '', []),
100 ("delete", 1): ('%s %d', ZERO, '', []),
101 ("deleteid", 1): ('%s %d', ZERO, '', []),
102 ("playlistinfo", 1): ('%s %d', MANY, '', plitem_delim),
103 ("playlistid", 1): ('%s %d', MANY, '', plitem_delim),
104 ("crossfade", 1): ('%s %d', ZERO, '', []),
105 ("play", 1): ('%s %d', ZERO, '', []),
106 ("playid", 1): ('%s %d', ZERO, '', []),
107 ("random", 1): ('%s %d', ZERO, '', []),
108 ("repeat", 1): ('%s %d', ZERO, '', []),
109 ("setvol", 1): ('%s %d', ZERO, '', []),
110 ("plchanges", 1): ('%s %d', MANY, '', plitem_delim),
111 ("pause", 1): ('%s %d', ZERO, '', []),
112
113 ("update", 1): ('%s "%s"', ONE, 'update', []),
114 ("listall", 1): ('%s "%s"', MANY, '', plitem_delim),
115 ("listallinfo", 1): ('%s "%s"', MANY, '', plitem_delim),
116 ("lsinfo", 1): ('%s "%s"', MANY, '', plitem_delim),
117 ("add", 1): ('%s "%s"', ZERO, '', []),
118 ("load", 1): ('%s "%s"', ZERO, '', []),
119 ("rm", 1): ('%s "%s"', ZERO, '', []),
120 ("save", 1): ('%s "%s"', ZERO, '', []),
121 ("password", 1): ('%s "%s"', ZERO, '', []),
122
123 ("move", 2): ("%s %d %d", ZERO, '', []),
124 ("moveid", 2): ("%s %d %d", ZERO, '', []),
125 ("swap", 2): ("%s %d %d", ZERO, '', []),
126 ("swapid", 2): ("%s %d %d", ZERO, '', []),
127 ("seek", 2): ("%s %d %d", ZERO, '', []),
128 ("seekid", 2): ("%s %d %d", ZERO, '', []),
129
130
131 ("find", 2): ('%s "%s" "%s"', MANY, '', plitem_delim),
132
133
134 ("search", 2): ('%s "%s" "%s"', MANY, '', plitem_delim),
135
136
137
138
139 ("list", 1): ('%s "%s"', MANY, '', plitem_delim),
140
141
142 ("list", 3): ('%s "%s" "%s" "%s"', MANY, '', plitem_delim),
143 }
144
147
153
155 try:
156 return commands[(cmd, len(args))]
157 except KeyError:
158 raise RuntimeError("no such command: %s (%d args)" % (cmd, len(args)))
159
161 args = list(args[:])
162 for i, arg in enumerate(args):
163 if not isinstance(arg, int):
164 args[i] = escape(str(arg))
165 format = get_command(cmd, args)[0]
166 talker.putline(format % tuple([cmd] + list(args)))
167
170 self.sender = sender
171 self.fetcher = fetcher
172 self.iterate = False
173
176
178 getattr(self.sender, cmd)(*args)
179 junk, howmany, type, keywords = get_command(cmd, args)
180
181 if howmany == ZERO:
182 self.fetcher.clear()
183 return
184
185 if howmany == ONE:
186 return self.fetcher.one_object(keywords, type)
187
188 assert howmany == MANY
189 result = self.fetcher.all_objects(keywords, type)
190
191 if not self.iterate:
192 result = list(result)
193 self.fetcher.clear()
194 return result
195
196
197
198 def yield_then_clear(it):
199 for x in it:
200 yield x
201 self.fetcher.clear()
202 return yield_then_clear(result)
203
204
210
213 self.talker = talker
214 self.converters = {}
215
217 while not self.talker.done:
218 self.talker.current_line = ''
219 self.talker.get_line()
220 self.talker.current_line = ''
221
223
224
225
226
227
228
229 entity = dictobj()
230 if type:
231 entity['type'] = type
232
233 while not self.talker.done:
234 self.talker.get_line()
235 pair = self.talker.get_pair()
236
237 if not pair:
238 self.talker.current_line = ''
239 return entity
240
241 key, val = pair
242 key = key.lower()
243
244 if key in keywords and key in entity.keys():
245 return entity
246
247 if not type and 'type' not in entity.keys():
248 entity['type'] = key
249
250 entity[key] = self.convert(entity['type'], key, val)
251 self.talker.current_line = ''
252
253 return entity
254
256 while 1:
257 obj = self.one_object(keywords, type)
258 if not obj:
259 raise StopIteration
260 yield obj
261 if self.talker.done:
262 raise StopIteration
263
265
266 return self.converters.get(cmd, {}).get(key, lambda x: x)(val)
267
270 try:
271 return self[attr]
272 except KeyError:
273 raise AttributeError
275
276
277
278
279
280 return (object.__repr__(self).rstrip('>') + ' ..\n' +
281 ' {\n ' +
282 ',\n '.join([ '%s: %s' % (k, v) for k, v in self.items() ]) +
283 '\n }>')
284
293
295 line = self.talker.get_line()
296 if not line.startswith("OK MPD "):
297 raise RuntimeError("this ain't mpd")
298 self.mpd_version = line[len("OK MPD "):].strip()
299 self.talker.current_line = ''
300
301
303 if is_command(attr):
304 return getattr(self.do, attr)
305 raise AttributeError(attr)
306
308 if '@' in host:
309 return host.split('@', 1)
310 return '', host
311
333