]> git.wh0rd.org Git - chrome-ext/music-player-client.git/blob - js/mpc.js
initial extension
[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) {
4         this._socket = socket;
5         this._cb_update_state = cb_update_state;
6         this._queue = ['init'];
7         this.state = {};
8 }
9
10 Mpc.log = function(msg, obj) {
11         console.log('mpc: ' + msg, obj);
12 }
13
14 Mpc.prototype.send = function(msg) {
15         this._queue.push(msg);
16         this._socket.send(msg, function(x) {
17                 Mpc.log('send: ' + msg + ':', x);
18         });
19 }
20
21 Mpc.prototype.recv_msg = function(lines) {
22         curr = this._queue.shift();
23         Mpc.log('recv: [' + curr + ']:', lines.join('\n'));
24         curr = curr.split(' ');
25
26         switch (curr[0]) {
27         // Needs to return a list of dicts (see above for dicts).
28         //case 'playlistinfo':
29         case 'currentsong':
30         case 'stats':
31         case 'status':
32                 state = {};
33                 lines.forEach(function(line) {
34                         i = line.indexOf(':');
35                         if (i == -1)
36                                 return; // Ignores the OK line
37                         key = line.substr(0, i);
38                         val = line.substr(i + 2);
39                         state[key] = val;
40                 });
41                 this.state = state;
42                 this._cb_update_state(state);
43                 break;
44         default:
45                 this._cb_update_state(lines, curr);
46                 break;
47         }
48 }
49
50 Mpc.prototype.recv = function(msg) {
51         /* We can get back a bunch of responses in a row, so parse them out */
52         /* XXX: Do we have to handle partial reads ?  like long playlists ... */
53         lines = msg.split('\n');
54         var i = 0;
55         while (i < lines.length) {
56                 if (lines[i] == 'OK' || lines[i].substr(0, 3) == 'OK ') {
57                         this.recv_msg(lines.splice(0, i + 1));
58                         i = 0;
59                 } else
60                         ++i;
61         }
62 }
63
64 /*
65  * Command generator helpers.
66  */
67
68 Mpc.__make_send_void = function(cmd) {
69         return function() { this.send(cmd); }
70 }
71
72 Mpc.__make_send_arg1 = function(cmd) {
73         return function(a1) {
74                 if (a1 === undefined)
75                         Mpc.log(cmd + ': function requires one argument');
76                 else
77                         this.send(cmd + ' ' + a1);
78         }
79 }
80
81 Mpc.__make_send_arg2 = function(cmd) {
82         return function(a1, a2) {
83                 if (a1 === undefined || a2 === undefined)
84                         Mpc.log(cmd + ': function requires two arguments');
85                 else
86                         this.send(cmd + ' ' + a1 + ' ' + a2);
87         }
88 }
89
90 Mpc.__make_send_opt = function(cmd) {
91         return function(arg) {
92                 if (arg === undefined)
93                         arg = '';
94                 this.send(cmd + ' ' + arg);
95         };
96 }
97
98 Mpc.__make_send_range = function(cmd, min, max, def) {
99         return function(arg) {
100                 if (arg === undefined)
101                         arg = def;
102                 if (arg >= min && arg <= max)
103                         this.send(cmd + ' ' + arg);
104                 else
105                         Mpc.log(cmd + ': arg must be [' + min + ',' + max + '] but got "' + arg + '"');
106         };
107 }
108
109 /*
110  * Querying MPD's status
111  * http://www.musicpd.org/doc/protocol/ch03.html#idp118752
112  */
113
114 // clearerror
115 Mpc.prototype.clearerror          = Mpc.__make_send_void('clearerror');
116 // currentsong
117 Mpc.prototype.currentsong         = Mpc.__make_send_void('currentsong');
118 // idle [SUBSYSTEMS...]
119 // TODO
120 // status
121 Mpc.prototype.status              = Mpc.__make_send_void('status');
122 // stats
123 Mpc.prototype.stats               = Mpc.__make_send_void('stats');
124
125 /*
126  * Playback options
127  * http://www.musicpd.org/doc/protocol/ch03s02.html
128  */
129
130 // consume {STATE}
131 Mpc.prototype.consume             = Mpc.__make_send_range('consume', 0, 1, 1);
132 // crossfade {SECONDS}
133 Mpc.prototype.consume             = Mpc.__make_send_arg1('crossfade');
134 // mixrampdb {deciBels}
135 Mpc.prototype.mixrampdb           = Mpc.__make_send_arg1('mixrampdb');
136 // mixrampdelay {SECONDS|nan}
137 // Note: Probably should handle javascript NaN here.
138 Mpc.prototype.mixrampdelay        = Mpc.__make_send_arg1('mixrampdelay');
139 // random {STATE}
140 Mpc.prototype.random              = Mpc.__make_send_range('random', 0, 1, 1);
141 // repeat {STATE}
142 Mpc.prototype.repeat              = Mpc.__make_send_range('repeat', 0, 1, 1);
143 // setvol {VOL}
144 Mpc.prototype.setvol              = Mpc.__make_send_range('setvol', 0, 100);
145 // single {STATE}
146 Mpc.prototype.single              = Mpc.__make_send_range('single', 0, 1, 1);
147 // replay_gain_mode {MODE}
148 Mpc.prototype.replay_gain_mode    = Mpc.__make_send_arg1('replay_gain_mode');
149 // replay_gain_status
150
151 /*
152  * Controlling playback
153  * http://www.musicpd.org/doc/protocol/ch03s03.html
154  */
155
156 // next
157 Mpc.prototype.next                = Mpc.__make_send_void('next');
158 // pause {PAUSE}
159 Mpc.prototype.pause               = Mpc.__make_send_range('pause', 0, 1, 1);
160 // play [SONGPOS]
161 Mpc.prototype.play                = Mpc.__make_send_opt('play');
162 // playid [SONGID]
163 Mpc.prototype.playid              = Mpc.__make_send_opt('playid');
164 // previous
165 Mpc.prototype.previous            = Mpc.__make_send_void('previous');
166 // seek {SONGPOS} {TIME}
167 Mpc.prototype.seek                = Mpc.__make_send_arg2('seek');
168 // seekid {SONGID} {TIME}
169 Mpc.prototype.seekid              = Mpc.__make_send_arg2('seekid');
170 // seekcur {TIME}
171 Mpc.prototype.seekcur             = Mpc.__make_send_arg1('seek');
172 // stop
173 Mpc.prototype.stop                = Mpc.__make_send_void('stop');
174
175 /*
176  * Connection settings
177  * http://www.musicpd.org/doc/protocol/ch03s08.html
178  */
179
180 // close
181 Mpc.prototype.close               = Mpc.__make_send_void('close');
182 // kill
183 Mpc.prototype.kill                = Mpc.__make_send_void('kill');
184 // password {PASSWORD}
185 Mpc.prototype.password            = Mpc.__make_send_arg1('password');
186 // ping
187 Mpc.prototype.ping                = Mpc.__make_send_void('ping');