Fix: Artist selection by storing artist name in URI
## Problem
The `artist()` method queries by MediaStore artist ID, but `artists()` generates synthetic URIs. They don't match, causing artist selection to fail.
## Solution
Store the artist name in the URI path so `artist()` can extract and use it directly.
## Implementation
Replace the `artists()` method with:
```kotlin
override fun artists(
providerIdentifier: ProviderIdentifier,
sortingRule: SortingRule,
) = providersManager.flatMapWithInstanceOf(providerIdentifier) {
// Get all audios to extract album artist information
contentResolver.queryFlow(
audiosUri,
audiosProjection,
).mapEachRowToAudio().mapLatest { audios ->
// Group by album artist, falling back to track artist
val artistGroups = audios
.groupBy { audio ->
audio.albumArtist ?: audio.artistName ?: "Unknown Artist"
}
// Sort based on sorting rule
val sortedArtistNames = when (sortingRule.strategy) {
SortingStrategy.NAME -> {
if (sortingRule.reverse) {
artistGroups.keys.sortedDescending()
} else {
artistGroups.keys.sorted()
}
}
else -> artistGroups.keys.sorted()
}
// Create Artist objects with custom URIs
sortedArtistNames.map { artistName ->
// Create a custom URI with artist name encoded
val customUri = Uri.Builder()
.scheme("content")
.authority("org.lineageos.twelve.artist")
.appendPath(artistName)
.build()
Artist.Builder(customUri)
.setName(artistName)
.build()
}
}.mapLatest {
Result.Success(it)
}
}
```
Replace the `artist()` method with:
```kotlin
override fun artist(artistUri: Uri) = withVolumeName(artistUri) { volumeName ->
// Extract artist name from custom URI
val artistName = artistUri.lastPathSegment ?: return@withVolumeName flowOf(
Result.Error(Error.NOT_FOUND)
)
// Get all audios
contentResolver.queryFlow(
getAudiosUri(volumeName),
audiosProjection,
).mapEachRowToAudio(volumeName).mapLatest { audios ->
// Filter audios by album artist or track artist
val matchingAudios = audios.filter { audio ->
(audio.albumArtist ?: audio.artistName ?: "Unknown Artist") == artistName
}
if (matchingAudios.isEmpty()) {
return@mapLatest Result.Error<Pair<Artist, ArtistWorks>, Error>(Error.NOT_FOUND)
}
// Get unique albums
val albumIds = matchingAudios
.map { it.albumUri }
.distinct()
.map { ContentUris.parseId(it).toString() }
// Query albums
contentResolver.queryFlow(
getAlbumsUri(volumeName),
albumsProjection,
bundleOf(
ContentResolver.QUERY_ARG_SQL_SELECTION to query {
MediaStore.Audio.AudioColumns._ID `in` List(albumIds.size) {
Query.ARG
}
},
ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS to albumIds.toTypedArray(),
)
).mapEachRowToAlbum(volumeName).mapLatest { albums ->
val artist = Artist.Builder(artistUri)
.setName(artistName)
.build()
val artistWorks = ArtistWorks(
albums,
listOf(),
listOf(),
)
Result.Success(artist to artistWorks)
}
}.flatMapLatest { it }
}
```
## How it works
1. **artists()** creates URIs with the artist name in the path
2. **artist()** extracts the artist name from the URI
3. Filters audios by album artist (with fallback to track artist)
4. Returns albums for that artist
## Testing
After implementing:
1. Rebuild APK
2. Tap on an artist - should now display correctly
3. Verify compilation albums are grouped
4. Check that artist details show all albums
task