[rygel] media-export: Prefer titles set by UPnP actions over discovered ones.



commit 3b90050725bc196bd9ce22f723148de3571893cc
Author: Krzesimir Nowak <krnowak openismus com>
Date:   Fri Mar 1 10:41:24 2013 +0100

    media-export: Prefer titles set by UPnP actions over discovered ones.
    
    For this to work we have to mark an object created with CreateObject
    call as guarded. It means that some of its properties (for now title
    only) can't be overriden with a value from metadata extractor. The
    only way to change a title of such object is by UpdateObject call.
    
    All harvested objects that did not exist in database are not marked as
    guarded. Doing UpdateObject on any object marks it as such though.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=683926

 src/plugins/media-export/Makefile.am               |    1 +
 .../rygel-media-export-harvesting-task.vala        |    2 +-
 .../rygel-media-export-media-cache-upgrader.vala   |   23 +++++
 .../rygel-media-export-media-cache.vala            |   92 ++++++++++++++++++--
 .../rygel-media-export-music-item.vala             |    7 ++-
 .../rygel-media-export-photo-item.vala             |    7 ++-
 .../rygel-media-export-playlist-item.vala          |   11 ++-
 .../rygel-media-export-sql-factory.vala            |   36 +++++++--
 .../rygel-media-export-updatable-object.vala       |   30 +++++++
 .../rygel-media-export-video-item.vala             |   11 ++-
 .../rygel-media-export-writable-db-container.vala  |    3 +-
 11 files changed, 198 insertions(+), 25 deletions(-)
---
diff --git a/src/plugins/media-export/Makefile.am b/src/plugins/media-export/Makefile.am
index b59010e..0f384a3 100644
--- a/src/plugins/media-export/Makefile.am
+++ b/src/plugins/media-export/Makefile.am
@@ -33,6 +33,7 @@ librygel_media_export_la_SOURCES = \
        rygel-media-export-photo-item.vala \
        rygel-media-export-playlist-item.vala \
        rygel-media-export-trackable-db-container.vala \
+       rygel-media-export-updatable-object.vala \
        rygel-media-export-collate.c
 
 librygel_media_export_la_VALAFLAGS = \
diff --git a/src/plugins/media-export/rygel-media-export-harvesting-task.vala 
b/src/plugins/media-export/rygel-media-export-harvesting-task.vala
index f34a6c4..c0da9f8 100644
--- a/src/plugins/media-export/rygel-media-export-harvesting-task.vala
+++ b/src/plugins/media-export/rygel-media-export-harvesting-task.vala
@@ -323,7 +323,7 @@ public class Rygel.MediaExport.HarvestingTask : Rygel.StateMachine,
             // This is only necessary to generate the proper <objAdd LastChange
             // entry
             if (entry.known) {
-                (item as UpdatableObject).commit.begin ();
+                (item as UpdatableObject).non_overriding_commit.begin ();
             } else {
                 var container = item.parent as TrackableContainer;
                 container.add_child_tracked.begin (item) ;
diff --git a/src/plugins/media-export/rygel-media-export-media-cache-upgrader.vala 
b/src/plugins/media-export/rygel-media-export-media-cache-upgrader.vala
index 3fbf339..bb22737 100644
--- a/src/plugins/media-export/rygel-media-export-media-cache-upgrader.vala
+++ b/src/plugins/media-export/rygel-media-export-media-cache-upgrader.vala
@@ -116,6 +116,9 @@ internal class Rygel.MediaExport.MediaCacheUpgrader {
                 case 11:
                     update_v11_v12 ();
                     break;
+                case 12:
+                    update_v12_v13 ();
+                    break;
                 default:
                     warning ("Cannot upgrade");
                     database = null;
@@ -413,4 +416,24 @@ internal class Rygel.MediaExport.MediaCacheUpgrader {
             database = null;
         }
     }
+
+    private void update_v12_v13 () {
+        try {
+            this.database.begin ();
+            this.database.exec ("ALTER TABLE object " +
+                                "ADD COLUMN is_guarded INTEGER");
+            /* This intentionally sets all rows in is_guarded column
+             * to zero.
+             */
+            this.database.exec ("UPDATE object SET is_guarded = 0");
+
+            database.commit ();
+            database.exec ("VACUUM");
+            database.analyze ();
+        } catch (DatabaseError error) {
+            database.rollback ();
+            warning ("Database upgrade failed: %s", error.message);
+            database = null;
+        }
+    }
 }
diff --git a/src/plugins/media-export/rygel-media-export-media-cache.vala 
b/src/plugins/media-export/rygel-media-export-media-cache.vala
index 13cc5de..79bdce3 100644
--- a/src/plugins/media-export/rygel-media-export-media-cache.vala
+++ b/src/plugins/media-export/rygel-media-export-media-cache.vala
@@ -111,11 +111,12 @@ public class Rygel.MediaExport.MediaCache : Object {
     /**
      * Add the item to the cache.
      */
-    public void save_item (Rygel.MediaItem item) throws Error {
+    public void save_item (Rygel.MediaItem item,
+                           bool override_guarded = false) throws Error {
         try {
             db.begin ();
             save_metadata (item);
-            create_object (item);
+            create_object (item, override_guarded);
             db.commit ();
         } catch (DatabaseError error) {
             warning (_("Failed to add item with ID %s: %s"),
@@ -519,7 +520,39 @@ public class Rygel.MediaExport.MediaCache : Object {
         }
     }
 
+    public void make_object_guarded (MediaObject object,
+                                     bool guarded = true) {
+        var guarded_val = guarded ? 1 : 0;
+
+        try {
+            GLib.Value[] values = { guarded_val,
+                                    object.id };
+
+            this.db.exec (this.sql.make (SQLString.MAKE_GUARDED), values);
+        } catch (DatabaseError error) {
+            warning ("Failed to mark item %s as guarded (%d): %s",
+                     object.id,
+                     guarded_val,
+                     error.message);
+        }
+    }
+
     // Private functions
+    private bool is_object_guarded (string id) {
+        try {
+            GLib.Value[] id_value = { id };
+
+            return this.query_value (SQLString.IS_GUARDED,
+                                     id_value) == 1;
+        } catch (DatabaseError error) {
+            warning ("Failed to get whether item %s is guarded: %s",
+                     id,
+                     error.message);
+
+            return false;
+        }
+    }
+
     private void get_exists_cache () throws DatabaseError {
         this.exists_cache = new HashMap<string, ExistsCacheEntry?> ();
         var cursor = this.exec_cursor (SQLString.EXISTS_CACHE);
@@ -649,10 +682,7 @@ public class Rygel.MediaExport.MediaCache : Object {
         this.db.exec (this.sql.make (SQLString.SAVE_METADATA), values);
     }
 
-    /**
-     * Add the container or item to the cache.
-     */    
-    private void create_object (MediaObject object) throws Error {
+    private void update_guarded_object (MediaObject object) throws Error {
         int type = ObjectType.CONTAINER;
         GLib.Value parent;
 
@@ -667,7 +697,6 @@ public class Rygel.MediaExport.MediaCache : Object {
         }
 
         GLib.Value[] values = { object.id,
-                                object.title,
                                 type,
                                 parent,
                                 object.modified,
@@ -682,10 +711,59 @@ public class Rygel.MediaExport.MediaCache : Object {
             values[8] = container.update_id;
         }
 
+        this.db.exec (this.sql.make (SQLString.UPDATE_GUARDED_OBJECT), values);
+    }
+
+    private void create_normal_object (MediaObject object,
+                                       bool is_guarded) throws Error {
+        int type = ObjectType.CONTAINER;
+        GLib.Value parent;
+
+        if (object is MediaItem) {
+            type = ObjectType.ITEM;
+        }
+
+        if (object.parent == null) {
+            parent = Database  null ();
+        } else {
+            parent = object.parent.id;
+        }
+
+        GLib.Value[] values = { object.id,
+                                object.title,
+                                type,
+                                parent,
+                                object.modified,
+                                object.uris.is_empty ? null : object.uris[0],
+                                object.object_update_id,
+                                -1,
+                                -1,
+                                is_guarded ? 1 : 0
+                              };
+        if (object is MediaContainer) {
+            var container = object as MediaContainer;
+            values[7] = container.total_deleted_child_count;
+            values[8] = container.update_id;
+        }
+
         this.db.exec (this.sql.make (SQLString.INSERT), values);
     }
 
     /**
+     * Add the container or item to the cache.
+     */
+    private void create_object (MediaObject object,
+                                bool override_guarded = false) throws Error {
+        var is_guarded = this.is_object_guarded (object.id);
+
+        if (!override_guarded && is_guarded) {
+            update_guarded_object (object);
+        } else {
+            create_normal_object (object, (is_guarded || override_guarded));
+        }
+    }
+
+    /**
      * Create the current schema.
      *
      * If schema creation fails, schema will be rolled back
diff --git a/src/plugins/media-export/rygel-media-export-music-item.vala 
b/src/plugins/media-export/rygel-media-export-music-item.vala
index 2ff0be3..fd5daaa 100644
--- a/src/plugins/media-export/rygel-media-export-music-item.vala
+++ b/src/plugins/media-export/rygel-media-export-music-item.vala
@@ -26,6 +26,7 @@
  */
 internal class Rygel.MediaExport.MusicItem : Rygel.MusicItem,
                                              Rygel.UpdatableObject,
+                                             Rygel.MediaExport.UpdatableObject,
                                              Rygel.TrackableItem {
     public int disc;
 
@@ -37,9 +38,13 @@ internal class Rygel.MediaExport.MusicItem : Rygel.MusicItem,
     }
 
     public async void commit () throws Error {
+        yield this.commit_custom (true);
+    }
+
+    public async void commit_custom (bool override_guarded) throws Error {
         this.changed ();
         var cache = MediaCache.get_default ();
-        cache.save_item (this);
+        cache.save_item (this, override_guarded);
     }
 
 }
diff --git a/src/plugins/media-export/rygel-media-export-photo-item.vala 
b/src/plugins/media-export/rygel-media-export-photo-item.vala
index 9d7ad43..09049e9 100644
--- a/src/plugins/media-export/rygel-media-export-photo-item.vala
+++ b/src/plugins/media-export/rygel-media-export-photo-item.vala
@@ -22,6 +22,7 @@
 
 internal class Rygel.MediaExport.PhotoItem : Rygel.PhotoItem,
                                              Rygel.UpdatableObject,
+                                             Rygel.MediaExport.UpdatableObject,
                                              Rygel.TrackableItem {
     public PhotoItem (string         id,
                       MediaContainer parent,
@@ -31,8 +32,12 @@ internal class Rygel.MediaExport.PhotoItem : Rygel.PhotoItem,
     }
 
     public async void commit () throws Error {
+        yield this.commit_custom (true);
+    }
+
+    public async void commit_custom (bool override_guarded) throws Error {
         this.changed ();
         var cache = MediaCache.get_default ();
-        cache.save_item (this);
+        cache.save_item (this, override_guarded);
     }
 }
diff --git a/src/plugins/media-export/rygel-media-export-playlist-item.vala 
b/src/plugins/media-export/rygel-media-export-playlist-item.vala
index 6d94cae..b5c534e 100644
--- a/src/plugins/media-export/rygel-media-export-playlist-item.vala
+++ b/src/plugins/media-export/rygel-media-export-playlist-item.vala
@@ -20,12 +20,9 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-/**
- * Own MusicItem class to provide disc number inside music item for sorting
- * and metadata extraction.
- */
 internal class Rygel.MediaExport.PlaylistItem : Rygel.PlaylistItem,
                                                 Rygel.UpdatableObject,
+                                                Rygel.MediaExport.UpdatableObject,
                                                 Rygel.TrackableItem {
     public PlaylistItem (string         id,
                          MediaContainer parent,
@@ -35,9 +32,13 @@ internal class Rygel.MediaExport.PlaylistItem : Rygel.PlaylistItem,
     }
 
     public async void commit () throws Error {
+        yield this.commit_custom (true);
+    }
+
+    public async void commit_custom (bool override_guarded) throws Error {
         this.changed ();
         var cache = MediaCache.get_default ();
-        cache.save_item (this);
+        cache.save_item (this, override_guarded);
     }
 
 }
diff --git a/src/plugins/media-export/rygel-media-export-sql-factory.vala 
b/src/plugins/media-export/rygel-media-export-sql-factory.vala
index 272cc3e..a5215ca 100644
--- a/src/plugins/media-export/rygel-media-export-sql-factory.vala
+++ b/src/plugins/media-export/rygel-media-export-sql-factory.vala
@@ -73,7 +73,10 @@ internal enum Rygel.MediaExport.SQLString {
     EXISTS_CACHE,
     STATISTICS,
     RESET_TOKEN,
-    MAX_UPDATE_ID
+    MAX_UPDATE_ID,
+    MAKE_GUARDED,
+    IS_GUARDED,
+    UPDATE_GUARDED_OBJECT
 }
 
 internal class Rygel.MediaExport.SQLFactory : Object {
@@ -82,14 +85,22 @@ internal class Rygel.MediaExport.SQLFactory : Object {
         "(size, mime_type, width, height, class, " +
          "author, album, date, bitrate, " +
          "sample_freq, bits_per_sample, channels, " +
-         "track, color_depth, duration, object_fk, dlna_profile, genre, disc) VALUES " +
+         "track, color_depth, duration, object_fk, " +
+         "dlna_profile, genre, disc) VALUES " +
          "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
 
     private const string INSERT_OBJECT_STRING =
     "INSERT OR REPLACE INTO Object " +
         "(upnp_id, title, type_fk, parent, timestamp, uri, " +
-        " object_update_id, deleted_child_count, container_update_id) " +
-        "VALUES (?,?,?,?,?,?,?,?,?)";
+         "object_update_id, deleted_child_count, container_update_id, " +
+         "is_guarded) VALUES " +
+        "(?,?,?,?,?,?,?,?,?,?)";
+
+    private const string UPDATE_GUARDED_OBJECT_STRING =
+    "REPLACE INTO Object " +
+        "(upnp_id, type_fk, parent, timestamp, uri, " +
+         "object_update_id, deleted_child_count, container_update_id) " +
+        "VALUES (?,?,?,?,?,?,?,?)";
 
     private const string DELETE_BY_ID_STRING =
     "DELETE FROM Object WHERE upnp_id IN " +
@@ -169,7 +180,7 @@ internal class Rygel.MediaExport.SQLFactory : Object {
         "WHERE _column IS NOT NULL %s ORDER BY _column COLLATE CASEFOLD " +
     "LIMIT ?,?";
 
-    internal const string SCHEMA_VERSION = "12";
+    internal const string SCHEMA_VERSION = "13";
     internal const string CREATE_META_DATA_TABLE_STRING =
     "CREATE TABLE meta_data (size INTEGER NOT NULL, " +
                             "mime_type TEXT NOT NULL, " +
@@ -207,7 +218,8 @@ internal class Rygel.MediaExport.SQLFactory : Object {
                           "flags TEXT, " +
                           "object_update_id INTEGER, " +
                           "deleted_child_count INTEGER, " +
-                          "container_update_id INTEGER);" +
+                          "container_update_id INTEGER, " +
+                          "is_guarded INTEGER);" +
     "INSERT INTO schema_info (version) VALUES ('" +
     SQLFactory.SCHEMA_VERSION + "'); ";
 
@@ -272,6 +284,12 @@ internal class Rygel.MediaExport.SQLFactory : Object {
     private const string MAX_UPDATE_ID_STRING =
     "SELECT MAX(MAX(object_update_id), MAX(container_update_id)) FROM Object";
 
+    private const string MAKE_GUARDED_STRING =
+    "UPDATE Object SET is_guarded = ? WHERE Object.upnp_id = ?";
+
+    private const string IS_GUARDED_STRING =
+    "SELECT is_guarded FROM Object WHERE Object.upnp_id = ?";
+
     public unowned string make (SQLString query) {
         switch (query) {
             case SQLString.SAVE_METADATA:
@@ -320,6 +338,12 @@ internal class Rygel.MediaExport.SQLFactory : Object {
                 return RESET_TOKEN_STRING;
             case SQLString.MAX_UPDATE_ID:
                 return MAX_UPDATE_ID_STRING;
+            case SQLString.MAKE_GUARDED:
+                return MAKE_GUARDED_STRING;
+            case SQLString.IS_GUARDED:
+                return IS_GUARDED_STRING;
+            case SQLString.UPDATE_GUARDED_OBJECT:
+                return UPDATE_GUARDED_OBJECT_STRING;
             default:
                 assert_not_reached ();
         }
diff --git a/src/plugins/media-export/rygel-media-export-updatable-object.vala 
b/src/plugins/media-export/rygel-media-export-updatable-object.vala
new file mode 100644
index 0000000..376cac1
--- /dev/null
+++ b/src/plugins/media-export/rygel-media-export-updatable-object.vala
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * Author: Krzesimir Nowak <krnowak openismus com>
+ *
+ * This file is part of Rygel.
+ *
+ * Rygel is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Rygel is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+public interface Rygel.MediaExport.UpdatableObject : Rygel.MediaObject {
+    public async void non_overriding_commit () throws Error {
+        yield this.commit_custom (false);
+    }
+
+    public abstract async void commit_custom (bool override_guarded)
+                                              throws Error;
+}
diff --git a/src/plugins/media-export/rygel-media-export-video-item.vala 
b/src/plugins/media-export/rygel-media-export-video-item.vala
index 18e5fcd..dd60409 100644
--- a/src/plugins/media-export/rygel-media-export-video-item.vala
+++ b/src/plugins/media-export/rygel-media-export-video-item.vala
@@ -21,8 +21,9 @@
  */
 
 internal class Rygel.MediaExport.VideoItem : Rygel.VideoItem,
-                                             Rygel.TrackableItem,
-                                             Rygel.UpdatableObject {
+                                             Rygel.UpdatableObject,
+                                             Rygel.MediaExport.UpdatableObject,
+                                             Rygel.TrackableItem {
     public VideoItem (string         id,
                       MediaContainer parent,
                       string         title,
@@ -31,9 +32,13 @@ internal class Rygel.MediaExport.VideoItem : Rygel.VideoItem,
     }
 
     public async void commit () throws Error {
+        yield this.commit_custom (true);
+    }
+
+    public async void commit_custom (bool override_guarded) throws Error {
         this.changed ();
         var cache = MediaCache.get_default ();
-        cache.save_item (this);
+        cache.save_item (this, override_guarded);
     }
 
 }
diff --git a/src/plugins/media-export/rygel-media-export-writable-db-container.vala 
b/src/plugins/media-export/rygel-media-export-writable-db-container.vala
index be1a0a6..7a2944e 100644
--- a/src/plugins/media-export/rygel-media-export-writable-db-container.vala
+++ b/src/plugins/media-export/rygel-media-export-writable-db-container.vala
@@ -66,10 +66,11 @@ internal class Rygel.MediaExport.WritableDbContainer : TrackableDbContainer,
         }
         item.id = MediaCache.get_id (file);
         yield this.add_child_tracked (item);
+        this.media_db.make_object_guarded (item);
     }
 
     public async void add_container (MediaContainer container,
-                                     Cancellable?   cancellable) 
+                                     Cancellable?   cancellable)
                                      throws Error {
         container.parent = this;
         switch (container.upnp_class) {


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