Dynamic source settings

master
Koitharu 2 years ago
parent 43c65bf95b
commit 10dc1d10ed
Signed by: Koitharu
GPG Key ID: 676DEE768C17A9D7

@ -17,7 +17,7 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.util.ext.configureForParser import org.koitharu.kotatsu.core.util.ext.configureForParser
import org.koitharu.kotatsu.core.util.ext.toUriOrNull import org.koitharu.kotatsu.core.util.ext.toUriOrNull
@ -44,7 +44,7 @@ class BrowserActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallback
setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material) setHomeAsUpIndicator(materialR.drawable.abc_ic_clear_material)
} }
val mangaSource = MangaSource(intent?.getStringExtra(EXTRA_SOURCE)) val mangaSource = MangaSource(intent?.getStringExtra(EXTRA_SOURCE))
val repository = mangaRepositoryFactory.create(mangaSource) as? RemoteMangaRepository val repository = mangaRepositoryFactory.create(mangaSource) as? ParserMangaRepository
repository?.headers?.get(CommonHeaders.USER_AGENT) repository?.headers?.get(CommonHeaders.USER_AGENT)
viewBinding.webView.configureForParser(userAgent) viewBinding.webView.configureForParser(userAgent)
CookieManager.getInstance().setAcceptThirdPartyCookies(viewBinding.webView, true) CookieManager.getInstance().setAcceptThirdPartyCookies(viewBinding.webView, true)

@ -11,7 +11,7 @@ import okio.IOException
import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.BuildConfig
import org.koitharu.kotatsu.core.parser.MangaLoaderContextImpl import org.koitharu.kotatsu.core.parser.MangaLoaderContextImpl
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
import org.koitharu.kotatsu.parsers.util.mergeWith import org.koitharu.kotatsu.parsers.util.mergeWith
@ -30,7 +30,7 @@ class CommonHeadersInterceptor @Inject constructor(
val request = chain.request() val request = chain.request()
val source = request.tag(MangaSource::class.java) val source = request.tag(MangaSource::class.java)
val repository = if (source != null) { val repository = if (source != null) {
mangaRepositoryFactoryLazy.get().create(source) as? RemoteMangaRepository mangaRepositoryFactoryLazy.get().create(source) as? ParserMangaRepository
} else { } else {
if (BuildConfig.DEBUG) { if (BuildConfig.DEBUG) {
Log.w("Http", "Request without source tag: ${request.url}") Log.w("Http", "Request without source tag: ${request.url}")

@ -13,7 +13,7 @@ import okhttp3.internal.canParseAsIpAddress
import okhttp3.internal.closeQuietly import okhttp3.internal.closeQuietly
import okhttp3.internal.publicsuffix.PublicSuffixDatabase import okhttp3.internal.publicsuffix.PublicSuffixDatabase
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.parsers.model.MangaParserSource import org.koitharu.kotatsu.parsers.model.MangaParserSource
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
@ -54,7 +54,7 @@ class MirrorSwitchInterceptor @Inject constructor(
} }
} }
suspend fun trySwitchMirror(repository: RemoteMangaRepository): Boolean = runInterruptible(Dispatchers.Default) { suspend fun trySwitchMirror(repository: ParserMangaRepository): Boolean = runInterruptible(Dispatchers.Default) {
if (!isEnabled) { if (!isEnabled) {
return@runInterruptible false return@runInterruptible false
} }
@ -76,14 +76,14 @@ class MirrorSwitchInterceptor @Inject constructor(
} }
} }
fun rollback(repository: RemoteMangaRepository, oldMirror: String) = synchronized(obtainLock(repository.source)) { fun rollback(repository: ParserMangaRepository, oldMirror: String) = synchronized(obtainLock(repository.source)) {
blacklist[repository.source]?.remove(oldMirror) blacklist[repository.source]?.remove(oldMirror)
repository.domain = oldMirror repository.domain = oldMirror
} }
private fun trySwitchMirror(request: Request, chain: Interceptor.Chain): Response? { private fun trySwitchMirror(request: Request, chain: Interceptor.Chain): Response? {
val source = request.tag(MangaSource::class.java) ?: return null val source = request.tag(MangaSource::class.java) ?: return null
val repository = mangaRepositoryFactoryLazy.get().create(source) as? RemoteMangaRepository ?: return null val repository = mangaRepositoryFactoryLazy.get().create(source) as? ParserMangaRepository ?: return null
val mirrors = repository.getAvailableMirrors() val mirrors = repository.getAvailableMirrors()
if (mirrors.isEmpty()) { if (mirrors.isEmpty()) {
return null return null
@ -94,7 +94,7 @@ class MirrorSwitchInterceptor @Inject constructor(
} }
private fun tryMirrors( private fun tryMirrors(
repository: RemoteMangaRepository, repository: ParserMangaRepository,
mirrors: List<String>, mirrors: List<String>,
chain: Interceptor.Chain, chain: Interceptor.Chain,
request: Request, request: Request,

@ -52,7 +52,7 @@ class MangaLinkResolver @Inject constructor(
val host = uri.host ?: return null val host = uri.host ?: return null
val repo = sourcesRepository.allMangaSources.asSequence() val repo = sourcesRepository.allMangaSources.asSequence()
.map { source -> .map { source ->
repositoryFactory.create(source) as RemoteMangaRepository repositoryFactory.create(source) as ParserMangaRepository
}.find { repo -> }.find { repo ->
host in repo.domains host in repo.domains
} ?: return null } ?: return null
@ -86,7 +86,7 @@ class MangaLinkResolver @Inject constructor(
} }
private suspend fun MangaRepository.getDetailsNoCache(manga: Manga): Manga { private suspend fun MangaRepository.getDetailsNoCache(manga: Manga): Manga {
return if (this is RemoteMangaRepository) { return if (this is ParserMangaRepository) {
getDetails(manga, CachePolicy.READ_ONLY) getDetails(manga, CachePolicy.READ_ONLY)
} else { } else {
getDetails(manga) getDetails(manga)

@ -88,7 +88,7 @@ interface MangaRepository {
} }
private fun createRepository(source: MangaSource): MangaRepository? = when (source) { private fun createRepository(source: MangaSource): MangaRepository? = when (source) {
is MangaParserSource -> RemoteMangaRepository( is MangaParserSource -> ParserMangaRepository(
parser = MangaParser(source, loaderContext), parser = MangaParser(source, loaderContext),
cache = contentCache, cache = contentCache,
mirrorSwitchInterceptor = mirrorSwitchInterceptor, mirrorSwitchInterceptor = mirrorSwitchInterceptor,

@ -36,7 +36,7 @@ import org.koitharu.kotatsu.parsers.util.domain
import org.koitharu.kotatsu.parsers.util.runCatchingCancellable import org.koitharu.kotatsu.parsers.util.runCatchingCancellable
import java.util.Locale import java.util.Locale
class RemoteMangaRepository( class ParserMangaRepository(
private val parser: MangaParser, private val parser: MangaParser,
private val cache: MemoryContentCache, private val cache: MemoryContentCache,
private val mirrorSwitchInterceptor: MirrorSwitchInterceptor, private val mirrorSwitchInterceptor: MirrorSwitchInterceptor,
@ -220,14 +220,14 @@ class RemoteMangaRepository(
if (result.isValidResult()) { if (result.isValidResult()) {
return result.getOrThrow() return result.getOrThrow()
} }
return if (trySwitchMirror(this@RemoteMangaRepository)) { return if (trySwitchMirror(this@ParserMangaRepository)) {
val newResult = runCatchingCancellable { val newResult = runCatchingCancellable {
block() block()
} }
if (newResult.isValidResult()) { if (newResult.isValidResult()) {
return newResult.getOrThrow() return newResult.getOrThrow()
} else { } else {
rollback(this@RemoteMangaRepository, initialMirror) rollback(this@ParserMangaRepository, initialMirror)
return result.getOrThrow() return result.getOrThrow()
} }
} else { } else {

@ -25,7 +25,7 @@ import okio.buffer
import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException import org.koitharu.kotatsu.core.exceptions.CloudFlareProtectedException
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.util.ext.requireBody import org.koitharu.kotatsu.core.util.ext.requireBody
import org.koitharu.kotatsu.core.util.ext.writeAllCancellable import org.koitharu.kotatsu.core.util.ext.writeAllCancellable
import org.koitharu.kotatsu.local.data.CacheDir import org.koitharu.kotatsu.local.data.CacheDir
@ -53,7 +53,7 @@ class FaviconFetcher(
override suspend fun fetch(): FetchResult { override suspend fun fetch(): FetchResult {
getCached(options)?.let { return it } getCached(options)?.let { return it }
val repo = mangaRepositoryFactory.create(mangaSource) as RemoteMangaRepository val repo = mangaRepositoryFactory.create(mangaSource) as ParserMangaRepository
val sizePx = maxOf( val sizePx = maxOf(
options.size.width.pxOrElse { FALLBACK_SIZE }, options.size.width.pxOrElse { FALLBACK_SIZE },
options.size.height.pxOrElse { FALLBACK_SIZE }, options.size.height.pxOrElse { FALLBACK_SIZE },

@ -25,7 +25,7 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.formatNumber import org.koitharu.kotatsu.core.model.formatNumber
import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.ui.model.DateTimeAgo import org.koitharu.kotatsu.core.ui.model.DateTimeAgo
import org.koitharu.kotatsu.core.ui.util.ReversibleAction import org.koitharu.kotatsu.core.ui.util.ReversibleAction
@ -326,6 +326,6 @@ class DownloadsViewModel @Inject constructor(
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null) }.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, null)
private suspend fun tryLoad(manga: Manga) = runCatchingCancellable { private suspend fun tryLoad(manga: Manga) = runCatchingCancellable {
(mangaRepositoryFactory.create(manga.source) as RemoteMangaRepository).getDetails(manga) (mangaRepositoryFactory.create(manga.source) as ParserMangaRepository).getDetails(manga)
}.getOrNull() }.getOrNull()
} }

@ -3,7 +3,7 @@ package org.koitharu.kotatsu.download.ui.worker
import androidx.collection.MutableObjectLongMap import androidx.collection.MutableObjectLongMap
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
class DownloadSlowdownDispatcher( class DownloadSlowdownDispatcher(
@ -13,7 +13,7 @@ class DownloadSlowdownDispatcher(
private val timeMap = MutableObjectLongMap<MangaSource>() private val timeMap = MutableObjectLongMap<MangaSource>()
suspend fun delay(source: MangaSource) { suspend fun delay(source: MangaSource) {
val repo = mangaRepositoryFactory.create(source) as? RemoteMangaRepository ?: return val repo = mangaRepositoryFactory.create(source) as? ParserMangaRepository ?: return
if (!repo.isSlowdownEnabled()) { if (!repo.isSlowdownEnabled()) {
return return
} }

@ -12,7 +12,7 @@ import org.koitharu.kotatsu.bookmarks.domain.BookmarksRepository
import org.koitharu.kotatsu.core.model.findById import org.koitharu.kotatsu.core.model.findById
import org.koitharu.kotatsu.core.parser.MangaDataRepository import org.koitharu.kotatsu.core.parser.MangaDataRepository
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty import org.koitharu.kotatsu.core.util.ext.ifNullOrEmpty
import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug
import org.koitharu.kotatsu.parsers.exception.ParseException import org.koitharu.kotatsu.parsers.exception.ParseException
@ -73,7 +73,7 @@ class CoverRestoreInterceptor @Inject constructor(
if (dataRepository.findMangaById(manga.id) == null) { if (dataRepository.findMangaById(manga.id) == null) {
return false return false
} }
val repo = repositoryFactory.create(manga.source) as? RemoteMangaRepository ?: return false val repo = repositoryFactory.create(manga.source) as? ParserMangaRepository ?: return false
val fixed = repo.find(manga) ?: return false val fixed = repo.find(manga) ?: return false
return if (fixed != manga) { return if (fixed != manga) {
dataRepository.storeManga(fixed) dataRepository.storeManga(fixed)
@ -100,7 +100,7 @@ class CoverRestoreInterceptor @Inject constructor(
} }
private suspend fun restoreBookmarkImpl(bookmark: Bookmark): Boolean { private suspend fun restoreBookmarkImpl(bookmark: Bookmark): Boolean {
val repo = repositoryFactory.create(bookmark.manga.source) as? RemoteMangaRepository ?: return false val repo = repositoryFactory.create(bookmark.manga.source) as? ParserMangaRepository ?: return false
val chapter = repo.getDetails(bookmark.manga).chapters?.findById(bookmark.chapterId) ?: return false val chapter = repo.getDetails(bookmark.manga).chapters?.findById(bookmark.chapterId) ?: return false
val page = repo.getPages(chapter)[bookmark.page] val page = repo.getPages(chapter)[bookmark.page]
val imageUrl = page.preview.ifNullOrEmpty { page.url } val imageUrl = page.preview.ifNullOrEmpty { page.url }

@ -32,7 +32,7 @@ import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.core.network.MangaHttpClient import org.koitharu.kotatsu.core.network.MangaHttpClient
import org.koitharu.kotatsu.core.network.imageproxy.ImageProxyInterceptor import org.koitharu.kotatsu.core.network.imageproxy.ImageProxyInterceptor
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.FileSize import org.koitharu.kotatsu.core.util.FileSize
import org.koitharu.kotatsu.core.util.RetainedLifecycleCoroutineScope import org.koitharu.kotatsu.core.util.RetainedLifecycleCoroutineScope
@ -91,7 +91,7 @@ class PageLoader @Inject constructor(
private val edgeDetector = EdgeDetector(context) private val edgeDetector = EdgeDetector(context)
fun isPrefetchApplicable(): Boolean { fun isPrefetchApplicable(): Boolean {
return repository is RemoteMangaRepository return repository is ParserMangaRepository
&& settings.isPagesPreloadEnabled && settings.isPagesPreloadEnabled
&& !context.isPowerSaveMode() && !context.isPowerSaveMode()
&& !isLowRam() && !isLowRam()

@ -7,7 +7,7 @@ import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.util.ext.mapToArray import org.koitharu.kotatsu.core.util.ext.mapToArray
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.model.MangaSource import org.koitharu.kotatsu.parsers.model.MangaSource
@ -20,7 +20,7 @@ class ImageServerDelegate(
) { ) {
private val repositoryLazy = SuspendLazy { private val repositoryLazy = SuspendLazy {
mangaRepositoryFactory.create(checkNotNull(mangaSource)) as RemoteMangaRepository mangaRepositoryFactory.create(checkNotNull(mangaSource)) as ParserMangaRepository
} }
suspend fun isAvailable() = withContext(Dispatchers.Default) { suspend fun isAvailable() = withContext(Dispatchers.Default) {

@ -21,7 +21,7 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.model.distinctById import org.koitharu.kotatsu.core.model.distinctById
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.call
@ -75,7 +75,7 @@ open class RemoteListViewModel @Inject constructor(
get() = repository.isSearchSupported get() = repository.isSearchSupported
val browserUrl: String? val browserUrl: String?
get() = (repository as? RemoteMangaRepository)?.domain?.let { "https://$it" } get() = (repository as? ParserMangaRepository)?.domain?.let { "https://$it" }
override val content = combine( override val content = combine(
mangaList.map { it?.skipNsfwIfNeeded() }, mangaList.map { it?.skipNsfwIfNeeded() },

@ -7,7 +7,9 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreferenceCompat import androidx.preference.SwitchPreferenceCompat
import org.koitharu.kotatsu.R import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.EmptyMangaRepository
import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.util.ext.mapToArray import org.koitharu.kotatsu.core.util.ext.mapToArray
import org.koitharu.kotatsu.parsers.config.ConfigKey import org.koitharu.kotatsu.parsers.config.ConfigKey
import org.koitharu.kotatsu.parsers.network.UserAgents import org.koitharu.kotatsu.parsers.network.UserAgents
@ -17,7 +19,14 @@ import org.koitharu.kotatsu.settings.utils.EditTextDefaultSummaryProvider
import org.koitharu.kotatsu.settings.utils.validation.DomainValidator import org.koitharu.kotatsu.settings.utils.validation.DomainValidator
import org.koitharu.kotatsu.settings.utils.validation.HeaderValidator import org.koitharu.kotatsu.settings.utils.validation.HeaderValidator
fun PreferenceFragmentCompat.addPreferencesFromRepository(repository: RemoteMangaRepository) { fun PreferenceFragmentCompat.addPreferencesFromRepository(repository: MangaRepository) = when (repository) {
is ParserMangaRepository -> addPreferencesFromParserRepository(repository)
is EmptyMangaRepository -> addPreferencesFromEmptyRepository()
else -> Unit
}
private fun PreferenceFragmentCompat.addPreferencesFromParserRepository(repository: ParserMangaRepository) {
addPreferencesFromResource(R.xml.pref_source_parser)
val configKeys = repository.getConfigKeys() val configKeys = repository.getConfigKeys()
val screen = preferenceScreen val screen = preferenceScreen
for (key in configKeys) { for (key in configKeys) {
@ -100,6 +109,16 @@ fun PreferenceFragmentCompat.addPreferencesFromRepository(repository: RemoteMang
} }
} }
private fun PreferenceFragmentCompat.addPreferencesFromEmptyRepository() {
val preference = Preference(requireContext())
preference.setIcon(R.drawable.ic_alert_outline)
preference.isPersistent = false
preference.isSelectable = false
preference.order = 200
preference.setSummary(R.string.unsupported_source)
preferenceScreen.addPreference(preference)
}
private fun Array<out String>.toStringArray(): Array<String> { private fun Array<out String>.toStringArray(): Array<String> {
return Array(size) { i -> this[i] as? String ?: "" } return Array(size) { i -> this[i] as? String ?: "" }
} }

@ -10,7 +10,10 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver import org.koitharu.kotatsu.core.exceptions.resolve.ExceptionResolver
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
import org.koitharu.kotatsu.core.parser.EmptyMangaRepository
import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.AppSettings
import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.core.ui.BasePreferenceFragment import org.koitharu.kotatsu.core.ui.BasePreferenceFragment
import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver import org.koitharu.kotatsu.core.ui.util.ReversibleActionObserver
import org.koitharu.kotatsu.core.util.ext.observe import org.koitharu.kotatsu.core.util.ext.observe
@ -37,15 +40,18 @@ class SourceSettingsFragment : BasePreferenceFragment(0), Preference.OnPreferenc
preferenceManager.sharedPreferencesName = viewModel.source.name preferenceManager.sharedPreferencesName = viewModel.source.name
addPreferencesFromResource(R.xml.pref_source) addPreferencesFromResource(R.xml.pref_source)
addPreferencesFromRepository(viewModel.repository) addPreferencesFromRepository(viewModel.repository)
val isValidSource = viewModel.repository !is EmptyMangaRepository
findPreference<SwitchPreferenceCompat>(KEY_ENABLE)?.run { findPreference<SwitchPreferenceCompat>(KEY_ENABLE)?.run {
isVisible = isValidSource
onPreferenceChangeListener = this@SourceSettingsFragment onPreferenceChangeListener = this@SourceSettingsFragment
} }
findPreference<Preference>(KEY_AUTH)?.run { findPreference<Preference>(KEY_AUTH)?.run {
val authProvider = viewModel.repository.getAuthProvider() val authProvider = (viewModel.repository as? ParserMangaRepository)?.getAuthProvider()
isVisible = authProvider != null isVisible = authProvider != null
isEnabled = authProvider?.isAuthorized == false isEnabled = authProvider?.isAuthorized == false
} }
findPreference<Preference>(SourceSettings.KEY_SLOWDOWN)?.isVisible = isValidSource
} }
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

@ -11,13 +11,14 @@ import org.koitharu.kotatsu.R
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar import org.koitharu.kotatsu.core.network.cookies.MutableCookieJar
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.prefs.SourceSettings import org.koitharu.kotatsu.core.prefs.SourceSettings
import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.ui.util.ReversibleAction import org.koitharu.kotatsu.core.ui.util.ReversibleAction
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call import org.koitharu.kotatsu.core.util.ext.call
import org.koitharu.kotatsu.explore.data.MangaSourcesRepository import org.koitharu.kotatsu.explore.data.MangaSourcesRepository
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
import javax.inject.Inject import javax.inject.Inject
@ -30,7 +31,7 @@ class SourceSettingsViewModel @Inject constructor(
) : BaseViewModel(), SharedPreferences.OnSharedPreferenceChangeListener { ) : BaseViewModel(), SharedPreferences.OnSharedPreferenceChangeListener {
val source = MangaSource(savedStateHandle.get<String>(SourceSettingsFragment.EXTRA_SOURCE)) val source = MangaSource(savedStateHandle.get<String>(SourceSettingsFragment.EXTRA_SOURCE))
val repository = mangaRepositoryFactory.create(source) as RemoteMangaRepository val repository = mangaRepositoryFactory.create(source)
val onActionDone = MutableEventFlow<ReversibleAction>() val onActionDone = MutableEventFlow<ReversibleAction>()
val username = MutableStateFlow<String?>(null) val username = MutableStateFlow<String?>(null)
@ -38,28 +39,41 @@ class SourceSettingsViewModel @Inject constructor(
private var usernameLoadJob: Job? = null private var usernameLoadJob: Job? = null
init { init {
when (repository) {
is ParserMangaRepository -> {
repository.getConfig().subscribe(this) repository.getConfig().subscribe(this)
loadUsername() loadUsername(repository.getAuthProvider())
}
}
} }
override fun onCleared() { override fun onCleared() {
when (repository) {
is ParserMangaRepository -> {
repository.getConfig().unsubscribe(this) repository.getConfig().unsubscribe(this)
}
}
super.onCleared() super.onCleared()
} }
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
when (repository) {
is ParserMangaRepository -> {
if (key != SourceSettings.KEY_SLOWDOWN && key != SourceSettings.KEY_SORT_ORDER) { if (key != SourceSettings.KEY_SLOWDOWN && key != SourceSettings.KEY_SORT_ORDER) {
repository.invalidateCache() repository.invalidateCache()
} }
} }
}
}
fun onResume() { fun onResume() {
if (usernameLoadJob?.isActive != true) { if (usernameLoadJob?.isActive != true && repository is ParserMangaRepository) {
loadUsername() loadUsername(repository.getAuthProvider())
} }
} }
fun clearCookies() { fun clearCookies() {
if (repository !is ParserMangaRepository) return
launchLoadingJob(Dispatchers.Default) { launchLoadingJob(Dispatchers.Default) {
val url = HttpUrl.Builder() val url = HttpUrl.Builder()
.scheme("https") .scheme("https")
@ -67,7 +81,7 @@ class SourceSettingsViewModel @Inject constructor(
.build() .build()
cookieJar.removeCookies(url, null) cookieJar.removeCookies(url, null)
onActionDone.call(ReversibleAction(R.string.cookies_cleared, null)) onActionDone.call(ReversibleAction(R.string.cookies_cleared, null))
loadUsername() loadUsername(repository.getAuthProvider())
} }
} }
@ -77,11 +91,11 @@ class SourceSettingsViewModel @Inject constructor(
} }
} }
private fun loadUsername() { private fun loadUsername(authProvider: MangaParserAuthProvider?) {
launchLoadingJob(Dispatchers.Default) { launchLoadingJob(Dispatchers.Default) {
try { try {
username.value = null username.value = null
username.value = repository.getAuthProvider()?.getUsername() username.value = authProvider?.getUsername()
} catch (_: AuthRequiredException) { } catch (_: AuthRequiredException) {
} }
} }

@ -21,7 +21,7 @@ import org.koitharu.kotatsu.browser.WebViewBackPressedCallback
import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.core.model.MangaSource
import org.koitharu.kotatsu.core.network.CommonHeaders import org.koitharu.kotatsu.core.network.CommonHeaders
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.ui.BaseActivity import org.koitharu.kotatsu.core.ui.BaseActivity
import org.koitharu.kotatsu.core.util.TaggedActivityResult import org.koitharu.kotatsu.core.util.TaggedActivityResult
import org.koitharu.kotatsu.core.util.ext.configureForParser import org.koitharu.kotatsu.core.util.ext.configureForParser
@ -52,7 +52,7 @@ class SourceAuthActivity : BaseActivity<ActivityBrowserBinding>(), BrowserCallba
finishAfterTransition() finishAfterTransition()
return return
} }
val repository = mangaRepositoryFactory.create(source) as? RemoteMangaRepository val repository = mangaRepositoryFactory.create(source) as? ParserMangaRepository
authProvider = (repository)?.getAuthProvider() ?: run { authProvider = (repository)?.getAuthProvider() ?: run {
Toast.makeText( Toast.makeText(
this, this,

@ -5,7 +5,7 @@ import coil.request.CachePolicy
import dagger.Reusable import dagger.Reusable
import org.koitharu.kotatsu.core.model.getPreferredBranch import org.koitharu.kotatsu.core.model.getPreferredBranch
import org.koitharu.kotatsu.core.parser.MangaRepository import org.koitharu.kotatsu.core.parser.MangaRepository
import org.koitharu.kotatsu.core.parser.RemoteMangaRepository import org.koitharu.kotatsu.core.parser.ParserMangaRepository
import org.koitharu.kotatsu.core.util.MultiMutex import org.koitharu.kotatsu.core.util.MultiMutex
import org.koitharu.kotatsu.core.util.ext.toInstantOrNull import org.koitharu.kotatsu.core.util.ext.toInstantOrNull
import org.koitharu.kotatsu.history.data.HistoryRepository import org.koitharu.kotatsu.history.data.HistoryRepository
@ -36,7 +36,7 @@ class Tracker @Inject constructor(
): MangaUpdates = mangaMutex.withLock(track.manga.id) { ): MangaUpdates = mangaMutex.withLock(track.manga.id) {
val updates = runCatchingCancellable { val updates = runCatchingCancellable {
val repo = mangaRepositoryFactory.create(track.manga.source) val repo = mangaRepositoryFactory.create(track.manga.source)
require(repo is RemoteMangaRepository) { "Repository ${repo.javaClass.simpleName} is not supported" } require(repo is ParserMangaRepository) { "Repository ${repo.javaClass.simpleName} is not supported" }
val manga = repo.getDetails(track.manga, CachePolicy.WRITE_ONLY) val manga = repo.getDetails(track.manga, CachePolicy.WRITE_ONLY)
compare(track, manga, getBranch(manga)) compare(track, manga, getBranch(manga))
}.getOrElse { error -> }.getOrElse { error ->

@ -11,21 +11,6 @@
android:persistent="false" android:persistent="false"
android:title="@string/enable_source" /> android:title="@string/enable_source" />
<Preference
android:key="auth"
android:order="100"
android:persistent="false"
android:title="@string/sign_in"
app:allowDividerAbove="true" />
<Preference
android:key="cookies_clear"
android:order="101"
android:persistent="false"
android:summary="@string/clear_source_cookies_summary"
android:title="@string/clear_cookies"
app:allowDividerAbove="true" />
<SwitchPreferenceCompat <SwitchPreferenceCompat
android:defaultValue="false" android:defaultValue="false"
android:key="slowdown" android:key="slowdown"

@ -0,0 +1,21 @@
<?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">
<Preference
android:key="auth"
android:order="100"
android:persistent="false"
android:title="@string/sign_in"
app:allowDividerAbove="true" />
<Preference
android:key="cookies_clear"
android:order="101"
android:persistent="false"
android:summary="@string/clear_source_cookies_summary"
android:title="@string/clear_cookies"
app:allowDividerAbove="true" />
</PreferenceScreen>
Loading…
Cancel
Save