diff -u -u -r1.47 Makefile.am
--- Makefile.am	11 Mar 2006 05:02:21 -0000	1.47
+++ Makefile.am	25 Mar 2006 02:16:29 -0000
@@ -6,7 +6,7 @@
 distuninstallcheck_listfiles = find . -type f -print | grep -v '^\./var/scrollkeeper'
 
 SUBDIRS = macros lib metadata player rhythmdb widgets sources iradio podcast remote \
-	daapsharing plugins bindings shell data po help tests doc
+	daapsharing backends plugins bindings shell data po help tests doc
 
 EXTRA_DIST = 			\
 	autogen.sh		\
diff -u -u -r1.220 configure.ac
--- configure.ac	21 Mar 2006 08:34:46 -0000	1.220
+++ configure.ac	25 Mar 2006 02:16:30 -0000
@@ -52,6 +52,7 @@
 		  libgnomeui-2.0			\
 		  libglade-2.0				\
 		  gnome-vfs-2.0 >= $GNOME_VFS_REQS	\
+		  gnome-media-profiles			\
 		  gnome-vfs-module-2.0)
 
 PKG_CHECK_MODULES(TOTEM_PLPARSER, totem-plparser >= $TOTEM_PLPARSER_REQS, have_totem_plparser=yes, have_totem_plparser=no)
@@ -862,6 +863,8 @@
 tests/Makefile
 doc/Makefile
 doc/reference/Makefile
+backends/Makefile
+backends/gstreamer/Makefile
 ])
 
 AC_MSG_NOTICE([Rhythmbox was configured with the following options:])
diff -u -u -r1.66 rhythmbox.schemas
--- data/rhythmbox.schemas	1 Mar 2006 03:12:43 -0000	1.66
+++ data/rhythmbox.schemas	25 Mar 2006 02:16:30 -0000
@@ -38,6 +38,39 @@
         </locale>
       </schema>
       <schema>
+        <key>/schemas/apps/rhythmbox/library_layout_path</key>
+        <applyto>/apps/rhythmbox/library_layout_path</applyto>
+        <owner>rhythmbox</owner>
+        <type>string</type>
+        <default>%aa/%at</default>
+        <locale name="C">
+          <short>Directory heirarchy of library</short>
+          <long>The path used to store track in, under the chosen library. Various substitutions are done</long>
+        </locale>
+      </schema>
+      <schema>
+        <key>/schemas/apps/rhythmbox/library_layout_filename</key>
+        <applyto>/apps/rhythmbox/library_layout_filename</applyto>
+        <owner>rhythmbox</owner>
+        <type>string</type>
+        <default>%tN - %tt</default>
+        <locale name="C">
+          <short>File name of tracks</short>
+          <long>The path used to store track in, under the chosen library. Various substitutions are done</long>
+        </locale>
+      </schema>
+      <schema>
+        <key>/schemas/apps/rhythmbox/library_preferred_format</key>
+        <applyto>/apps/rhythmbox/library_preferred_format</applyto>
+        <owner>rhythmbox</owner>
+        <type>string</type>
+        <default>cdlossy</default>
+        <locale name="C">
+          <short>id of gnome-media audio profile</short>
+          <long>The ID of the preferred gnome audio profile, used for ripping CDs</long>
+        </locale>
+      </schema>
+      <schema>
         <key>/schemas/apps/rhythmbox/monitor_library</key>
         <applyto>/apps/rhythmbox/monitor_library</applyto>
         <owner>rhythmbox</owner>
diff -u -u -r1.12 general-prefs.glade
--- data/glade/general-prefs.glade	18 Feb 2006 06:56:17 -0000	1.12
+++ data/glade/general-prefs.glade	25 Mar 2006 02:16:30 -0000
@@ -28,6 +28,195 @@
       <property name="spacing">18</property>
 
       <child>
+	<widget class="GtkVBox" id="vbox14">
+	  <property name="visible">True</property>
+	  <property name="homogeneous">False</property>
+	  <property name="spacing">6</property>
+
+	  <child>
+	    <widget class="GtkLabel" id="browser_views_label">
+	      <property name="visible">True</property>
+	      <property name="label" translatable="yes">Browser Views</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>
+	      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+	      <property name="width_chars">-1</property>
+	      <property name="single_line_mode">False</property>
+	      <property name="angle">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="hbox16">
+	      <property name="visible">True</property>
+	      <property name="homogeneous">False</property>
+	      <property name="spacing">0</property>
+
+	      <child>
+		<widget class="GtkLabel" id="label23">
+		  <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>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">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="hbox17">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">0</property>
+
+		  <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">8</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkVBox" id="vbox15">
+		      <property name="visible">True</property>
+		      <property name="homogeneous">False</property>
+		      <property name="spacing">6</property>
+
+		      <child>
+			<widget class="GtkRadioButton" id="library_browser_views_radio">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="label" translatable="yes">_Artists and albums</property>
+			  <property name="use_underline">True</property>
+			  <property name="relief">GTK_RELIEF_NORMAL</property>
+			  <property name="focus_on_click">True</property>
+			  <property name="active">True</property>
+			  <property name="inconsistent">False</property>
+			  <property name="draw_indicator">True</property>
+			  <signal name="toggled" handler="rb_shell_preferences_browser_views_activated_cb" last_modification_time="Sun, 26 Jan 2003 20:03:56 GMT"/>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkRadioButton" id="radio2">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="label" translatable="yes">_Genres and artists</property>
+			  <property name="use_underline">True</property>
+			  <property name="relief">GTK_RELIEF_NORMAL</property>
+			  <property name="focus_on_click">True</property>
+			  <property name="active">False</property>
+			  <property name="inconsistent">False</property>
+			  <property name="draw_indicator">True</property>
+			  <property name="group">library_browser_views_radio</property>
+			  <signal name="toggled" handler="rb_shell_preferences_browser_views_activated_cb" last_modification_time="Sun, 26 Jan 2003 20:03:56 GMT"/>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkRadioButton" id="radio3">
+			  <property name="visible">True</property>
+			  <property name="can_focus">True</property>
+			  <property name="label" translatable="yes">G_enres, artists and albums</property>
+			  <property name="use_underline">True</property>
+			  <property name="relief">GTK_RELIEF_NORMAL</property>
+			  <property name="focus_on_click">True</property>
+			  <property name="active">False</property>
+			  <property name="inconsistent">False</property>
+			  <property name="draw_indicator">True</property>
+			  <property name="group">library_browser_views_radio</property>
+			  <signal name="toggled" handler="rb_shell_preferences_browser_views_activated_cb" last_modification_time="Sun, 26 Jan 2003 20:03:56 GMT"/>
+			</widget>
+			<packing>
+			  <property name="padding">0</property>
+			  <property name="expand">False</property>
+			  <property name="fill">False</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>
+	    <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>
+
+      <child>
 	<widget class="GtkVBox" id="vbox2">
 	  <property name="visible">True</property>
 	  <property name="homogeneous">False</property>
diff -u -u -r1.11 library-prefs.glade
--- data/glade/library-prefs.glade	28 Feb 2006 10:31:22 -0000	1.11
+++ data/glade/library-prefs.glade	25 Mar 2006 02:16:30 -0000
@@ -40,195 +40,6 @@
 	  <property name="spacing">18</property>
 
 	  <child>
-	    <widget class="GtkVBox" id="vbox9">
-	      <property name="visible">True</property>
-	      <property name="homogeneous">False</property>
-	      <property name="spacing">6</property>
-
-	      <child>
-		<widget class="GtkLabel" id="browser_views_label">
-		  <property name="visible">True</property>
-		  <property name="label" translatable="yes">Browser Views</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>
-		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-		  <property name="width_chars">-1</property>
-		  <property name="single_line_mode">False</property>
-		  <property name="angle">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="hbox12">
-		  <property name="visible">True</property>
-		  <property name="homogeneous">False</property>
-		  <property name="spacing">0</property>
-
-		  <child>
-		    <widget class="GtkLabel" id="label16">
-		      <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>
-		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-		      <property name="width_chars">-1</property>
-		      <property name="single_line_mode">False</property>
-		      <property name="angle">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="hbox13">
-		      <property name="visible">True</property>
-		      <property name="homogeneous">False</property>
-		      <property name="spacing">0</property>
-
-		      <child>
-			<widget class="GtkLabel" id="label17">
-			  <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">8</property>
-			  <property name="ypad">0</property>
-			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
-			  <property name="width_chars">-1</property>
-			  <property name="single_line_mode">False</property>
-			  <property name="angle">0</property>
-			</widget>
-			<packing>
-			  <property name="padding">0</property>
-			  <property name="expand">False</property>
-			  <property name="fill">False</property>
-			</packing>
-		      </child>
-
-		      <child>
-			<widget class="GtkVBox" id="vbox10">
-			  <property name="visible">True</property>
-			  <property name="homogeneous">False</property>
-			  <property name="spacing">6</property>
-
-			  <child>
-			    <widget class="GtkRadioButton" id="library_browser_views_radio">
-			      <property name="visible">True</property>
-			      <property name="can_focus">True</property>
-			      <property name="label" translatable="yes">_Artists and albums</property>
-			      <property name="use_underline">True</property>
-			      <property name="relief">GTK_RELIEF_NORMAL</property>
-			      <property name="focus_on_click">True</property>
-			      <property name="active">True</property>
-			      <property name="inconsistent">False</property>
-			      <property name="draw_indicator">True</property>
-			      <signal name="toggled" handler="rb_library_source_browser_views_activated_cb" last_modification_time="Sun, 26 Jan 2003 20:03:41 GMT"/>
-			    </widget>
-			    <packing>
-			      <property name="padding">0</property>
-			      <property name="expand">False</property>
-			      <property name="fill">False</property>
-			    </packing>
-			  </child>
-
-			  <child>
-			    <widget class="GtkRadioButton" id="radiobutton2">
-			      <property name="visible">True</property>
-			      <property name="can_focus">True</property>
-			      <property name="label" translatable="yes">_Genres and artists</property>
-			      <property name="use_underline">True</property>
-			      <property name="relief">GTK_RELIEF_NORMAL</property>
-			      <property name="focus_on_click">True</property>
-			      <property name="active">False</property>
-			      <property name="inconsistent">False</property>
-			      <property name="draw_indicator">True</property>
-			      <property name="group">library_browser_views_radio</property>
-			      <signal name="toggled" handler="rb_library_source_browser_views_activated_cb" last_modification_time="Sun, 26 Jan 2003 20:03:48 GMT"/>
-			    </widget>
-			    <packing>
-			      <property name="padding">0</property>
-			      <property name="expand">False</property>
-			      <property name="fill">False</property>
-			    </packing>
-			  </child>
-
-			  <child>
-			    <widget class="GtkRadioButton" id="radiobutton3">
-			      <property name="visible">True</property>
-			      <property name="can_focus">True</property>
-			      <property name="label" translatable="yes">G_enres, artists and albums</property>
-			      <property name="use_underline">True</property>
-			      <property name="relief">GTK_RELIEF_NORMAL</property>
-			      <property name="focus_on_click">True</property>
-			      <property name="active">False</property>
-			      <property name="inconsistent">False</property>
-			      <property name="draw_indicator">True</property>
-			      <property name="group">library_browser_views_radio</property>
-			      <signal name="toggled" handler="rb_library_source_browser_views_activated_cb" last_modification_time="Sun, 26 Jan 2003 20:03:56 GMT"/>
-			    </widget>
-			    <packing>
-			      <property name="padding">0</property>
-			      <property name="expand">False</property>
-			      <property name="fill">False</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>
-		<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">False</property>
-	      <property name="fill">False</property>
-	    </packing>
-	  </child>
-
-	  <child>
 	    <widget class="GtkVBox" id="vbox11">
 	      <property name="visible">True</property>
 	      <property name="homogeneous">False</property>
@@ -466,32 +277,306 @@
 	    </widget>
 	    <packing>
 	      <property name="padding">0</property>
-	      <property name="expand">True</property>
-	      <property name="fill">True</property>
+	      <property name="expand">False</property>
+	      <property name="fill">False</property>
 	    </packing>
 	  </child>
 
 	  <child>
-	    <widget class="GtkAlignment" id="alignment2">
+	    <widget class="GtkVBox" id="vbox13">
 	      <property name="visible">True</property>
-	      <property name="xalign">0.5</property>
-	      <property name="yalign">0.5</property>
-	      <property name="xscale">1</property>
-	      <property name="yscale">1</property>
-	      <property name="top_padding">0</property>
-	      <property name="bottom_padding">0</property>
-	      <property name="left_padding">0</property>
-	      <property name="right_padding">0</property>
+	      <property name="homogeneous">False</property>
+	      <property name="spacing">6</property>
 
 	      <child>
-		<placeholder/>
+		<widget class="GtkLabel" id="library_structure_label">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Library Structure</property>
+		  <property name="use_underline">True</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>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">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="hbox17">
+		  <property name="visible">True</property>
+		  <property name="homogeneous">False</property>
+		  <property name="spacing">6</property>
+
+		  <child>
+		    <widget class="GtkLabel" id="label23">
+		      <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>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="padding">0</property>
+		      <property name="expand">False</property>
+		      <property name="fill">False</property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkTable" id="table1">
+		      <property name="visible">True</property>
+		      <property name="n_rows">5</property>
+		      <property name="n_columns">2</property>
+		      <property name="homogeneous">False</property>
+		      <property name="row_spacing">6</property>
+		      <property name="column_spacing">6</property>
+
+		      <child>
+			<widget class="GtkLabel" id="label24">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">Folder _Hierarchy:</property>
+			  <property name="use_underline">True</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>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
+			</widget>
+			<packing>
+			  <property name="left_attach">0</property>
+			  <property name="right_attach">1</property>
+			  <property name="top_attach">0</property>
+			  <property name="bottom_attach">1</property>
+			  <property name="x_options">fill</property>
+			  <property name="y_options"></property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkLabel" id="label25">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">_File Name:</property>
+			  <property name="use_underline">True</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>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
+			</widget>
+			<packing>
+			  <property name="left_attach">0</property>
+			  <property name="right_attach">1</property>
+			  <property name="top_attach">1</property>
+			  <property name="bottom_attach">2</property>
+			  <property name="x_options">fill</property>
+			  <property name="y_options"></property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkLabel" id="label27">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">Preferred Format:</property>
+			  <property name="use_underline">True</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>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
+			</widget>
+			<packing>
+			  <property name="left_attach">0</property>
+			  <property name="right_attach">1</property>
+			  <property name="top_attach">4</property>
+			  <property name="bottom_attach">5</property>
+			  <property name="x_options">fill</property>
+			  <property name="y_options"></property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkLabel" id="layout_example_label">
+			  <property name="visible">True</property>
+			  <property name="label" translatable="yes">Artist/Artist - Album/Artist (Album) - 01 - Title.ogg</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>
+			  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+			  <property name="width_chars">-1</property>
+			  <property name="single_line_mode">False</property>
+			  <property name="angle">0</property>
+			</widget>
+			<packing>
+			  <property name="left_attach">1</property>
+			  <property name="right_attach">2</property>
+			  <property name="top_attach">2</property>
+			  <property name="bottom_attach">3</property>
+			  <property name="x_options">fill</property>
+			  <property name="y_options"></property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkHBox" id="layout_path_menu_box">
+			  <property name="visible">True</property>
+			  <property name="homogeneous">False</property>
+			  <property name="spacing">0</property>
+
+			  <child>
+			    <placeholder/>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="left_attach">1</property>
+			  <property name="right_attach">2</property>
+			  <property name="top_attach">0</property>
+			  <property name="bottom_attach">1</property>
+			  <property name="x_options">fill</property>
+			  <property name="y_options">fill</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkHBox" id="layout_filename_menu_box">
+			  <property name="visible">True</property>
+			  <property name="homogeneous">False</property>
+			  <property name="spacing">0</property>
+
+			  <child>
+			    <placeholder/>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="left_attach">1</property>
+			  <property name="right_attach">2</property>
+			  <property name="top_attach">1</property>
+			  <property name="bottom_attach">2</property>
+			  <property name="x_options">fill</property>
+			  <property name="y_options">fill</property>
+			</packing>
+		      </child>
+
+		      <child>
+			<widget class="GtkHBox" id="hbox18">
+			  <property name="visible">True</property>
+			  <property name="homogeneous">False</property>
+			  <property name="spacing">6</property>
+
+			  <child>
+			    <widget class="GtkHBox" id="preferred_format_menu_box">
+			      <property name="visible">True</property>
+			      <property name="homogeneous">False</property>
+			      <property name="spacing">0</property>
+
+			      <child>
+				<placeholder/>
+			      </child>
+			    </widget>
+			    <packing>
+			      <property name="padding">0</property>
+			      <property name="expand">True</property>
+			      <property name="fill">True</property>
+			    </packing>
+			  </child>
+
+			  <child>
+			    <widget class="GtkButton" id="edit_profile_button">
+			      <property name="visible">True</property>
+			      <property name="can_focus">True</property>
+			      <property name="label">gtk-edit</property>
+			      <property name="use_stock">True</property>
+			      <property name="relief">GTK_RELIEF_NORMAL</property>
+			      <property name="focus_on_click">True</property>
+			    </widget>
+			    <packing>
+			      <property name="padding">0</property>
+			      <property name="expand">False</property>
+			      <property name="fill">False</property>
+			    </packing>
+			  </child>
+			</widget>
+			<packing>
+			  <property name="left_attach">1</property>
+			  <property name="right_attach">2</property>
+			  <property name="top_attach">4</property>
+			  <property name="bottom_attach">5</property>
+			  <property name="x_options">fill</property>
+			  <property name="y_options">fill</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>
 	    <packing>
 	      <property name="padding">0</property>
-	      <property name="expand">False</property>
-	      <property name="fill">False</property>
+	      <property name="expand">True</property>
+	      <property name="fill">True</property>
 	    </packing>
+	  </child>
+
+	  <child>
+	    <placeholder/>
 	  </child>
 	</widget>
       </child>
diff -u -u -r1.52 rhythmbox-ui.xml
--- data/ui/rhythmbox-ui.xml	19 Mar 2006 22:39:40 -0000	1.52
+++ data/ui/rhythmbox-ui.xml	25 Mar 2006 02:16:30 -0000
@@ -218,7 +218,7 @@
   </popup>
   
   <popup name="AudioCdSourcePopup">
-    <menuitem name="AudioCdSourcePopupImportCd" action="MusicImportCD"/>
+    <menuitem name="AudioCdSourcePopupCopyAllTracks" action="RemovableSourceCopyAllTracks"/>
     <menuitem name="AudioCdSourcePopupEjectCd" action="RemovableSourceEject"/>
   </popup>
 
diff -u -u -r1.13 rb-marshal.list
--- lib/rb-marshal.list	9 Dec 2005 12:18:15 -0000	1.13
+++ lib/rb-marshal.list	25 Mar 2006 02:16:30 -0000
@@ -10,4 +10,5 @@
 VOID:INT,POINTER
 VOID:POINTER,INT,POINTER,POINTER
 VOID:BOOLEAN,BOOLEAN
+VOID:INT,INT,DOUBLE
 
diff -u -u -r1.28 rb-preferences.h
--- lib/rb-preferences.h	11 Mar 2006 05:02:22 -0000	1.28
+++ lib/rb-preferences.h	25 Mar 2006 02:16:31 -0000
@@ -29,8 +29,6 @@
 
 #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_MONITOR_LIBRARY	CONF_PREFIX "/monitor_library"
 #define CONF_UI_DIR               CONF_PREFIX "/ui"
 #define CONF_UI_STATUSBAR_HIDDEN  CONF_PREFIX "/ui/statusbar_hidden"
 #define CONF_UI_TOOLBAR_HIDDEN  CONF_PREFIX "/ui/toolbar_hidden"
@@ -57,6 +55,13 @@
 #define CONF_DAAP_SHARE_NAME       CONF_PREFIX "/sharing/share_name"
 #define CONF_DAAP_SHARE_PASSWORD   CONF_PREFIX "/sharing/share_password"
 #define CONF_DAAP_REQUIRE_PASSWORD CONF_PREFIX "/sharing/require_password"
+
+#define CONF_LIBRARY_LOCATION	CONF_PREFIX "/library_locations"
+#define CONF_MONITOR_LIBRARY	CONF_PREFIX "/monitor_library"
+#define CONF_LIBRARY_STRIP_CHARS	CONF_PREFIX "/library_strip_chars"
+#define CONF_LIBRARY_LAYOUT_PATH	CONF_PREFIX "/library_layout_path"
+#define CONF_LIBRARY_LAYOUT_FILENAME	CONF_PREFIX "/library_layout_filename"
+#define CONF_LIBRARY_PREFERRED_FORMAT	CONF_PREFIX "/library_preferred_format"
 
 #define CONF_PLUGINS_PREFIX	CONF_PREFIX "/plugins"
 #define CONF_PLUGIN_ACTIVE_KEY	CONF_PLUGINS_PREFIX "/%s/active"
diff -u -u -r1.14 Makefile.am
--- player/Makefile.am	21 Mar 2006 06:56:34 -0000	1.14
+++ player/Makefile.am	25 Mar 2006 02:16:31 -0000
@@ -27,6 +27,7 @@
 	-I$(top_srcdir)/widgets				\
 	-I$(top_srcdir)/daapsharing			\
 	-I$(top_builddir)/lib                           \
+	-I$(top_builddir)/lib                           \
 	$(LIBNAUTILUS_BURN_CFLAGS)			\
 	$(RHYTHMBOX_CFLAGS)
 
diff -u -u -r1.191 rhythmdb.c
--- rhythmdb/rhythmdb.c	24 Mar 2006 09:05:00 -0000	1.191
+++ rhythmdb/rhythmdb.c	25 Mar 2006 02:16:34 -0000
@@ -1128,6 +1128,41 @@
 }
 
 /**
+ * rhythmdb_entry_example_new:
+ * @db: a #RhythmDB.
+ * @type: type of entry to create
+ * @uri: the location of the entry, this be unique amongst all entries.
+ *
+ * Creates a new sample entry of type @type and location @uri, it does not insert
+ * it into the database.  This is indended for use as a example entry.
+ *
+ * This may return NULL if entry creation fails.
+ * 
+ * Returns: the newly created #RhythmDBEntry
+ **/
+RhythmDBEntry *
+rhythmdb_entry_example_new (RhythmDB *db, RhythmDBEntryType type, const char *uri)
+{
+	RhythmDBEntry *ret;
+	
+	ret = rhythmdb_entry_allocate (db, type);
+	ret->location = g_strdup (uri);
+
+	if (type == RHYTHMDB_ENTRY_TYPE_SONG) {
+		rb_refstring_unref (ret->artist);
+		ret->artist = rb_refstring_new ("The Beatles");
+		rb_refstring_unref (ret->album);
+		ret->album = rb_refstring_new ("Help!");
+		rb_refstring_unref (ret->title);
+		ret->title = rb_refstring_new ("Ticket To Ride");
+		ret->tracknum = 7;
+	} else {
+	}
+
+	return ret;
+}
+
+/**
  * rhythmdb_entry_ref:
  * @db: a #RhythmDB.
  * @entry: a #RhythmDBEntry.
diff -u -u -r1.74 rhythmdb.h
--- rhythmdb/rhythmdb.h	21 Mar 2006 08:34:48 -0000	1.74
+++ rhythmdb/rhythmdb.h	25 Mar 2006 02:16:34 -0000
@@ -254,6 +254,7 @@
 gboolean	rhythmdb_entry_is_editable (RhythmDB *db, RhythmDBEntry *entry);
 
 RhythmDBEntry *	rhythmdb_entry_new	(RhythmDB *db, RhythmDBEntryType type, const char *uri);
+RhythmDBEntry *	rhythmdb_entry_example_new	(RhythmDB *db, RhythmDBEntryType type, const char *uri);
 
 void		rhythmdb_add_uri	(RhythmDB *db, const char *uri);
 void		rhythmdb_add_uri_with_type	(RhythmDB *db, const char *uri, RhythmDBEntryType type);
diff -u -u -r1.74 Makefile.am
--- shell/Makefile.am	21 Mar 2006 08:42:04 -0000	1.74
+++ shell/Makefile.am	25 Mar 2006 02:16:34 -0000
@@ -39,6 +39,7 @@
 	-I$(top_srcdir)/iradio                    	\
 	-I$(top_srcdir)/podcast                    	\
 	-I$(top_srcdir)/remote				\
+ 	-I$(top_srcdir)/backends			\
 	-I$(top_builddir)/remote			\
 	-I$(top_builddir)/lib				\
 	-I$(top_srcdir)/plugins				\
@@ -101,6 +102,7 @@
 	librbshell.la					\
 	$(top_builddir)/sources/libsources.la	        \
 	$(top_builddir)/sources/libsourcesimpl.la	\
+ 	$(top_builddir)/backends/librbbackends.la       \
 	$(top_builddir)/iradio/librbiradio.la	        \
 	$(top_builddir)/podcast/librbpodcast.la	        \
 	$(top_builddir)/remote/librbremote.la	        \
diff -u -u -r1.19 rb-removable-media-manager.c
--- shell/rb-removable-media-manager.c	4 Mar 2006 22:37:39 -0000	1.19
+++ shell/rb-removable-media-manager.c	25 Mar 2006 02:16:35 -0000
@@ -46,6 +46,9 @@
 #include "rb-dialog.h"
 #include "rb-stock-icons.h"
 #include "rhythmdb.h"
+#include "rb-marshal.h"
+#include "rb-encoder.h"
+#include "rb-util.h"
 
 #ifndef HAVE_BURN_DRIVE_UNREF
 #define nautilus_burn_drive_unref nautilus_burn_drive_free
@@ -54,6 +57,7 @@
 static void rb_removable_media_manager_class_init (RBRemovableMediaManagerClass *klass);
 static void rb_removable_media_manager_init (RBRemovableMediaManager *mgr);
 static void rb_removable_media_manager_dispose (GObject *object);
+static void rb_removable_media_manager_finalize (GObject *object);
 static void rb_removable_media_manager_set_property (GObject *object,
 					      guint prop_id,
 					      const GValue *value,
@@ -67,6 +71,8 @@
 						       RBRemovableMediaManager *manager);
 static void rb_removable_media_manager_cmd_eject_medium (GtkAction *action,
 					       RBRemovableMediaManager *mgr);
+static void rb_removable_media_manager_cmd_copy_tracks (GtkAction *action,
+							RBRemovableMediaManager *mgr);
 static void rb_removable_media_manager_set_uimanager (RBRemovableMediaManager *mgr, 
 					     GtkUIManager *uimanager);
 
@@ -84,6 +90,7 @@
 				GnomeVFSVolume *volume, 
 				gpointer data);
 static void rb_removable_media_manager_scan (RBRemovableMediaManager *manager);
+static void do_transfer (RBRemovableMediaManager *manager);
 
 typedef struct
 {
@@ -110,6 +117,12 @@
 	GList *cur_volume_list;
 
 	char *playing_uri;
+
+	GAsyncQueue *transfer_queue;
+	gboolean transfer_running;
+	gint transfer_total;
+	gint transfer_done;
+	double transfer_fraction;
 } RBRemovableMediaManagerPrivate;
 
 G_DEFINE_TYPE (RBRemovableMediaManager, rb_removable_media_manager, G_TYPE_OBJECT)
@@ -126,6 +139,7 @@
 enum
 {
 	MEDIUM_ADDED,
+	TRANSFER_PROGRESS,
 	LAST_SIGNAL
 };
 
@@ -136,6 +150,9 @@
 	{ "RemovableSourceEject", GNOME_MEDIA_EJECT, N_("_Eject"), NULL,
 	  N_("Eject this medium"),
 	  G_CALLBACK (rb_removable_media_manager_cmd_eject_medium) },
+	{ "RemovableSourceCopyAllTracks", GTK_STOCK_CDROM, N_("_Copy to library"), NULL,
+	  N_("Copy all tracks to the library"),
+	  G_CALLBACK (rb_removable_media_manager_cmd_copy_tracks) },
 	{ "MusicScanMedia", NULL, N_("_Scan Removable Media"), NULL,
 	  N_("Scan for new Removable Media"),
 	  G_CALLBACK (rb_removable_media_manager_cmd_scan_media) },
@@ -149,7 +166,7 @@
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
 	object_class->dispose = rb_removable_media_manager_dispose;
-
+	object_class->finalize = rb_removable_media_manager_finalize;
 	object_class->set_property = rb_removable_media_manager_set_property;
 	object_class->get_property = rb_removable_media_manager_get_property;
 
@@ -186,6 +203,17 @@
 			      G_TYPE_NONE,
 			      1, G_TYPE_OBJECT);
 
+	rb_removable_media_manager_signals[TRANSFER_PROGRESS] =
+		g_signal_new ("transfer-progress",
+			      RB_TYPE_REMOVABLE_MEDIA_MANAGER,
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBRemovableMediaManagerClass, transfer_progress),
+			      NULL, NULL,
+			      rb_marshal_VOID__INT_INT_DOUBLE,
+			      G_TYPE_NONE,
+			      3, G_TYPE_INT, G_TYPE_INT, G_TYPE_DOUBLE);
+
+
 	g_type_class_add_private (klass, sizeof (RBRemovableMediaManagerPrivate));
 }
 
@@ -195,6 +223,7 @@
 	RBRemovableMediaManagerPrivate *priv = REMOVABLE_MEDIA_MANAGER_GET_PRIVATE (mgr);
 
 	priv->volume_mapping = g_hash_table_new (NULL, NULL);
+	priv->transfer_queue = g_async_queue_new ();
 }
 
 static void
@@ -219,14 +248,6 @@
 		g_list_free (priv->sources);
 		priv->sources = NULL;
 	}
-	if (priv->volume_mapping) {
-		g_hash_table_destroy (priv->volume_mapping);
-		priv->volume_mapping = NULL;
-	}
-	if (priv->cd_drive_mapping) {
-		g_hash_table_destroy (priv->cd_drive_mapping);
-		priv->cd_drive_mapping = NULL;
-	}
 
 	priv->disposed = TRUE;
 
@@ -234,6 +255,18 @@
 }
 
 static void
+rb_removable_media_manager_finalize (GObject *object)
+{
+	RBRemovableMediaManagerPrivate *priv = REMOVABLE_MEDIA_MANAGER_GET_PRIVATE (object);
+
+	g_hash_table_destroy (priv->volume_mapping);
+	g_hash_table_destroy (priv->cd_drive_mapping);
+	g_async_queue_unref (priv->transfer_queue);
+	
+	G_OBJECT_CLASS (rb_removable_media_manager_parent_class)->finalize (object);
+}
+
+static void
 rb_removable_media_manager_set_property (GObject *object,
 				  guint prop_id,
 				  const GValue *value,
@@ -779,4 +812,166 @@
 		}
 	}
 	g_list_free (list);
+}
+
+
+
+/* Track transfer */
+
+typedef struct {
+	RBRemovableMediaManager *manager;
+	RhythmDBEntry *entry;
+	char *dest;
+	char *mime_type;
+	gboolean failed;
+	RBTranferCompleteCallback callback;
+	gpointer userdata;
+} TransferData;
+
+static void
+emit_progress (RBRemovableMediaManager *mgr)
+{
+	RBRemovableMediaManagerPrivate *priv = REMOVABLE_MEDIA_MANAGER_GET_PRIVATE (mgr);
+
+	g_signal_emit (G_OBJECT (mgr), rb_removable_media_manager_signals[TRANSFER_PROGRESS], 0,
+		       priv->transfer_done,
+		       priv->transfer_total,
+		       priv->transfer_fraction);
+}
+
+static void
+error_cb (RBEncoder *encoder, GError *error, TransferData *data)
+{
+	rb_debug ("Error transferring track to %s: %s", data->dest, error->message);
+	rb_error_dialog (NULL, _("Error transferring track"), "%s", error->message);
+
+	data->failed = TRUE;
+	rb_encoder_cancel (encoder);
+}
+
+static void
+progress_cb (RBEncoder *encoder, double fraction, TransferData *data)
+{
+	RBRemovableMediaManagerPrivate *priv = REMOVABLE_MEDIA_MANAGER_GET_PRIVATE (data->manager);
+
+	rb_debug ("transfer progress %f", (float)fraction);
+	priv->transfer_fraction = fraction;
+	emit_progress (data->manager);
+}
+
+static void
+completed_cb (RBEncoder *encoder, TransferData *data)
+{
+	RBRemovableMediaManagerPrivate *priv = REMOVABLE_MEDIA_MANAGER_GET_PRIVATE (data->manager);
+
+	rb_debug ("completed transferring track to %s", data->dest);
+	if (!data->failed)
+		(data->callback) (data->entry, data->dest, data->userdata);
+
+	priv->transfer_running = FALSE;
+	priv->transfer_done++;
+	priv->transfer_fraction = 0.0;
+	do_transfer (data->manager);
+
+	g_object_unref (G_OBJECT (encoder));
+	g_free (data->dest);
+	g_free (data->mime_type);
+	g_free (data);
+}
+
+static void
+do_transfer (RBRemovableMediaManager *manager)
+{
+	RBRemovableMediaManagerPrivate *priv = REMOVABLE_MEDIA_MANAGER_GET_PRIVATE (manager);
+	TransferData *data;
+	RBEncoder *encoder;
+
+	g_assert (rb_is_main_thread ());
+	
+	emit_progress (manager);
+
+	if (priv->transfer_running)
+		return;
+
+	data = g_async_queue_try_pop (priv->transfer_queue);
+	if (data == NULL) {
+		priv->transfer_total = 0;
+		priv->transfer_done = 0;
+		emit_progress (manager);
+		return;
+	}
+
+	priv->transfer_running = TRUE;
+	priv->transfer_fraction = 0.0;
+
+	encoder = rb_encoder_new ();
+	g_signal_connect (G_OBJECT (encoder),
+			  "error", G_CALLBACK (error_cb),
+			  data);
+	g_signal_connect (G_OBJECT (encoder),
+			  "progress", G_CALLBACK (progress_cb),
+			  data);
+	g_signal_connect (G_OBJECT (encoder),
+			  "completed", G_CALLBACK (completed_cb),
+			  data);
+	rb_encoder_encode (encoder, data->entry, data->dest, NULL);
+}
+
+void
+rb_removable_media_manager_queue_transfer (RBRemovableMediaManager *manager,
+					  RhythmDBEntry *entry,
+					  const char *dest,
+					  const char *mime_type,
+					  RBTranferCompleteCallback callback,
+					  gpointer userdata)
+{
+	RBRemovableMediaManagerPrivate *priv = REMOVABLE_MEDIA_MANAGER_GET_PRIVATE (manager);
+	TransferData *data;
+
+	g_assert (rb_is_main_thread ());
+
+	data = g_new0 (TransferData, 1);
+	data->manager = manager;
+	data->entry = entry;
+	data->dest = g_strdup (dest);
+	data->mime_type = g_strdup (mime_type);
+	data->callback = callback;
+	data->userdata = userdata;
+
+	g_async_queue_push (priv->transfer_queue, data);
+	priv->transfer_total++;
+	do_transfer (manager);
+}
+
+static gboolean
+copy_entry (RhythmDBQueryModel *model,
+	    GtkTreePath *path,
+	    GtkTreeIter *iter,
+	    GList **list)
+{
+	GList *l;
+	l = g_list_append (*list, rhythmdb_query_model_iter_to_entry (model, iter));
+	*list = l;
+	return FALSE;
+}
+
+static void
+rb_removable_media_manager_cmd_copy_tracks (GtkAction *action, RBRemovableMediaManager *mgr)
+{
+	RBRemovableMediaManagerPrivate *priv = REMOVABLE_MEDIA_MANAGER_GET_PRIVATE (mgr);
+	RBRemovableMediaSource *source;
+	RBLibrarySource *library;
+	RhythmDBQueryModel *model;
+	GList *list = NULL;
+
+	source = RB_REMOVABLE_MEDIA_SOURCE (priv->selected_source);
+	g_object_get (G_OBJECT (source), "query-model", &model, NULL);
+	g_object_get (G_OBJECT (priv->shell), "library-source", &library, NULL);
+
+	gtk_tree_model_foreach (GTK_TREE_MODEL (model), (GtkTreeModelForeachFunc)copy_entry, &list);
+	rb_source_paste (RB_SOURCE (library), list);
+	g_list_free (list);
+
+	g_object_unref (G_OBJECT (model));
+	g_object_unref (G_OBJECT (library));
 }
diff -u -u -r1.1 rb-removable-media-manager.h
--- shell/rb-removable-media-manager.h	11 Sep 2005 04:27:15 -0000	1.1
+++ shell/rb-removable-media-manager.h	25 Mar 2006 02:16:35 -0000
@@ -36,6 +36,12 @@
 #define RB_IS_REMOVABLE_MEDIA_MANAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), RB_TYPE_REMOVABLE_MEDIA_MANAGER))
 #define RB_REMOVABLE_MEDIA_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), RB_TYPE_REMOVABLE_MEDIA_MANAGER, RBRemovableMediaManagerClass))
 
+
+typedef void (*RBTranferCompleteCallback) (RhythmDBEntry *entry,
+					   const char *dest,
+					   gpointer userdata);
+				      
+
 typedef struct
 {
 	GObject parent;
@@ -46,7 +52,12 @@
 	GObjectClass parent_class;
 
 	/* signals */
-	void	(*medium_added) (RBSource *source);
+	void	(*medium_added)		(RBRemovableMediaManager *mgr,
+					 RBSource *source);
+	void	(*transfer_progress)	(RBRemovableMediaManager *mgr,
+					 gint done,
+					 gint total,
+					 double fraction);
 } RBRemovableMediaManagerClass;
 
 
@@ -54,6 +65,13 @@
 GType			rb_removable_media_manager_get_type	(void);
 
 gboolean		rb_removable_media_manager_load_media	(RBRemovableMediaManager *mgr);
+
+void	rb_removable_media_manager_queue_transfer (RBRemovableMediaManager *mgr,
+						   RhythmDBEntry *entry,
+						   const char *dest,
+						   const char *mime_type,
+						   RBTranferCompleteCallback callback,
+						   gpointer userdata);
 
 G_END_DECLS
 
diff -u -u -r1.40 rb-shell-clipboard.c
--- shell/rb-shell-clipboard.c	12 Mar 2006 02:04:45 -0000	1.40
+++ shell/rb-shell-clipboard.c	25 Mar 2006 02:16:35 -0000
@@ -425,7 +425,7 @@
 	rb_debug ("syncing clipboard");
 	
 	if (g_list_length (clipboard->priv->entries) > 0)
-		can_paste = rb_source_can_cut (clipboard->priv->source);
+		can_paste = rb_source_can_paste (clipboard->priv->source);
 
 	if (have_selection) {
 		can_cut = rb_source_can_cut (clipboard->priv->source);
diff -u -u -r1.228 rb-shell-player.c
--- shell/rb-shell-player.c	24 Mar 2006 09:09:13 -0000	1.228
+++ shell/rb-shell-player.c	25 Mar 2006 02:16:36 -0000
@@ -917,7 +917,7 @@
 	GError *error = NULL;
 
 	GDK_THREADS_ENTER ();
-	rb_statusbar_set_progress (data->player->priv->statusbar_widget, 0.01, _("Connecting"));
+	rb_statusbar_set_progress (data->player->priv->statusbar_widget, 0.0, _("Connecting"));
 	GDK_THREADS_LEAVE ();
 
 	playlist = totem_pl_parser_new ();
diff -u -u -r1.57 rb-shell-preferences.c
--- shell/rb-shell-preferences.c	18 Feb 2006 06:56:17 -0000	1.57
+++ shell/rb-shell-preferences.c	25 Mar 2006 02:16:37 -0000
@@ -56,6 +56,8 @@
 
 void rb_shell_preferences_column_check_changed_cb (GtkCheckButton *butt,
 						   RBShellPreferences *shell_preferences);
+void rb_shell_preferences_browser_views_activated_cb (GtkWidget *widget,
+						      RBShellPreferences *shell_preferences);
 
 
 enum
@@ -82,6 +84,8 @@
 	GtkWidget *quality_check;
 	GtkWidget *year_check;
 
+	GSList *browser_views_group;
+
 	gboolean loading;
 };
 
@@ -119,7 +123,7 @@
 static void
 rb_shell_preferences_init (RBShellPreferences *shell_preferences)
 {
-	GtkWidget *help;
+	GtkWidget *tmp;
 	GladeXML *xml;
 
 	shell_preferences->priv = RB_SHELL_PREFERENCES_GET_PRIVATE (shell_preferences);
@@ -136,10 +140,10 @@
 	gtk_dialog_add_button (GTK_DIALOG (shell_preferences),
 			       GTK_STOCK_CLOSE,
 			       GTK_RESPONSE_CLOSE);
-	help = gtk_dialog_add_button (GTK_DIALOG (shell_preferences),
+	tmp = gtk_dialog_add_button (GTK_DIALOG (shell_preferences),
 			              GTK_STOCK_HELP,
 			              GTK_RESPONSE_HELP);
-	g_signal_connect_object (G_OBJECT (help), "clicked",
+	g_signal_connect_object (G_OBJECT (tmp), "clicked",
 				 G_CALLBACK (help_cb), shell_preferences, 0);
 	gtk_dialog_set_default_response (GTK_DIALOG (shell_preferences),
 					 GTK_RESPONSE_CLOSE);
@@ -187,6 +191,14 @@
 	shell_preferences->priv->first_seen_check =
 		glade_xml_get_widget (xml, "first_seen_check");
 
+	/* browser options */
+	rb_glade_boldify_label (xml, "browser_views_label");
+
+	tmp = glade_xml_get_widget (xml, "library_browser_views_radio");
+	shell_preferences->priv->browser_views_group =
+		g_slist_reverse (g_slist_copy (gtk_radio_button_get_group 
+					       (GTK_RADIO_BUTTON (tmp))));
+
 	gtk_notebook_append_page (GTK_NOTEBOOK (shell_preferences->priv->notebook),
 				  glade_xml_get_widget (xml, "general_vbox"),
 				  gtk_label_new (_("General")));
@@ -533,6 +545,8 @@
 rb_shell_preferences_sync (RBShellPreferences *shell_preferences)
 {
 	char *columns;
+	GSList  *l;
+	gint view, i;
 
 	shell_preferences->priv->loading = TRUE;
 
@@ -578,5 +592,25 @@
 
 	g_free (columns);
 
+	view = eel_gconf_get_integer (CONF_UI_BROWSER_VIEWS);
+	for (l = shell_preferences->priv->browser_views_group, i = 0; l != NULL; l = g_slist_next (l), i++)
+		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (l->data), (i == view));
+
 	shell_preferences->priv->loading = FALSE;
 }
+
+void
+rb_shell_preferences_browser_views_activated_cb (GtkWidget *widget,
+						 RBShellPreferences *shell_preferences)
+{
+	int index;
+
+	if (shell_preferences->priv->loading)
+		return;
+
+	index = g_slist_index (shell_preferences->priv->browser_views_group, widget);
+
+	eel_gconf_set_integer (CONF_UI_BROWSER_VIEWS, index);
+}
+
+
diff -u -u -r1.415 rb-shell.c
--- shell/rb-shell.c	22 Mar 2006 11:40:44 -0000	1.415
+++ shell/rb-shell.c	25 Mar 2006 02:16:39 -0000
@@ -148,6 +148,11 @@
 static void rb_shell_playlist_added_cb (RBPlaylistManager *mgr, RBSource *source, RBShell *shell);
 static void rb_shell_playlist_created_cb (RBPlaylistManager *mgr, RBSource *source, RBShell *shell);
 static void rb_shell_medium_added_cb (RBRemovableMediaManager *mgr, RBSource *source, RBShell *shell);
+static void rb_shell_transfer_progress_cb (RBRemovableMediaManager *mgr,
+					   gint done,
+					   gint total,
+					   double fraction,
+					   RBShell *shell);
 static void rb_shell_source_deleted_cb (RBSource *source, RBShell *shell);
 static void rb_shell_set_window_title (RBShell *shell, const char *window_title);
 static void rb_shell_set_elapsed (RBShell *shell, guint elapsed);
@@ -312,7 +317,8 @@
 	PROP_WINDOW,
 	PROP_PREFS,
 	PROP_QUEUE_SOURCE,
-	PROP_PROXY_CONFIG
+	PROP_PROXY_CONFIG,
+	PROP_LIBRARY_SOURCE
 };
 
 /* prefs */
@@ -612,7 +618,7 @@
 					 g_param_spec_object ("removable-media-manager",
 						 	      "RBRemovableMediaManager",
 							      "RBRemovableMediaManager object",
-							      RB_TYPE_SHELL_PLAYER,
+							      RB_TYPE_REMOVABLE_MEDIA_MANAGER,
 							      G_PARAM_READABLE));
 	g_object_class_install_property (object_class,
 					 PROP_WINDOW,
@@ -642,6 +648,13 @@
 							      "HTTP proxy configuration",
 							      RB_TYPE_PROXY_CONFIG,
 							      G_PARAM_READABLE));
+	g_object_class_install_property (object_class,
+					 PROP_LIBRARY_SOURCE,
+					 g_param_spec_object ("library-source", 
+							      "library-source", 
+							      "Library source", 
+							      RB_TYPE_LIBRARY_SOURCE,
+							      G_PARAM_READABLE));
 
 
 	g_type_class_add_private (klass, sizeof (RBShellPrivate));
@@ -807,6 +820,9 @@
 	case PROP_PROXY_CONFIG:
 		g_value_set_object (value, shell->priv->proxy_config);
 		break;
+ 	case PROP_LIBRARY_SOURCE:
+ 		g_value_set_object (value, shell->priv->library_source);
+ 		break;
 	default:
 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 		break;
@@ -1236,6 +1252,8 @@
 
 	g_signal_connect_object (G_OBJECT (shell->priv->removable_media_manager), "medium_added",
 				 G_CALLBACK (rb_shell_medium_added_cb), shell, 0);
+	g_signal_connect_object (G_OBJECT (shell->priv->removable_media_manager), "transfer-progress",
+				 G_CALLBACK (rb_shell_transfer_progress_cb), shell, 0);
 
 	rb_debug ("shell: loading ui");
 	gtk_ui_manager_insert_action_group (shell->priv->ui_manager,
@@ -1702,6 +1720,33 @@
 }
 
 static void
+rb_shell_transfer_progress_cb (RBRemovableMediaManager *mgr,
+			       gint done,
+			       gint total,
+			       double fraction,
+			       RBShell *shell)
+{
+	rb_debug ("transferred %d tracks out of %d", done, total);
+
+	if (total > 0) {
+		char *s;
+
+		if (fraction >= 0)
+			s = g_strdup_printf (_("Transferring track %d out of %d (%.0f%%)"),
+						   done + 1, total, fraction * 100);
+		else
+			s = g_strdup_printf (_("Transferring track %d out of %d"),
+						   done + 1, total);
+			
+		rb_statusbar_set_progress (shell->priv->statusbar,
+					   (((double)(done) + fraction)/total),
+					   s);
+	} else {
+		rb_statusbar_set_progress (shell->priv->statusbar, -1, NULL);
+	}
+}
+
+static void
 rb_shell_source_deleted_cb (RBSource *source,
 			    RBShell *shell)
 {
@@ -2313,6 +2358,8 @@
 	rb_shell_shutdown (shell);
 	rb_shell_sync_state (shell);
 	g_object_unref (G_OBJECT (shell));
+
+	g_timeout_add (10000, (GSourceFunc)gtk_main_quit, NULL);
 }
 
 static gboolean
diff -u -u -r1.44 rb-statusbar.c
--- shell/rb-statusbar.c	3 Jan 2006 09:44:41 -0000	1.44
+++ shell/rb-statusbar.c	25 Mar 2006 02:16:39 -0000
@@ -489,7 +489,7 @@
                 statusbar->priv->progress_text = NULL;
         }
         
-        if (progress > 0.0) {
+        if (progress >= 0.0) {
                 statusbar->priv->progress_fraction = progress;
                 statusbar->priv->progress_changed = TRUE;
                 statusbar->priv->progress_text = g_strdup (text);
diff -u -u -r1.25 rb-audiocd-source.c
--- sources/rb-audiocd-source.c	11 Mar 2006 00:58:54 -0000	1.25
+++ sources/rb-audiocd-source.c	25 Mar 2006 02:16:40 -0000
@@ -92,6 +92,9 @@
 	/* don't bother showing the browser/search bits */
 	source_class->impl_can_search = (RBSourceFeatureFunc) rb_false_function;
 	source_class->impl_can_browse = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_paste = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_copy = (RBSourceFeatureFunc) rb_true_function;
 
 	source_class->impl_show_popup = impl_show_popup;
 	source_class->impl_delete_thyself = impl_delete_thyself;
@@ -269,6 +272,7 @@
 	entry_set_string_prop (db, entry, FALSE, RHYTHMDB_PROP_ARTIST, NULL);
 	entry_set_string_prop (db, entry, FALSE, RHYTHMDB_PROP_ALBUM, NULL);
 	entry_set_string_prop (db, entry, FALSE, RHYTHMDB_PROP_GENRE, NULL);
+	entry_set_string_prop (db, entry, FALSE, RHYTHMDB_PROP_MIMETYPE, "audio/x-raw-int");
 
 	rhythmdb_commit (db);
 	g_free (audio_path);
@@ -584,7 +588,7 @@
 {
 	GList *actions = NULL;
 
-	actions = g_list_prepend (actions, "MusicImportCD");
+	actions = g_list_prepend (actions, "RemovableSourceCopyAllTracks");
 	actions = g_list_prepend (actions, "RemovableSourceEject");
 
 	return actions;
diff -u -u -r1.156 rb-library-source.c
--- sources/rb-library-source.c	22 Mar 2006 11:35:45 -0000	1.156
+++ sources/rb-library-source.c	25 Mar 2006 02:16:41 -0000
@@ -28,10 +28,12 @@
 #include <glib/gi18n.h>
 #include <libgnomevfs/gnome-vfs.h>
 #include <glade/glade.h>
+#include <profiles/gnome-media-profiles.h>
+#include <profiles/audio-profile-choose.h>
 
 #include "rb-source.h"
 #include "rb-library-source.h"
-
+#include "rhythmdb.h"
 #include "rhythmdb-query-model.h"
 #include "rb-property-view.h"
 #include "rb-glade-helpers.h"
@@ -47,6 +49,7 @@
 #include "rb-search-entry.h"
 #include "rb-preferences.h"
 #include "rb-shell-preferences.h"
+#include "rb-removable-media-manager.h"
 
 static void rb_library_source_class_init (RBLibrarySourceClass *klass);
 static void rb_library_source_init (RBLibrarySource *source);
@@ -88,15 +91,18 @@
 					       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_library_pref_changed (GConfClient *client,
+						    guint cnxn_id,
+						    GConfEntry *entry,
+						    RBLibrarySource *source);
+static void rb_library_source_edit_profile_clicked_cb (GtkButton *button,
+						       RBLibrarySource *source);
 static void rb_library_source_location_button_clicked_cb (GtkButton *button,
 							  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);
+
 /* source methods */
 static const char *impl_get_browser_key (RBSource *source);
 static RBEntryView *impl_get_entry_view (RBSource *source);
@@ -111,9 +117,9 @@
 static gboolean impl_show_popup (RBSource *source);
 static const char * impl_get_paned_key (RBLibrarySource *source);
 static GList *impl_get_search_actions (RBSource *source);
+static gboolean impl_can_paste (RBSource *asource);
+static void impl_paste (RBSource *source, GList *entries);
 
-void rb_library_source_browser_views_activated_cb (GtkWidget *widget,
-						 RBLibrarySource *source);
 static void songs_view_drag_data_received_cb (GtkWidget *widget,
 					      GdkDragContext *dc,
 					      gint x, gint y,
@@ -124,6 +130,13 @@
 						RBLibrarySource *source);
 static void rb_library_source_do_query (RBLibrarySource *source,
 					gboolean subset);
+						
+static void rb_library_source_path_changed_cb (GtkComboBox *box,
+						RBLibrarySource *source);
+static void rb_library_source_filename_changed_cb (GtkComboBox *box,
+						   RBLibrarySource *source);
+static void rb_library_source_format_changed_cb (GtkWidget *widget,
+						 RBLibrarySource *source);
 
 #define CONF_UI_LIBRARY_DIR CONF_PREFIX "/ui/library"
 #define CONF_STATE_LIBRARY_DIR CONF_PREFIX "/state/library"
@@ -131,13 +144,37 @@
 #define CONF_STATE_PANED_POSITION CONF_PREFIX "/state/library/paned_position"
 #define CONF_STATE_SHOW_BROWSER   CONF_PREFIX "/state/library/show_browser"
 
+
+typedef struct {
+	char *title;
+	char *path;
+} LibraryPathElement;
+
+const LibraryPathElement library_layout_paths[] = {
+	{N_("Artist/Artist - Album"), "%aa/%aa - %at"},
+	{N_("Artist/Album"), "%aa/%at"},
+	{N_("Artist - Album"), "%aa - %at"},
+	{N_("Album"), "%at"},
+	{N_("Artist"), "%aa"},
+};
+const int num_library_layout_paths = G_N_ELEMENTS (library_layout_paths);
+
+const LibraryPathElement library_layout_filenames[] = {
+	{N_("Number - Title"), "%tN - %tt"},
+	{N_("Artist - Title"), "%ta - %tt"},
+	{N_("Artist - Number - Title"), "%ta - %tN - %tt"},
+	{N_("Artist (Album) - Number - Title"), "%ta (%at) - %tN - %tt"},
+	{N_("Title"), "%tt"},
+	{N_("Number. Artist - Title"), "%tN. %ta - %tt"},
+};
+const int num_library_layout_filenames = G_N_ELEMENTS (library_layout_filenames);
+
 struct RBLibrarySourcePrivate
 {
 	RhythmDB *db;
 	
 	RBLibraryBrowser *browser;
 	GtkWidget *vbox;
-	GSList *browser_views_group;
 
 	GdkPixbuf *pixbuf;
 
@@ -163,6 +200,10 @@
 
 	GtkWidget *library_location_entry;
 	GtkWidget *watch_library_check;
+	GtkWidget *layout_path_menu;
+	GtkWidget *layout_filename_menu;
+	GtkWidget *preferred_format_menu;
+	GtkWidget *layout_example_label;
 	
 	RhythmDBEntryType entry_type;
 
@@ -171,7 +212,9 @@
 	guint state_paned_notify_id;
 	guint state_browser_notify_id;
 	guint state_sorting_notify_id;
-	guint library_location_notify_id;
+	guint library_pref_notify_id;
+	guint layout_path_notify_id;
+	guint layout_filename_notify_id;
 };
 
 #define RB_LIBRARY_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_LIBRARY_SOURCE, RBLibrarySourcePrivate))
@@ -214,6 +257,7 @@
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
+	GConfClient *gconf_client;
 
 	object_class->dispose = rb_library_source_dispose;
 	object_class->finalize = rb_library_source_finalize;
@@ -233,6 +277,7 @@
 	source_class->impl_song_properties = impl_song_properties;
 	source_class->impl_can_pause = (RBSourceFeatureFunc) rb_true_function;
 	source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_paste = (RBSourceFeatureFunc) impl_can_paste;
 	source_class->impl_can_copy = (RBSourceFeatureFunc) rb_true_function;
 	source_class->impl_can_delete = (RBSourceFeatureFunc) rb_true_function;
 	source_class->impl_can_add_to_queue = (RBSourceFeatureFunc) rb_true_function;
@@ -243,6 +288,7 @@
 	source_class->impl_receive_drag = impl_receive_drag;
 	source_class->impl_show_popup = impl_show_popup;
 	source_class->impl_get_search_actions = impl_get_search_actions;
+	source_class->impl_paste = impl_paste;
 
 	klass->impl_get_paned_key = impl_get_paned_key;
 	klass->impl_has_first_added_column = (RBLibrarySourceFeatureFunc) rb_true_function;
@@ -267,13 +313,17 @@
 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
 
 	g_type_class_add_private (klass, sizeof (RBLibrarySourcePrivate));
+
+	gconf_client = gconf_client_get_default ();
+	gnome_media_profiles_init (gconf_client);
+	g_object_unref (gconf_client);
 }
 
 static void
-rb_library_source_library_location_changed (GConfClient *client,
-					    guint cnxn_id,
-					    GConfEntry *entry,
-					    RBLibrarySource *source)
+rb_library_source_library_pref_changed (GConfClient *client,
+					guint cnxn_id,
+					GConfEntry *entry,
+					RBLibrarySource *source)
 {
 	if (source->priv->config_widget)
 		rb_library_source_preferences_sync (source);
@@ -296,6 +346,284 @@
 	rb_library_source_ui_prefs_sync (source);
 }
 
+/**
+ * Perform magic on a path to make it safe.
+ *
+ * This will always replace '/' with ' ', and optionally make the file name
+ * shell-friendly. This involves removing [?*\ ] and replacing with '_'.  Also
+ * any leading periods are removed so that the files don't end up being hidden.
+ */
+static char *
+sanitize_path (const char *str)
+{
+  gchar *res = NULL;
+  gchar *s;
+
+  /* Skip leading periods, otherwise files disappear... */
+  while (*str == '.')
+    str++;
+  
+  s = g_strdup(str);
+  /* Replace path seperators with a hyphen */
+  g_strdelimit (s, "/", '-');
+  if (eel_gconf_get_boolean (CONF_LIBRARY_STRIP_CHARS)) {
+    /* Replace separators with a hyphen */
+    g_strdelimit (s, "\\:|", '-');
+    /* Replace all other weird characters to whitespace */
+    g_strdelimit (s, "*?&!\'\"$()`>{}", ' ');
+    /* Replace all whitespace with underscores */
+    /* TODO: I'd like this to compress whitespace aswell */
+    g_strdelimit (s, "\t ", '_');
+  }
+  res = g_filename_from_utf8(s, -1, NULL, NULL, NULL);
+  g_free(s);
+  return res ? res : g_strdup(str);
+}
+
+/**
+ * Parse a filename pattern and replace markers with values from a TrackDetails
+ * structure.
+ *
+ * Valid markers so far are:
+ * %at -- album title
+ * %aa -- album artist
+ * %aA -- album artist (lowercase)
+ * %as -- album artist sortname
+ * %aS -- album artist sortname (lowercase)
+ * %tn -- track number (i.e 8)
+ * %tN -- track number, zero padded (i.e 08)
+ * %tt -- track title
+ * %ta -- track artist
+ * %tA -- track artist (lowercase)
+ * %ts -- track artist sortname
+ * %tS -- track artist sortname (lowercase)
+ */
+static char *
+filepath_parse_pattern (const char *pattern, RhythmDBEntry *entry)
+{
+	/* p is the pattern iterator, i is a general purpose iterator */
+	const char *p;
+	char *temp;
+	GString *s;
+
+	if (pattern == NULL || pattern[0] == 0)
+		return g_strdup (" ");
+
+	s = g_string_new (NULL);
+
+	p = pattern;
+	while (*p) {
+		char *string = NULL;
+
+		/* If not a % marker, copy and continue */
+		if (*p != '%') {
+			g_string_append_c (s, *p++);
+			/* Explicit increment as we continue past the increment */
+			continue;
+		}
+
+		/* Is a % marker, go to next and see what to do */
+		switch (*++p) {
+		case '%':
+			/*
+			 * Literal %
+			 */
+			g_string_append_c (s, '%');
+			break;
+		case 'a':
+			/*
+			 * Album tag
+			 */
+			switch (*++p) {
+			case 't':
+				string = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM));
+				break;
+			case 'T':
+				temp = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM_FOLDED));
+				break;
+			case 'a':
+				string = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
+				break;
+			case 'A':
+				string = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST_FOLDED));
+				break;
+			/*case 's':
+				string = sanitize_path (album sort name);
+				break;
+			case 'S':
+				char *t = g_utf8_strdown (album sort name)
+				string = sanitize_path (t);
+				g_free (t);
+				break;*/
+			default:
+				string = g_strdup_printf ("%%a%c", *p);
+			}
+			
+			break;
+
+		case 't':
+			/*
+			 * Track tag
+			 */
+			switch (*++p) {
+			case 't':
+				string = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE));
+				break;
+			case 'T':
+				string = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE_FOLDED));
+				break;
+			case 'a':
+				string = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST));
+				break;
+			case 'A':
+				string = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST_FOLDED));
+				break;
+			/*case 's':
+				string = sanitize_path (artist sort name);
+				break;
+			case 'S':
+				char *t = g_utf8_strdown (artist sort name)
+				string = sanitize_path (t);
+				g_free (t);
+				break;*/
+			case 'n':
+				/* Track number */
+				string = g_strdup_printf ("%u", (guint)rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER));
+				break;
+			case 'N':
+				/* Track number, zero-padded */
+				string = g_strdup_printf ("%02u", (guint)rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER));
+				break;
+			default:
+				string = g_strdup_printf ("%%t%c", *p);
+ 			}
+
+			break;
+			
+		default:
+			string = g_strdup_printf ("%%%c", *p);
+		}
+
+		if (string)
+			g_string_append (s, string);
+		g_free (string);
+
+		++p;
+	}
+
+	temp = s->str;
+	g_string_free (s, FALSE);
+	return temp;
+}
+
+static void
+layout_example_label_update (RBLibrarySource *source)
+{
+	char *file_pattern;
+	char *path_pattern;
+	char *file_value;
+	char *path_value;
+	char *example;
+	char *format;
+	GMAudioProfile *profile;
+	RhythmDBEntry *sample_entry;
+
+  	profile = gm_audio_profile_choose_get_active (source->priv->preferred_format_menu);
+
+	/* TODO: sucky. Replace with get-gconf-key-with-default mojo */
+	file_pattern = eel_gconf_get_string (CONF_LIBRARY_LAYOUT_FILENAME);
+	if (file_pattern == NULL) {
+		file_pattern = g_strdup (library_layout_filenames[0].path);
+	}
+	path_pattern = eel_gconf_get_string (CONF_LIBRARY_LAYOUT_PATH);
+	if (path_pattern == NULL) {
+		path_pattern = g_strdup (library_layout_paths[0].path);
+	}
+
+	sample_entry = rhythmdb_entry_example_new (source->priv->db, RHYTHMDB_ENTRY_TYPE_SONG, NULL);
+	file_value = filepath_parse_pattern (file_pattern, sample_entry);
+	path_value = filepath_parse_pattern (path_pattern, sample_entry);
+	rhythmdb_entry_unref (source->priv->db, sample_entry);
+
+	example = g_build_filename (G_DIR_SEPARATOR_S, path_value, file_value, NULL);
+	g_free (file_value);
+	g_free (file_pattern);
+	g_free (path_value);
+	g_free (path_pattern);
+
+	format = g_strconcat ("<small><i><b>Example Path:</b> ",
+			      example,
+			      ".",
+			      gm_audio_profile_get_extension (profile),
+			      "</i></small>", NULL);
+	g_free (example);
+  
+	gtk_label_set_markup (GTK_LABEL (source->priv->layout_example_label), format);
+	g_free (format);
+}
+
+static void
+rb_library_source_layout_path_changed (GConfClient *client,
+				       guint cnxn_id,
+				       GConfEntry *entry,
+				       RBLibrarySource *source)
+{
+	char *value;
+	int i = 0;
+
+	g_return_if_fail (strcmp (entry->key, CONF_LIBRARY_LAYOUT_PATH) == 0);
+
+	rb_debug ("layout path changed");
+
+	if (entry->value == NULL) {
+		value = g_strdup (library_layout_paths[0].path);
+	} else if (entry->value->type == GCONF_VALUE_STRING) {
+		value = g_strdup (gconf_value_get_string (entry->value));
+	} else {
+		return;
+	}
+
+	while (library_layout_paths[i].path && strcmp (library_layout_paths[i].path, value) != 0) {
+		i++;
+	}
+
+	g_free (value);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (source->priv->layout_path_menu), i);
+
+	layout_example_label_update (source);
+}
+
+static void
+rb_library_source_layout_filename_changed (GConfClient *client,
+					   guint cnxn_id,
+					   GConfEntry *entry,
+					   RBLibrarySource *source)
+{
+	char *value;
+	int i = 0;
+  
+	g_return_if_fail (strcmp (entry->key, CONF_LIBRARY_LAYOUT_FILENAME) == 0);
+
+	rb_debug ("layout filename changed");
+  
+	if (entry->value == NULL) {
+		value = g_strdup (library_layout_filenames[0].path);
+	} else if (entry->value->type == GCONF_VALUE_STRING) {
+		value = g_strdup (gconf_value_get_string (entry->value));
+	} else {
+		return;
+	}
+
+	while (library_layout_filenames[i].path && strcmp (library_layout_filenames[i].path, value) != 0) {
+		i++;
+	}
+
+	g_free (value);
+	gtk_combo_box_set_active (GTK_COMBO_BOX (source->priv->layout_filename_menu), i);
+
+	layout_example_label_update (source);
+}
+
 static void
 rb_library_source_init (RBLibrarySource *source)
 {
@@ -354,10 +682,12 @@
 	rb_debug ("finalizing library source");
 	
 	eel_gconf_notification_remove (source->priv->ui_dir_notify_id);
-	eel_gconf_notification_remove (source->priv->library_location_notify_id);
+	eel_gconf_notification_remove (source->priv->library_pref_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);
+	eel_gconf_notification_remove (source->priv->layout_path_notify_id);
+	eel_gconf_notification_remove (source->priv->layout_filename_notify_id);
 
 	g_free (source->priv->sorting_key);
 
@@ -540,12 +870,13 @@
 					    source);
 	}
 
+
 	source->priv->ui_dir_notify_id =
 		eel_gconf_notification_add (CONF_UI_LIBRARY_DIR,
 				    (GConfClientNotifyFunc) rb_library_source_ui_pref_changed, source);
-	source->priv->library_location_notify_id =
-		eel_gconf_notification_add (CONF_LIBRARY_LOCATION,
-				    (GConfClientNotifyFunc) rb_library_source_library_location_changed, source);
+	source->priv->library_pref_notify_id =
+		eel_gconf_notification_add (CONF_PREFIX,
+				    (GConfClientNotifyFunc) rb_library_source_library_pref_changed, source);
 
 	source->priv->cached_all_query = rhythmdb_query_model_new_empty (source->priv->db);
 	rb_library_browser_set_model (source->priv->browser, source->priv->cached_all_query, TRUE);
@@ -779,6 +1110,7 @@
 	RBLibrarySource *source = RB_LIBRARY_SOURCE (asource);
 	GtkWidget *tmp;
 	GladeXML *xml;
+	int i;
 
 	if (source->priv->config_widget)
 		return source->priv->config_widget;
@@ -789,37 +1121,85 @@
 	xml = rb_glade_xml_new ("library-prefs.glade", "library_vbox", source);
 	source->priv->config_widget =
 		glade_xml_get_widget (xml, "library_vbox");
-	tmp = glade_xml_get_widget (xml, "library_browser_views_radio");
-	source->priv->browser_views_group =
-		g_slist_reverse (g_slist_copy (gtk_radio_button_get_group 
-					       (GTK_RADIO_BUTTON (tmp))));
 
 	source->priv->library_location_entry = glade_xml_get_widget (xml, "library_location_entry");
-	source->priv->watch_library_check = glade_xml_get_widget (xml, "watch_library_check");
 	tmp = glade_xml_get_widget (xml, "library_location_button");
 	g_signal_connect (G_OBJECT (tmp),
 			  "clicked",
 			  G_CALLBACK (rb_library_source_location_button_clicked_cb),
 			  asource);
-
-	rb_glade_boldify_label (xml, "browser_views_label");
-	rb_glade_boldify_label (xml, "library_location_label");
-	g_object_unref (G_OBJECT (xml));
-	
-	rb_library_source_preferences_sync (source);
 	g_signal_connect (G_OBJECT (source->priv->library_location_entry),
 			  "focus-out-event",
 			  G_CALLBACK (rb_library_source_library_location_cb),
 			  asource);
+
+	source->priv->watch_library_check = glade_xml_get_widget (xml, "watch_library_check");
 	g_signal_connect (G_OBJECT (source->priv->watch_library_check),
 			  "toggled",
 			  G_CALLBACK (rb_library_source_watch_toggled_cb),
 			  asource);
 
+	tmp = glade_xml_get_widget (xml, "layout_path_menu_box");
+	source->priv->layout_path_menu = gtk_combo_box_new_text ();
+	gtk_box_pack_start_defaults (GTK_BOX (tmp), source->priv->layout_path_menu);
+	g_signal_connect (G_OBJECT (source->priv->layout_path_menu),
+			  "changed",
+			  G_CALLBACK (rb_library_source_path_changed_cb),
+			  asource);
+	for (i = 0; i < num_library_layout_paths; i++) {
+		gtk_combo_box_append_text (GTK_COMBO_BOX (source->priv->layout_path_menu),
+					   _(library_layout_paths[i].title));
+	}
+
+	tmp = glade_xml_get_widget (xml, "layout_filename_menu_box");
+	source->priv->layout_filename_menu = gtk_combo_box_new_text ();
+	gtk_box_pack_start_defaults (GTK_BOX (tmp), source->priv->layout_filename_menu);
+	g_signal_connect (G_OBJECT (source->priv->layout_filename_menu),
+			  "changed",
+			  G_CALLBACK (rb_library_source_filename_changed_cb),
+			  asource);
+	for (i = 0; i < num_library_layout_filenames; i++) {
+		gtk_combo_box_append_text (GTK_COMBO_BOX (source->priv->layout_filename_menu),
+					   _(library_layout_filenames[i].title));
+	}
+
+	tmp = glade_xml_get_widget (xml, "edit_profile_button");
+	g_signal_connect (G_OBJECT (tmp),
+			  "clicked",
+			  G_CALLBACK (rb_library_source_edit_profile_clicked_cb),
+			  asource);
+
+	tmp = glade_xml_get_widget (xml, "preferred_format_menu_box");
+	source->priv->preferred_format_menu = gm_audio_profile_choose_new ();
+	gtk_box_pack_start_defaults (GTK_BOX (tmp), source->priv->preferred_format_menu);
+	g_signal_connect (G_OBJECT (source->priv->preferred_format_menu),
+			  "changed",
+			  G_CALLBACK (rb_library_source_format_changed_cb),
+			  asource);
+
+	source->priv->layout_example_label = glade_xml_get_widget (xml, "layout_example_label");
+
+	rb_glade_boldify_label (xml, "library_location_label");
+	rb_glade_boldify_label (xml, "library_structure_label");
+	g_object_unref (G_OBJECT (xml));
+	
+	rb_library_source_preferences_sync (source);
+
 	return source->priv->config_widget;
 }
 
 static void
+rb_library_source_edit_profile_clicked_cb (GtkButton *button, RBLibrarySource *source)
+{
+	GtkWidget *dialog;
+
+	dialog = gm_audio_profiles_edit_new (eel_gconf_client_get_global (),
+					     GTK_WINDOW (source->priv->shell_prefs));
+	gtk_widget_show_all (dialog);
+	gtk_dialog_run (GTK_DIALOG (dialog));
+}
+
+static void
 rb_library_source_location_button_clicked_cb (GtkButton *button, RBLibrarySource *source)
 {
 	GtkWidget *dialog;
@@ -852,13 +1232,12 @@
 rb_library_source_preferences_sync (RBLibrarySource *source)
 {
 	GSList *list;
+	const char *str;
+	GConfClient *gconf_client;
 
 	rb_debug ("syncing pref dialog state");
 
-	list = g_slist_nth (source->priv->browser_views_group,
-			    eel_gconf_get_integer (CONF_UI_BROWSER_VIEWS));
-	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (list->data), TRUE);
-
+	/* library location */
 	list = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
 
 	/* don't trigger the change notification */
@@ -891,8 +1270,27 @@
 	g_slist_foreach (list, (GFunc) g_free, NULL);
 	g_slist_free (list);
 
+	/* watch checkbox */
 	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (source->priv->watch_library_check),
 				      eel_gconf_get_boolean (CONF_MONITOR_LIBRARY));
+
+	/* preferred format */
+	str = eel_gconf_get_string (CONF_LIBRARY_PREFERRED_FORMAT);
+	gm_audio_profile_choose_set_active (source->priv->preferred_format_menu, str);
+
+	source->priv->layout_path_notify_id =
+		eel_gconf_notification_add (CONF_LIBRARY_LAYOUT_PATH,
+				    (GConfClientNotifyFunc) rb_library_source_layout_path_changed, source);
+	source->priv->layout_filename_notify_id =
+		eel_gconf_notification_add (CONF_LIBRARY_LAYOUT_FILENAME,
+				    (GConfClientNotifyFunc) rb_library_source_layout_filename_changed, source);
+
+	gconf_client = gconf_client_get_default ();
+	/* layout path */
+	rb_library_source_layout_path_changed (gconf_client, -1, gconf_client_get_entry (gconf_client, CONF_LIBRARY_LAYOUT_PATH, NULL, TRUE, NULL), source);
+	/* layout filename */
+	rb_library_source_layout_filename_changed (gconf_client, -1, gconf_client_get_entry (gconf_client, CONF_LIBRARY_LAYOUT_FILENAME, NULL, TRUE, NULL), source);
+	g_object_unref (gconf_client);
 }
 
 static void
@@ -931,20 +1329,6 @@
 }
 
 
-void
-rb_library_source_browser_views_activated_cb (GtkWidget *widget,
-					    RBLibrarySource *source)
-{
-	int index;
-
-	if (source->priv->loading_prefs == TRUE)
-		return;
-
-	index = g_slist_index (source->priv->browser_views_group, widget);
-
-	eel_gconf_set_integer (CONF_UI_BROWSER_VIEWS, index);
-}
-
 static void
 impl_delete (RBSource *asource)
 {
@@ -1111,36 +1495,39 @@
 impl_receive_drag (RBSource *asource, GtkSelectionData *data)
 {
 	RBLibrarySource *source = RB_LIBRARY_SOURCE (asource);
-	GList *list, *uri_list, *i;
+	GList *list, *i;
+	GList *entries = NULL;
 
 	rb_debug ("parsing uri list");
-	list = gnome_vfs_uri_list_parse ((char *) data->data);
-
-	if (list == NULL)
-		return FALSE;
+	list = rb_uri_list_parse ((const char *) data->data);
 
-	uri_list = NULL;
+	for (i = list; i != NULL; i = g_list_next (i)) {
+		if (i->data != NULL) {
+			char *uri = i->data;
+			RhythmDBEntry *entry;
 
-	for (i = list; i != NULL; i = g_list_next (i))
-		uri_list = g_list_prepend (uri_list, gnome_vfs_uri_to_string ((const GnomeVFSURI *) i->data, 0));
+			entry = rhythmdb_entry_lookup_by_location (source->priv->db, uri);
 
-	gnome_vfs_uri_list_free (list);
-
-	if (uri_list == NULL)
-		return FALSE;
-	
-	rb_debug ("adding uris");
-
-	for (i = uri_list; i != NULL; i = i->next) {
-		char *uri = i->data;
+			if (entry == NULL) {
+				/* add to the library */
+				rhythmdb_add_uri (source->priv->db, uri);
+			} else {
+				/* add to list of entries to copy */
+				entries = g_list_prepend (entries, entry);
+			}
 
-		if (uri != NULL)
-			rhythmdb_add_uri (source->priv->db, uri);
+			g_free (uri);
+		}
+	}
 
-		g_free (uri);
+	if (entries) {
+		entries = g_list_reverse (entries);
+		if (rb_source_can_paste (asource))
+			rb_source_paste (asource, entries);
+		g_list_free (entries);
 	}
 
-	g_list_free (uri_list);
+	g_list_free (list);
 	return TRUE;
 }
 
@@ -1216,6 +1603,173 @@
 	g_object_unref (G_OBJECT (query_model));
 	
 	rb_source_notify_filter_changed (RB_SOURCE (source));
+}
+
+static void
+rb_library_source_path_changed_cb (GtkComboBox *box, RBLibrarySource *source)
+{
+	const char *path;
+	gint index;
+
+	index = gtk_combo_box_get_active (box);
+	path = (index >= 0) ? library_layout_paths[index].path : "";
+	eel_gconf_set_string (CONF_LIBRARY_LAYOUT_PATH, path);
+}
+
+static void
+rb_library_source_filename_changed_cb (GtkComboBox *box, RBLibrarySource *source)
+{
+	const char *filename;
+	gint index;
+
+	index = gtk_combo_box_get_active (box);
+	filename = (index >= 0) ? library_layout_filenames[index].path : "";
+	eel_gconf_set_string (CONF_LIBRARY_LAYOUT_FILENAME, filename);
+}
+
+static void
+rb_library_source_format_changed_cb (GtkWidget *widget, RBLibrarySource *source)
+{
+	GMAudioProfile *profile;
+
+	profile = gm_audio_profile_choose_get_active (widget);
+	eel_gconf_set_string (CONF_LIBRARY_PREFERRED_FORMAT, gm_audio_profile_get_id (profile));
+}
+
+/**
+ * Build the absolute filename for the specified track.
+ *
+ * The base path is the extern variable 'base_path', the format to use
+ * is the extern variable 'file_pattern'. Free the result when you
+ * have finished with it.
+ *
+ * Stolen from Sound-Juicer
+ */
+static char*
+build_filename (RBLibrarySource *source, RhythmDBEntry *entry)
+{
+	GnomeVFSURI *uri;
+	GnomeVFSURI *new;
+	char *realfile;
+	char *realpath;
+	char *filename;
+	char *string;
+	char *extension;
+	GSList *list;
+	const char *layout_path;
+	const char *layout_filename;
+	const char *preferred_format;
+
+	list = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+	layout_path = eel_gconf_get_string (CONF_LIBRARY_LAYOUT_PATH);
+	layout_filename = eel_gconf_get_string (CONF_LIBRARY_LAYOUT_FILENAME);
+	preferred_format = eel_gconf_get_string (CONF_LIBRARY_PREFERRED_FORMAT);
+
+	if (list == NULL || layout_path == NULL || layout_filename == NULL || preferred_format == NULL) {
+		/* emit warning */
+		rb_debug ("Could not retrieve settings from GConf");
+		return NULL;
+	}
+
+	uri = gnome_vfs_uri_new ((const char *)list->data);
+	g_slist_free (list);
+
+	realpath = filepath_parse_pattern (layout_path, entry);
+	new = gnome_vfs_uri_append_path (uri, realpath);
+	gnome_vfs_uri_unref (uri);
+	uri = new;
+	g_free (realpath);
+
+	if (g_str_has_prefix (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE), "audio/x-raw")) {
+		GMAudioProfile *profile;
+		profile = gm_audio_profile_lookup (preferred_format);
+		extension = g_strdup (gm_audio_profile_get_extension (profile));
+	} else {
+		char *tmp;
+		
+		/* use the old extension. strip anything after a '?' for http/daap/etc */
+		extension = g_strdup (g_utf8_strrchr (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION), -1, '.') + 1);
+
+		tmp = g_utf8_strchr (extension, -1, '?');
+		if (tmp)
+			*tmp = '\0';
+	}
+	
+	realfile = filepath_parse_pattern (layout_filename, entry);
+	if (extension) {
+		filename = g_strdup_printf ("%s.%s", realfile, extension);
+		g_free (realfile);
+	} else {
+		filename = realfile;
+	}
+
+	new = gnome_vfs_uri_append_file_name (uri, filename);
+	gnome_vfs_uri_unref (uri);
+	uri = new;
+	g_free (extension);
+	g_free (filename);
+
+	string = gnome_vfs_uri_to_string (uri, 0);
+	gnome_vfs_uri_unref (uri);
+	return string;
+}
+
+static gboolean
+impl_can_paste (RBSource *asource)
+{
+	GSList *list;
+
+	list = eel_gconf_get_string_list (CONF_LIBRARY_LOCATION);
+	if (list == NULL)
+		return FALSE;
+
+	g_slist_free (list);
+	return TRUE;
+}
+
+static void
+completed_cb (RhythmDBEntry *entry, const char *dest, RBLibrarySource *source)
+{
+	rhythmdb_add_uri (source->priv->db, dest);
+}
+
+static void
+impl_paste (RBSource *asource, GList *entries)
+{
+	RBLibrarySource *source = RB_LIBRARY_SOURCE (asource);
+	RBRemovableMediaManager *rm_mgr;
+	GList *l;
+	RBShell *shell;
+
+	g_object_get (G_OBJECT (source), "shell", &shell, NULL);
+	g_object_get (G_OBJECT (shell), "removable-media-manager", &rm_mgr, NULL);
+	g_object_unref (G_OBJECT (shell));
+
+	for (l = entries; l != NULL; l = g_list_next (l)) {
+		RhythmDBEntry *entry = (RhythmDBEntry *)l->data;
+		RhythmDBEntryType entry_type;
+		char *dest;
+
+		rb_debug ("pasting entry %s", rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION));
+
+		entry_type = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TYPE);
+		if (entry_type == RHYTHMDB_ENTRY_TYPE_IRADIO_STATION ||
+		    entry_type == RHYTHMDB_ENTRY_TYPE_PODCAST_FEED ||
+		    entry_type == RHYTHMDB_ENTRY_TYPE_PODCAST_POST)
+			continue;
+
+		dest = build_filename (source, entry);
+		if (dest == NULL) {
+			rb_debug ("could not create destination path for entry");
+			continue;
+		}
+
+		rb_removable_media_manager_queue_transfer (rm_mgr, entry,
+							  dest, NULL,
+							  (RBTranferCompleteCallback)completed_cb, source);
+	}
+
+	g_object_unref (G_OBJECT (rm_mgr));
 }
 
 static void
diff -u -u -r1.11 rb-removable-media-source.c
--- sources/rb-removable-media-source.c	9 Mar 2006 10:26:12 -0000	1.11
+++ sources/rb-removable-media-source.c	25 Mar 2006 02:16:41 -0000
@@ -87,7 +87,8 @@
 
 	source_class->impl_delete_thyself = impl_delete_thyself;
 	source_class->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
-	source_class->impl_can_copy = (RBSourceFeatureFunc) rb_false_function;
+	source_class->impl_can_copy = (RBSourceFeatureFunc) rb_true_function;
+	source_class->impl_can_paste = (RBSourceFeatureFunc) rb_false_function;
 	source_class->impl_can_delete = (RBSourceFeatureFunc) rb_false_function;
 	source_class->impl_receive_drag = NULL;
 	source_class->impl_can_move_to_trash = (RBSourceFeatureFunc) rb_false_function;
diff -u -u -r1.61 rb-source.c
--- sources/rb-source.c	12 Mar 2006 23:01:00 -0000	1.61
+++ sources/rb-source.c	25 Mar 2006 02:16:41 -0000
@@ -127,6 +127,7 @@
 	klass->impl_can_rename = default_can_rename;
 	klass->impl_can_search = default_can_search;
 	klass->impl_can_cut = (RBSourceFeatureFunc) rb_false_function;
+	klass->impl_can_paste = (RBSourceFeatureFunc) rb_false_function;
 	klass->impl_can_delete = (RBSourceFeatureFunc) rb_false_function;
 	klass->impl_can_copy = (RBSourceFeatureFunc) rb_false_function;
 	klass->impl_can_add_to_queue = (RBSourceFeatureFunc) rb_false_function;
@@ -578,6 +579,14 @@
 	RBSourceClass *klass = RB_SOURCE_GET_CLASS (source);
 
 	return klass->impl_can_cut (source);
+}
+
+gboolean
+rb_source_can_paste (RBSource *source)
+{
+	RBSourceClass *klass = RB_SOURCE_GET_CLASS (source);
+
+	return klass->impl_can_paste (source);
 }
 
 gboolean
diff -u -u -r1.39 rb-source.h
--- sources/rb-source.h	12 Mar 2006 23:01:00 -0000	1.39
+++ sources/rb-source.h	25 Mar 2006 02:16:41 -0000
@@ -90,6 +90,7 @@
 	gboolean	(*impl_can_delete)	(RBSource *source);
 	gboolean	(*impl_can_move_to_trash) (RBSource *source);
 	gboolean	(*impl_can_copy)	(RBSource *source);
+	gboolean	(*impl_can_paste)	(RBSource *source);
 	gboolean	(*impl_can_add_to_queue)(RBSource *source);
 	
 	GList *		(*impl_cut)		(RBSource *source);
@@ -153,6 +154,7 @@
 gboolean	rb_source_can_delete		(RBSource *source);
 gboolean	rb_source_can_move_to_trash	(RBSource *source);
 gboolean	rb_source_can_copy		(RBSource *source);
+gboolean	rb_source_can_paste		(RBSource *source);
 gboolean	rb_source_can_add_to_queue	(RBSource *source);
 
 GList *		rb_source_cut			(RBSource *source);
diff -u -u -r1.21 rb-sourcelist-model.c
--- sources/rb-sourcelist-model.c	21 Mar 2006 08:34:49 -0000	1.21
+++ sources/rb-sourcelist-model.c	25 Mar 2006 02:16:41 -0000
@@ -347,7 +347,7 @@
 		gtk_tree_model_get (GTK_TREE_MODEL (model), &iter,
 				    RB_SOURCELIST_MODEL_COLUMN_SOURCE, &source, -1);
 		
-		return rb_source_can_cut (source);
+		return rb_source_can_paste (source);
 
 	}
 	return FALSE;
diff -u -u -r1.16 rb-static-playlist-source.c
--- sources/rb-static-playlist-source.c	15 Mar 2006 09:16:44 -0000	1.16
+++ sources/rb-static-playlist-source.c	25 Mar 2006 02:16:41 -0000
@@ -126,7 +126,7 @@
 	object_class->finalize = rb_static_playlist_source_finalize;
 
 	source_class->impl_can_cut = (RBSourceFeatureFunc) rb_true_function;
-	source_class->impl_can_copy = (RBSourceFeatureFunc) rb_true_function;
+	source_class->impl_can_paste = (RBSourceFeatureFunc) rb_true_function;
 	source_class->impl_can_delete = (RBSourceFeatureFunc) rb_true_function;
 	source_class->impl_cut = impl_cut;
 	source_class->impl_paste = impl_paste;
--- /dev/null	2006-03-24 05:28:51.000000000 +1100
+++ backends/gstreamer/rb-encoder-gst.c	2006-03-25 12:35:14.000000000 +1100
@@ -0,0 +1,710 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * arch-tag: Implementation of GStreamer encoding backend
+ * 
+ * Based on Sound-Juicer's ripping code
+ *
+ * Copyright (C) 2003 Ross Burton <ross@burtonini.com>
+ * Copyright (C) 2006 James Livingston <jrl@ids.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <glib/gi18n.h>
+#include <libgnomevfs/gnome-vfs-utils.h>
+#include <libgnomevfs/gnome-vfs-uri.h>
+#include <libgnomevfs/gnome-vfs-ops.h>
+#include <gst/gst.h>
+#include <string.h>
+#include <profiles/gnome-media-profiles.h>
+#include <gtk/gtk.h>
+
+#include "rhythmdb.h"
+#include "eel-gconf-extensions.h"
+#include "rb-preferences.h"
+#include "rb-encoder.h"
+#include "rb-encoder-gst.h"
+#include "rb-debug.h"
+
+
+static void rb_encoder_gst_class_init (RBEncoderGstClass *klass);
+static void rb_encoder_gst_init       (RBEncoderGst *encoder);
+static void rb_encoder_gst_finalize   (GObject *object);
+static void rb_encoder_init (RBEncoderIface *iface);
+
+
+struct _RBEncoderGstPrivate {
+	GstElement *pipeline;
+	
+	gboolean completion_emitted;
+
+	gulong total_length;
+	guint progress_id;
+};
+
+G_DEFINE_TYPE_WITH_CODE(RBEncoderGst, rb_encoder_gst, G_TYPE_OBJECT,
+			G_IMPLEMENT_INTERFACE(RB_TYPE_ENCODER,
+					      rb_encoder_init))
+#define RB_ENCODER_GST_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_ENCODER_GST, RBEncoderGstPrivate))
+
+
+static gboolean rb_encoder_gst_encode (RBEncoder *encoder,
+				       RhythmDBEntry *entry,
+				       const char *dest,
+				       const char *mime_type);
+static void rb_encoder_gst_cancel (RBEncoder *encoder);
+static void rb_encoder_gst_emit_completed (RBEncoderGst *encoder);
+	
+static void
+rb_encoder_gst_class_init (RBEncoderGstClass *klass)
+{
+        GObjectClass *object_class = (GObjectClass *) klass;
+
+        object_class->finalize = rb_encoder_gst_finalize;
+
+        g_type_class_add_private (klass, sizeof (RBEncoderGstPrivate));
+}
+
+static void
+rb_encoder_gst_init (RBEncoderGst *encoder)
+{
+        encoder->priv = RB_ENCODER_GST_GET_PRIVATE (encoder);
+}
+
+static void
+rb_encoder_init (RBEncoderIface *iface)
+{
+	iface->encode = rb_encoder_gst_encode;
+	iface->cancel = rb_encoder_gst_cancel;
+}
+
+static void
+rb_encoder_gst_finalize (GObject *object)
+{
+	RBEncoderGst *encoder = RB_ENCODER_GST (object);
+
+	if (encoder->priv->completion_emitted == FALSE) {
+		g_warning ("completion not emitted for encoder");
+		rb_encoder_gst_emit_completed (encoder);
+	}
+	
+	if (encoder->priv->progress_id != 0)
+		g_source_remove (encoder->priv->progress_id);	
+	
+	if (encoder->priv->pipeline) {
+		gst_element_set_state (encoder->priv->pipeline, GST_STATE_NULL);
+		g_object_unref (encoder->priv->pipeline);
+		encoder->priv->pipeline = NULL;
+	}	
+
+        G_OBJECT_CLASS (rb_encoder_gst_parent_class)->finalize (object);
+}
+
+RBEncoder*
+rb_encoder_gst_new (void)
+{
+	return RB_ENCODER (g_object_new (RB_TYPE_ENCODER_GST, NULL));
+}
+
+static void
+rb_encoder_gst_emit_completed (RBEncoderGst *encoder)
+{
+	g_return_if_fail (encoder->priv->completion_emitted == FALSE);
+
+	if (encoder->priv->progress_id != 0)
+		g_source_remove (encoder->priv->progress_id);	
+
+	encoder->priv->completion_emitted = TRUE;
+	_rb_encoder_emit_completed (RB_ENCODER (encoder));
+}
+
+
+#ifdef HAVE_GSTREAMER_0_10
+static gboolean
+bus_watch_cb (GstBus *bus, GstMessage *message, gpointer data)
+{
+	RBEncoderGst *encoder = RB_ENCODER_GST (data);
+	char *string;
+	GError *error;
+
+	/* ref ourselves, in case one of the signal handler unrefs us */
+	g_object_ref (G_OBJECT (encoder));
+
+	switch (GST_MESSAGE_TYPE (message)) {
+	case GST_MESSAGE_ERROR:
+		gst_message_parse_error (message, &error, &string);
+		_rb_encoder_emit_error (RB_ENCODER (encoder), error);
+		rb_debug ("received error %s", string);
+		g_error_free (error);
+		g_free (string);
+		
+		rb_encoder_cancel (RB_ENCODER (encoder));
+		break;
+
+	case GST_MESSAGE_WARNING:
+		gst_message_parse_warning (message, &error, &string);
+		rb_debug ("received warning %s", string);
+		g_error_free (error);
+		g_free (string);
+		break;
+	
+	case GST_MESSAGE_EOS:
+		rb_debug ("received EOS");
+
+		gst_element_set_state (encoder->priv->pipeline, GST_STATE_NULL);
+
+		rb_encoder_gst_emit_completed (encoder);
+
+		g_object_unref (encoder->priv->pipeline);
+		encoder->priv->pipeline = NULL;
+		break;
+	
+	default:
+		rb_debug ("message of type %s", gst_message_type_get_name (GST_MESSAGE_TYPE (message)));
+		break;
+	}
+
+	g_object_unref (G_OBJECT (encoder));
+	return TRUE;
+}
+#endif
+
+#ifdef HAVE_GSTREAMER_0_8
+static void
+gst_eos_cb (GstElement *element, RBEncoderGst *encoder)
+{
+	rb_debug ("received EOS");
+
+	gst_element_set_state (encoder->priv->pipeline, GST_STATE_NULL);
+
+	rb_encoder_gst_emit_completed (encoder);
+
+	g_object_unref (encoder->priv->pipeline);
+	encoder->priv->pipeline = NULL;
+}
+
+static void
+gst_error_cb (GstElement *element,
+			  GstElement *source,
+			  GError *error,
+			  gchar *debug,
+			  RBEncoderGst *encoder)
+{
+	_rb_encoder_emit_error (RB_ENCODER (encoder), error);
+	rb_debug ("received error %s", debug);
+		
+	rb_encoder_cancel (RB_ENCODER (encoder));
+}
+
+#endif
+
+static gboolean
+progress_timeout_cb (RBEncoderGst *encoder)
+{
+	gint64 nanos;
+	gint secs;
+	GstState state;
+	static GstFormat format = GST_FORMAT_TIME;
+
+	if (encoder->priv->pipeline == NULL)
+		return FALSE;
+
+	gst_element_get_state (encoder->priv->pipeline, &state, NULL, GST_CLOCK_TIME_NONE);
+	if (state != GST_STATE_PLAYING)
+		return FALSE;
+
+	if (!gst_element_query_position (encoder->priv->pipeline, &format, &nanos)) {
+		g_warning ("Could not get current track position");
+		return TRUE;
+	}
+
+	secs = nanos / GST_SECOND;
+	rb_debug ("encoding progress at %d out of %d", secs, encoder->priv->total_length);
+	_rb_encoder_emit_progress (RB_ENCODER (encoder), ((double)secs) / encoder->priv->total_length);
+
+	return TRUE;
+}
+
+static gboolean
+start_pipeline (RBEncoderGst *encoder, GError **error)
+{
+	GstStateChangeReturn result;
+	
+#ifdef HAVE_GSTREAMER_0_10
+	GstBus *bus;
+
+	g_assert (encoder->priv->pipeline);
+	
+	bus = gst_pipeline_get_bus (GST_PIPELINE (encoder->priv->pipeline));
+	gst_bus_add_watch (bus, bus_watch_cb, encoder);
+#elif HAVE_GSTREAMER_0_8
+	g_signal_connect_object (G_OBJECT (encoder->priv->pipeline),
+				 "error", G_CALLBACK (gst_error_cb),
+				 encoder, 0);
+	g_signal_connect_object (G_OBJECT (encoder->priv->pipeline),
+				 "eos", G_CALLBACK (gst_eos_cb),
+				 encoder, 0);
+#endif
+
+	result = gst_element_set_state (encoder->priv->pipeline, GST_STATE_PLAYING);
+	
+	if (result != GST_STATE_CHANGE_FAILURE) {
+		/* start reporting progress */
+		if (encoder->priv->total_length > 0) {
+			_rb_encoder_emit_progress (RB_ENCODER (encoder), 0.0);
+			encoder->priv->progress_id = g_timeout_add (250, (GSourceFunc)progress_timeout_cb, encoder);
+		} else {
+			_rb_encoder_emit_progress (RB_ENCODER (encoder), -1);
+		}
+	}
+	
+	return (result != GST_STATE_CHANGE_FAILURE);
+}
+
+#ifdef HAVE_GSTREAMER_0_8
+/* this is basically what the function in 0.10 does */
+static GstPad*
+rb_gst_bin_find_unconnected_pad (GstBin *bin, GstPadDirection dir)
+{
+	const GList *elements, *el;
+
+	elements = gst_bin_get_list (GST_BIN (bin));
+	for (el = elements; el != NULL; el = el->next) {
+		GstElement *element = GST_ELEMENT (el->data);
+		const GList *pads, *pl;
+
+		pads = gst_element_get_pad_list (element);
+
+		for (pl = pads; pl != NULL; pl = pl->next) {
+			GstPad *pad = GST_PAD (pl->data);
+
+			if (!GST_PAD_IS_LINKED (pad) && GST_PAD_DIRECTION (pad) == dir)
+				return pad;
+		}
+	}
+
+	return NULL;
+}
+
+#define gst_bin_find_unconnected_pad rb_gst_bin_find_unconnected_pad
+
+const char *GST_ENCODING_PROFILE = "audioscale ! audioconvert ! %s";
+#elif HAVE_GSTREAMER_0_10
+const char *GST_ENCODING_PROFILE = "audioresample ! audioconvert ! %s";
+#endif
+
+static GstElement*
+add_encoding_pipeline (RBEncoderGst *encoder,
+		       GstElement *start,
+		       GMAudioProfile *profile,
+		       GError **error)
+{
+	GstElement *queue, *encoding_bin, *queue2;
+	GstPad *pad;
+	char *tmp;
+
+	queue = gst_element_factory_make ("queue", NULL);
+	if (queue == NULL)
+		return NULL;
+	queue2 = gst_element_factory_make ("queue", NULL);
+	if (queue2 == NULL)
+		return NULL;
+
+	/* Nice big buffers... */
+	g_object_set (queue, "max-size-time", 120 * GST_SECOND, NULL);
+
+	tmp = g_strdup_printf (GST_ENCODING_PROFILE, gm_audio_profile_get_pipeline (profile));
+	encoding_bin = GST_ELEMENT (gst_parse_launch (tmp, error));
+	g_free (tmp);
+
+	if (encoding_bin == NULL)
+		return NULL;
+
+
+	/* find pads and ghost them if necessary */
+	if ((pad = gst_bin_find_unconnected_pad (GST_BIN (encoding_bin), GST_PAD_SRC)))
+		gst_element_add_pad (encoding_bin, gst_ghost_pad_new ("src", pad));
+	if ((pad = gst_bin_find_unconnected_pad (GST_BIN (encoding_bin), GST_PAD_SINK)))
+		gst_element_add_pad (encoding_bin, gst_ghost_pad_new ("sink", pad));
+
+	gst_bin_add_many (GST_BIN (encoder->priv->pipeline), queue, encoding_bin, queue2, NULL);
+	gst_element_link_many (start, queue, encoding_bin, queue2, NULL);
+
+	return queue2;
+}
+
+static gboolean
+add_tags_from_entry (RBEncoderGst *encoder,
+		     RhythmDBEntry *entry,
+		     GError **error)
+{
+	GstTagList *tags;
+	gboolean result = TRUE;
+
+	tags = gst_tag_list_new ();
+	gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE_ALL,
+			  /* FIXME: add the rest of them */
+			  GST_TAG_TITLE, rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_TITLE),
+			  GST_TAG_ARTIST, rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST),
+			  GST_TAG_TRACK_NUMBER, rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER),
+			  GST_TAG_ALBUM, rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ALBUM),
+			  GST_TAG_ENCODER, "Rhythmbox",
+			  GST_TAG_ENCODER_VERSION, VERSION,
+			  NULL);
+
+#ifdef HAVE_GSTREAMER_0_10
+	GstIterator *iter;
+	gboolean done;
+
+	iter = gst_bin_iterate_all_by_interface (GST_BIN (encoder->priv->pipeline), GST_TYPE_TAG_SETTER);
+	done = FALSE;
+	while (!done) {
+		GstTagSetter *tagger = NULL;
+		GstTagSetter **tagger_ptr = &tagger;
+
+		switch (gst_iterator_next (iter, (gpointer*)tagger_ptr)) {
+		case GST_ITERATOR_OK:
+			gst_tag_setter_merge_tags (tagger, tags, GST_TAG_MERGE_REPLACE_ALL);
+			break;
+		case GST_ITERATOR_RESYNC:
+			gst_iterator_resync (iter);
+			break;
+		case GST_ITERATOR_ERROR:
+			g_set_error (error,
+				     RB_ENCODER_ERROR, RB_ENCODER_ERROR_INTERNAL,
+				     "Could not add tags to tag-setter");
+			result = FALSE;
+			done = TRUE;
+			break;
+		case GST_ITERATOR_DONE:
+			done = TRUE;
+			break;
+		}
+		
+		if (tagger)
+			gst_object_unref (tagger);
+	}
+	gst_iterator_free (iter);
+#elif HAVE_GSTREAMER_0_8
+	GstElement *tagger;
+
+        tagger = gst_bin_get_by_interface (GST_BIN (encoder->priv->pipeline), GST_TYPE_TAG_SETTER);
+	if (tagger)
+		gst_tag_setter_merge (GST_TAG_SETTER (tagger), tags, GST_TAG_MERGE_REPLACE_ALL);
+#endif
+
+	gst_tag_list_free (tags);
+	return result;
+}
+
+static gboolean
+gnomevfs_allow_overwrite_cb (GstElement *element, GnomeVFSURI *uri, RBEncoderGst *encoder)
+{
+	GtkWidget *dialog;
+	gint response;
+	char *name;
+	char *display_name;
+
+	name = gnome_vfs_uri_to_string (uri, GNOME_VFS_URI_HIDE_USER_NAME | GNOME_VFS_URI_HIDE_PASSWORD);
+	display_name = gnome_vfs_format_uri_for_display (name);
+
+	dialog = gtk_message_dialog_new (NULL, 0,
+					 GTK_MESSAGE_QUESTION, GTK_BUTTONS_YES_NO,
+					 _("Do you want to overwrite the file \"%s\"?"),
+					 display_name);
+	response = gtk_dialog_run (GTK_DIALOG (dialog));
+	gtk_widget_destroy (dialog);
+	
+	g_free (display_name);
+	g_free (name);
+	
+	return (response == GTK_RESPONSE_YES);				 
+}
+
+static gboolean
+attach_output_pipeline (RBEncoderGst *encoder,
+			GstElement *end,
+			const char *dest,
+			GError **error)
+{
+	GstElement *sink;
+
+	sink = gst_element_make_from_uri (GST_URI_SINK, dest, "sink");
+
+	/* handle overwriting if we are using gnomevfssink
+	 * it would be nice if GST had an interface for sinks with thi, but it doesn't
+	 */
+	if (g_type_is_a (G_OBJECT_TYPE (sink), g_type_from_name ("GstGnomeVFSSink"))) {
+		g_signal_connect_object (G_OBJECT (sink),
+					 "allow-overwrite", G_CALLBACK (gnomevfs_allow_overwrite_cb),
+					 encoder, 0);
+	}
+
+	gst_bin_add (GST_BIN (encoder->priv->pipeline), sink);
+	gst_element_link (end, sink);
+
+	return TRUE;
+}
+
+static GMAudioProfile*
+get_profile_from_mime_type (const char *mime_type)
+{
+	/* TODO */
+	return NULL;
+}
+
+static GstElement *
+create_pipeline_and_source (RBEncoderGst *encoder,
+			    RhythmDBEntry *entry,
+			    GError **error)
+{
+	const char *uri;
+	GstElement *src;
+
+	uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
+	src = gst_element_make_from_uri (GST_URI_SRC, uri, "source");
+	if (src == NULL) {
+		g_set_error (error,
+			     RB_ENCODER_ERROR, RB_ENCODER_ERROR_INTERNAL,
+			     "could not create source element for '%s'", uri);
+		return NULL;
+	}
+
+	encoder->priv->pipeline = gst_pipeline_new ("pipeline");
+	gst_bin_add (GST_BIN (encoder->priv->pipeline), src);
+
+	/* TODO: add progress reporting */
+
+	return src;
+}
+
+static gboolean
+copy_track (RBEncoderGst *encoder,
+	    RhythmDBEntry *entry,
+	    const char *dest,
+	    GError **error)
+{
+	/* source ! sink */
+	GstElement *src;
+
+	g_assert (encoder->priv->pipeline == NULL);
+
+	src = create_pipeline_and_source (encoder, entry, error);
+	if (src == NULL)
+		return FALSE;
+
+	if (!attach_output_pipeline (encoder, src, dest, error))
+		return FALSE;
+
+	if (!start_pipeline (encoder, error))
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+extract_track (RBEncoderGst *encoder,
+	       RhythmDBEntry *entry,
+	       const char *dest,
+	       GError **error)
+{
+	/* cdsrc ! encoder ! sink */
+	const char *uri;
+	const char *device;
+	const char *profile_name;
+	GMAudioProfile *profile;
+	GstElement *src, *end;
+
+	g_assert (encoder->priv->pipeline == NULL);
+
+	profile_name = eel_gconf_get_string (CONF_LIBRARY_PREFERRED_FORMAT);
+	profile = gm_audio_profile_lookup (profile_name);
+	if (profile == NULL) {
+		g_set_error (error,
+			     RB_ENCODER_ERROR, RB_ENCODER_ERROR_FORMAT_UNSUPPORTED,
+			     "Could not find encoding profile '%s'", profile_name);
+		return FALSE;
+	}
+
+	src = create_pipeline_and_source (encoder, entry, error);
+	if (src == NULL)
+		return FALSE;
+
+	g_assert (encoder->priv->pipeline != NULL);
+
+	/* setup cd extraction properties */
+	uri = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_LOCATION);
+
+	device = g_utf8_strrchr (uri, -1, '#');
+	g_object_set (G_OBJECT (src),
+		      "device", device + 1, /* skip the '#' */
+		      "track", rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_TRACK_NUMBER),
+		      NULL);
+	if (g_object_class_find_property (G_OBJECT_GET_CLASS (src), "paranoia-mode")) {
+		int paranoia_mode;
+
+		paranoia_mode = 255; /* TODO: make configurable */
+		g_object_set (G_OBJECT (src), "paranoia-mode", paranoia_mode, NULL);
+	}
+
+	end = add_encoding_pipeline (encoder, src, profile, error);
+	if (end == NULL)
+		return FALSE;
+
+	if (!attach_output_pipeline (encoder, end, dest, error))
+		return FALSE;
+	if (!add_tags_from_entry (encoder, entry, error))
+		return FALSE;
+	if (!start_pipeline (encoder, error))
+		return FALSE;
+
+	return TRUE;
+}
+
+static gboolean
+transcode_track (RBEncoderGst *encoder,
+	 	 RhythmDBEntry *entry,
+		 const char *dest,
+		 const char *mime_type,
+		 GError **error)
+{
+	/* cdsrc ! encoder ! sink */
+	GMAudioProfile *profile;
+	GstElement *src, *spider, *end;
+
+	g_assert (encoder->priv->pipeline == NULL);
+
+	profile = get_profile_from_mime_type (mime_type);
+	if (profile == NULL) {
+		g_set_error (error,
+			     RB_ENCODER_ERROR, RB_ENCODER_ERROR_FORMAT_UNSUPPORTED,
+			     "Unable to locate encoding profile for mime-type '%s'", mime_type);
+		return FALSE;
+	}
+
+	src = create_pipeline_and_source (encoder, entry, error);
+	if (src == NULL)
+		return FALSE;
+
+	spider = gst_element_factory_make ("spider", "spider");
+	if (spider == NULL) {
+		g_set_error (error,
+			     RB_ENCODER_ERROR, RB_ENCODER_ERROR_INTERNAL,
+			     "Could not create encoding profile '%s'", gm_audio_profile_get_id (profile));
+		return FALSE;
+	}
+	gst_bin_add (GST_BIN (encoder->priv->pipeline), spider);
+	gst_element_link (src, spider);
+
+	end = add_encoding_pipeline (encoder, spider, profile, error);
+	if (end == NULL)
+		return FALSE;
+
+	if (!attach_output_pipeline (encoder, end, dest, error))
+		return FALSE;
+	if (!add_tags_from_entry (encoder, entry, error))
+		return FALSE;
+	if (!start_pipeline (encoder, error))
+		return FALSE;
+
+	return TRUE;
+}
+
+static void
+create_parent_dirs_uri (GnomeVFSURI *uri)
+{
+	GnomeVFSURI *parent_uri;
+
+	if (gnome_vfs_uri_exists (uri))
+		return;
+
+	parent_uri = gnome_vfs_uri_get_parent (uri);
+	create_parent_dirs_uri (parent_uri);
+	gnome_vfs_uri_unref (parent_uri);
+
+	gnome_vfs_make_directory_for_uri (uri, 0750);
+}
+
+static void
+create_parent_dirs (const char *uri)
+{
+	GnomeVFSURI *vfs_uri;
+	GnomeVFSURI *parent_uri;
+
+	vfs_uri = gnome_vfs_uri_new (uri);
+	parent_uri = gnome_vfs_uri_get_parent (vfs_uri);
+
+	create_parent_dirs_uri (parent_uri);
+
+	gnome_vfs_uri_unref (parent_uri);
+	gnome_vfs_uri_unref (vfs_uri);
+}
+
+static void
+rb_encoder_gst_cancel (RBEncoder *encoder)
+{
+	RBEncoderGstPrivate *priv = RB_ENCODER_GST (encoder)->priv;
+
+	if (priv->pipeline == NULL)
+		return;
+
+	gst_element_set_state (priv->pipeline, GST_STATE_NULL);
+	g_object_unref (priv->pipeline);
+	priv->pipeline = NULL;
+}
+
+static gboolean
+rb_encoder_gst_encode (RBEncoder *encoder,
+		       RhythmDBEntry *entry,
+		       const char *dest,
+		       const char *mime_type)
+{
+	RBEncoderGstPrivate *priv = RB_ENCODER_GST (encoder)->priv;
+	const char *entry_mime_type;
+	gboolean was_raw;
+	gboolean result;
+	GError *error = NULL;
+
+	g_return_val_if_fail (priv->pipeline == NULL, FALSE);
+	
+	entry_mime_type = rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_MIMETYPE);
+	was_raw = g_str_has_prefix (entry_mime_type, "audio/x-raw");
+
+	priv->total_length = rhythmdb_entry_get_ulong (entry, RHYTHMDB_PROP_DURATION);
+
+	create_parent_dirs (dest);
+
+	if ((mime_type == NULL && !was_raw) || (mime_type && (strcmp (mime_type, entry_mime_type) == 0))) {
+		result = copy_track (RB_ENCODER_GST (encoder), entry, dest, &error);
+	} else {
+		if (mime_type == NULL) {
+			result = extract_track (RB_ENCODER_GST (encoder), entry, dest, &error);
+		} else {
+			result = transcode_track (RB_ENCODER_GST (encoder), entry, dest, mime_type, &error);
+		}
+	}
+
+	if (error) {
+		rb_encoder_cancel (encoder);
+		_rb_encoder_emit_error (encoder, error);
+		g_error_free (error);
+		rb_encoder_gst_emit_completed (RB_ENCODER_GST (encoder));
+	}
+
+	return result;
+}
--- /dev/null	2006-03-24 05:28:51.000000000 +1100
+++ backends/gstreamer/Makefile.am	2006-03-23 13:35:38.000000000 +1100
@@ -0,0 +1,27 @@
+## arch-tag: Automake rules for gstreamer backend library
+
+noinst_LTLIBRARIES = librbbackendsgstreamer.la
+
+librbbackendsgstreamer_la_SOURCES =	\
+	rb-encoder-gst.h		\
+	rb-encoder-gst.c
+
+librbbackendsgstreamer_la_LIBADD =				\
+	$(RHYTHMBOX_LIBS)
+
+librbbackendsgstreamer_la_LDFLAGS = -export-dynamic
+
+INCLUDES = 						\
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"        \
+	-DG_LOG_DOMAIN=\"Rhythmbox\"			\
+	-I$(top_srcdir) 				\
+	-I$(top_srcdir)/lib 				\
+	-I$(top_srcdir)/metadata			\
+	-I$(top_srcdir)/sources				\
+	-I$(top_srcdir)/rhythmdb			\
+	-I$(top_srcdir)/backends			\
+	-I$(top_srcdir)/widgets				\
+	$(LIBJUICER_CFLAGS)				\
+	$(RHYTHMBOX_CFLAGS)
+
+
--- /dev/null	2006-03-24 05:28:51.000000000 +1100
+++ backends/gstreamer/rb-encoder-gst.h	2006-03-23 13:35:38.000000000 +1100
@@ -0,0 +1,56 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * arch-tag: Interface to audio encoder backend  
+ *
+ * Copyright (C) 2006 James Livingston <jrl@ids.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __RB_ENCODER_GST_H__
+#define __RB_ENCODER_GST_H__
+
+#include <glib-object.h>
+
+#include "rb-encoder.h"
+
+G_BEGIN_DECLS
+
+
+#define RB_TYPE_ENCODER_GST            (rb_encoder_gst_get_type ())
+#define RB_ENCODER_GST(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), RB_TYPE_ENCODER, RBEncoderGst))
+#define RB_IS_ENCODER_GST(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RB_TYPE_ENCODER))
+
+typedef struct _RBEncoderGstPrivate RBEncoderGstPrivate;
+
+typedef struct
+{
+	GObjectClass obj_class;
+} RBEncoderGstClass;
+
+typedef struct
+{
+	GObject obj;
+	RBEncoderGstPrivate *priv;
+} RBEncoderGst;
+
+RBEncoder*	rb_encoder_gst_new		(void);
+GType rb_encoder_gst_get_type (void);
+
+
+G_END_DECLS
+
+#endif /* __RB_ENCODER_GST_H__ */
--- /dev/null	2006-03-24 05:28:51.000000000 +1100
+++ backends/rb-encoder.c	2006-03-23 13:35:38.000000000 +1100
@@ -0,0 +1,145 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ *  Copyright (C) 2006  James Livingston  <jrl@ids.org.au>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include <config.h>
+
+#include "rb-encoder.h"
+#include "rb-encoder-gst.h"
+
+/* Signals */
+enum {
+	PROGRESS,
+	COMPLETED,
+	ERROR,
+	LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+static void
+rb_encoder_interface_init (RBEncoderIface *iface)
+{
+	signals[PROGRESS] =
+		g_signal_new ("progress",
+			      G_TYPE_FROM_INTERFACE (iface),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBEncoderIface, progress),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__DOUBLE,
+			      G_TYPE_NONE,
+			      1, G_TYPE_DOUBLE);
+	signals[COMPLETED] =
+		g_signal_new ("completed",
+			      G_TYPE_FROM_INTERFACE (iface),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBEncoderIface, completed),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__VOID,
+			      G_TYPE_NONE,
+			      0);
+	signals[ERROR] =
+		g_signal_new ("error",
+			      G_TYPE_FROM_INTERFACE (iface),
+			      G_SIGNAL_RUN_LAST,
+			      G_STRUCT_OFFSET (RBEncoderIface, error),
+			      NULL, NULL,
+			      g_cclosure_marshal_VOID__POINTER,
+			      G_TYPE_NONE,
+			      1, G_TYPE_POINTER);
+
+}
+
+GType
+rb_encoder_get_type (void)
+{
+	static GType our_type = 0;
+
+	if (!our_type) {
+		static const GTypeInfo our_info = {
+			sizeof (RBEncoderIface),
+			NULL,	/* base_init */
+			NULL,	/* base_finalize */
+			(GClassInitFunc)rb_encoder_interface_init,
+			NULL,	/* class_finalize */
+			NULL,	/* class_data */
+			0,
+			0,
+			NULL
+		};
+
+		our_type = g_type_register_static (G_TYPE_INTERFACE, "RBEncoder", &our_info, 0);
+	}
+
+	return our_type;
+}
+
+
+gboolean
+rb_encoder_encode (RBEncoder *encoder,
+		   RhythmDBEntry *entry,
+		   const char *dest,
+		   const char *mime_type)
+{
+	RBEncoderIface *iface = RB_ENCODER_GET_IFACE (encoder);
+
+	return iface->encode (encoder, entry, dest, mime_type);	  	 
+}
+	
+void
+rb_encoder_cancel (RBEncoder *encoder)
+{
+	RBEncoderIface *iface = RB_ENCODER_GET_IFACE (encoder);
+
+	iface->cancel (encoder);	  	 
+}
+
+RBEncoder*
+rb_encoder_new (void)
+{
+	return rb_encoder_gst_new ();
+}
+
+void
+_rb_encoder_emit_progress (RBEncoder *encoder, double fraction)
+{
+	g_signal_emit (encoder, signals[PROGRESS], 0, fraction);
+}
+
+void
+_rb_encoder_emit_completed (RBEncoder *encoder)
+{
+	g_signal_emit (encoder, signals[COMPLETED], 0);
+}
+
+void
+_rb_encoder_emit_error (RBEncoder *encoder, GError *error)
+{
+	g_signal_emit (encoder, signals[ERROR], 0, error);
+}
+
+GQuark
+rb_encoder_error_quark (void)
+{
+	static GQuark quark = 0;
+	if (!quark)
+		quark = g_quark_from_static_string ("rb_encoder_error");
+
+	return quark;
+}
--- /dev/null	2006-03-24 05:28:51.000000000 +1100
+++ backends/rb-encoder.h	2006-03-23 13:35:38.000000000 +1100
@@ -0,0 +1,83 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
+/*
+ * arch-tag: Interface to audio encoder backend  
+ *
+ * Copyright (C) 2006 James Livingston <jrl@ids.org.au>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __RB_ENCODER_H__
+#define __RB_ENCODER_H__
+
+#include <glib-object.h>
+
+#include "rhythmdb.h"
+
+G_BEGIN_DECLS
+
+#define RB_TYPE_ENCODER            (rb_encoder_get_type ())
+#define RB_ENCODER(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), RB_TYPE_ENCODER, RBEncoder))
+#define RB_IS_ENCODER(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), RB_TYPE_ENCODER))
+#define RB_ENCODER_GET_IFACE(obj)  (G_TYPE_INSTANCE_GET_INTERFACE ((obj), RB_TYPE_ENCODER, RBEncoderIface))
+
+
+enum
+{
+	RB_ENCODER_ERROR_FORMAT_UNSUPPORTED,
+	RB_ENCODER_ERROR_INTERNAL,
+};
+
+#define RB_ENCODER_ERROR rb_encoder_error_quark ()
+
+GQuark rb_encoder_error_quark (void);
+
+typedef struct _RBEncoder RBEncoder;
+
+typedef struct
+{
+	GTypeInterface g_iface;
+
+	/* vtable */
+	gboolean	(*encode)	(RBEncoder *encoder,
+					 RhythmDBEntry *entry,
+					 const char *dest,
+					 const char *mime_type);
+	void		(*cancel)	(RBEncoder *encoder);
+
+	/* signals */
+	void (*progress) (RBEncoder *encoder,  double fraction);
+	void (*completed) (RBEncoder *encoder);
+	void (*error) (RBEncoder *encoder, GError *error);
+} RBEncoderIface;
+
+RBEncoder*	rb_encoder_new		(void);
+GType rb_encoder_get_type (void);
+
+gboolean	rb_encoder_encode	(RBEncoder *encoder,
+					 RhythmDBEntry *entry,
+					 const char *dest,
+					 const char *mime_type);
+void		rb_encoder_cancel	(RBEncoder *encoder);
+
+/* obly to be used by subclasses */
+void	_rb_encoder_emit_progress (RBEncoder *encoder, double fraction);
+void	_rb_encoder_emit_completed (RBEncoder *encoder);
+void	_rb_encoder_emit_error (RBEncoder *encoder, GError *error);
+
+G_END_DECLS
+
+#endif /* __RB_ENCODER_H__ */
--- /dev/null	2006-03-24 05:28:51.000000000 +1100
+++ backends/Makefile.am	2006-03-23 13:35:38.000000000 +1100
@@ -0,0 +1,29 @@
+## arch-tag: Automake rules for backends library
+
+noinst_LTLIBRARIES = librbbackends.la
+
+SUBDIRS = gstreamer
+
+librbbackends_la_SOURCES =	\
+	rb-encoder.h 		\
+	rb-encoder.c
+
+librbbackends_la_LIBADD =				\
+	$(RHYTHMBOX_LIBS)				\
+	$(top_builddir)/backends/gstreamer/librbbackendsgstreamer.la
+
+librbbackends_la_LDFLAGS = -export-dynamic
+
+INCLUDES = 						\
+	-DGNOMELOCALEDIR=\""$(datadir)/locale"\"        \
+	-DG_LOG_DOMAIN=\"Rhythmbox\"			\
+	-I$(top_srcdir) 				\
+	-I$(top_srcdir)/lib 				\
+	-I$(top_srcdir)/metadata			\
+	-I$(top_srcdir)/shell				\
+	-I$(top_srcdir)/rhythmdb			\
+	-I$(top_srcdir)/widgets				\
+	-I$(top_srcdir)/backends/gstreamer		\
+	$(LIBNAUTILUS_BURN_CFLAGS)			\
+	$(RHYTHMBOX_CFLAGS)
+
