From b21b2e49d3ef596b4d55b43e78f7abc404911486 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Mon, 17 Mar 2025 09:15:35 -0600 Subject: [PATCH] musikr: split albums w/full album artist coverage This is like the old Auxio behavior, but should now trigger with only full album artist coverage, rather than before where it would always trigger and break apart sparsely tagged albums. Still not a perfect heuristic, but it's the best one I can do. --- .../org/oxycblt/musikr/graph/MusicGraph.kt | 31 +++++++++++++++++-- .../oxycblt/musikr/tag/interpret/PreMusic.kt | 12 +++++-- .../musikr/tag/interpret/TagInterpreter.kt | 6 ++-- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt b/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt index 2b634ae5e..1d2bb75db 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/graph/MusicGraph.kt @@ -23,6 +23,7 @@ import org.oxycblt.musikr.playlist.SongPointer import org.oxycblt.musikr.playlist.interpret.PrePlaylist import org.oxycblt.musikr.tag.interpret.PreAlbum import org.oxycblt.musikr.tag.interpret.PreArtist +import org.oxycblt.musikr.tag.interpret.PreArtistsFrom import org.oxycblt.musikr.tag.interpret.PreGenre import org.oxycblt.musikr.tag.interpret.PreSong import org.oxycblt.musikr.util.unlikelyToBeNull @@ -75,7 +76,7 @@ private class MusicGraphBuilderImpl : MusicGraph.Builder { // Albums themselves have their own parent artists that also need to be // linked up. val albumArtistVertices = - preSong.preAlbum.preArtists.map { preArtist -> + preSong.preAlbum.preArtists.preArtists.map { preArtist -> artistVertices.getOrPut(preArtist) { ArtistVertex(preArtist) } } val albumVertex = AlbumVertex(preSong.preAlbum, albumArtistVertices.toMutableList()) @@ -288,7 +289,7 @@ private class MusicGraphBuilderImpl : MusicGraph.Builder { return } // No full MBID coverage, discard the MBIDs from the graph. - val strippedCluster = + val strippedMbidCluster = cluster.map { val noMbidPreAlbum = it.preAlbum.copy(musicBrainzId = null) val simpleMbidVertex = @@ -298,7 +299,31 @@ private class MusicGraphBuilderImpl : MusicGraph.Builder { meldAlbumVertices(it, simpleMbidVertex) simpleMbidVertex } - simplifyAlbumClusterImpl(strippedCluster) + val fullAlbumArtistCoverage = + strippedMbidCluster.all { it.preAlbum.preArtists is PreArtistsFrom.Album } + if (fullAlbumArtistCoverage) { + // All albums have album artists, we can reasonably cluster around artists + // rather than just name. + val albumArtistClusters = + strippedMbidCluster.groupBy { it.preAlbum.preArtists.preArtists } + for (albumArtistCluster in albumArtistClusters.values) { + simplifyAlbumClusterImpl(albumArtistCluster) + } + return + } + val strippedAlbumArtistCluster = + strippedMbidCluster.map { + val noAlbumArtistPreAlbum = + it.preAlbum.copy( + preArtists = PreArtistsFrom.Individual(it.preAlbum.preArtists.preArtists)) + val simpleAlbumArtistVertex = + albumVertices.getOrPut(noAlbumArtistPreAlbum) { + AlbumVertex(noAlbumArtistPreAlbum, it.artistVertices.toMutableList()) + } + meldAlbumVertices(it, simpleAlbumArtistVertex) + simpleAlbumArtistVertex + } + simplifyAlbumClusterImpl(strippedAlbumArtistCluster) } private fun simplifyAlbumClusterImpl(cluster: Collection) { diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt index 62f6f3689..4fc5822c0 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/PreMusic.kt @@ -54,16 +54,24 @@ internal data class PreSong( val preAlbum: PreAlbum, val preArtists: List, val preGenres: List -) {} +) internal data class PreAlbum( val musicBrainzId: UUID?, val name: Name, val rawName: String?, val releaseType: ReleaseType, - val preArtists: List + val preArtists: PreArtistsFrom, ) +internal sealed interface PreArtistsFrom { + val preArtists: List + + data class Individual(override val preArtists: List) : PreArtistsFrom + + data class Album(override val preArtists: List) : PreArtistsFrom +} + internal data class PreArtist(val musicBrainzId: UUID?, val name: Name, val rawName: String?) internal data class PreGenre( diff --git a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt index eb2787e7a..246892685 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/tag/interpret/TagInterpreter.kt @@ -165,9 +165,9 @@ private class TagInterpreterImpl(private val interpretation: Interpretation) : T ReleaseType.parse(interpretation.separators.split(parsedTags.releaseTypes)) ?: ReleaseType.Album(null), preArtists = - albumPreArtists - .ifEmpty { individualPreArtists } - .ifEmpty { listOf(unknownPreArtist()) }) + PreArtistsFrom.Album(albumPreArtists).takeIf { it.preArtists.isNotEmpty() } + ?: PreArtistsFrom.Individual( + individualPreArtists.ifEmpty { listOf(unknownPreArtist()) })) } private fun makePreArtists(