/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */ /* * GData Client * Copyright (C) Richard Schwarting 2009 * Copyright (C) Philip Withnall 2009–2010 * * 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 . */ /** * SECTION:gdata-picasaweb-album * @short_description: GData PicasaWeb album object * @stability: Stable * @include: gdata/services/picasaweb/gdata-picasaweb-album.h * * #GDataPicasaWebAlbum is a subclass of #GDataEntry to represent an album from Google PicasaWeb. * * For more details of Google PicasaWeb's GData API, see the * online documentation. * * * Getting Basic Album Data * * GDataFeed *album_feed; * GList *album_entries; * * /* Query for a feed of GDataPicasaWebAlbums owned by user "libgdata.picasaweb" */ * album_feed = gdata_picasaweb_service_query_all_albums (service, NULL, "libgdata.picasaweb", NULL, NULL, NULL, NULL); * * /* Get a list of GDataPicasaWebAlbums from the query's feed */ * for (album_entries = gdata_feed_get_entries (album_feed); album_entries != NULL; album_entries = album_entries->next) { * GDataPicasaWebAlbum *album; * guint num_photos; * const gchar *owner_nickname, *title, *summary; * gint64 timestamp; * GList *thumbnails; * * album = GDATA_PICASAWEB_ALBUM (album_entries->data); * * /* Get various bits of information about the album */ * num_photos = gdata_picasaweb_album_get_num_photos (album); * owner_nickname = gdata_picasaweb_album_get_nickname (album); * title = gdata_entry_get_title (GDATA_ENTRY (album)); * summary = gdata_entry_get_summary (GDATA_ENTRY (album)); * /* Get the day the album was shot on or, if not set, when it was uploaded. This is in milliseconds since the epoch. */ * timestamp = gdata_picasaweb_album_get_timestamp (album); * * for (thumbnails = gdata_picasaweb_album_get_thumbnails (album); thumbnails != NULL; thumbnails = thumbnails->next) { * GDataMediaThumbnail *thumbnail; * GDataDownloadStream *download_stream; * GdkPixbuf *pixbuf; * * thumbnail = GDATA_MEDIA_THUMBNAIL (thumbnails->data); * /* Do something fun with the thumbnails, like download and display them. We could just as easily download them into * * files using g_file_create() and g_output_stream_splice(), rather than create GdkPixbufs directly from them. * * Note that this is a blocking operation. */ * download_stream = gdata_media_thumbnail_download (thumbnail, GDATA_SERVICE (service), NULL, NULL); * pixbuf = gdk_pixbuf_new_from_stream (G_INPUT_STREAM (download_stream), NULL, NULL); * g_object_unref (download_stream); * /* ... */ * g_object_unref (pixbuf); * } * * /* Do something worthwhile with your album data */ * } * * g_object_unref (album_feed); * * * * Since: 0.4.0 */ /* TODO: support the album cover/icon ? I think this is already done with the thumbnails, but we don't set it yet :( */ #include #include #include #include #include #include "gdata-picasaweb-album.h" #include "gdata-private.h" #include "gdata-service.h" #include "gdata-parsable.h" #include "gdata-parser.h" #include "gdata-types.h" #include "media/gdata-media-group.h" #include "gdata-picasaweb-enums.h" #include "georss/gdata-georss-where.h" static GObject *gdata_picasaweb_album_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params); static void gdata_picasaweb_album_dispose (GObject *object); static void gdata_picasaweb_album_finalize (GObject *object); static void gdata_picasaweb_album_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); static void gdata_picasaweb_album_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void get_xml (GDataParsable *parsable, GString *xml_string); static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error); static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces); struct _GDataPicasaWebAlbumPrivate { gchar *album_id; gchar *user; gchar *nickname; gint64 edited; gchar *location; GDataPicasaWebVisibility visibility; gint64 timestamp; /* in milliseconds! */ guint num_photos; guint num_photos_remaining; glong bytes_used; gboolean is_commenting_enabled; guint comment_count; /* media:group */ GDataMediaGroup *media_group; /* georss:where */ GDataGeoRSSWhere *georss_where; }; enum { PROP_USER = 1, PROP_NICKNAME, PROP_EDITED, PROP_LOCATION, PROP_VISIBILITY, PROP_TIMESTAMP, PROP_NUM_PHOTOS, PROP_NUM_PHOTOS_REMAINING, PROP_BYTES_USED, PROP_IS_COMMENTING_ENABLED, PROP_COMMENT_COUNT, PROP_TAGS, PROP_LATITUDE, PROP_LONGITUDE, PROP_ALBUM_ID }; G_DEFINE_TYPE (GDataPicasaWebAlbum, gdata_picasaweb_album, GDATA_TYPE_ENTRY) static void gdata_picasaweb_album_class_init (GDataPicasaWebAlbumClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GDataParsableClass *parsable_class = GDATA_PARSABLE_CLASS (klass); GDataEntryClass *entry_class = GDATA_ENTRY_CLASS (klass); g_type_class_add_private (klass, sizeof (GDataPicasaWebAlbumPrivate)); gobject_class->constructor = gdata_picasaweb_album_constructor; gobject_class->get_property = gdata_picasaweb_album_get_property; gobject_class->set_property = gdata_picasaweb_album_set_property; gobject_class->dispose = gdata_picasaweb_album_dispose; gobject_class->finalize = gdata_picasaweb_album_finalize; parsable_class->parse_xml = parse_xml; parsable_class->get_xml = get_xml; parsable_class->get_namespaces = get_namespaces; entry_class->kind_term = "http://schemas.google.com/photos/2007#album"; /** * GDataPicasaWebAlbum:album-id: * * The ID of the album. This is a substring of the ID returned by gdata_entry_get_id() for #GDataPicasaWebAlbums; for example, * if gdata_entry_get_id() returned "http://picasaweb.google.com/data/entry/user/libgdata.picasaweb/albumid/5328889949261497249" for a * particular #GDataPicasaWebAlbum, the #GDataPicasaWebAlbum:album-id property would be "5328889949261497249". * * For more information, see the * gphoto specification. * * Since: 0.7.0 */ g_object_class_install_property (gobject_class, PROP_ALBUM_ID, g_param_spec_string ("album-id", "Album ID", "The ID of the album.", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:user: * * The username of the album owner. * * For more information, see the * gphoto specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_USER, g_param_spec_string ("user", "User", "The username of the album owner.", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:nickname: * * The user's nickname. This is a user-specified value that should be used when referring to the user by name. * * For more information, see the * gphoto specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_NICKNAME, g_param_spec_string ("nickname", "Nickname", "The user's nickname.", NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:edited: * * The time this album was last edited. If the album has not been edited yet, the content indicates the time it was created. * * For more information, see the * Atom Publishing Protocol specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_EDITED, g_param_spec_int64 ("edited", "Edited", "The time this album was last edited.", -1, G_MAXINT64, -1, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:location: * * The user-specified location associated with the album. A place name. * * For more information, see the * gphoto specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_LOCATION, g_param_spec_string ("location", "Location", "The user-specified location associated with the album.", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:visibility: * * The visibility (or access rights) of the album. * * For more information, see the * gphoto specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_VISIBILITY, g_param_spec_enum ("visibility", "Visibility", "The visibility (or access rights) of the album.", GDATA_TYPE_PICASAWEB_VISIBILITY, GDATA_PICASAWEB_PRIVATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:timestamp: * * The timestamp of when the album occurred, settable by the user. This a UNIX timestamp in milliseconds (not seconds) since the epoch. * * For more information, see the * gphoto specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_TIMESTAMP, g_param_spec_int64 ("timestamp", "Timestamp", "The timestamp of when the album occurred, settable by the user.", -1, G_MAXINT64, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /* TODO: Change to photo-count? */ /** * GDataPicasaWebAlbum:num-photos: * * The number of photos and videos in the album. * * For more information, see the * gphoto specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_NUM_PHOTOS, g_param_spec_uint ("num-photos", "Number of photos", "The number of photos and videos in the album.", 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /* TODO: Change to remaining-photos-count? */ /** * GDataPicasaWebAlbum:num-photos-remaining: * * The number of photos and videos that can still be uploaded to this album. * This doesn't account for quota, just a hardcoded maximum number per album set by Google. * * For more information, see the * gphoto specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_NUM_PHOTOS_REMAINING, g_param_spec_uint ("num-photos-remaining", "Number of photo spaces remaining", "The number of files spaces still free for uploads.", 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:bytes-used: * * The number of bytes consumed by this album and its contents. Note that this is only set if the authenticated user is the owner of the * album; it's otherwise -1. * * For more information, see the * gphoto specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_BYTES_USED, g_param_spec_long ("bytes-used", "Number of bytes used", "The number of bytes consumed by this album and its contents.", -1, G_MAXLONG, -1, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:commenting-enabled: * * Whether commenting is enabled for this album. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_IS_COMMENTING_ENABLED, g_param_spec_boolean ("is-commenting-enabled", "Commenting enabled?", "Whether commenting is enabled for this album.", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:comment-count: * * The number of comments on the album. * * For more information, see the * gphoto specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_COMMENT_COUNT, g_param_spec_uint ("comment-count", "Comment count", "The number of comments on the album.", 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:tags: * * A %NULL-terminated array of tags associated with the album; all the tags associated with the individual photos in the album. * * For more information, see the * Media RSS specification. * * Since: 0.4.0 */ g_object_class_install_property (gobject_class, PROP_TAGS, g_param_spec_boxed ("tags", "Tags", "A NULL-terminated array of tags associated with the album", G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:latitude: * * The location as a latitude coordinate associated with this album. Valid latitudes range from -90.0 * to 90.0 inclusive. * * For more information, see the * GeoRSS specification. * * Since: 0.5.0 */ g_object_class_install_property (gobject_class, PROP_LATITUDE, g_param_spec_double ("latitude", "Latitude", "The location as a latitude coordinate associated with this album.", -90.0, 90.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); /** * GDataPicasaWebAlbum:longitude: * * The location as a longitude coordinate associated with this album. Valid longitudes range from -180.0 * to 180.0 inclusive. * * For more information, see the * GeoRSS specification. * * Since: 0.5.0 */ g_object_class_install_property (gobject_class, PROP_LONGITUDE, g_param_spec_double ("longitude", "Longitude", "The location as a longitude coordinate associated with this album.", -180.0, 180.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } static void notify_title_cb (GDataPicasaWebAlbum *self, GParamSpec *pspec, gpointer user_data) { /* Update our media:group title */ if (self->priv->media_group != NULL) gdata_media_group_set_title (self->priv->media_group, gdata_entry_get_title (GDATA_ENTRY (self))); } static void notify_summary_cb (GDataPicasaWebAlbum *self, GParamSpec *pspec, gpointer user_data) { /* Update our media:group description */ if (self->priv->media_group != NULL) gdata_media_group_set_description (self->priv->media_group, gdata_entry_get_summary (GDATA_ENTRY (self))); } static void notify_visibility_cb (GDataPicasaWebAlbum *self, GParamSpec *pspec, gpointer user_data); static void notify_rights_cb (GDataPicasaWebAlbum *self, GParamSpec *pspec, gpointer user_data) { const gchar *rights = gdata_entry_get_rights (GDATA_ENTRY (self)); /* Update our gphoto:visibility */ g_signal_handlers_block_by_func (self, notify_visibility_cb, NULL); if (rights == NULL || strcmp (rights, "public") == 0) { gdata_picasaweb_album_set_visibility (self, GDATA_PICASAWEB_PUBLIC); } else if (strcmp (rights, "private") == 0) { gdata_picasaweb_album_set_visibility (self, GDATA_PICASAWEB_PRIVATE); } else { /* Print out a warning and leave the visibility as it is */ g_warning ("Unknown or value: %s", rights); } g_signal_handlers_unblock_by_func (self, notify_visibility_cb, NULL); } static void notify_visibility_cb (GDataPicasaWebAlbum *self, GParamSpec *pspec, gpointer user_data) { /* Update our GDataEntry's atom:rights */ g_signal_handlers_block_by_func (self, notify_rights_cb, NULL); switch (self->priv->visibility) { case GDATA_PICASAWEB_PUBLIC: gdata_entry_set_rights (GDATA_ENTRY (self), "public"); break; case GDATA_PICASAWEB_PRIVATE: gdata_entry_set_rights (GDATA_ENTRY (self), "private"); break; default: g_assert_not_reached (); } g_signal_handlers_unblock_by_func (self, notify_rights_cb, NULL); } static void gdata_picasaweb_album_init (GDataPicasaWebAlbum *self) { self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, GDATA_TYPE_PICASAWEB_ALBUM, GDataPicasaWebAlbumPrivate); self->priv->media_group = g_object_new (GDATA_TYPE_MEDIA_GROUP, NULL); self->priv->georss_where = g_object_new (GDATA_TYPE_GEORSS_WHERE, NULL); self->priv->edited = -1; self->priv->timestamp = -1; /* Set the initial visibility */ self->priv->visibility = GDATA_PICASAWEB_PRIVATE; gdata_entry_set_rights (GDATA_ENTRY (self), "private"); /* Connect to the notify::title signal from GDataEntry so our media:group title can be kept in sync * (the title of an album is duplicated in atom:title and media:group/media:title) */ g_signal_connect (GDATA_ENTRY (self), "notify::title", G_CALLBACK (notify_title_cb), NULL); /* Connect to the notify::description signal from GDataEntry so our media:group description can be kept in sync * (the description of an album is duplicated in atom:summary and media:group/media:description) */ g_signal_connect (GDATA_ENTRY (self), "notify::summary", G_CALLBACK (notify_summary_cb), NULL); /* Connect to the notify::rights signal from GDataEntry so our gphoto:visibility can be kept in sync (and vice-versa) * (visibility settings are duplicated in atom:rights and gphoto:visibility) */ g_signal_connect (GDATA_ENTRY (self), "notify::rights", G_CALLBACK (notify_rights_cb), NULL); g_signal_connect (self, "notify::visibility", G_CALLBACK (notify_visibility_cb), NULL); } static GObject * gdata_picasaweb_album_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params) { GObject *object; /* Chain up to the parent class */ object = G_OBJECT_CLASS (gdata_picasaweb_album_parent_class)->constructor (type, n_construct_params, construct_params); if (_gdata_parsable_is_constructed_from_xml (GDATA_PARSABLE (object)) == FALSE) { GDataPicasaWebAlbumPrivate *priv = GDATA_PICASAWEB_ALBUM (object)->priv; GTimeVal time_val; /* Set the edited and timestamp properties to the current time (creation time). bgo#599140 * We don't do this in *_init() since that would cause setting it from parse_xml() to fail (duplicate element). */ g_get_current_time (&time_val); priv->timestamp = (gint64) time_val.tv_sec * 1000; priv->edited = time_val.tv_sec; } return object; } static void gdata_picasaweb_album_dispose (GObject *object) { GDataPicasaWebAlbumPrivate *priv = GDATA_PICASAWEB_ALBUM (object)->priv; if (priv->media_group != NULL) g_object_unref (priv->media_group); priv->media_group = NULL; if (priv->georss_where != NULL) g_object_unref (priv->georss_where); priv->georss_where = NULL; /* Chain up to the parent class */ G_OBJECT_CLASS (gdata_picasaweb_album_parent_class)->dispose (object); } static void gdata_picasaweb_album_finalize (GObject *object) { GDataPicasaWebAlbumPrivate *priv = GDATA_PICASAWEB_ALBUM (object)->priv; g_free (priv->album_id); g_free (priv->user); g_free (priv->nickname); g_free (priv->location); /* Chain up to the parent class */ G_OBJECT_CLASS (gdata_picasaweb_album_parent_class)->finalize (object); } static void gdata_picasaweb_album_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { GDataPicasaWebAlbumPrivate *priv = GDATA_PICASAWEB_ALBUM (object)->priv; switch (property_id) { case PROP_ALBUM_ID: g_value_set_string (value, priv->album_id); break; case PROP_USER: g_value_set_string (value, priv->user); break; case PROP_NICKNAME: g_value_set_string (value, priv->nickname); break; case PROP_EDITED: g_value_set_int64 (value, priv->edited); break; case PROP_LOCATION: g_value_set_string (value, priv->location); break; case PROP_VISIBILITY: g_value_set_enum (value, priv->visibility); break; case PROP_TIMESTAMP: g_value_set_int64 (value, priv->timestamp); break; case PROP_NUM_PHOTOS: g_value_set_uint (value, priv->num_photos); break; case PROP_NUM_PHOTOS_REMAINING: g_value_set_uint (value, priv->num_photos_remaining); break; case PROP_BYTES_USED: g_value_set_long (value, priv->bytes_used); break; case PROP_IS_COMMENTING_ENABLED: g_value_set_boolean (value, priv->is_commenting_enabled); break; case PROP_COMMENT_COUNT: g_value_set_uint (value, priv->comment_count); break; case PROP_TAGS: g_value_set_boxed (value, gdata_media_group_get_keywords (priv->media_group)); break; case PROP_LATITUDE: g_value_set_double (value, gdata_georss_where_get_latitude (priv->georss_where)); break; case PROP_LONGITUDE: g_value_set_double (value, gdata_georss_where_get_longitude (priv->georss_where)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void gdata_picasaweb_album_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { GDataPicasaWebAlbum *self = GDATA_PICASAWEB_ALBUM (object); switch (property_id) { case PROP_ALBUM_ID: /* Construct only */ g_free (self->priv->album_id); self->priv->album_id = g_value_dup_string (value); break; case PROP_LOCATION: gdata_picasaweb_album_set_location (self, g_value_get_string (value)); break; case PROP_VISIBILITY: gdata_picasaweb_album_set_visibility (self, g_value_get_enum (value)); break; case PROP_TIMESTAMP: gdata_picasaweb_album_set_timestamp (self, g_value_get_int64 (value)); break; case PROP_IS_COMMENTING_ENABLED: gdata_picasaweb_album_set_is_commenting_enabled (self, g_value_get_boolean (value)); break; case PROP_TAGS: gdata_picasaweb_album_set_tags (self, g_value_get_boxed (value)); break; case PROP_LATITUDE: gdata_picasaweb_album_set_coordinates (self, g_value_get_double (value), gdata_georss_where_get_longitude (self->priv->georss_where)); break; case PROP_LONGITUDE: gdata_picasaweb_album_set_coordinates (self, gdata_georss_where_get_latitude (self->priv->georss_where), g_value_get_double (value)); break; default: /* We don't have any other property... */ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static gboolean parse_xml (GDataParsable *parsable, xmlDoc *doc, xmlNode *node, gpointer user_data, GError **error) { gboolean success; GDataPicasaWebAlbum *self = GDATA_PICASAWEB_ALBUM (parsable); /* TODO: media:group should also be P_NO_DUPES, but we can't, as priv->media_group has to be pre-populated * in order for things like gdata_picasaweb_album_get_tags() to work. */ if (gdata_parser_is_namespace (node, "http://www.w3.org/2007/app") == TRUE && gdata_parser_int64_time_from_element (node, "edited", P_REQUIRED | P_NO_DUPES, &(self->priv->edited), &success, error) == TRUE) { return success; } else if (gdata_parser_is_namespace (node, "http://search.yahoo.com/mrss/") == TRUE && gdata_parser_object_from_element (node, "group", P_REQUIRED, GDATA_TYPE_MEDIA_GROUP, &(self->priv->media_group), &success, error) == TRUE) { return success; } else if (gdata_parser_is_namespace (node, "http://www.georss.org/georss") == TRUE && gdata_parser_object_from_element (node, "where", P_REQUIRED, GDATA_TYPE_GEORSS_WHERE, &(self->priv->georss_where), &success, error) == TRUE) { return success; } else if (gdata_parser_is_namespace (node, "http://schemas.google.com/photos/2007") == TRUE) { if (gdata_parser_string_from_element (node, "user", P_REQUIRED | P_NON_EMPTY, &(self->priv->user), &success, error) == TRUE || gdata_parser_string_from_element (node, "nickname", P_REQUIRED | P_NON_EMPTY, &(self->priv->nickname), &success, error) == TRUE || gdata_parser_string_from_element (node, "location", P_NONE, &(self->priv->location), &success, error) == TRUE || gdata_parser_string_from_element (node, "id", P_REQUIRED | P_NON_EMPTY | P_NO_DUPES, &(self->priv->album_id), &success, error) == TRUE) { return success; } else if (xmlStrcmp (node->name, (xmlChar*) "access") == 0) { /* gphoto:access */ xmlChar *access_level = xmlNodeListGetString (doc, node->children, TRUE); if (xmlStrcmp (access_level, (xmlChar*) "public") == 0) { gdata_picasaweb_album_set_visibility (self, GDATA_PICASAWEB_PUBLIC); } else if (xmlStrcmp (access_level, (xmlChar*) "private") == 0 || xmlStrcmp (access_level, (xmlChar*) "protected") == 0) { gdata_picasaweb_album_set_visibility (self, GDATA_PICASAWEB_PRIVATE); } else { gdata_parser_error_unknown_content (node, (gchar*) access_level, error); xmlFree (access_level); return FALSE; } xmlFree (access_level); } else if (xmlStrcmp (node->name, (xmlChar*) "timestamp") == 0) { /* gphoto:timestamp */ xmlChar *timestamp_str; guint64 milliseconds; timestamp_str = xmlNodeListGetString (doc, node->children, TRUE); milliseconds = g_ascii_strtoull ((gchar*) timestamp_str, NULL, 10); xmlFree (timestamp_str); gdata_picasaweb_album_set_timestamp (self, (gint64) milliseconds); } else if (xmlStrcmp (node->name, (xmlChar*) "numphotos") == 0) { /* gphoto:numphotos */ xmlChar *num_photos = xmlNodeListGetString (doc, node->children, TRUE); if (num_photos == NULL || *num_photos == '\0') { xmlFree (num_photos); return gdata_parser_error_required_content_missing (node, error); } self->priv->num_photos = g_ascii_strtoull ((char*) num_photos, NULL, 10); xmlFree (num_photos); } else if (xmlStrcmp (node->name, (xmlChar*) "numphotosremaining") == 0) { /* gphoto:numphotosremaining */ xmlChar *num_photos_remaining = xmlNodeListGetString (doc, node->children, TRUE); if (num_photos_remaining == NULL || *num_photos_remaining == '\0') { xmlFree (num_photos_remaining); return gdata_parser_error_required_content_missing (node, error); } self->priv->num_photos_remaining = g_ascii_strtoull ((char*) num_photos_remaining, NULL, 10); xmlFree (num_photos_remaining); } else if (xmlStrcmp (node->name, (xmlChar*) "bytesUsed") == 0) { /* gphoto:bytesUsed */ xmlChar *bytes_used = xmlNodeListGetString (doc, node->children, TRUE); if (bytes_used == NULL || *bytes_used == '\0') { xmlFree (bytes_used); return gdata_parser_error_required_content_missing (node, error); } self->priv->bytes_used = g_ascii_strtoll ((char*) bytes_used, NULL, 10); xmlFree (bytes_used); } else if (xmlStrcmp (node->name, (xmlChar*) "commentingEnabled") == 0) { /* gphoto:commentingEnabled */ xmlChar *commenting_enabled = xmlNodeListGetString (doc, node->children, TRUE); if (commenting_enabled == NULL || *commenting_enabled == '\0') { xmlFree (commenting_enabled); return gdata_parser_error_required_content_missing (node, error); } gdata_picasaweb_album_set_is_commenting_enabled (self, (xmlStrcmp (commenting_enabled, (xmlChar*) "true") == 0) ? TRUE : FALSE); xmlFree (commenting_enabled); } else if (xmlStrcmp (node->name, (xmlChar*) "commentCount") == 0) { /* gphoto:commentCount */ xmlChar *comment_count = xmlNodeListGetString (doc, node->children, TRUE); if (comment_count == NULL || *comment_count == '\0') { xmlFree (comment_count); return gdata_parser_error_required_content_missing (node, error); } self->priv->comment_count = g_ascii_strtoull ((char*) comment_count, NULL, 10); xmlFree (comment_count); } else { return GDATA_PARSABLE_CLASS (gdata_picasaweb_album_parent_class)->parse_xml (parsable, doc, node, user_data, error); } } else { return GDATA_PARSABLE_CLASS (gdata_picasaweb_album_parent_class)->parse_xml (parsable, doc, node, user_data, error); } return TRUE; } static void get_xml (GDataParsable *parsable, GString *xml_string) { GDataPicasaWebAlbumPrivate *priv = GDATA_PICASAWEB_ALBUM (parsable)->priv; /* Chain up to the parent class */ GDATA_PARSABLE_CLASS (gdata_picasaweb_album_parent_class)->get_xml (parsable, xml_string); /* Add all the album-specific XML */ if (priv->album_id != NULL) gdata_parser_string_append_escaped (xml_string, "", priv->album_id, ""); if (priv->location != NULL) gdata_parser_string_append_escaped (xml_string, "", priv->location, ""); switch (priv->visibility) { case GDATA_PICASAWEB_PUBLIC: g_string_append (xml_string, "public"); break; case GDATA_PICASAWEB_PRIVATE: g_string_append (xml_string, "private"); break; default: g_assert_not_reached (); } if (priv->timestamp != -1) { /* in milliseconds */ g_string_append_printf (xml_string, "%" G_GINT64_FORMAT "", priv->timestamp); } if (priv->is_commenting_enabled == FALSE) g_string_append (xml_string, "false"); else g_string_append (xml_string, "true"); /* media:group */ _gdata_parsable_get_xml (GDATA_PARSABLE (priv->media_group), xml_string, FALSE); /* georss:where */ if (priv->georss_where != NULL && gdata_georss_where_get_latitude (priv->georss_where) != G_MAXDOUBLE && gdata_georss_where_get_longitude (priv->georss_where) != G_MAXDOUBLE) { _gdata_parsable_get_xml (GDATA_PARSABLE (priv->georss_where), xml_string, FALSE); } /* TODO: * - Finish supporting all tags * - Check all tags here are valid for insertions and updates */ } static void get_namespaces (GDataParsable *parsable, GHashTable *namespaces) { GDataPicasaWebAlbumPrivate *priv = GDATA_PICASAWEB_ALBUM (parsable)->priv; /* Chain up to the parent class */ GDATA_PARSABLE_CLASS (gdata_picasaweb_album_parent_class)->get_namespaces (parsable, namespaces); g_hash_table_insert (namespaces, (gchar*) "gphoto", (gchar*) "http://schemas.google.com/photos/2007"); g_hash_table_insert (namespaces, (gchar*) "app", (gchar*) "http://www.w3.org/2007/app"); /* Add the media:group namespaces */ GDATA_PARSABLE_GET_CLASS (priv->media_group)->get_namespaces (GDATA_PARSABLE (priv->media_group), namespaces); /* Add the georss:where namespaces */ GDATA_PARSABLE_GET_CLASS (priv->georss_where)->get_namespaces (GDATA_PARSABLE (priv->georss_where), namespaces); } /** * gdata_picasaweb_album_new: * @id: (allow-none): the album's entry ID, or %NULL * * Creates a new #GDataPicasaWebAlbum with the given ID and default properties. @id is the ID which would be returned by gdata_entry_get_id(), * not gdata_picasaweb_album_get_id(). * * If @id is not %NULL and can't be parsed to extract an album ID, %NULL will be returned. * * Return value: a new #GDataPicasaWebAlbum, or %NULL; unref with g_object_unref() * * Since: 0.4.0 */ GDataPicasaWebAlbum * gdata_picasaweb_album_new (const gchar *id) { const gchar *album_id = NULL, *i; if (id != NULL) { album_id = g_strrstr (id, "/"); if (album_id == NULL) return NULL; album_id++; /* skip the slash */ /* Ensure the @album_id is entirely numeric */ for (i = album_id; *i != '\0'; i = g_utf8_next_char (i)) { if (g_unichar_isdigit (g_utf8_get_char (i)) == FALSE) return NULL; } } return GDATA_PICASAWEB_ALBUM (g_object_new (GDATA_TYPE_PICASAWEB_ALBUM, "id", id, "album-id", album_id, NULL)); } /** * gdata_picasaweb_album_get_id: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:album-id property. * * Return value: the album's ID * * Since: 0.7.0 */ const gchar * gdata_picasaweb_album_get_id (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), NULL); return self->priv->album_id; } /** * gdata_picasaweb_album_get_user: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:user property. * * Return value: the album owner's username * * Since: 0.4.0 */ const gchar * gdata_picasaweb_album_get_user (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), NULL); return self->priv->user; } /** * gdata_picasaweb_album_get_nickname: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:nickname property. * * Return value: the album owner's nickname * * Since: 0.4.0 */ const gchar * gdata_picasaweb_album_get_nickname (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), NULL); return self->priv->nickname; } /** * gdata_picasaweb_album_get_edited: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:edited property. If the property is unset, -1 will be returned. * * Return value: the UNIX timestamp for the time the album was last edited, or -1 * * Since: 0.4.0 */ gint64 gdata_picasaweb_album_get_edited (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), -1); return self->priv->edited; } /** * gdata_picasaweb_album_get_location: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:location property. * * Return value: the album's location, or %NULL * * Since: 0.4.0 */ const gchar * gdata_picasaweb_album_get_location (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), NULL); return self->priv->location; } /** * gdata_picasaweb_album_set_location: * @self: a #GDataPicasaWebAlbum * @location: (allow-none): the new album location, or %NULL * * Sets the #GDataPicasaWebAlbum:location property to @location. * * Set @location to %NULL to unset the property. * * Since: 0.4.0 */ void gdata_picasaweb_album_set_location (GDataPicasaWebAlbum *self, const gchar *location) { g_return_if_fail (GDATA_IS_PICASAWEB_ALBUM (self)); g_free (self->priv->location); self->priv->location = g_strdup (location); g_object_notify (G_OBJECT (self), "location"); } /** * gdata_picasaweb_album_get_visibility: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:visibility property. * * Return value: the album's visibility level * * Since: 0.4.0 */ GDataPicasaWebVisibility gdata_picasaweb_album_get_visibility (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), GDATA_PICASAWEB_PUBLIC); return self->priv->visibility; } /** * gdata_picasaweb_album_set_visibility: * @self: a #GDataPicasaWebAlbum * @visibility: the new album visibility level * * Sets the #GDataPicasaWebAlbum:visibility property to @visibility. * * Since: 0.4.0 */ void gdata_picasaweb_album_set_visibility (GDataPicasaWebAlbum *self, GDataPicasaWebVisibility visibility) { g_return_if_fail (GDATA_IS_PICASAWEB_ALBUM (self)); self->priv->visibility = visibility; g_object_notify (G_OBJECT (self), "visibility"); } /** * gdata_picasaweb_album_get_timestamp: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:timestamp property. This value usually holds either the date that best corresponds to the album of photos, or to the * day it was uploaded. It's a UNIX timestamp in milliseconds (not seconds) since the epoch. If the property is unset, -1 * will be returned. * * Return value: the UNIX timestamp for the timestamp property in milliseconds, or -1 * * Since: 0.4.0 */ gint64 gdata_picasaweb_album_get_timestamp (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), -1); return self->priv->timestamp; } /** * gdata_picasaweb_album_set_timestamp: * @self: a #GDataPicasaWebAlbum * @timestamp: a UNIX timestamp, or -1 * * Sets the #GDataPicasaWebAlbum:timestamp property from @timestamp. This should be a UNIX timestamp in milliseconds (not seconds) since the epoch. * * Set @timestamp to -1 to unset the property. * * Since: 0.4.0 */ void gdata_picasaweb_album_set_timestamp (GDataPicasaWebAlbum *self, gint64 timestamp) { g_return_if_fail (GDATA_IS_PICASAWEB_ALBUM (self)); g_return_if_fail (timestamp >= -1); self->priv->timestamp = timestamp; g_object_notify (G_OBJECT (self), "timestamp"); } /** * gdata_picasaweb_album_get_num_photos: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:num-photos property. * * Return value: the number of photos currently in the album * * Since: 0.4.0 */ guint gdata_picasaweb_album_get_num_photos (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), 0); return self->priv->num_photos; } /** * gdata_picasaweb_album_get_num_photos_remaining: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:num-photos-remaining property. * * Return value: the number of photos that can still be uploaded to the album * * Since: 0.4.0 */ guint gdata_picasaweb_album_get_num_photos_remaining (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), 0); return self->priv->num_photos_remaining; } /** * gdata_picasaweb_album_get_bytes_used: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:bytes-used property. It will return -1 if the current authenticated * user is not the owner of the album. * * Return value: the number of bytes used by the album and its contents, or -1 * * Since: 0.4.0 */ glong gdata_picasaweb_album_get_bytes_used (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), -1); return self->priv->bytes_used; } /** * gdata_picasaweb_album_is_commenting_enabled: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:is-commenting-enabled property. * * Return value: %TRUE if commenting is enabled for the album, %FALSE otherwise * * Since: 0.4.0 */ gboolean gdata_picasaweb_album_is_commenting_enabled (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), FALSE); return self->priv->is_commenting_enabled; } /** * gdata_picasaweb_album_set_is_commenting_enabled: * @self: a #GDataPicasaWebAlbum * @is_commenting_enabled: %TRUE if commenting should be enabled for the album, %FALSE otherwise * * Sets the #GDataPicasaWebAlbum:is-commenting-enabled property to @is_commenting_enabled. * * Since: 0.4.0 */ void gdata_picasaweb_album_set_is_commenting_enabled (GDataPicasaWebAlbum *self, gboolean is_commenting_enabled) { g_return_if_fail (GDATA_IS_PICASAWEB_ALBUM (self)); self->priv->is_commenting_enabled = is_commenting_enabled; g_object_notify (G_OBJECT (self), "is-commenting-enabled"); } /** * gdata_picasaweb_album_get_comment_count: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:comment-count property. * * Return value: the number of comments on the album * * Since: 0.4.0 */ guint gdata_picasaweb_album_get_comment_count (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), 0); return self->priv->comment_count; } /** * gdata_picasaweb_album_get_tags: * @self: a #GDataPicasaWebAlbum * * Gets the #GDataPicasaWebAlbum:tags property. * * Return value: (array zero-terminated=1) (transfer none): a %NULL-terminated array of tags associated with all the photos in the album, or %NULL * * Since: 0.4.0 */ const gchar * const * gdata_picasaweb_album_get_tags (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), NULL); return gdata_media_group_get_keywords (self->priv->media_group); } /** * gdata_picasaweb_album_set_tags: * @self: a #GDataPicasaWebAlbum * @tags: (array zero-terminated=1) (allow-none): the new %NULL-terminated array of tags, or %NULL * * Sets the #GDataPicasaWebAlbum:tags property to @tags. * * Set @tags to %NULL to unset the album's tag list. * * Since: 0.4.0 */ void gdata_picasaweb_album_set_tags (GDataPicasaWebAlbum *self, const gchar * const *tags) { g_return_if_fail (GDATA_IS_PICASAWEB_ALBUM (self)); gdata_media_group_set_keywords (self->priv->media_group, tags); g_object_notify (G_OBJECT (self), "tags"); } /** * gdata_picasaweb_album_get_contents: * @self: a #GDataPicasaWebAlbum * * Returns a list of media content, such as the cover image for the album. * * Return value: (element-type GData.MediaContent) (transfer none): a #GList of #GDataMediaContent items * * Since: 0.4.0 */ GList * gdata_picasaweb_album_get_contents (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), NULL); return gdata_media_group_get_contents (self->priv->media_group); } /** * gdata_picasaweb_album_get_thumbnails: * @self: a #GDataPicasaWebAlbum * * Returns a list of thumbnails, often at different sizes, for this album. * * Return value: (element-type GData.MediaThumbnail) (transfer none): a #GList of #GDataMediaThumbnails, or %NULL * * Since: 0.4.0 */ GList * gdata_picasaweb_album_get_thumbnails (GDataPicasaWebAlbum *self) { g_return_val_if_fail (GDATA_IS_PICASAWEB_ALBUM (self), NULL); return gdata_media_group_get_thumbnails (self->priv->media_group); } /** * gdata_picasaweb_album_get_coordinates: * @self: a #GDataPicasaWebAlbum * @latitude: (out caller-allocates) (allow-none): return location for the latitude, or %NULL * @longitude: (out caller-allocates) (allow-none): return location for the longitude, or %NULL * * Gets the #GDataPicasaWebAlbum:latitude and #GDataPicasaWebAlbum:longitude properties, * setting the out parameters to them. If either latitude or longitude is %NULL, that parameter will not be set. * If the coordinates are unset, @latitude and @longitude will be set to %G_MAXDOUBLE. * * Since: 0.5.0 */ void gdata_picasaweb_album_get_coordinates (GDataPicasaWebAlbum *self, gdouble *latitude, gdouble *longitude) { g_return_if_fail (GDATA_IS_PICASAWEB_ALBUM (self)); if (latitude != NULL) *latitude = gdata_georss_where_get_latitude (self->priv->georss_where); if (longitude != NULL) *longitude = gdata_georss_where_get_longitude (self->priv->georss_where); } /** * gdata_picasaweb_album_set_coordinates: * @self: a #GDataPicasaWebAlbum * @latitude: the album's new latitude coordinate, or %G_MAXDOUBLE * @longitude: the album's new longitude coordinate, or %G_MAXDOUBLE * * Sets the #GDataPicasaWebAlbum:latitude and #GDataPicasaWebAlbum:longitude properties to * @latitude and @longitude respectively. * * Since: 0.5.0 */ void gdata_picasaweb_album_set_coordinates (GDataPicasaWebAlbum *self, gdouble latitude, gdouble longitude) { g_return_if_fail (GDATA_IS_PICASAWEB_ALBUM (self)); gdata_georss_where_set_latitude (self->priv->georss_where, latitude); gdata_georss_where_set_longitude (self->priv->georss_where, longitude); g_object_freeze_notify (G_OBJECT (self)); g_object_notify (G_OBJECT (self), "latitude"); g_object_notify (G_OBJECT (self), "longitude"); g_object_thaw_notify (G_OBJECT (self)); }