Re: [Rhythmbox-devel] Watched Directories



On Thu, 2005-10-06 at 01:35 +1100, James Livingston wrote: 
> Attached is a small patch which lets Rhythmbox monitor directories for
> new tracks. However there are several caveats:
> 
> * There is no UI for it yet. Set the gconf
> key /apps/rhythmbox/library_locations to be a list of strings, which are
> the URIs of the director(y/ies) you want to watch. NOTE: these are uris
> with trailing slashes, not path names - e.g. "file:///media/music/" not
> "/media/music".

I've added some UI now, you can select a watched directory from the
Library pane of the preferences.

Currently you can only select one directory in the prefs, because a) I'm
not sure how many people will want to watch multiple directories, and b)
the UI for handling an arbitrary number would be _much_ more
complicated. You can still enter multiple directories with gconf-editor,
and the UI could be added if people think it would be an improvement.


The format of the gconf key has also been relaxed, so that the "file://"
prefix (for local files) and trailing slash are not required.


> * Rhythmbox will not monitor tracks in the library for changes, if they
> are not in a watched directory. This is currently half-broken anyway
> (due to bug 316910), and should be easy enough to fix.

I've fix this, so that it will monitor tracks that aren't in a watch
directory. It actually monitors slightly too much, but correcting that
would add significant complexity to the code and I'm not sure it's worth
it. In particular, if you have /foo/bar in the library (but /foo/ isn't
watched) it still monitors /foo/ - which means that it will notice (and
add) any new files or directories in /foo/.


Ryan Skadberg <skadz1 gmail com> wrote:
> I get this on installing the rpm I made
>
> WARNING: no <list_type> specified for schema of type list
> WARNING: invalid or missing list_type for schema
> (/schemas/apps/rhythmbox/library_locations)
> WARNING: failed to install schema
> `/schemas/apps/rhythmbox/library_locations' locale `C': Schema
> specifies type list but doesn't specify the type of the list elements

That was me not knowing how to write gconf schemas properly, and I
forgot to put the <list-type ...> tag in there - it should be fixed now.


Cheers,

James "Doc" Livingston
-- 
In God we Trust. All others must submit an X.509 certificate.
Index: data/rhythmbox.schemas
===================================================================
RCS file: /cvs/gnome/rhythmbox/data/rhythmbox.schemas,v
retrieving revision 1.50
diff -u -r1.50 rhythmbox.schemas
--- data/rhythmbox.schemas	24 Sep 2005 14:19:15 -0000	1.50
+++ data/rhythmbox.schemas	6 Oct 2005 10:05:13 -0000
@@ -25,6 +25,18 @@
 	<long>When Rhythmbox's database contains a song stored on a mount point that is no longer available, Rhythmbox won't remove it from its XML file immedialty, but will keep it for a number of days defined by this key. Setting it to a negative number makes Rhythmbox keep the songs forever.</long>
         </locale>
       </schema>
+      <schema>
+        <key>/schemas/apps/rhythmbox/library_locations</key>
+        <applyto>/apps/rhythmbox/library_locations</applyto>
+        <owner>rhythmbox</owner>
+        <type>list</type>
+        <list type="string">
+        <default></default>
+        <locale name="C">
+	<short>Directories that Rhythmbox should monitor</short>
+	<long>A list of directory URIs that Rhythmbox should monitor for changes and new tracks.</long>
+        </locale>
+      </schema>
 
       <schema>
         <key>/schemas/apps/rhythmbox/state/paned_position</key>
Index: data/glade/library-prefs.glade
===================================================================
RCS file: /cvs/gnome/rhythmbox/data/glade/library-prefs.glade,v
retrieving revision 1.5
diff -u -r1.5 library-prefs.glade
--- data/glade/library-prefs.glade	26 Jun 2005 21:49:57 -0000	1.5
+++ data/glade/library-prefs.glade	6 Oct 2005 10:05:14 -0000
@@ -204,6 +204,112 @@
 	      <property name="fill">False</property>
 	    </packing>
 	  </child>
+
+	  <child>
+	    <widget class="GtkVBox" id="vbox11">
+	      <property name="visible">True</property>
+	      <property name="homogeneous">False</property>
+	      <property name="spacing">6</property>
+
+	      <child>
+		<widget class="GtkLabel" id="library_location_label">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Library Location</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">False</property>
+		  <property name="fill">False</property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkHBox" id="hbox14">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <child>
+		    <widget class="GtkLabel" id="label19">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes"></property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label20">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">    </property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0.5</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkFileChooserButton" id="library_location_chooser">
+		      <property name="visible">True</property>
+		      <property name="title" translatable="yes">Select A Folder</property>
+		      <property name="action">GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER</property>
+		      <property name="local_only">True</property>
+		      <property name="show_hidden">False</property>
+		      <property name="do_overwrite_confirmation">False</property>
+		      <property name="width_chars">-1</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">True</property>
+		      <property name="fill">True</property>
+		    </packing>
+		  </child>
+		</widget>
+		<packing>
+		  <property name="padding">0</property>
+		  <property name="expand">True</property>
+		  <property name="fill">True</property>
+		</packing>
+	      </child>
+	    </widget>
+	    <packing>
+	      <property name="padding">0</property>
+	      <property name="expand">True</property>
+	      <property name="fill">True</property>
+	    </packing>
+	  </child>
 	</widget>
       </child>
     </widget>
Index: lib/rb-preferences.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-preferences.h,v
retrieving revision 1.17
diff -u -r1.17 rb-preferences.h
--- lib/rb-preferences.h	24 Sep 2005 14:19:16 -0000	1.17
+++ lib/rb-preferences.h	6 Oct 2005 10:05:14 -0000
@@ -29,6 +29,7 @@
 
 #define CONF_FIRST_TIME CONF_PREFIX   "/first_time_flag"
 #define CONF_GRACE_PERIOD CONF_PREFIX "/grace_period"
+#define CONF_LIBRARY_LOCATION	CONF_PREFIX "/library_locations"
 #define CONF_UI_DIR               CONF_PREFIX "/ui"
 #define CONF_UI_STATUSBAR_HIDDEN  CONF_PREFIX "/ui/statusbar_hidden"
 #define CONF_UI_SOURCELIST_HIDDEN CONF_PREFIX "/ui/sourcelist_hidden"
Index: rhythmdb/rhythmdb.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.c,v
retrieving revision 1.118
diff -u -r1.118 rhythmdb.c
--- rhythmdb/rhythmdb.c	28 Sep 2005 14:28:25 -0000	1.118
+++ rhythmdb/rhythmdb.c	6 Oct 2005 10:05:17 -0000
@@ -47,6 +47,7 @@
 #include "rb-util.h"
 #include "rb-cut-and-paste-code.h"
 #include "rb-preferences.h"
+#include "widgets/eel-gconf-extensions.h"
 
 #define RB_PARSE_CONJ (xmlChar *) "conjunction"
 #define RB_PARSE_SUBQUERY (xmlChar *) "subquery"
@@ -86,6 +87,8 @@
 	GAsyncQueue *restored_queue;
 
 	GHashTable *monitored_directories;
+	guint library_location_notify_id;
+	GSList *library_locations;
 
 	gboolean dry_run;
 	gboolean no_update;
@@ -200,6 +203,11 @@
 static gboolean free_entry_changes (RhythmDBEntry *entry, 
 				    GSList *changes,
 				    RhythmDB *db);
+static void library_location_changed_cb (GConfClient *client,
+					  guint cnxn_id,
+					  GConfEntry *entry,
+					  RhythmDB *db);
+static void rhythmdb_sync_library_location (RhythmDB *db);
 
 enum
 {
@@ -599,10 +607,11 @@
 	g_free (result);
 }
 
-static void rhythmdb_unmonitor_directories (char *dir,
-					    GnomeVFSMonitorHandle *handle, RhythmDB *db)
+static gboolean
+rhythmdb_unmonitor_directories (char *dir, GnomeVFSMonitorHandle *handle, RhythmDB *db)
 {
 	gnome_vfs_monitor_cancel (handle);
+	return TRUE;
 }
 
 void
@@ -615,8 +624,12 @@
 
 	db->priv->exiting = TRUE;
 
-	g_hash_table_foreach (db->priv->monitored_directories, (GHFunc) rhythmdb_unmonitor_directories,
-			      db);
+	eel_gconf_notification_remove (db->priv->library_location_notify_id);
+	g_hash_table_foreach_remove (db->priv->monitored_directories, (GHRFunc) rhythmdb_unmonitor_directories,
+				     db);
+	g_slist_foreach (db->priv->library_locations, (GFunc) g_free, NULL);
+	g_slist_free (db->priv->library_locations);
+	db->priv->library_locations = NULL;
 
 	while ((action = g_async_queue_try_pop (db->priv->action_queue)) != NULL)
 		rhythmdb_action_free (db, action);
@@ -972,12 +985,19 @@
 static void
 rhythmdb_monitor_uri_path (RhythmDB *db, const char *uri, GError **error)
 {
-	GnomeVFSURI *vfsuri;
 	char *directory;
 
-	vfsuri = gnome_vfs_uri_new (uri);
-	directory = gnome_vfs_uri_extract_dirname (vfsuri);
-	gnome_vfs_uri_unref (vfsuri);
+	if (rb_uri_is_directory (uri))
+		if (g_str_has_suffix(uri, G_DIR_SEPARATOR_S))
+			directory = g_strdup (uri);
+		else
+			directory = g_strconcat (uri, G_DIR_SEPARATOR_S, NULL);
+	else {
+		GnomeVFSURI *vfsuri = gnome_vfs_uri_new (uri);
+		directory = gnome_vfs_uri_extract_dirname (vfsuri);
+		gnome_vfs_uri_unref (vfsuri);
+	}
+
 	if (!g_hash_table_lookup (db->priv->monitored_directories, directory)) {
 		GnomeVFSResult vfsresult;
 		GnomeVFSMonitorHandle **handle = g_new0 (GnomeVFSMonitorHandle *, 1);
@@ -1257,6 +1277,8 @@
 					    
 			if (mtime == event->vfsinfo->mtime) {
 				rb_debug ("not modified: %s", event->real_uri);
+				/* monitor the file for changes */
+				rhythmdb_monitor_uri_path (db, entry->location, NULL /* FIXME */);
 			} else {
 				struct RhythmDBEvent *new_event;
 
@@ -1371,8 +1393,8 @@
 	/* Remember the mount point of the volume the song is on */
 	rhythmdb_entry_set_mount_point (db, entry, event->real_uri);
 
-	if (event->vfsinfo->flags & GNOME_VFS_FILE_FLAGS_LOCAL)
-		rhythmdb_monitor_uri_path (db, entry->location, NULL /* FIXME */);
+	/* monitor the file for changes */
+	rhythmdb_monitor_uri_path (db, entry->location, NULL /* FIXME */);
 
 	rhythmdb_commit_internal (db, FALSE);
 	
@@ -1804,6 +1826,13 @@
 
 	klass->impl_load (db, &db->priv->exiting);
 
+	/* begin monitoring the for new tracks */
+	db->priv->library_location_notify_id =
+		eel_gconf_notification_add (CONF_LIBRARY_LOCATION,
+					    (GConfClientNotifyFunc) library_location_changed_cb,
+					    db);
+	rhythmdb_sync_library_location (db);
+
 	rb_debug ("queuing db load complete signal");
 	result = g_new0 (struct RhythmDBEvent, 1);
 	result->type = RHYTHMDB_EVENT_DB_LOAD;
@@ -3077,3 +3106,86 @@
 		}
 	}
 }
+
+static void
+monitor_subdirectory (char *uri, RhythmDB *db)
+{
+	GError *error = NULL;
+
+	rhythmdb_monitor_uri_path (db, uri, &error);
+
+	if (error) {
+		/* FIXME: should we complain to the user? */
+		rb_debug ("error while attempting to monitor the library directory: %s", error->message);
+	}
+}
+
+static void
+monitor_library_directory (char *uri, RhythmDB *db)
+{
+	GError *error = NULL;
+
+	rb_debug ("beginning monitor of the library directory %s", uri);
+	rhythmdb_monitor_uri_path (db, uri, &error);
+	rb_uri_handle_recursively (uri, (GFunc) monitor_subdirectory, NULL, db);
+
+	if (error) {
+		/* FIXME: should we complain to the user? */
+		rb_debug ("error while attempting to monitor the library directory: %s", error->message);
+	}
+
+	rb_debug ("loading new tracks from library directory %s", uri);
+	rhythmdb_add_uri (db, uri);
+}
+
+static void
+monitor_entry_file (RhythmDBEntry *entry, RhythmDB *db)
+{
+	GError *error = NULL;
+
+	if (entry->type == RHYTHMDB_ENTRY_TYPE_SONG) {
+		rhythmdb_monitor_uri_path (db, entry->location, &error);
+	}
+
+	if (error) {
+		/* FIXME: should we complain to the user? */
+		rb_debug ("error while attempting to monitor library track: %s", error->message);
+	} 
+}
+
+static void
+rhythmdb_sync_library_location (RhythmDB *db)
+{
+	gboolean reload = (db->priv->library_locations != NULL);
+
+	if (reload) {
+		rb_debug ("ending monitor of old library directories");
+
+		g_hash_table_foreach_remove (db->priv->monitored_directories,
+					     (GHRFunc) rhythmdb_unmonitor_directories,
+					     db);
+		g_slist_foreach (db->priv->library_locations, (GFunc) g_free, NULL);
+		g_slist_free (db->priv->library_locations);
+	}
+
+	db->priv->library_locations = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+
+	if (db->priv->library_locations) {
+		g_slist_foreach (db->priv->library_locations, (GFunc) monitor_library_directory, db);
+	}
+
+	if (reload) {
+		/* monitor every directory that contains a (TYPE_SONG) track */
+		rhythmdb_entry_foreach (db, (GFunc) monitor_entry_file, db);
+	}
+}
+
+static void
+library_location_changed_cb (GConfClient *client,
+			     guint cnxn_id,
+			     GConfEntry *entry,
+			     RhythmDB *db)
+{
+	rhythmdb_sync_library_location (db);
+}
+
Index: sources/rb-library-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-library-source.c,v
retrieving revision 1.120
diff -u -r1.120 rb-library-source.c
--- sources/rb-library-source.c	27 Sep 2005 11:30:24 -0000	1.120
+++ sources/rb-library-source.c	6 Oct 2005 10:05:18 -0000
@@ -89,6 +89,8 @@
 			       RBLibrarySource *libsource);
 static void albums_selection_reset_cb (RBPropertyView *propview, RBLibrarySource *libsource);
 static void songs_view_sort_order_changed_cb (RBEntryView *view, RBLibrarySource *source);
+static void rb_library_source_library_location_cb (GtkFileChooser *chooser,
+						   RBLibrarySource *source);
 
 static void paned_size_allocate_cb (GtkWidget *widget,
 				    GtkAllocation *allocation,
@@ -105,6 +107,10 @@
 						     guint cnxn_id,
 						     GConfEntry *entry,
 						     RBLibrarySource *source);
+static void rb_library_source_library_location_changed (GConfClient *client,
+							guint cnxn_id,
+							GConfEntry *entry,
+							RBLibrarySource *source);
 static void rb_library_source_state_prefs_sync (RBLibrarySource *source);
 static void rb_library_source_ui_prefs_sync (RBLibrarySource *source);
 static void rb_library_source_preferences_sync (RBLibrarySource *source);
@@ -184,6 +190,9 @@
 	GtkActionGroup *action_group;
 	GtkWidget *config_widget;
 	GSList *browser_views_group;
+
+	GtkFileChooser *library_location_widget;
+	gboolean library_location_change_pending;
 	
 	RhythmDBEntryType entry_type;
 
@@ -193,6 +202,7 @@
 	guint state_browser_notify_id;
 	guint state_sorting_notify_id;
 	guint browser_view_notify_id;
+	guint library_location_notify_id;
 };
 
 static GtkActionEntry rb_library_source_actions [] =
@@ -388,6 +398,16 @@
 }
 
 static void
+rb_library_source_library_location_changed (GConfClient *client,
+					    guint cnxn_id,
+					    GConfEntry *entry,
+					    RBLibrarySource *source)
+{
+	if (source->priv->config_widget)
+		rb_library_source_preferences_sync (source);
+}
+
+static void
 rb_library_source_ui_prefs_sync (RBLibrarySource *source)
 {
 	if (source->priv->config_widget)
@@ -445,6 +465,7 @@
 	
 	eel_gconf_notification_remove (source->priv->ui_dir_notify_id);
 	eel_gconf_notification_remove (source->priv->browser_view_notify_id);
+	eel_gconf_notification_remove (source->priv->library_location_notify_id);
 	eel_gconf_notification_remove (source->priv->state_browser_notify_id);
 	eel_gconf_notification_remove (source->priv->state_paned_notify_id);
 	eel_gconf_notification_remove (source->priv->state_sorting_notify_id);
@@ -653,6 +674,9 @@
 	source->priv->browser_view_notify_id =
 		eel_gconf_notification_add (CONF_UI_LIBRARY_BROWSER_VIEWS,
 				    (GConfClientNotifyFunc) rb_library_source_browser_views_changed, source);
+	source->priv->library_location_notify_id =
+		eel_gconf_notification_add (CONF_LIBRARY_LOCATION,
+				    (GConfClientNotifyFunc) rb_library_source_library_location_changed, source);
 
 	rb_library_source_do_query (source, RB_LIBRARY_QUERY_TYPE_ALL);
 	return G_OBJECT (source);
@@ -1094,7 +1118,7 @@
 {
 	RBLibrarySource *source = RB_LIBRARY_SOURCE (asource);
 	GtkWidget *tmp;
-	GtkWidget *browser_views_label;
+	GtkWidget *browser_views_label, *library_location_label;
 	PangoAttrList *pattrlist;
 	PangoAttribute *attr;
 	GladeXML *xml;
@@ -1110,6 +1134,10 @@
 		g_slist_reverse (g_slist_copy (gtk_radio_button_get_group 
 					       (GTK_RADIO_BUTTON (tmp))));
 
+	source->priv->library_location_widget =
+		(GtkFileChooser*) glade_xml_get_widget (xml, "library_location_chooser");
+	gtk_file_chooser_set_local_only (source->priv->library_location_widget, TRUE);
+
 	pattrlist = pango_attr_list_new ();
 	attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
 	attr->start_index = 0;
@@ -1117,11 +1145,18 @@
 	pango_attr_list_insert (pattrlist, attr);
 	browser_views_label = glade_xml_get_widget (xml, "browser_views_label");
 	gtk_label_set_attributes (GTK_LABEL (browser_views_label), pattrlist);
+	library_location_label = glade_xml_get_widget (xml, "library_location_label");
+	gtk_label_set_attributes (GTK_LABEL (library_location_label), pattrlist);
 	pango_attr_list_unref (pattrlist);
 
 	g_object_unref (G_OBJECT (xml));
 	
 	rb_library_source_preferences_sync (source);
+	g_signal_connect (G_OBJECT (source->priv->library_location_widget),
+			  "selection-changed",
+			  G_CALLBACK (rb_library_source_library_location_cb),
+			  asource);
+
 	return source->priv->config_widget;
 }
 
@@ -1135,6 +1170,20 @@
 	list = g_slist_nth (source->priv->browser_views_group,
 			    eel_gconf_get_integer (CONF_UI_LIBRARY_BROWSER_VIEWS));
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (list->data), TRUE);
+
+	list = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+
+	if (g_slist_length (list) == 1) {
+		gtk_file_chooser_set_uri (source->priv->library_location_widget,
+					  list->data);
+	} else {
+		/* either no or multiple folders are chosen. make the widget blank*/
+		/*gtk_file_chooser_set_uri (source->priv->library_location_widget,
+					  "");*/
+	}
+
+	g_slist_foreach (list, (GFunc) g_free, NULL);
+	g_slist_free (list);
 }
 
 void
@@ -1639,3 +1688,32 @@
 	rb_source_receive_drag (RB_SOURCE (source), selection_data);
 }
 
+static gboolean
+rb_library_source_process_library_location_change (RBLibrarySource *source)
+{
+	GSList *list;
+	
+	if (!source->priv->library_location_change_pending)
+		return FALSE;
+
+	/* process the change */
+	list = gtk_file_chooser_get_uris (source->priv->library_location_widget);
+	eel_gconf_set_string_list (CONF_LIBRARY_LOCATION, list);
+
+	g_slist_foreach (list, (GFunc) g_free, NULL);
+	g_slist_free (list);
+
+	source->priv->library_location_change_pending = FALSE;
+	return FALSE;
+}
+
+static void
+rb_library_source_library_location_cb (GtkFileChooser *chooser,
+				       RBLibrarySource *source)
+{
+	/* this can't be processed immediately, because we sometimes get intemediate signals */
+	source->priv->library_location_change_pending = TRUE;
+
+	g_idle_add ((GSourceFunc) rb_library_source_process_library_location_change,
+		    source);
+}

Attachment: signature.asc
Description: This is a digitally signed message part



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