summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac2
-rw-r--r--data/xml/ContentDirectory-NoTrack.xml.in32
-rw-r--r--data/xml/ContentDirectory.xml.in32
-rw-r--r--src/librygel-server/filelist.am1
-rw-r--r--src/librygel-server/rygel-content-directory.vala15
-rw-r--r--src/librygel-server/rygel-item-updater.vala178
-rw-r--r--src/librygel-server/rygel-media-item.vala7
-rw-r--r--src/librygel-server/rygel-media-object.vala27
-rw-r--r--src/librygel-server/rygel-music-item.vala19
-rw-r--r--src/librygel-server/rygel-photo-item.vala14
-rw-r--r--src/librygel-server/rygel-video-item.vala14
11 files changed, 340 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac
index 183756a2..0457848a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -33,7 +33,7 @@ VALA_REQUIRED=0.16.1
VALADOC_REQUIRED=0.2
GSSDP_REQUIRED=0.13.0
GUPNP_REQUIRED=0.19.0
-GUPNP_AV_REQUIRED=0.11.0
+GUPNP_AV_REQUIRED=0.11.2
GUPNP_DLNA_REQUIRED=0.5.0
GSTREAMER_REQUIRED=0.10.36
GSTPBU_REQUIRED=0.10.35
diff --git a/data/xml/ContentDirectory-NoTrack.xml.in b/data/xml/ContentDirectory-NoTrack.xml.in
index b40ceefc..4c336fae 100644
--- a/data/xml/ContentDirectory-NoTrack.xml.in
+++ b/data/xml/ContentDirectory-NoTrack.xml.in
@@ -90,6 +90,11 @@
</stateVariable>
<stateVariable sendEvents="no">
+ <name>A_ARG_TYPE_TagValueList</name>
+ <dataType>string</dataType>
+ </stateVariable>
+
+ <stateVariable sendEvents="no">
<name>A_ARG_TYPE_TransferID</name>
<dataType>ui4</dataType>
</stateVariable>
@@ -330,6 +335,33 @@
</action>
<action>
+ <name>UpdateObject</name>
+ <argumentList>
+ <argument>
+ <name>ObjectID</name>
+ <direction>in</direction>
+ <relatedStateVariable>
+ A_ARG_TYPE_ObjectID
+ </relatedStateVariable>
+ </argument>
+ <argument>
+ <name>CurrentTagValue</name>
+ <direction>in</direction>
+ <relatedStateVariable>
+ A_ARG_TYPE_TagValueList
+ </relatedStateVariable>
+ </argument>
+ <argument>
+ <name>NewTagValue</name>
+ <direction>in</direction>
+ <relatedStateVariable>
+ A_ARG_TYPE_TagValueList
+ </relatedStateVariable>
+ </argument>
+ </argumentList>
+ </action>
+
+ <action>
<name>ImportResource</name>
<argumentList>
<argument>
diff --git a/data/xml/ContentDirectory.xml.in b/data/xml/ContentDirectory.xml.in
index 2e156c4f..81b82c68 100644
--- a/data/xml/ContentDirectory.xml.in
+++ b/data/xml/ContentDirectory.xml.in
@@ -95,6 +95,11 @@
</stateVariable>
<stateVariable sendEvents="no">
+ <name>A_ARG_TYPE_TagValueList</name>
+ <dataType>string</dataType>
+ </stateVariable>
+
+ <stateVariable sendEvents="no">
<name>A_ARG_TYPE_TransferID</name>
<dataType>ui4</dataType>
</stateVariable>
@@ -335,6 +340,33 @@
</action>
<action>
+ <name>UpdateObject</name>
+ <argumentList>
+ <argument>
+ <name>ObjectID</name>
+ <direction>in</direction>
+ <relatedStateVariable>
+ A_ARG_TYPE_ObjectID
+ </relatedStateVariable>
+ </argument>
+ <argument>
+ <name>CurrentTagValue</name>
+ <direction>in</direction>
+ <relatedStateVariable>
+ A_ARG_TYPE_TagValueList
+ </relatedStateVariable>
+ </argument>
+ <argument>
+ <name>NewTagValue</name>
+ <direction>in</direction>
+ <relatedStateVariable>
+ A_ARG_TYPE_TagValueList
+ </relatedStateVariable>
+ </argument>
+ </argumentList>
+ </action>
+
+ <action>
<name>ImportResource</name>
<argumentList>
<argument>
diff --git a/src/librygel-server/filelist.am b/src/librygel-server/filelist.am
index d96fe7e5..87794eb1 100644
--- a/src/librygel-server/filelist.am
+++ b/src/librygel-server/filelist.am
@@ -49,6 +49,7 @@ LIBRYGEL_SERVER_NONVAPI_SOURCE_FILES = \
rygel-import-resource.vala \
rygel-item-creator.vala \
rygel-item-destroyer.vala \
+ rygel-item-updater.vala \
rygel-item-removal-queue.vala \
rygel-last-change-entry.vala \
rygel-last-change-obj-add.vala \
diff --git a/src/librygel-server/rygel-content-directory.vala b/src/librygel-server/rygel-content-directory.vala
index 9d94d8be..6de630ee 100644
--- a/src/librygel-server/rygel-content-directory.vala
+++ b/src/librygel-server/rygel-content-directory.vala
@@ -31,12 +31,18 @@ using Gee;
*/
internal errordomain Rygel.ContentDirectoryError {
NO_SUCH_OBJECT = 701,
+ INVALID_CURRENT_TAG_VALUE = 702,
+ INVALID_NEW_TAG_VALUE = 703,
+ REQUIRED_TAG = 704,
+ READ_ONLY_TAG = 705,
+ PARAMETER_MISMATCH = 706,
INVALID_SORT_CRITERIA = 709,
RESTRICTED_OBJECT = 711,
BAD_METADATA = 712,
RESTRICTED_PARENT = 713,
NO_SUCH_DESTINATION_RESOURCE = 718,
CANT_PROCESS = 720,
+ OUTDATED_OBJECT_METADATA = 728,
INVALID_ARGS = 402
}
@@ -116,6 +122,7 @@ internal class Rygel.ContentDirectory: Service {
this.action_invoked["Search"].connect (this.search_cb);
this.action_invoked["CreateObject"].connect (this.create_object_cb);
this.action_invoked["DestroyObject"].connect (this.destroy_object_cb);
+ this.action_invoked["UpdateObject"].connect (this.update_object_cb);
this.action_invoked["ImportResource"].connect (this.import_resource_cb);
this.action_invoked["GetTransferProgress"].connect (
this.get_transfer_progress_cb);
@@ -198,6 +205,14 @@ internal class Rygel.ContentDirectory: Service {
destroyer.run.begin ();
}
+ /* UpdateObject action implementation */
+ private void update_object_cb (Service content_dir,
+ ServiceAction action) {
+ var updater = new ItemUpdater (this, action);
+
+ updater.run.begin ();
+ }
+
/* ImportResource action implementation */
private void import_resource_cb (Service content_dir,
ServiceAction action) {
diff --git a/src/librygel-server/rygel-item-updater.vala b/src/librygel-server/rygel-item-updater.vala
new file mode 100644
index 00000000..600ba70e
--- /dev/null
+++ b/src/librygel-server/rygel-item-updater.vala
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+using GUPnP;
+using Gee;
+
+/**
+ * UpdateObject action implementation.
+ */
+internal class Rygel.ItemUpdater: GLib.Object, Rygel.StateMachine {
+ private string object_id;
+ private string current_tag_value;
+ private string new_tag_value;
+
+ private ContentDirectory content_dir;
+ private ServiceAction action;
+
+ public Cancellable cancellable { get; set; }
+
+ public ItemUpdater (ContentDirectory content_dir,
+ owned ServiceAction action) {
+ this.content_dir = content_dir;
+ this.cancellable = content_dir.cancellable;
+ this.action = (owned) action;
+ }
+
+ public async void run () {
+ try {
+ this.action.get ("ObjectID",
+ typeof (string),
+ out this.object_id,
+ "CurrentTagValue",
+ typeof (string),
+ out this.current_tag_value,
+ "NewTagValue",
+ typeof (string),
+ out this.new_tag_value);
+ if (this.object_id == null) {
+ // Sorry we can't do anything without the ID
+ throw new ContentDirectoryError.NO_SUCH_OBJECT
+ (_("No such object"));
+ }
+
+ yield this.update_object ();
+
+ this.action.return ();
+
+ debug (_("Successfully updated object '%s'"), this.object_id);
+ } catch (Error error) {
+ if (error is ContentDirectoryError) {
+ this.action.return_error (error.code, error.message);
+ } else {
+ this.action.return_error (701, error.message);
+ }
+
+ warning (_("Failed to update object '%s': %s"),
+ this.object_id,
+ error.message);
+ }
+
+ this.completed ();
+ }
+
+ private static LinkedList<string> csv_split (string? tag_values) {
+ var list = new LinkedList<string> ();
+ var escape = false;
+ var token_start = 0;
+ var token_length = 0;
+ var len = (tag_values != null ? tag_values.length : 0);
+
+ for (int iter = 0; iter < len; ++iter) {
+ var c = tag_values[iter];
+
+ if (escape) {
+ escape = false;
+ } else {
+ switch (c) {
+ case '\\':
+ escape = true;
+
+ break;
+ case ',':
+ list.add (tag_values.substring (token_start, token_length));
+ token_start += token_length + 1;
+ token_length = 0;
+
+ break;
+ }
+ }
+ ++token_length;
+ }
+
+ // Single tag value only
+ if (len > 0 && list.is_empty) {
+ list.add (tag_values);
+ }
+
+ return list;
+ }
+
+ private async void update_object () throws Error {
+ var media_object = yield this.fetch_object ();
+ var current_list = csv_split (this.current_tag_value);
+ var new_list = csv_split (this.new_tag_value);
+
+
+ switch (media_object.apply_fragments (current_list,
+ new_list,
+ this.content_dir.http_server)) {
+ case DIDLLiteFragmentResult.OK:
+ break;
+ case DIDLLiteFragmentResult.CURRENT_BAD_XML:
+ case DIDLLiteFragmentResult.CURRENT_INVALID:
+ throw new ContentDirectoryError.INVALID_CURRENT_TAG_VALUE
+ ("Bad current tag value.");
+ case DIDLLiteFragmentResult.NEW_BAD_XML:
+ case DIDLLiteFragmentResult.NEW_INVALID:
+ throw new ContentDirectoryError.INVALID_NEW_TAG_VALUE
+ ("Bad current tag value.");
+ case DIDLLiteFragmentResult.REQUIRED_TAG:
+ throw new ContentDirectoryError.REQUIRED_TAG
+ ("Tried to delete required tag.");
+ case DIDLLiteFragmentResult.READONLY_TAG:
+ throw new ContentDirectoryError.READ_ONLY_TAG
+ ("Tried to change read-only property.");
+ case DIDLLiteFragmentResult.MISMATCH:
+ throw new ContentDirectoryError.PARAMETER_MISMATCH
+ ("Parameter count mismatch.");
+ default:
+ throw new ContentDirectoryError.NO_SUCH_OBJECT ("Unknown error.");
+ }
+ }
+
+ private async MediaObject fetch_object () throws Error {
+ var media_object = yield this.content_dir.root_container.find_object
+ (this.object_id,
+ this.cancellable);
+
+ if (media_object == null) {
+ throw new ContentDirectoryError.NO_SUCH_OBJECT
+ (_("No such object"));
+ } else if (!(OCMFlags.CHANGE_METADATA in media_object.ocm_flags)) {
+ var msg = _("Metadata modification of object %s not allowed");
+
+ throw new ContentDirectoryError.RESTRICTED_OBJECT (msg,
+ media_object.id);
+ } else if (media_object.parent.restricted) {
+ var msg = _("Metadata modification of object %s being a child " +
+ "of restricted object %s not allowed");
+
+ throw new ContentDirectoryError.RESTRICTED_PARENT
+ (msg,
+ media_object.id,
+ media_object.parent.id);
+ }
+
+ return media_object;
+ }
+}
diff --git a/src/librygel-server/rygel-media-item.vala b/src/librygel-server/rygel-media-item.vala
index fc02e60f..4e171a7f 100644
--- a/src/librygel-server/rygel-media-item.vala
+++ b/src/librygel-server/rygel-media-item.vala
@@ -188,6 +188,13 @@ public abstract class Rygel.MediaItem : MediaObject {
}
}
+ internal override void apply_didl_lite (DIDLLiteObject didl_object) {
+ base.apply_didl_lite (didl_object);
+
+ this.date = didl_object.date;
+ this.description = didl_object.description;
+ }
+
internal override DIDLLiteObject serialize (DIDLLiteWriter writer,
HTTPServer http_server)
throws Error {
diff --git a/src/librygel-server/rygel-media-object.vala b/src/librygel-server/rygel-media-object.vala
index 2421c56d..3e9e1d77 100644
--- a/src/librygel-server/rygel-media-object.vala
+++ b/src/librygel-server/rygel-media-object.vala
@@ -158,6 +158,33 @@ public abstract class Rygel.MediaObject : GLib.Object {
HTTPServer http_server)
throws Error;
+ internal virtual void apply_didl_lite (DIDLLiteObject didl_object) {
+ this.title = didl_object.title;
+ }
+
+ internal DIDLLiteFragmentResult apply_fragments
+ (LinkedList<string> current_fragments,
+ LinkedList<string> new_fragments,
+ HTTPServer http_server) {
+ var result = DIDLLiteFragmentResult.UNKNOWN_ERROR;
+
+ try {
+ var writer = new DIDLLiteWriter (null);
+ var didl_object = this.serialize (writer, http_server);
+
+ result = didl_object.apply_fragments
+ (current_fragments.to_array (),
+ new_fragments.to_array ());
+
+ if (result == DIDLLiteFragmentResult.OK) {
+ this.apply_didl_lite (didl_object);
+ }
+
+ } catch (Error e) {}
+
+ return result;
+ }
+
internal virtual int compare_by_property (MediaObject media_object,
string property) {
switch (property) {
diff --git a/src/librygel-server/rygel-music-item.vala b/src/librygel-server/rygel-music-item.vala
index 07f35624..4594f1c8 100644
--- a/src/librygel-server/rygel-music-item.vala
+++ b/src/librygel-server/rygel-music-item.vala
@@ -94,6 +94,25 @@ public class Rygel.MusicItem : AudioItem {
}
}
+ private string get_first (GLib.List<DIDLLiteContributor>? contributors) {
+ if (contributors != null) {
+ return contributors.data.name;
+ }
+
+ return "";
+ }
+
+ internal override void apply_didl_lite (DIDLLiteObject didl_object) {
+ base.apply_didl_lite (didl_object);
+
+ this.artist = get_first (didl_object.get_artists ());
+ this.track_number = didl_object.track_number;
+ this.album = didl_object.album;
+ this.genre = didl_object.genre;
+ // TODO: Not sure about it.
+ //this.album_art.uri = didl_object.album_art
+ }
+
internal override DIDLLiteObject serialize (DIDLLiteWriter writer,
HTTPServer http_server)
throws Error {
diff --git a/src/librygel-server/rygel-photo-item.vala b/src/librygel-server/rygel-photo-item.vala
index eab0d98c..4e8b7f56 100644
--- a/src/librygel-server/rygel-photo-item.vala
+++ b/src/librygel-server/rygel-photo-item.vala
@@ -58,6 +58,20 @@ public class Rygel.PhotoItem : ImageItem {
}
}
+ private string get_first (GLib.List<DIDLLiteContributor>? contributors) {
+ if (contributors != null) {
+ return contributors.data.name;
+ }
+
+ return "";
+ }
+
+ internal override void apply_didl_lite (DIDLLiteObject didl_object) {
+ base.apply_didl_lite (didl_object);
+
+ this.creator = get_first (didl_object.get_creators ());
+ }
+
internal override DIDLLiteObject serialize (DIDLLiteWriter writer,
HTTPServer http_server)
throws Error {
diff --git a/src/librygel-server/rygel-video-item.vala b/src/librygel-server/rygel-video-item.vala
index ffcc7b86..dbacc4e3 100644
--- a/src/librygel-server/rygel-video-item.vala
+++ b/src/librygel-server/rygel-video-item.vala
@@ -137,6 +137,20 @@ public class Rygel.VideoItem : AudioItem, VisualItem {
}
}
+ private string get_first (GLib.List<DIDLLiteContributor>? contributors) {
+ if (contributors != null) {
+ return contributors.data.name;
+ }
+
+ return "";
+ }
+
+ internal override void apply_didl_lite (DIDLLiteObject didl_object) {
+ base.apply_didl_lite (didl_object);
+
+ this.author = get_first (didl_object.get_authors ());
+ }
+
internal override DIDLLiteObject serialize (DIDLLiteWriter writer,
HTTPServer http_server)
throws Error {