Add proxy support #376

This commit is contained in:
Koitharu
2023-05-20 15:32:09 +03:00
parent 3729b5f2f0
commit eb7efaaac9
14 changed files with 192 additions and 7 deletions

View File

@@ -3,9 +3,9 @@ package org.koitharu.kotatsu.core.logs
import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.SOURCE)
@Retention(AnnotationRetention.BINARY)
annotation class TrackerLogger
@Qualifier
@Retention(AnnotationRetention.SOURCE)
@Retention(AnnotationRetention.BINARY)
annotation class SyncLogger

View File

@@ -0,0 +1,43 @@
package org.koitharu.kotatsu.core.network
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import java.io.IOException
import java.net.InetSocketAddress
import java.net.Proxy
import java.net.ProxySelector
import java.net.SocketAddress
import java.net.URI
class AppProxySelector(
private val settings: AppSettings,
) : ProxySelector() {
private var cachedProxy: Proxy? = null
override fun select(uri: URI?): List<Proxy> {
return listOf(getProxy())
}
override fun connectFailed(uri: URI?, sa: SocketAddress?, ioe: IOException?) {
ioe?.printStackTraceDebug()
}
private fun getProxy(): Proxy {
val type = settings.proxyType
val address = settings.proxyAddress
val port = settings.proxyPort
if (type == Proxy.Type.DIRECT || address.isNullOrEmpty() || port == 0) {
return Proxy.NO_PROXY
}
cachedProxy?.let {
val addr = it.address() as? InetSocketAddress
if (addr != null && it.type() == type && addr.port == port && addr.hostString == address) {
return it
}
}
val proxy = Proxy(type, InetSocketAddress(address, port))
cachedProxy = proxy
return proxy
}
}

View File

@@ -3,9 +3,9 @@ package org.koitharu.kotatsu.core.network
import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.SOURCE)
@Retention(AnnotationRetention.BINARY)
annotation class BaseHttpClient
@Qualifier
@Retention(AnnotationRetention.SOURCE)
@Retention(AnnotationRetention.BINARY)
annotation class MangaHttpClient

View File

@@ -58,6 +58,7 @@ interface NetworkModule {
readTimeout(60, TimeUnit.SECONDS)
writeTimeout(20, TimeUnit.SECONDS)
cookieJar(cookieJar)
proxySelector(AppProxySelector(settings))
dns(DoHManager(cache, settings))
if (settings.isSSLBypassEnabled) {
bypassSSLErrors()

View File

@@ -25,6 +25,7 @@ import org.koitharu.kotatsu.parsers.model.SortOrder
import org.koitharu.kotatsu.parsers.util.mapToSet
import org.koitharu.kotatsu.shelf.domain.ShelfSection
import java.io.File
import java.net.Proxy
import java.util.Collections
import java.util.EnumSet
import java.util.Locale
@@ -276,6 +277,18 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
val isSSLBypassEnabled: Boolean
get() = prefs.getBoolean(KEY_SSL_BYPASS, false)
val proxyType: Proxy.Type
get() {
val raw = prefs.getString(KEY_PROXY_TYPE, null) ?: return Proxy.Type.DIRECT
return enumValues<Proxy.Type>().find { it.name == raw } ?: Proxy.Type.DIRECT
}
val proxyAddress: String?
get() = prefs.getString(KEY_PROXY_ADDRESS, null)
val proxyPort: Int
get() = prefs.getString(KEY_PROXY_PORT, null)?.toIntOrNull() ?: 0
var localListOrder: SortOrder
get() = prefs.getEnumValue(KEY_LOCAL_LIST_ORDER, SortOrder.NEWEST)
set(value) = prefs.edit { putEnumValue(KEY_LOCAL_LIST_ORDER, value) }
@@ -413,6 +426,10 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
const val KEY_SSL_BYPASS = "ssl_bypass"
const val KEY_READER_AUTOSCROLL_SPEED = "as_speed"
const val KEY_MIRROR_SWITCHING = "mirror_switching"
const val KEY_PROXY = "proxy"
const val KEY_PROXY_TYPE = "proxy_type"
const val KEY_PROXY_ADDRESS = "proxy_address"
const val KEY_PROXY_PORT = "proxy_port"
// About
const val KEY_APP_UPDATE = "app_update"

View File

@@ -3,5 +3,5 @@ package org.koitharu.kotatsu.local.data
import javax.inject.Qualifier
@Qualifier
@Retention(AnnotationRetention.SOURCE)
@Retention(AnnotationRetention.BINARY)
annotation class LocalStorageChanges

View File

@@ -24,6 +24,7 @@ import org.koitharu.kotatsu.local.data.LocalStorageManager
import org.koitharu.kotatsu.parsers.util.names
import org.koitharu.kotatsu.util.ext.printStackTraceDebug
import java.io.File
import java.net.Proxy
import javax.inject.Inject
@AndroidEntryPoint
@@ -62,6 +63,7 @@ class ContentSettingsFragment :
if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled,
)
bindRemoteSourcesSummary()
bindProxySummary()
settings.subscribe(this)
}
@@ -93,6 +95,12 @@ class ContentSettingsFragment :
AppSettings.KEY_SSL_BYPASS -> {
Snackbar.make(listView, R.string.settings_apply_restart_required, Snackbar.LENGTH_INDEFINITE).show()
}
AppSettings.KEY_PROXY_TYPE,
AppSettings.KEY_PROXY_ADDRESS,
AppSettings.KEY_PROXY_PORT -> {
bindProxySummary()
}
}
}
@@ -130,6 +138,19 @@ class ContentSettingsFragment :
}
}
private fun bindProxySummary() {
findPreference<Preference>(AppSettings.KEY_PROXY)?.run {
val type = settings.proxyType
val address = settings.proxyAddress
val port = settings.proxyPort
summary = if (type == Proxy.Type.DIRECT || address.isNullOrEmpty() || port == 0) {
context.getString(R.string.disabled)
} else {
"$type $address:$port"
}
}
}
private fun updateDownloadsConstraints() {
val preference = findPreference<Preference>(AppSettings.KEY_DOWNLOADS_WIFI)
viewLifecycleScope.launch {

View File

@@ -0,0 +1,60 @@
package org.koitharu.kotatsu.settings
import android.content.SharedPreferences
import android.os.Bundle
import android.view.View
import android.view.inputmethod.EditorInfo
import androidx.preference.EditTextPreference
import androidx.preference.Preference
import dagger.hilt.android.AndroidEntryPoint
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
import org.koitharu.kotatsu.settings.utils.EditTextBindListener
import java.net.Proxy
@AndroidEntryPoint
class ProxySettingsFragment : BasePreferenceFragment(R.string.proxy),
SharedPreferences.OnSharedPreferenceChangeListener {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_proxy)
findPreference<EditTextPreference>(AppSettings.KEY_PROXY_ADDRESS)?.setOnBindEditTextListener(
EditTextBindListener(
inputType = EditorInfo.TYPE_CLASS_TEXT or EditorInfo.TYPE_TEXT_VARIATION_URI,
hint = null,
validator = DomainValidator(),
),
)
findPreference<EditTextPreference>(AppSettings.KEY_PROXY_PORT)?.setOnBindEditTextListener(
EditTextBindListener(
inputType = EditorInfo.TYPE_CLASS_NUMBER,
hint = null,
validator = null,
),
)
updateDependencies()
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
settings.subscribe(this)
}
override fun onDestroyView() {
settings.unsubscribe(this)
super.onDestroyView()
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
when (key) {
AppSettings.KEY_PROXY_TYPE -> updateDependencies()
}
}
private fun updateDependencies() {
val isProxyEnabled = settings.proxyType != Proxy.Type.DIRECT
findPreference<Preference>(AppSettings.KEY_PROXY_ADDRESS)?.isEnabled = isProxyEnabled
findPreference<Preference>(AppSettings.KEY_PROXY_PORT)?.isEnabled = isProxyEnabled
}
}

View File

@@ -6,7 +6,7 @@ import org.koitharu.kotatsu.core.util.EditTextValidator
class EditTextBindListener(
private val inputType: Int,
private val hint: String,
private val hint: String?,
private val validator: EditTextValidator?,
) : EditTextPreference.OnBindEditTextListener {

View File

@@ -53,4 +53,9 @@
<item>@string/status_on_hold</item>
<item>@string/status_dropped</item>
</string-array>
</resources>
<string-array name="proxy_types">
<item>@string/disabled</item>
<item>HTTP</item>
<item>SOCKS (v4/v5)</item>
</string-array>
</resources>

View File

@@ -50,4 +50,9 @@
<item>@string/sync_host_default</item>
<item>86.57.183.214:8081</item>
</string-array>
<string-array name="values_proxy_types" translatable="false">
<item>DIRECT</item>
<item>HTTP</item>
<item>SOCKS</item>
</string-array>
</resources>

View File

@@ -417,4 +417,8 @@
<string name="translations">Translations</string>
<string name="web_view_unavailable">WebView not available: check if WebView provider is installed</string>
<string name="clear_network_cache">Clear network cache</string>
<string name="type">Type</string>
<string name="address">Address</string>
<string name="port">Port</string>
<string name="proxy">Proxy</string>
</resources>

View File

@@ -37,6 +37,11 @@
app:allowDividerAbove="true"
app:useSimpleSummaryProvider="true" />
<PreferenceScreen
android:fragment="org.koitharu.kotatsu.settings.ProxySettingsFragment"
android:key="proxy"
android:title="@string/proxy" />
<SwitchPreferenceCompat
android:key="ssl_bypass"
android:title="@string/ignore_ssl_errors" />

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ListPreference
android:defaultValue="DIRECT"
android:entries="@array/proxy_types"
android:entryValues="@array/values_proxy_types"
android:key="proxy_type"
android:title="@string/type"
app:useSimpleSummaryProvider="true" />
<EditTextPreference
android:key="proxy_address"
android:title="@string/address"
app:useSimpleSummaryProvider="true" />
<EditTextPreference
android:key="proxy_port"
android:title="@string/port"
app:useSimpleSummaryProvider="true" />
</PreferenceScreen>