Index: rb-daap-connection.c
===================================================================
--- rb-daap-connection.c	(revision 5549)
+++ rb-daap-connection.c	(working copy)
@@ -47,6 +47,7 @@
 #include "rb-util.h"
 
 #define RB_DAAP_USER_AGENT "iTunes/4.6 (Windows; N)"
+#define RB_DAAP_REFRESH_TIMEOUT 20000
 
 static void      rb_daap_connection_dispose      (GObject *obj);
 static void      rb_daap_connection_set_property (GObject *object,
@@ -82,6 +83,7 @@
 
 	gboolean is_connected;
 	gboolean is_connecting;
+	gboolean is_refreshing;
 
 	SoupSession *session;
 	SoupUri *base_uri;
@@ -93,6 +95,7 @@
 
 	gint request_id;
 	gint database_id;
+	gint refresh_timeout;
 
 	guint reading_playlist;
 	GSList *playlists;
@@ -127,6 +130,7 @@
 	AUTHENTICATE,
 	CONNECTING,
 	CONNECTED,
+	REFRESHED,
 	DISCONNECTED,
 	OPERATION_DONE,
 	LAST_SIGNAL
@@ -243,6 +247,15 @@
 					       g_cclosure_marshal_VOID__VOID,
 					       G_TYPE_NONE,
 					       0);
+	signals [REFRESHED] = g_signal_new ("refreshed",
+					       G_TYPE_FROM_CLASS (object_class),
+					       G_SIGNAL_RUN_LAST,
+					       G_STRUCT_OFFSET (RBDAAPConnectionClass, refreshed),
+					       NULL,
+					       NULL,
+					       g_cclosure_marshal_VOID__VOID,
+					       G_TYPE_NONE,
+					       0);
 	signals [OPERATION_DONE] = g_signal_new ("operation-done",
 						 G_TYPE_FROM_CLASS (object_class),
 						 G_SIGNAL_RUN_FIRST,
@@ -308,6 +321,20 @@
 }
 
 static void
+connection_refreshed (RBDAAPConnection *connection)
+{
+	rb_debug("Emitting refreshed");
+
+	connection->priv->is_refreshing = FALSE;
+
+	GDK_THREADS_ENTER ();
+	g_signal_emit(connection,
+			signals [REFRESHED],
+			0);
+	GDK_THREADS_LEAVE();
+}
+
+static void
 connection_operation_done (RBDAAPConnection *connection)
 {
 	rb_debug ("Emitting operation done");
@@ -781,7 +808,22 @@
 		return;
 	}
 
-	priv->revision_number = g_value_get_int (&(item->content));
+	gint new_revision = g_value_get_int (&(item->content));
+
+	if (new_revision != priv->revision_number) {
+		rb_debug("updating revision number from %d to %d", priv->revision_number, new_revision);
+		priv->revision_number = new_revision;
+
+		if (priv->state == DAAP_REFRESH) {
+			priv->is_refreshing = TRUE;
+			priv->state = DAAP_GET_REVISION_NUMBER;
+		}
+	}
+	else {
+		rb_debug("same revision at %d, not doing anything", priv->revision_number);
+	}
+
+
 	rb_daap_connection_state_done (connection, TRUE);
 }
 
@@ -894,7 +936,10 @@
 		return;
 	}
 
-	priv->item_id_to_uri = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)rb_refstring_unref);
+	/* create an empty hash table if only we don't have one already */
+	if (! g_hash_table_size (priv->item_id_to_uri)) {
+		priv->item_id_to_uri = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify)rb_refstring_unref);
+	}
 
 	rb_profile_start ("handling song listing");
 	priv->progress = 0.0f;
@@ -988,6 +1033,13 @@
 		 * unreasonable to me, honestly
 		 */
 		/*}*/
+
+		/* check if the song is already in the rhythmdb */
+		if (rhythmdb_entry_lookup_by_location (priv->db, uri)) {
+			g_free (uri);
+			continue;
+		}
+
 		entry = rhythmdb_entry_new (priv->db, priv->db_type, uri);
 		if (entry == NULL) {
 			rb_debug ("cannot create entry for daap track %s", uri);
@@ -1083,6 +1135,34 @@
 	return strcmp(playlist1->name, playlist2->name);
 }
 
+static gboolean
+find_id_in_playlists (GSList *playlists, gint id)
+{
+		GSList *l;
+		for (l = playlists; l != NULL; l = g_slist_next(l)) {
+			RBDAAPPlaylist *pl = (RBDAAPPlaylist *) l->data;
+			if (pl->id == id)
+				return TRUE;
+		}
+		return FALSE;
+}
+
+static int
+find_uri_in_playlist (gconstpointer *a, gconstpointer *b)
+{
+	RBRefString *existing_uri = (RBRefString *) a;
+	RBRefString *new_uri = (RBRefString *) b;
+
+	return strcmp ( rb_refstring_get (existing_uri), rb_refstring_get (new_uri));
+}
+
+static void
+rb_daap_diff_unref (gpointer *a)
+{
+	RBDAAPPlaylistDiff *diff = (RBDAAPPlaylistDiff *) a;
+	rb_refstring_unref (diff->uri);
+}
+
 /* FIXME
  * what we really should do is only get a list of playlists and their ids
  * then when they are clicked on ('activate'd) by the user, get a list of
@@ -1140,12 +1220,18 @@
 		}
 		name = g_value_dup_string (&(item->content));
 
-		playlist = g_new0 (RBDAAPPlaylist, 1);
-		playlist->id = id;
-		playlist->name = name;
-		rb_debug ("Got playlist %p: name %s, id %d", playlist, playlist->name, playlist->id);
+		if (find_id_in_playlists(priv->playlists, id)) {
+			rb_debug ("Playlist %s already exists, not adding.", name);
+			continue;
+		}
+		else {
+			playlist = g_new0 (RBDAAPPlaylist, 1);
+			playlist->id = id;
+			playlist->name = name;
+			rb_debug ("Got playlist %p: name %s, id %d", playlist, playlist->name, playlist->id);
 
-		priv->playlists = g_slist_prepend (priv->playlists, playlist);
+			priv->playlists = g_slist_prepend (priv->playlists, playlist);
+		}
 	}
 
 	/* Sort the playlists into lexical order. Established DAAP clients already
@@ -1164,7 +1250,6 @@
 	RBDAAPPlaylist *playlist;
 	GNode *listing_node;
 	GNode *node;
-	gint i;
 	GList *playlist_uris = NULL;
 
 	if (structure == NULL || SOUP_STATUS_IS_SUCCESSFUL (status) == FALSE) {
@@ -1174,6 +1259,9 @@
 
 	playlist = (RBDAAPPlaylist *)g_slist_nth_data (priv->playlists, priv->reading_playlist);
 	g_assert (playlist);
+	
+	/* clear out old diffs */
+	g_list_foreach (playlist->diffs, (GFunc)rb_daap_diff_unref, NULL);
 
 	listing_node = rb_daap_structure_find_node (structure, RB_DAAP_CC_MLCL);
 	if (listing_node == NULL) {
@@ -1184,7 +1272,7 @@
 	}
 
 	rb_profile_start ("handling playlist entries");
-	for (i = 0, node = listing_node->children; node; node = node->next, i++) {
+	for (node = listing_node->children; node; node = node->next) {
 		RBRefString *item_uri;
 		gint playlist_item_id;
 		RBDAAPItem *item;
@@ -1203,12 +1291,33 @@
 				  playlist_item_id, playlist->name);
 			continue;
 		}
+		playlist_uris = g_list_prepend (playlist_uris, rb_refstring_ref (item_uri));
 
-		playlist_uris = g_list_prepend (playlist_uris, rb_refstring_ref (item_uri));
+		if (g_list_find_custom (playlist->uris, item_uri, (GCompareFunc)find_uri_in_playlist) == NULL) {
+			RBDAAPPlaylistDiff *diff = g_new0 (RBDAAPPlaylistDiff, 1);
+			diff->uri = rb_refstring_ref (item_uri);
+			diff->difftype = DAAP_ADD_URI;
+			playlist->diffs = g_list_prepend (playlist->diffs, diff); 
+		} 
 	}
 	rb_profile_end ("handling playlist entries");
 
+	GList *l;
+	for (l = playlist->uris; l != NULL; l = g_list_next (l)) {
+		RBRefString *uri = l->data;
+		if (g_list_find_custom (playlist_uris, uri, (GCompareFunc)find_uri_in_playlist) == NULL) {
+			RBDAAPPlaylistDiff *diff = g_new0 (RBDAAPPlaylistDiff, 1);
+			diff->uri = rb_refstring_ref (uri);
+			diff->difftype = DAAP_DEL_URI;
+			playlist->diffs = g_list_prepend (playlist->diffs, diff);
+		}
+	}
+	
 	playlist->uris = g_list_reverse (playlist_uris);
+	
+	if (priv->is_refreshing)
+		connection_refreshed (connection);
+
 	rb_daap_connection_state_done (connection, TRUE);
 }
 
@@ -1442,8 +1551,10 @@
 			break;
 		case DAAP_GET_PLAYLIST_ENTRIES:
 			/* keep reading playlists until we've got them all */
-			if (++priv->reading_playlist >= g_slist_length (priv->playlists))
+			if (++priv->reading_playlist >= g_slist_length (priv->playlists)) {
+				priv->reading_playlist = 0;
 				priv->state = DAAP_DONE;
+			}
 			break;
 
 		case DAAP_LOGOUT:
@@ -1454,6 +1565,10 @@
 			/* uhh.. */
 			rb_debug ("This should never happen.");
 			break;
+		case DAAP_REFRESH:
+			rb_debug ("Setting state back to done after refresh");
+			priv->state = DAAP_DONE;
+			break;
 
 		default:
 			/* in most states, we just move on to the next */
@@ -1535,6 +1650,7 @@
 
 		break;
 
+	case DAAP_REFRESH:
 	case DAAP_GET_REVISION_NUMBER:
 		rb_debug ("Getting DAAP server database revision number");
 		path = g_strdup_printf ("/update?session-id=%u&revision-number=1", priv->session_id);
@@ -1696,6 +1812,21 @@
 	return connection->priv->playlists;
 }
 
+gboolean
+rb_daap_connection_refresh_cb (RBDAAPConnection *connection) {
+	if (connection->priv->state == DAAP_DONE) {
+		connection->priv->state = DAAP_REFRESH;
+		rb_daap_connection_do_something(connection);
+	}
+	return TRUE;
+}
+
+void
+rb_daap_connection_refresh_init (RBDAAPConnection *connection)
+{
+	connection->priv->refresh_timeout = g_timeout_add(RB_DAAP_REFRESH_TIMEOUT, (GSourceFunc) rb_daap_connection_refresh_cb, connection);
+}
+
 static void
 rb_daap_connection_dispose (GObject *object)
 {
@@ -1704,6 +1835,11 @@
 
 	rb_debug ("DAAP connection dispose");
 
+	if (priv->refresh_timeout != 0) {
+		g_source_remove (priv->refresh_timeout);
+		priv->refresh_timeout = 0;
+	}
+
 	if (priv->emit_progress_id != 0) {
 		g_source_remove (priv->emit_progress_id);
 		priv->emit_progress_id = 0;
@@ -1740,6 +1876,8 @@
 
 			g_list_foreach (playlist->uris, (GFunc)rb_refstring_unref, NULL);
 			g_list_free (playlist->uris);
+			g_list_foreach (playlist->diffs, (GFunc)rb_daap_diff_unref, NULL);
+			g_list_free (playlist->diffs);
 			g_free (playlist->name);
 			g_free (playlist);
 			l->data = NULL;
Index: rb-daap-source.c
===================================================================
--- rb-daap-source.c	(revision 5549)
+++ rb-daap-source.c	(working copy)
@@ -431,6 +431,7 @@
 		source->priv->connection_status = _("Retrieving songs from music share");
 		break;
 	case DAAP_LOGOUT:
+	case DAAP_REFRESH:
 	case DAAP_DONE:
 		source->priv->connection_status = NULL;
 		break;
@@ -493,9 +494,14 @@
 }
 
 static void
-_add_location_to_playlist (RBRefString *uri, RBStaticPlaylistSource *source)
+_add_location_to_playlist (RBDAAPPlaylistDiff *diff, RBStaticPlaylistSource *source)
 {
-	rb_static_playlist_source_add_location (source, rb_refstring_get (uri), -1);
+	if (diff->difftype == DAAP_ADD_URI) {
+		rb_static_playlist_source_add_location (source, rb_refstring_get (diff->uri), -1);
+	}
+	else {
+		rb_static_playlist_source_remove_location (source, rb_refstring_get (diff->uri));
+	}
 }
 
 static void
@@ -536,7 +542,7 @@
 		RBSource *playlist_source;
 
 		playlist_source = rb_static_playlist_source_new (shell, playlist->name, FALSE, entry_type);
-		g_list_foreach (playlist->uris, (GFunc)_add_location_to_playlist, playlist_source);
+		g_list_foreach (playlist->diffs, (GFunc)_add_location_to_playlist, playlist_source);
 
 		rb_shell_append_source (shell, playlist_source, RB_SOURCE (daap_source));
 		daap_source->priv->playlist_sources = g_slist_prepend (daap_source->priv->playlist_sources, playlist_source);
@@ -544,9 +550,55 @@
 
 	g_object_unref (shell);
 	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+	rb_daap_connection_refresh_init( RB_DAAP_CONNECTION (daap_source->priv->connection) );
 }
 
 static void
+connection_refreshed_cb (RBDAAPConnection *connection,
+				RBDAAPSource	*source)
+{
+	RBDAAPSource *daap_source = RB_DAAP_SOURCE (source);
+	RBShell *shell = NULL;
+	GSList *playlists;
+	GSList *l;
+	GSList *m;
+	RhythmDBEntryType entry_type;
+
+	g_object_get (daap_source,
+		      "shell", &shell,
+		      "entry-type", &entry_type,
+		      NULL);
+	playlists = rb_daap_connection_get_playlists (RB_DAAP_CONNECTION (daap_source->priv->connection));
+	for (l = playlists; l != NULL; l = g_slist_next (l)) {
+		RBDAAPPlaylist *playlist = l->data;
+
+		RBSource *playlist_source = NULL;
+		for (m = daap_source->priv->playlist_sources; m != NULL; m = g_slist_next(m)) {
+			RBSource *existing_source = m->data;
+			char *name;
+			g_object_get (existing_source, "name", &name, NULL);
+			if (strcmp (name, playlist->name) == 0) {
+				playlist_source = existing_source;
+				g_free(name);
+				continue;
+			}
+			g_free(name);
+		}
+		if (playlist_source == NULL) {
+			playlist_source = rb_static_playlist_source_new (shell, playlist->name, FALSE, entry_type);
+			rb_shell_append_source (shell, playlist_source, RB_SOURCE (daap_source));
+			daap_source->priv->playlist_sources = g_slist_prepend (daap_source->priv->playlist_sources, playlist_source);
+		}
+		g_list_foreach (playlist->diffs, (GFunc)_add_location_to_playlist, playlist_source);
+
+	}
+
+	g_object_unref (shell);
+	g_boxed_free (RHYTHMDB_TYPE_ENTRY_TYPE, entry_type);
+
+}
+
+static void
 rb_daap_source_activate (RBSource *source)
 {
 	RBDAAPSource *daap_source = RB_DAAP_SOURCE (source);
@@ -589,6 +641,10 @@
 			  "disconnected",
                           G_CALLBACK (connection_disconnected_cb),
 			  source);
+		g_signal_connect (daap_source->priv->connection,
+				"refreshed",
+				          G_CALLBACK (connection_refreshed_cb),
+			  source);
 
 	rb_daap_connection_connect (RB_DAAP_CONNECTION (daap_source->priv->connection),
 				    (RBDAAPConnectionCallback) rb_daap_source_connection_cb,
Index: rb-daap-connection.h
===================================================================
--- rb-daap-connection.h	(revision 5549)
+++ rb-daap-connection.h	(working copy)
@@ -33,8 +33,20 @@
 	char  *name;
 	int    id;
 	GList *uris;
+	GList *diffs;
 } RBDAAPPlaylist;
 
+typedef enum {
+	DAAP_ADD_URI,
+	DAAP_DEL_URI,
+} RBDAAPDiffType;
+
+typedef struct {
+	RBRefString *uri;
+	RBDAAPDiffType difftype;
+} RBDAAPPlaylistDiff;
+
+
 #define RB_TYPE_DAAP_CONNECTION		(rb_daap_connection_get_type ())
 #define RB_DAAP_CONNECTION(o)		(G_TYPE_CHECK_INSTANCE_CAST ((o), RB_TYPE_DAAP_CONNECTION, RBDAAPConnection))
 #define RB_DAAP_CONNECTION_CLASS(k)	(G_TYPE_CHECK_CLASS_CAST((k), RB_TYPE_DAAP_CONNECTION, RBDAAPConnectionClass))
@@ -54,7 +66,8 @@
 	DAAP_GET_PLAYLISTS,
 	DAAP_GET_PLAYLIST_ENTRIES,
 	DAAP_LOGOUT,
-	DAAP_DONE
+	DAAP_DONE,
+	DAAP_REFRESH
 } RBDAAPConnectionState;
 
 typedef struct {
@@ -75,6 +88,7 @@
 				   float		 progress);
 
 	void   (* operation_done) (RBDAAPConnection     *connection);
+	void   (* refreshed)        (RBDAAPConnection		*connection);
 
 } RBDAAPConnectionClass;
 
@@ -107,6 +121,9 @@
 
 GSList *           rb_daap_connection_get_playlists   (RBDAAPConnection         *connection);
 
+gboolean           rb_daap_connection_refresh_cb (RBDAAPConnection *connection);
+void               rb_daap_connection_refresh_init (RBDAAPConnection *connection);
+
 G_END_DECLS
 
 #endif /* __RB_DAAP_CONNECTION_H */
