Index: rhythmdb/rhythmdb-tree.c
===================================================================
--- rhythmdb/rhythmdb-tree.c	(revision 4975)
+++ rhythmdb/rhythmdb-tree.c	(working copy)
@@ -1010,11 +1010,13 @@ save_entry (RhythmDBTree *db,
 			for (l = keywords; l != NULL; l = g_list_next (l)) {
 				RBRefString *keyword = (RBRefString*)l->data;
 
-				RHYTHMDB_FWRITE_STATICSTR ("    <keyword>", ctx->handle, ctx->error);
-				encoded	= xmlEncodeEntitiesReentrant (NULL, BAD_CAST rb_refstring_get (keyword));
-				RHYTHMDB_FWRITE (encoded, 1, xmlStrlen (encoded), ctx->handle, ctx->error);
-				g_free (encoded);
-				RHYTHMDB_FWRITE_STATICSTR ("</keyword>\n", ctx->handle, ctx->error);
+				if ((rb_refstring_get (keyword))[0] != '!') {
+					RHYTHMDB_FWRITE_STATICSTR ("    <keyword>", ctx->handle, ctx->error);
+					encoded	= xmlEncodeEntitiesReentrant (NULL, BAD_CAST rb_refstring_get (keyword));
+					RHYTHMDB_FWRITE (encoded, 1, xmlStrlen (encoded), ctx->handle, ctx->error);
+					g_free (encoded);
+					RHYTHMDB_FWRITE_STATICSTR ("</keyword>\n", ctx->handle, ctx->error);
+				}
 
 				rb_refstring_unref (keyword);
 			}
Index: sources/rb-playlist-source.c
===================================================================
--- sources/rb-playlist-source.c	(revision 4975)
+++ sources/rb-playlist-source.c	(working copy)
@@ -101,7 +101,6 @@ struct RBPlaylistSourcePrivate
 	RhythmDB *db;
 
 	GHashTable *entries;
-
 	RhythmDBQueryModel *model;
 
 	RBEntryView *songs;
@@ -111,6 +110,7 @@ struct RBPlaylistSourcePrivate
 	gboolean dispose_has_run;
 
 	char *title;
+	RBRefString *present_keyword;
 };
 
 #define RB_PLAYLIST_SOURCE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_PLAYLIST_SOURCE, RBPlaylistSourcePrivate))
@@ -125,6 +125,8 @@ enum
 
 static const GtkTargetEntry target_uri [] = { { "text/uri-list", 0, 0 } };
 
+static gint current_playlist_id = 0;
+
 G_DEFINE_ABSTRACT_TYPE (RBPlaylistSource, rb_playlist_source, RB_TYPE_SOURCE);
 
 static void
@@ -183,7 +185,19 @@ rb_playlist_source_class_init (RBPlaylis
 static void
 rb_playlist_source_init (RBPlaylistSource *source)
 {
+	char *keyword;
+	gint id;
+
 	source->priv = RB_PLAYLIST_SOURCE_GET_PRIVATE (source);
+
+	source->priv->entries = g_hash_table_new_full (rb_refstring_hash, rb_refstring_equal,
+						       (GDestroyNotify)rb_refstring_unref, NULL);
+
+	id = current_playlist_id++;
+	keyword = g_strdup_printf ("!rb:playlist:present:%d", id);
+	rb_debug ("playlist %p has present-keyword of %s", source, keyword);
+	source->priv->present_keyword = rb_refstring_new (keyword);
+	g_free (keyword);
 }
 
 static void
@@ -216,13 +230,10 @@ rb_playlist_source_constructor (GType ty
 {
 	GObject *shell_player;
 	RBPlaylistSource *source;
-	RBPlaylistSourceClass *klass;
 	RBShell *shell;
 	RhythmDB *db;
 	RhythmDBQueryModel *query_model;
 
-	klass = RB_PLAYLIST_SOURCE_CLASS (g_type_class_peek (RB_TYPE_PLAYLIST_SOURCE));
-
 	source = RB_PLAYLIST_SOURCE (G_OBJECT_CLASS (rb_playlist_source_parent_class)->
 			constructor (type, n_construct_properties, construct_properties));
 
@@ -233,9 +244,6 @@ rb_playlist_source_constructor (GType ty
 	g_object_unref (db);
 	g_object_unref (shell);
 
-	source->priv->entries = g_hash_table_new_full (rb_refstring_hash, rb_refstring_equal,
-						       (GDestroyNotify)rb_refstring_unref, NULL);
-
 	source->priv->songs = rb_entry_view_new (source->priv->db,
 						 shell_player,
 					 	 NULL, TRUE, TRUE);
@@ -339,6 +347,7 @@ rb_playlist_source_finalize (GObject *ob
 	rb_debug ("Finalizing playlist source %p", source);
 
 	g_hash_table_destroy (source->priv->entries);
+	rb_refstring_unref (source->priv->present_keyword);
 
 	g_free (source->priv->title);
 	source->priv = NULL;
@@ -701,12 +710,29 @@ rb_playlist_source_row_deleted (GtkTreeM
 	location = rhythmdb_entry_get_refstring (entry, RHYTHMDB_PROP_LOCATION);
 	if (g_hash_table_remove (source->priv->entries, location))
 		source->priv->dirty = TRUE;
-
 	rb_refstring_unref (location);
+
+	rhythmdb_entry_keyword_remove (source->priv->db, entry, source->priv->present_keyword);
+
 	rhythmdb_entry_unref (entry);
 }
 
 static void
+rb_playlist_source_row_inserted (GtkTreeModel *model,
+				GtkTreePath *path,
+				GtkTreeIter *iter,
+				RBPlaylistSource *source)
+{
+	RhythmDBEntry *entry;
+
+	entry = rhythmdb_query_model_tree_path_to_entry (RHYTHMDB_QUERY_MODEL (model),
+							 path);
+
+	rhythmdb_entry_keyword_add (source->priv->db, entry, source->priv->present_keyword);
+
+	rhythmdb_entry_unref (entry);
+}
+static void
 rb_playlist_source_entry_added_cb (RhythmDB *db,
 				   RhythmDBEntry *entry,
 				   RBPlaylistSource *source)
@@ -775,6 +801,9 @@ rb_playlist_source_set_query_model (RBPl
 		g_signal_handlers_disconnect_by_func (source->priv->model,
 						      G_CALLBACK (rb_playlist_source_row_deleted),
 						      source);
+		g_signal_handlers_disconnect_by_func (source->priv->model,
+						      G_CALLBACK (rb_playlist_source_row_inserted),
+						      source);
 		g_object_unref (source->priv->model);
 	}
 
@@ -782,8 +811,10 @@ rb_playlist_source_set_query_model (RBPl
 
 	if (source->priv->model != NULL) {
 		g_object_ref (source->priv->model);
-		g_signal_connect_object (source->priv->model, "row_deleted",
+		g_signal_connect_object (source->priv->model, "row-deleted",
 					 G_CALLBACK (rb_playlist_source_row_deleted), source, 0);
+		g_signal_connect_object (source->priv->model, "row-inserted",
+					 G_CALLBACK (rb_playlist_source_row_inserted), source, 0);
 	}
 
 	rb_entry_view_set_model (source->priv->songs, RHYTHMDB_QUERY_MODEL (source->priv->model));
