[libgdata] youtube: Implement GDataCommentable on GDataYouTubeVideo
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libgdata] youtube: Implement GDataCommentable on GDataYouTubeVideo
- Date: Sat, 9 Jul 2011 19:02:53 +0000 (UTC)
commit bbb3d20ee62a740ef98a4117003c0364e7b06b26
Author: Philip Withnall <philip tecnocode co uk>
Date: Sat Jul 9 15:10:31 2011 +0100
youtube: Implement GDataCommentable on GDataYouTubeVideo
This adds support for comments to GDataYouTubeVideo, including a GDataComment
subclass, GDataYouTubeComment, and test cases.
This adds the following API:
â GDataYouTubeComment
Helps: bgo#598752
Makefile.am | 6 +-
docs/reference/gdata-docs.xml | 1 +
docs/reference/gdata-sections.txt | 20 +
gdata/gdata.h | 1 +
gdata/gdata.symbols | 4 +
gdata/services/youtube/gdata-youtube-comment.c | 207 +++++++++++
gdata/services/youtube/gdata-youtube-comment.h | 72 ++++
gdata/services/youtube/gdata-youtube-video.c | 88 +++++-
gdata/tests/youtube.c | 445 ++++++++++++++++++++++++
9 files changed, 841 insertions(+), 3 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index ae425c8..70f98db 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -277,7 +277,8 @@ gdata_youtube_headers = \
gdata/services/youtube/gdata-youtube-credit.h \
gdata/services/youtube/gdata-youtube-query.h \
gdata/services/youtube/gdata-youtube-state.h \
- gdata/services/youtube/gdata-youtube-category.h
+ gdata/services/youtube/gdata-youtube-category.h \
+ gdata/services/youtube/gdata-youtube-comment.h
private_headers += \
gdata/services/youtube/gdata-youtube-group.h \
gdata/services/youtube/gdata-youtube-control.h
@@ -382,7 +383,8 @@ gdata_sources = \
gdata/services/youtube/gdata-youtube-group.c \
gdata/services/youtube/gdata-youtube-state.c \
gdata/services/youtube/gdata-youtube-control.c \
- gdata/services/youtube/gdata-youtube-category.c
+ gdata/services/youtube/gdata-youtube-category.c \
+ gdata/services/youtube/gdata-youtube-comment.c
main_header = gdata/gdata.h
public_headers = \
diff --git a/docs/reference/gdata-docs.xml b/docs/reference/gdata-docs.xml
index 2cdcf0d..2a68183 100644
--- a/docs/reference/gdata-docs.xml
+++ b/docs/reference/gdata-docs.xml
@@ -127,6 +127,7 @@
<xi:include href="xml/gdata-youtube-service.xml"/>
<xi:include href="xml/gdata-youtube-query.xml"/>
<xi:include href="xml/gdata-youtube-video.xml"/>
+ <xi:include href="xml/gdata-youtube-comment.xml"/>
</chapter>
<chapter>
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index fda5a7b..946fdd2 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -2305,3 +2305,23 @@ gdata_comment_get_type
<SUBSECTION Private>
GDataCommentPrivate
</SECTION>
+
+<SECTION>
+<FILE>gdata-youtube-comment</FILE>
+<TITLE>GDataYouTubeComment</TITLE>
+GDataYouTubeComment
+GDataYouTubeCommentClass
+gdata_youtube_comment_new
+gdata_youtube_comment_get_parent_comment_uri
+gdata_youtube_comment_set_parent_comment_uri
+<SUBSECTION Standard>
+GDATA_TYPE_YOUTUBE_COMMENT
+GDATA_YOUTUBE_COMMENT
+GDATA_YOUTUBE_COMMENT_CLASS
+GDATA_IS_YOUTUBE_COMMENT
+GDATA_IS_YOUTUBE_COMMENT_CLASS
+GDATA_YOUTUBE_COMMENT_GET_CLASS
+gdata_youtube_comment_get_type
+<SUBSECTION Private>
+GDataYouTubeCommentPrivate
+</SECTION>
diff --git a/gdata/gdata.h b/gdata/gdata.h
index 4139d20..12d63bd 100644
--- a/gdata/gdata.h
+++ b/gdata/gdata.h
@@ -92,6 +92,7 @@
#include <gdata/services/youtube/gdata-youtube-state.h>
#include <gdata/services/youtube/gdata-youtube-enums.h>
#include <gdata/services/youtube/gdata-youtube-category.h>
+#include <gdata/services/youtube/gdata-youtube-comment.h>
/* Google Calendar */
#include <gdata/services/calendar/gdata-calendar-service.h>
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index c84a339..1ee3b34 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -923,3 +923,7 @@ gdata_commentable_delete_comment
gdata_commentable_delete_comment_async
gdata_commentable_delete_comment_finish
gdata_comment_get_type
+gdata_youtube_comment_get_type
+gdata_youtube_comment_new
+gdata_youtube_comment_get_parent_comment_uri
+gdata_youtube_comment_set_parent_comment_uri
diff --git a/gdata/services/youtube/gdata-youtube-comment.c b/gdata/services/youtube/gdata-youtube-comment.c
new file mode 100644
index 0000000..1cd9cee
--- /dev/null
+++ b/gdata/services/youtube/gdata-youtube-comment.c
@@ -0,0 +1,207 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2011 <philip tecnocode co uk>
+ *
+ * GData Client 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.1 of the License, or (at your option) any later version.
+ *
+ * GData Client 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 GData Client. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:gdata-youtube-comment
+ * @short_description: GData YouTube comment object
+ * @stability: Unstable
+ * @include: gdata/services/youtube/gdata-youtube-comment.h
+ *
+ * #GDataYouTubeComment is a subclass of #GDataComment to represent a comment on a #GDataYouTubeVideo. It is returned by the #GDataCommentable
+ * interface implementation on #GDataYouTubeVideo.
+ *
+ * It's possible to query for and add #GDataYouTubeComment<!-- -->s, but it is not possible to delete #GDataYouTubeComment<!-- -->s from any video
+ * using the GData API.
+ *
+ * Comments on YouTube videos can be arranged in a hierarchy by their #GDataYouTubeComment:parent-comment-uri<!-- -->s. If a
+ * #GDataYouTubeComment<!-- -->'s parent comment URI is non-%NULL, it should match the %GDATA_LINK_SELF #GDataLink of another #GDataYouTubeComment on
+ * the same video (as retrieved using gdata_entry_look_up_link() on the comments). Comments with #GDataYouTubeComment:parent-comment-uri set to %NULL
+ * are top-level comments.
+ *
+ * Since: 0.9.2
+ */
+
+#include <config.h>
+#include <glib.h>
+
+#include "gdata-youtube-comment.h"
+
+#define GDATA_LINK_PARENT_COMMENT_URI "http://gdata.youtube.com/schemas/2007#in-reply-to"
+
+static void gdata_youtube_comment_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec);
+static void gdata_youtube_comment_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec);
+
+enum {
+ PROP_PARENT_COMMENT_URI = 1,
+};
+
+G_DEFINE_TYPE (GDataYouTubeComment, gdata_youtube_comment, GDATA_TYPE_COMMENT)
+
+static void
+gdata_youtube_comment_class_init (GDataYouTubeCommentClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GDataEntryClass *entry_class = GDATA_ENTRY_CLASS (klass);
+
+ gobject_class->get_property = gdata_youtube_comment_get_property;
+ gobject_class->set_property = gdata_youtube_comment_set_property;
+
+ entry_class->kind_term = "http://gdata.youtube.com/schemas/2007#comment";
+
+ /**
+ * GDataYouTubeComment:parent-comment-uri:
+ *
+ * The URI of the parent comment to this one, or %NULL if this comment is a top-level comment.
+ *
+ * See the documentation for #GDataYouTubeComment for an explanation of the semantics of parent comment URIs.
+ *
+ * Since: 0.9.2.
+ */
+ g_object_class_install_property (gobject_class, PROP_PARENT_COMMENT_URI,
+ g_param_spec_string ("parent-comment-uri",
+ "Parent comment URI", "The URI of the parent comment to this one.",
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gdata_youtube_comment_init (GDataYouTubeComment *self)
+{
+ /* Nothing to see here. */
+}
+
+static void
+gdata_youtube_comment_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec)
+{
+ GDataYouTubeComment *self = GDATA_YOUTUBE_COMMENT (object);
+
+ switch (property_id) {
+ case PROP_PARENT_COMMENT_URI:
+ g_value_set_string (value, gdata_youtube_comment_get_parent_comment_uri (self));
+ break;
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+static void
+gdata_youtube_comment_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
+{
+ GDataYouTubeComment *self = GDATA_YOUTUBE_COMMENT (object);
+
+ switch (property_id) {
+ case PROP_PARENT_COMMENT_URI:
+ gdata_youtube_comment_set_parent_comment_uri (self, g_value_get_string (value));
+ break;
+ default:
+ /* We don't have any other property... */
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+ break;
+ }
+}
+
+/**
+ * gdata_youtube_comment_new:
+ * @id: the comment's ID, or %NULL
+ *
+ * Creates a new #GDataYouTubeComment with the given ID and default properties.
+ *
+ * Return value: a new #GDataYouTubeComment; unref with g_object_unref()
+ *
+ * Since: 0.9.2
+ */
+GDataYouTubeComment *
+gdata_youtube_comment_new (const gchar *id)
+{
+ return GDATA_YOUTUBE_COMMENT (g_object_new (GDATA_TYPE_YOUTUBE_COMMENT,
+ "id", id,
+ NULL));
+}
+
+/**
+ * gdata_youtube_comment_get_parent_comment_uri:
+ * @self: a #GDataYouTubeComment
+ *
+ * Gets the #GDataYouTubeComment:parent-comment-uri property.
+ *
+ * Return value: the parent comment URI, or %NULL
+ *
+ * Since: 0.9.2
+ */
+const gchar *
+gdata_youtube_comment_get_parent_comment_uri (GDataYouTubeComment *self)
+{
+ GDataLink *link_;
+
+ g_return_val_if_fail (GDATA_IS_YOUTUBE_COMMENT (self), NULL);
+
+ link_ = gdata_entry_look_up_link (GDATA_ENTRY (self), GDATA_LINK_PARENT_COMMENT_URI);
+ if (link_ == NULL) {
+ return NULL;
+ }
+
+ return gdata_link_get_uri (link_);
+}
+
+/**
+ * gdata_youtube_comment_set_parent_comment_uri:
+ * @self: a #GDataYouTubeComment
+ * @parent_comment_uri: a new parent comment URI, or %NULL
+ *
+ * Sets the #GDataYouTubeComment:parent-comment-uri property to @parent_comment_uri.
+ *
+ * Set @parent_comment_uri to %NULL to unset the #GDataYouTubeComment:parent-comment-uri property in the comment (i.e. make the comment a top-level
+ * comment).
+ *
+ * See the <ulink type="http" url="http://code.google.com/apis/youtube/2.0/developers_guide_protocol_comments.html#Retrieve_comments">online
+ * documentation</ulink> for more information.
+ *
+ * Since: 0.9.2
+ */
+void
+gdata_youtube_comment_set_parent_comment_uri (GDataYouTubeComment *self, const gchar *parent_comment_uri)
+{
+ GDataLink *link_;
+
+ g_return_if_fail (GDATA_IS_YOUTUBE_COMMENT (self));
+ g_return_if_fail (parent_comment_uri == NULL || *parent_comment_uri != '\0');
+
+ link_ = gdata_entry_look_up_link (GDATA_ENTRY (self), GDATA_LINK_PARENT_COMMENT_URI);
+
+ if ((link_ == NULL && parent_comment_uri == NULL) ||
+ (link_ != NULL && parent_comment_uri != NULL && g_strcmp0 (gdata_link_get_uri (link_), parent_comment_uri) == 0)) {
+ /* Nothing to do. */
+ return;
+ } else if (link_ == NULL && parent_comment_uri != NULL) {
+ /* Add the new link. */
+ link_ = gdata_link_new (parent_comment_uri, GDATA_LINK_PARENT_COMMENT_URI);
+ gdata_entry_add_link (GDATA_ENTRY (self), link_);
+ g_object_unref (link_);
+ } else if (link_ != NULL && parent_comment_uri == NULL) {
+ /* Remove the old link. */
+ gdata_entry_remove_link (GDATA_ENTRY (self), link_);
+ } else if (link_ != NULL && parent_comment_uri != NULL) {
+ /* Update the existing link. */
+ gdata_link_set_uri (link_, parent_comment_uri);
+ }
+
+ g_object_notify (G_OBJECT (self), "parent-comment-uri");
+}
diff --git a/gdata/services/youtube/gdata-youtube-comment.h b/gdata/services/youtube/gdata-youtube-comment.h
new file mode 100644
index 0000000..5b64f80
--- /dev/null
+++ b/gdata/services/youtube/gdata-youtube-comment.h
@@ -0,0 +1,72 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
+/*
+ * GData Client
+ * Copyright (C) Philip Withnall 2011 <philip tecnocode co uk>
+ *
+ * GData Client 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.1 of the License, or (at your option) any later version.
+ *
+ * GData Client 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 GData Client. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef GDATA_YOUTUBE_COMMENT_H
+#define GDATA_YOUTUBE_COMMENT_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+#include <gdata/gdata-comment.h>
+
+G_BEGIN_DECLS
+
+#define GDATA_TYPE_YOUTUBE_COMMENT (gdata_youtube_comment_get_type ())
+#define GDATA_YOUTUBE_COMMENT(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDATA_TYPE_YOUTUBE_COMMENT, GDataYouTubeComment))
+#define GDATA_YOUTUBE_COMMENT_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDATA_TYPE_YOUTUBE_COMMENT, GDataYouTubeCommentClass))
+#define GDATA_IS_YOUTUBE_COMMENT(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDATA_TYPE_YOUTUBE_COMMENT))
+#define GDATA_IS_YOUTUBE_COMMENT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDATA_TYPE_YOUTUBE_COMMENT))
+#define GDATA_YOUTUBE_COMMENT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDATA_TYPE_YOUTUBE_COMMENT, GDataYouTubeCommentClass))
+
+typedef struct _GDataYouTubeCommentPrivate GDataYouTubeCommentPrivate;
+
+/**
+ * GDataYouTubeComment:
+ *
+ * All the fields in the #GDataYouTubeComment structure are private and should never be accessed directly.
+ *
+ * Since: 0.9.2
+ */
+typedef struct {
+ GDataComment parent;
+ GDataYouTubeCommentPrivate *priv;
+} GDataYouTubeComment;
+
+/**
+ * GDataYouTubeCommentClass:
+ *
+ * All the fields in the #GDataYouTubeCommentClass structure are private and should never be accessed directly.
+ *
+ * Since: 0.9.2
+ */
+typedef struct {
+ /*< private >*/
+ GDataCommentClass parent;
+} GDataYouTubeCommentClass;
+
+GType gdata_youtube_comment_get_type (void) G_GNUC_CONST;
+
+GDataYouTubeComment *gdata_youtube_comment_new (const gchar *id) G_GNUC_WARN_UNUSED_RESULT G_GNUC_MALLOC;
+
+const gchar *gdata_youtube_comment_get_parent_comment_uri (GDataYouTubeComment *self) G_GNUC_PURE;
+void gdata_youtube_comment_set_parent_comment_uri (GDataYouTubeComment *self, const gchar *parent_comment_uri);
+
+G_END_DECLS
+
+#endif /* !GDATA_YOUTUBE_COMMENT_H */
diff --git a/gdata/services/youtube/gdata-youtube-video.c b/gdata/services/youtube/gdata-youtube-video.c
index 524bc4f..c56a9ea 100644
--- a/gdata/services/youtube/gdata-youtube-video.c
+++ b/gdata/services/youtube/gdata-youtube-video.c
@@ -25,6 +25,10 @@
*
* #GDataYouTubeVideo is a subclass of #GDataEntry to represent a single video on YouTube, either when uploading or querying.
*
+ * #GDataYouTubeVideo implements #GDataCommentable, allowing comments on videos to be queried using gdata_commentable_query_comments(), and new
+ * comments to be added to videos using gdata_commentable_insert_comment(). Note that deletion of comments on any #GDataYouTubeVideo is not permitted;
+ * gdata_commentable_delete_comment() will always fail if called on a #GDataYouTubeVideo.
+ *
* For more details of YouTube's GData API, see the <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html">
* online documentation</ulink>.
*
@@ -79,6 +83,10 @@
#include "gdata-youtube-control.h"
#include "gdata-youtube-enums.h"
#include "georss/gdata-georss-where.h"
+#include "gd/gdata-gd-feed-link.h"
+#include "gdata-commentable.h"
+#include "gdata-youtube-comment.h"
+#include "gdata-youtube-service.h"
static GObject *gdata_youtube_video_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params);
static void gdata_youtube_video_dispose (GObject *object);
@@ -90,6 +98,11 @@ static gboolean post_parse_xml (GDataParsable *parsable, gpointer user_data, GEr
static void get_xml (GDataParsable *parsable, GString *xml_string);
static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
static gchar *get_entry_uri (const gchar *id) G_GNUC_WARN_UNUSED_RESULT;
+static void gdata_youtube_video_commentable_init (GDataCommentableInterface *iface);
+static GDataAuthorizationDomain *get_authorization_domain (GDataCommentable *self) G_GNUC_CONST;
+static gchar *get_query_comments_uri (GDataCommentable *self) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+static gchar *get_insert_comment_uri (GDataCommentable *self, GDataComment *comment_) G_GNUC_MALLOC G_GNUC_WARN_UNUSED_RESULT;
+static gboolean is_comment_deletable (GDataCommentable *self, GDataComment *comment_);
struct _GDataYouTubeVideoPrivate {
guint view_count;
@@ -114,6 +127,9 @@ struct _GDataYouTubeVideoPrivate {
/* Other properties */
GDataYouTubeControl *youtube_control;
gint64 recorded;
+
+ /* Comments */
+ GDataGDFeedLink *comments_feed_link;
};
enum {
@@ -141,7 +157,8 @@ enum {
PROP_LONGITUDE
};
-G_DEFINE_TYPE (GDataYouTubeVideo, gdata_youtube_video, GDATA_TYPE_ENTRY)
+G_DEFINE_TYPE_WITH_CODE (GDataYouTubeVideo, gdata_youtube_video, GDATA_TYPE_ENTRY,
+ G_IMPLEMENT_INTERFACE (GDATA_TYPE_COMMENTABLE, gdata_youtube_video_commentable_init))
static void
gdata_youtube_video_class_init (GDataYouTubeVideoClass *klass)
@@ -488,6 +505,16 @@ gdata_youtube_video_class_init (GDataYouTubeVideoClass *klass)
}
static void
+gdata_youtube_video_commentable_init (GDataCommentableInterface *iface)
+{
+ iface->comment_type = GDATA_TYPE_YOUTUBE_COMMENT;
+ iface->get_authorization_domain = get_authorization_domain;
+ iface->get_query_comments_uri = get_query_comments_uri;
+ iface->get_insert_comment_uri = get_insert_comment_uri;
+ iface->is_comment_deletable = is_comment_deletable;
+}
+
+static void
notify_title_cb (GDataYouTubeVideo *self, GParamSpec *pspec, gpointer user_data)
{
/* Update our media:group title */
@@ -544,6 +571,10 @@ gdata_youtube_video_dispose (GObject *object)
g_object_unref (priv->youtube_control);
priv->youtube_control = NULL;
+ if (priv->comments_feed_link != NULL)
+ g_object_unref (priv->comments_feed_link);
+ priv->comments_feed_link = NULL;
+
/* Chain up to the parent class */
G_OBJECT_CLASS (gdata_youtube_video_parent_class)->dispose (object);
}
@@ -806,6 +837,20 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
self->priv->rating.max = strtoul ((gchar*) max, NULL, 10);
self->priv->rating.count = num_raters_uint;
self->priv->rating.average = average_double;
+ } else if (xmlStrcmp (node->name, (xmlChar*) "comments") == 0) {
+ /* gd:comments */
+ xmlNode *child_node;
+
+ /* This is actually the child of the <comments> element */
+ child_node = node->children;
+ if (child_node == NULL) {
+ return gdata_parser_error_required_element_missing ("gd:feedLink", "gd:comments", error);
+ }
+
+ if (gdata_parser_object_from_element (child_node, "feedLink", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_GD_FEED_LINK,
+ &(self->priv->comments_feed_link), &success, error) == TRUE) {
+ return success;
+ }
} else {
return GDATA_PARSABLE_CLASS (gdata_youtube_video_parent_class)->parse_xml (parsable, doc, node, user_data, error);
}
@@ -930,6 +975,47 @@ get_entry_uri (const gchar *id)
return uri;
}
+static GDataAuthorizationDomain *
+get_authorization_domain (GDataCommentable *self)
+{
+ return gdata_youtube_service_get_primary_authorization_domain ();
+}
+
+static gchar *
+get_query_comments_uri (GDataCommentable *self)
+{
+ GDataGDFeedLink *feed_link;
+
+ feed_link = GDATA_YOUTUBE_VIDEO (self)->priv->comments_feed_link;
+
+ if (feed_link == NULL) {
+ return NULL;
+ }
+
+ return g_strdup (gdata_gd_feed_link_get_uri (feed_link));
+}
+
+static gchar *
+get_insert_comment_uri (GDataCommentable *self, GDataComment *comment_)
+{
+ GDataGDFeedLink *feed_link;
+
+ feed_link = GDATA_YOUTUBE_VIDEO (self)->priv->comments_feed_link;
+
+ if (feed_link == NULL) {
+ return NULL;
+ }
+
+ return g_strdup (gdata_gd_feed_link_get_uri (feed_link));
+}
+
+static gboolean
+is_comment_deletable (GDataCommentable *self, GDataComment *comment_)
+{
+ /* Deletion of comments is unsupported. */
+ return FALSE;
+}
+
/**
* gdata_youtube_video_new:
* @id: (allow-none): the video's ID, or %NULL
diff --git a/gdata/tests/youtube.c b/gdata/tests/youtube.c
index 1315755..e9e0ae2 100644
--- a/gdata/tests/youtube.c
+++ b/gdata/tests/youtube.c
@@ -1057,6 +1057,81 @@ test_video_escaping (void)
}
static void
+test_comment_get_xml (void)
+{
+ GDataYouTubeComment *comment_;
+
+ comment_ = gdata_youtube_comment_new (NULL);
+ gdata_entry_set_content (GDATA_ENTRY (comment_), "This is a comment with <markup> & stÃff.");
+ gdata_youtube_comment_set_parent_comment_uri (comment_, "http://example.com/?foo=bar&baz=shizzle");
+
+ /* Check the outputted XML is OK */
+ gdata_test_assert_xml (comment_,
+ "<?xml version='1.0' encoding='UTF-8'?>"
+ "<entry xmlns='http://www.w3.org/2005/Atom' xmlns:gd='http://schemas.google.com/g/2005'>"
+ "<title type='text'></title>"
+ "<content type='text'>This is a comment with <markup> & stÃff.</content>"
+ "<category term='http://gdata.youtube.com/schemas/2007#comment' scheme='http://schemas.google.com/g/2005#kind'/>"
+ "<link href='http://example.com/?foo=bar&baz=shizzle' rel='http://gdata.youtube.com/schemas/2007#in-reply-to'/>"
+ "</entry>");
+
+ g_object_unref (comment_);
+}
+
+static void
+notify_cb (GDataYouTubeComment *comment_, GParamSpec *pspec, guint *notification_count)
+{
+ *notification_count = *notification_count + 1;
+}
+
+static void
+test_comment_properties_parent_comment_uri (void)
+{
+ GDataYouTubeComment *comment_;
+ guint notification_count = 0;
+ gchar *parent_comment_uri;
+
+ comment_ = gdata_youtube_comment_new (NULL);
+ g_signal_connect (comment_, "notify::parent-comment-uri", (GCallback) notify_cb, ¬ification_count);
+
+ /* Default. */
+ g_assert (gdata_youtube_comment_get_parent_comment_uri (comment_) == NULL);
+
+ /* Set the property. */
+ gdata_youtube_comment_set_parent_comment_uri (comment_, "foo");
+ g_assert_cmpuint (notification_count, ==, 1);
+
+ g_assert_cmpstr (gdata_youtube_comment_get_parent_comment_uri (comment_), ==, "foo");
+
+ /* Get the property a different way. */
+ g_object_get (G_OBJECT (comment_),
+ "parent-comment-uri", &parent_comment_uri,
+ NULL);
+
+ g_assert_cmpstr (parent_comment_uri, ==, "foo");
+
+ g_free (parent_comment_uri);
+
+ /* Set the property a different way. */
+ g_object_set (G_OBJECT (comment_),
+ "parent-comment-uri", "bar",
+ NULL);
+ g_assert_cmpuint (notification_count, ==, 2);
+
+ /* Set the property to the same value. */
+ gdata_youtube_comment_set_parent_comment_uri (comment_, "bar");
+ g_assert_cmpuint (notification_count, ==, 2);
+
+ /* Set the property back to NULL. */
+ gdata_youtube_comment_set_parent_comment_uri (comment_, NULL);
+ g_assert_cmpuint (notification_count, ==, 3);
+
+ g_assert (gdata_youtube_comment_get_parent_comment_uri (comment_) == NULL);
+
+ g_object_unref (comment_);
+}
+
+static void
test_query_uri (void)
{
gdouble latitude, longitude, radius;
@@ -1215,6 +1290,353 @@ test_query_single_async (gconstpointer service)
g_main_loop_unref (main_loop);
}
+typedef struct {
+ GDataYouTubeVideo *video;
+} CommentData;
+
+static void
+set_up_comment (CommentData *data, gconstpointer service)
+{
+ /* Get a video known to have comments on it. */
+ data->video = GDATA_YOUTUBE_VIDEO (gdata_service_query_single_entry (GDATA_SERVICE (service),
+ gdata_youtube_service_get_primary_authorization_domain (),
+ "tag:youtube.com,2008:video:RzR2k8yo4NY", NULL,
+ GDATA_TYPE_YOUTUBE_VIDEO, NULL, NULL));
+ g_assert (GDATA_IS_YOUTUBE_VIDEO (data->video));
+}
+
+static void
+tear_down_comment (CommentData *data, gconstpointer service)
+{
+ g_object_unref (data->video);
+}
+
+static void
+assert_comments_feed (GDataFeed *comments_feed)
+{
+ GList *comments;
+
+ g_assert (GDATA_IS_FEED (comments_feed));
+
+ for (comments = gdata_feed_get_entries (comments_feed); comments != NULL; comments = comments->next) {
+ GList *authors;
+ GDataYouTubeComment *comment_ = GDATA_YOUTUBE_COMMENT (comments->data);
+
+ /* We can't do much more than this, since we can't reasonably add test comments to public videos, and can't upload a new video
+ * for each test since it has to go through moderation. */
+ g_assert_cmpstr (gdata_entry_get_title (GDATA_ENTRY (comment_)), !=, NULL);
+ g_assert_cmpstr (gdata_entry_get_content (GDATA_ENTRY (comment_)), !=, NULL);
+
+ g_assert_cmpuint (g_list_length (gdata_entry_get_authors (GDATA_ENTRY (comment_))), >, 0);
+
+ for (authors = gdata_entry_get_authors (GDATA_ENTRY (comment_)); authors != NULL; authors = authors->next) {
+ GDataAuthor *author = GDATA_AUTHOR (authors->data);
+
+ /* Again, we can't test these much. */
+ g_assert_cmpstr (gdata_author_get_name (author), !=, NULL);
+ g_assert_cmpstr (gdata_author_get_uri (author), !=, NULL);
+ }
+ }
+}
+
+static void
+test_comment_query (CommentData *data, gconstpointer service)
+{
+ GDataFeed *comments_feed;
+ GError *error = NULL;
+
+ /* Get the comments feed for the video */
+ comments_feed = gdata_commentable_query_comments (GDATA_COMMENTABLE (data->video), GDATA_SERVICE (service), NULL, NULL, NULL, NULL, &error);
+ g_assert_no_error (error);
+ g_clear_error (&error);
+
+ assert_comments_feed (comments_feed);
+
+ g_object_unref (comments_feed);
+}
+
+typedef struct {
+ CommentData parent;
+ GMainLoop *main_loop;
+} CommentAsyncData;
+
+static void
+set_up_comment_async (CommentAsyncData *data, gconstpointer service)
+{
+ set_up_comment ((CommentData*) data, service);
+ data->main_loop = g_main_loop_new (NULL, FALSE);
+}
+
+static void
+tear_down_comment_async (CommentAsyncData *data, gconstpointer service)
+{
+ g_main_loop_unref (data->main_loop);
+ tear_down_comment ((CommentData*) data, service);
+}
+
+static void
+test_comment_query_async_cb (GDataCommentable *commentable, GAsyncResult *result, CommentAsyncData *data)
+{
+ GDataFeed *comments_feed;
+ GError *error = NULL;
+
+ comments_feed = gdata_commentable_query_comments_finish (commentable, result, &error);
+ g_assert_no_error (error);
+ g_clear_error (&error);
+
+ assert_comments_feed (comments_feed);
+
+ g_object_unref (comments_feed);
+
+ g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_query_async (CommentAsyncData *data, gconstpointer service)
+{
+ gdata_commentable_query_comments_async (GDATA_COMMENTABLE (data->parent.video), GDATA_SERVICE (service), NULL, NULL, NULL, NULL, NULL,
+ (GAsyncReadyCallback) test_comment_query_async_cb, data);
+
+ g_main_loop_run (data->main_loop);
+}
+
+static void
+test_comment_query_async_cancellation_cb (GDataCommentable *commentable, GAsyncResult *result, CommentAsyncData *data)
+{
+ GDataFeed *comments_feed;
+ GError *error = NULL;
+
+ comments_feed = gdata_commentable_query_comments_finish (commentable, result, &error);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ g_assert (comments_feed == NULL);
+ g_clear_error (&error);
+
+ g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_query_async_cancellation (CommentAsyncData *data, gconstpointer service)
+{
+ GCancellable *cancellable;
+
+ cancellable = g_cancellable_new ();
+ g_cancellable_cancel (cancellable);
+
+ gdata_commentable_query_comments_async (GDATA_COMMENTABLE (data->parent.video), GDATA_SERVICE (service), NULL, cancellable, NULL, NULL, NULL,
+ (GAsyncReadyCallback) test_comment_query_async_cancellation_cb, data);
+
+ g_main_loop_run (data->main_loop);
+
+ g_object_unref (cancellable);
+}
+
+/* Test that the progress callbacks from gdata_commentable_query_comments_async() are called correctly.
+ * We take a CommentAsyncData so that we can guarantee the video exists, but we don't use it much as we don't actually care about the specific
+ * video. */
+static void
+test_comment_query_async_progress_closure (CommentAsyncData *query_data, gconstpointer service)
+{
+ GDataAsyncProgressClosure *data = g_slice_new0 (GDataAsyncProgressClosure);
+
+ data->main_loop = g_main_loop_new (NULL, TRUE);
+
+ gdata_commentable_query_comments_async (GDATA_COMMENTABLE (query_data->parent.video), GDATA_SERVICE (service), NULL, NULL,
+ (GDataQueryProgressCallback) gdata_test_async_progress_callback,
+ data, (GDestroyNotify) gdata_test_async_progress_closure_free,
+ (GAsyncReadyCallback) gdata_test_async_progress_finish_callback, data);
+
+ g_main_loop_run (data->main_loop);
+ g_main_loop_unref (data->main_loop);
+
+ /* Check that both callbacks were called exactly once */
+ g_assert_cmpuint (data->progress_destroy_notify_count, ==, 1);
+ g_assert_cmpuint (data->async_ready_notify_count, ==, 1);
+
+ g_slice_free (GDataAsyncProgressClosure, data);
+}
+
+typedef struct {
+ CommentData parent;
+ GDataYouTubeComment *comment;
+} InsertCommentData;
+
+static void
+set_up_insert_comment (InsertCommentData *data, gconstpointer service)
+{
+ set_up_comment ((CommentData*) data, service);
+
+ /* Create a test comment to be inserted. */
+ data->comment = gdata_youtube_comment_new (NULL);
+ g_assert (GDATA_IS_YOUTUBE_COMMENT (data->comment));
+
+ gdata_entry_set_content (GDATA_ENTRY (data->comment), "This is a test comment.");
+}
+
+static void
+tear_down_insert_comment (InsertCommentData *data, gconstpointer service)
+{
+ if (data->comment != NULL) {
+ g_object_unref (data->comment);
+ }
+
+ tear_down_comment ((CommentData*) data, service);
+}
+
+static void
+assert_comments_equal (GDataComment *new_comment, GDataYouTubeComment *original_comment)
+{
+ GList *authors;
+ GDataAuthor *author;
+
+ g_assert (GDATA_IS_YOUTUBE_COMMENT (new_comment));
+ g_assert (GDATA_IS_YOUTUBE_COMMENT (original_comment));
+ g_assert (GDATA_YOUTUBE_COMMENT (new_comment) != original_comment);
+
+ g_assert_cmpstr (gdata_entry_get_content (GDATA_ENTRY (new_comment)), ==, gdata_entry_get_content (GDATA_ENTRY (original_comment)));
+ g_assert_cmpstr (gdata_youtube_comment_get_parent_comment_uri (GDATA_YOUTUBE_COMMENT (new_comment)), ==,
+ gdata_youtube_comment_get_parent_comment_uri (original_comment));
+
+ /* Check the author of the new comment. */
+ authors = gdata_entry_get_authors (GDATA_ENTRY (new_comment));
+ g_assert_cmpuint (g_list_length (authors), ==, 1);
+
+ author = GDATA_AUTHOR (authors->data);
+
+ g_assert_cmpstr (gdata_author_get_name (author), ==, "GDataTest");
+ g_assert_cmpstr (gdata_author_get_uri (author), ==, "https://gdata.youtube.com/feeds/api/users/gdatatest");
+}
+
+static void
+test_comment_insert (InsertCommentData *data, gconstpointer service)
+{
+ GDataComment *new_comment;
+ GError *error = NULL;
+
+ new_comment = gdata_commentable_insert_comment (GDATA_COMMENTABLE (data->parent.video), GDATA_SERVICE (service), GDATA_COMMENT (data->comment),
+ NULL, &error);
+ g_assert_no_error (error);
+ g_clear_error (&error);
+
+ assert_comments_equal (new_comment, data->comment);
+
+ g_object_unref (new_comment);
+}
+
+typedef struct {
+ InsertCommentData parent;
+ GMainLoop *main_loop;
+} InsertCommentAsyncData;
+
+static void
+set_up_insert_comment_async (InsertCommentAsyncData *data, gconstpointer service)
+{
+ set_up_insert_comment ((InsertCommentData*) data, service);
+ data->main_loop = g_main_loop_new (NULL, FALSE);
+}
+
+static void
+tear_down_insert_comment_async (InsertCommentAsyncData *data, gconstpointer service)
+{
+ g_main_loop_unref (data->main_loop);
+ tear_down_insert_comment ((InsertCommentData*) data, service);
+}
+
+static void
+test_comment_insert_async_cb (GDataCommentable *commentable, GAsyncResult *result, InsertCommentAsyncData *data)
+{
+ GDataComment *new_comment;
+ GError *error = NULL;
+
+ new_comment = gdata_commentable_insert_comment_finish (commentable, result, &error);
+ g_assert_no_error (error);
+ g_clear_error (&error);
+
+ assert_comments_equal (new_comment, data->parent.comment);
+
+ g_object_unref (new_comment);
+
+ g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_insert_async (InsertCommentAsyncData *data, gconstpointer service)
+{
+ gdata_commentable_insert_comment_async (GDATA_COMMENTABLE (data->parent.parent.video), GDATA_SERVICE (service),
+ GDATA_COMMENT (data->parent.comment), NULL, (GAsyncReadyCallback) test_comment_insert_async_cb, data);
+
+ g_main_loop_run (data->main_loop);
+}
+
+static void
+test_comment_insert_async_cancellation_cb (GDataCommentable *commentable, GAsyncResult *result, InsertCommentAsyncData *data)
+{
+ GDataComment *new_comment;
+ GError *error = NULL;
+
+ new_comment = gdata_commentable_insert_comment_finish (commentable, result, &error);
+ g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED);
+ g_assert (new_comment == NULL);
+ g_clear_error (&error);
+
+ g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_insert_async_cancellation (InsertCommentAsyncData *data, gconstpointer service)
+{
+ GCancellable *cancellable;
+
+ cancellable = g_cancellable_new ();
+ g_cancellable_cancel (cancellable);
+
+ gdata_commentable_insert_comment_async (GDATA_COMMENTABLE (data->parent.parent.video), GDATA_SERVICE (service),
+ GDATA_COMMENT (data->parent.comment), cancellable,
+ (GAsyncReadyCallback) test_comment_insert_async_cancellation_cb, data);
+
+ g_main_loop_run (data->main_loop);
+
+ g_object_unref (cancellable);
+}
+
+static void
+test_comment_delete (InsertCommentData *data, gconstpointer service)
+{
+ gboolean success;
+ GError *error = NULL;
+
+ /* We attempt to delete a comment which hasn't been inserted here, but that doesn't matter as the function should always immediately
+ * return an error because deleting YouTube comments isn't allowed. */
+ success = gdata_commentable_delete_comment (GDATA_COMMENTABLE (data->parent.video), GDATA_SERVICE (service), GDATA_COMMENT (data->comment),
+ NULL, &error);
+ g_assert_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_FORBIDDEN);
+ g_assert (success == FALSE);
+ g_clear_error (&error);
+}
+
+static void
+test_comment_delete_async_cb (GDataCommentable *commentable, GAsyncResult *result, InsertCommentAsyncData *data)
+{
+ gboolean success;
+ GError *error = NULL;
+
+ success = gdata_commentable_delete_comment_finish (commentable, result, &error);
+ g_assert_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_FORBIDDEN);
+ g_assert (success == FALSE);
+ g_clear_error (&error);
+
+ g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_comment_delete_async (InsertCommentAsyncData *data, gconstpointer service)
+{
+ /* See the note above in test_comment_delete(). */
+ gdata_commentable_delete_comment_async (GDATA_COMMENTABLE (data->parent.parent.video), GDATA_SERVICE (service),
+ GDATA_COMMENT (data->parent.comment), NULL, (GAsyncReadyCallback) test_comment_delete_async_cb, data);
+
+ g_main_loop_run (data->main_loop);
+}
+
static void
test_parsing_video_id_from_uri (void)
{
@@ -1520,6 +1942,26 @@ main (int argc, char *argv[])
g_test_add_data_func ("/youtube/query/single", service, test_query_single);
g_test_add_data_func ("/youtube/query/single_async", service, test_query_single_async);
+ g_test_add ("/youtube/comment/query", CommentData, service, set_up_comment, test_comment_query, tear_down_comment);
+ g_test_add ("/youtube/comment/query/async", CommentAsyncData, service, set_up_comment_async, test_comment_query_async,
+ tear_down_comment_async);
+ g_test_add ("/youtube/comment/query/async/cancellation", CommentAsyncData, service, set_up_comment_async,
+ test_comment_query_async_cancellation, tear_down_comment_async);
+ g_test_add ("/youtube/comment/query/async/progress_closure", CommentAsyncData, service, set_up_comment_async,
+ test_comment_query_async_progress_closure, tear_down_comment_async);
+
+ g_test_add ("/youtube/comment/insert", InsertCommentData, service, set_up_insert_comment, test_comment_insert,
+ tear_down_insert_comment);
+ g_test_add ("/youtube/comment/insert/async", InsertCommentAsyncData, service, set_up_insert_comment_async, test_comment_insert_async,
+ tear_down_insert_comment_async);
+ g_test_add ("/youtube/comment/insert/async/cancellation", InsertCommentAsyncData, service, set_up_insert_comment_async,
+ test_comment_insert_async_cancellation, tear_down_insert_comment_async);
+
+ g_test_add ("/youtube/comment/delete", InsertCommentData, service, set_up_insert_comment, test_comment_delete,
+ tear_down_insert_comment);
+ g_test_add ("/youtube/comment/delete/async", InsertCommentAsyncData, service, set_up_insert_comment_async, test_comment_delete_async,
+ tear_down_insert_comment_async);
+
g_test_add_data_func ("/youtube/categories", service, test_categories);
g_test_add_data_func ("/youtube/categories/async", service, test_categories_async);
@@ -1541,6 +1983,9 @@ main (int argc, char *argv[])
g_test_add_func ("/youtube/video/escaping", test_video_escaping);
+ g_test_add_func ("/youtube/comment/get_xml", test_comment_get_xml);
+ g_test_add_func ("/youtube/comment/properties/parent-comment-id", test_comment_properties_parent_comment_uri);
+
g_test_add_func ("/youtube/query/uri", test_query_uri);
g_test_add_func ("/youtube/query/etag", test_query_etag);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]