[rhythmbox] rhythmdb: implement plugin installation in RhythmDBImportJob
- From: Jonathan Matthew <jmatthew src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [rhythmbox] rhythmdb: implement plugin installation in RhythmDBImportJob
- Date: Fri, 18 Jun 2010 14:27:48 +0000 (UTC)
commit 665226c59f908db1f899d2012070eeaab5d69732
Author: Jonathan Matthew <jonathan d14n org>
Date: Fri Jun 18 22:15:38 2010 +1000
rhythmdb: implement plugin installation in RhythmDBImportJob
At the end of an import job, we check if any of the import error entries
created included plugin installer detail strings, and if so, we emit
a missing-plugins signal for the plugin install code. When the plugin
install finishes successfully, we retry the imports that resulted in
missing plugin errors.
This approach means that we don't process missing plugins for files imported
outside of a RhythmDBImportJob, which currently includes files picked up by
the library crawl on startup or by library monitoring. This is probably
a good thing, on the whole.
plugins/generic-player/rb-generic-player-source.c | 9 ++-
rhythmdb/rhythmdb-import-job.c | 134 ++++++++++++++++++++-
shell/rb-missing-plugins.c | 9 ++
shell/rb-missing-plugins.h | 3 +
sources/rb-library-source.c | 8 ++
5 files changed, 159 insertions(+), 4 deletions(-)
---
diff --git a/plugins/generic-player/rb-generic-player-source.c b/plugins/generic-player/rb-generic-player-source.c
index 6f8447d..323abc0 100644
--- a/plugins/generic-player/rb-generic-player-source.c
+++ b/plugins/generic-player/rb-generic-player-source.c
@@ -53,6 +53,7 @@
#include "rb-import-errors-source.h"
#include "rb-builder-helpers.h"
#include "rb-sync-settings.h"
+#include "rb-missing-plugins.h"
static void impl_constructed (GObject *object);
static void impl_dispose (GObject *object);
@@ -466,14 +467,20 @@ load_songs (RBGenericPlayerSource *source)
RhythmDBEntryType entry_type;
char **audio_folders;
char *mount_path;
+ RBShell *shell;
mount_path = rb_generic_player_source_get_mount_path (source);
- g_object_get (source, "entry-type", &entry_type, NULL);
+ g_object_get (source,
+ "entry-type", &entry_type,
+ "shell", &shell,
+ NULL);
/* if we have a set of folders on the device containing audio files,
* load only those folders, otherwise add the whole volume.
*/
priv->import_job = rhythmdb_import_job_new (priv->db, entry_type, priv->ignore_type, priv->error_type);
+ rb_missing_plugins_init_import_job (shell, priv->import_job);
+ g_object_unref (shell);
g_signal_connect_object (priv->import_job, "complete", G_CALLBACK (import_complete_cb), source, 0);
g_signal_connect_object (priv->import_job, "status-changed", G_CALLBACK (import_status_changed_cb), source, 0);
diff --git a/rhythmdb/rhythmdb-import-job.c b/rhythmdb/rhythmdb-import-job.c
index 7619461..ec9bf20 100644
--- a/rhythmdb/rhythmdb-import-job.c
+++ b/rhythmdb/rhythmdb-import-job.c
@@ -49,6 +49,7 @@ enum
STATUS_CHANGED,
SCAN_COMPLETE,
COMPLETE,
+ MISSING_PLUGINS,
LAST_SIGNAL
};
@@ -71,6 +72,9 @@ struct _RhythmDBImportJobPrivate
gboolean started;
GCancellable *cancel;
+ GSList *retry_entries;
+ gboolean retried;
+
int status_changed_id;
gboolean scan_complete;
gboolean complete;
@@ -139,6 +143,54 @@ rhythmdb_import_job_add_uri (RhythmDBImportJob *job, const char *uri)
g_static_mutex_unlock (&job->priv->lock);
}
+static void
+missing_plugins_retry_cb (gpointer instance, gboolean installed, RhythmDBImportJob *job)
+{
+ GSList *retry = NULL;
+ GSList *i;
+
+ g_static_mutex_lock (&job->priv->lock);
+ g_assert (job->priv->retried == FALSE);
+ if (installed == FALSE) {
+ rb_debug ("plugin installation was not successful; job complete");
+ g_signal_emit (job, signals[COMPLETE], 0, job->priv->total);
+ } else {
+ job->priv->retried = TRUE;
+
+ /* reset the job state to just show the retry information */
+ job->priv->total = g_slist_length (job->priv->retry_entries);
+ rb_debug ("plugin installation was successful, retrying %d entries", job->priv->total);
+ job->priv->imported = 0;
+
+ /* remove the import error entries and build the list of URIs to retry */
+ for (i = job->priv->retry_entries; i != NULL; i = i->next) {
+ RhythmDBEntry *entry = (RhythmDBEntry *)i->data;
+ char *uri;
+
+ uri = rhythmdb_entry_dup_string (entry, RHYTHMDB_PROP_LOCATION);
+ rhythmdb_entry_delete (job->priv->db, entry);
+
+ g_hash_table_insert (job->priv->outstanding, g_strdup (uri), GINT_TO_POINTER (1));
+ retry = g_slist_prepend (retry, uri);
+ }
+ rhythmdb_commit (job->priv->db);
+ retry = g_slist_reverse (retry);
+ }
+ g_static_mutex_unlock (&job->priv->lock);
+
+ for (i = retry; i != NULL; i = i->next) {
+ char *uri = (char *)i->data;
+
+ rhythmdb_add_uri_with_types (job->priv->db,
+ uri,
+ job->priv->entry_type,
+ job->priv->ignore_type,
+ job->priv->error_type);
+ }
+
+ rb_slist_deep_free (retry);
+}
+
static gboolean
emit_status_changed (RhythmDBImportJob *job)
{
@@ -153,8 +205,52 @@ emit_status_changed (RhythmDBImportJob *job)
*/
g_object_ref (job);
if (job->priv->scan_complete && job->priv->imported >= job->priv->total) {
- rb_debug ("emitting job complete");
- g_signal_emit (job, signals[COMPLETE], 0, job->priv->total);
+
+ if (job->priv->retry_entries != NULL && job->priv->retried == FALSE) {
+ gboolean processing = FALSE;
+ char **details = NULL;
+ GClosure *retry;
+ GSList *l;
+ int i;
+
+ /* gather missing plugin details etc. */
+ i = 0;
+ for (l = job->priv->retry_entries; l != NULL; l = l->next) {
+ RhythmDBEntry *entry;
+ char **bits;
+ int j;
+
+ entry = (RhythmDBEntry *)l->data;
+ bits = g_strsplit (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_COMMENT), "\n", 0);
+ for (j = 0; bits[j] != NULL; j++) {
+ if (rb_str_in_strv (bits[j], details) == FALSE) {
+ details = g_realloc (details, sizeof (char *) * (i+2));
+ details[i++] = g_strdup (bits[j]);
+ details[i] = NULL;
+ }
+ }
+ g_strfreev (bits);
+ }
+
+ retry = g_cclosure_new ((GCallback) missing_plugins_retry_cb,
+ g_object_ref (job),
+ (GClosureNotify)g_object_unref);
+ g_closure_set_marshal (retry, g_cclosure_marshal_VOID__BOOLEAN);
+
+ rb_debug ("emitting missing-plugins");
+ g_signal_emit (job, signals[MISSING_PLUGINS], 0, details, retry, &processing);
+ g_strfreev (details);
+ if (processing) {
+ rb_debug ("plugin installation is in progress");
+ } else {
+ rb_debug ("no plugin installation attempted; job complete");
+ g_signal_emit (job, signals[COMPLETE], 0, job->priv->total);
+ }
+ g_closure_sink (retry);
+ } else {
+ rb_debug ("emitting job complete");
+ g_signal_emit (job, signals[COMPLETE], 0, job->priv->total);
+ }
}
g_static_mutex_unlock (&job->priv->lock);
g_object_unref (job);
@@ -339,10 +435,20 @@ entry_added_cb (RhythmDB *db,
ours = g_hash_table_remove (job->priv->outstanding, uri);
if (ours) {
+ const char *details;
+
job->priv->imported++;
rb_debug ("got entry %s; %d now imported", uri, job->priv->imported);
g_signal_emit (job, signals[ENTRY_ADDED], 0, entry);
+ /* if it's an import error with missing plugins, add it to the retry list */
+ details = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_COMMENT);
+ if (rhythmdb_entry_get_entry_type (entry) == job->priv->error_type &&
+ (details != NULL || details[0] != '\0')) {
+ rb_debug ("entry %s is an import error with missing plugin details: %s", uri, details);
+ job->priv->retry_entries = g_slist_prepend (job->priv->retry_entries, rhythmdb_entry_ref (entry));
+ }
+
if (job->priv->status_changed_id == 0) {
job->priv->status_changed_id = g_idle_add ((GSourceFunc) emit_status_changed, job);
}
@@ -562,7 +668,29 @@ rhythmdb_import_job_class_init (RhythmDBImportJobClass *klass)
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE,
1, G_TYPE_INT);
+ /**
+ * RhythmDBImportJob::missing-plugins:
+ * @job: the #RhythmDBImportJob
+ * @details: NULL-terminated array of installer detail strings
+ * @closure: a closure to invoke once the installer has finished
+ *
+ * Emitted when the whole import job is complete (but before the
+ * 'complete' signal) but additional plugins are required to
+ * import some of the files.
+ *
+ * If a handler initiates plugin installation, it should return TRUE
+ * and invoke the closure when the installation finishes.
+ * Otherwise it should return FALSE.
+ */
+ signals[MISSING_PLUGINS] =
+ g_signal_new ("missing-plugins",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ 0, /* no internal handler */
+ NULL, NULL,
+ rb_marshal_BOOLEAN__POINTER_POINTER,
+ G_TYPE_BOOLEAN,
+ 2, G_TYPE_STRV, G_TYPE_CLOSURE);
g_type_class_add_private (klass, sizeof (RhythmDBImportJobPrivate));
}
-
diff --git a/shell/rb-missing-plugins.c b/shell/rb-missing-plugins.c
index 98c03b2..0ec0ff7 100644
--- a/shell/rb-missing-plugins.c
+++ b/shell/rb-missing-plugins.c
@@ -292,3 +292,12 @@ rb_missing_plugins_init (RBShell *shell)
GST_INFO ("Set up support for automatic missing plugin installation");
}
+
+void
+rb_missing_plugins_init_import_job (RBShell *shell, RhythmDBImportJob *job)
+{
+ g_signal_connect (job,
+ "missing-plugins",
+ G_CALLBACK (missing_plugins_cb),
+ shell);
+}
diff --git a/shell/rb-missing-plugins.h b/shell/rb-missing-plugins.h
index 8f3c0d8..20aa9e7 100644
--- a/shell/rb-missing-plugins.h
+++ b/shell/rb-missing-plugins.h
@@ -25,11 +25,14 @@
#define RB_MISSING_PLUGINS_H
#include <shell/rb-shell.h>
+#include <rhythmdb/rhythmdb-import-job.h>
G_BEGIN_DECLS
void rb_missing_plugins_init (RBShell *shell);
+void rb_missing_plugins_init_import_job (RBShell *shell, RhythmDBImportJob *job);
+
G_END_DECLS
#endif /* RB_MISSING_PLUGINS_H */
diff --git a/sources/rb-library-source.c b/sources/rb-library-source.c
index 473fec3..7c942a1 100644
--- a/sources/rb-library-source.c
+++ b/sources/rb-library-source.c
@@ -67,6 +67,7 @@
#include "rb-library-source.h"
#include "rb-auto-playlist-source.h"
#include "rb-encoder.h"
+#include "rb-missing-plugins.h"
static void rb_library_source_class_init (RBLibrarySourceClass *klass);
static void rb_library_source_init (RBLibrarySource *source);
@@ -1394,11 +1395,18 @@ maybe_create_import_job (RBLibrarySource *source)
{
RhythmDBImportJob *job;
if (source->priv->import_jobs == NULL || source->priv->start_import_job_id == 0) {
+ RBShell *shell;
+
rb_debug ("creating new import job");
job = rhythmdb_import_job_new (source->priv->db,
RHYTHMDB_ENTRY_TYPE_SONG,
RHYTHMDB_ENTRY_TYPE_IGNORE,
RHYTHMDB_ENTRY_TYPE_IMPORT_ERROR);
+
+ g_object_get (source, "shell", &shell, NULL);
+ rb_missing_plugins_init_import_job (shell, job);
+ g_object_unref (shell);
+
g_signal_connect_object (job,
"status-changed",
G_CALLBACK (import_job_status_changed_cb),
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]