]>
git.wh0rd.org - chrome-ext/music-player-client.git/blob - js/mpc.js
1 // Written by Mike Frysinger <vapier@gmail.com>. Released into the public domain. Suck it.
3 function Mpc(socket
, cb_update_state
, debug_enabled
) {
5 this._cb_update_state
= cb_update_state
;
6 this._debug_enabled
= debug_enabled
;
7 this._queue
= ['init'];
8 this._recv_buffer
= [];
9 this._recv_buffer_last
= 0;
13 Mpc
.prototype.log = function(lvl
, msg
, obj
) {
14 if (this._debug_enabled
& lvl
)
15 console
.log('mpc: ' + msg
, obj
);
18 Mpc
.prototype.err = function(msg
, obj
) {
19 console
.error('mpc: ' + msg
, obj
);
22 Mpc
.prototype.set_debug = function(val
) {
23 this._debug_enabled
= val
;
26 Mpc
.prototype.send = function(msg
) {
28 this._queue
.push(msg
);
29 this._socket
.send(msg
, function(x
) {
30 _this
.log(0x1, 'send: ' + msg
+ ':', x
);
34 Mpc
.prototype._parse_result = function(lines
) {
39 lines
.forEach(function(line
) {
40 i
= line
.indexOf(':');
42 return; // Ignores the OK line
43 key
= line
.substr(0, i
);
45 val
= line
.substr(i
+ 2);
55 Mpc
.prototype.recv_msg = function(lines
) {
57 var curr
= this._queue
.shift();
58 this.log(0x2, 'recv: [' + curr
+ ']:', lines
.join('\n'));
59 if (lines
[0].substr(0, 4) == 'ACK ')
60 this.err(curr
, lines
.join('\n'));
61 curr
= curr
.split(' ');
65 var i
= 2, playlist
= [], song
;
66 while (i
< lines
.length
) {
67 if (lines
[i
].substr(0, 5) == 'file:') {
68 song
= this._parse_result(lines
.splice(0, i
+ 1)).state
;
69 playlist
= playlist
.concat(song
);
74 this.state
.Playlist
= playlist
;
75 this._cb_update_state(this.state
);
79 this.state
.Currentsong
= this._parse_result(lines
).state
;
80 this._cb_update_state(this.state
);
85 ret
= this._parse_result(lines
);
89 // When mpd is stopped, it gives us back crap values for some things.
90 if ('state' in state
&& state
.state
== 'stop') {
91 if ('volume' in state
&& state
.volume
== '-1')
92 keys
.splice(keys
.indexOf('volume'), 1);
94 // Now merge the current state with the previous one so that we don't
95 // lose information like volume or song position.
96 var curr_state
= this.state
;
97 keys
.forEach(function(key
) {
98 curr_state
[key
] = state
[key
];
101 this._cb_update_state(curr_state
);
105 this._cb_update_state(lines
, curr
);
110 Mpc
.prototype.recv = function(msg
) {
111 /* We can get back a bunch of responses in a row, so parse them out */
112 var lines
= this._recv_buffer
= this._recv_buffer
.concat(msg
.split('\n'));
114 while (i
< lines
.length
) {
115 if (lines
[i
] == 'OK' || lines
[i
].substr(0, 3) == 'OK ' ||
116 lines
[i
].substr(0, 4) == 'ACK ') {
117 this.recv_msg(lines
.splice(0, i
+ 1));
123 if (lines
.length
&& this._recv_buffer_last
!= lines
.length
) {
124 // Keep sucking in data so long as more exists.
125 this._recv_buffer_last
= lines
.length
;
128 this._recv_buffer_last
= lines
.length
;
132 * Command generator helpers.
135 Mpc
.__make_send_void = function(cmd
) {
136 return function() { this.send(cmd
); }
139 Mpc
.__make_send_arg1 = function(cmd
) {
140 return function(a1
) {
141 if (a1
=== undefined)
142 this.err(cmd
+ ': function requires one argument');
144 this.send(cmd
+ ' ' + a1
);
148 Mpc
.__make_send_arg2 = function(cmd
) {
149 return function(a1
, a2
) {
150 if (a1
=== undefined || a2
=== undefined)
151 this.err(cmd
+ ': function requires two arguments');
153 this.send(cmd
+ ' ' + a1
+ ' ' + a2
);
157 Mpc
.__make_send_arg3 = function(cmd
) {
158 return function(a1
, a2
, a3
) {
159 if (a1
=== undefined || a2
=== undefined || a3
== undefined)
160 this.err(cmd
+ ': function requires three arguments');
162 this.send(cmd
+ ' ' + a1
+ ' ' + a2
+ ' ' + a3
);
166 Mpc
.__make_send_opt = function(cmd
) {
167 return function(arg
) {
168 if (arg
=== undefined)
170 this.send(cmd
+ ' ' + arg
);
174 Mpc
.__make_send_range = function(cmd
, min
, max
, def
) {
175 return function(arg
) {
176 if (arg
=== undefined)
178 if (arg
>= min
&& arg
<= max
)
179 this.send(cmd
+ ' ' + arg
);
181 this.err(cmd
+ ': arg must be [' + min
+ ',' + max
+ '] but got "' + arg
+ '"');
186 * Querying MPD's status
187 * http://www.musicpd.org/doc/protocol/ch03.html#idp118752
191 Mpc
.prototype.clearerror
= Mpc
.__make_send_void('clearerror');
193 Mpc
.prototype.currentsong
= Mpc
.__make_send_void('currentsong');
194 // idle [SUBSYSTEMS...]
197 Mpc
.prototype.status
= Mpc
.__make_send_void('status');
199 Mpc
.prototype.stats
= Mpc
.__make_send_void('stats');
203 * http://www.musicpd.org/doc/protocol/ch03s02.html
207 Mpc
.prototype.consume
= Mpc
.__make_send_range('consume', 0, 1, 1);
208 // crossfade {SECONDS}
209 Mpc
.prototype.crossfade
= Mpc
.__make_send_arg1('crossfade');
210 // mixrampdb {deciBels}
211 Mpc
.prototype.mixrampdb
= Mpc
.__make_send_arg1('mixrampdb');
212 // mixrampdelay {SECONDS|nan}
213 // Note: Probably should handle javascript NaN here.
214 Mpc
.prototype.mixrampdelay
= Mpc
.__make_send_arg1('mixrampdelay');
216 Mpc
.prototype.random
= Mpc
.__make_send_range('random', 0, 1, 1);
218 Mpc
.prototype.repeat
= Mpc
.__make_send_range('repeat', 0, 1, 1);
220 Mpc
.prototype.setvol
= Mpc
.__make_send_range('setvol', 0, 100);
222 Mpc
.prototype.single
= Mpc
.__make_send_range('single', 0, 1, 1);
223 // replay_gain_mode {MODE}
224 Mpc
.prototype.replay_gain_mode
= Mpc
.__make_send_arg1('replay_gain_mode');
225 // replay_gain_status
228 * Controlling playback
229 * http://www.musicpd.org/doc/protocol/ch03s03.html
233 Mpc
.prototype.next
= Mpc
.__make_send_void('next');
235 Mpc
.prototype.pause
= Mpc
.__make_send_range('pause', 0, 1, 1);
237 Mpc
.prototype.play
= Mpc
.__make_send_opt('play');
239 Mpc
.prototype.playid
= Mpc
.__make_send_opt('playid');
241 Mpc
.prototype.previous
= Mpc
.__make_send_void('previous');
242 // seek {SONGPOS} {TIME}
243 Mpc
.prototype.seek
= Mpc
.__make_send_arg2('seek');
244 // seekid {SONGID} {TIME}
245 Mpc
.prototype.seekid
= Mpc
.__make_send_arg2('seekid');
247 Mpc
.prototype.seekcur
= Mpc
.__make_send_arg1('seekcur');
249 Mpc
.prototype.stop
= Mpc
.__make_send_void('stop');
252 * The current playlist
253 * http://www.musicpd.org/doc/protocol/ch03s04.html
257 Mpc
.prototype.add
= Mpc
.__make_send_arg1('add');
258 // addid {URI} [POSITION]
259 // TODO: handle position
260 Mpc
.prototype.addid
= Mpc
.__make_send_arg1('addid');
262 Mpc
.prototype.clear
= Mpc
.__make_send_void('clear');
263 // delete [{POS} | {START:END}]
264 Mpc
.prototype.delete = Mpc
.__make_send_arg1('delete');
266 Mpc
.prototype.deleteid
= Mpc
.__make_send_arg1('deleteid');
267 // move [{FROM} | {START:END}] {TO}
268 Mpc
.prototype.move = Mpc
.__make_send_arg2('move');
269 // moveid {FROM} {TO}
270 Mpc
.prototype.moveid
= Mpc
.__make_send_arg2('moveid');
272 Mpc
.prototype.playlist
= Mpc
.__make_send_void('playlist');
273 // playlistfind {TAG} {NEEDLE}
274 Mpc
.prototype.playlistfind
= Mpc
.__make_send_arg2('playlistfind');
275 // playlistid {SONGID}
276 Mpc
.prototype.playlistid
= Mpc
.__make_send_arg1('playlistid');
277 // playlistinfo [[SONGPOS] | [START:END]]
278 Mpc
.prototype.playlistinfo
= Mpc
.__make_send_opt('playlistinfo');
279 // playlistsearch {TAG} {NEEDLE}
280 Mpc
.prototype.playlistsearch
= Mpc
.__make_send_arg2('playlistsearch');
281 // plchanges {VERSION}
282 Mpc
.prototype.plchanges
= Mpc
.__make_send_arg1('plchanges');
283 // plchangesposid {VERSION}
284 Mpc
.prototype.plchangesposid
= Mpc
.__make_send_arg1('plchangesposid');
285 // prio {PRIORITY} {START:END...}
286 Mpc
.prototype.prio
= Mpc
.__make_send_arg2('prio');
287 // prioid {PRIORITY} {ID...}
288 Mpc
.prototype.prioid
= Mpc
.__make_send_arg2('prioid');
289 // shuffle [START:END]
290 Mpc
.prototype.shuffle
= Mpc
.__make_send_opt('shuffle');
291 // swap {SONG1} {SONG2}
292 Mpc
.prototype.swap
= Mpc
.__make_send_arg2('swap');
293 // swapid {SONG1} {SONG2}
294 Mpc
.prototype.swapid
= Mpc
.__make_send_arg2('swapid');
298 * http://www.musicpd.org/doc/protocol/ch03s05.html
301 // listplaylist {NAME}
302 Mpc
.prototype.listplaylist
= Mpc
.__make_send_arg1('listplaylist');
303 // listplaylistinfo {NAME}
304 Mpc
.prototype.listplaylistinfo
= Mpc
.__make_send_arg1('listplaylistinfo');
306 Mpc
.prototype.listplaylists
= Mpc
.__make_send_void('listplaylists');
307 // load {NAME} [START:END]
308 // TODO: handle optional start:end
309 Mpc
.prototype.load
= Mpc
.__make_send_arg1('load');
310 // playlistadd {NAME} {URI}
311 Mpc
.prototype.playlistadd
= Mpc
.__make_send_arg2('playlistadd');
312 // playlistclear {NAME}
313 Mpc
.prototype.playlistclear
= Mpc
.__make_send_arg1('playlistclear');
314 // playlistdelete {NAME} {SONGPOS}
315 Mpc
.prototype.playlistdelete
= Mpc
.__make_send_arg2('playlistdelete');
316 // playlistmove {NAME} {SONGID} {SONGPOS}
317 Mpc
.prototype.playlistmove
= Mpc
.__make_send_arg3('playlistmove');
318 // rename {NAME} {NEW_NAME}
319 Mpc
.prototype.rename
= Mpc
.__make_send_arg2('rename');
321 Mpc
.prototype.rm
= Mpc
.__make_send_arg1('rm');
323 Mpc
.prototype.save
= Mpc
.__make_send_arg1('save');
327 * http://www.musicpd.org/doc/protocol/ch03s06.html
331 * Connection settings
332 * http://www.musicpd.org/doc/protocol/ch03s08.html
336 Mpc
.prototype.close
= Mpc
.__make_send_void('close');
338 Mpc
.prototype.kill
= Mpc
.__make_send_void('kill');
339 // password {PASSWORD}
340 Mpc
.prototype.password
= Mpc
.__make_send_arg1('password');
342 Mpc
.prototype.ping
= Mpc
.__make_send_void('ping');
345 * Audio output devices
346 * http://www.musicpd.org/doc/protocol/ch03s09.html
349 // disableoutput {ID}
350 Mpc
.prototype.disableoutput
= Mpc
.__make_send_arg1('disableoutput');
352 Mpc
.prototype.enableoutput
= Mpc
.__make_send_arg1('enableoutput');
354 Mpc
.prototype.outputs
= Mpc
.__make_send_void('outputs');
358 * http://www.musicpd.org/doc/protocol/ch03s10.html
362 Mpc
.prototype.config
= Mpc
.__make_send_void('config');
364 Mpc
.prototype.commands
= Mpc
.__make_send_void('commands');
366 Mpc
.prototype.notcommands
= Mpc
.__make_send_void('notcommands');
368 Mpc
.prototype.tagtypes
= Mpc
.__make_send_void('tagtypes');
370 Mpc
.prototype.urlhandlers
= Mpc
.__make_send_void('urlhandlers');
372 Mpc
.prototype.decoders
= Mpc
.__make_send_void('decoders');
376 * http://www.musicpd.org/doc/protocol/ch03s11.html
380 Mpc
.prototype.subscribe
= Mpc
.__make_send_arg1('subscribe');
381 // unsubscribe {NAME}
382 Mpc
.prototype.unsubscribe
= Mpc
.__make_send_arg1('unsubscribe');
384 Mpc
.prototype.channels
= Mpc
.__make_send_void('channels');
386 Mpc
.prototype.readmessages
= Mpc
.__make_send_void('readmessages');
387 // sendmessage {CHANNEL} {TEXT}
388 Mpc
.prototype.sendmessage
= Mpc
.__make_send_arg2('sendmessage');