Index: lib/rb-string-helpers.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-string-helpers.c,v
retrieving revision 1.15
diff -u -r1.15 rb-string-helpers.c
--- lib/rb-string-helpers.c	17 Dec 2003 02:22:29 -0000	1.15
+++ lib/rb-string-helpers.c	9 Aug 2005 16:02:26 -0000
@@ -180,3 +180,316 @@
 	return collated;
 }
 
+/* GStreamer
+ * Copyright (c) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
+ *
+ * search.c: Simple search dialog
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+
+/* 0 - 100 */
+static inline gint
+party_pattern_cost_replace (gunichar from, gunichar to)
+{
+	return from == to ? 0 : 100;
+}
+/* 0 - 100 */
+static inline gint
+party_pattern_cost_delete (gunichar c)
+{
+	return 100;
+}
+/* 0 - 100 */
+static inline gint
+party_pattern_cost_insert (gunichar c)
+{
+	return 100;
+}
+/**
+ * party_pattern_compare_word:
+ * @needle: The word that is looked for
+ * @haystack: The word to find
+ *
+ * Computes a percentage of how well needle is found in haystack.
+ *
+ * Return: the similarity from 0 to 100
+ */
+/* static */ gint
+party_pattern_compare_word (gunichar *needle, gunichar *haystack)
+{
+	/* right... we must reduce redundant array intializing..., well thats all doable
+	* first, we need a static variable holding the size of the array */
+	GStaticRWLock rwlock = G_STATIC_RW_LOCK_INIT;
+	static int cost_size = 0;
+	static  guint *costs = NULL;
+
+	gunichar *walk;
+	guint temp_cost, tmp, best, i;
+	guint needle_length = 0;
+
+	/* compute Levenshtein distance between the 2 strings */
+	g_assert (needle);
+	g_assert (haystack);
+
+	/* get length of needle */ /*where I use strlen */
+		walk = needle;
+		while (*walk) {
+		needle_length++;
+		walk++;
+	}
+
+	g_static_rw_lock_reader_lock (&rwlock);
+	/* initialize array */
+	if (cost_size < needle_length + 1) {
+	  	/* we need to reallocate the array */
+	  	g_static_rw_lock_reader_unlock (&rwlock);
+	  	g_static_rw_lock_writer_lock (&rwlock);
+
+		g_free (costs);
+	  	costs = g_new (guint, needle_length + 1);
+	  	cost_size = needle_length + 1;
+
+	  	g_static_rw_lock_writer_unlock (&rwlock);
+	  	g_static_rw_lock_reader_lock (&rwlock);
+	}
+	
+	
+	costs[0] = 0;
+	walk = needle;
+	for (i = 1; i <= needle_length; i++, walk++) {
+		costs[i] = costs[i - 1] + party_pattern_cost_insert (*walk);
+	}
+
+	/* do matrix calculation */
+	for (; *haystack; haystack++) {
+		temp_cost = costs[0] + 1; /* cheap start/end */
+		walk = needle;
+
+		for (i = 0; i < needle_length; i++, walk++) {
+			best = costs[i] + party_pattern_cost_replace (*haystack, *walk);
+			tmp = costs[i + 1] + party_pattern_cost_delete (*haystack);
+
+			if (tmp < best)
+				best = tmp;
+
+			tmp = temp_cost + party_pattern_cost_insert (*walk);
+			if (tmp < best)
+				best = tmp;
+
+			costs[i] = temp_cost;
+			temp_cost = best;
+		}
+		costs[needle_length] = (temp_cost <= costs[needle_length]) ? 
+		                        temp_cost : costs[needle_length] + 1; /* cheap start/end */
+	}
+
+	best = costs[needle_length];
+
+	g_static_rw_lock_reader_unlock (&rwlock);
+
+	/* now we need to calculate the similarity somehow */
+	best = 100 - MIN (100, 2 * best / needle_length);
+	return best;
+}
+/**
+ * party_pattern_compare:
+ * @needle: The text that is looked for
+ * @haystack: The text to find
+ *
+ * Computes a percentage of how well needle is found in haystack.
+ *
+ * Return: the similarity from 0 to 100
+ */
+/*static */ gint
+party_pattern_compare (PartyPattern needle, PartyPattern haystack)
+{
+	PartyPattern loop;
+	gint best_match, ret = 100;
+
+	while (*needle) {
+		loop = haystack;
+		best_match = 0;
+		while (*loop) {
+			best_match = MAX (best_match, party_pattern_compare_word (*needle, *loop));
+			if (best_match == 100)
+				break;
+			loop++;
+		}
+		ret *= best_match;
+		ret /= 100;
+		needle++;
+	}
+
+	return ret;
+}
+/**
+ * party_pattern_compare:
+ * @needle: The text that is looked for
+ * @haystack: The text to find
+ *
+ * Computes a percentage of how well needle is found in haystack.
+ *
+ * Return: the similarity from 0 to 100
+ */
+gint
+party_pattern_compare_multiple (PartyPattern needle, PartyPattern haystacks[], gint num_haystacks)
+{
+	PartyPattern loop;
+	gint best_match, ret = 100;
+
+	while (*needle) {
+		int i;
+		for (i = 0; i < num_haystacks; i++) {
+			loop = haystacks[i];
+			best_match = 0;
+			while (*loop && best_match != 100) {
+				best_match = MAX (best_match, party_pattern_compare_word (*needle, *loop));
+				loop++;
+			}
+			if (best_match == 100)
+				break;
+		}
+		ret *= best_match;
+		ret /= 100;
+		needle++;
+	}
+
+	return ret;
+}
+/**
+ * party_pattern_free:
+ * @pattern: the pattern to free
+ *
+ * Frees a party_pattern.
+ **/
+void
+party_pattern_free (PartyPattern pattern)
+{
+	if (pattern == NULL)
+		return;
+
+	g_free (pattern[0]);
+	g_free (pattern);
+}
+/**
+ * party_pattern_from_utf8:
+ * @text: Text to convert
+ *
+ * Converts a text to the format used by libparty to do text comparisons.
+ *
+ * Returns: A value to be used in text comparisons. Free with party_pattern_free.
+ **/
+/* static */ PartyPattern
+party_pattern_from_utf8 (const gchar *text) {
+	GSList *words, *firstword;
+	gunichar *unicode, *cur_write, *cur_read;
+	gboolean new_word = TRUE;
+	gint i, wordcount = 1;
+	PartyPattern ret;
+
+	g_return_val_if_fail (text != NULL, NULL);
+
+	cur_write = cur_read = unicode = g_utf8_to_ucs4_fast (text, -1, NULL);
+
+	/* we may fail here, we expect valid utf-8 */
+	g_return_val_if_fail (unicode != NULL, NULL);
+
+	words = g_slist_prepend (NULL, unicode);
+
+	/* now normalize this text */
+	while (*cur_read) {
+		switch (g_unichar_type (*cur_read)) {
+		case G_UNICODE_UNASSIGNED:
+			g_warning ("unassigned unicode character type found");
+			/* fall through */
+		case G_UNICODE_CONTROL:
+		case G_UNICODE_FORMAT:
+		case G_UNICODE_PRIVATE_USE:
+
+		case G_UNICODE_SURROGATE:
+		case G_UNICODE_LINE_SEPARATOR:
+		case G_UNICODE_PARAGRAPH_SEPARATOR:
+		case G_UNICODE_SPACE_SEPARATOR:
+			/* remove these and start a new word */
+			if (!new_word) {
+				/* end current word if it isn't ended yet */
+				*cur_write++ = 0;
+				new_word = TRUE;
+			}
+
+			break;
+		case G_UNICODE_COMBINING_MARK:
+		case G_UNICODE_ENCLOSING_MARK:
+		case G_UNICODE_NON_SPACING_MARK:
+		case G_UNICODE_CONNECT_PUNCTUATION:
+		case G_UNICODE_DASH_PUNCTUATION:
+		case G_UNICODE_CLOSE_PUNCTUATION:
+		case G_UNICODE_FINAL_PUNCTUATION:
+		case G_UNICODE_INITIAL_PUNCTUATION:
+		case G_UNICODE_OTHER_PUNCTUATION:
+		case G_UNICODE_OPEN_PUNCTUATION:
+			/* remove these */
+			break;
+		case G_UNICODE_LOWERCASE_LETTER:
+		case G_UNICODE_MODIFIER_LETTER:
+		case G_UNICODE_OTHER_LETTER:
+		case G_UNICODE_TITLECASE_LETTER:
+		case G_UNICODE_UPPERCASE_LETTER:
+			/* convert to lower (?) case */
+			*cur_read = g_unichar_tolower (*cur_read);
+			/* ... and fall through */
+		case G_UNICODE_DECIMAL_NUMBER:
+		case G_UNICODE_LETTER_NUMBER:
+		case G_UNICODE_OTHER_NUMBER:
+		case G_UNICODE_CURRENCY_SYMBOL:
+		case G_UNICODE_MODIFIER_SYMBOL:
+		case G_UNICODE_MATH_SYMBOL:
+		case G_UNICODE_OTHER_SYMBOL:
+			/* keep these unchanged */
+			*cur_write = *cur_read;
+			if (new_word) {
+				if (cur_write != unicode) {/* first insert has been done above */
+					words = g_slist_prepend (words, cur_write);
+					wordcount++;
+				}
+				new_word = FALSE;
+			}
+			cur_write++;
+			break;    
+		default:
+			g_warning ("unknown unicode character type found");
+			break;
+		}
+		cur_read++;
+	}
+
+	if (!new_word) {
+		*cur_write++ = 0;
+	}
+
+	ret = g_new (gunichar *, wordcount + 1); 
+	firstword = words;
+	for (i = wordcount - 1; i >= 0; i--) {
+		ret[i] = (gunichar *) words->data;
+		words = g_slist_next (words);
+	}
+	g_slist_free (firstword);
+	ret[wordcount] = NULL;
+
+	return ret;
+}
Index: lib/rb-string-helpers.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/lib/rb-string-helpers.h,v
retrieving revision 1.11
diff -u -r1.11 rb-string-helpers.h
--- lib/rb-string-helpers.h	16 Nov 2003 16:56:42 -0000	1.11
+++ lib/rb-string-helpers.h	9 Aug 2005 16:02:26 -0000
@@ -22,17 +22,23 @@
 
 #ifndef __RB_STRING_HELPERS_H
 #define __RB_STRING_HELPERS_H
-
+typedef gunichar ** PartyPattern;
 G_BEGIN_DECLS
 
 void	rb_string_helpers_init		(void);
 void	rb_string_helpers_shutdown	(void);
 
 char *	rb_unicodify			(const char *str);
-
 int	rb_utf8_strncasecmp		(gconstpointer a, gconstpointer b);
-
 char *	rb_get_sort_key			(const char *string);
+
+
+PartyPattern	party_pattern_from_utf8		(const gchar *text);
+void		party_pattern_free		(PartyPattern pattern);
+
+gint		party_pattern_compare		(PartyPattern needle, PartyPattern haystack);
+gint		party_pattern_compare_multiple	(PartyPattern needle, PartyPattern haystacks[], gint num_haystacks);
+gint		party_pattern_compare_word	(gunichar *needle, gunichar *haystack);
 
 G_END_DECLS
 
Index: rhythmdb/rb-refstring.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rb-refstring.c,v
retrieving revision 1.5
diff -u -r1.5 rb-refstring.c
--- rhythmdb/rb-refstring.c	11 Jul 2005 04:06:59 -0000	1.5
+++ rhythmdb/rb-refstring.c	9 Aug 2005 16:02:30 -0000
@@ -38,6 +38,7 @@
 	refstr->refcount = 0xdeadbeef;
 	g_free (refstr->folded);
 	g_free (refstr->sortkey);
+	party_pattern_free (refstr->pattern);
 	g_free (refstr);
 }
 
@@ -71,9 +72,11 @@
 	if (compute_sortdata) {
 		ret->folded = g_utf8_casefold (init, -1);
 		ret->sortkey = g_utf8_collate_key (ret->folded, -1);
+		ret->pattern = party_pattern_from_utf8 (init);
 	} else {
 		ret->folded = NULL;
 		ret->sortkey = NULL;
+		ret->pattern = NULL;
 	}
 	
 	strcpy (ret->value, init);
Index: rhythmdb/rb-refstring.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rb-refstring.h,v
retrieving revision 1.5
diff -u -r1.5 rb-refstring.h
--- rhythmdb/rb-refstring.h	27 Jul 2005 07:02:08 -0000	1.5
+++ rhythmdb/rb-refstring.h	9 Aug 2005 16:02:31 -0000
@@ -19,16 +19,18 @@
  *
  */
 
-#include <glib.h>
-
 #ifndef __RB_REFSTRING_H
 #define __RB_REFSTRING_H
 
+#include <glib.h>
+#include "lib/rb-string-helpers.h"
+
 typedef struct
 {
 	gint refcount;
 	char *folded;
 	char *sortkey;
+	PartyPattern pattern;
 	char value[1];
 } RBRefString;
 
@@ -46,6 +48,7 @@
 G_INLINE_FUNC const char *	rb_refstring_get (const RBRefString *val);
 G_INLINE_FUNC const char *	rb_refstring_get_folded (const RBRefString *val);
 G_INLINE_FUNC const char *	rb_refstring_get_sort_key (const RBRefString *val);
+G_INLINE_FUNC PartyPattern	rb_refstring_get_pattern (const RBRefString *val);
 
 G_INLINE_FUNC guint		rb_refstring_hash (gconstpointer a);
 G_INLINE_FUNC gboolean		rb_refstring_equal (gconstpointer a, gconstpointer b);
@@ -82,6 +85,12 @@
 rb_refstring_get_sort_key (const RBRefString *val)
 {
 	return val ? val->sortkey : NULL;
+}
+
+G_INLINE_FUNC PartyPattern
+rb_refstring_get_pattern (const RBRefString *val)
+{
+	return val ? val->pattern : NULL;
 }
 
 G_INLINE_FUNC guint
Index: rhythmdb/rhythmdb-tree.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb-tree.c,v
retrieving revision 1.66
diff -u -r1.66 rhythmdb-tree.c
--- rhythmdb/rhythmdb-tree.c	10 Jul 2005 12:37:56 -0000	1.66
+++ rhythmdb/rhythmdb-tree.c	9 Aug 2005 16:02:42 -0000
@@ -406,6 +406,7 @@
 		case RHYTHMDB_PROP_LAST_PLAYED_STR:
 		case RHYTHMDB_PROP_HIDDEN:
 		case RHYTHMDB_PROP_PLAYBACK_ERROR:
+		case RHYTHMDB_PROP_SEARCH_STRING:
 		case RHYTHMDB_NUM_PROPERTIES:
 			g_assert_not_reached ();
 			break;
@@ -712,6 +713,7 @@
 		case RHYTHMDB_PROP_LAST_PLAYED_STR:
 		case RHYTHMDB_PROP_HIDDEN:
 		case RHYTHMDB_PROP_PLAYBACK_ERROR:
+		case RHYTHMDB_PROP_SEARCH_STRING:
 		case RHYTHMDB_NUM_PROPERTIES:
 			break;
 		}
@@ -1265,6 +1270,34 @@
 		case RHYTHMDB_QUERY_DISJUNCTION:
 			g_assert_not_reached ();
 			break;
+		case RHYTHMDB_QUERY_PROP_FUZZY_MATCH:
+			if (rhythmdb_get_property_type (db, data->propid) == G_TYPE_STRING) {
+				PartyPattern searchterm = party_pattern_from_utf8 (g_value_get_string (data->val));
+				const RBRefString *entry_string;
+				gint distance;
+				
+				if (data->propid == RHYTHMDB_PROP_SEARCH_STRING) {
+					/* doing a search over multiple patterns */
+					const RhythmDBPropType prop_types[4] = { RHYTHMDB_PROP_TITLE, RHYTHMDB_PROP_GENRE,
+											      RHYTHMDB_PROP_ARTIST, RHYTHMDB_PROP_ALBUM };
+					PartyPattern patterns[4];
+					int i;
+
+					for (i = 0; i < 4; i++)
+						patterns[i] = rb_refstring_get_pattern (rhythmdb_entry_get_ref_string (entry, prop_types[i]));
+
+					distance = party_pattern_compare_multiple (searchterm, patterns, 4);
+				} else {
+					entry_string = rhythmdb_entry_get_ref_string (entry, data->propid);
+					distance = party_pattern_compare (searchterm, rb_refstring_get_pattern (entry_string));
+				}
+
+				party_pattern_free (searchterm);
+				
+				if (distance < 70)
+					return FALSE;
+			}
+		break;
 		}
 	}
 	return TRUE;
Index: rhythmdb/rhythmdb.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.c,v
retrieving revision 1.107
diff -u -r1.107 rhythmdb.c
--- rhythmdb/rhythmdb.c	1 Aug 2005 20:15:40 -0000	1.107
+++ rhythmdb/rhythmdb.c	9 Aug 2005 16:02:53 -0000
@@ -2164,6 +2164,7 @@
 		case RHYTHMDB_QUERY_PROP_NOT_LIKE:
 		case RHYTHMDB_QUERY_PROP_GREATER:
 		case RHYTHMDB_QUERY_PROP_LESS:
+		case RHYTHMDB_QUERY_PROP_FUZZY_MATCH:
 			data->propid = va_arg (args, guint);
 			data->val = g_new0 (GValue, 1);
 			g_value_init (data->val, rhythmdb_get_property_type (db, data->propid));
@@ -2234,6 +2235,7 @@
 		case RHYTHMDB_QUERY_PROP_NOT_LIKE:
 		case RHYTHMDB_QUERY_PROP_GREATER:
 		case RHYTHMDB_QUERY_PROP_LESS:
+		case RHYTHMDB_QUERY_PROP_FUZZY_MATCH:
 			g_value_unset (data->val);
 			g_free (data->val);
 			break;
@@ -2628,6 +2630,7 @@
 			ENUM_ENTRY (RHYTHMDB_QUERY_PROP_NOT_LIKE, "Inverted fuzzy property matching"),
 			ENUM_ENTRY (RHYTHMDB_QUERY_PROP_GREATER, "True if property1 >= property2"),
 			ENUM_ENTRY (RHYTHMDB_QUERY_PROP_LESS, "True if property1 <= property2"),
+			ENUM_ENTRY (RHYTHMDB_QUERY_PROP_FUZZY_MATCH, "True if ld(property1,property2) <= 3"),
 			{ 0, 0, 0 }
 		};
 
@@ -2689,6 +2692,7 @@
 			ENUM_ENTRY (RHYTHMDB_PROP_ALBUM_FOLDED, "Album folded (gchararray) [album-folded]"),
 			ENUM_ENTRY (RHYTHMDB_PROP_LAST_PLAYED_STR, "Last Played (gchararray) [last-played-str]"),
 			ENUM_ENTRY (RHYTHMDB_PROP_PLAYBACK_ERROR, "Playback error string (gchararray) [playback-error]"),
+			ENUM_ENTRY (RHYTHMDB_PROP_SEARCH_STRING, "Composite search string (gchararray) [search-string]"),
 			ENUM_ENTRY (RHYTHMDB_PROP_HIDDEN, "Visibility (gboolean) [visibility]"),
 			{ 0, 0, 0 }
 		};
Index: rhythmdb/rhythmdb.h
===================================================================
RCS file: /cvs/gnome/rhythmbox/rhythmdb/rhythmdb.h,v
retrieving revision 1.43
diff -u -r1.43 rhythmdb.h
--- rhythmdb/rhythmdb.h	30 Jul 2005 05:42:57 -0000	1.43
+++ rhythmdb/rhythmdb.h	9 Aug 2005 16:02:58 -0000
@@ -59,6 +59,7 @@
 	RHYTHMDB_QUERY_PROP_NOT_LIKE,
 	RHYTHMDB_QUERY_PROP_GREATER,
 	RHYTHMDB_QUERY_PROP_LESS,
+	RHYTHMDB_QUERY_PROP_FUZZY_MATCH,
 } RhythmDBQueryType;
 
 /* If you modify this enum, don't forget to modify rhythmdb_prop_get_type */
@@ -99,6 +100,7 @@
 	RHYTHMDB_PROP_LAST_PLAYED_STR,
 	RHYTHMDB_PROP_HIDDEN,
 	RHYTHMDB_PROP_PLAYBACK_ERROR,
+	RHYTHMDB_PROP_SEARCH_STRING,
 
 	RHYTHMDB_NUM_PROPERTIES
 } RhythmDBPropType;
@@ -176,6 +178,7 @@
 } RhythmDBEntryChange;
 
 G_INLINE_FUNC const char *rhythmdb_entry_get_string	(RhythmDBEntry *entry, RhythmDBPropType propid);
+G_INLINE_FUNC const RBRefString *rhythmdb_entry_get_ref_string (RhythmDBEntry *entry, RhythmDBPropType propid);
 G_INLINE_FUNC gboolean rhythmdb_entry_get_boolean	(RhythmDBEntry *entry, RhythmDBPropType propid);
 G_INLINE_FUNC guint64 rhythmdb_entry_get_uint64		(RhythmDBEntry *entry, RhythmDBPropType propid);
 G_INLINE_FUNC gulong rhythmdb_entry_get_ulong		(RhythmDBEntry *entry, RhythmDBPropType propid);
@@ -222,6 +225,35 @@
 		return rb_refstring_get (entry->last_played_str);
 	case RHYTHMDB_PROP_PLAYBACK_ERROR:
 		return entry->playback_error;
+	default:
+		g_assert_not_reached ();
+		return NULL;
+	}
+}
+
+G_INLINE_FUNC const RBRefString *
+rhythmdb_entry_get_ref_string (RhythmDBEntry *entry, RhythmDBPropType propid)
+{
+	switch (propid)
+	{
+	case RHYTHMDB_PROP_TITLE:
+	case RHYTHMDB_PROP_TITLE_FOLDED:
+		return entry->title;
+	case RHYTHMDB_PROP_ALBUM:
+	case RHYTHMDB_PROP_ALBUM_FOLDED:
+		return entry->album;
+	case RHYTHMDB_PROP_ARTIST:
+	case RHYTHMDB_PROP_ARTIST_FOLDED:
+		return entry->artist;
+	case RHYTHMDB_PROP_GENRE:
+	case RHYTHMDB_PROP_GENRE_FOLDED:
+		return entry->genre;
+	case RHYTHMDB_PROP_MIMETYPE:
+		return entry->mimetype;
+	case RHYTHMDB_PROP_MOUNTPOINT:
+		return entry->mountpoint;
+	case RHYTHMDB_PROP_LAST_PLAYED_STR:
+		return entry->last_played_str;
 	default:
 		g_assert_not_reached ();
 		return NULL;
Index: sources/rb-library-source.c
===================================================================
RCS file: /cvs/gnome/rhythmbox/sources/rb-library-source.c,v
retrieving revision 1.108
diff -u -r1.108 rb-library-source.c
--- sources/rb-library-source.c	23 Jul 2005 12:41:07 -0000	1.108
+++ sources/rb-library-source.c	9 Aug 2005 16:03:37 -0000
@@ -1385,20 +1385,8 @@
 
 	if (source->priv->search_text) {
 		GPtrArray *subquery = rhythmdb_query_parse (source->priv->db,
-							    RHYTHMDB_QUERY_PROP_LIKE,
-							    RHYTHMDB_PROP_GENRE_FOLDED,
-							    source->priv->search_text,
-							    RHYTHMDB_QUERY_DISJUNCTION,
-							    RHYTHMDB_QUERY_PROP_LIKE,
-							    RHYTHMDB_PROP_ARTIST_FOLDED,
-							    source->priv->search_text,
-							    RHYTHMDB_QUERY_DISJUNCTION,
-							    RHYTHMDB_QUERY_PROP_LIKE,
-							    RHYTHMDB_PROP_ALBUM_FOLDED,
-							    source->priv->search_text,
-							    RHYTHMDB_QUERY_DISJUNCTION,
-							    RHYTHMDB_QUERY_PROP_LIKE,
-							    RHYTHMDB_PROP_TITLE_FOLDED,
+							    RHYTHMDB_QUERY_PROP_FUZZY_MATCH,
+							    RHYTHMDB_PROP_SEARCH_STRING,
 							    source->priv->search_text,
 							    RHYTHMDB_QUERY_END);
 		rhythmdb_query_append (source->priv->db,
