coil: disable exoplayer loading

Disable exoplayer loading since apparently the way I use a blocking
call in the coil coroutine causes it to be uncancellable. This ends
up resulting in errors continuing to apply themselves to whatever
view they were requested from, even if it was an error. Because you
know. Android.
This commit is contained in:
OxygenCobalt 2021-11-16 06:35:05 -07:00
parent 1ea3ddb2e0
commit 71b15a3a6a
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
2 changed files with 92 additions and 94 deletions

View file

@ -27,11 +27,6 @@ import coil.fetch.FetchResult
import coil.fetch.Fetcher
import coil.fetch.SourceResult
import coil.size.Size
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.MediaMetadata
import com.google.android.exoplayer2.MetadataRetriever
import com.google.android.exoplayer2.metadata.flac.PictureFrame
import com.google.android.exoplayer2.metadata.id3.ApicFrame
import okio.buffer
import okio.source
import org.oxycblt.auxio.music.Album
@ -39,9 +34,7 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.toAlbumArtURI
import org.oxycblt.auxio.music.toURI
import org.oxycblt.auxio.settings.SettingsManager
import org.oxycblt.auxio.util.logD
import java.io.ByteArrayInputStream
import java.lang.Exception
/**
* Fetcher that returns the album art for a given [Album]. Handles settings on whether to use
@ -91,14 +84,14 @@ class AlbumArtFetcher(private val context: Context) : Fetcher<Album> {
if (result != null) {
return result
}
// Our next fallback is to rely on ExoPlayer's largely half-baked and undocumented
// metadata system.
val exoResult = fetchExoplayerCover(song)
if (exoResult != null) {
return exoResult
}
//
// // Our next fallback is to rely on ExoPlayer's largely half-baked and undocumented
// // metadata system.
// val exoResult = fetchExoplayerCover(song)
//
// if (exoResult != null) {
// return exoResult
// }
// If the previous two failed, we resort to MediaStore's covers despite it literally
// going against the point of this setting. The previous two calls are just too unreliable
@ -156,84 +149,86 @@ class AlbumArtFetcher(private val context: Context) : Fetcher<Album> {
return null
}
private fun fetchExoplayerCover(song: Song): FetchResult? {
val uri = song.id.toURI()
val future = MetadataRetriever.retrieveMetadata(
context, MediaItem.fromUri(song.id.toURI())
)
// Coil is async, we can just spin until the loading has ended
while (future.isDone) { /* no-op */ }
val tracks = try {
future.get()
} catch (e: Exception) {
null
}
if (tracks == null || tracks.isEmpty) {
// Unrecognized format. This is expected, as ExoPlayer only supports a
// subset of formats.
return null
}
// The metadata extraction process of ExoPlayer is normalized into a superclass.
// That means we have to iterate through and find the cover art ourselves.
val metadata = tracks[0].getFormat(0).metadata
if (metadata == null || metadata.length() == 0) {
// No (parsable) metadata. This is also expected.
return null
}
var stream: ByteArrayInputStream? = null
for (i in 0 until metadata.length()) {
// We can only extract pictures from two tags with this method, ID3v2's APIC or
// FLAC's PICTURE.
val pic: ByteArray?
val type: Int
when (val entry = metadata.get(i)) {
is ApicFrame -> {
pic = entry.pictureData
type = entry.pictureType
}
is PictureFrame -> {
pic = entry.pictureData
type = entry.pictureType
}
else -> continue
}
// Ensure the picture type here is a front cover image so that we don't extract
// an incorrect cover image.
// Yes, this does add some latency, but its quality covers so we can prioritize
// correctness over speed.
if (type == MediaMetadata.PICTURE_TYPE_FRONT_COVER) {
logD("Front cover successfully found")
// We have a front cover image. Great.
stream = ByteArrayInputStream(pic)
break
} else if (stream != null) {
// In the case a front cover is not found, use the first image in the tag instead.
// This can be corrected later on if a front cover frame is found.
logD("Image not a front cover, assigning image of type $type for now")
stream = ByteArrayInputStream(pic)
}
}
return stream?.use { stm ->
return SourceResult(
source = stm.source().buffer(),
mimeType = context.contentResolver.getType(uri),
dataSource = DataSource.DISK
)
}
}
// Disabled until I can figure out how the hell I can get a blocking call to play along in
// a suspend function. I doubt it's possible.
// private fun fetchExoplayerCover(song: Song): FetchResult? {
// val uri = song.id.toURI()
//
// val future = MetadataRetriever.retrieveMetadata(
// context, MediaItem.fromUri(song.id.toURI())
// )
//
// // Coil is async, we can just spin until the loading has ended
// while (future.isDone) { /* no-op */ }
//
// val tracks = try {
// future.get()
// } catch (e: Exception) {
// null
// }
//
// if (tracks == null || tracks.isEmpty) {
// // Unrecognized format. This is expected, as ExoPlayer only supports a
// // subset of formats.
// return null
// }
//
// // The metadata extraction process of ExoPlayer is normalized into a superclass.
// // That means we have to iterate through and find the cover art ourselves.
// val metadata = tracks[0].getFormat(0).metadata
//
// if (metadata == null || metadata.length() == 0) {
// // No (parsable) metadata. This is also expected.
// return null
// }
//
// var stream: ByteArrayInputStream? = null
//
// for (i in 0 until metadata.length()) {
// // We can only extract pictures from two tags with this method, ID3v2's APIC or
// // FLAC's PICTURE.
// val pic: ByteArray?
// val type: Int
//
// when (val entry = metadata.get(i)) {
// is ApicFrame -> {
// pic = entry.pictureData
// type = entry.pictureType
// }
// is PictureFrame -> {
// pic = entry.pictureData
// type = entry.pictureType
// }
// else -> continue
// }
//
// // Ensure the picture type here is a front cover image so that we don't extract
// // an incorrect cover image.
// // Yes, this does add some latency, but its quality covers so we can prioritize
// // correctness over speed.
// if (type == MediaMetadata.PICTURE_TYPE_FRONT_COVER) {
// logD("Front cover successfully found")
//
// // We have a front cover image. Great.
// stream = ByteArrayInputStream(pic)
// break
// } else if (stream != null) {
// // In the case a front cover is not found, use the first image in the tag instead.
// // This can be corrected later on if a front cover frame is found.
// logD("Image not a front cover, assigning image of type $type for now")
//
// stream = ByteArrayInputStream(pic)
// }
// }
//
// return stream?.use { stm ->
// return SourceResult(
// source = stm.source().buffer(),
// mimeType = context.contentResolver.getType(uri),
// dataSource = DataSource.DISK
// )
// }
// }
override fun key(data: Album) = data.id.toString()
}

View file

@ -25,6 +25,7 @@ import androidx.annotation.DrawableRes
import androidx.core.graphics.drawable.toBitmap
import androidx.databinding.BindingAdapter
import coil.Coil
import coil.clear
import coil.fetch.Fetcher
import coil.request.ImageRequest
import coil.size.OriginalSize
@ -83,7 +84,9 @@ inline fun <reified T : BaseModel> ImageView.load(
@DrawableRes error: Int,
fetcher: Fetcher<T>,
) {
val disposable = Coil.imageLoader(context).enqueue(
clear()
Coil.imageLoader(context).enqueue(
ImageRequest.Builder(context)
.target(this)
.data(data)