diff options
author | Iago Toral <itoral@igalia.com> | 2010-02-18 17:18:49 +0100 |
---|---|---|
committer | Iago Toral <itoral@igalia.com> | 2010-02-18 17:18:49 +0100 |
commit | 8320aa8bf0ccd5e5e6502631f426c421207829c0 (patch) | |
tree | 9db3f3616f03bc1133631963bd886cf936dd73d1 | |
parent | 6d70e95f999153a5f3586019804dec7560680df8 (diff) | |
download | grilo-plugins-8320aa8bf0ccd5e5e6502631f426c421207829c0.tar.gz |
[bookmarks] Added plugin for managing media bookmarks.
-rw-r--r-- | configure.ac | 43 | ||||
-rw-r--r-- | src/Makefile.am | 6 | ||||
-rw-r--r-- | src/bookmarks/Makefile.am | 26 | ||||
-rw-r--r-- | src/bookmarks/grl-bookmarks.c | 809 | ||||
-rw-r--r-- | src/bookmarks/grl-bookmarks.h | 75 |
5 files changed, 958 insertions, 1 deletions
diff --git a/configure.ac b/configure.ac index 0a26dae..1c4f0e1 100644 --- a/configure.ac +++ b/configure.ac @@ -392,6 +392,48 @@ then GRL_PLUGINS_ENABLED="$GRL_PLUGINS_ENABLED podcasts" fi + +# ---------------------------------------------------------- +# BUILD BOOKMARKS PLUGIN +# ---------------------------------------------------------- + +AC_ARG_ENABLE(bookmarks, + AC_HELP_STRING([--enable-bookmarks], + [enable Bookmarks plugin (default: auto)]), + [ + case "$enableval" in + yes) + if test "x$HAVE_GIO" = "xno"; then + AC_MSG_ERROR([GIO not found, install it or use --disable-bookmarks]) + fi + if test "x$HAVE_XML" = "xno"; then + AC_MSG_ERROR([xml2 not found, install it or use --disable-bookmarks]) + fi + if test "x$HAVE_SQLITE" = "xno"; then + AC_MSG_ERROR([sqlite3 not found, install it or use --disable-bookmarks]) + fi + ;; + esac + ], + [ + if test "x$HAVE_GIO" = "xyes" -a "x$HAVE_XML" = "xyes"; then + if test "x$HAVE_SQLITE" = "xyes"; then + enable_bookmarks=yes + else + enable_bookmarks=no + fi + else + enable_bookmarks=no + fi + ]) + +AM_CONDITIONAL([BOOKMARKS_PLUGIN], [test "x$enable_bookmarks" = "xyes"]) +GRL_PLUGINS_ALL="$GRL_PLUGINS_ALL bookmarks" +if test "x$enable_bookmarks" = "xyes" +then + GRL_PLUGINS_ENABLED="$GRL_PLUGINS_ENABLED bookmarks" +fi + # ---------------------------------------------------------- # GETTEXT # ---------------------------------------------------------- @@ -424,6 +466,7 @@ AC_CONFIG_FILES([ src/upnp/Makefile src/flickr/Makefile src/podcasts/Makefile + src/bookmarks/Makefile test/Makefile ]) diff --git a/src/Makefile.am b/src/Makefile.am index b214290..68f2220 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -39,7 +39,11 @@ if PODCASTS_PLUGIN SUBDIRS += podcasts endif -DIST_SUBDIRS = youtube fake-metadata filesystem jamendo lastfm-albumart upnp flickr podcasts +if BOOKMARKS_PLUGIN +SUBDIRS += bookmarks +endif + +DIST_SUBDIRS = youtube fake-metadata filesystem jamendo lastfm-albumart upnp flickr podcasts bookmarks MAINTAINERCLEANFILES = \ *.in \ diff --git a/src/bookmarks/Makefile.am b/src/bookmarks/Makefile.am new file mode 100644 index 0000000..efae7ff --- /dev/null +++ b/src/bookmarks/Makefile.am @@ -0,0 +1,26 @@ +# +# Makefile.am +# +# Author: Iago Toral Quiroga <itoral@igalia.com> +# +# Copyright (C) 2010 Igalia S.L. All rights reserved. + +lib_LTLIBRARIES = libgrlbookmarks.la + +libgrlbookmarks_la_CFLAGS = \ + $(DEPS_CFLAGS) \ + $(SQLITE_CFLAGS) + +libgrlbookmarks_la_LIBADD = \ + $(DEPS_LIBS) \ + $(SQLITE_LIBS) + +libgrlbookmarks_la_SOURCES = grl-bookmarks.c grl-bookmarks.h + +libdir=$(GRL_PLUGINS_DIR) + +MAINTAINERCLEANFILES = \ + *.in \ + *~ + +DISTCLEANFILES = $(MAINTAINERCLEANFILES) diff --git a/src/bookmarks/grl-bookmarks.c b/src/bookmarks/grl-bookmarks.c new file mode 100644 index 0000000..65635fa --- /dev/null +++ b/src/bookmarks/grl-bookmarks.c @@ -0,0 +1,809 @@ +/* + * Copyright (C) 2010 Igalia S.L. + * + * Contact: Iago Toral Quiroga <itoral@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 <sqlite3.h> +#include <string.h> +#include <stdlib.h> + +#include "grl-bookmarks.h" + +#define GRL_BOOKMARKS_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE((object), \ + GRL_BOOKMARKS_SOURCE_TYPE, \ + GrlBookmarksPrivate)) + +/* --------- Logging -------- */ + +#undef G_LOG_DOMAIN +#define G_LOG_DOMAIN "grl-bookmarks" + +/* --- Database --- */ + +#define GRL_SQL_DB ".grl-bookmarks" + +#define GRL_SQL_CREATE_TABLE_BOOKMARKS \ + "CREATE TABLE IF NOT EXISTS bookmarks (" \ + "id INTEGER PRIMARY KEY AUTOINCREMENT," \ + "parent INTEGER REFERENCES bookmarks (id)," \ + "type INTEGER," \ + "url TEXT," \ + "title TEXT," \ + "date TEXT," \ + "mime TEXT," \ + "desc TEXT)" + +#define GRL_SQL_GET_BOOKMARKS_BY_PARENT \ + "SELECT * FROM bookmarks " \ + "WHERE parent='%s' " \ + "LIMIT %u OFFSET %u" + +#define GRL_SQL_GET_BOOKMARK_BY_ID \ + "SELECT * FROM bookmarks " \ + "WHERE id='%s' " \ + "LIMIT 1" + +#define GRL_SQL_STORE_BOOKMARK \ + "INSERT INTO bookmarks " \ + "(parent, type, title, url, date, desc, mime) " \ + "VALUES (?, ?, ?, ?, ?, ?, ?)" + +#define GRL_SQL_REMOVE_BOOKMARK \ + "DELETE FROM bookmarks " \ + "WHERE id='%s' or parent='%s'" + +#define GRL_SQL_REMOVE_ORPHAN \ + "DELETE FROM bookmarks " \ + "WHERE id in ( " \ + " SELECT DISTINCT id FROM bookmarks " \ + " WHERE parent NOT IN ( " \ + " SELECT DISTINCT id FROM bookmarks) " \ + " and parent <> 0)" + +#define GRL_SQL_GET_BOOKMARKS_BY_TEXT \ + "SELECT * FROM bookmarks " \ + "WHERE title LIKE '%%%s%%' OR desc LIKE '%%%s%%' " \ + "LIMIT %u OFFSET %u" + +#define GRL_SQL_GET_BOOKMARKS_BY_QUERY \ + "SELECT * FROM bookmarks " \ + "WHERE %s " \ + "LIMIT %u OFFSET %u" + +/* --- Plugin information --- */ + +#define PLUGIN_ID "grl-bookmarks" +#define PLUGIN_NAME "Bookmarks" +#define PLUGIN_DESC "A plugin for organizing media bookmarks" + +#define SOURCE_ID "grl-bookmarks" +#define SOURCE_NAME "Bookmarks" +#define SOURCE_DESC "A source for organizing media bookmarks" + +#define AUTHOR "Igalia S.L." +#define LICENSE "LGPL" +#define SITE "http://www.igalia.com" + + +enum { + BOOKMARK_TYPE_CATEGORY = 0, + BOOKMARK_TYPE_STREAM, +}; + +enum { + BOOKMARK_ID = 0, + BOOKMARK_PARENT, + BOOKMARK_TYPE, + BOOKMARK_URL, + BOOKMARK_TITLE, + BOOKMARK_DATE, + BOOKMARK_MIME, + BOOKMARK_DESC, +}; + +struct _GrlBookmarksPrivate { + sqlite3 *db; +}; + +typedef struct { + GrlMediaSource *source; + guint operation_id; + const gchar *media_id; + guint skip; + guint count; + GrlMediaSourceResultCb callback; + guint error_code; + gboolean is_query; + gpointer user_data; +} OperationSpec; + +static GrlBookmarksSource *grl_bookmarks_source_new (void); + +static void grl_bookmarks_source_finalize (GObject *plugin); + +static const GList *grl_bookmarks_source_supported_keys (GrlMetadataSource *source); +static GrlSupportedOps grl_bookmarks_source_supported_operations (GrlMetadataSource *metadata_source); + +static void grl_bookmarks_source_search (GrlMediaSource *source, + GrlMediaSourceSearchSpec *ss); +static void grl_bookmarks_source_query (GrlMediaSource *source, + GrlMediaSourceQuerySpec *qs); +static void grl_bookmarks_source_browse (GrlMediaSource *source, + GrlMediaSourceBrowseSpec *bs); +static void grl_bookmarks_source_metadata (GrlMediaSource *source, + GrlMediaSourceMetadataSpec *ms); +static void grl_bookmarks_source_store (GrlMediaSource *source, + GrlMediaSourceStoreSpec *ss); +static void grl_bookmarks_source_remove (GrlMediaSource *source, + GrlMediaSourceRemoveSpec *rs); + +/* =================== Bookmarks Plugin =============== */ + +static gboolean +grl_bookmarks_plugin_init (GrlPluginRegistry *registry, + const GrlPluginInfo *plugin) +{ + g_debug ("grl_bookmarks_plugin_init\n"); + + GrlBookmarksSource *source = grl_bookmarks_source_new (); + grl_plugin_registry_register_source (registry, + plugin, + GRL_MEDIA_PLUGIN (source)); + return TRUE; +} + +GRL_PLUGIN_REGISTER (grl_bookmarks_plugin_init, + NULL, + PLUGIN_ID, + PLUGIN_NAME, + PLUGIN_DESC, + PACKAGE_VERSION, + AUTHOR, + LICENSE, + SITE); + +/* ================== Bookmarks GObject ================ */ + +static GrlBookmarksSource * +grl_bookmarks_source_new (void) +{ + g_debug ("grl_bookmarks_source_new"); + return g_object_new (GRL_BOOKMARKS_SOURCE_TYPE, + "source-id", SOURCE_ID, + "source-name", SOURCE_NAME, + "source-desc", SOURCE_DESC, + NULL); +} + +static void +grl_bookmarks_source_class_init (GrlBookmarksSourceClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GrlMediaSourceClass *source_class = GRL_MEDIA_SOURCE_CLASS (klass); + GrlMetadataSourceClass *metadata_class = GRL_METADATA_SOURCE_CLASS (klass); + + gobject_class->finalize = grl_bookmarks_source_finalize; + + metadata_class->supported_operations = + grl_bookmarks_source_supported_operations; + + source_class->browse = grl_bookmarks_source_browse; + source_class->search = grl_bookmarks_source_search; + source_class->query = grl_bookmarks_source_query; + source_class->store = grl_bookmarks_source_store; + source_class->remove = grl_bookmarks_source_remove; + source_class->metadata = grl_bookmarks_source_metadata; + + metadata_class->supported_keys = grl_bookmarks_source_supported_keys; + + g_type_class_add_private (klass, sizeof (GrlBookmarksPrivate)); +} + +static void +grl_bookmarks_source_init (GrlBookmarksSource *source) +{ + gint r; + const gchar *home; + gchar *db_path; + gchar *sql_error = NULL; + + source->priv = GRL_BOOKMARKS_GET_PRIVATE (source); + memset (source->priv, 0, sizeof (GrlBookmarksPrivate)); + + home = g_getenv ("HOME"); + if (!home) { + g_warning ("$HOME not set, cannot open database"); + return; + } + + g_debug ("Opening database connection..."); + db_path = g_strconcat (home, G_DIR_SEPARATOR_S, GRL_SQL_DB, NULL); + r = sqlite3_open (db_path, &source->priv->db); + if (r) { + g_critical ("Failed to open database '%s': %s", + db_path, sqlite3_errmsg (source->priv->db)); + sqlite3_close (source->priv->db); + return; + } + g_debug (" OK"); + + g_debug ("Checking database tables..."); + r = sqlite3_exec (source->priv->db, GRL_SQL_CREATE_TABLE_BOOKMARKS, + NULL, NULL, &sql_error); + + if (r) { + if (sql_error) { + g_warning ("Failed to create database tables: %s", sql_error); + sqlite3_free (sql_error); + sql_error = NULL; + } else { + g_warning ("Failed to create database tables."); + } + sqlite3_close (source->priv->db); + return; + } + g_debug (" OK"); + + g_free (db_path); +} + +G_DEFINE_TYPE (GrlBookmarksSource, grl_bookmarks_source, GRL_TYPE_MEDIA_SOURCE); + +static void +grl_bookmarks_source_finalize (GObject *object) +{ + GrlBookmarksSource *source; + + g_debug ("grl_bookmarks_source_finalize"); + + source = GRL_BOOKMARKS_SOURCE (object); + + sqlite3_close (source->priv->db); + + G_OBJECT_CLASS (grl_bookmarks_source_parent_class)->finalize (object); +} + +/* ======================= Utilities ==================== */ + +static gboolean +mime_is_video (const gchar *mime) +{ + return mime && strstr (mime, "video") != NULL; +} + +static gboolean +mime_is_audio (const gchar *mime) +{ + return mime && strstr (mime, "audio") != NULL; +} + +static GrlContentMedia * +build_media_from_stmt (GrlContentMedia *content, sqlite3_stmt *sql_stmt) +{ + GrlContentMedia *media = NULL; + gchar *id; + gchar *title; + gchar *url; + gchar *desc; + gchar *date; + gchar *mime; + guint type; + + if (content) { + media = content; + } + + id = (gchar *) sqlite3_column_text (sql_stmt, BOOKMARK_ID); + title = (gchar *) sqlite3_column_text (sql_stmt, BOOKMARK_TITLE); + url = (gchar *) sqlite3_column_text (sql_stmt, BOOKMARK_URL); + desc = (gchar *) sqlite3_column_text (sql_stmt, BOOKMARK_DESC); + date = (gchar *) sqlite3_column_text (sql_stmt, BOOKMARK_DATE); + mime = (gchar *) sqlite3_column_text (sql_stmt, BOOKMARK_MIME); + type = (guint) sqlite3_column_int (sql_stmt, BOOKMARK_TYPE); + + if (!media) { + if (type == BOOKMARK_TYPE_CATEGORY) { + media = GRL_CONTENT_MEDIA (grl_content_box_new ()); + } else if (mime_is_audio (mime)) { + media = GRL_CONTENT_MEDIA (grl_content_media_new ()); + } else if (mime_is_video (mime)) { + media = GRL_CONTENT_MEDIA (grl_content_media_new ()); + } else { + media = GRL_CONTENT_MEDIA (grl_content_media_new ()); + } + } + + grl_content_media_set_id (media, id); + grl_content_media_set_title (media, title); + if (url) { + grl_content_media_set_url (media, url); + } + if (desc) { + grl_content_media_set_description (media, desc); + } + if (date) { + grl_content_media_set_date (media, date); + } + + return media; +} + +static void +bookmark_metadata (GrlMediaSourceMetadataSpec *ms) +{ + gint r; + sqlite3_stmt *sql_stmt = NULL; + sqlite3 *db; + GError *error = NULL; + gchar *sql; + const gchar *id; + + g_debug ("bookmark_metadata"); + + db = GRL_BOOKMARKS_SOURCE (ms->source)->priv->db; + + id = grl_content_media_get_id (ms->media); + if (!id) { + /* Root category: special case */ + grl_content_media_set_title (ms->media, ""); + ms->callback (ms->source, ms->media, ms->user_data, NULL); + return; + } + + sql = g_strdup_printf (GRL_SQL_GET_BOOKMARK_BY_ID, id); + g_debug ("%s", sql); + r = sqlite3_prepare_v2 (db, sql, strlen (sql), &sql_stmt, NULL); + g_free (sql); + + if (r != SQLITE_OK) { + g_warning ("Failed to get bookmark: %s", sqlite3_errmsg (db)); + error = g_error_new (GRL_ERROR, + GRL_ERROR_METADATA_FAILED, + "Failed to get bookmark metadata"); + ms->callback (ms->source, ms->media, ms->user_data, error); + g_error_free (error); + return; + } + + while ((r = sqlite3_step (sql_stmt)) == SQLITE_BUSY); + + if (r == SQLITE_ROW) { + build_media_from_stmt (ms->media, sql_stmt); + ms->callback (ms->source, ms->media, ms->user_data, NULL); + } else { + g_warning ("Failed to get bookmark: %s", sqlite3_errmsg (db)); + error = g_error_new (GRL_ERROR, + GRL_ERROR_METADATA_FAILED, + "Failed to get bookmark metadata"); + ms->callback (ms->source, ms->media, ms->user_data, error); + g_error_free (error); + } + + sqlite3_finalize (sql_stmt); +} + +static void +produce_bookmarks_from_sql (OperationSpec *os, const gchar *sql) +{ + gint r; + sqlite3_stmt *sql_stmt = NULL; + sqlite3 *db; + GrlContentMedia *media; + GError *error = NULL; + GList *medias = NULL; + guint count = 0; + GList *iter; + + g_debug ("produce_bookmarks_from_sql"); + + g_debug ("%s", sql); + db = GRL_BOOKMARKS_SOURCE (os->source)->priv->db; + r = sqlite3_prepare_v2 (db, sql, strlen (sql), &sql_stmt, NULL); + + if (r != SQLITE_OK) { + g_warning ("Failed to retrieve bookmarks: %s", sqlite3_errmsg (db)); + error = g_error_new (GRL_ERROR, + os->error_code, + "Failed to retrieve bookmarks list"); + os->callback (os->source, os->operation_id, NULL, 0, os->user_data, error); + g_error_free (error); + goto free_resources; + } + + while ((r = sqlite3_step (sql_stmt)) == SQLITE_BUSY); + + while (r == SQLITE_ROW) { + media = build_media_from_stmt (NULL, sql_stmt); + medias = g_list_prepend (medias, media); + count++; + r = sqlite3_step (sql_stmt); + } + + if (r != SQLITE_DONE) { + g_warning ("Failed to retrieve bookmarks: %s", sqlite3_errmsg (db)); + error = g_error_new (GRL_ERROR, + os->error_code, + "Failed to retrieve bookmarks list"); + os->callback (os->source, os->operation_id, NULL, 0, os->user_data, error); + g_error_free (error); + goto free_resources; + } + + if (count > 0) { + medias = g_list_reverse (medias); + iter = medias; + while (iter) { + media = GRL_CONTENT_MEDIA (iter->data); + os->callback (os->source, + os->operation_id, + media, + --count, + os->user_data, + NULL); + iter = g_list_next (iter); + } + g_list_free (medias); + } else { + os->callback (os->source, os->operation_id, NULL, 0, os->user_data, NULL); + } + + free_resources: + if (sql_stmt) + sqlite3_finalize (sql_stmt); +} + +static void +produce_bookmarks_by_query (OperationSpec *os, const gchar *query) +{ + gchar *sql; + g_debug ("produce_bookmarks_by_query"); + sql = g_strdup_printf (GRL_SQL_GET_BOOKMARKS_BY_QUERY, + query, os->count, os->skip); + produce_bookmarks_from_sql (os, sql); + g_free (sql); +} + +static void +produce_bookmarks_by_text (OperationSpec *os, const gchar *text) +{ + gchar *sql; + g_debug ("produce_bookmarks_by_text"); + sql = g_strdup_printf (GRL_SQL_GET_BOOKMARKS_BY_TEXT, + text, text, os->count, os->skip); + produce_bookmarks_from_sql (os, sql); + g_free (sql); +} + +static void +produce_bookmarks_from_category (OperationSpec *os, const gchar *category_id) +{ + gchar *sql; + g_debug ("produce_bookmarks_from_category"); + sql = g_strdup_printf (GRL_SQL_GET_BOOKMARKS_BY_PARENT, + category_id, os->count, os->skip); + produce_bookmarks_from_sql (os, sql); + g_free (sql); +} + +static void +remove_bookmark (sqlite3 *db, const gchar *bookmark_id, GError **error) +{ + gint r; + gchar *sql_error; + gchar *sql; + + g_debug ("remove_bookmark"); + + sql = g_strdup_printf (GRL_SQL_REMOVE_BOOKMARK, bookmark_id, bookmark_id); + g_debug ("%s", sql); + r = sqlite3_exec (db, sql, NULL, NULL, &sql_error); + g_free (sql); + + if (r != SQLITE_OK) { + g_warning ("Failed to remove bookmark '%s': %s", bookmark_id, sql_error); + *error = g_error_new (GRL_ERROR, + GRL_ERROR_REMOVE_FAILED, + "Failed to remove bookmark"); + sqlite3_free (sql_error); + } + + /* Remove orphan nodes from database */ + g_debug ("%s", GRL_SQL_REMOVE_ORPHAN); + r = sqlite3_exec (db, GRL_SQL_REMOVE_ORPHAN, NULL, NULL, NULL); +} + +static void +store_bookmark (sqlite3 *db, + GrlContentBox *parent, + GrlContentMedia *bookmark, + GError **error) +{ + gint r; + sqlite3_stmt *sql_stmt = NULL; + const gchar *title; + const gchar *url; + const gchar *desc; + GTimeVal now; + const gchar *parent_id; + const gchar *mime; + gchar *date; + guint type; + + g_debug ("store_bookmark"); + + title = grl_content_media_get_title (bookmark); + url = grl_content_media_get_url (bookmark); + desc = grl_content_media_get_description (bookmark); + mime = grl_content_media_get_mime (bookmark); + g_get_current_time (&now); + date = g_time_val_to_iso8601 (&now); + + if (!parent) { + parent_id = "0"; + } else { + parent_id = grl_content_media_get_id (parent); + } + if (!parent_id) { + parent_id = "0"; + } + + g_debug ("%s", GRL_SQL_STORE_BOOKMARK); + r = sqlite3_prepare_v2 (db, + GRL_SQL_STORE_BOOKMARK, + strlen (GRL_SQL_STORE_BOOKMARK), + &sql_stmt, NULL); + if (r != SQLITE_OK) { + g_warning ("Failed to store bookmark '%s': %s", title, sqlite3_errmsg (db)); + *error = g_error_new (GRL_ERROR, + GRL_ERROR_STORE_FAILED, + "Failed to store bookmark '%s'", title); + return; + } + + g_debug ("URL: '%s'", url); + + if (url && url[0]) { + type = BOOKMARK_TYPE_STREAM; + } else { + type = BOOKMARK_TYPE_CATEGORY; + } + + sqlite3_bind_text (sql_stmt, 1, parent_id, -1, SQLITE_STATIC); + sqlite3_bind_int (sql_stmt, 2, type); + sqlite3_bind_text (sql_stmt, 3, title, -1, SQLITE_STATIC); + if (type == BOOKMARK_TYPE_STREAM) { + sqlite3_bind_text (sql_stmt, 4, url, -1, SQLITE_STATIC); + } else { + sqlite3_bind_null (sql_stmt, 4); + } + if (date) { + sqlite3_bind_text (sql_stmt, 5, date, -1, SQLITE_STATIC); + } else { + sqlite3_bind_null (sql_stmt, 5); + } + if (mime) { + sqlite3_bind_text (sql_stmt, 6, mime, -1, SQLITE_STATIC); + } else { + sqlite3_bind_null (sql_stmt, 6); + } + if (desc) { + sqlite3_bind_text (sql_stmt, 7, desc, -1, SQLITE_STATIC); + } else { + sqlite3_bind_null (sql_stmt, 7); + } + + while ((r = sqlite3_step (sql_stmt)) == SQLITE_BUSY); + + if (r != SQLITE_DONE) { + g_warning ("Failed to store bookmark '%s': %s", title, sqlite3_errmsg (db)); + *error = g_error_new (GRL_ERROR, + GRL_ERROR_STORE_FAILED, + "Failed to store bookmark '%s'", title); + sqlite3_finalize (sql_stmt); + return; + } + + sqlite3_finalize (sql_stmt); +} + +/* ================== API Implementation ================ */ + +static const GList * +grl_bookmarks_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_URL, + GRL_METADATA_KEY_CHILDCOUNT, + GRL_METADATA_KEY_DESCRIPTION, + GRL_METADATA_KEY_DATE, + NULL); + } + return keys; +} + +static void +grl_bookmarks_source_browse (GrlMediaSource *source, + GrlMediaSourceBrowseSpec *bs) +{ + g_debug ("grl_bookmarks_source_browse"); + + OperationSpec *os; + GrlBookmarksSource *bookmarks_source; + GError *error = NULL; + + bookmarks_source = GRL_BOOKMARKS_SOURCE (source); + if (!bookmarks_source->priv->db) { + g_warning ("Can't execute operation: no database connection."); + error = g_error_new (GRL_ERROR, + GRL_ERROR_BROWSE_FAILED, + "No database connection"); + bs->callback (bs->source, bs->browse_id, NULL, 0, bs->user_data, error); + g_error_free (error); + } + + /* Configure browse operation */ + os = g_new0 (OperationSpec, 1); + os->source = bs->source; + os->operation_id = bs->browse_id; + os->media_id = grl_content_media_get_id (bs->container); + os->count = bs->count; + os->skip = bs->skip; + os->callback = bs->callback; + os->user_data = bs->user_data; + os->error_code = GRL_ERROR_BROWSE_FAILED; + + produce_bookmarks_from_category (os, os->media_id ? os->media_id : "0"); + g_free (os); +} + +static void +grl_bookmarks_source_search (GrlMediaSource *source, + GrlMediaSourceSearchSpec *ss) +{ + g_debug ("grl_bookmarks_source_search"); + + GrlBookmarksSource *bookmarks_source; + OperationSpec *os; + GError *error = NULL; + + bookmarks_source = GRL_BOOKMARKS_SOURCE (source); + if (!bookmarks_source->priv->db) { + g_warning ("Can't execute operation: no database connection."); + error = g_error_new (GRL_ERROR, + GRL_ERROR_QUERY_FAILED, + "No database connection"); + ss->callback (ss->source, ss->search_id, NULL, 0, ss->user_data, error); + g_error_free (error); + } + + os = g_new0 (OperationSpec, 1); + os->source = ss->source; + os->operation_id = ss->search_id; + os->count = ss->count; + os->skip = ss->skip; + os->callback = ss->callback; + os->user_data = ss->user_data; + os->error_code = GRL_ERROR_SEARCH_FAILED; + produce_bookmarks_by_text (os, ss->text); + g_free (os); +} + +static void +grl_bookmarks_source_query (GrlMediaSource *source, + GrlMediaSourceQuerySpec *qs) +{ + g_debug ("grl_bookmarks_source_query"); + + GrlBookmarksSource *bookmarks_source; + OperationSpec *os; + GError *error = NULL; + + bookmarks_source = GRL_BOOKMARKS_SOURCE (source); + if (!bookmarks_source->priv->db) { + g_warning ("Can't execute operation: no database connection."); + error = g_error_new (GRL_ERROR, + GRL_ERROR_QUERY_FAILED, + "No database connection"); + qs->callback (qs->source, qs->query_id, NULL, 0, qs->user_data, error); + g_error_free (error); + } + + os = g_new0 (OperationSpec, 1); + os->source = qs->source; + os->operation_id = qs->query_id; + os->count = qs->count; + os->skip = qs->skip; + os->callback = qs->callback; + os->user_data = qs->user_data; + os->error_code = GRL_ERROR_SEARCH_FAILED; + produce_bookmarks_by_query (os, qs->query); + g_free (os); +} + +static void +grl_bookmarks_source_store (GrlMediaSource *source, GrlMediaSourceStoreSpec *ss) +{ + g_debug ("grl_bookmarks_source_store"); + /* FIXME: Try to guess bookmark mime somehow */ + GError *error = NULL; + store_bookmark (GRL_BOOKMARKS_SOURCE (ss->source)->priv->db, + ss->parent, ss->media, &error); + ss->callback (ss->source, ss->parent, ss->media, ss->user_data, error); + if (error) { + g_error_free (error); + } +} + +static void grl_bookmarks_source_remove (GrlMediaSource *source, + GrlMediaSourceRemoveSpec *rs) +{ + g_debug ("grl_bookmarks_source_remove"); + GError *error = NULL; + remove_bookmark (GRL_BOOKMARKS_SOURCE (rs->source)->priv->db, + rs->media_id, &error); + rs->callback (rs->source, rs->media, rs->user_data, error); + if (error) { + g_error_free (error); + } +} + +static void +grl_bookmarks_source_metadata (GrlMediaSource *source, + GrlMediaSourceMetadataSpec *ms) +{ + g_debug ("grl_bookmarks_source_metadata"); + + GrlBookmarksSource *bookmarks_source; + GError *error = NULL; + + bookmarks_source = GRL_BOOKMARKS_SOURCE (source); + if (!bookmarks_source->priv->db) { + g_warning ("Can't execute operation: no database connection."); + error = g_error_new (GRL_ERROR, + GRL_ERROR_METADATA_FAILED, + "No database connection"); + ms->callback (ms->source, ms->media, ms->user_data, error); + g_error_free (error); + } + + bookmark_metadata (ms); +} + +static GrlSupportedOps +grl_bookmarks_source_supported_operations (GrlMetadataSource *metadata_source) +{ + GrlSupportedOps caps; + GrlBookmarksSource *source; + + source = GRL_BOOKMARKS_SOURCE (metadata_source); + caps = GRL_OP_BROWSE | GRL_OP_METADATA | GRL_OP_SEARCH | GRL_OP_QUERY | + GRL_OP_STORE | GRL_OP_STORE_PARENT | GRL_OP_REMOVE; + + return caps; +} diff --git a/src/bookmarks/grl-bookmarks.h b/src/bookmarks/grl-bookmarks.h new file mode 100644 index 0000000..b5529b1 --- /dev/null +++ b/src/bookmarks/grl-bookmarks.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2010 Igalia S.L. + * + * Contact: Iago Toral Quiroga <itoral@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_BOOKMARKS_SOURCE_H_ +#define _GRL_BOOKMARKS_SOURCE_H_ + +#include <grilo.h> + +#define GRL_BOOKMARKS_SOURCE_TYPE \ + (grl_bookmarks_source_get_type ()) + +#define GRL_BOOKMARKS_SOURCE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GRL_BOOKMARKS_SOURCE_TYPE, \ + GrlBookmarksSource)) + +#define GRL_IS_BOOKMARKS_SOURCE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + GRL_BOOKMARKS_SOURCE_TYPE)) + +#define GRL_BOOKMARKS_SOURCE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GRL_BOOKMARKS_SOURCE_TYPE, \ + GrlBookmarksSourceClass)) + +#define GRL_IS_BOOKMARKS_SOURCE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), \ + GRL_BOOKMARKS_SOURCE_TYPE)) + +#define GRL_BOOKMARKS_SOURCE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GRL_BOOKMARKS_SOURCE_TYPE, \ + GrlBookmarksSourceClass)) + +typedef struct _GrlBookmarksPrivate GrlBookmarksPrivate; +typedef struct _GrlBookmarksSource GrlBookmarksSource; + +struct _GrlBookmarksSource { + + GrlMediaSource parent; + + /*< private >*/ + GrlBookmarksPrivate *priv; +}; + +typedef struct _GrlBookmarksSourceClass GrlBookmarksSourceClass; + +struct _GrlBookmarksSourceClass { + + GrlMediaSourceClass parent_class; + +}; + +GType grl_bookmarks_source_get_type (void); + +#endif /* _GRL_BOOKMARKS_SOURCE_H_ */ |