Update parsers

This commit is contained in:
Koitharu
2025-05-24 21:13:33 +03:00
parent 771954ffb8
commit 19d0fe97a0
9 changed files with 59 additions and 7 deletions

View File

@@ -76,7 +76,6 @@ android {
'-opt-in=kotlin.contracts.ExperimentalContracts',
'-opt-in=coil3.annotation.ExperimentalCoilApi',
'-opt-in=coil3.annotation.InternalCoilApi',
'-opt-in=org.koitharu.kotatsu.parsers.InternalParsersApi',
'-Xjspecify-annotations=strict',
'-Xtype-enhancement-improvements-strict-mode'
]

View File

@@ -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)
}
}

View File

@@ -19,6 +19,7 @@ import org.koitharu.kotatsu.core.exceptions.InteractiveActionRequiredException
import org.koitharu.kotatsu.core.image.BitmapDecoderCompat
import org.koitharu.kotatsu.core.network.MangaHttpClient
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.util.ext.configureForParser
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
@@ -51,6 +52,7 @@ class MangaLoaderContextImpl @Inject constructor(
private var webViewCached: WeakReference<WebView>? = null
private val webViewUserAgent by lazy { obtainWebViewUserAgent() }
@Deprecated("Provide a base url")
@SuppressLint("SetJavaScriptEnabled")
override suspend fun evaluateJs(script: String): String? = withContext(Dispatchers.Main.immediate) {
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 getConfig(source: MangaSource): MangaSourceConfig {

View File

@@ -215,6 +215,7 @@ fun WebView.configureForParser(userAgentOverride: String?) = with(settings) {
WebViewCompat.setAudioMuted(this@configureForParser, true)
}
databaseEnabled = true
allowContentAccess = false
if (userAgentOverride != null) {
userAgentString = userAgentOverride
}

View File

@@ -6,6 +6,7 @@ import androidx.fragment.app.viewModels
import androidx.preference.Preference
import androidx.preference.SwitchPreferenceCompat
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.flow.filterNotNull
import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
import org.koitharu.kotatsu.core.model.getTitle
@@ -49,13 +50,15 @@ class SourceSettingsFragment : BasePreferenceFragment(0), Preference.OnPreferenc
findPreference<Preference>(KEY_AUTH)?.run {
val authProvider = (viewModel.repository as? ParserMangaRepository)?.getAuthProvider()
isVisible = authProvider != null
isEnabled = authProvider?.isAuthorized == false
}
findPreference<Preference>(SourceSettings.KEY_SLOWDOWN)?.isVisible = isValidSource
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
viewModel.isAuthorized.filterNotNull().observe(viewLifecycleOwner) { isAuthorized ->
findPreference<Preference>(KEY_AUTH)?.isEnabled = !isAuthorized
}
viewModel.username.observe(viewLifecycleOwner) { username ->
findPreference<Preference>(KEY_AUTH)?.summary = username?.let {
getString(R.string.logged_in_as, it)

View File

@@ -38,6 +38,7 @@ class SourceSettingsViewModel @Inject constructor(
val onActionDone = MutableEventFlow<ReversibleAction>()
val username = MutableStateFlow<String?>(null)
val isAuthorized = MutableStateFlow<Boolean?>(null)
val browserUrl = MutableStateFlow<String?>(null)
val isEnabled = mangaSourcesRepository.observeIsEnabled(source)
private var usernameLoadJob: Job? = null
@@ -103,6 +104,8 @@ class SourceSettingsViewModel @Inject constructor(
launchLoadingJob(Dispatchers.Default) {
try {
username.value = null
isAuthorized.value = null
isAuthorized.value = authProvider?.isAuthorized()
username.value = authProvider?.getUsername()
} catch (_: AuthRequiredException) {
}

View File

@@ -9,6 +9,7 @@ import androidx.activity.result.contract.ActivityResultContract
import androidx.lifecycle.lifecycleScope
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.koitharu.kotatsu.R
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.parsers.MangaParserAuthProvider
import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
@AndroidEntryPoint
class SourceAuthActivity : BaseBrowserActivity(), BrowserCallback {
private lateinit var authProvider: MangaParserAuthProvider
private var authCheckJob: Job? = null
override fun onCreate2(savedInstanceState: Bundle?, source: MangaSource, repository: ParserMangaRepository?) {
if (repository == null) {
finishAfterTransition()
@@ -72,10 +76,20 @@ class SourceAuthActivity : BaseBrowserActivity(), BrowserCallback {
override fun onLoadingStateChanged(isLoading: Boolean) {
super.onLoadingStateChanged(isLoading)
if (!isLoading && authProvider.isAuthorized) {
Toast.makeText(this, R.string.auth_complete, Toast.LENGTH_SHORT).show()
setResult(RESULT_OK)
finishAfterTransition()
if (isLoading) {
return
}
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()
}
}
}

View File

@@ -4,6 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto">
<Preference
android:enabled="false"
android:key="auth"
android:order="100"
android:persistent="false"