diff --git a/app/src/main/java/org/oxycblt/auxio/music/device/RawMusic.kt b/app/src/main/java/org/oxycblt/auxio/music/device/RawMusic.kt index 9bfc1f7c3..edadce46a 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/device/RawMusic.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/device/RawMusic.kt @@ -22,8 +22,7 @@ import java.util.UUID import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.fs.DeviceFile -import org.oxycblt.auxio.music.fs.Path +import org.oxycblt.auxio.music.stack.fs.DeviceFile import org.oxycblt.auxio.music.info.Date import org.oxycblt.auxio.music.info.ReleaseType diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/MetadataModule.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/MetadataModule.kt index 9d03f7bfd..082db839c 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/MetadataModule.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/MetadataModule.kt @@ -22,6 +22,10 @@ import dagger.Binds import dagger.Module import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent +import org.oxycblt.auxio.music.stack.extractor.ExoPlayerTagExtractor +import org.oxycblt.auxio.music.stack.extractor.ExoPlayerTagExtractorImpl +import org.oxycblt.auxio.music.stack.extractor.TagInterpreter2 +import org.oxycblt.auxio.music.stack.extractor.TagInterpreter2Impl @Module @InstallIn(SingletonComponent::class) diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagInterpreter.kt b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagInterpreter.kt index ffe333a76..f87433039 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagInterpreter.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/metadata/TagInterpreter.kt @@ -26,6 +26,7 @@ import kotlin.math.min import org.oxycblt.auxio.image.extractor.CoverExtractor import org.oxycblt.auxio.music.device.RawSong import org.oxycblt.auxio.music.info.Date +import org.oxycblt.auxio.music.stack.extractor.TextTags import org.oxycblt.auxio.util.nonZeroOrNull import timber.log.Timber as L diff --git a/app/src/main/java/org/oxycblt/auxio/music/stack/Indexer.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/Indexer.kt new file mode 100644 index 000000000..326cfcdb9 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/Indexer.kt @@ -0,0 +1,66 @@ +package org.oxycblt.auxio.music.stack + +import android.net.Uri +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.SharingStarted +import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.buffer +import kotlinx.coroutines.flow.filterIsInstance +import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.flow.merge +import kotlinx.coroutines.flow.shareIn +import org.oxycblt.auxio.music.device.DeviceLibrary +import org.oxycblt.auxio.music.device.RawSong +import org.oxycblt.auxio.music.stack.cache.TagCache +import org.oxycblt.auxio.music.stack.extractor.ExoPlayerTagExtractor +import org.oxycblt.auxio.music.stack.extractor.TagResult +import org.oxycblt.auxio.music.stack.fs.DeviceFile +import org.oxycblt.auxio.music.stack.fs.DeviceFiles +import org.oxycblt.auxio.music.stack.interpreter.Interpreter +import javax.inject.Inject + +interface Indexer { + suspend fun run(uris: List): DeviceLibrary +} + +class IndexerImpl @Inject constructor( + private val deviceFiles: DeviceFiles, + private val tagCache: TagCache, + private val tagExtractor: ExoPlayerTagExtractor, + private val interpreter: Interpreter +) : Indexer { + override suspend fun run(uris: List) = coroutineScope { + val deviceFiles = deviceFiles.explore(uris.asFlow()) + .flowOn(Dispatchers.IO) + .buffer() + val tagRead = tagCache.read(deviceFiles) + .flowOn(Dispatchers.IO) + .buffer() + val (cacheFiles, cacheSongs) = tagRead.split() + val tagExtractor = + tagExtractor.process(cacheFiles) + .flowOn(Dispatchers.IO) + .buffer() + val (_, extractorSongs) = tagExtractor.split() + val sharedExtractorSongs = extractorSongs.shareIn( + CoroutineScope(Dispatchers.Main), + started = SharingStarted.WhileSubscribed(), + replay = Int.MAX_VALUE + ) + val tagWrite = async { tagCache.write(merge(cacheSongs, sharedExtractorSongs)) } + val deviceLibrary = async { interpreter.interpret(sharedExtractorSongs) }.await() + tagWrite.await() + deviceLibrary + } + + private fun Flow.split(): Pair, Flow> { + val files = filterIsInstance().map { it.file } + val songs = filterIsInstance().map { it.rawSong } + return files to songs + } +} \ No newline at end of file diff --git a/app/src/main/java/org/oxycblt/auxio/music/cache/CacheModule.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/cache/CacheModule.kt similarity index 97% rename from app/src/main/java/org/oxycblt/auxio/music/cache/CacheModule.kt rename to app/src/main/java/org/oxycblt/auxio/music/stack/cache/CacheModule.kt index 175dbde36..794c0098d 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/cache/CacheModule.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/cache/CacheModule.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music.cache +package org.oxycblt.auxio.music.stack.cache import android.content.Context import androidx.room.Room diff --git a/app/src/main/java/org/oxycblt/auxio/music/cache/TagCache.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/cache/TagCache.kt similarity index 85% rename from app/src/main/java/org/oxycblt/auxio/music/cache/TagCache.kt rename to app/src/main/java/org/oxycblt/auxio/music/stack/cache/TagCache.kt index 2dad7b98f..93a50b156 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/cache/TagCache.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/cache/TagCache.kt @@ -1,11 +1,10 @@ -package org.oxycblt.auxio.music.cache +package org.oxycblt.auxio.music.stack.cache import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.transform import org.oxycblt.auxio.music.device.RawSong -import org.oxycblt.auxio.music.fs.DeviceFile -import org.oxycblt.auxio.music.metadata.TagResult +import org.oxycblt.auxio.music.stack.fs.DeviceFile +import org.oxycblt.auxio.music.stack.extractor.TagResult import javax.inject.Inject interface TagCache { diff --git a/app/src/main/java/org/oxycblt/auxio/music/cache/TagDatabase.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/cache/TagDatabase.kt similarity index 99% rename from app/src/main/java/org/oxycblt/auxio/music/cache/TagDatabase.kt rename to app/src/main/java/org/oxycblt/auxio/music/stack/cache/TagDatabase.kt index 1d62adb3e..45fd145a6 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/cache/TagDatabase.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/cache/TagDatabase.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music.cache +package org.oxycblt.auxio.music.stack.cache import androidx.room.Dao import androidx.room.Database diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor2.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/extractor/TagExtractor2.kt similarity index 97% rename from app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor2.kt rename to app/src/main/java/org/oxycblt/auxio/music/stack/extractor/TagExtractor2.kt index a442a9265..9e8037021 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagExtractor2.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/extractor/TagExtractor2.kt @@ -1,4 +1,4 @@ -package org.oxycblt.auxio.music.metadata +package org.oxycblt.auxio.music.stack.extractor import android.os.HandlerThread import androidx.media3.common.MediaItem @@ -9,7 +9,7 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.FlowCollector import kotlinx.coroutines.flow.flow import org.oxycblt.auxio.music.device.RawSong -import org.oxycblt.auxio.music.fs.DeviceFile +import org.oxycblt.auxio.music.stack.fs.DeviceFile import java.util.concurrent.Future import javax.inject.Inject import timber.log.Timber as L diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagInterpreter2.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/extractor/TagInterpreter2.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/music/metadata/TagInterpreter2.kt rename to app/src/main/java/org/oxycblt/auxio/music/stack/extractor/TagInterpreter2.kt index 5056a5971..b0de6aa1f 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TagInterpreter2.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/extractor/TagInterpreter2.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music.metadata +package org.oxycblt.auxio.music.stack.extractor import androidx.core.text.isDigitsOnly import androidx.media3.exoplayer.MetadataRetriever @@ -24,6 +24,8 @@ import javax.inject.Inject import org.oxycblt.auxio.image.extractor.CoverExtractor import org.oxycblt.auxio.music.device.RawSong import org.oxycblt.auxio.music.info.Date +import org.oxycblt.auxio.music.metadata.parseId3v2PositionField +import org.oxycblt.auxio.music.metadata.parseVorbisPositionField import org.oxycblt.auxio.util.nonZeroOrNull /** diff --git a/app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/extractor/TextTags.kt similarity index 97% rename from app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt rename to app/src/main/java/org/oxycblt/auxio/music/stack/extractor/TextTags.kt index 7e8c87391..a1dd821bb 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/metadata/TextTags.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/extractor/TextTags.kt @@ -16,12 +16,13 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music.metadata +package org.oxycblt.auxio.music.stack.extractor import androidx.media3.common.Metadata import androidx.media3.extractor.metadata.id3.InternalFrame import androidx.media3.extractor.metadata.id3.TextInformationFrame import androidx.media3.extractor.metadata.vorbis.VorbisComment +import org.oxycblt.auxio.music.metadata.correctWhitespace /** * Processing wrapper for [Metadata] that allows organized access to text-based audio tags. diff --git a/app/src/main/java/org/oxycblt/auxio/music/fs/DeviceFiles.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/fs/DeviceFiles.kt similarity index 96% rename from app/src/main/java/org/oxycblt/auxio/music/fs/DeviceFiles.kt rename to app/src/main/java/org/oxycblt/auxio/music/stack/fs/DeviceFiles.kt index 8e2d4df2c..2b90ad811 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/fs/DeviceFiles.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/fs/DeviceFiles.kt @@ -16,7 +16,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.music.fs +package org.oxycblt.auxio.music.stack.fs import android.content.ContentResolver import android.content.Context @@ -31,6 +31,9 @@ import kotlinx.coroutines.flow.emitAll import kotlinx.coroutines.flow.flatMapMerge import kotlinx.coroutines.flow.flattenMerge import kotlinx.coroutines.flow.flow +import org.oxycblt.auxio.music.fs.Components +import org.oxycblt.auxio.music.fs.contentResolverSafe +import org.oxycblt.auxio.music.fs.useQuery interface DeviceFiles { fun explore(uris: Flow): Flow diff --git a/app/src/main/java/org/oxycblt/auxio/music/stack/interpreter/Interpreter.kt b/app/src/main/java/org/oxycblt/auxio/music/stack/interpreter/Interpreter.kt new file mode 100644 index 000000000..fb2d42bae --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/music/stack/interpreter/Interpreter.kt @@ -0,0 +1,9 @@ +package org.oxycblt.auxio.music.stack.interpreter + +import kotlinx.coroutines.flow.Flow +import org.oxycblt.auxio.music.device.DeviceLibrary +import org.oxycblt.auxio.music.device.RawSong + +interface Interpreter { + suspend fun interpret(rawSong: Flow): DeviceLibrary +} \ No newline at end of file diff --git a/app/src/test/java/org/oxycblt/auxio/music/cache/CacheRepositoryTest.kt b/app/src/test/java/org/oxycblt/auxio/music/cache/CacheRepositoryTest.kt index 43872923e..23a791662 100644 --- a/app/src/test/java/org/oxycblt/auxio/music/cache/CacheRepositoryTest.kt +++ b/app/src/test/java/org/oxycblt/auxio/music/cache/CacheRepositoryTest.kt @@ -33,6 +33,8 @@ import org.junit.Assert.assertTrue import org.junit.Test import org.oxycblt.auxio.music.device.RawSong import org.oxycblt.auxio.music.info.Date +import org.oxycblt.auxio.music.stack.cache.TagDao +import org.oxycblt.auxio.music.stack.cache.Tags class CacheRepositoryTest { @Test diff --git a/app/src/test/java/org/oxycblt/auxio/music/metadata/TextTagsTest.kt b/app/src/test/java/org/oxycblt/auxio/music/metadata/TextTagsTest.kt index 9966c16e9..90c571e52 100644 --- a/app/src/test/java/org/oxycblt/auxio/music/metadata/TextTagsTest.kt +++ b/app/src/test/java/org/oxycblt/auxio/music/metadata/TextTagsTest.kt @@ -27,6 +27,7 @@ import androidx.media3.extractor.metadata.vorbis.VorbisComment import org.junit.Assert.assertEquals import org.junit.Assert.assertTrue import org.junit.Test +import org.oxycblt.auxio.music.stack.extractor.TextTags class TextTagsTest { @Test