[grilo-plugins] magnatune: Adding Magnatune plugin



commit d38fecb43d287bae844e4b80158cead538ddd252
Author: Victor Toso <me victortoso com>
Date:   Fri Apr 19 01:47:07 2013 -0300

    magnatune: Adding Magnatune plugin
    
    Search implemented for Track title, Albums and Artists names.
    The function looks into database provided by magnatune website.
    
    A subset of keys are returned and could be incresead when implementing
    other functions.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=698523

 Makefile.am                     |    1 +
 configure.ac                    |   41 ++++
 src/Makefile.am                 |    6 +-
 src/magnatune/Makefile.am       |   34 +++
 src/magnatune/grl-magnatune.c   |  439 +++++++++++++++++++++++++++++++++++++++
 src/magnatune/grl-magnatune.h   |   66 ++++++
 src/magnatune/grl-magnatune.xml |   10 +
 7 files changed, 596 insertions(+), 1 deletions(-)
---
diff --git a/Makefile.am b/Makefile.am
index eaaf008..2882544 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -45,6 +45,7 @@ DISTCHECK_CONFIGURE_FLAGS = --disable-scrollkeeper \
                             --enable-jamendo \
                             --enable-lastfm-albumart \
                             --enable-localmetadata \
+                            --enable-magnatune \
                             --enable-metadata-store \
                             --enable-optical-media \
                             --enable-podcasts \
diff --git a/configure.ac b/configure.ac
index bb7805f..2b5bba7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -708,6 +708,46 @@ DEPS_APPLE_TRAILERS_LIBS="$DEPS_LIBS $GRLNET_LIBS $XML_LIBS"
 AC_SUBST(DEPS_APPLE_TRAILERS_LIBS)
 
 # ----------------------------------------------------------
+# BUILD MAGNATUNE PLUGIN
+# ----------------------------------------------------------
+
+AC_ARG_ENABLE(magnatune,
+        AC_HELP_STRING([--enable-magnatune],
+                [enable Magnatune plugin (default: auto)]),
+        [
+                case "$enableval" in
+                     yes)
+                        if test "x$HAVE_SQLITE" = "xno"; then
+                           AC_MSG_ERROR([sqlite3 not found, install it or use --disable-magnatune])
+                        fi
+                        ;;
+                esac
+        ],
+        [
+                if test "x$HAVE_SQLITE" = "xyes"; then
+                  enable_magnatune=yes
+                else
+                  enable_magnatune=no
+                fi
+        ])
+
+AM_CONDITIONAL([MAGNATUNE_PLUGIN], [test "x$enable_magnatune" = "xyes"])
+GRL_PLUGINS_ALL="$GRL_PLUGINS_ALL magnatune"
+if test "x$enable_magnatune" = "xyes"
+then
+       GRL_PLUGINS_ENABLED="$GRL_PLUGINS_ENABLED magnatune"
+fi
+
+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"
+AC_SUBST(DEPS_MAGNATUNE_CFLAGS)
+DEPS_MAGNATUNE_LIBS="$DEPS_LIBS $SQLITE_LIBS"
+AC_SUBST(DEPS_MAGNATUNE_LIBS)
+
+# ----------------------------------------------------------
 # BUILD METADATA-STORE PLUGIN
 # ----------------------------------------------------------
 
@@ -1110,6 +1150,7 @@ AC_CONFIG_FILES([
   src/jamendo/Makefile
   src/lastfm-albumart/Makefile
   src/local-metadata/Makefile
+  src/magnatune/Makefile
   src/metadata-store/Makefile
   src/optical-media/Makefile
   src/podcasts/Makefile
diff --git a/src/Makefile.am b/src/Makefile.am
index 933bc8c..b61a12f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -52,6 +52,10 @@ if LOCALMETADATA_PLUGIN
 SUBDIRS += local-metadata
 endif
 
+if MAGNATUNE_PLUGIN
+SUBDIRS += magnatune 
+endif
+
 if METADATA_STORE_PLUGIN
 SUBDIRS += metadata-store
 endif
@@ -94,7 +98,7 @@ endif
 
 DIST_SUBDIRS = \
        apple-trailers bliptv bookmarks dmap fake-metadata filesystem flickr    \
-       gravatar jamendo lastfm-albumart local-metadata metadata-store                  \
+       gravatar jamendo lastfm-albumart local-metadata magnatune metadata-store\
        optical-media podcasts raitv shoutcast tmdb tracker upnp vimeo                  \
        youtube
 
diff --git a/src/magnatune/Makefile.am b/src/magnatune/Makefile.am
new file mode 100644
index 0000000..e8d3c14
--- /dev/null
+++ b/src/magnatune/Makefile.am
@@ -0,0 +1,34 @@
+#
+# Makefile.am
+#
+# Author: Victor Toso <me victortoso com>
+#
+# Copyright (C) 2013 Victor Toso. All rights reserved.
+
+ext_LTLIBRARIES = libgrlmagnatune.la
+
+libgrlmagnatune_la_CFLAGS =    \
+       $(DEPS_MAGNATUNE_CFLAGS)        \
+       -DLOCALEDIR=\"$(localedir)\"
+
+libgrlmagnatune_la_LIBADD =    \
+       $(DEPS_MAGNATUNE_LIBS)
+
+libgrlmagnatune_la_LDFLAGS = \
+       -no-undefined       \
+       -module             \
+       -avoid-version
+
+libgrlmagnatune_la_SOURCES = grl-magnatune.c grl-magnatune.h
+
+extdir                         = $(GRL_PLUGINS_DIR)
+magnatunexmldir        = $(GRL_PLUGINS_DIR)
+magnatunexml_DATA      = $(MAGNATUNE_PLUGIN_ID).xml
+
+EXTRA_DIST = $(magnatunexml_DATA)
+
+MAINTAINERCLEANFILES = \
+       *.in            \
+       *~
+
+DISTCLEANFILES = $(MAINTAINERCLEANFILES)
diff --git a/src/magnatune/grl-magnatune.c b/src/magnatune/grl-magnatune.c
new file mode 100644
index 0000000..2a3e454
--- /dev/null
+++ b/src/magnatune/grl-magnatune.c
@@ -0,0 +1,439 @@
+/*
+ * Copyright (C) 2013 Victor Toso.
+ *
+ * Contact: Victor Toso <me victortoso 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 <glib.h>
+#include <glib/gi18n-lib.h>
+#include <grilo.h>
+#include <sqlite3.h>
+
+#include "grl-magnatune.h"
+
+#define GRL_MAGNATUNE_GET_PRIVATE(object)                 \
+  (G_TYPE_INSTANCE_GET_PRIVATE((object),                  \
+                               GRL_MAGNATUNE_SOURCE_TYPE, \
+                               GrlMagnatunePrivate))
+
+/* --------- Logging  -------- */
+
+#define GRL_LOG_DOMAIN_DEFAULT magnatune_log_domain
+GRL_LOG_DOMAIN_STATIC(magnatune_log_domain);
+
+/* --- Database --- */
+
+#define GRL_SQL_SONGS_QUERY_ALL                                 \
+  "SELECT DISTINCT son.song_id, art.name, alb.name, son.name, " \
+    "son.track_no, son.duration, son.mp3 "                      \
+  "FROM songs son "                                             \
+  "LEFT OUTER JOIN albums alb "                                 \
+    "ON (alb.album_id = son.album_id) "                         \
+  "LEFT OUTER JOIN artists art "                                \
+    "ON (art.artists_id = alb.artist_id) "                      \
+  "WHERE (art.name like '%%%s%%') "                             \
+    "OR (alb.name like '%%%s%%') "                              \
+    "OR (son.name like '%%%s%%') "                              \
+    "LIMIT %u OFFSET %u"
+
+/* --- Files --- */
+
+#define GRL_SQL_DB      "grl-magnatune.db"
+
+/* --- URLs --- */
+
+#define URL_SONG_PLAY "http://he3.magnatune.com/all";
+
+/* --- Plugin information --- */
+
+#define SOURCE_ID       "grl-magnatune"
+#define SOURCE_NAME     "Magnatune"
+#define SOURCE_DESC     _("A source for browsing music")
+
+enum {
+  MAGNATUNE_TRACK_ID,
+  MAGNATUNE_ARTIST_NAME,
+  MAGNATUNE_ALBUM_NAME,
+  MAGNATUNE_TRACK_NAME,
+  MAGNATUNE_TRACK_NUMBER,
+  MAGNATUNE_TRACK_DURATION,
+  MAGNATUNE_TRACK_URL_TO_MP3,
+};
+
+struct _GrlMagnatunePrivate {
+  sqlite3 *db;
+};
+
+struct _OperationSpec {
+  GrlSource *source;
+  guint operation_id;
+  const gchar *media_id;
+  guint skip;
+  guint count;
+  const gchar *text;
+  GrlSourceResultCb callback;
+  gpointer user_data;
+  guint error_code;
+};
+
+typedef struct _OperationSpec OperationSpec;
+
+typedef GrlMedia* (MagnatuneBuildMediaFn)(sqlite3_stmt *);
+
+static GrlMagnatuneSource *grl_magnatune_source_new(void);
+
+static void grl_magnatune_source_finalize(GObject *object);
+
+static const GList *grl_magnatune_source_supported_keys(GrlSource *source);
+
+static void grl_magnatune_source_search(GrlSource *source,
+                                        GrlSourceSearchSpec *ss);
+
+/* ================== Magnatune Plugin  ================= */
+
+static gboolean
+grl_magnatune_plugin_init(GrlRegistry *registry,
+                          GrlPlugin *plugin,
+                          GList *configs)
+{
+  GrlMagnatuneSource *source;
+
+  GRL_LOG_DOMAIN_INIT(magnatune_log_domain, "magnatune");
+
+  GRL_DEBUG("magnatune_plugin_init");
+
+  source = grl_magnatune_source_new();
+  if (source->priv->db == NULL)
+    return FALSE;
+
+  grl_registry_register_source(registry,
+                               plugin,
+                               GRL_SOURCE(source),
+                               NULL);
+  return TRUE;
+}
+
+GRL_PLUGIN_REGISTER(grl_magnatune_plugin_init, NULL, SOURCE_ID);
+
+/* ================== Magnatune GObject ================= */
+
+static GrlMagnatuneSource *
+grl_magnatune_source_new(void)
+{
+  GObject *object;
+  GrlMagnatuneSource *source;
+
+  GRL_DEBUG("magnatune_source_new");
+
+  object = g_object_new(GRL_MAGNATUNE_SOURCE_TYPE,
+                        "source-id", SOURCE_ID,
+                        "source-name", SOURCE_NAME,
+                        "source-desc", SOURCE_DESC,
+                        "supported-media", GRL_MEDIA_TYPE_AUDIO,
+                        NULL);
+
+  source = GRL_MAGNATUNE_SOURCE(object);
+
+  return source;
+}
+
+static void
+grl_magnatune_source_class_init(GrlMagnatuneSourceClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
+  GrlSourceClass *source_class = GRL_SOURCE_CLASS(klass);
+
+  gobject_class->finalize = grl_magnatune_source_finalize;
+
+  source_class->supported_keys = grl_magnatune_source_supported_keys;
+  source_class->search = grl_magnatune_source_search;
+
+  g_type_class_add_private(klass, sizeof(GrlMagnatunePrivate));
+}
+
+static void
+grl_magnatune_source_init(GrlMagnatuneSource *source)
+{
+  gint ret;
+  gchar *path;
+  gchar *db_path;
+
+  GRL_DEBUG("magnatune_source_init");
+
+  source->priv = GRL_MAGNATUNE_GET_PRIVATE(source);
+  source->priv->db = NULL;
+
+  path = g_build_filename(g_get_user_data_dir(), "grilo-plugins", NULL);
+  db_path = g_build_filename(path, GRL_SQL_DB, 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.");
+
+    ret = sqlite3_open(db_path, &source->priv->db);
+    if (ret != 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;
+    }
+  } else {
+    GRL_DEBUG("No database was found.");
+  }
+
+  g_free(db_path);
+  g_free(path);
+}
+
+G_DEFINE_TYPE(GrlMagnatuneSource, grl_magnatune_source, GRL_TYPE_SOURCE);
+
+static void
+grl_magnatune_source_finalize(GObject *object)
+{
+  GrlMagnatuneSource *source;
+
+  GRL_DEBUG("grl_magnatune_source_finalize");
+
+  source = GRL_MAGNATUNE_SOURCE(object);
+
+  if (source->priv->db != NULL) {
+    sqlite3_close(source->priv->db);
+  }
+
+  G_OBJECT_CLASS(grl_magnatune_source_parent_class)->finalize(object);
+}
+
+/* ======================= Utilities ==================== */
+
+static GrlMedia *
+build_media(gint track_id,
+            const gchar *artist_name,
+            const gchar *album_name,
+            const gchar *track_name,
+            gint track_number,
+            gint duration,
+            const gchar *url_to_mp3)
+{
+  GrlMedia *media = NULL;
+  GrlMediaAudio *audio = NULL;
+  gchar *str_track_id = NULL;
+
+  media = grl_media_audio_new();
+  audio = GRL_MEDIA_AUDIO(media);
+  grl_media_audio_set_track_number(audio, track_number);
+  grl_media_audio_set_artist(audio, artist_name);
+  grl_media_audio_set_album(audio, album_name);
+
+  grl_media_set_url(media, url_to_mp3);
+  grl_media_set_duration(media, duration);
+  grl_media_set_title(media, track_name);
+
+  str_track_id = g_strdup_printf("%d", track_id);
+  grl_media_set_id(media, str_track_id);
+  g_free(str_track_id);
+
+  return media;
+}
+
+static GrlMedia *
+build_media_track_from_stmt(sqlite3_stmt *sql_stmt)
+{
+  GrlMedia *media = NULL;
+
+  gint track_id;
+  gint duration;
+  gint track_number;
+  const gchar *artist_name;
+  const gchar *album_name;
+  const gchar *track_name;
+  const gchar *raw_url;
+  gchar *encoded_url;
+  gchar *url_to_mp3;
+
+  track_id = (guint) sqlite3_column_int(sql_stmt, MAGNATUNE_TRACK_ID);
+  artist_name = (gchar *) sqlite3_column_text(sql_stmt, MAGNATUNE_ARTIST_NAME);
+  album_name = (gchar *) sqlite3_column_text(sql_stmt, MAGNATUNE_ALBUM_NAME);
+  duration = (guint) sqlite3_column_int(sql_stmt, MAGNATUNE_TRACK_DURATION);
+  track_number = (guint) sqlite3_column_int(sql_stmt, MAGNATUNE_TRACK_NUMBER);
+  track_name = (gchar *) sqlite3_column_text(sql_stmt, MAGNATUNE_TRACK_NAME);
+  raw_url = (gchar *) sqlite3_column_text(sql_stmt, MAGNATUNE_TRACK_URL_TO_MP3);
+
+  encoded_url = g_uri_escape_string(raw_url, "", FALSE);
+  url_to_mp3 = g_strdup_printf("%s/%s", URL_SONG_PLAY, encoded_url);
+  media = build_media(track_id, artist_name, album_name, track_name,
+                      track_number, duration, url_to_mp3);
+
+  g_free(encoded_url);
+  g_free(url_to_mp3);
+
+  return media;
+}
+
+static GList* 
+magnatune_sqlite_execute(OperationSpec *os,
+                         gchar *sql,
+                         MagnatuneBuildMediaFn build_media_fn,
+                         GError **error)
+{
+  GrlMedia *media = NULL;
+  sqlite3 *db = NULL;
+  sqlite3_stmt *sql_stmt = NULL;
+  gint ret = 0;
+  GError *err = NULL;
+  GList *list_medias = NULL;
+
+  GRL_DEBUG("magnatune_sqlite_execute");
+
+  db = GRL_MAGNATUNE_SOURCE(os->source)->priv->db;
+
+  ret = sqlite3_prepare_v2(db, sql, strlen(sql), &sql_stmt, NULL);
+  if (ret != SQLITE_OK) {
+    err = g_error_new(GRL_CORE_ERROR,
+                      os->error_code,
+                      _("Failed to get table from magnatune db: %s"),
+                      sqlite3_errmsg(db));
+    goto end_sqlite_execute;
+  }
+
+  while ((ret = sqlite3_step(sql_stmt)) == SQLITE_BUSY); 
+
+  while (ret == SQLITE_ROW) {
+    media = build_media_fn(sql_stmt);
+    list_medias = g_list_prepend(list_medias, media);
+    ret = sqlite3_step(sql_stmt);
+  }
+
+  if (ret != SQLITE_DONE) {
+    err = g_error_new(GRL_CORE_ERROR,
+                      os->error_code,
+                      _("Fail before returning media to user: %s"),
+                      sqlite3_errmsg(db));
+
+    g_list_free_full(list_medias, g_object_unref);
+    goto end_sqlite_execute;
+  }
+
+  list_medias = g_list_reverse(list_medias);
+
+end_sqlite_execute:
+  sqlite3_finalize(sql_stmt);
+
+  if (err != NULL) {
+    *error = err;
+    return NULL;
+  }
+
+  return list_medias;
+}
+
+static void
+magnatune_execute_search(OperationSpec *os)
+{
+  GrlMedia *media = NULL;
+  gchar *sql = NULL;
+  GList *list_medias = NULL;
+  GList *iter = NULL;
+  gint num_medias = 0;
+  gchar *id = NULL;
+  GError *err = NULL;
+
+  GRL_DEBUG("magnatune_execute_search");
+
+  sql = g_strdup_printf(GRL_SQL_SONGS_QUERY_ALL,
+                        os->text, os->text, os->text,
+                        os->count, os->skip);
+
+  list_medias = magnatune_sqlite_execute(os,
+                                         sql,
+                                         build_media_track_from_stmt,
+                                         &err);
+  g_free(sql);
+
+  if (list_medias == NULL)
+    goto end_search;
+
+  num_medias = g_list_length(list_medias) - 1;
+  for (iter = list_medias; iter; iter = iter->next) {
+    media = iter->data;
+    id = g_strdup_printf("%s-%s", "track", grl_media_get_id(media));
+    grl_media_set_id(media, id);
+    g_free(id);
+    os->callback(os->source,
+                 os->operation_id,
+                 media,
+                 num_medias,
+                 os->user_data,
+                 NULL);
+    num_medias--;
+  }
+
+  g_list_free(list_medias);
+
+end_search:
+  if (err != NULL) {
+    os->callback(os->source, os->operation_id, NULL, 0, os->user_data, err);
+    g_error_free(err);
+  }
+
+  g_slice_free(OperationSpec, os);
+}
+
+/* ================== API Implementation ================ */
+
+static const GList *
+grl_magnatune_source_supported_keys(GrlSource *source)
+{
+  static GList *keys = NULL;
+  if (!keys) {
+    keys = grl_metadata_key_list_new(GRL_METADATA_KEY_ID,
+                                     GRL_METADATA_KEY_ARTIST,
+                                     GRL_METADATA_KEY_ALBUM,
+                                     GRL_METADATA_KEY_DURATION,
+                                     GRL_METADATA_KEY_TITLE,
+                                     GRL_METADATA_KEY_TRACK_NUMBER,
+                                     GRL_METADATA_KEY_URL,
+                                     GRL_METADATA_KEY_INVALID);
+  }
+  return keys;
+}
+
+static void
+grl_magnatune_source_search(GrlSource *source, GrlSourceSearchSpec *ss)
+{
+  OperationSpec *os = NULL;
+
+  os = g_slice_new0(OperationSpec);
+  os->source = ss->source;
+  os->operation_id = ss->operation_id;
+  os->text = (ss->text == NULL) ? "": ss->text;
+  os->count = grl_operation_options_get_count(ss->options);
+  os->skip = grl_operation_options_get_skip(ss->options);
+  os->callback = ss->callback;
+  os->user_data = ss->user_data;
+  os->error_code = GRL_CORE_ERROR_SEARCH_FAILED;
+  magnatune_execute_search(os);
+}
diff --git a/src/magnatune/grl-magnatune.h b/src/magnatune/grl-magnatune.h
new file mode 100644
index 0000000..7aa6d50
--- /dev/null
+++ b/src/magnatune/grl-magnatune.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2013 Victor Toso.
+ *
+ * Contact: Victor Toso <me victortoso 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_MAGNATUNE_SOURCE_H_
+#define _GRL_MAGNATUNE_SOURCE_H_
+
+#include <grilo.h>
+
+#define GRL_MAGNATUNE_SOURCE_TYPE                        \
+  (grl_magnatune_source_get_type())
+
+#define GRL_MAGNATUNE_SOURCE(obj)                        \
+  (G_TYPE_CHECK_INSTANCE_CAST((obj),                     \
+                              GRL_MAGNATUNE_SOURCE_TYPE, \
+                              GrlMagnatuneSource))
+
+#define GRL_MAGNATUNE_SOURCE_CLASS(klass)                \
+  (G_TYPE_CHECK_CLASS_CAST((klass),                      \
+                           GRL_MAGNATUNE_SOURCE_TYPE,    \
+                           GrlMagnatuneSourceClass))
+
+#define GRL_IS_MAGNATUNE_SOURCE_CLASS(klass)             \
+  (G_TYPE_CHECK_CLASS_TYPE((klass),                      \
+                           GRL_MAGNATUNE_SOURCE_TYPE))
+
+#define GRL_MAGNATUNE_SOURCE_GET_CLASS(obj)              \
+  (G_TYPE_INSTANCE_GET_CLASS((obj),                      \
+                              GRL_MAGNATUNE_SOURCE_TYPE, \
+                              GrlMagnatuneSourceClass))
+
+typedef struct _GrlMagnatunePrivate GrlMagnatunePrivate;
+typedef struct _GrlMagnatuneSource  GrlMagnatuneSource;
+
+struct _GrlMagnatuneSource {
+  GrlSource parent;
+  GrlMagnatunePrivate *priv;
+};
+
+typedef struct _GrlMagnatuneSourceClass GrlMagnatuneSourceClass;
+
+struct _GrlMagnatuneSourceClass {
+  GrlSourceClass parent_class;
+};
+
+GType grl_magnatune_source_get_type(void);
+
+#endif /* _GRL_MAGNATUNE_SOURCE_H_ */
diff --git a/src/magnatune/grl-magnatune.xml b/src/magnatune/grl-magnatune.xml
new file mode 100644
index 0000000..d1aef08
--- /dev/null
+++ b/src/magnatune/grl-magnatune.xml
@@ -0,0 +1,10 @@
+<plugin>
+  <info>
+    <name>Magnatune</name>
+    <module>libgrlmagnatune</module>
+    <description>A plugin for searching music</description>
+    <author>Victor Toso</author>
+    <license>LGPL</license>
+    <site>http://live.gnome.org/Grilo</site>
+  </info>
+</plugin>


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