MangaParser interface
parent
a4827d1b7d
commit
29cf04c804
@ -0,0 +1,128 @@
|
||||
package org.koitharu.kotatsu.parsers
|
||||
|
||||
import androidx.annotation.CallSuper
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
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.model.search.MangaSearchQuery
|
||||
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQueryCapabilities
|
||||
import org.koitharu.kotatsu.parsers.network.OkHttpWebClient
|
||||
import org.koitharu.kotatsu.parsers.network.WebClient
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.util.*
|
||||
|
||||
@InternalParsersApi
|
||||
public abstract class AbstractMangaParser @InternalParsersApi constructor(
|
||||
@property:InternalParsersApi public val context: MangaLoaderContext,
|
||||
public override val source: MangaParserSource,
|
||||
) : MangaParser {
|
||||
|
||||
@Deprecated("Please check searchQueryCapabilities")
|
||||
public abstract val filterCapabilities: MangaListFilterCapabilities
|
||||
|
||||
public override val searchQueryCapabilities: MangaSearchQueryCapabilities
|
||||
get() = filterCapabilities.toMangaSearchQueryCapabilities()
|
||||
|
||||
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)
|
||||
|
||||
protected val isNsfwSource: Boolean = source.contentType == ContentType.HENTAI
|
||||
|
||||
/**
|
||||
* 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())
|
||||
|
||||
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)
|
||||
|
||||
/**
|
||||
* Search list of manga by specified searchQuery
|
||||
*
|
||||
* @param searchQuery searchQuery
|
||||
*/
|
||||
public override suspend fun queryManga(searchQuery: MangaSearchQuery): List<Manga> {
|
||||
if (!searchQuery.skipValidation) {
|
||||
searchQueryCapabilities.validate(searchQuery)
|
||||
}
|
||||
|
||||
return getList(searchQuery)
|
||||
}
|
||||
|
||||
/**
|
||||
* Search list of manga by specified searchQuery
|
||||
*
|
||||
* @param query searchQuery
|
||||
*/
|
||||
protected open suspend fun getList(query: MangaSearchQuery): List<Manga> = getList(
|
||||
offset = query.offset,
|
||||
order = query.order ?: defaultSortOrder,
|
||||
filter = convertToMangaListFilter(query),
|
||||
)
|
||||
|
||||
/**
|
||||
* Parse list of manga by specified criteria
|
||||
*
|
||||
* @param offset starting from 0 and used for pagination.
|
||||
* Note than passed value may not be divisible by internal page size, so you should adjust it manually.
|
||||
* @param order one of [availableSortOrders] or [defaultSortOrder] for default value
|
||||
* @param filter is a set of filter rules
|
||||
*
|
||||
* @deprecated New [getList] should be preferred.
|
||||
*/
|
||||
@Deprecated("New getList(query: MangaSearchQuery) method should be preferred")
|
||||
public abstract suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga>
|
||||
|
||||
/**
|
||||
* 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]
|
||||
*/
|
||||
internal open suspend fun resolveLink(resolver: LinkResolver, link: HttpUrl): Manga? = null
|
||||
|
||||
}
|
||||
@ -1,145 +1,60 @@
|
||||
package org.koitharu.kotatsu.parsers
|
||||
|
||||
import androidx.annotation.CallSuper
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
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.model.search.*
|
||||
import org.koitharu.kotatsu.parsers.network.OkHttpWebClient
|
||||
import org.koitharu.kotatsu.parsers.network.WebClient
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQuery
|
||||
import org.koitharu.kotatsu.parsers.model.search.MangaSearchQueryCapabilities
|
||||
import java.util.*
|
||||
|
||||
public abstract class MangaParser @InternalParsersApi constructor(
|
||||
@property:InternalParsersApi public val context: MangaLoaderContext,
|
||||
public val source: MangaParserSource,
|
||||
) {
|
||||
public interface MangaParser {
|
||||
|
||||
public val source: MangaParserSource
|
||||
|
||||
/**
|
||||
* Supported [SortOrder] variants. Must not be empty.
|
||||
*
|
||||
* For better performance use [EnumSet] for more than one item.
|
||||
*/
|
||||
public abstract val availableSortOrders: Set<SortOrder>
|
||||
|
||||
@Deprecated("Please check searchQueryCapabilities")
|
||||
public abstract val filterCapabilities: MangaListFilterCapabilities
|
||||
|
||||
public open val searchQueryCapabilities: MangaSearchQueryCapabilities
|
||||
get() = filterCapabilities.toMangaSearchQueryCapabilities()
|
||||
|
||||
public val config: MangaSourceConfig by lazy { context.getConfig(source) }
|
||||
public val availableSortOrders: Set<SortOrder>
|
||||
|
||||
public open val sourceLocale: Locale
|
||||
get() = if (source.locale.isEmpty()) Locale.ROOT else Locale(source.locale)
|
||||
public val searchQueryCapabilities: MangaSearchQueryCapabilities
|
||||
|
||||
protected val isNsfwSource: Boolean = source.contentType == ContentType.HENTAI
|
||||
|
||||
/**
|
||||
* Provide default domain and available alternatives, if any.
|
||||
*
|
||||
* Never hardcode domain in requests, use [domain] instead.
|
||||
*/
|
||||
@InternalParsersApi
|
||||
public abstract val configKeyDomain: ConfigKey.Domain
|
||||
public val config: MangaSourceConfig
|
||||
|
||||
protected open val userAgentKey: ConfigKey.UserAgent = ConfigKey.UserAgent(context.getDefaultUserAgent())
|
||||
public val domain: String
|
||||
|
||||
public open 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 }
|
||||
}
|
||||
|
||||
@JvmField
|
||||
protected val webClient: WebClient = OkHttpWebClient(context.httpClient, source)
|
||||
|
||||
/**
|
||||
* Search list of manga by specified searchQuery
|
||||
*
|
||||
* @param searchQuery searchQuery
|
||||
*/
|
||||
public suspend fun queryManga(searchQuery: MangaSearchQuery): List<Manga> {
|
||||
if (!searchQuery.skipValidation) {
|
||||
searchQueryCapabilities.validate(searchQuery)
|
||||
}
|
||||
|
||||
return getList(searchQuery)
|
||||
}
|
||||
|
||||
/**
|
||||
* Search list of manga by specified searchQuery
|
||||
*
|
||||
* @param query searchQuery
|
||||
*/
|
||||
protected open suspend fun getList(query: MangaSearchQuery): List<Manga> = getList(
|
||||
offset = query.offset,
|
||||
order = query.order ?: defaultSortOrder,
|
||||
filter = convertToMangaListFilter(query),
|
||||
)
|
||||
|
||||
/**
|
||||
* Parse list of manga by specified criteria
|
||||
*
|
||||
* @param offset starting from 0 and used for pagination.
|
||||
* Note than passed value may not be divisible by internal page size, so you should adjust it manually.
|
||||
* @param order one of [availableSortOrders] or [defaultSortOrder] for default value
|
||||
* @param filter is a set of filter rules
|
||||
*
|
||||
* @deprecated New [getList] should be preferred.
|
||||
*/
|
||||
@Deprecated("New getList(query: MangaSearchQuery) method should be preferred")
|
||||
public abstract suspend fun getList(offset: Int, order: SortOrder, filter: MangaListFilter): List<Manga>
|
||||
public suspend fun queryManga(searchQuery: MangaSearchQuery): List<Manga>
|
||||
|
||||
/**
|
||||
* Parse details for [Manga]: chapters list, description, large cover, etc.
|
||||
* Must return the same manga, may change any fields excepts id, url and source
|
||||
* @see Manga.copy
|
||||
*/
|
||||
public abstract suspend fun getDetails(manga: Manga): Manga
|
||||
public suspend fun getDetails(manga: Manga): Manga
|
||||
|
||||
/**
|
||||
* Parse pages list for specified chapter.
|
||||
* @see MangaPage for details
|
||||
*/
|
||||
public abstract suspend fun getPages(chapter: MangaChapter): List<MangaPage>
|
||||
public suspend fun getPages(chapter: MangaChapter): List<MangaPage>
|
||||
|
||||
/**
|
||||
* Fetch direct link to the page image.
|
||||
*/
|
||||
public open suspend fun getPageUrl(page: MangaPage): String = page.url.toAbsoluteUrl(domain)
|
||||
public suspend fun getPageUrl(page: MangaPage): String
|
||||
|
||||
public abstract suspend fun getFilterOptions(): MangaListFilterOptions
|
||||
public suspend fun getFilterOptions(): MangaListFilterOptions
|
||||
|
||||
/**
|
||||
* Parse favicons from the main page of the source`s website
|
||||
*/
|
||||
public open suspend fun getFavicons(): Favicons {
|
||||
return FaviconParser(webClient, domain).parseFavicons()
|
||||
}
|
||||
public suspend fun getFavicons(): Favicons
|
||||
|
||||
@CallSuper
|
||||
public open fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
keys.add(configKeyDomain)
|
||||
}
|
||||
public fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>)
|
||||
|
||||
public open suspend fun getRelatedManga(seed: Manga): List<Manga> {
|
||||
return RelatedMangaFinder(listOf(this)).invoke(seed)
|
||||
}
|
||||
|
||||
/**
|
||||
* Return [Manga] object by web link to it
|
||||
* @see [Manga.publicUrl]
|
||||
*/
|
||||
internal open suspend fun resolveLink(resolver: LinkResolver, link: HttpUrl): Manga? = null
|
||||
public suspend fun getRelatedManga(seed: Manga): List<Manga>
|
||||
|
||||
public fun getRequestHeaders(): Headers
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue