Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1a4642d
display artist
darrell-k May 2, 2026
33893cd
album join fix
darrell-k May 7, 2026
53b9540
draft schema changes
darrell-k May 18, 2026
45888ca
oops
darrell-k May 18, 2026
e2ea843
implement 3nf schema changes
darrell-k May 18, 2026
7b9889b
Merge branch 'LMS-Community:public/9.2' into display_artist
darrell-k May 18, 2026
8e0f88a
new table clear
darrell-k May 18, 2026
71ad0ff
Extract _getOrCreateDisplayContributor helper from inline _newTrack code
Rouzax May 18, 2026
22d8f5e
Replace tag swap with display string capture in _newTrack
Rouzax May 18, 2026
9f31f1c
Fix rescan path: populate display_contributor on track update
Rouzax May 18, 2026
b7490c9
Populate contributor_track_display junction for track-level display
Rouzax May 18, 2026
5c64d69
Add track-level display_artist to queries with aliased JOINs
Rouzax May 18, 2026
9414398
Add usePluralArtistTags preference for plural tag contributor creation
Rouzax May 18, 2026
d676985
Index display_artist in fulltext search via contributor_display JOINs
Rouzax May 18, 2026
6416924
Add changelog entry for #1555 display_artist support
Rouzax May 18, 2026
00cc68c
Fix pref persistence, rescan trigger, and scalar plural tag handling
Rouzax May 19, 2026
81b63ba
Improve usePluralArtistTags description for non-technical users
Rouzax May 19, 2026
5258c10
Merge pull request #21 from Rouzax/pr/darrell-3nf-rebase
darrell-k May 19, 2026
6f661ea
pass album artist for queue
darrell-k May 20, 2026
0985bc3
Merge branch 'LMS-Community:public/9.2' into display_artist
darrell-k May 20, 2026
3f5fc9e
use 'A' tag for display_artist in status query
darrell-k May 22, 2026
7c11250
Merge branch 'public/9.2' into display_artist
darrell-k May 22, 2026
baa2a58
Display Artist: Simplify Scan
darrell-k May 22, 2026
a1b5cdb
Merge remote-tracking branch 'origin/display_artist' into display_artist
darrell-k May 22, 2026
8fd765c
Merge pull request #24 from darrell-k/display_artist_simplify_scan
darrell-k May 22, 2026
3ef4055
WIP
darrell-k May 24, 2026
67ced17
WIP
darrell-k May 27, 2026
c333340
Merge branch 'LMS-Community:public/9.2' into display_artist
darrell-k May 27, 2026
586cb84
Merge branch 'public/9.2' into display_artist
darrell-k Jun 8, 2026
1127737
Merge branch 'public/9.2' into display_artist
darrell-k Jun 9, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Changelog9.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ <h2><a name="v9.2.0" id="v9.2.0"></a>Version 9.2.0</h2>
<li><a href="https://github.com/LMS-Community/slimserver/pull/1541">#1541</a> - Add per-player timezone support: players can now display date and time, and fire alarms, in their own timezone rather than the server's. (@boudekerk)</li>
<li><a href="https://github.com/LMS-Community/slimserver/pull/1546">#1546</a> - Add "Default Adjustment for Local Tracks" player option. (@SamInPgh)</li>
<li><a href="https://github.com/LMS-Community/slimserver/pull/1564">#1564</a> - Add Dismiss option to Jive alarm popup (@boudekerk)</li>
<li><a href="https://github.com/LMS-Community/slimserver/issues/1555">#1555</a> - Store display_artist from ALBUMARTIST/ARTIST tags separately from individual contributors. Optional use of ALBUMARTISTS/ARTISTS plural tags for contributor creation. (@Rouzax, @darrell-k)</li>
</ul>
<br />

Expand Down
9 changes: 9 additions & 0 deletions HTML/EN/settings/server/behavior.html
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,15 @@
</select>
[% END %]

[% WRAPPER setting title="SETUP_USEPLURALARTISTTAGS" desc="SETUP_USEPLURALARTISTTAGS_DESC"%]
<select class="stdedit" name="pref_usePluralArtistTags" id="usePluralArtistTags">

<option [% IF NOT prefs.pref_usePluralArtistTags %]selected [% END %]value="0">[% 'SETUP_USEPLURALARTISTTAGS_0' | string %]</option>
<option [% IF prefs.pref_usePluralArtistTags %]selected [% END %]value="1">[% 'SETUP_USEPLURALARTISTTAGS_1' | string %]</option>

</select>
[% END %]

[% WRAPPER setting title="SETUP_YEARMENU" desc="SETUP_YEARMENU_DESC"%]
<select class="stdedit" name="pref_onlyAlbumYears" id="onlyAlbumYears">

Expand Down
Empty file added SQL/SQLite/schema_27_down.sql
Empty file.
36 changes: 36 additions & 0 deletions SQL/SQLite/schema_27_up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
-- full relational solution for display_artist

DROP TABLE IF EXISTS contributor_display;
CREATE TABLE contributor_display (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name blob);
ALTER TABLE albums ADD display_contributor integer;

DROP TABLE IF EXISTS contributor_album_display;
CREATE TABLE contributor_album_display (
contributor_display int(10),
contributor int(10),
album int(10),
PRIMARY KEY (contributor_display,contributor,album),
FOREIGN KEY (`album`) REFERENCES `albums` (`id`) ON DELETE CASCADE,
FOREIGN KEY (`contributor`) REFERENCES `contributors` (`id`) ON DELETE CASCADE
);
CREATE INDEX contributor_album_displayContribIndex ON contributor_album_display (contributor);
CREATE INDEX contributor_album_displayAlbumIndex ON contributor_album_display (album);
CREATE INDEX contributor_album_displayContributorDisplayIndex ON contributor_album_display (contributor_display);

ALTER TABLE tracks ADD display_contributor integer;

DROP TABLE IF EXISTS contributor_track_display;
CREATE TABLE contributor_track_display (
contributor_display int(10),
contributor int(10),
track int(10),
PRIMARY KEY (contributor_display,contributor,track),
FOREIGN KEY (`track`) REFERENCES `tracks` (`id`) ON DELETE CASCADE,
FOREIGN KEY (`contributor`) REFERENCES `contributors` (`id`) ON DELETE CASCADE
);
CREATE INDEX contributor_track_displayContribIndex ON contributor_track_display (contributor);
CREATE INDEX contributor_track_displayTrackIndex ON contributor_track_display (track);
CREATE INDEX contributor_track_displayContributorDisplayIndex ON contributor_track_display (contributor_display);

8 changes: 7 additions & 1 deletion SQL/SQLite/schema_clear.sql
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ DELETE FROM library_album;
DELETE FROM library_contributor;
DELETE FROM library_genre;

DELETE FROM contributor_display;

DELETE FROM contributor_album_display;

DELETE FROM contributor_track_display;

-- these table are created by the Fulltext Search plugin
DROP TABLE IF EXISTS fulltext;
DROP TABLE IF EXISTS fulltext_terms;
Expand All @@ -40,4 +46,4 @@ UPDATE metainformation SET value = 0 WHERE name = 'lastRescanTime';
-- start the contributor ID at the old offset to prevent ID overlap between scans
UPDATE SQLITE_SEQUENCE SET seq = (SELECT old.seq FROM old_autoincrement AS old WHERE old.name = 'contributors') WHERE name = 'contributors';

DROP TABLE old_autoincrement;
DROP TABLE old_autoincrement;
Empty file added SQL/mysql/schema_27_down.sql
Empty file.
36 changes: 36 additions & 0 deletions SQL/mysql/schema_27_up.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
-- full relational solution for display_artist.

DROP TABLE IF EXISTS contributor_display;
CREATE TABLE contributor_display (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name blob);
ALTER TABLE albums ADD display_contributor integer;

DROP TABLE IF EXISTS contributor_album_display;
CREATE TABLE contributor_album_display (
contributor_display int(10),
contributor int(10),
album int(10),
PRIMARY KEY (contributor_display,contributor,album),
FOREIGN KEY (`album`) REFERENCES `albums` (`id`) ON DELETE CASCADE,
FOREIGN KEY (`contributor`) REFERENCES `contributors` (`id`) ON DELETE CASCADE
);
CREATE INDEX contributor_album_displayContribIndex ON contributor_album_display (contributor);
CREATE INDEX contributor_album_displayAlbumIndex ON contributor_album_display (album);
CREATE INDEX contributor_album_displayContributorDisplayIndex ON contributor_album_display (contributor_display);

ALTER TABLE tracks ADD display_contributor integer;

DROP TABLE IF EXISTS contributor_track_display;
CREATE TABLE contributor_track_display (
contributor_display int(10),
contributor int(10),
track int(10),
PRIMARY KEY (contributor_display,contributor,track),
FOREIGN KEY (`track`) REFERENCES `tracks` (`id`) ON DELETE CASCADE,
FOREIGN KEY (`contributor`) REFERENCES `contributors` (`id`) ON DELETE CASCADE
);
CREATE INDEX contributor_track_displayContribIndex ON contributor_track_display (contributor);
CREATE INDEX contributor_track_displayTrackIndex ON contributor_track_display (track);
CREATE INDEX contributor_track_displayContributorDisplayIndex ON contributor_track_display (contributor_display);

6 changes: 6 additions & 0 deletions SQL/mysql/schema_clear.sql
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ DELETE FROM scanned_files;

DELETE FROM works;

DELETE FROM contributor_display;

DELETE FROM contributor_album_display;

DELETE FROM contributor_track_display;

UPDATE metainformation SET value = 0 WHERE name = 'lastRescanTime';

UPDATE tracks_persistent SET track = NULL;
Expand Down
30 changes: 30 additions & 0 deletions Slim/Control/Queries.pm
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,9 @@ sub albumsQuery {
# We need the main albums.contributor name for favorites, so always do this join unless getting count only.
$sql .= 'JOIN contributors ON contributors.id = albums.contributor ';
$c->{'contributors.name'} = 1;
$c->{'albums.label'} = 1;
$sql .= 'LEFT JOIN contributor_display ON albums.display_contributor = contributor_display.id ';
$c->{'contributor_display.name'} = 1;
}

if ( $tags =~ /s/ ) {
Expand Down Expand Up @@ -836,6 +839,7 @@ sub albumsQuery {
utf8::decode( $c->{'composer.name'} ) if exists $c->{'composer.name'};
utf8::decode( $c->{'tracks.performance'} ) if exists $c->{'tracks.performance'};
utf8::decode( $c->{'contributors.name'} ) if exists $c->{'contributors.name'};
utf8::decode( $c->{'contributor_display.name'} ) if exists $c->{'contributor_display.name'};
$request->addResultLoop($loopname, $chunkCount, 'id', $c->{'albums.id'});
$request->addResultLoopIfValueDefined($loopname, $chunkCount, 'work_id', $c->{'tracks.work'});
$request->addResultLoopIfValueDefined($loopname, $chunkCount, 'work_name', $c->{'works.title'});
Expand Down Expand Up @@ -899,6 +903,7 @@ sub albumsQuery {
if ( !$work ) {
$tags =~ /S/ && $request->addResultLoopIfValueDefined($loopname, $chunkCount, 'artist_id', $c->{'albums.contributor'});
$tags =~ /a/ && $request->addResultLoopIfValueDefined($loopname, $chunkCount, 'artist', $c->{'contributors.name'});
$tags =~ /a/ && $c->{'contributor_display.name'} && $request->addResultLoopIfValueDefined($loopname, $chunkCount, 'display_artist', $c->{'contributor_display.name'});
$tags =~ /4/ && $request->addResultLoopIfValueDefined($loopname, $chunkCount, 'portraitid', $c->{'contributors.portraitid'});
}

Expand Down Expand Up @@ -5794,6 +5799,9 @@ sub _songDataFromHash {
$returnHash{$role} = $res->{$role};
}
}
$returnHash{display_trackartist} = $res->{'tacd.name'} if $res->{'tacd.name'};
$returnHash{display_artist} = $res->{'tacd.name'} if $res->{'tacd.name'};
$returnHash{display_albumartist} = $res->{'aacd.name'} if $res->{'aacd.name'};
}
elsif ( $tag eq 'S' ) {
for my $role ( @contributorRoles ) {
Expand Down Expand Up @@ -6397,6 +6405,19 @@ sub _getTagDataForTracks {
}
};

my $join_contributor_display = sub {
if ( $sql !~ /JOIN contributor_display AS aacd/ ) {
$join_albums->();
$sql .= 'LEFT JOIN contributor_display AS aacd ON albums.display_contributor = aacd.id ';
}
};

my $join_track_contributor_display = sub {
if ( $sql !~ /JOIN contributor_display AS tacd/ ) {
$sql .= 'LEFT JOIN contributor_display AS tacd ON tracks.display_contributor = tacd.id ';
}
};

if ( my $year = $args->{year} ) {
push @{$w}, 'tracks.year = ?';
push @{$p}, $year;
Expand Down Expand Up @@ -6521,6 +6542,13 @@ sub _getTagDataForTracks {
push @{$w}, 'contributor_track.role IN (' . join(', ', map {'?'} @roles) . ')';
};

$tags =~ /A/ && do {
$join_contributor_display->();
$join_track_contributor_display->();
$c->{'aacd.name'} = 1;
$c->{'tacd.name'} = 1;
};

$tags =~ /s/ && do {
$join_contributors->();
$c->{'contributors.id'} = 1;
Expand Down Expand Up @@ -6661,6 +6689,8 @@ sub _getTagDataForTracks {
utf8::decode( $c->{'tracks.lyrics'} ) if exists $c->{'tracks.lyrics'};
utf8::decode( $c->{'albums.title'} ) if exists $c->{'albums.title'};
utf8::decode( $c->{'contributors.name'} ) if exists $c->{'contributors.name'};
utf8::decode( $c->{'aacd.name'} ) if exists $c->{'aacd.name'};
utf8::decode( $c->{'tacd.name'} ) if exists $c->{'tacd.name'};
utf8::decode( $c->{'genres.name'} ) if exists $c->{'genres.name'};
utf8::decode( $c->{'comments.value'} ) if exists $c->{'comments.value'};
utf8::decode( $c->{'tracks.discsubtitle'}) if exists $c->{'tracks.discsubtitle'};
Expand Down
8 changes: 6 additions & 2 deletions Slim/Plugin/FullTextSearch/Plugin.pm
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ use constant SQL_CREATE_TRACK_ITEM => q{
UNIQUE_TOKENS(LOWER(IFNULL(tracks.title, '')) || ' ' || IFNULL(tracks.titlesearch, '') || ' ' || IFNULL(tracks.customsearch, '')),
-- weight 5
UNIQUE_TOKENS(IFNULL(tracks.year, '') || ' ' || GROUP_CONCAT(albums.title, ' ') || ' ' || GROUP_CONCAT(albums.titlesearch, ' ') || ' '
|| GROUP_CONCAT(genres.name, ' ') || ' ' || GROUP_CONCAT(genres.namesearch, ' ')),
|| GROUP_CONCAT(genres.name, ' ') || ' ' || GROUP_CONCAT(genres.namesearch, ' ') || ' '
|| IFNULL(tcd.name, '') || ' ' || IFNULL(acd.name, '')),
-- weight 3 - contributors create multiple hits, therefore only w3
UNIQUE_TOKENS(CONCAT_CONTRIBUTOR_ROLE(tracks.id, GROUP_CONCAT(contributor_track.contributor, ','), 'contributor_track') || ' '
|| IGNORE_CASE(comments.value) || ' ' || IGNORE_CASE(tracks.lyrics) || ' ' || IFNULL(tracks.content_type, '') || ' '
Expand All @@ -52,6 +53,8 @@ use constant SQL_CREATE_TRACK_ITEM => q{
LEFT JOIN genre_track ON genre_track.track = tracks.id
LEFT JOIN genres ON genres.id = genre_track.genre
LEFT JOIN comments ON comments.track = tracks.id
LEFT JOIN contributor_display AS acd ON albums.display_contributor = acd.id
LEFT JOIN contributor_display AS tcd ON tracks.display_contributor = tcd.id

%s

Expand Down Expand Up @@ -112,7 +115,7 @@ use constant SQL_CREATE_ALBUM_ITEM => qq{
UNIQUE_TOKENS(LOWER(IFNULL(albums.title, '')) || ' ' || IFNULL(albums.titlesearch, '') || ' ' || IFNULL(albums.customsearch, '') || ' '
|| IFNULL((SELECT GROUP_CONCAT(wt,' ') FROM (SELECT DISTINCT works.titlesearch wt FROM tracks JOIN works ON tracks.work = works.id WHERE tracks.album = albums.id) ), ' ') ),
-- weight 5
IFNULL(albums.year, ''),
UNIQUE_TOKENS(IFNULL(albums.year, '') || ' ' || IFNULL(contributor_display.name, '')),
-- weight 3
UNIQUE_TOKENS(CONCAT_CONTRIBUTOR_ROLE(albums.id, GROUP_CONCAT(contributor_album.contributor, ','), 'contributor_album')),
-- weight 1
Expand All @@ -122,6 +125,7 @@ use constant SQL_CREATE_ALBUM_ITEM => qq{
FROM albums
LEFT JOIN contributor_album ON contributor_album.album = albums.id
LEFT JOIN contributors ON contributors.id = contributor_album.contributor
LEFT JOIN contributor_display ON albums.display_contributor = contributor_display.id

%s

Expand Down
Loading