Fix downloading slowdown
This commit is contained in:
@@ -1,16 +1,20 @@
|
||||
package org.koitharu.kotatsu.download.ui.worker
|
||||
|
||||
import android.os.SystemClock
|
||||
import androidx.collection.MutableObjectLongMap
|
||||
import kotlinx.coroutines.delay
|
||||
import org.koitharu.kotatsu.core.parser.MangaRepository
|
||||
import org.koitharu.kotatsu.core.parser.ParserMangaRepository
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
class DownloadSlowdownDispatcher(
|
||||
@Singleton
|
||||
class DownloadSlowdownDispatcher @Inject constructor(
|
||||
private val mangaRepositoryFactory: MangaRepository.Factory,
|
||||
private val defaultDelay: Long,
|
||||
) {
|
||||
private val timeMap = MutableObjectLongMap<MangaSource>()
|
||||
private val defaultDelay = 1_600L
|
||||
|
||||
suspend fun delay(source: MangaSource) {
|
||||
val repo = mangaRepositoryFactory.create(source) as? ParserMangaRepository ?: return
|
||||
@@ -19,11 +23,11 @@ class DownloadSlowdownDispatcher(
|
||||
}
|
||||
val lastRequest = synchronized(timeMap) {
|
||||
val res = timeMap.getOrDefault(source, 0L)
|
||||
timeMap[source] = System.currentTimeMillis()
|
||||
timeMap[source] = SystemClock.elapsedRealtime()
|
||||
res
|
||||
}
|
||||
if (lastRequest != 0L) {
|
||||
delay(lastRequest + defaultDelay - System.currentTimeMillis())
|
||||
delay(lastRequest + defaultDelay - SystemClock.elapsedRealtime())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +101,7 @@ class DownloadWorker @AssistedInject constructor(
|
||||
private val mangaRepositoryFactory: MangaRepository.Factory,
|
||||
private val settings: AppSettings,
|
||||
@LocalStorageChanges private val localStorageChanges: MutableSharedFlow<LocalManga?>,
|
||||
private val slowdownDispatcher: DownloadSlowdownDispatcher,
|
||||
private val imageProxyInterceptor: ImageProxyInterceptor,
|
||||
notificationFactoryFactory: DownloadNotificationFactory.Factory,
|
||||
) : CoroutineWorker(appContext, params) {
|
||||
@@ -110,7 +111,6 @@ class DownloadWorker @AssistedInject constructor(
|
||||
isSilent = params.inputData.getBoolean(IS_SILENT, false),
|
||||
)
|
||||
private val notificationManager = appContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
private val slowdownDispatcher = DownloadSlowdownDispatcher(mangaRepositoryFactory, SLOWDOWN_DELAY)
|
||||
|
||||
@Volatile
|
||||
private var lastPublishedState: DownloadState? = null
|
||||
@@ -569,7 +569,6 @@ class DownloadWorker @AssistedInject constructor(
|
||||
const val MAX_PAGES_PARALLELISM = 4
|
||||
const val DOWNLOAD_ERROR_DELAY = 2_000L
|
||||
const val MAX_RETRY_DELAY = 7_200_000L // 2 hours
|
||||
const val SLOWDOWN_DELAY = 200L
|
||||
const val MANGA_ID = "manga_id"
|
||||
const val CHAPTERS_IDS = "chapters"
|
||||
const val IS_SILENT = "silent"
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
package org.koitharu.kotatsu.reader.domain
|
||||
|
||||
import android.content.ContentResolver.MimeTypeInfo
|
||||
import android.content.Context
|
||||
import android.graphics.Rect
|
||||
import android.net.Uri
|
||||
import android.webkit.MimeTypeMap
|
||||
import androidx.annotation.AnyThread
|
||||
import androidx.collection.LongSparseArray
|
||||
import androidx.collection.set
|
||||
@@ -29,6 +27,7 @@ import kotlinx.coroutines.sync.withPermit
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okio.use
|
||||
import org.koitharu.kotatsu.core.image.BitmapDecoderCompat
|
||||
import org.koitharu.kotatsu.core.network.CommonHeaders
|
||||
import org.koitharu.kotatsu.core.network.MangaHttpClient
|
||||
import org.koitharu.kotatsu.core.network.imageproxy.ImageProxyInterceptor
|
||||
@@ -46,11 +45,13 @@ import org.koitharu.kotatsu.core.util.ext.exists
|
||||
import org.koitharu.kotatsu.core.util.ext.getCompletionResultOrNull
|
||||
import org.koitharu.kotatsu.core.util.ext.isPowerSaveMode
|
||||
import org.koitharu.kotatsu.core.util.ext.isTargetNotEmpty
|
||||
import org.koitharu.kotatsu.core.util.ext.mimeType
|
||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||
import org.koitharu.kotatsu.core.util.ext.ramAvailable
|
||||
import org.koitharu.kotatsu.core.util.ext.use
|
||||
import org.koitharu.kotatsu.core.util.ext.withProgress
|
||||
import org.koitharu.kotatsu.core.util.progress.ProgressDeferred
|
||||
import org.koitharu.kotatsu.download.ui.worker.DownloadSlowdownDispatcher
|
||||
import org.koitharu.kotatsu.local.data.PagesCache
|
||||
import org.koitharu.kotatsu.local.data.isFileUri
|
||||
import org.koitharu.kotatsu.local.data.isZipUri
|
||||
@@ -59,8 +60,6 @@ import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.mimeType
|
||||
import org.koitharu.kotatsu.parsers.util.requireBody
|
||||
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||
import org.koitharu.kotatsu.core.image.BitmapDecoderCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.mimeType
|
||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
||||
import java.util.LinkedList
|
||||
import java.util.concurrent.atomic.AtomicInteger
|
||||
@@ -79,6 +78,7 @@ class PageLoader @Inject constructor(
|
||||
private val settings: AppSettings,
|
||||
private val mangaRepositoryFactory: MangaRepository.Factory,
|
||||
private val imageProxyInterceptor: ImageProxyInterceptor,
|
||||
private val downloadSlowdownDispatcher: DownloadSlowdownDispatcher,
|
||||
) {
|
||||
|
||||
val loaderScope = RetainedLifecycleCoroutineScope(lifecycle) + InternalErrorHandler() + Dispatchers.Default
|
||||
@@ -127,7 +127,7 @@ class PageLoader @Inject constructor(
|
||||
} else if (task?.isCancelled == false) {
|
||||
return task
|
||||
}
|
||||
task = loadPageAsyncImpl(page, force)
|
||||
task = loadPageAsyncImpl(page, skipCache = force, isPrefetch = false)
|
||||
synchronized(tasks) {
|
||||
tasks[page.id] = task
|
||||
}
|
||||
@@ -186,7 +186,7 @@ class PageLoader @Inject constructor(
|
||||
val page = prefetchQueue.pollFirst() ?: return@launch
|
||||
if (cache.get(page.url) == null) {
|
||||
synchronized(tasks) {
|
||||
tasks[page.id] = loadPageAsyncImpl(page, false)
|
||||
tasks[page.id] = loadPageAsyncImpl(page, skipCache = false, isPrefetch = true)
|
||||
}
|
||||
return@launch
|
||||
}
|
||||
@@ -194,7 +194,11 @@ class PageLoader @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private fun loadPageAsyncImpl(page: MangaPage, skipCache: Boolean): ProgressDeferred<Uri, Float> {
|
||||
private fun loadPageAsyncImpl(
|
||||
page: MangaPage,
|
||||
skipCache: Boolean,
|
||||
isPrefetch: Boolean,
|
||||
): ProgressDeferred<Uri, Float> {
|
||||
val progress = MutableStateFlow(PROGRESS_UNDEFINED)
|
||||
val deferred = loaderScope.async {
|
||||
if (!skipCache) {
|
||||
@@ -202,7 +206,7 @@ class PageLoader @Inject constructor(
|
||||
}
|
||||
counter.incrementAndGet()
|
||||
try {
|
||||
loadPageImpl(page, progress)
|
||||
loadPageImpl(page, progress, isPrefetch)
|
||||
} finally {
|
||||
if (counter.decrementAndGet() == 0) {
|
||||
onIdle()
|
||||
@@ -222,7 +226,11 @@ class PageLoader @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun loadPageImpl(page: MangaPage, progress: MutableStateFlow<Float>): Uri = semaphore.withPermit {
|
||||
private suspend fun loadPageImpl(
|
||||
page: MangaPage,
|
||||
progress: MutableStateFlow<Float>,
|
||||
isPrefetch: Boolean,
|
||||
): Uri = semaphore.withPermit {
|
||||
val pageUrl = getPageUrl(page)
|
||||
check(pageUrl.isNotBlank()) { "Cannot obtain full image url for $page" }
|
||||
val uri = Uri.parse(pageUrl)
|
||||
@@ -235,6 +243,9 @@ class PageLoader @Inject constructor(
|
||||
|
||||
uri.isFileUri() -> uri
|
||||
else -> {
|
||||
if (isPrefetch) {
|
||||
downloadSlowdownDispatcher.delay(page.source)
|
||||
}
|
||||
val request = createPageRequest(pageUrl, page.source)
|
||||
imageProxyInterceptor.interceptPageRequest(request, okHttp).ensureSuccess().use { response ->
|
||||
response.requireBody().withProgress(progress).use {
|
||||
|
||||
Reference in New Issue
Block a user