Feature/refresh outdated thumbnail url on fetch failure (#910)
* Extract thumbnail url fresh into function * Remove incorrect non-null assertion According to the typing there is no guarantee that fetching a manga from the source provides a thumbnail url * Refresh manga thumbnail url on 404 error * Refresh manga thumbnail url on unreachable origin cloudflare errors
This commit is contained in:
@@ -8,13 +8,17 @@ package suwayomi.tachidesk.manga.impl
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.HttpException
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
import eu.kanade.tachiyomi.source.local.LocalSource
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import io.javalin.http.HttpCode
|
||||
import mu.KotlinLogging
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.Response
|
||||
import org.jetbrains.exposed.sql.ResultRow
|
||||
import org.jetbrains.exposed.sql.SortOrder
|
||||
import org.jetbrains.exposed.sql.and
|
||||
@@ -251,9 +255,53 @@ object Manga {
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun fetchThumbnailUrl(mangaId: Int): String? {
|
||||
getManga(mangaId, true)
|
||||
return transaction {
|
||||
MangaTable.select { MangaTable.id eq mangaId }.first()
|
||||
}[MangaTable.thumbnail_url]
|
||||
}
|
||||
|
||||
private val applicationDirs by DI.global.instance<ApplicationDirs>()
|
||||
private val network: NetworkHelper by injectLazy()
|
||||
|
||||
private suspend fun fetchHttpSourceMangaThumbnail(
|
||||
source: HttpSource,
|
||||
mangaEntry: ResultRow,
|
||||
refreshUrl: Boolean = false,
|
||||
): Response {
|
||||
val mangaId = mangaEntry[MangaTable.id].value
|
||||
|
||||
val requiresInitialization = mangaEntry[MangaTable.thumbnail_url] == null && !mangaEntry[MangaTable.initialized]
|
||||
val refreshThumbnailUrl = refreshUrl || requiresInitialization
|
||||
|
||||
val thumbnailUrl =
|
||||
if (refreshThumbnailUrl) {
|
||||
fetchThumbnailUrl(mangaId)
|
||||
} else {
|
||||
mangaEntry[MangaTable.thumbnail_url]
|
||||
} ?: throw NullPointerException("No thumbnail found")
|
||||
|
||||
return try {
|
||||
source.client.newCall(
|
||||
GET(thumbnailUrl, source.headers, cache = CacheControl.FORCE_NETWORK),
|
||||
).awaitSuccess()
|
||||
} catch (e: HttpException) {
|
||||
val tryToRefreshUrl =
|
||||
!refreshUrl &&
|
||||
listOf(
|
||||
HttpCode.NOT_FOUND.status,
|
||||
523, // (Cloudflare) Origin Is Unreachable
|
||||
522, // (Cloudflare) Connection timed out
|
||||
).contains(e.code)
|
||||
if (!tryToRefreshUrl) {
|
||||
throw e
|
||||
}
|
||||
|
||||
fetchHttpSourceMangaThumbnail(source, mangaEntry, refreshUrl = true)
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun fetchMangaThumbnail(mangaId: Int): Pair<InputStream, String> {
|
||||
val cacheSaveDir = applicationDirs.tempThumbnailCacheRoot
|
||||
val fileName = mangaId.toString()
|
||||
@@ -264,22 +312,7 @@ object Manga {
|
||||
return when (val source = getCatalogueSourceOrStub(sourceId)) {
|
||||
is HttpSource ->
|
||||
getImageResponse(cacheSaveDir, fileName) {
|
||||
val thumbnailUrl =
|
||||
mangaEntry[MangaTable.thumbnail_url]
|
||||
?: if (!mangaEntry[MangaTable.initialized]) {
|
||||
// initialize then try again
|
||||
getManga(mangaId)
|
||||
transaction {
|
||||
MangaTable.select { MangaTable.id eq mangaId }.first()
|
||||
}[MangaTable.thumbnail_url]!!
|
||||
} else {
|
||||
// source provides no thumbnail url for this manga
|
||||
throw NullPointerException("No thumbnail found")
|
||||
}
|
||||
|
||||
source.client.newCall(
|
||||
GET(thumbnailUrl, source.headers, cache = CacheControl.FORCE_NETWORK),
|
||||
).await()
|
||||
fetchHttpSourceMangaThumbnail(source, mangaEntry)
|
||||
}
|
||||
|
||||
is LocalSource -> {
|
||||
|
||||
Reference in New Issue
Block a user