[discident-glib] Add EAN query support
- From: Bastien Nocera <hadess src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [discident-glib] Add EAN query support
- Date: Thu, 16 Dec 2010 19:10:22 +0000 (UTC)
commit 1546ded8f8c90e05f4f3d31ed93dead59ae43659
Author: Bastien Nocera <hadess hadess net>
Date: Thu Dec 16 19:08:56 2010 +0000
Add EAN query support
Only sync functions right now.
configure.ac | 6 +-
discident-glib/Makefile.am | 12 +-
discident-glib/discident-ean-glib.c | 361 +++++++++++++++++++++++++++++++++
discident-glib/discident-ean-glib.h | 61 ++++++
discident-glib/discident-glib.symbols | 5 +
discident-glib/test-diglib.c | 28 ++-
6 files changed, 462 insertions(+), 11 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index cc0f0b6..630765a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -51,10 +51,12 @@ GTK_DOC_CHECK(1.9)
AC_DEFINE_UNQUOTED(LOCALEDIR, "${prefix}/share/locale", [Directory for the localization files])
-dnl Requires for the properties window
+dnl Requires for the library
PKG_CHECK_MODULES(DISCIDENT,
gio-2.0
- json-glib-1.0)
+ json-glib-1.0
+ libsoup-gnome-2.4
+ libxml-2.0)
GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0`
AC_SUBST(GLIB_GENMARSHAL)
diff --git a/discident-glib/Makefile.am b/discident-glib/Makefile.am
index 5ed739e..2ed8d08 100644
--- a/discident-glib/Makefile.am
+++ b/discident-glib/Makefile.am
@@ -7,7 +7,11 @@ lib_LTLIBRARIES = libdiscident-glib.la
public_files = \
discident-glib.c \
- discident-glib.h
+ discident-glib.h \
+ discident-ean-glib.c \
+ discident-ean-glib.h \
+ discident-error.c \
+ discident-error.h
libdiscident_glib_la_SOURCES = \
$(public_files) \
@@ -22,7 +26,7 @@ libdiscident_glib_la_LDFLAGS = \
-export-symbols $(srcdir)/discident-glib.symbols
diglibdir = $(pkgincludedir)
-diglib_HEADERS = discident-glib.h
+diglib_HEADERS = discident-glib.h discident-ean-glib.h
AM_CFLAGS = -I$(srcdir) $(DISCIDENT_CFLAGS) $(COMMON_CFLAGS) $(WARN_CFLAGS) $(DISABLE_DEPRECATED)
@@ -36,8 +40,8 @@ if HAVE_INTROSPECTION
introspection_files = $(public_files)
DiscidentGlib-1.0.gir: libdiscident-glib.la
-DiscidentGlib_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0
-DiscidentGlib_1_0_gir_PACKAGES = gobject-2.0 gmodule-2.0 glib-2.0 gio-2.0
+DiscidentGlib_1_0_gir_INCLUDES = GObject-2.0 Gio-2.0 Json-1.0 SoupGNOME-2.4
+DiscidentGlib_1_0_gir_PACKAGES = gobject-2.0 gmodule-2.0 glib-2.0 gio-2.0 libsoup-gnome-2.4 json-glib-1.0
DiscidentGlib_1_0_gir_CFLAGS = -I$(srcdir)
DiscidentGlib_1_0_gir_LIBS = libdiscident-glib.la
DiscidentGlib_1_0_gir_SCANNERFLAGS = --symbol-prefix=discident_ --identifier-prefix=Discident --pkg-export=discident-glib-1.0
diff --git a/discident-glib/discident-ean-glib.c b/discident-glib/discident-ean-glib.c
new file mode 100644
index 0000000..6d87dc2
--- /dev/null
+++ b/discident-glib/discident-ean-glib.c
@@ -0,0 +1,361 @@
+/*
+ Copyright (C) 2010 Bastien Nocera
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA.
+
+ Authors: Bastien Nocera <hadess hadess net>
+
+ */
+
+#include <string.h>
+
+#include <libsoup/soup-gnome.h>
+#include <glib/gprintf.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+
+#include "discident-ean-glib.h"
+#include "discident-error.h"
+
+#define APPID "19d78263508549b98db3809824f79c4d0fcad11b"
+#define EMULATED_VERSION "2.7.0"
+#define ORIGINAL_QUERY "http://redlaser.com:8008/getinfo.ashx?v=" EMULATED_VERSION "&app=rl&responseId=20100708&udid=" APPID
+#define SEARCH_URL "http://%s/searchresults.ashx"
+#define SEARCH_QUERY "barcode=%s&btype=EAN13&cachedimages=ebay_small,googlelogo_24,thefindlogo¤cy=GBP&locale=en_GB&udid=" APPID "&v=" EMULATED_VERSION
+
+struct DiscidentEanPrivate {
+ char *server;
+ gboolean enabled;
+ char *message;
+};
+
+G_DEFINE_TYPE (DiscidentEan, discident_ean, G_TYPE_OBJECT)
+
+static void
+discident_ean_finalize (GObject *object)
+{
+ DiscidentEan *ean;
+
+ ean = DISCIDENT_EAN (object);
+
+ g_free (ean->priv->server);
+ ean->priv->server = NULL;
+
+ g_free (ean->priv->message);
+ ean->priv->message = NULL;
+
+ G_OBJECT_CLASS (discident_ean_parent_class)->finalize (object);
+}
+
+static void
+discident_ean_class_init (DiscidentEanClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = discident_ean_finalize;
+
+ g_type_class_add_private (klass, sizeof (DiscidentEanPrivate));
+}
+
+static void
+discident_ean_init (DiscidentEan *ean)
+{
+ ean->priv = G_TYPE_INSTANCE_GET_PRIVATE ((ean), DISCIDENT_TYPE_EAN, DiscidentEanPrivate);
+ ean->priv->enabled = TRUE;
+}
+
+static gboolean
+parse_login_response (DiscidentEan *ean,
+ char *response)
+{
+ GHashTable *hash;
+ char **items;
+ guint i;
+ const char *disable_capture;
+
+ hash = g_hash_table_new_full (g_str_hash, g_str_equal,
+ g_free, g_free);
+
+ /* Remove trailing '|' */
+ if (response[strlen (response) - 1] == '|')
+ response[strlen (response) - 1] = '\0';
+
+ items = g_strsplit (response, ",", -1);
+ for (i = 0; items[i] != NULL; i++) {
+ char **vars;
+
+ vars = g_strsplit (items[i], "=", -1);
+ if (items[0] == NULL || items[1] == NULL) {
+ g_strfreev (items);
+ continue;
+ }
+ g_hash_table_insert (hash, g_ascii_strdown (vars[0], -1), g_strdup (vars[1]));
+ g_strfreev (vars);
+ }
+ g_strfreev (items);
+
+ ean->priv->server = g_strdup (g_hash_table_lookup (hash, "ssvr"));
+ if (ean->priv->server == NULL) {
+ g_hash_table_destroy (hash);
+ return FALSE;
+ }
+ ean->priv->message = g_strdup (g_hash_table_lookup (hash, "disablecapturemessage"));
+ disable_capture = g_hash_table_lookup (hash, "disablecapture");
+ if (disable_capture != NULL &&
+ g_ascii_strncasecmp (disable_capture, "no", 2) != 0) {
+ ean->priv->enabled = FALSE;
+ }
+
+ g_hash_table_destroy (hash);
+
+ return TRUE;
+}
+
+gboolean
+discident_ean_login (DiscidentEan *ean,
+ GError **error)
+{
+ SoupSession *session;
+ SoupMessage *msg;
+ char *response;
+ int ret;
+
+ g_return_val_if_fail (DISCIDENT_IS_EAN (ean), FALSE);
+
+ session = soup_session_sync_new_with_options (
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_GNOME,
+ NULL);
+
+ msg = soup_message_new ("GET", ORIGINAL_QUERY);
+ g_assert (msg != NULL);
+
+ response = NULL;
+
+ ret = soup_session_send_message (session, msg);
+ if (SOUP_STATUS_IS_SUCCESSFUL (ret) &&
+ msg->response_body != NULL) {
+ response = g_strdup (msg->response_body->data);
+ }
+ g_object_unref (msg);
+ g_object_unref (session);
+
+ if (response == NULL) {
+ g_set_error (error, SOUP_HTTP_ERROR, ret, "Could not login to EAN service");
+ return FALSE;
+ }
+
+ if (parse_login_response (ean, response) == FALSE) {
+ g_set_error (error, DISCIDENT_ERROR, DISCIDENT_ERROR_PARSE, "Failed to parse login response from EAN service");
+ g_free (response);
+ return FALSE;
+ }
+ g_free (response);
+
+ return TRUE;
+}
+
+static char *
+get_search_uri (DiscidentEan *ean)
+{
+ return g_strdup_printf (SEARCH_URL, ean->priv->server);
+}
+
+static char *
+get_post_data (const char *barcode)
+{
+ return g_strdup_printf (SEARCH_QUERY, barcode);
+}
+
+static char *
+uncompress (const char *data,
+ gssize len)
+{
+ GConverter *converter;
+ GInputStream *input_stream, *stream;
+ GOutputStream *output;
+ char *ret;
+
+ input_stream = g_memory_input_stream_new ();
+ converter = G_CONVERTER (g_zlib_decompressor_new (G_ZLIB_COMPRESSOR_FORMAT_GZIP));
+ stream = (GInputStream *) g_converter_input_stream_new (input_stream, converter);
+ output = (GOutputStream *) g_memory_output_stream_new (NULL, 0, g_realloc, g_free);
+
+ g_memory_input_stream_add_data ((GMemoryInputStream *) input_stream,
+ g_memdup (data, len), len,
+ (GDestroyNotify) g_free);
+
+ if (!g_output_stream_splice (G_OUTPUT_STREAM (output), stream,
+ G_OUTPUT_STREAM_SPLICE_CLOSE_SOURCE,
+ NULL, NULL)) {
+ g_object_unref (output);
+ return NULL;
+ }
+
+ ret = g_strdup (g_memory_output_stream_get_data ((GMemoryOutputStream *) output));
+ g_object_unref (output);
+
+ return ret;
+}
+
+static gboolean
+parse_lookup_response (const char *response,
+ char **ret_title,
+ char **ret_img_url)
+{
+ xmlDocPtr doc;
+ xmlChar *title, *img_url;
+
+ doc = xmlParseMemory (response, strlen (response));
+ if (doc == NULL)
+ doc = xmlRecoverMemory (response, strlen (response));
+
+ if(!doc ||
+ !doc->children ||
+ !doc->children->name ||
+ g_ascii_strcasecmp ((char *)doc->children->name, "response") != 0) {
+ if (doc != NULL)
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+
+ title = xmlGetProp (doc->children, (const xmlChar *) "title");
+ if (title == NULL) {
+ xmlFreeDoc (doc);
+ return FALSE;
+ }
+ *ret_title = (char *) title;
+
+ img_url = xmlGetProp (doc->children, (const xmlChar *) "imageUrl");
+ if (img_url != NULL)
+ *ret_img_url = (char *) img_url;
+
+ xmlFreeDoc (doc);
+
+ return TRUE;
+}
+
+gboolean
+discident_ean_lookup (DiscidentEan *ean,
+ const char *barcode,
+ char **title,
+ char **img_url,
+ GError **error)
+{
+ SoupSession *session;
+ SoupMessage *msg;
+ char *uri, *data, *response;
+ int ret;
+
+ g_return_val_if_fail (DISCIDENT_IS_EAN (ean), FALSE);
+ g_return_val_if_fail (title != NULL, FALSE);
+
+ session = soup_session_sync_new_with_options (
+ SOUP_SESSION_ADD_FEATURE_BY_TYPE, SOUP_TYPE_PROXY_RESOLVER_GNOME,
+ NULL);
+
+ uri = get_search_uri (ean);
+ msg = soup_message_new ("POST", uri);
+ g_message ("uri %s", uri);
+ g_free (uri);
+
+ data = get_post_data (barcode);
+ g_message ("post %s", data);
+ soup_message_set_request (msg, "application/x-www-form-urlencoded",
+ SOUP_MEMORY_TAKE, data, strlen (data));
+
+ response = NULL;
+
+ ret = soup_session_send_message (session, msg);
+ if (SOUP_STATUS_IS_SUCCESSFUL (ret) &&
+ msg->response_body != NULL) {
+ response = uncompress (msg->response_body->data,
+ msg->response_body->length);
+ /* Probably not compressed */
+ if (response == NULL) {
+ response = g_strndup (msg->response_body->data,
+ msg->response_body->length);
+ }
+ }
+ g_object_unref (msg);
+ g_object_unref (session);
+
+ if (response == NULL) {
+ g_set_error (error, SOUP_HTTP_ERROR, ret, "Could not login to EAN service");
+ return FALSE;
+ }
+
+ if (parse_lookup_response (response, title, img_url) == FALSE) {
+ g_set_error (error, DISCIDENT_ERROR, DISCIDENT_ERROR_PARSE, "Failed to parse response from EAN service");
+ return FALSE;
+ }
+
+ g_free (response);
+
+ return TRUE;
+}
+
+DiscidentEan *
+discident_ean_new (void)
+{
+ return g_object_new (DISCIDENT_TYPE_EAN, NULL);
+}
+
+#if 0
+void
+discident_ean_login_async (DiscidentEan *ean,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new (G_OBJECT (directory),
+ callback,
+ user_data,
+ discident_ean_login_async);
+
+ if (cancellable != NULL) {
+ g_object_set_data_full (G_OBJECT (simple), "cancellable",
+ g_object_ref (cancellable), g_object_unref);
+ }
+
+ discident_get_gtin_file_async (directory,
+ cancellable,
+ on_discident_got_gtin,
+ simple);
+}
+
+gboolean
+discident_ean_login_finish (DiscidentEan *ean,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res);
+ char *ret;
+
+ g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == discident_ean_login_async);
+
+ ret = NULL;
+
+ if (g_simple_async_result_propagate_error (simple, error))
+ goto out;
+
+ ret = g_simple_async_result_get_op_res_gpointer (simple);
+
+out:
+ return ret;
+}
+#endif
diff --git a/discident-glib/discident-ean-glib.h b/discident-glib/discident-ean-glib.h
new file mode 100644
index 0000000..5f3898c
--- /dev/null
+++ b/discident-glib/discident-ean-glib.h
@@ -0,0 +1,61 @@
+/*
+ Copyright (C) 2010 Bastien Nocera
+
+ The Gnome Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public License as
+ published by the Free Software Foundation; either version 2 of the
+ License, or (at your option) any later version.
+
+ The Gnome 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public
+ License along with the Gnome Library; see the file COPYING.LIB. If not,
+ write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301 USA.
+
+ Authors: Bastien Nocera <hadess hadess net>
+
+ */
+
+#ifndef DISCIDENT_EAN_GLIB_H
+#define DISCIDENT_EAN_GLIB_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define DISCIDENT_TYPE_EAN (discident_ean_get_type ())
+#define DISCIDENT_EAN(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), DISCIDENT_TYPE_EAN, DiscidentEan))
+#define DISCIDENT_EAN_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), DISCIDENT_TYPE_EAN, DiscidentEanClass))
+#define DISCIDENT_IS_EAN(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), DISCIDENT_TYPE_EAN))
+#define DISCIDENT_IS_EAN_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), DISCIDENT_TYPE_EAN))
+#define DISCIDENT_EAN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), DISCIDENT_TYPE_EAN, DiscidentEanClass))
+
+typedef struct DiscidentEanPrivate DiscidentEanPrivate;
+
+typedef struct {
+ GObject parent;
+ DiscidentEanPrivate *priv;
+} DiscidentEan;
+
+typedef struct {
+ GObjectClass parent_class;
+} DiscidentEanClass;
+
+GType discident_ean_get_type (void);
+DiscidentEan *discident_ean_new (void);
+gboolean discident_ean_login (DiscidentEan *ean,
+ GError **error);
+
+gboolean discident_ean_lookup (DiscidentEan *ean,
+ const char *barcode,
+ char **title,
+ char **img_url,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* DISCIDENT_EAN_GLIB_H */
diff --git a/discident-glib/discident-glib.symbols b/discident-glib/discident-glib.symbols
index 7a1ebe2..7e0c03c 100644
--- a/discident-glib/discident-glib.symbols
+++ b/discident-glib/discident-glib.symbols
@@ -6,3 +6,8 @@ discident_get_title_file_async
discident_get_title_file_finish
generate_hash
discident_get_title_for_gtin
+discident_ean_get_type
+discident_ean_new
+discident_ean_login
+discident_ean_lookup
+discident_error_quark
diff --git a/discident-glib/test-diglib.c b/discident-glib/test-diglib.c
index 57c3eee..3494e58 100644
--- a/discident-glib/test-diglib.c
+++ b/discident-glib/test-diglib.c
@@ -4,6 +4,7 @@
#include <glib.h>
#include <gio/gio.h>
#include <discident-glib.h>
+#include <discident-ean-glib.h>
#include <discident-glib-private.h>
static gboolean option_async = FALSE;
@@ -63,11 +64,12 @@ test_json (void)
const char *gtin;
const char *title;
} dvds[] = {
- { "3809DA3F-8323-2E48-70C6-861B34968674", NULL },
- { "5F03F0D5-6AB6-FDB4-43AE-825693898CFF", "The Kite Runner" },
- { "4C059E8A-37E4-493E-6272-F9A713DB5AA9", "55853 STRAIGHT_STORY" },
- { "724DAC2A-6BB7-21E8-2F85-BCD0A56ED995", "WOODSMAN" },
- { "D2740096-2507-09FC-EE0F-D577CBF98536", "ETRE_AVOIR" },
+ { "3809DA3F-8323-2E48-70C6-861B34968674", "ALEXANDER_NEVSKY" },
+ /* Disabled as somebody busted the actual title
+ { "5F03F0D5-6AB6-FDB4-43AE-825693898CFF", "The Kite Runner" }, */
+ { "4C059E8A-37E4-493E-6272-F9A713DB5AA9", "Straight Story" },
+ { "724DAC2A-6BB7-21E8-2F85-BCD0A56ED995", "The Woodsman" },
+ { "D2740096-2507-09FC-EE0F-D577CBF98536", "Ã?tre et Avoir" },
};
for (i = 0; i < G_N_ELEMENTS (dvds); i++) {
@@ -76,6 +78,21 @@ test_json (void)
}
static void
+test_ean (void)
+{
+ DiscidentEan *ean;
+ char *title, *img_url;
+
+ ean = discident_ean_new ();
+ g_assert (discident_ean_login (ean, NULL) != FALSE);
+
+ /* The Little Book of Stress: Calm is for Wimps, Get Real, Get Stressed */
+ g_assert (discident_ean_lookup (ean, "9780091865856", &title, &img_url, NULL) != FALSE);
+ g_assert_cmpstr ("The Little Book of Stress: Calm is for Wimps, Get Real, Get Stressed by Rohan Candappa (Paperback, 1998)", ==, title);
+ g_assert (img_url != NULL);
+}
+
+static void
discident_title_print (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
@@ -152,6 +169,7 @@ int main (int argc, char **argv)
}
if (uris == NULL) {
+ g_test_add_func ("/discident/ean", test_ean);
g_test_add_func ("/discident/hash", test_hash);
g_test_add_func ("/discident/file_list", test_file_list);
g_test_add_func ("/discident/json", test_json);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]