fix SocketTimeoutException
Build Futon with Niadd patch / Build Futon Niadd debug APK (push) Failing after 26s
Build Futon with Niadd patch / Build Futon Niadd debug APK (push) Failing after 26s
This commit is contained in:
@@ -148,3 +148,131 @@
|
||||
private const val PREFETCH_LIMIT_DEFAULT = 6
|
||||
private const val PREFETCH_MIN_RAM_MB = 80L
|
||||
|
||||
--- a/app/src/main/kotlin/io/github/landwarderer/futon/details/ui/pager/pages/MangaPageFetcher.kt
|
||||
+++ b/app/src/main/kotlin/io/github/landwarderer/futon/details/ui/pager/pages/MangaPageFetcher.kt
|
||||
@@ -14,21 +14,26 @@
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
+import okio.Buffer
|
||||
import okio.FileSystem
|
||||
import okio.Path.Companion.toOkioPath
|
||||
import io.github.landwarderer.futon.core.network.MangaHttpClient
|
||||
import io.github.landwarderer.futon.core.network.imageproxy.ImageProxyInterceptor
|
||||
import io.github.landwarderer.futon.core.parser.MangaRepository
|
||||
import io.github.landwarderer.futon.core.util.MimeTypes
|
||||
+import io.github.landwarderer.futon.core.util.ext.MimeType
|
||||
import io.github.landwarderer.futon.core.util.ext.fetch
|
||||
import io.github.landwarderer.futon.core.util.ext.isNetworkUri
|
||||
import io.github.landwarderer.futon.core.util.ext.toMimeTypeOrNull
|
||||
import io.github.landwarderer.futon.local.data.LocalStorageCache
|
||||
import io.github.landwarderer.futon.local.data.PageCache
|
||||
import org.koitharu.kotatsu.parsers.model.MangaPage
|
||||
+import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.util.mimeType
|
||||
import org.koitharu.kotatsu.parsers.util.requireBody
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
+import kotlinx.coroutines.sync.Semaphore
|
||||
+import kotlinx.coroutines.sync.withPermit
|
||||
import io.github.landwarderer.futon.reader.domain.PageLoader
|
||||
import javax.inject.Inject
|
||||
class MangaPageFetcher(
|
||||
@@ -67,6 +72,12 @@
|
||||
imageLoader.fetch(pageUrl, options)
|
||||
}
|
||||
private suspend fun fetchPage(pageUrl: String): FetchResult {
|
||||
+ if (page.source == MangaParserSource.NINEMANGA_RU) {
|
||||
+ return niaddSemaphore.withPermit {
|
||||
+ fetchNiaddPageByRanges(pageUrl)
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
val request = PageLoader.createPageRequest(pageUrl, page.source)
|
||||
return imageProxyInterceptor.interceptPageRequest(request, okHttpClient).use { response ->
|
||||
if (!response.isSuccessful) {
|
||||
@@ -83,6 +94,73 @@
|
||||
)
|
||||
}
|
||||
}
|
||||
+
|
||||
+ private suspend fun fetchNiaddPageByRanges(pageUrl: String): FetchResult {
|
||||
+ val buffer = Buffer()
|
||||
+ var mimeType: MimeType? = null
|
||||
+ var offset = 0L
|
||||
+ var totalBytes = -1L
|
||||
+
|
||||
+ while (totalBytes < 0L || offset < totalBytes) {
|
||||
+ val requestedEnd = if (totalBytes > 0L) {
|
||||
+ minOf(offset + NIADD_RANGE_CHUNK_SIZE - 1L, totalBytes - 1L)
|
||||
+ } else {
|
||||
+ offset + NIADD_RANGE_CHUNK_SIZE - 1L
|
||||
+ }
|
||||
+ val request = PageLoader.createPageRequest(pageUrl, page.source)
|
||||
+ .newBuilder()
|
||||
+ .header("Range", "bytes=$offset-$requestedEnd")
|
||||
+ .header("Connection", "close")
|
||||
+ .build()
|
||||
+
|
||||
+ okHttpClient.newCall(request).execute().use { response ->
|
||||
+ check(response.code == 206) {
|
||||
+ "Niadd CDN ignored range request: HTTP ${response.code} for $pageUrl"
|
||||
+ }
|
||||
+
|
||||
+ val contentRange = response.header("Content-Range")
|
||||
+ ?: error("Niadd CDN response has no Content-Range for $pageUrl")
|
||||
+ val responseTotal = contentRange
|
||||
+ .substringAfterLast('/', "")
|
||||
+ .toLongOrNull()
|
||||
+ ?.takeIf { it > 0L }
|
||||
+ ?: error("Invalid Niadd Content-Range: $contentRange")
|
||||
+
|
||||
+ if (totalBytes < 0L) {
|
||||
+ totalBytes = responseTotal
|
||||
+ } else {
|
||||
+ check(totalBytes == responseTotal) {
|
||||
+ "Niadd CDN changed content size from $totalBytes to $responseTotal for $pageUrl"
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (mimeType == null) {
|
||||
+ mimeType = response.mimeType?.toMimeTypeOrNull()
|
||||
+ }
|
||||
+
|
||||
+ val expectedEnd = minOf(requestedEnd, totalBytes - 1L)
|
||||
+ val expectedBytes = expectedEnd - offset + 1L
|
||||
+ val receivedBytes = buffer.writeAll(response.requireBody().source())
|
||||
+ check(receivedBytes == expectedBytes) {
|
||||
+ "Short Niadd range: expected $expectedBytes bytes, got $receivedBytes " +
|
||||
+ "for bytes=$offset-$expectedEnd ($pageUrl)"
|
||||
+ }
|
||||
+
|
||||
+ offset += receivedBytes
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ check(totalBytes > 0L && buffer.size == totalBytes) {
|
||||
+ "Incomplete Niadd image: expected $totalBytes bytes, got ${buffer.size} for $pageUrl"
|
||||
+ }
|
||||
+
|
||||
+ val file = pagesCache.set(pageUrl, buffer, mimeType)
|
||||
+ return SourceFetchResult(
|
||||
+ source = ImageSource(file.toOkioPath(), FileSystem.SYSTEM),
|
||||
+ mimeType = mimeType?.toString(),
|
||||
+ dataSource = DataSource.NETWORK,
|
||||
+ )
|
||||
+ }
|
||||
private fun Response.toNetworkResponse() = NetworkResponse(
|
||||
code = code,
|
||||
requestMillis = sentRequestAtMillis,
|
||||
@@ -99,6 +177,11 @@
|
||||
}
|
||||
return headers.build()
|
||||
}
|
||||
+ companion object {
|
||||
+ private const val NIADD_RANGE_CHUNK_SIZE = 16L * 1024L
|
||||
+ private val niaddSemaphore = Semaphore(1)
|
||||
+ }
|
||||
+
|
||||
class Factory @Inject constructor(
|
||||
@MangaHttpClient private val okHttpClient: OkHttpClient,
|
||||
@PageCache private val pagesCache: LocalStorageCache,
|
||||
|
||||
Reference in New Issue
Block a user