diff --git a/Slim/Control/Queries.pm b/Slim/Control/Queries.pm index 5c68f5e5fb..ef85c99b31 100644 --- a/Slim/Control/Queries.pm +++ b/Slim/Control/Queries.pm @@ -929,9 +929,15 @@ sub albumsQuery { } if ( $tags =~ /R/ ) { - $contributorRoleSth ||= $dbh->prepare_cached("SELECT role FROM contributor_album WHERE album = ? AND contributor = ?"); - my $rolesRef = $dbh->selectall_arrayref($contributorRoleSth, , undef, $c->{'albums.id'}, $contributorID || $c->{'albums.contributor'}); - + my $rolesRef; + my $contributorRoleSql = "SELECT role FROM contributor_album WHERE album = ?"; + $contributorRoleSql .= " AND contributor = ?" if $contributorID; + $contributorRoleSth ||= $dbh->prepare_cached($contributorRoleSql); + if ( $contributorID ) { + $rolesRef = $dbh->selectall_arrayref( $contributorRoleSth, undef, ($c->{'albums.id'}, $contributorID) ); + } else { + $rolesRef = $dbh->selectall_arrayref( $contributorRoleSth, undef, ($c->{'albums.id'}) ); + } if ($rolesRef) { my $roles = join(',', map { $_->[0] } @$rolesRef); $request->addResultLoopIfValueDefined($loopname, $chunkCount, 'role_ids', $roles); diff --git a/Slim/Menu/BrowseLibrary/Releases.pm b/Slim/Menu/BrowseLibrary/Releases.pm index dbc8a37c86..cac9b9b671 100644 --- a/Slim/Menu/BrowseLibrary/Releases.pm +++ b/Slim/Menu/BrowseLibrary/Releases.pm @@ -8,6 +8,7 @@ use Slim::Utils::Strings qw(cstring); # Should we page through results instead of doing one huge bulk request? use constant MAX_ALBUMS => 1500; +use constant LIST_LIMIT => 980; # SQL parameter limit is 999. This is used to limit the number of album_ids passed in. Leave some room for other searchTags. my $log = logger('database.info'); my $prefs = preferences('server'); @@ -16,15 +17,18 @@ my $prefs = preferences('server'); sub _releases { my ($client, $callback, $args, $pt) = @_; my @searchTags = $pt->{'searchTags'} ? @{$pt->{'searchTags'}} : (); - my @originalSearchTags = @searchTags; my $tags = 'lWRSw'; my $library_id = $args->{'library_id'} || $pt->{'library_id'}; my $orderBy = $args->{'orderBy'} || $pt->{'orderBy'}; my $menuMode = $args->{'params'}->{'menu_mode'}; my $menuRoles = $args->{'params'}->{'menu_roles'}; + my $search = $args->{'search'}; + + push @searchTags, "search:$search" if $search && !grep /search:/, @searchTags; + my @originalSearchTags = @searchTags; # map menuRoles to name for readability - $menuRoles = join(',', map { Slim::Schema::Contributor->roleToType($_) } split(',', $menuRoles || '')); + $menuRoles = join(',', map { Slim::Schema::Contributor->roleToType($_) || $_ } split(',', $menuRoles || '')); Slim::Schema::Album->addReleaseTypeStrings(); @@ -34,7 +38,7 @@ sub _releases { # library_id:-1 is supposed to clear/override the global library_id $_ && $_ !~ /(?:library_id\s*:\s*-1|remote_library)/ } @searchTags; - push @searchTags, "role_id:$menuRoles" if $menuRoles; + push @searchTags, "role_id:$menuRoles" if $menuRoles && $menuMode ne 'artists'; my @artistIds = grep /artist_id:/, @searchTags; my $artistId; @@ -52,10 +56,10 @@ sub _releases { main::INFOLOG && $log->is_info && $log->info("$query ($index, $quantity): tags ->", join(', ', @searchTags)); # get the artist's albums list to create releases sub-items etc. - my $request = Slim::Control::Request->new( undef, [ $query, 0, MAX_ALBUMS, @searchTags, 'role_id:'. ($menuRoles ? $menuRoles : join(',',Slim::Schema::Contributor->contributorRoles)) ] ); - $request->execute(); + my $releasesRequest = Slim::Control::Request->new( undef, [ $query, 0, MAX_ALBUMS, @searchTags ] ); + $releasesRequest->execute(); - $log->error($request->getStatusText()) if $request->isStatusError(); + $log->error($releasesRequest->getStatusText()) if $releasesRequest->isStatusError(); # compile list of release types and contributions my %releaseTypes; @@ -66,43 +70,43 @@ sub _releases { my $checkComposerGenres = !( $menuMode && $menuMode ne 'artists' && $menuRoles ) && $prefs->get('showComposerReleasesbyAlbum') == 2; my $allComposers = ( $menuMode && $menuMode ne 'artists' && $menuRoles ) || $prefs->get('showComposerReleasesbyAlbum') == 1; - foreach (@{ $request->getResult('albums_loop') || [] }) { + foreach my $release (@{ $releasesRequest->getResult('albums_loop') || [] }) { # map to role's name for readability - $_->{role_ids} = join(',', map { Slim::Schema::Contributor->roleToType($_) } split(',', $_->{role_ids} || '')); - my ($defaultRoles, $userDefinedRoles) = Slim::Schema::Contributor->splitDefaultAndCustomRoles($_->{role_ids}); + $release->{role_ids} = join(',', map { Slim::Schema::Contributor->roleToType($_) } split(',', $release->{role_ids} || '')); + my ($defaultRoles, $userDefinedRoles) = Slim::Schema::Contributor->splitDefaultAndCustomRoles($release->{role_ids}); my $genreMatch = undef; if ( $checkComposerGenres ) { - my $request = Slim::Control::Request->new( undef, [ 'genres', 0, MAX_ALBUMS, 'album_id:' . $_->{id} ] ); - $request->execute(); + my $genresRequest = Slim::Control::Request->new( undef, [ 'genres', 0, MAX_ALBUMS, 'album_id:' . $release->{id} ] ); + $genresRequest->execute(); - if ($request->isStatusError()) { - $log->error($request->getStatusText()); + if ($genresRequest->isStatusError()) { + $log->error($genresRequest->getStatusText()); } else { - foreach my $genre (@{$request->getResult('genres_loop')}) { + foreach my $genre (@{$genresRequest->getResult('genres_loop')}) { last if $genreMatch = Slim::Schema::Genre->isMyClassicalGenre($genre->{genre}); } } } my $addToMainReleases = sub { - $isPrimaryArtist{$_->{id}}++; - $releaseTypes{$_->{release_type}}++; - $albumList{$_->{release_type}} ||= []; - push @{$albumList{$_->{release_type}}}, $_->{id}; + $isPrimaryArtist{$release->{id}}++; + $releaseTypes{$release->{release_type}}++; + $albumList{$release->{release_type}} ||= []; + push @{$albumList{$release->{release_type}}}, $release->{id}; }; my $addUserDefinedRoles = sub { foreach my $role ( split(',', $userDefinedRoles || '') ) { $contributions{$role} ||= []; - push @{$contributions{$role}}, $_->{id}; + push @{$contributions{$role}}, $release->{id}; } }; - if ($_->{compilation}) { - $_->{release_type} = 'COMPILATION'; + if ($release->{compilation}) { + $release->{release_type} = 'COMPILATION'; $addToMainReleases->(); # only list default roles outside the compilations if Composer/Conductor if ( $defaultRoles !~ /COMPOSER|CONDUCTOR/ || $defaultRoles =~ /ARTIST|BAND/ ) { @@ -119,7 +123,7 @@ sub _releases { # Consider this artist the main (album) artist if there's no other, defined album artist elsif ( $defaultRoles =~ /ARTIST/ ) { my $albumArtist = Slim::Schema->first('ContributorAlbum', { - album => $_->{id}, + album => $release->{id}, role => Slim::Schema::Contributor->typeToRole('ALBUMARTIST'), contributor => { '!=' => $artistId } }); @@ -134,14 +138,14 @@ sub _releases { # Default roles on other releases foreach my $role ( grep { $_ ne 'ALBUMARTIST' } split(',', $defaultRoles || '') ) { # don't list as trackartist, if the artist is albumartist, too - next if $role eq 'TRACKARTIST' && $isPrimaryArtist{$_->{id}}; + next if $role eq 'TRACKARTIST' && $isPrimaryArtist{$release->{id}}; if ( $role eq 'COMPOSER' && ( $genreMatch || $allComposers ) ) { $role = 'COMPOSERALBUM'; } $contributions{$role} ||= []; - push @{$contributions{$role}}, $_->{id}; + push @{$contributions{$role}}, $release->{id}; } # User-defined roles @@ -163,9 +167,10 @@ sub _releases { } keys %releaseTypes); foreach my $releaseType (@sortedReleaseTypes) { - my $name = Slim::Schema::Album->releaseTypeName($releaseType, $client); if ($releaseTypes{uc($releaseType)}) { + my $name = Slim::Schema::Album->releaseTypeName($releaseType, $client); + $name = _limitList($client, $albumList{$releaseType}, $name); $pt->{'searchTags'} = $releaseType eq 'COMPILATION' ? [@searchTags, 'compilation:1', "album_id:" . join(',', @{$albumList{$releaseType}})] : [@searchTags, "compilation:0", "release_type:$releaseType", "album_id:" . join(',', @{$albumList{$releaseType}})]; @@ -174,13 +179,17 @@ sub _releases { } if (my $albumIds = delete $contributions{COMPOSERALBUM}) { + my $name = cstring($client, 'COMPOSERALBUMS'); + $name = _limitList($client, $albumIds, $name); $pt->{'searchTags'} = [@searchTags, "role_id:COMPOSER", "album_id:" . join(',', @$albumIds)]; - push @items, _createItem(cstring($client, 'COMPOSERALBUMS'), [{%$pt}]); + push @items, _createItem($name, [{%$pt}]); } if (my $albumIds = delete $contributions{COMPOSER}) { + my $name = cstring($client, 'COMPOSITIONS'); + $name = _limitList($client, $albumIds, $name); push @items, { - name => cstring($client, 'COMPOSITIONS'), + name => $name, image => 'html/images/playlists.png', type => 'playlist', playlist => \&_tracks, @@ -191,24 +200,26 @@ sub _releases { } if (my $albumIds = delete $contributions{TRACKARTIST}) { + my $name = cstring($client, 'APPEARANCES'); + $name = _limitList($client, $albumIds, $name); $pt->{'searchTags'} = [@searchTags, "role_id:TRACKARTIST", "album_id:" . join(',', @$albumIds)]; - push @items, _createItem(cstring($client, 'APPEARANCES'), [{%$pt}]); + push @items, _createItem($name, [{%$pt}]); } foreach my $role (sort keys %contributions) { my $name = cstring($client, $role) if Slim::Utils::Strings::stringExists($role); + $name = _limitList($client, $contributions{$role}, $name || ucfirst($role)); $pt->{'searchTags'} = [@searchTags, "role_id:$role", "album_id:" . join(',', @{$contributions{$role}})]; - push @items, _createItem($name || ucfirst($role), [{%$pt}]); + push @items, _createItem($name, [{%$pt}]); } # Add item for Classical Works if the artist has any. push @searchTags, "role_id:$menuRoles" if $menuRoles && $menuMode && $menuMode ne 'artists'; push @searchTags, "genre_id:" . Slim::Schema::Genre->myClassicalGenreIds() if $checkComposerGenres; main::INFOLOG && $log->is_info && $log->info("works ($index, $quantity): tags ->", join(', ', @searchTags)); - my $requestRef = [ 'works', 0, MAX_ALBUMS, @searchTags ]; - my $request = Slim::Control::Request->new( $client ? $client->id() : undef, $requestRef ); - $request->execute(); - $log->error($request->getStatusText()) if $request->isStatusError(); + my $worksRequest = Slim::Control::Request->new( undef, [ 'works', 0, MAX_ALBUMS, @searchTags ] ); + $worksRequest->execute(); + $log->error($worksRequest->getStatusText()) if $worksRequest->isStatusError(); push @items, { name => cstring($client, 'WORKS_CLASSICAL'), @@ -217,7 +228,7 @@ sub _releases { playlist => \&_tracks, url => \&_works, passthrough => [ { searchTags => [@searchTags, "work_id:-1", "wantMetadata:1", "wantIndex:1"] } ], - } if ( $request->getResult('count') > 1 || ( scalar @items && $request->getResult('count') ) ); + } if ( $worksRequest->getResult('count') > 1 || ( scalar @items && $worksRequest->getResult('count') ) ); # restore original search tags $pt->{'searchTags'} = [@originalSearchTags]; @@ -277,4 +288,14 @@ sub _createItem { }; } +sub _limitList { + my ($client, $listRef, $name) = @_; + my $albumCount = scalar @$listRef; + if ( $albumCount > LIST_LIMIT ) { + splice @$listRef, LIST_LIMIT; + $name .= ' ' . cstring($client, 'FIRST_N_ALBUMS', LIST_LIMIT); + } + return $name; +} + 1; diff --git a/strings.txt b/strings.txt index 8aefa052d0..0ce43564e8 100644 --- a/strings.txt +++ b/strings.txt @@ -26924,3 +26924,10 @@ SETUP_MYCLASSICALGENRES_DESC FR Précisez les genres concernés par les œuvres et les compositeurs. Séparez-les par des virgules. NL Gebruik deze genres voor werken en albums van componisten. Scheid met komma's. +FIRST_N_ALBUMS + DE (erste %s Alben) + EN (first %s albums) + ES (primeros %s álbumes) + FR (premiers %s albums) + NL (eerste %s albums) +