refactored asunder and added build scripts
[stereo.git] / Asunder / src / webserver / index.xhtml
blobe199fc75802741115e10e0f9a1e6a175b8603895
1 <?xml version="1.0" encoding="utf-8" ?>
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
3 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
4 <html xmlns="http://www.w3.org/1999/xhtml"
5 xmlns:svg="http://www.w3.org/2000/svg">
6 <head>
7 <title>Stereo</title>
8 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
9 <script type="text/javascript" charset="utf-8">
10 //<![CDATA[
11 function getPlaybackStatusUpdate() {
12 var request = "/ctrl-int/1/playstatusupdate";
14 if (lastUpdate && lastUpdate.revision) {
15 request += "?revision-number="+lastUpdate.revision;
18 ajax.request(request, function (response) {
19 var tree = new Node(response);
21 var up = new PlayStatusUpdate(tree, 0);
23 updateStatus(up);
25 if (!lastUpdate || up.revision != lastUpdate.revision) {
26 getPlaylistUpdate();
27 getAlbumArt(up.revision);
28 if ((!lastUpdate && up.status == 4)
29 || (lastUpdate.status == 2 && up.status == 4)) {
30 document.body.className = "playing";
34 lastUpdate = up;
35 if (up.status) {
36 getPlaybackStatusUpdate();
37 getVolume();
39 });
42 function getPlaylistUpdate() {
43 var request = "/ctrl-int/1/playlist";
44 ajax.request(request, function (text) {
45 var tree = new Node(text);
46 var playlist = new Playlist(tree, 0);
47 updatePlaylist(playlist);
48 });
51 function getAlbumArt(revision) {
52 document.getElementById("albumart").src = "/ctrl-int/1/nowplayingartwork?revision="+revision;
55 function getPlaylists() {
56 var request = "/databases/1/containers";
57 var callback = function (text) {
59 var tree = new Node(text);
61 var list = findNode(tree, 0, "mlcl");
63 var playlists = getItems(tree, list, function (t, i) {
64 return new Container(t, i);
65 });
67 var parent = document.getElementById("browse-playlists-container");
68 while (parent.childNodes.length > 0) {
69 parent.removeChild(parent.firstChild);
72 for (p in playlists) {
73 var item = document.createElement("DIV");
74 item.className="item";
76 item.appendChild(createNode("title", playlists[p].name));
77 item.appendChild(createNode("count", playlists[p].items));
78 item.collection = playlists[p].id;
79 item.persistent = playlists[p].persistent;
81 if (playlists[p].id == lastUpdate.container) {
82 item.className += " current";
85 parent.appendChild(item);
88 ajax.request(request, callback);
91 function getArtists() {
92 var request = "/databases/1/browse/artists";
93 var callback = function (text) {
95 var tree = new Node(text);
97 var list = findNode(tree, 0, "abar");
99 var artists = getItems(tree, list, function (t, i) {
100 return t.stringVal(i);
103 var parent = document.getElementById("browse-artists-container");
104 while (parent.childNodes.length > 0) {
105 parent.removeChild(parent.firstChild);
108 for (a in artists) {
109 var item = document.createElement("DIV");
110 item.className="item";
111 item.query="'daap.songartist:"+artists[a]+"'";
113 item.appendChild(createNode("title", artists[a]));
115 parent.appendChild(item);
118 ajax.request(request, callback);
121 function getAlbums(query, callback) {
122 var request = "/databases/1/groups?group-type=albums&sort=albums&query="+query;
123 var fn = function (text) {
125 var tree = new Node(text);
127 var list = findNode(tree, 0, "mlcl");
129 var albums = getItems(tree, list, function (t, i) {
130 return new Album(t, i);
133 callback(albums);
135 ajax.request(request, fn);
139 function getTracks(query, callback) {
141 var request = "/databases/1/containers/1/items?query="+query;
142 var fn = function (text) {
144 var tree = new Node(text);
146 var list = findNode(tree, 0, "mlcl");
148 var tracks = getItems(tree, list, function (t, i) {
149 return new Track(t, i);
152 callback(tracks);
154 ajax.request(request, fn);
157 function getCollectionTracks(collection, callback) {
159 var request = "/databases/1/containers/" + collection + "/items";
160 var fn = function (text) {
162 var tree = new Node(text);
164 var list = findNode(tree, 0, "mlcl");
166 var tracks = getItems(tree, list, function (t, i) {
167 return new Track(t, i);
170 callback(tracks);
172 ajax.request(request, fn);
175 function getVolume() {
177 var request = "/ctrl-int/1/getproperty?properties=dmcp.volume"
178 var fn = function (text) {
180 var tree = new Node(text);
182 var volume = tree.intVal(findNode(tree, 0, "cmvo"));
184 var vol = 15 + (volume * 270 / 100);
186 document.getElementById("volume-control").setAttribute("cx", vol);
188 ajax.request(request, fn);
191 function setVolume(volume) {
192 var request = new XMLHttpRequest();
193 request.open("GET", "/ctrl-int/1/setproperty?dmcp.volume="+volume);
194 request.send(null);
197 function next() {
198 var request = new XMLHttpRequest();
199 request.open("GET", "/ctrl-int/1/nextitem", true);
200 request.send(null);
203 function prev() {
204 var request = new XMLHttpRequest();
205 request.open("GET", "/ctrl-int/1/previtem", true);
206 request.send(null);
209 function play() {
210 var request = new XMLHttpRequest();
211 request.open("GET", "/ctrl-int/1/playpause", true);
212 request.send(null);
215 function pause() {
216 var request = new XMLHttpRequest();
217 request.open("GET", "/ctrl-int/1/pause", true);
218 request.send(null);
221 function jump(index) {
222 var request = new XMLHttpRequest();
223 request.open("GET", "/ctrl-int/1/cue?command=play&index="+index);
224 request.send(null);
227 function clear() {
228 var request = new XMLHttpRequest();
229 request.open("GET", "/ctrl-int/1/cue?command=clear");
230 request.send(null);
233 function enqueue(query) {
234 var request = new XMLHttpRequest();
235 request.open("GET", "/ctrl-int/1/cue?command=play&query="+query);
236 request.send(null);
239 function setCollection(persistent) {
240 var request = new XMLHttpRequest();
241 request.open("GET", "/ctrl-int/1/playspec?playlist-spec="+persistent);
242 request.send(null);
245 var lastUpdate = 0;
246 var previousPane = new Array();
248 function updateStatus(update) {
250 if (update.status == 2) {
251 document.getElementById("state").className = "stopped";
253 document.getElementById("play").className = "";
254 document.getElementById("pause").className = "hidden";
255 } else if (update.status == 3) {
256 document.getElementById("state").className = "paused";
257 setText(document.getElementById("title"), update.title);
258 setText(document.getElementById("artist"), update.artist);
259 setText(document.getElementById("album"), update.album);
260 setText(document.getElementById("genre"), update.genre);
262 document.getElementById("play").className = "";
263 document.getElementById("pause").className = "hidden";
264 } else if (update.status == 4) {
265 document.getElementById("state").className = "playing";
266 setText(document.getElementById("title"), update.title);
267 setText(document.getElementById("artist"), update.artist);
268 setText(document.getElementById("album"), update.album);
269 setText(document.getElementById("genre"), update.genre);
270 document.title = update.title + " - " + update.artist;
272 document.getElementById("play").className = "hidden";
273 document.getElementById("pause").className = "";
277 function setText(node, text) {
278 while (node.childNodes.length > 0) {
279 node.removeChild(node.firstChild);
281 node.appendChild(document.createTextNode(text));
284 function updatePlaylist(playlist) {
286 var list = document.getElementById("playlist");
287 list.innerHTML = "";
289 var current = lastUpdate.id;
291 for (i in playlist.tracks) {
292 var track = playlist.tracks[i];
294 var node = document.createElement("DIV");
295 node.className = "item";
297 node.appendChild(createNode("album", track.album));
298 node.appendChild(createNode("title", track.title));
299 node.appendChild(createNode("artist", track.artist));
300 node.appendChild(createNode("genre", track.genre));
301 node.appendChild(createNode("id", track.id));
303 if (current && track.id == current) {
304 node.className += " current";
305 current = 0;
307 while (list.childNodes.length > 2) {
308 list.removeChild(list.childNodes[0]);
312 list.appendChild(node);
316 function createNode(type, value) {
317 var node = document.createElement("DIV");
318 node.className = type;
319 node.appendChild(document.createTextNode(value));
320 return node;
323 function registerControls() {
325 document.getElementById("back").onclick = function() {
326 if (previousPane.length == 0) {
327 previousPane.push("playlists");
329 document.body.className = previousPane.pop();
331 document.getElementById("playing").onclick = function() {
332 if (document.body.className) {
333 previousPane.push(document.body.className);
335 document.body.className = "playing";
338 document.body.className = "playlists";
340 document.getElementById("previous").onclick = function() {
341 prev();
343 document.getElementById("play").onclick = function() {
344 play();
346 document.getElementById("pause").onclick = function() {
347 pause();
349 document.getElementById("next").onclick = function() {
350 next();
353 var dragging = false;
354 document.getElementById("volume-control").onmousedown = function() {
355 dragging = true;
357 document.getElementById("volume").onmouseup = function(e) {
358 if (dragging) {
359 dragging = false;
360 var x = e.clientX-document.getElementById("volume-wrapper").offsetLeft;
361 if (x < 15) x = 15;
362 if (x > 285) x = 285;
363 var volume = Math.round((x - 15) * 100 / 270);
364 setVolume(volume);
367 document.getElementById("volume").onmouseout = function(e) {
368 if (dragging && e.target == document.getElementById("volume")) {
369 dragging = false;
370 var x = e.clientX-document.getElementById("volume-wrapper").offsetLeft;
371 if (x < 15) x = 15;
372 if (x > 285) x = 285;
373 var volume = Math.round((x - 15) * 100 / 270);
374 setVolume(volume);
377 document.getElementById("volume").onmousemove = function(e) {
378 if (dragging) {
379 var x = e.clientX-document.getElementById("volume-wrapper").offsetLeft;
380 if (x < 15) x = 15;
381 if (x > 285) x = 285;
382 var control = document.getElementById("volume-control");
383 control.setAttribute("cx", x);
387 document.getElementById("playlist").onclick = function(e) {
388 var node = e.target;
389 while (!node.className.match("item")) {
390 node = node.parentNode;
391 if (node == document.body)
392 return;
394 var playlist = document.getElementById("playlist");
395 var offset = -1;
396 for (child in playlist.childNodes) {
397 if (playlist.childNodes[child].className
398 && playlist.childNodes[child].className
399 .match("current")) {
400 offset = child;
403 if (offset == -1)
404 return;
405 for (child in playlist.childNodes) {
406 if (playlist.childNodes[child] == node) {
407 jump(child - offset);
408 break;
413 document.getElementById("browse-playlists-container").onclick = function(e) {
414 var node = e.target;
415 while (!node.className.match("item")) {
416 node = node.parentNode;
417 if (node == document.body)
418 return;
421 var collection = node.collection;
422 var persistent = node.persistent;
424 getCollectionTracks(collection, function (tracks) {
425 var parent = document.getElementById("browse-playlists-tracks");
426 while (parent.childNodes.length > 0) {
427 parent.removeChild(parent.firstChild);
430 var shuffle = document.createElement("DIV");
431 shuffle.className="item";
432 shuffle.persistent=persistent;
433 shuffle.query="";
434 shuffle.appendChild(createNode("title", "Shuffle"));
435 shuffle.appendChild(createNode("artist", ""));
436 parent.appendChild(shuffle);
438 for (t in tracks) {
439 var item = document.createElement("DIV");
440 item.className="item";
441 item.persistent=persistent;
442 item.query="'dmap.persistentid:"+tracks[t].persistent+"'";
444 item.appendChild(createNode("title", tracks[t].title));
445 item.appendChild(createNode("artist", tracks[t].artist));
447 parent.appendChild(item);
449 previousPane.push("playlists");
450 document.body.className = "playlist-tracks";
454 document.getElementById("browse-playlists-tracks").onclick = function(e) {
455 var node = e.target;
456 while (!node.className.match("item")) {
457 node = node.parentNode;
458 if (node == document.body)
459 return;
462 var query = node.query;
463 var persistent = node.persistent;
465 setCollection(persistent);
467 if (query != "") {
468 clear();
469 enqueue(query);
472 previousPane.push("playlist-tracks");
473 document.body.className = "playing";
476 document.getElementById("browse-artists-container").onclick = function(e) {
477 var node = e.target;
478 while (!node.className.match("item")) {
479 node = node.parentNode;
480 if (node == document.body)
481 return;
484 var query = node.query;
486 getAlbums(query, function (albums) {
487 var parent = document.getElementById("browse-artists-albums");
488 while (parent.childNodes.length > 0) {
489 parent.removeChild(parent.firstChild);
491 for (a in albums) {
492 var item = document.createElement("DIV");
493 item.className="item";
494 item.query="'daap.songalbum="+albums[a].name+"'";
496 item.appendChild(createNode("title", albums[a].name));
498 parent.appendChild(item);
500 previousPane.push("artists");
501 document.body.className = "artist-albums";
505 document.getElementById("browse-artists-albums").onclick = function(e) {
506 var node = e.target;
507 while (!node.className.match("item")) {
508 node = node.parentNode;
509 if (node == document.body)
510 return;
512 var query = "'daap.songalbum:"+node.textContent+"'";
513 getTracks(query, function (tracks) {
514 var parent = document.getElementById("browse-artists-tracks");
515 while (parent.childNodes.length > 0) {
516 parent.removeChild(parent.firstChild);
519 var item = document.createElement("DIV");
520 item.className="item";
521 item.query = query;
522 item.appendChild(createNode("title", "All Songs"));
523 parent.appendChild(item);
525 for (t in tracks) {
526 item = document.createElement("DIV");
527 item.className="item";
528 item.query = query+"+'dmap.itemname:"+tracks[t].title+"'";
529 item.appendChild(createNode("title", tracks[t].title));
531 parent.appendChild(item);
533 previousPane.push("artist-albums");
534 document.body.className = "artist-tracks";
538 document.getElementById("browse-artists-tracks").onclick = function (e) {
539 var node = e.target;
540 while (!node.className.match("item")) {
541 node = node.parentNode;
542 if (node == document.body)
543 return;
546 var query = node.query;
548 clear();
549 enqueue(query);
551 previousPane.push("artist-tracks");
552 document.body.className = "playing";
555 document.getElementById("browse-albums-container").onclick = function(e) {
556 var node = e.target;
557 while (!node.className.match("item")) {
558 node = node.parentNode;
559 if (node == document.body)
560 return;
563 var query = node.query;
565 getTracks(query, function (tracks) {
566 var parent = document.getElementById("browse-albums-tracks");
567 while (parent.childNodes.length > 0) {
568 parent.removeChild(parent.firstChild);
571 var item = document.createElement("DIV");
572 item.className="item";
573 item.query = query;
574 item.appendChild(createNode("title", "All Songs"));
575 parent.appendChild(item);
577 for (t in tracks) {
578 item = document.createElement("DIV");
579 item.className="item";
580 item.query = query+"+'dmap.itemname:"+tracks[t].title+"'";
581 item.appendChild(createNode("title", tracks[t].title));
582 item.appendChild(createNode("artist", tracks[t].artist));
583 parent.appendChild(item);
586 previousPane.push("albums");
587 document.body.className = "album-tracks";
591 document.getElementById("browse-albums-tracks").onclick = function (e) {
592 var node = e.target;
593 while (!node.className.match("item")) {
594 node = node.parentNode;
595 if (node == document.body)
596 return;
599 var query = node.query;
601 clear();
602 enqueue(query);
604 previousPane.push("album-tracks");
605 document.body.className = "playing";
608 document.getElementById("browse-menu-playlists").onclick = function() {
609 getPlaylists();
610 document.body.className = "playlists";
612 document.getElementById("browse-menu-artists").onclick = function() {
613 getArtists();
614 document.body.className = "artists";
616 document.getElementById("browse-menu-albums").onclick = function() {
617 getAlbums("'daap.songalbum!:'", function (albums) {
618 var parent = document.getElementById("browse-albums-container");
619 while (parent.childNodes.length > 0) {
620 parent.removeChild(parent.firstChild);
622 for (a in albums) {
623 var item = document.createElement("DIV");
624 item.className="item";
625 item.query="'daap.songalbum:"+albums[a].name+"'";
627 item.appendChild(createNode("title", albums[a].name));
629 parent.appendChild(item);
631 document.body.className = "albums";
634 document.getElementById("browse-menu-search").onclick = function() {
635 getSearch();
636 document.body.className = "search";
638 getPlaylists();
639 document.body.className = "playlists";
641 //]]>
642 </script>
644 <link rel="stylesheet" type="text/css" href="style.css" />
646 </head>
647 <body onload="registerControls(); getPlaybackStatusUpdate(); getVolume();">
648 <div id="navigation">
649 <div id="back">Back</div>
650 <div id="playing">Now Playing</div>
651 </div>
652 <div id="current">
653 <div id="state"><img id="albumart" src="" alt="" />
654 <div id="title" class="title"></div>
655 <div id="album" class="album"></div>
656 <div id="artist" class="artist"></div>
657 <div id="genre" class="genre"></div>
658 </div>
659 <div id="control">
660 <div id="previous">previous</div>
661 <div id="play">play</div>
662 <div id="pause">pause</div>
663 <div id="next">next</div>
664 <div id="volume">volume</div>
665 </div>
666 <div id="playlist" class="content"></div>
667 </div>
668 <div id="browse">
669 <div id="browse-menu">
670 <div id="browse-menu-playlists">Playlists</div>
671 <div id="browse-menu-artists">Artists</div>
672 <div id="browse-menu-albums">Albums</div>
673 <div id="browse-menu-search">Search</div>
674 </div>
675 <div id="browse-playlists" class="content">
676 <div id="browse-playlists-container" class="container"></div>
677 <div id="browse-playlists-tracks" class="container"></div>
678 </div>
679 <div id="browse-artists" class="content">
680 <div id="browse-artists-container" class="container"></div>
681 <div id="browse-artists-albums" class="container"></div>
682 <div id="browse-artists-tracks" class="container"></div>
683 </div>
684 <div id="browse-albums" class="content">
685 <div id="browse-albums-container" class="container"></div>
686 <div id="browse-albums-tracks" class="container"></div>
687 </div>
688 <div id="browse-search" class="content">
689 <div id="browse-search-interface">
690 <input type="text" name="songs" id="browse-search-input" />
691 <button type="submit" />
692 </div>
693 <div id="browse-search-container" class="container"></div>
694 </div>
695 </div>
697 <script type="text/javascript" src="svgloader.js"></script>
698 <script type="text/javascript" src="ajax.js"></script>
699 <script type="text/javascript" src="dacp.js"></script>
700 <script type="text/javascript" src="bignum.js"></script>
701 <script type="text/javascript">
702 createSVGcontrols();
703 </script>
704 </body>
705 </html>