diff --git a/app/src/main/java/org/oxycblt/auxio/image/CoverView.kt b/app/src/main/java/org/oxycblt/auxio/image/CoverView.kt index f26bd8e8d..704378c11 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/CoverView.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/CoverView.kt @@ -372,7 +372,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr * @param errorRes The resource of the error drawable to use if the cover cannot be loaded. */ fun bind(songs: List, desc: String, @DrawableRes errorRes: Int) = - bindImpl(Cover.Multi.from(songs.mapNotNull { it.cover }), desc, errorRes) + bindImpl(Cover.multi(songs), desc, errorRes) private fun bindImpl(cover: Cover?, desc: String, @DrawableRes errorRes: Int) { val request = diff --git a/app/src/main/java/org/oxycblt/auxio/image/coil/Components.kt b/app/src/main/java/org/oxycblt/auxio/image/coil/Components.kt index dd580cbdf..73e56b29f 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/coil/Components.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/coil/Components.kt @@ -47,7 +47,7 @@ import org.oxycblt.musikr.cover.Cover import org.oxycblt.musikr.cover.StoredCovers class CoverKeyer @Inject constructor() : Keyer { - override fun key(data: Cover, options: Options) = "${data.id}&${options.size}" + override fun key(data: Cover, options: Options) = "${data.key}&${options.size}" } class CoverFetcher @@ -56,14 +56,16 @@ private constructor( private val cover: Cover, private val size: Size, ) : Fetcher { + private val storedCovers = StoredCovers.from(context, "covers") + override suspend fun fetch(): FetchResult? { val streams = when (val cover = cover) { - is Cover.Single -> listOfNotNull(cover.resolve()) + is Cover.Single -> listOfNotNull(storedCovers.read(cover)) is Cover.Multi -> buildList { for (single in cover.all) { - single.resolve()?.let { add(it) } + storedCovers.read(single)?.let { add(it) } if (size == 4) { break } 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 90e2b9844..e8564f861 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt @@ -38,7 +38,6 @@ import org.oxycblt.musikr.Storage import org.oxycblt.musikr.cache.Cache import org.oxycblt.musikr.cache.CacheDatabase import org.oxycblt.musikr.cover.StoredCovers -import org.oxycblt.musikr.fs.Components import org.oxycblt.musikr.playlist.db.PlaylistDatabase import org.oxycblt.musikr.playlist.db.StoredPlaylists import org.oxycblt.musikr.tag.interpret.Naming @@ -369,15 +368,15 @@ constructor( revision = this.library?.revision ?: musicSettings.revision storage = Storage( - Cache.writeOnly(cacheDatabase), - StoredCovers.editor(context, Components.parseUnix("covers_${UUID.randomUUID()}")), + Cache.full(cacheDatabase), + StoredCovers.from(context, "covers_$revision"), StoredPlaylists.from(playlistDatabase)) } else { revision = UUID.randomUUID() storage = Storage( Cache.writeOnly(cacheDatabase), - StoredCovers.editor(context, Components.parseUnix("covers_$revision")), + StoredCovers.from(context, "covers_$revision"), StoredPlaylists.from(playlistDatabase)) } diff --git a/app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt b/app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt index c7ba67933..bd398776d 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/RevisionedLibrary.kt @@ -18,8 +18,6 @@ package org.oxycblt.auxio.music -import org.oxycblt.musikr.Album -import org.oxycblt.musikr.Artist import java.util.UUID import org.oxycblt.musikr.Library import org.oxycblt.musikr.MutableLibrary diff --git a/musikr/src/main/java/org/oxycblt/musikr/Config.kt b/musikr/src/main/java/org/oxycblt/musikr/Config.kt index 8b5f9ee0d..8b2ea8807 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/Config.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/Config.kt @@ -26,7 +26,7 @@ import org.oxycblt.musikr.tag.interpret.Separators data class Storage( val cache: Cache, - val coverEditor: StoredCovers.Editor, + val storedCovers: StoredCovers, val storedPlaylists: StoredPlaylists ) diff --git a/musikr/src/main/java/org/oxycblt/musikr/cache/Cache.kt b/musikr/src/main/java/org/oxycblt/musikr/cache/Cache.kt index f7dce3c20..89639a33c 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cache/Cache.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cache/Cache.kt @@ -18,12 +18,11 @@ package org.oxycblt.musikr.cache -import org.oxycblt.musikr.cover.StoredCovers import org.oxycblt.musikr.fs.DeviceFile import org.oxycblt.musikr.pipeline.RawSong interface Cache { - suspend fun read(file: DeviceFile, storedCovers: StoredCovers): CacheResult + suspend fun read(file: DeviceFile): CacheResult suspend fun write(song: RawSong) @@ -41,9 +40,9 @@ sealed interface CacheResult { } private class FullCache(private val cacheInfoDao: CacheInfoDao) : Cache { - override suspend fun read(file: DeviceFile, storedCovers: StoredCovers): CacheResult = + override suspend fun read(file: DeviceFile) = cacheInfoDao.selectSong(file.uri.toString(), file.lastModified)?.let { - CacheResult.Hit(it.intoRawSong(file, storedCovers)) + CacheResult.Hit(it.intoRawSong(file)) } ?: CacheResult.Miss(file) override suspend fun write(song: RawSong) = @@ -51,8 +50,7 @@ private class FullCache(private val cacheInfoDao: CacheInfoDao) : Cache { } private class WriteOnlyCache(private val cacheInfoDao: CacheInfoDao) : Cache { - override suspend fun read(file: DeviceFile, storedCovers: StoredCovers) = - CacheResult.Miss(file) + override suspend fun read(file: DeviceFile) = CacheResult.Miss(file) override suspend fun write(song: RawSong) = cacheInfoDao.updateSong(CachedSong.fromRawSong(song)) diff --git a/musikr/src/main/java/org/oxycblt/musikr/cache/CacheDatabase.kt b/musikr/src/main/java/org/oxycblt/musikr/cache/CacheDatabase.kt index c4c930acc..da8721f64 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cache/CacheDatabase.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cache/CacheDatabase.kt @@ -31,7 +31,6 @@ import androidx.room.RoomDatabase import androidx.room.TypeConverter import androidx.room.TypeConverters import org.oxycblt.musikr.cover.Cover -import org.oxycblt.musikr.cover.StoredCovers import org.oxycblt.musikr.fs.DeviceFile import org.oxycblt.musikr.metadata.Properties import org.oxycblt.musikr.pipeline.RawSong @@ -90,9 +89,9 @@ internal data class CachedSong( val genreNames: List, val replayGainTrackAdjustment: Float?, val replayGainAlbumAdjustment: Float?, - val coverId: String?, + val cover: Cover.Single?, ) { - suspend fun intoRawSong(file: DeviceFile, storedCovers: StoredCovers) = + fun intoRawSong(file: DeviceFile) = RawSong( file, Properties(mimeType, durationMs, bitrateHz, sampleRateHz), @@ -118,7 +117,7 @@ internal data class CachedSong( genreNames = genreNames, replayGainTrackAdjustment = replayGainTrackAdjustment, replayGainAlbumAdjustment = replayGainAlbumAdjustment), - coverId?.let { storedCovers.find(it) }) + cover) object Converters { @TypeConverter @@ -131,6 +130,10 @@ internal data class CachedSong( @TypeConverter fun fromDate(date: Date?) = date?.toString() @TypeConverter fun toDate(string: String?) = string?.let(Date::from) + + @TypeConverter fun fromCover(cover: Cover.Single?) = cover?.key + + @TypeConverter fun toCover(key: String?) = key?.let { Cover.Single(it) } } companion object { @@ -159,9 +162,9 @@ internal data class CachedSong( genreNames = rawSong.tags.genreNames, replayGainTrackAdjustment = rawSong.tags.replayGainTrackAdjustment, replayGainAlbumAdjustment = rawSong.tags.replayGainAlbumAdjustment, + cover = rawSong.cover, mimeType = rawSong.properties.mimeType, bitrateHz = rawSong.properties.bitrateKbps, - sampleRateHz = rawSong.properties.sampleRateHz, - coverId = rawSong.cover?.id) + sampleRateHz = rawSong.properties.sampleRateHz) } } diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/AppFiles.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/AppFiles.kt deleted file mode 100644 index 4d5e95f6a..000000000 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/AppFiles.kt +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (c) 2024 Auxio Project - * AppFiles.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 . - */ - -package org.oxycblt.musikr.cover - -import android.content.Context -import android.util.Log -import java.io.File -import java.io.IOException -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.sync.Mutex -import kotlinx.coroutines.sync.withLock -import kotlinx.coroutines.withContext -import org.oxycblt.musikr.fs.Components -import org.oxycblt.musikr.util.update -import java.io.InputStream -import java.io.OutputStream -import java.security.MessageDigest -import java.util.UUID - -internal interface AppFiles { - suspend fun read(path: Components): AppFile? - - suspend fun write(path: Components, block: suspend (OutputStream) -> Unit): AppFile? - - companion object { - fun from(context: Context): AppFiles = - AppFilesImpl(context.filesDir) - } -} - -interface AppFile { - val path: Components - suspend fun open(): InputStream? -} - -private class AppFilesImpl(private val rootDir: File) : - AppFiles { - private val tempDir = File(rootDir, "tmp-${UUID.randomUUID()}") - private val fileMutexes = mutableMapOf() - private val mapMutex = Mutex() - - private suspend fun getMutexForFile(path: String): Mutex { - return mapMutex.withLock { fileMutexes.getOrPut(path) { Mutex() } } - } - - override suspend fun read(path: Components): AppFile? = - withContext(Dispatchers.IO) { - val file = rootDir.resolve(path.unixString) - if (file.exists()) { - AppFileImpl(path, file) - } else { - null - } - } - - override suspend fun write(path: Components, block: suspend (OutputStream) -> Unit): AppFile? = - withContext(Dispatchers.IO) { - if (!tempDir.exists()) { - tempDir.mkdirs() - } - val parentDir = rootDir.resolve(path.parent().toString()) - if (parentDir.isFile) { - parentDir.delete() - } - if (!parentDir.exists()) { - parentDir.mkdirs() - } - val pathString = path.unixString - val fileMutex = getMutexForFile(pathString) - - fileMutex.withLock { - val targetFile = rootDir.resolve(pathString) - if (targetFile.exists()) { - return@withLock AppFileImpl(path, targetFile) - } - val tempFile = tempDir.resolve(pathString.sha256()) - - try { - block(tempFile.outputStream()) - tempFile.renameTo(targetFile) - AppFileImpl(path, targetFile) - } catch (e: IOException) { - tempFile.delete() - null - } - } - } -} - -class AppFileImpl( - override val path: Components, - private val file: File -) : AppFile { - override suspend fun open() = withContext(Dispatchers.IO) { file.inputStream() } -} - -@OptIn(ExperimentalStdlibApi::class) -private fun String.sha256() = MessageDigest.getInstance("SHA-256").let { - it.update(this) - it.digest().toHexString() -} - diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/Cover.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/Cover.kt index 9b9b04769..c206bfd7d 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/Cover.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/Cover.kt @@ -15,31 +15,34 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package org.oxycblt.musikr.cover import org.oxycblt.musikr.Song -import java.io.InputStream sealed interface Cover { - val id: String + val key: String - interface Single : Cover { - suspend fun resolve(): InputStream? + data class Single(override val key: String) : Cover + + class Multi(val all: List) : Cover { + override val key = "multi@${all.hashCode()}" } - class Multi private constructor(val all: List) : Cover { - override val id = "multi@${all.hashCode()}" + companion object { + fun nil() = Multi(listOf()) - companion object { - fun from(covers: Collection) = - Multi( - covers - .groupBy { it.id } - .entries - .sortedByDescending { it.key } - .sortedByDescending { it.value.size } - .map { it.value.first() }) - } + fun single(key: String) = Single(key) + + fun multi(songs: Collection) = order(songs).run { Multi(this) } + + private fun order(songs: Collection) = + songs + .mapNotNull { it.cover } + .groupBy { it.key } + .entries + .sortedByDescending { it.key } + .sortedByDescending { it.value.size } + .map { it.value.first() } } } diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFiles.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFiles.kt new file mode 100644 index 000000000..e1cb17000 --- /dev/null +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/CoverFiles.kt @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2024 Auxio Project + * CoverFiles.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 . + */ + +package org.oxycblt.musikr.cover + +import android.content.Context +import java.io.File +import java.io.IOException +import java.io.InputStream +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlinx.coroutines.withContext + +internal interface CoverFiles { + suspend fun read(id: String): InputStream? + + suspend fun write(id: String, data: ByteArray) + + companion object { + fun from(context: Context, path: String, format: CoverFormat): CoverFiles = + CoverFilesImpl(File(context.filesDir, path).also { it.mkdirs() }, format) + } +} + +private class CoverFilesImpl(private val dir: File, private val coverFormat: CoverFormat) : + CoverFiles { + private val fileMutexes = mutableMapOf() + private val mapMutex = Mutex() + + private suspend fun getMutexForFile(file: String): Mutex { + return mapMutex.withLock { fileMutexes.getOrPut(file) { Mutex() } } + } + + override suspend fun read(id: String): InputStream? = + withContext(Dispatchers.IO) { + try { + File(dir, getTargetFilePath(id)).inputStream() + } catch (e: IOException) { + null + } + } + + override suspend fun write(id: String, data: ByteArray) { + val fileMutex = getMutexForFile(id) + + fileMutex.withLock { + val targetFile = File(dir, getTargetFilePath(id)) + if (targetFile.exists()) { + return + } + withContext(Dispatchers.IO) { + val tempFile = File(dir, getTempFilePath(id)) + + try { + tempFile.outputStream().use { coverFormat.transcodeInto(data, it) } + tempFile.renameTo(targetFile) + } catch (e: IOException) { + tempFile.delete() + } + } + } + } + + private fun getTargetFilePath(name: String) = "cover_${name}.${coverFormat.extension}" + + private fun getTempFilePath(name: String) = "${getTargetFilePath(name)}.tmp" +} diff --git a/musikr/src/main/java/org/oxycblt/musikr/cover/StoredCovers.kt b/musikr/src/main/java/org/oxycblt/musikr/cover/StoredCovers.kt index cd223b07a..a1340990d 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/cover/StoredCovers.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/cover/StoredCovers.kt @@ -15,63 +15,33 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - + package org.oxycblt.musikr.cover import android.content.Context -import android.util.Log -import org.oxycblt.musikr.fs.Components -import java.io.File import java.io.InputStream interface StoredCovers { - suspend fun find(id: String): Cover.Single? + suspend fun read(cover: Cover.Single): InputStream? - interface Editor : StoredCovers { - suspend fun add(data: ByteArray): Cover.Single? - } + suspend fun write(data: ByteArray): Cover.Single? companion object { - fun from(context: Context): StoredCovers = - FileStoredCovers(AppFiles.from(context)) - - fun editor(context: Context, path: Components): Editor = - FileStoredCoversEditor( - path, - AppFiles.from(context), - CoverIdentifier.md5(), - CoverFormat.webp() - ) + fun from(context: Context, path: String): StoredCovers = + FileStoredCovers( + CoverIdentifier.md5(), CoverFiles.from(context, path, CoverFormat.webp())) } } -private open class FileStoredCovers( - private val appFiles: AppFiles +private class FileStoredCovers( + private val coverIdentifier: CoverIdentifier, + private val coverFiles: CoverFiles ) : StoredCovers { - override suspend fun find(id: String) = - appFiles.read(Components.parseUnix(id))?.let { FileCover(it) } -} + override suspend fun read(cover: Cover.Single) = coverFiles.read(cover.key) -private class FileStoredCoversEditor( - val root: Components, - val appFiles: AppFiles, - val coverIdentifier: CoverIdentifier, - val coverFormat: CoverFormat -) : FileStoredCovers(appFiles), StoredCovers.Editor { - override suspend fun add(data: ByteArray): Cover.Single? { - val id = coverIdentifier.identify(data) - val path = getTargetPath(id) - val file = appFiles.write(path) { - coverFormat.transcodeInto(data, it) + override suspend fun write(data: ByteArray) = + coverIdentifier.identify(data).let { key -> + coverFiles.write(key, data) + Cover.Single(key) } - return file?.let { FileCover(it) } - } - - private fun getTargetPath(id: String) = root.child("$id.${coverFormat.extension}") } - -private class FileCover(private val file: AppFile) : Cover.Single { - override val id: String = file.path.unixString - - override suspend fun resolve() = file.open() -} \ No newline at end of file diff --git a/musikr/src/main/java/org/oxycblt/musikr/fs/Path.kt b/musikr/src/main/java/org/oxycblt/musikr/fs/Path.kt index 99630df25..f889d516b 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/fs/Path.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/fs/Path.kt @@ -154,7 +154,7 @@ value class Components private constructor(val components: List) { fun containing(other: Components) = Components(other.components.drop(components.size)) - companion object { + internal companion object { /** * Parses a path string into a [Components] instance by the unix path separator (/). * diff --git a/musikr/src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt b/musikr/src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt index 8d8e89840..19be4885c 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/model/AlbumImpl.kt @@ -56,7 +56,7 @@ internal class AlbumImpl(private val core: AlbumCore) : Album { override val releaseType = preAlbum.releaseType override val durationMs = core.songs.sumOf { it.durationMs } override val dateAdded = core.songs.minOf { it.dateAdded } - override val cover = Cover.Multi.from(core.songs.mapNotNull { it.cover }) + override val cover = Cover.multi(core.songs) override val dates: Date.Range? = core.songs.mapNotNull { it.date }.ifEmpty { null }?.run { Date.Range(min(), max()) } diff --git a/musikr/src/main/java/org/oxycblt/musikr/model/ArtistImpl.kt b/musikr/src/main/java/org/oxycblt/musikr/model/ArtistImpl.kt index 9caa70482..4a2ca3990 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/model/ArtistImpl.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/model/ArtistImpl.kt @@ -55,7 +55,7 @@ internal class ArtistImpl(private val core: ArtistCore) : Artist { get() = core.resolveGenres().toList() override val durationMs = core.songs.sumOf { it.durationMs } - override val cover = Cover.Multi.from(core.songs.mapNotNull { it.cover }) + override val cover = Cover.multi(core.songs) private val hashCode = 31 * (31 * uid.hashCode() + core.preArtist.hashCode()) * core.songs.hashCode() diff --git a/musikr/src/main/java/org/oxycblt/musikr/model/GenreImpl.kt b/musikr/src/main/java/org/oxycblt/musikr/model/GenreImpl.kt index 171595622..203c6c60a 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/model/GenreImpl.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/model/GenreImpl.kt @@ -44,7 +44,7 @@ internal class GenreImpl(private val core: GenreCore) : Genre { override val songs = core.songs override val artists = core.artists override val durationMs = core.songs.sumOf { it.durationMs } - override val cover = Cover.Multi.from(core.songs.mapNotNull { it.cover }) + override val cover = Cover.multi(core.songs) private val hashCode = 31 * (31 * uid.hashCode() + core.preGenre.hashCode()) + songs.hashCode() diff --git a/musikr/src/main/java/org/oxycblt/musikr/model/PlaylistImpl.kt b/musikr/src/main/java/org/oxycblt/musikr/model/PlaylistImpl.kt index f70d3ddc3..602e10f77 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/model/PlaylistImpl.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/model/PlaylistImpl.kt @@ -33,7 +33,7 @@ internal class PlaylistImpl(val core: PlaylistCore) : Playlist { override val uid = core.prePlaylist.handle.uid override val name: Name.Known = core.prePlaylist.name override val durationMs = core.songs.sumOf { it.durationMs } - override val cover = Cover.Multi.from(core.songs.mapNotNull { it.cover }) + override val cover = Cover.multi(core.songs) override val songs = core.songs private var hashCode = diff --git a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt index 8523f2bca..89f98b016 100644 --- a/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt +++ b/musikr/src/main/java/org/oxycblt/musikr/pipeline/ExtractStep.kt @@ -19,7 +19,6 @@ package org.oxycblt.musikr.pipeline import android.content.Context -import android.util.Log import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.flow.Flow @@ -51,7 +50,7 @@ internal interface ExtractStep { MetadataExtractor.from(context), TagParser.new(), storage.cache, - storage.coverEditor) + storage.storedCovers) } } @@ -60,7 +59,7 @@ private class ExtractStepImpl( private val metadataExtractor: MetadataExtractor, private val tagParser: TagParser, private val cache: Cache, - private val coverEditor: StoredCovers.Editor + private val storedCovers: StoredCovers ) : ExtractStep { override fun extract(nodes: Flow): Flow { val filterFlow = @@ -75,7 +74,7 @@ private class ExtractStepImpl( val cacheResults = audioNodes - .map { wrap(it) { cache.read(it, coverEditor) } } + .map { wrap(it, cache::read) } .flowOn(Dispatchers.IO) .buffer(Channel.UNLIMITED) val cacheFlow = @@ -121,9 +120,7 @@ private class ExtractStepImpl( metadata .mapNotNull { fileWith -> val tags = tagParser.parse(fileWith.file, fileWith.with) - val cover = fileWith.with.cover?.let { - coverEditor.add(it) - } + val cover = fileWith.with.cover?.let { storedCovers.write(it) } RawSong(fileWith.file, fileWith.with.properties, tags, cover) } .flowOn(Dispatchers.IO)