musikr: move storage/interpretation dependence to construction
This makes some testing and certain code more ergonomic.
This commit is contained in:
parent
f3913b148a
commit
bdfd9d6e23
11 changed files with 87 additions and 81 deletions
|
@ -26,7 +26,6 @@ import dagger.hilt.InstallIn
|
||||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
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.Musikr
|
|
||||||
import org.oxycblt.musikr.cache.CacheDatabase
|
import org.oxycblt.musikr.cache.CacheDatabase
|
||||||
import org.oxycblt.musikr.playlist.db.PlaylistDatabase
|
import org.oxycblt.musikr.playlist.db.PlaylistDatabase
|
||||||
|
|
||||||
|
@ -48,6 +47,4 @@ class MusikrShimModule {
|
||||||
@Singleton
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
fun playlistDatabase(@ApplicationContext context: Context) = PlaylistDatabase.from(context)
|
fun playlistDatabase(@ApplicationContext context: Context) = PlaylistDatabase.from(context)
|
||||||
|
|
||||||
@Provides fun musikr(@ApplicationContext context: Context) = Musikr.new(context)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ import timber.log.Timber as L
|
||||||
*/
|
*/
|
||||||
interface MusicRepository {
|
interface MusicRepository {
|
||||||
val library: Library?
|
val library: Library?
|
||||||
|
|
||||||
/** The current state of music loading. Null if no load has occurred yet. */
|
/** The current state of music loading. Null if no load has occurred yet. */
|
||||||
val indexingState: IndexingState?
|
val indexingState: IndexingState?
|
||||||
|
|
||||||
|
@ -212,7 +213,6 @@ interface MusicRepository {
|
||||||
class MusicRepositoryImpl
|
class MusicRepositoryImpl
|
||||||
@Inject
|
@Inject
|
||||||
constructor(
|
constructor(
|
||||||
private val musikr: Musikr,
|
|
||||||
@ApplicationContext private val context: Context,
|
@ApplicationContext private val context: Context,
|
||||||
private val cacheDatabase: CacheDatabase,
|
private val cacheDatabase: CacheDatabase,
|
||||||
private val playlistDatabase: PlaylistDatabase,
|
private val playlistDatabase: PlaylistDatabase,
|
||||||
|
@ -375,9 +375,11 @@ constructor(
|
||||||
StoredCovers.from(context, "covers"),
|
StoredCovers.from(context, "covers"),
|
||||||
StoredPlaylists.from(playlistDatabase))
|
StoredPlaylists.from(playlistDatabase))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val interpretation = Interpretation(nameFactory, separators)
|
||||||
|
|
||||||
val newLibrary =
|
val newLibrary =
|
||||||
musikr.run(
|
Musikr.new(context, storage, interpretation).run(locations, ::emitIndexingProgress)
|
||||||
locations, storage, Interpretation(nameFactory, separators), ::emitIndexingProgress)
|
|
||||||
|
|
||||||
emitIndexingCompletion(null)
|
emitIndexingCompletion(null)
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
package org.oxycblt.musikr
|
package org.oxycblt.musikr
|
||||||
|
|
||||||
import org.oxycblt.musikr.cover.StoredCovers
|
|
||||||
import org.oxycblt.musikr.fs.Path
|
import org.oxycblt.musikr.fs.Path
|
||||||
|
|
||||||
interface Library {
|
interface Library {
|
||||||
|
@ -28,8 +27,6 @@ interface Library {
|
||||||
val genres: Collection<Genre>
|
val genres: Collection<Genre>
|
||||||
val playlists: Collection<Playlist>
|
val playlists: Collection<Playlist>
|
||||||
|
|
||||||
val storedCovers: StoredCovers
|
|
||||||
|
|
||||||
fun findSong(uid: Music.UID): Song?
|
fun findSong(uid: Music.UID): Song?
|
||||||
|
|
||||||
fun findSongByPath(path: Path): Song?
|
fun findSongByPath(path: Path): Song?
|
||||||
|
|
|
@ -33,14 +33,15 @@ import org.oxycblt.musikr.pipeline.ExtractStep
|
||||||
interface Musikr {
|
interface Musikr {
|
||||||
suspend fun run(
|
suspend fun run(
|
||||||
locations: List<MusicLocation>,
|
locations: List<MusicLocation>,
|
||||||
storage: Storage,
|
|
||||||
interpretation: Interpretation,
|
|
||||||
onProgress: suspend (IndexingProgress) -> Unit = {}
|
onProgress: suspend (IndexingProgress) -> Unit = {}
|
||||||
): MutableLibrary
|
): MutableLibrary
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun new(context: Context): Musikr =
|
fun new(context: Context, storage: Storage, interpretation: Interpretation): Musikr =
|
||||||
MusikrImpl(ExploreStep.from(context), ExtractStep.from(context), EvaluateStep.new())
|
MusikrImpl(
|
||||||
|
ExploreStep.from(context, storage),
|
||||||
|
ExtractStep.from(context, storage),
|
||||||
|
EvaluateStep.new(storage, interpretation))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,24 +63,22 @@ private class MusikrImpl(
|
||||||
) : Musikr {
|
) : Musikr {
|
||||||
override suspend fun run(
|
override suspend fun run(
|
||||||
locations: List<MusicLocation>,
|
locations: List<MusicLocation>,
|
||||||
storage: Storage,
|
|
||||||
interpretation: Interpretation,
|
|
||||||
onProgress: suspend (IndexingProgress) -> Unit
|
onProgress: suspend (IndexingProgress) -> Unit
|
||||||
) = coroutineScope {
|
) = coroutineScope {
|
||||||
var exploredCount = 0
|
var exploredCount = 0
|
||||||
var extractedCount = 0
|
var extractedCount = 0
|
||||||
val explored =
|
val explored =
|
||||||
exploreStep
|
exploreStep
|
||||||
.explore(locations, storage)
|
.explore(locations)
|
||||||
.buffer(Channel.UNLIMITED)
|
.buffer(Channel.UNLIMITED)
|
||||||
.onStart { onProgress(IndexingProgress.Songs(0, 0)) }
|
.onStart { onProgress(IndexingProgress.Songs(0, 0)) }
|
||||||
.onEach { onProgress(IndexingProgress.Songs(extractedCount, ++exploredCount)) }
|
.onEach { onProgress(IndexingProgress.Songs(extractedCount, ++exploredCount)) }
|
||||||
val extracted =
|
val extracted =
|
||||||
extractStep
|
extractStep
|
||||||
.extract(storage, explored)
|
.extract(explored)
|
||||||
.buffer(Channel.UNLIMITED)
|
.buffer(Channel.UNLIMITED)
|
||||||
.onEach { onProgress(IndexingProgress.Songs(++extractedCount, exploredCount)) }
|
.onEach { onProgress(IndexingProgress.Songs(++extractedCount, exploredCount)) }
|
||||||
.onCompletion { onProgress(IndexingProgress.Indeterminate) }
|
.onCompletion { onProgress(IndexingProgress.Indeterminate) }
|
||||||
evaluateStep.evaluate(storage, interpretation, extracted)
|
evaluateStep.evaluate(extracted)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,19 +21,23 @@ package org.oxycblt.musikr.model
|
||||||
import org.oxycblt.musikr.Album
|
import org.oxycblt.musikr.Album
|
||||||
import org.oxycblt.musikr.Artist
|
import org.oxycblt.musikr.Artist
|
||||||
import org.oxycblt.musikr.Genre
|
import org.oxycblt.musikr.Genre
|
||||||
import org.oxycblt.musikr.Interpretation
|
|
||||||
import org.oxycblt.musikr.MutableLibrary
|
import org.oxycblt.musikr.MutableLibrary
|
||||||
import org.oxycblt.musikr.Song
|
import org.oxycblt.musikr.Song
|
||||||
import org.oxycblt.musikr.Storage
|
|
||||||
import org.oxycblt.musikr.graph.AlbumVertex
|
import org.oxycblt.musikr.graph.AlbumVertex
|
||||||
import org.oxycblt.musikr.graph.ArtistVertex
|
import org.oxycblt.musikr.graph.ArtistVertex
|
||||||
import org.oxycblt.musikr.graph.GenreVertex
|
import org.oxycblt.musikr.graph.GenreVertex
|
||||||
import org.oxycblt.musikr.graph.MusicGraph
|
import org.oxycblt.musikr.graph.MusicGraph
|
||||||
import org.oxycblt.musikr.graph.PlaylistVertex
|
import org.oxycblt.musikr.graph.PlaylistVertex
|
||||||
import org.oxycblt.musikr.graph.SongVertex
|
import org.oxycblt.musikr.graph.SongVertex
|
||||||
|
import org.oxycblt.musikr.playlist.db.StoredPlaylists
|
||||||
|
import org.oxycblt.musikr.playlist.interpret.PlaylistInterpreter
|
||||||
|
|
||||||
internal interface LibraryFactory {
|
internal interface LibraryFactory {
|
||||||
fun create(graph: MusicGraph, storage: Storage, interpretation: Interpretation): MutableLibrary
|
fun create(
|
||||||
|
graph: MusicGraph,
|
||||||
|
storedPlaylists: StoredPlaylists,
|
||||||
|
playlistInterpreter: PlaylistInterpreter
|
||||||
|
): MutableLibrary
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun new(): LibraryFactory = LibraryFactoryImpl()
|
fun new(): LibraryFactory = LibraryFactoryImpl()
|
||||||
|
@ -43,8 +47,8 @@ internal interface LibraryFactory {
|
||||||
private class LibraryFactoryImpl() : LibraryFactory {
|
private class LibraryFactoryImpl() : LibraryFactory {
|
||||||
override fun create(
|
override fun create(
|
||||||
graph: MusicGraph,
|
graph: MusicGraph,
|
||||||
storage: Storage,
|
storedPlaylists: StoredPlaylists,
|
||||||
interpretation: Interpretation
|
playlistInterpreter: PlaylistInterpreter
|
||||||
): MutableLibrary {
|
): MutableLibrary {
|
||||||
val songs =
|
val songs =
|
||||||
graph.songVertex.mapTo(mutableSetOf()) { vertex ->
|
graph.songVertex.mapTo(mutableSetOf()) { vertex ->
|
||||||
|
@ -66,7 +70,8 @@ private class LibraryFactoryImpl() : LibraryFactory {
|
||||||
graph.playlistVertex.mapTo(mutableSetOf()) { vertex ->
|
graph.playlistVertex.mapTo(mutableSetOf()) { vertex ->
|
||||||
PlaylistImpl(PlaylistVertexCore(vertex))
|
PlaylistImpl(PlaylistVertexCore(vertex))
|
||||||
}
|
}
|
||||||
return LibraryImpl(songs, albums, artists, genres, playlists, storage, interpretation)
|
return LibraryImpl(
|
||||||
|
songs, albums, artists, genres, playlists, storedPlaylists, playlistInterpreter)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SongVertexCore(private val vertex: SongVertex) : SongCore {
|
private class SongVertexCore(private val vertex: SongVertex) : SongCore {
|
||||||
|
|
|
@ -18,13 +18,14 @@
|
||||||
|
|
||||||
package org.oxycblt.musikr.model
|
package org.oxycblt.musikr.model
|
||||||
|
|
||||||
import org.oxycblt.musikr.Interpretation
|
|
||||||
import org.oxycblt.musikr.Music
|
import org.oxycblt.musikr.Music
|
||||||
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.Storage
|
|
||||||
import org.oxycblt.musikr.fs.Path
|
import org.oxycblt.musikr.fs.Path
|
||||||
|
import org.oxycblt.musikr.playlist.db.StoredPlaylists
|
||||||
|
import org.oxycblt.musikr.playlist.interpret.PlaylistInterpreter
|
||||||
|
import org.oxycblt.musikr.playlist.interpret.PostPlaylist
|
||||||
|
|
||||||
internal data class LibraryImpl(
|
internal data class LibraryImpl(
|
||||||
override val songs: Collection<SongImpl>,
|
override val songs: Collection<SongImpl>,
|
||||||
|
@ -32,8 +33,8 @@ internal data class LibraryImpl(
|
||||||
override val artists: Collection<ArtistImpl>,
|
override val artists: Collection<ArtistImpl>,
|
||||||
override val genres: Collection<GenreImpl>,
|
override val genres: Collection<GenreImpl>,
|
||||||
override val playlists: Collection<Playlist>,
|
override val playlists: Collection<Playlist>,
|
||||||
private val storage: Storage,
|
private val storedPlaylists: StoredPlaylists,
|
||||||
private val interpretation: Interpretation
|
private val playlistInterpreter: PlaylistInterpreter
|
||||||
) : MutableLibrary {
|
) : MutableLibrary {
|
||||||
private val songUidMap = songs.associateBy { it.uid }
|
private val songUidMap = songs.associateBy { it.uid }
|
||||||
private val albumUidMap = albums.associateBy { it.uid }
|
private val albumUidMap = albums.associateBy { it.uid }
|
||||||
|
@ -41,8 +42,6 @@ internal data class LibraryImpl(
|
||||||
private val genreUidMap = genres.associateBy { it.uid }
|
private val genreUidMap = genres.associateBy { it.uid }
|
||||||
private val playlistUidMap = playlists.associateBy { it.uid }
|
private val playlistUidMap = playlists.associateBy { it.uid }
|
||||||
|
|
||||||
override val storedCovers = storage.storedCovers
|
|
||||||
|
|
||||||
override fun findSong(uid: Music.UID) = songUidMap[uid]
|
override fun findSong(uid: Music.UID) = songUidMap[uid]
|
||||||
|
|
||||||
override fun findSongByPath(path: Path) = songs.find { it.path == path }
|
override fun findSongByPath(path: Path) = songs.find { it.path == path }
|
||||||
|
@ -76,4 +75,9 @@ internal data class LibraryImpl(
|
||||||
override suspend fun deletePlaylist(playlist: Playlist): MutableLibrary {
|
override suspend fun deletePlaylist(playlist: Playlist): MutableLibrary {
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class NewPlaylistCore(
|
||||||
|
override val prePlaylist: PostPlaylist,
|
||||||
|
override val songs: List<Song>
|
||||||
|
) : PlaylistCore
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,32 +32,30 @@ import org.oxycblt.musikr.MutableLibrary
|
||||||
import org.oxycblt.musikr.Storage
|
import org.oxycblt.musikr.Storage
|
||||||
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.playlist.db.StoredPlaylists
|
||||||
import org.oxycblt.musikr.playlist.interpret.PlaylistInterpreter
|
import org.oxycblt.musikr.playlist.interpret.PlaylistInterpreter
|
||||||
import org.oxycblt.musikr.tag.interpret.TagInterpreter
|
import org.oxycblt.musikr.tag.interpret.TagInterpreter
|
||||||
|
|
||||||
internal interface EvaluateStep {
|
internal interface EvaluateStep {
|
||||||
suspend fun evaluate(
|
suspend fun evaluate(extractedMusic: Flow<ExtractedMusic>): MutableLibrary
|
||||||
storage: Storage,
|
|
||||||
interpretation: Interpretation,
|
|
||||||
extractedMusic: Flow<ExtractedMusic>
|
|
||||||
): MutableLibrary
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun new(): EvaluateStep =
|
fun new(storage: Storage, interpretation: Interpretation): EvaluateStep =
|
||||||
EvaluateStepImpl(TagInterpreter.new(), PlaylistInterpreter.new(), LibraryFactory.new())
|
EvaluateStepImpl(
|
||||||
|
TagInterpreter.new(interpretation),
|
||||||
|
PlaylistInterpreter.new(interpretation),
|
||||||
|
storage.storedPlaylists,
|
||||||
|
LibraryFactory.new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class EvaluateStepImpl(
|
private class EvaluateStepImpl(
|
||||||
private val tagInterpreter: TagInterpreter,
|
private val tagInterpreter: TagInterpreter,
|
||||||
private val playlistInterpreter: PlaylistInterpreter,
|
private val playlistInterpreter: PlaylistInterpreter,
|
||||||
|
private val storedPlaylists: StoredPlaylists,
|
||||||
private val libraryFactory: LibraryFactory
|
private val libraryFactory: LibraryFactory
|
||||||
) : EvaluateStep {
|
) : EvaluateStep {
|
||||||
override suspend fun evaluate(
|
override suspend fun evaluate(extractedMusic: Flow<ExtractedMusic>): MutableLibrary {
|
||||||
storage: Storage,
|
|
||||||
interpretation: Interpretation,
|
|
||||||
extractedMusic: Flow<ExtractedMusic>
|
|
||||||
): MutableLibrary {
|
|
||||||
val filterFlow =
|
val filterFlow =
|
||||||
extractedMusic.divert {
|
extractedMusic.divert {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@ -68,12 +66,12 @@ private class EvaluateStepImpl(
|
||||||
val rawSongs = filterFlow.right
|
val rawSongs = filterFlow.right
|
||||||
val preSongs =
|
val preSongs =
|
||||||
rawSongs
|
rawSongs
|
||||||
.map { tagInterpreter.interpret(it, interpretation) }
|
.map { tagInterpreter.interpret(it) }
|
||||||
.flowOn(Dispatchers.Default)
|
.flowOn(Dispatchers.Default)
|
||||||
.buffer(Channel.UNLIMITED)
|
.buffer(Channel.UNLIMITED)
|
||||||
val prePlaylists =
|
val prePlaylists =
|
||||||
filterFlow.left
|
filterFlow.left
|
||||||
.map { playlistInterpreter.interpret(it, interpretation) }
|
.map { playlistInterpreter.interpret(it) }
|
||||||
.flowOn(Dispatchers.Default)
|
.flowOn(Dispatchers.Default)
|
||||||
.buffer(Channel.UNLIMITED)
|
.buffer(Channel.UNLIMITED)
|
||||||
val graphBuilder = MusicGraph.builder()
|
val graphBuilder = MusicGraph.builder()
|
||||||
|
@ -84,6 +82,6 @@ private class EvaluateStepImpl(
|
||||||
prePlaylists.onEach { graphBuilder.add(it) })
|
prePlaylists.onEach { graphBuilder.add(it) })
|
||||||
graphBuild.collect()
|
graphBuild.collect()
|
||||||
val graph = graphBuilder.build()
|
val graph = graphBuilder.build()
|
||||||
return libraryFactory.create(graph, storage, interpretation)
|
return libraryFactory.create(graph, storedPlaylists, playlistInterpreter)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,18 +34,23 @@ import org.oxycblt.musikr.fs.DeviceFile
|
||||||
import org.oxycblt.musikr.fs.MusicLocation
|
import org.oxycblt.musikr.fs.MusicLocation
|
||||||
import org.oxycblt.musikr.fs.query.DeviceFiles
|
import org.oxycblt.musikr.fs.query.DeviceFiles
|
||||||
import org.oxycblt.musikr.playlist.PlaylistFile
|
import org.oxycblt.musikr.playlist.PlaylistFile
|
||||||
|
import org.oxycblt.musikr.playlist.db.StoredPlaylists
|
||||||
import org.oxycblt.musikr.playlist.m3u.M3U
|
import org.oxycblt.musikr.playlist.m3u.M3U
|
||||||
|
|
||||||
internal interface ExploreStep {
|
internal interface ExploreStep {
|
||||||
fun explore(locations: List<MusicLocation>, storage: Storage): Flow<ExploreNode>
|
fun explore(locations: List<MusicLocation>): Flow<ExploreNode>
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun from(context: Context): ExploreStep = ExploreStepImpl(DeviceFiles.from(context))
|
fun from(context: Context, storage: Storage): ExploreStep =
|
||||||
|
ExploreStepImpl(DeviceFiles.from(context), storage.storedPlaylists)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ExploreStepImpl(private val deviceFiles: DeviceFiles) : ExploreStep {
|
private class ExploreStepImpl(
|
||||||
override fun explore(locations: List<MusicLocation>, storage: Storage): Flow<ExploreNode> {
|
private val deviceFiles: DeviceFiles,
|
||||||
|
private val storedPlaylists: StoredPlaylists
|
||||||
|
) : ExploreStep {
|
||||||
|
override fun explore(locations: List<MusicLocation>): Flow<ExploreNode> {
|
||||||
val audios =
|
val audios =
|
||||||
deviceFiles
|
deviceFiles
|
||||||
.explore(locations.asFlow())
|
.explore(locations.asFlow())
|
||||||
|
@ -59,7 +64,7 @@ private class ExploreStepImpl(private val deviceFiles: DeviceFiles) : ExploreSte
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
.buffer()
|
.buffer()
|
||||||
val playlists =
|
val playlists =
|
||||||
flow { emitAll(storage.storedPlaylists.read().asFlow()) }
|
flow { emitAll(storedPlaylists.read().asFlow()) }
|
||||||
.map { ExploreNode.Playlist(it) }
|
.map { ExploreNode.Playlist(it) }
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
.buffer()
|
.buffer()
|
||||||
|
|
|
@ -28,8 +28,10 @@ import kotlinx.coroutines.flow.map
|
||||||
import kotlinx.coroutines.flow.mapNotNull
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.flow.merge
|
import kotlinx.coroutines.flow.merge
|
||||||
import org.oxycblt.musikr.Storage
|
import org.oxycblt.musikr.Storage
|
||||||
|
import org.oxycblt.musikr.cache.Cache
|
||||||
import org.oxycblt.musikr.cache.CacheResult
|
import org.oxycblt.musikr.cache.CacheResult
|
||||||
import org.oxycblt.musikr.cover.Cover
|
import org.oxycblt.musikr.cover.Cover
|
||||||
|
import org.oxycblt.musikr.cover.StoredCovers
|
||||||
import org.oxycblt.musikr.fs.DeviceFile
|
import org.oxycblt.musikr.fs.DeviceFile
|
||||||
import org.oxycblt.musikr.metadata.MetadataExtractor
|
import org.oxycblt.musikr.metadata.MetadataExtractor
|
||||||
import org.oxycblt.musikr.metadata.Properties
|
import org.oxycblt.musikr.metadata.Properties
|
||||||
|
@ -38,19 +40,25 @@ import org.oxycblt.musikr.tag.parse.ParsedTags
|
||||||
import org.oxycblt.musikr.tag.parse.TagParser
|
import org.oxycblt.musikr.tag.parse.TagParser
|
||||||
|
|
||||||
internal interface ExtractStep {
|
internal interface ExtractStep {
|
||||||
fun extract(storage: Storage, nodes: Flow<ExploreNode>): Flow<ExtractedMusic>
|
fun extract(nodes: Flow<ExploreNode>): Flow<ExtractedMusic>
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun from(context: Context): ExtractStep =
|
fun from(context: Context, storage: Storage): ExtractStep =
|
||||||
ExtractStepImpl(MetadataExtractor.from(context), TagParser.new())
|
ExtractStepImpl(
|
||||||
|
MetadataExtractor.from(context),
|
||||||
|
TagParser.new(),
|
||||||
|
storage.cache,
|
||||||
|
storage.storedCovers)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ExtractStepImpl(
|
private class ExtractStepImpl(
|
||||||
private val metadataExtractor: MetadataExtractor,
|
private val metadataExtractor: MetadataExtractor,
|
||||||
private val tagParser: TagParser
|
private val tagParser: TagParser,
|
||||||
|
private val cache: Cache,
|
||||||
|
private val storedCovers: StoredCovers
|
||||||
) : ExtractStep {
|
) : ExtractStep {
|
||||||
override fun extract(storage: Storage, nodes: Flow<ExploreNode>): Flow<ExtractedMusic> {
|
override fun extract(nodes: Flow<ExploreNode>): Flow<ExtractedMusic> {
|
||||||
val filterFlow =
|
val filterFlow =
|
||||||
nodes.divert {
|
nodes.divert {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@ -62,10 +70,7 @@ private class ExtractStepImpl(
|
||||||
val playlistNodes = filterFlow.left.map { ExtractedMusic.Playlist(it) }
|
val playlistNodes = filterFlow.left.map { ExtractedMusic.Playlist(it) }
|
||||||
|
|
||||||
val cacheResults =
|
val cacheResults =
|
||||||
audioNodes
|
audioNodes.map { cache.read(it) }.flowOn(Dispatchers.IO).buffer(Channel.UNLIMITED)
|
||||||
.map { storage.cache.read(it) }
|
|
||||||
.flowOn(Dispatchers.IO)
|
|
||||||
.buffer(Channel.UNLIMITED)
|
|
||||||
val cacheFlow =
|
val cacheFlow =
|
||||||
cacheResults.divert {
|
cacheResults.divert {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@ -82,7 +87,7 @@ private class ExtractStepImpl(
|
||||||
.mapNotNull { file ->
|
.mapNotNull { file ->
|
||||||
val metadata = metadataExtractor.extract(file) ?: return@mapNotNull null
|
val metadata = metadataExtractor.extract(file) ?: return@mapNotNull null
|
||||||
val tags = tagParser.parse(file, metadata)
|
val tags = tagParser.parse(file, metadata)
|
||||||
val cover = metadata.cover?.let { storage.storedCovers.write(it) }
|
val cover = metadata.cover?.let { storedCovers.write(it) }
|
||||||
RawSong(file, metadata.properties, tags, cover)
|
RawSong(file, metadata.properties, tags, cover)
|
||||||
}
|
}
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
|
@ -91,7 +96,7 @@ private class ExtractStepImpl(
|
||||||
val writtenSongs =
|
val writtenSongs =
|
||||||
merge(*extractedSongs)
|
merge(*extractedSongs)
|
||||||
.map {
|
.map {
|
||||||
storage.cache.write(it)
|
cache.write(it)
|
||||||
ExtractedMusic.Song(it)
|
ExtractedMusic.Song(it)
|
||||||
}
|
}
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
|
|
|
@ -21,33 +21,27 @@ package org.oxycblt.musikr.playlist.interpret
|
||||||
import org.oxycblt.musikr.Interpretation
|
import org.oxycblt.musikr.Interpretation
|
||||||
import org.oxycblt.musikr.playlist.PlaylistFile
|
import org.oxycblt.musikr.playlist.PlaylistFile
|
||||||
import org.oxycblt.musikr.playlist.PlaylistHandle
|
import org.oxycblt.musikr.playlist.PlaylistHandle
|
||||||
|
import org.oxycblt.musikr.tag.interpret.Naming
|
||||||
|
|
||||||
internal interface PlaylistInterpreter {
|
internal interface PlaylistInterpreter {
|
||||||
fun interpret(file: PlaylistFile, interpretation: Interpretation): PrePlaylist
|
fun interpret(file: PlaylistFile): PrePlaylist
|
||||||
|
|
||||||
fun interpret(
|
fun interpret(name: String, handle: PlaylistHandle): PostPlaylist
|
||||||
name: String,
|
|
||||||
handle: PlaylistHandle,
|
|
||||||
interpretation: Interpretation
|
|
||||||
): PostPlaylist
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun new(): PlaylistInterpreter = PlaylistInterpreterImpl
|
fun new(interpretation: Interpretation): PlaylistInterpreter =
|
||||||
|
PlaylistInterpreterImpl(interpretation.naming)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data object PlaylistInterpreterImpl : PlaylistInterpreter {
|
private class PlaylistInterpreterImpl(private val naming: Naming) : PlaylistInterpreter {
|
||||||
override fun interpret(file: PlaylistFile, interpretation: Interpretation) =
|
override fun interpret(file: PlaylistFile) =
|
||||||
PrePlaylist(
|
PrePlaylist(
|
||||||
name = interpretation.naming.name(file.name, null),
|
name = naming.name(file.name, null),
|
||||||
rawName = file.name,
|
rawName = file.name,
|
||||||
handle = file.handle,
|
handle = file.handle,
|
||||||
songPointers = file.songPointers)
|
songPointers = file.songPointers)
|
||||||
|
|
||||||
override fun interpret(
|
override fun interpret(name: String, handle: PlaylistHandle): PostPlaylist =
|
||||||
name: String,
|
PostPlaylist(name = naming.name(name, null), rawName = name, handle = handle)
|
||||||
handle: PlaylistHandle,
|
|
||||||
interpretation: Interpretation
|
|
||||||
): PostPlaylist =
|
|
||||||
PostPlaylist(name = interpretation.naming.name(name, null), rawName = name, handle = handle)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,15 +31,15 @@ import org.oxycblt.musikr.tag.parse.ParsedTags
|
||||||
import org.oxycblt.musikr.util.toUuidOrNull
|
import org.oxycblt.musikr.util.toUuidOrNull
|
||||||
|
|
||||||
internal interface TagInterpreter {
|
internal interface TagInterpreter {
|
||||||
fun interpret(song: RawSong, interpretation: Interpretation): PreSong
|
fun interpret(song: RawSong): PreSong
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun new(): TagInterpreter = TagInterpreterImpl
|
fun new(interpretation: Interpretation): TagInterpreter = TagInterpreterImpl(interpretation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private data object TagInterpreterImpl : TagInterpreter {
|
private class TagInterpreterImpl(private val interpretation: Interpretation) : TagInterpreter {
|
||||||
override fun interpret(song: RawSong, interpretation: Interpretation): PreSong {
|
override fun interpret(song: RawSong): PreSong {
|
||||||
val individualPreArtists =
|
val individualPreArtists =
|
||||||
makePreArtists(
|
makePreArtists(
|
||||||
song.tags.artistMusicBrainzIds,
|
song.tags.artistMusicBrainzIds,
|
||||||
|
|
Loading…
Reference in a new issue