[grilo-plugins] dmap: provide a hierarchical view of media database
- From: Juan A. Suarez Romero <jasuarez src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [grilo-plugins] dmap: provide a hierarchical view of media database
- Date: Fri, 7 Feb 2014 08:17:39 +0000 (UTC)
commit e254e9be5c58c35a7012c039392e8d3b9c50b6c1
Author: W. Michael Petullo <mike flyn org>
Date: Sun Feb 2 22:00:02 2014 -0500
dmap: provide a hierarchical view of media database
https://bugzilla.gnome.org/show_bug.cgi?id=723574
Signed-off-by: W. Michael Petullo <mike flyn org>
src/dmap/grl-dmap.c | 191 ++++++++------------------
src/dmap/simple-dmap-db.c | 333 +++++++++++++++++++++++++++++++++++++++------
src/dmap/simple-dmap-db.h | 24 +++-
3 files changed, 368 insertions(+), 180 deletions(-)
---
diff --git a/src/dmap/grl-dmap.c b/src/dmap/grl-dmap.c
index b31c235..bcc8b50 100644
--- a/src/dmap/grl-dmap.c
+++ b/src/dmap/grl-dmap.c
@@ -66,13 +66,12 @@ struct _GrlDmapSourcePrivate {
typedef struct _ResultCbAndArgs {
GrlSourceResultCb callback;
GrlSource *source;
+ GrlMedia *container;
guint op_id;
- gint code_error;
GHRFunc predicate;
gchar *predicate_data;
guint skip;
guint count;
- guint remaining;
gpointer user_data;
} ResultCbAndArgs;
@@ -129,7 +128,7 @@ grl_dmap_plugin_init (GrlRegistry *registry,
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
browser = dmap_mdns_browser_new (DMAP_MDNS_BROWSER_SERVICE_TYPE_DAAP);
- connections = g_hash_table_new (g_str_hash, g_str_equal);
+ connections = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
sources = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
g_signal_connect (G_OBJECT (browser),
@@ -232,140 +231,71 @@ build_url (DMAPMdnsBrowserService *service)
}
static void
-add_media_from_service (gpointer id,
- DAAPRecord *record,
- ResultCbAndArgs *cb)
+do_browse (ResultCbAndArgsAndDb *cb_and_db)
{
- gint duration = 0;
- gint32 bitrate = 0,
- track = 0;
- gchar *id_s = NULL,
- *title = NULL,
- *album = NULL,
- *artist = NULL,
- *genre = NULL,
- *url = NULL;
- gboolean has_video;
- GrlMedia *media;
-
- g_object_get (record,
- "songalbum",
- &album,
- "songartist",
- &artist,
- "bitrate",
- &bitrate,
- "duration",
- &duration,
- "songgenre",
- &genre,
- "title",
- &title,
- "track",
- &track,
- "location",
- &url,
- "has-video",
- &has_video,
- NULL);
-
- id_s = g_strdup_printf ("%u", GPOINTER_TO_UINT (id));
-
- if (has_video == TRUE) {
- media = grl_media_video_new ();
- } else {
- media = grl_media_audio_new ();
- }
-
- grl_media_set_id (media, id_s);
- grl_media_set_duration (media, duration);
-
- if (title) {
- grl_media_set_title (media, title);
- }
-
- if (url) {
- // Replace URL's daap:// with http://.
- url[0] = 'h'; url[1] = 't'; url[2] = 't'; url[3] = 'p';
- grl_media_set_url (media, url);
- }
-
- if (has_video == FALSE) {
- GrlMediaAudio *media_audio = GRL_MEDIA_AUDIO (media);
-
- grl_media_audio_set_bitrate (media_audio, bitrate);
- grl_media_audio_set_track_number (media_audio, track);
+ simple_dmap_db_browse (cb_and_db->db,
+ cb_and_db->cb.container,
+ cb_and_db->cb.source,
+ cb_and_db->cb.op_id,
+ cb_and_db->cb.skip,
+ cb_and_db->cb.count,
+ cb_and_db->cb.callback,
+ cb_and_db->cb.user_data);
- if (album) {
- grl_media_audio_set_album (media_audio, album);
- }
-
- if (artist) {
- grl_media_audio_set_artist (media_audio, artist);
- }
-
- if (genre) {
- grl_media_audio_set_genre (media_audio, genre);
- }
- }
-
- g_free (id_s);
-
- cb->callback (cb->source,
- cb->op_id,
- media,
- --cb->remaining,
- cb->user_data,
- NULL);
+ g_free (cb_and_db);
}
static void
-add_to_hash_table (gpointer key, gpointer value, GHashTable *hash_table)
+do_search (ResultCbAndArgsAndDb *cb_and_db)
{
- g_hash_table_insert (hash_table, key, value);
+ simple_dmap_db_search (cb_and_db->db,
+ cb_and_db->cb.source,
+ cb_and_db->cb.op_id,
+ (GHRFunc) cb_and_db->cb.predicate,
+ cb_and_db->cb.predicate_data,
+ cb_and_db->cb.callback,
+ cb_and_db->cb.user_data);
+
+ g_free (cb_and_db);
}
static void
-add_filtered_media_from_service (ResultCbAndArgsAndDb *cb_and_db)
+browse_connected_cb (DMAPConnection *connection,
+ gboolean result,
+ const char *reason,
+ ResultCbAndArgsAndDb *cb_and_db)
{
- GHashTable *hash_table;
- hash_table = g_hash_table_new (g_direct_hash, g_direct_equal);
-
- simple_dmap_db_filtered_foreach (cb_and_db->db,
- cb_and_db->cb.skip,
- cb_and_db->cb.count,
- (GHRFunc) cb_and_db->cb.predicate,
- cb_and_db->cb.predicate_data,
- (GHFunc) add_to_hash_table,
- hash_table);
-
- cb_and_db->cb.remaining = g_hash_table_size (hash_table);
- if (cb_and_db->cb.remaining > 0) {
- g_hash_table_foreach (hash_table, (GHFunc) add_media_from_service, &cb_and_db->cb);
- } else {
+ GError *error;
+
+ // NOTE: connection argument is required by API but ignored in this case.
+ if (!result) {
+ error = g_error_new_literal (GRL_CORE_ERROR,
+ GRL_CORE_ERROR_BROWSE_FAILED,
+ reason);
cb_and_db->cb.callback (cb_and_db->cb.source,
cb_and_db->cb.op_id,
NULL,
0,
cb_and_db->cb.user_data,
- NULL);
+ error);
+ g_error_free (error);
+ } else {
+ do_browse (cb_and_db);
}
- g_hash_table_destroy (hash_table);
- g_free (cb_and_db);
}
static void
-connected_cb (DMAPConnection *connection,
- gboolean result,
- const char *reason,
- ResultCbAndArgsAndDb *cb_and_db)
+search_connected_cb (DMAPConnection *connection,
+ gboolean result,
+ const char *reason,
+ ResultCbAndArgsAndDb *cb_and_db)
{
GError *error;
// NOTE: connection argument is required by API but ignored in this case.
if (!result) {
error = g_error_new_literal (GRL_CORE_ERROR,
- cb_and_db->cb.code_error,
+ GRL_CORE_ERROR_BROWSE_FAILED,
reason);
cb_and_db->cb.callback (cb_and_db->cb.source,
cb_and_db->cb.op_id,
@@ -375,7 +305,7 @@ connected_cb (DMAPConnection *connection,
error);
g_error_free (error);
} else {
- add_filtered_media_from_service (cb_and_db);
+ do_search (cb_and_db);
}
}
@@ -428,16 +358,15 @@ grl_dmap_connect (gchar *name, gchar *host, guint port, ResultCbAndArgsAndDb *cb
}
static gboolean
-always_true (gpointer key, gpointer value, gpointer user_data)
+match (GrlMedia *media, gpointer val, gpointer user_data)
{
- return TRUE;
-}
+ g_assert (GRL_IS_MEDIA_AUDIO (media) || GRL_IS_MEDIA_VIDEO (media));
-static gboolean
-match (gpointer key, DAAPRecord *record, gpointer user_data)
-{
- char *title;
- g_object_get (record, "title", &title, NULL);
+ if (NULL == user_data) {
+ return TRUE;
+ }
+
+ const char *title = grl_media_get_title (media);
return strstr (title, user_data) != NULL;
}
@@ -480,17 +409,15 @@ grl_dmap_source_browse (GrlSource *source,
cb_and_db->cb.callback = bs->callback;
cb_and_db->cb.source = bs->source;
+ cb_and_db->cb.container = bs->container;
cb_and_db->cb.op_id = bs->operation_id;
- cb_and_db->cb.code_error = GRL_CORE_ERROR_BROWSE_FAILED;
- cb_and_db->cb.predicate = always_true;
- cb_and_db->cb.predicate_data = NULL;
cb_and_db->cb.skip = grl_operation_options_get_skip (bs->options);
cb_and_db->cb.count = grl_operation_options_get_count (bs->options);
cb_and_db->cb.user_data = bs->user_data;
if ((cb_and_db->db = g_hash_table_lookup (connections, url))) {
// Just call directly; already connected, already populated database.
- connected_cb (NULL, TRUE, NULL, cb_and_db);
+ browse_connected_cb (NULL, TRUE, NULL, cb_and_db);
} else {
// Connect.
cb_and_db->db = simple_dmap_db_new ();
@@ -499,9 +426,9 @@ grl_dmap_source_browse (GrlSource *source,
dmap_source->priv->service->host,
dmap_source->priv->service->port,
cb_and_db,
- (DMAPConnectionCallback) connected_cb);
+ (DMAPConnectionCallback) browse_connected_cb);
- g_hash_table_insert (connections, (gpointer) url, cb_and_db->db);
+ g_hash_table_insert (connections, g_strdup (url), cb_and_db->db);
}
g_free (url);
@@ -520,22 +447,20 @@ static void grl_dmap_source_search (GrlSource *source,
cb_and_db->cb.callback = ss->callback;
cb_and_db->cb.source = ss->source;
+ cb_and_db->cb.container = NULL;
cb_and_db->cb.op_id = ss->operation_id;
- cb_and_db->cb.code_error = GRL_CORE_ERROR_SEARCH_FAILED;
cb_and_db->cb.predicate = (GHRFunc) match;
cb_and_db->cb.predicate_data = ss->text;
- cb_and_db->cb.skip = grl_operation_options_get_skip (ss->options);
- cb_and_db->cb.count = grl_operation_options_get_count (ss->options);
cb_and_db->cb.user_data = ss->user_data;
if ((cb_and_db->db = g_hash_table_lookup (connections, url))) {
// Just call directly; already connected, already populated database.
- connected_cb (NULL, TRUE, NULL, cb_and_db);
+ search_connected_cb (NULL, TRUE, NULL, cb_and_db);
} else {
// Connect.
cb_and_db->db = simple_dmap_db_new ();
- grl_dmap_connect (service->name, service->host, service->port, cb_and_db, (DMAPConnectionCallback)
connected_cb);
- g_hash_table_insert (connections, url, cb_and_db->db);
+ grl_dmap_connect (service->name, service->host, service->port, cb_and_db, (DMAPConnectionCallback)
search_connected_cb);
+ g_hash_table_insert (connections, g_strdup (url), cb_and_db->db);
}
g_free (url);
diff --git a/src/dmap/simple-dmap-db.c b/src/dmap/simple-dmap-db.c
index f49ee6a..2be026f 100644
--- a/src/dmap/simple-dmap-db.c
+++ b/src/dmap/simple-dmap-db.c
@@ -15,23 +15,64 @@
*
* 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* This DMAP database implementation maintains a series of hash tables that
+ * represent sets of media. The tables include: root, albums, and artists.
+ * Root contains albums and artists, and albums and artists each contain
+ * the set of albums and artists in the database, respectively. Thus this
+ * database implementation imposes a hierarchical structure, whereas DMAP
+ * normally provides a flat structure.
+ *
+ * Each hash table/set is a mapping between a GrlMediaBox and a series of
+ * GrlMedia objects (either more GrlMediaBox objects, or, in the case of a
+ * leaf, GrlMediaAudio objects). The constant GrlMediaBox objects (e.g.,
+ * albums_box and artists_box) facilitate this, along with additional
+ * GrlMediaAudio objects that the simple_dmap_db_add function creates.
+ *
+ * An application will normally first browse using the NULL container,
+ * and thus will first receive albums_box and artists_box. Browsing
+ * albums_box will provide the application the GrlMediaBox objects in
+ * albums. Further browsing one of these objects will provide the
+ * application with the songs contained therein.
+ *
+ * Grilo IDs must be unique. Here the convention is:
*
+ * 1. Top-level IDs resemble their name (e.g., Album's ID is "albums").
+ * 2. The ID for albums, artists, etc. is the item name prefixed by
+ * the category name (e.g., albums-NAME-OF-ALBUM).
+ * 3. The ID for songs is the string form of the integer identifier used
+ * to identify the song to libdmapsharing.
*/
-#include <string.h>
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <glib/gi18n-lib.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <glib.h>
+#include <string.h>
#include "simple-dmap-db.h"
/* Media ID's start at max and go down. Container ID's start at 1 and go up. */
static guint nextid = G_MAXINT; /* NOTE: this should be G_MAXUINT, but iPhoto can't handle it. */
+static const gchar *ALBUMS_ID = "albums";
+static const gchar *ALBUMS_NAME = "Albums";
+static const gchar *ARTISTS_ID = "artists";
+static const gchar *ARTISTS_NAME = "Artists";
+
struct SimpleDMAPDbPrivate {
- GHashTable *db;
+ GrlMediaBox *albums_box; // Contains each album box (tracked with albums hash table).
+ GrlMediaBox *artists_box; // Contains each artist box (tracked with artist hash table).
+
+ GHashTable *root;
+ GHashTable *albums;
+ GHashTable *artists;
};
enum {
@@ -39,21 +80,31 @@ enum {
PROP_RECORD_FACTORY,
};
+static guint
+box_hash (gconstpointer a)
+{
+ return g_str_hash (grl_media_get_id (GRL_MEDIA (a)));
+}
+
+static gboolean
+box_equal (gconstpointer a, gconstpointer b)
+{
+ return g_str_equal (grl_media_get_id (GRL_MEDIA (a)), grl_media_get_id (GRL_MEDIA (b)));
+}
+
SimpleDMAPDb *
simple_dmap_db_new (void)
{
- return SIMPLE_DMAP_DB (g_object_new (TYPE_SIMPLE_DMAP_DB, NULL));
+ SimpleDMAPDb *db = g_object_new (TYPE_SIMPLE_DMAP_DB, NULL);
+
+ return db;
}
static DMAPRecord *
simple_dmap_db_lookup_by_id (const DMAPDb *db, guint id)
{
- DMAPRecord *record;
-
- record = g_hash_table_lookup (SIMPLE_DMAP_DB (db)->priv->db, GUINT_TO_POINTER (id));
- g_object_ref (record);
-
- return record;
+ g_error ("Not implemented");
+ return NULL;
}
static void
@@ -61,22 +112,125 @@ simple_dmap_db_foreach (const DMAPDb *db,
GHFunc func,
gpointer data)
{
- g_hash_table_foreach (SIMPLE_DMAP_DB (db)->priv->db, func, data);
+ g_error ("Not implemented");
}
static gint64
simple_dmap_db_count (const DMAPDb *db)
{
- return g_hash_table_size (SIMPLE_DMAP_DB (db)->priv->db);
+ g_error ("Not implemented");
+ return 0;
+}
+
+static void
+set_insert (GHashTable *category, const char *category_name, char *set_name, GrlMedia *media)
+{
+ gchar *id = NULL;
+ GrlMedia *box;
+ GHashTable *set;
+
+ id = g_strdup_printf ("%s-%s", category_name, set_name);
+
+ box = g_object_new (GRL_TYPE_MEDIA_BOX, NULL);
+ grl_media_set_id (box, id);
+ grl_media_set_title (box, set_name);
+
+ set = g_hash_table_lookup (category, box);
+ if (NULL == set) {
+ set = g_hash_table_new_full (box_hash, box_equal, g_object_unref, NULL);
+ g_hash_table_insert (category, g_object_ref (box), set);
+ }
+
+ g_hash_table_insert (set, g_object_ref (media), NULL);
+
+ g_free (id);
+ g_object_unref (box);
}
static guint
-simple_dmap_db_add (DMAPDb *db, DMAPRecord *record)
+simple_dmap_db_add (DMAPDb *_db, DMAPRecord *record)
{
- g_object_ref (record);
- g_hash_table_insert (SIMPLE_DMAP_DB (db)->priv->db, GUINT_TO_POINTER (nextid--), record);
+ SimpleDMAPDb *db = SIMPLE_DMAP_DB (_db);
+ gint duration = 0;
+ gint32 bitrate = 0,
+ track = 0;
+ gchar *id_s = NULL,
+ *title = NULL,
+ *album = NULL,
+ *artist = NULL,
+ *genre = NULL,
+ *url = NULL;
+ gboolean has_video;
+ GrlMedia *media;
+
+ g_object_get (record,
+ "songalbum",
+ &album,
+ "songartist",
+ &artist,
+ "bitrate",
+ &bitrate,
+ "duration",
+ &duration,
+ "songgenre",
+ &genre,
+ "title",
+ &title,
+ "track",
+ &track,
+ "location",
+ &url,
+ "has-video",
+ &has_video,
+ NULL);
+
+ id_s = g_strdup_printf ("%u", nextid);
+
+ if (has_video == TRUE) {
+ media = grl_media_video_new ();
+ } else {
+ media = grl_media_audio_new ();
+ }
+
+ grl_media_set_id (media, id_s);
+ grl_media_set_duration (media, duration);
+
+ if (title) {
+ grl_media_set_title (media, title);
+ }
+
+ if (url) {
+ // Replace URL's daap:// with http://.
+ url[0] = 'h'; url[1] = 't'; url[2] = 't'; url[3] = 'p';
+ grl_media_set_url (media, url);
+ }
+
+ if (has_video == FALSE) {
+ GrlMediaAudio *media_audio = GRL_MEDIA_AUDIO (media);
+
+ grl_media_audio_set_bitrate (media_audio, bitrate);
+ grl_media_audio_set_track_number (media_audio, track);
+
+ if (album) {
+ grl_media_audio_set_album (media_audio, album);
+ }
+
+ if (artist) {
+ grl_media_audio_set_artist (media_audio, artist);
+ }
+
+ if (genre) {
+ grl_media_audio_set_genre (media_audio, genre);
+ }
+ }
+
+ set_insert (db->priv->artists, ARTISTS_ID, artist, media);
+ set_insert (db->priv->albums, ALBUMS_ID, album, media);
+
+ g_free (id_s);
+ g_object_unref (media);
- return nextid;
+ return --nextid;
}
static void
@@ -92,31 +246,113 @@ simple_dmap_db_interface_init (gpointer iface, gpointer data)
dmap_db->count = simple_dmap_db_count;
}
+static gboolean
+same_media (GrlMedia *a, GrlMedia *b)
+{
+ return ! strcmp (grl_media_get_id (a), grl_media_get_id (b));
+}
+
void
-simple_dmap_db_filtered_foreach (SimpleDMAPDb *db,
- guint skip,
- guint count,
- GHRFunc predicate,
- gpointer pred_user_data,
- GHFunc func,
- gpointer user_data)
+simple_dmap_db_browse (SimpleDMAPDb *db,
+ GrlMedia *container,
+ GrlSource *source,
+ guint op_id,
+ guint skip,
+ guint count,
+ GrlSourceResultCb func,
+ gpointer user_data)
{
+ int i;
+ guint remaining;
+ GHashTable *hash_table;
GHashTableIter iter;
gpointer key, val;
- guint i;
- g_hash_table_iter_init (&iter, db->priv->db);
- for (i = 0; g_hash_table_iter_next (&iter, &key, &val); i++) {
+ const gchar *box_id = grl_media_get_id (container);
+ if (NULL == box_id) {
+ hash_table = db->priv->root;
+ } else if (same_media (container, GRL_MEDIA (db->priv->albums_box))) {
+ hash_table = db->priv->albums;
+ } else if (same_media (container, GRL_MEDIA (db->priv->artists_box))) {
+ hash_table = db->priv->artists;
+ } else {
+ hash_table = g_hash_table_lookup (db->priv->artists, container);
+ if (NULL == hash_table) {
+ hash_table = g_hash_table_lookup (db->priv->albums, container);
+ }
+ }
+
+ // Should not be NULL; this means the container requested
+ // does not exist in the database.
+ if (NULL == hash_table) {
+ GError *error = g_error_new (GRL_CORE_ERROR,
+ GRL_CORE_ERROR_BROWSE_FAILED,
+ _("Invalid container identifier %s"),
+ box_id);
+ func (source, op_id, NULL, 0, user_data, error);
+ goto done;
+ }
+
+ remaining = g_hash_table_size (hash_table) - skip;
+ remaining = remaining < count ? remaining : count;
+ g_hash_table_iter_init (&iter, hash_table);
+ for (i = 0; g_hash_table_iter_next (&iter, &key, &val) && i < skip + count; i++) {
if (i < skip) {
continue;
}
- if (i == skip + count) {
- break;
+ if (GRL_IS_MEDIA_BOX (key)) {
+ grl_media_box_set_childcount (GRL_MEDIA_BOX (key), g_hash_table_size (val));
}
- if (predicate (key, val, pred_user_data)) {
- func (key, val, user_data);
+ func (source, op_id, GRL_MEDIA (g_object_ref (key)), --remaining, user_data, NULL);
+ }
+done:
+ return;
+}
+
+void
+simple_dmap_db_search (SimpleDMAPDb *db,
+ GrlSource *source,
+ guint op_id,
+ GHRFunc predicate,
+ gpointer pred_user_data,
+ GrlSourceResultCb func,
+ gpointer user_data)
+{
+ gint i, j, k;
+ guint remaining = 0;
+ gpointer key1, val1, key2, val2;
+ GHashTable *hash_table[] = { db->priv->albums, db->priv->artists };
+ GHashTable *results = NULL; // Use hash table to avoid duplicates.
+ GHashTableIter iter1, iter2;
+
+ results = g_hash_table_new (g_str_hash, g_str_equal);
+
+ // For albums and artists...
+ for (i = 0; i < 2; i++) {
+ g_hash_table_iter_init (&iter1, hash_table[i]);
+ // For each album or artist in above...
+ for (j = 0; g_hash_table_iter_next (&iter1, &key1, &val1); j++) {
+ if (GRL_IS_MEDIA_BOX (key1)) {
+ g_hash_table_iter_init (&iter2, val1);
+ // For each media item in above...
+ for (k = 0; g_hash_table_iter_next (&iter2, &key2, &val2); k++) {
+ const char *id = grl_media_get_id (GRL_MEDIA (key2));
+ // If the predicate returns true, add to results set.
+ if (predicate (key2, val2, pred_user_data)
+ && ! g_hash_table_contains (results, id)) {
+ remaining++;
+ g_hash_table_insert (results, (gpointer) id, key2);
+ }
+ }
+ }
}
}
+
+ // Process results set.
+ g_hash_table_iter_init (&iter1, results);
+ for (i = 0; g_hash_table_iter_next (&iter1, &key1, &val1); i++) {
+ func (source, op_id, GRL_MEDIA (g_object_ref (val1)), --remaining, user_data, NULL);
+ }
}
G_DEFINE_TYPE_WITH_CODE (SimpleDMAPDb, simple_dmap_db, G_TYPE_OBJECT,
@@ -132,13 +368,26 @@ simple_dmap_db_constructor (GType type, guint n_construct_params, GObjectConstru
return object;
}
-static void simple_dmap_db_init (SimpleDMAPDb *db)
+static void
+simple_dmap_db_init (SimpleDMAPDb *db)
{
db->priv = SIMPLE_DMAP_DB_GET_PRIVATE (db);
- db->priv->db = g_hash_table_new_full (g_direct_hash,
- g_direct_equal,
- NULL,
- g_object_unref);
+
+ db->priv->albums_box = g_object_new (GRL_TYPE_MEDIA_BOX, NULL);
+ db->priv->artists_box = g_object_new (GRL_TYPE_MEDIA_BOX, NULL);
+
+ grl_media_set_id (GRL_MEDIA (db->priv->albums_box), ALBUMS_ID);
+ grl_media_set_title (GRL_MEDIA (db->priv->albums_box), _(ALBUMS_NAME));
+
+ grl_media_set_id (GRL_MEDIA (db->priv->artists_box), ARTISTS_ID);
+ grl_media_set_title (GRL_MEDIA (db->priv->artists_box), _(ARTISTS_NAME));
+
+ db->priv->root = g_hash_table_new_full (box_hash, box_equal, g_object_unref, (GDestroyNotify)
g_hash_table_destroy);
+ db->priv->albums = g_hash_table_new_full (box_hash, box_equal, g_object_unref, (GDestroyNotify)
g_hash_table_destroy);
+ db->priv->artists = g_hash_table_new_full (box_hash, box_equal, g_object_unref, (GDestroyNotify)
g_hash_table_destroy);
+
+ g_hash_table_insert (db->priv->root, g_object_ref (db->priv->albums_box), db->priv->albums);
+ g_hash_table_insert (db->priv->root, g_object_ref (db->priv->artists_box), db->priv->artists);
}
static void
@@ -146,10 +395,13 @@ simple_dmap_db_finalize (GObject *object)
{
SimpleDMAPDb *db = SIMPLE_DMAP_DB (object);
- g_debug ("Finalizing SimpleDMAPDb (%d records)",
- g_hash_table_size (db->priv->db));
+ g_debug ("Finalizing SimpleDMAPDb");
- g_hash_table_destroy (db->priv->db);
+ g_object_unref (db->priv->albums_box);
+ g_object_unref (db->priv->artists_box);
+
+ g_hash_table_destroy (db->priv->albums);
+ g_hash_table_destroy (db->priv->artists);
}
static void
@@ -179,7 +431,8 @@ simple_dmap_db_get_property (GObject *object,
}
-static void simple_dmap_db_class_init (SimpleDMAPDbClass *klass)
+static void
+simple_dmap_db_class_init (SimpleDMAPDbClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
diff --git a/src/dmap/simple-dmap-db.h b/src/dmap/simple-dmap-db.h
index f0e5ae5..fd890ae 100644
--- a/src/dmap/simple-dmap-db.h
+++ b/src/dmap/simple-dmap-db.h
@@ -22,6 +22,7 @@
#define __SIMPLE_DMAP_DB
#include <libdmapsharing/dmap.h>
+#include <grilo.h>
G_BEGIN_DECLS
@@ -65,13 +66,22 @@ typedef struct {
GObjectClass parent;
} SimpleDMAPDbClass;
-void simple_dmap_db_filtered_foreach (SimpleDMAPDb *db,
- guint skip,
- guint count,
- GHRFunc predicate,
- gpointer pred_user_data,
- GHFunc func,
- gpointer user_data);
+void simple_dmap_db_browse (SimpleDMAPDb *db,
+ GrlMedia *container,
+ GrlSource *source,
+ guint op_id,
+ guint skip,
+ guint count,
+ GrlSourceResultCb func,
+ gpointer user_data);
+
+void simple_dmap_db_search (SimpleDMAPDb *db,
+ GrlSource *source,
+ guint op_id,
+ GHRFunc predicate,
+ gpointer pred_user_data,
+ GrlSourceResultCb func,
+ gpointer user_data);
SimpleDMAPDb *simple_dmap_db_new (void);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]