library: keep display-only artists out of the artist lists

Filter the paged, search and home artist lists to artists referenced by the
plural credits, falling back to the full list while the relation tables are
still empty. Display names keep using the singular tag and navigation keeps
using the plural refs.
This commit is contained in:
austinried
2026-10-18 05:51:55 +00:00
parent 0c2e85134b
commit 4761772b9a
3 changed files with 54 additions and 6 deletions
@@ -93,9 +93,18 @@ private const val DOWNLOADED_ARTIST_ALBUMS =
"WHERE song_artists.sourceId = :sourceId AND song_artists.artistId = artists.id " +
"AND sd.status = 'Completed' AND songs.albumId IS NOT NULL"
internal const val ARTIST_CREDITED =
"((NOT EXISTS (SELECT 1 FROM album_artists WHERE sourceId = artists.sourceId) " +
"AND NOT EXISTS (SELECT 1 FROM song_artists WHERE sourceId = artists.sourceId)) " +
"OR EXISTS (SELECT 1 FROM album_artists aa " +
"WHERE aa.sourceId = artists.sourceId AND aa.artistId = artists.id) " +
"OR EXISTS (SELECT 1 FROM song_artists sa " +
"WHERE sa.sourceId = artists.sourceId AND sa.artistId = artists.id))"
internal const val ARTISTS_FILTER =
"FROM artists WHERE sourceId = :sourceId " +
"AND (:starredFilter = 0 OR (:starredFilter = 1 AND starred IS NOT NULL) OR (:starredFilter = 2 AND starred IS NULL)) " +
"AND $ARTIST_CREDITED " +
"AND (:downloadedFilter = 0 OR EXISTS (" +
"SELECT 1 FROM ($ARTIST_DOWNLOAD_ROWS) dl " +
"WHERE dl.id = artists.id AND dl.status = 'Completed')) " +
@@ -325,7 +334,7 @@ interface LibraryDao {
): Flow<List<Album>>
@Query(
"SELECT * FROM artists WHERE sourceId = :sourceId AND played IS NOT NULL " +
"SELECT * FROM artists WHERE sourceId = :sourceId AND played IS NOT NULL AND $ARTIST_CREDITED " +
"ORDER BY played DESC, sortName COLLATE NOCASE, id LIMIT :limit",
)
fun recentlyPlayedArtists(
@@ -343,7 +352,7 @@ interface LibraryDao {
): Flow<List<Album>>
@Query(
"SELECT * FROM artists WHERE sourceId = :sourceId AND playCount > 0 " +
"SELECT * FROM artists WHERE sourceId = :sourceId AND playCount > 0 AND $ARTIST_CREDITED " +
"ORDER BY playCount DESC, sortName COLLATE NOCASE, id LIMIT :limit",
)
fun mostPlayedArtists(
@@ -392,7 +401,7 @@ interface LibraryDao {
): Flow<List<Album>>
@Query(
"SELECT * FROM artists WHERE sourceId = :sourceId AND $ARTIST_SEARCH_FILTER " +
"SELECT * FROM artists WHERE sourceId = :sourceId AND $ARTIST_SEARCH_FILTER AND $ARTIST_CREDITED " +
"ORDER BY sortName COLLATE NOCASE, id LIMIT :limit",
)
fun searchArtists(
@@ -803,10 +812,16 @@ interface LibraryDao {
@Query("SELECT * FROM albums WHERE sourceId = :sourceId ORDER BY created DESC, sortName COLLATE NOCASE, id")
fun homeRecentlyAddedAlbums(sourceId: Long): PagingSource<Int, Album>
@Query("SELECT * FROM artists WHERE sourceId = :sourceId AND played IS NOT NULL ORDER BY played DESC, sortName COLLATE NOCASE, id")
@Query(
"SELECT * FROM artists WHERE sourceId = :sourceId AND played IS NOT NULL AND $ARTIST_CREDITED " +
"ORDER BY played DESC, sortName COLLATE NOCASE, id",
)
fun homeRecentlyPlayedArtists(sourceId: Long): PagingSource<Int, Artist>
@Query("SELECT * FROM artists WHERE sourceId = :sourceId AND playCount > 0 ORDER BY playCount DESC, sortName COLLATE NOCASE, id")
@Query(
"SELECT * FROM artists WHERE sourceId = :sourceId AND playCount > 0 AND $ARTIST_CREDITED " +
"ORDER BY playCount DESC, sortName COLLATE NOCASE, id",
)
fun homeMostPlayedArtists(sourceId: Long): PagingSource<Int, Artist>
@Query(
@@ -22,6 +22,7 @@ internal const val ALBUMS_FILTER_BASE =
internal const val ARTISTS_FILTER_BASE =
"FROM artists WHERE sourceId = ? " +
"AND (? = 0 OR (? = 1 AND starred IS NOT NULL) OR (? = 2 AND starred IS NULL)) " +
"AND $ARTIST_CREDITED " +
"AND (? = '' " +
"OR (length(?) >= 3 AND rowid IN (SELECT rowid FROM artist_search " +
"WHERE artist_search MATCH '\"' || replace(?, '\"', '\"\"') || '\"')) " +
@@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -58,7 +59,7 @@ class SyncServiceTest {
FakeMusicSource(
artists = listOf(artist("a1"), artist("a2")),
albums = listOf(album("al1")),
songs = listOf(song("s1"), song("s2")),
songs = listOf(song("s1"), song("s2").copy(artistId = "a2")),
playlists = listOf(playlist("p1")),
playlistSongs = listOf(PlaylistSong(1, "p1", "s1", 0)),
)
@@ -1064,6 +1065,37 @@ class SyncServiceTest {
assertEquals("Zulu", db.libraryDao().songOnce(1, "s1")!!.artistSort)
}
@Test
fun theArtistsListHidesNamesThatAreOnlyDisplayStrings() =
runTest {
insertSource()
val source =
FakeMusicSource(
artists = listOf(artist("a1", "Alpha"), artist("combo", "Alpha & Beta")),
albums = listOf(album("al1")),
songs = listOf(song("s1")),
)
SyncService(db, source).sync()
assertEquals(
listOf("a1"),
db
.libraryDao()
.artistsByName(1, 0, "")
.allRows()
.map { it.id },
)
assertEquals(
listOf("a1"),
db
.libraryDao()
.searchArtists(1, "alpha", 10)
.first()
.map { it.id },
)
}
@Test
fun everyAlbumArtistAndTrackArtistReachesTheSharedAlbum() =
runTest {