music: enable tag caching

This commit is contained in:
Alexander Capehart 2024-11-29 16:29:00 -07:00
parent a22e972bd3
commit a3da28fb84
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
2 changed files with 38 additions and 14 deletions

View file

@ -35,10 +35,12 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.withIndex
import org.oxycblt.auxio.music.stack.IndexingProgress
import org.oxycblt.auxio.music.stack.explore.cache.CacheResult
import org.oxycblt.auxio.music.stack.explore.cache.TagCache
import org.oxycblt.auxio.music.stack.explore.extractor.TagExtractor
import org.oxycblt.auxio.music.stack.explore.fs.DeviceFiles
import org.oxycblt.auxio.music.stack.explore.playlists.StoredPlaylists
import timber.log.Timber
interface Explorer {
fun explore(uris: List<Uri>, onProgress: suspend (IndexingProgress.Songs) -> Unit): Files
@ -65,24 +67,26 @@ constructor(
deviceFiles
.explore(uris.asFlow())
.onEach {
Timber.d("File explored: $it")
explored++
onProgress(IndexingProgress.Songs(loaded, explored))
}
.flowOn(Dispatchers.IO)
.buffer(Channel.UNLIMITED)
// val cacheResults = tagCache.read(deviceFiles).flowOn(Dispatchers.IO).buffer()
// val (handle, uncachedDeviceFiles, cachedAudioFiles) = tagRead.results()
val extractedAudioFiles =
deviceFiles.stretch(8) { tagExtractor.extract(it).flowOn(Dispatchers.IO) }
// val writtenAudioFiles =
// tagCache.write(extractedAudioFiles).flowOn(Dispatchers.IO).buffer()
// val audioFiles = merge(cachedAudioFiles, writtenAudioFiles)
val cacheResults = tagCache.read(deviceFiles).flowOn(Dispatchers.IO).buffer()
val audioFiles =
extractedAudioFiles.onEach {
loaded++
onProgress(IndexingProgress.Songs(loaded, explored))
}
cacheResults
.handleMisses {
val extracted =
it.stretch(8) { tagExtractor.extract(it).flowOn(Dispatchers.IO) }.buffer()
val written = tagCache.write(extracted).flowOn(Dispatchers.IO).buffer()
written
}
.onEach {
loaded++
onProgress(IndexingProgress.Songs(loaded, explored))
Timber.d("File extracted: $it")
}
val playlistFiles = storedPlaylists.read()
return Files(audioFiles, playlistFiles)
}
@ -103,4 +107,24 @@ constructor(
posChannels.map { creator(it.receiveAsFlow()).buffer(Channel.UNLIMITED) }.asFlow()
return merge(divert, handle.flattenMerge())
}
private fun Flow<CacheResult>.handleMisses(
uncached: (Flow<DeviceFile>) -> Flow<AudioFile>
): Flow<AudioFile> {
val uncachedChannel = Channel<DeviceFile>()
val cachedChannel = Channel<AudioFile>()
val divert: Flow<AudioFile> = flow {
collect {
when (it) {
is CacheResult.Hit -> cachedChannel.send(it.audioFile)
is CacheResult.Miss -> uncachedChannel.send(it.deviceFile)
}
}
cachedChannel.close()
uncachedChannel.close()
}
val uncached = uncached(uncachedChannel.receiveAsFlow())
val cached = cachedChannel.receiveAsFlow()
return merge(divert, uncached, cached)
}
}

View file

@ -20,8 +20,8 @@ package org.oxycblt.auxio.music.stack.explore.cache
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.flow.transform
import org.oxycblt.auxio.music.stack.explore.AudioFile
import org.oxycblt.auxio.music.stack.explore.DeviceFile
@ -39,7 +39,7 @@ interface TagCache {
class TagCacheImpl @Inject constructor(private val tagDao: TagDao) : TagCache {
override fun read(files: Flow<DeviceFile>) =
files.transform<DeviceFile, CacheResult> { file ->
files.map { file ->
val tags = tagDao.selectTags(file.uri.toString(), file.lastModified)
if (tags != null) {
CacheResult.Hit(tags.toAudioFile(file))