From 35282097d5b050fda7cc8bba6aa0363203477069 Mon Sep 17 00:00:00 2001 From: "W. Michael Petullo" Date: Sat, 5 Sep 2015 08:57:34 -0400 Subject: dmap: Add DPAP plugin https://bugzilla.gnome.org/show_bug.cgi?id=746722 --- configure.ac | 4 + src/dmap/Makefile.am | 34 ++- src/dmap/grl-dpap-db.c | 368 +++++++++++++++++++++++++++++++ src/dmap/grl-dpap-db.h | 90 ++++++++ src/dmap/grl-dpap-record-factory.c | 58 +++++ src/dmap/grl-dpap-record-factory.h | 72 ++++++ src/dmap/grl-dpap-record.c | 247 +++++++++++++++++++++ src/dmap/grl-dpap-record.h | 78 +++++++ src/dmap/grl-dpap.c | 439 +++++++++++++++++++++++++++++++++++++ src/dmap/grl-dpap.h | 73 ++++++ src/dmap/grl-dpap.xml | 10 + 11 files changed, 1471 insertions(+), 2 deletions(-) create mode 100644 src/dmap/grl-dpap-db.c create mode 100644 src/dmap/grl-dpap-db.h create mode 100644 src/dmap/grl-dpap-record-factory.c create mode 100644 src/dmap/grl-dpap-record-factory.h create mode 100644 src/dmap/grl-dpap-record.c create mode 100644 src/dmap/grl-dpap-record.h create mode 100644 src/dmap/grl-dpap.c create mode 100644 src/dmap/grl-dpap.h create mode 100644 src/dmap/grl-dpap.xml diff --git a/configure.ac b/configure.ac index 0d1bfaa..a0768d5 100644 --- a/configure.ac +++ b/configure.ac @@ -1079,6 +1079,10 @@ DAAP_PLUGIN_ID="grl-daap" AC_SUBST(DAAP_PLUGIN_ID) AC_DEFINE_UNQUOTED([DAAP_PLUGIN_ID], ["$DAAP_PLUGIN_ID"], [DAAP plugin ID]) +DPAP_PLUGIN_ID="grl-dpap" +AC_SUBST(DPAP_PLUGIN_ID) +AC_DEFINE_UNQUOTED([DPAP_PLUGIN_ID], ["$DPAP_PLUGIN_ID"], [DPAP plugin ID]) + DEPS_DMAP_CFLAGS="$DEPS_CFLAGS $DMAP_CFLAGS $XML_CFLAGS" AC_SUBST(DEPS_DMAP_CFLAGS) DEPS_DMAP_LIBS="$DEPS_LIBS $DMAP_LIBS $XML_LIBS" diff --git a/src/dmap/Makefile.am b/src/dmap/Makefile.am index c89bb0f..e6f3cf0 100644 --- a/src/dmap/Makefile.am +++ b/src/dmap/Makefile.am @@ -7,7 +7,8 @@ include $(top_srcdir)/gtester.mk -ext_LTLIBRARIES = libgrldaap.la +ext_LTLIBRARIES = libgrldaap.la libgrldpap.la +extdir = $(GRL_PLUGINS_DIR) libgrldaap_la_CFLAGS = \ $(DEPS_DMAP_CFLAGS) \ @@ -34,10 +35,39 @@ libgrldaap_la_SOURCES = \ grl-daap-db.c \ grl-daap-db.h -extdir = $(GRL_PLUGINS_DIR) daapxmldir = $(GRL_PLUGINS_DIR) daapxml_DATA = $(DAAP_PLUGIN_ID).xml EXTRA_DIST += $(daapxml_DATA) +libgrldpap_la_CFLAGS = \ + $(DEPS_DMAP_CFLAGS) \ + -DG_LOG_DOMAIN=\"GrlDmap\" \ + -DLOCALEDIR=\"$(localedir)\" + +libgrldpap_la_LIBADD = \ + $(DEPS_DMAP_LIBS) + +libgrldpap_la_LDFLAGS = \ + -no-undefined \ + -module \ + -avoid-version + +libgrldpap_la_SOURCES = \ + grl-common.c \ + grl-common.h \ + grl-dpap.c \ + grl-dpap.h \ + grl-dpap-record.c \ + grl-dpap-record.h \ + grl-dpap-record-factory.c \ + grl-dpap-record-factory.h \ + grl-dpap-db.c \ + grl-dpap-db.h + +dpapxmldir = $(GRL_PLUGINS_DIR) +dpapxml_DATA = $(DPAP_PLUGIN_ID).xml + +EXTRA_DIST += $(dpapxml_DATA) + -include $(top_srcdir)/git.mk diff --git a/src/dmap/grl-dpap-db.c b/src/dmap/grl-dpap-db.c new file mode 100644 index 0000000..ea418d2 --- /dev/null +++ b/src/dmap/grl-dpap-db.c @@ -0,0 +1,368 @@ +/* + * Copyright (C) 2012 W. Michael Petullo. + * + * Contact: W. Michael Petullo + * + * 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 + */ + +/* See grl-daap-db.c for a description of this database. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include +#include + +#include "grl-dpap-db.h" + +#define PHOTOS_ID "photos" +#define PHOTOS_NAME _("Photos") + +/* Media IDs start at max and go down. Container IDs start at 1 and go up. */ +static guint nextid = G_MAXINT; /* NOTE: this should be G_MAXUINT, but iPhoto can't handle it. */ + +struct GrlDPAPDbPrivate { + /* Contains each picture box (tracked with photos hash table) */ + GrlMediaBox *photos_box; + + GHashTable *root; + GHashTable *photos; +}; + +enum { + PROP_0, + 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))); +} + +GrlDPAPDb * +grl_dpap_db_new (void) +{ + GrlDPAPDb *db = g_object_new (TYPE_GRL_DPAP_DB, NULL); + + return db; +} + +static DMAPRecord * +grl_dpap_db_lookup_by_id (const DMAPDb *db, guint id) +{ + g_warning ("Not implemented"); + return NULL; +} + +static void +grl_dpap_db_foreach (const DMAPDb *db, + GHFunc func, + gpointer data) +{ + g_warning ("Not implemented"); +} + +static gint64 +grl_dpap_db_count (const DMAPDb *db) +{ + g_warning ("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 (set == NULL) { + 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 +grl_dpap_db_add (DMAPDb *_db, DMAPRecord *_record) +{ + g_assert (IS_GRL_DPAP_DB (_db)); + g_assert (IS_DPAP_RECORD (_record)); + + GrlDPAPDb *db = GRL_DPAP_DB (_db); + DPAPRecord *record = DPAP_RECORD (_record); + + gint height = 0, + width = 0, + largefilesize = 0, + creationdate = 0, + rating = 0; + GByteArray *thumbnail = NULL; + gchar *id_s = NULL, + *filename = NULL, + *aspectratio = NULL, + *format = NULL, + *comments = NULL, + *url = NULL; + GrlMedia *media; + + g_object_get (record, + "large-filesize", + &largefilesize, + "creation-date", + &creationdate, + "rating", + &rating, + "filename", + &filename, + "aspect-ratio", + &aspectratio, + "pixel-height", + &height, + "pixel-width", + &width, + "format", + &format, + "comments", + &comments, + "thumbnail", + &thumbnail, + "location", + &url, + NULL); + + id_s = g_strdup_printf ("%u", nextid); + + media = grl_media_image_new (); + + grl_media_set_id (media, id_s); + + if (filename) + grl_media_set_title (media, filename); + + if (url) { + /* Replace URL's dpap:// with http:// */ + memcpy (url, "http", 4); + grl_media_set_url (media, url); + } + + GrlMediaImage *media_image = GRL_MEDIA_IMAGE (media); + + grl_media_image_set_width (media_image, width); + grl_media_image_set_height (media_image, height); + + set_insert (db->priv->photos, PHOTOS_ID, "Unknown", media); + + g_free (id_s); + g_object_unref (media); + + return --nextid; +} + +static gboolean +same_media (GrlMedia *a, GrlMedia *b) +{ + return (strcmp (grl_media_get_id (a), grl_media_get_id (b)) == 0); +} + +void +grl_dpap_db_browse (GrlDPAPDb *db, + GrlMedia *container, + GrlSource *source, + guint op_id, + guint skip, + guint count, + GrlSourceResultCb func, + gpointer user_data) +{ + g_assert (IS_GRL_DPAP_DB (db)); + + int i; + guint remaining; + GHashTable *hash_table; + GHashTableIter iter; + gpointer key, val; + + const gchar *box_id = grl_media_get_id (container); + if (box_id == NULL) { + hash_table = db->priv->root; + } else if (same_media (container, GRL_MEDIA (db->priv->photos_box))) { + hash_table = db->priv->photos; + } else { + hash_table = g_hash_table_lookup (db->priv->photos, container); + } + + /* Should not be NULL; this means the container requested + does not exist in the database. */ + if (hash_table == NULL) { + 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 (GRL_IS_MEDIA_BOX (key)) + grl_media_box_set_childcount (GRL_MEDIA_BOX (key), g_hash_table_size (val)); + func (source, op_id, GRL_MEDIA (g_object_ref (key)), --remaining, user_data, NULL); + } +done: + return; +} + +void +grl_dpap_db_search (GrlDPAPDb *db, + GrlSource *source, + guint op_id, + GHRFunc predicate, + gpointer pred_user_data, + GrlSourceResultCb func, + gpointer user_data) +{ + g_assert (IS_GRL_DPAP_DB (db)); + + gint i, j, k; + guint remaining = 0; + gpointer key1, val1, key2, val2; + GHashTable *hash_tables[] = { db->priv->photos }; + + /* Use hash table to avoid duplicates */ + GHashTable *results = NULL; + GHashTableIter iter1, iter2; + + results = g_hash_table_new (g_str_hash, g_str_equal); + + /* For photos ... */ + for (i = 0; i < G_N_ELEMENTS (hash_tables); i++) { + g_hash_table_iter_init (&iter1, hash_tables[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); + } +} + +static void +dmap_db_interface_init (gpointer iface, gpointer data) +{ + DMAPDbIface *dpap_db = iface; + + g_assert (G_TYPE_FROM_INTERFACE (dpap_db) == DMAP_TYPE_DB); + + dpap_db->add = grl_dpap_db_add; + dpap_db->lookup_by_id = grl_dpap_db_lookup_by_id; + dpap_db->foreach = grl_dpap_db_foreach; + dpap_db->count = grl_dpap_db_count; +} + +G_DEFINE_TYPE_WITH_CODE (GrlDPAPDb, grl_dpap_db, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (DMAP_TYPE_DB, dmap_db_interface_init)) + +static GObject* +grl_dpap_db_constructor (GType type, guint n_construct_params, GObjectConstructParam *construct_params) +{ + GObject *object; + + object = G_OBJECT_CLASS (grl_dpap_db_parent_class)->constructor (type, n_construct_params, construct_params); + + return object; +} + +static void +grl_dpap_db_init (GrlDPAPDb *db) +{ + db->priv = GRL_DPAP_DB_GET_PRIVATE (db); + + db->priv->photos_box = g_object_new (GRL_TYPE_MEDIA_BOX, NULL); + + grl_media_set_id (GRL_MEDIA (db->priv->photos_box), PHOTOS_ID); + grl_media_set_title (GRL_MEDIA (db->priv->photos_box), PHOTOS_NAME); + + db->priv->root = g_hash_table_new_full (box_hash, box_equal, g_object_unref, (GDestroyNotify) g_hash_table_destroy); + db->priv->photos = 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->photos_box), db->priv->photos); +} + +static void +grl_dpap_db_finalize (GObject *object) +{ + GrlDPAPDb *db = GRL_DPAP_DB (object); + + GRL_DEBUG ("Finalizing GrlDPAPDb"); + + g_object_unref (db->priv->photos_box); + + g_hash_table_destroy (db->priv->photos); +} + +static void +grl_dpap_db_class_init (GrlDPAPDbClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GrlDPAPDbPrivate)); + + object_class->finalize = grl_dpap_db_finalize; + object_class->constructor = grl_dpap_db_constructor; +} diff --git a/src/dmap/grl-dpap-db.h b/src/dmap/grl-dpap-db.h new file mode 100644 index 0000000..4c17d1a --- /dev/null +++ b/src/dmap/grl-dpap-db.h @@ -0,0 +1,90 @@ +/* + * Database class for DPAP sharing + * + * Copyright (C) 2008 W. Michael Petullo + * + * 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; either + * 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_DPAP_DB +#define __GRL_DPAP_DB + +#include +#include + +G_BEGIN_DECLS + +#define TYPE_GRL_DPAP_DB \ + (grl_dpap_db_get_type ()) + +#define GRL_DPAP_DB(o) \ + (G_TYPE_CHECK_INSTANCE_CAST ((o), \ + TYPE_GRL_DPAP_DB, \ + GrlDPAPDb)) + +#define GRL_DPAP_DB_CLASS(k) \ + (G_TYPE_CHECK_CLASS_CAST((k), \ + TYPE_GRL_DPAP_DB, \ + GrlDPAPDbClass)) +#define IS_GRL_DPAP_DB(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE((o), \ + TYPE_GRL_DPAP_DB)) +#define IS_GRL_DPAP_DB_CLASS(k) \ + (G_TYPE_CHECK_CLASS_TYPE((k), \ + TYPE_GRL_DPAP_DB_CLASS)) + +#define GRL_DPAP_DB_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS((o), \ + TYPE_GRL_DPAP_DB, \ + GrlDPAPDbClass)) + +#define GRL_DPAP_DB_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), \ + TYPE_GRL_DPAP_DB, \ + GrlDPAPDbPrivate)) + +typedef struct GrlDPAPDbPrivate GrlDPAPDbPrivate; + +typedef struct { + GObject parent; + GrlDPAPDbPrivate *priv; +} GrlDPAPDb; + +typedef struct { + GObjectClass parent; +} GrlDPAPDbClass; + +GrlDPAPDb *grl_dpap_db_new (void); +void grl_dpap_db_browse (GrlDPAPDb *_db, + GrlMedia *container, + GrlSource *source, + guint op_id, + guint skip, + guint count, + GrlSourceResultCb func, + gpointer user_data); +void grl_dpap_db_search (GrlDPAPDb *_db, + GrlSource *source, + guint op_id, + GHRFunc predicate, + gpointer pred_user_data, + GrlSourceResultCb func, + gpointer user_data); + +GType grl_dpap_db_get_type (void); + +#endif /* __GRL_DPAP_DB */ + +G_END_DECLS diff --git a/src/dmap/grl-dpap-record-factory.c b/src/dmap/grl-dpap-record-factory.c new file mode 100644 index 0000000..8174338 --- /dev/null +++ b/src/dmap/grl-dpap-record-factory.c @@ -0,0 +1,58 @@ +/* + * DPAPRecord factory class + * + * Copyright (C) 2008 W. Michael Petullo + * + * 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; either + * 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 + */ + +#include "grl-dpap-record-factory.h" +#include "grl-dpap-record.h" + +DMAPRecord * +grl_dpap_record_factory_create (DMAPRecordFactory *factory, gpointer user_data) +{ + return DMAP_RECORD (grl_dpap_record_new ()); +} + +static void +grl_dpap_record_factory_init (GrlDPAPRecordFactory *factory) +{ +} + +static void +grl_dpap_record_factory_class_init (GrlDPAPRecordFactoryClass *klass) +{ +} + +static void +grl_dpap_record_factory_interface_init (gpointer iface, gpointer data) +{ + DMAPRecordFactoryIface *factory = iface; + + g_assert (G_TYPE_FROM_INTERFACE (factory) == DMAP_TYPE_RECORD_FACTORY); + + factory->create = grl_dpap_record_factory_create; +} + +G_DEFINE_TYPE_WITH_CODE (GrlDPAPRecordFactory, grl_dpap_record_factory, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (DMAP_TYPE_RECORD_FACTORY, + grl_dpap_record_factory_interface_init)) + +GrlDPAPRecordFactory * +grl_dpap_record_factory_new (void) +{ + return SIMPLE_DPAP_RECORD_FACTORY (g_object_new (TYPE_SIMPLE_DPAP_RECORD_FACTORY, NULL)); +} diff --git a/src/dmap/grl-dpap-record-factory.h b/src/dmap/grl-dpap-record-factory.h new file mode 100644 index 0000000..c2106b1 --- /dev/null +++ b/src/dmap/grl-dpap-record-factory.h @@ -0,0 +1,72 @@ +/* + * GrlDPAPRecord factory class + * + * Copyright (C) 2008 W. Michael Petullo + * + * 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; either + * 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 __SIMPLE_DPAP_RECORD_FACTORY +#define __SIMPLE_DPAP_RECORD_FACTORY + +#include + +G_BEGIN_DECLS + +#define TYPE_SIMPLE_DPAP_RECORD_FACTORY \ + (grl_dpap_record_factory_get_type ()) + +#define SIMPLE_DPAP_RECORD_FACTORY(o) \ + (G_TYPE_CHECK_INSTANCE_CAST((o), \ + TYPE_SIMPLE_DPAP_RECORD_FACTORY, \ + GrlDPAPRecordFactory)) + +#define SIMPLE_DPAP_RECORD_FACTORY_CLASS(k) \ + (G_TYPE_CHECK_CLASS_CAST((k), \ + TYPE_SIMPLE_DPAP_RECORD_FACTORY, \ + GrlDPAPRecordFactoryClass)) + +#define IS_SIMPLE_DPAP_RECORD_FACTORY(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE((o), \ + TYPE_SIMPLE_DPAP_RECORD_FACTORY)) + +#define IS_SIMPLE_DPAP_RECORD_FACTORY_CLASS(k) \ + (G_TYPE_CHECK_CLASS_TYPE((k), \ + TYPE_SIMPLE_DPAP_RECORD_FACTORY_CLASS)) + +#define SIMPLE_DPAP_RECORD_FACTORY_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS((o), \ + TYPE_SIMPLE_DPAP_RECORD_FACTORY, \ + GrlDPAPRecordFactoryClass)) + +typedef struct GrlDPAPRecordFactoryPrivate GrlDPAPRecordFactoryPrivate; + +typedef struct { + GObject parent; +} GrlDPAPRecordFactory; + +typedef struct { + GObjectClass parent; +} GrlDPAPRecordFactoryClass; + +GType grl_dpap_record_factory_get_type (void); + +GrlDPAPRecordFactory *grl_dpap_record_factory_new (void); + +DMAPRecord *grl_dpap_record_factory_create (DMAPRecordFactory *factory, gpointer user_data); + +#endif /* __SIMPLE_DPAP_RECORD_FACTORY */ + +G_END_DECLS diff --git a/src/dmap/grl-dpap-record.c b/src/dmap/grl-dpap-record.c new file mode 100644 index 0000000..c4a73db --- /dev/null +++ b/src/dmap/grl-dpap-record.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2012 W. Michael Petullo. + * + * Contact: W. Michael Petullo + * + * 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 + * + */ + +#include "grl-dpap-record.h" + +struct GrlDPAPRecordPrivate { + char *location; + gint largefilesize; + gint creationdate; + gint rating; + char *filename; + GByteArray *thumbnail; + char *aspectratio; + gint height; + gint width; + char *format; + char *comments; +}; + +enum { + PROP_0, + PROP_LOCATION, + PROP_LARGE_FILESIZE, + PROP_CREATION_DATE, + PROP_RATING, + PROP_FILENAME, + PROP_ASPECT_RATIO, + PROP_PIXEL_HEIGHT, + PROP_PIXEL_WIDTH, + PROP_FORMAT, + PROP_COMMENTS, + PROP_THUMBNAIL +}; + +static void +grl_dpap_record_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GrlDPAPRecord *record = SIMPLE_DPAP_RECORD (object); + + switch (prop_id) { + case PROP_LOCATION: + g_free (record->priv->location); + record->priv->location = g_value_dup_string (value); + break; + case PROP_LARGE_FILESIZE: + record->priv->largefilesize = g_value_get_int (value); + break; + case PROP_CREATION_DATE: + record->priv->creationdate = g_value_get_int (value); + break; + case PROP_RATING: + record->priv->rating = g_value_get_int (value); + break; + case PROP_FILENAME: + g_free (record->priv->filename); + record->priv->filename = g_value_dup_string (value); + break; + case PROP_ASPECT_RATIO: + g_free (record->priv->aspectratio); + record->priv->aspectratio = g_value_dup_string (value); + break; + case PROP_PIXEL_HEIGHT: + record->priv->height = g_value_get_int (value); + break; + case PROP_PIXEL_WIDTH: + record->priv->width = g_value_get_int (value); + break; + case PROP_FORMAT: + g_free (record->priv->format); + record->priv->format = g_value_dup_string (value); + break; + case PROP_COMMENTS: + g_free (record->priv->comments); + record->priv->comments = g_value_dup_string (value); + break; + case PROP_THUMBNAIL: + if (record->priv->thumbnail) + g_byte_array_unref (record->priv->thumbnail); + record->priv->thumbnail = g_byte_array_ref (g_value_get_pointer (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +grl_dpap_record_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GrlDPAPRecord *record = SIMPLE_DPAP_RECORD (object); + + switch (prop_id) { + case PROP_LOCATION: + g_value_set_static_string (value, record->priv->location); + break; + case PROP_LARGE_FILESIZE: + g_value_set_int (value, record->priv->largefilesize); + break; + case PROP_CREATION_DATE: + g_value_set_int (value, record->priv->creationdate); + break; + case PROP_RATING: + g_value_set_int (value, record->priv->rating); + break; + case PROP_FILENAME: + g_value_set_static_string (value, record->priv->filename); + break; + case PROP_ASPECT_RATIO: + g_value_set_static_string (value, record->priv->aspectratio); + break; + case PROP_PIXEL_HEIGHT: + g_value_set_int (value, record->priv->height); + break; + case PROP_PIXEL_WIDTH: + g_value_set_int (value, record->priv->width); + break; + case PROP_FORMAT: + g_value_set_static_string (value, record->priv->format); + break; + case PROP_COMMENTS: + g_value_set_static_string (value, record->priv->comments); + break; + case PROP_THUMBNAIL: + g_value_set_pointer (value, record->priv->thumbnail); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +GrlDPAPRecord * +grl_dpap_record_new (void) +{ + return SIMPLE_DPAP_RECORD (g_object_new (TYPE_SIMPLE_DPAP_RECORD, NULL)); +} + +GInputStream * +grl_dpap_record_read (DPAPRecord *record, GError **error) +{ + GFile *file; + GInputStream *stream; + + file = g_file_new_for_uri (SIMPLE_DPAP_RECORD (record)->priv->location); + stream = G_INPUT_STREAM (g_file_read (file, NULL, error)); + + g_object_unref (file); + + return stream; +} + +static void +grl_dpap_record_init (GrlDPAPRecord *record) +{ + record->priv = SIMPLE_DPAP_RECORD_GET_PRIVATE (record); +} + +static void grl_dpap_record_finalize (GObject *object); + +static void +grl_dpap_record_class_init (GrlDPAPRecordClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (klass, sizeof (GrlDPAPRecordPrivate)); + + gobject_class->set_property = grl_dpap_record_set_property; + gobject_class->get_property = grl_dpap_record_get_property; + gobject_class->finalize = grl_dpap_record_finalize; + + g_object_class_override_property (gobject_class, PROP_LOCATION, "location"); + g_object_class_override_property (gobject_class, PROP_LARGE_FILESIZE, "large-filesize"); + g_object_class_override_property (gobject_class, PROP_CREATION_DATE, "creation-date"); + g_object_class_override_property (gobject_class, PROP_RATING, "rating"); + g_object_class_override_property (gobject_class, PROP_FILENAME, "filename"); + g_object_class_override_property (gobject_class, PROP_ASPECT_RATIO, "aspect-ratio"); + g_object_class_override_property (gobject_class, PROP_PIXEL_HEIGHT, "pixel-height"); + g_object_class_override_property (gobject_class, PROP_PIXEL_WIDTH, "pixel-width"); + g_object_class_override_property (gobject_class, PROP_FORMAT, "format"); + g_object_class_override_property (gobject_class, PROP_COMMENTS, "comments"); + g_object_class_override_property (gobject_class, PROP_THUMBNAIL, "thumbnail"); +} + +static void +grl_dpap_record_dpap_iface_init (gpointer iface, gpointer data) +{ + DPAPRecordIface *dpap_record = iface; + + g_assert (G_TYPE_FROM_INTERFACE (dpap_record) == DPAP_TYPE_RECORD); + + dpap_record->read = grl_dpap_record_read; +} + +static void +grl_dpap_record_dmap_iface_init (gpointer iface, gpointer data) +{ + DMAPRecordIface *dmap_record = iface; + + g_assert (G_TYPE_FROM_INTERFACE (dmap_record) == DMAP_TYPE_RECORD); +} + + +G_DEFINE_TYPE_WITH_CODE (GrlDPAPRecord, grl_dpap_record, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (DPAP_TYPE_RECORD, grl_dpap_record_dpap_iface_init) + G_IMPLEMENT_INTERFACE (DMAP_TYPE_RECORD, grl_dpap_record_dmap_iface_init)) + +static void +grl_dpap_record_finalize (GObject *object) +{ + GrlDPAPRecord *record = SIMPLE_DPAP_RECORD (object); + + g_free (record->priv->location); + g_free (record->priv->filename); + g_free (record->priv->aspectratio); + g_free (record->priv->format); + g_free (record->priv->comments); + + if (record->priv->thumbnail) + g_byte_array_unref (record->priv->thumbnail); + + G_OBJECT_CLASS (grl_dpap_record_parent_class)->finalize (object); +} diff --git a/src/dmap/grl-dpap-record.h b/src/dmap/grl-dpap-record.h new file mode 100644 index 0000000..4441740 --- /dev/null +++ b/src/dmap/grl-dpap-record.h @@ -0,0 +1,78 @@ +/* + * Database record class for DPAP sharing + * + * Copyright (C) 2008 W. Michael Petullo + * + * 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; either + * 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 __SIMPLE_DPAP_RECORD +#define __SIMPLE_DPAP_RECORD + +#include + +G_BEGIN_DECLS + +#define TYPE_SIMPLE_DPAP_RECORD \ + (grl_dpap_record_get_type ()) + +#define SIMPLE_DPAP_RECORD(o) \ + (G_TYPE_CHECK_INSTANCE_CAST((o), \ + TYPE_SIMPLE_DPAP_RECORD, \ + GrlDPAPRecord)) + +#define SIMPLE_DPAP_RECORD_CLASS(k) \ + (G_TYPE_CHECK_CLASS_CAST((k), \ + TYPE_SIMPLE_DPAP_RECORD, \ + GrlDPAPRecordClass)) + +#define IS_SIMPLE_DPAP_RECORD(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE((o), \ + TYPE_SIMPLE_DPAP_RECORD)) + +#define IS_SIMPLE_DPAP_RECORD_CLASS(k) \ + (G_TYPE_CHECK_CLASS_TYPE((k), \ + TYPE_SIMPLE_DPAP_RECORD_CLASS)) + +#define SIMPLE_DPAP_RECORD_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS((o), \ + TYPE_SIMPLE_DPAP_RECORD, \ + GrlDPAPRecordClass)) + +#define SIMPLE_DPAP_RECORD_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE((o), \ + TYPE_SIMPLE_DPAP_RECORD, \ + GrlDPAPRecordPrivate)) + +typedef struct GrlDPAPRecordPrivate GrlDPAPRecordPrivate; + +typedef struct { + GObject parent; + GrlDPAPRecordPrivate *priv; +} GrlDPAPRecord; + +typedef struct { + GObjectClass parent; +} GrlDPAPRecordClass; + +GType grl_dpap_record_get_type (void); + +GrlDPAPRecord *grl_dpap_record_new (void); +GInputStream *grl_dpap_record_read (DPAPRecord *record, GError **error); +gint grl_dpap_record_get_id (DPAPRecord *record); + +#endif /* __SIMPLE_DPAP_RECORD */ + +G_END_DECLS diff --git a/src/dmap/grl-dpap.c b/src/dmap/grl-dpap.c new file mode 100644 index 0000000..007e220 --- /dev/null +++ b/src/dmap/grl-dpap.c @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2011 W. Michael Petullo. + * Copyright (C) 2012 Igalia S.L. + * + * Contact: W. Michael Petullo + * + * 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 +#include +#include +#include +#include +#include +#include + +#include "grl-common.h" +#include "grl-dpap.h" +#include "grl-dpap-db.h" +#include "grl-dpap-record.h" +#include "grl-dpap-record-factory.h" + +/* --------- Logging -------- */ + +#define GRL_LOG_DOMAIN_DEFAULT dmap_log_domain +GRL_LOG_DOMAIN_STATIC(dmap_log_domain); + +/* --- Plugin information --- */ + +#define PLUGIN_ID DPAP_PLUGIN_ID + +#define SOURCE_ID_TEMPLATE "grl-dpap-%s" +#define SOURCE_DESC_TEMPLATE _("A source for browsing the DPAP server '%s'") + +/* --- Grilo DPAP Private --- */ + +#define GRL_DPAP_SOURCE_GET_PRIVATE(object) \ + (G_TYPE_INSTANCE_GET_PRIVATE((object), \ + GRL_DPAP_SOURCE_TYPE, \ + GrlDpapSourcePrivate)) + +struct _GrlDpapSourcePrivate { + DMAPMdnsBrowserService *service; +}; + +/* --- Data types --- */ + +static GrlDpapSource *grl_dpap_source_new (DMAPMdnsBrowserService *service); + +static void grl_dpap_source_finalize (GObject *object); + +gboolean grl_dpap_plugin_init (GrlRegistry *registry, + GrlPlugin *plugin, + GList *configs); + +static const GList *grl_dpap_source_supported_keys (GrlSource *source); + +static void grl_dpap_source_browse (GrlSource *source, + GrlSourceBrowseSpec *bs); + +static void grl_dpap_source_search (GrlSource *source, + GrlSourceSearchSpec *ss); + + +static void grl_dpap_service_added_cb (DMAPMdnsBrowser *browser, + DMAPMdnsBrowserService *service, + GrlPlugin *plugin); + +static void grl_dpap_service_removed_cb (DMAPMdnsBrowser *browser, + const gchar *service_name, + GrlPlugin *plugin); + +/* ===================== Globals ======================= */ +static DMAPMdnsBrowser *browser; +/* Maps URIs to DBs */ +static GHashTable *connections; +/* Map DPAP services to Grilo media sources */ +static GHashTable *sources; + +/* =================== DPAP Plugin ====================== */ + +gboolean +grl_dpap_plugin_init (GrlRegistry *registry, + GrlPlugin *plugin, + GList *configs) +{ + GError *error = NULL; + + GRL_LOG_DOMAIN_INIT (dmap_log_domain, "dmap"); + + GRL_DEBUG ("dmap_plugin_init"); + + /* Initialize i18n */ + bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + + browser = dmap_mdns_browser_new (DMAP_MDNS_BROWSER_SERVICE_TYPE_DPAP); + 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), + "service-added", + G_CALLBACK (grl_dpap_service_added_cb), + (gpointer) plugin); + + g_signal_connect (G_OBJECT (browser), + "service-removed", + G_CALLBACK (grl_dpap_service_removed_cb), + (gpointer) plugin); + + if (!dmap_mdns_browser_start (browser, &error)) { + GRL_DEBUG ("error starting browser. code: %d message: %s", + error->code, + error->message); + g_error_free (error); + + g_hash_table_unref (connections); + g_hash_table_unref (sources); + g_object_unref (browser); + return FALSE; + } + + return TRUE; +} + +GRL_PLUGIN_REGISTER (grl_dpap_plugin_init, + NULL, + PLUGIN_ID); + +/* ================== DMAP GObject ====================== */ + +G_DEFINE_TYPE (GrlDpapSource, + grl_dpap_source, + GRL_TYPE_SOURCE); + +static GrlDpapSource * +grl_dpap_source_new (DMAPMdnsBrowserService *service) +{ + gchar *source_desc; + gchar *source_id; + + GrlDpapSource *source; + + GRL_DEBUG ("grl_dpap_source_new"); + + source_desc = g_strdup_printf (SOURCE_DESC_TEMPLATE, service->name); + source_id = g_strdup_printf (SOURCE_ID_TEMPLATE, service->name); + + source = g_object_new (GRL_DPAP_SOURCE_TYPE, + "source-id", source_id, + "source-name", service->name, + "source-desc", source_desc, + NULL); + + source->priv->service = service; + + g_free (source_desc); + g_free (source_id); + + return source; +} + +static void +grl_dpap_source_class_init (GrlDpapSourceClass * klass) +{ + GrlSourceClass *source_class = GRL_SOURCE_CLASS (klass); + + source_class->browse = grl_dpap_source_browse; + source_class->search = grl_dpap_source_search; + source_class->supported_keys = grl_dpap_source_supported_keys; + + G_OBJECT_CLASS (source_class)->finalize = grl_dpap_source_finalize; + + g_type_class_add_private (klass, sizeof (GrlDpapSourcePrivate)); +} + +static void +grl_dpap_source_init (GrlDpapSource *source) +{ + source->priv = GRL_DPAP_SOURCE_GET_PRIVATE (source); +} + +static void +grl_dpap_source_finalize (GObject *object) +{ + G_OBJECT_CLASS (grl_dpap_source_parent_class)->finalize (object); +} + +/* ======================= Utilities ==================== */ + +static void +grl_dpap_do_browse (ResultCbAndArgsAndDb *cb_and_db) +{ + grl_dpap_db_browse(GRL_DPAP_DB(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); + + g_free (cb_and_db); +} + +static void +grl_dpap_do_search (ResultCbAndArgsAndDb *cb_and_db) +{ + grl_dpap_db_search(GRL_DPAP_DB(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 +browse_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, + 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, + error); + g_error_free (error); + } else { + grl_dpap_do_browse (cb_and_db); + } +} + +static void +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, + 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, + error); + g_error_free (error); + } else { + grl_dpap_do_search (cb_and_db); + } +} + +static void +grl_dpap_service_added_cb (DMAPMdnsBrowser *browser, + DMAPMdnsBrowserService *service, + GrlPlugin *plugin) +{ + GrlRegistry *registry = grl_registry_get_default (); + GrlDpapSource *source = grl_dpap_source_new (service); + + GRL_DEBUG (__FUNCTION__); + + g_object_add_weak_pointer (G_OBJECT (source), (gpointer *) &source); + grl_registry_register_source (registry, + plugin, + GRL_SOURCE (source), + NULL); + if (source != NULL) { + g_hash_table_insert (sources, g_strdup (service->name), g_object_ref (source)); + g_object_remove_weak_pointer (G_OBJECT (source), (gpointer *) &source); + } +} + +static void +grl_dpap_service_removed_cb (DMAPMdnsBrowser *browser, + const gchar *service_name, + GrlPlugin *plugin) +{ + GrlRegistry *registry = grl_registry_get_default (); + GrlDpapSource *source = g_hash_table_lookup (sources, service_name); + + GRL_DEBUG (__FUNCTION__); + + if (source) { + grl_registry_unregister_source (registry, GRL_SOURCE (source), NULL); + g_hash_table_remove (sources, service_name); + } +} + +static void +grl_dpap_connect (gchar *name, gchar *host, guint port, ResultCbAndArgsAndDb *cb_and_db, DMAPConnectionCallback callback) +{ + DMAPRecordFactory *factory; + DMAPConnection *connection; + + factory = DMAP_RECORD_FACTORY (grl_dpap_record_factory_new ()); + connection = DMAP_CONNECTION (dpap_connection_new (name, host, port, DMAP_DB (cb_and_db->db), factory)); + dmap_connection_connect (connection, (DMAPConnectionCallback) callback, cb_and_db); +} + +static gboolean +grl_dpap_match (GrlMedia *media, gpointer val, gpointer user_data) +{ + g_assert (GRL_IS_MEDIA_IMAGE (media)); + + if (user_data == NULL) + return TRUE; + + const char *title = grl_media_get_title (media); + return strstr (title, user_data) != NULL; +} + +/* ================== API Implementation ================ */ + +static const GList * +grl_dpap_source_supported_keys (GrlSource *source) +{ + static GList *keys = NULL; + + GRL_DEBUG (__func__); + + if (!keys) + keys = grl_metadata_key_list_new (GRL_METADATA_KEY_HEIGHT, + GRL_METADATA_KEY_THUMBNAIL, + GRL_METADATA_KEY_WIDTH, + GRL_METADATA_KEY_ID, + GRL_METADATA_KEY_URL, + NULL); + + return keys; +} + +static void +grl_dpap_source_browse (GrlSource *source, + GrlSourceBrowseSpec *bs) +{ + GrlDpapSource *dmap_source = GRL_DPAP_SOURCE (source); + gchar *url = grl_dmap_build_url (dmap_source->priv->service); + + GRL_DEBUG (__func__); + + ResultCbAndArgsAndDb *cb_and_db; + + cb_and_db = g_new (ResultCbAndArgsAndDb, 1); + + 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.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. */ + browse_connected_cb (NULL, TRUE, NULL, cb_and_db); + } else { + /* Connect */ + cb_and_db->db = DMAP_DB (grl_dpap_db_new ()); + + grl_dpap_connect (dmap_source->priv->service->name, + dmap_source->priv->service->host, + dmap_source->priv->service->port, + cb_and_db, + (DMAPConnectionCallback) browse_connected_cb); + + g_hash_table_insert (connections, g_strdup (url), cb_and_db->db); + } + + g_free (url); +} + +static void grl_dpap_source_search (GrlSource *source, + GrlSourceSearchSpec *ss) +{ + GrlDpapSource *dmap_source = GRL_DPAP_SOURCE (source); + + ResultCbAndArgsAndDb *cb_and_db; + DMAPMdnsBrowserService *service = dmap_source->priv->service; + gchar *url = grl_dmap_build_url (service); + + cb_and_db = g_new (ResultCbAndArgsAndDb, 1); + + 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.predicate = (GHRFunc) grl_dpap_match; + cb_and_db->cb.predicate_data = ss->text; + 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 */ + search_connected_cb (NULL, TRUE, NULL, cb_and_db); + } else { + /* Connect */ + cb_and_db->db = DMAP_DB (grl_dpap_db_new ()); + grl_dpap_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/grl-dpap.h b/src/dmap/grl-dpap.h new file mode 100644 index 0000000..1f36cfc --- /dev/null +++ b/src/dmap/grl-dpap.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2011 W. Michael Petullo + * Copyright (C) 2012 Igalia S.L. + * + * Contact: W. Michael Petullo + * + * 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_DPAP_SOURCE_H_ +#define _GRL_DPAP_SOURCE_H_ + +#include + +#define GRL_DPAP_SOURCE_TYPE \ + (grl_dpap_source_get_type ()) + +#define GRL_DPAP_SOURCE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + GRL_DPAP_SOURCE_TYPE, \ + GrlDpapSource)) + +#define GRL_IS_DPAP_SOURCE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + GRL_DPAP_SOURCE_TYPE)) + +#define GRL_DPAP_SOURCE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + GRL_DPAP_SOURCE_TYPE, \ + GrlDpapSourceClass)) + +#define GRL_IS_DPAP_SOURCE_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), \ + GRL_DPAP_SOURCE_TYPE)) + +#define GRL_DPAP_SOURCE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + GRL_DPAP_SOURCE_TYPE, \ + GrlDpapSourceClass)) + +typedef struct _GrlDpapSourcePrivate GrlDpapSourcePrivate; +typedef struct _GrlDpapSource GrlDpapSource; + +struct _GrlDpapSource { + GrlSource parent; + + /*< private >*/ + GrlDpapSourcePrivate *priv; +}; + +typedef struct _GrlDpapSourceClass GrlDpapSourceClass; + +struct _GrlDpapSourceClass { + GrlSourceClass parent_class; +}; + +GType grl_dpap_source_get_type (void); + +#endif /* _GRL_DPAP_SOURCE_H_ */ diff --git a/src/dmap/grl-dpap.xml b/src/dmap/grl-dpap.xml new file mode 100644 index 0000000..2e38ae4 --- /dev/null +++ b/src/dmap/grl-dpap.xml @@ -0,0 +1,10 @@ + + + DPAP + libgrldpap + A plugin for browsing DPAP servers + W. Michael Petullo + LGPL + http://www.flyn.org + + -- cgit v1.2.1