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'];
11 Mpc.prototype.log = function(lvl, msg, obj) {
12 if (this._debug_enabled & lvl)
13 console.log('mpc: ' + msg, obj);
16 Mpc.prototype.err = function(msg, obj) {
17 console.error('mpc: ' + msg, obj);
20 Mpc.prototype.set_debug = function(val) {
21 this._debug_enabled = val;
24 Mpc.prototype.send = function(msg) {
26 this._queue.push(msg);
27 this._socket.send(msg, function(x) {
28 _this.log(0x1, 'send: ' + msg + ':', x);
32 Mpc.prototype.recv_msg = function(lines) {
33 curr = this._queue.shift();
34 this.log(0x2, 'recv: [' + curr + ']:', lines.join('\n'));
35 curr = curr.split(' ');
38 // Needs to return a list of dicts (see above for dicts).
39 //case 'playlistinfo':
45 lines.forEach(function(line) {
46 i = line.indexOf(':');
48 return; // Ignores the OK line
49 key = line.substr(0, i);
51 val = line.substr(i + 2);
55 // When mpd is stopped, it gives us back crap values for some things.
56 if ('state' in state && state.state == 'stop') {
57 if ('volume' in state && state.volume == '-1')
58 keys.splice(keys.indexOf('volume'), 1);
60 // Now merge the current state with the previous one so that we don't
61 // lose information like volume or song position.
62 curr_state = this.state;
63 keys.forEach(function(key) {
64 curr_state[key] = state[key];
67 this._cb_update_state(curr_state);
70 this._cb_update_state(lines, curr);
75 Mpc.prototype.recv = function(msg) {
76 /* We can get back a bunch of responses in a row, so parse them out */
77 /* XXX: Do we have to handle partial reads ? like long playlists ... */
78 lines = msg.split('\n');
80 while (i < lines.length) {
81 if (lines[i] == 'OK' || lines[i].substr(0, 3) == 'OK ') {
82 this.recv_msg(lines.splice(0, i + 1));
90 * Command generator helpers.
93 Mpc.__make_send_void = function(cmd) {
94 return function() { this.send(cmd); }
97 Mpc.__make_send_arg1 = function(cmd) {
100 this.err(cmd + ': function requires one argument');
102 this.send(cmd + ' ' + a1);
106 Mpc.__make_send_arg2 = function(cmd) {
107 return function(a1, a2) {
108 if (a1 === undefined || a2 === undefined)
109 this.err(cmd + ': function requires two arguments');
111 this.send(cmd + ' ' + a1 + ' ' + a2);
115 Mpc.__make_send_opt = function(cmd) {
116 return function(arg) {
117 if (arg === undefined)
119 this.send(cmd + ' ' + arg);
123 Mpc.__make_send_range = function(cmd, min, max, def) {
124 return function(arg) {
125 if (arg === undefined)
127 if (arg >= min && arg <= max)
128 this.send(cmd + ' ' + arg);
130 this.err(cmd + ': arg must be [' + min + ',' + max + '] but got "' + arg + '"');
135 * Querying MPD's status
136 * http://www.musicpd.org/doc/protocol/ch03.html#idp118752
140 Mpc.prototype.clearerror = Mpc.__make_send_void('clearerror');
142 Mpc.prototype.currentsong = Mpc.__make_send_void('currentsong');
143 // idle [SUBSYSTEMS...]
146 Mpc.prototype.status = Mpc.__make_send_void('status');
148 Mpc.prototype.stats = Mpc.__make_send_void('stats');
152 * http://www.musicpd.org/doc/protocol/ch03s02.html
156 Mpc.prototype.consume = Mpc.__make_send_range('consume', 0, 1, 1);
157 // crossfade {SECONDS}
158 Mpc.prototype.crossfade = Mpc.__make_send_arg1('crossfade');
159 // mixrampdb {deciBels}
160 Mpc.prototype.mixrampdb = Mpc.__make_send_arg1('mixrampdb');
161 // mixrampdelay {SECONDS|nan}
162 // Note: Probably should handle javascript NaN here.
163 Mpc.prototype.mixrampdelay = Mpc.__make_send_arg1('mixrampdelay');
165 Mpc.prototype.random = Mpc.__make_send_range('random', 0, 1, 1);
167 Mpc.prototype.repeat = Mpc.__make_send_range('repeat', 0, 1, 1);
169 Mpc.prototype.setvol = Mpc.__make_send_range('setvol', 0, 100);
171 Mpc.prototype.single = Mpc.__make_send_range('single', 0, 1, 1);
172 // replay_gain_mode {MODE}
173 Mpc.prototype.replay_gain_mode = Mpc.__make_send_arg1('replay_gain_mode');
174 // replay_gain_status
177 * Controlling playback
178 * http://www.musicpd.org/doc/protocol/ch03s03.html
182 Mpc.prototype.next = Mpc.__make_send_void('next');
184 Mpc.prototype.pause = Mpc.__make_send_range('pause', 0, 1, 1);
186 Mpc.prototype.play = Mpc.__make_send_opt('play');
188 Mpc.prototype.playid = Mpc.__make_send_opt('playid');
190 Mpc.prototype.previous = Mpc.__make_send_void('previous');
191 // seek {SONGPOS} {TIME}
192 Mpc.prototype.seek = Mpc.__make_send_arg2('seek');
193 // seekid {SONGID} {TIME}
194 Mpc.prototype.seekid = Mpc.__make_send_arg2('seekid');
196 Mpc.prototype.seekcur = Mpc.__make_send_arg1('seek');
198 Mpc.prototype.stop = Mpc.__make_send_void('stop');
201 * Connection settings
202 * http://www.musicpd.org/doc/protocol/ch03s08.html
206 Mpc.prototype.close = Mpc.__make_send_void('close');
208 Mpc.prototype.kill = Mpc.__make_send_void('kill');
209 // password {PASSWORD}
210 Mpc.prototype.password = Mpc.__make_send_arg1('password');
212 Mpc.prototype.ping = Mpc.__make_send_void('ping');
215 * Audio output devices
216 * http://www.musicpd.org/doc/protocol/ch03s09.html
219 // disableoutput {ID}
220 Mpc.prototype.disableoutput = Mpc.__make_send_arg1('disableoutput');
222 Mpc.prototype.enableoutput = Mpc.__make_send_arg1('enableoutput');
224 Mpc.prototype.outputs = Mpc.__make_send_void('outputs');
228 * http://www.musicpd.org/doc/protocol/ch03s10.html
232 Mpc.prototype.config = Mpc.__make_send_void('config');
234 Mpc.prototype.commands = Mpc.__make_send_void('commands');
236 Mpc.prototype.notcommands = Mpc.__make_send_void('notcommands');
238 Mpc.prototype.tagtypes = Mpc.__make_send_void('tagtypes');
240 Mpc.prototype.urlhandlers = Mpc.__make_send_void('urlhandlers');
242 Mpc.prototype.decoders = Mpc.__make_send_void('decoders');
246 * http://www.musicpd.org/doc/protocol/ch03s11.html
250 Mpc.prototype.subscribe = Mpc.__make_send_arg1('subscribe');
251 // unsubscribe {NAME}
252 Mpc.prototype.unsubscribe = Mpc.__make_send_arg1('unsubscribe');
254 Mpc.prototype.channels = Mpc.__make_send_void('channels');
256 Mpc.prototype.readmessages = Mpc.__make_send_void('readmessages');
257 // sendmessage {CHANNEL} {TEXT}
258 Mpc.prototype.sendmessage = Mpc.__make_send_arg2('sendmessage');