diff --git a/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/Interpreter.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/Interpreter.kt index 92f9fcb0b..4655157d3 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/Interpreter.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/Interpreter.kt @@ -46,14 +46,17 @@ class InterpreterImpl( val artistLinker = ArtistLinker() val artistLinkedSongs = artistLinker.register(genreLinkedSongs).flowOn(Dispatchers.Main).buffer() + // This is intentional. Song and album instances are dependent on artist + // data, so we need to ensure that all of the linked artist data is resolved + // before we go any further. + val genres = genreLinker.resolve() + val artists = artistLinker.resolve() val albumLinker = AlbumLinker() val albumLinkedSongs = albumLinker.register(artistLinkedSongs) .flowOn(Dispatchers.Main) .map { LinkedSongImpl(it) } .toList() - val genres = genreLinker.resolve() - val artists = artistLinker.resolve() val albums = albumLinker.resolve() val songs = albumLinkedSongs.map { SongImpl(it) } return LibraryImpl(songs, albums, artists, genres) diff --git a/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/linker/AlbumLinker.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/linker/AlbumLinker.kt index 6d5d6900e..d583de771 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/linker/AlbumLinker.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/interpret/linker/AlbumLinker.kt @@ -2,16 +2,83 @@ package org.oxycblt.auxio.music.stack.interpret.linker import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.map +import org.oxycblt.auxio.music.Album +import org.oxycblt.auxio.music.Music +import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.stack.interpret.model.AlbumImpl +import org.oxycblt.auxio.music.stack.interpret.model.ArtistImpl +import org.oxycblt.auxio.music.stack.interpret.model.GenreImpl import org.oxycblt.auxio.music.stack.interpret.model.SongImpl +import org.oxycblt.auxio.music.stack.interpret.prepare.PreAlbum +import org.oxycblt.auxio.music.stack.interpret.prepare.PreGenre +import org.oxycblt.auxio.music.stack.interpret.prepare.PreSong +import java.util.UUID class AlbumLinker { - fun register(linkedSongs: Flow): Flow = emptyFlow() - fun resolve(): Collection = setOf() + private val tree = mutableMapOf>() + + fun register(linkedSongs: Flow) = linkedSongs.map { + val nameKey = it.linkedAlbum.preAlbum.rawName.lowercase() + val musicBrainzIdKey = it.linkedAlbum.preAlbum.musicBrainzId + val albumLink = tree.getOrPut(nameKey) { mutableMapOf() } + .getOrPut(musicBrainzIdKey) { AlbumLink(AlbumNode(Contribution())) } + albumLink.node.contributors.contribute(it.linkedAlbum) + LinkedSong(it, albumLink) + } + + fun resolve(): Collection = + tree.values.flatMap { musicBrainzIdBundle -> + val only = + musicBrainzIdBundle.values.singleOrNull() + if (only != null) { + return@flatMap listOf(only.node.resolve()) + } + val nullBundle = musicBrainzIdBundle[null] + ?: return@flatMap musicBrainzIdBundle.values.map { it.node.resolve() } + // Only partially tagged with MBIDs, must go through and + musicBrainzIdBundle.filter { it.key != null }.forEach { + val candidates = it.value.node.contributors.candidates + nullBundle.node.contributors.contribute(candidates) + it.value.node = nullBundle.node + } + listOf(nullBundle.node.resolve()) + } data class LinkedSong( - val linkedArtistSong: ArtistLinker.LinkedSong, + val linkedSong: ArtistLinker.LinkedSong, val album: Linked ) -} \ No newline at end of file + + private data class AlbumLink( + var node: AlbumNode + ) : Linked { + override fun resolve(child: SongImpl): AlbumImpl { + return requireNotNull(node.albumImpl) { "Album not resolved yet" }.also { + it.link(child) + } + } + } + + private class AlbumNode( + val contributors: Contribution + ) { + var albumImpl: AlbumImpl? = null + private set + + fun resolve(): AlbumImpl { + val impl = AlbumImpl(LinkedAlbumImpl(contributors.resolve())) + albumImpl = impl + return impl + } + } + + private class LinkedAlbumImpl( + private val artistLinkedAlbum: ArtistLinker.LinkedAlbum + ) : LinkedAlbum { + override val preAlbum = artistLinkedAlbum.preAlbum + + override val artists = artistLinkedAlbum.artists + } +}