1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2 /*
3 * GData Client
4 * Copyright (C) Philip Withnall 2009–2010 <philip@tecnocode.co.uk>
5 *
6 * GData Client is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * GData Client is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with GData Client. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 /*
21 * SECTION:gdata-media-group
22 * @short_description: Media RSS group element
23 * @stability: Stable
24 * @include: gdata/media/gdata-media-group.h
25 *
26 * #GDataMediaGroup represents a "group" element from the
27 * <ulink type="http" url="http://video.search.yahoo.com/mrss">Media RSS specification</ulink>.
28 *
29 * It is private API, since implementing classes are likely to proxy the properties and functions
30 * of #GDataMediaGroup as appropriate; most entry types which implement #GDataMediaGroup have no use
31 * for most of its properties, and it would be unnecessary and confusing to expose #GDataMediaGroup itself.
32 *
33 * For this reason, properties have not been implemented on #GDataMediaGroup (yet).
34 */
35
36 #include <glib.h>
37 #include <libxml/parser.h>
38 #include <string.h>
39
40 #include "gdata-media-group.h"
41 #include "gdata-parsable.h"
42 #include "gdata-parser.h"
43 #include "gdata-private.h"
44 #include "media/gdata-media-category.h"
45 #include "media/gdata-media-credit.h"
46 #include "media/gdata-media-thumbnail.h"
47
48 static void gdata_media_group_dispose (GObject *object);
49 static void gdata_media_group_finalize (GObject *object);
50 static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error);
51 static void get_xml (GDataParsable *parsable, GString *xml_string);
52 static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces);
53
54 struct _GDataMediaGroupPrivate {
55 gchar **keywords;
56 gchar *player_uri;
57 GHashTable *restricted_countries;
58 gchar *simple_rating;
59 gchar *mpaa_rating;
60 gchar *v_chip_rating;
61 GList *thumbnails; /* GDataMediaThumbnail */
62 gchar *title;
63 GDataMediaCategory *category;
64 GList *contents; /* GDataMediaContent */
65 GDataMediaCredit *credit;
66 gchar *description;
67 };
68
G_DEFINE_TYPE(GDataMediaGroup,gdata_media_group,GDATA_TYPE_PARSABLE)69 G_DEFINE_TYPE (GDataMediaGroup, gdata_media_group, GDATA_TYPE_PARSABLE)
70
71 static void
72 gdata_media_group_class_init (GDataMediaGroupClass *klass)
73 {
74 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
75 GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass);
76
77 g_type_class_add_private (klass, sizeof (GDataMediaGroupPrivate));
78
79 gobject_class->dispose = gdata_media_group_dispose;
80 gobject_class->finalize = gdata_media_group_finalize;
81
82 parsable_class->parse_xml = parse_xml;
83 parsable_class->get_xml = get_xml;
84 parsable_class->get_namespaces = get_namespaces;
85 parsable_class->element_name = "group";
86 parsable_class->element_namespace = "media";
87 }
88
89 static void
gdata_media_group_init(GDataMediaGroup * self)90 gdata_media_group_init (GDataMediaGroup *self)
91 {
92 self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_MEDIA_GROUP, GDataMediaGroupPrivate);
93 self->priv->restricted_countries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
94 }
95
96 static void
gdata_media_group_dispose(GObject * object)97 gdata_media_group_dispose (GObject *object)
98 {
99 GDataMediaGroupPrivate *priv = GDATA_MEDIA_GROUP (object)->priv;
100
101 if (priv->category != NULL)
102 g_object_unref (priv->category);
103 priv->category = NULL;
104
105 if (priv->credit != NULL)
106 g_object_unref (priv->credit);
107 priv->credit = NULL;
108
109 g_list_free_full (priv->contents, g_object_unref);
110 priv->contents = NULL;
111
112 g_list_free_full (priv->thumbnails, g_object_unref);
113 priv->thumbnails = NULL;
114
115 /* Chain up to the parent class */
116 G_OBJECT_CLASS (gdata_media_group_parent_class)->dispose (object);
117 }
118
119 static void
gdata_media_group_finalize(GObject * object)120 gdata_media_group_finalize (GObject *object)
121 {
122 GDataMediaGroupPrivate *priv = GDATA_MEDIA_GROUP (object)->priv;
123
124 g_strfreev (priv->keywords);
125 g_free (priv->player_uri);
126 g_free (priv->v_chip_rating);
127 g_free (priv->mpaa_rating);
128 g_free (priv->simple_rating);
129 g_hash_table_destroy (priv->restricted_countries);
130 g_free (priv->title);
131 g_free (priv->description);
132
133 /* Chain up to the parent class */
134 G_OBJECT_CLASS (gdata_media_group_parent_class)->finalize (object);
135 }
136
137 static gboolean
parse_xml(GDataParsable * parsable,xmlDoc * doc,xmlNode * node,gpointer user_data,GError ** error)138 parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error)
139 {
140 gboolean success;
141 GDataMediaGroup *self = GDATA_MEDIA_GROUP (parsable);
142
143 if (gdata_parser_is_namespace (node, "http://search.yahoo.com/mrss/") == TRUE) {
144 if (gdata_parser_string_from_element (node, "title", P_NONE, &(self->priv->title), &success, error) == TRUE ||
145 gdata_parser_string_from_element (node, "description", P_NONE, &(self->priv->description), &success, error) == TRUE ||
146 gdata_parser_object_from_element_setter (node, "category", P_REQUIRED, GDATA_TYPE_MEDIA_CATEGORY,
147 gdata_media_group_set_category, self, &success, error) == TRUE ||
148 gdata_parser_object_from_element_setter (node, "content", P_REQUIRED, GDATA_TYPE_MEDIA_CONTENT,
149 _gdata_media_group_add_content, self, &success, error) == TRUE ||
150 gdata_parser_object_from_element_setter (node, "thumbnail", P_REQUIRED, GDATA_TYPE_MEDIA_THUMBNAIL,
151 _gdata_media_group_add_thumbnail, self, &success, error) == TRUE ||
152 gdata_parser_object_from_element (node, "credit", P_REQUIRED | P_NO_DUPES, GDATA_TYPE_MEDIA_CREDIT,
153 &(self->priv->credit), &success, error) == TRUE) {
154 return success;
155 } else if (xmlStrcmp (node->name, (xmlChar*) "keywords") == 0) {
156 /* media:keywords */
157 guint i;
158 xmlChar *text = xmlNodeListGetString (node->doc, node->children, TRUE);
159
160 g_strfreev (self->priv->keywords);
161 if (text == NULL) {
162 self->priv->keywords = NULL;
163 return TRUE;
164 }
165
166 self->priv->keywords = g_strsplit ((gchar*) text, ",", -1);
167 xmlFree (text);
168
169 for (i = 0; self->priv->keywords[i] != NULL; i++) {
170 gchar *comma, *start = self->priv->keywords[i];
171 gchar *end = start + strlen (start);
172
173 /* Strip any whitespace from the ends of the keyword */
174 g_strstrip (start);
175
176 /* Unescape any %2Cs in the keyword to commas in-place */
177 while ((comma = g_strstr_len (start, -1, "%2C")) != NULL) {
178 /* Unescape the comma */
179 *comma = ',';
180
181 /* Move forwards, skipping the comma */
182 comma++;
183 end -= 2;
184
185 /* Shift the remainder of the string downwards */
186 memmove (comma, comma + 2, end - comma);
187 *end = '\0';
188 }
189 }
190 } else if (xmlStrcmp (node->name, (xmlChar*) "player") == 0) {
191 /* media:player */
192 xmlChar *player_uri = xmlGetProp (node, (xmlChar*) "url");
193 g_free (self->priv->player_uri);
194 self->priv->player_uri = (gchar*) player_uri;
195 } else if (xmlStrcmp (node->name, (xmlChar*) "rating") == 0) {
196 /* media:rating */
197 xmlChar *scheme;
198
199 /* The possible schemes are defined here:
200 * • http://video.search.yahoo.com/mrss
201 * • http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_media:rating
202 */
203 scheme = xmlGetProp (node, (xmlChar*) "scheme");
204
205 if (scheme == NULL || xmlStrcmp (scheme, (xmlChar*) "urn:simple") == 0) {
206 /* Options: adult, nonadult */
207 gdata_parser_string_from_element (node, "rating", P_REQUIRED | P_NON_EMPTY, &(self->priv->simple_rating),
208 &success, error);
209 } else if (xmlStrcmp (scheme, (xmlChar*) "urn:mpaa") == 0) {
210 /* Options: g, pg, pg-13, r, nc-17 */
211 gdata_parser_string_from_element (node, "rating", P_REQUIRED | P_NON_EMPTY, &(self->priv->mpaa_rating),
212 &success, error);
213 } else if (xmlStrcmp (scheme, (xmlChar*) "urn:v-chip") == 0) {
214 /* Options: tv-y, tv-y7, tv-y7-fv, tv-g, tv-pg, tv-14, tv-ma */
215 gdata_parser_string_from_element (node, "rating", P_REQUIRED | P_NON_EMPTY, &(self->priv->v_chip_rating),
216 &success, error);
217 } else if (xmlStrcmp (scheme, (xmlChar*) "http://gdata.youtube.com/schemas/2007#mediarating") == 0) {
218 /* No content, but we do get a list of countries. There's nothing like overloading the semantics of XML elements
219 * to brighten up one's day. */
220 xmlChar *countries;
221
222 countries = xmlGetProp (node, (xmlChar*) "country");
223
224 if (countries != NULL) {
225 gchar **country_list, **country;
226
227 /* It's either a comma-separated list of countries, or the value "all" */
228 country_list = g_strsplit ((const gchar*) countries, ",", -1);
229 xmlFree (countries);
230
231 /* Add all the listed countries to the restricted countries table */
232 for (country = country_list; *country != NULL; country++) {
233 g_hash_table_insert (self->priv->restricted_countries, *country, GUINT_TO_POINTER (TRUE));
234 }
235
236 g_free (country_list);
237 } else {
238 /* Assume it's restricted in all countries */
239 g_hash_table_insert (self->priv->restricted_countries, g_strdup ("all"), GUINT_TO_POINTER (TRUE));
240 }
241
242 success = TRUE;
243 } else {
244 /* Error */
245 gdata_parser_error_unknown_property_value (node, "scheme", (gchar*) scheme, error);
246 success = FALSE;
247 }
248
249 xmlFree (scheme);
250
251 return success;
252 } else if (xmlStrcmp (node->name, (xmlChar*) "restriction") == 0) {
253 /* media:restriction */
254 xmlChar *type, *countries, *relationship;
255 gchar **country_list, **country;
256 gboolean relationship_bool;
257
258 /* Check the type property is "country" */
259 type = xmlGetProp (node, (xmlChar*) "type");
260 if (xmlStrcmp (type, (xmlChar*) "country") != 0) {
261 gdata_parser_error_unknown_property_value (node, "type", (gchar*) type, error);
262 xmlFree (type);
263 return FALSE;
264 }
265 xmlFree (type);
266
267 relationship = xmlGetProp (node, (xmlChar*) "relationship");
268 if (xmlStrcmp (relationship, (xmlChar*) "allow") == 0) {
269 relationship_bool = FALSE; /* it's *not* a restricted country */
270 } else if (xmlStrcmp (relationship, (xmlChar*) "deny") == 0) {
271 relationship_bool = TRUE; /* it *is* a restricted country */
272 } else {
273 gdata_parser_error_unknown_property_value (node, "relationship", (gchar*) relationship, error);
274 xmlFree (relationship);
275 return FALSE;
276 }
277 xmlFree (relationship);
278
279 countries = xmlNodeListGetString (doc, node->children, TRUE);
280 country_list = g_strsplit ((const gchar*) countries, " ", -1);
281 xmlFree (countries);
282
283 /* Add "all" to the table, since it's an exception table */
284 g_hash_table_insert (self->priv->restricted_countries, g_strdup ("all"), GUINT_TO_POINTER (!relationship_bool));
285
286 /* Add all the listed countries to the restricted countries table */
287 for (country = country_list; *country != NULL; country++)
288 g_hash_table_insert (self->priv->restricted_countries, *country, GUINT_TO_POINTER (relationship_bool));
289 g_free (country_list);
290 } else {
291 return GDATA_PARSABLE_CLASS (gdata_media_group_parent_class)->parse_xml (parsable, doc, node, user_data, error);
292 }
293 } else {
294 return GDATA_PARSABLE_CLASS (gdata_media_group_parent_class)->parse_xml (parsable, doc, node, user_data, error);
295 }
296
297 return TRUE;
298 }
299
300 static void
get_xml(GDataParsable * parsable,GString * xml_string)301 get_xml (GDataParsable *parsable, GString *xml_string)
302 {
303 GDataMediaGroupPrivate *priv = GDATA_MEDIA_GROUP (parsable)->priv;
304
305 /* Media category */
306 if (priv->category != NULL)
307 _gdata_parsable_get_xml (GDATA_PARSABLE (priv->category), xml_string, FALSE);
308
309 if (priv->title != NULL)
310 gdata_parser_string_append_escaped (xml_string, "<media:title type='plain'>", priv->title, "</media:title>");
311
312 if (priv->description != NULL)
313 gdata_parser_string_append_escaped (xml_string, "<media:description type='plain'>", priv->description, "</media:description>");
314
315 if (priv->keywords != NULL) {
316 guint i;
317
318 g_string_append (xml_string, "<media:keywords>");
319
320 /* Add each keyword to the text content, comma-separated from the previous one */
321 for (i = 0; priv->keywords[i] != NULL; i++) {
322 const gchar *comma, *start = priv->keywords[i];
323
324 /* Delimit the previous keyword */
325 if (i != 0)
326 g_string_append_c (xml_string, ',');
327
328 /* Escape any commas in the keyword to %2C */
329 while ((comma = g_utf8_strchr (start, -1, ',')) != NULL) {
330 /* Copy the span */
331 gchar *span = g_strndup (start, comma - start);
332 gdata_parser_string_append_escaped (xml_string, NULL, span, NULL);
333 g_free (span);
334
335 /* Add an escaped comma */
336 g_string_append (xml_string, "%2C");
337
338 /* Move forwards, skipping the comma */
339 start = comma + 1;
340 }
341
342 /* Append the rest of the string (the entire string if there were no commas) */
343 gdata_parser_string_append_escaped (xml_string, NULL, start, NULL);
344 }
345
346 g_string_append (xml_string, "</media:keywords>");
347 }
348 }
349
350 static void
get_namespaces(GDataParsable * parsable,GHashTable * namespaces)351 get_namespaces (GDataParsable *parsable, GHashTable *namespaces)
352 {
353 g_hash_table_insert (namespaces, (gchar*) "media", (gchar*) "http://search.yahoo.com/mrss/");
354 }
355
356 /**
357 * gdata_media_group_get_title:
358 * @self: a #GDataMediaGroup
359 *
360 * Gets the #GDataMediaGroup:title property.
361 *
362 * Return value: the group's title, or %NULL
363 *
364 * Since: 0.4.0
365 */
366 const gchar *
gdata_media_group_get_title(GDataMediaGroup * self)367 gdata_media_group_get_title (GDataMediaGroup *self)
368 {
369 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
370 return self->priv->title;
371 }
372
373 /**
374 * gdata_media_group_set_title:
375 * @self: a #GDataMediaGroup
376 * @title: (allow-none): the group's new title, or %NULL
377 *
378 * Sets the #GDataMediaGroup:title property to @title.
379 *
380 * Set @title to %NULL to unset the property.
381 *
382 * Since: 0.4.0
383 */
384 void
gdata_media_group_set_title(GDataMediaGroup * self,const gchar * title)385 gdata_media_group_set_title (GDataMediaGroup *self, const gchar *title)
386 {
387 g_return_if_fail (GDATA_IS_MEDIA_GROUP (self));
388 g_free (self->priv->title);
389 self->priv->title = g_strdup (title);
390 }
391
392 /**
393 * gdata_media_group_get_description:
394 * @self: a #GDataMediaGroup
395 *
396 * Gets the #GDataMediaGroup:description property.
397 *
398 * Return value: the group's description, or %NULL
399 *
400 * Since: 0.4.0
401 */
402 const gchar *
gdata_media_group_get_description(GDataMediaGroup * self)403 gdata_media_group_get_description (GDataMediaGroup *self)
404 {
405 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
406 return self->priv->description;
407 }
408
409 /**
410 * gdata_media_group_set_description:
411 * @self: a #GDataMediaGroup
412 * @description: (allow-none): the group's new description, or %NULL
413 *
414 * Sets the #GDataMediaGroup:description property to @description.
415 *
416 * Set @description to %NULL to unset the property.
417 *
418 * Since: 0.4.0
419 */
420 void
gdata_media_group_set_description(GDataMediaGroup * self,const gchar * description)421 gdata_media_group_set_description (GDataMediaGroup *self, const gchar *description)
422 {
423 g_return_if_fail (GDATA_IS_MEDIA_GROUP (self));
424 g_free (self->priv->description);
425 self->priv->description = g_strdup (description);
426 }
427
428 /**
429 * gdata_media_group_get_keywords:
430 * @self: a #GDataMediaGroup
431 *
432 * Gets the #GDataMediaGroup:keywords property.
433 *
434 * Return value: (array zero-terminated=1): a %NULL-terminated array of the group's keywords, or %NULL
435 *
436 * Since: 0.4.0
437 */
438 const gchar * const *
gdata_media_group_get_keywords(GDataMediaGroup * self)439 gdata_media_group_get_keywords (GDataMediaGroup *self)
440 {
441 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
442 return (const gchar * const *) self->priv->keywords;
443 }
444
445 /**
446 * gdata_media_group_set_keywords:
447 * @self: a #GDataMediaGroup
448 * @keywords: (array zero-terminated=1) (allow-none): a %NULL-terminated array of the group's new keywords, or %NULL
449 *
450 * Sets the #GDataMediaGroup:keywords property to @keywords.
451 *
452 * Set @keywords to %NULL to unset the property.
453 *
454 * Since: 0.4.0
455 */
456 void
gdata_media_group_set_keywords(GDataMediaGroup * self,const gchar * const * keywords)457 gdata_media_group_set_keywords (GDataMediaGroup *self, const gchar * const *keywords)
458 {
459 g_return_if_fail (GDATA_IS_MEDIA_GROUP (self));
460 g_strfreev (self->priv->keywords);
461 self->priv->keywords = g_strdupv ((gchar**) keywords);
462 }
463
464 /**
465 * gdata_media_group_get_category:
466 * @self: a #GDataMediaGroup
467 *
468 * Gets the #GDataMediaGroup:category property.
469 *
470 * Return value: a #GDataMediaCategory giving the group's category, or %NULL
471 */
472 GDataMediaCategory *
gdata_media_group_get_category(GDataMediaGroup * self)473 gdata_media_group_get_category (GDataMediaGroup *self)
474 {
475 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
476 return self->priv->category;
477 }
478
479 /**
480 * gdata_media_group_set_category:
481 * @self: a #GDataMediaGroup
482 * @category: (allow-none): a new #GDataMediaCategory, or %NULL
483 *
484 * Sets the #GDataMediaGroup:category property to @category, and increments its reference count.
485 */
486 void
gdata_media_group_set_category(GDataMediaGroup * self,GDataMediaCategory * category)487 gdata_media_group_set_category (GDataMediaGroup *self, GDataMediaCategory *category)
488 {
489 g_return_if_fail (GDATA_IS_MEDIA_GROUP (self));
490 g_return_if_fail (category == NULL || GDATA_IS_MEDIA_CATEGORY (category));
491
492 if (self->priv->category != NULL)
493 g_object_unref (self->priv->category);
494 self->priv->category = (category == NULL) ? NULL : g_object_ref (category);
495 }
496
497 static gint
content_compare_cb(const GDataMediaContent * content,const gchar * type)498 content_compare_cb (const GDataMediaContent *content, const gchar *type)
499 {
500 return strcmp (gdata_media_content_get_content_type ((GDataMediaContent*) content), type);
501 }
502
503 /**
504 * gdata_media_group_look_up_content:
505 * @self: a #GDataMediaGroup
506 * @type: the MIME type of the content desired
507 *
508 * Looks up a #GDataMediaContent from the group with the given MIME type. The group's list of contents is
509 * a list of URIs to various formats of the group content itself, such as the SWF URI or RTSP stream for a video.
510 *
511 * Return value: (transfer none): a #GDataMediaContent matching @type, or %NULL
512 */
513 GDataMediaContent *
gdata_media_group_look_up_content(GDataMediaGroup * self,const gchar * type)514 gdata_media_group_look_up_content (GDataMediaGroup *self, const gchar *type)
515 {
516 GList *element;
517
518 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
519 g_return_val_if_fail (type != NULL, NULL);
520
521 /* TODO: If type is required, and is unique, the contents can be stored in a hash table rather than a linked list */
522 element = g_list_find_custom (self->priv->contents, type, (GCompareFunc) content_compare_cb);
523 if (element == NULL)
524 return NULL;
525 return GDATA_MEDIA_CONTENT (element->data);
526 }
527
528 /**
529 * gdata_media_group_get_contents:
530 * @self: a #GDataMediaGroup
531 *
532 * Returns a list of #GDataMediaContents, giving the content enclosed by the group.
533 *
534 * Return value: (element-type GData.MediaContent) (transfer none): a #GList of #GDataMediaContents, or %NULL
535 */
536 GList *
gdata_media_group_get_contents(GDataMediaGroup * self)537 gdata_media_group_get_contents (GDataMediaGroup *self)
538 {
539 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
540 return self->priv->contents;
541 }
542
543 void
_gdata_media_group_add_content(GDataMediaGroup * self,GDataMediaContent * content)544 _gdata_media_group_add_content (GDataMediaGroup *self, GDataMediaContent *content)
545 {
546 g_return_if_fail (GDATA_IS_MEDIA_GROUP (self));
547 g_return_if_fail (GDATA_IS_MEDIA_CONTENT (content));
548 self->priv->contents = g_list_prepend (self->priv->contents, g_object_ref (content));
549 }
550
551 /**
552 * gdata_media_group_get_credit:
553 * @self: a #GDataMediaGroup
554 *
555 * Gets the #GDataMediaGroup:credit property.
556 *
557 * Return value: a #GDataMediaCredit giving information on whom to credit for the media group, or %NULL
558 */
559 GDataMediaCredit *
gdata_media_group_get_credit(GDataMediaGroup * self)560 gdata_media_group_get_credit (GDataMediaGroup *self)
561 {
562 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
563 return self->priv->credit;
564 }
565
566 void
_gdata_media_group_set_credit(GDataMediaGroup * self,GDataMediaCredit * credit)567 _gdata_media_group_set_credit (GDataMediaGroup *self, GDataMediaCredit *credit)
568 {
569 g_return_if_fail (GDATA_IS_MEDIA_GROUP (self));
570 g_return_if_fail (credit == NULL ||GDATA_IS_MEDIA_CREDIT (credit));
571
572 if (self->priv->credit != NULL)
573 g_object_unref (self->priv->credit);
574 self->priv->credit = g_object_ref (credit);
575 }
576
577 /**
578 * gdata_media_group_get_media_group:
579 * @self: a #GDataMediaGroup
580 *
581 * Gets the #GDataMediaGroup:player-uri property.
582 *
583 * Return value: a URI where the media group is playable in a web browser, or %NULL
584 */
585 const gchar *
gdata_media_group_get_player_uri(GDataMediaGroup * self)586 gdata_media_group_get_player_uri (GDataMediaGroup *self)
587 {
588 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
589 return self->priv->player_uri;
590 }
591
592 /**
593 * gdata_media_group_is_restricted_in_country:
594 * @self: a #GDataMediaGroup
595 * @country: an ISO 3166 two-letter country code to check
596 *
597 * Checks whether viewing of the media is restricted in @country, either by its content rating, or by the request of the producer.
598 * The return value from this function is purely informational, and no obligation is assumed.
599 *
600 * Return value: %TRUE if the media is restricted in @country, %FALSE otherwise
601 */
602 gboolean
gdata_media_group_is_restricted_in_country(GDataMediaGroup * self,const gchar * country)603 gdata_media_group_is_restricted_in_country (GDataMediaGroup *self, const gchar *country)
604 {
605 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), FALSE);
606 g_return_val_if_fail (country != NULL && *country != '\0', FALSE);
607
608 if (GPOINTER_TO_UINT (g_hash_table_lookup (self->priv->restricted_countries, country)) == TRUE)
609 return TRUE;
610
611 return GPOINTER_TO_UINT (g_hash_table_lookup (self->priv->restricted_countries, "all"));
612 }
613
614 /**
615 * gdata_media_group_get_media_rating:
616 * @self: a #GDataMediaGroup
617 * @rating_type: the type of rating to retrieve
618 *
619 * 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.
620 * The valid values for @rating_type are: <code class="literal">simple</code>, <code class="literal">mpaa</code> and
621 * <code class="literal">v-chip</code>.
622 *
623 * The rating values returned for each of these rating types are string as defined in the
624 * <ulink type="http" url="http://code.google.com/apis/youtube/2.0/reference.html#youtube_data_api_tag_media:rating">YouTube documentation</ulink> and
625 * <ulink type="http" url="http://video.search.yahoo.com/mrss">MRSS specification</ulink>.
626 *
627 * Return value: rating for the given rating type, or %NULL if the media has no rating for that type (or the type is invalid)
628 */
629 const gchar *
gdata_media_group_get_media_rating(GDataMediaGroup * self,const gchar * rating_type)630 gdata_media_group_get_media_rating (GDataMediaGroup *self, const gchar *rating_type)
631 {
632 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
633 g_return_val_if_fail (rating_type != NULL && *rating_type != '\0', NULL);
634
635 if (strcmp (rating_type, "simple") == 0) {
636 return self->priv->simple_rating;
637 } else if (strcmp (rating_type, "mpaa") == 0) {
638 return self->priv->mpaa_rating;
639 } else if (strcmp (rating_type, "v-chip") == 0) {
640 return self->priv->v_chip_rating;
641 }
642
643 return NULL;
644 }
645
646 /**
647 * gdata_media_group_get_thumbnails:
648 * @self: a #GDataMediaGroup
649 *
650 * Gets a list of the thumbnails available for the group.
651 *
652 * Return value: (element-type GData.MediaThumbnail) (transfer none): a #GList of #GDataMediaThumbnails, or %NULL
653 */
654 GList *
gdata_media_group_get_thumbnails(GDataMediaGroup * self)655 gdata_media_group_get_thumbnails (GDataMediaGroup *self)
656 {
657 g_return_val_if_fail (GDATA_IS_MEDIA_GROUP (self), NULL);
658 return self->priv->thumbnails;
659 }
660
661 void
_gdata_media_group_add_thumbnail(GDataMediaGroup * self,GDataMediaThumbnail * thumbnail)662 _gdata_media_group_add_thumbnail (GDataMediaGroup *self, GDataMediaThumbnail *thumbnail)
663 {
664 g_return_if_fail (GDATA_IS_MEDIA_GROUP (self));
665 g_return_if_fail (GDATA_IS_MEDIA_THUMBNAIL (thumbnail));
666 self->priv->thumbnails = g_list_prepend (self->priv->thumbnails, g_object_ref (thumbnail));
667 }
668