Skip to content

Commit

Permalink
Merge pull request #1303 from darrell-k/more-releases-rework
Browse files Browse the repository at this point in the history
 More releases rework
  • Loading branch information
michaelherger authored Jan 22, 2025
2 parents f391a23 + 73dff39 commit 75dcb91
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 37 deletions.
12 changes: 9 additions & 3 deletions Slim/Control/Queries.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
89 changes: 55 additions & 34 deletions Slim/Menu/BrowseLibrary/Releases.pm
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand All @@ -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();

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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/ ) {
Expand All @@ -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 }
});
Expand All @@ -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
Expand All @@ -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}})];
Expand All @@ -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,
Expand All @@ -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'),
Expand All @@ -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];
Expand Down Expand Up @@ -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;
7 changes: 7 additions & 0 deletions strings.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)

0 comments on commit 75dcb91

Please sign in to comment.