library: bound the artist bio request

This commit is contained in:
austinried
2026-10-19 13:14:08 +00:00
parent d4ba9c0faf
commit b379a22517
3 changed files with 11 additions and 9 deletions
@@ -8,6 +8,7 @@ import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import java.io.InputStream import java.io.InputStream
import java.security.MessageDigest import java.security.MessageDigest
import java.util.concurrent.TimeUnit
open class SubsonicException( open class SubsonicException(
val code: Int, val code: Int,
@@ -55,11 +56,12 @@ class SubsonicClient(
fun <T> stream( fun <T> stream(
method: String, method: String,
params: Map<String, String> = emptyMap(), params: Map<String, String> = emptyMap(),
timeoutMs: Long? = null,
body: (InputStream) -> T, body: (InputStream) -> T,
): T { ): T {
val usedTokenAuth = useTokenAuth val usedTokenAuth = useTokenAuth
return try { return try {
execute(method, params, body) execute(method, params, timeoutMs, body)
} catch (failure: SubsonicException) { } catch (failure: SubsonicException) {
if (failure.code !in TOKEN_AUTH_UNSUPPORTED_CODES || !usedTokenAuth) { if (failure.code !in TOKEN_AUTH_UNSUPPORTED_CODES || !usedTokenAuth) {
Log.w("http", "$method failed: server code ${failure.code} \"${failure.message}\"") Log.w("http", "$method failed: server code ${failure.code} \"${failure.message}\"")
@@ -67,13 +69,14 @@ class SubsonicClient(
} }
Log.w("http", "$method: token auth unsupported (server code ${failure.code}), retrying with plaintext") Log.w("http", "$method: token auth unsupported (server code ${failure.code}), retrying with plaintext")
disableTokenAuth() disableTokenAuth()
execute(method, params, body) execute(method, params, timeoutMs, body)
} }
} }
private fun <T> execute( private fun <T> execute(
method: String, method: String,
params: Map<String, String>, params: Map<String, String>,
timeoutMs: Long?,
body: (InputStream) -> T, body: (InputStream) -> T,
): T { ): T {
val request = val request =
@@ -81,7 +84,9 @@ class SubsonicClient(
.Builder() .Builder()
.url(uri(method, params)) .url(uri(method, params))
.build() .build()
http.newCall(request).execute().use { response -> val call = http.newCall(request)
timeoutMs?.let { call.timeout().timeout(it, TimeUnit.MILLISECONDS) }
call.execute().use { response ->
if (!response.isSuccessful) { if (!response.isSuccessful) {
throw SubsonicException(-1, "HTTP ${response.code}", UiMessage(R.string.error_http, listOf(response.code))) throw SubsonicException(-1, "HTTP ${response.code}", UiMessage(R.string.error_http, listOf(response.code)))
} }
@@ -87,7 +87,7 @@ class SubsonicSource(
override suspend fun artistBiography(artistId: String): String? = override suspend fun artistBiography(artistId: String): String? =
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
client.stream("getArtistInfo2", mapOf("id" to artistId)) { input -> client.stream("getArtistInfo2", mapOf("id" to artistId), timeoutMs = ARTIST_BIO_TIMEOUT_MS) { input ->
SubsonicXml.artistBiography(input) SubsonicXml.artistBiography(input)
} }
} }
@@ -372,6 +372,7 @@ class SubsonicSource(
const val PAGE_SIZE = 500 const val PAGE_SIZE = 500
const val MAX_PAGES = 20_000 const val MAX_PAGES = 20_000
const val THUMBNAIL_SIZE = 384 const val THUMBNAIL_SIZE = 384
const val ARTIST_BIO_TIMEOUT_MS = 15_000L
} }
} }
@@ -29,9 +29,6 @@ import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.stateIn import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeoutOrNull
private const val BIO_REFRESH_TIMEOUT_MS = 15_000L
@OptIn(ExperimentalCoroutinesApi::class) @OptIn(ExperimentalCoroutinesApi::class)
class ArtistDetailViewModel( class ArtistDetailViewModel(
@@ -102,8 +99,7 @@ class ArtistDetailViewModel(
} }
_bioLoading.value = true _bioLoading.value = true
try { try {
val result = withTimeoutOrNull(BIO_REFRESH_TIMEOUT_MS) { libraryRepository.refreshArtistBio(id, artistId) } _bioUnavailable.value = libraryRepository.refreshArtistBio(id, artistId).isFailure
_bioUnavailable.value = result == null || result.isFailure
} finally { } finally {
_bioLoading.value = false _bioLoading.value = false
} }