music: re-add song deduplication

This commit is contained in:
Alexander Capehart 2024-11-26 10:05:17 -07:00
parent 3bf80073f4
commit 9d9f810356
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
4 changed files with 42 additions and 20 deletions

View file

@ -26,6 +26,7 @@ import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.toList
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.stack.Indexer
import org.oxycblt.auxio.music.stack.explore.AudioFile
import org.oxycblt.auxio.music.stack.explore.PlaylistFile
@ -42,6 +43,7 @@ import org.oxycblt.auxio.music.stack.interpret.model.MutableLibrary
import org.oxycblt.auxio.music.stack.interpret.model.SongImpl
import org.oxycblt.auxio.music.stack.interpret.prepare.PreSong
import org.oxycblt.auxio.music.stack.interpret.prepare.Preparer
import timber.log.Timber as L
interface Interpreter {
suspend fun interpret(
@ -88,8 +90,22 @@ class InterpreterImpl @Inject constructor(private val preparer: Preparer) : Inte
.toList()
val albums = albumLinker.resolve()
val songs = albumLinkedSongs.map { SongImpl(it) }
return LibraryImpl(songs, albums, artists, genres)
val uidMap = mutableMapOf<Music.UID, SongImpl>()
val songs = albumLinkedSongs.mapNotNull {
val uid = it.preSong.computeUid()
val other = uidMap[uid]
if (other == null) {
SongImpl(it)
} else {
L.d("Song @ $uid already exists at ${other.path}, ignoring")
null
}
}
return LibraryImpl(
songs,
albums.onEach { it.finalize() },
artists.onEach { it.finalize() },
genres.onEach { it.finalize() })
}
private data class LinkedSongImpl(private val albumLinkedSong: AlbumLinker.LinkedSong) :

View file

@ -43,23 +43,7 @@ import org.oxycblt.auxio.util.update
class SongImpl(linkedSong: LinkedSong) : Song {
private val preSong = linkedSong.preSong
override val uid =
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
preSong.musicBrainzId?.let { Music.UID.musicBrainz(MusicType.SONGS, it) }
?: Music.UID.auxio(MusicType.SONGS) {
// Song UIDs are based on the raw data without parsing so that they remain
// consistent across music setting changes. Parents are not held up to the
// same standard since grouping is already inherently linked to settings.
update(preSong.rawName)
update(preSong.preAlbum.rawName)
update(preSong.date)
update(preSong.track)
update(preSong.disc?.number)
update(preSong.preArtists.map { it.rawName })
update(preSong.preAlbum.preArtists.map { it.rawName })
}
override val uid = preSong.computeUid()
override val name = preSong.name
override val track = preSong.track
override val disc = preSong.disc

View file

@ -47,6 +47,8 @@ class LibraryImpl(
) : MutableLibrary {
override val playlists = emptySet<Playlist>()
private val songUidMap = songs.associ { it.uid }
override fun findSong(uid: Music.UID): Song? {
TODO("Not yet implemented")
}

View file

@ -21,6 +21,8 @@ package org.oxycblt.auxio.music.stack.interpret.prepare
import android.net.Uri
import java.util.UUID
import org.oxycblt.auxio.image.extractor.Cover
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicType
import org.oxycblt.auxio.music.info.Date
import org.oxycblt.auxio.music.info.Disc
import org.oxycblt.auxio.music.info.Name
@ -29,6 +31,7 @@ import org.oxycblt.auxio.music.stack.explore.PlaylistHandle
import org.oxycblt.auxio.music.stack.explore.fs.MimeType
import org.oxycblt.auxio.music.stack.explore.fs.Path
import org.oxycblt.auxio.playback.replaygain.ReplayGainAdjustment
import org.oxycblt.auxio.util.update
data class PreSong(
val musicBrainzId: UUID?,
@ -48,7 +51,24 @@ data class PreSong(
val preAlbum: PreAlbum,
val preArtists: List<PreArtist>,
val preGenres: List<PreGenre>
)
) {
fun computeUid() =
musicBrainzId?.let { Music.UID.musicBrainz(MusicType.SONGS, it) }
?: Music.UID.auxio(MusicType.SONGS) {
// Song UIDs are based on the raw data without parsing so that they remain
// consistent across music setting changes. Parents are not held up to the
// same standard since grouping is already inherently linked to settings.
update(rawName)
update(preAlbum.rawName)
update(date)
update(track)
update(disc?.number)
update(preArtists.map { artist -> artist.rawName })
update(preAlbum.preArtists.map { artist -> artist.rawName })
}
}
data class PreAlbum(
val musicBrainzId: UUID?,