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