c23c3166bb95ae13daace31b8a30f8da065efadc
[mpd-lua.git] / mpd.js
1 urlbase="/cgi-bin/mpd.lua?"
2 minScrollHeight=200
3
4 currentState=""
5
6 function GetFilename(url)
7 {
8    if (url)
9    return url.split('/').pop().split('#')[0].split('?')[0];
10 }
11
12 function EscapeStr(str) {
13   res = str.replace(/'/g,"\\'");
14   return res;
15 }
16
17 function SetSize() {
18   var w = window,
19       d = document,
20       e = d.documentElement,
21       g = d.getElementsByTagName('body')[0],
22       body_h = g.clientHeight,
23       window_h = w.innerHeight|| e.clientHeight|| g.clientHeight,
24       items = d.getElementById('items'),
25       current_h = items.clientHeight,
26       new_h=(window_h-body_h)+current_h;
27       if (new_h>minScrollHeight) {
28         items.style.height=new_h+"px";
29       }
30 }
31
32 function toHHMMSS(seconds) {
33     var hours = Math.floor(seconds / 3600);
34     seconds -= hours*3600;
35     var minutes = Math.floor(seconds / 60);
36     seconds -= minutes*60;
37
38     if (hours   < 10) {hours   = "0"+hours;}
39     if (minutes < 10) {minutes = "0"+minutes;}
40     if (seconds < 10) {seconds = "0"+seconds;}
41     if (hours == 0) {
42      return minutes+':'+seconds;
43     } else {
44      return hours+':'+minutes+':'+seconds;
45     }
46 }
47
48 function RefreshTime() {
49   if (currentSeconds) {
50     currentTime = toHHMMSS(currentSeconds)
51     trackTime = toHHMMSS(trackSeconds)
52     nowPlayingTime = currentTime+"/"+trackTime
53   } else {
54     nowPlayingTime = "-:--/-:--"
55   }
56   document.getElementById('nowplaying_tracklen').innerHTML=nowPlayingTime;
57 }
58
59 function PeriodicRefreshTime() {
60   if (currentState == "play") {
61     nowTime = Date.now()
62     delta = (nowTime - updateTime)/1000
63     currentSeconds = updateSeconds + Math.round(delta)
64     if (currentSeconds > trackSeconds) {
65       currentSeconds = trackSeconds
66     }
67     RefreshTime()
68   }
69 }
70
71 function RefreshPageStatus() {
72
73   var req = new XMLHttpRequest();
74
75   req.onreadystatechange = function () {
76     if (this.readyState != 4 || this.status != 200) return;
77     var returnedData = JSON.parse(this.responseText);
78     trackName = GetFilename(returnedData['current_playing']);
79     trackNo = returnedData['song'];
80     currentState = returnedData['state'];
81     document.title='MPD Player: '+trackName;
82     nowPlayingTrack = (1+Number(trackNo)) + '/' + returnedData['playlistlength'];
83     nowPlayingName = trackName;
84     playingTime = returnedData['time']
85     if (playingTime) {
86       var splits = playingTime.split(":")
87       updateTime = Date.now()
88       currentSeconds = Number(splits[0])
89       updateSeconds = currentSeconds
90       trackSeconds = Number(splits[1])
91     } else {
92       currentSeconds = null
93     }
94     if (currentState=='stop') {
95       nowPlayingName = '<font color="gray">' + nowPlayingName+ '</font>'
96     }
97     document.getElementById('nowplaying_trackno').innerHTML=nowPlayingTrack;
98     document.getElementById('nowplaying_trackname').innerHTML=nowPlayingName;
99     RefreshTime()
100     if (currentState=="play") {
101       document.getElementById('playpausebutton').innerHTML="<span onclick=\"Command('pause')\"><img class=\"button\" title=\"Pause\" src=\"images/pause.svg\"></span>";
102     } else {
103       document.getElementById('playpausebutton').innerHTML="<span onclick=\"Command('play')\"><img class=\"button\" title=\"Play\" src=\"images/play-button.svg\"></span>";
104     }
105     if (currentState=="stop") {
106       document.getElementById('stopbutton').innerHTML="<span><img class=\"button\" src=\"images/stopoff.svg\"></span>";
107     } else {
108       document.getElementById('stopbutton').innerHTML="<span onclick=\"Command('stop')\"><img class=\"button\" title=\"Stop\" src=\"images/stop.svg\"></span>";
109     }
110     if (returnedData["repeat"]=="1") {
111       document.getElementById('repeatstate').innerHTML="<img class=\"button\" title=\"Replay is on\" src=\"images/replay.svg\"></a>";
112     } else {
113       document.getElementById('repeatstate').innerHTML="<img class=\"button\" title=\"Replay is off\" src=\"images/replayoff.svg\"></a>";
114     }
115     document.getElementById('volume_total').innerHTML="<div id=\"volume_actual\" style=\"width:"+returnedData["volume"]+"%\">";
116
117     var items = document.getElementById('items');
118     var table = items.getElementsByClassName('track');
119     var current_track="track_"+trackNo;
120     for (var i = 0; i < table.length; i++) {
121       if (table[i].id==current_track) {
122         table[i].classList.add("itemActive");
123       } else {
124         table[i].classList.remove("itemActive")
125       }
126     }
127         
128   };
129
130   req.open("GET", urlbase+"status", true);
131   req.send();
132
133 }
134
135 function RefreshPlaylist() {
136
137 var req = new XMLHttpRequest();
138
139 req.onreadystatechange = function () {
140   if (this.readyState != 4 || this.status != 200) return;
141   var returnedData = JSON.parse(this.responseText);
142
143   var playlistMenuText = "<table>\
144   <tr>\
145   <td><span onclick=\"EditPlayList()\"><img class=\"medium-button\" title=\"Files\" src=\"images/folder.svg\"></span><td>\
146   <td><span onclick=\"LoadPlayList()\"><img class=\"medium-button\" title=\"Lists\" src=\"images/list.svg\"></span><td>\
147   <td><span onclick=\"SavePlayList()\"><img class=\"medium-button\" title=\"Save current list\" src=\"images/download.svg\"></span><td>\
148   <td><span onclick=\"return confirm('Clear current playlist, are you sure?') ? PlaylistCommand('clear') : false;\" ><img class=\"medium-button\" title=\"Clear current list\"  src=\"images/cancel.svg\"></span><td>\
149   </tr>\
150   </table>";
151
152   var itemsText="<table>\
153   <tr id=\"items_heading\">\
154   <td></td class=\"track_number\"><td class=\"file\">Title</td><td class=\"medium-button\" colspan=\"3\">Controls</td>\
155   </tr>";
156
157   var even = 0;
158   for (var key in returnedData) {
159        var rec=returnedData[key];
160        var name=GetFilename(rec["name"]);
161        var id=rec["id"];
162
163        if (even) { 
164          evText="itemEven"; 
165        } else { 
166          evText="itemOdd";
167        };
168
169        even = ! even;
170
171        itemsText = itemsText + "<tr id=\"track_"+id+"\" class=\"track "+evText+"\">\
172   <td class=\"track_number\">\
173   <a name=\""+id+"\">"+(Number(id)+1)+"</a></td>\
174   </td>\
175   <td class=\"file\">\
176   <span class=\"link\" onclick=\"PlaylistCommand('playitem',"+id+")\">"+name+"</span>\
177   </td>\
178   <td class=\"move\">\
179   <span onclick=\"PlaylistCommand('moveup',"+id+")\"><img class=\"small-button\" title=\"Move up\" src=\"images/up-arrow.svg\"></span>\
180   </td>\
181   <td class=\"move\">\
182   <span onclick=\"PlaylistCommand('movedown',"+id+")\"><img class=\"small-button\" title=\"Move down\" src=\"images/down-arrow.svg\"></span>\
183   </td>\
184   <td class=\"remove\">\
185   <span onclick=\"PlaylistCommand('remove',"+id+")\"><img class=\"small-button\" title=\"Remove\" src=\"images/cancel.svg\"></span>\
186   </td>\
187   </tr>"; 
188   }
189
190   itemsText = itemsText + "</table>";
191
192   document.getElementById('items').innerHTML=itemsText;
193   document.getElementById('playlist_menu_top').innerHTML=playlistMenuText;
194   document.getElementById('playlist_menu_bottom').innerHTML=playlistMenuText;
195 };
196
197 req.open("GET", urlbase+"playlist", true);
198 req.send();
199
200 }
201
202 function EditPlayList(dir) {
203
204 var req = new XMLHttpRequest();
205
206 req.onreadystatechange = function () {
207   if (this.readyState != 4 || this.status != 200) return;
208   var returnedData = JSON.parse(this.responseText);
209
210   var playlistMenuText = "<table>\
211   <tr>\
212   <td><span onclick=\"RefreshPlaylist()\"><img class=\"medium-button\" title=\"Home\" src=\"images/list.svg\"></span><td>\
213   <td><span onclick=\"return confirm('Add all to the list, are you sure?') ? PlaylistEditCommand('add','"+EscapeStr(dir)+"') : false;\" ><img class=\"medium-button\" title=\"Add all\" src=\"images/plus.svg\"></span><td>\
214   </tr>\
215   </table>";
216
217   var itemsText= "<table>\
218   <tr id=\"items_heading\">\
219   <td></td class=\"track_number\"><td class=\"file\">Title</td><td colspan=\"2\">Controls</td>\
220   </tr>";
221
222   var even = 0;
223   if (dir) {
224     var lastSlash=dir.lastIndexOf("/");
225     if (lastSlash>0) {
226       var upperLevel=dir.slice(0,lastSlash);
227     } else {
228       var upperLevel="";
229     }
230     even = ! even;
231     var itemsText = itemsText + "<tr class=\"itemOdd\">\
232   <td class=\"track_number\"></td>\
233   <td class=\"file\"><span class=\"link\" onclick=\"EditPlayList('"+upperLevel+"')\">..</span></td>\
234   <td></td><td></td>";
235   } 
236
237   var i = 0;
238   for (var key in returnedData) {
239        var rec=returnedData[key];
240        var type=rec["type"];
241        var name=rec["name"];
242        var lastSlash=name.lastIndexOf("/");
243        if (lastSlash>0) {
244          var tailName=name.slice(lastSlash+1);
245        } else {
246          var tailName=name
247        };
248
249        if (type == "directory" || type == "file") {
250          if (even) { 
251            evText="itemEven"; 
252          } else { 
253            evText="itemOdd";
254          };
255
256          i = i + 1;
257          even = ! even;
258
259          itemsText = itemsText + "<tr class=\""+evText+"\">\
260            <td class=\"track_number\">\
261            <a name=\""+i+"\"></a></td>\
262            </td>";
263       
264          if (type == "directory") {
265            itemsText = itemsText + "<td class=\"file\">\
266              <span class=\"link\" onclick=\"EditPlayList('"+EscapeStr(name)+"')\">"+tailName+"</span></td><td>\
267              <span onclick=\"PlaylistEditCommand('add','"+EscapeStr(name)+"')\"><img class=\"small-button\" title=\"Add\" src=\"images/plus.svg\"></span></td>";
268          }; 
269
270          if (type == "file") {
271            itemsText = itemsText + "<td class=\"file\">\
272              <span class=\"link\" onclick=\"PlaylistEditCommand('add','"+EscapeStr(name)+"')\">"+tailName+"</span></td><td>\
273              <span onclick=\"PlaylistEditCommand('add','"+EscapeStr(name)+"')\"><img class=\"small-button\" title=\"Add\" src=\"images/plus.svg\"></span></td>";
274          };
275
276          itemsText = itemsText + "</tr>";
277
278        }       
279        
280   }
281
282   var itemsText = itemsText+"</table>";
283   document.getElementById('items').innerHTML=itemsText;
284   document.getElementById('playlist_menu_top').innerHTML=playlistMenuText;
285   document.getElementById('playlist_menu_bottom').innerHTML=playlistMenuText;
286 };
287
288 if (!dir) { dir = ''; };
289
290 req.open("GET", urlbase+"lists|edit|"+dir, true);
291 req.send();
292
293 }
294
295 function LoadPlayList() {
296
297 var req = new XMLHttpRequest();
298
299 req.onreadystatechange = function () {
300   if (this.readyState != 4 || this.status != 200) return;
301   var returnedData = JSON.parse(this.responseText);
302   playlistMenuText="<table>\
303     <tr>\
304       <td><span onclick=\"RefreshPlaylist()\"><img class=\"medium-button\" title=\"Home\" src=\"images/list.svg\"></span><td>\
305       <td><span onclick=\"confirm('Clear current playlist, are you sure?') ? PlaylistCommandRefStatus('clear') : false;\" ><img class=\"medium-button\" title=\"Clear all\" src=\"images/cancel.svg\"></span><td>\
306     </tr>\
307     </table>";
308   itemsText="<table>\
309     <tr id=\"items_heading\">\
310       <td class=\"track_number\"></td><td class=\"file\">Name</td><td>Controls</td>\
311     </tr>";
312
313   var even = 0;
314   for (var key in returnedData) {
315        var name=returnedData[key];
316
317        if (even) { 
318          evText="itemEven"; 
319        } else { 
320          evText="itemOdd";
321        };
322
323        even = ! even;
324
325        itemsText = itemsText + "<tr class=\""+evText+"\">\
326       <td class=\"track_number\"><a name=\"0\"></a></td>\
327       <td class=\"file\"><span class=\"link\" onclick=\"PlaylistEditCommandRefFull('load','"+EscapeStr(name)+"')\">"+name+"</td>\
328       <td class=\"controls\"><span onclick=\"confirm('Delete playlist "+name+", are you sure?') ? DelPlayList('"+EscapeStr(name)+"') : false;\"><img class=\"small-button\" title=\"Delete\" src=\"images/minus.svg\"></span></td>\
329     </tr>";
330   }
331
332   itemsText=itemsText+"</table>";
333   document.getElementById('items').innerHTML=itemsText;
334   document.getElementById('playlist_menu_top').innerHTML=playlistMenuText;
335   document.getElementById('playlist_menu_bottom').innerHTML=playlistMenuText;
336 };
337
338 req.open("GET", urlbase+"lists|load", true);
339 req.send();
340
341 }
342
343 function SavePlayList() {
344
345 var name=window.prompt('List name','');
346
347 var req = new XMLHttpRequest();
348
349 req.onreadystatechange = function () {
350   if (this.readyState != 4 || this.status != 200) return;
351   if (this.responseText != 'OK') {
352     window.alert(this.responseText);
353   }
354 };
355
356 req.open("GET", urlbase+"lists|save|"+name, true);
357 req.send();
358
359 }
360
361 function DelPlayList(item) {
362
363 var req = new XMLHttpRequest();
364
365 req.onreadystatechange = function () {
366   if (this.readyState != 4 || this.status != 200) return;
367   LoadPlayList();
368   RefreshPageStatus();
369 };
370
371 req.open("GET", urlbase+"lists|delete|"+item, true);
372 req.send();
373
374 }
375
376 function RefreshPageContent() {
377   RefreshPlaylist();
378   RefreshPageStatus();
379 }
380
381 function Command(cmd) {
382
383 var req = new XMLHttpRequest();
384
385 req.onreadystatechange = function () {
386   if (this.readyState != 4 || this.status != 200) return;
387   RefreshPageStatus();
388 };
389
390 req.open("GET", urlbase+cmd, true);
391 req.send();
392
393 }
394
395 function PlaylistCommand(cmd,item) {
396
397 var req = new XMLHttpRequest();
398
399 req.onreadystatechange = function () {
400   if (this.readyState != 4 || this.status != 200) return;
401   RefreshPageContent();
402 };
403
404 req.open("GET", urlbase+"cpl|"+cmd+"|"+item, true);
405 req.send();
406
407 }
408
409 function PlaylistCommandRefStatus(cmd,item) {
410
411 var req = new XMLHttpRequest();
412
413 req.onreadystatechange = function () {
414   if (this.readyState != 4 || this.status != 200) return;
415   RefreshPageStatus();
416 };
417
418 req.open("GET", urlbase+"cpl|"+cmd+"|"+item, true);
419 req.send();
420
421 }
422
423 function PlaylistEditCommand(cmd,item) {
424
425 var req = new XMLHttpRequest();
426
427 req.onreadystatechange = function () {
428   if (this.readyState != 4 || this.status != 200) return;
429   RefreshPageStatus();
430 };
431
432 req.open("GET", urlbase+"lists|"+cmd+"|"+item, true);
433 req.send();
434
435 }
436
437 function PlaylistEditCommandRefFull(cmd,item) {
438
439 var req = new XMLHttpRequest();
440
441 req.onreadystatechange = function () {
442   if (this.readyState != 4 || this.status != 200) return;
443   RefreshPageContent();
444 };
445
446 req.open("GET", urlbase+"lists|"+cmd+"|"+item, true);
447 req.send();
448
449 }
450
451 function subscribe_status() {
452   var xhr = new XMLHttpRequest();
453
454   xhr.onreadystatechange = function() {
455     if (this.readyState != 4) return;
456     if (this.status == 200) {
457       RefreshPageStatus()
458       setTimeout(subscribe_status,1000)
459     } else {
460       setTimeout(subscribe_status,15000)
461     }
462   }
463   xhr.open("GET", urlbase+"idle", true);
464   xhr.send();
465 }
466
467 setTimeout(subscribe_status,5000)
468 setInterval(PeriodicRefreshTime, 1000);