Update parsers structure
parent
29cf04c804
commit
f681ed270b
@ -1,42 +0,0 @@
|
||||
package org.koitharu.kotatsu.parsers
|
||||
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQuery
|
||||
import org.koitharu.kotatsu.parsers.util.convertToMangaListFilter
|
||||
|
||||
@InternalParsersApi
|
||||
public abstract class SinglePageMangaParser(
|
||||
context: MangaLoaderContext,
|
||||
source: MangaParserSource,
|
||||
) : AbstractMangaParser(context, source) {
|
||||
|
||||
|
||||
final override suspend fun getList(query: MangaSearchQuery): List<Manga> {
|
||||
if (query.offset > 0) {
|
||||
return emptyList()
|
||||
}
|
||||
return searchSinglePageManga(query)
|
||||
}
|
||||
|
||||
public open suspend fun searchSinglePageManga(searchQuery: MangaSearchQuery): List<Manga> {
|
||||
return getList(
|
||||
searchQuery.offset,
|
||||
searchQuery.order ?: defaultSortOrder,
|
||||
convertToMangaListFilter(searchQuery),
|
||||
)
|
||||
}
|
||||
|
||||
@Deprecated("New searchManga method should be preferred")
|
||||
final override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
||||
if (offset > 0) {
|
||||
return emptyList()
|
||||
}
|
||||
return getList(order, filter)
|
||||
}
|
||||
|
||||
@Deprecated("New searchManga method should be preferred")
|
||||
public abstract suspend fun getList(order: SortOrder, filter: MangaListFilter): List<Manga>
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
package org.koitharu.kotatsu.parsers.core
|
||||
|
||||
import androidx.annotation.CallSuper
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import org.koitharu.kotatsu.parsers.InternalParsersApi
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.network.OkHttpWebClient
|
||||
import org.koitharu.kotatsu.parsers.network.WebClient
|
||||
import org.koitharu.kotatsu.parsers.util.FaviconParser
|
||||
import org.koitharu.kotatsu.parsers.util.LinkResolver
|
||||
import org.koitharu.kotatsu.parsers.util.RelatedMangaFinder
|
||||
import org.koitharu.kotatsu.parsers.util.toAbsoluteUrl
|
||||
import java.util.*
|
||||
|
||||
@InternalParsersApi
|
||||
public abstract class AbstractMangaParser @InternalParsersApi constructor(
|
||||
@property:InternalParsersApi public val context: MangaLoaderContext,
|
||||
public override val source: MangaParserSource,
|
||||
) : MangaParser {
|
||||
|
||||
public override val config: MangaSourceConfig by lazy { context.getConfig(source) }
|
||||
|
||||
public open val sourceLocale: Locale
|
||||
get() = if (source.locale.isEmpty()) Locale.ROOT else Locale(source.locale)
|
||||
|
||||
/**
|
||||
* Provide default domain and available alternatives, if any.
|
||||
*
|
||||
* Never hardcode domain in requests, use [domain] instead.
|
||||
*/
|
||||
@InternalParsersApi
|
||||
public abstract val configKeyDomain: ConfigKey.Domain
|
||||
|
||||
protected open val userAgentKey: ConfigKey.UserAgent = ConfigKey.UserAgent(context.getDefaultUserAgent())
|
||||
|
||||
@Deprecated("Override intercept() instead")
|
||||
override fun getRequestHeaders(): Headers = Headers.Builder()
|
||||
.add("User-Agent", config[userAgentKey])
|
||||
.build()
|
||||
|
||||
/**
|
||||
* Used as fallback if value of `order` passed to [getList] is null
|
||||
*/
|
||||
public open val defaultSortOrder: SortOrder
|
||||
get() {
|
||||
val supported = availableSortOrders
|
||||
return SortOrder.entries.first { it in supported }
|
||||
}
|
||||
|
||||
override val domain: String
|
||||
get() = config[configKeyDomain]
|
||||
|
||||
@JvmField
|
||||
protected val webClient: WebClient = OkHttpWebClient(context.httpClient, source)
|
||||
|
||||
/**
|
||||
* Fetch direct link to the page image.
|
||||
*/
|
||||
public override suspend fun getPageUrl(page: MangaPage): String = page.url.toAbsoluteUrl(domain)
|
||||
|
||||
/**
|
||||
* Parse favicons from the main page of the source`s website
|
||||
*/
|
||||
public override suspend fun getFavicons(): Favicons {
|
||||
return FaviconParser(webClient, domain).parseFavicons()
|
||||
}
|
||||
|
||||
@CallSuper
|
||||
public override fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
keys.add(configKeyDomain)
|
||||
}
|
||||
|
||||
public override suspend fun getRelatedManga(seed: Manga): List<Manga> {
|
||||
return RelatedMangaFinder(listOf(this)).invoke(seed)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return [Manga] object by web link to it
|
||||
* @see [Manga.publicUrl]
|
||||
*/
|
||||
override suspend fun resolveLink(resolver: LinkResolver, link: HttpUrl): Manga? = null
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response = chain.proceed(chain.request())
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
package org.koitharu.kotatsu.parsers.core
|
||||
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import org.koitharu.kotatsu.parsers.InternalParsersApi
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
import org.koitharu.kotatsu.parsers.util.Paginator
|
||||
|
||||
@InternalParsersApi
|
||||
public abstract class LegacyPagedMangaParser(
|
||||
context: MangaLoaderContext,
|
||||
source: MangaParserSource,
|
||||
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) @JvmField public val pageSize: Int,
|
||||
searchPageSize: Int = pageSize,
|
||||
) : LegacyMangaParser(context, source) {
|
||||
|
||||
@JvmField
|
||||
protected val paginator: Paginator = Paginator(pageSize)
|
||||
|
||||
@JvmField
|
||||
protected val searchPaginator: Paginator = Paginator(searchPageSize)
|
||||
|
||||
final override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
||||
return getList(
|
||||
paginator = if (filter.query.isNullOrEmpty()) {
|
||||
paginator
|
||||
} else {
|
||||
searchPaginator
|
||||
},
|
||||
offset = offset,
|
||||
order = order,
|
||||
filter = filter,
|
||||
)
|
||||
}
|
||||
|
||||
public abstract suspend fun getListPage(page: Int, order: SortOrder, filter: MangaListFilter): List<Manga>
|
||||
|
||||
private suspend fun getList(
|
||||
paginator: Paginator,
|
||||
offset: Int,
|
||||
order: SortOrder,
|
||||
filter: MangaListFilter,
|
||||
): List<Manga> {
|
||||
val page = paginator.getPage(offset)
|
||||
val list = getListPage(page, order, filter)
|
||||
paginator.onListReceived(offset, page, list.size)
|
||||
return list
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
package org.koitharu.kotatsu.parsers.core
|
||||
|
||||
import org.koitharu.kotatsu.parsers.InternalParsersApi
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaListFilter
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.SortOrder
|
||||
|
||||
@InternalParsersApi
|
||||
public abstract class LegacySinglePageMangaParser(
|
||||
context: MangaLoaderContext,
|
||||
source: MangaParserSource,
|
||||
) : LegacyMangaParser(context, source) {
|
||||
|
||||
final override suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga> {
|
||||
if (offset > 0) {
|
||||
return emptyList()
|
||||
}
|
||||
return getList(order, filter)
|
||||
}
|
||||
|
||||
public abstract suspend fun getList(order: SortOrder, filter: MangaListFilter): List<Manga>
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
package org.koitharu.kotatsu.parsers.core
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQuery
|
||||
import org.koitharu.kotatsu.parsers.util.mergeWith
|
||||
|
||||
internal class MangaParserWrapper(
|
||||
private val delegate: MangaParser,
|
||||
) : MangaParser by delegate {
|
||||
|
||||
override suspend fun getList(searchQuery: MangaSearchQuery): List<Manga> = withContext(Dispatchers.Default) {
|
||||
if (!searchQuery.skipValidation) {
|
||||
searchQueryCapabilities.validate(searchQuery)
|
||||
}
|
||||
delegate.getList(searchQuery)
|
||||
}
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga = withContext(Dispatchers.Default) {
|
||||
delegate.getDetails(manga)
|
||||
}
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> = withContext(Dispatchers.Default) {
|
||||
delegate.getPages(chapter)
|
||||
}
|
||||
|
||||
override suspend fun getPageUrl(page: MangaPage): String = withContext(Dispatchers.Default) {
|
||||
delegate.getPageUrl(page)
|
||||
}
|
||||
|
||||
override suspend fun getFilterOptions(): MangaListFilterOptions = withContext(Dispatchers.Default) {
|
||||
delegate.getFilterOptions()
|
||||
}
|
||||
|
||||
override suspend fun getFavicons(): Favicons = withContext(Dispatchers.Default) {
|
||||
delegate.getFavicons()
|
||||
}
|
||||
|
||||
override suspend fun getRelatedManga(seed: Manga): List<Manga> = withContext(Dispatchers.Default) {
|
||||
delegate.getRelatedManga(seed)
|
||||
}
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
val headers = request.headers.newBuilder()
|
||||
.mergeWith(delegate.getRequestHeaders(), replaceExisting = false)
|
||||
.build()
|
||||
val newRequest = request.newBuilder().headers(headers).build()
|
||||
return delegate.intercept(ProxyChain(chain, newRequest))
|
||||
}
|
||||
|
||||
private class ProxyChain(
|
||||
private val delegate: Interceptor.Chain,
|
||||
private val request: Request,
|
||||
) : Interceptor.Chain by delegate {
|
||||
|
||||
override fun request(): Request = request
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
package org.koitharu.kotatsu.parsers.core
|
||||
|
||||
import org.koitharu.kotatsu.parsers.InternalParsersApi
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaParserSource
|
||||
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQuery
|
||||
|
||||
@InternalParsersApi
|
||||
public abstract class SinglePageMangaParser(
|
||||
context: MangaLoaderContext,
|
||||
source: MangaParserSource,
|
||||
) : AbstractMangaParser(context, source) {
|
||||
|
||||
final override suspend fun getList(query: MangaSearchQuery): List<Manga> {
|
||||
if (query.offset > 0) {
|
||||
return emptyList()
|
||||
}
|
||||
return getSinglePageList(query)
|
||||
}
|
||||
|
||||
public abstract suspend fun getSinglePageList(searchQuery: MangaSearchQuery): List<Manga>
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue