From edab7526f40cc5ed97b2feebe1c782d4f6582b03 Mon Sep 17 00:00:00 2001 From: "stephen@sfnelson.org" Date: Thu, 2 Oct 2008 21:29:31 +0000 Subject: [PATCH] More work on client browsing and some query fixes on DACP server git-svn-id: https://stereo.googlecode.com/svn/trunk@346 c67ee986-0855-0410-825f-15918b819f62 --- DAAPLib/src/reader/DACPRequestParser.java | 16 +- DAAPLib/src/util/command/ctrlint/Cue.java | 2 +- DAAPLib/src/util/command/databases/Browse.java | 2 +- DAAPLib/src/util/command/databases/Groups.java | 3 +- DAAPLib/src/util/command/databases/Items.java | 2 +- DAAPLib/src/util/command/stereo.html | 285 ++++++++++++++++++++++--- DAAPLib/src/util/queryparser/QueryParser.java | 18 +- DAAPLib/src/util/queryparser/Token.java | 1 + 8 files changed, 291 insertions(+), 38 deletions(-) diff --git a/DAAPLib/src/reader/DACPRequestParser.java b/DAAPLib/src/reader/DACPRequestParser.java index b489a8f..dc006f0 100644 --- a/DAAPLib/src/reader/DACPRequestParser.java +++ b/DAAPLib/src/reader/DACPRequestParser.java @@ -1,7 +1,9 @@ package reader; +import java.io.UnsupportedEncodingException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.net.URLDecoder; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; @@ -48,12 +50,12 @@ public class DACPRequestParser { final Scanner request = new Scanner(p); final String type = request.next(); - final String URI = request.next(); + final String uri = request.next(); final String protocol = request.next(); - System.out.println("Received request: " + URI + " (" + type + ", " + protocol + ")"); + System.out.println("Received request: " + uri + " (" + type + ", " + protocol + ")"); - Scanner req = new Scanner(URI); + Scanner req = new Scanner(uri); req.useDelimiter("[?]"); Scanner cmd = new Scanner(req.next()); @@ -82,7 +84,7 @@ public class DACPRequestParser { if (cmd.hasNextInt()) { arg = cmd.nextInt(); if (!cmd.hasNext()) { - throw new IllegalArgumentException("invalid command string: " + URI); + throw new IllegalArgumentException("invalid command string: " + uri); } } @@ -90,7 +92,7 @@ public class DACPRequestParser { String name = cmd.next(); if (name.charAt(0) >= '0' && name.charAt(0) <= '9') { - throw new IllegalArgumentException("invalid command string: " + URI); + throw new IllegalArgumentException("invalid command string: " + uri); } while (name.indexOf('-') != -1) { int i = name.indexOf('-'); @@ -104,7 +106,7 @@ public class DACPRequestParser { } } if (method == null) { - throw new IllegalArgumentException("unexpected command '" + name + "' for path " + node.getClass().getName() + ": " + URI); + throw new IllegalArgumentException("unexpected command '" + name + "' for path " + node.getClass().getName() + ": " + uri); } try { if (arg == -1) { @@ -133,7 +135,7 @@ public class DACPRequestParser { return c; } - throw new IllegalArgumentException("invalid command string: " + URI); + throw new IllegalArgumentException("invalid command string: " + uri); } catch (NoSuchElementException e) { throw new IllegalArgumentException("invalid command string"); diff --git a/DAAPLib/src/util/command/ctrlint/Cue.java b/DAAPLib/src/util/command/ctrlint/Cue.java index c96c0bd..a7093e4 100644 --- a/DAAPLib/src/util/command/ctrlint/Cue.java +++ b/DAAPLib/src/util/command/ctrlint/Cue.java @@ -32,7 +32,7 @@ public class Cue implements Command { if (args.containsKey("query")) { - Filter f = QueryParser.parser.parse(args.get("query")); + Filter f = QueryParser.parse(args.get("query")); System.out.println(f); playlist = ApplyFilter.filter(f, playlist); diff --git a/DAAPLib/src/util/command/databases/Browse.java b/DAAPLib/src/util/command/databases/Browse.java index 61d2814..d676820 100644 --- a/DAAPLib/src/util/command/databases/Browse.java +++ b/DAAPLib/src/util/command/databases/Browse.java @@ -42,7 +42,7 @@ public class Browse implements Command { System.out.println("library has " + songs.size() + " elements"); if (args != null && args.containsKey("filter")) { - Filter f = QueryParser.parser.parse(args.get("filter")); + Filter f = QueryParser.parse(args.get("filter")); System.out.println(f); songs = ApplyFilter.filter(f, songs); } diff --git a/DAAPLib/src/util/command/databases/Groups.java b/DAAPLib/src/util/command/databases/Groups.java index ec3a4d8..306b3f4 100644 --- a/DAAPLib/src/util/command/databases/Groups.java +++ b/DAAPLib/src/util/command/databases/Groups.java @@ -37,7 +37,8 @@ public class Groups implements Command { //don't query, as albums store name as minm not asal if (args.containsKey("query")) { - Filter q = QueryParser.parser.parse(args.get("query")); + String query = args.get("query").replace(' ', '_'); + Filter q = QueryParser.parse(query); System.out.println(q); albums = ApplyFilter.filter(q, albums); } diff --git a/DAAPLib/src/util/command/databases/Items.java b/DAAPLib/src/util/command/databases/Items.java index 6e9cd9d..ca16856 100644 --- a/DAAPLib/src/util/command/databases/Items.java +++ b/DAAPLib/src/util/command/databases/Items.java @@ -47,7 +47,7 @@ public class Items implements Command { System.out.println("playlist has " + playlist.size() + " elements"); if (args != null && args.containsKey("query")) { - Filter f = QueryParser.parser.parse(args.get("query")); + Filter f = QueryParser.parse(args.get("query")); System.out.println(f); playlist = ApplyFilter.filter(f, playlist); } diff --git a/DAAPLib/src/util/command/stereo.html b/DAAPLib/src/util/command/stereo.html index e55ec7c..edd6215 100644 --- a/DAAPLib/src/util/command/stereo.html +++ b/DAAPLib/src/util/command/stereo.html @@ -64,7 +64,7 @@ } } - var parent = document.getElementById("browse-playlists"); + var parent = document.getElementById("browse-playlists-container"); while (parent.childNodes.length > 0) { parent.removeChild(parent.firstChild); } @@ -107,7 +107,8 @@ } } - var parent = document.getElementById("browse-artists"); + var parent = document.getElementById("browse-artists-container"); + while (parent.childNodes.length > 0) { parent.removeChild(parent.firstChild); } @@ -115,6 +116,7 @@ for (a in artists) { var item = document.createElement("DIV"); item.className="item"; + item.query="'daap.songartist:"+artists[a]+"'"; item.appendChild(createNode("title", artists[a])); @@ -128,6 +130,68 @@ request.send(null); } + function getAlbums(query, callback) { + var request = new XMLHttpRequest(); + request.onreadystatechange = function() { + if (request.readyState == 4) { + var text = request.responseText; + + var tree = new Node(); + parseNode(tree, text, 0); + tree = tree.children[0]; + + var albums = new Array(); + + for (node in tree.children) { + if (tree.children[node].name = "mlcl") { + var list = tree.children[node]; + for (item in list.children) { + albums.push(new Album(list.children[item])); + } + } + } + + callback(albums); + } + }; + + request.open("GET", "/databases/1/groups?group-type=albums&sort=albums&query="+query, true); + //XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com] + request.overrideMimeType('text/plain; charset=x-user-defined'); + request.send(null); + } + + function getTracks(query, callback) { + var request = new XMLHttpRequest(); + request.onreadystatechange = function() { + if (request.readyState == 4) { + var text = request.responseText; + + var tree = new Node(); + parseNode(tree, text, 0); + tree = tree.children[0]; + + var tracks = new Array(); + + for (node in tree.children) { + if (tree.children[node].name = "mlcl") { + var list = tree.children[node]; + for (item in list.children) { + tracks.push(new Track(list.children[item])); + } + } + } + + callback(tracks); + } + }; + + request.open("GET", "/databases/1/containers/1/items?query="+query, true); + //XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com] + request.overrideMimeType('text/plain; charset=x-user-defined'); + request.send(null); + } + function next() { var request = new XMLHttpRequest(); request.open("GET", "/ctrl-int/1/nextitem", true); @@ -367,6 +431,7 @@ } var lastUpdate = 0; + var previousPane = new Array(); function PlayStatusUpdate(tree) { @@ -467,6 +532,32 @@ } } + function Album(tree) { + + this.id = 0; + this.name = ""; + this.artist = 0; + this.persistantId = 0; + + for (child in tree.children) { + var node = tree.children[child]; + switch (node.name) { + case "miid": + this.id = node.value; + break; + case "minm": + this.name = node.value; + break; + case "asaa": + this.artist = node.value; + break; + case "mper": + this.persistantId = node.value; + break; + } + } + } + function Track(tree) { this.album = ""; @@ -574,13 +665,19 @@ function registerControls() { document.getElementById("back").onclick = function() { - document.body.className = "main"; + if (previousPane.length == 0) { + previousPane.push("playlists"); + } + document.body.className = previousPane.pop(); } document.getElementById("playing").onclick = function() { + if (document.body.className) { + previousPane.push(document.body.className); + } document.body.className = "playing"; } - document.body.className = "main"; + document.body.className = "playlists"; document.getElementById("previous").onclick = function() { prev(); @@ -621,6 +718,89 @@ } } + document.getElementById("browse-artists-container").onclick = function(e) { + var node = e.target; + while (!node.className.match("item")) { + node = node.parentNode; + if (node == document.body) + return; + } + + var query = node.query; + + getAlbums(query, function (albums) { + var parent = document.getElementById("browse-artists-albums"); + while (parent.childNodes.length > 0) { + parent.removeChild(parent.firstChild); + } + for (a in albums) { + var item = document.createElement("DIV"); + item.className="item"; + item.query="'daap.songalbum="+albums[a].name+"'"; + + item.appendChild(createNode("title", albums[a].name)); + + parent.appendChild(item); + } + previousPane.push("artists"); + document.body.className = "artist-albums"; + }); + } + + document.getElementById("browse-artists-albums").onclick = function(e) { + var node = e.target; + while (!node.className.match("item")) { + node = node.parentNode; + if (node == document.body) + return; + } + var query = "'daap.songalbum:"+node.textContent+"'"; + getTracks(query, function (tracks) { + var parent = document.getElementById("browse-artists-tracks"); + while (parent.childNodes.length > 0) { + parent.removeChild(parent.firstChild); + } + for (t in tracks) { + var item = document.createElement("DIV"); + item.className="item"; + + item.appendChild(createNode("title", tracks[t].title)); + + parent.appendChild(item); + } + previousPane.push("artist-albums"); + document.body.className = "artist-tracks"; + }); + } + + document.getElementById("browse-albums-container").onclick = function(e) { + var node = e.target; + while (!node.className.match("item")) { + node = node.parentNode; + if (node == document.body) + return; + } + + var query = node.query; + + getTracks(query, function (tracks) { + var parent = document.getElementById("browse-albums-tracks"); + while (parent.childNodes.length > 0) { + parent.removeChild(parent.firstChild); + } + for (t in tracks) { + var item = document.createElement("DIV"); + item.className="item"; + + item.appendChild(createNode("title", tracks[t].title)); + + parent.appendChild(item); + } + previousPane.push("albums"); + document.body.className = "album-tracks"; + }); + } + replacePrev(); replacePause(); replacePlay(); @@ -628,22 +808,36 @@ document.getElementById("browse-menu-playlists").onclick = function() { getPlaylists(); - document.getElementById("browse").className = "playlists"; + document.body.className = "playlists"; } document.getElementById("browse-menu-artists").onclick = function() { getArtists(); - document.getElementById("browse").className = "artists"; + document.body.className = "artists"; } document.getElementById("browse-menu-albums").onclick = function() { - getAlbums(); - document.getElementById("browse").className = "albums"; + getAlbums("'daap.songalbum!:'", function (albums) { + var parent = document.getElementById("browse-albums-container"); + while (parent.childNodes.length > 0) { + parent.removeChild(parent.firstChild); + } + for (a in albums) { + var item = document.createElement("DIV"); + item.className="item"; + item.query="'daap.songalbum:"+albums[a].name+"'"; + + item.appendChild(createNode("title", albums[a].name)); + + parent.appendChild(item); + } + document.body.className = "albums"; + }); } document.getElementById("browse-menu-search").onclick = function() { getSearch(); - document.getElementById("browse").className = "search"; + document.body.className = "search"; } getPlaylists(); - document.getElementById("browse").className = "playlists"; + document.body.className = "playlists"; } function replacePrev() { @@ -811,6 +1005,10 @@ types["abro"] = list; types["abar"] = list; + + types["agal"] = list; + types["apso"] = list; + //]]> @@ -827,8 +1025,8 @@ body { height: 4ex; left: 0; right: 0; - background-color: #222; - color: white; + background-color: #ccc; + color: black; } #navigation div { font-size: 80%; @@ -838,14 +1036,10 @@ body { background-color: #222; color: white; } -.main #navigation { - background-color: #ccc; - color: black; -} .playing #playing { display: none; } -.main #back { +.playlists #back, .albums #back, .artists #back, .search #back { display: none; } #back { @@ -859,12 +1053,12 @@ body { margin-bottom: 8ex; } #playlist { - margin-top: 20ex; + margin-top: 18ex; } #state { position: fixed; top: 4ex; - height: 12ex; + height: 10ex; left: 0; right: 0; padding: 2ex 1em; @@ -930,9 +1124,12 @@ body { #play,#pause { padding: 2ex 3em; } -.main #current { +#current { display: none; } +.playing #current { + display: block; +} .playing #browse { display: none; } @@ -956,13 +1153,42 @@ body { #browse .content { display: none; } +#browse .content .container { + display: none; +} .playlists #browse-playlists { display: block; } -.artists #browse-artists { +.playlists .content #browse-playlists-container { + display: block; +} +.artists #browse-artists, +.artist-albums #browse-artists, +.artist-tracks #browse-artists { + display: block; +} +.artists .content #browse-artists-container { + display: block; +} +.artist-albums .content #browse-artists-albums { + display: block; +} +.artist-tracks .content #browse-artists-tracks { + display: block; +} +.albums #browse-albums, +.album-tracks #browse-albums { + display: block; +} +.albums .content #browse-albums-container { + display: block; +} +.album-tracks .content #browse-albums-tracks { + display: block; +} +.search #browse-search { display: block; } - @@ -996,9 +1222,18 @@ body {
Albums
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/DAAPLib/src/util/queryparser/QueryParser.java b/DAAPLib/src/util/queryparser/QueryParser.java index 8dca08e..9d4af50 100644 --- a/DAAPLib/src/util/queryparser/QueryParser.java +++ b/DAAPLib/src/util/queryparser/QueryParser.java @@ -1,5 +1,8 @@ package util.queryparser; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; + import org.codehaus.jparsec.OperatorTable; import org.codehaus.jparsec.Parser; import org.codehaus.jparsec.Parsers; @@ -54,9 +57,20 @@ public class QueryParser { private static Parser nodelim = Parsers.always(); - public static final Parser parser = query(TOKEN).from(TOKENIZER, nodelim); + private static final Parser parser = query(TOKEN).from(TOKENIZER, nodelim); + + public static Filter parse(String source) { + source = source.replace('+', '_'); + try { + source = URLDecoder.decode(source, "UTF-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + source = source.replace('_', '+').replace(' ', '_'); + return parser.parse(source); + } public static void main(String args[]) { - System.out.println(QueryParser.parser.parse("'hi:bye'+'ho!:bo'")); + System.out.println(QueryParser.parse("'hi:bye'+'ho!:bo on'")); } } diff --git a/DAAPLib/src/util/queryparser/Token.java b/DAAPLib/src/util/queryparser/Token.java index e377b78..85f7b86 100644 --- a/DAAPLib/src/util/queryparser/Token.java +++ b/DAAPLib/src/util/queryparser/Token.java @@ -29,6 +29,7 @@ public class Token implements Filter { catch (URISyntaxException ex) { ex.printStackTrace(); } + val = val.replace('_',' '); value = val; } else { -- 2.11.4.GIT