[rygel/wip/create-reference: 5/5] media-export: Implement playlistContainer
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rygel/wip/create-reference: 5/5] media-export: Implement playlistContainer
- Date: Fri, 12 Apr 2013 11:28:15 +0000 (UTC)
commit ed1e742ffad0996f0389fd66e946839b8828bbc0
Author: Jens Georg <jensg openismus com>
Date: Thu Feb 28 15:00:43 2013 +0100
media-export: Implement playlistContainer
src/plugins/media-export/Makefile.am | 2 +
.../rygel-media-export-media-cache-upgrader.vala | 22 ++++
.../rygel-media-export-media-cache.vala | 8 +-
.../rygel-media-export-object-factory.vala | 8 ++
.../rygel-media-export-playlist-container.vala | 109 ++++++++++++++++++++
...rygel-media-export-playlist-root-container.vala | 92 +++++++++++++++++
.../rygel-media-export-sql-factory.vala | 26 ++++--
.../rygel-media-export-writable-db-container.vala | 24 +++--
8 files changed, 273 insertions(+), 18 deletions(-)
---
diff --git a/src/plugins/media-export/Makefile.am b/src/plugins/media-export/Makefile.am
index 5921883..7c7b11a 100644
--- a/src/plugins/media-export/Makefile.am
+++ b/src/plugins/media-export/Makefile.am
@@ -28,6 +28,8 @@ librygel_media_export_la_SOURCES = \
rygel-media-export-jpeg-writer.vala \
rygel-media-export-object-factory.vala \
rygel-media-export-writable-db-container.vala \
+ rygel-media-export-playlist-root-container.vala \
+ rygel-media-export-playlist-container.vala \
rygel-media-export-music-item.vala \
rygel-media-export-video-item.vala \
rygel-media-export-photo-item.vala \
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 67c8730..6695ea7 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
@@ -119,6 +119,9 @@ internal class Rygel.MediaExport.MediaCacheUpgrader {
case 12:
update_v12_v13 ();
break;
+ case 13:
+ this.update_v13_v14 ();
+ break;
default:
warning ("Cannot upgrade");
database = null;
@@ -479,4 +482,23 @@ internal class Rygel.MediaExport.MediaCacheUpgrader {
this.database = null;
}
}
+
+ private void update_v13_v14 () {
+ try {
+ this.database.begin ();
+
+ this.database.exec ("ALTER TABLE Object ADD COLUMN reference_id " +
+ "DEFAULT NULL");
+ this.database.exec (this.sql.make (SQLString.TRIGGER_REFERENCE));
+
+ this.database.exec ("UPDATE schema_info SET version = '14'");
+ this.database.commit ();
+ this.database.exec ("VACUUM");
+ this.database.analyze ();
+ } catch (DatabaseError error) {
+ this.database.rollback ();
+ warning ("Database upgrade failed: %s", error.message);
+ this.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 e904cca..4e43a53 100644
--- a/src/plugins/media-export/rygel-media-export-media-cache.vala
+++ b/src/plugins/media-export/rygel-media-export-media-cache.vala
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2009,2010 Jens Georg <mail jensge org>.
+ * Copyright (C) 2013 Intel Corporation.
*
* Author: Jens Georg <mail jensge org>
*
@@ -726,7 +727,8 @@ public class Rygel.MediaExport.MediaCache : Object {
object.object_update_id,
-1,
-1,
- is_guarded ? 1 : 0
+ is_guarded ? 1 : 0,
+ object.ref_id ?? null
};
if (object is MediaContainer) {
var container = object as MediaContainer;
@@ -767,6 +769,7 @@ public class Rygel.MediaExport.MediaCache : Object {
db.exec (this.sql.make (SQLString.TABLE_CLOSURE));
db.exec (this.sql.make (SQLString.INDEX_COMMON));
db.exec (this.sql.make (SQLString.TRIGGER_CLOSURE));
+ db.exec (this.sql.make (SQLString.TRIGGER_REFERENCE));
db.commit ();
db.analyze ();
this.save_reset_token (UUID.get ());
@@ -836,6 +839,7 @@ public class Rygel.MediaExport.MediaCache : Object {
}
object.object_update_id = (uint) statement.column_int64
(DetailColumn.OBJECT_UPDATE_ID);
+ object.ref_id = statement.column_text (DetailColumn.REFERENCE_ID);
}
return object;
@@ -949,7 +953,7 @@ public class Rygel.MediaExport.MediaCache : Object {
column = "m.duration";
break;
case "@refID":
- column = "NULL";
+ column = "o.reference_id";
break;
case "@id":
column = "o.upnp_id";
diff --git a/src/plugins/media-export/rygel-media-export-object-factory.vala
b/src/plugins/media-export/rygel-media-export-object-factory.vala
index 1b62107..fd251d7 100644
--- a/src/plugins/media-export/rygel-media-export-object-factory.vala
+++ b/src/plugins/media-export/rygel-media-export-object-factory.vala
@@ -50,6 +50,10 @@ internal class Rygel.MediaExport.ObjectFactory : Object {
return factory.create_from_hashed_id (id, title);
}
+ if (id.has_prefix ("virtual-parent:" + Rygel.PlaylistItem.UPNP_CLASS)) {
+ return new PlaylistRootContainer (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.
@@ -61,6 +65,10 @@ internal class Rygel.MediaExport.ObjectFactory : Object {
return new TrackableDbContainer (id, title);
}
+ if (id.has_prefix ("playlist:")) {
+ return new PlaylistContainer (id, title);
+ }
+
// Return a writable container for anything with a URI,
// such as child folders of the file system,
// to allow uploads.
diff --git a/src/plugins/media-export/rygel-media-export-playlist-container.vala
b/src/plugins/media-export/rygel-media-export-playlist-container.vala
new file mode 100644
index 0000000..9c89b44
--- /dev/null
+++ b/src/plugins/media-export/rygel-media-export-playlist-container.vala
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * 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.
+ */
+
+using Gee;
+
+internal class Rygel.MediaExport.PlaylistContainer : DBContainer,
+ Rygel.WritableContainer {
+ internal static const string URI = WritableContainer.WRITABLE_SCHEME +
+ "playlist-container";
+ public ArrayList<string> create_classes { get; set; }
+
+ public PlaylistContainer (string id, string title) {
+ Object (id : id,
+ title : title,
+ parent : null,
+ child_count : 0);
+ }
+
+ public override void constructed () {
+ base.constructed ();
+
+ this.upnp_class = Rygel.MediaContainer.PLAYLIST;
+ this.create_classes = new ArrayList<string> ();
+ // Only items, no folders
+ this.create_classes.add (Rygel.ImageItem.UPNP_CLASS);
+ this.create_classes.add (Rygel.PhotoItem.UPNP_CLASS);
+ this.create_classes.add (Rygel.VideoItem.UPNP_CLASS);
+ this.create_classes.add (Rygel.AudioItem.UPNP_CLASS);
+ this.create_classes.add (Rygel.MusicItem.UPNP_CLASS);
+
+ // Need to add an URI otherwise core doesn't mark the container as
+ // writable
+ this.uris.add (PlaylistContainer.URI);
+ }
+
+ public async string add_reference (Rygel.MediaObject object,
+ Cancellable? cancellable)
+ throws Error {
+ if (object is MediaContainer) {
+ throw new WritableContainerError.NOT_IMPLEMENTED
+ ("Cannot create references to containers");
+ }
+
+ object.parent = this;
+
+ // If the original is already a ref_id, point to the original item as
+ // we should not daisy-chain reference items.
+ if (object.ref_id == null) {
+ object.ref_id = object.id;
+ }
+ object.id = UUID.get ();
+
+ var cache = MediaCache.get_default ();
+ cache.save_item (object as MediaItem);
+
+ return object.id;
+ }
+
+
+ public async void add_item (Rygel.MediaItem item,
+ Cancellable? cancellable)
+ throws Error {
+ throw new WritableContainerError.NOT_IMPLEMENTED
+ (_("Can't create items in %s"),
+ this.id);
+ }
+
+ public async void remove_item (string id,
+ Cancellable? cancellable)
+ throws Error {
+ throw new WritableContainerError.NOT_IMPLEMENTED
+ (_("Can't remove items in %s"),
+ this.id);
+ }
+
+ public async void add_container (Rygel.MediaContainer container,
+ Cancellable? cancellable)
+ throws Error {
+ throw new WritableContainerError.NOT_IMPLEMENTED
+ (_("Can't add containers in %s"),
+ this.id);
+ }
+
+ public async void remove_container (string id,
+ Cancellable? cancellable)
+ throws Error {
+ throw new WritableContainerError.NOT_IMPLEMENTED
+ (_("Can't remove containers in %s"),
+ this.id);
+ }
+
+}
diff --git a/src/plugins/media-export/rygel-media-export-playlist-root-container.vala
b/src/plugins/media-export/rygel-media-export-playlist-root-container.vala
new file mode 100644
index 0000000..5bef6b4
--- /dev/null
+++ b/src/plugins/media-export/rygel-media-export-playlist-root-container.vala
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2013 Intel Corporation.
+ *
+ * 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.
+ */
+
+using Gee;
+
+/**
+ * Special class for the toplevel virtual container which aggregates all
+ * playlists.
+ *
+ * This is a special class compared to the the other virtual classes as it
+ * allows the creation of subfolders to create server-side playlists.
+ * It does not allow adding or removal of items, only container adding and
+ * removal.
+ */
+internal class Rygel.MediaExport.PlaylistRootContainer : Rygel.WritableContainer,
+ DBContainer {
+ internal static const string URI = WritableContainer.WRITABLE_SCHEME +
+ "playlist-root";
+ public ArrayList<string> create_classes { get; set; }
+
+ public PlaylistRootContainer (string id, string title) {
+ Object (id : id,
+ title : title,
+ parent : null,
+ child_count : 0);
+ }
+
+ public override void constructed () {
+ base.constructed ();
+
+ // We don't support adding real folders here, just playlist container
+ this.create_classes = new ArrayList<string> ();
+ this.create_classes.add (Rygel.MediaContainer.PLAYLIST);
+
+ // Need to add an URI otherwise core doesn't mark the container as
+ // writable
+ this.uris.add (PlaylistRootContainer.URI);
+ }
+
+ public async void add_item (Rygel.MediaItem item,
+ Cancellable? cancellable)
+ throws Error {
+ throw new WritableContainerError.NOT_IMPLEMENTED
+ (_("Can't create items in %s"),
+ this.id);
+ }
+
+ public async void remove_item (string id,
+ Cancellable? cancellable)
+ throws Error {
+ throw new WritableContainerError.NOT_IMPLEMENTED
+ (_("Can't remove items in %s"),
+ this.id);
+ }
+
+ public async void add_container (Rygel.MediaContainer container,
+ Cancellable? cancellable)
+ throws Error {
+ if (container.upnp_class != Rygel.MediaContainer.PLAYLIST) {
+ throw new WritableContainerError.NOT_IMPLEMENTED
+ (_("upnp:class not supported in %s"),
+ this.id);
+ }
+ container.id = "playlist:" + UUID.get ();
+
+ this.media_db.save_container (container);
+ this.media_db.make_object_guarded (container);
+ }
+
+ public async void remove_container (string id,
+ Cancellable? cancellable)
+ throws Error {
+ this.media_db.remove_by_id (id);
+ }
+ }
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 42b6201..db3db40 100644
--- a/src/plugins/media-export/rygel-media-export-sql-factory.vala
+++ b/src/plugins/media-export/rygel-media-export-sql-factory.vala
@@ -47,7 +47,8 @@ internal enum Rygel.MediaExport.DetailColumn {
DISC,
OBJECT_UPDATE_ID,
DELETED_CHILD_COUNT,
- CONTAINER_UPDATE_ID
+ CONTAINER_UPDATE_ID,
+ REFERENCE_ID
}
internal enum Rygel.MediaExport.SQLString {
@@ -76,7 +77,8 @@ internal enum Rygel.MediaExport.SQLString {
MAX_UPDATE_ID,
MAKE_GUARDED,
IS_GUARDED,
- UPDATE_GUARDED_OBJECT
+ UPDATE_GUARDED_OBJECT,
+ TRIGGER_REFERENCE
}
internal class Rygel.MediaExport.SQLFactory : Object {
@@ -93,8 +95,8 @@ internal class Rygel.MediaExport.SQLFactory : Object {
"INSERT OR REPLACE INTO Object " +
"(upnp_id, title, type_fk, parent, timestamp, uri, " +
"object_update_id, deleted_child_count, container_update_id, " +
- "is_guarded) VALUES " +
- "(?,?,?,?,?,?,?,?,?,?)";
+ "is_guarded, reference_id) VALUES " +
+ "(?,?,?,?,?,?,?,?,?,?,?)";
private const string UPDATE_GUARDED_OBJECT_STRING =
"UPDATE Object SET " +
@@ -117,7 +119,7 @@ internal class Rygel.MediaExport.SQLFactory : Object {
"m.sample_freq, m.bits_per_sample, m.channels, m.track, " +
"m.color_depth, m.duration, o.upnp_id, o.parent, o.timestamp, " +
"o.uri, m.dlna_profile, m.genre, m.disc, o.object_update_id, " +
- "o.deleted_child_count, o.container_update_id ";
+ "o.deleted_child_count, o.container_update_id, o.reference_id ";
private const string GET_OBJECT_WITH_PATH =
"SELECT DISTINCT " + ALL_DETAILS_STRING +
@@ -185,7 +187,7 @@ internal class Rygel.MediaExport.SQLFactory : Object {
"WHERE _column IS NOT NULL %s ORDER BY _column COLLATE CASEFOLD " +
"LIMIT ?,?";
- internal const string SCHEMA_VERSION = "13";
+ internal const string SCHEMA_VERSION = "14";
internal const string CREATE_META_DATA_TABLE_STRING =
"CREATE TABLE meta_data (size INTEGER NOT NULL, " +
"mime_type TEXT NOT NULL, " +
@@ -223,7 +225,8 @@ internal class Rygel.MediaExport.SQLFactory : Object {
"object_update_id INTEGER, " +
"deleted_child_count INTEGER, " +
"container_update_id INTEGER, " +
- "is_guarded INTEGER);" +
+ "is_guarded INTEGER, " +
+ "reference_id TEXT DEFAULT NULL);" +
"INSERT INTO schema_info (version) VALUES ('" +
SQLFactory.SCHEMA_VERSION + "'); ";
@@ -259,6 +262,13 @@ internal class Rygel.MediaExport.SQLFactory : Object {
"DELETE FROM meta_data WHERE meta_data.object_fk = OLD.upnp_id; "+
"END;";
+ private const string DELETE_REFERENCE_TRIGGER_STRING =
+ "CREATE TRIGGER trgr_delete_references " +
+ "BEFORE DELETE ON Object " +
+ "FOR EACH ROW BEGIN " +
+ "DELETE FROM Object WHERE OLD.upnp_id = Object.reference_id; " +
+ "END;";
+
private const string CREATE_INDICES_STRING =
"CREATE INDEX IF NOT EXISTS idx_parent on Object(parent);" +
"CREATE INDEX IF NOT EXISTS idx_object_upnp_id on Object(upnp_id);" +
@@ -348,6 +358,8 @@ internal class Rygel.MediaExport.SQLFactory : Object {
return IS_GUARDED_STRING;
case SQLString.UPDATE_GUARDED_OBJECT:
return UPDATE_GUARDED_OBJECT_STRING;
+ case SQLString.TRIGGER_REFERENCE:
+ return DELETE_REFERENCE_TRIGGER_STRING;
default:
assert_not_reached ();
}
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 023d3be..2e0a272 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
@@ -56,8 +56,13 @@ internal class Rygel.MediaExport.WritableDbContainer : TrackableDbContainer,
this.create_classes.add (Rygel.MediaContainer.STORAGE_FOLDER);
}
- public async void add_item (Rygel.MediaItem item, Cancellable? cancellable)
- throws Error {
+ public virtual async void add_item (Rygel.MediaItem item,
+ Cancellable? cancellable)
+ throws Error {
+ if (item.id == null && item.ref_id != null) {
+ warning ("=> CreateReference not supported");
+ throw new WritableContainerError.NOT_IMPLEMENTED ("Not supported");
+ }
item.parent = this;
var file = File.new_for_uri (item.uris[0]);
// TODO: Mark as place-holder. Make this proper some time.
@@ -69,9 +74,9 @@ internal class Rygel.MediaExport.WritableDbContainer : TrackableDbContainer,
this.media_db.make_object_guarded (item);
}
- public async void add_container (MediaContainer container,
- Cancellable? cancellable)
- throws Error {
+ public virtual async void add_container (MediaContainer container,
+ Cancellable? cancellable)
+ throws Error {
container.parent = this;
switch (container.upnp_class) {
case MediaContainer.STORAGE_FOLDER:
@@ -91,15 +96,16 @@ internal class Rygel.MediaExport.WritableDbContainer : TrackableDbContainer,
this.media_db.make_object_guarded (container);
}
- public async void remove_item (string id, Cancellable? cancellable)
- throws Error {
+ public virtual async void remove_item (string id, Cancellable? cancellable)
+ throws Error {
var object = this.media_db.get_object (id);
yield this.remove_child_tracked (object);
}
- public async void remove_container (string id, Cancellable? cancellable)
- throws Error {
+ public virtual async void remove_container (string id,
+ Cancellable? cancellable)
+ throws Error {
throw new WritableContainerError.NOT_IMPLEMENTED ("Not supported");
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]