--- a/src/db/ProxyDatabasePlugin.cxx
+++ b/src/db/ProxyDatabasePlugin.cxx
@@ -30,6 +30,8 @@
 #include "tag/TagBuilder.hxx"
 #include "util/Error.hxx"
 #include "util/Domain.hxx"
+#include "Log.hxx"
+#include "SongFilter.hxx"
 
 #undef MPD_DIRECTORY_H
 #undef MPD_SONG_H
@@ -113,12 +115,24 @@ Convert(enum tag_type tag_type)
 }
 
 static bool
-CheckError(struct mpd_connection *connection, Error &error)
+CheckError(struct mpd_connection *connection, Error &error, int *ccodep = 0,
+	   int *scodep = 0)
 {
+	if (ccodep)
+		*ccodep = MPD_ERROR_SUCCESS;
+	if (scodep)
+		*scodep = MPD_SERVER_ERROR_UNK;
 	const auto code = mpd_connection_get_error(connection);
 	if (code == MPD_ERROR_SUCCESS)
 		return true;
 
+	if (ccodep)
+		*ccodep = code;
+	if (code == MPD_ERROR_SERVER) {
+		int scode = mpd_connection_get_server_error(connection);
+		if (scodep)
+			*scodep = scode;
+	}
 	error.Set(libmpdclient_domain, (int)code,
 		  mpd_connection_get_error_message(connection));
 	mpd_connection_clear_error(connection);
@@ -178,35 +192,6 @@ ProxyDatabase::Close()
 static Song *
 Convert(const struct mpd_song *song);
 
-Song *
-ProxyDatabase::GetSong(const char *uri, Error &error) const
-{
-	// TODO: implement
-	// TODO: auto-reconnect
-
-	if (!mpd_send_list_meta(connection, uri)) {
-		CheckError(connection, error);
-		return nullptr;
-	}
-
-	struct mpd_song *song = mpd_recv_song(connection);
-	Song *song2 = song != nullptr
-		? Convert(song)
-		: nullptr;
-	mpd_song_free(song);
-	if (!mpd_response_finish(connection)) {
-		if (song2 != nullptr)
-			song2->Free();
-
-		CheckError(connection, error);
-		return nullptr;
-	}
-
-	if (song2 == nullptr)
-		error.Format(db_domain, DB_NOT_FOUND, "No such song: %s", uri);
-
-	return song2;
-}
 
 void
 ProxyDatabase::ReturnSong(Song *song) const
@@ -220,12 +205,14 @@ ProxyDatabase::ReturnSong(Song *song) const
 
 static bool
 Visit(struct mpd_connection *connection, const char *uri,
+	  const DatabaseSelection &selection,
       bool recursive, VisitDirectory visit_directory, VisitSong visit_song,
       VisitPlaylist visit_playlist, Error &error);
 
 static bool
 Visit(struct mpd_connection *connection,
       bool recursive, const struct mpd_directory *directory,
+	  const DatabaseSelection &selection,
       VisitDirectory visit_directory, VisitSong visit_song,
       VisitPlaylist visit_playlist, Error &error)
 {
@@ -240,7 +227,7 @@ Visit(struct mpd_connection *connection,
 	}
 
 	if (recursive &&
-	    !Visit(connection, path, recursive,
+	    !Visit(connection, path, selection, recursive,
 		   visit_directory, visit_song, visit_playlist, error))
 		return false;
 
@@ -283,12 +270,15 @@ Convert(const struct mpd_song *song)
 
 static bool
 Visit(const struct mpd_song *song,
+	  const DatabaseSelection &selection,
       VisitSong visit_song, Error &error)
 {
 	if (!visit_song)
 		return true;
 
 	Song *s = Convert(song);
+	if (!selection.Match(*s))
+		return true;
 	bool success = visit_song(*s, error);
 	s->Free();
 
@@ -346,8 +336,80 @@ ReceiveEntities(struct mpd_connection *connection)
 	return entities;
 }
 
+static std::string 
+PathGetParent(const std::string &s) 
+{
+	if (s.empty())
+		return s;
+	std::string father(s);
+
+	if (*(father.rbegin()) == '/')
+		father.erase(father.length()-1);
+
+	std::string::size_type slp = father.rfind('/');
+	if (slp == std::string::npos)
+		return std::string();
+
+	father.erase(slp);
+	return father;
+}
+
+static std::list<ProxyEntity> 
+FindInParent(struct mpd_connection *connection, const std::string& uri,
+			   Error &error)
+{
+	std::string parent_uri = PathGetParent(uri);
+
+	std::list<ProxyEntity> entities;
+	if (!mpd_send_list_meta(connection, parent_uri.c_str()) ||
+		!CheckError(connection, error)) {
+		return entities;
+	}
+	
+	struct mpd_entity *entity;
+	while ((entity = mpd_recv_entity(connection)) != NULL) {
+		if (mpd_entity_get_type(entity) == MPD_ENTITY_TYPE_SONG) {
+			const struct mpd_song *song;
+			if ((song = mpd_entity_get_song(entity))) {
+				std::string otheruri = mpd_song_get_uri(song);
+				if (!otheruri.compare(uri)) {
+					entities.push_back(ProxyEntity(entity));
+				}
+			}
+		}
+	}
+	return entities;
+}
+
+Song *
+ProxyDatabase::GetSong(const char *uri, Error &error) const
+{
+	// TODO: auto-reconnect
+
+	std::list<ProxyEntity> entities = FindInParent(connection, uri, error);
+
+	Song *song2 = nullptr;
+
+	if (!entities.empty()) {
+		const auto &entity(*entities.begin());
+		switch (mpd_entity_get_type(entity) != MPD_ENTITY_TYPE_SONG) {
+			break;
+		}
+		const mpd_song *song = mpd_entity_get_song(entity);
+		if (song) {
+			song2 = Convert(song);
+		}
+	}
+
+	if (song2 == nullptr)
+		error.Format(db_domain, DB_NOT_FOUND, "No such song: %s", uri);
+
+	return song2;
+}
+
 static bool
 Visit(struct mpd_connection *connection, const char *uri,
+	  const DatabaseSelection &selection,
       bool recursive, VisitDirectory visit_directory, VisitSong visit_song,
       VisitPlaylist visit_playlist, Error &error)
 {
@@ -355,8 +417,24 @@ Visit(struct mpd_connection *connection, const char *uri,
 		return CheckError(connection, error);
 
 	std::list<ProxyEntity> entities(ReceiveEntities(connection));
-	if (!CheckError(connection, error))
-		return false;
+	int ccode, scode;
+	if (!CheckError(connection, error, &ccode, &scode)) {
+		if (ccode == MPD_ERROR_SERVER && scode == MPD_SERVER_ERROR_NO_EXIST) {
+			/* We get this when  the visited url is not a directory */
+			// Hopefuly we are looking for a song. Unfortunately the
+			// client lib does not seem to have the concept of
+			// retrieving info for a non-directory object. So we try
+			// to find the target inside its parent. There should be only
+			// one
+			entities = FindInParent(connection, uri, error);
+			if (entities.empty()) {
+				error.Format(db_domain, DB_NOT_FOUND, "No such uri: %s", uri);
+				return false;
+			}
+		} else {
+			return false;
+		}
+	}
 
 	for (const auto &entity : entities) {
 		switch (mpd_entity_get_type(entity)) {
@@ -366,18 +444,25 @@ Visit(struct mpd_connection *connection, const char *uri,
 		case MPD_ENTITY_TYPE_DIRECTORY:
 			if (!Visit(connection, recursive,
 				   mpd_entity_get_directory(entity),
+				   selection,
 				   visit_directory, visit_song, visit_playlist,
 				   error))
 				return false;
 			break;
 
 		case MPD_ENTITY_TYPE_SONG:
-			if (!Visit(mpd_entity_get_song(entity), visit_song,
+			if (!Visit(mpd_entity_get_song(entity), selection, visit_song,
 				   error))
 				return false;
 			break;
 
 		case MPD_ENTITY_TYPE_PLAYLIST:
+			// For this to work with playlists from the load/save
+			// directory, it would need to be seen with the same path
+			// on the server and client, which is highly unlikely in
+			// general. Either playlist file access must go through
+			// the proxy or playlist management must be made local
+			// even in proxy mode.
 			if (!Visit(mpd_entity_get_playlist(entity),
 				   visit_playlist, error))
 				return false;
@@ -395,12 +480,15 @@ ProxyDatabase::Visit(const DatabaseSelection &selection,
 		     VisitPlaylist visit_playlist,
 		     Error &error) const
 {
-	// TODO: match
+	FormatDebug(db_domain, "ProxyDatabase::Visit. uri [%s], recursive %d\n",
+				selection.uri, selection.recursive);
 	// TODO: auto-reconnect
 
-	return ::Visit(connection, selection.uri, selection.recursive,
-		       visit_directory, visit_song, visit_playlist,
-		       error);
+	return ::Visit(connection, selection.uri, 
+				   selection,
+				   selection.recursive,
+				   visit_directory, visit_song, visit_playlist,
+				   error);
 }
 
 bool
@@ -418,9 +506,28 @@ ProxyDatabase::VisitUniqueTags(const DatabaseSelection &selection,
 	if (!mpd_search_db_tags(connection, tag_type2))
 		return CheckError(connection, error);
 
-	// TODO: match
-	(void)selection;
+	if (selection.uri && *selection.uri) {
+		mpd_search_add_uri_constraint(connection, MPD_OPERATOR_DEFAULT, 
+									  selection.uri);
+	}
 
+	if (selection.filter) {
+		const auto items = selection.filter->GetItems();
+		for (auto it = items->begin(); it != items->end(); it++) {
+			enum tag_type tt = (enum tag_type)(it->GetTag());
+			const char *value = it->GetValue();
+			enum mpd_tag_type tt2 = Convert(tt);
+			if (tt2 == MPD_TAG_COUNT) {
+				mpd_search_add_any_tag_constraint(connection,
+								  MPD_OPERATOR_DEFAULT,
+								  value);
+			} else {
+				mpd_search_add_tag_constraint(connection,
+							      MPD_OPERATOR_DEFAULT,
+							      tt2, value);
+			}
+		}
+	}
 	if (!mpd_search_commit(connection))
 		return CheckError(connection, error);
 