Add proxy support #376
This commit is contained in:
@@ -3,9 +3,9 @@ package org.koitharu.kotatsu.core.logs
|
|||||||
import javax.inject.Qualifier
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
@Qualifier
|
@Qualifier
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
annotation class TrackerLogger
|
annotation class TrackerLogger
|
||||||
|
|
||||||
@Qualifier
|
@Qualifier
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
annotation class SyncLogger
|
annotation class SyncLogger
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,9 +3,9 @@ package org.koitharu.kotatsu.core.network
|
|||||||
import javax.inject.Qualifier
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
@Qualifier
|
@Qualifier
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
annotation class BaseHttpClient
|
annotation class BaseHttpClient
|
||||||
|
|
||||||
@Qualifier
|
@Qualifier
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
annotation class MangaHttpClient
|
annotation class MangaHttpClient
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ interface NetworkModule {
|
|||||||
readTimeout(60, TimeUnit.SECONDS)
|
readTimeout(60, TimeUnit.SECONDS)
|
||||||
writeTimeout(20, TimeUnit.SECONDS)
|
writeTimeout(20, TimeUnit.SECONDS)
|
||||||
cookieJar(cookieJar)
|
cookieJar(cookieJar)
|
||||||
|
proxySelector(AppProxySelector(settings))
|
||||||
dns(DoHManager(cache, settings))
|
dns(DoHManager(cache, settings))
|
||||||
if (settings.isSSLBypassEnabled) {
|
if (settings.isSSLBypassEnabled) {
|
||||||
bypassSSLErrors()
|
bypassSSLErrors()
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.koitharu.kotatsu.parsers.model.SortOrder
|
|||||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||||
import org.koitharu.kotatsu.shelf.domain.ShelfSection
|
import org.koitharu.kotatsu.shelf.domain.ShelfSection
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.net.Proxy
|
||||||
import java.util.Collections
|
import java.util.Collections
|
||||||
import java.util.EnumSet
|
import java.util.EnumSet
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
@@ -276,6 +277,18 @@ class AppSettings @Inject constructor(@ApplicationContext context: Context) {
|
|||||||
val isSSLBypassEnabled: Boolean
|
val isSSLBypassEnabled: Boolean
|
||||||
get() = prefs.getBoolean(KEY_SSL_BYPASS, false)
|
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
|
var localListOrder: SortOrder
|
||||||
get() = prefs.getEnumValue(KEY_LOCAL_LIST_ORDER, SortOrder.NEWEST)
|
get() = prefs.getEnumValue(KEY_LOCAL_LIST_ORDER, SortOrder.NEWEST)
|
||||||
set(value) = prefs.edit { putEnumValue(KEY_LOCAL_LIST_ORDER, value) }
|
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_SSL_BYPASS = "ssl_bypass"
|
||||||
const val KEY_READER_AUTOSCROLL_SPEED = "as_speed"
|
const val KEY_READER_AUTOSCROLL_SPEED = "as_speed"
|
||||||
const val KEY_MIRROR_SWITCHING = "mirror_switching"
|
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
|
// About
|
||||||
const val KEY_APP_UPDATE = "app_update"
|
const val KEY_APP_UPDATE = "app_update"
|
||||||
|
|||||||
@@ -3,5 +3,5 @@ package org.koitharu.kotatsu.local.data
|
|||||||
import javax.inject.Qualifier
|
import javax.inject.Qualifier
|
||||||
|
|
||||||
@Qualifier
|
@Qualifier
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
@Retention(AnnotationRetention.BINARY)
|
||||||
annotation class LocalStorageChanges
|
annotation class LocalStorageChanges
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import org.koitharu.kotatsu.local.data.LocalStorageManager
|
|||||||
import org.koitharu.kotatsu.parsers.util.names
|
import org.koitharu.kotatsu.parsers.util.names
|
||||||
import org.koitharu.kotatsu.util.ext.printStackTraceDebug
|
import org.koitharu.kotatsu.util.ext.printStackTraceDebug
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.net.Proxy
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
@@ -62,6 +63,7 @@ class ContentSettingsFragment :
|
|||||||
if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled,
|
if (settings.isSuggestionsEnabled) R.string.enabled else R.string.disabled,
|
||||||
)
|
)
|
||||||
bindRemoteSourcesSummary()
|
bindRemoteSourcesSummary()
|
||||||
|
bindProxySummary()
|
||||||
settings.subscribe(this)
|
settings.subscribe(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,6 +95,12 @@ class ContentSettingsFragment :
|
|||||||
AppSettings.KEY_SSL_BYPASS -> {
|
AppSettings.KEY_SSL_BYPASS -> {
|
||||||
Snackbar.make(listView, R.string.settings_apply_restart_required, Snackbar.LENGTH_INDEFINITE).show()
|
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() {
|
private fun updateDownloadsConstraints() {
|
||||||
val preference = findPreference<Preference>(AppSettings.KEY_DOWNLOADS_WIFI)
|
val preference = findPreference<Preference>(AppSettings.KEY_DOWNLOADS_WIFI)
|
||||||
viewLifecycleScope.launch {
|
viewLifecycleScope.launch {
|
||||||
|
|||||||
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,7 +6,7 @@ import org.koitharu.kotatsu.core.util.EditTextValidator
|
|||||||
|
|
||||||
class EditTextBindListener(
|
class EditTextBindListener(
|
||||||
private val inputType: Int,
|
private val inputType: Int,
|
||||||
private val hint: String,
|
private val hint: String?,
|
||||||
private val validator: EditTextValidator?,
|
private val validator: EditTextValidator?,
|
||||||
) : EditTextPreference.OnBindEditTextListener {
|
) : EditTextPreference.OnBindEditTextListener {
|
||||||
|
|
||||||
|
|||||||
@@ -53,4 +53,9 @@
|
|||||||
<item>@string/status_on_hold</item>
|
<item>@string/status_on_hold</item>
|
||||||
<item>@string/status_dropped</item>
|
<item>@string/status_dropped</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
</resources>
|
<string-array name="proxy_types">
|
||||||
|
<item>@string/disabled</item>
|
||||||
|
<item>HTTP</item>
|
||||||
|
<item>SOCKS (v4/v5)</item>
|
||||||
|
</string-array>
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -50,4 +50,9 @@
|
|||||||
<item>@string/sync_host_default</item>
|
<item>@string/sync_host_default</item>
|
||||||
<item>86.57.183.214:8081</item>
|
<item>86.57.183.214:8081</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
|
<string-array name="values_proxy_types" translatable="false">
|
||||||
|
<item>DIRECT</item>
|
||||||
|
<item>HTTP</item>
|
||||||
|
<item>SOCKS</item>
|
||||||
|
</string-array>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -417,4 +417,8 @@
|
|||||||
<string name="translations">Translations</string>
|
<string name="translations">Translations</string>
|
||||||
<string name="web_view_unavailable">WebView not available: check if WebView provider is installed</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="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>
|
</resources>
|
||||||
|
|||||||
@@ -37,6 +37,11 @@
|
|||||||
app:allowDividerAbove="true"
|
app:allowDividerAbove="true"
|
||||||
app:useSimpleSummaryProvider="true" />
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
|
||||||
|
<PreferenceScreen
|
||||||
|
android:fragment="org.koitharu.kotatsu.settings.ProxySettingsFragment"
|
||||||
|
android:key="proxy"
|
||||||
|
android:title="@string/proxy" />
|
||||||
|
|
||||||
<SwitchPreferenceCompat
|
<SwitchPreferenceCompat
|
||||||
android:key="ssl_bypass"
|
android:key="ssl_bypass"
|
||||||
android:title="@string/ignore_ssl_errors" />
|
android:title="@string/ignore_ssl_errors" />
|
||||||
|
|||||||
24
app/src/main/res/xml/pref_proxy.xml
Normal file
24
app/src/main/res/xml/pref_proxy.xml
Normal 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>
|
||||||
Reference in New Issue
Block a user