[Slim-Checkins] r8758 - in /trunk/server: ./ HTML/EN/ SQL/mysql/ Slim/ Slim/Control/ Slim/Schema/ Slim/Schema/ResultSet/ Slim/Utils/ Slim/Web/Pages/

dsully at svn.slimdevices.com dsully at svn.slimdevices.com
Tue Aug 1 13:45:58 PDT 2006


Author: dsully
Date: Tue Aug  1 13:45:38 2006
New Revision: 8758

URL: http://svn.slimdevices.com?rev=8758&view=rev
Log:
Bug: 3793
Description: Refactor Web Searching (part 1):

* Add searchRef type so that the same search can be performed again.
  Use in place of listRef, so we don't keep a large list of objects in memory.

* Fix All Songs links when searching to search a searchRef or *.namesearch

* Move searchStringSplit() into Slim::Utils::Text

* Move as much common code as possible into Web::Search()

* Turn on comment & lyrics search. These columns need to be TEXT in the DB to
  allow for case insensitive searching.

* Further TODO (perhaps post 6.5) - the loop in ::Search and ::BrowseDB are very similar.

Modified:
    trunk/server/Changelog6.html
    trunk/server/HTML/EN/advanced_search.html
    trunk/server/HTML/EN/search.html
    trunk/server/SQL/mysql/schema_1_up.sql
    trunk/server/Slim/Control/Commands.pm
    trunk/server/Slim/Schema.pm
    trunk/server/Slim/Schema/ResultSet/Album.pm
    trunk/server/Slim/Schema/ResultSet/Base.pm
    trunk/server/Slim/Schema/ResultSet/Contributor.pm
    trunk/server/Slim/Schema/ResultSet/Genre.pm
    trunk/server/Slim/Schema/ResultSet/Track.pm
    trunk/server/Slim/Schema/Track.pm
    trunk/server/Slim/Utils/Text.pm
    trunk/server/Slim/Web/Pages/BrowseDB.pm
    trunk/server/Slim/Web/Pages/LiveSearch.pm
    trunk/server/Slim/Web/Pages/Search.pm

Modified: trunk/server/Changelog6.html
URL: http://svn.slimdevices.com/trunk/server/Changelog6.html?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Changelog6.html (original)
+++ trunk/server/Changelog6.html Tue Aug  1 13:45:38 2006
@@ -436,6 +436,7 @@
 		<li><a href="http://bugs.slimdevices.com/show_bug.cgi?id=3776">#3776</a> - Dublicate breadcumb links in browse Years</li>
 		<li><a href="http://bugs.slimdevices.com/show_bug.cgi?id=3780">#3780</a> - Artist links lead to all tracks in library</li>
 		<li><a href="http://bugs.slimdevices.com/show_bug.cgi?id=3786">#3786</a> - Browse Genre contains ARRAY(0xnnnnnnn) entries</li>
+		<li><a href="http://bugs.slimdevices.com/show_bug.cgi?id=3793">#3793</a> - Can't play "All Songs" from search result page</li>
 		<li><a href="http://bugs.slimdevices.com/show_bug.cgi?id=3800">#3800</a> - Multi-Discs albums will not show correcty in web interface</li>
 		<li><a href="http://bugs.slimdevices.com/show_bug.cgi?id=3801">#3801</a> - Playing a song from a saved playlist will play the whole list</li>
 		<li><a href="http://bugs.slimdevices.com/show_bug.cgi?id=3803">#3803</a> - changing 'Maintain Client Playlists' setting crashes server</li>

Modified: trunk/server/HTML/EN/advanced_search.html
URL: http://svn.slimdevices.com/trunk/server/HTML/EN/advanced_search.html?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/HTML/EN/advanced_search.html (original)
+++ trunk/server/HTML/EN/advanced_search.html Tue Aug  1 13:45:38 2006
@@ -138,23 +138,20 @@
 	<input name="search.filesize" value="[% search.filesize.value %]" size="12" maxlength="12" style="text-align: right;" type="text">
 	[% "BYTES" | string %]
 [% END %]
-<!-- 
-	Not yet.
 
 	<tr>
 		<td class="content" align="right" nowrap="nowrap" valign="middle" width="25%">[% "COMMENT" | string %]&nbsp;</td>
 		<td class="content" align="left" valign="middle" width="75%">
-			<input name="search.comments" value="" size="[% size %]" maxlength="1000" type="text">
+			<input name="search.comments.value" value="" size="[% size %]" maxlength="1000" type="text">
 		</td>
 	</tr>
 
 	<tr>
-		<td class="content" align="right" nowrap="nowrap" valign="middle" width="25%">Lyrics</td>
+		<td class="content" align="right" nowrap="nowrap" valign="middle" width="25%">[% "LYRICS" | string %]&nbsp;</td>
 		<td class="content" align="left" valign="middle" width="75%">
-		  <input name="search.lyrics" value="" size="[% size %]" maxlength="1000" type="text">
+		  <input name="search.lyrics" value="[% search.lyrics.value %]" size="[% size %]" maxlength="1000" type="text">
 		</td>
 	</tr>
--->
 
 	<tr>
 		<td>&nbsp;</td>
@@ -178,23 +175,17 @@
 	</div>
 
 	<div id="browsedbList">
-		[% IF numresults != '-1' && numresults != '0' %]
-		<div class="even">
-			<div class="browsedbListItem">
-				[% "ALL_SONGS" | string %]
-				<div class="browsedbControls">
-					[% WRAPPER playlink %]href="[% webroot %][% statusroot %]?player=[% playerURI %]&amp;command=playlist&amp;subcommand=playtracks&amp;listref=searchResults"[% END %]
-					[% WRAPPER addlink %]href="[% webroot %][% statusroot %]?player=[% playerURI %]&amp;command=playlist&amp;subcommand=addtracks&amp;listref=searchResults"[% END %]
-				</div>
-			</div>
-		</div>
-		[% ELSIF numresults == '0' %]
-			[% "EMPTY" | string%]
-		[% END %]
-		[% IF browse_items %]
+
+		[% IF browse_items.size %]
+
 			[% FOREACH item = browse_items %]
 				[% PROCESS browsedbitems_list.html %]
 			[% END %]
+
+		[% ELSE %]
+
+			[% "NO_SEARCH_RESULTS" | string %]
+
 		[% END %]
 	</div>
 

Modified: trunk/server/HTML/EN/search.html
URL: http://svn.slimdevices.com/trunk/server/HTML/EN/search.html?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/HTML/EN/search.html (original)
+++ trunk/server/HTML/EN/search.html Tue Aug  1 13:45:38 2006
@@ -6,53 +6,44 @@
 [% PROCESS pageheader.html %]
 <script type="text/javascript" src="/html/prototype.js"></script>
 
-	[% IF liveSearch %]
+[% IF liveSearch %]
 
 	<form id="searchForm" name="searchForm" method="GET" action="search.html">
 		<input type="text" id="query" name="query" size="40" autocomplete="off" />
 
-	[% ELSE %]
+[% ELSE %]
 
 	<form id="searchForm" name="searchForm" method="GET" action="search.html">
 		<input type="text" id="query" name="query" size="40" value="[% query %]"/>
 
-	[% END %]
+[% END %]
 
 		<input name="submit" type=submit class="stdclick" value="[% "SEARCH" | string %]"><p>
 		<input type="hidden" value="1" name="manualSearch">
 		<input type="hidden" value="[% player %]" name="player">
 	</form>
 
-	<div id="search-results"></div>
+<div id="search-results"></div>
 
-	<div id="browsedbHeader">
-		[% IF searchError %]
-			[% searchError %]
+<div id="browsedbHeader">
+	[% IF searchError %]
+		[% searchError %]
+	[% END %]
+	[% IF pageinfo.totalpages && pageinfo.totalpages > 1 %][% PROCESS pagebar %][% END %]
+</div>
+
+<div id="browsedbList">
+
+	[% IF browse_items.size %]
+
+		[% FOREACH item = browse_items %]
+			[% PROCESS browsedbitems_list.html %]
 		[% END %]
-		[% IF pageinfo.totalpages > 1 %][% PROCESS pagebar %][% END %]
-	</div>
 
-	<div id="browsedbList">
-			[% IF numresults != '-1' && numresults != '0' %]
-			<div class="even">
-				<div class="browsedbListItem">
-					[% "ALL_SONGS" | string %]
-					<div class="browsedbControls">
-						[% WRAPPER playlink %]href="[% webroot %][% statusroot %]?player=[% playerURI %]&amp;command=playlist&amp;subcommand=playtracks&amp;listref=searchResults"[% END %]
-						[% WRAPPER addlink %]href="[% webroot %][% statusroot %]?player=[% playerURI %]&amp;command=playlist&amp;subcommand=addtracks&amp;listref=searchResults"[% END %]
-					</div>
-				</div>
-			</div>
-			[% ELSIF numresults == '0' %]
-				[% "NO_SEARCH_RESULTS" | string%]
-			[% END %]
-			[% IF browse_items %]
-				[% FOREACH item = browse_items %]
-					[% PROCESS browsedbitems_list.html %]
-				[% END %]
-			[% END %]
-	</div>
-[% IF pageinfo.totalpages > 1 %][% PROCESS pagebar %][% END %]
+	[% END %]
+</div>
+
+[% IF pageinfo.totalpages && pageinfo.totalpages > 1 %][% PROCESS pagebar %][% END %]
 
 [% IF liveSearch; INCLUDE "search-observer.html"; END %]
 

Modified: trunk/server/SQL/mysql/schema_1_up.sql
URL: http://svn.slimdevices.com/trunk/server/SQL/mysql/schema_1_up.sql?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/SQL/mysql/schema_1_up.sql (original)
+++ trunk/server/SQL/mysql/schema_1_up.sql Tue Aug  1 13:45:38 2006
@@ -78,7 +78,7 @@
   audio bool,
   remote bool,
   lossless bool,
-  lyrics blob,
+  lyrics text, -- needs to be text so that searches are case insensitive.
   moodlogic_id  int(10) unsigned,
   moodlogic_mixable bool,
   musicbrainz_id varchar(40),	-- musicbrainz uuid (36 bytes of text)
@@ -250,7 +250,7 @@
 CREATE TABLE comments (
   id int(10) unsigned NOT NULL auto_increment,
   track  int(10) unsigned,
-  value blob,
+  value text, -- needs to be text so that searches are case insensitive.
   PRIMARY KEY (id),
   INDEX trackIndex (track),
   FOREIGN KEY (`track`) REFERENCES `tracks` (`id`) ON DELETE CASCADE

Modified: trunk/server/Slim/Control/Commands.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Control/Commands.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Control/Commands.pm (original)
+++ trunk/server/Slim/Control/Commands.pm Tue Aug  1 13:45:38 2006
@@ -1002,9 +1002,16 @@
 	# parse the param
 	my @tracks = ();
 
-	if ($what =~ /listref/i) {
+	if ($what =~ /listRef/i) {
+
 		@tracks = _playlistXtracksCommand_parseListRef($client, $what, $listref);
+
+	} elsif ($what =~ /searchRef/i) {
+
+		@tracks = _playlistXtracksCommand_parseSearchRef($client, $what, $listref);
+
 	} else {
+
 		@tracks = _playlistXtracksCommand_parseSearchTerms($client, $what);
 	}
 
@@ -2109,7 +2116,14 @@
 
 		} else {
 
-			$find{$key} = Slim::Utils::Text::ignoreCaseArticles($value);
+			if ($key =~ /\.(?:name|title)search$/) {
+
+				$find{$key} = { 'like' => Slim::Utils::Text::searchStringSplit($value) };
+
+			} else {
+
+				$find{$key} = Slim::Utils::Text::ignoreCaseArticles($value);
+			}
 		}
 	}
 
@@ -2175,6 +2189,28 @@
 	}
 }
 
+sub _playlistXtracksCommand_parseSearchRef {
+	my $client    = shift;
+	my $term      = shift;
+	my $searchRef = shift;
+
+	$d_commands && msg("Commands::_playlistXtracksCommand_parseSearchRef()\n");
+
+	if ($term =~ /searchRef=(\w+)&?/i) {
+		$searchRef = $client->param($1);
+	}
+
+	my $cond = $searchRef->{'cond'} || {};
+	my $attr = $searchRef->{'attr'} || {};
+
+	# XXX - For some reason, the join key isn't passed along with the ref.
+	# Perl bug because 'join' is a keyword?
+	if (!$attr->{'join'} && $attr->{'joins'}) {
+		$attr->{'join'} = delete $attr->{'joins'};
+	}
+
+	return Slim::Schema->rs('Track')->search($cond, $attr)->distinct->all;
+}
 
 sub _showCommand_done {
 	my $args = shift;

Modified: trunk/server/Slim/Schema.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Schema.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Schema.pm (original)
+++ trunk/server/Slim/Schema.pm Tue Aug  1 13:45:38 2006
@@ -302,6 +302,13 @@
 	return $object;
 }
 
+# Return the common searchable types.
+sub searchTypes {
+	my $class = shift;
+
+	return qw(contributor album track);
+}
+
 sub lastRescanTime {
 	my $class = shift;
 
@@ -1691,9 +1698,6 @@
 
 			} else {
 
-				# Check if the album name is one of the "common album names"
-				# we've identified in prefs. If so, we require a match on
-				# both album name and primary artist name.
 				if (blessed($contributor)) {
 					$search->{'contributor'} = $contributor->id;
 				}

Modified: trunk/server/Slim/Schema/ResultSet/Album.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Schema/ResultSet/Album.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Schema/ResultSet/Album.pm (original)
+++ trunk/server/Slim/Schema/ResultSet/Album.pm Tue Aug  1 13:45:38 2006
@@ -52,13 +52,21 @@
 	return 1;
 }
 
+sub searchColumn {
+	my $self  = shift;
+
+	return 'titlesearch';
+}
+
 sub searchNames {
-	my ($self, $terms) = @_;
+	my $self  = shift;
+	my $terms = shift;
+	my $attrs = shift || {};
 
-	return $self->search(
-		{ 'me.titlesearch' => { 'like' => $terms } },
-		{ 'order_by' => 'me.titlesort, me.disc', 'distinct' => 'me.id' }
-	);
+	$attrs->{'order_by'} ||= 'me.titlesort, me.disc';
+	$attrs->{'distinct'} ||= 'me.id';
+
+	return $self->search({ 'me.titlesearch' => { 'like' => $terms } }, $attrs);
 }
 
 sub browse {

Modified: trunk/server/Slim/Schema/ResultSet/Base.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Schema/ResultSet/Base.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Schema/ResultSet/Base.pm (original)
+++ trunk/server/Slim/Schema/ResultSet/Base.pm Tue Aug  1 13:45:38 2006
@@ -15,6 +15,7 @@
 sub descendTransform   { '' }
 sub browseBodyTemplate { '' }
 sub orderBy            { '' }
+sub searchColumn       { 'id' }
 sub pageBarResults     { 0 }
 sub alphaPageBar       { 0 }
 sub ignoreArticles     { 0 }

Modified: trunk/server/Slim/Schema/ResultSet/Contributor.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Schema/ResultSet/Contributor.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Schema/ResultSet/Contributor.pm (original)
+++ trunk/server/Slim/Schema/ResultSet/Contributor.pm Tue Aug  1 13:45:38 2006
@@ -36,8 +36,16 @@
 sub alphaPageBar { 1 }
 sub ignoreArticles { 1 }
 
+sub searchColumn {
+	my $self  = shift;
+
+	return 'namesearch';
+}
+
 sub searchNames {
-	my ($self, $terms) = @_;
+	my $self  = shift;
+	my $terms = shift;
+	my $attrs = shift || {};
 
 	my @joins = ();
 	my $cond  = {
@@ -51,11 +59,11 @@
 		push @joins, 'contributorAlbums';
 	}
 
-	return $self->search($cond, {
-		'order_by' => 'me.namesort',
-		'distinct' => 'me.id',
-		'join'     => \@joins,
-	});
+	$attrs->{'order_by'} ||= 'me.namesort';
+	$attrs->{'distinct'} ||= 'me.id';
+	$attrs->{'join'}     ||= \@joins;
+
+	return $self->search($cond, $attrs);
 }
 
 sub browse {

Modified: trunk/server/Slim/Schema/ResultSet/Genre.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Schema/ResultSet/Genre.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Schema/ResultSet/Genre.pm (original)
+++ trunk/server/Slim/Schema/ResultSet/Genre.pm Tue Aug  1 13:45:38 2006
@@ -35,13 +35,21 @@
 
 sub alphaPageBar { 1 }
 
+sub searchColumn {
+	my $self  = shift;
+
+	return 'namesearch';
+}
+
 sub searchNames {
-	my ($self, $terms) = @_;
+	my $self  = shift;
+	my $terms = shift;
+	my $attrs = shift || {};
 
-	return $self->search(
-		{ 'me.namesearch' => { 'like' => $terms } },
-		{ 'order_by' => 'me.namesort', 'distinct' => 'me.id' }
-	);
+	$attrs->{'order_by'} ||= 'me.namesort';
+	$attrs->{'distinct'} ||= 'me.id';
+
+	return $self->search({ 'me.namesearch' => { 'like' => $terms } }, $attrs);
 }
 
 sub browse {

Modified: trunk/server/Slim/Schema/ResultSet/Track.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Schema/ResultSet/Track.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Schema/ResultSet/Track.pm (original)
+++ trunk/server/Slim/Schema/ResultSet/Track.pm Tue Aug  1 13:45:38 2006
@@ -35,13 +35,24 @@
 
 sub ignoreArticles { 1 }
 
+sub searchColumn {
+	my $self  = shift;
+
+	return 'titlesearch';
+}
+
 sub searchNames {
-	my ($self, $terms) = @_;
+	my $self  = shift;
+	my $terms = shift;
+	my $attrs = shift || {};
+
+	$attrs->{'order_by'} ||= 'me.disc, me.titlesort';
+	$attrs->{'distinct'} ||= 'me.id';
 
 	return $self->search({
 		'me.titlesearch' => { 'like' => $terms },
 		'me.audio'       => 1,
-	}, { 'order_by' => 'me.titlesort', 'distinct' => 'me.id' });
+	}, $attrs);
 }
 
 sub orderBy {

Modified: trunk/server/Slim/Schema/Track.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Schema/Track.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Schema/Track.pm (original)
+++ trunk/server/Slim/Schema/Track.pm Tue Aug  1 13:45:38 2006
@@ -13,10 +13,10 @@
 use Slim::Utils::Misc;
 
 our @allColumns = (qw(
-	id url content_type title titlesort titlesearch album tracknum timestamp
-	filesize tag disc thumb remote audio audio_size audio_offset
-	year secs cover vbr_scale bitrate samplerate samplesize channels block_alignment
-	endian bpm tagversion drm moodlogic_id moodlogic_mixable musicmagic_mixable
+	id url content_type title titlesort titlesearch album tracknum
+	timestamp filesize disc thumb remote audio audio_size audio_offset year secs
+	cover vbr_scale bitrate samplerate samplesize channels block_alignment endian
+	bpm tagversion drm moodlogic_id moodlogic_mixable musicmagic_mixable
 	musicbrainz_id playcount lastplayed lossless lyrics rating replay_gain replay_peak
 ));
 
@@ -33,7 +33,7 @@
 	$class->belongs_to('album' => 'Slim::Schema::Album');
 
 	$class->has_many('genreTracks'       => 'Slim::Schema::GenreTrack' => 'track');
-	$class->has_many('comment_objects'   => 'Slim::Schema::Comment'    => 'track');
+	$class->has_many('comments'          => 'Slim::Schema::Comment'    => 'track');
 
 	$class->has_many('contributorTracks' => 'Slim::Schema::ContributorTrack');
 
@@ -66,12 +66,6 @@
 	)->search(@_);
 }
 
-sub comments {
-	my $self = shift;
-
-	return map { $_->value } $self->comment_objects(@_);
-}
-
 sub genres {
 	my $self = shift;
 
@@ -149,7 +143,7 @@
 	my $comment;
 
 	# extract multiple comments and concatenate them
-	for my $c ($self->comments) {
+	for my $c (map { $_->value } $self->comments) {
 
 		next unless $c;
 
@@ -388,7 +382,7 @@
 	for my $mixer (keys %{$Imports}) {
 
 		if (defined $Imports->{$mixer}->{'mixerlink'}) {
-			&{$Imports->{$mixer}->{'mixerlink'}}($self,$form,0);
+			&{$Imports->{$mixer}->{'mixerlink'}}($self, $form, 0);
 		}
 	}
 }

Modified: trunk/server/Slim/Utils/Text.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Utils/Text.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Utils/Text.pm (original)
+++ trunk/server/Slim/Utils/Text.pm Tue Aug  1 13:45:38 2006
@@ -101,11 +101,34 @@
 	$ignoredArticles   = undef;
 }
 
+sub searchStringSplit {
+	my $search  = shift;
+	my $searchSubString = shift;
+
+	$searchSubString = defined $searchSubString ? $searchSubString : Slim::Utils::Prefs::get('searchSubString');
+
+	# normalize the string
+	$search = ignoreCaseArticles($search);
+	
+	my @strings = ();
+
+	# Don't split - causes an explict AND, which is what we want.. I think.
+	# for my $string (split(/\s+/, $search)) {
+	my $string = $search;
+
+		if ($searchSubString) {
+
+			push @strings, "\%$string\%";
+
+		} else {
+
+			push @strings, [ "$string\%", "\% $string\%" ];
+		}
+	#}
+
+	return \@strings;
+}
+
 1;
 
 __END__
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:t
-# End:

Modified: trunk/server/Slim/Web/Pages/BrowseDB.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Pages/BrowseDB.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Web/Pages/BrowseDB.pm (original)
+++ trunk/server/Slim/Web/Pages/BrowseDB.pm Tue Aug  1 13:45:38 2006
@@ -98,7 +98,6 @@
 		'title'	       => $title,
 		'hierarchy'    => $hierarchy,
 		'level'	       => 0,
-		'attributes'   => (scalar(@attrs) ? ('&' . join("&", @attrs)) : ''),
 	);
 
 	push @{$params->{'pwd_list'}}, {
@@ -107,7 +106,6 @@
 		'hierarchy'    => $hierarchy,
 		'level'	       => 0,
 		'orderBy'      => $orderBy,
-		'attributes'   => (scalar(@attrs) ? ('&' . join("&", @attrs)) : ''),
 	};
 
 	# We want to include Compilations in the pwd, so we need the artist,

Modified: trunk/server/Slim/Web/Pages/LiveSearch.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Pages/LiveSearch.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Web/Pages/LiveSearch.pm (original)
+++ trunk/server/Slim/Web/Pages/LiveSearch.pm Tue Aug  1 13:45:38 2006
@@ -7,7 +7,6 @@
 # the results as XMLish data stream, to be dynamically displayed in a <div>
 #
 # Todo - call filltemplate stuff instead? May be too slow.
-# Use LIMIT - but then we don't get our "total matches" correct.
 
 use strict;
 
@@ -19,47 +18,10 @@
 
 use constant MAXRESULTS => 10;
 
-my @allTypes = qw(contributor album track);
-
-sub query {
-	my ($class, $query, $types, $limit, $offset) = @_;
-
-	my @data   = ();
-	my $search = Slim::Web::Pages::Search::searchStringSplit($query);
-
-	# Default to a valid list of types
-	if (!ref($types) || !defined $types->[0]) {
-
-		$types = \@allTypes;
-	}
-
-	for my $type (@$types) {
-
-		my $rs      = Slim::Schema->rs($type)->searchNames($search);
-		my $count   = $rs->count;
-		my @results = ();
-
-		if ($count) {
-
-			@results = $rs->slice($offset, $limit);
-		}
-
-		push @data, [ $type, $count, \@results ];
-	}
-
-	return \@data;
-}
-
-sub queryWithLimit {
-	my ($class, $query, $types, $limit, $offset) = @_;
-
-	return $class->query($query, $types, ($limit || MAXRESULTS), ($offset || 0));
-}
-
-sub outputAsXHTML { 
+sub outputAsXHTML {
 	my $class   = shift;
 	my $query   = shift;
-	my $results = shift;
+	my $rsList  = shift;
 	my $player  = shift;
 
 	my @xml = (
@@ -67,28 +29,20 @@
 		'<div id="browsedbList">',
 	);
 
-	for my $result (@$results) {
+	for my $rs (@$rsList) {
 
-		my $type   = $result->[0];
-		my $total  = $result->[1];
-		my $data   = $result->[2];
+		my $type   = lc($rs->result_source->source_name);
+		my $total  = $rs->count;
 		my $count  = 0;
 		my @output = ();
 
-		next unless ref($data);
-
-		for my $item (@{$data}) {
+		while (my $item = $rs->next) {
 
 			if ($count <= MAXRESULTS) {
 
 				my $rowType = $count % 2 ? 'even' : 'odd';
 
-				push @output, renderItem(
-					$rowType,
-					$type,
-					$item,
-					$player
-				);
+				push @output, renderItem($rowType, $type, $item, $player);
 			}
 
 			$count++;
@@ -108,9 +62,58 @@
 	}
 
 	push @xml, "</div>\n";
-	my $string = join('', @xml);
 
-	return \$string;
+	return \join('', @xml);
+}
+
+sub outputAsXML {
+	my $class   = shift;
+	my $query   = shift;
+	my $rsList  = shift;
+	my $player  = shift;
+
+	my @xml = (
+		'<?xml version="1.0" encoding="utf-8" standalone="yes"?>',
+		'<livesearch>',
+	);
+
+	for my $rs (@$rsList) {
+
+		my $type   = lc($rs->result_source->source_name);
+		my $total  = $rs->count;
+		my $count  = 0;
+		my @output = ();
+
+		while (my $item = $rs->next) {
+
+			my $rowType = $count % 2 ? 'even' : 'odd';
+
+			if ($count <= MAXRESULTS) {
+
+				push @output, sprintf('<livesearchitem id="%s">%s</livesearchitem>', $item->id, $item->name);
+			}
+
+			$count++;
+		}
+
+		push @xml, sprintf("<searchresults type=\"%s\" hierarchy=\"%s\" mstring=\"%s &quot;$query&quot;: $total\">", 
+			$type,
+			$Slim::Web::Pages::hierarchy{$type} || '',
+			Slim::Utils::Strings::string(uc($type . 'SMATCHING'))
+		);
+
+		push @xml, @output if $count;
+
+		if ($total && $total > MAXRESULTS) {
+			push @xml, "<morematches query=\"$query\"/>";
+		}
+
+		push @xml, "</searchresults>";
+	}
+
+	push @xml, "</livesearch>\n";
+
+	return \join('', @xml);
 }
 
 sub renderItem {
@@ -180,64 +183,8 @@
 		<img src=\"html/images/b_add.gif\" width=\"13\" height=\"13\" alt=\"Add to playlist\" title=\"Add to playlist\"/></a> \n
 		</div>\n</div>\n</div>\n";
 
-	my $string = join('', @xml);
-
-	return $string;
+	return join('', @xml);
 }
-
-sub outputAsXML { 
-	my $class   = shift;
-	my $query   = shift;
-	my $results = shift;
-	my $player  = shift;
-
-	my @xml = (
-		'<?xml version="1.0" encoding="utf-8" standalone="yes"?>',
-		'<livesearch>',
-	);
-
-	for my $result (@$results) {
-
-		my $type   = $result->[0];
-		my $total  = $result->[1];
-		my $data   = $result->[2];
-		my $count  = 0;
-		my @output = ();
-
-		for my $item (@{$data}) {
-
-			my $rowType = $count % 2 ? 'even' : 'odd';
-			if ($count <= MAXRESULTS) {
-
-				push @output, sprintf('<livesearchitem id="%s">%s</livesearchitem>',
-					$item->id, $item->name,
-				);
-			}
-
-			$count++;
-		}
-
-		push @xml, sprintf("<searchresults type=\"%s\" hierarchy=\"%s\" mstring=\"%s &quot;$query&quot;: $total\">", 
-			$type,
-			$Slim::Web::Pages::hierarchy{$type} || '',
-			Slim::Utils::Strings::string(uc($type . 'SMATCHING'))
-		);
-
-		push @xml, @output if $count;
-
-		if ($total && $total > MAXRESULTS) {
-			push @xml, "<morematches query=\"$query\"/>";
-		}
-
-		push @xml, "</searchresults>";
-	}
-
-	push @xml, "</livesearch>\n";
-	my $string = join('', @xml);
-
-	return \$string;
-}
-
 1;
 
 __END__

Modified: trunk/server/Slim/Web/Pages/Search.pm
URL: http://svn.slimdevices.com/trunk/server/Slim/Web/Pages/Search.pm?rev=8758&r1=8757&r2=8758&view=diff
==============================================================================
--- trunk/server/Slim/Web/Pages/Search.pm (original)
+++ trunk/server/Slim/Web/Pages/Search.pm Tue Aug  1 13:45:38 2006
@@ -11,13 +11,13 @@
 
 use Date::Parse qw(str2time);
 use File::Spec::Functions qw(:ALL);
-use POSIX ();
 use Scalar::Util qw(blessed);
 
 use Slim::Player::TranscodingHelper;
 use Slim::Utils::DateTime;
 use Slim::Utils::Misc;
 use Slim::Utils::Strings qw(string);
+use Slim::Utils::Text;
 use Slim::Web::Pages;
 use Slim::Web::Pages::LiveSearch;
 
@@ -37,10 +37,10 @@
 	my $query  = $params->{'query'};
 
 	# set some defaults for the template
-	$params->{'browse_list'} = " ";
-	$params->{'numresults'}  = -1;
-	$params->{'itemsPerPage'} ||= Slim::Utils::Prefs::get('itemsPerPage');
+	$params->{'browse_list'}  = " ";
+	$params->{'numresults'}   = -1;
 	$params->{'browse_items'} = [];
+	$params->{'artwork'}      = 0;
 
 	# short circuit
 	if (!defined($query) || ($params->{'manualSearch'} && !$query)) {
@@ -53,50 +53,45 @@
 	}
 
 	# Don't kill the database - use limit & offsets
-	my $data = Slim::Web::Pages::LiveSearch->queryWithLimit($query, [ $params->{'type'} ], $params->{'itemsPerPage'}, $params->{'start'});
+	my $types  = [ $params->{'type'} ];
+	my $limit  = $params->{'itemPerPage'} || 10;
+	my $offset = $params->{'start'} || 0;
+	my $search = Slim::Utils::Text::searchStringSplit($query);
+
+	# Default to a valid list of types
+	if (!ref($types) || !defined $types->[0]) {
+
+		$types = [ Slim::Schema->searchTypes ];
+	}
+
+	my @rsList = ();
+
+	# Create a ResultSet for each of Contributor, Album & Track
+	for my $type (@$types) {
+
+		my $rs = Slim::Schema->rs($type)->searchNames($search);
+		push @rsList, $rs;
+	}
 
 	# The user has hit enter, or has a browser that can't handle the javascript.
 	if ($params->{'manualSearch'}) {
 
 		# Tell the template not to do a livesearch request anymore.
 		$params->{'liveSearch'} = 0;
-
-		my @results = ();
-		my $descend = 1;
-		my @qstring = ('manualSearch=1');
-
-		for my $item (@$data) {
-
-			$params->{'type'}       = $item->[0];
-			$params->{'numresults'} = $item->[1];
-			$params->{'path'}       = 'search.html';
-
-			if ($params->{'type'} eq 'track' && $params->{'numresults'}) {
-
-				push @results, $item->[2];
-
-				$descend = undef;
-			}
-
-			fillInSearchResults($params, $item->[2], $descend, \@qstring);
-		}
-
-		if (defined $client && scalar @results && !$params->{'start'}) {
-			# stash the full resultset if not paging through the results
-			# assumes that when the start parameter is 0 or undefined that
-			# the query has just been run
-			my $fulldata = Slim::Web::Pages::LiveSearch->query($query, [ 'track' ]);
-			$client->param('searchResults', $fulldata->[0][2]);
+		$params->{'path'}       = 'search.html';
+
+		for my $rs (@rsList) {
+
+			fillInSearchResults($params, $rs, [ 'manualSearch=1' ]);
 		}
 
 		return Slim::Web::HTTP::filltemplatefile("search.html", $params);
-	}
-
-	# do it live - and send back the div
-	if ($params->{'xmlmode'}) {
-		return Slim::Web::Pages::LiveSearch->outputAsXML($query, $data, $player);
+
 	} else {
-		return Slim::Web::Pages::LiveSearch->outputAsXHTML($query, $data, $player);
+
+		# do it live - and send back the div
+		# this should be replaced with a call to filltemplatefile()
+		return Slim::Web::Pages::LiveSearch->outputAsXHTML($query, \@rsList, $player);
 	}
 }
 
@@ -108,10 +103,9 @@
 	my @qstring = ();
 
 	# template defaults
-	$params->{'browse_list'} = " ";
-	$params->{'liveSearch'}  = 0;
+	$params->{'browse_list'}  = " ";
+	$params->{'liveSearch'}   = 0;
 	$params->{'browse_items'} = [];
-	$params->{'itemsPerPage'} ||= Slim::Utils::Prefs::get('itemsPerPage');
 
 	# Prep the date format
 	$params->{'dateFormat'} = Slim::Utils::DateTime::shortDateF();
@@ -174,13 +168,13 @@
 		# We need the _'s in the form, because . means hash key.
 		if ($newKey =~ s/_(titlesearch|namesearch)$/\.$1/) {
 
-			$params->{$key} = { 'like' => searchStringSplit($params->{$key}) };
-		}
-
-		# Wildcard comment searches
-		if ($newKey =~ /comment/) {
-
-			$params->{$key} = "\*$params->{$key}\*";
+			$params->{$key} = { 'like' => Slim::Utils::Text::searchStringSplit($params->{$key}) };
+		}
+
+		# Wildcard searches
+		if ($newKey =~ /comment/ || $newKey =~ /lyrics/) {
+
+			$params->{$key} = { 'like' => Slim::Utils::Text::searchStringSplit($params->{$key}) };
 		}
 
 		$query{$newKey} = $params->{$key};
@@ -203,7 +197,8 @@
 
 	# short-circuit the query
 	if (scalar keys %query == 0) {
-		$params->{'numresults'}  = -1;
+		$params->{'numresults'} = -1;
+
 		return Slim::Web::HTTP::filltemplatefile("advanced_search.html", $params);
 	}
 
@@ -227,6 +222,7 @@
 		}
 	}
 
+	# Pull in the required joins
 	if ($query{'genre'}) {
 
 		push @joins, 'genreTracks';
@@ -235,6 +231,11 @@
 	if ($query{'album.titlesearch'}) {
 
 		push @joins, 'album';
+	}
+
+	if ($query{'comments.value'}) {
+
+		push @joins, 'comments';
 	}
 
 	# Disambiguate year
@@ -242,181 +243,140 @@
 		$query{'me.year'} = delete $query{'year'};
 	}
 
-	# Do the actual search
-	my $rs    = Slim::Schema->search('Track',
-		\%query,
-		{ 'order_by' => 'titlesort', 'join' => \@joins }
+	# XXXX - for some reason, the 'join' key isn't preserved when passed
+	# along as a ref. Perl bug because 'join' is a keyword? Use 'joins' as well.
+	my %attrs = (
+		'order_by' => 'me.disc, me.titlesort',
+		'join'     => \@joins,
+		'joins'    => \@joins,
 	);
 
-	my $count = $rs->count;
-
-	my $start = ($params->{'start'} || 0),
-	my $end   = $params->{'itemsPerPage'} - 1;
+	# Create a resultset - have fillInSearchResults do the actual search.
+	my $rs  = Slim::Schema->search('Track', \%query, \%attrs);
 
 	if (defined $client && !$params->{'start'}) {
 
-		# stash the full resultset if not paging through the results
-		# assumes that when the start parameter is 0 or undefined that
-		# the query has just been run
-		$client->param('searchResults', [ $rs->all ]);
-
-		$rs->reset;
-	}
-
-	if ($count == $params->{'itemsPerPage'}) {
-
-		$params->{'numresults'} = $count;
-	}
-	
-	fillInSearchResults($params, [ $rs->slice($start, $end) ], undef, \@qstring, 1);
+		# stash parameters used to generate this query, so if the user
+		# wants to play All Songs, we can run it again, but without
+		# keeping all the tracks in memory twice.
+		$client->param('searchTrackResults', { 'cond' => \%query, 'attr' => \%attrs });
+	}
+
+	fillInSearchResults($params, $rs, \@qstring, 1);
 
 	return Slim::Web::HTTP::filltemplatefile("advanced_search.html", $params);
 }
 
 sub fillInSearchResults {
-	my ($params, $results, $descend, $qstring, $typeSeparator) = @_;
+	my ($params, $rs, $qstring, $typeSeparator) = @_;
 
 	my $player = $params->{'player'};
 	my $query  = $params->{'query'}  || '';
-	my $type   = $params->{'type'}   || 'track';
-
-	$params->{'type'} = $type;
-	
+	my $type   = lc($rs->result_source->source_name) || 'track';
+	my $count  = $rs->count || return 0;
+
+	# Set some reasonable defaults
+	$params->{'numresults'}   = $count;
+	$params->{'itemsPerPage'} ||= Slim::Utils::Prefs::get('itemsPerPage');
+
+	# This is handed to pageInfo to generate the pagebar 1 2 3 >> links.
 	my $otherParams = 'player=' . Slim::Utils::Misc::escape($player) . 
 			  ($type ?'&type='. $type : '') . 
 			  ($query ? '&query=' . Slim::Utils::Misc::escape($query) : '' ) . 
 			  '&' .
 			  join('&', @$qstring);
 
-	# Make sure that we have something to show.
-	if (!defined $params->{'numresults'} && defined $results && ref($results) eq 'ARRAY') {
-
-		$params->{'numresults'} = scalar @$results;
-	}
-
-	# put in the type separator
-	if ($type && !$typeSeparator) {
+	# Put in the type separator
+	if (!$typeSeparator && $count) {
 
 		# add reduced item for type headings
 		push @{$params->{'browse_items'}}, {
-			'numresults' => $params->{'numresults'},
-			'query'   => $query,
-			'heading' => $type,
+			'numresults' => $count,
+			'query'      => $query,
+			'heading'    => $type,
+			'odd'        => 0,
 		};
 	}
 
-	my ($start, $end);
-
-	if ($params->{'numresults'}) {
-
-		$params->{'pageinfo'} = Slim::Web::Pages->pageInfo({
-
-			'itemCount'    => $params->{'numresults'},
-			'path'         => $params->{'path'},
-			'otherParams'  => $otherParams,
-			'start'        => $params->{'start'},
-			'perPage'      => $params->{'itemsPerPage'},
-		});
-
-		$start = $params->{'start'} = $params->{'pageinfo'}{'startitem'};
-		$end   = $params->{'pageinfo'}{'enditem'};
-		
-		my $itemnumber = 1;
-		my $lastAnchor = '';
-
-		for my $item (@$results) {
-
-			next unless defined $item && ref($item);
-
-			# Contributor/Artist uses name, Album & Track uses title.
-			my %form = %$params;
-
-			$form{'attributes'} = '&' . join('.id=', $type, $item->id);
-			$form{'descend'}    = $descend;
-			$form{'odd'}        = ($itemnumber) % 2;
-
-			if ($type eq 'track') {
-				
-				# If we can't get an object for this url, skip it, as the
-				# user's database is likely out of date. Bug 863
-				my $itemObj = $item;
-
-				if (!blessed($itemObj) || !$itemObj->can('id')) {
-
-					$itemObj = Slim::Schema->rs('Track')->objectForUrl($item);
-				}
-
-				if (!blessed($itemObj) || !$itemObj->can('id')) {
-
-					next;
-				}
-
-				$itemObj->displayAsHTML(\%form, 0);
-
-			} else {
-
-				if ($type eq 'contributor') {
-
-					$form{'hierarchy'} = 'contributor,album,track';
-					$form{'level'}     = 1;
-					$form{'hreftype'}  = 'browseDb';
-
-				} elsif ($type eq 'album') {
-
-					$form{'hierarchy'} = 'album,track';
-					$form{'level'}     = 1;
-					$form{'hreftype'}  = 'browseDb';
-				}
-				
-				$form{'text'} = $item->name;
-			}
-
-			$itemnumber++;
-
-			my $anchor = substr($item->namesort, 0, 1);
-
-			if ($lastAnchor ne $anchor) {
-				$form{'anchor'} = $lastAnchor = $anchor;
-			}
-
-			push @{$params->{'browse_items'}}, \%form;
-		}
+	# Add in ALL
+	if ($count > 1) {
+
+		my $attributes = '';
+
+		if ($typeSeparator) {
+			$attributes = sprintf('&searchRef=search%sResults', ucfirst($type));
+		} else {
+			$attributes = sprintf('&%s.%s=%s', $type, $rs->searchColumn, $query);
+		}
+
+		push @{$params->{'browse_items'}}, {
+			'text'       => string('ALL_SONGS'),
+			'player'     => $params->{'player'},
+			'attributes' => $attributes,
+			'odd'        => 1,
+		};
+	}
+
+	my $offset = ($params->{'start'} || 0),
+	my $limit  = ($params->{'itemsPerPage'} || 10) - 1;
+
+	$params->{'pageinfo'} = Slim::Web::Pages->pageInfo({
+
+		'itemCount'    => $params->{'numresults'},
+		'path'         => $params->{'path'},
+		'otherParams'  => $otherParams,
+		'start'        => $params->{'start'},
+		'perPage'      => $params->{'itemsPerPage'},
+	});
+
+	$params->{'start'} = $params->{'pageinfo'}{'startitem'};
+	
+	my $itemCount  = 1;
+	my $lastAnchor = '';
+	my $descend    = $type eq 'track' ? 0 : 1;
+
+	# Get just the items we need for this loop.
+	$rs = $rs->slice($offset, $limit);
+
+	# This is very similar to a loop in Slim::Web::Pages::BrowseDB....
+	while (my $obj = $rs->next) {
+
+		my %form = (
+			'levelName'    => $type,
+			'hreftype'     => 'browseDb',
+			'descend'      => $descend,
+			'odd'          => ($itemCount + 1) % 2,
+			'skinOverride' => $params->{'skinOverride'},
+			'player'       => $params->{'player'},
+			'itemobj'      => $obj,
+			'level'        => 1,
+			'artwork'      => 0,
+			'attributes'   => sprintf('&%s.id=%d', $type, $obj->id),
+		);
+
+		if ($type eq 'contributor') {
+
+			$form{'hierarchy'} = 'contributor,album,track';
+
+		} elsif ($type eq 'album') {
+
+			$form{'hierarchy'} = 'album,track';
+		}
+
+		$obj->displayAsHTML(\%form, $descend);
+
+		$itemCount++;
+
+		my $anchor = substr($obj->namesort, 0, 1);
+
+		if ($lastAnchor ne $anchor) {
+			$form{'anchor'} = $lastAnchor = $anchor;
+		}
+
+		push @{$params->{'browse_items'}}, \%form;
 	}
 }
 
-sub searchStringSplit {
-	my $search  = shift;
-	my $searchSubString = shift;
-	
-	$searchSubString = defined $searchSubString ? $searchSubString : Slim::Utils::Prefs::get('searchSubString');
-
-	# normalize the string
-	$search = Slim::Utils::Text::ignoreCaseArticles($search);
-	
-	my @strings = ();
-
-	# Don't split - causes an explict AND, which is what we want.. I think.
-	# for my $string (split(/\s+/, $search)) {
-	my $string = $search;
-
-		if ($searchSubString) {
-
-			push @strings, "\%$string\%";
-
-		} else {
-
-			push @strings, [ "$string\%", "\% $string\%" ];
-		}
-	#}
-
-	return \@strings;
-}
-
 1;
 
 __END__
-
-# Local Variables:
-# tab-width:4
-# indent-tabs-mode:t
-# End:



More information about the checkins mailing list