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