Index: /Users/mh/Documents/workspace/Boom/server/Slim/Control/Queries.pm =================================================================== --- /Users/mh/Documents/workspace/Boom/server/Slim/Control/Queries.pm (revision 23017) +++ /Users/mh/Documents/workspace/Boom/server/Slim/Control/Queries.pm (working copy) @@ -1547,7 +1547,21 @@ } # Pull the directory list, which will be used for looping. - my ($topLevelObj, $items, $count) = Slim::Utils::Misc::findAndScanDirectoryTree($params); + my ($topLevelObj, $items, $count); + + # if this is a follow up query ($index > 0), try to read from the cache + if ($index > 0 && $cache->{bmf} + && $cache->{bmf}->{id} eq ($params->{url} || $params->{id}) + && $cache->{bmf}->{ttl} > time()) { + + $items = $cache->{bmf}->{items}; + $topLevelObj = $cache->{bmf}->{topLevelObj}; + $count = $cache->{bmf}->{count}; + } + else { + + ($topLevelObj, $items, $count) = Slim::Utils::Misc::findAndScanDirectoryTree($params); + } # create filtered data @@ -1553,41 +1567,6 @@ my $topPath = $topLevelObj->path; my $osName = Slim::Utils::OSDetect::OS(); - my @data; - - for my $relPath (@$items) { - - $log->debug("relPath: $relPath" ); - - my $url = Slim::Utils::Misc::fixPath($relPath, $topPath) || next; - - $log->debug("url: $url" ); - - # Amazingly, this just works. :) - # Do the cheap compare for osName first - so non-windows users - # won't take the penalty for the lookup. - if ($osName eq 'win' && Slim::Music::Info::isWinShortcut($url)) { - $url = Slim::Utils::Misc::fileURLFromWinShortcut($url); - } - - my $item = Slim::Schema->rs('Track')->objectForUrl({ - 'url' => $url, - 'create' => 1, - 'readTags' => 1, - }); - - if (!blessed($item) || !$item->can('content_type')) { - - next; - } - - # Bug: 1360 - Don't show files referenced in a cuesheet - next if ($item->content_type eq 'cur'); - - push @data, $item; - } - - $count = scalar(@data); # now build the result @@ -1659,20 +1638,24 @@ my ($valid, $start, $end) = $request->normalize(scalar($index), scalar($quantity), $count); - my @playlist = (); - if ( $playalbum ) { - for my $eachitem (@data[$start..$end]) { - if (Slim::Music::Info::isSong($eachitem)) { - push @playlist, $eachitem->url; + if ($valid) { + + my @playlist = (); + my %urls; + + for my $eachitem (@$items[$start..$end]) { + + my $url = Slim::Utils::Misc::fixPath($eachitem, $topPath) || next; + $urls{$eachitem} = $url; + + if ( $playalbum && Slim::Music::Info::isSong($url)) { + push @playlist, $url; } } - } - - if ($valid) { - my $loopname = $menuMode?'item_loop':'folder_loop'; + my $loopname = $menuMode ? 'item_loop' : 'folder_loop'; my $chunkCount = 0; - $request->addResult( 'offset', $request->getParam('_index') ) if $menuMode; + $request->addResult( 'offset', $index ) if $menuMode; if ($insertAll) { $chunkCount = _playAll(start => $start, end => $end, chunkCount => $chunkCount, request => $request, loopname => $loopname); @@ -1679,12 +1662,32 @@ } my $listIndex = 0; - for my $eachitem (@data[$start..$end]) { + for my $filename (@$items[$start..$end]) { - next if ($eachitem == undef); + my $url = $urls{$filename} || next; - my $filename = Slim::Music::Info::fileName($eachitem->url()); - my $id = $eachitem->id(); + # Amazingly, this just works. :) + # Do the cheap compare for osName first - so non-windows users + # won't take the penalty for the lookup. + if ($osName eq 'win' && Slim::Music::Info::isWinShortcut($url)) { + $url = Slim::Utils::Misc::fileURLFromWinShortcut($url); + } + + my $item = Slim::Schema->rs('Track')->objectForUrl({ + 'url' => $url, + 'create' => 1, + 'readTags' => 1, + }); + + if (!blessed($item) || !$item->can('content_type')) { + + next; + } + + # Bug: 1360 - Don't show files referenced in a cuesheet + next if ($item->content_type eq 'cur'); + + my $id = $item->id(); $id += 0; if ($menuMode) { @@ -1691,7 +1694,7 @@ $request->addResultLoop($loopname, $chunkCount, 'text', $filename); my $params = { - 'textkey' => uc(substr($filename, 0, 1)), + 'textkey' => uc(substr(Slim::Utils::Text::ignorePunct($filename), 0, 1)), }; # each item is different, but most items are folders @@ -1696,10 +1699,9 @@ # each item is different, but most items are folders # the base assumes so above, we override it here - # assumed case, folder - if (Slim::Music::Info::isDir($eachitem) || -d Slim::Utils::Misc::pathFromMacAlias($eachitem->url)) { + if (Slim::Music::Info::isDir($item) || -d Slim::Utils::Misc::pathFromMacAlias($url)) { $params->{'folder_id'} = $id; @@ -1704,7 +1706,7 @@ $params->{'folder_id'} = $id; # playlist - } elsif (Slim::Music::Info::isPlaylist($eachitem)) { + } elsif (Slim::Music::Info::isPlaylist($item)) { my $actions = { 'go' => { @@ -1743,7 +1745,7 @@ $request->addResultLoop($loopname, $chunkCount, 'actions', $actions); # song - } elsif (Slim::Music::Info::isSong($eachitem)) { + } elsif (Slim::Music::Info::isSong($item)) { my $actions = { 'go' => { @@ -1842,13 +1844,13 @@ $request->addResultLoop($loopname, $chunkCount, 'id', $id); $request->addResultLoop($loopname, $chunkCount, 'filename', $filename); - if (Slim::Music::Info::isDir($eachitem)) { + if (Slim::Music::Info::isDir($item)) { $request->addResultLoop($loopname, $chunkCount, 'type', 'folder'); - } elsif (Slim::Music::Info::isPlaylist($eachitem)) { + } elsif (Slim::Music::Info::isPlaylist($item)) { $request->addResultLoop($loopname, $chunkCount, 'type', 'playlist'); - } elsif (Slim::Music::Info::isSong($eachitem)) { + } elsif (Slim::Music::Info::isSong($item)) { $request->addResultLoop($loopname, $chunkCount, 'type', 'track'); - } elsif (-d Slim::Utils::Misc::pathFromMacAlias($eachitem->url)) { + } elsif (-d Slim::Utils::Misc::pathFromMacAlias($url)) { $request->addResultLoop($loopname, $chunkCount, 'type', 'folder'); } else { $request->addResultLoop($loopname, $chunkCount, 'type', 'unknown'); @@ -1864,6 +1866,16 @@ $request->addResult('count', $totalCount); } + # cache results in case the same folder is queried again shortly + # should speed up Jive BMF, as only the first chunk needs to run the full loop above + $cache->{bmf} = { + id => ($params->{url} || $params->{id}), + ttl => (time() + 15), + items => $items, + topLevelObj => $topLevelObj, + count => $count, + }; + # we might have changed - flush to the db to be in sync. $topLevelObj->update;