From a1188b8d4b21339d7bc87907a52621eb69aaad79 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Tue, 17 Dec 2024 15:40:05 -0500 Subject: [PATCH] music: introduce library revisions Will be used to maintain image loading consistency even during loads. --- .../oxycblt/auxio/music/MusicRepository.kt | 30 +++++++++++------ .../org/oxycblt/auxio/music/MusicSettings.kt | 14 ++++++++ .../oxycblt/auxio/music/RevisionedLibrary.kt | 32 +++++++++++++++++++ app/src/main/res/values/settings.xml | 2 ++ 4 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt index e5b6934e3..fe76217e5 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt @@ -43,6 +43,7 @@ import org.oxycblt.musikr.playlist.db.PlaylistDatabase import org.oxycblt.musikr.playlist.db.StoredPlaylists import org.oxycblt.musikr.tag.interpret.Naming import org.oxycblt.musikr.tag.interpret.Separators +import java.util.UUID import timber.log.Timber as L /** @@ -57,7 +58,8 @@ import timber.log.Timber as L * configurations */ interface MusicRepository { - val library: Library? + /** The current library */ + val library: RevisionedLibrary? /** The current state of music loading. Null if no load has occurred yet. */ val indexingState: IndexingState? @@ -222,7 +224,7 @@ constructor( private val indexingListeners = mutableListOf() @Volatile private var indexingWorker: MusicRepository.IndexingWorker? = null - @Volatile override var library: MutableLibrary? = null + @Volatile override var library: MutableRevisionedLibrary? = null @Volatile private var previousCompletedState: IndexingState.Completed? = null @Volatile private var currentIndexingState: IndexingState? = null override val indexingState: IndexingState? @@ -362,17 +364,19 @@ constructor( } val locations = musicSettings.musicLocations - val storage = + val revision: UUID + val storage: Storage if (withCache) { - Storage( + revision = this.library?.revision ?: musicSettings.revision + storage = Storage( Cache.full(cacheDatabase), - StoredCovers.from(context, "covers"), + StoredCovers.from(context, "covers_$revision"), StoredPlaylists.from(playlistDatabase)) } else { - // TODO: Revisioned cache (as a stateful extension of musikr) - Storage( + revision = UUID.randomUUID() + storage = Storage( Cache.writeOnly(cacheDatabase), - StoredCovers.from(context, "covers"), + StoredCovers.from(context, "covers_$revision"), StoredPlaylists.from(playlistDatabase)) } @@ -381,6 +385,9 @@ constructor( val newLibrary = Musikr.new(context, storage, interpretation).run(locations, ::emitIndexingProgress) + val revisionedLibrary = + MutableRevisionedLibrary(revision, newLibrary) + emitIndexingCompletion(null) // We want to make sure that all reads and writes are synchronized due to the sheer @@ -402,7 +409,7 @@ constructor( return } - this.library = newLibrary + this.library = revisionedLibrary } // Consumers expect their updates to be on the main thread (notably PlaybackService), @@ -410,6 +417,11 @@ constructor( withContext(Dispatchers.Main) { dispatchLibraryChange(deviceLibraryChanged, userLibraryChanged) } + + // Quietly update the revision if needed (this way we don't disrupt any new loads) + if (!withCache) { + musicSettings.revision = revisionedLibrary.revision + } } private suspend fun emitIndexingProgress(progress: IndexingProgress) { diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt index 7c7a66742..b64625e54 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicSettings.kt @@ -25,6 +25,7 @@ import javax.inject.Inject import org.oxycblt.auxio.R import org.oxycblt.auxio.settings.Settings import org.oxycblt.musikr.fs.MusicLocation +import java.util.UUID import timber.log.Timber as L /** @@ -33,6 +34,8 @@ import timber.log.Timber as L * @author Alexander Capehart (OxygenCobalt) */ interface MusicSettings : Settings { + /** The current library revision. */ + var revision: UUID /** The locations of music to load. */ var musicLocations: List /** Whether to exclude non-music audio files from the music library. */ @@ -55,6 +58,17 @@ interface MusicSettings : Settings { class MusicSettingsImpl @Inject constructor(@ApplicationContext private val context: Context) : Settings.Impl(context), MusicSettings { + override var revision: UUID + get() = UUID.fromString( + sharedPreferences.getString(getString(R.string.set_key_library_revision), null) + ?: UUID.randomUUID().toString()) + set(value) { + sharedPreferences.edit { + putString(getString(R.string.set_key_library_revision), value.toString()) + apply() + } + } + override var musicLocations: List get() { val locations = diff --git a/app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt b/app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt new file mode 100644 index 000000000..37363eb55 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt @@ -0,0 +1,32 @@ +package org.oxycblt.auxio.music + +import org.oxycblt.musikr.Library +import org.oxycblt.musikr.MutableLibrary +import org.oxycblt.musikr.Playlist +import org.oxycblt.musikr.Song +import java.util.UUID + +interface RevisionedLibrary : Library { + val revision: UUID +} + +class MutableRevisionedLibrary( + override val revision: UUID, + private val inner: MutableLibrary +) : RevisionedLibrary, Library by inner, MutableLibrary { + override suspend fun createPlaylist(name: String, songs: List) = + MutableRevisionedLibrary(revision, inner.createPlaylist(name, songs)) + + override suspend fun renamePlaylist(playlist: Playlist, name: String) = + MutableRevisionedLibrary(revision, inner.renamePlaylist(playlist, name)) + + override suspend fun addToPlaylist(playlist: Playlist, songs: List) = + MutableRevisionedLibrary(revision, inner.addToPlaylist(playlist, songs)) + + override suspend fun rewritePlaylist(playlist: Playlist, songs: List) = + MutableRevisionedLibrary(revision, inner.rewritePlaylist(playlist, songs)) + + override suspend fun deletePlaylist(playlist: Playlist) = + MutableRevisionedLibrary(revision, inner.deletePlaylist(playlist)) + +} \ No newline at end of file diff --git a/app/src/main/res/values/settings.xml b/app/src/main/res/values/settings.xml index 6bc79e6d3..a3502babb 100644 --- a/app/src/main/res/values/settings.xml +++ b/app/src/main/res/values/settings.xml @@ -53,6 +53,8 @@ auxio_artist_sort auxio_genre_sort + auxio_library_revision + @string/set_theme_auto @string/set_theme_day