[gnome-online-miners/wip/facebook: 1/2] src: add a Facebook miner based on GFBGraph



commit e324a9fa8a0810ba239ed16ab77bc486478bb621
Author: Álvaro Peña <alvaropg gmail com>
Date:   Tue Jun 25 19:42:18 2013 +0200

    src: add a Facebook miner based on GFBGraph
    
    https://bugzilla.gnome.org/show_bug.cgi?id=701499

 configure.ac                  |    2 +
 src/Makefile.am               |   27 +++
 src/gom-facebook-miner-main.c |   33 ++++
 src/gom-facebook-miner.c      |  375 +++++++++++++++++++++++++++++++++++++++++
 src/gom-facebook-miner.h      |   73 ++++++++
 5 files changed, 510 insertions(+), 0 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index e0d8f46..c82b8a7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -20,6 +20,7 @@ AC_PROG_CC_C_O
 AC_HEADER_STDC
 
 GDATA_MIN_VERSION=0.13.3
+GFBGRAPH_MIN_VERSION=0.1
 GLIB_MIN_VERSION=2.35.1
 GOA_MIN_VERSION=3.2.0
 GRILO_MIN_VERSION=0.2.6
@@ -33,6 +34,7 @@ GNOME_MAINTAINER_MODE_DEFINES
 LT_INIT
 
 PKG_CHECK_MODULES(GDATA, [libgdata >= $GDATA_MIN_VERSION])
+PKG_CHECK_MODULES(GFBGRAPH, [libgfbgraph-0.1 >= $GFBGRAPH_MIN_VERSION])
 PKG_CHECK_MODULES(GLIB, [glib-2.0 >= $GLIB_MIN_VERSION])
 PKG_CHECK_MODULES(GIO, [gio-2.0])
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 24c4d42..4b104ed 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -31,11 +31,38 @@ libgom_1_0_la_LDFLAGS = \
     $(NULL)
 
 libexec_PROGRAMS = \
+    gom-facebook-miner \
     gom-flickr-miner \
     gom-gdata-miner \
     gom-zpj-miner \
     $(NULL)
 
+gom_facebook_miner_SOURCES = \
+    gom-facebook-miner-main.c \
+    gom-facebook-miner.c \
+    gom-facebook-miner.h \
+    $(NULL)
+
+gom_facebook_miner_CPPFLAGS = \
+    -DG_LOG_DOMAIN=\"Gom\" \
+    -DG_DISABLE_DEPRECATED \
+    -I$(top_srcdir)/src \
+    $(GFBGRAPH_CFLAGS) \
+    $(GIO_CFLAGS) \
+    $(GLIB_CFLAGS) \
+    $(GOA_CFLAGS) \
+    $(TRACKER_CFLAGS) \
+    $(NULL)
+
+gom_facebook_miner_LDADD = \
+    libgom-1.0.la  \
+    $(GFBGRAPH_LIBS) \
+    $(GIO_LIBS) \
+    $(GLIB_LIBS) \
+    $(GOA_LIBS) \
+    $(TRACKER_LIBS) \
+    $(NULL)
+
 gom_flickr_miner_SOURCES = \
     gom-flickr-miner-main.c \
     gom-flickr-miner.c \
diff --git a/src/gom-facebook-miner-main.c b/src/gom-facebook-miner-main.c
new file mode 100644
index 0000000..596ca9b
--- /dev/null
+++ b/src/gom-facebook-miner-main.c
@@ -0,0 +1,33 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2; -*- */
+/*
+ * Copyright (c) 2013 The GNOME Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Author: Álvaro Peña <alvaropg gmail com>
+ *
+ */
+
+#include "config.h"
+
+#define INSIDE_MINER
+#define MINER_NAME "FACEBOOK"
+#define MINER_TYPE GOM_TYPE_FACEBOOK_MINER
+#define MINER_BUS_NAME "org.gnome.OnlineMiners.Facebook"
+#define MINER_OBJECT_PATH "/org/gnome/OnlineMiners/Facebook"
+
+#include "gom-facebook-miner.h"
+#include "gom-miner-main.c"
diff --git a/src/gom-facebook-miner.c b/src/gom-facebook-miner.c
new file mode 100644
index 0000000..972afd8
--- /dev/null
+++ b/src/gom-facebook-miner.c
@@ -0,0 +1,375 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2; -*- */
+/*
+ * GNOME Online Miners - crawls through your online content
+ * Copyright (c) 2013 The GNOME Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Author: Álvaro Peña <alvaropg gmail com>
+ *
+ */
+
+#include "config.h"
+
+#include <goa/goa.h>
+#include <gfbgraph/gfbgraph.h>
+#include <gfbgraph/gfbgraph-goa-authorizer.h>
+
+#include "gom-facebook-miner.h"
+
+#define MINER_IDENTIFIER  "gd:facebook:miner:7735c11213574dbb9a589fe6b9bad06a"
+#define MINER_VERSION     1
+#define GOA_PROVIDER_TYPE "facebook"
+
+/* object functions */
+static void     gom_facebook_miner_class_init    (GomFacebookMinerClass *klass);
+static void     gom_facebook_miner_init          (GomFacebookMiner *miner);
+/* miner functions */
+static GObject *create_service                  (GomMiner *self, GoaObject *object);
+static void     query_facebook                  (GomAccountMinerJob *job, GError **error);
+/* private functions */
+static gboolean account_miner_job_lookup_album  (GomAccountMinerJob *job, GFBGraphAlbum *album, const gchar 
*creator, GError **error);
+static gboolean account_miner_job_process_photo (GomAccountMinerJob *job, GFBGraphPhoto *photo, const gchar 
*parent_identifier, const gchar *creator,GError **error);
+
+G_DEFINE_TYPE (GomFacebookMiner, gom_facebook_miner, GOM_TYPE_MINER)
+
+static void
+gom_facebook_miner_class_init (GomFacebookMinerClass *klass)
+{
+  GomMinerClass *miner_class = GOM_MINER_CLASS (klass);
+
+  miner_class->goa_provider_type = GOA_PROVIDER_TYPE;
+  miner_class->miner_identifier = MINER_IDENTIFIER;
+  miner_class->version = MINER_VERSION;
+
+  miner_class->create_service = create_service;
+  miner_class->query = query_facebook;
+}
+
+static void
+gom_facebook_miner_init (GomFacebookMiner *miner)
+{
+}
+
+static GObject *
+create_service (GomMiner *self, GoaObject *object)
+{
+  GFBGraphGoaAuthorizer *authorizer;
+  GError *error = NULL;
+
+  authorizer = gfbgraph_goa_authorizer_new (object);
+
+  if (GFBGRAPH_IS_GOA_AUTHORIZER (authorizer)) {
+    g_debug ("GFBGraph GOA authorizer created");
+    g_object_ref (authorizer);
+  }
+
+  gfbgraph_authorizer_refresh_authorization (GFBGRAPH_AUTHORIZER (authorizer), NULL, &error);
+  if (error != NULL) {
+    g_warning ("Error refreshing authorization (%d): %s", error->code, error->message);
+  }
+
+  return G_OBJECT (authorizer);
+}
+
+static void
+query_facebook (GomAccountMinerJob *job, GError **error)
+{
+  GFBGraphUser *me;
+  gchar *me_name;
+  GList *albums = NULL;
+  GList *album_iter = NULL;
+  GError *tmp_error = NULL;
+
+  me = gfbgraph_user_get_me (GFBGRAPH_AUTHORIZER (job->service), &tmp_error);
+  if (tmp_error != NULL) {
+    g_warning ("Error getting \"me\" user. Error (%d): %s", tmp_error->code, tmp_error->message);
+    goto out;
+  }
+
+  g_object_get (me, "name", &me_name, NULL);
+
+  albums = gfbgraph_user_get_albums (me, GFBGRAPH_AUTHORIZER (job->service), &tmp_error);
+  if (tmp_error != NULL) {
+    g_warning ("Error getting albums. Error (%d): %s", tmp_error->code, tmp_error->message);
+    goto out;
+  }
+
+  album_iter = albums;
+  while (album_iter) {
+    GFBGraphAlbum *album;
+
+    album = GFBGRAPH_ALBUM (album_iter->data);
+    account_miner_job_lookup_album (job, album, (const gchar*) me_name, error);
+
+    album_iter = g_list_next (album_iter);
+  }
+
+ out:
+  if (tmp_error != NULL)
+    g_propagate_error (error, tmp_error);
+
+  if (albums != NULL)
+    g_list_free_full (albums, g_object_unref);
+
+  if (me_name)
+    g_free (me_name);
+
+  g_clear_object (&me);
+}
+
+/* TODO: Until GFBGraph parse the "from" node section, we require the album creator (generally the logged 
user) */
+static gboolean
+account_miner_job_lookup_album (GomAccountMinerJob *job, GFBGraphAlbum *album, const gchar *creator, GError 
**error)
+{
+  const gchar *album_id;
+  gchar *album_name;
+  gchar *album_description;
+  const gchar *album_link;
+  const gchar *album_created_time;
+  gchar *identifier;
+  const gchar *class = "nfo:DataContainer";
+  gchar *resource = NULL;
+  gboolean resource_exists;
+  gchar *contact_resource;
+  GList *photos = NULL;
+  GList *photo_iter = NULL;
+
+  album_id = gfbgraph_node_get_id (GFBGRAPH_NODE (album));
+  album_link = gfbgraph_node_get_link (GFBGRAPH_NODE (album));
+  album_created_time = gfbgraph_node_get_created_time (GFBGRAPH_NODE (album));
+  g_object_get (album,
+                "name", &album_name,
+                "description", &album_description,
+                NULL);
+
+  identifier = g_strdup_printf ("photos:collection:facebook:%s", album_id);
+
+  /* remove from the list of the previous resources */
+  g_hash_table_remove (job->previous_resources, identifier);
+
+  resource = gom_tracker_sparql_connection_ensure_resource (job->connection,
+                                                            job->cancellable, error,
+                                                            &resource_exists,
+                                                            job->datasource_urn, identifier,
+                                                            "nfo:RemoteDataObject", class,
+                                                            NULL);
+
+  if (*error != NULL)
+    goto out;
+
+  gom_tracker_update_datasource (job->connection, job->datasource_urn,
+                                 resource_exists, identifier, resource,
+                                 job->cancellable, error);
+
+  if (*error != NULL)
+    goto out;
+
+  /* TODO: Check updated time to avoid updating the photo if has not been modified since our last run */
+
+  /* insert album url */
+  gom_tracker_sparql_connection_insert_or_replace_triple (job->connection,
+                                                          job->cancellable, error,
+                                                          job->datasource_urn, resource,
+                                                          "nie:url", album_link);
+  if (*error != NULL)
+    goto out;
+
+  /* insert description */
+  gom_tracker_sparql_connection_insert_or_replace_triple (job->connection,
+                                                          job->cancellable, error,
+                                                          job->datasource_urn, resource,
+                                                          "nie:description", album_description);
+  if (*error != NULL)
+    goto out;
+
+  /* insert filename */
+  gom_tracker_sparql_connection_insert_or_replace_triple (job->connection,
+                                                          job->cancellable, error,
+                                                          job->datasource_urn, resource,
+                                                          "nfo:fileName", album_name);
+  if (*error != NULL)
+    goto out;
+
+  gom_tracker_sparql_connection_insert_or_replace_triple (job->connection,
+                                                          job->cancellable, error,
+                                                          job->datasource_urn, resource,
+                                                          "nie:contentCreated", album_created_time);
+  if (*error != NULL)
+    goto out;
+
+  contact_resource = gom_tracker_utils_ensure_contact_resource (job->connection,
+                                                                job->cancellable, error,
+                                                                job->datasource_urn, creator);
+  if (*error != NULL)
+    goto out;
+
+  gom_tracker_sparql_connection_insert_or_replace_triple (job->connection,
+                                                          job->cancellable, error,
+                                                          job->datasource_urn, resource,
+                                                          "nco:creator", contact_resource);
+  g_free (contact_resource);
+  if (*error != NULL)
+    goto out;
+
+  /* Album photos */
+  photos = gfbgraph_node_get_connection_nodes (GFBGRAPH_NODE (album), GFBGRAPH_TYPE_PHOTO,
+                                               GFBGRAPH_AUTHORIZER (job->service),
+                                               error);
+  if (*error != NULL)
+    goto out;
+
+  photo_iter = photos;
+  while (photo_iter) {
+    GFBGraphPhoto *photo;
+
+    photo = GFBGRAPH_PHOTO (photo_iter->data);
+    account_miner_job_process_photo (job, photo, (const gchar*) identifier, creator, error);
+
+    photo_iter = g_list_next (photo_iter);
+  }
+
+ out:
+  g_free (album_name);
+  g_free (album_description);
+  g_free (identifier);
+  g_free (resource);
+
+  if (photos != NULL)
+    g_list_free_full (photos, g_object_unref);
+
+  if (*error != NULL)
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+account_miner_job_process_photo (GomAccountMinerJob *job, GFBGraphPhoto *photo, const gchar 
*parent_identifier, const gchar *creator, GError **error)
+{
+  gchar *photo_id;
+  gchar *photo_name;
+  gchar *photo_source;
+  gchar *photo_created_time;
+  gchar *identifier;
+  const gchar *class = "nmm:Photo";
+  gchar *resource = NULL;
+  gboolean resource_exists;
+  gchar *contact_resource;
+  gchar *parent_resource_urn;
+
+  g_object_get (photo,
+                "id", &photo_id,
+                "name", &photo_name,
+                "source", &photo_source,
+                "created_time", &photo_created_time,
+                NULL);
+
+  identifier = g_strdup_printf ("facebook:photos:%s", photo_id);
+
+  /* remove from the list of the previous resources */
+  g_hash_table_remove (job->previous_resources, identifier);
+
+  resource = gom_tracker_sparql_connection_ensure_resource (job->connection,
+                                                            job->cancellable, error,
+                                                            &resource_exists,
+                                                            job->datasource_urn, identifier,
+                                                            "nfo:RemoteDataObject", class, NULL);
+  if (*error != NULL)
+    goto out;
+
+  gom_tracker_update_datasource (job->connection, job->datasource_urn,
+                                 resource_exists, identifier, resource,
+                                 job->cancellable, error);
+  if (*error != NULL)
+    goto out;
+
+  /* TODO: Check updated time to avoid updating the photo if has not been modified since our last run */
+
+  /* insert url */
+  gom_tracker_sparql_connection_insert_or_replace_triple (job->connection,
+                                                          job->cancellable, error,
+                                                          job->datasource_urn, resource,
+                                                          "nie:url", photo_source);
+  if (*error != NULL)
+    goto out;
+
+  /* link with the album */
+  parent_resource_urn = gom_tracker_sparql_connection_ensure_resource (job->connection,
+                                                                       job->cancellable, error,
+                                                                       NULL,
+                                                                       job->datasource_urn, 
parent_identifier,
+                                                                       "nfo:RemoteDataObject", 
"nfo:DataContainer", NULL);
+  if (*error != NULL)
+    goto out;
+
+  gom_tracker_sparql_connection_insert_or_replace_triple (job->connection,
+                                                          job->cancellable, error,
+                                                          job->datasource_urn, resource,
+                                                          "nie:isPartOf", parent_resource_urn);
+  g_free (parent_resource_urn);
+
+  if (*error != NULL)
+    goto out;
+
+  /* insert the photo title, sometimes, there is not a photo name, so we use the ugly photo id */
+  if (photo_name == NULL) {
+    photo_name = g_strdup (photo_id);
+  }
+  gom_tracker_sparql_connection_insert_or_replace_triple (job->connection,
+                                                          job->cancellable, error,
+                                                          job->datasource_urn, resource,
+                                                          "nie:title", photo_name);
+  if (*error != NULL)
+    goto out;
+
+  /* created time */
+  gom_tracker_sparql_connection_insert_or_replace_triple (job->connection,
+                                                          job->cancellable, error,
+                                                          job->datasource_urn, resource,
+                                                          "nie:contentCreated", photo_created_time);
+  if (*error != NULL)
+    goto out;
+
+  /* Creator */
+  contact_resource = gom_tracker_utils_ensure_contact_resource (job->connection,
+                                                                job->cancellable, error,
+                                                                job->datasource_urn, creator);
+  if (*error != NULL)
+    goto out;
+
+  gom_tracker_sparql_connection_insert_or_replace_triple (job->connection,
+                                                          job->cancellable, error,
+                                                          job->datasource_urn, resource,
+                                                          "nco:creator", contact_resource);
+  g_free (contact_resource);
+  if (*error != NULL)
+    goto out;
+
+ out:
+  g_free (photo_id);
+  g_free (photo_name);
+  g_free (photo_source);
+  g_free (photo_created_time);
+  g_free (identifier);
+  g_free (resource);
+  g_free (contact_resource);
+
+  if (*error != NULL)
+    return FALSE;
+
+  return TRUE;
+}
diff --git a/src/gom-facebook-miner.h b/src/gom-facebook-miner.h
new file mode 100644
index 0000000..9f582b8
--- /dev/null
+++ b/src/gom-facebook-miner.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 2; tab-width: 2; -*- */
+/*
+ * GNOME Online Miners - crawls through your online content
+ * Copyright (c) 2013 The GNOME Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ *
+ * Author: Álvaro Peña <alvaropg gmail com>
+ *
+ */
+
+#ifndef __GOM_FACEBOOK_MINER_H__
+#define __GOM_FACEBOOK_MINER_H__
+
+#include <gio/gio.h>
+#include "gom-miner.h"
+
+G_BEGIN_DECLS
+
+#define GOM_TYPE_FACEBOOK_MINER gom_facebook_miner_get_type()
+
+#define GOM_FACEBOOK_MINER(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
+   GOM_TYPE_FACEBOOK_MINER, GomFacebookMiner))
+
+#define GOM_FACEBOOK_MINER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), \
+   GOM_TYPE_FACEBOOK_MINER, GomFacebookMinerClass))
+
+#define GOM_IS_FACEBOOK_MINER(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
+   GOM_TYPE_FACEBOOK_MINER))
+
+#define GOM_IS_FACEBOOK_MINER_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), \
+   GOM_TYPE_FACEBOOK_MINER))
+
+#define GOM_FACEBOOK_MINER_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), \
+   GOM_TYPE_FACEBOOK_MINER, GomFacebookMinerClass))
+
+typedef struct _GomFacebookMiner GomFacebookMiner;
+typedef struct _GomFacebookMinerClass GomFacebookMinerClass;
+typedef struct _GomFacebookMinerPrivate GomFacebookMinerPrivate;
+
+struct _GomFacebookMiner {
+  GomMiner parent;
+
+  GomFacebookMinerPrivate *priv;
+};
+
+struct _GomFacebookMinerClass {
+  GomMinerClass parent_class;
+};
+
+GType gom_facebook_miner_get_type(void);
+
+G_END_DECLS
+
+#endif /* __GOM_FACEBOOK_MINER_H__ */


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