Option to slowdown downloads and configure parallelism

This commit is contained in:
Koitharu
2022-04-19 10:27:22 +03:00
parent fa536220eb
commit 8fc9b27840
10 changed files with 86 additions and 25 deletions

View File

@@ -141,6 +141,12 @@ class AppSettings(context: Context) {
}
}
val isDownloadsSlowdownEnabled: Boolean
get() = prefs.getBoolean(KEY_DOWNLOADS_SLOWDOWN, false)
val downloadsParallelism: Int
get() = prefs.getInt(KEY_DOWNLOADS_PARALLELISM, 2)
val isSuggestionsEnabled: Boolean
get() = prefs.getBoolean(KEY_SUGGESTIONS, false)
@@ -261,6 +267,8 @@ class AppSettings(context: Context) {
const val KEY_SUGGESTIONS_EXCLUDE_NSFW = "suggestions_exclude_nsfw"
const val KEY_SUGGESTIONS_EXCLUDE_TAGS = "suggestions_exclude_tags"
const val KEY_SEARCH_SINGLE_SOURCE = "search_single_source"
const val KEY_DOWNLOADS_PARALLELISM = "downloads_parallelism"
const val KEY_DOWNLOADS_SLOWDOWN = "downloads_slowdown"
// About
const val KEY_APP_UPDATE = "app_update"

View File

@@ -17,6 +17,7 @@ import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.local.data.PagesCache
import org.koitharu.kotatsu.local.domain.CbzMangaOutput
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
@@ -30,8 +31,8 @@ import org.koitharu.kotatsu.utils.progress.ProgressJob
import java.io.File
private const val MAX_DOWNLOAD_ATTEMPTS = 3
private const val MAX_PARALLEL_DOWNLOADS = 2
private const val DOWNLOAD_ERROR_DELAY = 500L
private const val SLOWDOWN_DELAY = 200L
class DownloadManager(
private val coroutineScope: CoroutineScope,
@@ -40,9 +41,10 @@ class DownloadManager(
private val okHttp: OkHttpClient,
private val cache: PagesCache,
private val localMangaRepository: LocalMangaRepository,
private val settings: AppSettings,
) {
private val connectivityManager = context.applicationContext.getSystemService(
private val connectivityManager = context.getSystemService(
Context.CONNECTIVITY_SERVICE
) as ConnectivityManager
private val coverWidth = context.resources.getDimensionPixelSize(
@@ -51,7 +53,7 @@ class DownloadManager(
private val coverHeight = context.resources.getDimensionPixelSize(
androidx.core.R.dimen.compat_notification_large_icon_max_height
)
private val semaphore = Semaphore(MAX_PARALLEL_DOWNLOADS)
private val semaphore = Semaphore(settings.downloadsParallelism)
fun downloadManga(
manga: Manga,
@@ -141,6 +143,10 @@ class DownloadManager(
totalPages = pages.size,
currentPage = pageIndex,
)
if (settings.isDownloadsSlowdownEnabled) {
delay(SLOWDOWN_DELAY)
}
}
}
outState.value = DownloadState.PostProcessing(startId, data, cover)
@@ -206,4 +212,24 @@ class DownloadManager(
error = throwable,
)
}
class Factory(
private val context: Context,
private val imageLoader: ImageLoader,
private val okHttp: OkHttpClient,
private val cache: PagesCache,
private val localMangaRepository: LocalMangaRepository,
private val settings: AppSettings,
) {
fun create(coroutineScope: CoroutineScope) = DownloadManager(
coroutineScope = coroutineScope,
context = context,
imageLoader = imageLoader,
okHttp = okHttp,
cache = cache,
localMangaRepository = localMangaRepository,
settings = settings,
)
}
}

View File

@@ -49,13 +49,8 @@ class DownloadService : BaseService() {
notificationSwitcher = ForegroundNotificationSwitcher(this)
val wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager)
.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "kotatsu:downloading")
downloadManager = DownloadManager(
downloadManager = get<DownloadManager.Factory>().create(
coroutineScope = lifecycleScope + WakeLockNode(wakeLock, TimeUnit.HOURS.toMillis(1)),
context = this,
imageLoader = get(),
okHttp = get(),
cache = get(),
localMangaRepository = get(),
)
DownloadNotification.createChannel(this)
registerReceiver(controlReceiver, IntentFilter(ACTION_DOWNLOAD_CANCEL))

View File

@@ -3,6 +3,7 @@ package org.koitharu.kotatsu.local
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
import org.koitharu.kotatsu.download.domain.DownloadManager
import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.local.domain.LocalMangaRepository
import org.koitharu.kotatsu.local.ui.LocalListViewModel
@@ -16,5 +17,7 @@ val localModule
factory { ExternalStorageHelper(androidContext()) }
factory { DownloadManager.Factory(androidContext(), get(), get(), get(), get(), get()) }
viewModel { LocalListViewModel(get(), get(), get(), get()) }
}

View File

@@ -4,7 +4,6 @@ import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import androidx.preference.Preference
import java.io.File
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.koitharu.kotatsu.R
@@ -13,8 +12,10 @@ import org.koitharu.kotatsu.base.ui.dialog.StorageSelectDialog
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.settings.utils.SliderPreference
import org.koitharu.kotatsu.utils.ext.getStorageName
import org.koitharu.kotatsu.utils.ext.viewLifecycleScope
import java.io.File
class ContentSettingsFragment :
BasePreferenceFragment(R.string.content),
@@ -29,6 +30,13 @@ class ContentSettingsFragment :
findPreference<Preference>(AppSettings.KEY_SUGGESTIONS)?.setSummary(
if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled
)
findPreference<SliderPreference>(AppSettings.KEY_DOWNLOADS_PARALLELISM)?.run {
summary = value.toString()
setOnPreferenceChangeListener { preference, newValue ->
preference.summary = newValue.toString()
true
}
}
bindRemoteSourcesSummary()
}

View File

@@ -17,6 +17,7 @@ suspend fun ConnectivityManager.waitForNetwork(): Network {
return suspendCancellableCoroutine { cont ->
val callback = object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
unregisterNetworkCallback(this)
if (cont.isActive) {
cont.resume(network)
}

View File

@@ -5,13 +5,12 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:baselineAligned="false"
android:clipChildren="false"
android:clipToPadding="false"
android:orientation="horizontal"
android:gravity="center_vertical"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:orientation="horizontal"
android:paddingStart="?android:attr/listPreferredItemPaddingStart"
android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
tools:ignore="PrivateResource">
@@ -27,17 +26,18 @@
android:clipToPadding="false"
android:orientation="vertical">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:baselineAligned="true"
android:baselineAlignedChildIndex="0"
android:layout_height="wrap_content">
<TextView
android:id="@android:id/title"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_toStartOf="@android:id/summary"
android:ellipsize="marquee"
android:labelFor="@id/seekbar"
android:singleLine="true"
@@ -49,12 +49,11 @@
style="@style/PreferenceSummaryTextStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:singleLine="true"
android:textAlignment="viewStart"
android:textColor="?android:attr/textColorSecondary" />
</RelativeLayout>
</LinearLayout>
<com.google.android.material.slider.Slider
android:id="@+id/slider"

View File

@@ -271,4 +271,7 @@
<string name="text_delete_local_manga_batch">Удалить выбранную мангу с накопителя?</string>
<string name="removal_completed">Удаление завершено</string>
<string name="batch_manga_save_confirm">Загрузить выбранную мангу со всеми главами? Это может привести к большому расходу трафика и места на накопителе</string>
<string name="parallel_downloads">Загружать параллельно</string>
<string name="download_slowdown">Замедление загрузки</string>
<string name="download_slowdown_summary">Помогает избежать блокировки IP-адреса</string>
</resources>

View File

@@ -274,4 +274,7 @@
<string name="text_delete_local_manga_batch">Delete selected items from device permanently?</string>
<string name="removal_completed">Removal completed</string>
<string name="batch_manga_save_confirm">Are you sure you want to download all selected manga with all its chapters? This action can consume a lot of traffic and storage</string>
<string name="parallel_downloads">Parallel downloads</string>
<string name="download_slowdown">Download slowdown</string>
<string name="download_slowdown_summary">Helps avoid blocking your IP address</string>
</resources>

View File

@@ -8,17 +8,32 @@
android:key="remote_sources"
android:title="@string/remote_sources" />
<Preference
android:key="local_storage"
android:persistent="false"
android:title="@string/manga_save_location" />
<PreferenceScreen
android:fragment="org.koitharu.kotatsu.settings.SuggestionsSettingsFragment"
android:key="suggestions"
android:persistent="false"
android:title="@string/suggestions" />
<Preference
android:key="local_storage"
android:persistent="false"
android:title="@string/manga_save_location"
app:allowDividerAbove="true" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:key="downloads_slowdown"
android:summary="@string/download_slowdown_summary"
android:title="@string/download_slowdown" />
<org.koitharu.kotatsu.settings.utils.SliderPreference
android:key="downloads_parallelism"
android:stepSize="1"
android:title="@string/parallel_downloads"
android:valueFrom="1"
android:valueTo="5"
app:defaultValue="2" />
<PreferenceScreen
android:fragment="org.koitharu.kotatsu.settings.backup.BackupSettingsFragment"
android:title="@string/backup_restore"