musikr: remove di requirement from tagcache

This commit is contained in:
Alexander Capehart 2024-12-11 06:58:16 -07:00
parent 45ead8253a
commit 530d8cc2b5
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
11 changed files with 109 additions and 77 deletions

View file

@ -18,11 +18,15 @@
package org.oxycblt.auxio.music package org.oxycblt.auxio.music
import android.content.Context
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton import javax.inject.Singleton
import org.oxycblt.musikr.tag.cache.TagDatabase
@Module @Module
@InstallIn(SingletonComponent::class) @InstallIn(SingletonComponent::class)
@ -31,3 +35,11 @@ interface MusicModule {
@Binds fun settings(musicSettingsImpl: MusicSettingsImpl): MusicSettings @Binds fun settings(musicSettingsImpl: MusicSettingsImpl): MusicSettings
} }
@Module
@InstallIn(SingletonComponent::class)
class MusikrShimModule {
@Singleton
@Provides
fun tagDatabase(@ApplicationContext context: Context) = TagDatabase.from(context)
}

View file

@ -26,19 +26,18 @@ import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield import kotlinx.coroutines.yield
import org.oxycblt.auxio.music.MusicRepository.IndexingWorker import org.oxycblt.auxio.music.MusicRepository.IndexingWorker
import org.oxycblt.musikr.IndexingProgress import org.oxycblt.musikr.IndexingProgress
import org.oxycblt.musikr.Interpretation
import org.oxycblt.musikr.Library import org.oxycblt.musikr.Library
import org.oxycblt.musikr.Music import org.oxycblt.musikr.Music
import org.oxycblt.musikr.Musikr import org.oxycblt.musikr.Musikr
import org.oxycblt.musikr.MutableLibrary import org.oxycblt.musikr.MutableLibrary
import org.oxycblt.musikr.Playlist import org.oxycblt.musikr.Playlist
import org.oxycblt.musikr.Song import org.oxycblt.musikr.Song
import org.oxycblt.musikr.Interpretation
import org.oxycblt.musikr.Storage import org.oxycblt.musikr.Storage
import org.oxycblt.musikr.cover.Cover
import org.oxycblt.musikr.cover.StoredCovers import org.oxycblt.musikr.cover.StoredCovers
import org.oxycblt.musikr.tag.Name import org.oxycblt.musikr.tag.Name
import org.oxycblt.musikr.tag.cache.FullTagCache import org.oxycblt.musikr.tag.cache.TagCache
import org.oxycblt.musikr.tag.cache.WriteOnlyTagCache import org.oxycblt.musikr.tag.cache.TagDatabase
import org.oxycblt.musikr.tag.interpret.Separators import org.oxycblt.musikr.tag.interpret.Separators
import timber.log.Timber as L import timber.log.Timber as L
@ -208,8 +207,11 @@ interface MusicRepository {
class MusicRepositoryImpl class MusicRepositoryImpl
@Inject @Inject
constructor(private val musikr: Musikr, private val fullTagCache: FullTagCache, private val writeOnlyTagCache: WriteOnlyTagCache, private val musicSettings: MusicSettings) : constructor(
MusicRepository { private val musikr: Musikr,
private val tagDatabase: TagDatabase,
private val musicSettings: MusicSettings
) : MusicRepository {
private val updateListeners = mutableListOf<MusicRepository.UpdateListener>() private val updateListeners = mutableListOf<MusicRepository.UpdateListener>()
private val indexingListeners = mutableListOf<MusicRepository.IndexingListener>() private val indexingListeners = mutableListOf<MusicRepository.IndexingListener>()
@Volatile private var indexingWorker: MusicRepository.IndexingWorker? = null @Volatile private var indexingWorker: MusicRepository.IndexingWorker? = null
@ -354,13 +356,15 @@ constructor(private val musikr: Musikr, private val fullTagCache: FullTagCache,
} }
val locations = musicSettings.musicLocations val locations = musicSettings.musicLocations
val storage = if (withCache) { val storage =
Storage(fullTagCache, StoredCovers.buildOn()) if (withCache) {
} else { Storage(TagCache.full(tagDatabase), StoredCovers.buildOn())
Storage(writeOnlyTagCache, StoredCovers.new()) } else {
} Storage(TagCache.writeOnly(tagDatabase), StoredCovers.new())
}
val newLibrary = val newLibrary =
musikr.run(locations, storage, Interpretation(nameFactory, separators), ::emitIndexingProgress) musikr.run(
locations, storage, Interpretation(nameFactory, separators), ::emitIndexingProgress)
emitIndexingCompletion(null) emitIndexingCompletion(null)

View file

@ -1,3 +1,21 @@
/*
* Copyright (c) 2024 Auxio Project
* Config.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.musikr package org.oxycblt.musikr
import org.oxycblt.musikr.cover.StoredCovers import org.oxycblt.musikr.cover.StoredCovers

View file

@ -18,13 +18,9 @@
package org.oxycblt.musikr.cover package org.oxycblt.musikr.cover
import android.content.Context
import androidx.room.Room
import dagger.Binds import dagger.Binds
import dagger.Module import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton import javax.inject.Singleton

View file

@ -1,11 +1,29 @@
/*
* Copyright (c) 2024 Auxio Project
* CoverParser.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.musikr.cover package org.oxycblt.musikr.cover
import androidx.media3.common.MediaMetadata import androidx.media3.common.MediaMetadata
import androidx.media3.common.Metadata import androidx.media3.common.Metadata
import androidx.media3.extractor.metadata.flac.PictureFrame import androidx.media3.extractor.metadata.flac.PictureFrame
import androidx.media3.extractor.metadata.id3.ApicFrame import androidx.media3.extractor.metadata.id3.ApicFrame
import org.oxycblt.musikr.metadata.AudioMetadata
import javax.inject.Inject import javax.inject.Inject
import org.oxycblt.musikr.metadata.AudioMetadata
interface CoverParser { interface CoverParser {
suspend fun extract(metadata: AudioMetadata): ByteArray? suspend fun extract(metadata: AudioMetadata): ByteArray?
@ -32,12 +50,10 @@ class CoverParserImpl @Inject constructor() : CoverParser {
pic = entry.pictureData pic = entry.pictureData
type = entry.pictureType type = entry.pictureType
} }
is PictureFrame -> { is PictureFrame -> {
pic = entry.pictureData pic = entry.pictureData
type = entry.pictureType type = entry.pictureType
} }
else -> continue else -> continue
} }
@ -50,4 +66,4 @@ class CoverParserImpl @Inject constructor() : CoverParser {
return fallbackPic return fallbackPic
} }
} }

View file

@ -1,3 +1,21 @@
/*
* Copyright (c) 2024 Auxio Project
* StoredCovers.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.musikr.cover package org.oxycblt.musikr.cover
import java.io.InputStream import java.io.InputStream
@ -11,6 +29,7 @@ interface StoredCovers {
companion object { companion object {
suspend fun buildOn(): Editor = TODO() suspend fun buildOn(): Editor = TODO()
fun new(): Editor = TODO() fun new(): Editor = TODO()
} }
} }

View file

@ -26,10 +26,10 @@ import kotlinx.coroutines.flow.buffer
import kotlinx.coroutines.flow.filterIsInstance import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.flowOn import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import org.oxycblt.musikr.Interpretation
import org.oxycblt.musikr.MutableLibrary import org.oxycblt.musikr.MutableLibrary
import org.oxycblt.musikr.graph.MusicGraph import org.oxycblt.musikr.graph.MusicGraph
import org.oxycblt.musikr.model.LibraryFactory import org.oxycblt.musikr.model.LibraryFactory
import org.oxycblt.musikr.Interpretation
import org.oxycblt.musikr.tag.interpret.TagInterpreter import org.oxycblt.musikr.tag.interpret.TagInterpreter
interface EvaluateStep { interface EvaluateStep {

View file

@ -18,7 +18,6 @@
package org.oxycblt.musikr.tag.cache package org.oxycblt.musikr.tag.cache
import javax.inject.Inject
import org.oxycblt.musikr.fs.query.DeviceFile import org.oxycblt.musikr.fs.query.DeviceFile
import org.oxycblt.musikr.tag.parse.ParsedTags import org.oxycblt.musikr.tag.parse.ParsedTags
@ -26,9 +25,15 @@ interface TagCache {
suspend fun read(file: DeviceFile): ParsedTags? suspend fun read(file: DeviceFile): ParsedTags?
suspend fun write(file: DeviceFile, tags: ParsedTags) suspend fun write(file: DeviceFile, tags: ParsedTags)
companion object {
fun full(db: TagDatabase): TagCache = FullTagCache(db.cachedSongsDao())
fun writeOnly(db: TagDatabase): TagCache = WriteOnlyTagCache(db.cachedSongsDao())
}
} }
class FullTagCache @Inject constructor(private val tagDao: TagDao) : TagCache { private class FullTagCache(private val tagDao: TagDao) : TagCache {
override suspend fun read(file: DeviceFile) = override suspend fun read(file: DeviceFile) =
tagDao.selectTags(file.uri.toString(), file.lastModified)?.intoParsedTags() tagDao.selectTags(file.uri.toString(), file.lastModified)?.intoParsedTags()
@ -36,9 +41,9 @@ class FullTagCache @Inject constructor(private val tagDao: TagDao) : TagCache {
tagDao.updateTags(CachedTags.fromParsedTags(file, tags)) tagDao.updateTags(CachedTags.fromParsedTags(file, tags))
} }
class WriteOnlyTagCache @Inject constructor(private val tagDao: TagDao) : TagCache { private class WriteOnlyTagCache(private val tagDao: TagDao) : TagCache {
override suspend fun read(file: DeviceFile) = null override suspend fun read(file: DeviceFile) = null
override suspend fun write(file: DeviceFile, tags: ParsedTags) = override suspend fun write(file: DeviceFile, tags: ParsedTags) =
tagDao.updateTags(CachedTags.fromParsedTags(file, tags)) tagDao.updateTags(CachedTags.fromParsedTags(file, tags))
} }

View file

@ -1,48 +0,0 @@
/*
* Copyright (c) 2023 Auxio Project
* TagCacheModule.kt is part of Auxio.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.musikr.tag.cache
import android.content.Context
import androidx.room.Room
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
@Module
@InstallIn(SingletonComponent::class)
interface TagCacheModule {
@Binds fun tagCache(cacheRepository: TagCacheImpl): TagCache
}
@Module
@InstallIn(SingletonComponent::class)
class TagDatabaseModule {
@Singleton
@Provides
fun database(@ApplicationContext context: Context) =
Room.databaseBuilder(context.applicationContext, TagDatabase::class.java, "music_cache.db")
.fallbackToDestructiveMigration()
.build()
@Provides fun tagsDao(database: TagDatabase) = database.cachedSongsDao()
}

View file

@ -18,6 +18,7 @@
package org.oxycblt.musikr.tag.cache package org.oxycblt.musikr.tag.cache
import android.content.Context
import androidx.room.Dao import androidx.room.Dao
import androidx.room.Database import androidx.room.Database
import androidx.room.Entity import androidx.room.Entity
@ -25,6 +26,7 @@ import androidx.room.Insert
import androidx.room.OnConflictStrategy import androidx.room.OnConflictStrategy
import androidx.room.PrimaryKey import androidx.room.PrimaryKey
import androidx.room.Query import androidx.room.Query
import androidx.room.Room
import androidx.room.RoomDatabase import androidx.room.RoomDatabase
import androidx.room.TypeConverter import androidx.room.TypeConverter
import androidx.room.TypeConverters import androidx.room.TypeConverters
@ -36,11 +38,19 @@ import org.oxycblt.musikr.tag.util.splitEscaped
@Database(entities = [CachedTags::class], version = 50, exportSchema = false) @Database(entities = [CachedTags::class], version = 50, exportSchema = false)
abstract class TagDatabase : RoomDatabase() { abstract class TagDatabase : RoomDatabase() {
abstract fun cachedSongsDao(): TagDao internal abstract fun cachedSongsDao(): TagDao
companion object {
fun from(context: Context) =
Room.databaseBuilder(
context.applicationContext, TagDatabase::class.java, "music_cache.db")
.fallbackToDestructiveMigration()
.build()
}
} }
@Dao @Dao
interface TagDao { internal interface TagDao {
@Query("SELECT * FROM CachedTags WHERE uri = :uri AND dateModified = :dateModified") @Query("SELECT * FROM CachedTags WHERE uri = :uri AND dateModified = :dateModified")
suspend fun selectTags(uri: String, dateModified: Long): CachedTags? suspend fun selectTags(uri: String, dateModified: Long): CachedTags?
@ -49,7 +59,7 @@ interface TagDao {
@Entity @Entity
@TypeConverters(CachedTags.Converters::class) @TypeConverters(CachedTags.Converters::class)
data class CachedTags( internal data class CachedTags(
/** /**
* The Uri of the [AudioFile]'s audio file, obtained from SAF. This should ideally be a black * The Uri of the [AudioFile]'s audio file, obtained from SAF. This should ideally be a black
* box only used for comparison. * box only used for comparison.

View file

@ -22,10 +22,10 @@ import javax.inject.Inject
import org.oxycblt.auxio.R import org.oxycblt.auxio.R
import org.oxycblt.auxio.playback.replaygain.ReplayGainAdjustment import org.oxycblt.auxio.playback.replaygain.ReplayGainAdjustment
import org.oxycblt.auxio.util.toUuidOrNull import org.oxycblt.auxio.util.toUuidOrNull
import org.oxycblt.musikr.Interpretation
import org.oxycblt.musikr.fs.MimeType import org.oxycblt.musikr.fs.MimeType
import org.oxycblt.musikr.fs.query.DeviceFile import org.oxycblt.musikr.fs.query.DeviceFile
import org.oxycblt.musikr.tag.Disc import org.oxycblt.musikr.tag.Disc
import org.oxycblt.musikr.Interpretation
import org.oxycblt.musikr.tag.Name import org.oxycblt.musikr.tag.Name
import org.oxycblt.musikr.tag.ReleaseType import org.oxycblt.musikr.tag.ReleaseType
import org.oxycblt.musikr.tag.parse.ParsedTags import org.oxycblt.musikr.tag.parse.ParsedTags