[rhythmbox] ext-db: rethink how keys work
- From: Jonathan Matthew <jmatthew src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rhythmbox] ext-db: rethink how keys work
- Date: Wed, 4 Jan 2012 22:49:01 +0000 (UTC)
commit 0c31ced64c1e7daba3716768ee0bb349c161c1b7
Author: Jonathan Matthew <jonathan d14n org>
Date: Mon Jan 2 22:05:12 2012 +1000
ext-db: rethink how keys work
Keys now consist of fields, only one of which can be multi-valued,
and info. This removes the annoying confusion between artist and
album-artist.
metadata/rb-ext-db-key.c | 438 ++++++++++++++------
metadata/rb-ext-db-key.h | 29 +-
metadata/rb-ext-db.c | 10 +-
plugins/artsearch/artsearch.py | 26 +--
plugins/artsearch/lastfm.py | 42 +-
plugins/artsearch/local.py | 35 +-
plugins/artsearch/musicbrainz.py | 23 +-
plugins/artsearch/oldcache.py | 24 +-
.../rb-audioscrobbler-radio-source.c | 4 +-
plugins/grilo/rb-grilo-plugin.c | 7 +-
plugins/ipod/rb-ipod-source.c | 6 +-
plugins/magnatune/MagnatuneSource.py | 4 +-
plugins/mtpdevice/rb-mtp-source.c | 7 +-
podcast/rb-podcast-manager.c | 2 +-
rhythmdb/rhythmdb.c | 86 ++---
shell/rb-shell-player.c | 4 +-
16 files changed, 434 insertions(+), 313 deletions(-)
---
diff --git a/metadata/rb-ext-db-key.c b/metadata/rb-ext-db-key.c
index 717599e..94555be 100644
--- a/metadata/rb-ext-db-key.c
+++ b/metadata/rb-ext-db-key.c
@@ -47,20 +47,23 @@
typedef struct
{
char *name;
- char *value;
- RBExtDBFieldType type;
+ GPtrArray *values;
+ gboolean match_null;
} RBExtDBField;
struct _RBExtDBKey
{
+ gboolean lookup;
+ RBExtDBField *multi_field;
GList *fields;
+ GList *info;
};
static void
rb_ext_db_field_free (RBExtDBField *field)
{
g_free (field->name);
- g_free (field->value);
+ g_ptr_array_free (field->values, TRUE);
g_slice_free (RBExtDBField, field);
}
@@ -68,10 +71,14 @@ static RBExtDBField *
rb_ext_db_field_copy (RBExtDBField *field)
{
RBExtDBField *copy;
+ int i;
+
copy = g_slice_new0 (RBExtDBField);
copy->name = g_strdup (field->name);
- copy->value = g_strdup (field->value);
- copy->type = field->type;
+ copy->values = g_ptr_array_new_with_free_func (g_free);
+ for (i = 0; i < field->values->len; i++) {
+ g_ptr_array_add (copy->values, g_strdup (g_ptr_array_index (field->values, i)));
+ }
return copy;
}
@@ -104,9 +111,14 @@ rb_ext_db_key_copy (RBExtDBKey *key)
GList *l;
copy = g_slice_new0 (RBExtDBKey);
+ copy->lookup = key->lookup;
+ copy->multi_field = key->multi_field;
for (l = key->fields; l != NULL; l = l->next) {
copy->fields = g_list_append (copy->fields, rb_ext_db_field_copy (l->data));
}
+ for (l = key->info; l != NULL; l = l->next) {
+ copy->info = g_list_append (copy->info, rb_ext_db_field_copy (l->data));
+ }
return copy;
}
@@ -120,53 +132,152 @@ void
rb_ext_db_key_free (RBExtDBKey *key)
{
g_list_free_full (key->fields, (GDestroyNotify) rb_ext_db_field_free);
+ g_list_free_full (key->info, (GDestroyNotify) rb_ext_db_field_free);
g_slice_free (RBExtDBKey, key);
}
+static RBExtDBKey *
+do_create (const char *field, const char *value, gboolean lookup)
+{
+ RBExtDBKey *key;
+ key = g_slice_new0 (RBExtDBKey);
+ key->lookup = lookup;
+ rb_ext_db_key_add_field (key, field, value);
+ return key;
+}
+
/**
- * rb_ext_db_key_create:
+ * rb_ext_db_key_create_lookup:
* @field: required field name
* @value: value for field
*
- * Creates a new metadata lookup key with a single required field.
+ * Creates a new metadata lookup key with a single field.
* Use @rb_ext_db_key_add_field to add more.
*
* Return value: the new key
*/
RBExtDBKey *
-rb_ext_db_key_create (const char *field, const char *value)
+rb_ext_db_key_create_lookup (const char *field, const char *value)
{
- RBExtDBKey *key;
+ return do_create (field, value, TRUE);
+}
- key = g_slice_new0 (RBExtDBKey);
- rb_ext_db_key_add_field (key, field, RB_EXT_DB_FIELD_REQUIRED, value);
+/**
+ * rb_ext_db_key_create_storage:
+ * @field: required field name
+ * @value: value for field
+ *
+ * Creates a new metadata storage key with a single field.
+ * Use @rb_ext_db_key_add_field to add more.
+ *
+ * Return value: the new key
+ */
+RBExtDBKey *
+rb_ext_db_key_create_storage (const char *field, const char *value)
+{
+ return do_create (field, value, FALSE);
+}
- return key;
+/**
+ * rb_ext_db_key_is_lookup:
+ * @key: a #RBExtDBKey
+ *
+ * Returns %TRUE if the key is a lookup key
+ *
+ * Return value: whether the key is a lookup key
+ */
+gboolean
+rb_ext_db_key_is_lookup (RBExtDBKey *key)
+{
+ return key->lookup;
+}
+
+static void
+add_to_list (GList **list, RBExtDBField **multi, const char *name, const char *value)
+{
+ RBExtDBField *f;
+ GList *l;
+ int i;
+
+ for (l = *list; l != NULL; l = l->next) {
+ f = l->data;
+ if (strcmp (f->name, name) == 0) {
+ g_assert (multi != NULL);
+
+ if (value != NULL) {
+ for (i = 0; i < f->values->len; i++) {
+ if (strcmp (g_ptr_array_index (f->values, i), value) == 0) {
+ /* duplicate value */
+ return;
+ }
+ }
+ g_assert (*multi == NULL || *multi == f);
+ g_ptr_array_add (f->values, g_strdup (value));
+ *multi = f;
+ } else {
+ g_assert (*multi == NULL || *multi == f);
+ f->match_null = TRUE;
+ *multi = f;
+ }
+ return;
+ }
+ }
+
+ f = g_slice_new0 (RBExtDBField);
+ f->name = g_strdup (name);
+ f->values = g_ptr_array_new_with_free_func (g_free);
+ g_ptr_array_add (f->values, g_strdup (value));
+ *list = g_list_append (*list, f);
+}
+
+static char **
+get_list_names (GList *list)
+{
+ char **names;
+ GList *l;
+ int i;
+
+ names = g_new0 (char *, g_list_length (list) + 1);
+ i = 0;
+ for (l = list; l != NULL; l = l->next) {
+ RBExtDBField *f = l->data;
+ names[i++] = g_strdup (f->name);
+ }
+
+ return names;
}
+static GPtrArray *
+get_list_values (GList *list, const char *field)
+{
+ RBExtDBField *f;
+ GList *l;
+
+ for (l = list; l != NULL; l = l->next) {
+ f = l->data;
+ if (strcmp (f->name, field) == 0) {
+ return f->values;
+ }
+ }
+
+ return NULL;
+}
+
+
/**
* rb_ext_db_key_add_field:
* @key: a #RBExtDBKey
* @field: name of the field to add
- * @field_type: field type (required, optional, or informational)
* @value: field value
*
- * Adds a field to the key. Does not check that the field does not
- * already exist.
+ * Adds a field to the key, or an additional value to an existing field.
*/
void
rb_ext_db_key_add_field (RBExtDBKey *key,
const char *field,
- RBExtDBFieldType field_type,
const char *value)
{
- RBExtDBField *f;
-
- f = g_slice_new0 (RBExtDBField);
- f->name = g_strdup (field);
- f->value = g_strdup (value);
- f->type = field_type;
- key->fields = g_list_append (key->fields, f);
+ add_to_list (&key->fields, &key->multi_field, field, value);
}
/**
@@ -181,18 +292,7 @@ rb_ext_db_key_add_field (RBExtDBKey *key,
char **
rb_ext_db_key_get_field_names (RBExtDBKey *key)
{
- char **names;
- GList *l;
- int i;
-
- names = g_new0 (char *, g_list_length (key->fields) + 1);
- i = 0;
- for (l = key->fields; l != NULL; l = l->next) {
- RBExtDBField *f = l->data;
- names[i++] = g_strdup (f->name);
- }
-
- return names;
+ return get_list_names (key->fields);
}
/**
@@ -200,68 +300,124 @@ rb_ext_db_key_get_field_names (RBExtDBKey *key)
* @key: a #RBExtDBKey
* @field: field to retrieve
*
- * Extracts the value for the specified field.
+ * Extracts the value for a single-valued field.
*
* Return value: field value, or NULL
*/
const char *
rb_ext_db_key_get_field (RBExtDBKey *key, const char *field)
{
- GList *l;
-
- for (l = key->fields; l != NULL; l = l->next) {
- RBExtDBField *f = l->data;
- if (g_strcmp0 (field, f->name) == 0) {
- return f->value;
- }
+ GPtrArray *v = get_list_values (key->fields, field);
+ if (v != NULL && v->len > 0) {
+ return g_ptr_array_index (v, 0);
+ } else {
+ return NULL;
}
-
- return NULL;
}
+
/**
- * rb_ext_db_key_get_field_type:
+ * rb_ext_db_key_get_field_values:
* @key: a #RBExtDBKey
* @field: field to retrieve
*
- * Extracts the field type for the specified field.
+ * Extracts the values for the specified field.
*
- * Return value: field type value
+ * Return value: (transfer full): field values, or NULL
*/
-RBExtDBFieldType
-rb_ext_db_key_get_field_type (RBExtDBKey *key, const char *field)
+char **
+rb_ext_db_key_get_field_values (RBExtDBKey *key, const char *field)
{
- GList *l;
+ GPtrArray *v = get_list_values (key->fields, field);
+ char **strv;
+ int i;
- for (l = key->fields; l != NULL; l = l->next) {
- RBExtDBField *f = l->data;
- if (g_strcmp0 (field, f->name) == 0) {
- return f->type;
- }
+ if (v == NULL) {
+ return NULL;
}
- /* check that the field exists before calling this */
- return RB_EXT_DB_FIELD_INFORMATIONAL;
+ strv = g_new0 (char *, v->len + 1);
+ for (i = 0; i < v->len; i++) {
+ strv[i] = g_strdup (g_ptr_array_index (v, i));
+ }
+ return strv;
}
-static gboolean
-match_field (RBExtDBKey *key, RBExtDBField *field)
+/**
+ * rb_ext_db_key_add_info:
+ * @key: a #RBExtDBKey
+ * @field: name of the field to add
+ * @value: field value
+ *
+ * Adds an information field to the key.
+ */
+void
+rb_ext_db_key_add_info (RBExtDBKey *key,
+ const char *field,
+ const char *value)
{
- const char *value;
+ add_to_list (&key->info, NULL, field, value);
+}
- if (field->type == RB_EXT_DB_FIELD_INFORMATIONAL)
- return TRUE;
+/**
+ * rb_ext_db_key_get_info_names:
+ * @key: a #RBExtDBKey
+ *
+ * Returns a NULL-terminated array containing the names of the info
+ * fields * present in the key.
+ *
+ * Return value: (transfer full): array of info field names
+ */
+char **
+rb_ext_db_key_get_info_names (RBExtDBKey *key)
+{
+ return get_list_names (key->info);
+}
- value = rb_ext_db_key_get_field (key, field->name);
- if (value == NULL) {
- if (field->type == RB_EXT_DB_FIELD_REQUIRED)
- return FALSE;
+/**
+ * rb_ext_db_key_get_info:
+ * @key: a #RBExtDBKey
+ * @name: info field to retrieve
+ *
+ * Extracts the value for the specified info field.
+ *
+ * Return value: field value, or NULL
+ */
+const char *
+rb_ext_db_key_get_info (RBExtDBKey *key, const char *name)
+{
+ GPtrArray *v = get_list_values (key->fields, name);
+ if (v != NULL && v->len > 0) {
+ return g_ptr_array_index (v, 0);
} else {
- if (g_strcmp0 (value, field->value) != 0)
- return FALSE;
+ return NULL;
}
+}
- return TRUE;
+
+
+
+static gboolean
+match_field (RBExtDBKey *key, RBExtDBField *field)
+{
+ GPtrArray *values;
+ int i;
+ int j;
+
+ values = get_list_values (key->fields, field->name);
+ if (values == NULL) {
+ return field->match_null;
+ }
+
+ for (i = 0; i < field->values->len; i++) {
+ const char *a = g_ptr_array_index (field->values, i);
+ for (j = 0; j < values->len; j++) {
+ const char *b = g_ptr_array_index (values, j);
+ if (strcmp (a, b) == 0)
+ return TRUE;
+ }
+ }
+ return FALSE;
}
/**
@@ -298,46 +454,90 @@ rb_ext_db_key_matches (RBExtDBKey *a, RBExtDBKey *b)
return TRUE;
}
-static void
-create_store_key (RBExtDBKey *key, guint optional_count, guint optional_fields, TDB_DATA *data)
+/**
+ * rb_ext_db_key_field_matches:
+ * @key: an #RBExtDBKey
+ * @field: a field to check
+ * @value: a value to match against
+ *
+ * Checks whether a specified field in @key matches a value.
+ * This can be used to match keys against other types of data.
+ * To match keys against each other, use @rb_ext_db_key_matches.
+ *
+ * Return value: %TRUE if the field matches the value
+ */
+gboolean
+rb_ext_db_key_field_matches (RBExtDBKey *key, const char *field, const char *value)
+{
+ GPtrArray *v;
+ int i;
+
+ v = get_list_values (key->fields, field);
+ if (v == NULL) {
+ /* if the key doesn't have this field, anything matches */
+ return TRUE;
+ }
+
+ if (value == NULL) {
+ if (key->multi_field == NULL) {
+ /* no multi field, so null can't match */
+ return FALSE;
+ }
+
+ if (g_strcmp0 (field, key->multi_field->name) == 0) {
+ /* this is the multi field, so null might match */
+ return key->multi_field->match_null;
+ } else {
+ /* this isn't the multi field, null can't match */
+ return FALSE;
+ }
+ }
+
+ for (i = 0; i < v->len; i++) {
+ if (strcmp (g_ptr_array_index (v, i), value) == 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+create_store_key (RBExtDBKey *key, int option, TDB_DATA *data)
{
GByteArray *k;
GList *l;
- int opt = 0;
guint8 nul = '\0';
+ if (key->multi_field != NULL &&
+ option > key->multi_field->values->len &&
+ key->multi_field->match_null == FALSE) {
+ return FALSE;
+ } else if (key->multi_field == NULL && option != 0) {
+ return FALSE;
+ }
+
k = g_byte_array_sized_new (512);
for (l = key->fields; l != NULL; l = l->next) {
RBExtDBField *f = l->data;
- switch (f->type) {
- case RB_EXT_DB_FIELD_OPTIONAL:
- /* decide if we want to include this one */
- if (optional_fields != G_MAXUINT) {
- int bit = 1 << ((optional_count-1) - opt);
- opt++;
- if ((optional_fields & bit) == 0)
- break;
- }
- /* fall through */
- case RB_EXT_DB_FIELD_REQUIRED:
- g_byte_array_append (k, (guint8 *)f->name, strlen (f->name));
- g_byte_array_append (k, &nul, 1);
- g_byte_array_append (k, (guint8 *)f->value, strlen (f->value));
- g_byte_array_append (k, &nul, 1);
- break;
-
- case RB_EXT_DB_FIELD_INFORMATIONAL:
- break;
-
- default:
- g_assert_not_reached ();
- break;
+ const char *value;
+
+ if (f != key->multi_field) {
+ value = g_ptr_array_index (f->values, 0);
+ } else if (option < f->values->len) {
+ value = g_ptr_array_index (f->values, option);
+ } else {
+ continue;
}
-
+ g_byte_array_append (k, (guint8 *)f->name, strlen (f->name));
+ g_byte_array_append (k, &nul, 1);
+ g_byte_array_append (k, (guint8 *)value, strlen (value));
+ g_byte_array_append (k, &nul, 1);
}
data->dsize = k->len;
data->dptr = g_byte_array_free (k, FALSE);
+ return TRUE;
}
/**
@@ -358,28 +558,21 @@ rb_ext_db_key_lookups (RBExtDBKey *key,
RBExtDBKeyLookupCallback callback,
gpointer user_data)
{
- int optional_count = 0;
- int optional_keys;
- GList *l;
-
- for (l = key->fields; l != NULL; l = l->next) {
- RBExtDBField *field = l->data;
- if (field->type == RB_EXT_DB_FIELD_OPTIONAL) {
- optional_count++;
- }
- }
-
- for (optional_keys = (1<<optional_count)-1; optional_keys >= 0; optional_keys--) {
+ int i = 0;
+ while (TRUE) {
TDB_DATA sk;
gboolean result;
- create_store_key (key, optional_count, optional_keys, &sk);
+ if (create_store_key (key, i, &sk) == FALSE)
+ break;
result = callback (sk, user_data);
g_free (sk.dptr);
if (result == FALSE)
break;
+
+ i++;
}
}
@@ -403,29 +596,6 @@ TDB_DATA
rb_ext_db_key_to_store_key (RBExtDBKey *key)
{
TDB_DATA k = {0,};
- /* include all optional keys */
- create_store_key (key, G_MAXUINT, G_MAXUINT, &k);
+ create_store_key (key, 0, &k);
return k;
}
-
-
-
-#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
-
-GType
-rb_ext_db_field_type_get_type (void)
-{
- static GType etype = 0;
-
- if (etype == 0) {
- static const GEnumValue values[] = {
- ENUM_ENTRY(RB_EXT_DB_FIELD_REQUIRED, "required"),
- ENUM_ENTRY(RB_EXT_DB_FIELD_OPTIONAL, "optional"),
- ENUM_ENTRY(RB_EXT_DB_FIELD_INFORMATIONAL, "informational"),
- { 0, 0, 0 }
- };
- etype = g_enum_register_static ("RBExtDBFieldType", values);
- }
-
- return etype;
-}
diff --git a/metadata/rb-ext-db-key.h b/metadata/rb-ext-db-key.h
index 959007f..06b8545 100644
--- a/metadata/rb-ext-db-key.h
+++ b/metadata/rb-ext-db-key.h
@@ -37,16 +37,6 @@
G_BEGIN_DECLS
-
-typedef enum {
- RB_EXT_DB_FIELD_REQUIRED, /* results must match this; stored */
- RB_EXT_DB_FIELD_OPTIONAL, /* results should match this; stored */
- RB_EXT_DB_FIELD_INFORMATIONAL /* may be used to find results, not stored */
-} RBExtDBFieldType;
-
-GType rb_ext_db_field_type_get_type (void);
-#define RB_TYPE_EXT_DB_FIELD_TYPE (rb_ext_db_field_type_get_type ())
-
typedef struct _RBExtDBKey RBExtDBKey;
struct _RBExtDBKey;
@@ -58,19 +48,30 @@ GType rb_ext_db_key_get_type (void);
RBExtDBKey * rb_ext_db_key_copy (RBExtDBKey *key);
void rb_ext_db_key_free (RBExtDBKey *key);
-RBExtDBKey * rb_ext_db_key_create (const char *field,
+RBExtDBKey * rb_ext_db_key_create_lookup (const char *field,
const char *value);
+RBExtDBKey * rb_ext_db_key_create_storage (const char *field,
+ const char *value);
+gboolean rb_ext_db_key_is_lookup (RBExtDBKey *key);
void rb_ext_db_key_add_field (RBExtDBKey *key,
const char *field,
- RBExtDBFieldType field_type,
const char *value);
-
char ** rb_ext_db_key_get_field_names (RBExtDBKey *key);
const char * rb_ext_db_key_get_field (RBExtDBKey *key,
const char *field);
-RBExtDBFieldType rb_ext_db_key_get_field_type (RBExtDBKey *key,
+char ** rb_ext_db_key_get_field_values (RBExtDBKey *key,
const char *field);
+gboolean rb_ext_db_key_field_matches (RBExtDBKey *key,
+ const char *field,
+ const char *value);
+
+void rb_ext_db_key_add_info (RBExtDBKey *key,
+ const char *name,
+ const char *value);
+char ** rb_ext_db_key_get_info_names (RBExtDBKey *key);
+const char * rb_ext_db_key_get_info (RBExtDBKey *key,
+ const char *name);
gboolean rb_ext_db_key_matches (RBExtDBKey *a,
RBExtDBKey *b);
diff --git a/metadata/rb-ext-db.c b/metadata/rb-ext-db.c
index ab90387..194edb0 100644
--- a/metadata/rb-ext-db.c
+++ b/metadata/rb-ext-db.c
@@ -676,18 +676,20 @@ rb_ext_db_request (RBExtDB *store,
return FALSE;
}
- /* discard duplicate requests */
+ /* discard duplicate requests, combine equivalent requests */
for (l = store->priv->requests; l != NULL; l = l->next) {
req = l->data;
+ if (rb_ext_db_key_matches (key, req->key) == FALSE)
+ continue;
+
if (req->callback == callback &&
req->user_data == user_data &&
- req->destroy_notify == destroy &&
- rb_ext_db_key_matches (key, req->key)) {
+ req->destroy_notify == destroy) {
rb_debug ("found matching existing request");
if (destroy)
destroy (user_data);
return TRUE;
- } else if (rb_ext_db_key_matches (key, req->key)) {
+ } else {
rb_debug ("found existing equivalent request");
emit_request = FALSE;
}
diff --git a/plugins/artsearch/artsearch.py b/plugins/artsearch/artsearch.py
index bb14573..d8d5304 100644
--- a/plugins/artsearch/artsearch.py
+++ b/plugins/artsearch/artsearch.py
@@ -41,40 +41,18 @@ class Search(object):
self.last_time = last_time
self.searches = searches
-
def next_search(self):
if len(self.searches) == 0:
self.store.store(self.key, RB.ExtDBSourceType.NONE, None)
return False
search = self.searches.pop(0)
- search.search(self.key, self.last_time, self.search_results, None)
+ search.search(self.key, self.last_time, self.store, self.search_done, None)
return True
-
- def search_results(self, storekey, data, source_type, args):
-
- if data is None or storekey is None:
- pass
- elif isinstance(data, str) or isinstance(data, unicode):
- print "got a uri: %s" % str(data)
- self.store.store_uri(storekey, source_type, data)
- elif isinstance(data, list) or isinstance(data, tuple):
- print "got a uri list: %s" % str(data)
- for u in data:
- self.store.store_uri(storekey, source_type, u)
- elif isinstance(data, GdkPixbuf.Pixbuf):
- print "got a pixbuf"
- self.store.store(storekey, source_type, data)
- else:
- # complain quietly
- print "got mystery meat: %s" % data
- pass
-
- # keep going anyway
+ def search_done(self, args):
self.next_search()
-
class ArtSearchPlugin (GObject.GObject, Peas.Activatable):
__gtype_name__ = 'ArtSearchPlugin'
object = GObject.property(type=GObject.GObject)
diff --git a/plugins/artsearch/lastfm.py b/plugins/artsearch/lastfm.py
index 33db7bb..8ad267a 100644
--- a/plugins/artsearch/lastfm.py
+++ b/plugins/artsearch/lastfm.py
@@ -123,20 +123,21 @@ class LastFMSearch (object):
if len(image_urls) > 0:
# images tags appear in order of increasing size, and we want the largest. probably.
url = image_urls.pop()
- self.callback(self.current_key, url, RB.ExtDBSourceType.SEARCH, self.callback_args)
+ self.store.store_uri(self.current_key, RB.ExtDBSourceType.SEARCH, url)
+ self.callback(self.callback_args)
else:
self.search_next()
def search_next (self):
if len(self.searches) == 0:
- self.callback(None, None, RB.ExtDBSourceType.NONE, self.callback_args)
+ self.callback(self.callback_args)
return
- (artist, album, album_mbid, artist_field) = self.searches.pop(0)
- self.current_key = RB.ExtDBKey.create("album", album)
+ (artist, album, album_mbid) = self.searches.pop(0)
+ self.current_key = RB.ExtDBKey.create_storage("album", album)
if artist is not None:
- self.current_key.add_field(artist_field, RB.ExtDBFieldType.OPTIONAL, artist)
+ self.current_key.add_field("artist", artist)
url = self.search_url(artist, album, album_mbid)
@@ -144,41 +145,36 @@ class LastFMSearch (object):
l.get_url(url, self.album_info_cb)
- def search(self, key, last_time, callback, args):
+ def search(self, key, last_time, store, callback, args):
if last_time > (time.time() - REPEAT_SEARCH_PERIOD):
print "we already tried this one"
- callback (None, None, RB.ExtDBSourceType.NONE, args)
+ callback (args)
return
if user_has_account() == False:
print "can't search: no last.fm account details"
- callback (None, None, RB.ExtDBSourceType.NONE, args)
+ callback (args)
return
album = key.get_field("album")
- albumartist = key.get_field("album-artist")
- album_mbid = key.get_field("musicbrainz-albumid")
- artist = key.get_field("artist")
-
- if albumartist in ("", _("Unknown")):
- albumartist = None
- if artist in ("", _("Unknown")):
- artist = None
+ artists = key.get_field_values("artist")
+ album_mbid = key.get_info("musicbrainz-albumid")
+
+ artists = filter(lambda x: x not in (None, "", _("Unknown")), artists)
if album in ("", _("Unknown")):
album = None
- if album == None or (albumartist == None and artist == None):
+ if album == None or len(artists) == 0:
print "can't search: no useful details"
- callback (None, None, RB.ExtDBSourceType.NONE, args)
+ callback (args)
return
self.searches = []
- if artist != albumartist and artist != None:
- self.searches.append([artist, album, album_mbid, "artist"])
- if albumartist != None:
- self.searches.append([albumartist, album, album_mbid, "album-artist"])
- self.searches.append(["Various Artists", album, album_mbid, "album-artist"])
+ for a in artists:
+ self.searches.append([a, album, album_mbid])
+ self.searches.append(["Various Artists", album, album_mbid])
+ self.store = store
self.callback = callback
self.callback_args = args
self.search_next()
diff --git a/plugins/artsearch/local.py b/plugins/artsearch/local.py
index 79be909..b14eb91 100644
--- a/plugins/artsearch/local.py
+++ b/plugins/artsearch/local.py
@@ -51,21 +51,28 @@ class LocalSearch:
def finished(self, results):
parent = self.file.get_parent()
ordered = []
+ key = RB.ExtDBKey.create_storage("album", self.album)
+ key.add_field("artist", self.artist)
# Compare lower case, without file extension
for name in [file_root (self.file.get_basename())] + IMAGE_NAMES:
for f_name in results:
if file_root (f_name) == name:
- ordered.append(parent.resolve_relative_path(f_name).get_uri())
+ uri = parent.resolve_relative_path(f_name).get_uri()
+ self.store.store_uri(key, RB.ExtDBSourceType.USER, uri)
# look for file names containing the artist and album (case-insensitive)
# (mostly for jamendo downloads)
- artist = self.artist.lower()
album = self.album.lower()
for f_name in results:
f_root = file_root (f_name).lower()
- if f_root.find (artist) != -1 and f_root.find (album) != -1:
- ordered.append(parent.resolve_relative_path(f_name).get_uri())
+ for artist in self.artists:
+ artist = artist.lower()
+ if f_root.find (artist) != -1 and f_root.find (album) != -1:
+ nkey = RB.ExtDBKey.create_storage("album", album)
+ nkey.add_field("artist", artist)
+ uri = parent.resolve_relative_path(f_name).get_uri()
+ self.store.store_uri(nkey. RB.ExtDBSourceType.USER, uri)
# if that didn't work, look for the longest shared prefix
# only accept matches longer than 2 to avoid weird false positives
@@ -78,11 +85,10 @@ class LocalSearch:
match = f_name
if match is not None:
- ordered.append(parent.resolve_relative_path(match).get_uri())
+ uri = parent.resolve_relative_path(match).get_uri()
+ self.store.store_uri(nkey. RB.ExtDBSourceType.USER, uri)
- key = RB.ExtDBKey.create("album", self.album)
- key.add_field("album-artist", RB.ExtDBFieldType.OPTIONAL, self.artist)
- self.callback(key, ordered, RB.ExtDBSourceType.USER, self.callback_args)
+ self.callback(self.callback_args)
def _enum_dir_cb(self, fileenum, result, results):
try:
@@ -117,28 +123,27 @@ class LocalSearch:
print "okay, probably done: %s" % e
import sys
sys.excepthook(*sys.exc_info())
- self.callback(None, None, RB.ExtDBSourceType.NONE, self.callback_args)
+ self.callback(self.callback_args)
- def search (self, key, last_time, callback, args):
+ def search (self, key, last_time, store, callback, args):
# ignore last_time
location = key.get_field("location")
if location is None:
print "not searching, we don't have a location"
- callback(None, None, RB.ExtDBSourceType.NONE, args)
+ callback(args)
return
self.file = Gio.file_new_for_uri(location)
if self.file.get_uri_scheme() in IGNORED_SCHEMES:
print 'not searching for local art for %s' % (self.file.get_uri())
- callback(None, None, RB.ExtDBSourceType.NONE, args)
+ callback(args)
return
self.album = key.get_field("album")
- self.artist = key.get_field("album-artist")
- if self.artist in (None, ""):
- self.artist = key.get_field("artist")
+ self.artists = key.get_field_values("artist")
+ self.store = store
self.callback = callback
self.callback_args = args
diff --git a/plugins/artsearch/musicbrainz.py b/plugins/artsearch/musicbrainz.py
index fdf90b7..6b38d2d 100644
--- a/plugins/artsearch/musicbrainz.py
+++ b/plugins/artsearch/musicbrainz.py
@@ -43,16 +43,16 @@ AMAZON_IMAGE_URL = "http://images.amazon.com/images/P/%s.01.LZZZZZZZ.jpg"
class MusicBrainzSearch(object):
def get_release_cb (self, data, args):
- (key, callback, cbargs) = args
+ (key, store, callback, cbargs) = args
if data is None:
print "musicbrainz release request returned nothing"
- callback(None, None, RB.ExtDBSourceType.NONE, *cbargs)
+ callback(*cbargs)
return
try:
parsed = dom.parseString(data)
- storekey = RB.ExtDBKey.create('album', key.get_field('album'))
+ storekey = RB.ExtDBKey.create_storage('album', key.get_field('album'))
# check that there's an artist that isn't 'various artists'
artist_tags = parsed.getElementsByTagName('artist')
@@ -64,7 +64,7 @@ class MusicBrainzSearch(object):
if len(nametags) > 0:
artistname = nametags[0].firstChild.data
print "got musicbrainz artist name %s" % artistname
- storekey.add_field('album-artist', RB.ExtDBFieldType.OPTIONAL, artistname)
+ storekey.add_field('artist', artistname)
# look for an ASIN tag
@@ -75,20 +75,21 @@ class MusicBrainzSearch(object):
print "got ASIN %s" % asin
image_url = AMAZON_IMAGE_URL % asin
- callback(storekey, image_url, RB.ExtDBSourceType.SEARCH, *cbargs)
+ store.store_uri(storekey, RB.ExtDBSourceType.SEARCH, image_url)
else:
print "no ASIN for this release"
- callback(None, None, RB.ExtDBSourceType.NONE, *cbargs)
+
+ callback(*cbargs)
except Exception, e:
print "exception parsing musicbrainz response: %s" % e
- callback(None, None, RB.ExtDBSourceType.NONE, *cbargs)
+ callback(*cbargs)
- def search(self, key, last_time, callback, *args):
+ def search(self, key, last_time, store, callback, *args):
key = key.copy() # ugh
- album_id = key.get_field("musicbrainz-albumid")
+ album_id = key.get_info("musicbrainz-albumid")
if album_id is None:
print "no musicbrainz release ID for this track"
- callback(None, None, RB.ExtDBSourceType.NONE, *args)
+ callback(*args)
return
if album_id.startswith(MUSICBRAINZ_RELEASE_PREFIX):
@@ -101,4 +102,4 @@ class MusicBrainzSearch(object):
url = MUSICBRAINZ_RELEASE_URL % (album_id)
loader = rb.Loader()
- loader.get_url(url, self.get_release_cb, (key, callback, args))
+ loader.get_url(url, self.get_release_cb, (key, store, callback, args))
diff --git a/plugins/artsearch/oldcache.py b/plugins/artsearch/oldcache.py
index eecf125..f689e07 100644
--- a/plugins/artsearch/oldcache.py
+++ b/plugins/artsearch/oldcache.py
@@ -45,25 +45,21 @@ class OldCacheSearch(object):
album = album.replace('/', '-')
return os.path.join(ART_FOLDER, '%s - %s.%s' % (artist, album, extension))
- def search(self, key, last_time, callback, *args):
+ def search(self, key, last_time, store, callback, *args):
album = key.get_field("album")
- artist = key.get_field("artist")
- albumartist = key.get_field("album-artist")
-
- print "looking for %s by (%s, %s)" % (album, artist, albumartist)
- for field in ('album-artist', 'artist'):
- artist = key.get_field(field)
- if artist is None:
- continue
+ artists = key.get_field_values("artist") or []
+ print "looking for %s by %s" % (album, str(artists))
+ for artist in artists:
for ext in ('jpg', 'png'):
- path = self.filename(album, field, ext)
+ path = self.filename(album, artist, ext)
if os.path.exists(path):
print "found %s" % path
uri = "file://" + urllib.pathname2url(path)
- storekey = RB.ExtDBKey.create('album', album)
- storekey.add_field(field, RB.ExtDBFieldType.OPTIONAL, artist)
- callback(storekey, uri, RB.ExtDBSourceType.SEARCH, *args)
+ storekey = RB.ExtDBKey.create_storage('album', album)
+ storekey.add_field("artist", artist)
+ store.store_uri(storekey, RB.ExtDBSourceType.SEARCH, uri)
+ callback(*args)
return
- callback(None, None, RB.ExtDBSourceType.NONE, *args)
+ callback(*args)
diff --git a/plugins/audioscrobbler/rb-audioscrobbler-radio-source.c b/plugins/audioscrobbler/rb-audioscrobbler-radio-source.c
index 6efd109..8f5831b 100644
--- a/plugins/audioscrobbler/rb-audioscrobbler-radio-source.c
+++ b/plugins/audioscrobbler/rb-audioscrobbler-radio-source.c
@@ -698,8 +698,8 @@ playing_song_changed_cb (RBShellPlayer *player,
}
/* provide cover art */
- key = rb_ext_db_key_create ("album", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
- rb_ext_db_key_add_field (key, "artist", RB_EXT_DB_FIELD_OPTIONAL, rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
+ key = rb_ext_db_key_create_storage ("album", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
+ rb_ext_db_key_add_field (key, "artist", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
track_data = RHYTHMDB_ENTRY_GET_TYPE_DATA(entry, RBAudioscrobblerRadioTrackData);
rb_ext_db_store_uri (source->priv->art_store,
key,
diff --git a/plugins/grilo/rb-grilo-plugin.c b/plugins/grilo/rb-grilo-plugin.c
index 75c990a..e9032a0 100644
--- a/plugins/grilo/rb-grilo-plugin.c
+++ b/plugins/grilo/rb-grilo-plugin.c
@@ -153,11 +153,8 @@ playing_song_changed_cb (RBShellPlayer *player, RhythmDBEntry *entry, RBGriloPlu
if (uri != NULL) {
RBExtDBKey *key;
- key = rb_ext_db_key_create ("album", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
- rb_ext_db_key_add_field (key,
- "artist",
- RB_EXT_DB_FIELD_OPTIONAL,
- rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
+ key = rb_ext_db_key_create_storage ("album", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
+ rb_ext_db_key_add_field (key, "artist", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
rb_ext_db_store_uri (plugin->art_store,
key,
diff --git a/plugins/ipod/rb-ipod-source.c b/plugins/ipod/rb-ipod-source.c
index 021f399..39717ce 100644
--- a/plugins/ipod/rb-ipod-source.c
+++ b/plugins/ipod/rb-ipod-source.c
@@ -1572,10 +1572,10 @@ impl_track_added (RBTransferTarget *target,
device = rb_ipod_db_get_device (priv->ipod_db);
if (device && itdb_device_supports_artwork (device)) {
RBExtDBKey *key;
- key = rb_ext_db_key_create ("album", song->album);
- rb_ext_db_key_add_field (key, "artist", RB_EXT_DB_FIELD_OPTIONAL, song->artist);
+ key = rb_ext_db_key_create_lookup ("album", song->album);
+ rb_ext_db_key_add_field (key, "artist", song->artist);
if (song->albumartist) {
- rb_ext_db_key_add_field (key, "album-artist", RB_EXT_DB_FIELD_OPTIONAL, song->albumartist);
+ rb_ext_db_key_add_field (key, "artist", song->albumartist);
}
rb_ext_db_request (priv->art_store,
diff --git a/plugins/magnatune/MagnatuneSource.py b/plugins/magnatune/MagnatuneSource.py
index 3f5f561..d269bbe 100644
--- a/plugins/magnatune/MagnatuneSource.py
+++ b/plugins/magnatune/MagnatuneSource.py
@@ -553,8 +553,8 @@ class MagnatuneSource(RB.BrowserSource):
return
sku = self.__sku_dict[entry.get_string(RB.RhythmDBPropType.LOCATION)]
- key = RB.ExtDBKey.create("album", entry.get_string(RB.RhythmDBPropType.ALBUM))
- key.add_field("artist", RB.ExtDBFieldType.OPTIONAL, entry.get_string(RB.RhythmDBPropType.ARTIST))
+ key = RB.ExtDBKey.create_storage("album", entry.get_string(RB.RhythmDBPropType.ALBUM))
+ key.add_field("artist", entry.get_string(RB.RhythmDBPropType.ARTIST))
self.__art_store.store_uri(key, self.__art_dict[sku])
GObject.type_register(MagnatuneSource)
diff --git a/plugins/mtpdevice/rb-mtp-source.c b/plugins/mtpdevice/rb-mtp-source.c
index d559633..f2af5a7 100644
--- a/plugins/mtpdevice/rb-mtp-source.c
+++ b/plugins/mtpdevice/rb-mtp-source.c
@@ -1093,11 +1093,8 @@ impl_track_added (RBTransferTarget *target,
RBExtDBKey *key;
/* need to do this in an idle handler? */
- key = rb_ext_db_key_create ("album", track->album);
- rb_ext_db_key_add_field (key,
- "artist",
- RB_EXT_DB_FIELD_OPTIONAL,
- track->artist);
+ key = rb_ext_db_key_create_lookup ("album", track->album);
+ rb_ext_db_key_add_field (key, "artist", track->artist);
rb_ext_db_request (priv->art_store,
key,
(RBExtDBRequestCallback) art_request_cb,
diff --git a/podcast/rb-podcast-manager.c b/podcast/rb-podcast-manager.c
index b4f02e7..b04e35f 100644
--- a/podcast/rb-podcast-manager.c
+++ b/podcast/rb-podcast-manager.c
@@ -1993,7 +1993,7 @@ rb_podcast_manager_insert_feed (RBPodcastManager *pd, RBPodcastChannel *data)
rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_IMAGE, &image_val);
g_value_unset (&image_val);
- key = rb_ext_db_key_create ("album", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE));
+ key = rb_ext_db_key_create_storage ("album", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE));
rb_ext_db_store_uri (pd->priv->art_store,
key,
RB_EXT_DB_SOURCE_SEARCH, /* sort of */
diff --git a/rhythmdb/rhythmdb.c b/rhythmdb/rhythmdb.c
index df2617d..86e6c64 100644
--- a/rhythmdb/rhythmdb.c
+++ b/rhythmdb/rhythmdb.c
@@ -5386,60 +5386,39 @@ rhythmdb_entry_create_ext_db_key (RhythmDBEntry *entry, RhythmDBPropType prop)
switch (prop) {
case RHYTHMDB_PROP_ALBUM:
- key = rb_ext_db_key_create ("album", rhythmdb_entry_get_string (entry, prop));
+ key = rb_ext_db_key_create_lookup ("album", rhythmdb_entry_get_string (entry, prop));
rb_ext_db_key_add_field (key,
"artist",
- RB_EXT_DB_FIELD_OPTIONAL,
rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
str = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM_ARTIST);
if (g_strcmp0 (str, "") != 0 && g_strcmp0 (str, _("Unknown")) != 0) {
- rb_ext_db_key_add_field (key,
- "album-artist",
- RB_EXT_DB_FIELD_OPTIONAL,
- str);
- } else {
- /* try artist name as album-artist too */
- rb_ext_db_key_add_field (key,
- "album-artist",
- RB_EXT_DB_FIELD_OPTIONAL,
- rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
+ rb_ext_db_key_add_field (key, "artist", str);
}
str = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MUSICBRAINZ_ALBUMID);
if (g_strcmp0 (str, "") != 0 && g_strcmp0 (str, _("Unknown")) != 0) {
- rb_ext_db_key_add_field (key,
- "musicbrainz-albumid",
- RB_EXT_DB_FIELD_INFORMATIONAL,
- str);
+ rb_ext_db_key_add_info (key, "musicbrainz-albumid", str);
}
break;
case RHYTHMDB_PROP_TITLE:
- key = rb_ext_db_key_create ("title", rhythmdb_entry_get_string (entry, prop));
- rb_ext_db_key_add_field (key,
- "artist",
- RB_EXT_DB_FIELD_OPTIONAL,
- rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
- rb_ext_db_key_add_field (key,
- "album",
- RB_EXT_DB_FIELD_OPTIONAL,
- rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
+ key = rb_ext_db_key_create_lookup ("title", rhythmdb_entry_get_string (entry, prop));
+ /* maybe these should be info? */
+ rb_ext_db_key_add_field (key, "artist", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
+ rb_ext_db_key_add_field (key, "album", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
break;
case RHYTHMDB_PROP_ARTIST:
/* not really sure what this might be useful for */
- key = rb_ext_db_key_create ("artist", rhythmdb_entry_get_string (entry, prop));
+ key = rb_ext_db_key_create_lookup ("artist", rhythmdb_entry_get_string (entry, prop));
break;
default:
g_assert_not_reached ();
}
- rb_ext_db_key_add_field (key,
- "location",
- RB_EXT_DB_FIELD_INFORMATIONAL,
- rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
+ rb_ext_db_key_add_info (key, "location", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
return key;
}
@@ -5461,38 +5440,37 @@ rhythmdb_entry_matches_ext_db_key (RhythmDB *db, RhythmDBEntry *entry, RBExtDBKe
fields = rb_ext_db_key_get_field_names (key);
for (i = 0; fields[i] != NULL; i++) {
- const char *value;
- const char *entry_value;
RhythmDBPropType prop;
+ RhythmDBPropType extra_prop;
+ const char *v;
prop = rhythmdb_propid_from_nice_elt_name (db, (const xmlChar *)fields[i]);
- value = rb_ext_db_key_get_field (key, fields[i]);
-
- switch (rb_ext_db_key_get_field_type (key, fields[i])) {
- case RB_EXT_DB_FIELD_INFORMATIONAL:
- /* ignore */
- break;
-
- case RB_EXT_DB_FIELD_OPTIONAL:
- if (prop == -1)
- break;
-
- entry_value = rhythmdb_entry_get_string (entry, prop);
- if (entry_value != NULL && strlen (entry_value) > 0 && strcmp (entry_value, value) != 0) {
+ if (prop == -1) {
+ if (rb_ext_db_key_field_matches (key, fields[i], NULL) == FALSE)
return FALSE;
- }
- break;
- case RB_EXT_DB_FIELD_REQUIRED:
- if (prop == -1)
- return FALSE;
+ continue;
+ }
- entry_value = rhythmdb_entry_get_string (entry, prop);
- if (entry_value == NULL || strcmp (entry_value, value) != 0) {
- return FALSE;
- }
+ /* check additional values for some fields */
+ switch (prop) {
+ case RHYTHMDB_PROP_ARTIST:
+ extra_prop = RHYTHMDB_PROP_ALBUM_ARTIST;
+ break;
+ default:
+ extra_prop = -1;
break;
}
+
+ if (extra_prop != -1) {
+ v = rhythmdb_entry_get_string (entry, extra_prop);
+ if (rb_ext_db_key_field_matches (key, fields[i], v))
+ continue;
+ }
+
+ v = rhythmdb_entry_get_string (entry, prop);
+ if (rb_ext_db_key_field_matches (key, fields[i], v) == FALSE)
+ return FALSE;
}
return TRUE;
diff --git a/shell/rb-shell-player.c b/shell/rb-shell-player.c
index 01854fe..2eac737 100644
--- a/shell/rb-shell-player.c
+++ b/shell/rb-shell-player.c
@@ -3727,12 +3727,12 @@ player_image_cb (RBPlayer *player,
store = rb_ext_db_new ("album-art");
- key = rb_ext_db_key_create ("album", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
+ key = rb_ext_db_key_create_storage ("album", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
artist = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM_ARTIST);
if (artist == NULL || artist[0] == '\0' || strcmp (artist, _("Unknown")) == 0) {
artist = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST);
}
- rb_ext_db_key_add_field (key, "album-artist", RB_EXT_DB_FIELD_OPTIONAL, artist);
+ rb_ext_db_key_add_field (key, "artist", artist);
g_value_init (&v, GDK_TYPE_PIXBUF);
g_value_set_object (&v, image);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]