[rygel] media-export: Simplify virtual folder parsing



commit 3346c553ee30f309eed8df59a0413456f2093e63
Author: Jens Georg <mail jensge org>
Date:   Sun Mar 14 11:01:40 2010 +0100

    media-export: Simplify virtual folder parsing
    
    Virtual folders now contain the complete hierarchy from the beginning. The
    format of the virtual folder definition has changed to use ? as
    placeholder; also the complete hierarchy has to be defined before hand.
    
    Example: virtual-folder:dc:date,?,upnp:artist,?,upnp:album,?
    
    Will present a hierarchy that let's you browse by date, then by artist who
    did something in that year and then by artist.

 .../rygel-media-export-query-container.vala        |   80 ++++++++++++--------
 .../rygel-media-export-root-container.vala         |    7 +-
 2 files changed, 50 insertions(+), 37 deletions(-)
---
diff --git a/src/plugins/media-export/rygel-media-export-query-container.vala b/src/plugins/media-export/rygel-media-export-query-container.vala
index 42199d9..b1f3484 100644
--- a/src/plugins/media-export/rygel-media-export-query-container.vala
+++ b/src/plugins/media-export/rygel-media-export-query-container.vala
@@ -23,61 +23,56 @@ using GUPnP;
 
 internal class Rygel.MediaExportQueryContainer : Rygel.MediaDBContainer {
     public static const string PREFIX = "virtual-container:";
-    private bool item_container;
     private string attribute;
     private SearchExpression expression;
     private static HashMap<string,string> virtual_container_map = null;
     public string plaintext_id;
+    private string pattern = "";
 
     public MediaExportQueryContainer (MediaDB media_db,
                                       string  id,
                                       string  name) {
         // parse the id
         // Following the schema:
-        // virtual-folder:<class> -> get all of that class (eg. Albums)
+        // virtual-folder:<class>,? -> get all of that class (eg. Albums)
         // virtual-folder:<class>,<item> -> get all that is contained in that
         //                                  class
         // If an item suffix is present, the children are items, otherwise
         // containers
-        // example: virtual-folder:upnp:album -> All albums
+        // To define a complete hierarchy of containers, use multiple
+        // levels:
+        // virtual-folder:<meta_data>,?,<meta_data>,? etc.
+        // example: virtual-folder:upnp:album,? -> All albums
         //          virtual-folder:upnp:album,The White Album -> All tracks of
         //          the White Album
-        //          virtual-folder:dc:creator,The Beatles,upnp:album ->
-        //          All Albums by the Beatles
+        //          virtual-folder:dc:creator,The Beatles,upnp:album,? -> All
+        //          Albums by the Beatles
         //          the parts not prefixed by virtual-folder: are URL-escaped
+        //          virtual-folder:dc:creator,?,upnp:album,? -> start of
+        //          hierarchy starting with artists then containing albums of
+        //          that artist
         base (media_db, id, name);
 
         this.plaintext_id = get_virtual_container_definition (id);
         debug ("plaintext id is: %s", this.plaintext_id);
         var args = this.plaintext_id.split(",");
 
-        // build SearchExpression from container-id
-        int i = args.length - 1 - args.length % 2;
-        while (i >= 1 - args.length % 2) {
-            var exp = new RelationalExpression ();
-            var op1 = args[i - 1].replace (PREFIX, "");
-            exp.operand1 = Uri.unescape_string (op1);
-            exp.op = SearchCriteriaOp.EQ;
-            exp.operand2 = Uri.unescape_string (args[i]);
-            if (this.expression != null) {
-                var exp2 = new LogicalExpression ();
-                exp2.operand1 = this.expression;
-                exp2.operand2 = exp;
-                exp2.op = LogicalOperator.AND;
-                this.expression = exp2;
-            } else {
-                this.expression = exp;
-            }
-
-            i -= 2;
+        if ((args.length % 2) != 0) {
+            assert_not_reached ();
         }
 
-        if (args.length % 2 == 0) {
-            // we will contain items
-            this.item_container = true;
-        } else {
-            this.item_container = false;
-            this.attribute = args[args.length - 1].replace (PREFIX, "");
+        int i = 0;
+        while (i < args.length) {
+            if (args[i + 1] != "?") {
+                update_search_expression (args[i], args[i + 1]);
+            } else {
+                args[i + 1] = "%s";
+                this.attribute = args[i].replace (PREFIX, "");
+                this.attribute = Uri.unescape_string (this.attribute);
+                this.pattern = string.joinv(",", args);
+                break;
+            }
+            i += 2;
         }
     }
 
@@ -114,7 +109,7 @@ internal class Rygel.MediaExportQueryContainer : Rygel.MediaDBContainer {
                                        uint             max_count,
                                        Cancellable?     cancellable)
                                        throws GLib.Error {
-        if (item_container) {
+        if (pattern == "") {
             uint total_matches;
             return yield this.search (this.expression,
                                       offset,
@@ -139,8 +134,10 @@ internal class Rygel.MediaExportQueryContainer : Rygel.MediaDBContainer {
                 continue;
             }
 
-            var new_id = this.plaintext_id + ",";
-            new_id += Uri.escape_string (meta_data, "", true);
+            var new_id = Uri.escape_string (meta_data, "", true);
+            // pattern contains URL escaped text. This means it might
+            // contain '%' chars which will makes sprintf crash
+            new_id = this.pattern.replace ("%s", new_id);
             new_id = register_virtual_container (new_id);
             var container = new MediaExportQueryContainer (this.media_db,
                                                            new_id,
@@ -175,4 +172,21 @@ internal class Rygel.MediaExportQueryContainer : Rygel.MediaDBContainer {
 
         return null;
     }
+
+    private void update_search_expression (string op1_, string op2) {
+        var exp = new RelationalExpression ();
+        var op1 = op1_.replace (PREFIX, "");
+        exp.operand1 = Uri.unescape_string (op1);
+        exp.op = SearchCriteriaOp.EQ;
+        exp.operand2 = Uri.unescape_string (op2);
+        if (this.expression != null) {
+            var exp2 = new LogicalExpression ();
+            exp2.operand1 = this.expression;
+            exp2.operand2 = exp;
+            exp2.op = LogicalOperator.AND;
+            this.expression = exp2;
+        } else {
+            this.expression = exp;
+        }
+    }
 }
diff --git a/src/plugins/media-export/rygel-media-export-root-container.vala b/src/plugins/media-export/rygel-media-export-root-container.vala
index be96e7f..ee88d51 100644
--- a/src/plugins/media-export/rygel-media-export-root-container.vala
+++ b/src/plugins/media-export/rygel-media-export-root-container.vala
@@ -109,14 +109,14 @@ public class Rygel.MediaExportRootContainer : Rygel.MediaDBContainer {
                     return new MediaExportQueryContainer (
                                        this.media_db,
                                        MediaExportQueryContainer.register_virtual_container
-                                       ("virtual-container:upnp:album"),
+                                       ("virtual-container:upnp:album,?"),
                                        "Albums");
 
                 case "object.container.person.musicArtist":
                     return new MediaExportQueryContainer (
                                        this.media_db,
                                        MediaExportQueryContainer.register_virtual_container
-                                       ("virtual-container:dc:creator"),
+                                       ("virtual-container:dc:creator,?,upnp:album,?"),
                                        "Artists");
                 default:
                     return null;
@@ -189,8 +189,7 @@ public class Rygel.MediaExportRootContainer : Rygel.MediaDBContainer {
                                 Uri.escape_string (exp_.operand2, "", true) +
                                 cont.plaintext_id.replace ("virtual-container:", ",");
                 debug ("Translated search request to %s", new_id);
-                new_id = MediaExportQueryContainer.register_virtual_container
-                (new_id);
+                new_id = MediaExportQueryContainer.register_virtual_container (new_id);
                 var query_cont_ = new MediaExportQueryContainer (this.media_db,
                                                             new_id,
                                                             exp_.operand2);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]