add helpful tip to people who find the console
[chrome-ext/music-player-client.git] / js / mpc.js
CommitLineData
50dafc4c
MF
1// Written by Mike Frysinger <vapier@gmail.com>. Released into the public domain. Suck it.
2
4d3d4e03 3function Mpc(socket, cb_update_state, debug_enabled) {
50dafc4c
MF
4 this._socket = socket;
5 this._cb_update_state = cb_update_state;
4d3d4e03 6 this._debug_enabled = debug_enabled;
50dafc4c
MF
7 this._queue = ['init'];
8 this.state = {};
9}
10
e4657cab
MF
11Mpc.prototype.log = function(lvl, msg, obj) {
12 if (this._debug_enabled & lvl)
4d3d4e03
MF
13 console.log('mpc: ' + msg, obj);
14}
15
e4657cab
MF
16Mpc.prototype.err = function(msg, obj) {
17 console.error('mpc: ' + msg, obj);
18}
19
4d3d4e03
MF
20Mpc.prototype.set_debug = function(val) {
21 this._debug_enabled = val;
50dafc4c
MF
22}
23
24Mpc.prototype.send = function(msg) {
4d3d4e03 25 var _this = this;
50dafc4c
MF
26 this._queue.push(msg);
27 this._socket.send(msg, function(x) {
e4657cab 28 _this.log(0x1, 'send: ' + msg + ':', x);
50dafc4c
MF
29 });
30}
31
32Mpc.prototype.recv_msg = function(lines) {
33 curr = this._queue.shift();
e4657cab 34 this.log(0x2, 'recv: [' + curr + ']:', lines.join('\n'));
50dafc4c
MF
35 curr = curr.split(' ');
36
37 switch (curr[0]) {
38 // Needs to return a list of dicts (see above for dicts).
39 //case 'playlistinfo':
40 case 'currentsong':
41 case 'stats':
42 case 'status':
43 state = {};
44 lines.forEach(function(line) {
45 i = line.indexOf(':');
46 if (i == -1)
47 return; // Ignores the OK line
48 key = line.substr(0, i);
49 val = line.substr(i + 2);
50 state[key] = val;
51 });
52 this.state = state;
53 this._cb_update_state(state);
54 break;
55 default:
56 this._cb_update_state(lines, curr);
57 break;
58 }
59}
60
61Mpc.prototype.recv = function(msg) {
62 /* We can get back a bunch of responses in a row, so parse them out */
63 /* XXX: Do we have to handle partial reads ? like long playlists ... */
64 lines = msg.split('\n');
65 var i = 0;
66 while (i < lines.length) {
67 if (lines[i] == 'OK' || lines[i].substr(0, 3) == 'OK ') {
68 this.recv_msg(lines.splice(0, i + 1));
69 i = 0;
70 } else
71 ++i;
72 }
73}
74
75/*
76 * Command generator helpers.
77 */
78
79Mpc.__make_send_void = function(cmd) {
80 return function() { this.send(cmd); }
81}
82
83Mpc.__make_send_arg1 = function(cmd) {
84 return function(a1) {
85 if (a1 === undefined)
e4657cab 86 this.err(cmd + ': function requires one argument');
50dafc4c
MF
87 else
88 this.send(cmd + ' ' + a1);
89 }
90}
91
92Mpc.__make_send_arg2 = function(cmd) {
93 return function(a1, a2) {
94 if (a1 === undefined || a2 === undefined)
e4657cab 95 this.err(cmd + ': function requires two arguments');
50dafc4c
MF
96 else
97 this.send(cmd + ' ' + a1 + ' ' + a2);
98 }
99}
100
101Mpc.__make_send_opt = function(cmd) {
102 return function(arg) {
103 if (arg === undefined)
104 arg = '';
105 this.send(cmd + ' ' + arg);
106 };
107}
108
109Mpc.__make_send_range = function(cmd, min, max, def) {
110 return function(arg) {
111 if (arg === undefined)
112 arg = def;
113 if (arg >= min && arg <= max)
114 this.send(cmd + ' ' + arg);
115 else
e4657cab 116 this.err(cmd + ': arg must be [' + min + ',' + max + '] but got "' + arg + '"');
50dafc4c
MF
117 };
118}
119
120/*
121 * Querying MPD's status
122 * http://www.musicpd.org/doc/protocol/ch03.html#idp118752
123 */
124
125// clearerror
126Mpc.prototype.clearerror = Mpc.__make_send_void('clearerror');
127// currentsong
128Mpc.prototype.currentsong = Mpc.__make_send_void('currentsong');
129// idle [SUBSYSTEMS...]
130// TODO
131// status
132Mpc.prototype.status = Mpc.__make_send_void('status');
133// stats
134Mpc.prototype.stats = Mpc.__make_send_void('stats');
135
136/*
137 * Playback options
138 * http://www.musicpd.org/doc/protocol/ch03s02.html
139 */
140
141// consume {STATE}
142Mpc.prototype.consume = Mpc.__make_send_range('consume', 0, 1, 1);
143// crossfade {SECONDS}
f5ed7157 144Mpc.prototype.crossfade = Mpc.__make_send_arg1('crossfade');
50dafc4c
MF
145// mixrampdb {deciBels}
146Mpc.prototype.mixrampdb = Mpc.__make_send_arg1('mixrampdb');
147// mixrampdelay {SECONDS|nan}
148// Note: Probably should handle javascript NaN here.
149Mpc.prototype.mixrampdelay = Mpc.__make_send_arg1('mixrampdelay');
150// random {STATE}
151Mpc.prototype.random = Mpc.__make_send_range('random', 0, 1, 1);
152// repeat {STATE}
153Mpc.prototype.repeat = Mpc.__make_send_range('repeat', 0, 1, 1);
154// setvol {VOL}
155Mpc.prototype.setvol = Mpc.__make_send_range('setvol', 0, 100);
156// single {STATE}
157Mpc.prototype.single = Mpc.__make_send_range('single', 0, 1, 1);
158// replay_gain_mode {MODE}
159Mpc.prototype.replay_gain_mode = Mpc.__make_send_arg1('replay_gain_mode');
160// replay_gain_status
161
162/*
163 * Controlling playback
164 * http://www.musicpd.org/doc/protocol/ch03s03.html
165 */
166
167// next
168Mpc.prototype.next = Mpc.__make_send_void('next');
169// pause {PAUSE}
170Mpc.prototype.pause = Mpc.__make_send_range('pause', 0, 1, 1);
171// play [SONGPOS]
172Mpc.prototype.play = Mpc.__make_send_opt('play');
173// playid [SONGID]
174Mpc.prototype.playid = Mpc.__make_send_opt('playid');
175// previous
176Mpc.prototype.previous = Mpc.__make_send_void('previous');
177// seek {SONGPOS} {TIME}
178Mpc.prototype.seek = Mpc.__make_send_arg2('seek');
179// seekid {SONGID} {TIME}
180Mpc.prototype.seekid = Mpc.__make_send_arg2('seekid');
181// seekcur {TIME}
182Mpc.prototype.seekcur = Mpc.__make_send_arg1('seek');
183// stop
184Mpc.prototype.stop = Mpc.__make_send_void('stop');
185
186/*
187 * Connection settings
188 * http://www.musicpd.org/doc/protocol/ch03s08.html
189 */
190
191// close
192Mpc.prototype.close = Mpc.__make_send_void('close');
193// kill
194Mpc.prototype.kill = Mpc.__make_send_void('kill');
195// password {PASSWORD}
196Mpc.prototype.password = Mpc.__make_send_arg1('password');
197// ping
198Mpc.prototype.ping = Mpc.__make_send_void('ping');
024ea284
MF
199
200/*
201 * Audio output devices
202 * http://www.musicpd.org/doc/protocol/ch03s09.html
203 */
204
205// disableoutput {ID}
206Mpc.prototype.disableoutput = Mpc.__make_send_arg1('disableoutput');
207// enableoutput {ID}
208Mpc.prototype.enableoutput = Mpc.__make_send_arg1('enableoutput');
209// outputs
210Mpc.prototype.outputs = Mpc.__make_send_void('outputs');
211
212/*
213 * Reflection
214 * http://www.musicpd.org/doc/protocol/ch03s10.html
215 */
216
217// config
218Mpc.prototype.config = Mpc.__make_send_void('config');
219// commands
220Mpc.prototype.commands = Mpc.__make_send_void('commands');
221// notcommands
222Mpc.prototype.notcommands = Mpc.__make_send_void('notcommands');
223// tagtypes
224Mpc.prototype.tagtypes = Mpc.__make_send_void('tagtypes');
225// urlhandlers
226Mpc.prototype.urlhandlers = Mpc.__make_send_void('urlhandlers');
227// decoders
228Mpc.prototype.decoders = Mpc.__make_send_void('decoders');
229
230/*
231 * Client to client
232 * http://www.musicpd.org/doc/protocol/ch03s11.html
233 */
234
235// subscribe {NAME}
236Mpc.prototype.subscribe = Mpc.__make_send_arg1('subscribe');
237// unsubscribe {NAME}
238Mpc.prototype.unsubscribe = Mpc.__make_send_arg1('unsubscribe');
239// channels
240Mpc.prototype.channels = Mpc.__make_send_void('channels');
241// readmessages
242Mpc.prototype.readmessages = Mpc.__make_send_void('readmessages');
243// sendmessage {CHANNEL} {TEXT}
244Mpc.prototype.sendmessage = Mpc.__make_send_arg2('sendmessage');