[libgdata] Bug 647882 — Support rating schemes



commit 96d88904bc10e066ebcee75e5eac4cf18e23ad55
Author: Philip Withnall <philip tecnocode co uk>
Date:   Fri Jul 29 23:39:34 2011 +0100

    Bug 647882 â Support rating schemes
    
    Add support for media rating schemes (such as the MPAA's certificates) to
    GDataYouTubeVideo (and GDataMediaGroup). This includes tests, and adds the
    following new API:
     â gdata_youtube_video_get_media_rating()
     â GDATA_YOUTUBE_RATING_TYPE_SIMPLE
     â GDATA_YOUTUBE_RATING_TYPE_MPAA
     â GDATA_YOUTUBE_RATING_TYPE_V_CHIP
    
    Closes: bgo#647882

 docs/reference/gdata-sections.txt            |    4 +
 gdata/gdata.symbols                          |    4 +
 gdata/media/gdata-media-group.c              |  106 +++++++++++++++++++++----
 gdata/media/gdata-media-group.h              |    1 +
 gdata/services/youtube/gdata-youtube-video.c |   27 ++++++
 gdata/services/youtube/gdata-youtube-video.h |   34 ++++++++
 gdata/tests/youtube.c                        |  111 ++++++++++++++++++++++++++
 7 files changed, 271 insertions(+), 16 deletions(-)
---
diff --git a/docs/reference/gdata-sections.txt b/docs/reference/gdata-sections.txt
index 58ab6ee..2da91d1 100644
--- a/docs/reference/gdata-sections.txt
+++ b/docs/reference/gdata-sections.txt
@@ -217,6 +217,9 @@ GDATA_YOUTUBE_ACTION_COMMENT_VOTE
 GDATA_YOUTUBE_ACTION_VIDEO_RESPOND
 GDATA_YOUTUBE_ACTION_EMBED
 GDATA_YOUTUBE_ACTION_SYNDICATE
+GDATA_YOUTUBE_RATING_TYPE_SIMPLE
+GDATA_YOUTUBE_RATING_TYPE_MPAA
+GDATA_YOUTUBE_RATING_TYPE_V_CHIP
 GDataYouTubeVideo
 GDataYouTubeVideoClass
 GDataYouTubePermission
@@ -236,6 +239,7 @@ gdata_youtube_video_set_location
 gdata_youtube_video_get_view_count
 gdata_youtube_video_get_favorite_count
 gdata_youtube_video_is_restricted_in_country
+gdata_youtube_video_get_media_rating
 gdata_youtube_video_get_access_control
 gdata_youtube_video_set_access_control
 gdata_youtube_video_get_player_uri
diff --git a/gdata/gdata.symbols b/gdata/gdata.symbols
index 41f88ba..1220ce9 100644
--- a/gdata/gdata.symbols
+++ b/gdata/gdata.symbols
@@ -929,3 +929,7 @@ gdata_youtube_comment_get_parent_comment_uri
 gdata_youtube_comment_set_parent_comment_uri
 gdata_picasaweb_comment_get_type
 gdata_picasaweb_comment_new
+GDATA_YOUTUBE_RATING_TYPE_SIMPLE
+GDATA_YOUTUBE_RATING_TYPE_MPAA
+GDATA_YOUTUBE_RATING_TYPE_V_CHIP
+gdata_youtube_video_get_media_rating
diff --git a/gdata/media/gdata-media-group.c b/gdata/media/gdata-media-group.c
index 94bf01e..21b9e33 100644
--- a/gdata/media/gdata-media-group.c
+++ b/gdata/media/gdata-media-group.c
@@ -55,6 +55,9 @@ struct _GDataMediaGroupPrivate {
 	gchar **keywords;
 	gchar *player_uri;
 	GHashTable *restricted_countries;
+	gchar *simple_rating;
+	gchar *mpaa_rating;
+	gchar *v_chip_rating;
 	GList *thumbnails; /* GDataMediaThumbnail */
 	gchar *title;
 	GDataMediaCategory *category;
@@ -126,6 +129,9 @@ gdata_media_group_finalize (GObject *object)
 
 	g_strfreev (priv->keywords);
 	g_free (priv->player_uri);
+	g_free (priv->v_chip_rating);
+	g_free (priv->mpaa_rating);
+	g_free (priv->simple_rating);
 	g_hash_table_destroy (priv->restricted_countries);
 	g_free (priv->title);
 	g_free (priv->description);
@@ -194,25 +200,61 @@ parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_da
 			self->priv->player_uri = (gchar*) player_uri;
 		} else if (xmlStrcmp (node->name, (xmlChar*) "rating") == 0) {
 			/* media:rating */
-			xmlChar *countries;
-
-			countries = xmlGetProp (node, (xmlChar*) "country");
-
-			if (countries != NULL) {
-				gchar **country_list, **country;
-
-				/* It's either a comma-separated list of countries, or the value "all" */
-				country_list = g_strsplit ((const gchar*) countries, ",", -1);
-				xmlFree (countries);
+			xmlChar *scheme;
+
+			/* The possible schemes are defined here:
+			 *  â http://video.search.yahoo.com/mrss
+			 *  â http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_media:rating
+			 */
+			scheme = xmlGetProp (node, (xmlChar*) "scheme");
+
+			if (scheme == NULL || xmlStrcmp (scheme, (xmlChar*) "urn:simple") == 0) {
+				/* Options: adult, nonadult */
+				gdata_parser_string_from_element (node, "rating", P_REQUIRED | P_NON_EMPTY, &(self->priv->simple_rating),
+				                                  &success, error);
+			} else if (xmlStrcmp (scheme, (xmlChar*) "urn:mpaa") == 0) {
+				/* Options: g, pg, pg-13, r, nc-17 */
+				gdata_parser_string_from_element (node, "rating", P_REQUIRED | P_NON_EMPTY, &(self->priv->mpaa_rating),
+				                                  &success, error);
+			} else if (xmlStrcmp (scheme, (xmlChar*) "urn:v-chip") == 0) {
+				/* Options: tv-y, tv-y7, tv-y7-fv, tv-g, tv-pg, tv-14, tv-ma */
+				gdata_parser_string_from_element (node, "rating", P_REQUIRED | P_NON_EMPTY, &(self->priv->v_chip_rating),
+				                                  &success, error);
+			} else if (xmlStrcmp (scheme, (xmlChar*) "http://gdata.youtube.com/schemas/2007#mediarating";) == 0) {
+				/* No content, but we do get a list of countries. There's nothing like overloading the semantics of XML elements
+				 * to brighten up one's day. */
+				xmlChar *countries;
+
+				countries = xmlGetProp (node, (xmlChar*) "country");
+
+				if (countries != NULL) {
+					gchar **country_list, **country;
+
+					/* It's either a comma-separated list of countries, or the value "all" */
+					country_list = g_strsplit ((const gchar*) countries, ",", -1);
+					xmlFree (countries);
+
+					/* Add all the listed countries to the restricted countries table */
+					for (country = country_list; *country != NULL; country++) {
+						g_hash_table_insert (self->priv->restricted_countries, *country, GUINT_TO_POINTER (TRUE));
+					}
+
+					g_free (country_list);
+				} else {
+					/* Assume it's restricted in all countries */
+					g_hash_table_insert (self->priv->restricted_countries, g_strdup ("all"), GUINT_TO_POINTER (TRUE));
+				}
 
-				/* Add all the listed countries to the restricted countries table */
-				for (country = country_list; *country != NULL; country++)
-					g_hash_table_insert (self->priv->restricted_countries, *country, GUINT_TO_POINTER (TRUE));
-				g_free (country_list);
+				success = TRUE;
 			} else {
-				/* Assume it's restricted in all countries */
-				g_hash_table_insert (self->priv->restricted_countries, g_strdup ("all"), GUINT_TO_POINTER (TRUE));
+				/* Error */
+				gdata_parser_error_unknown_property_value (node, "scheme", (gchar*) scheme, error);
+				success = FALSE;
 			}
+
+			xmlFree (scheme);
+
+			return success;
 		} else if (xmlStrcmp (node->name, (xmlChar*) "restriction") == 0) {
 			/* media:restriction */
 			xmlChar *type, *countries, *relationship;
@@ -576,6 +618,38 @@ gdata_media_group_is_restricted_in_country (GDataMediaGroup *self, const gchar *
 }
 
 /**
+ * gdata_media_group_get_media_rating:
+ * @self: a #GDataMediaGroup
+ * @rating_type: the type of rating to retrieve
+ *
+ * Returns the rating of the given type for the media, if one exists. For example, this could be a film rating awarded by the MPAA.
+ * The valid values for @rating_type are: <code class="literal">simple</code>, <code class="literal">mpaa</code> and
+ * <code class="literal">v-chip</code>.
+ *
+ * The rating values returned for each of these rating types are string as defined in the
+ * <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_media:rating";>YouTube documentation</ulink> and
+ * <ulink type="http" url="http://video.search.yahoo.com/mrss";>MRSS specification</ulink>.
+ *
+ * Return value: rating for the given rating type, or %NULL if the media has no rating for that type (or the type is invalid)
+ */
+const gchar *
+gdata_media_group_get_media_rating (GDataMediaGroup *self, const gchar *rating_type)
+{
+	g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
+	g_return_val_if_fail (rating_type != NULL && *rating_type != '\0', NULL);
+
+	if (strcmp (rating_type, "simple") == 0) {
+		return self->priv->simple_rating;
+	} else if (strcmp (rating_type, "mpaa") == 0) {
+		return self->priv->mpaa_rating;
+	} else if (strcmp (rating_type, "v-chip") == 0) {
+		return self->priv->v_chip_rating;
+	}
+
+	return NULL;
+}
+
+/**
  * gdata_media_group_get_thumbnails:
  * @self: a #GDataMediaGroup
  *
diff --git a/gdata/media/gdata-media-group.h b/gdata/media/gdata-media-group.h
index 9156699..f8ce7aa 100644
--- a/gdata/media/gdata-media-group.h
+++ b/gdata/media/gdata-media-group.h
@@ -79,6 +79,7 @@ GDataMediaCredit *gdata_media_group_get_credit (GDataMediaGroup *self) G_GNUC_PU
 void _gdata_media_group_set_credit (GDataMediaGroup *self, GDataMediaCredit *credit);
 const gchar *gdata_media_group_get_player_uri (GDataMediaGroup *self) G_GNUC_PURE;
 gboolean gdata_media_group_is_restricted_in_country (GDataMediaGroup *self, const gchar *country) G_GNUC_PURE;
+const gchar *gdata_media_group_get_media_rating (GDataMediaGroup *self, const gchar *rating_type) G_GNUC_PURE;
 GList *gdata_media_group_get_thumbnails (GDataMediaGroup *self) G_GNUC_PURE;
 void _gdata_media_group_add_thumbnail (GDataMediaGroup *self, GDataMediaThumbnail *thumbnail);
 
diff --git a/gdata/services/youtube/gdata-youtube-video.c b/gdata/services/youtube/gdata-youtube-video.c
index c56a9ea..4b60ebf 100644
--- a/gdata/services/youtube/gdata-youtube-video.c
+++ b/gdata/services/youtube/gdata-youtube-video.c
@@ -1237,6 +1237,33 @@ gdata_youtube_video_is_restricted_in_country (GDataYouTubeVideo *self, const gch
 }
 
 /**
+ * gdata_youtube_video_get_media_rating:
+ * @self: a #GDataYouTubeVideo
+ * @rating_type: the type of rating to retrieve
+ *
+ * Returns the rating of the given type for the video, if one exists. For example, this could be a film rating awarded by the MPAA; or a simple
+ * rating specifying whether the video contains adult content.
+ *
+ * The valid values for @rating_type are: %GDATA_YOUTUBE_RATING_TYPE_SIMPLE, %GDATA_YOUTUBE_RATING_TYPE_MPAA and %GDATA_YOUTUBE_RATING_TYPE_V_CHIP.
+ * Further values may be added in future; if an unknown rating type is passed to the function, %NULL will be returned.
+ *
+ * The possible return values depend on what's passed to @rating_type. Valid values for each rating type are listed in the documentation for the
+ * rating types.
+ *
+ * Return value: the rating of the video for the given @rating_type, or %NULL if the video isn't rated with that type (or the type is unknown)
+ *
+ * Since: 0.9.2
+ */
+const gchar *
+gdata_youtube_video_get_media_rating (GDataYouTubeVideo *self, const gchar *rating_type)
+{
+	g_return_val_if_fail (GDATA_IS_YOUTUBE_VIDEO (self), NULL);
+	g_return_val_if_fail (rating_type != NULL && *rating_type != '\0', NULL);
+
+	return gdata_media_group_get_media_rating (self->priv->media_group, rating_type);
+}
+
+/**
  * gdata_youtube_video_get_category:
  * @self: a #GDataYouTubeVideo
  *
diff --git a/gdata/services/youtube/gdata-youtube-video.h b/gdata/services/youtube/gdata-youtube-video.h
index 6fbce5e..93b80c2 100644
--- a/gdata/services/youtube/gdata-youtube-video.h
+++ b/gdata/services/youtube/gdata-youtube-video.h
@@ -98,6 +98,39 @@ G_BEGIN_DECLS
 #define GDATA_YOUTUBE_ACTION_SYNDICATE "syndicate"
 
 /**
+ * GDATA_YOUTUBE_RATING_TYPE_SIMPLE:
+ *
+ * A rating type to pass to gdata_youtube_video_get_media_rating() for âsimpleâ ratings. The values which can be returned for such ratings are:
+ * <code class="literal">adult</code> and <code class="literal">nonadult</code>.
+ *
+ * Since: 0.9.2
+ */
+#define GDATA_YOUTUBE_RATING_TYPE_SIMPLE "simple"
+
+/**
+ * GDATA_YOUTUBE_RATING_TYPE_MPAA:
+ *
+ * A rating type to pass to gdata_youtube_video_get_media_rating() for ratings by the <ulink type="http" url="http://www.mpaa.org/";>MPAA</ulink>. The
+ * values which can be returned for such ratings are: <code class="literal">g</code>, <code class="literal">pg</code>,
+ * <code class="literal">pg-13</code>, <code class="literal">r</code> and <code class="literal">nc-17</code>.
+ *
+ * Since: 0.9.2
+ */
+#define GDATA_YOUTUBE_RATING_TYPE_MPAA "mpaa"
+
+/**
+ * GDATA_YOUTUBE_RATING_TYPE_V_CHIP:
+ *
+ * A rating type to pass to gdata_youtube_video_get_media_rating() for ratings following the FCC
+ * <ulink type="http" url="http://www.fcc.gov/vchip/";>V-Chip</ulink> system. The values which can be returned for such ratings are:
+ * <code class="literal">tv-y</code>, <code class="literal">tv-y7</code>, <code class="literal">tv-y7-fv</code>, <code class="literal">tv-g</code>,
+ * <code class="literal">tv-pg</code>, <code class="literal">tv-14</code> and <code class="literal">tv-ma</code>.
+ *
+ * Since: 0.9.2
+ */
+#define GDATA_YOUTUBE_RATING_TYPE_V_CHIP "v-chip"
+
+/**
  * GDataYouTubePermission:
  * @GDATA_YOUTUBE_PERMISSION_ALLOWED: the action is allowed for everyone
  * @GDATA_YOUTUBE_PERMISSION_DENIED: the action is denied for everyone
@@ -160,6 +193,7 @@ const gchar * const *gdata_youtube_video_get_keywords (GDataYouTubeVideo *self)
 void gdata_youtube_video_set_keywords (GDataYouTubeVideo *self, const gchar * const *keywords);
 const gchar *gdata_youtube_video_get_player_uri (GDataYouTubeVideo *self) G_GNUC_PURE;
 gboolean gdata_youtube_video_is_restricted_in_country (GDataYouTubeVideo *self, const gchar *country) G_GNUC_PURE;
+const gchar *gdata_youtube_video_get_media_rating (GDataYouTubeVideo *self, const gchar *rating_type) G_GNUC_PURE;
 GDataMediaCategory *gdata_youtube_video_get_category (GDataYouTubeVideo *self) G_GNUC_PURE;
 void gdata_youtube_video_set_category (GDataYouTubeVideo *self, GDataMediaCategory *category);
 GDataYouTubeCredit *gdata_youtube_video_get_credit (GDataYouTubeVideo *self) G_GNUC_PURE;
diff --git a/gdata/tests/youtube.c b/gdata/tests/youtube.c
index e9e0ae2..708e7db 100644
--- a/gdata/tests/youtube.c
+++ b/gdata/tests/youtube.c
@@ -1023,6 +1023,115 @@ test_parsing_media_group (void)
 }
 
 static void
+test_parsing_media_group_ratings (void)
+{
+	GDataYouTubeVideo *video;
+	GError *error = NULL;
+
+	/* Parse all ratings */
+	video = GDATA_YOUTUBE_VIDEO (gdata_parsable_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO,
+		"<entry xmlns='http://www.w3.org/2005/Atom' "
+		       "xmlns:media='http://search.yahoo.com/mrss/' "
+		       "xmlns:yt='http://gdata.youtube.com/schemas/2007' "
+		       "xmlns:gd='http://schemas.google.com/g/2005'>"
+			"<id>tag:youtube.com,2008:video:JAagedeKdcQ</id>"
+			"<published>2006-05-16T14:06:37.000Z</published>"
+			"<updated>2009-03-23T12:46:58.000Z</updated>"
+			"<category scheme='http://schemas.google.com/g/2005#kind' term='http://gdata.youtube.com/schemas/2007#video'/>"
+			"<title>Some video somewhere</title>"
+			"<media:group>"
+				"<media:rating scheme='urn:simple'>nonadult</media:rating>"
+				"<media:rating scheme='urn:mpaa'>pg</media:rating>"
+				"<media:rating scheme='urn:v-chip'>tv-pg</media:rating>"
+			"</media:group>"
+		"</entry>", -1, &error));
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_YOUTUBE_VIDEO (video));
+	g_clear_error (&error);
+
+	/* Check the ratings, and check that we haven't ended up with a country restriction */
+	g_assert_cmpstr (gdata_youtube_video_get_media_rating (video, GDATA_YOUTUBE_RATING_TYPE_SIMPLE), ==, "nonadult");
+	g_assert_cmpstr (gdata_youtube_video_get_media_rating (video, GDATA_YOUTUBE_RATING_TYPE_MPAA), ==, "pg");
+	g_assert_cmpstr (gdata_youtube_video_get_media_rating (video, GDATA_YOUTUBE_RATING_TYPE_V_CHIP), ==, "tv-pg");
+
+	g_assert (gdata_youtube_video_is_restricted_in_country (video, "US") == FALSE);
+
+	g_object_unref (video);
+
+	/* Parse a video with one rating missing and see what happens */
+	video = GDATA_YOUTUBE_VIDEO (gdata_parsable_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO,
+		"<entry xmlns='http://www.w3.org/2005/Atom' "
+		       "xmlns:media='http://search.yahoo.com/mrss/' "
+		       "xmlns:yt='http://gdata.youtube.com/schemas/2007' "
+		       "xmlns:gd='http://schemas.google.com/g/2005'>"
+			"<id>tag:youtube.com,2008:video:JAagedeKdcQ</id>"
+			"<published>2006-05-16T14:06:37.000Z</published>"
+			"<updated>2009-03-23T12:46:58.000Z</updated>"
+			"<category scheme='http://schemas.google.com/g/2005#kind' term='http://gdata.youtube.com/schemas/2007#video'/>"
+			"<title>Some video somewhere</title>"
+			"<media:group>"
+				"<media:rating scheme='urn:v-chip'>tv-y7-fv</media:rating>"
+				"<media:rating>adult</media:rating>"
+			"</media:group>"
+		"</entry>", -1, &error));
+	g_assert_no_error (error);
+	g_assert (GDATA_IS_YOUTUBE_VIDEO (video));
+	g_clear_error (&error);
+
+	/* Check the ratings again */
+	g_assert_cmpstr (gdata_youtube_video_get_media_rating (video, GDATA_YOUTUBE_RATING_TYPE_SIMPLE), ==, "adult");
+	g_assert_cmpstr (gdata_youtube_video_get_media_rating (video, GDATA_YOUTUBE_RATING_TYPE_MPAA), ==, NULL);
+	g_assert_cmpstr (gdata_youtube_video_get_media_rating (video, GDATA_YOUTUBE_RATING_TYPE_V_CHIP), ==, "tv-y7-fv");
+
+	/* Check that calling with an arbitrary rating type returns NULL */
+	g_assert_cmpstr (gdata_youtube_video_get_media_rating (video, "fooish bar"), ==, NULL);
+
+	g_object_unref (video);
+}
+
+static void
+test_parsing_media_group_ratings_error_handling (void)
+{
+	GDataYouTubeVideo *video;
+	GError *error = NULL;
+
+#define TEST_XML_ERROR_HANDLING(x) \
+	video = GDATA_YOUTUBE_VIDEO (gdata_parsable_new_from_xml (GDATA_TYPE_YOUTUBE_VIDEO,\
+		"<entry xmlns='http://www.w3.org/2005/Atom' "\
+		       "xmlns:media='http://search.yahoo.com/mrss/' "\
+		       "xmlns:yt='http://gdata.youtube.com/schemas/2007' "\
+		       "xmlns:gd='http://schemas.google.com/g/2005'>"\
+			"<id>tag:youtube.com,2008:video:JAagedeKdcQ</id>"\
+			"<published>2006-05-16T14:06:37.000Z</published>"\
+			"<updated>2009-03-23T12:46:58.000Z</updated>"\
+			"<category scheme='http://schemas.google.com/g/2005#kind' term='http://gdata.youtube.com/schemas/2007#video'/>"\
+			"<title>Some video somewhere</title>"\
+			"<media:group>"\
+				x\
+			"</media:group>"\
+		"</entry>", -1, &error));\
+	g_assert_error (error, GDATA_SERVICE_ERROR, GDATA_SERVICE_ERROR_PROTOCOL_ERROR);\
+	g_assert (video == NULL);\
+	g_clear_error (&error)
+
+	/* Missing content */
+	TEST_XML_ERROR_HANDLING ("<media:rating scheme='urn:simple'/>");
+	TEST_XML_ERROR_HANDLING ("<media:rating scheme='urn:mpaa'/>");
+	TEST_XML_ERROR_HANDLING ("<media:rating scheme='urn:v-chip'/>");
+
+	/* Empty content */
+	TEST_XML_ERROR_HANDLING ("<media:rating scheme='urn:simple'></media:rating>");
+	TEST_XML_ERROR_HANDLING ("<media:rating scheme='urn:mpaa'></media:rating>");
+	TEST_XML_ERROR_HANDLING ("<media:rating scheme='urn:v-chip'></media:rating>");
+
+	/* Unknown/Empty scheme */
+	TEST_XML_ERROR_HANDLING ("<media:rating scheme=''>foo</media:rating>");
+	TEST_XML_ERROR_HANDLING ("<media:rating scheme='urn:baz'>bob</media:rating>");
+
+#undef TEST_XML_ERROR_HANDLING
+}
+
+static void
 test_video_escaping (void)
 {
 	GDataYouTubeVideo *video;
@@ -1980,6 +2089,8 @@ main (int argc, char *argv[])
 	g_test_add_func ("/youtube/parsing/video_id_from_uri", test_parsing_video_id_from_uri);
 	g_test_add_func ("/youtube/parsing/georss:where", test_parsing_georss_where);
 	g_test_add_func ("/youtube/parsing/media:group", test_parsing_media_group);
+	g_test_add_func ("/youtube/parsing/media:group/ratings", test_parsing_media_group_ratings);
+	g_test_add_func ("/youtube/parsing/media:group/ratings/error_handling", test_parsing_media_group_ratings_error_handling);
 
 	g_test_add_func ("/youtube/video/escaping", test_video_escaping);
 



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