diff --git a/plugins/audiocd/Makefile.am b/plugins/audiocd/Makefile.am
index 37b2302..04cf0dc 100644
--- a/plugins/audiocd/Makefile.am
+++ b/plugins/audiocd/Makefile.am
@@ -53,7 +53,9 @@ libaudiocd_la_LIBADD += $(NULL)
 
 
 gtkbuilderdir = $(plugindir)
-gtkbuilder_DATA = multiple-album.ui
+gtkbuilder_DATA = 					\
+	album-info.ui					\
+	multiple-album.ui
 
 uixmldir = $(plugindir)
 uixml_DATA = audiocd-ui.xml
diff --git a/plugins/audiocd/album-info.ui b/plugins/audiocd/album-info.ui
new file mode 100644
index 0000000..471f0f3
--- /dev/null
+++ b/plugins/audiocd/album-info.ui
@@ -0,0 +1,196 @@
+<?xml version="1.0"?>
+<interface>
+  <!-- interface-requires gtk+ 2.12 -->
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkTable" id="album_info">
+    <property name="visible">True</property>
+    <property name="border_width">6</property>
+    <property name="n_rows">4</property>
+    <property name="n_columns">2</property>
+    <property name="column_spacing">12</property>
+    <property name="row_spacing">6</property>
+    <child>
+      <object class="GtkLabel" id="album_label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">A_lbum:</property>
+        <property name="use_markup">True</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">album_entry</property>
+      </object>
+      <packing>
+        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+        <property name="y_options"></property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="artist_label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Artist:</property>
+        <property name="use_markup">True</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">artist_entry</property>
+      </object>
+      <packing>
+        <property name="top_attach">1</property>
+        <property name="bottom_attach">2</property>
+        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+        <property name="y_options"></property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="album_entry">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">&#x25CF;</property>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="hbox1">
+        <property name="visible">True</property>
+        <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+        <property name="spacing">12</property>
+        <child>
+          <object class="GtkEntry" id="genre_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">&#x25CF;</property>
+          </object>
+          <packing>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="year_label">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">_Year:</property>
+            <property name="use_markup">True</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">year_entry</property>
+            <accessibility>
+              <relation type="label-for" target="year_entry"/>
+            </accessibility>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="year_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="max_length">4</property>
+            <property name="invisible_char">&#x25CF;</property>
+            <property name="width_chars">4</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkLabel" id="disc_number_label">
+            <property name="visible">True</property>
+            <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
+            <property name="xalign">0</property>
+            <property name="label" translatable="yes">_Disc:</property>
+            <property name="use_markup">True</property>
+            <property name="use_underline">True</property>
+            <property name="mnemonic_widget">disc_number_entry</property>
+            <accessibility>
+              <relation type="label-for" target="disc_number_entry"/>
+            </accessibility>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkEntry" id="disc_number_entry">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="invisible_char">&#x25CF;</property>
+            <property name="width_chars">2</property>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="position">4</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="left_attach">1</property>
+        <property name="right_attach">2</property>
+        <property name="top_attach">3</property>
+        <property name="bottom_attach">4</property>
+        <property name="x_options">GTK_FILL</property>
+        <property name="y_options">GTK_SHRINK | GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="genre_label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">_Genre:</property>
+        <property name="use_markup">True</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">genre_entry</property>
+      </object>
+      <packing>
+        <property name="top_attach">3</property>
+        <property name="bottom_attach">4</property>
+        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkLabel" id="artist_sort_label">
+        <property name="visible">True</property>
+        <property name="xalign">0</property>
+        <property name="label" translatable="yes">Artist s_ort order:</property>
+        <property name="use_markup">True</property>
+        <property name="use_underline">True</property>
+        <property name="mnemonic_widget">artist_sort_entry</property>
+      </object>
+      <packing>
+        <property name="top_attach">2</property>
+        <property name="bottom_attach">3</property>
+        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="artist_sort_entry">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">&#x25CF;</property>
+      </object>
+      <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>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkEntry" id="artist_entry">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="invisible_char">&#x25CF;</property>
+      </object>
+      <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>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/plugins/audiocd/rb-audiocd-source.c b/plugins/audiocd/rb-audiocd-source.c
index ef57800..3b0587e 100644
--- a/plugins/audiocd/rb-audiocd-source.c
+++ b/plugins/audiocd/rb-audiocd-source.c
@@ -56,9 +56,18 @@
 #include "sj-structures.h"
 #endif
 
+enum
+{
+	PROP_0,
+	PROP_SEARCH_TYPE
+};
+
 static void rb_audiocd_source_dispose (GObject *object);
+static void rb_audiocd_source_finalize (GObject *object);
 static GObject *rb_audiocd_source_constructor (GType type, guint n_construct_properties,
 					        GObjectConstructParam *construct_properties);
+static void impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
+static void impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
 
 static gboolean impl_show_popup (RBSource *source);
 static guint impl_want_uri (RBSource *source, const char *uri);
@@ -67,10 +76,21 @@ static gboolean impl_uri_is_source (RBSource *source, const char *uri);
 static void impl_delete_thyself (RBSource *source);
 static GList* impl_get_ui_actions (RBSource *source);
 
+static void impl_pack_paned (RBBrowserSource *source, GtkWidget *paned);
+
 static gpointer rb_audiocd_load_songs (RBAudioCdSource *source);
 static void rb_audiocd_load_metadata (RBAudioCdSource *source, RhythmDB *db);
 static void rb_audiocd_load_metadata_cancel (RBAudioCdSource *source);
 
+static void metadata_gather_cb (RhythmDB *db, RhythmDBEntry *entry, RBStringValueMap *data, RBAudioCdSource *source);
+static GValue *album_artist_metadata_request_cb (RhythmDB *db, RhythmDBEntry *entry, RBAudioCdSource *source);
+static GValue *album_artist_sortname_metadata_request_cb (RhythmDB *db, RhythmDBEntry *entry, RBAudioCdSource *source);
+
+static gboolean update_album_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
+static gboolean update_genre_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
+static gboolean update_year_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
+static gboolean update_disc_number_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source);
+
 typedef struct
 {
 	gchar *device_path;
@@ -80,6 +100,14 @@ typedef struct
 	GstElement *cdda;
 	GstElement *fakesink;
 
+	GtkWidget *box;
+	GtkWidget *artist_entry;
+	GtkWidget *artist_sort_entry;
+	GtkWidget *album_entry;
+	GtkWidget *year_entry;
+	GtkWidget *genre_entry;
+	GtkWidget *disc_number_entry;
+
 #ifdef HAVE_SJ_METADATA_GETTER
 	SjMetadataGetter *metadata;
 #endif
@@ -91,14 +119,33 @@ RB_PLUGIN_DEFINE_TYPE (RBAudioCdSource, rb_audiocd_source, RB_TYPE_REMOVABLE_MED
 #ifdef HAVE_SJ_METADATA_GETTER
 static AlbumDetails* multiple_album_dialog (GList *albums, RBAudioCdSource *source);
 #endif
+
+static RhythmDB *
+get_db_for_source (RBAudioCdSource *source)
+{
+	RBShell *shell;
+	RhythmDB *db;
+
+	g_object_get (source, "shell", &shell, NULL);
+	g_object_get (shell, "db", &db, NULL);
+	g_object_unref (shell);
+
+	return db;
+}
+
+
 static void
 rb_audiocd_source_class_init (RBAudioCdSourceClass *klass)
 {
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	RBSourceClass *source_class = RB_SOURCE_CLASS (klass);
+	RBBrowserSourceClass *browser_source_class = RB_BROWSER_SOURCE_CLASS (klass);
 
 	object_class->constructor = rb_audiocd_source_constructor;
 	object_class->dispose = rb_audiocd_source_dispose;
+	object_class->finalize = rb_audiocd_source_finalize;
+	object_class->set_property = impl_set_property;
+	object_class->get_property = impl_get_property;
 
 	/* don't bother showing the browser/search bits */
 	source_class->impl_can_browse = (RBSourceFeatureFunc) rb_false_function;
@@ -113,17 +160,23 @@ rb_audiocd_source_class_init (RBAudioCdSourceClass *klass)
 	source_class->impl_try_playlist = (RBSourceFeatureFunc) rb_true_function;	/* shouldn't need this. */
 	source_class->impl_want_uri = impl_want_uri;
 
+	/* add the browser below the album info section */
+	browser_source_class->impl_pack_paned = impl_pack_paned;
+
+	g_object_class_override_property (object_class,
+					  PROP_SEARCH_TYPE,
+					  "search-type");
+
 	g_type_class_add_private (klass, sizeof (RBAudioCdSourcePrivate));
 }
 
 static void
 rb_audiocd_source_init (RBAudioCdSource *self)
 {
-
 }
 
 static void
-rb_audiocd_source_dispose (GObject *object)
+rb_audiocd_source_finalize (GObject *object)
 {
 	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (object);
 
@@ -133,6 +186,15 @@ rb_audiocd_source_dispose (GObject *object)
 		g_list_free (priv->tracks);
 		priv->tracks = NULL;
 	}
+
+	G_OBJECT_CLASS (rb_audiocd_source_parent_class)->finalize (object);
+}
+
+static void
+rb_audiocd_source_dispose (GObject *object)
+{
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (object);
+
 	if (priv->pipeline) {
 		gst_object_unref (GST_OBJECT (priv->pipeline));
 		priv->pipeline = NULL;
@@ -148,6 +210,9 @@ rb_audiocd_source_constructor (GType type,
 {
 	RBAudioCdSource *source;
 	RBEntryView *entry_view;
+	RhythmDB *db;
+	RBPlugin *plugin;
+	char *ui_file;
 
 	source = RB_AUDIOCD_SOURCE (G_OBJECT_CLASS (rb_audiocd_source_parent_class)->
 			constructor (type, n_construct_properties, construct_properties));
@@ -158,6 +223,63 @@ rb_audiocd_source_constructor (GType type,
 	entry_view = rb_source_get_entry_view (RB_SOURCE (source));
 	rb_entry_view_set_sorting_order (entry_view, "Track", GTK_SORT_ASCENDING);
 
+	/* hide the 'album' column */
+	gtk_tree_view_column_set_visible (rb_entry_view_get_column (entry_view, RB_ENTRY_VIEW_COL_ALBUM), FALSE);
+
+	/* handle extra metadata requests for album artist and album artist sortname */
+	db = get_db_for_source (source);
+	g_signal_connect_object (G_OBJECT (db), "entry-extra-metadata-request::" RHYTHMDB_PROP_ALBUM_ARTIST,
+				 G_CALLBACK (album_artist_metadata_request_cb), source, 0);
+	g_signal_connect_object (G_OBJECT (db), "entry-extra-metadata-request::" RHYTHMDB_PROP_ALBUM_ARTIST_SORTNAME,
+				 G_CALLBACK (album_artist_sortname_metadata_request_cb), source, 0);
+	g_signal_connect_object (G_OBJECT (db), "entry-extra-metadata-gather",
+				 G_CALLBACK (metadata_gather_cb), source, 0);
+	g_object_unref (db);
+
+	/* set up the album info widgets */
+	g_object_get (source, "plugin", &plugin, NULL);
+	ui_file = rb_plugin_find_file (plugin, "album-info.ui");
+	g_object_unref (plugin);
+
+	if (ui_file == NULL) {
+		g_warning ("couldn't find album-info.ui");
+	} else {
+		RBAudioCdSourcePrivate *priv;
+		GtkWidget *table;
+		GtkBuilder *builder;
+
+		priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+
+		builder = rb_builder_load (ui_file, NULL);
+		g_free (ui_file);
+
+		table = GTK_WIDGET (gtk_builder_get_object (builder, "album_info"));
+		g_assert (table != NULL);
+
+		rb_builder_boldify_label (builder, "artist_label");
+		rb_builder_boldify_label (builder, "artist_sort_label");
+		rb_builder_boldify_label (builder, "album_label");
+		rb_builder_boldify_label (builder, "year_label");
+		rb_builder_boldify_label (builder, "genre_label");
+		rb_builder_boldify_label (builder, "disc_number_label");
+
+		priv->artist_entry = GTK_WIDGET (gtk_builder_get_object (builder, "artist_entry"));
+		priv->artist_sort_entry = GTK_WIDGET (gtk_builder_get_object (builder, "artist_sort_entry"));
+		priv->album_entry = GTK_WIDGET (gtk_builder_get_object (builder, "album_entry"));
+		priv->year_entry = GTK_WIDGET (gtk_builder_get_object (builder, "year_entry"));
+		priv->genre_entry = GTK_WIDGET (gtk_builder_get_object (builder, "genre_entry"));
+		priv->disc_number_entry = GTK_WIDGET (gtk_builder_get_object (builder, "disc_number_entry"));
+
+		g_signal_connect_object (priv->album_entry, "focus-out-event", G_CALLBACK (update_album_cb), source, 0);
+		g_signal_connect_object (priv->genre_entry, "focus-out-event", G_CALLBACK (update_genre_cb), source, 0);
+		g_signal_connect_object (priv->year_entry, "focus-out-event", G_CALLBACK (update_year_cb), source, 0);
+		g_signal_connect_object (priv->disc_number_entry, "focus-out-event", G_CALLBACK (update_disc_number_cb), source, 0);
+
+		gtk_box_pack_start (GTK_BOX (priv->box), table, FALSE, FALSE, 0);
+		gtk_box_reorder_child (GTK_BOX (priv->box), table, 0);
+		g_object_unref (builder);
+	}
+
 	g_object_ref (G_OBJECT (source));
 	g_thread_create ((GThreadFunc)rb_audiocd_load_songs, source, FALSE, NULL);
 
@@ -204,6 +326,43 @@ rb_audiocd_source_new (RBPlugin *plugin,
 }
 
 static void
+impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	case PROP_SEARCH_TYPE:
+		/* ignored */
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
+{
+	switch (prop_id) {
+	case PROP_SEARCH_TYPE:
+		g_value_set_enum (value, RB_SOURCE_SEARCH_NONE);
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+		break;
+	}
+}
+
+static void
+impl_pack_paned (RBBrowserSource *source, GtkWidget *paned)
+{
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+
+	priv->box = gtk_vbox_new (FALSE, 6);
+	gtk_widget_show_all (priv->box);
+	gtk_container_add (GTK_CONTAINER (source), priv->box);
+	gtk_box_pack_start (GTK_BOX (priv->box), paned, TRUE, TRUE, 0);
+}
+
+static void
 entry_set_string_prop (RhythmDB *db,
 		       RhythmDBEntry *entry,
 		       gboolean is_inserted,
@@ -357,19 +516,6 @@ rb_audiocd_scan_songs (RBAudioCdSource *source,
 	return ok;
 }
 
-static RhythmDB *
-get_db_for_source (RBAudioCdSource *source)
-{
-	RBShell *shell;
-	RhythmDB *db;
-
-  	g_object_get (source, "shell", &shell, NULL);
-  	g_object_get (shell, "db", &db, NULL);
-  	g_object_unref (shell);
-
-        return db;
-}
-
 #ifdef HAVE_SJ_METADATA_GETTER
 
 /*
@@ -538,7 +684,37 @@ metadata_cb (SjMetadataGetter *metadata,
 		return;
 	}
 
+	if (album->artist != NULL) {
+		gtk_entry_set_text (GTK_ENTRY (priv->artist_entry), album->artist);
+	}
+	if (album->artist_sortname != NULL) {
+		gtk_entry_set_text (GTK_ENTRY (priv->artist_sort_entry), album->artist_sortname);
+	}
+	if (album->title != NULL) {
+		gtk_entry_set_text (GTK_ENTRY (priv->album_entry), album->title);
+	}
+	if (album->release_date != NULL) {
+		char *year;
+		year = g_strdup_printf ("%d", g_date_get_year (album->release_date));
+		gtk_entry_set_text (GTK_ENTRY (priv->year_entry), year);
+		g_free (year);
+	}
+	if (album->disc_number != 0) {
+		char *num;
+		num = g_strdup_printf ("%d", album->disc_number);
+		gtk_entry_set_text (GTK_ENTRY (priv->disc_number_entry), num);
+		g_free (num);
+	}
+	if (album->genre != NULL) {
+		gtk_entry_set_text (GTK_ENTRY (priv->genre_entry), album->genre);
+	}
+
 	g_object_set (G_OBJECT (source), "name", album->title, NULL);
+	rb_debug ("musicbrainz_albumid: %s", album->album_id);
+	rb_debug ("musicbrainz_albumartistid: %s", album->artist_id);
+	rb_debug ("album artist: %s", album->artist);
+	rb_debug ("disc number: %d", album->disc_number);
+	rb_debug ("genre: %s", album->genre);
 
 	while (album->tracks && cd_track) {
 		TrackDetails *track = (TrackDetails*)album->tracks->data;
@@ -547,12 +723,9 @@ metadata_cb (SjMetadataGetter *metadata,
 
 		rb_debug ("storing metadata for %s - %s - %s", track->artist, album->title, track->title);
 
-		rb_debug ("genre: %s", album->genre);
 		rb_debug ("musicbrainz_trackid: %s", track->track_id);
 		rb_debug ("musicbrainz_artistid: %s", track->artist_id);
-		rb_debug ("musicbrainz_albumid: %s", album->album_id);
-		rb_debug ("musicbrainz_albumartistid: %s", album->artist_id);
-		rb_debug ("album sortname: %s", album->artist_sortname);
+		rb_debug ("artist sortname: %s", track->artist_sortname);
 
 		/* record track info in entry*/
 		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_TITLE, track->title);
@@ -563,13 +736,20 @@ metadata_cb (SjMetadataGetter *metadata,
 		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_MUSICBRAINZ_ARTISTID, track->artist_id);
 		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_MUSICBRAINZ_ALBUMID, album->album_id);
 		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_MUSICBRAINZ_ALBUMARTISTID, album->artist_id);
-		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_ARTIST_SORTNAME, album->artist_sortname);
+		entry_set_string_prop (db, entry, TRUE, RHYTHMDB_PROP_ARTIST_SORTNAME, track->artist_sortname);
 
 		g_value_init (&value, G_TYPE_ULONG);
 		g_value_set_ulong (&value, track->duration);
 		rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_DURATION, &value);
 		g_value_unset (&value);
 
+		if (album->disc_number != 0) {
+			g_value_init (&value, G_TYPE_ULONG);
+			g_value_set_ulong (&value, album->disc_number);
+			rhythmdb_entry_set (db, entry, RHYTHMDB_PROP_DISC_NUMBER, &value);
+			g_value_unset (&value);
+		}
+
 		/*album->release_date (could potentially have multiple values)*/
 		/* in current sj-structures.h, however, it does not */
 
@@ -810,3 +990,140 @@ impl_uri_is_source (RBSource *source, const char *uri)
 	return FALSE;
 }
 
+static void
+metadata_gather_cb (RhythmDB *db, RhythmDBEntry *entry, RBStringValueMap *data, RBAudioCdSource *source)
+{
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+	GValue value = {0,};
+
+	if (_rb_source_check_entry_type (RB_SOURCE (source), entry) == FALSE) {
+		return;
+	}
+
+	if (gtk_entry_get_text_length (GTK_ENTRY (priv->artist_entry)) > 0) {
+		g_value_init (&value, G_TYPE_STRING);
+		g_value_set_string (&value, gtk_entry_get_text (GTK_ENTRY (priv->artist_entry)));
+		rb_string_value_map_set (data, RHYTHMDB_PROP_ALBUM_ARTIST, &value);
+		g_value_unset (&value);
+	}
+
+	if (gtk_entry_get_text_length (GTK_ENTRY (priv->artist_sort_entry)) > 0) {
+		g_value_init (&value, G_TYPE_STRING);
+		g_value_set_string (&value, gtk_entry_get_text (GTK_ENTRY (priv->artist_sort_entry)));
+		rb_string_value_map_set (data, RHYTHMDB_PROP_ALBUM_ARTIST_SORTNAME, &value);
+		g_value_unset (&value);
+	}
+}
+
+
+static GValue *
+album_artist_metadata_request_cb (RhythmDB *db, RhythmDBEntry *entry, RBAudioCdSource *source)
+{
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+	GValue *value = NULL;
+
+	if (_rb_source_check_entry_type (RB_SOURCE (source), entry) == FALSE) {
+		return NULL;
+	}
+
+	if (gtk_entry_get_text_length (GTK_ENTRY (priv->artist_entry)) > 0) {
+		value = g_new0 (GValue, 1);
+		g_value_init (value, G_TYPE_STRING);
+		g_value_set_string (value, gtk_entry_get_text (GTK_ENTRY (priv->artist_entry)));
+	}
+
+	return value;
+}
+
+static GValue *
+album_artist_sortname_metadata_request_cb (RhythmDB *db, RhythmDBEntry *entry, RBAudioCdSource *source)
+{
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+	GValue *value = NULL;
+
+	if (_rb_source_check_entry_type (RB_SOURCE (source), entry) == FALSE) {
+		return NULL;
+	}
+
+	if (gtk_entry_get_text_length (GTK_ENTRY (priv->artist_sort_entry)) > 0) {
+		value = g_new0 (GValue, 1);
+		g_value_init (value, G_TYPE_STRING);
+		g_value_set_string (value, gtk_entry_get_text (GTK_ENTRY (priv->artist_sort_entry)));
+	}
+
+	return value;
+}
+
+static void
+update_tracks (RBAudioCdSource *source, RhythmDBPropType property, GValue *value)
+{
+	RBAudioCdSourcePrivate *priv = AUDIOCD_SOURCE_GET_PRIVATE (source);
+	RhythmDB *db;
+	GList *i;
+
+	db = get_db_for_source (source);
+
+	for (i = priv->tracks; i != NULL; i = i->next) {
+		rhythmdb_entry_set (db, i->data, property, value);
+	}
+
+	rhythmdb_commit (db);
+	g_object_unref (db);
+}
+
+static void
+update_tracks_string (RBAudioCdSource *source, RhythmDBPropType property, const char *str)
+{
+	GValue v = {0, };
+	g_value_init (&v, G_TYPE_STRING);
+	g_value_set_string (&v, str);
+	update_tracks (source, property, &v);
+	g_value_unset (&v);
+}
+
+static gboolean
+update_album_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source)
+{
+	update_tracks_string (source, RHYTHMDB_PROP_ALBUM, gtk_entry_get_text (GTK_ENTRY (widget)));
+	return FALSE;
+}
+
+static gboolean
+update_genre_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source)
+{
+	update_tracks_string (source, RHYTHMDB_PROP_GENRE, gtk_entry_get_text (GTK_ENTRY (widget)));
+	return FALSE;
+}
+
+static gboolean
+update_year_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source)
+{
+	int year;
+	GDate date;
+	GValue v = {0, };
+
+	year = strtol (gtk_entry_get_text (GTK_ENTRY (widget)), NULL, 10);
+	g_date_clear (&date, 1);
+	g_date_set_dmy (&date, 1, 1, year);
+
+	g_value_init (&v, G_TYPE_ULONG);
+	g_value_set_ulong (&v, g_date_get_julian (&date));
+	update_tracks (source, RHYTHMDB_PROP_DATE, &v);
+	g_value_unset (&v);
+
+	return FALSE;
+}
+
+static gboolean
+update_disc_number_cb (GtkWidget *widget, GdkEventFocus *event, RBAudioCdSource *source)
+{
+	GValue v = {0, };
+
+	g_value_init (&v, G_TYPE_ULONG);
+	g_value_set_ulong (&v, strtoul (gtk_entry_get_text (GTK_ENTRY (widget)), NULL, 10));
+	update_tracks (source, RHYTHMDB_PROP_DISC_NUMBER, &v);
+	g_value_unset (&v);
+
+	return FALSE;
+}
+
diff --git a/rhythmdb/rhythmdb.h b/rhythmdb/rhythmdb.h
index 039df15..3e0aa01 100644
--- a/rhythmdb/rhythmdb.h
+++ b/rhythmdb/rhythmdb.h
@@ -230,6 +230,8 @@ enum {
 #define RHYTHMDB_PROP_STREAM_SONG_ALBUM		"rb:stream-song-album"
 #define RHYTHMDB_PROP_COVER_ART			"rb:coverArt"
 #define RHYTHMDB_PROP_COVER_ART_URI		"rb:coverArt-uri"
+#define RHYTHMDB_PROP_ALBUM_ARTIST		"rb:album-artist"
+#define RHYTHMDB_PROP_ALBUM_ARTIST_SORTNAME	"rb:album-artist-sortname"
 
 GType rhythmdb_query_type_get_type (void);
 GType rhythmdb_prop_type_get_type (void);
diff --git a/sources/rb-library-source.c b/sources/rb-library-source.c
index 32bf8ab..4a00a9f 100644
--- a/sources/rb-library-source.c
+++ b/sources/rb-library-source.c
@@ -827,17 +827,30 @@ sanitize_pattern (const char *pat)
  * %tS -- track artist sortname (lowercase)
  */
 static char *
-filepath_parse_pattern (const char *pattern,
+filepath_parse_pattern (RhythmDB *db,
+			const char *pattern,
 			RhythmDBEntry *entry)
 {
 	/* p is the pattern iterator, i is a general purpose iterator */
 	const char *p;
 	char *temp;
 	GString *s;
+	GValue *value;
+	RBRefString *albumartist;
 
 	if (pattern == NULL || pattern[0] == 0)
 		return g_strdup (" ");
 
+	/* request album artist (this is sort of temporary) */
+	value = rhythmdb_entry_request_extra_metadata (db, entry, RHYTHMDB_PROP_ALBUM_ARTIST);
+	if (value != NULL) {
+		albumartist = rb_refstring_new (g_value_get_string (value));
+		g_value_unset (value);
+		g_free (value);
+	} else {
+		albumartist = rhythmdb_entry_get_refstring (entry, RHYTHMDB_PROP_ARTIST);
+	}
+
 	s = g_string_new (NULL);
 
 	p = pattern;
@@ -872,10 +885,10 @@ filepath_parse_pattern (const char *pattern,
 				string = 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));
+				string = sanitize_path (rb_refstring_get (albumartist));
 				break;
 			case 'A':
-				string = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST_FOLDED));
+				string = sanitize_path (rb_refstring_get_folded (albumartist));
 				break;
 			case 's':
 				string = sanitize_path (rhythmdb_entry_get_string (entry, RHYTHMDB_PROP_ARTIST_SORTNAME));
@@ -943,6 +956,7 @@ filepath_parse_pattern (const char *pattern,
 
 	temp = s->str;
 	g_string_free (s, FALSE);
+	rb_refstring_unref (albumartist);
 	return temp;
 }
 
@@ -980,8 +994,8 @@ layout_example_label_update (RBLibrarySource *source)
 	sample_entry = rhythmdb_entry_example_new (source->priv->db, entry_type, NULL);
 	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
 
-	file_value = filepath_parse_pattern (file_pattern, sample_entry);
-	path_value = filepath_parse_pattern (path_pattern, sample_entry);
+	file_value = filepath_parse_pattern (source->priv->db, file_pattern, sample_entry);
+	path_value = filepath_parse_pattern (source->priv->db, path_pattern, sample_entry);
 	rhythmdb_entry_unref (sample_entry);
 
 	example = g_build_filename (G_DIR_SEPARATOR_S, path_value, file_value, NULL);
@@ -1106,7 +1120,7 @@ build_filename (RBLibrarySource *source, RhythmDBEntry *entry)
 	g_free (layout_filename);
 	layout_filename = tmp;
 
-	realpath = filepath_parse_pattern (layout_path, entry);
+	realpath = filepath_parse_pattern (source->priv->db, layout_path, entry);
 
 	library_location = g_file_new_for_uri ((const char *)list->data);
 	dir = g_file_resolve_relative_path (library_location, realpath);
@@ -1140,7 +1154,7 @@ build_filename (RBLibrarySource *source, RhythmDBEntry *entry)
 			*tmp = '\0';
 	}
 
-	realfile = filepath_parse_pattern (layout_filename, entry);
+	realfile = filepath_parse_pattern (source->priv->db, layout_filename, entry);
 	if (extension) {
 		filename = g_strdup_printf ("%s.%s", realfile, extension);
 		g_free (realfile);
diff --git a/sources/rb-source.c b/sources/rb-source.c
index 2b5109f..f77dd01 100644
--- a/sources/rb-source.c
+++ b/sources/rb-source.c
@@ -325,7 +325,7 @@ rb_source_class_init (RBSourceClass *klass)
 						 	      "RBPlugin",
 							      "RBPlugin instance for the plugin that created the source",
 							      RB_TYPE_PLUGIN,
-							      G_PARAM_READWRITE));
+							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
 	/**
 	 * RBSource:base-query-model:
 	 *
