]> git.wh0rd.org Git - chrome-ext/music-player-client.git/blob - js/mpc.js
add refresh option for updating the gui automatically
[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');