music: add rescan option

Add an option to "rescan" the music library (i.e load without the cache).

If there are issues with the cache, this can be used instead.
This commit is contained in:
Alexander Capehart 2022-11-15 08:43:04 -07:00
parent 2b35fd07b6
commit d9a5920fee
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
8 changed files with 42 additions and 18 deletions

View file

@ -44,8 +44,15 @@ class MusicViewModel : ViewModel(), Indexer.Callback {
indexer.registerCallback(this)
}
/**
* Re-index the music library.
*/
fun reindex() {
indexer.requestReindex()
indexer.requestReindex(true)
}
fun rescan() {
indexer.requestReindex(false)
}
override fun onIndexerStateChanged(state: Indexer.State?) {

View file

@ -38,11 +38,15 @@ import java.io.File
* modification times for files, as these are required for the cache to function well.
* @author OxygenCobalt
*/
class CacheExtractor(private val context: Context) {
class CacheExtractor(private val context: Context, private val noop: Boolean) {
private var cacheMap: Map<Long, Song.Raw>? = null
private var shouldWriteCache = false
private var shouldWriteCache = noop
fun init() {
if (noop) {
return
}
try {
cacheMap = CacheDatabase.getInstance(context).read()
} catch (e: Exception) {

View file

@ -24,7 +24,6 @@ import android.os.Build
import androidx.core.content.ContextCompat
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield
import org.oxycblt.auxio.BuildConfig
@ -134,8 +133,9 @@ class Indexer {
/**
* Start the indexing process. This should be done by [Controller] in a background thread. When
* complete, a new completion state will be pushed to each callback.
* @param fresh Whether to use the cache when loading.
*/
suspend fun index(context: Context) {
suspend fun index(context: Context, fresh: Boolean) {
val notGranted =
ContextCompat.checkSelfPermission(context, PERMISSION_READ_AUDIO) ==
PackageManager.PERMISSION_DENIED
@ -148,7 +148,7 @@ class Indexer {
val response =
try {
val start = System.currentTimeMillis()
val library = indexImpl(context)
val library = indexImpl(context, fresh)
if (library != null) {
logD(
"Music indexing completed successfully in " +
@ -175,11 +175,12 @@ class Indexer {
/**
* Request that re-indexing should be done. This should be used by components that do not manage
* the indexing process to re-index music.
* @param withCache Whether to use the cache when loading music.
*/
@Synchronized
fun requestReindex() {
fun requestReindex(withCache: Boolean) {
logD("Requesting reindex")
controller?.onStartIndexing()
controller?.onStartIndexing(withCache)
}
/**
@ -196,13 +197,13 @@ class Indexer {
/**
* Run the proper music loading process.
*/
private suspend fun indexImpl(context: Context): MusicStore.Library? {
private suspend fun indexImpl(context: Context, withCache: Boolean): MusicStore.Library? {
// Create the chain of extractors. Each extractor builds on the previous and
// enables version-specific features in order to create the best possible music
// experience. This is technically dependency injection. Except it doesn't increase
// your compile times by 3x. Isn't that nice.
val cacheDatabase = CacheExtractor(context)
val cacheDatabase = CacheExtractor(context, !withCache)
val mediaStoreExtractor =
when {
@ -434,7 +435,7 @@ class Indexer {
}
interface Controller : Callback {
fun onStartIndexing()
fun onStartIndexing(withCache: Boolean)
}
companion object {

View file

@ -89,7 +89,7 @@ class IndexerService : Service(), Indexer.Controller, Settings.Callback {
indexer.registerController(this)
if (musicStore.library == null && indexer.isIndeterminate) {
logD("No library present and no previous response, indexing music now")
onStartIndexing()
onStartIndexing(true)
}
logD("Service created.")
@ -117,13 +117,13 @@ class IndexerService : Service(), Indexer.Controller, Settings.Callback {
// --- CONTROLLER CALLBACKS ---
override fun onStartIndexing() {
override fun onStartIndexing(withCache: Boolean) {
if (indexer.isIndexing) {
currentIndexJob?.cancel()
indexer.cancelLast()
}
currentIndexJob = indexScope.launch { indexer.index(this@IndexerService) }
currentIndexJob = indexScope.launch { indexer.index(this@IndexerService, withCache) }
}
override fun onIndexerStateChanged(state: Indexer.State?) {
@ -228,7 +228,7 @@ class IndexerService : Service(), Indexer.Controller, Settings.Callback {
getString(R.string.set_key_exclude_non_music),
getString(R.string.set_key_music_dirs),
getString(R.string.set_key_music_dirs_include),
getString(R.string.set_key_separators) -> onStartIndexing()
getString(R.string.set_key_separators) -> onStartIndexing(true)
getString(R.string.set_key_observing) -> {
if (!indexer.isIndexing) {
updateIdleSession()
@ -263,7 +263,8 @@ class IndexerService : Service(), Indexer.Controller, Settings.Callback {
// Check here if we should even start a reindex. This is much less bug-prone than
// registering and de-registering this component as this setting changes.
if (settings.shouldBeObserving) {
onStartIndexing()
onSt
artIndexing(true)
}
}
}

View file

@ -145,6 +145,9 @@ class PreferenceFragment : PreferenceFragmentCompat() {
context.getString(R.string.set_key_reindex) -> {
musicModel.reindex()
}
context.getString(R.string.set_key_rescan) -> {
musicModel.rescan()
}
else -> return super.onPreferenceTreeClick(preference)
}

View file

@ -6,6 +6,7 @@
<string name="set_key_accent" translatable="false">auxio_accent2</string>
<string name="set_key_reindex" translatable="false">auxio_reindex</string>
<string name="set_key_rescan" translatable="false">auxio_rescan</string>
<string name="set_key_observing" translatable="false">auxio_observing</string>
<string name="set_key_music_dirs" translatable="false">auxio_music_dirs</string>
<string name="set_key_cover_mode" translatable="false">auxio_cover_mode</string>

View file

@ -218,9 +218,12 @@
<string name="set_content">Content</string>
<string name="set_reindex">Reload music</string>
<string name="set_reindex_desc">May wipe playback state</string>
<string name="set_reindex_desc">Reload the music library, using the cache whenever possible</string>
<!-- Different from "Reload music" -->
<string name="set_rescan">Rescan music</string>
<string name="set_rescan_desc">Reload the music library and re-create the cache (Slower, but more complete)</string>
<string name="set_observing">Automatic reloading</string>
<string name="set_observing_desc">Reload your music library whenever it changes (Requires persistent notification)</string>
<string name="set_observing_desc">Reload the music library whenever it changes (Requires persistent notification)</string>
<string name="set_dirs">Music folders</string>
<string name="set_dirs_desc">Manage where music should be loaded from</string>
<!-- As in the mode to be used with the music folders setting -->

View file

@ -139,6 +139,10 @@
app:key="@string/set_key_reindex"
app:summary="@string/set_reindex_desc"
app:title="@string/set_reindex" />
<Preference
app:key="@string/set_key_rescan"
app:summary="@string/set_rescan_desc"
app:title="@string/set_rescan" />
<SwitchPreferenceCompat
app:defaultValue="false"