Update parsers
This commit is contained in:
@@ -76,7 +76,6 @@ android {
|
|||||||
'-opt-in=kotlin.contracts.ExperimentalContracts',
|
'-opt-in=kotlin.contracts.ExperimentalContracts',
|
||||||
'-opt-in=coil3.annotation.ExperimentalCoilApi',
|
'-opt-in=coil3.annotation.ExperimentalCoilApi',
|
||||||
'-opt-in=coil3.annotation.InternalCoilApi',
|
'-opt-in=coil3.annotation.InternalCoilApi',
|
||||||
'-opt-in=org.koitharu.kotatsu.parsers.InternalParsersApi',
|
|
||||||
'-Xjspecify-annotations=strict',
|
'-Xjspecify-annotations=strict',
|
||||||
'-Xtype-enhancement-improvements-strict-mode'
|
'-Xtype-enhancement-improvements-strict-mode'
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package org.koitharu.kotatsu.core.network.webview
|
||||||
|
|
||||||
|
import android.webkit.WebView
|
||||||
|
import android.webkit.WebViewClient
|
||||||
|
import kotlin.coroutines.Continuation
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
|
||||||
|
class ContinuationResumeWebViewClient(
|
||||||
|
private val continuation: Continuation<Unit>,
|
||||||
|
) : WebViewClient() {
|
||||||
|
|
||||||
|
override fun onPageFinished(view: WebView?, url: String?) {
|
||||||
|
view?.webViewClient = WebViewClient() // reset to default
|
||||||
|
continuation.resume(Unit)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,6 +19,7 @@ import org.koitharu.kotatsu.core.exceptions.InteractiveActionRequiredException
|
|||||||
import org.koitharu.kotatsu.core.image.BitmapDecoderCompat
|
import org.koitharu.kotatsu.core.image.BitmapDecoderCompat
|
||||||
import org.koitharu.kotatsu.core.network.MangaHttpClient
|
import org.koitharu.kotatsu.core.network.MangaHttpClient
|
||||||
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
|
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
|
||||||
|
import org.koitharu.kotatsu.core.network.webview.ContinuationResumeWebViewClient
|
||||||
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
import org.koitharu.kotatsu.core.prefs.SourceSettings
|
||||||
import org.koitharu.kotatsu.core.util.ext.configureForParser
|
import org.koitharu.kotatsu.core.util.ext.configureForParser
|
||||||
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
|
||||||
@@ -51,6 +52,7 @@ class MangaLoaderContextImpl @Inject constructor(
|
|||||||
private var webViewCached: WeakReference<WebView>? = null
|
private var webViewCached: WeakReference<WebView>? = null
|
||||||
private val webViewUserAgent by lazy { obtainWebViewUserAgent() }
|
private val webViewUserAgent by lazy { obtainWebViewUserAgent() }
|
||||||
|
|
||||||
|
@Deprecated("Provide a base url")
|
||||||
@SuppressLint("SetJavaScriptEnabled")
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
override suspend fun evaluateJs(script: String): String? = withContext(Dispatchers.Main.immediate) {
|
override suspend fun evaluateJs(script: String): String? = withContext(Dispatchers.Main.immediate) {
|
||||||
val webView = obtainWebView()
|
val webView = obtainWebView()
|
||||||
@@ -61,6 +63,19 @@ class MangaLoaderContextImpl @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun evaluateJs(baseUrl: String, script: String): String? = withContext(Dispatchers.Main.immediate) {
|
||||||
|
val webView = obtainWebView()
|
||||||
|
suspendCoroutine { cont ->
|
||||||
|
webView.webViewClient = ContinuationResumeWebViewClient(cont)
|
||||||
|
webView.loadDataWithBaseURL(baseUrl, " ", "text/html", null, null)
|
||||||
|
}
|
||||||
|
suspendCoroutine { cont ->
|
||||||
|
webView.evaluateJavascript(script) { result ->
|
||||||
|
cont.resume(result?.takeUnless { it == "null" })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun getDefaultUserAgent(): String = webViewUserAgent
|
override fun getDefaultUserAgent(): String = webViewUserAgent
|
||||||
|
|
||||||
override fun getConfig(source: MangaSource): MangaSourceConfig {
|
override fun getConfig(source: MangaSource): MangaSourceConfig {
|
||||||
|
|||||||
@@ -215,6 +215,7 @@ fun WebView.configureForParser(userAgentOverride: String?) = with(settings) {
|
|||||||
WebViewCompat.setAudioMuted(this@configureForParser, true)
|
WebViewCompat.setAudioMuted(this@configureForParser, true)
|
||||||
}
|
}
|
||||||
databaseEnabled = true
|
databaseEnabled = true
|
||||||
|
allowContentAccess = false
|
||||||
if (userAgentOverride != null) {
|
if (userAgentOverride != null) {
|
||||||
userAgentString = userAgentOverride
|
userAgentString = userAgentOverride
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import androidx.fragment.app.viewModels
|
|||||||
import androidx.preference.Preference
|
import androidx.preference.Preference
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import kotlinx.coroutines.flow.filterNotNull
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
||||||
import org.koitharu.kotatsu.core.model.getTitle
|
import org.koitharu.kotatsu.core.model.getTitle
|
||||||
@@ -49,13 +50,15 @@ class SourceSettingsFragment : BasePreferenceFragment(0), Preference.OnPreferenc
|
|||||||
findPreference<Preference>(KEY_AUTH)?.run {
|
findPreference<Preference>(KEY_AUTH)?.run {
|
||||||
val authProvider = (viewModel.repository as? ParserMangaRepository)?.getAuthProvider()
|
val authProvider = (viewModel.repository as? ParserMangaRepository)?.getAuthProvider()
|
||||||
isVisible = authProvider != null
|
isVisible = authProvider != null
|
||||||
isEnabled = authProvider?.isAuthorized == false
|
|
||||||
}
|
}
|
||||||
findPreference<Preference>(SourceSettings.KEY_SLOWDOWN)?.isVisible = isValidSource
|
findPreference<Preference>(SourceSettings.KEY_SLOWDOWN)?.isVisible = isValidSource
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
|
viewModel.isAuthorized.filterNotNull().observe(viewLifecycleOwner) { isAuthorized ->
|
||||||
|
findPreference<Preference>(KEY_AUTH)?.isEnabled = !isAuthorized
|
||||||
|
}
|
||||||
viewModel.username.observe(viewLifecycleOwner) { username ->
|
viewModel.username.observe(viewLifecycleOwner) { username ->
|
||||||
findPreference<Preference>(KEY_AUTH)?.summary = username?.let {
|
findPreference<Preference>(KEY_AUTH)?.summary = username?.let {
|
||||||
getString(R.string.logged_in_as, it)
|
getString(R.string.logged_in_as, it)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ class SourceSettingsViewModel @Inject constructor(
|
|||||||
|
|
||||||
val onActionDone = MutableEventFlow<ReversibleAction>()
|
val onActionDone = MutableEventFlow<ReversibleAction>()
|
||||||
val username = MutableStateFlow<String?>(null)
|
val username = MutableStateFlow<String?>(null)
|
||||||
|
val isAuthorized = MutableStateFlow<Boolean?>(null)
|
||||||
val browserUrl = MutableStateFlow<String?>(null)
|
val browserUrl = MutableStateFlow<String?>(null)
|
||||||
val isEnabled = mangaSourcesRepository.observeIsEnabled(source)
|
val isEnabled = mangaSourcesRepository.observeIsEnabled(source)
|
||||||
private var usernameLoadJob: Job? = null
|
private var usernameLoadJob: Job? = null
|
||||||
@@ -103,6 +104,8 @@ class SourceSettingsViewModel @Inject constructor(
|
|||||||
launchLoadingJob(Dispatchers.Default) {
|
launchLoadingJob(Dispatchers.Default) {
|
||||||
try {
|
try {
|
||||||
username.value = null
|
username.value = null
|
||||||
|
isAuthorized.value = null
|
||||||
|
isAuthorized.value = authProvider?.isAuthorized()
|
||||||
username.value = authProvider?.getUsername()
|
username.value = authProvider?.getUsername()
|
||||||
} catch (_: AuthRequiredException) {
|
} catch (_: AuthRequiredException) {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import androidx.activity.result.contract.ActivityResultContract
|
|||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.google.android.material.snackbar.Snackbar
|
import com.google.android.material.snackbar.Snackbar
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import org.koitharu.kotatsu.R
|
import org.koitharu.kotatsu.R
|
||||||
import org.koitharu.kotatsu.browser.BaseBrowserActivity
|
import org.koitharu.kotatsu.browser.BaseBrowserActivity
|
||||||
@@ -20,12 +21,15 @@ import org.koitharu.kotatsu.core.parser.ParserMangaRepository
|
|||||||
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
|
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
|
||||||
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
|
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
|
||||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||||
|
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class SourceAuthActivity : BaseBrowserActivity(), BrowserCallback {
|
class SourceAuthActivity : BaseBrowserActivity(), BrowserCallback {
|
||||||
|
|
||||||
private lateinit var authProvider: MangaParserAuthProvider
|
private lateinit var authProvider: MangaParserAuthProvider
|
||||||
|
|
||||||
|
private var authCheckJob: Job? = null
|
||||||
|
|
||||||
override fun onCreate2(savedInstanceState: Bundle?, source: MangaSource, repository: ParserMangaRepository?) {
|
override fun onCreate2(savedInstanceState: Bundle?, source: MangaSource, repository: ParserMangaRepository?) {
|
||||||
if (repository == null) {
|
if (repository == null) {
|
||||||
finishAfterTransition()
|
finishAfterTransition()
|
||||||
@@ -72,10 +76,20 @@ class SourceAuthActivity : BaseBrowserActivity(), BrowserCallback {
|
|||||||
|
|
||||||
override fun onLoadingStateChanged(isLoading: Boolean) {
|
override fun onLoadingStateChanged(isLoading: Boolean) {
|
||||||
super.onLoadingStateChanged(isLoading)
|
super.onLoadingStateChanged(isLoading)
|
||||||
if (!isLoading && authProvider.isAuthorized) {
|
if (isLoading) {
|
||||||
Toast.makeText(this, R.string.auth_complete, Toast.LENGTH_SHORT).show()
|
return
|
||||||
setResult(RESULT_OK)
|
}
|
||||||
finishAfterTransition()
|
val prevJob = authCheckJob
|
||||||
|
authCheckJob = lifecycleScope.launch {
|
||||||
|
prevJob?.join()
|
||||||
|
val isAuthorized = runCatchingCancellable {
|
||||||
|
authProvider.isAuthorized()
|
||||||
|
}.getOrDefault(false)
|
||||||
|
if (isAuthorized) {
|
||||||
|
Toast.makeText(this@SourceAuthActivity, R.string.auth_complete, Toast.LENGTH_SHORT).show()
|
||||||
|
setResult(RESULT_OK)
|
||||||
|
finishAfterTransition()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
|
android:enabled="false"
|
||||||
android:key="auth"
|
android:key="auth"
|
||||||
android:order="100"
|
android:order="100"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ material = "1.14.0-alpha01"
|
|||||||
moshi = "1.15.2"
|
moshi = "1.15.2"
|
||||||
okhttp = "4.12.0"
|
okhttp = "4.12.0"
|
||||||
okio = "3.11.0"
|
okio = "3.11.0"
|
||||||
parsers = "276349e23c"
|
parsers = "7b1a0b8d0d"
|
||||||
preference = "1.2.1"
|
preference = "1.2.1"
|
||||||
recyclerview = "1.4.0"
|
recyclerview = "1.4.0"
|
||||||
room = "2.7.1"
|
room = "2.7.1"
|
||||||
|
|||||||
Reference in New Issue
Block a user