fix NaN check
[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
4d3d4e03
MF
11Mpc.prototype.log = function(msg, obj) {
12 if (this._debug_enabled)
13 console.log('mpc: ' + msg, obj);
14}
15
16Mpc.prototype.set_debug = function(val) {
17 this._debug_enabled = val;
50dafc4c
MF
18}
19
20Mpc.prototype.send = function(msg) {
4d3d4e03 21 var _this = this;
50dafc4c
MF
22 this._queue.push(msg);
23 this._socket.send(msg, function(x) {
4d3d4e03 24 _this.log('send: ' + msg + ':', x);
50dafc4c
MF
25 });
26}
27
28Mpc.prototype.recv_msg = function(lines) {
29 curr = this._queue.shift();
4d3d4e03 30 this.log('recv: [' + curr + ']:', lines.join('\n'));
50dafc4c
MF
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
57Mpc.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
75Mpc.__make_send_void = function(cmd) {
76 return function() { this.send(cmd); }
77}
78
79Mpc.__make_send_arg1 = function(cmd) {
80 return function(a1) {
81 if (a1 === undefined)
4d3d4e03 82 this.log(cmd + ': function requires one argument');
50dafc4c
MF
83 else
84 this.send(cmd + ' ' + a1);
85 }
86}
87
88Mpc.__make_send_arg2 = function(cmd) {
89 return function(a1, a2) {
90 if (a1 === undefined || a2 === undefined)
4d3d4e03 91 this.log(cmd + ': function requires two arguments');
50dafc4c
MF
92 else
93 this.send(cmd + ' ' + a1 + ' ' + a2);
94 }
95}
96
97Mpc.__make_send_opt = function(cmd) {
98 return function(arg) {
99 if (arg === undefined)
100 arg = '';
101 this.send(cmd + ' ' + arg);
102 };
103}
104
105Mpc.__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
4d3d4e03 112 this.log(cmd + ': arg must be [' + min + ',' + max + '] but got "' + arg + '"');
50dafc4c
MF
113 };
114}
115
116/*
117 * Querying MPD's status
118 * http://www.musicpd.org/doc/protocol/ch03.html#idp118752
119 */
120
121// clearerror
122Mpc.prototype.clearerror = Mpc.__make_send_void('clearerror');
123// currentsong
124Mpc.prototype.currentsong = Mpc.__make_send_void('currentsong');
125// idle [SUBSYSTEMS...]
126// TODO
127// status
128Mpc.prototype.status = Mpc.__make_send_void('status');
129// stats
130Mpc.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}
138Mpc.prototype.consume = Mpc.__make_send_range('consume', 0, 1, 1);
139// crossfade {SECONDS}
f5ed7157 140Mpc.prototype.crossfade = Mpc.__make_send_arg1('crossfade');
50dafc4c
MF
141// mixrampdb {deciBels}
142Mpc.prototype.mixrampdb = Mpc.__make_send_arg1('mixrampdb');
143// mixrampdelay {SECONDS|nan}
144// Note: Probably should handle javascript NaN here.
145Mpc.prototype.mixrampdelay = Mpc.__make_send_arg1('mixrampdelay');
146// random {STATE}
147Mpc.prototype.random = Mpc.__make_send_range('random', 0, 1, 1);
148// repeat {STATE}
149Mpc.prototype.repeat = Mpc.__make_send_range('repeat', 0, 1, 1);
150// setvol {VOL}
151Mpc.prototype.setvol = Mpc.__make_send_range('setvol', 0, 100);
152// single {STATE}
153Mpc.prototype.single = Mpc.__make_send_range('single', 0, 1, 1);
154// replay_gain_mode {MODE}
155Mpc.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
164Mpc.prototype.next = Mpc.__make_send_void('next');
165// pause {PAUSE}
166Mpc.prototype.pause = Mpc.__make_send_range('pause', 0, 1, 1);
167// play [SONGPOS]
168Mpc.prototype.play = Mpc.__make_send_opt('play');
169// playid [SONGID]
170Mpc.prototype.playid = Mpc.__make_send_opt('playid');
171// previous
172Mpc.prototype.previous = Mpc.__make_send_void('previous');
173// seek {SONGPOS} {TIME}
174Mpc.prototype.seek = Mpc.__make_send_arg2('seek');
175// seekid {SONGID} {TIME}
176Mpc.prototype.seekid = Mpc.__make_send_arg2('seekid');
177// seekcur {TIME}
178Mpc.prototype.seekcur = Mpc.__make_send_arg1('seek');
179// stop
180Mpc.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
188Mpc.prototype.close = Mpc.__make_send_void('close');
189// kill
190Mpc.prototype.kill = Mpc.__make_send_void('kill');
191// password {PASSWORD}
192Mpc.prototype.password = Mpc.__make_send_arg1('password');
193// ping
194Mpc.prototype.ping = Mpc.__make_send_void('ping');