musikr: include context in pipeline errors
This commit is contained in:
parent
a1188b8d4b
commit
acd4dab74c
3 changed files with 91 additions and 14 deletions
|
@ -66,20 +66,20 @@ private class EvaluateStepImpl(
|
||||||
val rawSongs = filterFlow.right
|
val rawSongs = filterFlow.right
|
||||||
val preSongs =
|
val preSongs =
|
||||||
rawSongs
|
rawSongs
|
||||||
.map { tagInterpreter.interpret(it) }
|
.map { wrap(it, tagInterpreter::interpret) }
|
||||||
.flowOn(Dispatchers.Default)
|
.flowOn(Dispatchers.Default)
|
||||||
.buffer(Channel.UNLIMITED)
|
.buffer(Channel.UNLIMITED)
|
||||||
val prePlaylists =
|
val prePlaylists =
|
||||||
filterFlow.left
|
filterFlow.left
|
||||||
.map { playlistInterpreter.interpret(it) }
|
.map { wrap(it, playlistInterpreter::interpret) }
|
||||||
.flowOn(Dispatchers.Default)
|
.flowOn(Dispatchers.Default)
|
||||||
.buffer(Channel.UNLIMITED)
|
.buffer(Channel.UNLIMITED)
|
||||||
val graphBuilder = MusicGraph.builder()
|
val graphBuilder = MusicGraph.builder()
|
||||||
val graphBuild =
|
val graphBuild =
|
||||||
merge(
|
merge(
|
||||||
filterFlow.manager,
|
filterFlow.manager,
|
||||||
preSongs.onEach { graphBuilder.add(it) },
|
preSongs.onEach { wrap(it, graphBuilder::add) },
|
||||||
prePlaylists.onEach { graphBuilder.add(it) })
|
prePlaylists.onEach { wrap(it, graphBuilder::add) })
|
||||||
graphBuild.collect()
|
graphBuild.collect()
|
||||||
val graph = graphBuilder.build()
|
val graph = graphBuilder.build()
|
||||||
return libraryFactory.create(graph, storedPlaylists, playlistInterpreter)
|
return libraryFactory.create(graph, storedPlaylists, playlistInterpreter)
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.oxycblt.musikr.pipeline
|
package org.oxycblt.musikr.pipeline
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
@ -48,7 +48,8 @@ internal interface ExtractStep {
|
||||||
MetadataExtractor.from(context),
|
MetadataExtractor.from(context),
|
||||||
TagParser.new(),
|
TagParser.new(),
|
||||||
storage.cache,
|
storage.cache,
|
||||||
storage.storedCovers)
|
storage.storedCovers
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +71,8 @@ private class ExtractStepImpl(
|
||||||
val playlistNodes = filterFlow.left.map { ExtractedMusic.Playlist(it) }
|
val playlistNodes = filterFlow.left.map { ExtractedMusic.Playlist(it) }
|
||||||
|
|
||||||
val cacheResults =
|
val cacheResults =
|
||||||
audioNodes.map { cache.read(it) }.flowOn(Dispatchers.IO).buffer(Channel.UNLIMITED)
|
audioNodes.map { wrap(it, cache::read) }.flowOn(Dispatchers.IO)
|
||||||
|
.buffer(Channel.UNLIMITED)
|
||||||
val cacheFlow =
|
val cacheFlow =
|
||||||
cacheResults.divert {
|
cacheResults.divert {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@ -84,11 +86,13 @@ private class ExtractStepImpl(
|
||||||
val extractedSongs =
|
val extractedSongs =
|
||||||
Array(distributedFlow.flows.size) { i ->
|
Array(distributedFlow.flows.size) { i ->
|
||||||
distributedFlow.flows[i]
|
distributedFlow.flows[i]
|
||||||
.mapNotNull { file ->
|
.mapNotNull { it ->
|
||||||
val metadata = metadataExtractor.extract(file) ?: return@mapNotNull null
|
wrap(it) { file ->
|
||||||
val tags = tagParser.parse(file, metadata)
|
val metadata = metadataExtractor.extract(file) ?: return@wrap null
|
||||||
val cover = metadata.cover?.let { storedCovers.write(it) }
|
val tags = tagParser.parse(file, metadata)
|
||||||
RawSong(file, metadata.properties, tags, cover)
|
val cover = metadata.cover?.let { storedCovers.write(it) }
|
||||||
|
RawSong(file, metadata.properties, tags, cover)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
.buffer(Channel.UNLIMITED)
|
.buffer(Channel.UNLIMITED)
|
||||||
|
@ -96,7 +100,7 @@ private class ExtractStepImpl(
|
||||||
val writtenSongs =
|
val writtenSongs =
|
||||||
merge(*extractedSongs)
|
merge(*extractedSongs)
|
||||||
.map {
|
.map {
|
||||||
cache.write(it)
|
wrap(it, cache::write)
|
||||||
ExtractedMusic.Song(it)
|
ExtractedMusic.Song(it)
|
||||||
}
|
}
|
||||||
.flowOn(Dispatchers.IO)
|
.flowOn(Dispatchers.IO)
|
||||||
|
@ -107,7 +111,8 @@ private class ExtractStepImpl(
|
||||||
cachedSongs,
|
cachedSongs,
|
||||||
distributedFlow.manager,
|
distributedFlow.manager,
|
||||||
writtenSongs,
|
writtenSongs,
|
||||||
playlistNodes)
|
playlistNodes
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
package org.oxycblt.musikr.pipeline
|
||||||
|
|
||||||
|
import org.oxycblt.musikr.fs.DeviceFile
|
||||||
|
import org.oxycblt.musikr.playlist.PlaylistFile
|
||||||
|
import org.oxycblt.musikr.playlist.interpret.PrePlaylist
|
||||||
|
import org.oxycblt.musikr.tag.interpret.PreSong
|
||||||
|
|
||||||
|
class PipelineException(
|
||||||
|
val processing: WhileProcessing,
|
||||||
|
val error: Exception
|
||||||
|
) : Exception() {
|
||||||
|
override val cause = error
|
||||||
|
|
||||||
|
override val message = "Error while processing ${processing}: $error"
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed interface WhileProcessing {
|
||||||
|
class AFile internal constructor(private val file: DeviceFile) : WhileProcessing {
|
||||||
|
override fun toString() = "File @ ${file.path}"
|
||||||
|
}
|
||||||
|
|
||||||
|
class ARawSong internal constructor(private val rawSong: RawSong) : WhileProcessing {
|
||||||
|
override fun toString() = "Raw Song @ ${rawSong.file.path}"
|
||||||
|
}
|
||||||
|
|
||||||
|
class APlaylistFile internal constructor(private val playlist: PlaylistFile) : WhileProcessing {
|
||||||
|
override fun toString() = "Playlist File @ ${playlist.name}"
|
||||||
|
}
|
||||||
|
|
||||||
|
class APreSong internal constructor(private val preSong: PreSong) : WhileProcessing {
|
||||||
|
override fun toString() = "Pre Song @ ${preSong.path}"
|
||||||
|
}
|
||||||
|
|
||||||
|
class APrePlaylist internal constructor(private val prePlaylist: PrePlaylist) : WhileProcessing {
|
||||||
|
override fun toString() = "Pre Playlist @ ${prePlaylist.name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun <R> wrap(file: DeviceFile, block: suspend (DeviceFile) -> R): R =
|
||||||
|
try {
|
||||||
|
block(file)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw PipelineException(WhileProcessing.AFile(file), e)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun <R> wrap(song: RawSong, block: suspend (RawSong) -> R): R =
|
||||||
|
try {
|
||||||
|
block(song)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw PipelineException(WhileProcessing.ARawSong(song), e)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun <R> wrap(file: PlaylistFile, block: suspend (PlaylistFile) -> R): R =
|
||||||
|
try {
|
||||||
|
block(file)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw PipelineException(WhileProcessing.APlaylistFile(file), e)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun <R> wrap(song: PreSong, block: suspend (PreSong) -> R): R =
|
||||||
|
try {
|
||||||
|
block(song)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw PipelineException(WhileProcessing.APreSong(song), e)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun <R> wrap(playlist: PrePlaylist, block: suspend (PrePlaylist) -> R): R =
|
||||||
|
try {
|
||||||
|
block(playlist)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw PipelineException(WhileProcessing.APrePlaylist(playlist), e)
|
||||||
|
}
|
Loading…
Reference in a new issue