[grilo-plugins] [vimeo] Added Vimeo plugin
- From: Juan A. Suarez Romero <jasuarez src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [grilo-plugins] [vimeo] Added Vimeo plugin
- Date: Fri, 30 Apr 2010 14:52:22 +0000 (UTC)
commit 7b0245a16a57b1716eca9d5b940dd8ef77abcf1c
Author: Joaquim Rocha <jrocha igalia com>
Date: Wed Apr 21 10:33:00 2010 +0200
[vimeo] Added Vimeo plugin
The Vimeo plugin allows to search videos, retrieving, among other data, the
video's play URL.
configure.ac | 47 +++++
src/Makefile.am | 6 +-
src/vimeo/Makefile.am | 34 ++++
src/vimeo/grl-vimeo.c | 391 +++++++++++++++++++++++++++++++++++++
src/vimeo/grl-vimeo.h | 77 ++++++++
src/vimeo/gvimeo.c | 513 +++++++++++++++++++++++++++++++++++++++++++++++++
src/vimeo/gvimeo.h | 112 +++++++++++
7 files changed, 1179 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 032a3c8..241379d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,6 +69,12 @@ PKG_CHECK_MODULES(SQLITE, sqlite3, HAVE_SQLITE=yes, HAVE_SQLITE=no)
PKG_CHECK_MODULES(GDATA, libgdata >= 0.4.0, HAVE_GDATA=yes, HAVE_GDATA=no)
+PKG_CHECK_MODULES(LIBSOUP, libsoup-2.4, HAVE_LIBSOUP=yes, HAVE_LIBSOUP=no)
+
+AC_CHECK_HEADER([gcrypt.h], HAVE_GCRYPT=yes, HAVE_GCRYPT=no)
+
+PKG_CHECK_MODULES(GTHREAD, gthread-2.0, HAVE_GTHREAD=yes, HAVE_GTHREAD=no)
+
# ----------------------------------------------------------
# GUPNP-AV VERSION
# ----------------------------------------------------------
@@ -516,6 +522,46 @@ then
fi
# ----------------------------------------------------------
+# BUILD VIMEO PLUGIN
+# ----------------------------------------------------------
+
+AC_ARG_ENABLE(vimeo,
+ AC_HELP_STRING([--enable-vimeo],
+ [enable Vimeo plugin (default: auto)]),
+ [
+ case "$enableval" in
+ yes)
+ if test "x$HAVE_XML" = "xno"; then
+ AC_MSG_ERROR([xml2 not found, install it or use --disable-vimeo])
+ fi
+ if test "x$HAVE_LIBSOUP" = "xno"; then
+ AC_MSG_ERROR([libsoup not found, install it or use --disable-vimeo])
+ fi
+ if test "x$HAVE_GCRYPT" = "xno"; then
+ AC_MSG_ERROR([libgcrypt not found, install it or use --disable-vimeo])
+ fi
+ if test "x$HAVE_GTHREAD" = "xno"; then
+ AC_MSG_ERROR([gthread not found, install it or use --disable-vimeo])
+ fi
+ ;;
+ esac
+ ],
+ [
+ if test "x$HAVE_XML" = "xyes" -a "x$HAVE_LIBSOUP" = "xyes" -a "x$HAVE_GCRYPT" = "xyes" -a "x$HAVE_GTHREAD" = "xyes"; then
+ enable_vimeo=yes
+ else
+ enable_vimeo=no
+ fi
+ ])
+
+AM_CONDITIONAL([VIMEO_PLUGIN], [test "x$enable_vimeo" = "xyes"])
+GRL_PLUGINS_ALL="$GRL_PLUGINS_ALL vimeo"
+if test "x$enable_vimeo" = "xyes"
+then
+ GRL_PLUGINS_ENABLED="$GRL_PLUGINS_ENABLED vimeo"
+fi
+
+# ----------------------------------------------------------
# GETTEXT
# ----------------------------------------------------------
@@ -551,6 +597,7 @@ AC_CONFIG_FILES([
src/shoutcast/Makefile
src/apple-trailers/Makefile
src/metadata-store/Makefile
+ src/vimeo/Makefile
test/Makefile
])
diff --git a/src/Makefile.am b/src/Makefile.am
index c45f9d3..e00b176 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -55,7 +55,11 @@ if METADATA_STORE_PLUGIN
SUBDIRS += metadata-store
endif
-DIST_SUBDIRS = youtube fake-metadata filesystem jamendo lastfm-albumart upnp flickr podcasts bookmarks shoutcast apple-trailers metadata-store
+if VIMEO_PLUGIN
+SUBDIRS += vimeo
+endif
+
+DIST_SUBDIRS = youtube fake-metadata filesystem jamendo lastfm-albumart upnp flickr podcasts bookmarks shoutcast apple-trailers metadata-store vimeo
MAINTAINERCLEANFILES = \
*.in \
diff --git a/src/vimeo/Makefile.am b/src/vimeo/Makefile.am
new file mode 100644
index 0000000..4526a2c
--- /dev/null
+++ b/src/vimeo/Makefile.am
@@ -0,0 +1,34 @@
+#
+# Makefile.am
+#
+# Author: Joaquim Rocha <jrocha igalia com>
+#
+# Copyright (C) 2010 Igalia S.L. All rights reserved.
+
+lib_LTLIBRARIES = libgrlvimeo.la
+
+libgrlvimeo_la_CFLAGS = \
+ $(DEPS_CFLAGS) \
+ $(XML_CFLAGS) \
+ $(GTHREAD_CFLAGS) \
+ $(LIBSOUP_CFLAGS)
+
+libgrlvimeo_la_LIBADD = \
+ $(DEPS_LIBS) \
+ $(XML_LIBS) \
+ $(GTHREAD_LIBS) \
+ $(LIBSOUP_LIBS)
+
+libgrlvimeo_la_SOURCES = \
+ grl-vimeo.c \
+ grl-vimeo.h \
+ gvimeo.c \
+ gvimeo.h
+
+libdir=$(GRL_PLUGINS_DIR)
+
+MAINTAINERCLEANFILES = \
+ *.in \
+ *~
+
+DISTCLEANFILES = $(MAINTAINERCLEANFILES)
diff --git a/src/vimeo/grl-vimeo.c b/src/vimeo/grl-vimeo.c
new file mode 100644
index 0000000..c929163
--- /dev/null
+++ b/src/vimeo/grl-vimeo.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Joaquim Rocha <jrocha igalia com>
+ *
+ * This library 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; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <grilo.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "grl-vimeo.h"
+#include "gvimeo.h"
+
+#define GRL_VIMEO_SOURCE_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((object), \
+ GRL_VIMEO_SOURCE_TYPE, \
+ GrlVimeoSourcePrivate))
+
+/* --------- Logging -------- */
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "grl-vimeo"
+
+/* --- Plugin information --- */
+
+#define PLUGIN_ID "grl-vimeo"
+#define PLUGIN_NAME "Vimeo"
+#define PLUGIN_DESC "A plugin for browsing and searching Vimeo videos"
+
+#define SOURCE_ID "grl-vimeo"
+#define SOURCE_NAME "Vimeo"
+#define SOURCE_DESC "A source for browsing and searching Vimeo videos"
+
+#define AUTHOR "Igalia S.L."
+#define LICENSE "LGPL"
+#define SITE "http://www.igalia.com"
+
+typedef struct {
+ GrlMediaSourceSearchSpec *ss;
+ gint offset;
+ gint page;
+} SearchData;
+
+struct _GrlVimeoSourcePrivate {
+ GVimeo *vimeo;
+};
+
+static GrlVimeoSource *grl_vimeo_source_new (void);
+
+gboolean grl_vimeo_plugin_init (GrlPluginRegistry *registry,
+ const GrlPluginInfo *plugin,
+ GList *configs);
+
+static const GList *grl_vimeo_source_supported_keys (GrlMetadataSource *source);
+
+static void grl_vimeo_source_metadata (GrlMediaSource *source,
+ GrlMediaSourceMetadataSpec *ss);
+
+static void grl_vimeo_source_search (GrlMediaSource *source,
+ GrlMediaSourceSearchSpec *ss);
+
+/* =================== Vimeo Plugin =============== */
+
+gboolean
+grl_vimeo_plugin_init (GrlPluginRegistry *registry,
+ const GrlPluginInfo *plugin,
+ GList *configs)
+{
+ const gchar *vimeo_key;
+ const gchar *vimeo_secret;
+ const GrlConfig *config;
+ gint config_count;
+ GrlVimeoSource *source;
+
+ g_debug ("vimeo_plugin_init\n");
+
+ if (!g_thread_supported ()) {
+ g_thread_init (NULL);
+ }
+
+ if (!configs) {
+ g_warning ("Missing configuration");
+ return FALSE;
+ }
+
+ config_count = g_list_length (configs);
+ if (config_count > 1) {
+ g_warning ("Provided %d configs, but will only use one", config_count);
+ }
+
+ config = GRL_CONFIG (configs->data);
+
+ vimeo_key = grl_config_get_api_key (config);
+ vimeo_secret = grl_config_get_api_secret (config);
+
+ if (!vimeo_key || !vimeo_secret) {
+ g_warning ("Required configuration keys not set up");
+ return FALSE;
+ }
+
+ source = grl_vimeo_source_new ();
+ source->priv->vimeo = g_vimeo_new (vimeo_key, vimeo_secret);
+
+ grl_plugin_registry_register_source (registry,
+ plugin,
+ GRL_MEDIA_PLUGIN (source));
+ return TRUE;
+}
+
+GRL_PLUGIN_REGISTER (grl_vimeo_plugin_init,
+ NULL,
+ PLUGIN_ID,
+ PLUGIN_NAME,
+ PLUGIN_DESC,
+ PACKAGE_VERSION,
+ AUTHOR,
+ LICENSE,
+ SITE);
+
+/* ================== Vimeo GObject ================ */
+
+static GrlVimeoSource *
+grl_vimeo_source_new (void)
+{
+ g_debug ("grl_vimeo_source_new");
+
+ return g_object_new (GRL_VIMEO_SOURCE_TYPE,
+ "source-id", SOURCE_ID,
+ "source-name", SOURCE_NAME,
+ "source-desc", SOURCE_DESC,
+ NULL);
+}
+
+static void
+grl_vimeo_source_class_init (GrlVimeoSourceClass * klass)
+{
+ GrlMediaSourceClass *source_class = GRL_MEDIA_SOURCE_CLASS (klass);
+ GrlMetadataSourceClass *metadata_class = GRL_METADATA_SOURCE_CLASS (klass);
+
+ source_class->metadata = grl_vimeo_source_metadata;
+ source_class->search = grl_vimeo_source_search;
+ metadata_class->supported_keys = grl_vimeo_source_supported_keys;
+
+ g_type_class_add_private (klass, sizeof (GrlVimeoSourcePrivate));
+}
+
+static void
+grl_vimeo_source_init (GrlVimeoSource *source)
+{
+ source->priv = GRL_VIMEO_SOURCE_GET_PRIVATE (source);
+}
+
+G_DEFINE_TYPE (GrlVimeoSource, grl_vimeo_source, GRL_TYPE_MEDIA_SOURCE);
+
+/* ======================= Utilities ==================== */
+
+static gint
+str_to_gint (gchar *str)
+{
+ gint number;
+
+ errno = 0;
+ number = (gint) g_ascii_strtod (str, NULL);
+ if (errno == 0)
+ {
+ return number;
+ }
+ return 0;
+}
+
+static void
+update_media (GrlMedia *media, GHashTable *video)
+{
+ gchar *str;
+
+ str = g_hash_table_lookup (video, VIMEO_VIDEO_ID);
+ if (str)
+ {
+ grl_media_set_id (media, str);
+ }
+
+ str = g_hash_table_lookup (video, VIMEO_VIDEO_TITLE);
+ if (str)
+ {
+ grl_media_set_title (media, str);
+ }
+
+ str = g_hash_table_lookup (video, VIMEO_VIDEO_DESCRIPTION);
+ if (str)
+ {
+ grl_media_set_description (media, str);
+ }
+
+ str = g_hash_table_lookup (video, VIMEO_VIDEO_DURATION);
+ if (str)
+ {
+ grl_media_set_duration (media, str_to_gint (str));
+ }
+
+ str = g_hash_table_lookup (video, VIMEO_VIDEO_OWNER_NAME);
+ if (str)
+ {
+ grl_media_set_author (media, str);
+ }
+
+ str = g_hash_table_lookup (video, VIMEO_VIDEO_UPLOAD_DATE);
+ if (str)
+ {
+ grl_media_set_date (media, str);
+ }
+
+ str = g_hash_table_lookup (video, VIMEO_VIDEO_THUMBNAIL);
+ if (str)
+ {
+ grl_media_set_thumbnail (media, str);
+ }
+
+ str = g_hash_table_lookup (video, VIMEO_VIDEO_WIDTH);
+ if (str)
+ {
+ grl_media_video_set_width (media, str_to_gint (str));
+ }
+
+ str = g_hash_table_lookup (video, VIMEO_VIDEO_HEIGHT);
+ if (str)
+ {
+ grl_media_video_set_height (media, str_to_gint (str));
+ }
+}
+
+
+static void
+search_cb (GVimeo *vimeo, GList *video_list, gpointer user_data)
+{
+ GrlMedia *media = NULL;
+ SearchData *sd = (SearchData *) user_data;
+ gchar *media_type;
+
+ /* Go to offset element */
+ video_list = g_list_nth (video_list, sd->offset);
+
+ /* No more elements can be sent */
+ if (!video_list) {
+ sd->ss->callback (sd->ss->source,
+ sd->ss->search_id,
+ NULL,
+ 0,
+ sd->ss->user_data,
+ NULL);
+ g_free (sd);
+ return;
+ }
+
+ while (video_list && sd->ss->count)
+ {
+ media_type = g_hash_table_lookup (video_list->data, "title");
+ if (media_type) {
+ media = grl_media_video_new ();
+ }
+
+ if (media)
+ {
+ update_media (media, video_list->data);
+ sd->ss->callback (sd->ss->source,
+ sd->ss->search_id,
+ media,
+ sd->ss->count == 1? 0: -1,
+ sd->ss->user_data,
+ NULL);
+ }
+ video_list = g_list_next (video_list);
+ sd->ss->count--;
+ media = NULL;
+ }
+
+ /* Get more elements */
+ if (sd->ss->count)
+ {
+ sd->offset = 0;
+ sd->page++;
+ g_vimeo_videos_search (vimeo, sd->ss->text, sd->page, search_cb, sd);
+ }
+ else
+ {
+ g_free (sd);
+ }
+}
+
+static void
+video_get_play_url_cb (gchar *url, gpointer user_data)
+{
+ GrlMediaSourceMetadataSpec *ms = (GrlMediaSourceMetadataSpec *) user_data;
+
+ if (url)
+ {
+ grl_media_set_url (ms->media, url);
+ }
+
+ ms->callback (ms->source, ms->media, ms->user_data, NULL);
+}
+
+/* ================== API Implementation ================ */
+
+static const GList *
+grl_vimeo_source_supported_keys (GrlMetadataSource *source)
+{
+ static GList *keys = NULL;
+ if (!keys) {
+ keys = grl_metadata_key_list_new (GRL_METADATA_KEY_ID,
+ GRL_METADATA_KEY_TITLE,
+ GRL_METADATA_KEY_DESCRIPTION,
+ GRL_METADATA_KEY_URL,
+ GRL_METADATA_KEY_AUTHOR,
+ GRL_METADATA_KEY_DATE,
+ GRL_METADATA_KEY_THUMBNAIL,
+ GRL_METADATA_KEY_DURATION,
+ GRL_METADATA_KEY_WIDTH,
+ GRL_METADATA_KEY_HEIGHT,
+ NULL);
+ }
+ return keys;
+}
+
+static void
+grl_vimeo_source_metadata (GrlMediaSource *source,
+ GrlMediaSourceMetadataSpec *ms)
+{
+ gint id;
+ const gchar *id_str;
+
+ if (!ms->media || (id_str = grl_media_get_id (ms->media)) == NULL)
+ {
+ ms->callback (ms->source, ms->media, ms->user_data, NULL);
+ return;
+ }
+
+ errno = 0;
+ id = (gint) g_ascii_strtod (id_str, NULL);
+ if (errno != 0)
+ {
+ return;
+ }
+
+ g_vimeo_video_get_play_url (GRL_VIMEO_SOURCE (source)->priv->vimeo,
+ id,
+ video_get_play_url_cb,
+ ms);
+}
+
+static void
+grl_vimeo_source_search (GrlMediaSource *source,
+ GrlMediaSourceSearchSpec *ss)
+{
+ SearchData *sd;
+ gint per_page;
+ GVimeo *vimeo = GRL_VIMEO_SOURCE (source)->priv->vimeo;
+
+ /* Compute items per page and page offset */
+ per_page = CLAMP (1 + ss->skip + ss->count, 0, 100);
+ g_vimeo_set_per_page (vimeo, per_page);
+
+ sd = g_new (SearchData, 1);
+ sd->page = 1 + (ss->skip / per_page);
+ sd->offset = ss->skip % per_page;
+ sd->ss = ss;
+
+ g_vimeo_videos_search (vimeo, ss->text, sd->page, search_cb, sd);
+}
diff --git a/src/vimeo/grl-vimeo.h b/src/vimeo/grl-vimeo.h
new file mode 100644
index 0000000..fde4f36
--- /dev/null
+++ b/src/vimeo/grl-vimeo.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Joaquim Rocha <jrocha igalia com>
+ *
+ * This library 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; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _GRL_VIMEO_SOURCE_H_
+#define _GRL_VIMEO_SOURCE_H_
+
+#include <grilo.h>
+
+#define GRL_VIMEO_SOURCE_TYPE \
+ (grl_vimeo_source_get_type ())
+
+#define GRL_VIMEO_SOURCE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ GRL_VIMEO_SOURCE_TYPE, \
+ GrlVimeoSource))
+
+#define GRL_IS_VIMEO_SOURCE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ GRL_VIMEO_SOURCE_TYPE))
+
+#define GRL_VIMEO_SOURCE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ GRL_VIMEO_SOURCE_TYPE, \
+ GrlVimeoSourceClass))
+
+#define GRL_IS_VIMEO_SOURCE_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ GRL_VIMEO_SOURCE_TYPE))
+
+#define GRL_VIMEO_SOURCE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ GRL_VIMEO_SOURCE_TYPE, \
+ GrlVimeoSourceClass))
+
+typedef struct _GrlVimeoSource GrlVimeoSource;
+typedef struct _GrlVimeoSourcePrivate GrlVimeoSourcePrivate;
+
+struct _GrlVimeoSource {
+
+ GrlMediaSource parent;
+
+ /*< private >*/
+ GrlVimeoSourcePrivate *priv;
+};
+
+typedef struct _GrlVimeoSourceClass GrlVimeoSourceClass;
+
+struct _GrlVimeoSourceClass {
+
+ GrlMediaSourceClass parent_class;
+
+};
+
+GType grl_vimeo_source_get_type (void);
+
+#endif /* _GRL_VIMEO_SOURCE_H_ */
diff --git a/src/vimeo/gvimeo.c b/src/vimeo/gvimeo.c
new file mode 100644
index 0000000..4ce67f9
--- /dev/null
+++ b/src/vimeo/gvimeo.c
@@ -0,0 +1,513 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Joaquim Rocha <jrocha igalia com>
+ *
+ * This library 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; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#include <gcrypt.h>
+#include <libsoup/soup.h>
+#include "gvimeo.h"
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+
+#define G_VIMEO_GET_PRIVATE(object) \
+ (G_TYPE_INSTANCE_GET_PRIVATE((object), \
+ G_VIMEO_TYPE, \
+ GVimeoPrivate))
+
+#define PLUGIN_USER_AGENT "Grilo Vimeo Plugin"
+
+#define VIMEO_ENDPOINT "http://vimeo.com/api/rest/v2"
+#define VIMEO_VIDEO_LOAD_URL "http://vimeo.com/moogaloop/load/clip:"
+#define VIMEO_VIDEO_PLAY_URL "http://vimeo.com/moogaloop/play/clip:"
+
+#define VIMEO_VIDEO_SEARCH_METHOD "vimeo.videos.search"
+#define VIMEO_API_OAUTH_SIGN_METHOD "HMAC-SHA1"
+#define VIMEO_API_OAUTH_SIGNATURE_PARAM "&oauth_signature=%s"
+
+#define VIMEO_VIDEO_SEARCH \
+ "full_response=yes" \
+ "&method=%s" \
+ "&oauth_consumer_key=%s" \
+ "&oauth_nonce=%s" \
+ "&oauth_signature_method=" VIMEO_API_OAUTH_SIGN_METHOD \
+ "&oauth_timestamp=%s" \
+ "&oauth_token=" \
+ "&page=%d" \
+ "&per_page=%d" \
+ "&query=%s"
+
+typedef struct {
+ GVimeo *vimeo;
+ GVimeoVideoSearchCb search_cb;
+ gpointer user_data;
+} GVimeoVideoSearchData;
+
+typedef struct {
+ GVimeo *vimeo;
+ gint video_id;
+ GVimeoURLCb callback;
+ gpointer user_data;
+} GVimeoVideoURLData;
+
+struct _GVimeoPrivate {
+ gchar *api_key;
+ gchar *auth_token;
+ gchar *auth_secret;
+ gint per_page;
+ SoupSession *async_session;
+};
+
+enum InfoType {SIMPLE, EXTENDED};
+
+typedef struct {
+ enum InfoType type;
+ gchar *name;
+} VideoInfo;
+
+static VideoInfo video_info[] = {{SIMPLE, VIMEO_VIDEO_TITLE},
+ {SIMPLE, VIMEO_VIDEO_DESCRIPTION},
+ {SIMPLE, VIMEO_VIDEO_UPLOAD_DATE},
+ {SIMPLE, VIMEO_VIDEO_WIDTH},
+ {SIMPLE, VIMEO_VIDEO_HEIGHT},
+ {SIMPLE, VIMEO_VIDEO_OWNER},
+ {SIMPLE, VIMEO_VIDEO_URL},
+ {SIMPLE, VIMEO_VIDEO_THUMBNAIL},
+ {SIMPLE, VIMEO_VIDEO_DURATION},
+ {EXTENDED, VIMEO_VIDEO_OWNER}};
+
+static void g_vimeo_finalize (GObject *object);
+
+/* -------------------- GOBJECT -------------------- */
+
+G_DEFINE_TYPE (GVimeo, g_vimeo, G_TYPE_OBJECT);
+
+static void
+g_vimeo_class_init (GVimeoClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = g_vimeo_finalize;
+
+ g_type_class_add_private (klass, sizeof (GVimeoPrivate));
+}
+
+static void
+g_vimeo_init (GVimeo *vimeo)
+{
+ vimeo->priv = G_VIMEO_GET_PRIVATE (vimeo);
+ vimeo->priv->per_page = 50;
+ vimeo->priv->async_session = soup_session_async_new ();
+}
+
+static void
+g_vimeo_finalize (GObject *object)
+{
+ GVimeo *vimeo = G_VIMEO (object);
+ g_free (vimeo->priv->api_key);
+ g_free (vimeo->priv->auth_secret);
+ g_object_unref (vimeo->priv->async_session);
+
+ G_OBJECT_CLASS (g_vimeo_parent_class)->finalize (object);
+}
+
+GVimeo *
+g_vimeo_new (const gchar *api_key, const gchar *auth_secret)
+{
+ GVimeo *vimeo = g_object_new (G_VIMEO_TYPE, NULL);
+ vimeo->priv->api_key = g_strdup (api_key);
+ vimeo->priv->auth_secret = g_strdup (auth_secret);
+
+ return vimeo;
+}
+
+/* -------------------- PRIVATE API -------------------- */
+
+static gchar *
+get_timestamp (void)
+{
+ time_t t = time (NULL);
+ return g_strdup_printf ("%d", (gint) t);
+}
+
+static gchar *
+get_nonce (void)
+{
+ gchar *timestamp = get_timestamp();
+ guint rnd_number = g_random_int ();
+ gchar *rnd_str = g_strdup_printf ("%d_%s", rnd_number, timestamp);
+ gchar *nonce = g_compute_checksum_for_string (G_CHECKSUM_MD5, rnd_str, -1);
+ g_free (timestamp);
+ g_free (rnd_str);
+
+ return nonce;
+}
+
+static gchar *
+get_videos_search_params (GVimeo *vimeo, const gchar *text, gint page) {
+ gchar *timestamp = get_timestamp ();
+ gchar *nonce = get_nonce ();
+ gchar *params = g_strdup_printf (VIMEO_VIDEO_SEARCH,
+ VIMEO_VIDEO_SEARCH_METHOD,
+ vimeo->priv->api_key,
+ nonce,
+ timestamp,
+ page,
+ vimeo->priv->per_page,
+ text);
+ g_free (timestamp);
+ g_free (nonce);
+
+ return params;
+}
+
+static gchar *
+sign_string (gchar *message, gchar *key)
+{
+ gchar *signed_message = NULL;
+ gcry_md_hd_t digest_obj;
+ unsigned char *hmac_digest;
+
+ gcry_md_open(&digest_obj,
+ GCRY_MD_SHA1,
+ GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC);
+ gcry_md_setkey(digest_obj, key, strlen (key));
+ gcry_md_write (digest_obj, message, strlen (message));
+ gcry_md_final (digest_obj);
+ hmac_digest = gcry_md_read (digest_obj, 0);
+
+ signed_message = g_base64_encode (hmac_digest,
+ strlen ((gchar *) hmac_digest));
+
+ gcry_md_close (digest_obj);
+
+ return signed_message;
+}
+
+static gboolean
+result_is_correct (xmlNodePtr node)
+{
+ gboolean correct = FALSE;
+ xmlChar *stat;
+
+ if (xmlStrcmp (node->name, (const xmlChar *) "rsp") == 0)
+ {
+ stat = xmlGetProp (node, (const xmlChar *) "stat");
+ if (stat && xmlStrcmp (stat, (const xmlChar *) "ok") == 0)
+ {
+ correct = TRUE;
+ xmlFree (stat);
+ }
+ }
+
+ return correct;
+}
+
+static void
+add_node (xmlNodePtr node, GHashTable *video)
+{
+ xmlAttrPtr attr;
+
+ for (attr = node->properties; attr != NULL; attr = attr->next)
+ {
+ g_hash_table_insert (video,
+ g_strconcat ((const gchar *) node->name,
+ "_",
+ (const gchar *) attr->name,
+ NULL),
+ (gchar *) xmlGetProp (node, attr->name));
+ }
+}
+
+static xmlNodePtr
+xpath_get_node (xmlXPathContextPtr context, gchar *xpath_expr)
+{
+ xmlNodePtr node = NULL;
+ xmlXPathObjectPtr xpath_obj;
+ xpath_obj = xmlXPathEvalExpression ((xmlChar *) xpath_expr, context);
+
+ if (xpath_obj && xpath_obj->nodesetval->nodeTab)
+ {
+ node = xpath_obj->nodesetval->nodeTab[0];
+ }
+ xmlXPathFreeObject (xpath_obj);
+
+ return node;
+}
+
+static gchar *
+get_node_text (xmlXPathContextPtr context, gchar *xpath_expr)
+{
+ xmlNodePtr node;
+ gchar *node_text = NULL;
+
+ node = xpath_get_node (context, xpath_expr);
+ if (node)
+ {
+ node_text = (gchar *) xmlNodeGetContent (node);
+ }
+
+ return node_text;
+}
+
+static GHashTable *
+get_video (xmlNodePtr node)
+{
+ gint i;
+ gint array_length;
+ xmlXPathContextPtr context;
+ gchar *video_id;
+ GHashTable *video = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ g_free);
+
+ /* Adds the video node's properties */
+ add_node (node, video);
+
+ context = xmlXPathNewContext (node->doc);
+ video_id = (gchar *) xmlGetProp (node, (xmlChar *) "id");
+
+ array_length = G_N_ELEMENTS (video_info);
+ for (i = 0; i < array_length; i++)
+ {
+ /* Look for the wanted information only under the current video */
+ gchar *xpath_name = g_strdup_printf ("//video[ id=%s]//%s",
+ video_id,
+ video_info[i].name);
+ xmlNodePtr info_node = xpath_get_node (context, xpath_name);
+ if (info_node)
+ {
+ if (video_info[i].type == EXTENDED) {
+ add_node (info_node, video);
+ }
+ else
+ {
+ g_hash_table_insert (video,
+ g_strdup ((const gchar *) info_node->name),
+ (gchar *) xmlNodeGetContent (info_node));
+ }
+ }
+ g_free (xpath_name);
+ }
+ g_free (video_id);
+
+ xmlXPathFreeContext (context);
+
+ return video;
+}
+
+
+static void
+process_video_search_result (const gchar *xml_result, gpointer user_data)
+{
+ xmlDocPtr doc;
+ xmlNodePtr node;
+ GList *video_list = NULL;
+ GVimeoVideoSearchData *data = (GVimeoVideoSearchData *) user_data;
+
+ doc = xmlReadMemory (xml_result,
+ xmlStrlen ((xmlChar *) xml_result),
+ NULL,
+ NULL,
+ XML_PARSE_RECOVER | XML_PARSE_NOBLANKS);
+ node = xmlDocGetRootElement (doc);
+
+ /* Check result is ok */
+ if (!node || !result_is_correct (node))
+ {
+ data->search_cb (data->vimeo, NULL, data->user_data);
+ }
+ else
+ {
+ node = node->xmlChildrenNode;
+
+ /* Now we're at "video pages" node */
+ node = node->xmlChildrenNode;
+ while (node)
+ {
+ video_list = g_list_prepend (video_list, get_video (node));
+ node = node->next;
+ }
+
+ data->search_cb (data->vimeo, g_list_reverse (video_list), data->user_data);
+ g_list_foreach (video_list, (GFunc) g_hash_table_unref, NULL);
+ g_list_free (video_list);
+ }
+ g_free (data);
+ xmlFreeDoc (doc);
+}
+
+static void
+search_videos_complete_cb (SoupSession *session,
+ SoupMessage *message,
+ gpointer *data)
+{
+ GVimeoVideoSearchCb *search_data = (GVimeoVideoSearchCb *) data;
+ process_video_search_result (message->response_body->data, search_data);
+}
+
+static gchar *
+get_play_url_from_vimeo_xml (const gchar *xml, gint video_id)
+{
+ xmlDocPtr doc = xmlRecoverDoc ((xmlChar *) xml);
+ xmlXPathContextPtr context = xmlXPathNewContext (doc);
+ gchar *request_signature = get_node_text (context,
+ "/xml/request_signature[1]");
+ gchar *signature_expires = get_node_text (context,
+ "/xml/request_signature_expires[1]");
+
+ gchar *url = g_strdup_printf ("%s%d/%s/%s/?q=sd",
+ VIMEO_VIDEO_PLAY_URL,
+ video_id,
+ request_signature,
+ signature_expires);
+
+ g_free (request_signature);
+ g_free (signature_expires);
+ xmlXPathFreeContext (context);
+ xmlFreeDoc (doc);
+
+ return url;
+}
+
+static void
+get_video_play_url_complete_cb (SoupSession *session,
+ SoupMessage *message,
+ gpointer *data)
+{
+ GVimeoVideoURLData *url_data;
+ gchar *url;
+
+ if (message->response_body == NULL)
+ {
+ return;
+ }
+
+ url_data = (GVimeoVideoURLData *) data;
+ url = get_play_url_from_vimeo_xml (message->response_body->data,
+ url_data->video_id);
+ url_data->callback (url, url_data->user_data);
+ g_free (url_data);
+}
+
+static gchar *
+encode_uri (gchar *uri)
+{
+ return soup_uri_encode (uri, "%!*'();:@&=+$,/?#[] ");
+}
+
+static gchar *
+build_request (GVimeo *vimeo, const gchar *query, gint page)
+{
+ gchar *params;
+ gchar *endpoint_encoded;
+ gchar *key;
+ gchar *escaped_str;
+ gchar *tmp_str;
+ gchar *signature;
+
+ g_return_val_if_fail (G_IS_VIMEO (vimeo), NULL);
+
+ params = get_videos_search_params (vimeo, query, page);
+ endpoint_encoded = encode_uri (VIMEO_ENDPOINT);
+ key = g_strdup_printf ("%s&", vimeo->priv->auth_secret);
+ escaped_str = encode_uri (params);
+ tmp_str = g_strdup_printf ("GET&%s&%s", endpoint_encoded, escaped_str);
+ signature = sign_string (tmp_str, key);
+ g_free (escaped_str);
+ g_free (tmp_str);
+ escaped_str = encode_uri (signature);
+ tmp_str = g_strdup_printf ("%s?%s" VIMEO_API_OAUTH_SIGNATURE_PARAM,
+ VIMEO_ENDPOINT,
+ params,
+ escaped_str);
+
+ g_free (endpoint_encoded);
+ g_free (params);
+ g_free (key);
+ g_free (escaped_str);
+ g_free (signature);
+
+ return tmp_str;
+}
+
+/* -------------------- PUBLIC API -------------------- */
+
+void
+g_vimeo_set_per_page (GVimeo *vimeo, gint per_page)
+{
+ g_return_if_fail (G_IS_VIMEO (vimeo));
+ vimeo->priv->per_page = per_page;
+}
+
+void
+g_vimeo_videos_search (GVimeo *vimeo,
+ const gchar *text,
+ gint page,
+ GVimeoVideoSearchCb callback,
+ gpointer user_data)
+{
+ SoupMessage *message;
+ GVimeoVideoSearchData *search_data;
+ gchar *request;
+
+ g_return_if_fail (G_IS_VIMEO (vimeo));
+
+ request = build_request (vimeo, text, page);
+ search_data = g_new (GVimeoVideoSearchData, 1);
+ search_data->vimeo = vimeo;
+ search_data->search_cb = callback;
+ search_data->user_data = user_data;
+
+ message = soup_message_new ("GET", request);
+ soup_session_queue_message (vimeo->priv->async_session,
+ message,
+ (SoupSessionCallback) search_videos_complete_cb,
+ search_data);
+ g_free (request);
+}
+
+void
+g_vimeo_video_get_play_url (GVimeo *vimeo,
+ gint id,
+ GVimeoURLCb callback,
+ gpointer user_data)
+{
+ GVimeoVideoURLData *data;
+ gchar *url = g_strdup_printf ("%s%d",
+ VIMEO_VIDEO_LOAD_URL,
+ id);
+ SoupMessage *message = soup_message_new ("GET", url);
+ SoupMessageHeaders *headers = message->request_headers;
+ soup_message_headers_append (headers, "User-Agent", PLUGIN_USER_AGENT);
+
+ data = g_new (GVimeoVideoURLData, 1);
+ data->video_id = id;
+ data->vimeo = vimeo;
+ data->callback = callback;
+ data->user_data = user_data;
+
+ soup_session_queue_message (vimeo->priv->async_session,
+ message,
+ (SoupSessionCallback) get_video_play_url_complete_cb,
+ data);
+ g_free (url);
+}
diff --git a/src/vimeo/gvimeo.h b/src/vimeo/gvimeo.h
new file mode 100644
index 0000000..34e17a3
--- /dev/null
+++ b/src/vimeo/gvimeo.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2010 Igalia S.L.
+ *
+ * Contact: Iago Toral Quiroga <itoral igalia com>
+ *
+ * Authors: Joaquim Rocha <jrocha igalia com>
+ *
+ * This library 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; version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef _G_VIMEO_H_
+#define _G_VIMEO_H_
+
+#include <glib-object.h>
+
+#define G_VIMEO_TYPE \
+ (g_vimeo_get_type ())
+
+#define G_VIMEO(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+ G_VIMEO_TYPE, \
+ GVimeo))
+
+#define G_IS_VIMEO(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+ G_VIMEO_TYPE))
+
+#define G_VIMEO_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_CAST((klass), \
+ G_VIMEO_TYPE, \
+ GVimeoClass))
+
+#define G_IS_VIMEO_CLASS(klass) \
+ (G_TYPE_CHECK_CLASS_TYPE((klass), \
+ G_VIMEO_TYPE))
+
+#define G_VIMEO_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+ G_VIMEO_TYPE, \
+ GVimeoClass))
+
+#define VIMEO_VIDEO "video"
+#define VIMEO_VIDEO_ID VIMEO_VIDEO "_id"
+#define VIMEO_VIDEO_TITLE "title"
+#define VIMEO_VIDEO_DESCRIPTION "description"
+#define VIMEO_VIDEO_URL "url"
+#define VIMEO_VIDEO_UPLOAD_DATE "upload_date"
+#define VIMEO_VIDEO_WIDTH "width"
+#define VIMEO_VIDEO_HEIGHT "height"
+#define VIMEO_VIDEO_DURATION "duration"
+#define VIMEO_VIDEO_OWNER "owner"
+#define VIMEO_VIDEO_THUMBNAIL "thumbnail"
+
+#define VIMEO_VIDEO_OWNER_NAME VIMEO_VIDEO_OWNER "_realname"
+
+typedef struct _GVimeo GVimeo;
+typedef struct _GVimeoPrivate GVimeoPrivate;
+
+struct _GVimeo {
+
+ GObject parent;
+
+ /*< private >*/
+ GVimeoPrivate *priv;
+};
+
+typedef struct _GVimeoClass GVimeoClass;
+
+struct _GVimeoClass {
+
+ GObjectClass parent_class;
+
+};
+
+typedef void (*GVimeoVideoSearchCb) (GVimeo *vimeo,
+ GList *videolist,
+ gpointer user_data);
+
+typedef void (*GVimeoURLCb) (gchar *url, gpointer user_data);
+
+GType g_vimeo_get_type (void);
+
+GVimeo *g_vimeo_new (const gchar *api_key, const gchar *auth_secret);
+
+void g_vimeo_video_get_play_url (GVimeo *vimeo,
+ gint id,
+ GVimeoURLCb callback,
+ gpointer user_data);
+
+void g_vimeo_set_per_page (GVimeo *vimeo, gint per_page);
+
+void g_vimeo_videos_search (GVimeo *vimeo,
+ const gchar *text,
+ gint page,
+ GVimeoVideoSearchCb callback,
+ gpointer user_data);
+
+#endif /* _G_VIMEO_H_ */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]