summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVictor Toso <me@victortoso.com>2013-05-13 02:16:13 -0300
committerJuan A. Suarez Romero <jasuarez@igalia.com>2013-05-22 15:19:27 +0000
commit744174d64fba52b2ace9108aa6826ee196ef98fe (patch)
tree20ca8592a27b9a7ff3c965aac7718d51a05d8988
parentd38fecb43d287bae844e4b80158cead538ddd252 (diff)
magnatune: Adding support to download database
All database and crc checks are made when user interact with the plugin. If there is no database and no internet connection, plugin_init fails. When current database has 7 days old the plugin starts to check for a newer database. To avoid checking crc to *every* user request a time interval of 12 hours is used. https://bugzilla.gnome.org/show_bug.cgi?id=698523
-rw-r--r--configure.ac7
-rw-r--r--src/magnatune/grl-magnatune.c332
2 files changed, 333 insertions, 6 deletions
diff --git a/configure.ac b/configure.ac
index 2b5bba7..ab1e038 100644
--- a/configure.ac
+++ b/configure.ac
@@ -720,6 +720,9 @@ AC_ARG_ENABLE(magnatune,
if test "x$HAVE_SQLITE" = "xno"; then
AC_MSG_ERROR([sqlite3 not found, install it or use --disable-magnatune])
fi
+ if test "x$HAVE_GRLNET" = "xno"; then
+ AC_MSG_ERROR([grilo-net not found, install it or use --disable-magnatune])
+ fi
;;
esac
],
@@ -742,9 +745,9 @@ MAGNATUNE_PLUGIN_ID="grl-magnatune"
AC_SUBST(MAGNATUNE_PLUGIN_ID)
AC_DEFINE_UNQUOTED([MAGNATUNE_PLUGIN_ID], ["$MAGNATUNE_PLUGIN_ID"], [Magnatune plugin ID])
-DEPS_MAGNATUNE_CFLAGS="$DEPS_CFLAGS $SQLITE_CFLAGS"
+DEPS_MAGNATUNE_CFLAGS="$DEPS_CFLAGS $GRLNET_CFLAGS $SQLITE_CFLAGS"
AC_SUBST(DEPS_MAGNATUNE_CFLAGS)
-DEPS_MAGNATUNE_LIBS="$DEPS_LIBS $SQLITE_LIBS"
+DEPS_MAGNATUNE_LIBS="$DEPS_LIBS $GRLNET_LIBS $SQLITE_LIBS"
AC_SUBST(DEPS_MAGNATUNE_LIBS)
# ----------------------------------------------------------
diff --git a/src/magnatune/grl-magnatune.c b/src/magnatune/grl-magnatune.c
index 2a3e454..0d11fa2 100644
--- a/src/magnatune/grl-magnatune.c
+++ b/src/magnatune/grl-magnatune.c
@@ -25,9 +25,11 @@
#endif
#include <glib.h>
+#include <glib/gstdio.h>
#include <glib/gi18n-lib.h>
#include <grilo.h>
#include <sqlite3.h>
+#include <net/grl-net.h>
#include "grl-magnatune.h"
@@ -59,11 +61,22 @@ GRL_LOG_DOMAIN_STATIC(magnatune_log_domain);
/* --- Files --- */
#define GRL_SQL_DB "grl-magnatune.db"
+#define GRL_SQL_NEW_DB "grl-magnatune-new.db"
+#define GRL_SQL_CRC "grl-magnatune-db.crc"
+#define GRL_SQL_NEW_CRC "grl-magnatune-new.crc"
/* --- URLs --- */
+#define URL_GET_DB "http://he3.magnatune.com/info/sqlite_normalized.db"
+#define URL_GET_CRC "http://magnatune.com/info/changed.txt"
+
#define URL_SONG_PLAY "http://he3.magnatune.com/all"
+/* --- Other --- */
+
+#define DB_UPDATE_TIME_INTERVAL (60 * 60 * 24 * 7)
+#define CRC_UPDATE_TIME_INTERVAL (60 * 60 * 12)
+
/* --- Plugin information --- */
#define SOURCE_ID "grl-magnatune"
@@ -84,6 +97,9 @@ struct _GrlMagnatunePrivate {
sqlite3 *db;
};
+struct _OperationSpec;
+typedef void (*GrlMagnatuneExecCb)(struct _OperationSpec *);
+
struct _OperationSpec {
GrlSource *source;
guint operation_id;
@@ -91,6 +107,7 @@ struct _OperationSpec {
guint skip;
guint count;
const gchar *text;
+ GrlMagnatuneExecCb magnatune_cb;
GrlSourceResultCb callback;
gpointer user_data;
guint error_code;
@@ -109,6 +126,10 @@ static const GList *grl_magnatune_source_supported_keys(GrlSource *source);
static void grl_magnatune_source_search(GrlSource *source,
GrlSourceSearchSpec *ss);
+static gboolean magnatune_has_network_conn(void);
+
+static void magnatune_get_db_async(OperationSpec *os);
+
/* ================== Magnatune Plugin ================= */
static gboolean
@@ -123,7 +144,7 @@ grl_magnatune_plugin_init(GrlRegistry *registry,
GRL_DEBUG("magnatune_plugin_init");
source = grl_magnatune_source_new();
- if (source->priv->db == NULL)
+ if (source->priv->db == NULL && magnatune_has_network_conn() == FALSE)
return FALSE;
grl_registry_register_source(registry,
@@ -177,6 +198,9 @@ grl_magnatune_source_init(GrlMagnatuneSource *source)
gint ret;
gchar *path;
gchar *db_path;
+ gchar *crc_path;
+ gchar *new_db_path;
+ gchar *new_crc_path;
GRL_DEBUG("magnatune_source_init");
@@ -185,14 +209,26 @@ grl_magnatune_source_init(GrlMagnatuneSource *source)
path = g_build_filename(g_get_user_data_dir(), "grilo-plugins", NULL);
db_path = g_build_filename(path, GRL_SQL_DB, NULL);
+ crc_path = g_build_filename(path, GRL_SQL_CRC, NULL);
+ new_db_path = g_build_filename(path, GRL_SQL_NEW_DB, NULL);
+ new_crc_path = g_build_filename(path, GRL_SQL_NEW_CRC, NULL);
if(!g_file_test(path, G_FILE_TEST_IS_DIR)) {
g_mkdir_with_parents(path, 0775);
}
if (g_file_test(db_path, G_FILE_TEST_EXISTS) == TRUE) {
- GRL_DEBUG("Opening database connection.");
+ if (g_file_test(new_db_path, G_FILE_TEST_EXISTS) == TRUE
+ && g_rename(new_db_path, db_path) == 0) {
+ GRL_DEBUG("New database in use.");
+ }
+
+ if (g_file_test(new_crc_path, G_FILE_TEST_EXISTS) == TRUE
+ && g_rename(new_crc_path, crc_path) == 0) {
+ GRL_DEBUG("New crc file in use.");
+ }
+ GRL_DEBUG("Opening database connection.");
ret = sqlite3_open(db_path, &source->priv->db);
if (ret != SQLITE_OK) {
GRL_WARNING("Failed to open database '%s': %s",
@@ -202,9 +238,12 @@ grl_magnatune_source_init(GrlMagnatuneSource *source)
source->priv->db = NULL;
}
} else {
- GRL_DEBUG("No database was found.");
+ GRL_DEBUG("No database was found. Download when user interact.");
}
+ g_free(new_crc_path);
+ g_free(new_db_path);
+ g_free(crc_path);
g_free(db_path);
g_free(path);
}
@@ -229,6 +268,281 @@ grl_magnatune_source_finalize(GObject *object)
/* ======================= Utilities ==================== */
+static gboolean
+magnatune_has_network_conn(void)
+{
+ gboolean ret = FALSE;
+ GNetworkMonitor *nm = NULL;
+ GSocketConnectable *addr = NULL;
+ GError *err = NULL;
+
+ nm = g_network_monitor_get_default();
+ addr = g_network_address_new("www.magnatune.com", 80);
+
+ ret = g_network_monitor_can_reach(nm, addr, NULL, &err);
+ if (ret == FALSE)
+ GRL_WARNING("Plugin can't reach magnatune.com - '%s'", err->message);
+
+ g_object_unref(addr);
+ return ret;
+}
+
+static void
+magnatune_get_crc_done(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ gchar *new_crc_path = NULL;
+ gchar *content = NULL;
+ gsize length = 0;
+ gboolean ret = FALSE;
+ GError *err = NULL;
+
+ GRL_DEBUG("magnatune_get_crc_done");
+
+ ret = grl_net_wc_request_finish(GRL_NET_WC(source_object),
+ res,
+ &content,
+ &length,
+ &err);
+ g_object_unref(source_object);
+
+ if (ret == TRUE) {
+ new_crc_path = g_build_filename(g_get_user_data_dir(), "grilo-plugins",
+ GRL_SQL_NEW_CRC, NULL);
+
+ ret = g_file_set_contents(new_crc_path,
+ content,
+ length,
+ &err);
+ if (ret == FALSE) {
+ GRL_WARNING("Failed to save crc-file from magnatune to: '%s' - '%s'",
+ new_crc_path, err->message);
+ }
+ g_free(new_crc_path);
+
+ } else {
+ GRL_WARNING("Failed to get crc-file from magnatune: %s", err->message);
+ }
+}
+
+static void
+magnatune_get_crc_async(void)
+{
+ GrlNetWc *wc = NULL;
+
+ GRL_DEBUG("magnatune_get_crc_async");
+
+ wc = grl_net_wc_new();
+ grl_net_wc_request_async(wc,
+ URL_GET_CRC,
+ NULL,
+ magnatune_get_crc_done,
+ NULL);
+}
+
+static void
+magnatune_get_db_done(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ gchar *db_path = NULL;
+ gchar *new_db_path = NULL;
+ gchar *content = NULL;
+ gsize length = 0;
+ gboolean ret = FALSE;
+ gboolean first_run = FALSE;
+ GError *err = NULL;
+ GError *err_fn = NULL;
+ OperationSpec *os = NULL;
+ GrlMagnatuneSource *source = NULL;
+
+ GRL_DEBUG("magnatune_get_db_done");
+ os = (OperationSpec *) user_data;
+ ret = grl_net_wc_request_finish(GRL_NET_WC(source_object),
+ res,
+ &content,
+ &length,
+ &err_fn);
+ g_object_unref(source_object);
+
+ if (ret == FALSE) {
+ err = g_error_new(GRL_CORE_ERROR,
+ GRL_CORE_ERROR_MEDIA_NOT_FOUND,
+ _("Failed to get database from magnatune: %s"),
+ err_fn->message);
+ g_error_free(err_fn);
+
+ if (os != NULL)
+ os->callback(os->source, os->operation_id, NULL, 0, os->user_data, err);
+
+ } else {
+ db_path = g_build_filename(g_get_user_data_dir(), "grilo-plugins",
+ GRL_SQL_DB, NULL);
+
+ /* If this is a first run, new database must be ready to use */
+ if (g_file_test(db_path, G_FILE_TEST_EXISTS) == FALSE) {
+ new_db_path = db_path;
+ first_run = TRUE;
+ } else {
+ g_free(db_path);
+ new_db_path = g_build_filename(g_get_user_data_dir(), "grilo-plugins",
+ GRL_SQL_NEW_DB, NULL);
+ }
+
+ GRL_WARNING("Saving database to path '%s'", new_db_path);
+ ret = g_file_set_contents(new_db_path,
+ content,
+ length,
+ &err_fn);
+
+ if (ret == FALSE) {
+ err = g_error_new(GRL_CORE_ERROR,
+ GRL_CORE_ERROR_MEDIA_NOT_FOUND,
+ _("Failed to save database from magnatune - '%s'"),
+ err_fn->message);
+ g_error_free(err_fn);
+
+ if (os != NULL)
+ os->callback(os->source, os->operation_id, NULL, 0, os->user_data, err);
+
+ } else if (first_run == TRUE) {
+ source = GRL_MAGNATUNE_SOURCE(os->source);
+
+ if (source->priv->db == NULL) {
+ GRL_DEBUG("Opening database connection.");
+ if (sqlite3_open(db_path, &source->priv->db) != SQLITE_OK) {
+ GRL_WARNING("Failed to open database '%s': %s",
+ db_path,
+ sqlite3_errmsg(source->priv->db));
+ sqlite3_close(source->priv->db);
+ source->priv->db = NULL;
+ }
+ }
+ }
+
+ g_free(new_db_path);
+ }
+
+ if (ret == TRUE && os != NULL) {
+ /* execute application's request */
+ os->magnatune_cb(os);
+ }
+}
+
+static void
+magnatune_get_db_async(OperationSpec *os)
+{
+ GrlNetWc *wc = NULL;
+
+ GRL_DEBUG("magnatune_get_db_async");
+
+ wc = grl_net_wc_new();
+ grl_net_wc_request_async(wc,
+ URL_GET_DB,
+ NULL,
+ magnatune_get_db_done,
+ os);
+}
+
+static void
+magnatune_check_update_done(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ gchar *crc_path = NULL;
+ gchar *new_crc_path = NULL;
+ gchar *new_crc = NULL;
+ gchar *old_crc = NULL;
+ gsize length = 0;
+ gboolean ret = FALSE;
+ GError *err = NULL;
+
+ ret = grl_net_wc_request_finish(GRL_NET_WC(source_object),
+ res,
+ &new_crc,
+ &length,
+ &err);
+ g_object_unref(source_object);
+
+ if (ret == TRUE) {
+ new_crc_path = g_build_filename(g_get_user_data_dir(), "grilo-plugins",
+ GRL_SQL_NEW_CRC, NULL);
+
+ ret = g_file_set_contents(new_crc_path,
+ new_crc,
+ length,
+ &err);
+
+ crc_path = g_build_filename(g_get_user_data_dir(), "grilo-plugins",
+ GRL_SQL_CRC, NULL);
+
+ ret = g_file_get_contents(crc_path,
+ &old_crc,
+ &length,
+ &err);
+
+ if (g_strcmp0(new_crc, old_crc) != 0) {
+ magnatune_get_db_async(NULL);
+ }
+
+ g_free(new_crc_path);
+ g_free(crc_path);
+ g_free(old_crc);
+ }
+}
+
+static void
+magnatune_check_update(void)
+{
+ gchar *db_path = NULL;
+ gchar *new_db_path = NULL;
+ gchar *new_crc_path = NULL;
+ static gboolean already_checked = FALSE;
+ struct stat file_st;
+ GTimeVal tv;
+ GrlNetWc *wc = NULL;
+
+ GRL_DEBUG("magnatune_check_update");
+
+ if (already_checked == TRUE)
+ return;
+
+ already_checked = TRUE;
+
+ g_get_current_time(&tv);
+
+ new_db_path = g_build_filename(g_get_user_data_dir(), "grilo-plugins",
+ GRL_SQL_NEW_DB, NULL);
+
+ if (g_file_test(new_db_path, G_FILE_TEST_EXISTS) == FALSE) {
+
+ db_path = g_build_filename(g_get_user_data_dir(), "grilo-plugins",
+ GRL_SQL_DB, NULL);
+ g_stat(db_path, &file_st);
+ if (tv.tv_sec - file_st.st_mtime > DB_UPDATE_TIME_INTERVAL) {
+
+ new_crc_path = g_build_filename(g_get_user_data_dir(), "grilo-plugins",
+ GRL_SQL_NEW_CRC, NULL);
+ g_stat(new_crc_path, &file_st);
+ if ((g_file_test(new_crc_path, G_FILE_TEST_EXISTS) == FALSE)
+ || (tv.tv_sec - file_st.st_mtime > CRC_UPDATE_TIME_INTERVAL)) {
+
+ wc = grl_net_wc_new();
+ grl_net_wc_request_async(wc,
+ URL_GET_CRC,
+ NULL,
+ magnatune_check_update_done,
+ NULL);
+ }
+ g_free(new_crc_path);
+ }
+ g_free(db_path);
+ }
+ g_free(new_db_path);
+}
+
+
static GrlMedia *
build_media(gint track_id,
const gchar *artist_name,
@@ -435,5 +749,15 @@ grl_magnatune_source_search(GrlSource *source, GrlSourceSearchSpec *ss)
os->callback = ss->callback;
os->user_data = ss->user_data;
os->error_code = GRL_CORE_ERROR_SEARCH_FAILED;
- magnatune_execute_search(os);
+ os->magnatune_cb = NULL;
+
+ if (GRL_MAGNATUNE_SOURCE(source)->priv->db == NULL) {
+ /* Get database first, then execute the search */
+ os->magnatune_cb = magnatune_execute_search;
+ magnatune_get_crc_async();
+ magnatune_get_db_async(os);
+ } else {
+ magnatune_execute_search(os);
+ magnatune_check_update();
+ }
}