this.remove_by_id (object.id);
}
+ /**
+ * Add the container to the cache, in a database transcation,
+ * rolling back the transaction if necessary.
+ */
public void save_container (MediaContainer container) throws Error {
try {
db.begin ();
}
}
+ /**
+ * Add the item to the cache.
+ */
public void save_item (Rygel.MediaItem item) throws Error {
try {
db.begin ();
}
}
+ /**
+ * Create a new container or item instance based on the ID.
+ *
+ * The Rygel server discards the object when the browse request is finished,
+ * after serializing the result.
+ */
public MediaObject? get_object (string object_id) throws DatabaseError {
GLib.Value[] values = { object_id };
MediaObject parent = null;
return data;
}
+ /**
+ * TODO
+ */
public Gee.List<string> get_object_attribute_by_search_expression
(string attribute,
SearchExpression? expression,
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 {
int type = ObjectType.CONTAINER;
GLib.Value parent;
return false;
}
+ /**
+ * Create a new container or item based on a SQL result.
+ *
+ * The Rygel server discards the object when the browse request is finished,
+ * after serializing the result.
+ *
+ * @param parent The object's parent container.
+ * @param statement a SQLite result indicating the container's details.
+ */
private MediaObject? get_object_from_statement (MediaContainer? parent,
Statement statement) {
MediaObject object = null;
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+/**
+ * A helper class to create container and item
+ * instances based on media-export object IDs,
+ * sometimes delegating to the QueryContainerFactory.
+ */
internal class Rygel.MediaExport.ObjectFactory : Object {
/**
- * Return a new instance of DBContainer
+ * Return a new instance of DBContainer.
*
* @param media_db instance of MediaDB
* @param title title of the container
return factory.create_from_hashed_id (id, title);
}
+ // Return a suitable container for the top-level virtual folders.
+ // This corresponds to the short-lived NullContainers that
+ // we used to save these in the database.
if (id.has_prefix ("virtual-parent:")) {
return new DBContainer (id, title);
}
return new TrackableDbContainer (id, title);
}
+ // Return a writable container for anything with a URI,
+ // such as child folders of the file system,
+ // to allow uploads.
+ // See https://bugzilla.gnome.org/show_bug.cgi?id=676379 to
+ // give more control over this.
return new WritableDbContainer (id, title);
}
string definition;
}
-// Titles and definitions of some virtual folders.
+// Titles and definitions of some virtual folders,
+// for use with QueryContainer.
const Rygel.MediaExport.FolderDefinition[] VIRTUAL_FOLDERS_DEFAULT = {
{ N_("Year"), "dc:date,?" },
{ N_("All"), "" }
};
+// Titles and definitions of virtual folders for Music,
+// for use with QueryContainer.
const Rygel.MediaExport.FolderDefinition[] VIRTUAL_FOLDERS_MUSIC = {
{ N_("Artist"), "upnp:artist,?,upnp:album,?" },
{ N_("Album"), "upnp:album,?" },
// Signal that the container has been updated with new/changed content.
private void root_updated () {
-
// Emit the "container-updated" signal
this.updated ();
});
}
+ /** Add the default virtual folders,
+ * for Music, Pictures, etc,
+ * saving them in the cache.
+ */
private void add_default_virtual_folders () {
try {
this.add_virtual_containers_for_class (_("Music"),
/**
* Add a QueryContainer to the provided container,
* for the specified UpNP class,
- * with the specified definition.
+ * with the specified definition,
+ * saving it in the cache.
*/
private void add_folder_definition (MediaContainer container,
string item_class,
FolderDefinition definition)
throws Error {
+
+ // Create a container ID that contains the virtual folder definition.
var id = "%supnp:class,%s,%s".printf (QueryContainer.PREFIX,
item_class,
definition.definition);
id = id.slice (0,-1);
}
+ // Create a QueryContainer based on the definition in the ID.
var factory = QueryContainerFactory.get_default ();
var query_container = factory.create_from_description_id
(id,
_(definition.title));
+ // The QueryContainer's constructor has already run some
+ // SQL to count the number of items.
+ // We remove the container if it has no children.
+ //
+ // Note that all the virtual folders are re-added anyway
+ // when the filesystem changes, so there is no need for
+ // the container to exist in case the query would have
+ // a non-zero result later.
if (query_container.child_count > 0) {
query_container.parent = container;
this.media_db.save_container (query_container);
}
}
+ /**
+ * Add a parent container with child containers for the definitions,
+ * saving them in the cache.
+ */
private void add_virtual_containers_for_class
(string parent,
string item_class,
FolderDefinition[]? definitions = null)
throws Error {
+ // Create a container for this virtual folder.
+ // We use a NullContainer just because our MediaCache API takes
+ // objects and, after saving the details in the database,
+ // it discards the actual container object anyway.
+ //
+ // This ID prefix is checked later in ObjectFactory.get_container(),
+ // which returns a regular DBContainer instead.
var container = new NullContainer ("virtual-parent:" + item_class, this, parent);
this.media_db.save_container (container);
+ // Add a child QueryContainer for each of the default definitions.
foreach (var definition in VIRTUAL_FOLDERS_DEFAULT) {
this.add_folder_definition (container, item_class, definition);
}
+ // Add a child QueryContainer for each of the additional specified definitions.
if (definitions != null) {
foreach (var definition in definitions) {
this.add_folder_definition (container, item_class, definition);
}
}
+ // If no child QueryContainers were added, remove
+ // the provided parent container.
if (this.media_db.get_child_count (container.id) == 0) {
this.media_db.remove_by_id (container.id);
} else {